Add detailed ram cost to mem command

This commit is contained in:
Martin Fournier
2022-01-05 16:41:48 -05:00
parent 7107dd682c
commit 4b06bdd89c
5 changed files with 55 additions and 22 deletions
+37 -10
View File
@@ -16,6 +16,17 @@ import { WorkerScript } from "../Netscript/WorkerScript";
import { areImportsEquals } from "../Terminal/DirectoryHelpers";
import { IPlayer } from "../PersonObjects/IPlayer";
export interface RamUsageEntry {
type: 'ns' | 'dom' | 'fn' | 'misc';
name: string;
cost: number;
}
export interface RamCalculation {
cost: number;
entries?: RamUsageEntry[];
}
// These special strings are used to reference the presence of a given logical
// construct within a user script.
const specialReferenceIF = "__SPECIAL_referenceIf";
@@ -38,7 +49,7 @@ async function parseOnlyRamCalculate(
otherScripts: Script[],
code: string,
workerScript: WorkerScript,
): Promise<number | RamCalculationErrorCode> {
): Promise<RamCalculation> {
try {
/**
* Maps dependent identifiers to their dependencies.
@@ -98,12 +109,12 @@ async function parseOnlyRamCalculate(
}
} catch (e) {
console.error(`Error dynamically importing module from ${nextModule} for RAM calculations: ${e}`);
return RamCalculationErrorCode.URLImportError;
return { cost: RamCalculationErrorCode.URLImportError };
}
} else {
if (!Array.isArray(otherScripts)) {
console.warn(`parseOnlyRamCalculate() not called with array of scripts`);
return RamCalculationErrorCode.ImportError;
return { cost: RamCalculationErrorCode.ImportError };
}
let script = null;
@@ -116,7 +127,7 @@ async function parseOnlyRamCalculate(
}
if (script == null) {
return RamCalculationErrorCode.ImportError; // No such script on the server
return { cost: RamCalculationErrorCode.ImportError }; // No such script on the server
}
code = script.code;
@@ -128,6 +139,7 @@ async function parseOnlyRamCalculate(
// Finally, walk the reference map and generate a ram cost. The initial set of keys to scan
// are those that start with __SPECIAL_INITIAL_MODULE__.
let ram = RamCostConstants.ScriptBaseRamCost;
const detailedCosts: RamUsageEntry[] = [{ type: 'misc', name: 'baseCost', cost: RamCostConstants.ScriptBaseRamCost}];
const unresolvedRefs = Object.keys(dependencyMap).filter((s) => s.startsWith(initialModule));
const resolvedRefs = new Set();
while (unresolvedRefs.length > 0) {
@@ -137,15 +149,19 @@ async function parseOnlyRamCalculate(
// 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.ScriptHacknetNodesRamCost;
detailedCosts.push({ type: 'ns', name: 'hacknet', cost: RamCostConstants.ScriptHacknetNodesRamCost});
}
if (ref === "document" && !resolvedRefs.has("document")) {
ram += RamCostConstants.ScriptDomRamCost;
detailedCosts.push({ type: 'dom', name: 'document', cost: RamCostConstants.ScriptDomRamCost});
}
if (ref === "window" && !resolvedRefs.has("window")) {
ram += RamCostConstants.ScriptDomRamCost;
detailedCosts.push({ type: 'dom', name: 'window', cost: RamCostConstants.ScriptDomRamCost});
}
if (ref === "corporation" && !resolvedRefs.has("corporation")) {
ram += RamCostConstants.ScriptCorporationRamCost;
detailedCosts.push({ type: 'ns', name: 'corporation', cost: RamCostConstants.ScriptCorporationRamCost});
}
resolvedRefs.add(ref);
@@ -187,34 +203,45 @@ async function parseOnlyRamCalculate(
// This accounts for namespaces (Bladeburner, CodingCpntract, etc.)
let func;
let refDetail = 'n/a';
if (ref in workerScript.env.vars.bladeburner) {
func = workerScript.env.vars.bladeburner[ref];
refDetail = `bladeburner.${ref}`;
} else if (ref in workerScript.env.vars.codingcontract) {
func = workerScript.env.vars.codingcontract[ref];
refDetail = `codingcontract.${ref}`;
} else if (ref in workerScript.env.vars.stanek) {
func = workerScript.env.vars.stanek[ref];
refDetail = `stanek.${ref}`;
} else if (ref in workerScript.env.vars.gang) {
func = workerScript.env.vars.gang[ref];
refDetail = `gang.${ref}`;
} else if (ref in workerScript.env.vars.sleeve) {
func = workerScript.env.vars.sleeve[ref];
refDetail = `sleeve.${ref}`;
} else if (ref in workerScript.env.vars.stock) {
func = workerScript.env.vars.stock[ref];
refDetail = `stock.${ref}`;
} else if (ref in workerScript.env.vars.ui) {
func = workerScript.env.vars.ui[ref];
refDetail = `ui.${ref}`;
} else {
func = workerScript.env.vars[ref];
refDetail = `${ref}`;
}
ram += applyFuncRam(func);
const fnRam = applyFuncRam(func);
ram += fnRam;
detailedCosts.push({ type: 'fn', name: refDetail, cost: fnRam});
} catch (error) {
continue;
}
}
return ram;
return { cost: ram, entries: detailedCosts.filter(e => e.cost > 0) };
} catch (error) {
// console.info("parse or eval error: ", error);
// This is not unexpected. The user may be editing a script, and it may be in
// a transitory invalid state.
return RamCalculationErrorCode.SyntaxError;
return { cost: RamCalculationErrorCode.SyntaxError };
}
}
@@ -382,7 +409,7 @@ export async function calculateRamUsage(
player: IPlayer,
codeCopy: string,
otherScripts: Script[],
): Promise<RamCalculationErrorCode | number> {
): Promise<RamCalculation> {
// We don't need a real WorkerScript for this. Just an object that keeps
// track of whatever's needed for RAM calculations
const workerScript = {
@@ -397,8 +424,8 @@ export async function calculateRamUsage(
} catch (e) {
console.error(`Failed to parse script for RAM calculations:`);
console.error(e);
return RamCalculationErrorCode.SyntaxError;
return { cost: RamCalculationErrorCode.SyntaxError };
}
return RamCalculationErrorCode.SyntaxError;
return { cost: RamCalculationErrorCode.SyntaxError };
}