mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-18 21:53:50 +01:00
Started server code refactor
This commit is contained in:
parent
af3323a111
commit
e1b8a23f1e
32
src/Message/Message.ts
Normal file
32
src/Message/Message.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON } from "../../utils/JSONReviver";
|
||||
|
||||
export class Message {
|
||||
// Initializes a Message Object from a JSON save state
|
||||
static fromJSON(value: any): Message {
|
||||
return Generic_fromJSON(Message, value.data);
|
||||
}
|
||||
|
||||
// Name of Message file
|
||||
filename: string = "";
|
||||
|
||||
// The text contains in the Message
|
||||
msg: string = "":
|
||||
|
||||
// Flag indicating whether this Message has been received by the player
|
||||
recvd: boolean = false;
|
||||
|
||||
constructor(filename="", msg="") {
|
||||
this.filename = filename;
|
||||
this.msg = msg;
|
||||
this.recvd = false;
|
||||
}
|
||||
|
||||
// Serialize the current object to a JSON save state
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("Message", this);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.Message = Message;
|
@ -1,34 +1,15 @@
|
||||
import { Augmentatation } from "./Augmentation/Augmentation";
|
||||
import { Augmentations } from "./Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { inMission } from "./Missions";
|
||||
import { Player } from "./Player";
|
||||
import { redPillFlag } from "./RedPill";
|
||||
import { GetServerByHostname } from "./Server";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { Message } from "./Message";
|
||||
import { Augmentatation } from "../Augmentation/Augmentation";
|
||||
import { Augmentations } from "../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
|
||||
import { Programs } from "../Programs/Programs";
|
||||
import { inMission } from "../Missions";
|
||||
import { Player } from "../Player";
|
||||
import { redPillFlag } from "../RedPill";
|
||||
import { GetServerByHostname } from "../Server";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { dialogBoxCreate,
|
||||
dialogBoxOpened} from "../utils/DialogBox";
|
||||
import {Reviver, Generic_toJSON,
|
||||
Generic_fromJSON} from "../utils/JSONReviver";
|
||||
|
||||
/* Message.js */
|
||||
function Message(filename="", msg="") {
|
||||
this.filename = filename;
|
||||
this.msg = msg;
|
||||
this.recvd = false;
|
||||
}
|
||||
|
||||
Message.prototype.toJSON = function() {
|
||||
return Generic_toJSON("Message", this);
|
||||
}
|
||||
|
||||
|
||||
Message.fromJSON = function(value) {
|
||||
return Generic_fromJSON(Message, value.data);
|
||||
}
|
||||
|
||||
Reviver.constructors.Message = Message;
|
||||
dialogBoxOpened} from "../../utils/DialogBox";
|
||||
|
||||
//Sends message to player, including a pop up
|
||||
function sendMessage(msg, forced=false) {
|
155
src/Script/RunningScript.ts
Normal file
155
src/Script/RunningScript.ts
Normal file
@ -0,0 +1,155 @@
|
||||
// Class representing a Script instance that is actively running.
|
||||
// A Script can have multiple active instances
|
||||
import { Script } from "./Script";
|
||||
import { IMap } from "../types";
|
||||
import { Generic_fromJSON,
|
||||
Generic_toJSON,
|
||||
Reviver } from "../../utils/JSONReviver";
|
||||
|
||||
export class RunningScript {
|
||||
// Initializes a RunningScript Object from a JSON save state
|
||||
static fromJSON(value: any): RunningScript {
|
||||
return Generic_fromJSON(RunningScript, value.data);
|
||||
}
|
||||
|
||||
// Script arguments
|
||||
args: any[] = [];
|
||||
|
||||
// Holds a map of servers hacked, where server = key and the value for each
|
||||
// server is an array of four numbers. The four numbers represent:
|
||||
// [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
||||
// This data is used for offline progress
|
||||
dataMap: IMap<number[]> = {};
|
||||
|
||||
// Script filename
|
||||
filename: string = "";
|
||||
|
||||
// This script's logs. An array of log entries
|
||||
logs: string[] = [];
|
||||
|
||||
// Flag indicating whether the logs have been updated since
|
||||
// the last time the UI was updated
|
||||
logUpd: boolean = false;
|
||||
|
||||
// Total amount of hacking experience earned from this script when offline
|
||||
offlineExpGained: number = 0;
|
||||
|
||||
// Total amount of money made by this script when offline
|
||||
offlineMoneyMade: number = 0;
|
||||
|
||||
// Number of seconds that the script has been running offline
|
||||
offlineRunningTime: number = 0.01;
|
||||
|
||||
// Total amount of hacking experience earned from this script when online
|
||||
onlineExpGained: number = 0;
|
||||
|
||||
// Total amount of money made by this script when online
|
||||
onlineMoneyMade: number = 0;
|
||||
|
||||
// Number of seconds that this script has been running online
|
||||
onlineRunningTime: number = 0.01;
|
||||
|
||||
// How much RAM this script uses for ONE thread
|
||||
ramUsage: number = 0;
|
||||
|
||||
// IP of the server on which this script is running
|
||||
server: string = "";
|
||||
|
||||
// Number of threads that this script is running with
|
||||
threads: number = 1;
|
||||
|
||||
constructor(script: Script | null = null, args: any[] = []) {
|
||||
if (script == null) { return; }
|
||||
this.filename = script.filename;
|
||||
this.args = args;
|
||||
|
||||
this.server = script.server; //IP Address only
|
||||
this.ramUsage = script.ramUsage;
|
||||
}
|
||||
|
||||
RunningScript.prototype.getCode = function() {
|
||||
const server = AllServers[this.server];
|
||||
if (server == null) { return ""; }
|
||||
for (let i = 0; i < server.scripts.length; ++i) {
|
||||
if (server.scripts[i].filename === this.filename) {
|
||||
return server.scripts[i].code;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
RunningScript.prototype.getRamUsage = function() {
|
||||
if (this.ramUsage != null && this.ramUsage > 0) { return this.ramUsage; } // Use cached value
|
||||
|
||||
const server = AllServers[this.server];
|
||||
if (server == null) { return 0; }
|
||||
for (let i = 0; i < server.scripts.length; ++i) {
|
||||
if (server.scripts[i].filename === this.filename) {
|
||||
// Cache the ram usage for the next call
|
||||
this.ramUsage = server.scripts[i].ramUsage;
|
||||
return this.ramUsage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
RunningScript.prototype.log = function(txt) {
|
||||
if (this.logs.length > Settings.MaxLogCapacity) {
|
||||
//Delete first element and add new log entry to the end.
|
||||
//TODO Eventually it might be better to replace this with circular array
|
||||
//to improve performance
|
||||
this.logs.shift();
|
||||
}
|
||||
let logEntry = txt;
|
||||
if (FconfSettings.ENABLE_TIMESTAMPS) {
|
||||
logEntry = "[" + getTimestamp() + "] " + logEntry;
|
||||
}
|
||||
this.logs.push(logEntry);
|
||||
this.logUpd = true;
|
||||
}
|
||||
|
||||
RunningScript.prototype.displayLog = function() {
|
||||
for (var i = 0; i < this.logs.length; ++i) {
|
||||
post(this.logs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
RunningScript.prototype.clearLog = function() {
|
||||
this.logs.length = 0;
|
||||
}
|
||||
|
||||
//Update the moneyStolen and numTimesHack maps when hacking
|
||||
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
|
||||
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||
}
|
||||
this.dataMap[serverIp][0] += moneyGained;
|
||||
this.dataMap[serverIp][1] += n;
|
||||
}
|
||||
|
||||
//Update the grow map when calling grow()
|
||||
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
|
||||
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||
}
|
||||
this.dataMap[serverIp][2] += n;
|
||||
}
|
||||
|
||||
//Update the weaken map when calling weaken() {
|
||||
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
|
||||
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||
}
|
||||
this.dataMap[serverIp][3] += n;
|
||||
}
|
||||
|
||||
// Serialize the current object to a JSON save state
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("RunningScript", this);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.RunningScript = RunningScript;
|
104
src/Script/Script.ts
Normal file
104
src/Script/Script.ts
Normal file
@ -0,0 +1,104 @@
|
||||
// Class representing a script file
|
||||
// This does NOT represent a script that is actively running and
|
||||
// being evaluated. See RunningScript for that
|
||||
import { Page,
|
||||
routing } from "../ui/navigationTracking";
|
||||
import { setTimeoutRef } from "../utils/SetTimeoutRef";
|
||||
import { Generic_fromJSON,
|
||||
Generic_toJSON,
|
||||
Reviver } from "../../utils/JSONReviver";
|
||||
import { roundToTwo } from "../../utils/helpers/roundToTwo";
|
||||
|
||||
export class Script {
|
||||
// Initializes a Script Object from a JSON save state
|
||||
static fromJSON(value: any): Script {
|
||||
return Generic_fromJSON(Script, value.data);
|
||||
}
|
||||
|
||||
// Code for this script
|
||||
code: string = "";
|
||||
|
||||
// Filename for the script file
|
||||
filename: string = "";
|
||||
|
||||
// The dynamic module generated for this script when it is run.
|
||||
// This is only applicable for NetscriptJS
|
||||
module: any = "";
|
||||
|
||||
// Amount of RAM this Script requres to run
|
||||
ramUsage: number = 0;
|
||||
|
||||
// IP of server that this script is on.
|
||||
server: string = "";
|
||||
|
||||
|
||||
constructor(fn: string = "", code: string = "", server: string = "") {
|
||||
this.filename = fn;
|
||||
this.code = code;
|
||||
this.ramUsage = 0;
|
||||
this.server = server; // IP of server this script is on
|
||||
this.module = "";
|
||||
if (this.code !== "") {this.updateRamUsage();}
|
||||
};
|
||||
|
||||
download(): void {
|
||||
const filename = this.filename + ".js";
|
||||
const file = new Blob([this.code], {type: 'text/plain'});
|
||||
if (window.navigator.msSaveOrOpenBlob) {// IE10+
|
||||
window.navigator.msSaveOrOpenBlob(file, filename);
|
||||
} else { // Others
|
||||
var a = document.createElement("a"),
|
||||
url = URL.createObjectURL(file);
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeoutRef(function() {
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Save a script FROM THE SCRIPT EDITOR
|
||||
saveScript(): void {
|
||||
if (routing.isOn(Page.ScriptEditor)) {
|
||||
//Update code and filename
|
||||
const code = getCurrentEditor().getCode();
|
||||
this.code = code.replace(/^\s+|\s+$/g, '');
|
||||
|
||||
const filenameElem: HTMLInputElement | null = document.getElementById("script-editor-filename") as HTMLInputElement;
|
||||
if (filenameElem == null) {
|
||||
console.error(`Failed to get Script filename DOM element`);
|
||||
return;
|
||||
}
|
||||
this.filename = filenameElem!.value;
|
||||
|
||||
// Server
|
||||
this.server = Player.currentServer;
|
||||
|
||||
//Calculate/update ram usage, execution time, etc.
|
||||
this.updateRamUsage();
|
||||
|
||||
this.module = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the script's RAM usage based on its code
|
||||
async updateRamUsage(): void {
|
||||
// TODO Commented this out because I think its unnecessary
|
||||
// DOuble check/Test
|
||||
// var codeCopy = this.code.repeat(1);
|
||||
var res = await calculateRamUsage(this.code);
|
||||
if (res !== -1) {
|
||||
this.ramUsage = roundToTwo(res);
|
||||
}
|
||||
}
|
||||
|
||||
// Serialize the current object to a JSON save state
|
||||
toJSON(): any {
|
||||
return Generic_toJSON("Script", this);
|
||||
}
|
||||
}
|
||||
|
||||
Reviver.constructors.Script = Script;
|
187
src/Script.js → src/Script/ScriptHelpers.js
Executable file → Normal file
187
src/Script.js → src/Script/ScriptHelpers.js
Executable file → Normal file
@ -308,44 +308,6 @@ function checkValidFilename(filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function Script(fn = "", code = "", server = "") {
|
||||
this.filename = fn;
|
||||
this.code = code;
|
||||
this.ramUsage = 0;
|
||||
this.server = server; //IP of server this script is on
|
||||
this.module = "";
|
||||
if (this.code !== "") {this.updateRamUsage();}
|
||||
};
|
||||
|
||||
//Get the script data from the Script Editor and save it to the object
|
||||
Script.prototype.saveScript = function() {
|
||||
if (routing.isOn(Page.ScriptEditor)) {
|
||||
//Update code and filename
|
||||
const code = getCurrentEditor().getCode();
|
||||
this.code = code.replace(/^\s+|\s+$/g, '');
|
||||
|
||||
var filename = document.getElementById("script-editor-filename").value;
|
||||
this.filename = filename;
|
||||
|
||||
//Server
|
||||
this.server = Player.currentServer;
|
||||
|
||||
//Calculate/update ram usage, execution time, etc.
|
||||
this.updateRamUsage();
|
||||
|
||||
this.module = "";
|
||||
}
|
||||
}
|
||||
|
||||
//Updates how much RAM the script uses when it is running.
|
||||
Script.prototype.updateRamUsage = async function() {
|
||||
var codeCopy = this.code.repeat(1);
|
||||
var res = await calculateRamUsage(codeCopy);
|
||||
if (res !== -1) {
|
||||
this.ramUsage = roundToTwo(res);
|
||||
}
|
||||
}
|
||||
|
||||
// These special strings are used to reference the presence of a given logical
|
||||
// construct within a user script.
|
||||
const specialReferenceIF = "__SPECIAL_referenceIf";
|
||||
@ -747,36 +709,6 @@ async function calculateRamUsage(codeCopy) {
|
||||
return ramUsage;
|
||||
}
|
||||
|
||||
Script.prototype.download = function() {
|
||||
var filename = this.filename + ".js";
|
||||
var file = new Blob([this.code], {type: 'text/plain'});
|
||||
if (window.navigator.msSaveOrOpenBlob) {// IE10+
|
||||
window.navigator.msSaveOrOpenBlob(file, filename);
|
||||
} else { // Others
|
||||
var a = document.createElement("a"),
|
||||
url = URL.createObjectURL(file);
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
setTimeoutRef(function() {
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Script.prototype.toJSON = function() {
|
||||
return Generic_toJSON("Script", this);
|
||||
}
|
||||
|
||||
|
||||
Script.fromJSON = function(value) {
|
||||
return Generic_fromJSON(Script, value.data);
|
||||
}
|
||||
|
||||
Reviver.constructors.Script = Script;
|
||||
|
||||
//Called when the game is loaded. Loads all running scripts (from all servers)
|
||||
//into worker scripts so that they will start running
|
||||
function loadAllRunningScripts() {
|
||||
@ -916,122 +848,5 @@ function findRunningScript(filename, args, server) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function RunningScript(script, args) {
|
||||
if (script == null || script == undefined) { return; }
|
||||
this.filename = script.filename;
|
||||
this.args = args;
|
||||
this.server = script.server; //IP Address only
|
||||
this.ramUsage = script.ramUsage;
|
||||
|
||||
this.logs = []; //Script logging. Array of strings, with each element being a log entry
|
||||
this.logUpd = false;
|
||||
|
||||
//Stats to display on the Scripts menu, and used to determine offline progress
|
||||
this.offlineRunningTime = 0.01; //Seconds
|
||||
this.offlineMoneyMade = 0;
|
||||
this.offlineExpGained = 0;
|
||||
this.onlineRunningTime = 0.01; //Seconds
|
||||
this.onlineMoneyMade = 0;
|
||||
this.onlineExpGained = 0;
|
||||
|
||||
this.threads = 1;
|
||||
|
||||
// Holds a map of all servers, where server = key and the value for each
|
||||
// server is an array of four numbers. The four numbers represent:
|
||||
// [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
||||
// This data is used for offline progress
|
||||
this.dataMap = {};
|
||||
}
|
||||
|
||||
RunningScript.prototype.getCode = function() {
|
||||
const server = AllServers[this.server];
|
||||
if (server == null) { return ""; }
|
||||
for (let i = 0; i < server.scripts.length; ++i) {
|
||||
if (server.scripts[i].filename === this.filename) {
|
||||
return server.scripts[i].code;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
RunningScript.prototype.getRamUsage = function() {
|
||||
if (this.ramUsage != null && this.ramUsage > 0) { return this.ramUsage; } // Use cached value
|
||||
|
||||
const server = AllServers[this.server];
|
||||
if (server == null) { return 0; }
|
||||
for (let i = 0; i < server.scripts.length; ++i) {
|
||||
if (server.scripts[i].filename === this.filename) {
|
||||
// Cache the ram usage for the next call
|
||||
this.ramUsage = server.scripts[i].ramUsage;
|
||||
return this.ramUsage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
RunningScript.prototype.log = function(txt) {
|
||||
if (this.logs.length > Settings.MaxLogCapacity) {
|
||||
//Delete first element and add new log entry to the end.
|
||||
//TODO Eventually it might be better to replace this with circular array
|
||||
//to improve performance
|
||||
this.logs.shift();
|
||||
}
|
||||
let logEntry = txt;
|
||||
if (FconfSettings.ENABLE_TIMESTAMPS) {
|
||||
logEntry = "[" + getTimestamp() + "] " + logEntry;
|
||||
}
|
||||
this.logs.push(logEntry);
|
||||
this.logUpd = true;
|
||||
}
|
||||
|
||||
RunningScript.prototype.displayLog = function() {
|
||||
for (var i = 0; i < this.logs.length; ++i) {
|
||||
post(this.logs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
RunningScript.prototype.clearLog = function() {
|
||||
this.logs.length = 0;
|
||||
}
|
||||
|
||||
//Update the moneyStolen and numTimesHack maps when hacking
|
||||
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
|
||||
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||
}
|
||||
this.dataMap[serverIp][0] += moneyGained;
|
||||
this.dataMap[serverIp][1] += n;
|
||||
}
|
||||
|
||||
//Update the grow map when calling grow()
|
||||
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
|
||||
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||
}
|
||||
this.dataMap[serverIp][2] += n;
|
||||
}
|
||||
|
||||
//Update the weaken map when calling weaken() {
|
||||
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
|
||||
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||
}
|
||||
this.dataMap[serverIp][3] += n;
|
||||
}
|
||||
|
||||
RunningScript.prototype.toJSON = function() {
|
||||
return Generic_toJSON("RunningScript", this);
|
||||
}
|
||||
|
||||
|
||||
RunningScript.fromJSON = function(value) {
|
||||
return Generic_fromJSON(RunningScript, value.data);
|
||||
}
|
||||
|
||||
Reviver.constructors.RunningScript = RunningScript;
|
||||
|
||||
export {loadAllRunningScripts, findRunningScript,
|
||||
RunningScript, Script, scriptEditorInit, isScriptFilename};
|
||||
scriptEditorInit, isScriptFilename};
|
468
src/Server.js
468
src/Server.js
@ -1,468 +0,0 @@
|
||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||
import { CodingContract,
|
||||
ContractTypes } from "./CodingContracts";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Script,
|
||||
isScriptFilename } from "./Script";
|
||||
import { Player } from "./Player";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { SpecialServerIps } from "./SpecialServerIps";
|
||||
import { TextFile } from "./TextFile";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { createRandomIp,
|
||||
ipExists } from "../utils/IPAddress";
|
||||
import { serverMetadata } from "./data/servers";
|
||||
import { Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON} from "../utils/JSONReviver";
|
||||
import {isValidIPAddress} from "../utils/helpers/isValidIPAddress";
|
||||
|
||||
function Server(params={ip:createRandomIp(), hostname:""}) {
|
||||
/* Properties */
|
||||
//Connection information
|
||||
this.ip = params.ip ? params.ip : createRandomIp();
|
||||
|
||||
var hostname = params.hostname;
|
||||
var i = 0;
|
||||
var suffix = "";
|
||||
while (GetServerByHostname(hostname+suffix) != null) {
|
||||
//Server already exists
|
||||
suffix = "-" + i;
|
||||
++i;
|
||||
}
|
||||
this.hostname = hostname + suffix;
|
||||
this.organizationName = params.organizationName != null ? params.organizationName : "";
|
||||
this.isConnectedTo = params.isConnectedTo != null ? params.isConnectedTo : false;
|
||||
|
||||
//Access information
|
||||
this.hasAdminRights = params.adminRights != null ? params.adminRights : false;
|
||||
this.purchasedByPlayer = params.purchasedByPlayer != null ? params.purchasedByPlayer : false;
|
||||
this.manuallyHacked = false; //Flag that tracks whether or not the server has been hacked at least once
|
||||
|
||||
//RAM, CPU speed and Scripts
|
||||
this.maxRam = params.maxRam != null ? params.maxRam : 0; //GB
|
||||
this.ramUsed = 0;
|
||||
this.cpuCores = 1; //Max of 8, affects hacking times and Hacking Mission starting Cores
|
||||
|
||||
this.scripts = [];
|
||||
this.runningScripts = []; //Stores RunningScript objects
|
||||
this.programs = [];
|
||||
this.messages = [];
|
||||
this.textFiles = [];
|
||||
this.contracts = [];
|
||||
this.dir = 0; //new Directory(this, null, ""); TODO
|
||||
|
||||
/* Hacking information (only valid for "foreign" aka non-purchased servers) */
|
||||
this.requiredHackingSkill = params.requiredHackingSkill != null ? params.requiredHackingSkill : 1;
|
||||
this.moneyAvailable = params.moneyAvailable != null ? params.moneyAvailable * BitNodeMultipliers.ServerStartingMoney : 0;
|
||||
this.moneyMax = 25 * this.moneyAvailable * BitNodeMultipliers.ServerMaxMoney;
|
||||
|
||||
//Hack Difficulty is synonymous with server security. Base Difficulty = Starting difficulty
|
||||
this.hackDifficulty = params.hackDifficulty != null ? params.hackDifficulty * BitNodeMultipliers.ServerStartingSecurity : 1;
|
||||
this.baseDifficulty = this.hackDifficulty;
|
||||
this.minDifficulty = Math.max(1, Math.round(this.hackDifficulty / 3));
|
||||
this.serverGrowth = params.serverGrowth != null ? params.serverGrowth : 1; //Integer from 0 to 100. Affects money increase from grow()
|
||||
|
||||
//The IP's of all servers reachable from this one (what shows up if you run scan/netstat)
|
||||
// NOTE: Only contains IP and not the Server objects themselves
|
||||
this.serversOnNetwork = [];
|
||||
|
||||
//Port information, required for porthacking servers to get admin rights
|
||||
this.numOpenPortsRequired = params.numOpenPortsRequired != null ? params.numOpenPortsRequired : 5;
|
||||
this.sshPortOpen = false; //Port 22
|
||||
this.ftpPortOpen = false; //Port 21
|
||||
this.smtpPortOpen = false; //Port 25
|
||||
this.httpPortOpen = false; //Port 80
|
||||
this.sqlPortOpen = false; //Port 1433
|
||||
this.openPortCount = 0;
|
||||
};
|
||||
|
||||
Server.prototype.setMaxRam = function(ram) {
|
||||
this.maxRam = ram;
|
||||
}
|
||||
|
||||
//The serverOnNetwork array holds the IP of all the servers. This function
|
||||
//returns the actual Server objects
|
||||
Server.prototype.getServerOnNetwork = function(i) {
|
||||
if (i > this.serversOnNetwork.length) {
|
||||
console.log("Tried to get server on network that was out of range");
|
||||
return;
|
||||
}
|
||||
return AllServers[this.serversOnNetwork[i]];
|
||||
}
|
||||
|
||||
//Given the name of the script, returns the corresponding
|
||||
//script object on the server (if it exists)
|
||||
Server.prototype.getScript = function(scriptName) {
|
||||
for (var i = 0; i < this.scripts.length; i++) {
|
||||
if (this.scripts[i].filename == scriptName) {
|
||||
return this.scripts[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Server.prototype.capDifficulty = function() {
|
||||
if (this.hackDifficulty < this.minDifficulty) {this.hackDifficulty = this.minDifficulty;}
|
||||
if (this.hackDifficulty < 1) {this.hackDifficulty = 1;}
|
||||
//Place some arbitrarily limit that realistically should never happen unless someone is
|
||||
//screwing around with the game
|
||||
if (this.hackDifficulty > 1000000) {this.hackDifficulty = 1000000;}
|
||||
}
|
||||
|
||||
//Strengthens a server's security level (difficulty) by the specified amount
|
||||
Server.prototype.fortify = function(amt) {
|
||||
this.hackDifficulty += amt;
|
||||
this.capDifficulty();
|
||||
}
|
||||
|
||||
Server.prototype.weaken = function(amt) {
|
||||
this.hackDifficulty -= (amt * BitNodeMultipliers.ServerWeakenRate);
|
||||
this.capDifficulty();
|
||||
}
|
||||
|
||||
// Write to a script file
|
||||
// Overwrites existing files. Creates new files if the script does not eixst
|
||||
Server.prototype.writeToScriptFile = function(fn, code) {
|
||||
var ret = {success: false, overwritten: false};
|
||||
if (!isScriptFilename(fn)) { return ret; }
|
||||
|
||||
//Check if the script already exists, and overwrite it if it does
|
||||
for (let i = 0; i < this.scripts.length; ++i) {
|
||||
if (fn === this.scripts[i].filename) {
|
||||
let script = this.scripts[i];
|
||||
script.code = code;
|
||||
script.updateRamUsage();
|
||||
script.module = "";
|
||||
ret.overwritten = true;
|
||||
ret.success = true;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
//Otherwise, create a new script
|
||||
var newScript = new Script();
|
||||
newScript.filename = fn;
|
||||
newScript.code = code;
|
||||
newScript.updateRamUsage();
|
||||
newScript.server = this.ip;
|
||||
this.scripts.push(newScript);
|
||||
ret.success = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Write to a text file
|
||||
// Overwrites existing files. Creates new files if the text file does not exist
|
||||
Server.prototype.writeToTextFile = function(fn, txt) {
|
||||
var ret = {success: false, overwritten: false};
|
||||
if (!fn.endsWith("txt")) { return ret; }
|
||||
|
||||
//Check if the text file already exists, and overwrite if it does
|
||||
for (let i = 0; i < this.textFiles.length; ++i) {
|
||||
if (this.textFiles[i].fn === fn) {
|
||||
ret.overwritten = true;
|
||||
this.textFiles[i].text = txt;
|
||||
ret.success = true;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
//Otherwise create a new text file
|
||||
var newFile = new TextFile(fn, txt);
|
||||
this.textFiles.push(newFile);
|
||||
ret.success = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Server.prototype.addContract = function(contract) {
|
||||
this.contracts.push(contract);
|
||||
}
|
||||
|
||||
Server.prototype.removeContract = function(contract) {
|
||||
if (contract instanceof CodingContract) {
|
||||
this.contracts = this.contracts.filter((c) => {
|
||||
return c.fn !== contract.fn;
|
||||
});
|
||||
} else {
|
||||
this.contracts = this.contracts.filter((c) => {
|
||||
return c.fn !== contract;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Server.prototype.getContract = function(contractName) {
|
||||
for (const contract of this.contracts) {
|
||||
if (contract.fn === contractName) {
|
||||
return contract;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Functions for loading and saving a Server
|
||||
Server.prototype.toJSON = function() {
|
||||
return Generic_toJSON("Server", this);
|
||||
}
|
||||
|
||||
Server.fromJSON = function(value) {
|
||||
return Generic_fromJSON(Server, value.data);
|
||||
}
|
||||
|
||||
Reviver.constructors.Server = Server;
|
||||
|
||||
export function initForeignServers() {
|
||||
/* Create a randomized network for all the foreign servers */
|
||||
//Groupings for creating a randomized network
|
||||
const networkLayers = [];
|
||||
for (let i = 0; i < 15; i++) {
|
||||
networkLayers.push([]);
|
||||
}
|
||||
|
||||
// Essentially any property that is of type 'number | IMinMaxRange'
|
||||
const propertiesToPatternMatch = [
|
||||
"hackDifficulty",
|
||||
"moneyAvailable",
|
||||
"requiredHackingSkill",
|
||||
"serverGrowth"
|
||||
];
|
||||
|
||||
const toNumber = (value) => {
|
||||
switch (typeof value) {
|
||||
case 'number':
|
||||
return value;
|
||||
case 'object':
|
||||
return getRandomInt(value.min, value.max);
|
||||
default:
|
||||
throw Error(`Do not know how to convert the type '${typeof value}' to a number`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const metadata of serverMetadata) {
|
||||
const serverParams = {
|
||||
hostname: metadata.hostname,
|
||||
ip: createRandomIp(),
|
||||
numOpenPortsRequired: metadata.numOpenPortsRequired,
|
||||
organizationName: metadata.organizationName
|
||||
};
|
||||
|
||||
if (metadata.maxRamExponent !== undefined) {
|
||||
serverParams.maxRam = Math.pow(2, toNumber(metadata.maxRamExponent));
|
||||
}
|
||||
|
||||
for (const prop of propertiesToPatternMatch) {
|
||||
if (metadata[prop] !== undefined) {
|
||||
serverParams[prop] = toNumber(metadata[prop]);
|
||||
}
|
||||
}
|
||||
|
||||
const server = new Server(serverParams);
|
||||
for (const filename of (metadata.literature || [])) {
|
||||
server.messages.push(filename);
|
||||
}
|
||||
|
||||
if (metadata.specialName !== undefined) {
|
||||
SpecialServerIps.addIp(metadata.specialName, server.ip);
|
||||
}
|
||||
|
||||
AddToAllServers(server);
|
||||
if (metadata.networkLayer !== undefined) {
|
||||
networkLayers[toNumber(metadata.networkLayer) - 1].push(server);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a randomized network for all the foreign servers */
|
||||
const linkComputers = (server1, server2) => {
|
||||
server1.serversOnNetwork.push(server2.ip);
|
||||
server2.serversOnNetwork.push(server1.ip);
|
||||
};
|
||||
|
||||
const getRandomArrayItem = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
||||
|
||||
const linkNetworkLayers = (network1, selectServer) => {
|
||||
for (const server of network1) {
|
||||
linkComputers(server, selectServer());
|
||||
}
|
||||
};
|
||||
|
||||
// Connect the first tier of servers to the player's home computer
|
||||
linkNetworkLayers(networkLayers[0], () => Player.getHomeComputer());
|
||||
for (let i = 1; i < networkLayers.length; i++) {
|
||||
linkNetworkLayers(networkLayers[i], () => getRandomArrayItem(networkLayers[i - 1]));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number of cycles needed to grow the specified server by the
|
||||
// specified amount. 'growth' parameter is in decimal form, not percentage
|
||||
export function numCycleForGrowth(server, growth) {
|
||||
let ajdGrowthRate = 1 + (CONSTANTS.ServerBaseGrowthRate - 1) / server.hackDifficulty;
|
||||
if(ajdGrowthRate > CONSTANTS.ServerMaxGrowthRate) {
|
||||
ajdGrowthRate = CONSTANTS.ServerMaxGrowthRate;
|
||||
}
|
||||
|
||||
const serverGrowthPercentage = server.serverGrowth / 100;
|
||||
|
||||
const cycles = Math.log(growth)/(Math.log(ajdGrowthRate)*Player.hacking_grow_mult*serverGrowthPercentage);
|
||||
return cycles;
|
||||
}
|
||||
|
||||
//Applied server growth for a single server. Returns the percentage growth
|
||||
export function processSingleServerGrowth(server, numCycles) {
|
||||
//Server growth processed once every 450 game cycles
|
||||
const numServerGrowthCycles = Math.max(Math.floor(numCycles / 450), 0);
|
||||
|
||||
//Get adjusted growth rate, which accounts for server security
|
||||
const growthRate = CONSTANTS.ServerBaseGrowthRate;
|
||||
var adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty;
|
||||
if (adjGrowthRate > CONSTANTS.ServerMaxGrowthRate) {adjGrowthRate = CONSTANTS.ServerMaxGrowthRate;}
|
||||
|
||||
//Calculate adjusted server growth rate based on parameters
|
||||
const serverGrowthPercentage = server.serverGrowth / 100;
|
||||
const numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
|
||||
|
||||
//Apply serverGrowth for the calculated number of growth cycles
|
||||
var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult);
|
||||
if (serverGrowth < 1) {
|
||||
console.log("WARN: serverGrowth calculated to be less than 1");
|
||||
serverGrowth = 1;
|
||||
}
|
||||
|
||||
const oldMoneyAvailable = server.moneyAvailable;
|
||||
server.moneyAvailable *= serverGrowth;
|
||||
|
||||
// in case of data corruption
|
||||
if (server.moneyMax && isNaN(server.moneyAvailable)) {
|
||||
server.moneyAvailable = server.moneyMax;
|
||||
}
|
||||
|
||||
// cap at max
|
||||
if (server.moneyMax && server.moneyAvailable > server.moneyMax) {
|
||||
server.moneyAvailable = server.moneyMax;
|
||||
}
|
||||
|
||||
// if there was any growth at all, increase security
|
||||
if (oldMoneyAvailable !== server.moneyAvailable) {
|
||||
//Growing increases server security twice as much as hacking
|
||||
let usedCycles = numCycleForGrowth(server, server.moneyAvailable / oldMoneyAvailable);
|
||||
usedCycles = Math.max(0, usedCycles);
|
||||
server.fortify(2 * CONSTANTS.ServerFortifyAmount * Math.ceil(usedCycles));
|
||||
}
|
||||
return server.moneyAvailable / oldMoneyAvailable;
|
||||
}
|
||||
|
||||
export function prestigeHomeComputer(homeComp) {
|
||||
const hasBitflume = homeComp.programs.includes(Programs.BitFlume.name);
|
||||
|
||||
homeComp.programs.length = 0; //Remove programs
|
||||
homeComp.runningScripts = [];
|
||||
homeComp.serversOnNetwork = [];
|
||||
homeComp.isConnectedTo = true;
|
||||
homeComp.ramUsed = 0;
|
||||
homeComp.programs.push(Programs.NukeProgram.name);
|
||||
if (hasBitflume) { homeComp.programs.push(Programs.BitFlume.name); }
|
||||
|
||||
//Update RAM usage on all scripts
|
||||
homeComp.scripts.forEach(function(script) {
|
||||
script.updateRamUsage();
|
||||
});
|
||||
|
||||
homeComp.messages.length = 0; //Remove .lit and .msg files
|
||||
homeComp.messages.push("hackers-starting-handbook.lit");
|
||||
}
|
||||
|
||||
//List of all servers that exist in the game, indexed by their ip
|
||||
let AllServers = {};
|
||||
|
||||
export function prestigeAllServers() {
|
||||
for (var member in AllServers) {
|
||||
delete AllServers[member];
|
||||
}
|
||||
AllServers = {};
|
||||
}
|
||||
|
||||
export function loadAllServers(saveString) {
|
||||
AllServers = JSON.parse(saveString, Reviver);
|
||||
}
|
||||
|
||||
function SizeOfAllServers() {
|
||||
var size = 0, key;
|
||||
for (key in AllServers) {
|
||||
if (AllServers.hasOwnProperty(key)) size++;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
//Add a server onto the map of all servers in the game
|
||||
export function AddToAllServers(server) {
|
||||
var serverIp = server.ip;
|
||||
if (ipExists(serverIp)) {
|
||||
console.log("IP of server that's being added: " + serverIp);
|
||||
console.log("Hostname of the server thats being added: " + server.hostname);
|
||||
console.log("The server that already has this IP is: " + AllServers[serverIp].hostname);
|
||||
throw new Error("Error: Trying to add a server with an existing IP");
|
||||
return;
|
||||
}
|
||||
AllServers[serverIp] = server;
|
||||
}
|
||||
|
||||
//Returns server object with corresponding hostname
|
||||
// Relatively slow, would rather not use this a lot
|
||||
export function GetServerByHostname(hostname) {
|
||||
for (var ip in AllServers) {
|
||||
if (AllServers.hasOwnProperty(ip)) {
|
||||
if (AllServers[ip].hostname == hostname) {
|
||||
return AllServers[ip];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Get server by IP or hostname. Returns null if invalid
|
||||
export function getServer(s) {
|
||||
if (!isValidIPAddress(s)) {
|
||||
return GetServerByHostname(s);
|
||||
}
|
||||
if(AllServers[s] !== undefined) {
|
||||
return AllServers[s];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Debugging tool
|
||||
function PrintAllServers() {
|
||||
for (var ip in AllServers) {
|
||||
if (AllServers.hasOwnProperty(ip)) {
|
||||
console.log("Ip: " + ip + ", hostname: " + AllServers[ip].hostname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Directory object (folders)
|
||||
function Directory(server, parent, name) {
|
||||
this.s = server; //Ref to server
|
||||
this.p = parent; //Ref to parent directory
|
||||
this.c = []; //Subdirs
|
||||
this.n = name;
|
||||
this.d = parent.d + 1; //We'll only have a maximum depth of 3 or something
|
||||
this.scrs = []; //Holds references to the scripts in server.scripts
|
||||
this.pgms = [];
|
||||
this.msgs = [];
|
||||
}
|
||||
|
||||
Directory.prototype.createSubdir = function(name) {
|
||||
var subdir = new Directory(this.s, this, name);
|
||||
|
||||
}
|
||||
|
||||
Directory.prototype.getPath = function(name) {
|
||||
var res = [];
|
||||
var i = this;
|
||||
while (i !== null) {
|
||||
res.unshift(i.n, "/");
|
||||
i = i.parent;
|
||||
}
|
||||
res.unshift("/");
|
||||
return res.join("");
|
||||
}
|
||||
|
||||
export {Server, AllServers};
|
111
src/Server/AllServers.ts
Normal file
111
src/Server/AllServers.ts
Normal file
@ -0,0 +1,111 @@
|
||||
import { ipExists } from "../../utils/IPAddress";
|
||||
|
||||
// Map of all Servers that exist in the game
|
||||
// Key (string) = IP
|
||||
// Value = Server object
|
||||
let AllServers = {};
|
||||
|
||||
// Saftely add a Server to the AllServers map
|
||||
export function AddToAllServers(server) {
|
||||
var serverIp = server.ip;
|
||||
if (ipExists(serverIp)) {
|
||||
console.log("IP of server that's being added: " + serverIp);
|
||||
console.log("Hostname of the server thats being added: " + server.hostname);
|
||||
console.log("The server that already has this IP is: " + AllServers[serverIp].hostname);
|
||||
throw new Error("Error: Trying to add a server with an existing IP");
|
||||
return;
|
||||
}
|
||||
AllServers[serverIp] = server;
|
||||
}
|
||||
|
||||
export function initForeignServers() {
|
||||
/* Create a randomized network for all the foreign servers */
|
||||
//Groupings for creating a randomized network
|
||||
const networkLayers = [];
|
||||
for (let i = 0; i < 15; i++) {
|
||||
networkLayers.push([]);
|
||||
}
|
||||
|
||||
// Essentially any property that is of type 'number | IMinMaxRange'
|
||||
const propertiesToPatternMatch = [
|
||||
"hackDifficulty",
|
||||
"moneyAvailable",
|
||||
"requiredHackingSkill",
|
||||
"serverGrowth"
|
||||
];
|
||||
|
||||
const toNumber = (value) => {
|
||||
switch (typeof value) {
|
||||
case 'number':
|
||||
return value;
|
||||
case 'object':
|
||||
return getRandomInt(value.min, value.max);
|
||||
default:
|
||||
throw Error(`Do not know how to convert the type '${typeof value}' to a number`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const metadata of serverMetadata) {
|
||||
const serverParams = {
|
||||
hostname: metadata.hostname,
|
||||
ip: createRandomIp(),
|
||||
numOpenPortsRequired: metadata.numOpenPortsRequired,
|
||||
organizationName: metadata.organizationName
|
||||
};
|
||||
|
||||
if (metadata.maxRamExponent !== undefined) {
|
||||
serverParams.maxRam = Math.pow(2, toNumber(metadata.maxRamExponent));
|
||||
}
|
||||
|
||||
for (const prop of propertiesToPatternMatch) {
|
||||
if (metadata[prop] !== undefined) {
|
||||
serverParams[prop] = toNumber(metadata[prop]);
|
||||
}
|
||||
}
|
||||
|
||||
const server = new Server(serverParams);
|
||||
for (const filename of (metadata.literature || [])) {
|
||||
server.messages.push(filename);
|
||||
}
|
||||
|
||||
if (metadata.specialName !== undefined) {
|
||||
SpecialServerIps.addIp(metadata.specialName, server.ip);
|
||||
}
|
||||
|
||||
AddToAllServers(server);
|
||||
if (metadata.networkLayer !== undefined) {
|
||||
networkLayers[toNumber(metadata.networkLayer) - 1].push(server);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a randomized network for all the foreign servers */
|
||||
const linkComputers = (server1, server2) => {
|
||||
server1.serversOnNetwork.push(server2.ip);
|
||||
server2.serversOnNetwork.push(server1.ip);
|
||||
};
|
||||
|
||||
const getRandomArrayItem = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
||||
|
||||
const linkNetworkLayers = (network1, selectServer) => {
|
||||
for (const server of network1) {
|
||||
linkComputers(server, selectServer());
|
||||
}
|
||||
};
|
||||
|
||||
// Connect the first tier of servers to the player's home computer
|
||||
linkNetworkLayers(networkLayers[0], () => Player.getHomeComputer());
|
||||
for (let i = 1; i < networkLayers.length; i++) {
|
||||
linkNetworkLayers(networkLayers[i], () => getRandomArrayItem(networkLayers[i - 1]));
|
||||
}
|
||||
}
|
||||
|
||||
export function prestigeAllServers() {
|
||||
for (var member in AllServers) {
|
||||
delete AllServers[member];
|
||||
}
|
||||
AllServers = {};
|
||||
}
|
||||
|
||||
export function loadAllServers(saveString) {
|
||||
AllServers = JSON.parse(saveString, Reviver);
|
||||
}
|
303
src/Server/Server.ts
Normal file
303
src/Server/Server.ts
Normal file
@ -0,0 +1,303 @@
|
||||
// Class representing a single generic Server
|
||||
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
|
||||
import { CodingContract } from "../CodingContracts";
|
||||
import { Message } from "../Message/Message";
|
||||
import { RunningScript } from "../Script/RunningScript";
|
||||
import { Script } from "../Script/Script";
|
||||
import { TextFile } from "../TextFile";
|
||||
|
||||
import { createRandomIp } from "../../utils/IPAddress";
|
||||
import { Generic_fromJSON,
|
||||
Generic_toJSON,
|
||||
Reviver } from "../../utils/JSONReviver";
|
||||
|
||||
interface IConstructorParams {
|
||||
adminRights?: boolean;
|
||||
hackDifficulty?: number;
|
||||
hostname: string;
|
||||
ip?: string;
|
||||
isConnectedTo?: boolean;
|
||||
maxRam?: number;
|
||||
moneyAvailable?: number;
|
||||
numOpenPortsRequired?: number;
|
||||
organizationName?: string;
|
||||
purchasedByPlayer?: boolean;
|
||||
requiredHackingSkill?: number;
|
||||
serverGrowth?: number;
|
||||
}
|
||||
|
||||
export class Server {
|
||||
// Initial server security level
|
||||
// (i.e. security level when the server was created)
|
||||
baseDifficulty: number = 1;
|
||||
|
||||
// Coding Contract files on this server
|
||||
contracts: CodingContract[] = [];
|
||||
|
||||
// How many CPU cores this server has. Maximum of 8.
|
||||
// Currently, this only affects hacking missions
|
||||
cpuCores: number = 1;
|
||||
|
||||
// Flag indicating whether the FTP port is open
|
||||
ftpPortOpen: boolean = false;
|
||||
|
||||
// Server Security Level
|
||||
hackDifficulty: number = 1;
|
||||
|
||||
// Flag indicating whether player has admin/root access to this server
|
||||
hasAdminRights: boolean = false;
|
||||
|
||||
// Hostname. Must be unique
|
||||
hostname: string = "";
|
||||
|
||||
// Flag indicating whether HTTP Port is open
|
||||
httpPortOpen: boolean = false;
|
||||
|
||||
// IP Address. Must be unique
|
||||
ip: string = "";
|
||||
|
||||
// Flag indicating whether player is curently connected to this server
|
||||
isConnectedTo: boolean = false;
|
||||
|
||||
// Flag indicating whether this server has been manually hacked (ie.
|
||||
// hacked through Terminal) by the player
|
||||
manuallyHacked: boolean = false;
|
||||
|
||||
// RAM (GB) available on this server
|
||||
maxRam: number = 0;
|
||||
|
||||
// Message files AND Literature files on this Server
|
||||
// For Literature files, this array contains only the filename (string)
|
||||
// For Messages, it contains the actual Message object
|
||||
// TODO Separate literature files into its own property
|
||||
messages: (Message | string)[] = [];
|
||||
|
||||
// Minimum server security level that this server can be weakened to
|
||||
minDifficulty: number = 1;
|
||||
|
||||
// How much money currently resides on the server and can be hacked
|
||||
moneyAvailable: number = 0;
|
||||
|
||||
// Maximum amount of money that this server can hold
|
||||
moneyMax: number = 0;
|
||||
|
||||
// Number of open ports required in order to gain admin/root access
|
||||
numOpenPortsRequired: number = 5;
|
||||
|
||||
// How many ports are currently opened on the server
|
||||
openPortCount: number = 0;
|
||||
|
||||
// Name of company/faction/etc. that this server belongs to.
|
||||
// Optional, not applicable to all Servers
|
||||
organizationName: string = "";
|
||||
|
||||
// Programs on this servers. Contains only the names of the programs
|
||||
programs: string[] = [];
|
||||
|
||||
// Flag indicating wehther this is a purchased server
|
||||
purchasedByPlayer: boolean = false;
|
||||
|
||||
// RAM (GB) used. i.e. unavailable RAM
|
||||
ramUsed: number = 0;
|
||||
|
||||
// Hacking level required to hack this server
|
||||
requiredHackingSkill: number = 1;
|
||||
|
||||
// RunningScript files on this server
|
||||
runningScripts: RunningScript[] = [];
|
||||
|
||||
// Script files on this Server
|
||||
scripts: Script[] = [];
|
||||
|
||||
// Parameter that affects how effectively this server's money can
|
||||
// be increased using the grow() Netscript function
|
||||
serverGrowth: number = 1;
|
||||
|
||||
// Contains the IP Addresses of all servers that are immediately
|
||||
// reachable from this one
|
||||
serversOnNetwork: string[] = [];
|
||||
|
||||
// Flag indicating whether SMTP Port is open
|
||||
smtpPortOpen: boolean = false;
|
||||
|
||||
// Flag indicating whether SQL Port is open
|
||||
sqlPortOpen: boolean = false;
|
||||
|
||||
// Flag indicating whether the SSH Port is open
|
||||
sshPortOpen: boolean = false;
|
||||
|
||||
// Text files on this server
|
||||
textFiles: TextFile[] = [];
|
||||
|
||||
constructor(params: IConstructorParams={hostname: "", ip: createRandomIp() }) {
|
||||
/* Properties */
|
||||
//Connection information
|
||||
this.ip = params.ip ? params.ip : createRandomIp();
|
||||
|
||||
var hostname = params.hostname;
|
||||
var i = 0;
|
||||
var suffix = "";
|
||||
while (GetServerByHostname(hostname+suffix) != null) {
|
||||
//Server already exists
|
||||
suffix = "-" + i;
|
||||
++i;
|
||||
}
|
||||
this.hostname = hostname + suffix;
|
||||
this.organizationName = params.organizationName != null ? params.organizationName : "";
|
||||
this.isConnectedTo = params.isConnectedTo != null ? params.isConnectedTo : false;
|
||||
|
||||
//Access information
|
||||
this.hasAdminRights = params.adminRights != null ? params.adminRights : false;
|
||||
this.purchasedByPlayer = params.purchasedByPlayer != null ? params.purchasedByPlayer : false;
|
||||
|
||||
//RAM, CPU speed and Scripts
|
||||
this.maxRam = params.maxRam != null ? params.maxRam : 0; //GB
|
||||
|
||||
/* Hacking information (only valid for "foreign" aka non-purchased servers) */
|
||||
this.requiredHackingSkill = params.requiredHackingSkill != null ? params.requiredHackingSkill : 1;
|
||||
this.moneyAvailable = params.moneyAvailable != null ? params.moneyAvailable * BitNodeMultipliers.ServerStartingMoney : 0;
|
||||
this.moneyMax = 25 * this.moneyAvailable * BitNodeMultipliers.ServerMaxMoney;
|
||||
|
||||
//Hack Difficulty is synonymous with server security. Base Difficulty = Starting difficulty
|
||||
this.hackDifficulty = params.hackDifficulty != null ? params.hackDifficulty * BitNodeMultipliers.ServerStartingSecurity : 1;
|
||||
this.baseDifficulty = this.hackDifficulty;
|
||||
this.minDifficulty = Math.max(1, Math.round(this.hackDifficulty / 3));
|
||||
this.serverGrowth = params.serverGrowth != null ? params.serverGrowth : 1; //Integer from 0 to 100. Affects money increase from grow()
|
||||
|
||||
//Port information, required for porthacking servers to get admin rights
|
||||
this.numOpenPortsRequired = params.numOpenPortsRequired != null ? params.numOpenPortsRequired : 5;
|
||||
};
|
||||
|
||||
setMaxRam(ram: number): void {
|
||||
this.maxRam = ram;
|
||||
}
|
||||
|
||||
//The serverOnNetwork array holds the IP of all the servers. This function
|
||||
//returns the actual Server objects
|
||||
Server.prototype.getServerOnNetwork = function(i) {
|
||||
if (i > this.serversOnNetwork.length) {
|
||||
console.log("Tried to get server on network that was out of range");
|
||||
return;
|
||||
}
|
||||
return AllServers[this.serversOnNetwork[i]];
|
||||
}
|
||||
|
||||
//Given the name of the script, returns the corresponding
|
||||
//script object on the server (if it exists)
|
||||
Server.prototype.getScript = function(scriptName) {
|
||||
for (var i = 0; i < this.scripts.length; i++) {
|
||||
if (this.scripts[i].filename == scriptName) {
|
||||
return this.scripts[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Server.prototype.capDifficulty = function() {
|
||||
if (this.hackDifficulty < this.minDifficulty) {this.hackDifficulty = this.minDifficulty;}
|
||||
if (this.hackDifficulty < 1) {this.hackDifficulty = 1;}
|
||||
//Place some arbitrarily limit that realistically should never happen unless someone is
|
||||
//screwing around with the game
|
||||
if (this.hackDifficulty > 1000000) {this.hackDifficulty = 1000000;}
|
||||
}
|
||||
|
||||
//Strengthens a server's security level (difficulty) by the specified amount
|
||||
Server.prototype.fortify = function(amt) {
|
||||
this.hackDifficulty += amt;
|
||||
this.capDifficulty();
|
||||
}
|
||||
|
||||
Server.prototype.weaken = function(amt) {
|
||||
this.hackDifficulty -= (amt * BitNodeMultipliers.ServerWeakenRate);
|
||||
this.capDifficulty();
|
||||
}
|
||||
|
||||
// Write to a script file
|
||||
// Overwrites existing files. Creates new files if the script does not eixst
|
||||
Server.prototype.writeToScriptFile = function(fn, code) {
|
||||
var ret = {success: false, overwritten: false};
|
||||
if (!isScriptFilename(fn)) { return ret; }
|
||||
|
||||
//Check if the script already exists, and overwrite it if it does
|
||||
for (let i = 0; i < this.scripts.length; ++i) {
|
||||
if (fn === this.scripts[i].filename) {
|
||||
let script = this.scripts[i];
|
||||
script.code = code;
|
||||
script.updateRamUsage();
|
||||
script.module = "";
|
||||
ret.overwritten = true;
|
||||
ret.success = true;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
//Otherwise, create a new script
|
||||
var newScript = new Script();
|
||||
newScript.filename = fn;
|
||||
newScript.code = code;
|
||||
newScript.updateRamUsage();
|
||||
newScript.server = this.ip;
|
||||
this.scripts.push(newScript);
|
||||
ret.success = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Write to a text file
|
||||
// Overwrites existing files. Creates new files if the text file does not exist
|
||||
Server.prototype.writeToTextFile = function(fn, txt) {
|
||||
var ret = {success: false, overwritten: false};
|
||||
if (!fn.endsWith("txt")) { return ret; }
|
||||
|
||||
//Check if the text file already exists, and overwrite if it does
|
||||
for (let i = 0; i < this.textFiles.length; ++i) {
|
||||
if (this.textFiles[i].fn === fn) {
|
||||
ret.overwritten = true;
|
||||
this.textFiles[i].text = txt;
|
||||
ret.success = true;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
//Otherwise create a new text file
|
||||
var newFile = new TextFile(fn, txt);
|
||||
this.textFiles.push(newFile);
|
||||
ret.success = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Server.prototype.addContract = function(contract) {
|
||||
this.contracts.push(contract);
|
||||
}
|
||||
|
||||
Server.prototype.removeContract = function(contract) {
|
||||
if (contract instanceof CodingContract) {
|
||||
this.contracts = this.contracts.filter((c) => {
|
||||
return c.fn !== contract.fn;
|
||||
});
|
||||
} else {
|
||||
this.contracts = this.contracts.filter((c) => {
|
||||
return c.fn !== contract;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Server.prototype.getContract = function(contractName) {
|
||||
for (const contract of this.contracts) {
|
||||
if (contract.fn === contractName) {
|
||||
return contract;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//Functions for loading and saving a Server
|
||||
Server.prototype.toJSON = function() {
|
||||
return Generic_toJSON("Server", this);
|
||||
}
|
||||
|
||||
Server.fromJSON = function(value) {
|
||||
return Generic_fromJSON(Server, value.data);
|
||||
}
|
||||
|
||||
Reviver.constructors.Server = Server;
|
126
src/Server/ServerHelpers.js
Normal file
126
src/Server/ServerHelpers.js
Normal file
@ -0,0 +1,126 @@
|
||||
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
|
||||
import { CodingContract,
|
||||
ContractTypes } from "./CodingContracts";
|
||||
import { CONSTANTS } from "./Constants";
|
||||
import { Script,
|
||||
isScriptFilename } from "./Script";
|
||||
import { Player } from "./Player";
|
||||
import { Programs } from "./Programs/Programs";
|
||||
import { SpecialServerIps } from "./SpecialServerIps";
|
||||
import { TextFile } from "./TextFile";
|
||||
import { getRandomInt } from "../utils/helpers/getRandomInt";
|
||||
import { serverMetadata } from "./data/servers";
|
||||
import { Reviver,
|
||||
Generic_toJSON,
|
||||
Generic_fromJSON} from "../utils/JSONReviver";
|
||||
import {isValidIPAddress} from "../utils/helpers/isValidIPAddress";
|
||||
|
||||
// Returns the number of cycles needed to grow the specified server by the
|
||||
// specified amount. 'growth' parameter is in decimal form, not percentage
|
||||
export function numCycleForGrowth(server, growth) {
|
||||
let ajdGrowthRate = 1 + (CONSTANTS.ServerBaseGrowthRate - 1) / server.hackDifficulty;
|
||||
if(ajdGrowthRate > CONSTANTS.ServerMaxGrowthRate) {
|
||||
ajdGrowthRate = CONSTANTS.ServerMaxGrowthRate;
|
||||
}
|
||||
|
||||
const serverGrowthPercentage = server.serverGrowth / 100;
|
||||
|
||||
const cycles = Math.log(growth)/(Math.log(ajdGrowthRate)*Player.hacking_grow_mult*serverGrowthPercentage);
|
||||
return cycles;
|
||||
}
|
||||
|
||||
//Applied server growth for a single server. Returns the percentage growth
|
||||
export function processSingleServerGrowth(server, numCycles) {
|
||||
//Server growth processed once every 450 game cycles
|
||||
const numServerGrowthCycles = Math.max(Math.floor(numCycles / 450), 0);
|
||||
|
||||
//Get adjusted growth rate, which accounts for server security
|
||||
const growthRate = CONSTANTS.ServerBaseGrowthRate;
|
||||
var adjGrowthRate = 1 + (growthRate - 1) / server.hackDifficulty;
|
||||
if (adjGrowthRate > CONSTANTS.ServerMaxGrowthRate) {adjGrowthRate = CONSTANTS.ServerMaxGrowthRate;}
|
||||
|
||||
//Calculate adjusted server growth rate based on parameters
|
||||
const serverGrowthPercentage = server.serverGrowth / 100;
|
||||
const numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage * BitNodeMultipliers.ServerGrowthRate;
|
||||
|
||||
//Apply serverGrowth for the calculated number of growth cycles
|
||||
var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult);
|
||||
if (serverGrowth < 1) {
|
||||
console.log("WARN: serverGrowth calculated to be less than 1");
|
||||
serverGrowth = 1;
|
||||
}
|
||||
|
||||
const oldMoneyAvailable = server.moneyAvailable;
|
||||
server.moneyAvailable *= serverGrowth;
|
||||
|
||||
// in case of data corruption
|
||||
if (server.moneyMax && isNaN(server.moneyAvailable)) {
|
||||
server.moneyAvailable = server.moneyMax;
|
||||
}
|
||||
|
||||
// cap at max
|
||||
if (server.moneyMax && server.moneyAvailable > server.moneyMax) {
|
||||
server.moneyAvailable = server.moneyMax;
|
||||
}
|
||||
|
||||
// if there was any growth at all, increase security
|
||||
if (oldMoneyAvailable !== server.moneyAvailable) {
|
||||
//Growing increases server security twice as much as hacking
|
||||
let usedCycles = numCycleForGrowth(server, server.moneyAvailable / oldMoneyAvailable);
|
||||
usedCycles = Math.max(0, usedCycles);
|
||||
server.fortify(2 * CONSTANTS.ServerFortifyAmount * Math.ceil(usedCycles));
|
||||
}
|
||||
return server.moneyAvailable / oldMoneyAvailable;
|
||||
}
|
||||
|
||||
export function prestigeHomeComputer(homeComp) {
|
||||
const hasBitflume = homeComp.programs.includes(Programs.BitFlume.name);
|
||||
|
||||
homeComp.programs.length = 0; //Remove programs
|
||||
homeComp.runningScripts = [];
|
||||
homeComp.serversOnNetwork = [];
|
||||
homeComp.isConnectedTo = true;
|
||||
homeComp.ramUsed = 0;
|
||||
homeComp.programs.push(Programs.NukeProgram.name);
|
||||
if (hasBitflume) { homeComp.programs.push(Programs.BitFlume.name); }
|
||||
|
||||
//Update RAM usage on all scripts
|
||||
homeComp.scripts.forEach(function(script) {
|
||||
script.updateRamUsage();
|
||||
});
|
||||
|
||||
homeComp.messages.length = 0; //Remove .lit and .msg files
|
||||
homeComp.messages.push("hackers-starting-handbook.lit");
|
||||
}
|
||||
|
||||
function SizeOfAllServers() {
|
||||
var size = 0, key;
|
||||
for (key in AllServers) {
|
||||
if (AllServers.hasOwnProperty(key)) size++;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
//Returns server object with corresponding hostname
|
||||
// Relatively slow, would rather not use this a lot
|
||||
export function GetServerByHostname(hostname) {
|
||||
for (var ip in AllServers) {
|
||||
if (AllServers.hasOwnProperty(ip)) {
|
||||
if (AllServers[ip].hostname == hostname) {
|
||||
return AllServers[ip];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//Get server by IP or hostname. Returns null if invalid
|
||||
export function getServer(s) {
|
||||
if (!isValidIPAddress(s)) {
|
||||
return GetServerByHostname(s);
|
||||
}
|
||||
if(AllServers[s] !== undefined) {
|
||||
return AllServers[s];
|
||||
}
|
||||
return null;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
import {AllServers} from "../src/Server";
|
||||
import {getRandomByte} from "./helpers/getRandomByte";
|
||||
|
||||
/* Functions to deal with manipulating IP addresses*/
|
||||
|
||||
//Generate a random IP address
|
||||
//Will not return an IP address that already exists in the AllServers array
|
||||
function createRandomIp() {
|
||||
var ip = getRandomByte(99) + '.' +
|
||||
getRandomByte(9) + '.' +
|
||||
getRandomByte(9) + '.' +
|
||||
getRandomByte(9);
|
||||
|
||||
//If the Ip already exists, recurse to create a new one
|
||||
if (ipExists(ip)) {
|
||||
return createRandomIp();
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
//Returns true if the IP already exists in one of the game's servers
|
||||
function ipExists(ip) {
|
||||
for (var property in AllServers) {
|
||||
if (AllServers.hasOwnProperty(property)) {
|
||||
if (property == ip) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export {createRandomIp, ipExists};
|
25
utils/IPAddress.ts
Normal file
25
utils/IPAddress.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import {AllServers} from "../src/Server";
|
||||
import {getRandomByte} from "./helpers/getRandomByte";
|
||||
|
||||
/* Functions to deal with manipulating IP addresses*/
|
||||
|
||||
//Generate a random IP address
|
||||
//Will not return an IP address that already exists in the AllServers array
|
||||
export function createRandomIp(): string {
|
||||
const ip: string = getRandomByte(99) + '.' +
|
||||
getRandomByte(9) + '.' +
|
||||
getRandomByte(9) + '.' +
|
||||
getRandomByte(9);
|
||||
|
||||
// If the Ip already exists, recurse to create a new one
|
||||
if (ipExists(ip)) {
|
||||
return createRandomIp();
|
||||
}
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
// Returns true if the IP already exists in one of the game's servers
|
||||
export function ipExists(ip: string) {
|
||||
return (AllServers[ip] != null);
|
||||
}
|
Loading…
Reference in New Issue
Block a user