// @ts-expect-error const metaUrl = import.meta.url; const _window = eval("window") as typeof window & { cheat?: CheatState }; interface CheatState { readonly pid: number, readonly metaUrl: typeof metaUrl, }; function getNSProp( obj: T, key: string, ): { method: Function } | { obj: object } | undefined { if (!Object.hasOwn(obj, key)) return undefined; const value = (obj as Record)[key]; if (typeof value === "function") return { method: value }; if (typeof value === "object" && value !== null) return { obj: value }; return undefined; } type RecurUnderscore = { [K in keyof T as K extends string ? T[K] extends ((...args: any[]) => any) ? ReturnType extends Promise ? never : `_${K}` : T[K] extends object ? `_${K}` : K : K ]: T[K] extends Function ? T[K] : T[K] extends object ? RecurUnderscore : T[K]; }; type a = (() => void) extends object ? "yes" : "no"; function cheatProxy(ns: NS) { const proxies = new Map(); const methods = new Set(); let ram = ns.ramOverride(); if (ram !== 1.6) throw new Error(`expected ${ns.formatRam(1.6)} of initial ram, got ${ns.formatRam(ram)}`); const createProxy = (obj: object, path: string[]) => new Proxy(obj, { get(target, key, receiver) { ns.tprint(`access ${String(key)}`); if (typeof key === "symbol" || key.charAt(0) !== "_") return Reflect.get(target, key, receiver); key = key.substring(1); const prop = getNSProp(obj, key); if (prop !== undefined) { const funcParts = [...path, key]; const funcPath = funcParts.join("."); if ("method" in prop) { if (!methods.has(funcPath)) { const oldRam = ram; const cost = ns.getFunctionRamCost(funcPath); ram = ns.ramOverride(ram + cost); ns.tprint(`${funcPath} accessed, increasing RAM by ${ns.formatRam(cost)}, from ${ns.formatRam(oldRam)} to ${ns.formatRam(ram)}`); if (ram === oldRam) throw new Error(`There's not enough RAM available on cheat host. ${funcPath} requires ${ns.formatRam(cost)}.`); methods.add(key); } return Reflect.get(target, key, receiver); } if ("obj" in prop) { if (!proxies.has(prop.obj)) proxies.set(prop.obj, createProxy(prop.obj, funcParts)); return proxies.get(prop.obj); } console.log(key, prop); throw new Error("unhandled prop"); } else return Reflect.get(target, key, receiver); } }); return createProxy(ns, []) as RecurUnderscore; } let cheatNS: RecurUnderscore | undefined; export function getCheatNS() { return cheatNS!; }; export async function main(ns: NS) { if (_window.cheat !== undefined) { ns.tprint(` Cheat is already running as PID ${_window.cheat.pid} metaUrls are ${metaUrl === _window.cheat.metaUrl ? "" : "not"} matching window.cheat: ${_window.cheat.metaUrl} cheat.ts: ${metaUrl}`); return; } _window.cheat = { pid: ns.pid, metaUrl, }; cheatNS = cheatProxy(ns); ns.atExit(() => { if (_window.cheat?.metaUrl === metaUrl) _window.cheat = undefined; cheatNS = undefined; }) await new Promise(() => {}); }