From 042f92670062558d4a2835c37fff07a14d84b47c Mon Sep 17 00:00:00 2001 From: danielyxie Date: Sat, 13 Jul 2019 20:55:58 -0700 Subject: [PATCH] Minor bugfixes with killing Netscript scripts, and cleaned up text --- doc/source/netscript/basicfunctions/clear.rst | 2 +- .../netscript/basicfunctions/getGrowTime.rst | 3 + .../netscript/basicfunctions/getHackTime.rst | 3 + .../basicfunctions/getWeakenTime.rst | 3 + .../basicfunctions/growthAnalyze.rst | 2 +- doc/source/netscript/netscriptmisc.rst | 14 +--- doc/source/netscript/netscriptsleeveapi.rst | 16 ++-- src/Augmentation/AugmentationHelpers.jsx | 21 +++-- src/Constants.ts | 6 +- src/Hacknet/data/HashUpgradesMetadata.ts | 7 +- src/Netscript/killWorkerScript.ts | 2 +- src/NetscriptFunctions.js | 48 ++++++----- src/NetscriptWorker.js | 80 ++++++++++++------- src/Server/ServerHelpers.ts | 17 ++-- src/Terminal.js | 16 ++-- src/utils/helpers/isValidNumber.ts | 7 ++ 16 files changed, 147 insertions(+), 100 deletions(-) create mode 100644 src/utils/helpers/isValidNumber.ts diff --git a/doc/source/netscript/basicfunctions/clear.rst b/doc/source/netscript/basicfunctions/clear.rst index 13f5393eb..90cfee85c 100644 --- a/doc/source/netscript/basicfunctions/clear.rst +++ b/doc/source/netscript/basicfunctions/clear.rst @@ -6,7 +6,7 @@ clear() Netscript Function :param string/number port/fn: Port or text file to clear :RAM cost: 1 GB - This function is used to clear data in a `Netscript Ports `_ or a text file. + This function is used to clear data in a :ref:`Netscript Port ` or a text file. If the *port/fn* argument is a number between 1 and 20, then it specifies a port and will clear it (deleting all data from the underlying queue). diff --git a/doc/source/netscript/basicfunctions/getGrowTime.rst b/doc/source/netscript/basicfunctions/getGrowTime.rst index adaf4f842..0c105c61b 100644 --- a/doc/source/netscript/basicfunctions/getGrowTime.rst +++ b/doc/source/netscript/basicfunctions/getGrowTime.rst @@ -11,3 +11,6 @@ getGrowTime() Netscript Function The function takes in an optional *hackLvl* parameter that can be specified to see what the grow time would be at different hacking levels. + + .. note:: For Hacknet Servers (the upgraded version of a Hacknet Node), this function will + return :code:`Infinity`. diff --git a/doc/source/netscript/basicfunctions/getHackTime.rst b/doc/source/netscript/basicfunctions/getHackTime.rst index 1372111e3..768c26373 100644 --- a/doc/source/netscript/basicfunctions/getHackTime.rst +++ b/doc/source/netscript/basicfunctions/getHackTime.rst @@ -11,3 +11,6 @@ getHackTime() Netscript Function The function takes in an optional *hackLvl* parameter that can be specified to see what the hack time would be at different hacking levels. + + .. note:: For Hacknet Servers (the upgraded version of a Hacknet Node), this function will + return :code:`Infinity`. diff --git a/doc/source/netscript/basicfunctions/getWeakenTime.rst b/doc/source/netscript/basicfunctions/getWeakenTime.rst index e13e7408e..056aaea27 100644 --- a/doc/source/netscript/basicfunctions/getWeakenTime.rst +++ b/doc/source/netscript/basicfunctions/getWeakenTime.rst @@ -11,3 +11,6 @@ getWeakenTime() Netscript Function The function takes in an optional *hackLvl* parameter that can be specified to see what the weaken time would be at different hacking levels. + + .. note:: For Hacknet Servers (the upgraded version of a Hacknet Node), this function will + return :code:`Infinity`. diff --git a/doc/source/netscript/basicfunctions/growthAnalyze.rst b/doc/source/netscript/basicfunctions/growthAnalyze.rst index 4414dbcfa..76120ae15 100644 --- a/doc/source/netscript/basicfunctions/growthAnalyze.rst +++ b/doc/source/netscript/basicfunctions/growthAnalyze.rst @@ -4,7 +4,7 @@ growthAnalyze() Netscript Function .. js:function:: growthAnalyze(hostname/ip, growthAmount) :param string hostname/ip: IP or hostname of server to analyze - :param number growthAmount: Multiplicative factor by which the server is grown. Decimal form. + :param number growthAmount: Multiplicative factor by which the server is grown. Decimal form. Must be >= 1. :returns: The amount of grow() calls needed to grow the specified server by the specified amount :RAM cost: 1 GB diff --git a/doc/source/netscript/netscriptmisc.rst b/doc/source/netscript/netscriptmisc.rst index 877d28c33..5d1cd9629 100644 --- a/doc/source/netscript/netscriptmisc.rst +++ b/doc/source/netscript/netscriptmisc.rst @@ -57,6 +57,10 @@ And the data in port 1 will look like:: [3, 4, 5, 6, 7, 8, 9] +.. warning:: In :ref:`netscriptjs`, do not trying writing base + `Promises `_ + to a port. + **Port Handles** WARNING: Port Handles only work in :ref:`netscriptjs`. They do not work in :ref:`netscript1` @@ -213,16 +217,6 @@ to specify a namespace for the import:: keyword should **NOT** be used in :ref:`netscript1`, as this will break the script. It can, however, be used in :ref:`netscriptjs` (but it's not required). -Importing in NetscriptJS -^^^^^^^^^^^^^^^^^^^^^^^^ -There is a minor annoyance when using the `import` feature in :ref:`netscriptjs`. -If you make a change in a NetscriptJS script, then you have to manually "refresh" all other -scripts that import from that script. - -The easiest way to do this is to simply save and then refresh the game. Alternatively, -you can open up all the scripts that need to be "refreshed" in the script editor -and then simply re-save them. - Standard, Built-In JavaScript Objects ------------------------------------- Standard built-in JavaScript objects such as diff --git a/doc/source/netscript/netscriptsleeveapi.rst b/doc/source/netscript/netscriptsleeveapi.rst index 03855f362..6ddcff634 100644 --- a/doc/source/netscript/netscriptsleeveapi.rst +++ b/doc/source/netscript/netscriptsleeveapi.rst @@ -63,17 +63,17 @@ Examples **Basic example usage**:: for (var i = 0; i < sleeve.getNumSleeves(); i++) { - sleeve.shockRecovery(i); + sleeve.setToShockRecovery(i); + } + + sleep(10 * 60 * 60); // wait 10h + + for (var i = 0; i < sleeve.getNumSleeves(); i++) { + sleeve.setToSynchronize(i); } sleep(10*60*60); // wait 10h for (var i = 0; i < sleeve.getNumSleeves(); i++) { - sleeve.synchronize(i); - } - - sleep(10*60*60); // wait 10h - - for (var i = 0; i < sleeve.getNumSleeves(); i++) { - sleeve.commitCrime(i, 'shoplift'); + sleeve.setToCommitCrime(i, 'shoplift'); } diff --git a/src/Augmentation/AugmentationHelpers.jsx b/src/Augmentation/AugmentationHelpers.jsx index fa4d57f6f..cb8060da4 100644 --- a/src/Augmentation/AugmentationHelpers.jsx +++ b/src/Augmentation/AugmentationHelpers.jsx @@ -8,7 +8,7 @@ import { AugmentationsRoot } from "./ui/Root"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { CONSTANTS } from "../Constants"; import { Factions, factionExists } from "../Faction/Factions"; -import { addWorkerScript } from "../NetscriptWorker"; +import { startWorkerScript } from "../NetscriptWorker"; import { Player } from "../Player"; import { prestigeAugmentation } from "../Prestige"; import { saveObject } from "../SaveObject"; @@ -2078,18 +2078,17 @@ function installAugmentations(cbScript=null) { //Run a script after prestiging if (cbScript && isString(cbScript)) { var home = Player.getHomeComputer(); - for (var i = 0; i < home.scripts.length; ++i) { - if (home.scripts[i].filename === cbScript) { - var script = home.scripts[i]; - var ramUsage = script.ramUsage; - var ramAvailable = home.maxRam - home.ramUsed; + for (const script of home.scripts) { + if (script.filename === cbScript) { + const ramUsage = script.ramUsage; + const ramAvailable = home.maxRam - home.ramUsed; if (ramUsage > ramAvailable) { - return; //Not enough RAM + return; // Not enough RAM } - var runningScriptObj = new RunningScript(script, []); //No args - runningScriptObj.threads = 1; //Only 1 thread - home.runScript(runningScriptObj, Player.hacknet_node_money_mult); - addWorkerScript(runningScriptObj, home); + const runningScriptObj = new RunningScript(script, []); // No args + runningScriptObj.threads = 1; // Only 1 thread + + startWorkerScript(runningScriptObj, home); } } } diff --git a/src/Constants.ts b/src/Constants.ts index ede50f91a..c6730a8b7 100644 --- a/src/Constants.ts +++ b/src/Constants.ts @@ -227,7 +227,6 @@ export let CONSTANTS: IMap = { Netscript Changes * Added tail() Netscript function * hacknet.getNodeStats() function now returns an additional property for Hacknet Servers: hashCapacity - * Bug fix: workForFaction() function now properly accounts for disabled logs * When writing to a file, the write() function now casts the data being written to a string (using String()) * BitNode-selection page now shows what Source-File level you have for each BitNode * Overloaded kill() function so that you can kill a script by its PID @@ -235,6 +234,9 @@ export let CONSTANTS: IMap = { * run() and exec() now return the PID of the newly-executed scripts, rather than a boolean ** (A PID is just a positive integer) * run(), exec(), and spawn() no longer need to be await-ed in NetscriptJS + * Bug fix: workForFaction() function now properly accounts for disabled logs + * Bug fix: RAM should now be properly calculated when running a callback script with installAugmentations() + * Bug fix: Fixed bug that caused scripts killed by exit()/spawn() to "clean up" twice Misc Changes * The 'kill' Terminal command can now kill a script by its PID @@ -242,5 +244,7 @@ export let CONSTANTS: IMap = { * After Infiltration, you will now return to the company page rather than the city page * Bug fix: Stock Market UI should no longer crash for certain locale settings * Bug fix: You can now properly remove unfinished programs (the *.exe-N%-INC files) + * Bug fix: Fixed an issue that allowed you to increase money on servers with a 'maxMoney' of 0 (like CSEC) + * Bug fix: Scripts no longer persist if they were started with syntax/import errors ` } diff --git a/src/Hacknet/data/HashUpgradesMetadata.ts b/src/Hacknet/data/HashUpgradesMetadata.ts index 0eb0b6ed8..eb3c0d5d5 100644 --- a/src/Hacknet/data/HashUpgradesMetadata.ts +++ b/src/Hacknet/data/HashUpgradesMetadata.ts @@ -18,14 +18,17 @@ export const HashUpgradesMetadata: IConstructorParams[] = [ { costPerLevel: 50, desc: "Use hashes to decrease the minimum security of a single server by 2%. " + - "Note that a server's minimum security cannot go below 1.", + "Note that a server's minimum security cannot go below 1. This effect persists " + + "until you install Augmentations (since servers are reset at that time).", hasTargetServer: true, name: "Reduce Minimum Security", value: 0.98, }, { costPerLevel: 50, - desc: "Use hashes to increase the maximum amount of money on a single server by 2%", + desc: "Use hashes to increase the maximum amount of money on a single server by 2%. " + + "This effect persists until you install Augmentations (since servers " + + "are reset at that time).", hasTargetServer: true, name: "Increase Maximum Money", value: 1.02, diff --git a/src/Netscript/killWorkerScript.ts b/src/Netscript/killWorkerScript.ts index 072bf5921..dc33af1f6 100644 --- a/src/Netscript/killWorkerScript.ts +++ b/src/Netscript/killWorkerScript.ts @@ -89,7 +89,7 @@ function removeWorkerScript(workerScript: WorkerScript, rerenderUi: boolean=true // Recalculate ram used on that server server.ramUsed = roundToTwo(server.ramUsed - workerScript.ramUsage); if (server.ramUsed < 0) { - console.warn(`Server RAM usage went negative (if it's due to floating pt imprecision, it's okay): ${server.ramUsed}`); + console.warn(`Server (${server.hostname}) RAM usage went negative (if it's due to floating pt imprecision, it's okay): ${server.ramUsed}`); server.ramUsed = 0; } diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js index b6f55f64c..8641a2f8a 100644 --- a/src/NetscriptFunctions.js +++ b/src/NetscriptFunctions.js @@ -611,8 +611,8 @@ function NetscriptFunctions(workerScript) { if (time === undefined) { throw makeRuntimeRejectMsg(workerScript, "sleep() call has incorrect number of arguments. Takes 1 argument"); } - if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.sleep == null) { - workerScript.scriptRef.log("Sleeping for " + time + " milliseconds"); + if (workerScript.shouldLog("sleep")) { + workerScript.log(`Sleeping for ${time} milliseconds`); } return netscriptDelay(time, workerScript).then(function() { return Promise.resolve(true); @@ -652,10 +652,10 @@ function NetscriptFunctions(workerScript) { if (growthPercentage == 1) { expGain = 0; } - if (workerScript.disableLogs.ALL == null && workerScript.disableLogs.grow == null) { - workerScript.scriptRef.log("Available money on " + server.hostname + " grown by " + - formatNumber((moneyAfter/moneyBefore)*100 - 100, 6) + "%. Gained " + - formatNumber(expGain, 4) + " hacking exp (t=" + threads +")"); + if (workerScript.shouldLog("grow")) { + workerScript.log("Available money on " + server.hostname + " grown by " + + formatNumber((moneyAfter/moneyBefore)*100 - 100, 6) + "%. Gained " + + formatNumber(expGain, 4) + " hacking exp (t=" + threads +")"); } workerScript.scriptRef.onlineExpGained += expGain; Player.gainHackingExp(expGain); @@ -670,8 +670,8 @@ function NetscriptFunctions(workerScript) { // Check argument validity const server = safeGetServer(ip, 'growthAnalyze'); - if (isNaN(growth)) { - throw makeRuntimeRejectMsg(workerScript, `Invalid growth argument passed into growthAnalyze: ${growth}. Must be numeric`); + if (typeof growth !== "number" || isNaN(growth) || growth < 1) { + throw makeRuntimeRejectMsg(workerScript, `Invalid growth argument passed into growthAnalyze: ${growth}. Must be numeric and >= 1`); } return numCycleForGrowth(server, Number(growth), Player); @@ -993,10 +993,15 @@ function NetscriptFunctions(workerScript) { return runScriptFromScript(scriptServer, scriptname, argsForNewScript, workerScript, threads); }, spawnDelay * 1e3); + if (workerScript.shouldLog("spawn")) { - workerScript.scriptRef.log(`spawn() will execute ${scriptname} in ${spawnDelay} seconds`); + workerScript.log(`spawn() will execute ${scriptname} in ${spawnDelay} seconds`); + } + + workerScript.running = false; // Prevent workerScript from "finishing execution naturally" + if (killWorkerScript(workerScript)) { + workerScript.log("Exiting..."); } - NetscriptFunctions(workerScript).exit(); }, kill: function(filename, ip, ...scriptArgs) { updateDynamicRam("kill", getRamCost("kill")); @@ -1015,7 +1020,7 @@ function NetscriptFunctions(workerScript) { const server = safeGetServer(ip); const runningScriptObj = getRunningScript(filename, ip, "kill", scriptArgs); if (runningScriptObj == null) { - workerScript.log(`tail() failed. ${getCannotFindRunningScriptErrorMessage(filename, ip, scriptArgs)}`) + workerScript.log(`kill() failed. ${getCannotFindRunningScriptErrorMessage(filename, ip, scriptArgs)}`) return false; } @@ -1064,14 +1069,11 @@ function NetscriptFunctions(workerScript) { return scriptsRunning; }, exit : function() { - var server = getServer(workerScript.serverIp); - if (server == null) { - throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in exit(). This is a bug please contact game dev"); - } - if (killWorkerScript(workerScript.scriptRef, server.ip)) { - workerScript.scriptRef.log("Exiting..."); + workerScript.running = false; // Prevent workerScript from "finishing execution naturally" + if (killWorkerScript(workerScript)) { + workerScript.log("Exiting..."); } else { - workerScript.scriptRef.log("Exit failed(). This is a bug please contact game developer"); + workerScript.log("Exit failed(). This is a bug please contact game developer"); } }, scp: function(scriptname, ip1, ip2) { @@ -3495,9 +3497,13 @@ function NetscriptFunctions(workerScript) { return false; } Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain); - workerScript.scriptRef.log("Installing Augmentations. This will cause this script to be killed"); - installAugmentations(cbScript); - return true; + workerScript.log("Installing Augmentations. This will cause this script to be killed"); + setTimeoutRef(() => { + installAugmentations(cbScript); + }, 0); + + workerScript.running = false; // Prevent workerScript from "finishing execution naturally" + killWorkerScript(workerScript); }, // Gang API diff --git a/src/NetscriptWorker.js b/src/NetscriptWorker.js index f188d7188..65390a3eb 100644 --- a/src/NetscriptWorker.js +++ b/src/NetscriptWorker.js @@ -48,6 +48,8 @@ for (var i = 0; i < CONSTANTS.NumNetscriptPorts; ++i) { export function prestigeWorkerScripts() { for (const ws of workerScripts.values()) { ws.env.stopFlag = true; + killWorkerScript(ws); + console.log(`Killing ${ws.name}`); } WorkerScriptStartStopEventEmitter.emitEvent(); @@ -149,6 +151,7 @@ function startNetscript1Script(workerScript) { dialogBoxCreate("Error processing Imports in " + workerScript.name + ":
" + e); workerScript.env.stopFlag = true; workerScript.running = false; + killWorkerScript(workerScript); return; } @@ -160,7 +163,7 @@ function startNetscript1Script(workerScript) { if (typeof entry === "function") { //Async functions need to be wrapped. See JS-Interpreter documentation if (name === "hack" || name === "grow" || name === "weaken" || name === "sleep" || - name === "prompt" || name === "run" || name === "exec") { + name === "prompt") { let tempWrapper = function() { let fnArgs = []; @@ -183,7 +186,8 @@ function startNetscript1Script(workerScript) { } int.setProperty(scope, name, int.createAsyncFunction(tempWrapper)); } else if (name === "sprintf" || name === "vsprintf" || name === "scp" || - name == "write" || name === "read" || name === "tryWrite") { + name == "write" || name === "read" || name === "tryWrite" || + name === "run" || name === "exec") { let tempWrapper = function() { let fnArgs = []; @@ -232,6 +236,7 @@ function startNetscript1Script(workerScript) { dialogBoxCreate("Syntax ERROR in " + workerScript.name + ":
" + e); workerScript.env.stopFlag = true; workerScript.running = false; + killWorkerScript(workerScript); return; } @@ -445,14 +450,35 @@ function generateNextPid() { } /** - * Start a script - * - * Given a RunningScript object, constructs a corresponding WorkerScript, + * Used to start a RunningScript (by creating and starting its + * corresponding WorkerScript), and add the RunningScript to the server on which + * it is active + * @param {RunningScript} runningScriptObj - Script that's being run + * @param {Server} server - Server on which the script is to be run + * @returns {number} pid of started script + */ +export function startWorkerScript(runningScript, server) { + if (createAndAddWorkerScript(runningScript, server)) { + // Push onto runningScripts. + // This has to come after createAndAddWorkerScript() because that fn updates RAM usage + server.runScript(runningScript, Player.hacknet_node_money_mult); + + // Once the WorkerScript is constructed in createAndAddWorkerScript(), the RunningScript + // object should have a PID assigned to it, so we return that + return runningScript.pid; + } + + return 0; +} + +/** + * Given a RunningScript object, constructs its corresponding WorkerScript, * adds it to the global 'workerScripts' pool, and begins executing it. * @param {RunningScript} runningScriptObj - Script that's being run * @param {Server} server - Server on which the script is to be run + * returns {boolean} indicating whether or not the workerScript was successfully added */ -export function addWorkerScript(runningScriptObj, server) { +export function createAndAddWorkerScript(runningScriptObj, server) { const filename = runningScriptObj.filename; // Update server's ram usage @@ -471,7 +497,7 @@ export function addWorkerScript(runningScriptObj, server) { `the game and the script's RAM usage increased (either because of an update to the game or ` + `your changes to the script.)` ); - return; + return false; } server.ramUsed = roundToTwo(server.ramUsed + ramUsage); @@ -489,31 +515,35 @@ export function addWorkerScript(runningScriptObj, server) { const s = new WorkerScript(runningScriptObj, pid, NetscriptFunctions); s.ramUsage = ramUsage; + // Add the WorkerScript to the global pool + workerScripts.set(pid, s); + WorkerScriptStartStopEventEmitter.emitEvent(); + // Start the script's execution let p = null; // Script's resulting promise if (s.name.endsWith(".js") || s.name.endsWith(".ns")) { p = startNetscript2Script(s); } else { p = startNetscript1Script(s); - if (!(p instanceof Promise)) { return; } + if (!(p instanceof Promise)) { return false; } } // Once the code finishes (either resolved or rejected, doesnt matter), set its // running status to false p.then(function(w) { + // If the WorkerScript is no longer "running", then this means its execution was + // already stopped somewhere else (maybe by something like exit()). This prevents + // the script from being cleaned up twice + if (!w.running) { return; } + console.log("Stopping script " + w.name + " because it finished running naturally"); killWorkerScript(s); - w.scriptRef.log("Script finished running"); + w.log("Script finished running"); }).catch(function(w) { if (w instanceof Error) { dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer"); console.error("Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN: " + w.toString()); return; - } else if (w.constructor === Array && w.length === 2 && w[0] === "RETURNSTATEMENT") { - // Script ends with a return statement - console.log("Script returning with value: " + w[1]); - // TODO maybe do something with this in the future - return; } else if (w instanceof WorkerScript) { if (isScriptErrorMessage(w.errorMessage)) { var errorTextArray = w.errorMessage.split("|"); @@ -529,9 +559,9 @@ export function addWorkerScript(runningScriptObj, server) { dialogBoxCreate("Script runtime error:
Server Ip: " + serverIp + "
Script name: " + scriptName + "
Args:" + arrayToString(w.args) + "
" + errorMsg); - w.scriptRef.log("Script crashed with runtime error"); + w.log("Script crashed with runtime error"); } else { - w.scriptRef.log("Script killed"); + w.log("Script killed"); return; // Already killed, so stop here } w.running = false; @@ -548,10 +578,7 @@ export function addWorkerScript(runningScriptObj, server) { killWorkerScript(s); }); - // Add the WorkerScript to the global pool - workerScripts.set(pid, s); - WorkerScriptStartStopEventEmitter.emitEvent(); - return; + return true; } /** @@ -589,7 +616,7 @@ export function loadAllRunningScripts() { server.runningScripts.length = 0; } else { for (let j = 0; j < server.runningScripts.length; ++j) { - addWorkerScript(server.runningScripts[j], server); + createAndAddWorkerScript(server.runningScripts[j], server); // Offline production total += scriptCalculateOfflineProduction(server.runningScripts[j]); @@ -655,19 +682,12 @@ export function runScriptFromScript(server, scriptname, args, workerScript, thre } let runningScriptObj = new RunningScript(script, args); runningScriptObj.threads = threads; - addWorkerScript(runningScriptObj, server); - // Push onto runningScripts. - // This has to come after addWorkerScript() because that fn updates RAM usage - server.runScript(runningScriptObj, Player.hacknet_node_money_mult); - - // Once the WorkerScript is constructed in addWorkerScript(), the RunningScript - // object should have a PID assigned to it, so we return that - return runningScriptObj.pid; + return startWorkerScript(runningScriptObj, server); } } } - + workerScript.log(`Could not find script ${scriptname} on ${server.hostname}`); return 0; } diff --git a/src/Server/ServerHelpers.ts b/src/Server/ServerHelpers.ts index c4a2c15de..6be47e424 100644 --- a/src/Server/ServerHelpers.ts +++ b/src/Server/ServerHelpers.ts @@ -11,6 +11,7 @@ import { HacknetServer } from "../Hacknet/HacknetServer"; import { IPlayer } from "../PersonObjects/IPlayer"; import { Programs } from "../Programs/Programs"; +import { isValidNumber } from "../utils/helpers/isValidNumber"; import { isValidIPAddress } from "../../utils/helpers/isValidIPAddress"; /** @@ -35,11 +36,17 @@ export function safetlyCreateUniqueServer(params: IConstructorParams): Server { return new Server(params); } -// Returns the number of cycles needed to grow the specified server by the -// specified amount. 'growth' parameter is in decimal form, not percentage +/** + * Returns the number of "growth cycles" needed to grow the specified server by the + * specified amount. + * @param server - Server being grown + * @param growth - How much the server is being grown by, in DECIMAL form (e.g. 1.5 rather than 50) + * @param p - Reference to Player object + * @returns Number of "growth cycles" needed + */ export function numCycleForGrowth(server: Server, growth: number, p: IPlayer) { let ajdGrowthRate = 1 + (CONSTANTS.ServerBaseGrowthRate - 1) / server.hackDifficulty; - if(ajdGrowthRate > CONSTANTS.ServerMaxGrowthRate) { + if (ajdGrowthRate > CONSTANTS.ServerMaxGrowthRate) { ajdGrowthRate = CONSTANTS.ServerMaxGrowthRate; } @@ -75,12 +82,12 @@ export function processSingleServerGrowth(server: Server, numCycles: number, p: server.moneyAvailable *= serverGrowth; // in case of data corruption - if (server.moneyMax && isNaN(server.moneyAvailable)) { + if (isValidNumber(server.moneyMax) && isNaN(server.moneyAvailable)) { server.moneyAvailable = server.moneyMax; } // cap at max - if (server.moneyMax && server.moneyAvailable > server.moneyMax) { + if (isValidNumber(server.moneyMax) && server.moneyAvailable > server.moneyMax) { server.moneyAvailable = server.moneyMax; } diff --git a/src/Terminal.js b/src/Terminal.js index 0bca33d4c..7157562de 100644 --- a/src/Terminal.js +++ b/src/Terminal.js @@ -53,7 +53,7 @@ import { import { showLiterature } from "./Literature"; import { Message } from "./Message/Message"; import { showMessage } from "./Message/MessageHelpers"; -import { addWorkerScript } from "./NetscriptWorker"; +import { startWorkerScript } from "./NetscriptWorker"; import { killWorkerScript } from "./Netscript/killWorkerScript"; import { WorkerScriptStartStopEventEmitter } from "./Netscript/WorkerScriptStartStopEventEmitter"; import { Player } from "./Player"; @@ -2303,21 +2303,19 @@ let Terminal = { return; } else { // Able to run script - post("Running script with " + numThreads + " thread(s) and args: " + arrayToString(args) + "."); var runningScriptObj = new RunningScript(script, args); runningScriptObj.threads = numThreads; - addWorkerScript(runningScriptObj, server); - - // This has to come after addWorkerScript() because that fn - // updates the RAM usage. This kinda sucks, address if possible - server.runScript(runningScriptObj, Player.hacknet_node_money_mult); - return; + if (startWorkerScript(runningScriptObj, server)) { + post("Running script with " + numThreads + " thread(s) and args: " + arrayToString(args) + "."); + } else { + postError(`Failed to start script`); + } + return; } } } - post("ERROR: No such script"); }, diff --git a/src/utils/helpers/isValidNumber.ts b/src/utils/helpers/isValidNumber.ts new file mode 100644 index 000000000..a501a3aeb --- /dev/null +++ b/src/utils/helpers/isValidNumber.ts @@ -0,0 +1,7 @@ +/** + * Checks that a variable is a valid number. A valid number + * must be a "number" type and cannot be NaN + */ +export function isValidNumber(n: number): boolean { + return (typeof n === "number") && !isNaN(n); +}