mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-26 17:43:48 +01:00
Implemented several optimizations - running scripts dont keep track of script refs or a map of ALL servers. Not completely tested yet
This commit is contained in:
parent
dc63b14476
commit
8c8e3f2476
@ -13,7 +13,6 @@
|
|||||||
"ajv-keywords": "^2.0.0",
|
"ajv-keywords": "^2.0.0",
|
||||||
"async": "^2.6.1",
|
"async": "^2.6.1",
|
||||||
"autosize": "^4.0.2",
|
"autosize": "^4.0.2",
|
||||||
"bluebird": "^3.5.1",
|
|
||||||
"brace": "^0.11.1",
|
"brace": "^0.11.1",
|
||||||
"codemirror": "^5.43.0",
|
"codemirror": "^5.43.0",
|
||||||
"decimal.js": "7.2.3",
|
"decimal.js": "7.2.3",
|
||||||
|
@ -166,7 +166,7 @@ function addActiveScriptsItem(workerscript) {
|
|||||||
margin: "4px",
|
margin: "4px",
|
||||||
padding: "4px",
|
padding: "4px",
|
||||||
clickListener: () => {
|
clickListener: () => {
|
||||||
killWorkerScript(workerscript.scriptRef, workerscript.scriptRef.scriptRef.server);
|
killWorkerScript(workerscript.scriptRef, workerscript.scriptRef.server);
|
||||||
dialogBoxCreate("Killing script, may take a few minutes to complete...");
|
dialogBoxCreate("Killing script, may take a few minutes to complete...");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -364,6 +364,11 @@ function initBitNodeMultipliers() {
|
|||||||
var inc = Math.pow(1.02, sf12Lvl);
|
var inc = Math.pow(1.02, sf12Lvl);
|
||||||
var dec = 1/inc;
|
var dec = 1/inc;
|
||||||
BitNodeMultipliers.HackingLevelMultiplier = dec;
|
BitNodeMultipliers.HackingLevelMultiplier = dec;
|
||||||
|
BitNodeMultipliers.StrengthLevelMultiplier = dec;
|
||||||
|
BitNodeMultipliers.DefenseLevelMultiplier = dec;
|
||||||
|
BitNodeMultipliers.DexterityLevelMultiplier = dec;
|
||||||
|
BitNodeMultipliers.AgilityLevelMultiplier = dec;
|
||||||
|
BitNodeMultipliers.CharismaLevelMultiplier = dec;
|
||||||
|
|
||||||
BitNodeMultipliers.ServerMaxMoney = dec;
|
BitNodeMultipliers.ServerMaxMoney = dec;
|
||||||
BitNodeMultipliers.ServerStartingMoney = dec;
|
BitNodeMultipliers.ServerStartingMoney = dec;
|
||||||
@ -373,6 +378,10 @@ function initBitNodeMultipliers() {
|
|||||||
//Does not scale, otherwise security might start at 300+
|
//Does not scale, otherwise security might start at 300+
|
||||||
BitNodeMultipliers.ServerStartingSecurity = 1.5;
|
BitNodeMultipliers.ServerStartingSecurity = 1.5;
|
||||||
|
|
||||||
|
BitNodeMultipliers.PurchasedServerCost = inc;
|
||||||
|
BitNodeMultipliers.PurchasedServerLimit = dec;
|
||||||
|
BitNodeMultipliers.PurchasedServerMaxRam = dec;
|
||||||
|
|
||||||
BitNodeMultipliers.ManualHackMoney = dec;
|
BitNodeMultipliers.ManualHackMoney = dec;
|
||||||
BitNodeMultipliers.ScriptHackMoney = dec;
|
BitNodeMultipliers.ScriptHackMoney = dec;
|
||||||
BitNodeMultipliers.CompanyWorkMoney = dec;
|
BitNodeMultipliers.CompanyWorkMoney = dec;
|
||||||
|
@ -3434,12 +3434,12 @@ Bladeburner.prototype.startActionNetscriptFn = function(type, name, workerScript
|
|||||||
try {
|
try {
|
||||||
this.startAction(actionId);
|
this.startAction(actionId);
|
||||||
if (workerScript.shouldLog("startAction")) {
|
if (workerScript.shouldLog("startAction")) {
|
||||||
workerScript.scriptRef.log("Starting bladeburner action with type " + type + " and name " + name);
|
workerScript.log("Starting bladeburner action with type " + type + " and name " + name);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
this.resetAction();
|
this.resetAction();
|
||||||
workerScript.scriptRef.log("ERROR: bladeburner.startAction() failed to start action of type " + type + " due to invalid name: " + name +
|
workerScript.log("ERROR: bladeburner.startAction() failed to start action of type " + type + " due to invalid name: " + name +
|
||||||
"Note that this name is case-sensitive and whitespace-sensitive");
|
"Note that this name is case-sensitive and whitespace-sensitive");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -521,6 +521,7 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
* Corporation "Smart Factories" and "Smart Storage" upgrades have slightly lower price multipliers
|
* Corporation "Smart Factories" and "Smart Storage" upgrades have slightly lower price multipliers
|
||||||
* Added 6 new Coding Contract problems
|
* Added 6 new Coding Contract problems
|
||||||
* Updated documentation with list of all Coding Contract problems
|
* Updated documentation with list of all Coding Contract problems
|
||||||
|
* Implemented several optimizations for active scripts. The game should now use less memory and the savefile should be slightly smaller when there are many scripts running
|
||||||
* Bug Fix: A Stock Forecast should no longer go above 1 (i.e. 100%)
|
* Bug Fix: A Stock Forecast should no longer go above 1 (i.e. 100%)
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -13,10 +13,10 @@ function unknownBladeburnerExceptionMessage(functionName, err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkBladeburnerAccess(workerScript, functionName) {
|
function checkBladeburnerAccess(workerScript, functionName) {
|
||||||
const accessDenied = `${functionName}() failed because you do not` +
|
const accessDenied = `${functionName}() failed because you do not ` +
|
||||||
" currently have access to the Bladeburner API. This is either" +
|
"currently have access to the Bladeburner API. To access the Bladeburner API" +
|
||||||
" because you are not currently employed at the Bladeburner division" +
|
"you must be employed at the Bladeburner division, AND you must either be in " +
|
||||||
" or because you do not have Source-File 7";
|
"BitNode-7 or have Source-File 7.";
|
||||||
const hasAccess = Player.bladeburner instanceof Bladeburner && (Player.bitNodeN === 7 || Player.sourceFiles.some(a=>{return a.n === 7}));
|
const hasAccess = Player.bladeburner instanceof Bladeburner && (Player.bitNodeN === 7 || Player.sourceFiles.some(a=>{return a.n === 7}));
|
||||||
if(!hasAccess) {
|
if(!hasAccess) {
|
||||||
throw makeRuntimeRejectMsg(workerScript, accessDenied);
|
throw makeRuntimeRejectMsg(workerScript, accessDenied);
|
||||||
|
@ -13,692 +13,7 @@ import {arrayToString} from "../utils/helpers/arrayToString
|
|||||||
import {isValidIPAddress} from "../utils/helpers/isValidIPAddress";
|
import {isValidIPAddress} from "../utils/helpers/isValidIPAddress";
|
||||||
import {isString} from "../utils/helpers/isString";
|
import {isString} from "../utils/helpers/isString";
|
||||||
|
|
||||||
var Promise = require("bluebird");
|
export function evaluateImport(exp, workerScript, checkingRam=false) {
|
||||||
|
|
||||||
Promise.config({
|
|
||||||
warnings: false,
|
|
||||||
longStackTraces: false,
|
|
||||||
cancellation: true,
|
|
||||||
monitoring: false
|
|
||||||
});
|
|
||||||
/* Evaluator
|
|
||||||
* Evaluates/Interprets the Abstract Syntax Tree generated by Acorns parser
|
|
||||||
*
|
|
||||||
* Returns a promise
|
|
||||||
*/
|
|
||||||
function evaluate(exp, workerScript) {
|
|
||||||
return Promise.delay(Settings.CodeInstructionRunTime).then(function() {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
if (exp == null) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error: NULL expression", exp));
|
|
||||||
}
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
switch (exp.type) {
|
|
||||||
case "BlockStatement":
|
|
||||||
case "Program":
|
|
||||||
var evaluateProgPromise = evaluateProg(exp, workerScript, 0); //TODO: make every block/program use individual enviroment
|
|
||||||
return evaluateProgPromise.then(function(w) {
|
|
||||||
return Promise.resolve(workerScript);
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e.constructor === Array && e.length === 2 && e[0] === "RETURNSTATEMENT") {
|
|
||||||
return Promise.reject(e);
|
|
||||||
} else if (isString(e)) {
|
|
||||||
workerScript.errorMessage = e;
|
|
||||||
return Promise.reject(workerScript);
|
|
||||||
} else if (e instanceof WorkerScript) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
} else {
|
|
||||||
return Promise.reject(workerScript);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "Literal":
|
|
||||||
return Promise.resolve(exp.value);
|
|
||||||
break;
|
|
||||||
case "Identifier":
|
|
||||||
//Javascript constructor() method can be used as an exploit to run arbitrary code
|
|
||||||
if (exp.name == "constructor") {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Illegal usage of constructor() method. If you have your own function named 'constructor', you must re-name it.", exp));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(exp.name in env.vars)){
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.name + " not defined", exp));
|
|
||||||
}
|
|
||||||
return Promise.resolve(env.get(exp.name))
|
|
||||||
break;
|
|
||||||
case "ExpressionStatement":
|
|
||||||
return evaluate(exp.expression, workerScript);
|
|
||||||
break;
|
|
||||||
case "ArrayExpression":
|
|
||||||
var argPromises = exp.elements.map(function(arg) {
|
|
||||||
return evaluate(arg, workerScript);
|
|
||||||
});
|
|
||||||
return Promise.all(argPromises).then(function(array) {
|
|
||||||
return Promise.resolve(array)
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "CallExpression":
|
|
||||||
return evaluate(exp.callee, workerScript).then(function(func) {
|
|
||||||
return Promise.map(exp.arguments, function(arg) {
|
|
||||||
return evaluate(arg, workerScript);
|
|
||||||
}).then(function(args) {
|
|
||||||
if (func instanceof Node) { //Player-defined function
|
|
||||||
//Create new Environment for the function
|
|
||||||
//Should be automatically garbage collected...
|
|
||||||
var funcEnv = env.extend();
|
|
||||||
|
|
||||||
//Define function arguments in this new environment
|
|
||||||
for (var i = 0; i < func.params.length; ++i) {
|
|
||||||
var arg;
|
|
||||||
if (i >= args.length) {
|
|
||||||
arg = null;
|
|
||||||
} else {
|
|
||||||
arg = args[i];
|
|
||||||
}
|
|
||||||
funcEnv.def(func.params[i].name, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Create a new WorkerScript for this function evaluation
|
|
||||||
var funcWorkerScript = new WorkerScript(workerScript.scriptRef);
|
|
||||||
funcWorkerScript.serverIp = workerScript.serverIp;
|
|
||||||
funcWorkerScript.env = funcEnv;
|
|
||||||
workerScript.fnWorker = funcWorkerScript;
|
|
||||||
|
|
||||||
return evaluate(func.body, funcWorkerScript).then(function(res) {
|
|
||||||
//If the function finished successfuly, that means there
|
|
||||||
//was no return statement since a return statement rejects. So resolve to null
|
|
||||||
workerScript.fnWorker = null;
|
|
||||||
return Promise.resolve(null);
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e.constructor === Array && e.length === 2 && e[0] === "RETURNSTATEMENT") {
|
|
||||||
//Return statement from function
|
|
||||||
return Promise.resolve(e[1]);
|
|
||||||
workerScript.fnWorker = null;
|
|
||||||
} else if (isString(e)) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e));
|
|
||||||
} else if (e instanceof WorkerScript) {
|
|
||||||
//Parse out the err message from the WorkerScript and re-reject
|
|
||||||
var errorMsg = e.errorMessage;
|
|
||||||
var errorTextArray = errorMsg.split("|");
|
|
||||||
if (errorTextArray.length === 4) {
|
|
||||||
errorMsg = errorTextArray[3];
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, errorMsg));
|
|
||||||
} else {
|
|
||||||
if (env.stopFlag) {
|
|
||||||
return Promise.reject(workerScript);
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error in one of your functions. Could not identify which function"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (e instanceof Error) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e.toString()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (exp.callee.type === "MemberExpression"){
|
|
||||||
return evaluate(exp.callee.object, workerScript).then(function(object) {
|
|
||||||
try {
|
|
||||||
if (func === "NETSCRIPTFOREACH") {
|
|
||||||
return evaluateForeach(object, args, workerScript).then(function(res) {
|
|
||||||
return Promise.resolve(res);
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var res = func.apply(object,args);
|
|
||||||
return Promise.resolve(res);
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e, exp));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
var out = func.apply(null,args);
|
|
||||||
if (out instanceof Promise){
|
|
||||||
return out.then(function(res) {
|
|
||||||
return Promise.resolve(res)
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (isScriptErrorMessage(e)) {
|
|
||||||
//Functions don't have line number appended in error message, so add it
|
|
||||||
var num = getErrorLineNumber(exp, workerScript);
|
|
||||||
e += " (Line " + num + ")";
|
|
||||||
}
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(out);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (isScriptErrorMessage(e)) {
|
|
||||||
if (isScriptErrorMessage(e)) {
|
|
||||||
//Functions don't have line number appended in error message, so add it
|
|
||||||
var num = getErrorLineNumber(exp, workerScript);
|
|
||||||
e += " (Line " + num + ")";
|
|
||||||
}
|
|
||||||
return Promise.reject(e);
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e, exp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "MemberExpression":
|
|
||||||
return evaluate(exp.object, workerScript).then(function(object) {
|
|
||||||
if (exp.computed){
|
|
||||||
return evaluate(exp.property, workerScript).then(function(index) {
|
|
||||||
if (index >= object.length) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid index for arrays", exp));
|
|
||||||
}
|
|
||||||
return Promise.resolve(object[index]);
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e instanceof WorkerScript || isScriptErrorMessage(e)) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid MemberExpression", exp));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (exp.property.name === "constructor") {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Illegal usage of constructor() method. If you have your own function named 'constructor', you must re-name it.", exp));
|
|
||||||
}
|
|
||||||
if (object != null && object instanceof Array && exp.property.name === "forEach") {
|
|
||||||
return "NETSCRIPTFOREACH";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Promise.resolve(object[exp.property.name])
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Failed to get property: " + e.toString(), exp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "LogicalExpression":
|
|
||||||
case "BinaryExpression":
|
|
||||||
return evalBinary(exp, workerScript);
|
|
||||||
break;
|
|
||||||
case "UnaryExpression":
|
|
||||||
return evalUnary(exp, workerScript);
|
|
||||||
break;
|
|
||||||
case "AssignmentExpression":
|
|
||||||
return evalAssignment(exp, workerScript);
|
|
||||||
break;
|
|
||||||
case "VariableDeclaration":
|
|
||||||
return evalVariableDeclaration(exp, workerScript);
|
|
||||||
break;
|
|
||||||
case "UpdateExpression":
|
|
||||||
if (exp.argument.type==="Identifier"){
|
|
||||||
if (exp.argument.name in env.vars){
|
|
||||||
if (exp.operator === "++" || exp.operator === "--") {
|
|
||||||
switch (exp.operator) {
|
|
||||||
case "++":
|
|
||||||
env.set(exp.argument.name,env.get(exp.argument.name)+1);
|
|
||||||
break;
|
|
||||||
case "--":
|
|
||||||
env.set(exp.argument.name,env.get(exp.argument.name)-1);
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
return Promise.resolve(env.get(exp.argument.name));
|
|
||||||
}
|
|
||||||
//Not sure what prefix UpdateExpressions there would be besides ++/--
|
|
||||||
if (exp.prefix){
|
|
||||||
return Promise.resolve(env.get(exp.argument.name))
|
|
||||||
}
|
|
||||||
switch (exp.operator){
|
|
||||||
default:
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". You are trying to use code that is currently unsupported", exp));
|
|
||||||
}
|
|
||||||
return Promise.resolve(env.get(exp.argument.name))
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.argument.name + " not defined", exp));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "argument must be an identifier", exp));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "EmptyStatement":
|
|
||||||
return Promise.resolve(false);
|
|
||||||
break;
|
|
||||||
case "ReturnStatement":
|
|
||||||
return evaluate(exp.argument, workerScript).then(function(res) {
|
|
||||||
return Promise.reject(["RETURNSTATEMENT", res]);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "BreakStatement":
|
|
||||||
return Promise.reject("BREAKSTATEMENT");
|
|
||||||
break;
|
|
||||||
case "ContinueStatement":
|
|
||||||
return Promise.reject("CONTINUESTATEMENT");
|
|
||||||
break;
|
|
||||||
case "IfStatement":
|
|
||||||
return evaluateIf(exp, workerScript);
|
|
||||||
break;
|
|
||||||
case "SwitchStatement":
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Switch statements are not yet implemented in Netscript", exp));
|
|
||||||
break;
|
|
||||||
case "WhileStatement":
|
|
||||||
return evaluateWhile(exp, workerScript).then(function(res) {
|
|
||||||
return Promise.resolve(res);
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e == "BREAKSTATEMENT" ||
|
|
||||||
(e instanceof WorkerScript && e.errorMessage == "BREAKSTATEMENT")) {
|
|
||||||
return Promise.resolve("whileLoopBroken");
|
|
||||||
} else {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "ForStatement":
|
|
||||||
return evaluate(exp.init, workerScript).then(function(expInit) {
|
|
||||||
return evaluateFor(exp, workerScript);
|
|
||||||
}).then(function(forLoopRes) {
|
|
||||||
return Promise.resolve("forLoopDone");
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e == "BREAKSTATEMENT" ||
|
|
||||||
(e instanceof WorkerScript && e.errorMessage == "BREAKSTATEMENT")) {
|
|
||||||
return Promise.resolve("forLoopBroken");
|
|
||||||
} else {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "FunctionDeclaration":
|
|
||||||
if (exp.id && exp.id.name) {
|
|
||||||
env.set(exp.id.name, exp);
|
|
||||||
return Promise.resolve(true);
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid function declaration", exp));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "ImportDeclaration":
|
|
||||||
return evaluateImport(exp, workerScript).then(function(res) {
|
|
||||||
return Promise.resolve(res);
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "ThrowStatement":
|
|
||||||
return evaluate(exp.argument, workerScript).then(function(res) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, res));
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". This is currently unsupported in Netscript", exp));
|
|
||||||
break;
|
|
||||||
} //End switch
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}); // End Promise
|
|
||||||
}
|
|
||||||
|
|
||||||
function evalBinary(exp, workerScript){
|
|
||||||
return evaluate(exp.left, workerScript).then(function(expLeft) {
|
|
||||||
//Short circuiting
|
|
||||||
if (expLeft && exp.operator === "||") {
|
|
||||||
return Promise.resolve(expLeft);
|
|
||||||
}
|
|
||||||
if (!expLeft && exp.operator === "&&") {
|
|
||||||
return Promise.resolve(expLeft);
|
|
||||||
}
|
|
||||||
return evaluate(exp.right, workerScript).then(function(expRight) {
|
|
||||||
switch (exp.operator){
|
|
||||||
case "===":
|
|
||||||
case "==":
|
|
||||||
return Promise.resolve(expLeft===expRight);
|
|
||||||
break;
|
|
||||||
case "!==":
|
|
||||||
case "!=":
|
|
||||||
return Promise.resolve(expLeft!==expRight);
|
|
||||||
break;
|
|
||||||
case "<":
|
|
||||||
return Promise.resolve(expLeft<expRight);
|
|
||||||
break;
|
|
||||||
case "<=":
|
|
||||||
return Promise.resolve(expLeft<=expRight);
|
|
||||||
break;
|
|
||||||
case ">":
|
|
||||||
return Promise.resolve(expLeft>expRight);
|
|
||||||
break;
|
|
||||||
case ">=":
|
|
||||||
return Promise.resolve(expLeft>=expRight);
|
|
||||||
break;
|
|
||||||
case "+":
|
|
||||||
return Promise.resolve(expLeft+expRight);
|
|
||||||
break;
|
|
||||||
case "-":
|
|
||||||
return Promise.resolve(expLeft-expRight);
|
|
||||||
break;
|
|
||||||
case "*":
|
|
||||||
return Promise.resolve(expLeft*expRight);
|
|
||||||
break;
|
|
||||||
case "/":
|
|
||||||
if (expRight === 0) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "ERROR: Divide by zero"));
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(expLeft/expRight);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "%":
|
|
||||||
return Promise.resolve(expLeft%expRight);
|
|
||||||
break;
|
|
||||||
case "in":
|
|
||||||
return Promise.resolve(expLeft in expRight);
|
|
||||||
break;
|
|
||||||
case "instanceof":
|
|
||||||
return Promise.resolve(expLeft instanceof expRight);
|
|
||||||
break;
|
|
||||||
case "||":
|
|
||||||
return Promise.resolve(expLeft || expRight);
|
|
||||||
break;
|
|
||||||
case "&&":
|
|
||||||
return Promise.resolve(expLeft && expRight);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unsupported operator: " + exp.operator));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evalUnary(exp, workerScript){
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
return evaluate(exp.argument, workerScript).then(function(res) {
|
|
||||||
if (exp.operator == "!") {
|
|
||||||
return Promise.resolve(!res);
|
|
||||||
} else if (exp.operator == "-") {
|
|
||||||
if (isNaN(res)) {
|
|
||||||
return Promise.resolve(res);
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(-1 * res);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unimplemented unary operator: " + exp.operator));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//Takes in a MemberExpression that should represent a Netscript array (possible multidimensional)
|
|
||||||
//The return value is an array of the form:
|
|
||||||
// [0th index (leftmost), array name, 1st index, 2nd index, ...]
|
|
||||||
function getArrayElement(exp, workerScript) {
|
|
||||||
var indices = [];
|
|
||||||
return evaluate(exp.property, workerScript).then(function(idx) {
|
|
||||||
if (isNaN(idx)) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid access to array. Index is not a number: " + idx));
|
|
||||||
} else {
|
|
||||||
if (exp.object.name === undefined && exp.object.object) {
|
|
||||||
return getArrayElement(exp.object, workerScript).then(function(res) {
|
|
||||||
res.push(idx);
|
|
||||||
indices = res;
|
|
||||||
return Promise.resolve(indices);
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
indices.push(idx);
|
|
||||||
indices.push(exp.object.name);
|
|
||||||
return Promise.resolve(indices);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evalAssignment(exp, workerScript) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
|
|
||||||
if (exp.left.type != "Identifier" && exp.left.type != "MemberExpression") {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to " + JSON.stringify(exp.left)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp.operator !== "=" && !(exp.left.name in env.vars)){
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.left.name + " not defined"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return evaluate(exp.right, workerScript).then(function(expRight) {
|
|
||||||
if (exp.left.type == "MemberExpression") {
|
|
||||||
if (!exp.left.computed) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to an object's property. This is currently unsupported in Netscript", exp));
|
|
||||||
}
|
|
||||||
//Assign to array element
|
|
||||||
//Array object designed by exp.left.object.name
|
|
||||||
//Index designated by exp.left.property
|
|
||||||
return getArrayElement(exp.left, workerScript).then(function(res) {
|
|
||||||
if (!(res instanceof Array) || res.length < 2) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error evaluating array assignment. This is (probably) a bug please report to game dev"));
|
|
||||||
}
|
|
||||||
|
|
||||||
//The array name is the second value
|
|
||||||
var arrName = res.splice(1, 1);
|
|
||||||
arrName = arrName[0];
|
|
||||||
|
|
||||||
var res;
|
|
||||||
try {
|
|
||||||
res = env.setArrayElement(arrName, res, expRight);
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e));
|
|
||||||
}
|
|
||||||
return Promise.resolve(res);
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
//Other assignments
|
|
||||||
try {
|
|
||||||
var assign;
|
|
||||||
switch (exp.operator) {
|
|
||||||
case "=":
|
|
||||||
assign = expRight; break;
|
|
||||||
case "+=":
|
|
||||||
assign = env.get(exp.left.name) + expRight; break;
|
|
||||||
case "-=":
|
|
||||||
assign = env.get(exp.left.name) - expRight; break;
|
|
||||||
case "*=":
|
|
||||||
assign = env.get(exp.left.name) * expRight; break;
|
|
||||||
case "/=":
|
|
||||||
assign = env.get(exp.left.name) / expRight; break;
|
|
||||||
case "%=":
|
|
||||||
assign = env.get(exp.left.name) % expRight; break;
|
|
||||||
default:
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Bitwise assignment is not implemented"));
|
|
||||||
}
|
|
||||||
env.set(exp.left.name, assign);
|
|
||||||
return Promise.resolve(assign);
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Failed to set environment variable: " + e.toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evalVariableDeclaration(exp, workerScript) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
|
|
||||||
if (!(exp.declarations instanceof Array)) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Variable declarations parsed incorrectly. This may be a syntax error"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp.kind !== "var") {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Only 'var' declarations are currently allowed (let, const, etc. are not allowed)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(exp.declarations.map((decl)=>{
|
|
||||||
evalVariableDeclarator(decl, workerScript);
|
|
||||||
})).then(function(res) {
|
|
||||||
return Promise.resolve(res);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//A Variable Declaration contains an array of Variable Declarators
|
|
||||||
function evalVariableDeclarator(exp, workerScript) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (exp.type !== "VariableDeclarator") {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid AST Node passed into evalVariableDeclarator: " + exp.type));
|
|
||||||
}
|
|
||||||
if (exp.init == null) {
|
|
||||||
env.set(exp.id.name, null);
|
|
||||||
return Promise.resolve(null);
|
|
||||||
} else {
|
|
||||||
return evaluate(exp.init, workerScript).then(function(initValue) {
|
|
||||||
env.set(exp.id.name, initValue);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateIf(exp, workerScript, i) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
return evaluate(exp.test, workerScript).then(function(condRes) {
|
|
||||||
if (condRes) {
|
|
||||||
return evaluate(exp.consequent, workerScript).then(function(res) {
|
|
||||||
return Promise.resolve(true);
|
|
||||||
}, function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else if (exp.alternate) {
|
|
||||||
return evaluate(exp.alternate, workerScript).then(function(res) {
|
|
||||||
return Promise.resolve(true);
|
|
||||||
}, function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.resolve("endIf");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//Evaluate the looping part of a for loop (Initialization block is NOT done in here)
|
|
||||||
function evaluateFor(exp, workerScript) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
function recurse() {
|
|
||||||
//Don't return a promise so the promise chain is broken on each recursion (saving memory)
|
|
||||||
evaluate(exp.test, workerScript).then(function(resCond) {
|
|
||||||
if (resCond) {
|
|
||||||
return evaluate(exp.body, workerScript).then(function(res) {
|
|
||||||
return evaluate(exp.update, workerScript);
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e == "CONTINUESTATEMENT" ||
|
|
||||||
(e instanceof WorkerScript && e.errorMessage == "CONTINUESTATEMENT")) {
|
|
||||||
//Continue statement, recurse to next iteration
|
|
||||||
return evaluate(exp.update, workerScript).then(function(resPostloop) {
|
|
||||||
return evaluateFor(exp, workerScript);
|
|
||||||
}).then(function(foo) {
|
|
||||||
return Promise.resolve("endForLoop");
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
}).then(recurse, reject).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}).catch(function(e) {
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
recurse();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateForeach(arr, args, workerScript) {
|
|
||||||
console.log("evaluateForeach called");
|
|
||||||
if (!(arr instanceof Array)) {
|
|
||||||
return Promise.reject("Invalid array passed into forEach");
|
|
||||||
}
|
|
||||||
if (!(args instanceof Array) && args.length != 1) {
|
|
||||||
return Promise.reject("Invalid argument passed into forEach");
|
|
||||||
}
|
|
||||||
var func = args[0];
|
|
||||||
if (typeof func !== "function") {
|
|
||||||
return Promise.reject("Invalid function passed into forEach");
|
|
||||||
}
|
|
||||||
console.log(func);
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
//Don't return a promise so the promise chain is broken on each recursion
|
|
||||||
function recurse(i) {
|
|
||||||
console.log("recurse() called with i: " + i);
|
|
||||||
if (i >= arr.length) {
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
return Promise.delay(Settings.CodeInstructionRunTime).then(function() {
|
|
||||||
console.log("About to apply function");
|
|
||||||
var res = func.apply(null, [arr[i]]);
|
|
||||||
console.log("Applied function");
|
|
||||||
++i;
|
|
||||||
Promise.resolve(res).then(function(val) {
|
|
||||||
recurse(i);
|
|
||||||
}, reject).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
recurse(0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateWhile(exp, workerScript) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
function recurse() {
|
|
||||||
//Don't return a promise so the promise chain is broken on each recursion (saving memory)
|
|
||||||
evaluate(exp.test, workerScript).then(function(resCond) {
|
|
||||||
if (resCond) {
|
|
||||||
return evaluate(exp.body, workerScript).catch(function(e) {
|
|
||||||
if (e == "CONTINUESTATEMENT" ||
|
|
||||||
(e instanceof WorkerScript && e.errorMessage == "CONTINUESTATEMENT")) {
|
|
||||||
//Continue statement, recurse
|
|
||||||
return evaluateWhile(exp, workerScript).then(function(foo) {
|
|
||||||
return Promise.resolve("endWhileLoop");
|
|
||||||
}, function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
}).then(recurse, reject).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}).catch(function(e) {
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
recurse();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateProg(exp, workerScript, index) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
if (index >= exp.body.length) {
|
|
||||||
return Promise.resolve("progFinished");
|
|
||||||
} else {
|
|
||||||
//Evaluate this line of code in the prog
|
|
||||||
//After the code finishes evaluating, evaluate the next line recursively
|
|
||||||
return evaluate(exp.body[index], workerScript).then(function(res) {
|
|
||||||
return evaluateProg(exp, workerScript, index + 1);
|
|
||||||
}).then(function(res) {
|
|
||||||
return Promise.resolve(workerScript);
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateImport(exp, workerScript, checkingRam=false) {
|
|
||||||
//When its checking RAM, it exports an array of nodes for each imported function
|
//When its checking RAM, it exports an array of nodes for each imported function
|
||||||
var ramCheckRes = [];
|
var ramCheckRes = [];
|
||||||
|
|
||||||
@ -808,7 +123,7 @@ function evaluateImport(exp, workerScript, checkingRam=false) {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function killNetscriptDelay(workerScript) {
|
export function killNetscriptDelay(workerScript) {
|
||||||
if (workerScript instanceof WorkerScript) {
|
if (workerScript instanceof WorkerScript) {
|
||||||
if (workerScript.delay) {
|
if (workerScript.delay) {
|
||||||
clearTimeout(workerScript.delay);
|
clearTimeout(workerScript.delay);
|
||||||
@ -817,7 +132,7 @@ function killNetscriptDelay(workerScript) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function netscriptDelay(time, workerScript) {
|
export function netscriptDelay(time, workerScript) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
workerScript.delay = setTimeout(()=>{
|
workerScript.delay = setTimeout(()=>{
|
||||||
workerScript.delay = null;
|
workerScript.delay = null;
|
||||||
@ -827,7 +142,7 @@ function netscriptDelay(time, workerScript) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
|
export function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
|
||||||
var lineNum = "";
|
var lineNum = "";
|
||||||
if (exp != null) {
|
if (exp != null) {
|
||||||
var num = getErrorLineNumber(exp, workerScript);
|
var num = getErrorLineNumber(exp, workerScript);
|
||||||
@ -837,7 +152,7 @@ function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Run a script from inside a script using run() command
|
//Run a script from inside a script using run() command
|
||||||
function runScriptFromScript(server, scriptname, args, workerScript, threads=1) {
|
export function runScriptFromScript(server, scriptname, args, workerScript, threads=1) {
|
||||||
//Check if the script is already running
|
//Check if the script is already running
|
||||||
var runningScriptObj = findRunningScript(scriptname, args, server);
|
var runningScriptObj = findRunningScript(scriptname, args, server);
|
||||||
if (runningScriptObj != null) {
|
if (runningScriptObj != null) {
|
||||||
@ -887,8 +202,8 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1)
|
|||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getErrorLineNumber(exp, workerScript) {
|
export function getErrorLineNumber(exp, workerScript) {
|
||||||
var code = workerScript.scriptRef.scriptRef.code;
|
var code = workerScript.scriptRef.codeCode();
|
||||||
|
|
||||||
//Split code up to the start of the node
|
//Split code up to the start of the node
|
||||||
try {
|
try {
|
||||||
@ -899,7 +214,7 @@ function getErrorLineNumber(exp, workerScript) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isScriptErrorMessage(msg) {
|
export function isScriptErrorMessage(msg) {
|
||||||
if (!isString(msg)) {return false;}
|
if (!isString(msg)) {return false;}
|
||||||
let splitMsg = msg.split("|");
|
let splitMsg = msg.split("|");
|
||||||
if (splitMsg.length != 4){
|
if (splitMsg.length != 4){
|
||||||
@ -911,6 +226,3 @@ function isScriptErrorMessage(msg) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {makeRuntimeRejectMsg, netscriptDelay, runScriptFromScript, evaluate,
|
|
||||||
isScriptErrorMessage, killNetscriptDelay, evaluateImport};
|
|
||||||
|
@ -28,8 +28,8 @@ const walk = require("acorn/dist/walk");
|
|||||||
function WorkerScript(runningScriptObj) {
|
function WorkerScript(runningScriptObj) {
|
||||||
this.name = runningScriptObj.filename;
|
this.name = runningScriptObj.filename;
|
||||||
this.running = false;
|
this.running = false;
|
||||||
this.serverIp = null;
|
this.serverIp = runningScriptObj.server;
|
||||||
this.code = runningScriptObj.scriptRef.code;
|
this.code = runningScriptObj.getCode();
|
||||||
this.env = new Environment(this);
|
this.env = new Environment(this);
|
||||||
this.env.set("args", runningScriptObj.args.slice());
|
this.env.set("args", runningScriptObj.args.slice());
|
||||||
this.output = "";
|
this.output = "";
|
||||||
@ -588,7 +588,7 @@ function addWorkerScript(runningScriptObj, server) {
|
|||||||
} else {
|
} else {
|
||||||
runningScriptObj.threads = 1;
|
runningScriptObj.threads = 1;
|
||||||
}
|
}
|
||||||
var ramUsage = roundToTwo(runningScriptObj.scriptRef.ramUsage * threads);
|
var ramUsage = roundToTwo(runningScriptObj.getRamUsage() * threads);
|
||||||
var ramAvailable = server.maxRam - server.ramUsed;
|
var ramAvailable = server.maxRam - server.ramUsed;
|
||||||
if (ramUsage > ramAvailable) {
|
if (ramUsage > ramAvailable) {
|
||||||
dialogBoxCreate("Not enough RAM to run script " + runningScriptObj.filename + " with args " +
|
dialogBoxCreate("Not enough RAM to run script " + runningScriptObj.filename + " with args " +
|
||||||
@ -601,7 +601,6 @@ function addWorkerScript(runningScriptObj, server) {
|
|||||||
|
|
||||||
//Create the WorkerScript
|
//Create the WorkerScript
|
||||||
var s = new WorkerScript(runningScriptObj);
|
var s = new WorkerScript(runningScriptObj);
|
||||||
s.serverIp = server.ip;
|
|
||||||
s.ramUsage = ramUsage;
|
s.ramUsage = ramUsage;
|
||||||
|
|
||||||
//Add the WorkerScript to the Active Scripts list
|
//Add the WorkerScript to the Active Scripts list
|
||||||
|
108
src/Script.js
108
src/Script.js
@ -650,7 +650,8 @@ async function calculateRamUsage(codeCopy) {
|
|||||||
var workerScript = new WorkerScript({
|
var workerScript = new WorkerScript({
|
||||||
filename:"foo",
|
filename:"foo",
|
||||||
scriptRef: {code:""},
|
scriptRef: {code:""},
|
||||||
args:[]
|
args:[],
|
||||||
|
getCode: function() { return ""; }
|
||||||
});
|
});
|
||||||
workerScript.checkingRam = true; //Netscript functions will return RAM usage
|
workerScript.checkingRam = true; //Netscript functions will return RAM usage
|
||||||
workerScript.serverIp = currServ.ip;
|
workerScript.serverIp = currServ.ip;
|
||||||
@ -778,10 +779,9 @@ Reviver.constructors.Script = Script;
|
|||||||
//Called when the game is loaded. Loads all running scripts (from all servers)
|
//Called when the game is loaded. Loads all running scripts (from all servers)
|
||||||
//into worker scripts so that they will start running
|
//into worker scripts so that they will start running
|
||||||
function loadAllRunningScripts() {
|
function loadAllRunningScripts() {
|
||||||
var count = 0;
|
|
||||||
var total = 0;
|
var total = 0;
|
||||||
let skipScriptLoad = (window.location.href.toLowerCase().indexOf("?noscripts") !== -1);
|
let skipScriptLoad = (window.location.href.toLowerCase().indexOf("?noscripts") !== -1);
|
||||||
if (skipScriptLoad) {console.log("Skipping the load of any scripts during startup");}
|
if (skipScriptLoad) { console.info("Skipping the load of any scripts during startup"); }
|
||||||
for (var property in AllServers) {
|
for (var property in AllServers) {
|
||||||
if (AllServers.hasOwnProperty(property)) {
|
if (AllServers.hasOwnProperty(property)) {
|
||||||
var server = AllServers[property];
|
var server = AllServers[property];
|
||||||
@ -799,8 +799,6 @@ function loadAllRunningScripts() {
|
|||||||
server.runningScripts.length = 0;
|
server.runningScripts.length = 0;
|
||||||
} else {
|
} else {
|
||||||
for (var j = 0; j < server.runningScripts.length; ++j) {
|
for (var j = 0; j < server.runningScripts.length; ++j) {
|
||||||
count++;
|
|
||||||
server.runningScripts[j].scriptRef.module = "";
|
|
||||||
addWorkerScript(server.runningScripts[j], server);
|
addWorkerScript(server.runningScripts[j], server);
|
||||||
|
|
||||||
//Offline production
|
//Offline production
|
||||||
@ -809,8 +807,8 @@ function loadAllRunningScripts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
console.log("Loaded " + count.toString() + " running scripts");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function scriptCalculateOfflineProduction(runningScriptObj) {
|
function scriptCalculateOfflineProduction(runningScriptObj) {
|
||||||
@ -827,7 +825,7 @@ function scriptCalculateOfflineProduction(runningScriptObj) {
|
|||||||
|
|
||||||
//Data map: [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
//Data map: [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
||||||
|
|
||||||
//Grow
|
// Grow
|
||||||
for (var ip in runningScriptObj.dataMap) {
|
for (var ip in runningScriptObj.dataMap) {
|
||||||
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
||||||
if (runningScriptObj.dataMap[ip][2] == 0 || runningScriptObj.dataMap[ip][2] == null) {continue;}
|
if (runningScriptObj.dataMap[ip][2] == 0 || runningScriptObj.dataMap[ip][2] == null) {continue;}
|
||||||
@ -841,6 +839,7 @@ function scriptCalculateOfflineProduction(runningScriptObj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Money from hacking
|
||||||
var totalOfflineProduction = 0;
|
var totalOfflineProduction = 0;
|
||||||
for (var ip in runningScriptObj.dataMap) {
|
for (var ip in runningScriptObj.dataMap) {
|
||||||
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
||||||
@ -862,19 +861,19 @@ function scriptCalculateOfflineProduction(runningScriptObj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Offline EXP gain
|
// Offline EXP gain
|
||||||
//A script's offline production will always be at most half of its online production.
|
// A script's offline production will always be at most half of its online production.
|
||||||
var expGain = 0.5 * (runningScriptObj.onlineExpGained / runningScriptObj.onlineRunningTime) * timePassed;
|
var expGain = 0.5 * (runningScriptObj.onlineExpGained / runningScriptObj.onlineRunningTime) * timePassed;
|
||||||
expGain *= confidence;
|
expGain *= confidence;
|
||||||
|
|
||||||
Player.gainHackingExp(expGain);
|
Player.gainHackingExp(expGain);
|
||||||
|
|
||||||
//Update script stats
|
// Update script stats
|
||||||
runningScriptObj.offlineMoneyMade += totalOfflineProduction;
|
runningScriptObj.offlineMoneyMade += totalOfflineProduction;
|
||||||
runningScriptObj.offlineRunningTime += timePassed;
|
runningScriptObj.offlineRunningTime += timePassed;
|
||||||
runningScriptObj.offlineExpGained += expGain;
|
runningScriptObj.offlineExpGained += expGain;
|
||||||
|
|
||||||
//Fortify a server's security based on how many times it was hacked
|
// Fortify a server's security based on how many times it was hacked
|
||||||
for (var ip in runningScriptObj.dataMap) {
|
for (var ip in runningScriptObj.dataMap) {
|
||||||
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
||||||
if (runningScriptObj.dataMap[ip][1] == 0 || runningScriptObj.dataMap[ip][1] == null) {continue;}
|
if (runningScriptObj.dataMap[ip][1] == 0 || runningScriptObj.dataMap[ip][1] == null) {continue;}
|
||||||
@ -887,7 +886,7 @@ function scriptCalculateOfflineProduction(runningScriptObj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Weaken
|
// Weaken
|
||||||
for (var ip in runningScriptObj.dataMap) {
|
for (var ip in runningScriptObj.dataMap) {
|
||||||
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
||||||
if (runningScriptObj.dataMap[ip][3] == 0 || runningScriptObj.dataMap[ip][3] == null) {continue;}
|
if (runningScriptObj.dataMap[ip][3] == 0 || runningScriptObj.dataMap[ip][3] == null) {continue;}
|
||||||
@ -916,11 +915,11 @@ function findRunningScript(filename, args, server) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function RunningScript(script, args) {
|
function RunningScript(script, args) {
|
||||||
if (script == null || script == undefined) {return;}
|
if (script == null || script == undefined) { return; }
|
||||||
this.filename = script.filename;
|
this.filename = script.filename;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
this.scriptRef = script;
|
|
||||||
this.server = script.server; //IP Address only
|
this.server = script.server; //IP Address only
|
||||||
|
this.ramUsage = script.ramUsage;
|
||||||
|
|
||||||
this.logs = []; //Script logging. Array of strings, with each element being a log entry
|
this.logs = []; //Script logging. Array of strings, with each element being a log entry
|
||||||
this.logUpd = false;
|
this.logUpd = false;
|
||||||
@ -935,8 +934,40 @@ function RunningScript(script, args) {
|
|||||||
|
|
||||||
this.threads = 1;
|
this.threads = 1;
|
||||||
|
|
||||||
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
// Holds a map of all servers, where server = key and the value for each
|
||||||
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
|
// server is an array of four numbers. The four numbers represent:
|
||||||
|
// [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
||||||
|
// This data is used for offline progress
|
||||||
|
this.dataMap = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
RunningScript.prototype.getCode = function() {
|
||||||
|
const server = AllServers[this.server];
|
||||||
|
if (server == null) { return ""; }
|
||||||
|
for (let i = 0; i < server.scripts.length; ++i) {
|
||||||
|
if (server.scripts[i].filename === this.filename) {
|
||||||
|
return server.scripts[i].code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
RunningScript.prototype.getRamUsage = function() {
|
||||||
|
if (this.ramUsage != null && this.ramUsage > 0) { return this.ramUsage; } // Use cached value
|
||||||
|
|
||||||
|
const server = AllServers[this.server];
|
||||||
|
if (server == null) { return 0; }
|
||||||
|
for (let i = 0; i < server.scripts.length; ++i) {
|
||||||
|
if (server.scripts[i].filename === this.filename) {
|
||||||
|
// Cache the ram usage for the next call
|
||||||
|
this.ramUsage = server.scripts[i].ramUsage;
|
||||||
|
return this.ramUsage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RunningScript.prototype.log = function(txt) {
|
RunningScript.prototype.log = function(txt) {
|
||||||
@ -966,9 +997,8 @@ RunningScript.prototype.clearLog = function() {
|
|||||||
|
|
||||||
//Update the moneyStolen and numTimesHack maps when hacking
|
//Update the moneyStolen and numTimesHack maps when hacking
|
||||||
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
|
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
|
||||||
if (this.dataMap == null) {
|
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||||
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||||
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
|
|
||||||
}
|
}
|
||||||
this.dataMap[serverIp][0] += moneyGained;
|
this.dataMap[serverIp][0] += moneyGained;
|
||||||
this.dataMap[serverIp][1] += n;
|
this.dataMap[serverIp][1] += n;
|
||||||
@ -976,18 +1006,16 @@ RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
|
|||||||
|
|
||||||
//Update the grow map when calling grow()
|
//Update the grow map when calling grow()
|
||||||
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
|
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
|
||||||
if (this.dataMap == null) {
|
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||||
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||||
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
|
|
||||||
}
|
}
|
||||||
this.dataMap[serverIp][2] += n;
|
this.dataMap[serverIp][2] += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update the weaken map when calling weaken() {
|
//Update the weaken map when calling weaken() {
|
||||||
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
|
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
|
||||||
if (this.dataMap == null) {
|
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||||
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||||
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
|
|
||||||
}
|
}
|
||||||
this.dataMap[serverIp][3] += n;
|
this.dataMap[serverIp][3] += n;
|
||||||
}
|
}
|
||||||
@ -1003,33 +1031,5 @@ RunningScript.fromJSON = function(value) {
|
|||||||
|
|
||||||
Reviver.constructors.RunningScript = RunningScript;
|
Reviver.constructors.RunningScript = RunningScript;
|
||||||
|
|
||||||
//Creates an object that creates a map/dictionary with the IP of each existing server as
|
|
||||||
//a key. Initializes every key with a specified value that can either by a number or an array
|
|
||||||
function AllServersMap(arr=false, filterOwned=false) {
|
|
||||||
for (var ip in AllServers) {
|
|
||||||
if (AllServers.hasOwnProperty(ip)) {
|
|
||||||
if (filterOwned && (AllServers[ip].purchasedByPlayer || AllServers[ip].hostname === "home")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (arr) {
|
|
||||||
this[ip] = [0, 0, 0, 0];
|
|
||||||
} else {
|
|
||||||
this[ip] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AllServersMap.prototype.toJSON = function() {
|
|
||||||
return Generic_toJSON("AllServersMap", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AllServersMap.fromJSON = function(value) {
|
|
||||||
return Generic_fromJSON(AllServersMap, value.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Reviver.constructors.AllServersMap = AllServersMap;
|
|
||||||
|
|
||||||
export {loadAllRunningScripts, findRunningScript,
|
export {loadAllRunningScripts, findRunningScript,
|
||||||
RunningScript, Script, AllServersMap, scriptEditorInit, isScriptFilename};
|
RunningScript, Script, scriptEditorInit, isScriptFilename};
|
||||||
|
@ -33,8 +33,10 @@ export function getPurchaseServerLimit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getPurchaseServerMaxRam() {
|
export function getPurchaseServerMaxRam() {
|
||||||
// TODO ensure this is a power of 2?
|
const ram = Math.round(CONSTANTS.PurchasedServerMaxRam * BitNodeMultipliers.PurchasedServerMaxRam);
|
||||||
return Math.round(CONSTANTS.PurchasedServerMaxRam * BitNodeMultipliers.PurchasedServerMaxRam);
|
|
||||||
|
// Round this to the nearest power of 2
|
||||||
|
return 1 << 31 - Math.clz32(ram);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manually purchase a server (NOT through Netscript)
|
// Manually purchase a server (NOT through Netscript)
|
||||||
|
@ -26,8 +26,9 @@ import {showMessage, Message} from "./Message";
|
|||||||
import {killWorkerScript, addWorkerScript} from "./NetscriptWorker";
|
import {killWorkerScript, addWorkerScript} from "./NetscriptWorker";
|
||||||
import {Player} from "./Player";
|
import {Player} from "./Player";
|
||||||
import {hackWorldDaemon} from "./RedPill";
|
import {hackWorldDaemon} from "./RedPill";
|
||||||
import {findRunningScript, RunningScript,
|
import { findRunningScript,
|
||||||
AllServersMap, isScriptFilename} from "./Script";
|
RunningScript,
|
||||||
|
isScriptFilename } from "./Script";
|
||||||
import {AllServers, GetServerByHostname,
|
import {AllServers, GetServerByHostname,
|
||||||
getServer, Server} from "./Server";
|
getServer, Server} from "./Server";
|
||||||
import {Settings} from "./Settings/Settings";
|
import {Settings} from "./Settings/Settings";
|
||||||
@ -779,7 +780,7 @@ let Terminal = {
|
|||||||
}
|
}
|
||||||
Terminal.analyzeFlag = false;
|
Terminal.analyzeFlag = false;
|
||||||
|
|
||||||
//Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
|
// Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
|
||||||
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
|
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
|
||||||
$("#hack-progress").attr('id', "old-hack-progress");
|
$("#hack-progress").attr('id', "old-hack-progress");
|
||||||
Terminal.resetTerminalInput();
|
Terminal.resetTerminalInput();
|
||||||
@ -804,7 +805,7 @@ let Terminal = {
|
|||||||
commands = commands.split(";");
|
commands = commands.split(";");
|
||||||
for (let i = 0; i < commands.length; i++) {
|
for (let i = 0; i < commands.length; i++) {
|
||||||
if(commands[i].match(/^\s*$/)) { continue; } // Don't run commands that only have whitespace
|
if(commands[i].match(/^\s*$/)) { continue; } // Don't run commands that only have whitespace
|
||||||
Terminal.executeCommand(commands[i]);
|
Terminal.executeCommand(commands[i].trim());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1538,7 +1539,7 @@ let Terminal = {
|
|||||||
let spacesThread = Array(numSpacesThread+1).join(" ");
|
let spacesThread = Array(numSpacesThread+1).join(" ");
|
||||||
|
|
||||||
//Calculate and transform RAM usage
|
//Calculate and transform RAM usage
|
||||||
let ramUsage = numeralWrapper.format(script.scriptRef.ramUsage * script.threads, '0.00') + " GB";
|
let ramUsage = numeralWrapper.format(script.getRamUsage() * script.threads, '0.00') + " GB";
|
||||||
|
|
||||||
var entry = [script.filename, spacesScript, script.threads, spacesThread, ramUsage];
|
var entry = [script.filename, spacesScript, script.threads, spacesThread, ramUsage];
|
||||||
post(entry.join(""));
|
post(entry.join(""));
|
||||||
@ -1823,11 +1824,15 @@ let Terminal = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
executeScanAnalyzeCommand: function(depth=1, all=false) {
|
executeScanAnalyzeCommand: function(depth=1, all=false) {
|
||||||
//We'll use the AllServersMap as a visited() array
|
|
||||||
//TODO Using array as stack for now, can make more efficient
|
//TODO Using array as stack for now, can make more efficient
|
||||||
post("~~~~~~~~~~ Beginning scan-analyze ~~~~~~~~~~");
|
post("~~~~~~~~~~ Beginning scan-analyze ~~~~~~~~~~");
|
||||||
post(" ");
|
post(" ");
|
||||||
var visited = new AllServersMap();
|
|
||||||
|
// Map of all servers to keep track of which have been visited
|
||||||
|
var visited = {};
|
||||||
|
for (const ip in AllServers) {
|
||||||
|
visited[ip] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
var stack = [];
|
var stack = [];
|
||||||
var depthQueue = [0];
|
var depthQueue = [0];
|
||||||
|
Loading…
Reference in New Issue
Block a user