Files
bitburner-src/src/NetscriptFunctions/UserInterface.ts

194 lines
6.8 KiB
TypeScript

import { UserInterface as IUserInterface } from "@nsdefs";
import { Settings } from "../Settings/Settings";
import { ThemeEvents } from "../Themes/ui/Theme";
import { defaultTheme } from "../Themes/Themes";
import { defaultStyles } from "../Themes/Styles";
import { CONSTANTS } from "../Constants";
import { commitHash } from "../utils/helpers/commitHash";
import { InternalAPI } from "../Netscript/APIWrapper";
import { Terminal } from "../../src/Terminal";
import { helpers, wrapUserNode } from "../Netscript/NetscriptHelpers";
import { assertAndSanitizeMainTheme, assertAndSanitizeStyles } from "../JsonSchema/JSONSchemaAssertion";
import { LogBoxCloserEvents, LogBoxEvents } from "../ui/React/LogBoxManager";
export function NetscriptUserInterface(): InternalAPI<IUserInterface> {
return {
openTail:
(ctx) =>
(scriptID, host, ...scriptArgs) => {
const ident = helpers.scriptIdentifier(ctx, scriptID, host, scriptArgs);
const runningScriptObj = helpers.getRunningScript(ctx, ident);
if (runningScriptObj == null) {
helpers.log(ctx, () => helpers.getCannotFindRunningScriptErrorMessage(ident));
return;
}
LogBoxEvents.emit(runningScriptObj);
},
renderTail:
(ctx) =>
(_pid = ctx.workerScript.scriptRef.pid) => {
const pid = helpers.number(ctx, "pid", _pid);
const runningScriptObj = helpers.getRunningScript(ctx, pid);
if (runningScriptObj == null) {
helpers.log(ctx, () => helpers.getCannotFindRunningScriptErrorMessage(pid));
return;
}
runningScriptObj.tailProps?.rerender();
},
moveTail:
(ctx) =>
(_x, _y, _pid = ctx.workerScript.scriptRef.pid) => {
const x = helpers.number(ctx, "x", _x);
const y = helpers.number(ctx, "y", _y);
const pid = helpers.number(ctx, "pid", _pid);
const runningScriptObj = helpers.getRunningScript(ctx, pid);
if (runningScriptObj == null) {
helpers.log(ctx, () => helpers.getCannotFindRunningScriptErrorMessage(pid));
return;
}
runningScriptObj.tailProps?.setPosition(x, y);
},
resizeTail:
(ctx) =>
(_w, _h, _pid = ctx.workerScript.scriptRef.pid) => {
const w = helpers.number(ctx, "w", _w);
const h = helpers.number(ctx, "h", _h);
const pid = helpers.number(ctx, "pid", _pid);
const runningScriptObj = helpers.getRunningScript(ctx, pid);
if (runningScriptObj == null) {
helpers.log(ctx, () => helpers.getCannotFindRunningScriptErrorMessage(pid));
return;
}
runningScriptObj.tailProps?.setSize(w, h);
},
closeTail:
(ctx) =>
(_pid = ctx.workerScript.scriptRef.pid) => {
const pid = helpers.number(ctx, "pid", _pid);
const runningScriptObj = helpers.getRunningScript(ctx, pid);
if (runningScriptObj == null) {
helpers.log(ctx, () => helpers.getCannotFindRunningScriptErrorMessage(pid));
return;
}
// Emit an event to tell the game to close the tail window if it exists.
LogBoxCloserEvents.emit(pid);
},
setTailTitle:
(ctx) =>
(title, _pid = ctx.workerScript.scriptRef.pid) => {
const pid = helpers.number(ctx, "pid", _pid);
const runningScriptObj = helpers.getRunningScript(ctx, pid);
if (runningScriptObj == null) {
helpers.log(ctx, () => helpers.getCannotFindRunningScriptErrorMessage(pid));
return;
}
runningScriptObj.title = typeof title === "string" ? title : wrapUserNode(title);
runningScriptObj.tailProps?.rerender();
},
setTailFontSize:
(ctx) =>
(_pixel, scriptID, host, ...scriptArgs) => {
const ident = helpers.scriptIdentifier(ctx, scriptID, host, scriptArgs);
const runningScriptObj = helpers.getRunningScript(ctx, ident);
if (runningScriptObj == null) {
helpers.log(ctx, () => helpers.getCannotFindRunningScriptErrorMessage(ident));
return;
}
if (_pixel === undefined) runningScriptObj.tailProps?.setFontSize(undefined);
else runningScriptObj.tailProps?.setFontSize(helpers.number(ctx, "pixel", _pixel));
},
setTailMinimized:
(ctx) =>
(_minimized, _pid = ctx.workerScript.scriptRef.pid) => {
const minimized = helpers.boolean(ctx, "minimized", _minimized);
const pid = helpers.number(ctx, "pid", _pid);
const runningScriptObj = helpers.getRunningScript(ctx, pid);
if (runningScriptObj == null) {
helpers.log(ctx, () => helpers.getCannotFindRunningScriptErrorMessage(pid));
return;
}
runningScriptObj.tailProps?.setMinimized(minimized);
},
windowSize: () => () => {
return [window.innerWidth, window.innerHeight];
},
getTheme: () => () => {
return { ...Settings.theme };
},
getStyles: () => () => {
return { ...Settings.styles };
},
setTheme: (ctx) => (newTheme) => {
let newData: unknown;
try {
/**
* assertAndSanitizeMainTheme may mutate its parameter, so we have to clone the user-provided data here.
*/
newData = structuredClone(newTheme);
assertAndSanitizeMainTheme(newData);
} catch (error) {
helpers.log(ctx, () => `Failed to set theme. Errors: ${error}`);
return;
}
Object.assign(Settings.theme, newData);
ThemeEvents.emit();
helpers.log(ctx, () => `Successfully set theme`);
},
setStyles: (ctx) => (newStyles) => {
let newData: unknown;
try {
/**
* assertAndSanitizeStyles may mutate its parameter, so we have to clone the user-provided data here.
*/
newData = structuredClone(newStyles);
assertAndSanitizeStyles(newData);
} catch (error) {
helpers.log(ctx, () => `Failed to set styles. Errors: ${error}`);
return;
}
Object.assign(Settings.styles, newData);
ThemeEvents.emit();
helpers.log(ctx, () => `Successfully set styles`);
},
resetTheme: (ctx) => () => {
Settings.theme = { ...defaultTheme };
ThemeEvents.emit();
helpers.log(ctx, () => `Reinitialized theme to default`);
},
resetStyles: (ctx) => () => {
Settings.styles = { ...defaultStyles };
ThemeEvents.emit();
helpers.log(ctx, () => `Reinitialized styles to default`);
},
getGameInfo: () => () => {
return {
version: CONSTANTS.VersionString,
versionNumber: CONSTANTS.VersionNumber,
commit: commitHash(),
platform: navigator.userAgent.toLowerCase().includes(" electron/") ? "Steam" : "Browser",
};
},
clearTerminal: (ctx) => () => {
helpers.log(ctx, () => `Clearing terminal`);
Terminal.clear();
},
};
}