diff --git a/markdown/bitburner.ns.spawn.md b/markdown/bitburner.ns.spawn.md index eb5cf9c66..732a58ced 100644 --- a/markdown/bitburner.ns.spawn.md +++ b/markdown/bitburner.ns.spawn.md @@ -30,6 +30,8 @@ RAM cost: 2 GB Terminates the current script, and then after a defined delay it will execute the newly-specified script. The purpose of this function is to execute a new script without being constrained by the RAM usage of the current one. This function can only be used to run scripts on the local server. +The delay specified can be 0; in this case the new script will synchronously replace the old one. (There will not be any opportunity for other scripts to use up the RAM in-between.) + Because this function immediately terminates the script, it does not have a return value. Running this function with 0 or fewer threads will cause a runtime error. diff --git a/markdown/bitburner.spawnoptions.md b/markdown/bitburner.spawnoptions.md index 4eded037d..4c0bd4f05 100644 --- a/markdown/bitburner.spawnoptions.md +++ b/markdown/bitburner.spawnoptions.md @@ -16,5 +16,5 @@ interface SpawnOptions extends RunOptions | Property | Modifiers | Type | Description | | --- | --- | --- | --- | -| [spawnDelay?](./bitburner.spawnoptions.spawndelay.md) | | number | _(Optional)_ Number of milliseconds to delay before spawning script, defaults to 10000 (10s). Must be a positive integer. | +| [spawnDelay?](./bitburner.spawnoptions.spawndelay.md) | | number | _(Optional)_ Number of milliseconds to delay before spawning script, defaults to 10000 (10s). Must be a non-negative integer. If 0, the script will be spawned synchronously. | diff --git a/markdown/bitburner.spawnoptions.spawndelay.md b/markdown/bitburner.spawnoptions.spawndelay.md index a3b86bc46..3caa6cda6 100644 --- a/markdown/bitburner.spawnoptions.spawndelay.md +++ b/markdown/bitburner.spawnoptions.spawndelay.md @@ -4,7 +4,7 @@ ## SpawnOptions.spawnDelay property -Number of milliseconds to delay before spawning script, defaults to 10000 (10s). Must be a positive integer. +Number of milliseconds to delay before spawning script, defaults to 10000 (10s). Must be a non-negative integer. If 0, the script will be spawned synchronously. **Signature:** diff --git a/src/Netscript/NetscriptHelpers.tsx b/src/Netscript/NetscriptHelpers.tsx index b44352d8a..a985e3757 100644 --- a/src/Netscript/NetscriptHelpers.tsx +++ b/src/Netscript/NetscriptHelpers.tsx @@ -93,7 +93,7 @@ export interface CompleteRunOptions { } /** SpawnOptions with non-optional, type-validated members, for passing between internal functions. */ export interface CompleteSpawnOptions extends CompleteRunOptions { - spawnDelay: PositiveInteger; + spawnDelay: number; } /** HGWOptions with non-optional, type-validated members, for passing between internal functions. */ export interface CompleteHGWOptions { @@ -189,11 +189,16 @@ function runOptions(ctx: NetscriptContext, threadOrOption: unknown): CompleteRun } function spawnOptions(ctx: NetscriptContext, threadOrOption: unknown): CompleteSpawnOptions { - const result: CompleteSpawnOptions = { spawnDelay: 10000 as PositiveInteger, ...runOptions(ctx, threadOrOption) }; + const result: CompleteSpawnOptions = { spawnDelay: 10000, ...runOptions(ctx, threadOrOption) }; if (typeof threadOrOption !== "object" || !threadOrOption) return result; // Safe assertion since threadOrOption type has been narrowed to a non-null object const { spawnDelay } = threadOrOption as Unknownify; - if (spawnDelay !== undefined) result.spawnDelay = positiveInteger(ctx, "spawnDelayMsec", spawnDelay); + if (spawnDelay !== undefined) { + result.spawnDelay = number(ctx, "spawnDelay", spawnDelay); + if (result.spawnDelay < 0) { + throw errorMessage(ctx, `spawnDelay must be non-negative, got ${spawnDelay}`); + } + } return result; } diff --git a/src/NetscriptFunctions.ts b/src/NetscriptFunctions.ts index e0b920de6..faaa3ba63 100644 --- a/src/NetscriptFunctions.ts +++ b/src/NetscriptFunctions.ts @@ -737,23 +737,36 @@ export const ns: InternalAPI = { const path = helpers.scriptPath(ctx, "scriptname", _scriptname); const runOpts = helpers.spawnOptions(ctx, _thread_or_opt); const args = helpers.scriptArgs(ctx, _args); - setTimeout(() => { + const spawnCb = () => { if (Router.page() === Page.BitVerse) { helpers.log(ctx, () => `Script execution is canceled because you are in Bitverse.`); return; } const scriptServer = GetServer(ctx.workerScript.hostname); - if (scriptServer === null) { + if (scriptServer == null) { throw helpers.errorMessage(ctx, `Cannot find server ${ctx.workerScript.hostname}`); } - runScriptFromScript("spawn", scriptServer, path, args, ctx.workerScript, runOpts); - }, runOpts.spawnDelay); + return runScriptFromScript("spawn", scriptServer, path, args, ctx.workerScript, runOpts); + }; - helpers.log(ctx, () => `Will execute '${path}' in ${runOpts.spawnDelay} milliseconds`); + if (runOpts.spawnDelay !== 0) { + setTimeout(spawnCb, runOpts.spawnDelay); + helpers.log(ctx, () => `Will execute '${path}' in ${runOpts.spawnDelay} milliseconds`); + } - if (killWorkerScript(ctx.workerScript)) { - helpers.log(ctx, () => "Exiting..."); + helpers.log(ctx, () => "About to exit..."); + const killed = killWorkerScript(ctx.workerScript); + + if (runOpts.spawnDelay === 0) { + helpers.log(ctx, () => `Executing '${path}' immediately`); + spawnCb(); + } + + if (killed) { + // This prevents error messages about statements after the spawn() + // trying to be executed when the script is dead. + throw new ScriptDeath(ctx.workerScript); } }, kill: diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 4b5f52e94..4e0e5960e 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -283,7 +283,10 @@ interface RunOptions { /** @public */ interface SpawnOptions extends RunOptions { - /** Number of milliseconds to delay before spawning script, defaults to 10000 (10s). Must be a positive integer. */ + /** + * Number of milliseconds to delay before spawning script, defaults to 10000 (10s). + * Must be a non-negative integer. If 0, the script will be spawned synchronously. + */ spawnDelay?: number; } @@ -6261,6 +6264,9 @@ export interface NS { * constrained by the RAM usage of the current one. This function can only be used to run scripts * on the local server. * + * The delay specified can be 0; in this case the new script will synchronously replace + * the old one. (There will not be any opportunity for other scripts to use up the RAM in-between.) + * * Because this function immediately terminates the script, it does not have a return value. * * Running this function with 0 or fewer threads will cause a runtime error.