mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-18 23:38:35 +02:00
The current implementation was naive; disableLog("ALL") was storing a
key for every function, and iterating over a different object to do it
(when iterating over objects is quite slow).
The common cases of Bitburner (and especially batching, where efficiency
matters most) are either never disabling anything, or disabling "ALL".
This optimizes for these two cases, at the expense of slightly more
complicated code to deal with the less-common edge cases.
153 lines
4.7 KiB
TypeScript
153 lines
4.7 KiB
TypeScript
/**
|
|
* The worker agent for running a script instance. Each running script instance
|
|
* has its own underlying WorkerScript object.
|
|
*
|
|
* Note that these objects are not saved and re-loaded when the game is refreshed.
|
|
* Instead, whenever the game is opened, WorkerScripts are re-created from
|
|
* RunningScript objects
|
|
*/
|
|
import type React from "react";
|
|
import type { BaseServer } from "../Server/BaseServer";
|
|
import type { NSFull } from "../NetscriptFunctions";
|
|
import type { ScriptFilePath } from "../Paths/ScriptFilePath";
|
|
import type { RunningScript } from "../Script/RunningScript";
|
|
import type { Script } from "../Script/Script";
|
|
import type { ScriptArg } from "@nsdefs";
|
|
import type { ScriptDeath } from "./ScriptDeath";
|
|
|
|
import { Environment } from "./Environment";
|
|
import { RamCostConstants } from "./RamCostGenerator";
|
|
import { GetServer } from "../Server/AllServers";
|
|
|
|
export class WorkerScript {
|
|
/** Script's arguments */
|
|
args: ScriptArg[];
|
|
|
|
/** Copy of the script's code */
|
|
code = "";
|
|
|
|
/**
|
|
* Holds the timeoutID (numeric value) for whenever this script is blocked by a
|
|
* timed Netscript function. i.e. Holds the return value of setTimeout()
|
|
*/
|
|
delay: number | null = null;
|
|
|
|
/** Holds the Promise reject() function while the script is "blocked" by an async op */
|
|
delayReject: ((reason?: ScriptDeath) => void) | undefined = undefined;
|
|
|
|
/** Stores names of all functions that have logging disabled */
|
|
disableLogs: Record<string, boolean> = {};
|
|
|
|
/**
|
|
* Used for dynamic RAM calculation. Stores names of all functions that have
|
|
* already been checked by this script.
|
|
* TODO: Could probably just combine this with loadedFns?
|
|
*/
|
|
dynamicLoadedFns: Record<string, boolean> = {};
|
|
|
|
/** Tracks dynamic RAM usage */
|
|
dynamicRamUsage: number = RamCostConstants.Base;
|
|
|
|
/** Netscript Environment for this script */
|
|
env: Environment;
|
|
|
|
/**
|
|
* Used for static RAM calculation. Stores names of all functions that have
|
|
* already been checked by this script
|
|
*/
|
|
loadedFns: Record<string, boolean> = {};
|
|
|
|
/** Filename of script */
|
|
name: ScriptFilePath;
|
|
|
|
/** Script's output/return value. Currently not used or implemented */
|
|
output = "";
|
|
|
|
/**
|
|
* Process ID. Must be an integer. Used for efficient script
|
|
* killing and removal.
|
|
*/
|
|
pid: number;
|
|
|
|
/** Reference to underlying RunningScript object */
|
|
scriptRef: RunningScript;
|
|
|
|
/** hostname on which this script is running */
|
|
hostname: string;
|
|
|
|
/**Map of functions called when the script ends. */
|
|
atExit: Map<string, () => void> = new Map();
|
|
|
|
constructor(runningScriptObj: RunningScript, pid: number, nsFuncsGenerator?: (ws: WorkerScript) => NSFull) {
|
|
this.name = runningScriptObj.filename;
|
|
this.hostname = runningScriptObj.server;
|
|
|
|
const sanitizedPid = Math.round(pid);
|
|
if (typeof sanitizedPid !== "number" || isNaN(sanitizedPid)) {
|
|
throw new Error(`Invalid PID when constructing WorkerScript: ${pid}`);
|
|
}
|
|
this.pid = sanitizedPid;
|
|
runningScriptObj.pid = sanitizedPid;
|
|
|
|
// Get the underlying script's code
|
|
const server = GetServer(this.hostname);
|
|
if (server == null) {
|
|
throw new Error(`WorkerScript constructed with invalid server ip: ${this.hostname}`);
|
|
}
|
|
const script = server.scripts.get(this.name);
|
|
if (!script) {
|
|
throw new Error(`WorkerScript constructed with invalid script filename: ${this.name}`);
|
|
}
|
|
this.code = script.code;
|
|
this.scriptRef = runningScriptObj;
|
|
this.args = runningScriptObj.args.slice();
|
|
this.env = new Environment();
|
|
if (typeof nsFuncsGenerator === "function") {
|
|
this.env.vars = nsFuncsGenerator(this);
|
|
}
|
|
}
|
|
|
|
/** Returns the Server on which this script is running */
|
|
getServer(): BaseServer {
|
|
const server = GetServer(this.hostname);
|
|
if (server == null) throw new Error(`Script ${this.name} pid ${this.pid} is running on non-existent server?`);
|
|
return server;
|
|
}
|
|
|
|
/**
|
|
* Returns the Script object for the underlying script.
|
|
* Returns null if it cannot be found (which would be a bug)
|
|
*/
|
|
getScript(): Script | null {
|
|
const server = this.getServer();
|
|
const script = server.scripts.get(this.name);
|
|
if (!script) {
|
|
console.error(
|
|
"Failed to find underlying Script object in WorkerScript.getScript(). This probably means somethings wrong",
|
|
);
|
|
return null;
|
|
}
|
|
return script;
|
|
}
|
|
|
|
shouldLog(fn: string): boolean {
|
|
return !(this.disableLogs.ALL || this.disableLogs[fn]);
|
|
}
|
|
|
|
log(func: string, txt: () => string): void {
|
|
if (this.shouldLog(func)) {
|
|
if (func && txt) {
|
|
this.scriptRef.log(`${func}: ${txt()}`);
|
|
} else if (func) {
|
|
this.scriptRef.log(func);
|
|
} else {
|
|
this.scriptRef.log(txt());
|
|
}
|
|
}
|
|
}
|
|
|
|
print(txt: React.ReactNode): void {
|
|
this.scriptRef.log(txt);
|
|
}
|
|
}
|