bitburner-src/src/Script/RunningScript.ts

149 lines
4.7 KiB
TypeScript
Raw Normal View History

/**
* Class representing a Script instance that is actively running.
* A Script can have multiple active instances
*/
import type React from "react";
import { Script } from "./Script";
import { ScriptURL } from "./LoadedModule";
import { Settings } from "../Settings/Settings";
2021-09-16 08:52:45 +02:00
import { Terminal } from "../Terminal";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
import { formatTime } from "../utils/helpers/formatTime";
import { ScriptArg } from "@nsdefs";
import { RamCostConstants } from "../Netscript/RamCostGenerator";
import { PositiveInteger } from "../types";
import { getKeyList } from "../utils/helpers/getKeyList";
FILES: Path rework & typesafety (#479) * Added new types for various file paths, all in the Paths folder. * TypeSafety and other helper functions related to these types * Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands * Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way * Server.textFiles is now a map * TextFile no longer uses a fn property, now it is filename * Added a shared ContentFile interface for shared functionality between TextFile and Script. * related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa. * File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root. * Singularized the MessageFilename and LiteratureName enums * Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath). * Fix several issues with tab completion, which included pretty much a complete rewrite * Changed the autocomplete display options so there's less chance it clips outside the display area. * Turned CompletedProgramName into an enum. * Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine. * For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
import { ScriptFilePath } from "../Paths/ScriptFilePath";
2019-03-03 04:15:10 +01:00
export class RunningScript {
2021-09-05 01:09:30 +02:00
// Script arguments
2022-07-18 08:36:51 +02:00
args: ScriptArg[] = [];
2019-03-03 04:15:10 +01:00
2021-10-07 23:55:49 +02:00
// Map of [key: hostname] -> Hacking data. Used for offline progress calculations.
2021-09-05 01:09:30 +02:00
// Hacking data format: [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
2022-10-03 18:12:16 +02:00
dataMap: Record<string, number[]> = {};
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// Script filename
FILES: Path rework & typesafety (#479) * Added new types for various file paths, all in the Paths folder. * TypeSafety and other helper functions related to these types * Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands * Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way * Server.textFiles is now a map * TextFile no longer uses a fn property, now it is filename * Added a shared ContentFile interface for shared functionality between TextFile and Script. * related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa. * File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root. * Singularized the MessageFilename and LiteratureName enums * Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath). * Fix several issues with tab completion, which included pretty much a complete rewrite * Changed the autocomplete display options so there's less chance it clips outside the display area. * Turned CompletedProgramName into an enum. * Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine. * For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
filename = "default.js" as ScriptFilePath;
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// This script's logs. An array of log entries
logs: React.ReactNode[] = [];
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// Flag indicating whether the logs have been updated since
// the last time the UI was updated
logUpd = false;
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// Total amount of hacking experience earned from this script when offline
offlineExpGained = 0;
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// Total amount of money made by this script when offline
offlineMoneyMade = 0;
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// Number of seconds that the script has been running offline
offlineRunningTime = 0.01;
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// Total amount of hacking experience earned from this script when online
onlineExpGained = 0;
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// Total amount of money made by this script when online
onlineMoneyMade = 0;
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// Number of seconds that this script has been running online
onlineRunningTime = 0.01;
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// Process ID. Must be an integer and equals the PID of corresponding WorkerScript
pid = -1;
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// How much RAM this script uses for ONE thread
ramUsage = RamCostConstants.Base;
2021-10-07 23:55:49 +02:00
// hostname of the server on which this script is running
2021-09-05 01:09:30 +02:00
server = "";
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
// Number of threads that this script is running with
threads = 1 as PositiveInteger;
2019-03-03 04:15:10 +01:00
// Whether this RunningScript is excluded from saves
temporary = false;
2021-12-13 01:39:53 +01:00
// Script urls for the current running script for translating urls back to file names in errors
dependencies: Map<ScriptURL, Script> = new Map();
2021-12-13 01:39:53 +01:00
constructor(script?: Script, ramUsage?: number, args: ScriptArg[] = []) {
if (!script) return;
if (!ramUsage) throw new Error("Must provide a ramUsage for RunningScript initialization.");
2021-09-05 01:09:30 +02:00
this.filename = script.filename;
this.args = args;
this.server = script.server;
this.ramUsage = ramUsage;
this.dependencies = script.dependencies;
2021-09-05 01:09:30 +02:00
}
log(txt: React.ReactNode): void {
2021-09-05 01:09:30 +02:00
if (this.logs.length > Settings.MaxLogCapacity) {
this.logs.shift();
2019-03-03 04:15:10 +01:00
}
2021-09-05 01:09:30 +02:00
let logEntry = txt;
if (Settings.TimestampsFormat && typeof txt === "string") {
logEntry = "[" + formatTime(Settings.TimestampsFormat) + "] " + logEntry;
2019-03-03 04:15:10 +01:00
}
2021-09-05 01:09:30 +02:00
this.logs.push(logEntry);
this.logUpd = true;
}
2019-03-03 04:15:10 +01:00
2021-09-05 01:09:30 +02:00
displayLog(): void {
for (const log of this.logs) {
if (typeof log === "string") {
Terminal.print(log);
} else {
Terminal.printRaw(log);
}
2019-03-03 04:15:10 +01:00
}
2021-09-05 01:09:30 +02:00
}
clearLog(): void {
this.logs.length = 0;
}
// Update the moneyStolen and numTimesHack maps when hacking
2021-10-07 23:55:49 +02:00
recordHack(hostname: string, moneyGained: number, n = 1): void {
if (this.dataMap[hostname] == null || this.dataMap[hostname].constructor !== Array) {
this.dataMap[hostname] = [0, 0, 0, 0];
2019-03-03 04:15:10 +01:00
}
2021-10-07 23:55:49 +02:00
this.dataMap[hostname][0] += moneyGained;
this.dataMap[hostname][1] += n;
2021-09-05 01:09:30 +02:00
}
// Update the grow map when calling grow()
2021-10-07 23:55:49 +02:00
recordGrow(hostname: string, n = 1): void {
if (this.dataMap[hostname] == null || this.dataMap[hostname].constructor !== Array) {
this.dataMap[hostname] = [0, 0, 0, 0];
2019-03-03 04:15:10 +01:00
}
2021-10-07 23:55:49 +02:00
this.dataMap[hostname][2] += n;
2021-09-05 01:09:30 +02:00
}
// Update the weaken map when calling weaken() {
2021-10-07 23:55:49 +02:00
recordWeaken(hostname: string, n = 1): void {
if (this.dataMap[hostname] == null || this.dataMap[hostname].constructor !== Array) {
this.dataMap[hostname] = [0, 0, 0, 0];
2021-05-01 09:17:31 +02:00
}
2021-10-07 23:55:49 +02:00
this.dataMap[hostname][3] += n;
2021-09-05 01:09:30 +02:00
}
// Serialize the current object to a JSON save state
2022-07-15 01:00:10 +02:00
toJSON(): IReviverValue {
return Generic_toJSON("RunningScript", this, includedProperties);
2021-09-05 01:09:30 +02:00
}
// Initializes a RunningScript Object from a JSON save state
2022-07-15 01:00:10 +02:00
static fromJSON(value: IReviverValue): RunningScript {
return Generic_fromJSON(RunningScript, value.data, includedProperties);
2021-09-05 01:09:30 +02:00
}
2019-03-03 04:15:10 +01:00
}
const includedProperties = getKeyList(RunningScript, { removedKeys: ["logs", "dependencies", "logUpd", "pid"] });
2019-03-03 04:15:10 +01:00
constructorsForReviver.RunningScript = RunningScript;