API: Move and rename purchased server functions to cloud API (#2367)

* Convert purchased server functions to cloud API

- Create `ns.cloud`
- Change `bitnode multipliers` and `server constants` wording for consistency
- change `server`, `ram` and `getting started` docs for consistency
- Added changes to 3.0.0 API Break and `setRemovedFunctions` in NetscriptFunctions.js

Tested by
- running tutorial `purchase-server-8gb.js`, and a more typical player one
- buying manually using vendor (Alpha Ent in Sector 12)
- deleting them all using script, and checked all deleted functions gave correct error
- Imported completed save to ensure auto-transfer of function work

* Revision in line with comments

- changed more `purchased` to `cloud` references
- Added BN mults auto-conversion

* Update getting_started.md

 - Corrected function names for new `cloud API`

* Don't show `cloud API` warning

v3.0.0 API break auto-replaces `cloud` functions, not warning suggested.

* API Break correction

- `cloud` affected API break replacement changed to be more descriptive and functional

* Fix typo and add empty lines

* Update many things (check commit's description)

- Comments
- Terminal message
- UI Text
- TSDoc
- md docs
- Improve error messages in src\NetscriptFunctions\Cloud.ts
This commit is contained in:
gmcew
2025-11-07 20:10:33 +00:00
committed by GitHub
parent d1a4ec8337
commit 7c0286222c
58 changed files with 1301 additions and 1045 deletions
+39 -202
View File
@@ -34,23 +34,14 @@ import {
SpecialBladeburnerActionTypeForSleeve,
} from "@enums";
import { PromptEvent } from "./ui/React/PromptManager";
import { GetServer, DeleteServer, AddToAllServers, createUniqueRandomIp } from "./Server/AllServers";
import { GetServer } from "./Server/AllServers";
import {
getServerOnNetwork,
numCycleForGrowth,
numCycleForGrowthCorrected,
processSingleServerGrowth,
safelyCreateUniqueServer,
getWeakenEffect,
} from "./Server/ServerHelpers";
import {
getPurchasedServerUpgradeCost,
getPurchaseServerCost,
getPurchaseServerLimit,
getPurchaseServerMaxRam,
renamePurchasedServer,
upgradePurchasedServer,
} from "./Server/ServerPurchases";
import { influenceStockThroughServerGrow } from "./StockMarket/PlayerInfluencing";
import { runScriptFromScript } from "./NetscriptWorker";
import { killWorkerScript, killWorkerScriptByPid } from "./Netscript/killWorkerScript";
@@ -85,6 +76,7 @@ import { NetscriptStockMarket } from "./NetscriptFunctions/StockMarket";
import { NetscriptGrafting } from "./NetscriptFunctions/Grafting";
import { NS, RecentScript, ProcessInfo, NSEnums } from "@nsdefs";
import { NetscriptSingularity } from "./NetscriptFunctions/Singularity";
import { NetscriptCloud } from "./NetscriptFunctions/Cloud";
import { dialogBoxCreate } from "./ui/React/DialogBox";
import { SnackbarEvents } from "./ui/React/Snackbar";
@@ -159,6 +151,7 @@ export const ns: InternalAPI<NSFull> = {
stock: NetscriptStockMarket(),
grafting: NetscriptGrafting(),
hacknet: NetscriptHacknet(),
cloud: NetscriptCloud(),
sprintf:
(ctx) =>
(_format, ...args) => {
@@ -1045,198 +1038,6 @@ export const ns: InternalAPI<NSFull> = {
const ident = helpers.scriptIdentifier(ctx, fn, host, scriptArgs);
return helpers.getRunningScript(ctx, ident) !== null;
},
getPurchasedServerLimit: () => () => {
return getPurchaseServerLimit();
},
getPurchasedServerMaxRam: () => () => {
return getPurchaseServerMaxRam();
},
getPurchasedServerCost: (ctx) => (_ram) => {
const ram = helpers.number(ctx, "ram", _ram);
const cost = getPurchaseServerCost(ram);
if (cost === Infinity) {
if (ram > getPurchaseServerMaxRam()) {
helpers.log(ctx, () => `Invalid argument: ram='${ram}' must not be greater than getPurchaseServerMaxRam`);
} else {
helpers.log(ctx, () => `Invalid argument: ram='${ram}' must be a positive power of 2`);
}
return Infinity;
}
return cost;
},
purchaseServer: (ctx) => (_name, _ram) => {
const name = helpers.string(ctx, "name", _name);
const ram = helpers.number(ctx, "ram", _ram);
let hostnameStr = String(name);
hostnameStr = hostnameStr.replace(/\s+/g, "");
if (hostnameStr == "" || isIPAddress(hostnameStr)) {
helpers.log(ctx, () => `Invalid argument: hostname='${hostnameStr}'`);
return "";
}
if (hostnameStr.startsWith("hacknet-node-") || hostnameStr.startsWith("hacknet-server-")) {
helpers.log(ctx, () => `Invalid argument: hostname='${hostnameStr}' is a reserved hostname.`);
return "";
}
if (Player.purchasedServers.length >= getPurchaseServerLimit()) {
helpers.log(
ctx,
() =>
`You have reached the maximum limit of ${getPurchaseServerLimit()} servers. You cannot purchase any more.`,
);
return "";
}
const cost = getPurchaseServerCost(ram);
if (cost === Infinity) {
if (ram > getPurchaseServerMaxRam()) {
helpers.log(ctx, () => `Invalid argument: ram='${ram}' must not be greater than getPurchaseServerMaxRam`);
} else {
helpers.log(ctx, () => `Invalid argument: ram='${ram}' must be a positive power of 2`);
}
return "";
}
if (Player.money < cost) {
helpers.log(ctx, () => `Not enough money to purchase server. Need ${formatMoney(cost)}`);
return "";
}
const newServ = safelyCreateUniqueServer({
ip: createUniqueRandomIp(),
hostname: hostnameStr,
organizationName: "",
isConnectedTo: false,
adminRights: true,
purchasedByPlayer: true,
maxRam: ram,
});
AddToAllServers(newServ);
Player.purchasedServers.push(newServ.hostname);
const homeComputer = Player.getHomeComputer();
homeComputer.serversOnNetwork.push(newServ.hostname);
newServ.serversOnNetwork.push(homeComputer.hostname);
Player.loseMoney(cost, "servers");
helpers.log(ctx, () => `Purchased new server with hostname '${newServ.hostname}' for ${formatMoney(cost)}`);
return newServ.hostname;
},
getPurchasedServerUpgradeCost: (ctx) => (_host, _ram) => {
const host = helpers.string(ctx, "host", _host);
const ram = helpers.number(ctx, "ram", _ram);
try {
return getPurchasedServerUpgradeCost(host, ram);
} catch (err) {
helpers.log(ctx, () => String(err));
return -1;
}
},
upgradePurchasedServer: (ctx) => (_host, _ram) => {
const host = helpers.string(ctx, "host", _host);
const ram = helpers.number(ctx, "ram", _ram);
try {
upgradePurchasedServer(host, ram);
return true;
} catch (err) {
helpers.log(ctx, () => String(err));
return false;
}
},
renamePurchasedServer: (ctx) => (_hostname, _newName) => {
const hostname = helpers.string(ctx, "hostname", _hostname);
const newName = helpers.string(ctx, "newName", _newName);
try {
renamePurchasedServer(hostname, newName);
return true;
} catch (err) {
helpers.log(ctx, () => String(err));
return false;
}
},
deleteServer: (ctx) => (_name) => {
const name = helpers.string(ctx, "name", _name);
let hostnameStr = String(name);
hostnameStr = hostnameStr.replace(/\s\s+/g, "");
const server = helpers.getNormalServer(ctx, hostnameStr);
if (!server.purchasedByPlayer || server.hostname === "home") {
helpers.log(ctx, () => "Cannot delete non-purchased server.");
return false;
}
const hostname = server.hostname;
// Can't delete server you're currently connected to
if (server.isConnectedTo) {
helpers.log(ctx, () => "You are currently connected to the server you are trying to delete.");
return false;
}
// A server cannot delete itself
if (hostname === ctx.workerScript.hostname) {
helpers.log(ctx, () => "Cannot delete the server this script is running on.");
return false;
}
// Delete all scripts running on server
if (server.runningScriptMap.size > 0) {
helpers.log(ctx, () => `Cannot delete server '${hostname}' because it still has scripts running.`);
return false;
}
// Delete from player's purchasedServers array
let found = false;
for (let i = 0; i < Player.purchasedServers.length; ++i) {
if (hostname == Player.purchasedServers[i]) {
found = true;
Player.purchasedServers.splice(i, 1);
break;
}
}
if (!found) {
helpers.log(
ctx,
() => `Could not identify server ${hostname} as a purchased server. This is a bug. Report to dev.`,
);
return false;
}
// Delete from all servers
DeleteServer(hostname);
// Delete from home computer
found = false;
const homeComputer = Player.getHomeComputer();
for (let i = 0; i < homeComputer.serversOnNetwork.length; ++i) {
if (hostname == homeComputer.serversOnNetwork[i]) {
homeComputer.serversOnNetwork.splice(i, 1);
helpers.log(ctx, () => `Deleted server '${hostnameStr}`);
return true;
}
}
// Wasn't found on home computer
helpers.log(ctx, () => `Could not find server ${hostname} as a purchased server. This is a bug. Report to dev.`);
return false;
},
getPurchasedServers:
(ctx) =>
(_returnOpts): string[] => {
const returnOpts = helpers.hostReturnOptions(_returnOpts);
const res: string[] = [];
for (const hostname of Player.purchasedServers) {
const server = helpers.getServer(ctx, hostname);
const id = helpers.returnServerID(server, returnOpts);
res.push(id);
}
return res;
},
writePort: (ctx) => (_portNumber, data) => {
const portNumber = helpers.portNumber(ctx, _portNumber);
return writePort(portNumber, data);
@@ -1725,6 +1526,42 @@ setRemovedFunctions(ns, {
version: "3.0.0",
replacement: "ns.ui.setTailTitle()",
},
getPurchasedServerCost: {
version: "3.0.0",
replacement: "ns.cloud.getServerCost()",
},
purchaseServer: {
version: "3.0.0",
replacement: "ns.cloud.purchaseServer()",
},
getPurchasedServerUpgradeCost: {
version: "3.0.0",
replacement: "ns.cloud.getServerUpgradeCost()",
},
upgradePurchasedServer: {
version: "3.0.0",
replacement: "ns.cloud.upgradeServer()",
},
renamePurchasedServer: {
version: "3.0.0",
replacement: "ns.cloud.renameServer()",
},
deleteServer: {
version: "3.0.0",
replacement: "ns.cloud.deleteServer()",
},
getPurchasedServers: {
version: "3.0.0",
replacement: "ns.cloud.getServerNames()",
},
getPurchasedServerLimit: {
version: "3.0.0",
replacement: "ns.cloud.getServerLimit()",
},
getPurchasedServerMaxRam: {
version: "3.0.0",
replacement: "ns.cloud.getRamLimit()",
},
});
export function NetscriptFunctions(ws: WorkerScript): NSFull {