diff --git a/src/Netscript/NetscriptHelpers.tsx b/src/Netscript/NetscriptHelpers.tsx index 54935596b..2126d41e0 100644 --- a/src/Netscript/NetscriptHelpers.tsx +++ b/src/Netscript/NetscriptHelpers.tsx @@ -104,6 +104,7 @@ export const helpers = { createPublicRunningScript, failOnHacknetServer, validateBitNodeOptions, + getNormalServer, }; /** RunOptions with non-optional, type-validated members, for passing between internal functions. */ @@ -478,7 +479,7 @@ function scriptIdentifier( * @param {string} hostname - Hostname of the server * @returns {BaseServer} The specified server as a BaseServer */ -function getServer(ctx: NetscriptContext, hostname: string) { +function getServer(ctx: NetscriptContext, hostname: string): BaseServer { const server = GetServer(hostname); if (server == null || (server.serversOnNetwork.length == 0 && server.hostname != "home")) { const str = hostname === "" ? "'' (empty string)" : "'" + hostname + "'"; @@ -487,6 +488,21 @@ function getServer(ctx: NetscriptContext, hostname: string) { return server; } +/** + * A "normal server" is an instance of the Server class in src/Server/Server.ts. + */ +function getNormalServer(ctx: NetscriptContext, host: string): Server { + const server = getServer(ctx, host); + if (!(server instanceof Server)) { + let errorMessage = `Cannot be executed on ${host}.`; + if (server instanceof HacknetServer) { + errorMessage += " The server must not be a hacknet server."; + } + throw helpers.errorMessage(ctx, errorMessage); + } + return server; +} + function isScriptArgs(args: unknown): args is ScriptArg[] { const isScriptArg = (arg: unknown) => typeof arg === "string" || typeof arg === "number" || typeof arg === "boolean"; return Array.isArray(args) && args.every(isScriptArg); @@ -495,10 +511,7 @@ function isScriptArgs(args: unknown): args is ScriptArg[] { function hack(ctx: NetscriptContext, hostname: string, manual: boolean, opts: unknown): Promise { const ws = ctx.workerScript; const { threads, stock, additionalMsec } = validateHGWOptions(ctx, opts); - const server = getServer(ctx, hostname); - if (!(server instanceof Server)) { - throw errorMessage(ctx, "Cannot be executed on this server."); - } + const server = getNormalServer(ctx, hostname); // Calculate the hacking time // This is in seconds @@ -785,8 +798,8 @@ function createPublicRunningScript(runningScript: RunningScript, workerScript?: /** * Used to fail a function if the function's target is a Hacknet Server. * This is used for functions that should run on normal Servers, but not Hacknet Servers + * @param {NetscriptContext} ctx - Netscript context * @param {Server} server - Target server - * @param {string} callingFn - Name of calling function. For logging purposes * @returns {boolean} True if the server is a Hacknet Server, false otherwise */ function failOnHacknetServer(ctx: NetscriptContext, server: BaseServer): boolean { diff --git a/src/NetscriptFunctions.ts b/src/NetscriptFunctions.ts index 3cc677243..3cc275e7f 100644 --- a/src/NetscriptFunctions.ts +++ b/src/NetscriptFunctions.ts @@ -51,7 +51,6 @@ import { renamePurchasedServer, upgradePurchasedServer, } from "./Server/ServerPurchases"; -import { Server } from "./Server/Server"; import { influenceStockThroughServerGrow } from "./StockMarket/PlayerInfluencing"; import { runScriptFromScript } from "./NetscriptWorker"; import { killWorkerScript, killWorkerScriptByPid } from "./Netscript/killWorkerScript"; @@ -200,11 +199,7 @@ export const ns: InternalAPI = { const hackAmount = helpers.number(ctx, "hackAmount", _hackAmount); // Check argument validity - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return -1; - } + const server = helpers.getNormalServer(ctx, host); if (isNaN(hackAmount)) { throw helpers.errorMessage( ctx, @@ -229,11 +224,7 @@ export const ns: InternalAPI = { hackAnalyze: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 0; - } + const server = helpers.getNormalServer(ctx, host); return calculatePercentMoneyHacked(server, Player); }, @@ -241,11 +232,7 @@ export const ns: InternalAPI = { let threads = helpers.number(ctx, "threads", _threads); if (_host) { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 0; - } + const server = helpers.getNormalServer(ctx, host); const percentHacked = calculatePercentMoneyHacked(server, Player); @@ -260,11 +247,7 @@ export const ns: InternalAPI = { hackAnalyzeChance: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 0; - } + const server = helpers.getNormalServer(ctx, host); return calculateHackingChance(server, Player); }, @@ -288,10 +271,7 @@ export const ns: InternalAPI = { const host = helpers.string(ctx, "host", _host); const { threads, stock, additionalMsec } = helpers.validateHGWOptions(ctx, opts); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - throw helpers.errorMessage(ctx, "Cannot be executed on this server."); - } + const server = helpers.getNormalServer(ctx, host); // No root access or skill level too low const canHack = netscriptCanGrow(server); @@ -341,12 +321,7 @@ export const ns: InternalAPI = { const cores = helpers.positiveInteger(ctx, "cores", _cores); // Check argument validity - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - // Todo 2.3: Make this throw instead of returning 0? - helpers.log(ctx, () => `${host} is not a hackable server. Returning 0.`); - return 0; - } + const server = helpers.getNormalServer(ctx, host); if (!Number.isFinite(mult) || mult < 1) { throw helpers.errorMessage(ctx, `Invalid argument: multiplier must be finite and >= 1, is ${mult}.`); } @@ -360,12 +335,7 @@ export const ns: InternalAPI = { if (_host) { const cores = helpers.number(ctx, "cores", _cores); const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 0; - } + const server = helpers.getNormalServer(ctx, host); const maxThreadsNeeded = Math.ceil( numCycleForGrowthCorrected(server, server.moneyMax, server.moneyAvailable, cores), @@ -380,10 +350,7 @@ export const ns: InternalAPI = { const host = helpers.string(ctx, "host", _host); const { threads, additionalMsec } = helpers.validateHGWOptions(ctx, opts); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - throw helpers.errorMessage(ctx, "Cannot be executed on this server."); - } + const server = helpers.getNormalServer(ctx, host); // No root access or skill level too low const canHack = netscriptCanWeaken(server); @@ -572,11 +539,7 @@ export const ns: InternalAPI = { nuke: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return false; - } + const server = helpers.getNormalServer(ctx, host); if (server.hasAdminRights) { helpers.log(ctx, () => `Already have root access to '${server.hostname}'.`); return true; @@ -595,11 +558,7 @@ export const ns: InternalAPI = { }, brutessh: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return false; - } + const server = helpers.getNormalServer(ctx, host); if (!Player.hasProgram(CompletedProgramName.bruteSsh)) { helpers.log(ctx, () => "You do not have the BruteSSH.exe program!"); return false; @@ -615,11 +574,7 @@ export const ns: InternalAPI = { }, ftpcrack: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return false; - } + const server = helpers.getNormalServer(ctx, host); if (!Player.hasProgram(CompletedProgramName.ftpCrack)) { helpers.log(ctx, () => "You do not have the FTPCrack.exe program!"); return false; @@ -635,11 +590,7 @@ export const ns: InternalAPI = { }, relaysmtp: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return false; - } + const server = helpers.getNormalServer(ctx, host); if (!Player.hasProgram(CompletedProgramName.relaySmtp)) { helpers.log(ctx, () => "You do not have the relaySMTP.exe program!"); return false; @@ -655,11 +606,7 @@ export const ns: InternalAPI = { }, httpworm: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return false; - } + const server = helpers.getNormalServer(ctx, host); if (!Player.hasProgram(CompletedProgramName.httpWorm)) { helpers.log(ctx, () => "You do not have the HTTPWorm.exe program!"); return false; @@ -675,11 +622,7 @@ export const ns: InternalAPI = { }, sqlinject: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return false; - } + const server = helpers.getNormalServer(ctx, host); if (!Player.hasProgram(CompletedProgramName.sqlInject)) { helpers.log(ctx, () => "You do not have the SQLInject.exe program!"); return false; @@ -1007,14 +950,7 @@ export const ns: InternalAPI = { }, getServerMoneyAvailable: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 0; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return 0; - } + const server = helpers.getNormalServer(ctx, host); if (server.hostname == "home") { // Return player's money helpers.log(ctx, () => `returned player's money: ${formatMoney(Player.money)}`); @@ -1025,92 +961,43 @@ export const ns: InternalAPI = { }, getServerSecurityLevel: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 1; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return 1; - } + const server = helpers.getNormalServer(ctx, host); helpers.log(ctx, () => `returned ${formatSecurity(server.hackDifficulty)} for '${server.hostname}'`); return server.hackDifficulty; }, getServerBaseSecurityLevel: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 1; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return 1; - } + const server = helpers.getNormalServer(ctx, host); helpers.log(ctx, () => `returned ${formatSecurity(server.baseDifficulty)} for '${server.hostname}'`); return server.baseDifficulty; }, getServerMinSecurityLevel: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 1; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return 1; - } + const server = helpers.getNormalServer(ctx, host); helpers.log(ctx, () => `returned ${formatSecurity(server.minDifficulty)} for ${server.hostname}`); return server.minDifficulty; }, getServerRequiredHackingLevel: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 1; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return 1; - } + const server = helpers.getNormalServer(ctx, host); helpers.log(ctx, () => `returned ${formatNumberNoSuffix(server.requiredHackingSkill, 0)} for '${server.hostname}'`); return server.requiredHackingSkill; }, getServerMaxMoney: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 0; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return 0; - } + const server = helpers.getNormalServer(ctx, host); helpers.log(ctx, () => `returned ${formatMoney(server.moneyMax)} for '${server.hostname}'`); return server.moneyMax; }, getServerGrowth: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 1; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return 1; - } + const server = helpers.getNormalServer(ctx, host); helpers.log(ctx, () => `returned ${server.serverGrowth} for '${server.hostname}'`); return server.serverGrowth; }, getServerNumPortsRequired: (ctx) => (_host) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "Cannot be executed on this server."); - return 5; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return 5; - } + const server = helpers.getNormalServer(ctx, host); helpers.log(ctx, () => `returned ${server.numOpenPortsRequired} for '${server.hostname}'`); return server.numOpenPortsRequired; }, @@ -1274,11 +1161,7 @@ export const ns: InternalAPI = { const name = helpers.string(ctx, "name", _name); let hostnameStr = String(name); hostnameStr = hostnameStr.replace(/\s\s+/g, ""); - const server = GetServer(hostnameStr); - if (!(server instanceof Server)) { - helpers.log(ctx, () => `Invalid argument: hostname='${hostnameStr}'`); - return false; - } + const server = helpers.getNormalServer(ctx, hostnameStr); if (!server.purchasedByPlayer || server.hostname === "home") { helpers.log(ctx, () => "Cannot delete non-purchased server."); @@ -1528,14 +1411,7 @@ export const ns: InternalAPI = { (ctx) => (_host = ctx.workerScript.hostname) => { const host = helpers.string(ctx, "hostname", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "invalid for this kind of server"); - return Infinity; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return Infinity; - } + const server = helpers.getNormalServer(ctx, host); return calculateHackingTime(server, Player) * 1000; }, @@ -1543,14 +1419,7 @@ export const ns: InternalAPI = { (ctx) => (_host = ctx.workerScript.hostname) => { const host = helpers.string(ctx, "host", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "invalid for this kind of server"); - return Infinity; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return Infinity; - } + const server = helpers.getNormalServer(ctx, host); return calculateGrowTime(server, Player) * 1000; }, @@ -1558,14 +1427,7 @@ export const ns: InternalAPI = { (ctx) => (_host = ctx.workerScript.hostname) => { const host = helpers.string(ctx, "hostname", _host); - const server = helpers.getServer(ctx, host); - if (!(server instanceof Server)) { - helpers.log(ctx, () => "invalid for this kind of server"); - return Infinity; - } - if (helpers.failOnHacknetServer(ctx, server)) { - return Infinity; - } + const server = helpers.getNormalServer(ctx, host); return calculateWeakenTime(server, Player) * 1000; }, diff --git a/src/utils/APIBreaks/3.0.0.ts b/src/utils/APIBreaks/3.0.0.ts index e2280023a..46949ceee 100644 --- a/src/utils/APIBreaks/3.0.0.ts +++ b/src/utils/APIBreaks/3.0.0.ts @@ -241,5 +241,61 @@ export const breakingChanges300: VersionBreakingChange = { info: 'The "VeChain" upgrade was removed. The cost of that upgrade was refunded.', showWarning: false, }, + { + brokenAPIs: [ + { name: "ns.hackAnalyzeThreads" }, + { name: "ns.hackAnalyze" }, + { name: "ns.hackAnalyzeSecurity" }, + { name: "ns.hackAnalyzeChance" }, + { name: "ns.growthAnalyze" }, + { name: "ns.growthAnalyzeSecurity" }, + { name: "ns.nuke" }, + { name: "ns.brutessh" }, + { name: "ns.ftpcrack" }, + { name: "ns.relaysmtp" }, + { name: "ns.httpworm" }, + { name: "ns.sqlinject" }, + { name: "ns.getServerMoneyAvailable" }, + { name: "ns.getServerSecurityLevel" }, + { name: "ns.getServerBaseSecurityLevel" }, + { name: "ns.getServerMinSecurityLevel" }, + { name: "ns.getServerRequiredHackingLevel" }, + { name: "ns.getServerMaxMoney" }, + { name: "ns.getServerGrowth" }, + { name: "ns.getServerNumPortsRequired" }, + { name: "ns.deleteServer" }, + { name: "ns.getHackTime" }, + { name: "ns.getGrowTime" }, + { name: "ns.getWeakenTime" }, + ], + info: + "Some APIs returned a default value when you passed the hostname of a non-hackable server (e.g., hacknet " + + "server) to them.\nThese APIs now throw an error. The affected APIs are:\n" + + "- ns.hackAnalyzeThreads\n" + + "- ns.hackAnalyze\n" + + "- ns.hackAnalyzeSecurity\n" + + "- ns.hackAnalyzeChance\n" + + "- ns.growthAnalyze\n" + + "- ns.growthAnalyzeSecurity\n" + + "- ns.nuke\n" + + "- ns.brutessh\n" + + "- ns.ftpcrack\n" + + "- ns.relaysmtp\n" + + "- ns.httpworm\n" + + "- ns.sqlinject\n" + + "- ns.getServerMoneyAvailable\n" + + "- ns.getServerSecurityLevel\n" + + "- ns.getServerBaseSecurityLevel\n" + + "- ns.getServerMinSecurityLevel\n" + + "- ns.getServerRequiredHackingLevel\n" + + "- ns.getServerMaxMoney\n" + + "- ns.getServerGrowth\n" + + "- ns.getServerNumPortsRequired\n" + + "- ns.deleteServer\n" + + "- ns.getHackTime\n" + + "- ns.getGrowTime\n" + + "- ns.getWeakenTime\n", + showWarning: false, + }, ], };