mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-26 17:43:48 +01:00
Fix/Unify NS1 wrapper
This commit is contained in:
parent
3ee55b2918
commit
6f36e9cdc5
@ -702,7 +702,7 @@ const base: InternalAPI<NS> = {
|
|||||||
throw helpers.makeRuntimeErrorMsg(ctx, "Could not find server. This is a bug. Report to dev.");
|
throw helpers.makeRuntimeErrorMsg(ctx, "Could not find server. This is a bug. Report to dev.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return runScriptFromScript(Player, "run", scriptServer, scriptname, args, ctx.workerScript, threads);
|
return runScriptFromScript("run", scriptServer, scriptname, args, ctx.workerScript, threads);
|
||||||
},
|
},
|
||||||
exec:
|
exec:
|
||||||
(ctx: NetscriptContext) =>
|
(ctx: NetscriptContext) =>
|
||||||
@ -718,7 +718,7 @@ const base: InternalAPI<NS> = {
|
|||||||
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid thread count. Must be numeric and > 0, is ${threads}`);
|
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid thread count. Must be numeric and > 0, is ${threads}`);
|
||||||
}
|
}
|
||||||
const server = helpers.getServer(ctx, hostname);
|
const server = helpers.getServer(ctx, hostname);
|
||||||
return runScriptFromScript(Player, "exec", server, scriptname, args, ctx.workerScript, threads);
|
return runScriptFromScript("exec", server, scriptname, args, ctx.workerScript, threads);
|
||||||
},
|
},
|
||||||
spawn:
|
spawn:
|
||||||
(ctx: NetscriptContext) =>
|
(ctx: NetscriptContext) =>
|
||||||
@ -740,7 +740,7 @@ const base: InternalAPI<NS> = {
|
|||||||
throw helpers.makeRuntimeErrorMsg(ctx, "Could not find server. This is a bug. Report to dev");
|
throw helpers.makeRuntimeErrorMsg(ctx, "Could not find server. This is a bug. Report to dev");
|
||||||
}
|
}
|
||||||
|
|
||||||
return runScriptFromScript(Player, "spawn", scriptServer, scriptname, args, ctx.workerScript, threads);
|
return runScriptFromScript("spawn", scriptServer, scriptname, args, ctx.workerScript, threads);
|
||||||
}, spawnDelay * 1e3);
|
}, spawnDelay * 1e3);
|
||||||
|
|
||||||
helpers.log(ctx, () => `Will execute '${scriptname}' in ${spawnDelay} seconds`);
|
helpers.log(ctx, () => `Will execute '${scriptname}' in ${spawnDelay} seconds`);
|
||||||
|
@ -92,7 +92,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
|||||||
}
|
}
|
||||||
const runningScriptObj = new RunningScript(script, []); // No args
|
const runningScriptObj = new RunningScript(script, []); // No args
|
||||||
runningScriptObj.threads = 1; // Only 1 thread
|
runningScriptObj.threads = 1; // Only 1 thread
|
||||||
startWorkerScript(player, runningScriptObj, home);
|
startWorkerScript(runningScriptObj, home);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -34,10 +34,8 @@ import { simple as walksimple } from "acorn-walk";
|
|||||||
import { areFilesEqual } from "./Terminal/DirectoryHelpers";
|
import { areFilesEqual } from "./Terminal/DirectoryHelpers";
|
||||||
import { Player } from "./Player";
|
import { Player } from "./Player";
|
||||||
import { Terminal } from "./Terminal";
|
import { Terminal } from "./Terminal";
|
||||||
import { IPlayer } from "./PersonObjects/IPlayer";
|
|
||||||
import { ScriptArg } from "./Netscript/ScriptArg";
|
import { ScriptArg } from "./Netscript/ScriptArg";
|
||||||
import { helpers } from "./Netscript/NetscriptHelpers";
|
import { helpers } from "./Netscript/NetscriptHelpers";
|
||||||
import { NS } from "./ScriptEditor/NetscriptDefinitions";
|
|
||||||
|
|
||||||
// Netscript Ports are instantiated here
|
// Netscript Ports are instantiated here
|
||||||
export const NetscriptPorts: IPort[] = [];
|
export const NetscriptPorts: IPort[] = [];
|
||||||
@ -61,10 +59,10 @@ export function prestigeWorkerScripts(): void {
|
|||||||
// JS script promises need a little massaging to have the same guarantees as netscript
|
// JS script promises need a little massaging to have the same guarantees as netscript
|
||||||
// promises. This does said massaging and kicks the script off. It returns a promise
|
// promises. This does said massaging and kicks the script off. It returns a promise
|
||||||
// that resolves or rejects when the corresponding worker script is done.
|
// that resolves or rejects when the corresponding worker script is done.
|
||||||
function startNetscript2Script(player: IPlayer, workerScript: WorkerScript): Promise<void> {
|
function startNetscript2Script(workerScript: WorkerScript): Promise<void> {
|
||||||
workerScript.running = true;
|
workerScript.running = true;
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
executeJSScript(player, workerScript.getServer().scripts, workerScript)
|
executeJSScript(Player, workerScript.getServer().scripts, workerScript)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
@ -114,43 +112,27 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<void> {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
const interpreterInitialization = function (int: Interpreter, scope: unknown): void {
|
function wrapNS1Layer(int: Interpreter, intLayer: unknown, path: string[] = []) {
|
||||||
interface NS1 extends NS {
|
//TODO: Better typing layers of interpreter scope and ns
|
||||||
|
interface BasicObject {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
//Add the Netscript environment
|
const nsLayer = path.reduce((prev, newPath) => prev[newPath], workerScript.env.vars as BasicObject);
|
||||||
const ns = NetscriptFunctions(workerScript) as NS1;
|
for (const [name, entry] of Object.entries(nsLayer)) {
|
||||||
for (const name of Object.keys(ns)) {
|
|
||||||
const entry = ns[name];
|
|
||||||
if (typeof entry === "function") {
|
if (typeof entry === "function") {
|
||||||
// Async functions need to be wrapped. See JS-Interpreter documentation
|
// Async functions need to be wrapped. See JS-Interpreter documentation
|
||||||
const asyncFuncs = ["hack", "grow", "weaken", "sleep", "prompt", "manualHack", "share", "wget"];
|
const wrapper = async (...args: unknown[]) => {
|
||||||
|
// This async wrapper is sent a resolver function as an extra arg.
|
||||||
if (asyncFuncs.includes(name)) {
|
// See JSInterpreter.js:3209
|
||||||
const tempWrapper = function (...args: unknown[]): void {
|
try {
|
||||||
const fnArgs = [];
|
const callback = args.pop() as (value: unknown) => void;
|
||||||
|
const result = await entry(...args.map(int.pseudoToNative));
|
||||||
//All of the Object/array elements are in JSInterpreter format, so
|
return callback(int.nativeToPseudo(result));
|
||||||
//we have to convert them back to native format to pass them to these fns
|
} catch (e: unknown) {
|
||||||
for (let i = 0; i < args.length - 1; ++i) {
|
// TODO: Unify error handling, this was stolen from previous async handler
|
||||||
if (typeof args[i] === "object" || Array.isArray(args[i])) {
|
if (typeof e === "string") {
|
||||||
fnArgs.push(int.pseudoToNative(args[i]));
|
console.error(e);
|
||||||
} else {
|
const errorTextArray = e.split("|DELIMITER|");
|
||||||
fnArgs.push(args[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const callb = args[args.length - 1];
|
|
||||||
const fnPromise = entry(...fnArgs);
|
|
||||||
fnPromise
|
|
||||||
.then(function (res: unknown) {
|
|
||||||
if (typeof callb === "function") {
|
|
||||||
callb(res);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(function (err: unknown) {
|
|
||||||
if (typeof err === "string") {
|
|
||||||
console.error(err);
|
|
||||||
const errorTextArray = err.split("|DELIMITER|");
|
|
||||||
const hostname = errorTextArray[1];
|
const hostname = errorTextArray[1];
|
||||||
const scriptName = errorTextArray[2];
|
const scriptName = errorTextArray[2];
|
||||||
const errorMsg = errorTextArray[3];
|
const errorMsg = errorTextArray[3];
|
||||||
@ -161,64 +143,25 @@ function startNetscript1Script(workerScript: WorkerScript): Promise<void> {
|
|||||||
workerScript.env.stopFlag = true;
|
workerScript.env.stopFlag = true;
|
||||||
workerScript.running = false;
|
workerScript.running = false;
|
||||||
killWorkerScript(workerScript);
|
killWorkerScript(workerScript);
|
||||||
return Promise.resolve();
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
|
||||||
int.setProperty(scope, name, int.createAsyncFunction(tempWrapper));
|
|
||||||
} else if (
|
|
||||||
name === "sprintf" ||
|
|
||||||
name === "vsprintf" ||
|
|
||||||
name === "scp" ||
|
|
||||||
name == "write" ||
|
|
||||||
name === "tryWritePort" ||
|
|
||||||
name === "run" ||
|
|
||||||
name === "exec"
|
|
||||||
) {
|
|
||||||
const tempWrapper = function (...args: unknown[]): void {
|
|
||||||
const fnArgs = [];
|
|
||||||
|
|
||||||
//All of the Object/array elements are in JSInterpreter format, so
|
|
||||||
//we have to convert them back to native format to pass them to these fns
|
|
||||||
for (let i = 0; i < args.length; ++i) {
|
|
||||||
if (typeof args[i] === "object" || Array.isArray(args[i])) {
|
|
||||||
fnArgs.push(int.pseudoToNative(args[i]));
|
|
||||||
} else {
|
|
||||||
fnArgs.push(args[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry(...fnArgs);
|
|
||||||
};
|
|
||||||
int.setProperty(scope, name, int.createNativeFunction(tempWrapper));
|
|
||||||
} else {
|
|
||||||
const tempWrapper = function (...args: unknown[]): unknown {
|
|
||||||
const res = entry(...args);
|
|
||||||
|
|
||||||
if (res == null) {
|
|
||||||
return res;
|
|
||||||
} else if (res.constructor === Array || res === Object(res)) {
|
|
||||||
//Objects and Arrays must be converted to the interpreter's format
|
|
||||||
return int.nativeToPseudo(res);
|
|
||||||
} else {
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
int.setProperty(scope, name, int.createNativeFunction(tempWrapper));
|
int.setProperty(intLayer, name, int.createAsyncFunction(wrapper));
|
||||||
}
|
} else if (Array.isArray(entry) || typeof entry !== "object"){
|
||||||
|
// args, strings on enums, etc
|
||||||
|
int.setProperty(intLayer, name, int.nativeToPseudo(entry));
|
||||||
} else {
|
} else {
|
||||||
//bladeburner, or anything else
|
// new object layer, e.g. bladeburner
|
||||||
int.setProperty(scope, name, int.nativeToPseudo(entry));
|
int.setProperty(intLayer, name, int.nativeToPseudo({}));
|
||||||
|
wrapNS1Layer(int, (intLayer as BasicObject).properties[name], [...path, name]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add the arguments
|
|
||||||
int.setProperty(scope, "args", int.nativeToPseudo(workerScript.args));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let interpreter: Interpreter;
|
let interpreter: Interpreter;
|
||||||
try {
|
try {
|
||||||
interpreter = new Interpreter(codeWithImports, interpreterInitialization, codeLineOffset);
|
interpreter = new Interpreter(codeWithImports, wrapNS1Layer, codeLineOffset);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
dialogBoxCreate("Syntax ERROR in " + workerScript.name + ":<br>" + String(e));
|
dialogBoxCreate("Syntax ERROR in " + workerScript.name + ":<br>" + String(e));
|
||||||
workerScript.env.stopFlag = true;
|
workerScript.env.stopFlag = true;
|
||||||
@ -422,12 +365,11 @@ function processNetscript1Imports(code: string, workerScript: WorkerScript): { c
|
|||||||
* it is active
|
* it is active
|
||||||
*/
|
*/
|
||||||
export function startWorkerScript(
|
export function startWorkerScript(
|
||||||
player: IPlayer,
|
|
||||||
runningScript: RunningScript,
|
runningScript: RunningScript,
|
||||||
server: BaseServer,
|
server: BaseServer,
|
||||||
parent?: WorkerScript,
|
parent?: WorkerScript,
|
||||||
): number {
|
): number {
|
||||||
if (createAndAddWorkerScript(player, runningScript, server, parent)) {
|
if (createAndAddWorkerScript(runningScript, server, parent)) {
|
||||||
// Push onto runningScripts.
|
// Push onto runningScripts.
|
||||||
// This has to come after createAndAddWorkerScript() because that fn updates RAM usage
|
// This has to come after createAndAddWorkerScript() because that fn updates RAM usage
|
||||||
server.runScript(runningScript);
|
server.runScript(runningScript);
|
||||||
@ -448,7 +390,6 @@ export function startWorkerScript(
|
|||||||
* returns {boolean} indicating whether or not the workerScript was successfully added
|
* returns {boolean} indicating whether or not the workerScript was successfully added
|
||||||
*/
|
*/
|
||||||
function createAndAddWorkerScript(
|
function createAndAddWorkerScript(
|
||||||
player: IPlayer,
|
|
||||||
runningScriptObj: RunningScript,
|
runningScriptObj: RunningScript,
|
||||||
server: BaseServer,
|
server: BaseServer,
|
||||||
parent?: WorkerScript,
|
parent?: WorkerScript,
|
||||||
@ -496,7 +437,7 @@ function createAndAddWorkerScript(
|
|||||||
// Start the script's execution
|
// Start the script's execution
|
||||||
let scriptExecution: Promise<void> | null = null; // Script's resulting promise
|
let scriptExecution: Promise<void> | null = null; // Script's resulting promise
|
||||||
if (workerScript.name.endsWith(".js")) {
|
if (workerScript.name.endsWith(".js")) {
|
||||||
scriptExecution = startNetscript2Script(player, workerScript);
|
scriptExecution = startNetscript2Script(workerScript);
|
||||||
} else {
|
} else {
|
||||||
scriptExecution = startNetscript1Script(workerScript);
|
scriptExecution = startNetscript1Script(workerScript);
|
||||||
if (!(scriptExecution instanceof Promise)) {
|
if (!(scriptExecution instanceof Promise)) {
|
||||||
@ -583,7 +524,7 @@ export function updateOnlineScriptTimes(numCycles = 1): void {
|
|||||||
* 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
|
||||||
*/
|
*/
|
||||||
export function loadAllRunningScripts(player: IPlayer): void {
|
export function loadAllRunningScripts(): void {
|
||||||
const skipScriptLoad = window.location.href.toLowerCase().indexOf("?noscripts") !== -1;
|
const skipScriptLoad = window.location.href.toLowerCase().indexOf("?noscripts") !== -1;
|
||||||
if (skipScriptLoad) {
|
if (skipScriptLoad) {
|
||||||
Terminal.warn("Skipped loading player scripts during startup");
|
Terminal.warn("Skipped loading player scripts during startup");
|
||||||
@ -604,7 +545,7 @@ export function loadAllRunningScripts(player: IPlayer): void {
|
|||||||
} else {
|
} else {
|
||||||
for (let j = 0; j < server.runningScripts.length; ++j) {
|
for (let j = 0; j < server.runningScripts.length; ++j) {
|
||||||
const fileName = server.runningScripts[j].filename;
|
const fileName = server.runningScripts[j].filename;
|
||||||
createAndAddWorkerScript(player, server.runningScripts[j], server);
|
createAndAddWorkerScript(server.runningScripts[j], server);
|
||||||
|
|
||||||
if (!server.runningScripts[j]) {
|
if (!server.runningScripts[j]) {
|
||||||
// createAndAddWorkerScript can modify the server.runningScripts array if a script is invalid
|
// createAndAddWorkerScript can modify the server.runningScripts array if a script is invalid
|
||||||
@ -623,7 +564,6 @@ export function loadAllRunningScripts(player: IPlayer): void {
|
|||||||
* Run a script from inside another script (run(), exec(), spawn(), etc.)
|
* Run a script from inside another script (run(), exec(), spawn(), etc.)
|
||||||
*/
|
*/
|
||||||
export function runScriptFromScript(
|
export function runScriptFromScript(
|
||||||
player: IPlayer,
|
|
||||||
caller: string,
|
caller: string,
|
||||||
server: BaseServer,
|
server: BaseServer,
|
||||||
scriptname: string,
|
scriptname: string,
|
||||||
@ -698,7 +638,7 @@ export function runScriptFromScript(
|
|||||||
runningScriptObj.threads = threads;
|
runningScriptObj.threads = threads;
|
||||||
runningScriptObj.server = server.hostname;
|
runningScriptObj.server = server.hostname;
|
||||||
|
|
||||||
return startWorkerScript(player, runningScriptObj, server, workerScript);
|
return startWorkerScript(runningScriptObj, server, workerScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
workerScript.log(caller, () => `Could not find script '${scriptname}' on '${server.hostname}'`);
|
workerScript.log(caller, () => `Could not find script '${scriptname}' on '${server.hostname}'`);
|
||||||
|
@ -76,7 +76,7 @@ export function runScript(
|
|||||||
const runningScript = new RunningScript(script, args);
|
const runningScript = new RunningScript(script, args);
|
||||||
runningScript.threads = numThreads;
|
runningScript.threads = numThreads;
|
||||||
|
|
||||||
const success = startWorkerScript(player, runningScript, server);
|
const success = startWorkerScript(runningScript, server);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
terminal.error(`Failed to start script`);
|
terminal.error(`Failed to start script`);
|
||||||
return;
|
return;
|
||||||
|
@ -278,7 +278,7 @@ const Engine: {
|
|||||||
Player.gainMoney(offlineHackingIncome, "hacking");
|
Player.gainMoney(offlineHackingIncome, "hacking");
|
||||||
// Process offline progress
|
// Process offline progress
|
||||||
|
|
||||||
loadAllRunningScripts(Player); // This also takes care of offline production for those scripts
|
loadAllRunningScripts(); // This also takes care of offline production for those scripts
|
||||||
|
|
||||||
if (Player.currentWork !== null) {
|
if (Player.currentWork !== null) {
|
||||||
Player.focus = true;
|
Player.focus = true;
|
||||||
|
@ -159,7 +159,7 @@ function LogWindow(props: IProps): React.ReactElement {
|
|||||||
if (server === null) return;
|
if (server === null) return;
|
||||||
const s = findRunningScript(script.filename, script.args, server);
|
const s = findRunningScript(script.filename, script.args, server);
|
||||||
if (s === null) {
|
if (s === null) {
|
||||||
startWorkerScript(Player, script, server);
|
startWorkerScript(script, server);
|
||||||
} else {
|
} else {
|
||||||
setScript(s);
|
setScript(s);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user