From dd78a2cb443c4dbc1c784ca6623939dde973cb7c Mon Sep 17 00:00:00 2001 From: catloversg <152669316+catloversg@users.noreply.github.com> Date: Tue, 17 Feb 2026 00:00:02 +0700 Subject: [PATCH] API: Remove RAM cost of hacknet namespace and set RAM cost of each hacknet API (#2502) * API: Remove RAM cost of hacknet namespace and set RAM cost of each hacknet API * Fix Jest tests * Update based on feedback --- src/Netscript/RamCostGenerator.ts | 44 +++++++++---------- src/Script/RamCalculations.ts | 4 -- src/utils/APIBreaks/3.0.0.ts | 29 ++++++++++++ src/utils/SaveDataMigrationUtils.ts | 2 + test/jest/Netscript/RamCalculation.test.ts | 9 +--- .../StaticRamParsingCalculation.test.ts | 18 ++------ 6 files changed, 58 insertions(+), 48 deletions(-) diff --git a/src/Netscript/RamCostGenerator.ts b/src/Netscript/RamCostGenerator.ts index d2bcf0589..cb3441d5f 100644 --- a/src/Netscript/RamCostGenerator.ts +++ b/src/Netscript/RamCostGenerator.ts @@ -35,7 +35,7 @@ export const RamCostConstants = { GetServerUsedRam: 0.05, FileExists: 0.1, IsRunning: 0.1, - HacknetNodes: 4.0, + Hacknet: 0.5, HNUpgLevel: 0.4, HNUpgRam: 0.6, HNUpgCore: 0.8, @@ -98,27 +98,27 @@ function SF4Cost(cost: number): () => number { // Hacknet API const hacknet = { - numNodes: 0, - purchaseNode: 0, - getPurchaseNodeCost: 0, - getNodeStats: 0, - upgradeLevel: 0, - upgradeRam: 0, - upgradeCore: 0, - upgradeCache: 0, - getLevelUpgradeCost: 0, - getRamUpgradeCost: 0, - getCoreUpgradeCost: 0, - getCacheUpgradeCost: 0, - numHashes: 0, - hashCost: 0, - spendHashes: 0, - maxNumNodes: 0, - hashCapacity: 0, - getHashUpgrades: 0, - getHashUpgradeLevel: 0, - getStudyMult: 0, - getTrainingMult: 0, + numNodes: RamCostConstants.Hacknet, + purchaseNode: RamCostConstants.Hacknet, + getPurchaseNodeCost: RamCostConstants.Hacknet, + getNodeStats: RamCostConstants.Hacknet, + upgradeLevel: RamCostConstants.Hacknet, + upgradeRam: RamCostConstants.Hacknet, + upgradeCore: RamCostConstants.Hacknet, + upgradeCache: RamCostConstants.Hacknet, + getLevelUpgradeCost: RamCostConstants.Hacknet, + getRamUpgradeCost: RamCostConstants.Hacknet, + getCoreUpgradeCost: RamCostConstants.Hacknet, + getCacheUpgradeCost: RamCostConstants.Hacknet, + numHashes: RamCostConstants.Hacknet, + hashCost: RamCostConstants.Hacknet, + spendHashes: RamCostConstants.Hacknet, + maxNumNodes: RamCostConstants.Hacknet, + hashCapacity: RamCostConstants.Hacknet, + getHashUpgrades: RamCostConstants.Hacknet, + getHashUpgradeLevel: RamCostConstants.Hacknet, + getStudyMult: RamCostConstants.Hacknet, + getTrainingMult: RamCostConstants.Hacknet, } as const; // Stock API diff --git a/src/Script/RamCalculations.ts b/src/Script/RamCalculations.ts index 443f2c0b1..609fb8ab8 100644 --- a/src/Script/RamCalculations.ts +++ b/src/Script/RamCalculations.ts @@ -182,10 +182,6 @@ function parseOnlyRamCalculate( return { cost: override, entries: [{ type: "misc", name: "override", cost: override }] }; } // Check if this is one of the special keys, and add the appropriate ram cost if so. - if (ref === "hacknet" && !resolvedRefs.has("hacknet")) { - ram += RamCostConstants.HacknetNodes; - detailedCosts.push({ type: "ns", name: "hacknet", cost: RamCostConstants.HacknetNodes }); - } if (ref === "document" && !resolvedRefs.has("document")) { ram += RamCostConstants.Dom; detailedCosts.push({ type: "dom", name: "document", cost: RamCostConstants.Dom }); diff --git a/src/utils/APIBreaks/3.0.0.ts b/src/utils/APIBreaks/3.0.0.ts index 3a73d6d21..ae6a53823 100644 --- a/src/utils/APIBreaks/3.0.0.ts +++ b/src/utils/APIBreaks/3.0.0.ts @@ -541,5 +541,34 @@ export const breakingChanges300: VersionBreakingChange = { showWarning: false, doNotSkip: true, }, + { + brokenAPIs: [ + { name: "ns.hacknet.numNodes" }, + { name: "ns.hacknet.purchaseNode" }, + { name: "ns.hacknet.getPurchaseNodeCost" }, + { name: "ns.hacknet.getNodeStats" }, + { name: "ns.hacknet.upgradeLevel" }, + { name: "ns.hacknet.upgradeRam" }, + { name: "ns.hacknet.upgradeCore" }, + { name: "ns.hacknet.upgradeCache" }, + { name: "ns.hacknet.getLevelUpgradeCost" }, + { name: "ns.hacknet.getRamUpgradeCost" }, + { name: "ns.hacknet.getCoreUpgradeCost" }, + { name: "ns.hacknet.getCacheUpgradeCost" }, + { name: "ns.hacknet.numHashes" }, + { name: "ns.hacknet.hashCost" }, + { name: "ns.hacknet.spendHashes" }, + { name: "ns.hacknet.maxNumNodes" }, + { name: "ns.hacknet.hashCapacity" }, + { name: "ns.hacknet.getHashUpgrades" }, + { name: "ns.hacknet.getHashUpgradeLevel" }, + { name: "ns.hacknet.getStudyMult" }, + { name: "ns.hacknet.getTrainingMult" }, + ], + info: + "Accessing the hacknet namespace incurred a one-time cost of 4 GB of RAM, and each hacknet API did not incur \n" + + "RAM cost. Now the hacknet namespace does not incur RAM cost, but each hacknet API incurs a 0.5GB RAM cost.", + showWarning: false, + }, ], }; diff --git a/src/utils/SaveDataMigrationUtils.ts b/src/utils/SaveDataMigrationUtils.ts index 81ca1f864..64e081365 100644 --- a/src/utils/SaveDataMigrationUtils.ts +++ b/src/utils/SaveDataMigrationUtils.ts @@ -620,6 +620,8 @@ Error: ${e}`, } if (ver < 45) { initDarkwebServer(); + } + if (ver < 46) { showAPIBreaks("3.0.0", breakingChanges300); } } diff --git a/test/jest/Netscript/RamCalculation.test.ts b/test/jest/Netscript/RamCalculation.test.ts index fe784d83c..f21d43706 100644 --- a/test/jest/Netscript/RamCalculation.test.ts +++ b/test/jest/Netscript/RamCalculation.test.ts @@ -140,13 +140,8 @@ describe("Netscript RAM Calculation/Generation Tests", function () { 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 if (typeof val === "object" && key !== "enums") { - //hacknet is currently the only layer with a layer cost. - const layerCost = key === "hacknet" ? 4 : 0; - testLayer(val as InternalAPI, externalLayer[key], ramLayer[key], newPath, layerCost); - } - // Other things like args, enums, etc. have no cost + // A layer should be the only other option, but we don't have any of those with a cost. + // Other things like args, enums, etc. have no cost. } }); } diff --git a/test/jest/Netscript/StaticRamParsingCalculation.test.ts b/test/jest/Netscript/StaticRamParsingCalculation.test.ts index 1658b660b..a55179881 100644 --- a/test/jest/Netscript/StaticRamParsingCalculation.test.ts +++ b/test/jest/Netscript/StaticRamParsingCalculation.test.ts @@ -10,7 +10,7 @@ const BaseCost = 1.6; const HackCost = 0.1; const GrowCost = 0.15; const SleeveGetTaskCost = 4; -const HacknetCost = 4; +const Hacknet = 0.5; const MaxCost = 1024; const filename = "testfile.js" as ScriptFilePath; @@ -148,18 +148,6 @@ describe("Parsing NetScript code to work out static RAM costs", function () { expectCost(calculated, 0); }); - it("Function 'purchaseNode' that can be confused with Hacknet.purchaseNode", function () { - const code = ` - export async function main(ns) { - purchaseNode(); - } - function purchaseNode() { return 0; } - `; - const calculated = calculateRamUsage(code, filename, server, new Map()).cost; - // Works at present, because the parser checks the namespace only, not the function name - expectCost(calculated, 0); - }); - // TODO: once we fix static parsing this should pass it.skip("Function 'getTask' that can be confused with Sleeve.getTask", function () { const code = ` @@ -174,14 +162,14 @@ describe("Parsing NetScript code to work out static RAM costs", function () { }); describe("Single files with non-core NS functions", function () { - it("Hacknet NS function with a cost from namespace", function () { + it("Hacknet NS functions with an individual cost", function () { const code = ` export async function main(ns) { ns.hacknet.purchaseNode(0); } `; const calculated = calculateRamUsage(code, filename, server, new Map()).cost; - expectCost(calculated, HacknetCost); + expectCost(calculated, Hacknet); }); it("Sleeve functions with an individual cost", function () {