BitNode-9 initial implementation

This commit is contained in:
danielyxie
2019-03-24 20:03:24 -07:00
committed by danielyxie
parent 2ce4af2498
commit 34d749809a
40 changed files with 2749 additions and 1083 deletions
+60 -187
View File
@@ -1,16 +1,12 @@
// Class representing a single generic Server
// Class representing a single hackable Server
import { BaseServer } from "./BaseServer";
// TODO This import is a circular import. Try to fix it in the future
import { GetServerByHostname } from "./ServerHelpers";
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 { isScriptFilename } from "../Script/ScriptHelpersTS";
import { TextFile } from "../TextFile";
import { createRandomString } from "../utils/createRandomString";
import { createRandomIp } from "../../utils/IPAddress";
import { Generic_fromJSON,
Generic_toJSON,
@@ -31,7 +27,7 @@ interface IConstructorParams {
serverGrowth?: number;
}
export class Server {
export class Server extends BaseServer {
// Initializes a Server Object from a JSON save state
static fromJSON(value: any): Server {
return Generic_fromJSON(Server, value.data);
@@ -41,47 +37,13 @@ export class Server {
// (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;
@@ -97,67 +59,35 @@ export class Server {
// 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();
super(params);
var hostname = params.hostname;
var i = 0;
var suffix = "";
while (GetServerByHostname(hostname+suffix) != null) {
//Server already exists
suffix = "-" + i;
++i;
// "hacknet-node-X" hostnames are reserved for Hacknet Servers
if (this.hostname.startsWith("hacknet-node-")) {
this.hostname = createRandomString(10);
}
// Validate hostname by ensuring there are no repeats
if (GetServerByHostname(this.hostname) != null) {
// Use a for loop to ensure that we don't get suck in an infinite loop somehow
let hostname: string = this.hostname;
for (let i = 0; i < 200; ++i) {
hostname = `${this.hostname}-${i}`;
if (GetServerByHostname(hostname) == null) { break; }
}
this.hostname = hostname;
}
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
@@ -178,23 +108,9 @@ export class Server {
this.numOpenPortsRequired = params.numOpenPortsRequired != null ? params.numOpenPortsRequired : 5;
};
setMaxRam(ram: number): void {
this.maxRam = ram;
}
// Given the name of the script, returns the corresponding
// script object on the server (if it exists)
getScript(scriptName: string): Script | null {
for (let i = 0; i < this.scripts.length; i++) {
if (this.scripts[i].filename === scriptName) {
return this.scripts[i];
}
}
return null;
}
// Ensures that the server's difficulty (server security) doesn't get too high
/**
* Ensures that the server's difficulty (server security) doesn't get too high
*/
capDifficulty(): void {
if (this.hackDifficulty < this.minDifficulty) {this.hackDifficulty = this.minDifficulty;}
if (this.hackDifficulty < 1) {this.hackDifficulty = 1;}
@@ -204,97 +120,54 @@ export class Server {
if (this.hackDifficulty > 1000000) {this.hackDifficulty = 1000000;}
}
// Strengthens a server's security level (difficulty) by the specified amount
/**
* Change this server's minimum security
* @param n - Value by which to increase/decrease the server's minimum security
* @param perc - Whether it should be changed by a percentage, or a flat value
*/
changeMinimumSecurity(n: number, perc: boolean=false): void {
if (perc) {
this.minDifficulty *= n;
} else {
this.minDifficulty += n;
}
// Server security cannot go below 1
this.minDifficulty = Math.max(1, this.minDifficulty);
}
/**
* Strengthens a server's security level (difficulty) by the specified amount
*/
fortify(amt: number): void {
this.hackDifficulty += amt;
this.capDifficulty();
}
// Lowers the server's security level (difficulty) by the specified amount)
/**
* Change this server's maximum money
* @param n - Value by which to change the server's maximum money
* @param perc - Whether it should be changed by a percentage, or a flat value
*/
changeMaximumMoney(n: number, perc: boolean=false): void {
if (perc) {
this.moneyMax *= n;
} else {
this.moneyMax += n;
}
}
/**
* Lowers the server's security level (difficulty) by the specified amount)
*/
weaken(amt: number): void {
this.hackDifficulty -= (amt * BitNodeMultipliers.ServerWeakenRate);
this.capDifficulty();
}
// Write to a script file
// Overwrites existing files. Creates new files if the script does not eixst
writeToScriptFile(fn: string, code: string) {
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
const 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
writeToTextFile(fn: string, txt: string) {
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;
}
addContract(contract: CodingContract) {
this.contracts.push(contract);
}
removeContract(contract: CodingContract) {
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;
});
}
}
getContract(contractName: string) {
for (const contract of this.contracts) {
if (contract.fn === contractName) {
return contract;
}
}
return null;
}
// Serialize the current object to a JSON save state
/**
* Serialize the current object to a JSON save state
*/
toJSON(): any {
return Generic_toJSON("Server", this);
}