diff --git a/src/Bladeburner/Bladeburner.tsx b/src/Bladeburner/Bladeburner.tsx index 2fecb70f6..38276949a 100644 --- a/src/Bladeburner/Bladeburner.tsx +++ b/src/Bladeburner/Bladeburner.tsx @@ -1,3 +1,4 @@ +import type { PromisePair } from "../Types/Promises"; import { AugmentationName, CityName, FactionName } from "@enums"; import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { ActionIdentifier } from "./ActionIdentifier"; @@ -42,8 +43,7 @@ export interface BlackOpsAttempt { isAvailable?: boolean; action?: BlackOperation; } - -export const BladeburnerResolvers: ((msProcessed: number) => void)[] = []; +export const BladeburnerPromise: PromisePair = { promise: null, resolve: null }; export class Bladeburner { numHosp = 0; @@ -2085,9 +2085,11 @@ export class Bladeburner { } } - // Handle "nextUpdate" resolvers after this update - for (const resolve of BladeburnerResolvers.splice(0)) { - resolve(seconds * 1000); + // Handle "nextUpdate" resolver after this update + if (BladeburnerPromise.resolve) { + BladeburnerPromise.resolve(seconds * 1000); + BladeburnerPromise.resolve = null; + BladeburnerPromise.promise = null; } } } diff --git a/src/Corporation/Corporation.ts b/src/Corporation/Corporation.ts index 1131c1f76..8241f0fef 100644 --- a/src/Corporation/Corporation.ts +++ b/src/Corporation/Corporation.ts @@ -1,3 +1,4 @@ +import type { PromisePair } from "../Types/Promises"; import { Player } from "@player"; import { CorpStateName, InvestmentOffer } from "@nsdefs"; import { CorpUnlockName, CorpUpgradeName, LiteratureName } from "@enums"; @@ -19,7 +20,7 @@ import { formatMoney } from "../ui/formatNumber"; import { isPositiveInteger } from "../types"; import { createEnumKeyedRecord, getRecordValues } from "../Types/Record"; -export const CorporationResolvers: ((prevState: CorpStateName) => void)[] = []; +export const CorporationPromise: PromisePair = { promise: null, resolve: null }; interface ICorporationParams { name?: string; @@ -175,9 +176,11 @@ export class Corporation { this.state.incrementState(); - // Handle "nextUpdate" resolvers after this update - for (const resolve of CorporationResolvers.splice(0)) { - resolve(state); + // Handle "nextUpdate" resolver after this update + if (CorporationPromise.resolve) { + CorporationPromise.resolve(state); + CorporationPromise.resolve = null; + CorporationPromise.promise = null; } } } diff --git a/src/Gang/Gang.ts b/src/Gang/Gang.ts index 1b4954147..9ed75dd27 100644 --- a/src/Gang/Gang.ts +++ b/src/Gang/Gang.ts @@ -3,6 +3,7 @@ * Add police clashes * balance point to keep them from running out of control */ +import type { PromisePair } from "../Types/Promises"; import { Factions } from "../Faction/Factions"; @@ -26,8 +27,7 @@ import { PowerMultiplier } from "./data/power"; import { FactionName } from "@enums"; import { CONSTANTS } from "../Constants"; -type NextUpdateData = { resolver: ((msProcessed: number) => void) | null; promise: Promise | null }; -export const GangNextUpdate: NextUpdateData = { resolver: null, promise: null }; +export const GangPromise: PromisePair = { promise: null, resolve: null }; export class Gang { facName: FactionName; @@ -108,10 +108,10 @@ export class Gang { } // Handle "nextUpdate" resolver after this update - if (GangNextUpdate.resolver) { - GangNextUpdate.resolver(cycles * CONSTANTS.MilliPerCycle); - GangNextUpdate.resolver = null; - GangNextUpdate.promise = null; + if (GangPromise.resolve) { + GangPromise.resolve(cycles * CONSTANTS.MilliPerCycle); + GangPromise.resolve = null; + GangPromise.promise = null; } } diff --git a/src/NetscriptFunctions/Bladeburner.ts b/src/NetscriptFunctions/Bladeburner.ts index 7d293a4d8..752619c3b 100644 --- a/src/NetscriptFunctions/Bladeburner.ts +++ b/src/NetscriptFunctions/Bladeburner.ts @@ -3,7 +3,7 @@ import type { Action } from "../Bladeburner/Action"; import type { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { Player } from "@player"; -import { Bladeburner, BladeburnerResolvers } from "../Bladeburner/Bladeburner"; +import { Bladeburner, BladeburnerPromise } from "../Bladeburner/Bladeburner"; import { currentNodeMults } from "../BitNode/BitNodeMultipliers"; import { BlackOperation } from "../Bladeburner/BlackOperation"; import { helpers } from "../Netscript/NetscriptHelpers"; @@ -329,8 +329,11 @@ export function NetscriptBladeburner(): InternalAPI { const bladeburner = getBladeburner(ctx); return Math.round(bladeburner.storedCycles / 5) * 1000; }, - nextUpdate: () => () => { - return new Promise((res) => BladeburnerResolvers.push(res)); + nextUpdate: (ctx) => () => { + checkBladeburnerAccess(ctx); + if (!BladeburnerPromise.promise) + BladeburnerPromise.promise = new Promise((res) => (BladeburnerPromise.resolve = res)); + return BladeburnerPromise.promise; }, }; } diff --git a/src/NetscriptFunctions/Corporation.ts b/src/NetscriptFunctions/Corporation.ts index 8731d6a2f..d9f023b07 100644 --- a/src/NetscriptFunctions/Corporation.ts +++ b/src/NetscriptFunctions/Corporation.ts @@ -5,7 +5,7 @@ import { Product } from "../Corporation/Product"; import { Material } from "../Corporation/Material"; import { Warehouse } from "../Corporation/Warehouse"; import { Division } from "../Corporation/Division"; -import { Corporation, CorporationResolvers } from "../Corporation/Corporation"; +import { Corporation, CorporationPromise } from "../Corporation/Corporation"; import { omit } from "lodash"; import { setDeprecatedProperties } from "../utils/DeprecationHelper"; import { @@ -800,7 +800,9 @@ export function NetscriptCorporation(): InternalAPI { }, nextUpdate: (ctx) => () => { checkAccess(ctx); - return new Promise((res) => CorporationResolvers.push(res)); + if (!CorporationPromise.promise) + CorporationPromise.promise = new Promise((res) => (CorporationPromise.resolve = res)); + return CorporationPromise.promise; }, }; diff --git a/src/NetscriptFunctions/Gang.ts b/src/NetscriptFunctions/Gang.ts index c868bd457..899be4c9e 100644 --- a/src/NetscriptFunctions/Gang.ts +++ b/src/NetscriptFunctions/Gang.ts @@ -4,7 +4,7 @@ import type { GangMember } from "../Gang/GangMember"; import type { GangMemberTask } from "../Gang/GangMemberTask"; import type { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; -import { GangNextUpdate } from "../Gang/Gang"; +import { GangPromise } from "../Gang/Gang"; import { Player } from "@player"; import { FactionName } from "@enums"; import { GangConstants } from "../Gang/data/Constants"; @@ -324,11 +324,10 @@ export function NetscriptGang(): InternalAPI { const gang = getGang(ctx); return Math.round(gang.storedCycles / 5) * 1000; }, - nextUpdate: () => () => { - if (!GangNextUpdate.promise) { - GangNextUpdate.promise = new Promise((res) => (GangNextUpdate.resolver = res)); - } - return GangNextUpdate.promise; + nextUpdate: (ctx) => () => { + getGang(ctx); + if (!GangPromise.promise) GangPromise.promise = new Promise((res) => (GangPromise.resolve = res)); + return GangPromise.promise; }, }; } diff --git a/src/NetscriptFunctions/StockMarket.ts b/src/NetscriptFunctions/StockMarket.ts index 55a0d02c3..0e360f5d5 100644 --- a/src/NetscriptFunctions/StockMarket.ts +++ b/src/NetscriptFunctions/StockMarket.ts @@ -6,7 +6,7 @@ import { placeOrder, cancelOrder, initStockMarket, - StockMarketResolvers, + StockMarketPromise, } from "../StockMarket/StockMarket"; import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/StockMarketHelpers"; import { PositionType, OrderType, StockSymbol } from "@enums"; @@ -415,7 +415,9 @@ export function NetscriptStockMarket(): InternalAPI { }, nextUpdate: (ctx) => () => { checkTixApiAccess(ctx); - return new Promise((res) => StockMarketResolvers.push(res)); + if (!StockMarketPromise.promise) + StockMarketPromise.promise = new Promise((res) => (StockMarketPromise.resolve = res)); + return StockMarketPromise.promise; }, }; } diff --git a/src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts b/src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts index ce87bea28..e7e37aa35 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts @@ -24,11 +24,11 @@ export class SleeveBladeburnerWork extends SleeveWorkClass { signalCompletion = () => { // Intentionally empty function, this is just an initial value and will never be used. }; - nextCompletion: Promise; + nextCompletionPromise: Promise | null; constructor(params?: SleeveBladeburnerWorkParams) { super(); - this.nextCompletion = new Promise((r) => (this.signalCompletion = r)); + this.nextCompletionPromise = null; this.actionType = params?.type ?? "General"; this.actionName = params?.name ?? "Field Analysis"; } @@ -40,7 +40,7 @@ export class SleeveBladeburnerWork extends SleeveWorkClass { } finish() { - this.signalCompletion(); + if (this.nextCompletionPromise) this.signalCompletion(); } process(sleeve: Sleeve, cycles: number) { @@ -73,11 +73,13 @@ export class SleeveBladeburnerWork extends SleeveWorkClass { this.tasksCompleted++; this.cyclesWorked -= this.cyclesNeeded(sleeve); // Resolve and reset nextCompletion promise - const resolver = this.signalCompletion; - this.nextCompletion = new Promise((r) => (this.signalCompletion = r)); - resolver(); + if (this.nextCompletionPromise) this.signalCompletion(); } } + get nextCompletion(): Promise { + if (!this.nextCompletionPromise) this.nextCompletionPromise = new Promise((r) => (this.signalCompletion = r)); + return this.nextCompletionPromise; + } APICopy(sleeve: Sleeve) { return { diff --git a/src/StockMarket/StockMarket.tsx b/src/StockMarket/StockMarket.tsx index b6866ed78..afbef7a83 100644 --- a/src/StockMarket/StockMarket.tsx +++ b/src/StockMarket/StockMarket.tsx @@ -1,3 +1,4 @@ +import type { PromisePair } from "../Types/Promises"; import type { IOrderBook } from "./IOrderBook"; import type { IStockMarket } from "./IStockMarket"; import { Order } from "./Order"; @@ -25,7 +26,7 @@ export let StockMarket: IStockMarket = { // Gross type, needs to be addressed export const SymbolToStockMap: Record = {}; // Maps symbol -> Stock object -export const StockMarketResolvers: ((msProcessed: number) => void)[] = []; +export const StockMarketPromise: PromisePair = { promise: null, resolve: null }; export function placeOrder( stock: Stock, @@ -280,9 +281,10 @@ export function processStockPrices(numCycles = 1): void { // Shares required for price movement gradually approaches max over time stock.shareTxUntilMovement = Math.min(stock.shareTxUntilMovement + 10, stock.shareTxForMovement); } - - // Handle "nextUpdate" resolvers after this update - for (const resolve of StockMarketResolvers.splice(0)) { - resolve(StockMarketConstants.msPerStockUpdate); + // Handle "nextUpdate" resolver after this update + if (StockMarketPromise.resolve) { + StockMarketPromise.resolve(StockMarketConstants.msPerStockUpdate); + StockMarketPromise.resolve = null; + StockMarketPromise.promise = null; } } diff --git a/src/Types/Promises.ts b/src/Types/Promises.ts new file mode 100644 index 000000000..0b62e38be --- /dev/null +++ b/src/Types/Promises.ts @@ -0,0 +1,5 @@ +// An object that contains a promise and its resolver (or possibly null) +export type PromisePair = { + promise: Promise | null; + resolve: ((value: ReturnType) => void) | null; +};