v1 api breaks

This commit is contained in:
Olivier Gagnon 2021-11-02 22:11:22 -04:00
parent fcf29fa37c
commit b2bf3fc21f
13 changed files with 273 additions and 242 deletions

34
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -179,7 +179,7 @@ export class Action implements IAction {
baseTime = Math.max(1, (baseTime * skillFac) / statFac);
return Math.ceil(baseTime * this.getActionTimePenalty());
return Math.ceil(baseTime * this.getActionTimePenalty()) * 1000;
}
// For actions that have teams. To be implemented by subtypes.

@ -1007,7 +1007,7 @@ export class Bladeburner implements IBladeburner {
getRecruitmentTime(player: IPlayer): number {
const effCharisma = player.charisma * this.skillMultipliers.effCha;
const charismaFactor = Math.pow(effCharisma, 0.81) + effCharisma / 90;
return Math.max(10, Math.round(BladeburnerConstants.BaseRecruitmentTimeNeeded - charismaFactor));
return Math.max(10, Math.round(BladeburnerConstants.BaseRecruitmentTimeNeeded - charismaFactor)) * 1000;
}
resetSkillMultipliers(): void {
@ -2108,13 +2108,13 @@ export class Bladeburner implements IBladeburner {
case ActionTypes["Training"]:
case ActionTypes["Field Analysis"]:
case ActionTypes["FieldAnalysis"]:
return 30;
return 30000;
case ActionTypes["Recruitment"]:
return this.getRecruitmentTime(player);
case ActionTypes["Diplomacy"]:
case ActionTypes["Hyperbolic Regeneration Chamber"]:
case ActionTypes["Incite Violence"]:
return 60;
return 60000;
default:
workerScript.log("bladeburner.getActionTime", errorLogText);
return -1;

@ -114,7 +114,7 @@ export const CONSTANTS: {
TotalNumBitNodes: number;
LatestUpdate: string;
} = {
Version: "0.58.0",
Version: "1.0.0",
// Speed (in ms) at which the main loop is updated
_idleSpeed: 200,
@ -281,64 +281,31 @@ export const CONSTANTS: {
TotalNumBitNodes: 24,
LatestUpdate: `
v0.58.0 - 2021-10-27 Road to Steam (hydroflame & community)
v1.0.0 - 2021-XX-XX Pre-Steam
-------------------------------------------
** Announcement **
** API BREAKS **
* To prepare for Steam we will fix some inconsistencies in the Netscript API. Ideally we can also write a
save file migration that will automatically convert all breaking changes in your scripts without any
player input.
** BREAKING (kindof) **
* All stock market functions are now under the 'stock' namespace, like 'hacknet'
However when you load your game with v0.58.0 for the first time it should automatically convert everything.
** SF -1 **
* new SF -1: Reality Alteration
** Gang **
* Ascension formula now better
* Karma requirement now much lower in most nodes
* Territory heavily penalizes gains
* T.R.P. not available outside BN2.
** Netscript **
* It is no longer possible to send anything but strings or numbers to other scripts. (prevents exploits)
* Improve code for some netscript functions (@omuretsu)
** Script Editor **
* Added Solarized light/dark as theme (@CalvinTrops)
* Added theme clo
* Fixed sleeve namespace smart autocomplete.
** Hacknet Servers **
* Cores affect grow/weaken like they do on home computer
** Infiltration **
* Slash game modified to be easier.
* bladeburner.getActionTime will return milliseconds instead of seconds.
* getHackTime will return milliseconds instead of seconds.
* getGrowTime will return milliseconds instead of seconds.
* getWeakenTime will return milliseconds instead of seconds.
* hackAnalyzePercent renamed to hackAnalyze
* hackAnalyzePercent will return decimal instead of percentage
* hackChance (not formulas.basic.hackChance) renamed to hackAnalyzeChance
* getPurchasedServers won't let you query for ips instead of hostnames.
* getStats is deprecated in favor getPlayer
* getCharacterInformation is deprecated in favor getPlayer
* getServerRam deprecated in favor of getServerMaxRam and getServerUsedRam
* getServerBaseSecurityLevel will be deprecated in favor of nothing, it's not really used.
* sleep can no longer be called simultenaously, a new function called asleep will let you.
* write returns promise (needs to be awaited).
* scp returns a promise (needs to be awaited).
* free port, write, read
* write, read does not support port anymore, writePort and readPort does.
** Misc. **
* Fix typo in corp (@Saynt_Garmo)
* Fixed a bug where corp wouldn't let you buyback shares. (@Saynt_Garmo)
* Fixed a bug where sleeves couldn't perform some crimes. (@Saynt_Garmo)
* Hospitalization and Eating noodles are now toasts (@Saynt_Garmo)
* Fixed some repeated code (@omuretsu)
* Fixed Character Overview preventing clicks underneath it even when hidden. (@omuretsu)
* Fixed typo in tutorial. (@omuretsu)
* Create Programs and Factions invitation badges now dissapear when you open their respective pages.
* Add killall script in character overview.
* Fixed bug in corp that made last city production be the production for all cities for newly created product.
* Fix bug that allowed reputation to transfer to new jobs.
* Fixed memory leak with ns2.
* nerf noodle bar
`,
};

@ -17,6 +17,7 @@ export enum Exploit {
UndocumentedFunctionCall = "UndocumentedFunctionCall",
TimeCompression = "TimeCompression",
RealityAlteration = "RealityAlteration",
N00dles = "N00dles",
// To the players reading this. Yes you're supposed to add EditSaveFile by
// editing your save file, yes you could add them all, no we don't care
// that's not the point.
@ -33,6 +34,7 @@ const names: {
Unclickable: "by clicking the unclickable.",
UndocumentedFunctionCall: "by looking beyond the documentation.",
RealityAlteration: "by altering reality to suit your whims.",
N00dles: "by harnessing the power of the n00dles.",
};
export function ExploitName(exploit: string): string {

@ -23,6 +23,7 @@ import { use } from "../../ui/Context";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { SnackbarEvents } from "../../ui/React/Snackbar";
import { N00dles } from "../../utils/helpers/N00dles";
import { Exploit } from "../../Exploits/Exploit";
type IProps = {
loc: Location;
@ -79,6 +80,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
function EatNoodles(): void {
SnackbarEvents.emit("You ate some delicious noodles and feel refreshed", "success");
N00dles();
if (player.sourceFiles.length > 0) player.giveExploit(Exploit.N00dles);
}
return (

@ -80,9 +80,9 @@ export const RamCosts: IMap<any> = {
scan: RamCostConstants.ScriptScanRamCost,
hack: RamCostConstants.ScriptHackRamCost,
hackAnalyzeThreads: RamCostConstants.ScriptHackAnalyzeRamCost,
hackAnalyzePercent: RamCostConstants.ScriptHackAnalyzeRamCost,
hackAnalyze: RamCostConstants.ScriptHackAnalyzeRamCost,
hackAnalyzeSecurity: RamCostConstants.ScriptHackAnalyzeRamCost,
hackChance: RamCostConstants.ScriptHackAnalyzeRamCost,
hackAnalyzeChance: RamCostConstants.ScriptHackAnalyzeRamCost,
sleep: 0,
grow: RamCostConstants.ScriptGrowRamCost,
growthAnalyze: RamCostConstants.ScriptGrowthAnalyzeRamCost,
@ -160,12 +160,12 @@ export const RamCosts: IMap<any> = {
purchaseServer: RamCostConstants.ScriptPurchaseServerRamCost,
deleteServer: RamCostConstants.ScriptPurchaseServerRamCost,
getPurchasedServers: RamCostConstants.ScriptPurchaseServerRamCost,
write: RamCostConstants.ScriptReadWriteRamCost,
tryWrite: RamCostConstants.ScriptReadWriteRamCost,
read: RamCostConstants.ScriptReadWriteRamCost,
peek: RamCostConstants.ScriptReadWriteRamCost,
clear: RamCostConstants.ScriptReadWriteRamCost,
getPortHandle: RamCostConstants.ScriptReadWriteRamCost * 10,
write: 0,
tryWrite: 0,
read: 0,
peek: 0,
clear: 0,
getPortHandle: 0,
rm: RamCostConstants.ScriptReadWriteRamCost,
scriptRunning: RamCostConstants.ScriptArbScriptRamCost,
scriptKill: RamCostConstants.ScriptArbScriptRamCost,

@ -516,26 +516,26 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
return hackAmount / Math.floor(server.moneyAvailable * percentHacked);
},
hackAnalyzePercent: function (hostname: any): any {
updateDynamicRam("hackAnalyzePercent", getRamCost("hackAnalyzePercent"));
hackAnalyze: function (hostname: any): any {
updateDynamicRam("hackAnalyze", getRamCost("hackAnalyze"));
const server = safeGetServer(hostname, "hackAnalyzePercent");
const server = safeGetServer(hostname, "hackAnalyze");
if (!(server instanceof Server)) {
workerScript.log("hackAnalyzePercent", "Cannot be executed on this server.");
workerScript.log("hackAnalyze", "Cannot be executed on this server.");
return false;
}
return calculatePercentMoneyHacked(server, Player) * 100;
return calculatePercentMoneyHacked(server, Player);
},
hackAnalyzeSecurity: function (threads: any): number {
return CONSTANTS.ServerFortifyAmount * threads;
},
hackChance: function (hostname: any): any {
updateDynamicRam("hackChance", getRamCost("hackChance"));
hackAnalyzeChance: function (hostname: any): any {
updateDynamicRam("hackAnalyzeChance", getRamCost("hackAnalyzeChance"));
const server = safeGetServer(hostname, "hackChance");
const server = safeGetServer(hostname, "hackAnalyzeChance");
if (!(server instanceof Server)) {
workerScript.log("hackChance", "Cannot be executed on this server.");
workerScript.log("hackAnalyzeChance", "Cannot be executed on this server.");
return false;
}
@ -550,6 +550,15 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
return Promise.resolve(true);
});
},
asleep: function (time: any): any {
if (time === undefined) {
throw makeRuntimeErrorMsg("asleep", "Takes 1 argument.");
}
workerScript.log("asleep", `Sleeping for ${time} milliseconds`);
return netscriptDelay(time, workerScript).then(function () {
return Promise.resolve(true);
});
},
grow: function (hostname: any, { threads: requestedThreads, stock }: any = {}): any {
updateDynamicRam("grow", getRamCost("grow"));
const threads = resolveNetscriptRequestedThreads(workerScript, "grow", requestedThreads);
@ -1000,7 +1009,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
workerScript.log("exit", "Failed. This is a bug. Report to dev.");
}
},
scp: function (scriptname: any, hostname1: any, hostname2: any): boolean {
scp: function (scriptname: any, hostname1: any, hostname2: any): Promise<boolean> {
updateDynamicRam("scp", getRamCost("scp"));
if (arguments.length !== 2 && arguments.length !== 3) {
throw makeRuntimeErrorMsg("scp", "Takes 2 or 3 arguments");
@ -1013,7 +1022,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
res = true;
}
});
return res;
return Promise.resolve(res);
}
// Invalid file type
@ -1064,18 +1073,18 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
if (!found) {
workerScript.log("scp", `File '${scriptname}' does not exist.`);
return false;
return Promise.resolve(false);
}
for (let i = 0; i < destServer.messages.length; ++i) {
if (destServer.messages[i] === scriptname) {
workerScript.log("scp", `File '${scriptname}' copied over to '${destServer.hostname}'.`);
return true; // Already exists
return Promise.resolve(true); // Already exists
}
}
destServer.messages.push(scriptname);
workerScript.log("scp", `File '${scriptname}' copied over to '${destServer.hostname}'.`);
return true;
return Promise.resolve(true);
}
// Scp for text files
@ -1089,7 +1098,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
}
if (txtFile === undefined) {
workerScript.log("scp", `File '${scriptname}' does not exist.`);
return false;
return Promise.resolve(false);
}
for (let i = 0; i < destServer.textFiles.length; ++i) {
@ -1097,13 +1106,13 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
// Overwrite
destServer.textFiles[i].text = txtFile.text;
workerScript.log("scp", `File '${scriptname}' copied over to '${destServer.hostname}'.`);
return true;
return Promise.resolve(true);
}
}
const newFile = new TextFile(txtFile.fn, txtFile.text);
destServer.textFiles.push(newFile);
workerScript.log("scp", `File '${scriptname}' copied over to '${destServer.hostname}'.`);
return true;
return Promise.resolve(true);
}
// Scp for script files
@ -1116,7 +1125,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
}
if (sourceScript == null) {
workerScript.log("scp", `File '${scriptname}' does not exist.`);
return false;
return Promise.resolve(false);
}
// Overwrite script if it already exists
@ -1127,11 +1136,11 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
// If it's the exact same file don't actually perform the
// copy to avoid recompiling uselessly. Players tend to scp
// liberally.
if (oldScript.code === sourceScript.code) return true;
if (oldScript.code === sourceScript.code) return Promise.resolve(true);
oldScript.code = sourceScript.code;
oldScript.ramUsage = sourceScript.ramUsage;
oldScript.markUpdated();
return true;
return Promise.resolve(true);
}
}
@ -1142,7 +1151,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
newScript.server = destServer.hostname;
destServer.scripts.push(newScript);
workerScript.log("scp", `File '${scriptname}' copied over to '${destServer.hostname}'.`);
return true;
return Promise.resolve(true);
},
ls: function (hostname: any, grep: any): any {
updateDynamicRam("ls", getRamCost("ls"));
@ -1339,6 +1348,10 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
},
getServerBaseSecurityLevel: function (hostname: any): any {
updateDynamicRam("getServerBaseSecurityLevel", getRamCost("getServerBaseSecurityLevel"));
workerScript.log(
"getServerBaseSecurityLevel",
`getServerBaseSecurityLevel is deprecated because it's not useful.`,
);
const server = safeGetServer(hostname, "getServerBaseSecurityLevel");
if (!(server instanceof Server)) {
workerScript.log("getServerNumPortsRequired", "Cannot be executed on this server.");
@ -1429,6 +1442,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
},
getServerRam: function (hostname: any): any {
updateDynamicRam("getServerRam", getRamCost("getServerRam"));
workerScript.log("getServerRam", `getServerRam is deprecated in favor of getServerMaxRam / getServerUsedRam`);
const server = safeGetServer(hostname, "getServerRam");
workerScript.log(
"getServerRam",
@ -1637,40 +1651,33 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
);
return false;
},
getPurchasedServers: function (hostnameMode: any = true): any {
getPurchasedServers: function (): any {
updateDynamicRam("getPurchasedServers", getRamCost("getPurchasedServers"));
const res: string[] = [];
Player.purchasedServers.forEach(function (hostname) {
if (hostnameMode) {
res.push(hostname);
} else {
const server = GetServer(hostname);
if (server == null) {
throw makeRuntimeErrorMsg("getPurchasedServers", "Could not find server. This is a bug. Report to dev.");
}
res.push(server.ip);
}
});
return res;
},
write: function (port: any, data: any = "", mode: any = "a"): any {
updateDynamicRam("write", getRamCost("write"));
if (!isNaN(port)) {
writePort: function (port: any, data: any = ""): any {
// Write to port
// Port 1-10
port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg(
"write",
"writePort",
`Trying to write to invalid port: ${port}. Only ports 1-${CONSTANTS.NumNetscriptPorts} are valid.`,
);
}
const iport = NetscriptPorts[port - 1];
if (iport == null || !(iport instanceof Object)) {
throw makeRuntimeErrorMsg("write", `Could not find port: ${port}. This is a bug. Report to dev.`);
throw makeRuntimeErrorMsg("writePort", `Could not find port: ${port}. This is a bug. Report to dev.`);
}
return iport.write(data);
} else if (isString(port)) {
return Promise.resolve(iport.write(data));
},
write: function (port: any, data: any = "", mode: any = "a"): any {
updateDynamicRam("write", getRamCost("write"));
if (isString(port)) {
// Write to script or text file
let fn = port;
if (!isValidFilePath(fn)) {
@ -1740,25 +1747,26 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
throw makeRuntimeErrorMsg("tryWrite", `Invalid argument: ${port}`);
}
},
read: function (port: any): any {
updateDynamicRam("read", getRamCost("read"));
if (!isNaN(port)) {
readPort: function (port: any): any {
// Read from port
// Port 1-10
port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg(
"read",
"readPort",
`Invalid port: ${port}. Only ports 1-${CONSTANTS.NumNetscriptPorts} are valid.`,
);
}
const iport = NetscriptPorts[port - 1];
if (iport == null || !(iport instanceof Object)) {
throw makeRuntimeErrorMsg("read", `Could not find port: ${port}. This is a bug. Report to dev.`);
throw makeRuntimeErrorMsg("readPort", `Could not find port: ${port}. This is a bug. Report to dev.`);
}
const x = iport.read();
return x;
} else if (isString(port)) {
},
read: function (port: any): any {
updateDynamicRam("read", getRamCost("read"));
if (isString(port)) {
// Read from script or text file
const fn = port;
const server = GetServer(workerScript.hostname);
@ -1954,7 +1962,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
return Infinity;
}
return calculateHackingTime(server, Player); // Returns seconds
return calculateHackingTime(server, Player) * 1000;
},
getGrowTime: function (hostname: any): any {
updateDynamicRam("getGrowTime", getRamCost("getGrowTime"));
@ -1967,7 +1975,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
return Infinity;
}
return calculateGrowTime(server, Player); // Returns seconds
return calculateGrowTime(server, Player) * 1000;
},
getWeakenTime: function (hostname: any): any {
updateDynamicRam("getWeakenTime", getRamCost("getWeakenTime"));
@ -1980,7 +1988,7 @@ function NetscriptFunctions(workerScript: WorkerScript): NS {
return Infinity;
}
return calculateWeakenTime(server, Player); // Returns seconds
return calculateWeakenTime(server, Player) * 1000;
},
getScriptIncome: function (scriptname: any, hostname: any, ...args: any[]): any {
updateDynamicRam("getScriptIncome", getRamCost("getScriptIncome"));

@ -75,7 +75,7 @@ function startNetscript2Script(workerScript: WorkerScript): Promise<WorkerScript
throw workerScript;
}
if (propName === "sleep") return f(...args); // OK for multiple simultaneous calls to sleep.
if (propName === "asleep") return f(...args); // OK for multiple simultaneous calls to sleep.
const msg =
"Concurrent calls to Netscript functions not allowed! " +

@ -17,6 +17,7 @@ import * as ExportBonus from "./ExportBonus";
import { dialogBoxCreate } from "./ui/React/DialogBox";
import { Reviver, Generic_toJSON, Generic_fromJSON } from "./utils/JSONReviver";
import { save } from "./db";
import { v1APIBreak } from "./utils/v1APIBreak";
/* SaveObject.js
* Defines the object used to save/load games
@ -103,9 +104,10 @@ class BitburnerSaveObject {
// Makes necessary changes to the loaded/imported data to ensure
// the game stills works with new versions
function evaluateVersionCompatibility(ver: string): void {
function evaluateVersionCompatibility(ver: string | number): void {
// We have to do this because ts won't let us otherwise
const anyPlayer = Player as any;
if (typeof ver === "string") {
// This version refactored the Company/job-related code
if (ver <= "0.41.2") {
// Player's company position is now a string
@ -206,6 +208,8 @@ function evaluateVersionCompatibility(ver: string): void {
}
}
}
v1APIBreak();
}
}
function loadGame(saveString: string): boolean {

48
src/utils/v1APIBreak.ts Normal file

@ -0,0 +1,48 @@
import { Script } from "../Script/Script";
import { GetAllServers } from "../Server/AllServers";
const changes: [RegExp, string][] = [
[/ns.getHackTime/g, "((...a)=>ns.getHackTime(...a)/1000)"],
[/ns.getGrowTime/g, "((...a)=>ns.getGrowTime(...a)/1000)"],
[/ns.getWeakenTime/g, "((...a)=>ns.getWeakenTime(...a)/1000)"],
[/ns.bladeburner.getActionTime/g, "((...a)=>ns.bladeburner.getActionTime(...a)/1000)"],
[/ns.hackAnalyzePercent/g, "((...a)=>ns.hackAnalyze(...a)*100)"],
[/ns.hackChance/g, "ns.hackAnalyzeChance"],
];
function hasChanges(code: string): boolean {
for (const change of changes) {
if (code.match(change[0])) return true;
}
return false;
}
function convert(code: string): string {
const lines = code.split("\n");
const out: string[] = [];
for (let i = 0; i < lines.length; i++) {
const orig = lines[i];
let line = lines[i];
for (const change of changes) {
line = line.replace(change[0], change[1]);
}
if (line != orig) {
out.push(`// =============================== original line ===============================`);
out.push(`// ${orig}`);
out.push(`// =============================================================================`);
}
out.push(line);
}
return out.join("\n");
}
export function v1APIBreak(): void {
for (const server of GetAllServers()) {
const backups: Script[] = [];
for (const script of server.scripts) {
if (!hasChanges(script.code)) continue;
backups.push(new Script("BACKUP_" + script.filename, script.code, script.server));
script.code = convert(script.code);
}
server.scripts = server.scripts.concat(backups);
}
}