mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-19 12:45:45 +01:00
NETSCRIPT: Add ramOverride as a RunOption (#441)
Allows overriding the static ram calculation. Dynamic ram limit still applies.
This commit is contained in:
parent
a03a441906
commit
2b54c6c9b9
@ -15,6 +15,7 @@ interface RunOptions
|
|||||||
|
|
||||||
| Property | Modifiers | Type | Description |
|
| Property | Modifiers | Type | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
|
| [ramOverride?](./bitburner.runoptions.ramoverride.md) | | number | <p>_(Optional)_ The RAM allocation to launch each thread of the script with.</p><p>Lowering this will <i>not</i> automatically let you get away with using less RAM: the dynamic RAM check enforces that all [NS](./bitburner.ns.md) functions actually called incur their cost. However, if you know that certain functions that are statically present (and thus included in the static RAM cost) will never be called in a particular circumstance, you can use this to avoid paying for them.</p><p>You can also use this to <i>increase</i> the RAM if the static RAM checker has missed functions that you need to call.</p><p>Must be greater-or-equal to the base RAM cost. Defaults to the statically calculated cost.</p> |
|
||||||
| [temporary?](./bitburner.runoptions.temporary.md) | | boolean | _(Optional)_ Whether this script is excluded from saves, defaults to false |
|
| [temporary?](./bitburner.runoptions.temporary.md) | | boolean | _(Optional)_ Whether this script is excluded from saves, defaults to false |
|
||||||
| [threads?](./bitburner.runoptions.threads.md) | | number | _(Optional)_ Number of threads that the script will run with, defaults to 1 |
|
| [threads?](./bitburner.runoptions.threads.md) | | number | _(Optional)_ Number of threads that the script will run with, defaults to 1 |
|
||||||
|
|
||||||
|
19
markdown/bitburner.runoptions.ramoverride.md
Normal file
19
markdown/bitburner.runoptions.ramoverride.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [bitburner](./bitburner.md) > [RunOptions](./bitburner.runoptions.md) > [ramOverride](./bitburner.runoptions.ramoverride.md)
|
||||||
|
|
||||||
|
## RunOptions.ramOverride property
|
||||||
|
|
||||||
|
The RAM allocation to launch each thread of the script with.
|
||||||
|
|
||||||
|
Lowering this will <i>not</i> automatically let you get away with using less RAM: the dynamic RAM check enforces that all [NS](./bitburner.ns.md) functions actually called incur their cost. However, if you know that certain functions that are statically present (and thus included in the static RAM cost) will never be called in a particular circumstance, you can use this to avoid paying for them.
|
||||||
|
|
||||||
|
You can also use this to <i>increase</i> the RAM if the static RAM checker has missed functions that you need to call.
|
||||||
|
|
||||||
|
Must be greater-or-equal to the base RAM cost. Defaults to the statically calculated cost.
|
||||||
|
|
||||||
|
**Signature:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
ramOverride?: number;
|
||||||
|
```
|
@ -6,7 +6,7 @@ import { ScriptDeath } from "./ScriptDeath";
|
|||||||
import { formatExp, formatMoney, formatRam, formatThreads } from "../ui/formatNumber";
|
import { formatExp, formatMoney, formatRam, formatThreads } from "../ui/formatNumber";
|
||||||
import { ScriptArg } from "./ScriptArg";
|
import { ScriptArg } from "./ScriptArg";
|
||||||
import { CityName } from "../Enums";
|
import { CityName } from "../Enums";
|
||||||
import { BasicHGWOptions, RunOptions, RunningScript as IRunningScript, Person as IPerson } from "@nsdefs";
|
import { BasicHGWOptions, RunningScript as IRunningScript, Person as IPerson } from "@nsdefs";
|
||||||
import { Server } from "../Server/Server";
|
import { Server } from "../Server/Server";
|
||||||
import {
|
import {
|
||||||
calculateHackingChance,
|
calculateHackingChance,
|
||||||
@ -33,7 +33,7 @@ import { BaseServer } from "../Server/BaseServer";
|
|||||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||||
import { checkEnum } from "../utils/helpers/enum";
|
import { checkEnum } from "../utils/helpers/enum";
|
||||||
import { RamCostConstants } from "./RamCostGenerator";
|
import { RamCostConstants } from "./RamCostGenerator";
|
||||||
import { isPositiveInteger, PositiveInteger } from "../types";
|
import { isPositiveInteger, PositiveInteger, Unknownify } from "../types";
|
||||||
import { Engine } from "../engine";
|
import { Engine } from "../engine";
|
||||||
|
|
||||||
export const helpers = {
|
export const helpers = {
|
||||||
@ -72,6 +72,7 @@ export const helpers = {
|
|||||||
export interface CompleteRunOptions {
|
export interface CompleteRunOptions {
|
||||||
threads: PositiveInteger;
|
threads: PositiveInteger;
|
||||||
temporary: boolean;
|
temporary: boolean;
|
||||||
|
ramOverride?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assertMember<T extends string>(
|
export function assertMember<T extends string>(
|
||||||
@ -181,21 +182,23 @@ function scriptArgs(ctx: NetscriptContext, args: unknown) {
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
function runOptions(ctx: NetscriptContext, thread_or_opt: unknown): CompleteRunOptions {
|
function runOptions(ctx: NetscriptContext, threadOrOption: unknown): CompleteRunOptions {
|
||||||
let threads: any = 1;
|
if (typeof threadOrOption !== "object" || threadOrOption === null) {
|
||||||
let temporary: any = false;
|
return { threads: positiveInteger(ctx, "threads", threadOrOption ?? 1), temporary: false };
|
||||||
if (typeof thread_or_opt !== "object" || thread_or_opt === null) {
|
|
||||||
threads = thread_or_opt ?? 1;
|
|
||||||
} else {
|
|
||||||
// Lie and pretend it's a RunOptions. It could be anything, we'll deal with that below.
|
|
||||||
const options = thread_or_opt as RunOptions;
|
|
||||||
threads = options.threads ?? 1;
|
|
||||||
temporary = options.temporary ?? false;
|
|
||||||
}
|
}
|
||||||
return {
|
// Safe assertion since threadOrOption type has been narrowed to a non-null object
|
||||||
threads: positiveInteger(ctx, "thread", threads),
|
const options = threadOrOption as Unknownify<CompleteRunOptions>;
|
||||||
temporary: !!temporary,
|
const threads = positiveInteger(ctx, "RunOptions.threads", options.threads ?? 1);
|
||||||
};
|
const temporary = !!options.temporary;
|
||||||
|
if (options.ramOverride === undefined || options.ramOverride === null) return { threads, temporary };
|
||||||
|
const ramOverride = number(ctx, "RunOptions.ramOverride", options.ramOverride);
|
||||||
|
if (ramOverride < RamCostConstants.Base) {
|
||||||
|
throw makeRuntimeErrorMsg(
|
||||||
|
ctx,
|
||||||
|
`RunOptions.ramOverride must be >= baseCost (${RamCostConstants.Base}), was ${ramOverride}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return { threads, temporary, ramOverride };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Convert multiple arguments for tprint or print into a single string. */
|
/** Convert multiple arguments for tprint or print into a single string. */
|
||||||
@ -375,17 +378,17 @@ function updateDynamicRam(ctx: NetscriptContext, ramCost: number): void {
|
|||||||
ws.dynamicLoadedFns[fnName] = true;
|
ws.dynamicLoadedFns[fnName] = true;
|
||||||
|
|
||||||
ws.dynamicRamUsage = Math.min(ws.dynamicRamUsage + ramCost, RamCostConstants.Max);
|
ws.dynamicRamUsage = Math.min(ws.dynamicRamUsage + ramCost, RamCostConstants.Max);
|
||||||
if (ws.dynamicRamUsage > 1.01 * ws.ramUsage) {
|
if (ws.dynamicRamUsage > 1.01 * ws.scriptRef.ramUsage) {
|
||||||
log(ctx, () => "Insufficient static ram available.");
|
log(ctx, () => "Insufficient static ram available.");
|
||||||
ws.env.stopFlag = true;
|
ws.env.stopFlag = true;
|
||||||
throw makeRuntimeErrorMsg(
|
throw makeRuntimeErrorMsg(
|
||||||
ctx,
|
ctx,
|
||||||
`Dynamic RAM usage calculated to be greater than initial RAM usage.
|
`Dynamic RAM usage calculated to be greater than RAM allocation.
|
||||||
This is probably because you somehow circumvented the static RAM calculation.
|
This is probably because you somehow circumvented the static RAM calculation.
|
||||||
|
|
||||||
Threads: ${ws.scriptRef.threads}
|
Threads: ${ws.scriptRef.threads}
|
||||||
Dynamic RAM Usage: ${formatRam(ws.dynamicRamUsage)} per thread
|
Dynamic RAM Usage: ${formatRam(ws.dynamicRamUsage)} per thread
|
||||||
Static RAM Usage: ${formatRam(ws.ramUsage)} per thread
|
RAM Allocation: ${formatRam(ws.scriptRef.ramUsage)} per thread
|
||||||
|
|
||||||
One of these could be the reason:
|
One of these could be the reason:
|
||||||
* Using eval() to get a reference to a ns function
|
* Using eval() to get a reference to a ns function
|
||||||
@ -394,6 +397,8 @@ function updateDynamicRam(ctx: NetscriptContext, ramCost: number): void {
|
|||||||
* Using map access to do the same
|
* Using map access to do the same
|
||||||
\u00a0\u00a0const myScan = ns['scan'];
|
\u00a0\u00a0const myScan = ns['scan'];
|
||||||
|
|
||||||
|
* Using RunOptions.ramOverride to set a smaller allocation than needed
|
||||||
|
|
||||||
Sorry :(`,
|
Sorry :(`,
|
||||||
"RAM USAGE",
|
"RAM USAGE",
|
||||||
);
|
);
|
||||||
@ -651,11 +656,10 @@ function log(ctx: NetscriptContext, message: () => string) {
|
|||||||
/**
|
/**
|
||||||
* Searches for and returns the RunningScript object for the specified script.
|
* Searches for and returns the RunningScript object for the specified script.
|
||||||
* If the 'fn' argument is not specified, this returns the current RunningScript.
|
* If the 'fn' argument is not specified, this returns the current RunningScript.
|
||||||
* @param {string} fn - Filename of script
|
* @param fn - Filename of script
|
||||||
* @param {string} hostname - Hostname/ip of the server on which the script resides
|
* @param hostname - Hostname/ip of the server on which the script resides
|
||||||
* @param {any[]} scriptArgs - Running script's arguments
|
* @param scriptArgs - Running script's arguments
|
||||||
* @returns {RunningScript}
|
* @returns Running script identified by the parameters, or null if no such script
|
||||||
* Running script identified by the parameters, or null if no such script
|
|
||||||
* exists, or the current running script if the first argument 'fn'
|
* exists, or the current running script if the first argument 'fn'
|
||||||
* is not specified.
|
* is not specified.
|
||||||
*/
|
*/
|
||||||
@ -706,10 +710,8 @@ function getRunningScript(ctx: NetscriptContext, ident: ScriptIdentifier): Runni
|
|||||||
/**
|
/**
|
||||||
* Helper function for getting the error log message when the user specifies
|
* Helper function for getting the error log message when the user specifies
|
||||||
* a nonexistent running script
|
* a nonexistent running script
|
||||||
* @param {string} fn - Filename of script
|
* @param ident - Identifier (pid or identifier object) of script.
|
||||||
* @param {string} hostname - Hostname/ip of the server on which the script resides
|
* @returns Error message to print to logs
|
||||||
* @param {any[]} scriptArgs - Running script's arguments
|
|
||||||
* @returns {string} Error message to print to logs
|
|
||||||
*/
|
*/
|
||||||
function getCannotFindRunningScriptErrorMessage(ident: ScriptIdentifier): string {
|
function getCannotFindRunningScriptErrorMessage(ident: ScriptIdentifier): string {
|
||||||
if (typeof ident === "number") return `Cannot find running script with pid: ${ident}`;
|
if (typeof ident === "number") return `Cannot find running script with pid: ${ident}`;
|
||||||
|
@ -71,9 +71,6 @@ export class WorkerScript {
|
|||||||
*/
|
*/
|
||||||
pid: number;
|
pid: number;
|
||||||
|
|
||||||
/** Script's Static RAM usage. Equivalent to underlying script's RAM usage */
|
|
||||||
ramUsage = RamCostConstants.Base;
|
|
||||||
|
|
||||||
/** Reference to underlying RunningScript object */
|
/** Reference to underlying RunningScript object */
|
||||||
scriptRef: RunningScript;
|
scriptRef: RunningScript;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ export function NetscriptExtra(): InternalAPI<INetscriptExtra> {
|
|||||||
real_document.completely_unused_field = undefined;
|
real_document.completely_unused_field = undefined;
|
||||||
// set one to true and check that it affected the other.
|
// set one to true and check that it affected the other.
|
||||||
real_document.completely_unused_field = true;
|
real_document.completely_unused_field = true;
|
||||||
if (d.completely_unused_field && ctx.workerScript.ramUsage === RamCostConstants.Base) {
|
if (d.completely_unused_field && ctx.workerScript.scriptRef.ramUsage === RamCostConstants.Base) {
|
||||||
Player.giveExploit(Exploit.Bypass);
|
Player.giveExploit(Exploit.Bypass);
|
||||||
}
|
}
|
||||||
d.completely_unused_field = undefined;
|
d.completely_unused_field = undefined;
|
||||||
|
@ -54,7 +54,6 @@ async function startNetscript2Script(workerScript: WorkerScript): Promise<void>
|
|||||||
if (script === null) throw "workerScript had no associated script. This is a bug.";
|
if (script === null) throw "workerScript had no associated script. This is a bug.";
|
||||||
if (!script.ramUsage) throw "Attempting to start a script with no calculated ram cost. This is a bug.";
|
if (!script.ramUsage) throw "Attempting to start a script with no calculated ram cost. This is a bug.";
|
||||||
const loadedModule = await compile(script, scripts);
|
const loadedModule = await compile(script, scripts);
|
||||||
workerScript.ramUsage = script.ramUsage;
|
|
||||||
const ns = workerScript.env.vars;
|
const ns = workerScript.env.vars;
|
||||||
|
|
||||||
if (!loadedModule) throw `${script.filename} cannot be run because the script module won't load`;
|
if (!loadedModule) throw `${script.filename} cannot be run because the script module won't load`;
|
||||||
@ -319,7 +318,6 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS
|
|||||||
// Create the WorkerScript. NOTE: WorkerScript ctor will set the underlying
|
// Create the WorkerScript. NOTE: WorkerScript ctor will set the underlying
|
||||||
// RunningScript's PID as well
|
// RunningScript's PID as well
|
||||||
const workerScript = new WorkerScript(runningScriptObj, pid, NetscriptFunctions);
|
const workerScript = new WorkerScript(runningScriptObj, pid, NetscriptFunctions);
|
||||||
workerScript.ramUsage = runningScriptObj.ramUsage;
|
|
||||||
|
|
||||||
// Add the WorkerScript to the global pool
|
// Add the WorkerScript to the global pool
|
||||||
workerScripts.set(pid, workerScript);
|
workerScripts.set(pid, workerScript);
|
||||||
@ -420,7 +418,7 @@ export function runScriptFromScript(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const singleRamUsage = script.getRamUsage(host.scripts);
|
const singleRamUsage = runOpts.ramOverride ?? script.getRamUsage(host.scripts);
|
||||||
if (!singleRamUsage) {
|
if (!singleRamUsage) {
|
||||||
workerScript.log(caller, () => `Ram usage could not be calculated for ${scriptname}`);
|
workerScript.log(caller, () => `Ram usage could not be calculated for ${scriptname}`);
|
||||||
return 0;
|
return 0;
|
||||||
|
15
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
15
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -203,6 +203,21 @@ interface RunOptions {
|
|||||||
threads?: number;
|
threads?: number;
|
||||||
/** Whether this script is excluded from saves, defaults to false */
|
/** Whether this script is excluded from saves, defaults to false */
|
||||||
temporary?: boolean;
|
temporary?: boolean;
|
||||||
|
/**
|
||||||
|
* The RAM allocation to launch each thread of the script with.
|
||||||
|
*
|
||||||
|
* Lowering this will <i>not</i> automatically let you get away with using less RAM:
|
||||||
|
* the dynamic RAM check enforces that all {@link NS} functions actually called incur their cost.
|
||||||
|
* However, if you know that certain functions that are statically present (and thus included
|
||||||
|
* in the static RAM cost) will never be called in a particular circumstance, you can use
|
||||||
|
* this to avoid paying for them.
|
||||||
|
*
|
||||||
|
* You can also use this to <i>increase</i> the RAM if the static RAM checker has missed functions
|
||||||
|
* that you need to call.
|
||||||
|
*
|
||||||
|
* Must be greater-or-equal to the base RAM cost. Defaults to the statically calculated cost.
|
||||||
|
*/
|
||||||
|
ramOverride?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
|
@ -7,6 +7,12 @@ export type PositiveInteger = Integer & PositiveNumber;
|
|||||||
export const isInteger = (n: unknown): n is Integer => Number.isInteger(n);
|
export const isInteger = (n: unknown): n is Integer => Number.isInteger(n);
|
||||||
export const isPositiveInteger = (n: unknown): n is PositiveInteger => isInteger(n) && n > 0;
|
export const isPositiveInteger = (n: unknown): n is PositiveInteger => isInteger(n) && n > 0;
|
||||||
|
|
||||||
|
/** Utility type for typechecking objects. Makes all keys optional and sets values to unknown,
|
||||||
|
* making it safe to assert a shape for the variable once it's known to be a non-null object */
|
||||||
|
export type Unknownify<T> = {
|
||||||
|
[key in keyof T]?: unknown;
|
||||||
|
};
|
||||||
|
|
||||||
/** Status object for functions that return a boolean indicating success/failure
|
/** Status object for functions that return a boolean indicating success/failure
|
||||||
* and an optional message */
|
* and an optional message */
|
||||||
export interface IReturnStatus {
|
export interface IReturnStatus {
|
||||||
|
Loading…
Reference in New Issue
Block a user