bitburner-src/src/Netscript/WorkerScript.ts

211 lines
5.4 KiB
TypeScript
Raw Normal View History

/**
* 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 { Environment } from "./Environment";
import { RamCostConstants } from "./RamCostGenerator";
import { RunningScript } from "../Script/RunningScript";
import { Script } from "../Script/Script";
2021-10-07 22:56:01 +02:00
import { GetServer } from "../Server/AllServers";
import { BaseServer } from "../Server/BaseServer";
import { IMap } from "../types";
2022-05-25 21:08:48 +02:00
import { NS } from "../ScriptEditor/NetscriptDefinitions";
2022-07-15 07:51:30 +02:00
import { ScriptDeath } from "./ScriptDeath";
import { ScriptArg } from "./ScriptArg";
export class WorkerScript {
2021-09-05 01:09:30 +02:00
/**
* Script's arguments
*/
2022-07-15 07:51:30 +02:00
args: ScriptArg[];
2021-09-05 01:09:30 +02:00
/**
* 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
2021-09-05 01:09:30 +02:00
*/
2022-07-15 07:51:30 +02:00
delayReject?: (reason?: ScriptDeath) => void;
2021-09-05 01:09:30 +02:00
/**
* Stores names of all functions that have logging disabled
*/
2021-09-25 03:49:49 +02:00
disableLogs: IMap<boolean> = {};
2021-09-05 01:09:30 +02:00
/**
* 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?
*/
2021-09-25 03:49:49 +02:00
dynamicLoadedFns: IMap<boolean> = {};
2021-09-05 01:09:30 +02:00
/**
* Tracks dynamic RAM usage
*/
dynamicRamUsage: number = RamCostConstants.ScriptBaseRamCost;
/**
* Netscript Environment for this script
*/
env: Environment;
/**
2022-02-06 00:14:53 +01:00
* Status message in case of script error.
2021-09-05 01:09:30 +02:00
*/
errorMessage = "";
/**
* Used for static RAM calculation. Stores names of all functions that have
* already been checked by this script
*/
2021-09-25 00:13:20 +02:00
loadedFns: IMap<boolean> = {};
2021-09-05 01:09:30 +02:00
/**
* Filename of script
*/
name: string;
/**
* 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;
/**
* Script's Static RAM usage. Equivalent to underlying script's RAM usage
*/
ramUsage = 0;
/**
* Reference to underlying RunningScript object
*/
scriptRef: RunningScript;
/**
2022-03-17 14:50:23 +01:00
* hostname on which this script is running
2021-09-05 01:09:30 +02:00
*/
2021-10-07 23:55:49 +02:00
hostname: string;
2021-09-05 01:09:30 +02:00
2021-10-15 02:13:26 +02:00
/**
* Function called when the script ends.
*/
2022-07-15 07:51:30 +02:00
atExit?: () => void;
2021-10-15 02:13:26 +02:00
2022-05-25 21:08:48 +02:00
constructor(runningScriptObj: RunningScript, pid: number, nsFuncsGenerator?: (ws: WorkerScript) => NS) {
2021-09-05 01:09:30 +02:00
this.name = runningScriptObj.filename;
2021-10-07 23:55:49 +02:00
this.hostname = runningScriptObj.server;
2021-09-05 01:09:30 +02:00
const sanitizedPid = Math.round(pid);
if (typeof sanitizedPid !== "number" || isNaN(sanitizedPid)) {
throw new Error(`Invalid PID when constructing WorkerScript: ${pid}`);
}
2021-09-05 01:09:30 +02:00
this.pid = sanitizedPid;
runningScriptObj.pid = sanitizedPid;
// Get the underlying script's code
2021-10-07 23:55:49 +02:00
const server = GetServer(this.hostname);
2021-09-05 01:09:30 +02:00
if (server == null) {
2021-10-07 23:55:49 +02:00
throw new Error(`WorkerScript constructed with invalid server ip: ${this.hostname}`);
}
2021-09-05 01:09:30 +02:00
let found = false;
for (let i = 0; i < server.scripts.length; ++i) {
if (server.scripts[i].filename === this.name) {
found = true;
this.code = server.scripts[i].code;
}
}
if (!found) {
2021-09-09 05:47:34 +02:00
throw new Error(`WorkerScript constructed with invalid script filename: ${this.name}`);
}
2021-10-15 19:12:18 +02:00
this.scriptRef = runningScriptObj;
this.args = runningScriptObj.args.slice();
2022-07-20 07:13:06 +02:00
this.env = new Environment();
2021-09-05 01:09:30 +02:00
if (typeof nsFuncsGenerator === "function") {
this.env.vars = nsFuncsGenerator(this);
}
}
/**
* Returns the Server on which this script is running
*/
getServer(): BaseServer {
2021-10-07 23:55:49 +02:00
const server = GetServer(this.hostname);
2021-09-09 05:47:34 +02:00
if (server == null) throw new Error(`Script ${this.name} pid ${this.pid} is running on non-existent server?`);
2021-09-05 01:09:30 +02:00
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();
for (let i = 0; i < server.scripts.length; ++i) {
if (server.scripts[i].filename === this.name) {
return server.scripts[i];
}
}
2021-09-05 01:09:30 +02:00
console.error(
"Failed to find underlying Script object in WorkerScript.getScript(). This probably means somethings wrong",
);
return null;
}
/**
* Returns the script with the specified filename on the specified server,
* or null if it cannot be found
*/
getScriptOnServer(fn: string, server: BaseServer): Script | null {
if (server == null) {
server = this.getServer();
}
2021-09-05 01:09:30 +02:00
for (let i = 0; i < server.scripts.length; ++i) {
if (server.scripts[i].filename === fn) {
return server.scripts[i];
}
}
2021-09-05 01:09:30 +02:00
return null;
}
shouldLog(fn: string): boolean {
return this.disableLogs[fn] == null;
}
log(func: string, txt: () => string): void {
2021-09-05 01:09:30 +02:00
if (this.shouldLog(func)) {
if (func && txt) {
this.scriptRef.log(`${func}: ${txt()}`);
2021-09-05 01:09:30 +02:00
} else if (func) {
this.scriptRef.log(func);
} else {
this.scriptRef.log(txt());
2021-09-05 01:09:30 +02:00
}
}
2021-09-05 01:09:30 +02:00
}
print(txt: string): void {
this.scriptRef.log(txt);
}
}