mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-18 12:15:44 +01:00
NETSCRIPT: More ns Proxy changes (#297)
This commit is contained in:
parent
3281b785ce
commit
4eef9eec03
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "bitburner",
|
"name": "bitburner",
|
||||||
"version": "2.2.0",
|
"version": "2.2.2dev",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "bitburner",
|
"name": "bitburner",
|
||||||
"version": "2.2.0",
|
"version": "2.2.2dev",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "SEE LICENSE IN license.txt",
|
"license": "SEE LICENSE IN license.txt",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "bitburner",
|
"name": "bitburner",
|
||||||
"license": "SEE LICENSE IN license.txt",
|
"license": "SEE LICENSE IN license.txt",
|
||||||
"version": "2.2.0",
|
"version": "2.2.2dev",
|
||||||
"main": "electron-main.js",
|
"main": "electron-main.js",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Daniel Xie, Olivier Gagnon, et al."
|
"name": "Daniel Xie, Olivier Gagnon, et al."
|
||||||
|
@ -3,18 +3,14 @@ import type { WorkerScript } from "./WorkerScript";
|
|||||||
import { helpers } from "./NetscriptHelpers";
|
import { helpers } from "./NetscriptHelpers";
|
||||||
|
|
||||||
/** Permissive type for the documented API functions */
|
/** Permissive type for the documented API functions */
|
||||||
type APIFn = (...args: any[]) => void;
|
type APIFn = (...args: any[]) => unknown;
|
||||||
/** Type for the actual wrapped function given to the player */
|
|
||||||
type WrappedFn = (...args: unknown[]) => unknown;
|
|
||||||
/** Type for internal, unwrapped ctx function that produces an APIFunction */
|
/** Type for internal, unwrapped ctx function that produces an APIFunction */
|
||||||
type InternalFn<F extends APIFn> = (ctx: NetscriptContext) => ((...args: unknown[]) => ReturnType<F>) & F;
|
type InternalFn<F extends APIFn> = (ctx: NetscriptContext) => ((...args: unknown[]) => ReturnType<F>) & F;
|
||||||
|
/** Type constraint for an API layer. They must all fit this "shape". */
|
||||||
|
type GenericAPI = { [key: string]: APIFn | GenericAPI };
|
||||||
|
|
||||||
// args, enums, and pid are excluded from the API for typing purposes via the definition of NSFull.
|
// args, enums, and pid are excluded from the API for typing purposes via the definition of NSFull.
|
||||||
// They do in fact exist on the external API (but are absent on the internal API and ramcost tree)
|
// They do in fact exist on the external API (but are absent on the internal API and ramcost tree)
|
||||||
export type ExternalAPI<API> = {
|
|
||||||
[key in keyof API]: API[key] extends APIFn ? WrappedFn : ExternalAPI<API[key]>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type InternalAPI<API> = {
|
export type InternalAPI<API> = {
|
||||||
[key in keyof API]: API[key] extends APIFn ? InternalFn<API[key]> : InternalAPI<API[key]>;
|
[key in keyof API]: API[key] extends APIFn ? InternalFn<API[key]> : InternalAPI<API[key]>;
|
||||||
};
|
};
|
||||||
@ -25,70 +21,91 @@ export type NetscriptContext = {
|
|||||||
functionPath: string;
|
functionPath: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function NSProxy<API>(
|
class NSProxyHandler<API extends GenericAPI> {
|
||||||
ws: WorkerScript,
|
ns: API;
|
||||||
ns: InternalAPI<API>,
|
ws: WorkerScript;
|
||||||
tree: string[],
|
tree: string[];
|
||||||
additionalData?: Record<string, unknown>,
|
additionalData: Record<string, unknown>;
|
||||||
): ExternalAPI<API> {
|
memoed: API = {} as API;
|
||||||
const memoed: ExternalAPI<API> = Object.assign({} as ExternalAPI<API>, additionalData ?? {});
|
|
||||||
|
|
||||||
const handler = {
|
constructor(ws: WorkerScript, ns: API, tree: string[], additionalData: Record<string, unknown>) {
|
||||||
has(__target: unknown, key: string) {
|
this.ns = ns;
|
||||||
return Reflect.has(ns, key);
|
this.ws = ws;
|
||||||
},
|
this.tree = tree;
|
||||||
ownKeys(__target: unknown) {
|
this.additionalData = additionalData;
|
||||||
return Reflect.ownKeys(ns);
|
Object.assign(this.memoed, additionalData);
|
||||||
},
|
}
|
||||||
getOwnPropertyDescriptor(__target: unknown, key: keyof API & string) {
|
|
||||||
if (!Reflect.has(ns, key)) return undefined;
|
has(__target: unknown, key: string): boolean {
|
||||||
|
return Reflect.has(this.ns, key) || Reflect.has(this.additionalData, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
ownKeys(__target: unknown): (string | symbol)[] {
|
||||||
|
return [...Reflect.ownKeys(this.ns), ...Reflect.ownKeys(this.additionalData)];
|
||||||
|
}
|
||||||
|
|
||||||
|
getOwnPropertyDescriptor(__target: unknown, key: keyof API & string): PropertyDescriptor | undefined {
|
||||||
|
if (!this.has(__target, key)) return undefined;
|
||||||
return { value: this.get(__target, key, this), configurable: true, enumerable: true, writable: false };
|
return { value: this.get(__target, key, this), configurable: true, enumerable: true, writable: false };
|
||||||
},
|
}
|
||||||
defineProperty(__target: unknown, __key: unknown, __attrs: unknown) {
|
|
||||||
|
defineProperty(__target: unknown, __key: unknown, __attrs: unknown): boolean {
|
||||||
throw new TypeError("ns instances are not modifiable!");
|
throw new TypeError("ns instances are not modifiable!");
|
||||||
},
|
}
|
||||||
set(__target: unknown, __key: unknown, __attrs: unknown) {
|
|
||||||
|
set(__target: unknown, __key: unknown, __attrs: unknown): boolean {
|
||||||
|
// Redundant with defineProperty, but we'll be explicit
|
||||||
throw new TypeError("ns instances are not modifiable!");
|
throw new TypeError("ns instances are not modifiable!");
|
||||||
},
|
}
|
||||||
|
|
||||||
get(__target: unknown, key: keyof API & string, __receiver: any) {
|
get(__target: unknown, key: keyof API & string, __receiver: any) {
|
||||||
const ours = memoed[key];
|
const ours = this.memoed[key];
|
||||||
if (ours) return ours;
|
if (ours) return ours;
|
||||||
|
|
||||||
const field = ns[key];
|
const field = this.ns[key];
|
||||||
if (!field) return field;
|
if (!field) return field;
|
||||||
|
|
||||||
if (typeof field === "function") {
|
if (typeof field === "function") {
|
||||||
const arrayPath = [...tree, key];
|
const arrayPath = [...this.tree, key];
|
||||||
const functionPath = arrayPath.join(".");
|
const functionPath = arrayPath.join(".");
|
||||||
|
const ctx = { workerScript: this.ws, function: key, functionPath };
|
||||||
|
// Only do the context-binding once, instead of each time the function
|
||||||
|
// is called.
|
||||||
|
const func: any = field(ctx);
|
||||||
const wrappedFunction = function (...args: unknown[]): unknown {
|
const wrappedFunction = function (...args: unknown[]): unknown {
|
||||||
const ctx = { workerScript: ws, function: key, functionPath };
|
// What remains *must* be called every time.
|
||||||
const func = field(ctx); //Allows throwing before ram check, for removedFunction
|
|
||||||
helpers.checkEnvFlags(ctx);
|
helpers.checkEnvFlags(ctx);
|
||||||
helpers.updateDynamicRam(ctx, getRamCost(...tree, key));
|
helpers.updateDynamicRam(ctx, getRamCost(...arrayPath));
|
||||||
return func(...args);
|
return func(...args);
|
||||||
};
|
};
|
||||||
return ((memoed[key] as WrappedFn) = wrappedFunction);
|
return ((this.memoed[key] as APIFn) = wrappedFunction);
|
||||||
}
|
}
|
||||||
if (typeof field === "object") {
|
if (typeof field === "object") {
|
||||||
// TODO unplanned: Make this work generically
|
return ((this.memoed[key] as GenericAPI) = NSProxy(this.ws, field as InternalAPI<GenericAPI>, [
|
||||||
return ((memoed[key] as ExternalAPI<API[keyof API]>) = NSProxy(ws, field as InternalAPI<API[keyof API]>, [
|
...this.tree,
|
||||||
...tree,
|
|
||||||
key,
|
key,
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
console.warn(`Unexpected data while wrapping API.`, "tree:", tree, "key:", key, "field:", field);
|
console.warn(`Unexpected data while wrapping API.`, "tree:", this.tree, "key:", key, "field:", field);
|
||||||
throw new Error("Error while wrapping netscript API. See console.");
|
throw new Error("Error while wrapping netscript API. See console.");
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
export function NSProxy<API extends GenericAPI>(
|
||||||
|
ws: WorkerScript,
|
||||||
|
ns: InternalAPI<API>,
|
||||||
|
tree: string[],
|
||||||
|
additionalData: Record<string, unknown> = {},
|
||||||
|
): API {
|
||||||
|
const handler = new NSProxyHandler(ws, ns, tree, additionalData);
|
||||||
// We target an empty Object, so that unproxied methods don't do anything.
|
// We target an empty Object, so that unproxied methods don't do anything.
|
||||||
// We *can't* freeze the target, because it would break invariants on ownKeys.
|
// We *can't* freeze the target, because it would break invariants on ownKeys.
|
||||||
return new Proxy({}, handler) as ExternalAPI<API>;
|
return new Proxy({}, handler) as API;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Specify when a function was removed from the game, and its replacement function. */
|
/** Specify when a function was removed from the game, and its replacement function. */
|
||||||
export function removedFunction(version: string, replacement: string, replaceMsg?: boolean) {
|
export function removedFunction(version: string, replacement: string, replaceMsg?: boolean) {
|
||||||
return (ctx: NetscriptContext) => {
|
return (ctx: NetscriptContext) => () => {
|
||||||
throw helpers.makeRuntimeErrorMsg(
|
throw helpers.makeRuntimeErrorMsg(
|
||||||
ctx,
|
ctx,
|
||||||
`Function removed in ${version}. ${replaceMsg ? replacement : `Please use ${replacement} instead.`}`,
|
`Function removed in ${version}. ${replaceMsg ? replacement : `Please use ${replacement} instead.`}`,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { NSFull } from "../NetscriptFunctions";
|
import { NSFull } from "../NetscriptFunctions";
|
||||||
import { ExternalAPI } from "./APIWrapper";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The environment in which a script runs. The environment holds
|
* The environment in which a script runs. The environment holds
|
||||||
@ -14,5 +13,5 @@ export class Environment {
|
|||||||
runningFn = "";
|
runningFn = "";
|
||||||
|
|
||||||
/** Environment variables (currently only Netscript functions) */
|
/** Environment variables (currently only Netscript functions) */
|
||||||
vars: ExternalAPI<NSFull> | null = null;
|
vars: NSFull | null = null;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@ import { GetServer } from "../Server/AllServers";
|
|||||||
import { BaseServer } from "../Server/BaseServer";
|
import { BaseServer } from "../Server/BaseServer";
|
||||||
import { ScriptDeath } from "./ScriptDeath";
|
import { ScriptDeath } from "./ScriptDeath";
|
||||||
import { ScriptArg } from "./ScriptArg";
|
import { ScriptArg } from "./ScriptArg";
|
||||||
import { ExternalAPI } from "./APIWrapper";
|
|
||||||
import { NSFull } from "../NetscriptFunctions";
|
import { NSFull } from "../NetscriptFunctions";
|
||||||
|
|
||||||
export class WorkerScript {
|
export class WorkerScript {
|
||||||
@ -84,11 +83,7 @@ export class WorkerScript {
|
|||||||
/** Function called when the script ends. */
|
/** Function called when the script ends. */
|
||||||
atExit?: () => void;
|
atExit?: () => void;
|
||||||
|
|
||||||
constructor(
|
constructor(runningScriptObj: RunningScript, pid: number, nsFuncsGenerator?: (ws: WorkerScript) => NSFull) {
|
||||||
runningScriptObj: RunningScript,
|
|
||||||
pid: number,
|
|
||||||
nsFuncsGenerator?: (ws: WorkerScript) => ExternalAPI<NSFull>,
|
|
||||||
) {
|
|
||||||
this.name = runningScriptObj.filename;
|
this.name = runningScriptObj.filename;
|
||||||
this.hostname = runningScriptObj.server;
|
this.hostname = runningScriptObj.server;
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ import { Flags } from "./NetscriptFunctions/Flags";
|
|||||||
import { calculateIntelligenceBonus } from "./PersonObjects/formulas/intelligence";
|
import { calculateIntelligenceBonus } from "./PersonObjects/formulas/intelligence";
|
||||||
import { CalculateShareMult, StartSharing } from "./NetworkShare/Share";
|
import { CalculateShareMult, StartSharing } from "./NetworkShare/Share";
|
||||||
import { recentScripts } from "./Netscript/RecentScripts";
|
import { recentScripts } from "./Netscript/RecentScripts";
|
||||||
import { ExternalAPI, InternalAPI, removedFunction, NSProxy } from "./Netscript/APIWrapper";
|
import { InternalAPI, removedFunction, NSProxy } from "./Netscript/APIWrapper";
|
||||||
import { INetscriptExtra } from "./NetscriptFunctions/Extra";
|
import { INetscriptExtra } from "./NetscriptFunctions/Extra";
|
||||||
import { ScriptDeath } from "./Netscript/ScriptDeath";
|
import { ScriptDeath } from "./Netscript/ScriptDeath";
|
||||||
import { getBitNodeMultipliers } from "./BitNode/BitNode";
|
import { getBitNodeMultipliers } from "./BitNode/BitNode";
|
||||||
@ -1894,7 +1894,7 @@ Object.assign(ns, {
|
|||||||
getServerRam: removedFunction("v2.2.0", "getServerMaxRam and getServerUsedRam"),
|
getServerRam: removedFunction("v2.2.0", "getServerMaxRam and getServerUsedRam"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function NetscriptFunctions(ws: WorkerScript): ExternalAPI<NSFull> {
|
export function NetscriptFunctions(ws: WorkerScript): NSFull {
|
||||||
return NSProxy(ws, ns, [], { args: ws.args.slice(), pid: ws.pid, enums });
|
return NSProxy(ws, ns, [], { args: ws.args.slice(), pid: ws.pid, enums });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import { InternalAPI } from "../Netscript/APIWrapper";
|
|||||||
import { helpers } from "../Netscript/NetscriptHelpers";
|
import { helpers } from "../Netscript/NetscriptHelpers";
|
||||||
import { Terminal } from "../Terminal";
|
import { Terminal } from "../Terminal";
|
||||||
|
|
||||||
export interface INetscriptExtra {
|
export type INetscriptExtra = {
|
||||||
heart: {
|
heart: {
|
||||||
break(): number;
|
break(): number;
|
||||||
};
|
};
|
||||||
@ -18,7 +18,7 @@ export interface INetscriptExtra {
|
|||||||
rainbow(guess: string): void;
|
rainbow(guess: string): void;
|
||||||
iKnowWhatImDoing(): void;
|
iKnowWhatImDoing(): void;
|
||||||
printRaw(value: React.ReactNode): void;
|
printRaw(value: React.ReactNode): void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function NetscriptExtra(): InternalAPI<INetscriptExtra> {
|
export function NetscriptExtra(): InternalAPI<INetscriptExtra> {
|
||||||
return {
|
return {
|
||||||
|
@ -83,11 +83,6 @@ async function startNetscript1Script(workerScript: WorkerScript): Promise<void>
|
|||||||
type BasicObject = Record<string, any>;
|
type BasicObject = Record<string, any>;
|
||||||
const wrappedNS = NetscriptFunctions(workerScript);
|
const wrappedNS = NetscriptFunctions(workerScript);
|
||||||
function wrapNS1Layer(int: Interpreter, intLayer: unknown, nsLayer = wrappedNS as BasicObject) {
|
function wrapNS1Layer(int: Interpreter, intLayer: unknown, nsLayer = wrappedNS as BasicObject) {
|
||||||
if (nsLayer === wrappedNS) {
|
|
||||||
int.setProperty(intLayer, "args", int.nativeToPseudo(nsLayer.args));
|
|
||||||
int.setProperty(intLayer, "enums", int.nativeToPseudo(nsLayer.enums));
|
|
||||||
int.setProperty(intLayer, "pid", nsLayer.pid);
|
|
||||||
}
|
|
||||||
for (const [name, entry] of Object.entries(nsLayer)) {
|
for (const [name, entry] of Object.entries(nsLayer)) {
|
||||||
if (typeof entry === "function") {
|
if (typeof entry === "function") {
|
||||||
const wrapper = async (...args: unknown[]) => {
|
const wrapper = async (...args: unknown[]) => {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { NSFull } from "../NetscriptFunctions";
|
import { NSFull } from "../NetscriptFunctions";
|
||||||
import { ExternalAPI } from "../Netscript/APIWrapper";
|
|
||||||
import { AutocompleteData } from "@nsdefs";
|
import { AutocompleteData } from "@nsdefs";
|
||||||
|
|
||||||
export interface ScriptModule {
|
export interface ScriptModule {
|
||||||
main?: (ns: ExternalAPI<NSFull>) => unknown;
|
main?: (ns: NSFull) => unknown;
|
||||||
autocomplete?: (data: AutocompleteData, flags: string[]) => unknown;
|
autocomplete?: (data: AutocompleteData, flags: string[]) => unknown;
|
||||||
}
|
}
|
||||||
|
93
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
93
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -1000,7 +1000,7 @@ interface NetscriptPort {
|
|||||||
* Stock market API
|
* Stock market API
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface TIX {
|
export type TIX = {
|
||||||
/**
|
/**
|
||||||
* Returns true if the player has access to a WSE Account
|
* Returns true if the player has access to a WSE Account
|
||||||
* @remarks RAM cost: 0.05 GB
|
* @remarks RAM cost: 0.05 GB
|
||||||
@ -1439,7 +1439,7 @@ export interface TIX {
|
|||||||
* @returns True if you successfully purchased it or if you already have access, false otherwise.
|
* @returns True if you successfully purchased it or if you already have access, false otherwise.
|
||||||
*/
|
*/
|
||||||
purchaseTixApi(): boolean;
|
purchaseTixApi(): boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singularity API
|
* Singularity API
|
||||||
@ -1448,7 +1448,7 @@ export interface TIX {
|
|||||||
* Source-File 4 levels.
|
* Source-File 4 levels.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface Singularity {
|
export type Singularity = {
|
||||||
/**
|
/**
|
||||||
* Backup game save.
|
* Backup game save.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -2292,7 +2292,7 @@ export interface Singularity {
|
|||||||
* @returns - An object representing the current work. Fields depend on the kind of work.
|
* @returns - An object representing the current work. Fields depend on the kind of work.
|
||||||
*/
|
*/
|
||||||
getCurrentWork(): any | null;
|
getCurrentWork(): any | null;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hacknet API
|
* Hacknet API
|
||||||
@ -2300,7 +2300,7 @@ export interface Singularity {
|
|||||||
* Not all these functions are immediately available.
|
* Not all these functions are immediately available.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface Hacknet {
|
export type Hacknet = {
|
||||||
/**
|
/**
|
||||||
* Get the number of hacknet nodes you own.
|
* Get the number of hacknet nodes you own.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -2651,7 +2651,7 @@ export interface Hacknet {
|
|||||||
* @returns Multiplier.
|
* @returns Multiplier.
|
||||||
*/
|
*/
|
||||||
getTrainingMult(): number;
|
getTrainingMult(): number;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bladeburner API
|
* Bladeburner API
|
||||||
@ -2660,7 +2660,7 @@ export interface Hacknet {
|
|||||||
* or have Source-File 7 in order to use this API.
|
* or have Source-File 7 in order to use this API.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface Bladeburner {
|
export type Bladeburner = {
|
||||||
/**
|
/**
|
||||||
* List all contracts.
|
* List all contracts.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -3148,13 +3148,13 @@ export interface Bladeburner {
|
|||||||
*
|
*
|
||||||
* @returns whether player is a member of bladeburner division. */
|
* @returns whether player is a member of bladeburner division. */
|
||||||
inBladeburner(): boolean;
|
inBladeburner(): boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coding Contract API
|
* Coding Contract API
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface CodingContract {
|
export type CodingContract = {
|
||||||
/**
|
/**
|
||||||
* Attempts a coding contract, returning a reward string on success or empty string on failure.
|
* Attempts a coding contract, returning a reward string on success or empty string on failure.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -3259,7 +3259,7 @@ export interface CodingContract {
|
|||||||
* RAM cost: 2 GB
|
* RAM cost: 2 GB
|
||||||
*/
|
*/
|
||||||
getContractTypes(): string[];
|
getContractTypes(): string[];
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gang API
|
* Gang API
|
||||||
@ -3267,7 +3267,7 @@ export interface CodingContract {
|
|||||||
* If you are not in BitNode-2, then you must have Source-File 2 in order to use this API.
|
* If you are not in BitNode-2, then you must have Source-File 2 in order to use this API.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface Gang {
|
export type Gang = {
|
||||||
/**
|
/**
|
||||||
* Create a gang.
|
* Create a gang.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -3526,7 +3526,7 @@ export interface Gang {
|
|||||||
* @returns Bonus time for the Gang mechanic in milliseconds.
|
* @returns Bonus time for the Gang mechanic in milliseconds.
|
||||||
*/
|
*/
|
||||||
getBonusTime(): number;
|
getBonusTime(): number;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleeve API
|
* Sleeve API
|
||||||
@ -3534,7 +3534,7 @@ export interface Gang {
|
|||||||
* If you are not in BitNode-10, then you must have Source-File 10 in order to use this API.
|
* If you are not in BitNode-10, then you must have Source-File 10 in order to use this API.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface Sleeve {
|
export type Sleeve = {
|
||||||
/**
|
/**
|
||||||
* Get the number of sleeves you own.
|
* Get the number of sleeves you own.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -3764,7 +3764,7 @@ export interface Sleeve {
|
|||||||
* @returns True if the sleeve started working out, false otherwise.
|
* @returns True if the sleeve started working out, false otherwise.
|
||||||
*/
|
*/
|
||||||
setToBladeburnerAction(sleeveNumber: number, action: string, contract?: string): boolean;
|
setToBladeburnerAction(sleeveNumber: number, action: string, contract?: string): boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Grafting API
|
* Grafting API
|
||||||
@ -3772,7 +3772,7 @@ export interface Sleeve {
|
|||||||
* This API requires Source-File 10 to use.
|
* This API requires Source-File 10 to use.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface Grafting {
|
export type Grafting = {
|
||||||
/**
|
/**
|
||||||
* Retrieve the grafting cost of an aug.
|
* Retrieve the grafting cost of an aug.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -3819,13 +3819,13 @@ export interface Grafting {
|
|||||||
* @throws Will error if called while you are not in New Tokyo.
|
* @throws Will error if called while you are not in New Tokyo.
|
||||||
*/
|
*/
|
||||||
graftAugmentation(augName: string, focus?: boolean): boolean;
|
graftAugmentation(augName: string, focus?: boolean): boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skills formulas
|
* Skills formulas
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
interface SkillsFormulas {
|
type SkillsFormulas = {
|
||||||
/**
|
/**
|
||||||
* Calculate skill level.
|
* Calculate skill level.
|
||||||
* @param exp - experience for that skill
|
* @param exp - experience for that skill
|
||||||
@ -3840,7 +3840,7 @@ interface SkillsFormulas {
|
|||||||
* @returns The calculated exp required.
|
* @returns The calculated exp required.
|
||||||
*/
|
*/
|
||||||
calculateExp(skill: number, skillMult?: number): number;
|
calculateExp(skill: number, skillMult?: number): number;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
interface WorkStats {
|
interface WorkStats {
|
||||||
@ -3859,7 +3859,7 @@ interface WorkStats {
|
|||||||
* Work formulas
|
* Work formulas
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
interface WorkFormulas {
|
type WorkFormulas = {
|
||||||
crimeSuccessChance(person: Person, crimeType: CrimeType | `${CrimeType}`): number;
|
crimeSuccessChance(person: Person, crimeType: CrimeType | `${CrimeType}`): number;
|
||||||
/** @returns The WorkStats gained when completing one instance of the specified crime. */
|
/** @returns The WorkStats gained when completing one instance of the specified crime. */
|
||||||
crimeGains(person: Person, crimeType: CrimeType | `${CrimeType}`): WorkStats;
|
crimeGains(person: Person, crimeType: CrimeType | `${CrimeType}`): WorkStats;
|
||||||
@ -3875,13 +3875,13 @@ interface WorkFormulas {
|
|||||||
factionGains(person: Person, workType: FactionWorkType | `${FactionWorkType}`, favor: number): WorkStats;
|
factionGains(person: Person, workType: FactionWorkType | `${FactionWorkType}`, favor: number): WorkStats;
|
||||||
/** @returns The WorkStats applied every game cycle (200ms) by performing the specified company work. */
|
/** @returns The WorkStats applied every game cycle (200ms) by performing the specified company work. */
|
||||||
companyGains(person: Person, companyName: string, workType: JobName | `${JobName}`, favor: number): WorkStats;
|
companyGains(person: Person, companyName: string, workType: JobName | `${JobName}`, favor: number): WorkStats;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reputation formulas
|
* Reputation formulas
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
interface ReputationFormulas {
|
type ReputationFormulas = {
|
||||||
/**
|
/**
|
||||||
* Calculate the total required amount of faction reputation to reach a target favor.
|
* Calculate the total required amount of faction reputation to reach a target favor.
|
||||||
* @param favor - target faction favor.
|
* @param favor - target faction favor.
|
||||||
@ -3902,13 +3902,13 @@ interface ReputationFormulas {
|
|||||||
* @param player - Player info from {@link NS.getPlayer | getPlayer}
|
* @param player - Player info from {@link NS.getPlayer | getPlayer}
|
||||||
*/
|
*/
|
||||||
repFromDonation(amount: number, player: Person): number;
|
repFromDonation(amount: number, player: Person): number;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hacking formulas
|
* Hacking formulas
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
interface HackingFormulas {
|
type HackingFormulas = {
|
||||||
/**
|
/**
|
||||||
* Calculate hack chance.
|
* Calculate hack chance.
|
||||||
* (Ex: 0.25 would indicate a 25% chance of success.)
|
* (Ex: 0.25 would indicate a 25% chance of success.)
|
||||||
@ -3968,13 +3968,13 @@ interface HackingFormulas {
|
|||||||
* @returns The calculated weaken time.
|
* @returns The calculated weaken time.
|
||||||
*/
|
*/
|
||||||
weakenTime(server: Server, player: Person): number;
|
weakenTime(server: Server, player: Person): number;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hacknet Node formulas
|
* Hacknet Node formulas
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
interface HacknetNodesFormulas {
|
type HacknetNodesFormulas = {
|
||||||
/**
|
/**
|
||||||
* Calculate money gain rate.
|
* Calculate money gain rate.
|
||||||
* @param level - level of the node.
|
* @param level - level of the node.
|
||||||
@ -4020,13 +4020,13 @@ interface HacknetNodesFormulas {
|
|||||||
* @returns An object with all hacknet node constants used by the game.
|
* @returns An object with all hacknet node constants used by the game.
|
||||||
*/
|
*/
|
||||||
constants(): HacknetNodeConstants;
|
constants(): HacknetNodeConstants;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hacknet Server formulas
|
* Hacknet Server formulas
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
interface HacknetServersFormulas {
|
type HacknetServersFormulas = {
|
||||||
/**
|
/**
|
||||||
* Calculate hash gain rate.
|
* Calculate hash gain rate.
|
||||||
* @param level - level of the server.
|
* @param level - level of the server.
|
||||||
@ -4087,13 +4087,13 @@ interface HacknetServersFormulas {
|
|||||||
* @returns An object with all hacknet server constants used by the game.
|
* @returns An object with all hacknet server constants used by the game.
|
||||||
*/
|
*/
|
||||||
constants(): HacknetServerConstants;
|
constants(): HacknetServerConstants;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gang formulas
|
* Gang formulas
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
interface GangFormulas {
|
type GangFormulas = {
|
||||||
/**
|
/**
|
||||||
* Calculate the wanted penalty.
|
* Calculate the wanted penalty.
|
||||||
* @param gang - Gang info from {@link Gang.getGangInformation | getGangInformation}
|
* @param gang - Gang info from {@link Gang.getGangInformation | getGangInformation}
|
||||||
@ -4138,7 +4138,7 @@ interface GangFormulas {
|
|||||||
* @returns The calculated ascension mult.
|
* @returns The calculated ascension mult.
|
||||||
*/
|
*/
|
||||||
ascensionMultiplier(points: number): number;
|
ascensionMultiplier(points: number): number;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formulas API
|
* Formulas API
|
||||||
@ -4146,7 +4146,7 @@ interface GangFormulas {
|
|||||||
* You need Formulas.exe on your home computer to use this API.
|
* You need Formulas.exe on your home computer to use this API.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface Formulas {
|
export type Formulas = {
|
||||||
mockServer(): Server;
|
mockServer(): Server;
|
||||||
mockPlayer(): Player;
|
mockPlayer(): Player;
|
||||||
mockPerson(): Person;
|
mockPerson(): Person;
|
||||||
@ -4164,7 +4164,7 @@ export interface Formulas {
|
|||||||
gang: GangFormulas;
|
gang: GangFormulas;
|
||||||
/** Work formulas */
|
/** Work formulas */
|
||||||
work: WorkFormulas;
|
work: WorkFormulas;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
interface Fragment {
|
interface Fragment {
|
||||||
@ -4189,7 +4189,7 @@ interface ActiveFragment {
|
|||||||
* Stanek's Gift API.
|
* Stanek's Gift API.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
interface Stanek {
|
type Stanek = {
|
||||||
/**
|
/**
|
||||||
* Stanek's Gift width.
|
* Stanek's Gift width.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -4295,7 +4295,7 @@ interface Stanek {
|
|||||||
* false otherwise.
|
* false otherwise.
|
||||||
*/
|
*/
|
||||||
acceptGift(): boolean;
|
acceptGift(): boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
interface InfiltrationReward {
|
interface InfiltrationReward {
|
||||||
@ -4321,7 +4321,7 @@ interface InfiltrationLocation {
|
|||||||
* Infiltration API.
|
* Infiltration API.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
interface Infiltration {
|
type Infiltration = {
|
||||||
/**
|
/**
|
||||||
* Get all locations that can be infiltrated.
|
* Get all locations that can be infiltrated.
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -4338,13 +4338,13 @@ interface Infiltration {
|
|||||||
* @returns Infiltration data for given location.
|
* @returns Infiltration data for given location.
|
||||||
*/
|
*/
|
||||||
getInfiltration(location: string): InfiltrationLocation;
|
getInfiltration(location: string): InfiltrationLocation;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User Interface API.
|
* User Interface API.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
interface UserInterface {
|
type UserInterface = {
|
||||||
/**
|
/**
|
||||||
* Get the current window size
|
* Get the current window size
|
||||||
* @remarks
|
* @remarks
|
||||||
@ -4427,7 +4427,7 @@ interface UserInterface {
|
|||||||
* RAM cost: 0.2 GB
|
* RAM cost: 0.2 GB
|
||||||
*/
|
*/
|
||||||
clearTerminal(): void;
|
clearTerminal(): void;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of all functions passed to scripts
|
* Collection of all functions passed to scripts
|
||||||
@ -4456,7 +4456,7 @@ interface UserInterface {
|
|||||||
* {@link https://bitburner.readthedocs.io/en/latest/netscript/netscriptjs.html| ns2 in-game docs}
|
* {@link https://bitburner.readthedocs.io/en/latest/netscript/netscriptjs.html| ns2 in-game docs}
|
||||||
* <hr>
|
* <hr>
|
||||||
*/
|
*/
|
||||||
export interface NS {
|
export type NS = {
|
||||||
/**
|
/**
|
||||||
* Namespace for hacknet functions.
|
* Namespace for hacknet functions.
|
||||||
* @remarks RAM cost: 4 GB
|
* @remarks RAM cost: 4 GB
|
||||||
@ -6853,7 +6853,7 @@ export interface NS {
|
|||||||
getSharePower(): number;
|
getSharePower(): number;
|
||||||
|
|
||||||
enums: NSEnums;
|
enums: NSEnums;
|
||||||
}
|
};
|
||||||
|
|
||||||
// BASE ENUMS
|
// BASE ENUMS
|
||||||
/** @public */
|
/** @public */
|
||||||
@ -7073,7 +7073,7 @@ export type NSEnums = {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface OfficeAPI {
|
export type OfficeAPI = {
|
||||||
/**
|
/**
|
||||||
* Hire an employee.
|
* Hire an employee.
|
||||||
* @param divisionName - Name of the division
|
* @param divisionName - Name of the division
|
||||||
@ -7165,7 +7165,7 @@ export interface OfficeAPI {
|
|||||||
* @returns Cost of upgrading the office
|
* @returns Cost of upgrading the office
|
||||||
*/
|
*/
|
||||||
getOfficeSizeUpgradeCost(divisionName: string, city: CityName | `${CityName}`, asize: number): number;
|
getOfficeSizeUpgradeCost(divisionName: string, city: CityName | `${CityName}`, asize: number): number;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Corporation Warehouse API
|
* Corporation Warehouse API
|
||||||
@ -7173,7 +7173,7 @@ export interface OfficeAPI {
|
|||||||
* Requires the Warehouse API upgrade from your corporation.
|
* Requires the Warehouse API upgrade from your corporation.
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface WarehouseAPI {
|
export type WarehouseAPI = {
|
||||||
/**
|
/**
|
||||||
* Set material sell data.
|
* Set material sell data.
|
||||||
* @param divisionName - Name of the division
|
* @param divisionName - Name of the division
|
||||||
@ -7396,13 +7396,13 @@ export interface WarehouseAPI {
|
|||||||
* @returns true if warehouse is present, false if not
|
* @returns true if warehouse is present, false if not
|
||||||
*/
|
*/
|
||||||
hasWarehouse(divisionName: string, city: CityName | `${CityName}`): boolean;
|
hasWarehouse(divisionName: string, city: CityName | `${CityName}`): boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Corporation API
|
* Corporation API
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export interface Corporation extends WarehouseAPI, OfficeAPI {
|
export type Corporation = {
|
||||||
/** Returns whether the player has a corporation. Does not require API access.
|
/** Returns whether the player has a corporation. Does not require API access.
|
||||||
* @returns whether the player has a corporation */
|
* @returns whether the player has a corporation */
|
||||||
hasCorporation(): boolean;
|
hasCorporation(): boolean;
|
||||||
@ -7513,7 +7513,8 @@ export interface Corporation extends WarehouseAPI, OfficeAPI {
|
|||||||
* “Bonus time” makes the game progress faster.
|
* “Bonus time” makes the game progress faster.
|
||||||
* @returns Bonus time for the Corporation mechanic in milliseconds. */
|
* @returns Bonus time for the Corporation mechanic in milliseconds. */
|
||||||
getBonusTime(): number;
|
getBonusTime(): number;
|
||||||
}
|
} & WarehouseAPI &
|
||||||
|
OfficeAPI;
|
||||||
|
|
||||||
/** Product rating information
|
/** Product rating information
|
||||||
* @public */
|
* @public */
|
||||||
|
@ -7,7 +7,7 @@ import { Script } from "../../../src/Script/Script";
|
|||||||
import { WorkerScript } from "../../../src/Netscript/WorkerScript";
|
import { WorkerScript } from "../../../src/Netscript/WorkerScript";
|
||||||
import { calculateRamUsage } from "../../../src/Script/RamCalculations";
|
import { calculateRamUsage } from "../../../src/Script/RamCalculations";
|
||||||
import { ns } from "../../../src/NetscriptFunctions";
|
import { ns } from "../../../src/NetscriptFunctions";
|
||||||
import { ExternalAPI, InternalAPI } from "src/Netscript/APIWrapper";
|
import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
|
||||||
import { Singularity } from "@nsdefs";
|
import { Singularity } from "@nsdefs";
|
||||||
|
|
||||||
type PotentiallyAsyncFunction = (arg?: unknown) => { catch?: PotentiallyAsyncFunction };
|
type PotentiallyAsyncFunction = (arg?: unknown) => { catch?: PotentiallyAsyncFunction };
|
||||||
@ -20,15 +20,10 @@ function getFunction(fn: unknown) {
|
|||||||
function grabCost<API>(ramEntry: RamCostTree<API>[keyof API]) {
|
function grabCost<API>(ramEntry: RamCostTree<API>[keyof API]) {
|
||||||
if (typeof ramEntry === "function") return ramEntry();
|
if (typeof ramEntry === "function") return ramEntry();
|
||||||
if (typeof ramEntry === "number") return ramEntry;
|
if (typeof ramEntry === "number") return ramEntry;
|
||||||
throw new Error("Invalid ramcost");
|
throw new Error("Invalid ramcost: " + ramEntry);
|
||||||
}
|
}
|
||||||
function isRemovedFunction(fn: Function) {
|
function isRemovedFunction(ctx: NetscriptContext, fn: (ctx: NetscriptContext) => (...__: unknown[]) => unknown) {
|
||||||
try {
|
return /REMOVED FUNCTION/.test(fn(ctx) + "");
|
||||||
fn();
|
|
||||||
} catch {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Netscript RAM Calculation/Generation Tests", function () {
|
describe("Netscript RAM Calculation/Generation Tests", function () {
|
||||||
@ -112,7 +107,7 @@ describe("Netscript RAM Calculation/Generation Tests", function () {
|
|||||||
describe("ns", () => {
|
describe("ns", () => {
|
||||||
function testLayer<API>(
|
function testLayer<API>(
|
||||||
internalLayer: InternalAPI<API>,
|
internalLayer: InternalAPI<API>,
|
||||||
externalLayer: ExternalAPI<API>,
|
externalLayer: API,
|
||||||
ramLayer: RamCostTree<API>,
|
ramLayer: RamCostTree<API>,
|
||||||
path: string[],
|
path: string[],
|
||||||
extraLayerCost: number,
|
extraLayerCost: number,
|
||||||
@ -122,18 +117,22 @@ describe("Netscript RAM Calculation/Generation Tests", function () {
|
|||||||
const newPath = [...path, key as string];
|
const newPath = [...path, key as string];
|
||||||
if (typeof val === "function") {
|
if (typeof val === "function") {
|
||||||
// Removed functions have no ram cost and should be skipped.
|
// Removed functions have no ram cost and should be skipped.
|
||||||
if (isRemovedFunction(val)) return;
|
if (isRemovedFunction({ workerScript }, val)) return;
|
||||||
const fn = getFunction(externalLayer[key]);
|
const fn = getFunction(externalLayer[key]);
|
||||||
const fnName = newPath.join(".");
|
const fnName = newPath.join(".");
|
||||||
|
if (!(key in ramLayer)) {
|
||||||
|
throw new Error("Missing ramcost for " + fnName);
|
||||||
|
}
|
||||||
const expectedRam = grabCost(ramLayer[key]);
|
const expectedRam = grabCost(ramLayer[key]);
|
||||||
it(`${fnName}()`, () => combinedRamCheck(fn, newPath, expectedRam, extraLayerCost));
|
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.
|
//A layer should be the only other option. Hacknet is currently the only layer with a layer cost.
|
||||||
else {
|
else if (typeof val === "object" && key !== "enums") {
|
||||||
//hacknet is currently the only layer with a layer cost.
|
//hacknet is currently the only layer with a layer cost.
|
||||||
const layerCost = key === "hacknet" ? 4 : 0;
|
const layerCost = key === "hacknet" ? 4 : 0;
|
||||||
testLayer(val as InternalAPI<unknown>, externalLayer[key], ramLayer[key], newPath, layerCost);
|
testLayer(val as InternalAPI<unknown>, externalLayer[key], ramLayer[key], newPath, layerCost);
|
||||||
}
|
}
|
||||||
|
// Other things like args, enums, etc. have no cost
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -149,7 +148,7 @@ describe("Netscript RAM Calculation/Generation Tests", function () {
|
|||||||
const singObjects = (
|
const singObjects = (
|
||||||
Object.entries(ns.singularity) as [keyof Singularity, InternalAPI<Singularity>[keyof Singularity]][]
|
Object.entries(ns.singularity) as [keyof Singularity, InternalAPI<Singularity>[keyof Singularity]][]
|
||||||
)
|
)
|
||||||
.filter(([_, v]) => typeof v === "function" && !isRemovedFunction(v))
|
.filter(([__, v]) => typeof v === "function" && !isRemovedFunction({ workerScript }, v))
|
||||||
.map(([name]) => {
|
.map(([name]) => {
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
|
Loading…
Reference in New Issue
Block a user