diff --git a/package-lock.json b/package-lock.json index 079c185a0..ceaaefbab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6068,9 +6068,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001414", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz", - "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==", + "version": "1.0.30001473", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz", + "integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==", "funding": [ { "type": "opencollective", @@ -6079,6 +6079,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -20196,9 +20200,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001414", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001414.tgz", - "integrity": "sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==" + "version": "1.0.30001473", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz", + "integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==" }, "chalk": { "version": "2.4.2", diff --git a/src/Augmentation/Augmentation.tsx b/src/Augmentation/Augmentation.tsx index 7b20ba596..872510252 100644 --- a/src/Augmentation/Augmentation.tsx +++ b/src/Augmentation/Augmentation.tsx @@ -6,7 +6,7 @@ import { Factions } from "../Faction/Factions"; import { formatPercent } from "../ui/formatNumber"; import { Money } from "../ui/React/Money"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { FactionNames } from "../Faction/data/FactionNames"; import { Player } from "@player"; import { AugmentationNames } from "./data/AugmentationNames"; @@ -607,4 +607,4 @@ export class Augmentation { } } -Reviver.constructors.Augmentation = Augmentation; +constructorsForReviver.Augmentation = Augmentation; diff --git a/src/Bladeburner/Action.tsx b/src/Bladeburner/Action.tsx index d2f273f82..f74ae4820 100644 --- a/src/Bladeburner/Action.tsx +++ b/src/Bladeburner/Action.tsx @@ -1,6 +1,6 @@ import { getRandomInt } from "../utils/helpers/getRandomInt"; import { addOffset } from "../utils/helpers/addOffset"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { BladeburnerConstants } from "./data/Constants"; import { Bladeburner } from "./Bladeburner"; import { Person } from "../PersonObjects/Person"; @@ -304,4 +304,4 @@ export class Action { } } -Reviver.constructors.Action = Action; +constructorsForReviver.Action = Action; diff --git a/src/Bladeburner/ActionIdentifier.ts b/src/Bladeburner/ActionIdentifier.ts index cab31083f..57b7995b8 100644 --- a/src/Bladeburner/ActionIdentifier.ts +++ b/src/Bladeburner/ActionIdentifier.ts @@ -1,4 +1,4 @@ -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; interface IParams { name?: string; @@ -23,4 +23,4 @@ export class ActionIdentifier { } } -Reviver.constructors.ActionIdentifier = ActionIdentifier; +constructorsForReviver.ActionIdentifier = ActionIdentifier; diff --git a/src/Bladeburner/BlackOperation.ts b/src/Bladeburner/BlackOperation.ts index 717c5859f..bdf79f139 100644 --- a/src/Bladeburner/BlackOperation.ts +++ b/src/Bladeburner/BlackOperation.ts @@ -1,5 +1,5 @@ import { Operation, IOperationParams } from "./Operation"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; export class BlackOperation extends Operation { constructor(params: IOperationParams | null = null) { @@ -29,4 +29,4 @@ export class BlackOperation extends Operation { } } -Reviver.constructors.BlackOperation = BlackOperation; +constructorsForReviver.BlackOperation = BlackOperation; diff --git a/src/Bladeburner/Bladeburner.tsx b/src/Bladeburner/Bladeburner.tsx index bcf3896eb..82dd1633b 100644 --- a/src/Bladeburner/Bladeburner.tsx +++ b/src/Bladeburner/Bladeburner.tsx @@ -1,4 +1,4 @@ -import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; +import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { ActionIdentifier } from "./ActionIdentifier"; import { ActionTypes } from "./data/ActionTypes"; import { Growths } from "./data/Growths"; @@ -2390,4 +2390,4 @@ export class Bladeburner { } } -Reviver.constructors.Bladeburner = Bladeburner; +constructorsForReviver.Bladeburner = Bladeburner; diff --git a/src/Bladeburner/City.ts b/src/Bladeburner/City.ts index cf218d875..3a78d80d8 100644 --- a/src/Bladeburner/City.ts +++ b/src/Bladeburner/City.ts @@ -1,6 +1,6 @@ import { BladeburnerConstants } from "./data/Constants"; import { getRandomInt } from "../utils/helpers/getRandomInt"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { addOffset } from "../utils/helpers/addOffset"; import { CityName } from "../Enums"; @@ -169,4 +169,4 @@ export class City { } } -Reviver.constructors.City = City; +constructorsForReviver.City = City; diff --git a/src/Bladeburner/Contract.ts b/src/Bladeburner/Contract.ts index 61a6a7d6f..d9baa7b94 100644 --- a/src/Bladeburner/Contract.ts +++ b/src/Bladeburner/Contract.ts @@ -1,6 +1,6 @@ import { Bladeburner } from "./Bladeburner"; import { Action, IActionParams } from "./Action"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; export class Contract extends Action { constructor(params: IActionParams | null = null) { @@ -20,4 +20,4 @@ export class Contract extends Action { } } -Reviver.constructors.Contract = Contract; +constructorsForReviver.Contract = Contract; diff --git a/src/Bladeburner/Operation.ts b/src/Bladeburner/Operation.ts index 4eef008c1..dfc257eb6 100644 --- a/src/Bladeburner/Operation.ts +++ b/src/Bladeburner/Operation.ts @@ -1,7 +1,7 @@ import { Bladeburner } from "./Bladeburner"; import { BladeburnerConstants } from "./data/Constants"; import { Action, IActionParams } from "./Action"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; export interface IOperationParams extends IActionParams { reqdRank?: number; @@ -53,4 +53,4 @@ export class Operation extends Action { } } -Reviver.constructors.Operation = Operation; +constructorsForReviver.Operation = Operation; diff --git a/src/CodingContracts.ts b/src/CodingContracts.ts index 9cb5f44fd..7b1efad7c 100644 --- a/src/CodingContracts.ts +++ b/src/CodingContracts.ts @@ -1,6 +1,6 @@ import { codingContractTypesMetadata, DescriptionFunc, GeneratorFunc, SolverFunc } from "./data/codingcontracttypes"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "./utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "./utils/JSONReviver"; import { CodingContractEvent } from "./ui/React/CodingContractModal"; /* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */ @@ -172,4 +172,4 @@ export class CodingContract { } } -Reviver.constructors.CodingContract = CodingContract; +constructorsForReviver.CodingContract = CodingContract; diff --git a/src/Company/Company.ts b/src/Company/Company.ts index aee521ac9..956ce9ff5 100644 --- a/src/Company/Company.ts +++ b/src/Company/Company.ts @@ -2,7 +2,7 @@ import { CompanyPosition } from "./CompanyPosition"; import * as posNames from "./data/JobTracks"; import { favorToRep, repToFavor } from "../Faction/formulas/favor"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; export interface IConstructorParams { name: string; @@ -143,4 +143,4 @@ export class Company { } } -Reviver.constructors.Company = Company; +constructorsForReviver.Company = Company; diff --git a/src/Corporation/Corporation.tsx b/src/Corporation/Corporation.tsx index e9229b5ef..b8188f92f 100644 --- a/src/Corporation/Corporation.tsx +++ b/src/Corporation/Corporation.tsx @@ -10,7 +10,7 @@ import { LiteratureNames } from "../Literature/data/LiteratureNames"; import { Player } from "@player"; import { dialogBoxCreate } from "../ui/React/DialogBox"; -import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; +import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { isString } from "../utils/helpers/isString"; import { CityName } from "../Enums"; import { CorpStateName } from "@nsdefs"; @@ -468,4 +468,4 @@ export class Corporation { } } -Reviver.constructors.Corporation = Corporation; +constructorsForReviver.Corporation = Corporation; diff --git a/src/Corporation/CorporationState.ts b/src/Corporation/CorporationState.ts index df0060b62..2056881cf 100644 --- a/src/Corporation/CorporationState.ts +++ b/src/Corporation/CorporationState.ts @@ -1,5 +1,5 @@ import { CorpStateName } from "@nsdefs"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { stateNames } from "./data/Constants"; export class CorporationState { // Number representing what state the Corporation is in. The number @@ -36,4 +36,4 @@ export class CorporationState { } } -Reviver.constructors.CorporationState = CorporationState; +constructorsForReviver.CorporationState = CorporationState; diff --git a/src/Corporation/Industry.ts b/src/Corporation/Industry.ts index ba567221c..d8497f329 100644 --- a/src/Corporation/Industry.ts +++ b/src/Corporation/Industry.ts @@ -1,4 +1,4 @@ -import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; +import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { CityName } from "../Enums"; import { IndustryResearchTrees, IndustriesData } from "./IndustryData"; import * as corpConstants from "./data/Constants"; @@ -1238,4 +1238,4 @@ export class Industry { } } -Reviver.constructors.Industry = Industry; +constructorsForReviver.Industry = Industry; diff --git a/src/Corporation/Material.ts b/src/Corporation/Material.ts index 636df77c7..7dc26aa0a 100644 --- a/src/Corporation/Material.ts +++ b/src/Corporation/Material.ts @@ -1,5 +1,5 @@ import { CorpMaterialName } from "@nsdefs"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { materialNames } from "./data/Constants"; import { Export } from "./Export"; import { MaterialInfo } from "./MaterialInfo"; @@ -140,4 +140,4 @@ export class Material { } } -Reviver.constructors.Material = Material; +constructorsForReviver.Material = Material; diff --git a/src/Corporation/OfficeSpace.ts b/src/Corporation/OfficeSpace.ts index 7b093d2ef..d1cd24c10 100644 --- a/src/Corporation/OfficeSpace.ts +++ b/src/Corporation/OfficeSpace.ts @@ -1,6 +1,6 @@ import { EmployeePositions } from "./data/Enums"; import * as corpConstants from "./data/Constants"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { Industry } from "./Industry"; import { Corporation } from "./Corporation"; import { getRandomInt } from "../utils/helpers/getRandomInt"; @@ -272,4 +272,4 @@ export class OfficeSpace { } } -Reviver.constructors.OfficeSpace = OfficeSpace; +constructorsForReviver.OfficeSpace = OfficeSpace; diff --git a/src/Corporation/Product.ts b/src/Corporation/Product.ts index 4cf7a2f36..a9b9c4601 100644 --- a/src/Corporation/Product.ts +++ b/src/Corporation/Product.ts @@ -5,7 +5,7 @@ import { IndustriesData } from "./IndustryData"; import { createCityMap } from "../Locations/createCityMap"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { getRandomInt } from "../utils/helpers/getRandomInt"; import { CityName } from "../Enums"; import { materialNames } from "./data/Constants"; @@ -285,4 +285,4 @@ export class Product { } } -Reviver.constructors.Product = Product; +constructorsForReviver.Product = Product; diff --git a/src/Corporation/Warehouse.ts b/src/Corporation/Warehouse.ts index 8b2bc93ff..e20fe1f6e 100644 --- a/src/Corporation/Warehouse.ts +++ b/src/Corporation/Warehouse.ts @@ -2,7 +2,7 @@ import { Material } from "./Material"; import { Corporation } from "./Corporation"; import { Industry } from "./Industry"; import { MaterialInfo } from "./MaterialInfo"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { exceptionAlert } from "../utils/helpers/exceptionAlert"; import { CityName } from "../Enums"; import { CorpMaterialName } from "@nsdefs"; @@ -107,4 +107,4 @@ export class Warehouse { } } -Reviver.constructors.Warehouse = Warehouse; +constructorsForReviver.Warehouse = Warehouse; diff --git a/src/CotMG/ActiveFragment.ts b/src/CotMG/ActiveFragment.ts index fe32ae5d9..4b35de5f2 100644 --- a/src/CotMG/ActiveFragment.ts +++ b/src/CotMG/ActiveFragment.ts @@ -1,5 +1,5 @@ import { Fragment, FragmentById } from "./Fragment"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; export interface IActiveFragmentParams { x: number; @@ -82,4 +82,4 @@ export class ActiveFragment { } } -Reviver.constructors.ActiveFragment = ActiveFragment; +constructorsForReviver.ActiveFragment = ActiveFragment; diff --git a/src/CotMG/StaneksGift.ts b/src/CotMG/StaneksGift.ts index a8f759687..cc2ae41c5 100644 --- a/src/CotMG/StaneksGift.ts +++ b/src/CotMG/StaneksGift.ts @@ -6,7 +6,7 @@ import { BaseGift } from "./BaseGift"; import { Factions } from "../Faction/Factions"; import { CalculateEffect } from "./formulas/effect"; import { StaneksGiftEvents } from "./StaneksGiftEvents"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { StanekConstants } from "./data/Constants"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { Player } from "@player"; @@ -255,4 +255,4 @@ export class StaneksGift extends BaseGift { } } -Reviver.constructors.StaneksGift = StaneksGift; +constructorsForReviver.StaneksGift = StaneksGift; diff --git a/src/Faction/Faction.ts b/src/Faction/Faction.ts index b3e6a7ffe..cf4aae5ab 100644 --- a/src/Faction/Faction.ts +++ b/src/Faction/Faction.ts @@ -1,6 +1,6 @@ import { FactionInfo, FactionInfos } from "./FactionInfo"; import { favorToRep, repToFavor } from "./formulas/favor"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; export class Faction { /** @@ -71,4 +71,4 @@ export class Faction { } } -Reviver.constructors.Faction = Faction; +constructorsForReviver.Faction = Faction; diff --git a/src/Gang/Gang.ts b/src/Gang/Gang.ts index 95fc1856a..50d867fd9 100644 --- a/src/Gang/Gang.ts +++ b/src/Gang/Gang.ts @@ -7,7 +7,7 @@ import { Factions } from "../Faction/Factions"; import { dialogBoxCreate } from "../ui/React/DialogBox"; -import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; +import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { exceptionAlert } from "../utils/helpers/exceptionAlert"; import { getRandomInt } from "../utils/helpers/getRandomInt"; @@ -403,4 +403,4 @@ export class Gang { } } -Reviver.constructors.Gang = Gang; +constructorsForReviver.Gang = Gang; diff --git a/src/Gang/GangMember.ts b/src/Gang/GangMember.ts index bb4f1acc6..99b58734b 100644 --- a/src/Gang/GangMember.ts +++ b/src/Gang/GangMember.ts @@ -5,7 +5,7 @@ import { GangMemberUpgrades } from "./GangMemberUpgrades"; import { IAscensionResult } from "./IAscensionResult"; import { Player } from "@player"; import { Gang } from "./Gang"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { calculateRespectGain, calculateMoneyGain, @@ -332,4 +332,4 @@ export class GangMember { } } -Reviver.constructors.GangMember = GangMember; +constructorsForReviver.GangMember = GangMember; diff --git a/src/Hacknet/HacknetNode.ts b/src/Hacknet/HacknetNode.ts index 714fff58e..e2d10267e 100644 --- a/src/Hacknet/HacknetNode.ts +++ b/src/Hacknet/HacknetNode.ts @@ -17,7 +17,7 @@ import { import { HacknetNodeConstants } from "./data/Constants"; import { dialogBoxCreate } from "../ui/React/DialogBox"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { ObjectValidator, minMax } from "../utils/Validator"; export class HacknetNode implements IHacknetNode { @@ -131,4 +131,4 @@ export class HacknetNode implements IHacknetNode { } } -Reviver.constructors.HacknetNode = HacknetNode; +constructorsForReviver.HacknetNode = HacknetNode; diff --git a/src/Hacknet/HacknetServer.ts b/src/Hacknet/HacknetServer.ts index 779da17a6..84b94d614 100644 --- a/src/Hacknet/HacknetServer.ts +++ b/src/Hacknet/HacknetServer.ts @@ -15,7 +15,7 @@ import { import { createRandomIp } from "../utils/IPAddress"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { Player } from "@player"; interface IConstructorParams { @@ -153,4 +153,4 @@ export class HacknetServer extends BaseServer implements IHacknetNode { } } -Reviver.constructors.HacknetServer = HacknetServer; +constructorsForReviver.HacknetServer = HacknetServer; diff --git a/src/Hacknet/HashManager.ts b/src/Hacknet/HashManager.ts index f4f4ca2e8..548fac2e2 100644 --- a/src/Hacknet/HashManager.ts +++ b/src/Hacknet/HashManager.ts @@ -9,7 +9,7 @@ import { HashUpgrades } from "./HashUpgrades"; import { HashUpgrade } from "./HashUpgrade"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; export class HashManager { // Max number of hashes this can hold. Equal to the sum of capacities of @@ -156,4 +156,4 @@ export class HashManager { } } -Reviver.constructors.HashManager = HashManager; +constructorsForReviver.HashManager = HashManager; diff --git a/src/Netscript/NetscriptHelpers.ts b/src/Netscript/NetscriptHelpers.ts index 58e2938d0..891d65800 100644 --- a/src/Netscript/NetscriptHelpers.ts +++ b/src/Netscript/NetscriptHelpers.ts @@ -234,8 +234,8 @@ function argsToString(args: unknown[]): string { /** Creates an error message string containing hostname, scriptname, and the error message msg */ function makeBasicErrorMsg(ws: WorkerScript | ScriptDeath, msg: string, type = "RUNTIME"): string { if (ws instanceof WorkerScript) { - for (const scriptUrl of ws.scriptRef.dependencies) { - msg = msg.replace(new RegExp(scriptUrl.url, "g"), scriptUrl.filename); + for (const [scriptUrl, script] of ws.scriptRef.dependencies) { + msg = msg.replace(new RegExp(scriptUrl, "g"), script.filename); } } return `${type} ERROR\n${ws.name}@${ws.hostname} (PID - ${ws.pid})\n\n${msg}`; @@ -248,20 +248,19 @@ function makeRuntimeErrorMsg(ctx: NetscriptContext, msg: string, type = "RUNTIME const stack = errstack.split("\n").slice(1); const ws = ctx.workerScript; const caller = ctx.functionPath; - const scripts = ws.getServer().scripts; const userstack = []; for (const stackline of stack) { - let filename; - for (const script of scripts) { - if (script.filename && stackline.includes(script.filename)) { - filename = script.filename; + const filename = (() => { + // Filename is current file if url found + if (ws.scriptRef.url && stackline.includes(ws.scriptRef.url)) return ws.scriptRef.filename; + // Also check urls for dependencies + for (const [url, script] of ws.scriptRef.dependencies) if (stackline.includes(url)) return script.filename; + // Check for filenames directly if no URL found + if (stackline.includes(ws.scriptRef.filename)) return ws.scriptRef.filename; + for (const script of ws.scriptRef.dependencies.values()) { + if (stackline.includes(script.filename)) return script.filename; } - for (const dependency of script.dependencies) { - if (stackline.includes(dependency.filename)) { - filename = dependency.filename; - } - } - } + })(); if (!filename) continue; interface ILine { diff --git a/src/NetscriptFunctions.ts b/src/NetscriptFunctions.ts index 372474131..705a52009 100644 --- a/src/NetscriptFunctions.ts +++ b/src/NetscriptFunctions.ts @@ -893,18 +893,15 @@ export const ns: InternalAPI = { } destScript.code = sourceScript.code; // Set ramUsage to null in order to force a recalculation prior to next run. - destScript.ramUsage = null; - destScript.markUpdated(); + destScript.invalidateModule(); helpers.log(ctx, () => `WARNING: File '${file}' overwritten on '${destServer?.hostname}'`); continue; } // Create new script if it does not already exist - const newScript = new Script(file); - newScript.code = sourceScript.code; - // Set ramUsage to null in order to force a recalculation prior to next run. - newScript.ramUsage = null; - newScript.server = destServer.hostname; + const newScript = new Script(file, sourceScript.code, destServer.hostname); + // If the script being copied has no dependencies, reuse the module / URL + // The new script will not show up in the correct location in the sources tab because it is just reusing the module from a different server destServer.scripts.push(newScript); helpers.log(ctx, () => `File '${file}' copied over to '${destServer?.hostname}'.`); } @@ -1389,7 +1386,7 @@ export const ns: InternalAPI = { } mode === "w" ? (script.code = String(data)) : (script.code += data); // Set ram to null so a recalc is performed the next time ram usage is needed - script.ramUsage = null; + script.invalidateModule(); return; } else { // Write to text file @@ -1831,14 +1828,14 @@ export const ns: InternalAPI = { dest_file.text = source_file.text; } else if (dest_file instanceof Script && source_file instanceof Script) { dest_file.code = source_file.code; - dest_file.markUpdated(); + dest_file.invalidateModule(); } destServer.removeFile(source); } else { source_file.filename = destination; if (source_file instanceof Script) { - source_file.markUpdated(); + source_file.invalidateModule(); } } }, diff --git a/src/NetscriptJSEvaluator.ts b/src/NetscriptJSEvaluator.ts index 652209f49..0736a24ab 100644 --- a/src/NetscriptJSEvaluator.ts +++ b/src/NetscriptJSEvaluator.ts @@ -5,8 +5,7 @@ import * as walk from "acorn-walk"; import { parse } from "acorn"; -import { ScriptUrl } from "./Script/ScriptUrl"; -import { Script } from "./Script/Script"; +import { Script, ScriptURL } from "./Script/Script"; import { areImportsEquals } from "./Terminal/DirectoryHelpers"; import { ScriptModule } from "./Script/ScriptModule"; @@ -18,6 +17,24 @@ function makeScriptBlob(code: string): Blob { return new Blob([code], { type: "text/javascript" }); } +const urlsToRevoke: ScriptURL[] = []; +let activeCompilations = 0; +/** Function to queue up revoking of script URLs. If there's no active compilation, just revoke it now. */ +export const queueUrlRevoke = (url: ScriptURL) => { + if (!activeCompilations) return URL.revokeObjectURL(url); + urlsToRevoke.push(url); +}; + +/** Function to revoke any expired urls */ +function triggerURLRevokes() { + if (activeCompilations === 0) { + // Revoke all pending revoke URLS + urlsToRevoke.forEach((url) => URL.revokeObjectURL(url)); + // Remove all url strings from array + urlsToRevoke.length = 0; + } +} + // Webpack likes to turn the import into a require, which sort of // but not really behaves like import. So we use a "magic comment" // to disable that and leave it as a dynamic import. @@ -29,171 +46,113 @@ function makeScriptBlob(code: string): Blob { // import() is not a function, so it can't be replaced. We need this separate // config object to provide a hook point. export const config = { - doImport(url: string): Promise { + doImport(url: ScriptURL): Promise { return import(/*webpackIgnore:true*/ url); }, }; -export async function compile(script: Script, scripts: Script[]): Promise { - //!shouldCompile ensures that script.module is non-null, hence the "as". - if (!shouldCompile(script, scripts)) return script.module as Promise; - script.queueCompile = true; - //If we're already in the middle of compiling (script.module has not resolved yet), wait for the previous compilation to finish - //If script.module is null, this does nothing. - await script.module; - //If multiple compiles were called on the same script before a compilation could be completed this ensures only one compilation is actually performed. - if (!script.queueCompile) return script.module as Promise; - script.queueCompile = false; - const uurls = _getScriptUrls(script, scripts, []); - const url = uurls[uurls.length - 1].url; - if (script.url && script.url !== url) URL.revokeObjectURL(script.url); - - if (script.dependencies.length > 0) script.dependencies.forEach((dep) => URL.revokeObjectURL(dep.url)); - script.url = uurls[uurls.length - 1].url; - // The URL at the top is the one we want to import. It will - // recursively import all the other modules in the urlStack. - script.module = config.doImport(uurls[uurls.length - 1].url); - script.dependencies = uurls; +export function compile(script: Script, scripts: Script[]): Promise { + // Return the module if it already exists + if (script.module) return script.module; + // While importing, use an existing url or generate a new one. + if (!script.url) script.url = generateScriptUrl(script, scripts, []); + activeCompilations++; + script.module = config + .doImport(script.url) + .catch((e) => { + script.invalidateModule(); + console.error(`Error occurred while attempting to compile ${script.filename} on ${script.server}:`); + console.error(e); + throw e; + }) + .finally(() => { + activeCompilations--; + triggerURLRevokes(); + }); return script.module; } -function isDependencyOutOfDate(filename: string, scripts: Script[], scriptModuleSequenceNumber: number): boolean { - const depScript = scripts.find((s) => s.filename == filename); - - // If the script is not present on the server, we should recompile, if only to get any necessary - // compilation errors. - if (!depScript) return true; - - const depIsMoreRecent = depScript.moduleSequenceNumber > scriptModuleSequenceNumber; - return depIsMoreRecent; -} -/** Returns whether we should compile the script parameter. +/** Add the necessary dependency relationships for a script. + * Dependents are used only for passing invalidation up an import tree, so only direct dependents need to be stored. + * Direct and indirect dependents need to have the current url/script added to their dependency map for error text. * - * @param {Script} script - * @param {Script[]} scripts - */ -function shouldCompile(script: Script, scripts: Script[]): boolean { - if (!script.module) return true; - if (script.dependencies.some((dep) => isDependencyOutOfDate(dep.filename, scripts, script.moduleSequenceNumber))) { - script.module = null; - return true; + * This should only be called once the script has an assigned URL. */ +function addDependencyInfo(script: Script, dependents: Script[]) { + if (!script.url) throw new Error(`addDependencyInfo called without an assigned script URL (${script.filename})`); + if (dependents.length) { + script.dependents.add(dependents[dependents.length - 1]); + for (const dependent of dependents) dependent.dependencies.set(script.url, script); } - return false; } -// Gets a stack of blob urls, the top/right-most element being -// the blob url for the named script on the named server. -// -// - script -- the script for whom we are getting a URL. -// - scripts -- all the scripts available on this server -// - seen -- The modules above this one -- to prevent mutual dependency. -// -// TODO 2.3 consider: Possibly reusing modules when imported in different locations. Per previous notes, this may -// require a topo-sort then url-izing from leaf-most to root-most. /** - * @param {Script} script - * @param {Script[]} scripts - * @param {Script[]} seen - * @returns {ScriptUrl[]} All of the compiled scripts, with the final one - * in the list containing the blob corresponding to - * the script parameter. + * @param script the script that needs a URL assigned + * @param scripts array of other scripts on the server + * @param dependents All scripts that were higher up in the import tree in a recursive call. */ -// BUG: apparently seen is never consulted. Oops. -function _getScriptUrls(script: Script, scripts: Script[], seen: Script[]): ScriptUrl[] { +function generateScriptUrl(script: Script, scripts: Script[], dependents: Script[]): ScriptURL { + // Early return for recursive calls where the script already has a URL + if (script.url) { + addDependencyInfo(script, dependents); + return script.url; + } + // Inspired by: https://stackoverflow.com/a/43834063/91401 - const urlStack: ScriptUrl[] = []; - // Seen contains the dependents of the current script. Make sure we include that in the script dependents. - for (const dependent of seen) { - if (!script.dependents.some((s) => s.server === dependent.server && s.filename == dependent.filename)) { - script.dependents.push({ server: dependent.server, filename: dependent.filename }); - } + const ast = parse(script.code, { sourceType: "module", ecmaVersion: "latest", ranges: true }); + interface importNode { + filename: string; + start: number; + end: number; } - seen.push(script); - try { - // Replace every import statement with an import to a blob url containing - // the corresponding script. E.g. - // - // import {foo} from "bar.js"; - // - // becomes - // - // import {foo} from "blob://" - // - // Where the blob URL contains the script content. + const importNodes: importNode[] = []; + // Walk the nodes of this tree and find any import declaration statements. + walk.simple(ast, { + ImportDeclaration(node: Node) { + // Push this import onto the stack to replace + if (!node.source) return; + importNodes.push({ + filename: node.source.value, + start: node.source.range[0] + 1, + end: node.source.range[1] - 1, + }); + }, + ExportNamedDeclaration(node: Node) { + if (!node.source) return; + importNodes.push({ + filename: node.source.value, + start: node.source.range[0] + 1, + end: node.source.range[1] - 1, + }); + }, + ExportAllDeclaration(node: Node) { + if (!node.source) return; + importNodes.push({ + filename: node.source.value, + start: node.source.range[0] + 1, + end: node.source.range[1] - 1, + }); + }, + }); + // Sort the nodes from last start index to first. This replaces the last import with a blob first, + // preventing the ranges for other imports from being shifted. + importNodes.sort((a, b) => b.start - a.start); + let newCode = script.code; + // Loop through each node and replace the script name with a blob url. + for (const node of importNodes) { + const filename = node.filename.startsWith("./") ? node.filename.substring(2) : node.filename; - // Parse the code into an ast tree - const ast = parse(script.code, { sourceType: "module", ecmaVersion: "latest", ranges: true }); - interface importNode { - filename: string; - start: number; - end: number; - } - const importNodes: importNode[] = []; - // Walk the nodes of this tree and find any import declaration statements. - walk.simple(ast, { - ImportDeclaration(node: Node) { - // Push this import onto the stack to replace - if (!node.source) return; - importNodes.push({ - filename: node.source.value, - start: node.source.range[0] + 1, - end: node.source.range[1] - 1, - }); - }, - ExportNamedDeclaration(node: Node) { - if (!node.source) return; - importNodes.push({ - filename: node.source.value, - start: node.source.range[0] + 1, - end: node.source.range[1] - 1, - }); - }, - ExportAllDeclaration(node: Node) { - if (!node.source) return; - importNodes.push({ - filename: node.source.value, - start: node.source.range[0] + 1, - end: node.source.range[1] - 1, - }); - }, - }); - // Sort the nodes from last start index to first. This replaces the last import with a blob first, - // preventing the ranges for other imports from being shifted. - importNodes.sort((a, b) => b.start - a.start); - let transformedCode = script.code; - // Loop through each node and replace the script name with a blob url. - for (const node of importNodes) { - const filename = node.filename.startsWith("./") ? node.filename.substring(2) : node.filename; + // Find the corresponding script. + const importedScript = scripts.find((s) => areImportsEquals(s.filename, filename)); + if (!importedScript) continue; - // Find the corresponding script. - const matchingScripts = scripts.filter((s) => areImportsEquals(s.filename, filename)); - if (matchingScripts.length === 0) continue; - - const [importedScript] = matchingScripts; - - const urls = _getScriptUrls(importedScript, scripts, seen); - - // The top url in the stack is the replacement import file for this script. - urlStack.push(...urls); - const blob = urls[urls.length - 1].url; - - // Replace the blob inside the import statement. - transformedCode = transformedCode.substring(0, node.start) + blob + transformedCode.substring(node.end); - } - - // We automatically define a print function() in the NetscriptJS module so that - // accidental calls to window.print() do not bring up the "print screen" dialog - transformedCode += `\n//# sourceURL=${script.server}/${script.filename}`; - - const blob = URL.createObjectURL(makeScriptBlob(transformedCode)); - // Push the blob URL onto the top of the stack. - urlStack.push(new ScriptUrl(script.filename, blob, script.moduleSequenceNumber)); - return urlStack; - } catch (err) { - // If there is an error, we need to clean up the URLs. - for (const url of urlStack) URL.revokeObjectURL(url.url); - throw err; - } finally { - seen.pop(); + importedScript.url = generateScriptUrl(importedScript, scripts, [...dependents, script]); + newCode = newCode.substring(0, node.start) + importedScript.url + newCode.substring(node.end); } + + newCode += `\n//# sourceURL=${script.server}/${script.filename}`; + + // At this point we have the full code and can construct a new blob / assign the URL. + script.url = URL.createObjectURL(makeScriptBlob(newCode)) as ScriptURL; + addDependencyInfo(script, dependents); + return script.url; } diff --git a/src/NetscriptWorker.ts b/src/NetscriptWorker.ts index 374a63380..68b8e1d86 100644 --- a/src/NetscriptWorker.ts +++ b/src/NetscriptWorker.ts @@ -51,16 +51,16 @@ export function prestigeWorkerScripts(): void { async function startNetscript2Script(workerScript: WorkerScript): Promise { const scripts = workerScript.getServer().scripts; const script = workerScript.getScript(); - 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); + if (!script) throw "workerScript had no associated script. This is a bug."; const ns = workerScript.env.vars; + if (!ns) throw `${script.filename} cannot be run because the NS object hasn't been constructed properly.`; + + const loadedModule = await compile(script, scripts); if (!loadedModule) throw `${script.filename} cannot be run because the script module won't load`; // TODO unplanned: Better error for "unexpected reserved word" when using await in non-async function? if (typeof loadedModule.main !== "function") throw `${script.filename} cannot be run because it does not have a main function.`; - if (!ns) throw `${script.filename} cannot be run because the NS object hasn't been constructed properly.`; await loadedModule.main(ns); } @@ -295,6 +295,7 @@ export function startWorkerScript(runningScript: RunningScript, server: BaseServ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseServer, parent?: WorkerScript): boolean { const ramUsage = roundToTwo(runningScriptObj.ramUsage * runningScriptObj.threads); const ramAvailable = server.maxRam - server.ramUsed; + // Check failure conditions before generating the workersScript and return false if (ramUsage > ramAvailable + 0.001) { dialogBoxCreate( `Not enough RAM to run script ${runningScriptObj.filename} with args ${arrayToString(runningScriptObj.args)}.\n` + @@ -304,17 +305,18 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS return false; } - server.updateRamUsed(roundToTwo(server.ramUsed + ramUsage)); - // Get the pid const pid = generateNextPid(); if (pid === -1) { - throw new Error( + dialogBoxCreate( `Failed to start script because could not find available PID. This is most ` + `because you have too many scripts running.`, ); + return false; } + server.updateRamUsed(roundToTwo(server.ramUsed + ramUsage)); + // Create the WorkerScript. NOTE: WorkerScript ctor will set the underlying // RunningScript's PID as well const workerScript = new WorkerScript(runningScriptObj, pid, NetscriptFunctions); @@ -366,28 +368,18 @@ export function loadAllRunningScripts(): void { // Reset each server's RAM usage to 0 server.ramUsed = 0; - // Reset modules on all scripts - for (let i = 0; i < server.scripts.length; ++i) { - server.scripts[i].markUpdated(); - } - if (skipScriptLoad) { // Start game with no scripts server.runningScripts.length = 0; - } else { - for (let j = 0; j < server.runningScripts.length; ++j) { - const fileName = server.runningScripts[j].filename; - createAndAddWorkerScript(server.runningScripts[j], server); - - if (!server.runningScripts[j]) { - // createAndAddWorkerScript can modify the server.runningScripts array if a script is invalid - console.error(`createAndAddWorkerScript removed ${fileName} from ${server}`); - continue; - } - - // Offline production - scriptCalculateOfflineProduction(server.runningScripts[j]); - } + continue; + } + // Using backwards index iteration to avoid complications when removing elements during iteration. + for (let i = server.runningScripts.length - 1; i >= 0; i--) { + const runningScript = server.runningScripts[i]; + const success = createAndAddWorkerScript(runningScript, server); + scriptCalculateOfflineProduction(runningScript); + // Remove the RunningScript if the WorkerScript failed to start. + if (!success) server.runningScripts.splice(i, 1); } } } diff --git a/src/PersonObjects/Player/PlayerObject.ts b/src/PersonObjects/Player/PlayerObject.ts index 117a6fd0a..e45e3e8ca 100644 --- a/src/PersonObjects/Player/PlayerObject.ts +++ b/src/PersonObjects/Player/PlayerObject.ts @@ -20,7 +20,7 @@ import { HacknetNode } from "../../Hacknet/HacknetNode"; import { HashManager } from "../../Hacknet/HashManager"; import { MoneySourceTracker } from "../../utils/MoneySourceTracker"; -import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../../utils/JSONReviver"; +import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../../utils/JSONReviver"; import { PlayerAchievement } from "../../Achievements/Achievements"; import { cyrb53 } from "../../utils/StringHelperFunctions"; import { getRandomInt } from "../../utils/helpers/getRandomInt"; @@ -175,4 +175,4 @@ export class PlayerObject extends Person implements IPlayer { setPlayer(new PlayerObject()); -Reviver.constructors.PlayerObject = PlayerObject; +constructorsForReviver.PlayerObject = PlayerObject; diff --git a/src/PersonObjects/Sleeve/Sleeve.ts b/src/PersonObjects/Sleeve/Sleeve.ts index ed25a502a..5be9a807d 100644 --- a/src/PersonObjects/Sleeve/Sleeve.ts +++ b/src/PersonObjects/Sleeve/Sleeve.ts @@ -22,7 +22,7 @@ import { CityName, CrimeType, GymType, LocationName, UniversityClassType } from import { Factions } from "../../Faction/Factions"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../utils/JSONReviver"; import { formatPercent } from "../../ui/formatNumber"; import { FactionWorkType } from "../../Enums"; import { SleeveWork } from "./Work/Work"; @@ -480,4 +480,4 @@ export class Sleeve extends Person implements SleevePerson { } } -Reviver.constructors.Sleeve = Sleeve; +constructorsForReviver.Sleeve = Sleeve; diff --git a/src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts b/src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts index 85d9d0455..40c6d2aa6 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts @@ -1,5 +1,5 @@ import { Player } from "@player"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Sleeve } from "../Sleeve"; import { applySleeveGains, Work, WorkType } from "./Work"; import { CONSTANTS } from "../../../Constants"; @@ -84,4 +84,4 @@ export class SleeveBladeburnerWork extends Work { } } -Reviver.constructors.SleeveBladeburnerWork = SleeveBladeburnerWork; +constructorsForReviver.SleeveBladeburnerWork = SleeveBladeburnerWork; diff --git a/src/PersonObjects/Sleeve/Work/SleeveClassWork.ts b/src/PersonObjects/Sleeve/Work/SleeveClassWork.ts index 410c0c050..f80921414 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveClassWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveClassWork.ts @@ -1,4 +1,4 @@ -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { applySleeveGains, Work, WorkType } from "./Work"; import { Classes, ClassType } from "../../../Work/ClassWork"; import { LocationName } from "../../../Enums"; @@ -60,4 +60,4 @@ export class SleeveClassWork extends Work { } } -Reviver.constructors.SleeveClassWork = SleeveClassWork; +constructorsForReviver.SleeveClassWork = SleeveClassWork; diff --git a/src/PersonObjects/Sleeve/Work/SleeveCompanyWork.ts b/src/PersonObjects/Sleeve/Work/SleeveCompanyWork.ts index 94379065f..ffc3baf79 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveCompanyWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveCompanyWork.ts @@ -1,4 +1,4 @@ -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Sleeve } from "../Sleeve"; import { applySleeveGains, Work, WorkType } from "./Work"; import { LocationName } from "../../../Enums"; @@ -63,4 +63,4 @@ export class SleeveCompanyWork extends Work { } } -Reviver.constructors.SleeveCompanyWork = SleeveCompanyWork; +constructorsForReviver.SleeveCompanyWork = SleeveCompanyWork; diff --git a/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts b/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts index 3f7e4e06d..2713a19f3 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts @@ -1,5 +1,5 @@ import { Player } from "@player"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Sleeve } from "../Sleeve"; import { applySleeveGains, Work, WorkType } from "./Work"; import { CrimeType } from "../../../Enums"; @@ -72,4 +72,4 @@ export class SleeveCrimeWork extends Work { } } -Reviver.constructors.SleeveCrimeWork = SleeveCrimeWork; +constructorsForReviver.SleeveCrimeWork = SleeveCrimeWork; diff --git a/src/PersonObjects/Sleeve/Work/SleeveFactionWork.ts b/src/PersonObjects/Sleeve/Work/SleeveFactionWork.ts index 74dcba1ad..b82b5a6dc 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveFactionWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveFactionWork.ts @@ -1,5 +1,5 @@ import { Player } from "@player"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Sleeve } from "../Sleeve"; import { applySleeveGains, Work, WorkType } from "./Work"; import { FactionWorkType } from "../../../Enums"; @@ -74,4 +74,4 @@ export class SleeveFactionWork extends Work { } } -Reviver.constructors.SleeveFactionWork = SleeveFactionWork; +constructorsForReviver.SleeveFactionWork = SleeveFactionWork; diff --git a/src/PersonObjects/Sleeve/Work/SleeveInfiltrateWork.ts b/src/PersonObjects/Sleeve/Work/SleeveInfiltrateWork.ts index b01a4b835..474fadcf6 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveInfiltrateWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveInfiltrateWork.ts @@ -1,5 +1,5 @@ import { Player } from "@player"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Sleeve } from "../Sleeve"; import { Work, WorkType } from "./Work"; import { CONSTANTS } from "../../../Constants"; @@ -45,4 +45,4 @@ export class SleeveInfiltrateWork extends Work { } } -Reviver.constructors.SleeveInfiltrateWork = SleeveInfiltrateWork; +constructorsForReviver.SleeveInfiltrateWork = SleeveInfiltrateWork; diff --git a/src/PersonObjects/Sleeve/Work/SleeveRecoveryWork.ts b/src/PersonObjects/Sleeve/Work/SleeveRecoveryWork.ts index 5655741f5..3065a4bff 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveRecoveryWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveRecoveryWork.ts @@ -1,4 +1,4 @@ -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Sleeve } from "../Sleeve"; import { Work, WorkType } from "./Work"; import { calculateIntelligenceBonus } from "../../formulas/intelligence"; @@ -32,4 +32,4 @@ export class SleeveRecoveryWork extends Work { } } -Reviver.constructors.SleeveRecoveryWork = SleeveRecoveryWork; +constructorsForReviver.SleeveRecoveryWork = SleeveRecoveryWork; diff --git a/src/PersonObjects/Sleeve/Work/SleeveSupportWork.ts b/src/PersonObjects/Sleeve/Work/SleeveSupportWork.ts index 093e1818e..0310e62f1 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveSupportWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveSupportWork.ts @@ -1,5 +1,5 @@ import { Player } from "@player"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Work, WorkType } from "./Work"; export const isSleeveSupportWork = (w: Work | null): w is SleeveSupportWork => @@ -35,4 +35,4 @@ export class SleeveSupportWork extends Work { } } -Reviver.constructors.SleeveSupportWork = SleeveSupportWork; +constructorsForReviver.SleeveSupportWork = SleeveSupportWork; diff --git a/src/PersonObjects/Sleeve/Work/SleeveSynchroWork.ts b/src/PersonObjects/Sleeve/Work/SleeveSynchroWork.ts index 86e586505..0c9cab0a2 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveSynchroWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveSynchroWork.ts @@ -1,5 +1,5 @@ import { Player } from "@player"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../../utils/JSONReviver"; import { Sleeve } from "../Sleeve"; import { Work, WorkType } from "./Work"; import { calculateIntelligenceBonus } from "../../formulas/intelligence"; @@ -33,4 +33,4 @@ export class SleeveSynchroWork extends Work { } } -Reviver.constructors.SleeveSynchroWork = SleeveSynchroWork; +constructorsForReviver.SleeveSynchroWork = SleeveSynchroWork; diff --git a/src/Prestige.ts b/src/Prestige.ts index 6f6df39a7..621d984b6 100755 --- a/src/Prestige.ts +++ b/src/Prestige.ts @@ -191,6 +191,8 @@ export function prestigeSourceFile(flume: boolean): void { // Reset home computer (only the programs) and add to AllServers AddToAllServers(homeComp); prestigeHomeComputer(homeComp); + // Ram usage needs to be cleared for bitnode-level resets, due to possible change in singularity cost. + for (const script of homeComp.scripts) script.ramUsage = undefined; // Re-create foreign servers initForeignServers(Player.getHomeComputer()); diff --git a/src/SaveObject.tsx b/src/SaveObject.tsx index b5f785847..405591ddc 100755 --- a/src/SaveObject.tsx +++ b/src/SaveObject.tsx @@ -21,7 +21,7 @@ import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar"; import * as ExportBonus from "./ExportBonus"; import { dialogBoxCreate } from "./ui/React/DialogBox"; -import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "./utils/JSONReviver"; +import { Reviver, constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "./utils/JSONReviver"; import { save } from "./db"; import { AwardNFG, v1APIBreak } from "./utils/v1APIBreak"; import { AugmentationNames } from "./Augmentation/data/AugmentationNames"; @@ -798,7 +798,7 @@ function download(filename: string, content: string): void { }, 0); } -Reviver.constructors.BitburnerSaveObject = BitburnerSaveObject; +constructorsForReviver.BitburnerSaveObject = BitburnerSaveObject; export { saveObject, loadGame, download }; diff --git a/src/Script/RunningScript.ts b/src/Script/RunningScript.ts index d7977348b..342f8be4d 100644 --- a/src/Script/RunningScript.ts +++ b/src/Script/RunningScript.ts @@ -3,16 +3,16 @@ * A Script can have multiple active instances */ import type React from "react"; -import { Script } from "./Script"; -import { ScriptUrl } from "./ScriptUrl"; +import { Script, ScriptURL } from "./Script"; import { Settings } from "../Settings/Settings"; import { Terminal } from "../Terminal"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { formatTime } from "../utils/helpers/formatTime"; import { ScriptArg } from "@nsdefs"; import { RamCostConstants } from "../Netscript/RamCostGenerator"; import { PositiveInteger } from "../types"; +import { getKeyList } from "../utils/helpers/getKeyList"; export class RunningScript { // Script arguments @@ -23,7 +23,7 @@ export class RunningScript { dataMap: Record = {}; // Script filename - filename = ""; + filename = "default.js"; // This script's logs. An array of log entries logs: React.ReactNode[] = []; @@ -66,7 +66,8 @@ export class RunningScript { temporary = false; // Script urls for the current running script for translating urls back to file names in errors - dependencies: ScriptUrl[] = []; + dependencies: Map = new Map(); + url?: ScriptURL; constructor(script?: Script, ramUsage?: number, args: ScriptArg[] = []) { if (!script) return; @@ -75,7 +76,7 @@ export class RunningScript { this.args = args; this.server = script.server; this.ramUsage = ramUsage; - this.dependencies = script.dependencies; + this.dependencies = new Map(script.dependencies); } log(txt: React.ReactNode): void { @@ -133,13 +134,14 @@ export class RunningScript { // Serialize the current object to a JSON save state toJSON(): IReviverValue { - return Generic_toJSON("RunningScript", this); + return Generic_toJSON("RunningScript", this, includedProperties); } // Initializes a RunningScript Object from a JSON save state static fromJSON(value: IReviverValue): RunningScript { - return Generic_fromJSON(RunningScript, value.data); + return Generic_fromJSON(RunningScript, value.data, includedProperties); } } +const includedProperties = getKeyList(RunningScript, { removedKeys: ["logs", "dependencies", "logUpd", "pid"] }); -Reviver.constructors.RunningScript = RunningScript; +constructorsForReviver.RunningScript = RunningScript; diff --git a/src/Script/Script.ts b/src/Script/Script.ts index 3171f6589..79655ebdf 100644 --- a/src/Script/Script.ts +++ b/src/Script/Script.ts @@ -5,58 +5,38 @@ * being evaluated. See RunningScript for that */ import { calculateRamUsage, RamUsageEntry } from "./RamCalculations"; -import { ScriptUrl } from "./ScriptUrl"; -import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver"; +import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver"; import { roundToTwo } from "../utils/helpers/roundToTwo"; import { ScriptModule } from "./ScriptModule"; import { RamCostConstants } from "../Netscript/RamCostGenerator"; +import { queueUrlRevoke } from "../NetscriptJSEvaluator"; -let globalModuleSequenceNumber = 0; - -interface ScriptReference { - filename: string; - server: string; -} +// The object portion of this type is not runtime information, it's only to ensure type validation +// And make it harder to overwrite a url with a random non-url string. +export type ScriptURL = string & { __type: "ScriptURL" }; export class Script { - // Code for this script code = ""; + filename = "default.js"; + server = "home"; - // Filename for the script file - filename = ""; - - // url of the script if any, only for NS2. - url = ""; - - // The dynamic module generated for this script when it is run. - // This is only applicable for NetscriptJS - module: Promise | null = null; - - // The timestamp when when the script was last updated. - moduleSequenceNumber: number; - - // Only used with NS2 scripts; the list of dependency script filenames. This is constructed - // whenever the script is first evaluated, and therefore may be out of date if the script - // has been updated since it was last run. - dependencies: ScriptUrl[] = []; - dependents: ScriptReference[] = []; - - // Amount of RAM this Script requires to run. null indicates an error in calculating ram. - ramUsage: number | null = null; + // Ram calculation, only exists after first poll of ram cost after updating + ramUsage?: number; ramUsageEntries?: RamUsageEntry[]; - // Used to deconflict multiple simultaneous compilations. - queueCompile = false; - - // hostname of server that this script is on. - server = ""; + // Runtime data that only exists when the script has been initiated. Cleared when script or a dependency script is updated. + module?: Promise; + url?: ScriptURL; + /** Scripts that directly import this one. Stored so we can invalidate these dependent scripts when this one is invalidated. */ + dependents: Set