From d9064b608f8969db4e1cdb2d5070066ea1d338a1 Mon Sep 17 00:00:00 2001 From: TheMas3212 Date: Mon, 10 Jan 2022 05:50:11 +1100 Subject: [PATCH 01/15] PoC for save validation on load via hooking the Reviver function and static property validationData on classes PoC/example implemented with HacknetNode: validates cores is a number in the range between 1 and HacknetNodeConstants.MaxCores validates level is a number in range between 1 and HacknetNodeConstants.MaxLevel validates ram is a number in range between 1 and HacknetNodeConstants.MaxRam validates onlineTimeSeconds in non negative number validates totalMoneyGenerated is a non negative number --- src/Hacknet/HacknetNode.ts | 28 ++++++++++++++++++++++++++++ src/utils/JSONReviver.ts | 8 +++++++- src/utils/Validator.ts | 31 +++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/utils/Validator.ts diff --git a/src/Hacknet/HacknetNode.ts b/src/Hacknet/HacknetNode.ts index 4982b606b..9d79f334d 100644 --- a/src/Hacknet/HacknetNode.ts +++ b/src/Hacknet/HacknetNode.ts @@ -18,8 +18,36 @@ import { HacknetNodeConstants } from "./data/Constants"; import { dialogBoxCreate } from "../ui/React/DialogBox"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; +import { ObjectValidator } from "src/utils/Validator"; export class HacknetNode implements IHacknetNode { + + static validationData: ObjectValidator = { + cores: { + default: 1, + min: 1, + max: HacknetNodeConstants.MaxCores + }, + level: { + default: 1, + min: 1, + max: HacknetNodeConstants.MaxLevel + }, + ram: { + default: 1, + min: 1, + max: HacknetNodeConstants.MaxRam + }, + onlineTimeSeconds: { + default: 0, + min: 0 + }, + totalMoneyGenerated: { + default: 0, + min: 0 + } + } + // Node's number of cores cores = 1; diff --git a/src/utils/JSONReviver.ts b/src/utils/JSONReviver.ts index eeb832cec..5b7447d09 100644 --- a/src/utils/JSONReviver.ts +++ b/src/utils/JSONReviver.ts @@ -1,5 +1,7 @@ /* Generic Reviver, toJSON, and fromJSON functions used for saving and loading objects */ +import { validateObject } from "./Validator"; + interface IReviverValue { ctor: string; data: any; @@ -26,7 +28,11 @@ export function Reviver(key: string, value: IReviverValue | null): any { const ctor = Reviver.constructors[value.ctor]; if (typeof ctor === "function" && typeof ctor.fromJSON === "function") { - return ctor.fromJSON(value); + const obj = ctor.fromJSON(value); + if (ctor.validationData !== undefined) { + validateObject(obj, ctor.validationData); + } + return obj; } } return value; diff --git a/src/utils/Validator.ts b/src/utils/Validator.ts new file mode 100644 index 000000000..a97b5b039 --- /dev/null +++ b/src/utils/Validator.ts @@ -0,0 +1,31 @@ +export type ObjectValidator = { + [key in keyof T]?: ParameterValidator; +} + +interface ParameterValidator { + default?: any; + min?: number; + max?: number; + func?: (obj: T, validator: ObjectValidator, key: U) => void; +} + +export function validateObject, U extends keyof T>(obj: T, validator: ObjectValidator): void { + for (const key of Object.keys(validator) as U[]) { + const paramValidator = validator[key]; + if (paramValidator !== undefined) { + if (paramValidator.func !== undefined) { + paramValidator.func(obj, validator, key); + } else { + if ((typeof obj[key]) !== (typeof paramValidator.default)) { + obj[key] = paramValidator.default + } + if (typeof obj[key] === 'number' && paramValidator.min !== undefined) { + if (obj[key] < paramValidator.min) obj[key] = paramValidator.min as T[U]; + } + if (typeof obj[key] === 'number' && paramValidator.max !== undefined) { + if (obj[key] > paramValidator.max) obj[key] = paramValidator.max as T[U]; + } + } + } + } +} \ No newline at end of file From 3da3a61e20db5cbb9d71393122254d50d8505a84 Mon Sep 17 00:00:00 2001 From: TheMas3212 Date: Mon, 10 Jan 2022 06:58:12 +1100 Subject: [PATCH 02/15] manMax, oneOf, subsetOf validators --- src/Hacknet/HacknetNode.ts | 30 +++------------ src/utils/Validator.ts | 75 +++++++++++++++++++++++++++++++------- 2 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/Hacknet/HacknetNode.ts b/src/Hacknet/HacknetNode.ts index 9d79f334d..5cb950232 100644 --- a/src/Hacknet/HacknetNode.ts +++ b/src/Hacknet/HacknetNode.ts @@ -18,34 +18,16 @@ import { HacknetNodeConstants } from "./data/Constants"; import { dialogBoxCreate } from "../ui/React/DialogBox"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; -import { ObjectValidator } from "src/utils/Validator"; +import { ObjectValidator, minMax } from "../utils/Validator"; export class HacknetNode implements IHacknetNode { static validationData: ObjectValidator = { - cores: { - default: 1, - min: 1, - max: HacknetNodeConstants.MaxCores - }, - level: { - default: 1, - min: 1, - max: HacknetNodeConstants.MaxLevel - }, - ram: { - default: 1, - min: 1, - max: HacknetNodeConstants.MaxRam - }, - onlineTimeSeconds: { - default: 0, - min: 0 - }, - totalMoneyGenerated: { - default: 0, - min: 0 - } + cores: minMax(1, 1, HacknetNodeConstants.MaxCores), + level: minMax(1, 1, HacknetNodeConstants.MaxLevel), + ram: minMax(1, 1, HacknetNodeConstants.MaxRam), + onlineTimeSeconds: minMax(0, 0, Infinity), + totalMoneyGenerated: minMax(0, 0, Infinity) } // Node's number of cores diff --git a/src/utils/Validator.ts b/src/utils/Validator.ts index a97b5b039..21daba59e 100644 --- a/src/utils/Validator.ts +++ b/src/utils/Validator.ts @@ -2,30 +2,77 @@ export type ObjectValidator = { [key in keyof T]?: ParameterValidator; } -interface ParameterValidator { +interface ParameterValidatorObject { default?: any; min?: number; max?: number; - func?: (obj: T, validator: ObjectValidator, key: U) => void; + func?: (obj: Type, validator: ObjectValidator, key: Key) => void; } +type ParameterValidatorFunction = (obj: Type, key: Key) => void; +type ParameterValidator = ParameterValidatorObject | ParameterValidatorFunction -export function validateObject, U extends keyof T>(obj: T, validator: ObjectValidator): void { - for (const key of Object.keys(validator) as U[]) { +export function validateObject, Key extends keyof Type>(obj: Type, validator: ObjectValidator): void { + for (const key of Object.keys(validator) as Key[]) { const paramValidator = validator[key]; if (paramValidator !== undefined) { - if (paramValidator.func !== undefined) { - paramValidator.func(obj, validator, key); + if (typeof paramValidator === 'function') { + paramValidator(obj, key); } else { - if ((typeof obj[key]) !== (typeof paramValidator.default)) { - obj[key] = paramValidator.default - } - if (typeof obj[key] === 'number' && paramValidator.min !== undefined) { - if (obj[key] < paramValidator.min) obj[key] = paramValidator.min as T[U]; - } - if (typeof obj[key] === 'number' && paramValidator.max !== undefined) { - if (obj[key] > paramValidator.max) obj[key] = paramValidator.max as T[U]; + if (paramValidator.func !== undefined) { + paramValidator.func(obj, validator, key); + } else { + if ((typeof obj[key]) !== (typeof paramValidator.default)) { + obj[key] = paramValidator.default + } + if (typeof obj[key] === 'number' && paramValidator.min !== undefined) { + if (obj[key] < paramValidator.min) obj[key] = paramValidator.min as Type[Key]; + } + if (typeof obj[key] === 'number' && paramValidator.max !== undefined) { + if (obj[key] > paramValidator.max) obj[key] = paramValidator.max as Type[Key]; + } } } } } +} + +export function minMax(def: number, min: number, max: number): (obj: Type, key: Key & keyof Type) => void { + return (obj, key) => { + if (typeof obj[key] !== 'number') { + obj[key] = def as unknown as Type[Key]; + return; + } + if ((obj[key] as unknown as number) < min) { + obj[key] = min as unknown as Type[Key]; + } + if ((obj[key] as unknown as number) > max) { + obj[key] = max as unknown as Type[Key]; + } + }; +} + +export function oneOf(def: Value, options: Value[]): (obj: Type, key: Key & keyof Type) => void { + return (obj, key) => { + if (typeof obj[key] !== typeof def) { + obj[key] = def as unknown as Type[Key]; + return; + } + if (!options.includes(obj[key] as unknown as Value)) { + obj[key] = def as unknown as Type[Key]; + } + }; +} + +export function subsetOf(options: Value[]): (obj: Type, key: Key & keyof Type) => void { + return (obj, key) => { + if (typeof obj[key] !== 'object' || !Array.isArray(obj[key])) { + obj[key] = [] as unknown as Type[Key]; + return; + } + const validValues: Value[] = []; + for (const value of obj[key] as unknown as Value[]) { + if (options.includes(value)) validValues.push(value); + } + obj[key] = validValues as unknown as Type[Key]; + }; } \ No newline at end of file From cfa1b9e236c07fd28eb1a1fe26b1193ff3e8ba95 Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 12:34:07 -0500 Subject: [PATCH 03/15] adds missing bitnode mults to definitions file fixes #2424 --- src/ScriptEditor/NetscriptDefinitions.d.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 058a46a42..3701cd8c2 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -462,6 +462,8 @@ export interface BitNodeMultipliers { FourSigmaMarketDataApiCost: number; /** Influences how much it costs to unlock the stock market's 4S Market Data (NOT API) */ FourSigmaMarketDataCost: number; + /** Influences the respect gain and money gain of your gang. */ + GangSoftcap: number; /** Influences the experienced gained when hacking a server. */ HackExpGain: number; /** Influences how quickly the player's hacking level (not experience) scales */ @@ -482,10 +484,14 @@ export interface BitNodeMultipliers { PurchasedServerLimit: number; /** Influences the maximum allowed RAM for a purchased server */ PurchasedServerMaxRam: number; + /** Influences cost of any purchased server at or above 128GB */ + PurchasedServerSoftCap: number; /** Influences the minimum favor the player must have with a faction before they can donate to gain rep. */ RepToDonateToFaction: number; - /** Influences how much money can be stolen from a server when a script performs a hack against it. */ + /** Influences how much the money on a server can be reduced when a script performs a hack against it. */ ScriptHackMoney: number; + /** Influences how much of the money stolen by a scripted hack will be added to the player's money. */ + ScriptHackMoneyGain: number; /** Influences the growth percentage per cycle against a server. */ ServerGrowthRate: number; /** Influences the maxmimum money that a server can grow to. */ @@ -498,6 +504,12 @@ export interface BitNodeMultipliers { ServerWeakenRate: number; /** Influences how quickly the player's strength level (not exp) scales */ StrengthLevelMultiplier: number; + /** Influences the power of the gift */ + StaneksGiftPowerMultiplier: number; + /** Influences the size of the gift */ + StaneksGiftExtraSize: number; + /** Influences the hacking skill required to backdoor the world daemon. */ + WorldDaemonDifficulty: number; } /** From 896ee81d5721c9dd9cb50e21f574d93a21a996c7 Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 12:39:09 -0500 Subject: [PATCH 04/15] remove n00dles from servers with 16GB RAM in getting started guide fixes #2444 --- ...tingstartedguideforbeginnerprogrammers.rst | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/doc/source/guidesandtips/gettingstartedguideforbeginnerprogrammers.rst b/doc/source/guidesandtips/gettingstartedguideforbeginnerprogrammers.rst index 571bcec7c..83fca99be 100644 --- a/doc/source/guidesandtips/gettingstartedguideforbeginnerprogrammers.rst +++ b/doc/source/guidesandtips/gettingstartedguideforbeginnerprogrammers.rst @@ -200,52 +200,52 @@ Here's what mine showed at the time I made this:: --Root Access: YES, Required hacking skill: 1 --Number of open ports required to NUKE: 0 --RAM: 4.00GB - + ----zer0 ------Root Access: NO, Required hacking skill: 75 ------Number of open ports required to NUKE: 1 ------RAM: 32.00GB - + foodnstuff --Root Access: NO, Required hacking skill: 1 --Number of open ports required to NUKE: 0 --RAM: 16.00GB - + sigma-cosmetics --Root Access: NO, Required hacking skill: 5 --Number of open ports required to NUKE: 0 --RAM: 16.00GB - + joesguns --Root Access: NO, Required hacking skill: 10 --Number of open ports required to NUKE: 0 --RAM: 16.00GB - + ----max-hardware ------Root Access: NO, Required hacking skill: 80 ------Number of open ports required to NUKE: 1 ------RAM: 32.00GB - + ----CSEC ------Root Access: NO, Required hacking skill: 54 ------Number of open ports required to NUKE: 1 ------RAM: 8.00GB - + hong-fang-tea --Root Access: NO, Required hacking skill: 30 --Number of open ports required to NUKE: 0 --RAM: 16.00GB - + ----nectar-net ------Root Access: NO, Required hacking skill: 20 ------Number of open ports required to NUKE: 0 ------RAM: 16.00GB - + harakiri-sushi --Root Access: NO, Required hacking skill: 40 --Number of open ports required to NUKE: 0 --RAM: 16.00GB - + iron-gym --Root Access: NO, Required hacking skill: 100 --Number of open ports required to NUKE: 1 @@ -253,7 +253,6 @@ Here's what mine showed at the time I made this:: Take note of the following servers: -* |n00dles| * |sigma-cosmetics| * |joesguns| * |nectar-net| @@ -807,8 +806,7 @@ startup script. Feel free to adjust it to your liking. // Array of all servers that don't need any ports opened // to gain root access. These have 16 GB of RAM - var servers0Port = ["n00dles", - "sigma-cosmetics", + var servers0Port = ["sigma-cosmetics", "joesguns", "nectar-net", "hong-fang-tea", From 1d4d88f637d3a36cd11003f1115613e22ddf4bf7 Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 12:45:00 -0500 Subject: [PATCH 05/15] Remove mention of exp gain and individual effects on infiltrate from stats.rst --- doc/source/basicgameplay/stats.rst | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/doc/source/basicgameplay/stats.rst b/doc/source/basicgameplay/stats.rst index ef2be4de3..756a85567 100644 --- a/doc/source/basicgameplay/stats.rst +++ b/doc/source/basicgameplay/stats.rst @@ -3,7 +3,8 @@ Stats ===== The player has several stats that can be increased in order to progress -in the game. +in the game. All of these stats other than Hacking will decrease the +difficulty of infiltrations. Hacking ^^^^^^^ @@ -16,7 +17,6 @@ Affects: * Chance to successfully hack a server * Percent money stolen when hacking a server * Success rate of certain crimes -* Success rate of Hacking option during Infiltration * Time it takes to create a program * Faction reputation gain when carrying out Hacking Contracts or Field Work * Company reputation gain for certain jobs @@ -26,7 +26,6 @@ Gain experience by: * Manually hacking servers through Terminal * Executing hack(), grow(), or weaken() through a script * Committing certain crimes -* Infiltration * Carrying out Hacking Contracts or doing Field work for Factions * Working certain jobs at a company * Studying at a university @@ -38,14 +37,12 @@ Represents the player's physical offensive power Affects: * Success rate of certain crimes -* Success rate of Combat options during Infiltration * Faction reputation gain for Security and Field Work * Company reputation gain for certain jobs Gain experience by: * Committing certain crimes -* Infiltration * Working out at a gym * Doing Security/Field Work for a faction * Working certain jobs at a company @@ -58,15 +55,12 @@ Affects: * Success rate of certain crimes * The player's HP -* Success rate of Combat options during Infiltration -* How much damage the player takes during Infiltration * Faction reputation gain for Security and Field Work * Company reputation gain for certain jobs Gain experience by: * Committing certain crimes -* Infiltration * Working out at a gym * Doing Security/Field Work for a faction * Working certain jobs at a company @@ -78,14 +72,12 @@ Represents the player's skill and adeptness in performing certain tasks Affects: * Success rate of certain crimes -* Success rate of Combat, Lockpick, and Escape options during Infiltration * Faction reputation gain for Security and Field Work * Company reputation gain for certain jobs Gain experience by: * Committing certain crimes -* Infiltration * Working out at a gym * Doing Security/Field Work for a faction * Working certain jobs at a company @@ -97,14 +89,12 @@ Represents the player's speed and ability to move Affects: * Success rate of certain crimes -* Success rate of Combat, Sneak, and Escape options during Infiltration * Faction reputation gain for Security and Field Work * Company reputation gain for certain jobs Gain experience by: * Committing certain crimes -* Infiltration * Working out at a gym * Doing Security/Field Work for a faction * Working certain jobs at a company @@ -116,14 +106,12 @@ Represents the player's social abilities Affects: * Success rate of certain crimes -* Success rate of Bribe option during Infiltration * Faction reputation gain for Field Work * Company reputation gain for most jobs Gain experience by: * Committing certain crimes -* Infiltration * Studying at a university * Working a relevant job at a company * Doing Field work for a Faction From 215702d96bd14e23e39a1841cfd568866a7166f1 Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 12:49:51 -0500 Subject: [PATCH 06/15] Add information about hp loss and "maximum level" to infiltration.rst fixes #2513 --- doc/source/basicgameplay/infiltration.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/source/basicgameplay/infiltration.rst b/doc/source/basicgameplay/infiltration.rst index 97201cada..c482f78da 100644 --- a/doc/source/basicgameplay/infiltration.rst +++ b/doc/source/basicgameplay/infiltration.rst @@ -20,6 +20,13 @@ None of the challenges use the mouse. The difficulty at the top lowers with better combat stats. It is not recommended to attempt infiltrations above mid-normal. +The "maximum level" is the number of challenges you will need to pass to receive +the infiltration reward. + +Every time you fail an infiltration challenge, you will take damage based on the +difficulty of the infiltration. If you are reduced to 0 hp or below, the +infiltration will immediately end. + * Most use spacebar as "action" * Some use WASD or arrows interchangeably. * A few others use the rest of the keyboard. @@ -60,4 +67,4 @@ Then move the cursor and press space to mark the mines on the board. ** Cut the wires ** Follow the instructions and press the numbers 1 through 9 to cut the appropriate -wires. \ No newline at end of file +wires. From 2989306ac87a109ceba9ffde0626ecae0911311a Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 13:23:28 -0500 Subject: [PATCH 07/15] Add (in GB) note to params/return values documentation where missing fixes #2403 --- src/ScriptEditor/NetscriptDefinitions.d.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 3701cd8c2..4fd1566b6 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -521,9 +521,9 @@ export interface NodeStats { name: string; /** Node's level */ level: number; - /** Node's RAM */ + /** Node's RAM (GB) */ ram: number; - /** Node's used RAM */ + /** Node's used RAM (GB) */ ramUsed: number; /** Node's number of cores */ cores: number; @@ -5050,7 +5050,7 @@ export interface NS extends Singularity { * const [totalRam, ramUsed] = ns.getServerRam("helios"); * ``` * @param host - Host of target server. - * @returns Array with total and used memory on the specified server. + * @returns Array with total and used memory on the specified server, in GB. */ getServerRam(host: string): [number, number]; @@ -5060,7 +5060,7 @@ export interface NS extends Singularity { * RAM cost: 0.05 GB * * @param host - Hostname of the target server. - * @returns max ram + * @returns max ram (GB) */ getServerMaxRam(host: string): number; /** @@ -5069,7 +5069,7 @@ export interface NS extends Singularity { * RAM cost: 0.05 GB * * @param host - Hostname of the target server. - * @returns used ram + * @returns used ram (GB) */ getServerUsedRam(host: string): number; @@ -5208,7 +5208,7 @@ export interface NS extends Singularity { * ns.tprint(i + " -- " + ns.getPurchasedServerCost(Math.pow(2, i))); * } * ``` - * @param ram - Amount of RAM of a potential purchased server. Must be a power of 2 (2, 4, 8, 16, etc.). Maximum value of 1048576 (2^20). + * @param ram - Amount of RAM of a potential purchased server, in GB. Must be a power of 2 (2, 4, 8, 16, etc.). Maximum value of 1048576 (2^20). * @returns The cost to purchase a server with the specified amount of ram. */ getPurchasedServerCost(ram: number): number; @@ -5256,7 +5256,7 @@ export interface NS extends Singularity { * } * ``` * @param hostname - Host of the purchased server. - * @param ram - Amount of RAM of the purchased server. Must be a power of 2 (2, 4, 8, 16, etc.). Maximum value of 1048576 (2^20). + * @param ram - Amount of RAM of the purchased server, in GB. Must be a power of 2 (2, 4, 8, 16, etc.). Maximum value of 1048576 (2^20). * @returns The hostname of the newly purchased server. */ purchaseServer(hostname: string, ram: number): string; @@ -5297,7 +5297,7 @@ export interface NS extends Singularity { * Returns the maximum RAM that a purchased server can have. * * @remarks RAM cost: 0.05 GB - * @returns Returns the maximum RAM that a purchased server can have. + * @returns Returns the maximum RAM (in GB) that a purchased server can have. */ getPurchasedServerMaxRam(): number; @@ -5504,7 +5504,7 @@ export interface NS extends Singularity { * * @param script - Filename of script. This is case-sensitive. * @param host - Host of target server the script is located on. This is optional, If it is not specified then the function will se the current server as the target server. - * @returns Amount of RAM required to run the specified script on the target server, and 0 if the script does not exist. + * @returns Amount of RAM (in GB) required to run the specified script on the target server, and 0 if the script does not exist. */ getScriptRam(script: string, host?: string): number; From e123642c8f2616a2c8193c4af5b1225f7e5fb433 Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 13:27:23 -0500 Subject: [PATCH 08/15] Changes possibly ambiguous description of array jumping game contract fixes #2281 --- doc/source/basicgameplay/codingcontracts.rst | 2 +- src/data/codingcontracttypes.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/basicgameplay/codingcontracts.rst b/doc/source/basicgameplay/codingcontracts.rst index a1e16ada8..f4f653250 100644 --- a/doc/source/basicgameplay/codingcontracts.rst +++ b/doc/source/basicgameplay/codingcontracts.rst @@ -113,7 +113,7 @@ The list contains the name of (i.e. the value returned by | | | to any position from i to i+n. | | | | | | | | Assuming you are initially positioned at the start of the array, determine | -| | | whether you are able to reach the last index of the array EXACTLY. | +| | | whether you are able to reach the last index of the array. | +------------------------------------+------------------------------------------------------------------------------------------+ | Merge Overlapping Intervals | | Given an array of intervals, merge all overlapping intervals. An interval | | | | is an array with two numbers, where the first number is always less than | diff --git a/src/data/codingcontracttypes.ts b/src/data/codingcontracttypes.ts index b6645ee47..2b68dba1c 100644 --- a/src/data/codingcontracttypes.ts +++ b/src/data/codingcontracttypes.ts @@ -279,7 +279,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [ "i to i+n.", "\n\nAssuming you are initially positioned", "at the start of the array, determine whether you are", - "able to reach the last index exactly.\n\n", + "able to reach the last index.\n\n", "Your answer should be submitted as 1 or 0, representing true and false respectively", ].join(" "); }, From 26ae4345cfcb93a5829dfabc7bac0b3dc481556a Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 15:28:50 -0500 Subject: [PATCH 09/15] Try to clear up confusing documentation for TIX.getOrders() api-documenter won't generate property lists for [key: string]: type interfaces, so I tried to put explanations and @links in the appropriate remarks sections. Since the list of stock symbols is known, this could also be fixed by setting each symbol as an optional property of the StockOrder interface Fixes #2269 --- src/ScriptEditor/NetscriptDefinitions.d.ts | 27 +++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 4fd1566b6..03e03e642 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -254,6 +254,24 @@ export interface AugmentPair { cost: number; } +/** + * @public + */ +export enum PositionTypes { + Long = "L", + Short = "S", +} + +/** + * @public + */ +export enum OrderTypes { + LimitBuy = "Limit Buy Order", + LimitSell = "Limit Sell Order", + StopBuy = "Stop Buy Order", + StopSell = "Stop Sell Order", +} + /** * Value in map of {@link StockOrder} * @public @@ -264,17 +282,18 @@ export interface StockOrderObject { /** Price per share */ price: number; /** Order type */ - type: string; + type: OrderTypes; /** Order position */ - position: string; + position: PositionTypes; } /** * Return value of {@link TIX.getOrders | getOrders} + * + * Keys are stock symbols, properties are arrays of {@link StockOrderObject} * @public */ export interface StockOrder { - /** Stock Symbol */ [key: string]: StockOrderObject[]; } @@ -1199,6 +1218,8 @@ export interface TIX { * @remarks * RAM cost: 2.5 GB * This is an object containing information for all the Limit and Stop Orders you have in the stock market. + * For each symbol you have a position in, the returned object will have a key with that symbol's name. + * The object's properties are each an array of {@link StockOrderObject} * The object has the following structure: * * ```ts From 3276cf3c32f442accf5607de070f050ccca85d6b Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 16:01:00 -0500 Subject: [PATCH 10/15] Add documentation for NetscriptPort to NetscriptDefinitions --- src/ScriptEditor/NetscriptDefinitions.d.ts | 85 ++++++++++++++++++++-- 1 file changed, 78 insertions(+), 7 deletions(-) diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 03e03e642..ebfda0e3b 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -961,6 +961,78 @@ export interface SleeveTask { factionWorkType: string; } +/** + * Object representing a port. A port is a serialized queue. + * @public + */ +export interface NetscriptPort { + /** + * Write data to a port. + * @remarks + * RAM cost: 0 GB + * + * @returns The data popped off the queue if it was full. + */ + write(value: string|number): null|string|number; + + /** + * Attempt to write data to the port. + * @remarks + * RAM cost: 0 GB + * + * @returns True if the data was added to the port, false if the port was full + */ + tryWrite(value: string|number): boolean; + + /** + * Shift an element out of the port. + * @remarks + * RAM cost: 0 GB + * + * This function will remove the first element from the port and return it. + * If the port is empty, then the string “NULL PORT DATA” will be returned. + * @returns the data read. + */ + read(): string|number; + + /** + * Retrieve the first element from the port without removing it. + * @remarks + * RAM cost: 0 GB + * + * This function is used to peek at the data from a port. It returns the + * first element in the specified port without removing that element. If + * the port is empty, the string “NULL PORT DATA” will be returned. + * @returns the data read + */ + peek(): string|number; + + /** + * Check if the port is full. + * @remarks + * RAM cost: 0 GB + * + * @returns true if the port is full, otherwise false + */ + full(): boolean; + + /** + * Check if the port is empty. + * @remarks + * RAM cost: 0 GB + * + * @returns true if the port is empty, otherwise false + */ + empty(): boolean; + + /** + * Empties all data from the port. + * @remarks + * RAM cost: 0 GB + */ + clear(): void; +} + /** * Stock market API * @public @@ -5327,7 +5399,7 @@ export interface NS extends Singularity { * @remarks * RAM cost: 0 GB * - * This function can be used to either write data to a text file (.txt). + * This function can be used to write data to a text file (.txt). * * This function will write data to that text file. If the specified text file does not exist, * then it will be created. The third argument mode, defines how the data will be written to @@ -5336,7 +5408,7 @@ export interface NS extends Singularity { * then the data will be written in “append” mode which means that the data will be added at the * end of the text file. * - * @param handle - Port or text file that will be written to. + * @param handle - Filename of the text file that will be written to. * @param data - Data to write. * @param mode - Defines the write mode. Only valid when writing to text files. */ @@ -5362,13 +5434,13 @@ export interface NS extends Singularity { * @remarks * RAM cost: 0 GB * - * This function is used to read data from a port or from a text file (.txt). + * This function is used to read data from a text file (.txt). * * This function will return the data in the specified text * file. If the text file does not exist, an empty string will be returned. * - * @param handle - Port or text file to read from. - * @returns Data in the specified text file or port. + * @param handle - Filename to read from. + * @returns Data in the specified text file. */ read(handle: string): any; @@ -5440,9 +5512,8 @@ export interface NS extends Singularity { * * @see https://bitburner.readthedocs.io/en/latest/netscript/netscriptmisc.html#netscript-ports * @param port - Port number. Must be an integer between 1 and 20. - * @returns Data in the specified port. */ - getPortHandle(port: number): any[]; + getPortHandle(port: number): NetscriptPort; /** * Delete a file. From ad71e5513c4c4eed1af3b102b4ac4177aefa949e Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 16:04:07 -0500 Subject: [PATCH 11/15] Remove mention of accessing underlying port data array from .rst file Fixes #2201 --- doc/source/netscript/netscriptmisc.rst | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/doc/source/netscript/netscriptmisc.rst b/doc/source/netscript/netscriptmisc.rst index ddbee4088..e41bfc0cf 100644 --- a/doc/source/netscript/netscriptmisc.rst +++ b/doc/source/netscript/netscriptmisc.rst @@ -59,15 +59,14 @@ And the data in port 1 will look like:: .. warning:: In :ref:`netscriptjs`, do not trying writing base `Promises `_ - to a port. + to a port. **Port Handles** WARNING: Port Handles only work in :ref:`netscriptjs`. They do not work in :ref:`netscript1` The :js:func:`getPortHandle` Netscript function can be used to get a handle to a Netscript Port. -This handle allows you to access several new port-related functions and the -port's underlying data structure, which is just a JavaScript array. The functions are: +This handle allows you to access several new port-related functions. The functions are: .. js:method:: NetscriptPort.writePort(data) @@ -111,22 +110,11 @@ port's underlying data structure, which is just a JavaScript array. The function Clears all data from the port. Works the same as the Netscript function `clear` -.. js:attribute:: NetscriptPort.data - - The Netscript port underlying data structure, which is just a Javascript array. All - valid Javascript Array methods can be called on this. - Port Handle Example:: port = getPortHandle(5); back = port.data.pop(); //Get and remove last element in port - //Remove an element from the port - i = port.data.findIndex("foo"); - if (i != -1) { - port.data.slice(i, 1); - } - //Wait for port data before reading while(port.empty()) { sleep(10000); From a16fad7f0117bc02924d278f18f1db6963cc9bc2 Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 16:18:36 -0500 Subject: [PATCH 12/15] Add documentation about using PID for some ns functions Fixes #2219 --- src/ScriptEditor/NetscriptDefinitions.d.ts | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index ebfda0e3b..5f9fa574e 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -109,6 +109,12 @@ interface RunningScript { threads: number; } +/** + * Filename or PID of a script. + * @public + */ +type FilenameOrPID = string | number; + /** * Data representing the internal values of a crime. * @public @@ -4489,11 +4495,11 @@ export interface NS extends Singularity { * //Get logs from foo.script on the foodnstuff server that was run with the arguments [1, "test"] * ns.tail("foo.script", "foodnstuff", 1, "test"); * ``` - * @param fn - Optional. Filename of the script being tailed. If omitted, the current script is tailed. + * @param fn - Optional. Filename or PID of the script being tailed. If omitted, the current script is tailed. * @param host - Optional. Hostname of the script being tailed. Defaults to the server this script is running on. If args are specified, this is not optional. * @param args - Arguments for the script being tailed. */ - tail(fn?: string, host?: string, ...args: any[]): void; + tail(fn?: FilenameOrPID, host?: string, ...args: any[]): void; /** * Get the list of servers connected to a server. @@ -5236,6 +5242,7 @@ export interface NS extends Singularity { * RAM cost: 0.1 GB * * Returns a boolean indicating whether the specified script is running on the target server. + * If you use a PID instead of a filename, the hostname and args parameters are unnecessary. * Remember that a script is uniquely identified by both its name and its arguments. * * @example @@ -5262,12 +5269,12 @@ export interface NS extends Singularity { * //The function call will return true if there is a script named foo.script running with the arguments 1, 5, and “test” (in that order) on the joesguns server, and false otherwise: * ns.isRunning("foo.script", "joesguns", 1, 5, "test"); * ``` - * @param script - Filename of script to check. This is case-sensitive. + * @param script - Filename or PID of script to check. This is case-sensitive. * @param host - Host of target server. * @param args - Arguments to specify/identify which scripts to search for. * @returns True if specified script is running on the target server, and false otherwise. */ - isRunning(script: string, host: string, ...args: string[]): boolean; + isRunning(script: FilenameOrPID, host: string, ...args: string[]): boolean; /** * Get general info about a running script. @@ -5275,10 +5282,14 @@ export interface NS extends Singularity { * RAM cost: 0.3 GB * * Running with no args returns curent script. + * If you use a PID as the first parameter, the hostname and args parameters are unnecessary. * + * @param filename - Optional. Filename or PID of the script. + * @param hostname - Optional. Name of host server the script is running on. + * @param args - Arguments to identify the script * @returns info about a running script */ - getRunningScript(filename?: string | number, hostname?: string, ...args: (string | number)[]): RunningScript; + getRunningScript(filename?: FilenameOrPID, hostname?: string, ...args: (string | number)[]): RunningScript; /** * Get cost of purchasing a server. From 181b8e0e73de38d57d64e90e16091d99c3b4ba48 Mon Sep 17 00:00:00 2001 From: Russell Stringer Date: Mon, 10 Jan 2022 16:26:25 -0500 Subject: [PATCH 13/15] remove mention of infiltration from stats.rst --- doc/source/basicgameplay/infiltration.rst | 2 +- doc/source/basicgameplay/stats.rst | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/source/basicgameplay/infiltration.rst b/doc/source/basicgameplay/infiltration.rst index c482f78da..ae3221107 100644 --- a/doc/source/basicgameplay/infiltration.rst +++ b/doc/source/basicgameplay/infiltration.rst @@ -17,7 +17,7 @@ says 'Infiltrate Company'. When infiltrating a company you will be presented with short active challenges. None of the challenges use the mouse. -The difficulty at the top lowers with better combat stats. It is not recommended +The difficulty at the top lowers with better combat stats and charisma. It is not recommended to attempt infiltrations above mid-normal. The "maximum level" is the number of challenges you will need to pass to receive diff --git a/doc/source/basicgameplay/stats.rst b/doc/source/basicgameplay/stats.rst index 756a85567..0df67b5a9 100644 --- a/doc/source/basicgameplay/stats.rst +++ b/doc/source/basicgameplay/stats.rst @@ -3,8 +3,7 @@ Stats ===== The player has several stats that can be increased in order to progress -in the game. All of these stats other than Hacking will decrease the -difficulty of infiltrations. +in the game. Hacking ^^^^^^^ From 358f5ee8eed19c61be54d4b6572fd637c7e57781 Mon Sep 17 00:00:00 2001 From: smolgumball Date: Mon, 10 Jan 2022 20:40:01 -0700 Subject: [PATCH 14/15] Add simple clickable links to ls command Only supports `nano` as I couldn't figure out how to infer `vim` support without an explicit `nano` or `vim` command being run. --- src/Terminal/commands/ls.tsx | 66 ++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/src/Terminal/commands/ls.tsx b/src/Terminal/commands/ls.tsx index 5cc498308..536af6995 100644 --- a/src/Terminal/commands/ls.tsx +++ b/src/Terminal/commands/ls.tsx @@ -1,9 +1,13 @@ +import { Theme } from "@mui/material/styles"; +import createStyles from "@mui/styles/createStyles"; +import makeStyles from "@mui/styles/makeStyles"; +import { toString } from "lodash"; import React from "react"; -import { ITerminal } from "../ITerminal"; -import { IRouter } from "../../ui/Router"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { BaseServer } from "../../Server/BaseServer"; -import { getFirstParentDirectory, isValidDirectoryPath, evaluateDirectoryPath } from "../../Terminal/DirectoryHelpers"; +import { evaluateDirectoryPath, getFirstParentDirectory, isValidDirectoryPath } from "../../Terminal/DirectoryHelpers"; +import { IRouter } from "../../ui/Router"; +import { ITerminal } from "../ITerminal"; export function ls( terminal: ITerminal, @@ -113,7 +117,51 @@ export function ls( allMessages.sort(); folders.sort(); - function postSegments(segments: string[], style?: any): void { + interface ClickableScriptRowProps { + row: string; + prefix: string; + } + + function ClickableScriptRow({ row, prefix }: ClickableScriptRowProps): React.ReactElement { + const classes = makeStyles((theme: Theme) => + createStyles({ + scriptLinksWrap: { + display: "flex", + color: theme.palette.warning.main, + }, + scriptLink: { + cursor: "pointer", + textDecorationLine: "underline", + paddingRight: "1.15em", + "&:last-child": { padding: 0 }, + }, + }), + )(); + + const rowSplit = row + .split(" ") + .map((x) => x.trim()) + .filter((x) => !!x); + + function onScriptLinkClick(filename: string): void { + if (filename.startsWith("/")) filename = filename.slice(1); + const filepath = terminal.getFilepath(`${prefix}${filename}`); + const code = toString(terminal.getScript(player, filepath)?.code); + router.toScriptEditor({ [filepath]: code }); + } + + return ( + + {rowSplit.map((rowItem) => ( + onScriptLinkClick(rowItem)}> + {rowItem} + + ))} + + ); + } + + function postSegments(segments: string[], style?: any, linked?: boolean): void { const maxLength = Math.max(...segments.map((s) => s.length)) + 1; const filesPerRow = Math.floor(80 / maxLength); for (let i = 0; i < segments.length; i++) { @@ -128,7 +176,11 @@ export function ls( if (!style) { terminal.print(row); } else { - terminal.printRaw({row}); + if (linked) { + terminal.printRaw(); + } else { + terminal.printRaw({row}); + } } } } @@ -139,9 +191,9 @@ export function ls( { segments: allTextFiles }, { segments: allPrograms }, { segments: allContracts }, - { segments: allScripts, style: { color: "yellow", fontStyle: "bold" } }, + { segments: allScripts, style: { color: "yellow", fontStyle: "bold" }, linked: true }, ].filter((g) => g.segments.length > 0); for (let i = 0; i < groups.length; i++) { - postSegments(groups[i].segments, groups[i].style); + postSegments(groups[i].segments, groups[i].style, groups[i].linked); } } From c8db709287967670275d5045763391173873f359 Mon Sep 17 00:00:00 2001 From: smolgumball Date: Mon, 10 Jan 2022 21:00:52 -0700 Subject: [PATCH 15/15] Add hostname safety --- src/Terminal/commands/ls.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Terminal/commands/ls.tsx b/src/Terminal/commands/ls.tsx index 536af6995..2c00e7f28 100644 --- a/src/Terminal/commands/ls.tsx +++ b/src/Terminal/commands/ls.tsx @@ -120,9 +120,10 @@ export function ls( interface ClickableScriptRowProps { row: string; prefix: string; + hostname: string; } - function ClickableScriptRow({ row, prefix }: ClickableScriptRowProps): React.ReactElement { + function ClickableScriptRow({ row, prefix, hostname }: ClickableScriptRowProps): React.ReactElement { const classes = makeStyles((theme: Theme) => createStyles({ scriptLinksWrap: { @@ -144,6 +145,9 @@ export function ls( .filter((x) => !!x); function onScriptLinkClick(filename: string): void { + if (player.getCurrentServer().hostname !== hostname) { + return terminal.error(`File is not on this server, connect to ${hostname} and try again`); + } if (filename.startsWith("/")) filename = filename.slice(1); const filepath = terminal.getFilepath(`${prefix}${filename}`); const code = toString(terminal.getScript(player, filepath)?.code); @@ -177,7 +181,7 @@ export function ls( terminal.print(row); } else { if (linked) { - terminal.printRaw(); + terminal.printRaw(); } else { terminal.printRaw({row}); }