mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-21 08:42:53 +02:00
v2.2.1 (#293)
* handle enums differently * Enums are frozen and fed directly to the proxy * Enums are not included in the NSFull definition, allowing samekeys for RamCostTree<API>, InternalAPI<API>, and ExternalAPI<API> * Rewrote a lot of the ramcalc test, with better typing thanks to the samekeys above * Fix ns1 for proxy (args, pid, and enums after above changes were not being added to ns1 scripts.) * Fixed an overview issue where the bars could display inaccurately. Update changelog and bump version to 2.2.1
This commit is contained in:
@@ -1,24 +1,26 @@
|
||||
import { Player } from "../../../src/Player";
|
||||
import { NetscriptFunctions } from "../../../src/NetscriptFunctions";
|
||||
import { RamCosts, getRamCost, RamCostConstants } from "../../../src/Netscript/RamCostGenerator";
|
||||
import { RamCosts, getRamCost, RamCostConstants, RamCostTree } from "../../../src/Netscript/RamCostGenerator";
|
||||
import { Environment } from "../../../src/Netscript/Environment";
|
||||
import { RunningScript } from "../../../src/Script/RunningScript";
|
||||
import { Script } from "../../../src/Script/Script";
|
||||
import { WorkerScript } from "../../../src/Netscript/WorkerScript";
|
||||
import { calculateRamUsage } from "../../../src/Script/RamCalculations";
|
||||
import { ns } from "../../../src/NetscriptFunctions";
|
||||
import { ExternalAPI, InternalAPI } from "src/Netscript/APIWrapper";
|
||||
import { Singularity } from "@nsdefs";
|
||||
|
||||
type PotentiallyAsyncFunction = (arg?: unknown) => { catch?: PotentiallyAsyncFunction };
|
||||
type NSLayer = {
|
||||
[key: string]: NSLayer | PotentiallyAsyncFunction;
|
||||
};
|
||||
type RamLayer = {
|
||||
[key: string]: number | (() => number) | RamLayer;
|
||||
};
|
||||
function grabCost(ramLayer: RamLayer, fullPath: string[]) {
|
||||
const ramEntry = ramLayer[fullPath[fullPath.length - 1]];
|
||||
const expectedRam = typeof ramEntry === "function" ? ramEntry() : ramEntry;
|
||||
if (typeof expectedRam !== "number") throw new Error(`There was no defined ram cost for ${fullPath.join(".")}().`);
|
||||
return expectedRam;
|
||||
|
||||
/** Get a potentiallyAsyncFunction from a layer of the external ns */
|
||||
function getFunction(fn: unknown) {
|
||||
if (typeof fn !== "function") throw new Error("Expected a function at this location.");
|
||||
return fn as PotentiallyAsyncFunction;
|
||||
}
|
||||
function grabCost<API>(ramEntry: RamCostTree<API>[keyof API]) {
|
||||
if (typeof ramEntry === "function") return ramEntry();
|
||||
if (typeof ramEntry === "number") return ramEntry;
|
||||
throw new Error("Invalid ramcost");
|
||||
}
|
||||
function isRemovedFunction(fn: Function) {
|
||||
try {
|
||||
@@ -63,7 +65,7 @@ describe("Netscript RAM Calculation/Generation Tests", function () {
|
||||
ramUsage: scriptRef.ramUsage,
|
||||
scriptRef,
|
||||
};
|
||||
const ns = NetscriptFunctions(workerScript as WorkerScript);
|
||||
const nsExternal = NetscriptFunctions(workerScript as WorkerScript);
|
||||
|
||||
function combinedRamCheck(
|
||||
fn: PotentiallyAsyncFunction,
|
||||
@@ -91,7 +93,7 @@ describe("Netscript RAM Calculation/Generation Tests", function () {
|
||||
env: new Environment(),
|
||||
dynamicLoadedFns: {},
|
||||
});
|
||||
workerScript.env.vars = ns;
|
||||
workerScript.env.vars = nsExternal;
|
||||
|
||||
// Run the function through the workerscript's args
|
||||
if (typeof fn === "function") {
|
||||
@@ -108,67 +110,60 @@ describe("Netscript RAM Calculation/Generation Tests", function () {
|
||||
}
|
||||
|
||||
describe("ns", () => {
|
||||
Object.entries(NetscriptFunctions(workerScript) as unknown as NSLayer).forEach(([key, val]) => {
|
||||
if (key === "args" || key === "enums") return;
|
||||
if (typeof val === "function") {
|
||||
// Removed functions have no ram cost and should be skipped.
|
||||
if (isRemovedFunction(val)) return;
|
||||
const expectedRam = grabCost(RamCosts, [key]);
|
||||
it(`${key}()`, () => combinedRamCheck(val.bind(ns), [key], expectedRam));
|
||||
}
|
||||
//The only other option should be an NSLayer
|
||||
const extraLayerCost = { hacknet: 4 }[key] ?? 0; // Currently only hacknet has a layer cost.
|
||||
testLayer(val as NSLayer, RamCosts[key as keyof typeof RamCosts] as RamLayer, [key], extraLayerCost);
|
||||
});
|
||||
function testLayer<API>(
|
||||
internalLayer: InternalAPI<API>,
|
||||
externalLayer: ExternalAPI<API>,
|
||||
ramLayer: RamCostTree<API>,
|
||||
path: string[],
|
||||
extraLayerCost: number,
|
||||
) {
|
||||
describe(path[path.length - 1] ?? "Base ns layer", () => {
|
||||
for (const [key, val] of Object.entries(internalLayer) as [keyof API, InternalAPI<API>[keyof API]][]) {
|
||||
const newPath = [...path, key as string];
|
||||
if (typeof val === "function") {
|
||||
// Removed functions have no ram cost and should be skipped.
|
||||
if (isRemovedFunction(val)) return;
|
||||
const fn = getFunction(externalLayer[key]);
|
||||
const fnName = newPath.join(".");
|
||||
const expectedRam = grabCost(ramLayer[key]);
|
||||
it(`${fnName}()`, () => combinedRamCheck(fn, newPath, expectedRam, extraLayerCost));
|
||||
}
|
||||
//A layer should be the only other option. Hacknet is currently the only layer with a layer cost.
|
||||
else {
|
||||
//hacknet is currently the only layer with a layer cost.
|
||||
const layerCost = key === "hacknet" ? 4 : 0;
|
||||
testLayer(val as InternalAPI<unknown>, externalLayer[key], ramLayer[key], newPath, layerCost);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
testLayer(ns, nsExternal, RamCosts, [], 0);
|
||||
});
|
||||
|
||||
function testLayer(nsLayer: NSLayer, ramLayer: RamLayer, path: string[], extraLayerCost: number) {
|
||||
// nsLayer is the layer on the main, unstamped wrappedNS object. The actualLayer is needed to check correct stamping.
|
||||
const actualLayer = path.reduce((prev, curr) => prev[curr], ns as any); //todo: do this typesafely?
|
||||
describe(path[path.length - 1], () => {
|
||||
Object.entries(nsLayer).forEach(([key, val]) => {
|
||||
const newPath = [...path, key];
|
||||
if (typeof val === "function") {
|
||||
// Removed functions have no ram cost and should be skipped.
|
||||
if (isRemovedFunction(val)) return;
|
||||
const fnName = newPath.join(".");
|
||||
const expectedRam = grabCost(ramLayer, newPath);
|
||||
it(`${fnName}()`, () => combinedRamCheck(val.bind(actualLayer), newPath, expectedRam, extraLayerCost));
|
||||
}
|
||||
//Skip enums layers
|
||||
else if (key === "enums") return;
|
||||
//A layer should be the only other option.
|
||||
else testLayer(val, ramLayer[key] as RamLayer, newPath, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe("Singularity multiplier checks", () => {
|
||||
// Checks were already done above for SF4.3 having normal ramcost.
|
||||
sf4.lvl = 3;
|
||||
const singFunctions = Object.entries(NetscriptFunctions(workerScript).singularity).filter(
|
||||
([__, val]) => typeof val === "function",
|
||||
);
|
||||
const singObjects = singFunctions
|
||||
.filter((fn) => !isRemovedFunction(fn))
|
||||
.map(([key, val]) => {
|
||||
const lvlToMult = { 0: 16, 1: 16, 2: 4 };
|
||||
const externalSingularity = nsExternal.singularity;
|
||||
const ramCostSingularity = RamCosts.singularity;
|
||||
const singObjects = (
|
||||
Object.entries(ns.singularity) as [keyof Singularity, InternalAPI<Singularity>[keyof Singularity]][]
|
||||
)
|
||||
.filter(([_, v]) => typeof v === "function" && !isRemovedFunction(v))
|
||||
.map(([name]) => {
|
||||
return {
|
||||
name: key,
|
||||
fn: val.bind(ns.singularity),
|
||||
baseRam: grabCost(RamCosts.singularity, ["singularity", key]),
|
||||
name,
|
||||
baseRam: grabCost<Singularity>(ramCostSingularity[name]),
|
||||
};
|
||||
});
|
||||
const lvlToMult: Record<number, number> = { 0: 16, 1: 16, 2: 4 };
|
||||
for (const lvl of [0, 1, 2]) {
|
||||
for (const lvl of [0, 1, 2] as const) {
|
||||
it(`SF4.${lvl} check for x${lvlToMult[lvl]} costs`, () => {
|
||||
sf4.lvl = lvl;
|
||||
singObjects.forEach((obj) =>
|
||||
combinedRamCheck(
|
||||
obj.fn as PotentiallyAsyncFunction,
|
||||
["singularity", obj.name],
|
||||
obj.baseRam * lvlToMult[lvl],
|
||||
0,
|
||||
),
|
||||
);
|
||||
const expectedMult = lvlToMult[lvl];
|
||||
singObjects.forEach(({ name, baseRam }) => {
|
||||
const fn = getFunction(externalSingularity[name]);
|
||||
combinedRamCheck(fn, ["singularity", name], baseRam * expectedMult);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user