From 437ebc27038b6f54d59accfcba7baf768e72698d Mon Sep 17 00:00:00 2001 From: Daniel Xie Date: Mon, 5 Dec 2016 16:31:46 -0600 Subject: [PATCH] Implemented Hack and sleep in script. IMplemented functionality that allows scripts to stop (rejecting the Promises). Scripts will now automatically stop if they are not infinite. THIS IS UNTESTED TEST THIS WHEN I CAN. Still need to implement kill command --- src/Netscript/Environment.js | 4 +- src/Netscript/Evaluator.js | 119 ++++++++++++++++++++++++++++++- src/Netscript/NetscriptWorker.js | 31 +++++++- src/Terminal.js | 11 ++- src/engine.js | 3 - utils/JSONReviver.js | 1 - 6 files changed, 158 insertions(+), 11 deletions(-) diff --git a/src/Netscript/Environment.js b/src/Netscript/Environment.js index 09c060315..c379030c9 100644 --- a/src/Netscript/Environment.js +++ b/src/Netscript/Environment.js @@ -44,5 +44,7 @@ Environment.prototype = { //Creates (or overwrites) a variable in the current scope def: function(name, value) { return this.vars[name] = value; - } + }, + + stopFlag: false }; \ No newline at end of file diff --git a/src/Netscript/Evaluator.js b/src/Netscript/Evaluator.js index ae59ed9b3..bfb13f7f0 100644 --- a/src/Netscript/Evaluator.js +++ b/src/Netscript/Evaluator.js @@ -11,11 +11,13 @@ function evaluate(exp, workerScript) { case "str": case "bool": return new Promise(function(resolve, reject) { + if (env.stopFlag) {reject("Stopping script");} resolve(exp.value); }); break; case "var": return new Promise(function(resolve, reject) { + if (env.stopFlag) {reject("Stopping script");} resolve(env.get(exp.value)); }); break; @@ -23,6 +25,8 @@ function evaluate(exp, workerScript) { case "assign": console.log("Evaluating assign operation"); return new Promise(function(resolve, reject) { + if (env.stopFlag) {reject("Stopping script");} + if (exp.left.type != "var") throw new Error("Cannot assign to " + JSON.stringify(exp.left)); @@ -31,6 +35,8 @@ function evaluate(exp, workerScript) { var expRightPromise = evaluate(exp.right, workerScript); expRightPromise.then(function(expRight) { resolve(expRight); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime) }); @@ -40,17 +46,23 @@ function evaluate(exp, workerScript) { env.set(exp.left.value, expRight); console.log("Assign operation finished"); resolve("assignFinished"); + }, function() { + reject("Stopping script"); }); }); case "binary": console.log("Binary operation called"); return new Promise(function(resolve, reject) { + if (env.stopFlag) {reject("Stopping script");} + var pLeft = new Promise(function(resolve, reject) { setTimeout(function() { var promise = evaluate(exp.left, workerScript); promise.then(function(valLeft) { resolve(valLeft); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime); }); @@ -61,6 +73,8 @@ function evaluate(exp, workerScript) { var promise = evaluate(exp.right, workerScript); promise.then(function(valRight) { resolve([valLeft, valRight]); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime); }); @@ -68,7 +82,11 @@ function evaluate(exp, workerScript) { pRight.then(function(args) { console.log("Resolving binary operation"); resolve(apply_op(exp.operator, args[0], args[1])); + }, function() { + reject("Stopping script"); }); + }, function() { + reject("Stopping script"); }); }); break; @@ -92,12 +110,16 @@ function evaluate(exp, workerScript) { case "for": return new Promise(function(resolve, reject) { + if (env.stopFlag) {reject("Stopping script");} + console.log("for loop encountered in evaluator"); var pInit = new Promise(function(resolve, reject) { setTimeout(function() { var resInit = evaluate(exp.init, workerScript); resInit.then(function(foo) { resolve(resInit); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime); }); @@ -106,24 +128,36 @@ function evaluate(exp, workerScript) { var pForLoop = evaluateFor(exp, workerScript); pForLoop.then(function(forLoopRes) { resolve("forLoopDone"); + }, function() { + reject("Stopping script"); }); + }, function() { + reject("Stopping script"); }); }); break; case "while": console.log("Evaluating while loop"); return new Promise(function(resolve, reject) { + if (env.stopFlag) {reject("Stopping script");} + var pEvaluateWhile = evaluateWhile(exp, workerScript); pEvaluateWhile.then(function(whileLoopRes) { resolve("whileLoopDone"); + }, function() { + reject("Stopping script"); }); }); break; case "prog": return new Promise(function(resolve, reject) { + if (env.stopFlag) {reject("Stopping script");} + var evaluateProgPromise = evaluateProg(exp, workerScript, 0); evaluateProgPromise.then(function(res) { resolve(res); + }, function() { + reject("Stopping script"); }); }); break; @@ -141,19 +175,68 @@ function evaluate(exp, workerScript) { // return evaluate(arg, env); //})); return new Promise(function(resolve, reject) { + if (env.stopFlag) {reject("Stopping script");} + setTimeout(function() { if (exp.func.value == "hack") { console.log("Execute hack()"); - resolve("hackExecuted"); + if (exp.args.length != 0) { + throw new Error("Hack() call has incorrect number of arguments. Takes no arguments");) + } + + var p = new Promise(function(resolve, reject) { + setTimeout(function() { + var hackChance = Player.calculateHackingChance(); + var rand = Math.random(); + var expGainedOnSuccess = Player.calculateExpGain(); + var expGainedOnFailure = Math.round(expGainedOnSuccess / 4); + if (rand < hackChance) { //Success! + var moneyGained = Player.calculatePercentMoneyHacked(); + moneyGained = Math.floor(Player.getCurrentServer().moneyAvailable * moneyGained); + + Player.getCurrentServer().moneyAvailable -= moneyGained; + Player.money += moneyGained; + + Player.hacking_exp += expGainedOnSuccess; + } else { + //Player only gains 25% exp for failure? TODO Can change this later to balance + Player.hacking_exp += expGainedOnFailure; + } + }, CONSTANTS.CodeInstructionRunTime); + }); + + p.then(function(res) { + resolve("hackExecuted"); + }); + } else if (exp.func.value == "sleep") { console.log("Execute sleep()"); - resolve("sleepExecuted"); + if (exp.args.length != 1) { + throw new Error("Sleep() call has incorrect number of arguments. Takes 1 argument."); + } + + var p = new Promise(function(resolve, reject) { + setTimeout(function() { + resolve("foo"); + }, exp.args[0]); + }); + + p.then(function(res) { + resolve("sleepExecuted"); + }); + } else if (exp.func.value == "print") { + if (exp.args.length != 1) { + throw new Error("Print() call has incorrect number of arguments. Takes 1 argument"); + } + var p = new Promise(function(resolve, reject) { setTimeout(function() { var evaluatePromise = evaluate(exp.args[0], workerScript); evaluatePromise.then(function(res) { resolve(res); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime); }); @@ -162,6 +245,8 @@ function evaluate(exp, workerScript) { post(res.toString()); console.log("Print call executed"); resolve("printExecuted"); + }, function() { + reject("Stopping script"); }); } }, CONSTANTS.CodeInstructionRunTime); @@ -183,6 +268,8 @@ function evaluateFor(exp, workerScript) { evaluatePromise.then(function(resCond) { console.log("Conditional evaluated to: " + resCond); resolve(resCond); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime); }); @@ -197,6 +284,8 @@ function evaluateFor(exp, workerScript) { evaluatePromise.then(function(resCode) { console.log("Evaluated an iteration of for loop code"); resolve(resCode); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime); }); @@ -209,6 +298,8 @@ function evaluateFor(exp, workerScript) { evaluatePromise.then(function(foo) { console.log("Evaluated for loop postloop"); resolve("postLoopFinished"); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime); }); @@ -217,14 +308,22 @@ function evaluateFor(exp, workerScript) { var recursiveCall = evaluateFor(exp, workerScript); recursiveCall.then(function(foo) { resolve("endForLoop"); + }, function() { + reject("Stopping script"); }); + }, function() { + reject("Stopping script"); }); + }, function() { + reject("Stopping script"); }); } else { console.log("Cond is false, stopping for loop"); resolve("endForLoop"); //Doesn't need to resolve to any particular value } + }, function() { + reject("Stopping script"); }); }); } @@ -238,6 +337,8 @@ function evaluateWhile(exp, workerScript) { evaluatePromise.then(function(resCond) { console.log("Conditional evaluated to: " + resCond); resolve(resCond); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime); }); @@ -251,6 +352,8 @@ function evaluateWhile(exp, workerScript) { evaluatePromise.then(function(resCode) { console.log("Evaluated an iteration of while loop code"); resolve(resCode); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime); }); @@ -260,12 +363,18 @@ function evaluateWhile(exp, workerScript) { var recursiveCall = evaluateWhile(exp, workerScript); recursiveCall.then(function(foo) { resolve("endWhileLoop"); + }, function() { + reject("Stopping script"); }); + }, function() { + reject("Stopping script"); }); } else { console.log("Cond is false, stopping while loop"); resolve("endWhileLoop"); //Doesn't need to resolve to any particular value } + }, function() { + reject("Stopping script"); }); }); } @@ -283,6 +392,8 @@ function evaluateProg(exp, workerScript, index) { var evaluatePromise = evaluate(exp.prog[index], workerScript); evaluatePromise.then(function(evalRes) { resolve(evalRes); + }, function() { + reject("Stopping script"); }); }, CONSTANTS.CodeInstructionRunTime); }); @@ -292,7 +403,11 @@ function evaluateProg(exp, workerScript, index) { var nextLine = evaluateProg(exp, workerScript, index + 1); nextLine.then(function(nextLineRes) { resolve("progDone"); + }, function() { + reject("Stopping script"); }); + }, function() { + reject("Stopping script"); }); } }); diff --git a/src/Netscript/NetscriptWorker.js b/src/Netscript/NetscriptWorker.js index f1e4da0d3..46fd13342 100644 --- a/src/Netscript/NetscriptWorker.js +++ b/src/Netscript/NetscriptWorker.js @@ -20,7 +20,9 @@ var workerScripts = []; //Loop through workerScripts and run every script that is not currently running function runScriptsLoop() { + //Run any scripts that haven't been started for (var i = 0; i < workerScripts.length; i++) { + //If it isn't running, start the script if (workerScripts[i].running == false) { var ast = Parser(Tokenizer(InputStream(workerScripts[i].code))); @@ -29,7 +31,34 @@ function runScriptsLoop() { console.log(ast); workerScripts[i].running = true; - evaluate(ast, workerScripts[i]); + var p = evaluate(ast, workerScripts[i]); + + //Once the code finishes (either resolved or rejected, doesnt matter), set its + //running status to false + p.then(function(foo) { + workerScripts[i].running = false; + }, function() { + workerScripts[i].running = false; + }); + } + } + + //Delete any scripts that finished or have been killed. Loop backwards bc removing + //items fucks up the indexing + for (var i = workerScripts.length - 1; i >= 0; i--) { + if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == true) { + //Delete script from the runningScripts array on its host serverIp + var ip = workerScripts[i].serverIp; + var name = workerScripts[i].name; + for (var j = 0; j < AllServers[ip].runningScripts.length; j++) { + if (AllServers[ip].runningScripts[j] == name) { + AllServers[i].runningScripts.splice(j, 1); + break; + } + } + + //Delete script from workerScripts + workerScripts.splice(i, 1); } } diff --git a/src/Terminal.js b/src/Terminal.js index d8a0a5334..e3c460528 100644 --- a/src/Terminal.js +++ b/src/Terminal.js @@ -221,9 +221,9 @@ var Terminal = { break; case "free": if (commandArray.length != 1) { - post("Incorrect usage of df command. Usage: df"); return; + post("Incorrect usage of free command. Usage: free"); return; } - console.log("df terminal command called"); + console.log("free terminal command called"); post("Total: " + Player.getCurrentServer().maxRam.toString() + " GB"); post("Used: " + Player.getCurrentServer().ramUsed.toString() + " GB"); post("Available: " + (Player.getCurrentServer().maxRam - Player.getCurrentServer().ramUsed).toString() + " GB"); @@ -359,7 +359,12 @@ var Terminal = { } break; case "ps": - //TODO + if (commandArray.length != 1) { + post("Incorrect usage of ps command. Usage: ps"); + } + for (var i = 0; i < Player.getCurrentServer().runningScripts.length; i++) { + post(Player.getCurrentServer().runningScripts[i]); + } break; case "rm": //TODO diff --git a/src/engine.js b/src/engine.js index 648dc5421..87f9b7678 100644 --- a/src/engine.js +++ b/src/engine.js @@ -1,6 +1,3 @@ -//TODO Saving only works with stirngs.key value pairs. Think of a system to do saves -// And everything with all the things I have - //Replaces the character at an index with a new character String.prototype.replaceAt=function(index, character) { return this.substr(0, index) + character + this.substr(index+character.length); diff --git a/utils/JSONReviver.js b/utils/JSONReviver.js index 1aff041b1..18e504c50 100644 --- a/utils/JSONReviver.js +++ b/utils/JSONReviver.js @@ -36,7 +36,6 @@ Reviver.constructors = {}; // A list of constructors the smart reviver should kn function Generic_toJSON(ctorName, obj, keys) { var data, index, key; - console.log("Generic_toJSON() called"); if (!keys) { keys = Object.keys(obj); // Only "own" properties are included }