mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-19 04:35:46 +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 |
|
||||
| --- | --- | --- | --- |
|
||||
| [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 |
|
||||
| [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 { ScriptArg } from "./ScriptArg";
|
||||
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 {
|
||||
calculateHackingChance,
|
||||
@ -33,7 +33,7 @@ import { BaseServer } from "../Server/BaseServer";
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
import { checkEnum } from "../utils/helpers/enum";
|
||||
import { RamCostConstants } from "./RamCostGenerator";
|
||||
import { isPositiveInteger, PositiveInteger } from "../types";
|
||||
import { isPositiveInteger, PositiveInteger, Unknownify } from "../types";
|
||||
import { Engine } from "../engine";
|
||||
|
||||
export const helpers = {
|
||||
@ -72,6 +72,7 @@ export const helpers = {
|
||||
export interface CompleteRunOptions {
|
||||
threads: PositiveInteger;
|
||||
temporary: boolean;
|
||||
ramOverride?: number;
|
||||
}
|
||||
|
||||
export function assertMember<T extends string>(
|
||||
@ -181,21 +182,23 @@ function scriptArgs(ctx: NetscriptContext, args: unknown) {
|
||||
return args;
|
||||
}
|
||||
|
||||
function runOptions(ctx: NetscriptContext, thread_or_opt: unknown): CompleteRunOptions {
|
||||
let threads: any = 1;
|
||||
let temporary: any = 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;
|
||||
function runOptions(ctx: NetscriptContext, threadOrOption: unknown): CompleteRunOptions {
|
||||
if (typeof threadOrOption !== "object" || threadOrOption === null) {
|
||||
return { threads: positiveInteger(ctx, "threads", threadOrOption ?? 1), temporary: false };
|
||||
}
|
||||
return {
|
||||
threads: positiveInteger(ctx, "thread", threads),
|
||||
temporary: !!temporary,
|
||||
};
|
||||
// Safe assertion since threadOrOption type has been narrowed to a non-null object
|
||||
const options = threadOrOption as Unknownify<CompleteRunOptions>;
|
||||
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. */
|
||||
@ -375,17 +378,17 @@ function updateDynamicRam(ctx: NetscriptContext, ramCost: number): void {
|
||||
ws.dynamicLoadedFns[fnName] = true;
|
||||
|
||||
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.");
|
||||
ws.env.stopFlag = true;
|
||||
throw makeRuntimeErrorMsg(
|
||||
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.
|
||||
|
||||
Threads: ${ws.scriptRef.threads}
|
||||
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:
|
||||
* 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
|
||||
\u00a0\u00a0const myScan = ns['scan'];
|
||||
|
||||
* Using RunOptions.ramOverride to set a smaller allocation than needed
|
||||
|
||||
Sorry :(`,
|
||||
"RAM USAGE",
|
||||
);
|
||||
@ -651,13 +656,12 @@ function log(ctx: NetscriptContext, message: () => string) {
|
||||
/**
|
||||
* Searches for and returns the RunningScript object for the specified script.
|
||||
* If the 'fn' argument is not specified, this returns the current RunningScript.
|
||||
* @param {string} fn - Filename of script
|
||||
* @param {string} hostname - Hostname/ip of the server on which the script resides
|
||||
* @param {any[]} scriptArgs - Running script's arguments
|
||||
* @returns {RunningScript}
|
||||
* Running script identified by the parameters, or null if no such script
|
||||
* exists, or the current running script if the first argument 'fn'
|
||||
* is not specified.
|
||||
* @param fn - Filename of script
|
||||
* @param hostname - Hostname/ip of the server on which the script resides
|
||||
* @param scriptArgs - Running script's arguments
|
||||
* @returns Running script identified by the parameters, or null if no such script
|
||||
* exists, or the current running script if the first argument 'fn'
|
||||
* is not specified.
|
||||
*/
|
||||
function getRunningScriptByArgs(
|
||||
ctx: NetscriptContext,
|
||||
@ -706,10 +710,8 @@ function getRunningScript(ctx: NetscriptContext, ident: ScriptIdentifier): Runni
|
||||
/**
|
||||
* Helper function for getting the error log message when the user specifies
|
||||
* a nonexistent running script
|
||||
* @param {string} fn - Filename of script
|
||||
* @param {string} hostname - Hostname/ip of the server on which the script resides
|
||||
* @param {any[]} scriptArgs - Running script's arguments
|
||||
* @returns {string} Error message to print to logs
|
||||
* @param ident - Identifier (pid or identifier object) of script.
|
||||
* @returns Error message to print to logs
|
||||
*/
|
||||
function getCannotFindRunningScriptErrorMessage(ident: ScriptIdentifier): string {
|
||||
if (typeof ident === "number") return `Cannot find running script with pid: ${ident}`;
|
||||
|
@ -71,9 +71,6 @@ export class WorkerScript {
|
||||
*/
|
||||
pid: number;
|
||||
|
||||
/** Script's Static RAM usage. Equivalent to underlying script's RAM usage */
|
||||
ramUsage = RamCostConstants.Base;
|
||||
|
||||
/** Reference to underlying RunningScript object */
|
||||
scriptRef: RunningScript;
|
||||
|
||||
|
@ -37,7 +37,7 @@ export function NetscriptExtra(): InternalAPI<INetscriptExtra> {
|
||||
real_document.completely_unused_field = undefined;
|
||||
// set one to true and check that it affected the other.
|
||||
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);
|
||||
}
|
||||
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.ramUsage) throw "Attempting to start a script with no calculated ram cost. This is a bug.";
|
||||
const loadedModule = await compile(script, scripts);
|
||||
workerScript.ramUsage = script.ramUsage;
|
||||
const ns = workerScript.env.vars;
|
||||
|
||||
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
|
||||
// RunningScript's PID as well
|
||||
const workerScript = new WorkerScript(runningScriptObj, pid, NetscriptFunctions);
|
||||
workerScript.ramUsage = runningScriptObj.ramUsage;
|
||||
|
||||
// Add the WorkerScript to the global pool
|
||||
workerScripts.set(pid, workerScript);
|
||||
@ -420,7 +418,7 @@ export function runScriptFromScript(
|
||||
return 0;
|
||||
}
|
||||
|
||||
const singleRamUsage = script.getRamUsage(host.scripts);
|
||||
const singleRamUsage = runOpts.ramOverride ?? script.getRamUsage(host.scripts);
|
||||
if (!singleRamUsage) {
|
||||
workerScript.log(caller, () => `Ram usage could not be calculated for ${scriptname}`);
|
||||
return 0;
|
||||
|
15
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
15
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -203,6 +203,21 @@ interface RunOptions {
|
||||
threads?: number;
|
||||
/** Whether this script is excluded from saves, defaults to false */
|
||||
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 */
|
||||
|
@ -7,6 +7,12 @@ export type PositiveInteger = Integer & PositiveNumber;
|
||||
export const isInteger = (n: unknown): n is Integer => Number.isInteger(n);
|
||||
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
|
||||
* and an optional message */
|
||||
export interface IReturnStatus {
|
||||
|
Loading…
Reference in New Issue
Block a user