mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-18 05:33:54 +01:00
NETSCRIPT: Rework script ram updates (#408)
This commit is contained in:
parent
14aafbe0a3
commit
759f86d6e5
@ -1,4 +1,4 @@
|
|||||||
import { PlayerObject } from "src/PersonObjects/Player/PlayerObject";
|
import { PlayerObject } from "../PersonObjects/Player/PlayerObject";
|
||||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||||
import { SkillNames } from "../Bladeburner/data/SkillNames";
|
import { SkillNames } from "../Bladeburner/data/SkillNames";
|
||||||
import { Skills } from "../Bladeburner/Skills";
|
import { Skills } from "../Bladeburner/Skills";
|
||||||
@ -341,7 +341,7 @@ export const achievements: Record<string, Achievement> = {
|
|||||||
SCRIPT_32GB: {
|
SCRIPT_32GB: {
|
||||||
...achievementData["SCRIPT_32GB"],
|
...achievementData["SCRIPT_32GB"],
|
||||||
Icon: "bigcost",
|
Icon: "bigcost",
|
||||||
Condition: () => Player.getHomeComputer().scripts.some((s) => s.ramUsage >= 32),
|
Condition: () => Player.getHomeComputer().scripts.some((s) => (s.ramUsage as number) >= 32),
|
||||||
},
|
},
|
||||||
FIRST_HACKNET_NODE: {
|
FIRST_HACKNET_NODE: {
|
||||||
...achievementData["FIRST_HACKNET_NODE"],
|
...achievementData["FIRST_HACKNET_NODE"],
|
||||||
|
@ -33,6 +33,7 @@ import { BaseServer } from "../Server/BaseServer";
|
|||||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||||
import { checkEnum } from "../utils/helpers/enum";
|
import { checkEnum } from "../utils/helpers/enum";
|
||||||
import { RamCostConstants } from "./RamCostGenerator";
|
import { RamCostConstants } from "./RamCostGenerator";
|
||||||
|
import { PositiveInteger } from "../types";
|
||||||
|
|
||||||
export const helpers = {
|
export const helpers = {
|
||||||
string,
|
string,
|
||||||
@ -158,12 +159,12 @@ function number(ctx: NetscriptContext, argName: string, v: unknown): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Convert provided value v for argument argName to a positive integer, throwing if it looks like something else. */
|
/** Convert provided value v for argument argName to a positive integer, throwing if it looks like something else. */
|
||||||
function positiveInteger(ctx: NetscriptContext, argName: string, v: unknown): number {
|
function positiveInteger(ctx: NetscriptContext, argName: string, v: unknown): PositiveInteger {
|
||||||
const n = number(ctx, argName, v);
|
const n = number(ctx, argName, v);
|
||||||
if (n < 1 || !Number.isInteger(n)) {
|
if (n < 1 || !Number.isInteger(n)) {
|
||||||
throw makeRuntimeErrorMsg(ctx, `${argName} should be a positive integer, was ${n}`, "TYPE");
|
throw makeRuntimeErrorMsg(ctx, `${argName} should be a positive integer, was ${n}`, "TYPE");
|
||||||
}
|
}
|
||||||
return n;
|
return n as PositiveInteger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns args back if it is a ScriptArg[]. Throws an error if it is not. */
|
/** Returns args back if it is a ScriptArg[]. Throws an error if it is not. */
|
||||||
@ -348,11 +349,6 @@ function updateDynamicRam(ctx: NetscriptContext, ramCost: number): void {
|
|||||||
if (ws.dynamicLoadedFns[fnName]) return;
|
if (ws.dynamicLoadedFns[fnName]) return;
|
||||||
ws.dynamicLoadedFns[fnName] = true;
|
ws.dynamicLoadedFns[fnName] = true;
|
||||||
|
|
||||||
let threads = ws.scriptRef.threads;
|
|
||||||
if (typeof threads !== "number") {
|
|
||||||
console.warn(`WorkerScript detected NaN for thread count for ${ws.name} on ${ws.hostname}`);
|
|
||||||
threads = 1;
|
|
||||||
}
|
|
||||||
ws.dynamicRamUsage = Math.min(ws.dynamicRamUsage + ramCost, RamCostConstants.Max);
|
ws.dynamicRamUsage = Math.min(ws.dynamicRamUsage + ramCost, RamCostConstants.Max);
|
||||||
if (ws.dynamicRamUsage > 1.01 * ws.ramUsage) {
|
if (ws.dynamicRamUsage > 1.01 * ws.ramUsage) {
|
||||||
log(ctx, () => "Insufficient static ram available.");
|
log(ctx, () => "Insufficient static ram available.");
|
||||||
@ -362,7 +358,7 @@ function updateDynamicRam(ctx: NetscriptContext, ramCost: number): void {
|
|||||||
`Dynamic RAM usage calculated to be greater than initial RAM usage.
|
`Dynamic RAM usage calculated to be greater than initial RAM usage.
|
||||||
This is probably because you somehow circumvented the static RAM calculation.
|
This is probably because you somehow circumvented the static RAM calculation.
|
||||||
|
|
||||||
Threads: ${threads}
|
Threads: ${ws.scriptRef.threads}
|
||||||
Dynamic RAM Usage: ${formatRam(ws.dynamicRamUsage)} per thread
|
Dynamic RAM Usage: ${formatRam(ws.dynamicRamUsage)} per thread
|
||||||
Static RAM Usage: ${formatRam(ws.ramUsage)} per thread
|
Static RAM Usage: ${formatRam(ws.ramUsage)} per thread
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ export class WorkerScript {
|
|||||||
pid: number;
|
pid: number;
|
||||||
|
|
||||||
/** Script's Static RAM usage. Equivalent to underlying script's RAM usage */
|
/** Script's Static RAM usage. Equivalent to underlying script's RAM usage */
|
||||||
ramUsage = 0;
|
ramUsage = RamCostConstants.Base;
|
||||||
|
|
||||||
/** Reference to underlying RunningScript object */
|
/** Reference to underlying RunningScript object */
|
||||||
scriptRef: RunningScript;
|
scriptRef: RunningScript;
|
||||||
|
@ -36,7 +36,7 @@ import {
|
|||||||
} from "./Server/ServerPurchases";
|
} from "./Server/ServerPurchases";
|
||||||
import { Server } from "./Server/Server";
|
import { Server } from "./Server/Server";
|
||||||
import { influenceStockThroughServerGrow } from "./StockMarket/PlayerInfluencing";
|
import { influenceStockThroughServerGrow } from "./StockMarket/PlayerInfluencing";
|
||||||
import { isValidFilePath, removeLeadingSlash } from "./Terminal/DirectoryHelpers";
|
import { areFilesEqual, isValidFilePath, removeLeadingSlash } from "./Terminal/DirectoryHelpers";
|
||||||
import { TextFile, getTextFile, createTextFile } from "./TextFile";
|
import { TextFile, getTextFile, createTextFile } from "./TextFile";
|
||||||
import { runScriptFromScript } from "./NetscriptWorker";
|
import { runScriptFromScript } from "./NetscriptWorker";
|
||||||
import { killWorkerScript } from "./Netscript/killWorkerScript";
|
import { killWorkerScript } from "./Netscript/killWorkerScript";
|
||||||
@ -890,7 +890,8 @@ export const ns: InternalAPI<NSFull> = {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
destScript.code = sourceScript.code;
|
destScript.code = sourceScript.code;
|
||||||
destScript.ramUsage = sourceScript.ramUsage;
|
// Set ramUsage to null in order to force a recalculation prior to next run.
|
||||||
|
destScript.ramUsage = null;
|
||||||
destScript.markUpdated();
|
destScript.markUpdated();
|
||||||
helpers.log(ctx, () => `WARNING: File '${file}' overwritten on '${destServer?.hostname}'`);
|
helpers.log(ctx, () => `WARNING: File '${file}' overwritten on '${destServer?.hostname}'`);
|
||||||
continue;
|
continue;
|
||||||
@ -899,11 +900,11 @@ export const ns: InternalAPI<NSFull> = {
|
|||||||
// Create new script if it does not already exist
|
// Create new script if it does not already exist
|
||||||
const newScript = new Script(file);
|
const newScript = new Script(file);
|
||||||
newScript.code = sourceScript.code;
|
newScript.code = sourceScript.code;
|
||||||
newScript.ramUsage = sourceScript.ramUsage;
|
// Set ramUsage to null in order to force a recalculation prior to next run.
|
||||||
|
newScript.ramUsage = null;
|
||||||
newScript.server = destServer.hostname;
|
newScript.server = destServer.hostname;
|
||||||
destServer.scripts.push(newScript);
|
destServer.scripts.push(newScript);
|
||||||
helpers.log(ctx, () => `File '${file}' copied over to '${destServer?.hostname}'.`);
|
helpers.log(ctx, () => `File '${file}' copied over to '${destServer?.hostname}'.`);
|
||||||
newScript.updateRamUsage(destServer.scripts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return noFailures;
|
return noFailures;
|
||||||
@ -1430,12 +1431,14 @@ export const ns: InternalAPI<NSFull> = {
|
|||||||
let script = ctx.workerScript.getScriptOnServer(fn, server);
|
let script = ctx.workerScript.getScriptOnServer(fn, server);
|
||||||
if (script == null) {
|
if (script == null) {
|
||||||
// Create a new script
|
// Create a new script
|
||||||
script = new Script(fn, String(data), server.hostname, server.scripts);
|
script = new Script(fn, String(data), server.hostname);
|
||||||
server.scripts.push(script);
|
server.scripts.push(script);
|
||||||
return script.updateRamUsage(server.scripts);
|
return;
|
||||||
}
|
}
|
||||||
mode === "w" ? (script.code = String(data)) : (script.code += data);
|
mode === "w" ? (script.code = String(data)) : (script.code += data);
|
||||||
return script.updateRamUsage(server.scripts);
|
// Set ram to null so a recalc is performed the next time ram usage is needed
|
||||||
|
script.ramUsage = null;
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Write to text file
|
// Write to text file
|
||||||
if (!fn.endsWith(".txt")) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid filename: ${fn}`);
|
if (!fn.endsWith(".txt")) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid filename: ${fn}`);
|
||||||
@ -1566,12 +1569,14 @@ export const ns: InternalAPI<NSFull> = {
|
|||||||
const scriptname = helpers.string(ctx, "scriptname", _scriptname);
|
const scriptname = helpers.string(ctx, "scriptname", _scriptname);
|
||||||
const hostname = helpers.string(ctx, "hostname", _hostname);
|
const hostname = helpers.string(ctx, "hostname", _hostname);
|
||||||
const server = helpers.getServer(ctx, hostname);
|
const server = helpers.getServer(ctx, hostname);
|
||||||
for (let i = 0; i < server.scripts.length; ++i) {
|
const script = server.scripts.find((serverScript) => areFilesEqual(serverScript.filename, scriptname));
|
||||||
if (server.scripts[i].filename == scriptname) {
|
if (!script) return 0;
|
||||||
return server.scripts[i].ramUsage;
|
const ramUsage = script.getRamUsage(server.scripts);
|
||||||
}
|
if (!ramUsage) {
|
||||||
}
|
helpers.log(ctx, () => `Could not calculate ram usage for ${scriptname} on ${hostname}.`);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
return ramUsage;
|
||||||
},
|
},
|
||||||
getRunningScript:
|
getRunningScript:
|
||||||
(ctx) =>
|
(ctx) =>
|
||||||
|
@ -6,6 +6,7 @@ import { Apr1Events as devMenu } from "../ui/Apr1";
|
|||||||
import { InternalAPI } from "../Netscript/APIWrapper";
|
import { InternalAPI } from "../Netscript/APIWrapper";
|
||||||
import { helpers } from "../Netscript/NetscriptHelpers";
|
import { helpers } from "../Netscript/NetscriptHelpers";
|
||||||
import { Terminal } from "../Terminal";
|
import { Terminal } from "../Terminal";
|
||||||
|
import { RamCostConstants } from "../Netscript/RamCostGenerator";
|
||||||
|
|
||||||
export type INetscriptExtra = {
|
export type INetscriptExtra = {
|
||||||
heart: {
|
heart: {
|
||||||
@ -36,7 +37,7 @@ export function NetscriptExtra(): InternalAPI<INetscriptExtra> {
|
|||||||
real_document.completely_unused_field = undefined;
|
real_document.completely_unused_field = undefined;
|
||||||
// set one to true and check that it affected the other.
|
// set one to true and check that it affected the other.
|
||||||
real_document.completely_unused_field = true;
|
real_document.completely_unused_field = true;
|
||||||
if (d.completely_unused_field && ctx.workerScript.ramUsage === 1.6) {
|
if (d.completely_unused_field && ctx.workerScript.ramUsage === RamCostConstants.Base) {
|
||||||
Player.giveExploit(Exploit.Bypass);
|
Player.giveExploit(Exploit.Bypass);
|
||||||
}
|
}
|
||||||
d.completely_unused_field = undefined;
|
d.completely_unused_field = undefined;
|
||||||
|
@ -49,6 +49,7 @@ import { canGetBonus, onExport } from "../ExportBonus";
|
|||||||
import { saveObject } from "../SaveObject";
|
import { saveObject } from "../SaveObject";
|
||||||
import { calculateCrimeWorkStats } from "../Work/Formulas";
|
import { calculateCrimeWorkStats } from "../Work/Formulas";
|
||||||
import { findEnumMember } from "../utils/helpers/enum";
|
import { findEnumMember } from "../utils/helpers/enum";
|
||||||
|
import { areFilesEqual } from "../Terminal/DirectoryHelpers";
|
||||||
|
|
||||||
export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
||||||
const getAugmentation = function (ctx: NetscriptContext, name: string): Augmentation {
|
const getAugmentation = function (ctx: NetscriptContext, name: string): Augmentation {
|
||||||
@ -77,18 +78,17 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
|||||||
//Run a script after reset
|
//Run a script after reset
|
||||||
if (!cbScript) return;
|
if (!cbScript) return;
|
||||||
const home = Player.getHomeComputer();
|
const home = Player.getHomeComputer();
|
||||||
for (const script of home.scripts) {
|
const script = home.scripts.find((serverScript) => areFilesEqual(serverScript.filename, cbScript));
|
||||||
if (script.filename === cbScript) {
|
if (!script) return;
|
||||||
const ramUsage = script.ramUsage;
|
const ramUsage = script.getRamUsage(home.scripts);
|
||||||
|
if (!ramUsage) {
|
||||||
|
return Terminal.error(`Attempted to launch ${cbScript} after reset but could not calculate ram usage.`);
|
||||||
|
}
|
||||||
const ramAvailable = home.maxRam - home.ramUsed;
|
const ramAvailable = home.maxRam - home.ramUsed;
|
||||||
if (ramUsage > ramAvailable + 0.001) {
|
if (ramUsage > ramAvailable + 0.001) return;
|
||||||
return; // Not enough RAM
|
// Start script with no args and 1 thread (default).
|
||||||
}
|
const runningScriptObj = new RunningScript(script, ramUsage, []);
|
||||||
const runningScriptObj = new RunningScript(script, []); // No args
|
|
||||||
runningScriptObj.threads = 1; // Only 1 thread
|
|
||||||
startWorkerScript(runningScriptObj, home);
|
startWorkerScript(runningScriptObj, home);
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const singularityAPI: InternalAPI<ISingularity> = {
|
const singularityAPI: InternalAPI<ISingularity> = {
|
||||||
|
@ -28,7 +28,6 @@ export async function compile(script: Script, scripts: Script[]): Promise<Script
|
|||||||
//If multiple compiles were called on the same script before a compilation could be completed this ensures only one compilation is actually performed.
|
//If multiple compiles were called on the same script before a compilation could be completed this ensures only one compilation is actually performed.
|
||||||
if (!script.queueCompile) return script.module as Promise<ScriptModule>;
|
if (!script.queueCompile) return script.module as Promise<ScriptModule>;
|
||||||
script.queueCompile = false;
|
script.queueCompile = false;
|
||||||
script.updateRamUsage(scripts);
|
|
||||||
const uurls = _getScriptUrls(script, scripts, []);
|
const uurls = _getScriptUrls(script, scripts, []);
|
||||||
const url = uurls[uurls.length - 1].url;
|
const url = uurls[uurls.length - 1].url;
|
||||||
if (script.url && script.url !== url) URL.revokeObjectURL(script.url);
|
if (script.url && script.url !== url) URL.revokeObjectURL(script.url);
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { Settings } from "./Settings/Settings";
|
import { Settings } from "./Settings/Settings";
|
||||||
import { NetscriptPort } from "@nsdefs";
|
import { NetscriptPort } from "@nsdefs";
|
||||||
import { NetscriptPorts } from "./NetscriptWorker";
|
import { NetscriptPorts } from "./NetscriptWorker";
|
||||||
|
import { PositiveInteger } from "./types";
|
||||||
|
|
||||||
type PortData = string | number;
|
type PortData = string | number;
|
||||||
type Resolver = () => void;
|
type Resolver = () => void;
|
||||||
const emptyPortData = "NULL PORT DATA";
|
const emptyPortData = "NULL PORT DATA";
|
||||||
/** The object property is for typechecking and is not present at runtime */
|
/** The object property is for typechecking and is not present at runtime */
|
||||||
export type PortNumber = number & { __PortNumber: true };
|
export type PortNumber = PositiveInteger & { __PortNumber: true };
|
||||||
|
|
||||||
/** Gets the numbered port, initializing it if it doesn't already exist.
|
/** Gets the numbered port, initializing it if it doesn't already exist.
|
||||||
* Only using for functions that write data/resolvers. Use NetscriptPorts.get(n) for */
|
* Only using for functions that write data/resolvers. Use NetscriptPorts.get(n) for */
|
||||||
|
@ -15,7 +15,6 @@ import { NetscriptFunctions } from "./NetscriptFunctions";
|
|||||||
import { compile, Node } from "./NetscriptJSEvaluator";
|
import { compile, Node } from "./NetscriptJSEvaluator";
|
||||||
import { Port, PortNumber } from "./NetscriptPort";
|
import { Port, PortNumber } from "./NetscriptPort";
|
||||||
import { RunningScript } from "./Script/RunningScript";
|
import { RunningScript } from "./Script/RunningScript";
|
||||||
import { getRamUsageFromRunningScript } from "./Script/RunningScriptHelpers";
|
|
||||||
import { scriptCalculateOfflineProduction } from "./Script/ScriptHelpers";
|
import { scriptCalculateOfflineProduction } from "./Script/ScriptHelpers";
|
||||||
import { Script } from "./Script/Script";
|
import { Script } from "./Script/Script";
|
||||||
import { GetAllServers } from "./Server/AllServers";
|
import { GetAllServers } from "./Server/AllServers";
|
||||||
@ -32,8 +31,9 @@ import { parse } from "acorn";
|
|||||||
import { simple as walksimple } from "acorn-walk";
|
import { simple as walksimple } from "acorn-walk";
|
||||||
import { areFilesEqual } from "./Terminal/DirectoryHelpers";
|
import { areFilesEqual } from "./Terminal/DirectoryHelpers";
|
||||||
import { Terminal } from "./Terminal";
|
import { Terminal } from "./Terminal";
|
||||||
import { ScriptArg } from "./Netscript/ScriptArg";
|
import { ScriptArg } from "@nsdefs";
|
||||||
import { handleUnknownError } from "./Netscript/NetscriptHelpers";
|
import { handleUnknownError } from "./Netscript/NetscriptHelpers";
|
||||||
|
import { PositiveInteger } from "./types";
|
||||||
|
|
||||||
export const NetscriptPorts: Map<PortNumber, Port> = new Map();
|
export const NetscriptPorts: Map<PortNumber, Port> = new Map();
|
||||||
|
|
||||||
@ -53,6 +53,7 @@ async function startNetscript2Script(workerScript: WorkerScript): Promise<void>
|
|||||||
const scripts = workerScript.getServer().scripts;
|
const scripts = workerScript.getServer().scripts;
|
||||||
const script = workerScript.getScript();
|
const script = workerScript.getScript();
|
||||||
if (script === null) throw "workerScript had no associated script. This is a bug.";
|
if (script === null) throw "workerScript had no associated script. This is a bug.";
|
||||||
|
if (!script.ramUsage) throw "Attempting to start a script with no calculated ram cost. This is a bug.";
|
||||||
const loadedModule = await compile(script, scripts);
|
const loadedModule = await compile(script, scripts);
|
||||||
workerScript.ramUsage = script.ramUsage;
|
workerScript.ramUsage = script.ramUsage;
|
||||||
const ns = workerScript.env.vars;
|
const ns = workerScript.env.vars;
|
||||||
@ -294,15 +295,7 @@ export function startWorkerScript(runningScript: RunningScript, server: BaseServ
|
|||||||
* returns {boolean} indicating whether or not the workerScript was successfully added
|
* returns {boolean} indicating whether or not the workerScript was successfully added
|
||||||
*/
|
*/
|
||||||
function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseServer, parent?: WorkerScript): boolean {
|
function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseServer, parent?: WorkerScript): boolean {
|
||||||
// Update server's ram usage
|
const ramUsage = roundToTwo(runningScriptObj.ramUsage * runningScriptObj.threads);
|
||||||
let threads = 1;
|
|
||||||
if (runningScriptObj.threads && !isNaN(runningScriptObj.threads)) {
|
|
||||||
threads = runningScriptObj.threads;
|
|
||||||
} else {
|
|
||||||
runningScriptObj.threads = 1;
|
|
||||||
}
|
|
||||||
const oneRamUsage = getRamUsageFromRunningScript(runningScriptObj);
|
|
||||||
const ramUsage = roundToTwo(oneRamUsage * threads);
|
|
||||||
const ramAvailable = server.maxRam - server.ramUsed;
|
const ramAvailable = server.maxRam - server.ramUsed;
|
||||||
if (ramUsage > ramAvailable + 0.001) {
|
if (ramUsage > ramAvailable + 0.001) {
|
||||||
dialogBoxCreate(
|
dialogBoxCreate(
|
||||||
@ -327,7 +320,7 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS
|
|||||||
// Create the WorkerScript. NOTE: WorkerScript ctor will set the underlying
|
// Create the WorkerScript. NOTE: WorkerScript ctor will set the underlying
|
||||||
// RunningScript's PID as well
|
// RunningScript's PID as well
|
||||||
const workerScript = new WorkerScript(runningScriptObj, pid, NetscriptFunctions);
|
const workerScript = new WorkerScript(runningScriptObj, pid, NetscriptFunctions);
|
||||||
workerScript.ramUsage = oneRamUsage;
|
workerScript.ramUsage = runningScriptObj.ramUsage;
|
||||||
|
|
||||||
// Add the WorkerScript to the global pool
|
// Add the WorkerScript to the global pool
|
||||||
workerScripts.set(pid, workerScript);
|
workerScripts.set(pid, workerScript);
|
||||||
@ -405,82 +398,61 @@ export function loadAllRunningScripts(): void {
|
|||||||
/** Run a script from inside another script (run(), exec(), spawn(), etc.) */
|
/** Run a script from inside another script (run(), exec(), spawn(), etc.) */
|
||||||
export function runScriptFromScript(
|
export function runScriptFromScript(
|
||||||
caller: string,
|
caller: string,
|
||||||
server: BaseServer,
|
host: BaseServer,
|
||||||
scriptname: string,
|
scriptname: string,
|
||||||
args: ScriptArg[],
|
args: ScriptArg[],
|
||||||
workerScript: WorkerScript,
|
workerScript: WorkerScript,
|
||||||
threads = 1,
|
threads = 1 as PositiveInteger,
|
||||||
): number {
|
): number {
|
||||||
// Sanitize arguments
|
/* Very inefficient, TODO change data structures so that finding script & checking if it's already running does
|
||||||
if (!(workerScript instanceof WorkerScript)) {
|
* not require iterating through all scripts and comparing names/args. This is a big part of slowdown when
|
||||||
|
* running a large number of scripts. */
|
||||||
|
|
||||||
|
// Find the script, fail if it doesn't exist.
|
||||||
|
const script = host.scripts.find((serverScript) => areFilesEqual(serverScript.filename, scriptname));
|
||||||
|
if (!script) {
|
||||||
|
workerScript.log(caller, () => `Could not find script '${scriptname}' on '${host.hostname}'`);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof scriptname !== "string" || !Array.isArray(args)) {
|
// Check if script is already running on server and fail if it is.
|
||||||
workerScript.log(caller, () => `Invalid arguments: scriptname='${scriptname} args='${args}'`);
|
if (host.getRunningScript(scriptname, args)) {
|
||||||
console.error(`runScriptFromScript() failed due to invalid arguments`);
|
workerScript.log(caller, () => `'${scriptname}' is already running on '${host.hostname}'`);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
args.forEach((arg, i) => {
|
const singleRamUsage = script.getRamUsage(host.scripts);
|
||||||
if (typeof arg !== "string" && typeof arg !== "number" && typeof arg !== "boolean")
|
if (!singleRamUsage) {
|
||||||
throw new Error(
|
workerScript.log(caller, () => `Ram usage could not be calculated for ${scriptname}`);
|
||||||
"Only strings, numbers, and booleans can be passed as arguments to other scripts.\n" +
|
|
||||||
`${scriptname} argument index ${i} is of type ${typeof arg} and value ${JSON.stringify(arg)}`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if the script is already running
|
|
||||||
const runningScriptObj = server.getRunningScript(scriptname, args);
|
|
||||||
if (runningScriptObj != null) {
|
|
||||||
workerScript.log(caller, () => `'${scriptname}' is already running on '${server.hostname}'`);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'null/undefined' arguments are not allowed
|
// Check if admin rights on host, fail if not.
|
||||||
for (let i = 0; i < args.length; ++i) {
|
if (host.hasAdminRights == false) {
|
||||||
if (args[i] == null) {
|
workerScript.log(caller, () => `You do not have root access on '${host.hostname}'`);
|
||||||
workerScript.log(caller, () => "Cannot execute a script with null/undefined as an argument");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the script exists and if it does run it
|
// Calculate ram usage including thread count
|
||||||
for (let i = 0; i < server.scripts.length; ++i) {
|
const ramUsage = singleRamUsage * threads;
|
||||||
if (!areFilesEqual(server.scripts[i].filename, scriptname)) continue;
|
|
||||||
// Check for admin rights and that there is enough RAM available to run
|
|
||||||
const script = server.scripts[i];
|
|
||||||
let ramUsage = script.ramUsage;
|
|
||||||
threads = Math.floor(Number(threads));
|
|
||||||
if (threads === 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ramUsage = ramUsage * threads;
|
|
||||||
const ramAvailable = server.maxRam - server.ramUsed;
|
|
||||||
|
|
||||||
if (server.hasAdminRights == false) {
|
// Check if there is enough ram to run the script, fail if not.
|
||||||
workerScript.log(caller, () => `You do not have root access on '${server.hostname}'`);
|
const ramAvailable = host.maxRam - host.ramUsed;
|
||||||
return 0;
|
if (ramUsage > ramAvailable + 0.001) {
|
||||||
} else if (ramUsage > ramAvailable + 0.001) {
|
|
||||||
workerScript.log(
|
workerScript.log(
|
||||||
caller,
|
caller,
|
||||||
() =>
|
() =>
|
||||||
`Cannot run script '${scriptname}' (t=${threads}) on '${server.hostname}' because there is not enough available RAM!`,
|
`Cannot run script '${scriptname}' (t=${threads}) on '${host.hostname}' because there is not enough available RAM!`,
|
||||||
);
|
);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Able to run script
|
// Able to run script
|
||||||
workerScript.log(
|
workerScript.log(
|
||||||
caller,
|
caller,
|
||||||
() => `'${scriptname}' on '${server.hostname}' with ${threads} threads and args: ${arrayToString(args)}.`,
|
() => `'${scriptname}' on '${host.hostname}' with ${threads} threads and args: ${arrayToString(args)}.`,
|
||||||
);
|
);
|
||||||
const runningScriptObj = new RunningScript(script, args);
|
const runningScriptObj = new RunningScript(script, singleRamUsage, args);
|
||||||
runningScriptObj.threads = threads;
|
runningScriptObj.threads = threads;
|
||||||
runningScriptObj.server = server.hostname;
|
|
||||||
|
|
||||||
return startWorkerScript(runningScriptObj, server, workerScript);
|
return startWorkerScript(runningScriptObj, host, workerScript);
|
||||||
}
|
|
||||||
|
|
||||||
workerScript.log(caller, () => `Could not find script '${scriptname}' on '${server.hostname}'`);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
@ -124,8 +124,8 @@ export const RFARequestHandler: Record<string, (message: RFAMessage) => void | R
|
|||||||
if (!isScriptFilename(fileData.filename)) return error("Filename isn't a script filename", msg);
|
if (!isScriptFilename(fileData.filename)) return error("Filename isn't a script filename", msg);
|
||||||
const script = server.getScript(fileData.filename);
|
const script = server.getScript(fileData.filename);
|
||||||
if (!script) return error("File doesn't exist", msg);
|
if (!script) return error("File doesn't exist", msg);
|
||||||
const ramUsage = script.ramUsage;
|
const ramUsage = script.getRamUsage(server.scripts);
|
||||||
|
if (!ramUsage) return error("Ram cost could not be calculated", msg);
|
||||||
return new RFAMessage({ result: ramUsage, id: msg.id });
|
return new RFAMessage({ result: ramUsage, id: msg.id });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -10,7 +10,9 @@ import { Terminal } from "../Terminal";
|
|||||||
|
|
||||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
||||||
import { formatTime } from "../utils/helpers/formatTime";
|
import { formatTime } from "../utils/helpers/formatTime";
|
||||||
import { ScriptArg } from "../Netscript/ScriptArg";
|
import { ScriptArg } from "@nsdefs";
|
||||||
|
import { RamCostConstants } from "../Netscript/RamCostGenerator";
|
||||||
|
import { PositiveInteger } from "../types";
|
||||||
|
|
||||||
export class RunningScript {
|
export class RunningScript {
|
||||||
// Script arguments
|
// Script arguments
|
||||||
@ -52,25 +54,24 @@ export class RunningScript {
|
|||||||
pid = -1;
|
pid = -1;
|
||||||
|
|
||||||
// How much RAM this script uses for ONE thread
|
// How much RAM this script uses for ONE thread
|
||||||
ramUsage = 0;
|
ramUsage = RamCostConstants.Base;
|
||||||
|
|
||||||
// hostname of the server on which this script is running
|
// hostname of the server on which this script is running
|
||||||
server = "";
|
server = "";
|
||||||
|
|
||||||
// Number of threads that this script is running with
|
// Number of threads that this script is running with
|
||||||
threads = 1;
|
threads = 1 as PositiveInteger;
|
||||||
|
|
||||||
// Script urls for the current running script for translating urls back to file names in errors
|
// Script urls for the current running script for translating urls back to file names in errors
|
||||||
dependencies: ScriptUrl[] = [];
|
dependencies: ScriptUrl[] = [];
|
||||||
|
|
||||||
constructor(script: Script | null = null, args: ScriptArg[] = []) {
|
constructor(script?: Script, ramUsage?: number, args: ScriptArg[] = []) {
|
||||||
if (script == null) {
|
if (!script) return;
|
||||||
return;
|
if (!ramUsage) throw new Error("Must provide a ramUsage for RunningScript initialization.");
|
||||||
}
|
|
||||||
this.filename = script.filename;
|
this.filename = script.filename;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
this.server = script.server;
|
this.server = script.server;
|
||||||
this.ramUsage = script.ramUsage;
|
this.ramUsage = ramUsage;
|
||||||
this.dependencies = script.dependencies;
|
this.dependencies = script.dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
import { GetServer } from "../Server/AllServers";
|
|
||||||
import { RunningScript } from "./RunningScript";
|
|
||||||
|
|
||||||
export function getRamUsageFromRunningScript(script: RunningScript): number {
|
|
||||||
if (script.ramUsage != null && script.ramUsage > 0) {
|
|
||||||
return script.ramUsage; // Use cached value
|
|
||||||
}
|
|
||||||
|
|
||||||
const server = GetServer(script.server);
|
|
||||||
if (server == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < server.scripts.length; ++i) {
|
|
||||||
if (server.scripts[i].filename === script.filename) {
|
|
||||||
// Cache the ram usage for the next call
|
|
||||||
script.ramUsage = server.scripts[i].ramUsage;
|
|
||||||
return script.ramUsage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -10,6 +10,7 @@ import { ScriptUrl } from "./ScriptUrl";
|
|||||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
|
||||||
import { roundToTwo } from "../utils/helpers/roundToTwo";
|
import { roundToTwo } from "../utils/helpers/roundToTwo";
|
||||||
import { ScriptModule } from "./ScriptModule";
|
import { ScriptModule } from "./ScriptModule";
|
||||||
|
import { RamCostConstants } from "../Netscript/RamCostGenerator";
|
||||||
|
|
||||||
let globalModuleSequenceNumber = 0;
|
let globalModuleSequenceNumber = 0;
|
||||||
|
|
||||||
@ -41,8 +42,8 @@ export class Script {
|
|||||||
dependencies: ScriptUrl[] = [];
|
dependencies: ScriptUrl[] = [];
|
||||||
dependents: ScriptReference[] = [];
|
dependents: ScriptReference[] = [];
|
||||||
|
|
||||||
// Amount of RAM this Script requires to run
|
// Amount of RAM this Script requires to run. null indicates an error in calculating ram.
|
||||||
ramUsage = 0;
|
ramUsage: number | null = null;
|
||||||
ramUsageEntries?: RamUsageEntry[];
|
ramUsageEntries?: RamUsageEntry[];
|
||||||
|
|
||||||
// Used to deconflict multiple simultaneous compilations.
|
// Used to deconflict multiple simultaneous compilations.
|
||||||
@ -51,14 +52,11 @@ export class Script {
|
|||||||
// hostname of server that this script is on.
|
// hostname of server that this script is on.
|
||||||
server = "";
|
server = "";
|
||||||
|
|
||||||
constructor(fn = "", code = "", server = "", otherScripts: Script[] = []) {
|
constructor(fn = "", code = "", server = "") {
|
||||||
this.filename = fn;
|
this.filename = fn;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.server = server; // hostname of server this script is on
|
this.server = server; // hostname of server this script is on
|
||||||
this.moduleSequenceNumber = ++globalModuleSequenceNumber;
|
this.moduleSequenceNumber = ++globalModuleSequenceNumber;
|
||||||
if (this.code !== "") {
|
|
||||||
this.updateRamUsage(otherScripts);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Download the script as a file */
|
/** Download the script as a file */
|
||||||
@ -97,14 +95,24 @@ export class Script {
|
|||||||
|
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
this.server = hostname;
|
this.server = hostname;
|
||||||
this.updateRamUsage(otherScripts);
|
// Null ramUsage forces a recalc next time ramUsage is needed
|
||||||
|
this.ramUsage = null;
|
||||||
this.markUpdated();
|
this.markUpdated();
|
||||||
for (const dependent of this.dependents) {
|
this.dependents.forEach((dependent) => {
|
||||||
const [dependentScript] = otherScripts.filter(
|
const scriptToUpdate = otherScripts.find(
|
||||||
(s) => s.filename === dependent.filename && s.server == dependent.server,
|
(otherScript) => otherScript.filename === dependent.filename && otherScript.server === dependent.server,
|
||||||
);
|
);
|
||||||
dependentScript?.markUpdated();
|
if (!scriptToUpdate) return;
|
||||||
|
scriptToUpdate.ramUsage = null;
|
||||||
|
scriptToUpdate.markUpdated();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the ram usage, while also attempting to update it if it's currently null */
|
||||||
|
getRamUsage(otherScripts: Script[]): number | null {
|
||||||
|
if (this.ramUsage) return this.ramUsage;
|
||||||
|
this.updateRamUsage(otherScripts);
|
||||||
|
return this.ramUsage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,11 +120,11 @@ export class Script {
|
|||||||
* @param {Script[]} otherScripts - Other scripts on the server. Used to process imports
|
* @param {Script[]} otherScripts - Other scripts on the server. Used to process imports
|
||||||
*/
|
*/
|
||||||
updateRamUsage(otherScripts: Script[]): void {
|
updateRamUsage(otherScripts: Script[]): void {
|
||||||
const res = calculateRamUsage(this.code, otherScripts);
|
const ramCalc = calculateRamUsage(this.code, otherScripts);
|
||||||
if (res.cost > 0) {
|
if (ramCalc.cost >= RamCostConstants.Base) {
|
||||||
this.ramUsage = roundToTwo(res.cost);
|
this.ramUsage = roundToTwo(ramCalc.cost);
|
||||||
this.ramUsageEntries = res.entries;
|
this.ramUsageEntries = ramCalc.entries;
|
||||||
}
|
} else this.ramUsage = null;
|
||||||
this.markUpdated();
|
this.markUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +272,8 @@ export abstract class BaseServer {
|
|||||||
if (fn === this.scripts[i].filename) {
|
if (fn === this.scripts[i].filename) {
|
||||||
const script = this.scripts[i];
|
const script = this.scripts[i];
|
||||||
script.code = code;
|
script.code = code;
|
||||||
script.updateRamUsage(this.scripts);
|
// Set ramUsage to null in order to force recalculation on next run
|
||||||
|
script.ramUsage = null;
|
||||||
script.markUpdated();
|
script.markUpdated();
|
||||||
ret.overwritten = true;
|
ret.overwritten = true;
|
||||||
ret.success = true;
|
ret.success = true;
|
||||||
@ -281,7 +282,7 @@ export abstract class BaseServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, create a new script
|
// Otherwise, create a new script
|
||||||
const newScript = new Script(fn, code, this.hostname, this.scripts);
|
const newScript = new Script(fn, code, this.hostname);
|
||||||
this.scripts.push(newScript);
|
this.scripts.push(newScript);
|
||||||
ret.success = true;
|
ret.success = true;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -254,9 +254,9 @@ export function prestigeHomeComputer(homeComp: Server): void {
|
|||||||
homeComp.programs.push(Programs.BitFlume.name);
|
homeComp.programs.push(Programs.BitFlume.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update RAM usage on all scripts
|
//Reset RAM usage calculation for all scripts
|
||||||
homeComp.scripts.forEach(function (script) {
|
homeComp.scripts.forEach(function (script) {
|
||||||
script.updateRamUsage(homeComp.scripts);
|
script.ramUsage = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
homeComp.messages.length = 0; //Remove .lit and .msg files
|
homeComp.messages.length = 0; //Remove .lit and .msg files
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { Terminal } from "../../Terminal";
|
import { Terminal } from "../../Terminal";
|
||||||
import { formatRam } from "../../ui/formatNumber";
|
import { formatRam } from "../../ui/formatNumber";
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
|
import { BaseServer } from "../../Server/BaseServer";
|
||||||
|
|
||||||
export function mem(args: (string | number | boolean)[]): void {
|
export function mem(args: (string | number | boolean)[], server: BaseServer): void {
|
||||||
try {
|
try {
|
||||||
if (args.length !== 1 && args.length !== 3) {
|
if (args.length !== 1 && args.length !== 3) {
|
||||||
Terminal.error("Incorrect usage of mem command. usage: mem [scriptname] [-t] [number threads]");
|
Terminal.error("Incorrect usage of mem command. usage: mem [scriptname] [-t] [number threads]");
|
||||||
@ -25,7 +26,10 @@ export function mem(args: (string | number | boolean)[]): void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ramUsage = script.ramUsage * numThreads;
|
const singleRamUsage = script.getRamUsage(server.scripts);
|
||||||
|
if (!singleRamUsage) return Terminal.error(`Could not calculate ram usage for ${scriptName}`);
|
||||||
|
|
||||||
|
const ramUsage = singleRamUsage * numThreads;
|
||||||
|
|
||||||
Terminal.print(`This script requires ${formatRam(ramUsage)} of RAM to run for ${numThreads} thread(s)`);
|
Terminal.print(`This script requires ${formatRam(ramUsage)} of RAM to run for ${numThreads} thread(s)`);
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ import { RunningScript } from "../../Script/RunningScript";
|
|||||||
import { findRunningScript } from "../../Script/ScriptHelpers";
|
import { findRunningScript } from "../../Script/ScriptHelpers";
|
||||||
import * as libarg from "arg";
|
import * as libarg from "arg";
|
||||||
import { formatRam } from "../../ui/formatNumber";
|
import { formatRam } from "../../ui/formatNumber";
|
||||||
|
import { ScriptArg } from "@nsdefs";
|
||||||
|
import { isPositiveInteger } from "../../types";
|
||||||
|
|
||||||
export function runScript(commandArgs: (string | number | boolean)[], server: BaseServer): void {
|
export function runScript(commandArgs: (string | number | boolean)[], server: BaseServer): void {
|
||||||
if (commandArgs.length < 1) {
|
if (commandArgs.length < 1) {
|
||||||
@ -24,11 +26,12 @@ export function runScript(commandArgs: (string | number | boolean)[], server: Ba
|
|||||||
});
|
});
|
||||||
const tailFlag = flags["--tail"] === true;
|
const tailFlag = flags["--tail"] === true;
|
||||||
const numThreads = parseFloat(flags["-t"] ?? 1);
|
const numThreads = parseFloat(flags["-t"] ?? 1);
|
||||||
if (numThreads < 1 || !Number.isInteger(numThreads)) {
|
if (!isPositiveInteger(numThreads)) {
|
||||||
Terminal.error("Invalid number of threads specified. Number of threads must be an integer greater than 0");
|
return Terminal.error("Invalid number of threads specified. Number of threads must be an integer greater than 0");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const args = flags["_"];
|
|
||||||
|
// Todo: Switch out arg for something with typescript support
|
||||||
|
const args = flags["_"] as ScriptArg[];
|
||||||
|
|
||||||
// Check if this script is already running
|
// Check if this script is already running
|
||||||
if (findRunningScript(scriptName, args, server) != null) {
|
if (findRunningScript(scriptName, args, server) != null) {
|
||||||
@ -46,7 +49,9 @@ export function runScript(commandArgs: (string | number | boolean)[], server: Ba
|
|||||||
// Check for admin rights and that there is enough RAM available to run
|
// Check for admin rights and that there is enough RAM available to run
|
||||||
const script = server.scripts[i];
|
const script = server.scripts[i];
|
||||||
script.server = server.hostname;
|
script.server = server.hostname;
|
||||||
const ramUsage = script.ramUsage * numThreads;
|
const singleRamUsage = script.getRamUsage(server.scripts);
|
||||||
|
if (!singleRamUsage) return Terminal.error("Error while calculating ram usage for this script.");
|
||||||
|
const ramUsage = singleRamUsage * numThreads;
|
||||||
const ramAvailable = server.maxRam - server.ramUsed;
|
const ramAvailable = server.maxRam - server.ramUsed;
|
||||||
|
|
||||||
if (!server.hasAdminRights) {
|
if (!server.hasAdminRights) {
|
||||||
@ -64,7 +69,7 @@ export function runScript(commandArgs: (string | number | boolean)[], server: Ba
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Able to run script
|
// Able to run script
|
||||||
const runningScript = new RunningScript(script, args);
|
const runningScript = new RunningScript(script, singleRamUsage, args);
|
||||||
runningScript.threads = numThreads;
|
runningScript.threads = numThreads;
|
||||||
|
|
||||||
const success = startWorkerScript(runningScript, server);
|
const success = startWorkerScript(runningScript, server);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Terminal } from "../../Terminal";
|
import { Terminal } from "../../Terminal";
|
||||||
import { BaseServer } from "../../Server/BaseServer";
|
import { BaseServer } from "../../Server/BaseServer";
|
||||||
import { getRamUsageFromRunningScript } from "../../Script/RunningScriptHelpers";
|
|
||||||
import { formatRam } from "../../ui/formatNumber";
|
import { formatRam } from "../../ui/formatNumber";
|
||||||
|
|
||||||
export function top(args: (string | number | boolean)[], server: BaseServer): void {
|
export function top(args: (string | number | boolean)[], server: BaseServer): void {
|
||||||
@ -45,7 +44,7 @@ export function top(args: (string | number | boolean)[], server: BaseServer): vo
|
|||||||
const spacesThread = " ".repeat(numSpacesThread);
|
const spacesThread = " ".repeat(numSpacesThread);
|
||||||
|
|
||||||
// Calculate and transform RAM usage
|
// Calculate and transform RAM usage
|
||||||
const ramUsage = formatRam(getRamUsageFromRunningScript(script) * script.threads);
|
const ramUsage = formatRam(script.ramUsage * script.threads);
|
||||||
|
|
||||||
const entry = [script.filename, spacesScript, script.pid, spacesPid, script.threads, spacesThread, ramUsage].join(
|
const entry = [script.filename, spacesScript, script.pid, spacesPid, script.threads, spacesThread, ramUsage].join(
|
||||||
"",
|
"",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Person } from "src/PersonObjects/Person";
|
import { Person } from "../PersonObjects/Person";
|
||||||
import { Player } from "@player";
|
import { Player } from "@player";
|
||||||
import { Multipliers } from "../PersonObjects/Multipliers";
|
import { Multipliers } from "../PersonObjects/Multipliers";
|
||||||
|
|
||||||
|
@ -1,3 +1,12 @@
|
|||||||
|
// The object properties on these numeric types are for typechecking only and do not exist at runtime. They're just a way to require a typechecking function.
|
||||||
|
export type Integer = number & { __Integer: true };
|
||||||
|
export type PositiveNumber = number & { __Positive: true };
|
||||||
|
export type PositiveInteger = Integer & PositiveNumber;
|
||||||
|
|
||||||
|
// Numeric typechecking functions
|
||||||
|
export const isInteger = (n: unknown): n is Integer => Number.isInteger(n);
|
||||||
|
export const isPositiveInteger = (n: unknown): n is PositiveInteger => isInteger(n) && n > 0;
|
||||||
|
|
||||||
/** Status object for functions that return a boolean indicating success/failure
|
/** Status object for functions that return a boolean indicating success/failure
|
||||||
* and an optional message */
|
* and an optional message */
|
||||||
export interface IReturnStatus {
|
export interface IReturnStatus {
|
||||||
|
@ -20,6 +20,8 @@ import { Settings } from "../../Settings/Settings";
|
|||||||
import { ANSIITypography } from "./ANSIITypography";
|
import { ANSIITypography } from "./ANSIITypography";
|
||||||
import { ScriptArg } from "../../Netscript/ScriptArg";
|
import { ScriptArg } from "../../Netscript/ScriptArg";
|
||||||
import { useRerender } from "./hooks";
|
import { useRerender } from "./hooks";
|
||||||
|
import { areFilesEqual } from "../../Terminal/DirectoryHelpers";
|
||||||
|
import { dialogBoxCreate } from "./DialogBox";
|
||||||
|
|
||||||
let layerCounter = 0;
|
let layerCounter = 0;
|
||||||
|
|
||||||
@ -220,7 +222,17 @@ function LogWindow(props: IProps): React.ReactElement {
|
|||||||
if (server === null) return;
|
if (server === null) return;
|
||||||
const s = findRunningScript(script.filename, script.args, server);
|
const s = findRunningScript(script.filename, script.args, server);
|
||||||
if (s === null) {
|
if (s === null) {
|
||||||
script.ramUsage = 0;
|
const baseScript = server.scripts.find((serverScript) => areFilesEqual(serverScript.filename, script.filename));
|
||||||
|
if (!baseScript) {
|
||||||
|
return dialogBoxCreate(
|
||||||
|
`Could not launch script. The script ${script.filename} no longer exists on the server ${server.hostname}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const ramUsage = baseScript.getRamUsage(server.scripts);
|
||||||
|
if (!ramUsage) {
|
||||||
|
return dialogBoxCreate(`Could not calculate ram usage for ${script.filename} on ${server.hostname}.`);
|
||||||
|
}
|
||||||
|
script.ramUsage = ramUsage;
|
||||||
startWorkerScript(script, server);
|
startWorkerScript(script, server);
|
||||||
} else {
|
} else {
|
||||||
setScript(s);
|
setScript(s);
|
||||||
|
@ -2,7 +2,7 @@ import * as React from "react";
|
|||||||
import LinearProgress from "@mui/material/LinearProgress";
|
import LinearProgress from "@mui/material/LinearProgress";
|
||||||
import { TableCell, Tooltip, Typography } from "@mui/material";
|
import { TableCell, Tooltip, Typography } from "@mui/material";
|
||||||
import { characterOverviewStyles } from "./CharacterOverview";
|
import { characterOverviewStyles } from "./CharacterOverview";
|
||||||
import { ISkillProgress } from "src/PersonObjects/formulas/skill";
|
import { ISkillProgress } from "../../PersonObjects/formulas/skill";
|
||||||
import { formatExp } from "../formatNumber";
|
import { formatExp } from "../formatNumber";
|
||||||
|
|
||||||
interface IProgressProps {
|
interface IProgressProps {
|
||||||
|
@ -36,8 +36,11 @@ describe("Netscript RAM Calculation/Generation Tests", function () {
|
|||||||
/** Creates a RunningScript object which calculates static ram usage */
|
/** Creates a RunningScript object which calculates static ram usage */
|
||||||
function createRunningScript(code: string) {
|
function createRunningScript(code: string) {
|
||||||
script.code = code;
|
script.code = code;
|
||||||
script.updateRamUsage([]);
|
// Force ram calculation reset
|
||||||
const runningScript = new RunningScript(script);
|
script.ramUsage = null;
|
||||||
|
const ramUsage = script.getRamUsage([]);
|
||||||
|
if (!ramUsage) throw new Error("Ram usage should be defined.");
|
||||||
|
const runningScript = new RunningScript(script, ramUsage);
|
||||||
return runningScript;
|
return runningScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ test.each([
|
|||||||
const alerted = new Promise((resolve) => {
|
const alerted = new Promise((resolve) => {
|
||||||
alertDelete = AlertEvents.subscribe((x) => resolve(x));
|
alertDelete = AlertEvents.subscribe((x) => resolve(x));
|
||||||
});
|
});
|
||||||
server = new Server({ hostname: "home", hasAdminRights: true, maxRam: 8 });
|
server = new Server({ hostname: "home", adminRights: true, maxRam: 8 });
|
||||||
AddToAllServers(server);
|
AddToAllServers(server);
|
||||||
for (const s of scripts) {
|
for (const s of scripts) {
|
||||||
expect(server.writeToScriptFile(s.name, s.code)).toEqual({ success: true, overwritten: false });
|
expect(server.writeToScriptFile(s.name, s.code)).toEqual({ success: true, overwritten: false });
|
||||||
@ -61,8 +61,8 @@ test.each([
|
|||||||
const script = server.scripts[server.scripts.length - 1];
|
const script = server.scripts[server.scripts.length - 1];
|
||||||
expect(script.filename).toEqual(scripts[scripts.length - 1].name);
|
expect(script.filename).toEqual(scripts[scripts.length - 1].name);
|
||||||
|
|
||||||
const runningScript = new RunningScript(script);
|
const ramUsage = script.getRamUsage(server.scripts);
|
||||||
runningScript.threads = 1;
|
const runningScript = new RunningScript(script, ramUsage as number);
|
||||||
expect(startWorkerScript(runningScript, server)).toBeGreaterThan(0);
|
expect(startWorkerScript(runningScript, server)).toBeGreaterThan(0);
|
||||||
// We don't care about start, so subscribe after that. Await script death.
|
// We don't care about start, so subscribe after that. Await script death.
|
||||||
const result = await Promise.race([
|
const result = await Promise.race([
|
||||||
|
Loading…
Reference in New Issue
Block a user