diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index 98737302d..953b29005 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -44,7 +44,6 @@ import { findEnumMember } from "../utils/helpers/enum"; import { Engine } from "../engine"; import { getEnumHelper } from "../utils/EnumHelper"; import { ScriptFilePath, resolveScriptFilePath } from "../Paths/ScriptFilePath"; -import { root } from "../Paths/Directory"; import { getRecordEntries } from "../Types/Record"; import { JobTracks } from "../Company/data/JobTracks"; import { ServerConstants } from "../Server/data/Constants"; @@ -52,6 +51,7 @@ import { blackOpsArray } from "../Bladeburner/data/BlackOperations"; import { calculateEffectiveRequiredReputation } from "../Company/utils"; import { calculateFavorAfterResetting } from "../Faction/formulas/favor"; import { validBitNodes } from "../BitNode/BitNodeUtils"; +import { exceptionAlert } from "../utils/helpers/exceptionAlert"; export function NetscriptSingularity(): InternalAPI { const runAfterReset = function (cbScript: ScriptFilePath) { @@ -479,40 +479,34 @@ export function NetscriptSingularity(): InternalAPI { throw helpers.errorMessage(ctx, `Invalid hostname: '${hostname}'`); } - //Home case - if (hostname === "home") { - Player.getCurrentServer().isConnectedTo = false; - Player.currentServer = Player.getHomeComputer().hostname; - Player.getCurrentServer().isConnectedTo = true; - Terminal.setcwd(root); - return true; - } - - //Adjacent server case + // Adjacent servers const server = Player.getCurrentServer(); for (let i = 0; i < server.serversOnNetwork.length; i++) { const other = getServerOnNetwork(server, i); - if (other === null) continue; - if (other.hostname == hostname) { - Player.getCurrentServer().isConnectedTo = false; - Player.currentServer = target.hostname; - Player.getCurrentServer().isConnectedTo = true; - Terminal.setcwd(root); + if (other === null) { + exceptionAlert( + new Error( + `${server.serversOnNetwork[i]} is on the network of ${server.hostname}, but we cannot find its data.`, + ), + ); + return false; + } + if (other.hostname === hostname) { + Terminal.connectToServer(hostname, true); return true; } } - //Backdoor case - const other = GetServer(hostname); - if (other !== null && other instanceof Server && other.backdoorInstalled) { - Player.getCurrentServer().isConnectedTo = false; - Player.currentServer = target.hostname; - Player.getCurrentServer().isConnectedTo = true; - Terminal.setcwd(root); + /** + * Backdoored + owned servers (home, private servers, or hacknet servers). With home computer, purchasedByPlayer + * is true. + */ + if (target.backdoorInstalled || target.purchasedByPlayer) { + Terminal.connectToServer(hostname, true); return true; } - //Failure case + // Failure case return false; }, manualHack: (ctx) => () => { diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index 1a329d0c3..40bb26ef1 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -586,19 +586,21 @@ export class Terminal { printOutput(root); } - connectToServer(server: string): void { - const serv = GetServer(server); - if (serv == null) { + connectToServer(hostname: string, singularity = false): void { + const server = GetServer(hostname); + if (server === null) { this.error("Invalid server. Connection failed."); return; } Player.getCurrentServer().isConnectedTo = false; - Player.currentServer = serv.hostname; - Player.getCurrentServer().isConnectedTo = true; - this.print("Connected to " + serv.hostname); + Player.currentServer = hostname; + server.isConnectedTo = true; this.setcwd(root); - if (Player.getCurrentServer().hostname == "darkweb") { - checkIfConnectedToDarkweb(); // Posts a 'help' message if connecting to dark web + if (!singularity) { + this.print("Connected to " + server.hostname); + if (Player.getCurrentServer().hostname == "darkweb") { + checkIfConnectedToDarkweb(); // Posts a 'help' message if connecting to dark web + } } } diff --git a/src/Terminal/commands/connect.ts b/src/Terminal/commands/connect.ts index 791d9a3aa..c1a28ad81 100644 --- a/src/Terminal/commands/connect.ts +++ b/src/Terminal/commands/connect.ts @@ -2,6 +2,7 @@ import { Terminal } from "../../Terminal"; import { BaseServer } from "../../Server/BaseServer"; import { getServerOnNetwork } from "../../Server/ServerHelpers"; import { GetServer } from "../../Server/AllServers"; +import { exceptionAlert } from "../../utils/helpers/exceptionAlert"; export function connect(args: (string | number | boolean)[], server: BaseServer): void { // Disconnect from current server in Terminal and connect to new one @@ -10,27 +11,41 @@ export function connect(args: (string | number | boolean)[], server: BaseServer) return; } - const hostname = args[0] + ""; + const hostname = String(args[0]); + const target = GetServer(hostname); + if (target === null) { + Terminal.error(`Invalid hostname: '${hostname}'`); + return; + } + + // Adjacent servers for (let i = 0; i < server.serversOnNetwork.length; i++) { const other = getServerOnNetwork(server, i); - if (other === null) throw new Error(`Server on network should not be null`); - if (other.hostname == hostname) { + if (other === null) { + exceptionAlert( + new Error( + `${server.serversOnNetwork[i]} is on the network of ${server.hostname}, but we cannot find its data.`, + ), + ); + return; + } + if (other.hostname === hostname) { Terminal.connectToServer(hostname); return; } } - const other = GetServer(hostname); - if (other !== null) { - if (other.backdoorInstalled || other.purchasedByPlayer) { - Terminal.connectToServer(hostname); - return; - } - Terminal.error( - `Cannot directly connect to ${hostname}. Make sure the server is backdoored or adjacent to your current Server`, - ); - } else { - Terminal.error("Host not found"); + /** + * Backdoored + owned servers (home, private servers, or hacknet servers). With home computer, purchasedByPlayer is + * true. + */ + if (target.backdoorInstalled || target.purchasedByPlayer) { + Terminal.connectToServer(hostname); + return; } + + Terminal.error( + `Cannot directly connect to ${hostname}. Make sure the server is backdoored or adjacent to your current server`, + ); } diff --git a/src/Terminal/commands/home.ts b/src/Terminal/commands/home.ts index beab626e1..3684bbb67 100644 --- a/src/Terminal/commands/home.ts +++ b/src/Terminal/commands/home.ts @@ -1,15 +1,9 @@ -import { root } from "../../Paths/Directory"; import { Terminal } from "../../Terminal"; -import { Player } from "@player"; export function home(args: (string | number | boolean)[]): void { if (args.length !== 0) { Terminal.error("Incorrect usage of home command. Usage: home"); return; } - Player.getCurrentServer().isConnectedTo = false; - Player.currentServer = Player.getHomeComputer().hostname; - Player.getCurrentServer().isConnectedTo = true; - Terminal.print("Connected to home"); - Terminal.setcwd(root); + Terminal.connectToServer("home"); } diff --git a/test/jest/Netscript/Singularity.test.ts b/test/jest/Netscript/Singularity.test.ts index cb1b65b53..cafed4f0d 100644 --- a/test/jest/Netscript/Singularity.test.ts +++ b/test/jest/Netscript/Singularity.test.ts @@ -8,6 +8,8 @@ import { SpecialServers } from "../../../src/Server/data/SpecialServers"; import { Factions } from "../../../src/Faction/Factions"; import { PlayerOwnedAugmentation } from "../../../src/Augmentation/PlayerOwnedAugmentation"; import { getNS, initGameEnvironment, setupBasicTestingEnvironment } from "./Utilities"; +import { Terminal } from "../../../src/Terminal"; +import type { NSFull } from "../../../src/NetscriptFunctions"; function setNumBlackOpsComplete(value: number): void { if (!Player.bladeburner) { @@ -297,3 +299,62 @@ describe("purchaseAugmentation", () => { }); }); }); + +describe("connect", () => { + beforeEach(() => { + setupBasicTestingEnvironment(); + Player.sourceFiles.set(9, 3); + prestigeSourceFile(true); + Player.money = 1e100; + }); + + describe("Success", () => { + const expectConnectSuccessfully = (ns: NSFull, targetHostname: string) => { + const currentServerBeforeConnecting = Player.getCurrentServer(); + expect(ns.singularity.connect(targetHostname)).toStrictEqual(true); + expect(currentServerBeforeConnecting.isConnectedTo).toStrictEqual(false); + + const currentServerAfterConnecting = Player.getCurrentServer(); + expect(currentServerAfterConnecting.hostname).toStrictEqual(targetHostname); + expect(currentServerAfterConnecting.isConnectedTo).toStrictEqual(true); + }; + test("Built-in adjacent server", () => { + expectConnectSuccessfully(getNS(), "n00dles"); + }); + test("Home", () => { + Terminal.connectToServer(SpecialServers.DaedalusServer); + expectConnectSuccessfully(getNS(), "home"); + }); + test("Private server", () => { + const ns = getNS(); + ns.purchaseServer("pserver-0", 8); + Terminal.connectToServer(SpecialServers.DaedalusServer); + expectConnectSuccessfully(ns, "pserver-0"); + }); + test("Hacknet server", () => { + const ns = getNS(); + ns.hacknet.purchaseNode(); + Terminal.connectToServer(SpecialServers.DaedalusServer); + expectConnectSuccessfully(ns, "hacknet-server-0"); + }); + test("Backdoored server", () => { + const ns = getNS(); + Terminal.connectToServer(SpecialServers.DaedalusServer); + GetServerOrThrow("n00dles").backdoorInstalled = true; + expectConnectSuccessfully(ns, "n00dles"); + }); + }); + + describe("Failure", () => { + test("Non-existent server", () => { + const ns = getNS(); + expect(() => ns.singularity.connect("abc")).toThrow(); + expect(Player.getCurrentServer().hostname).not.toStrictEqual("abc"); + }); + test("Non-adjacent server", () => { + const ns = getNS(); + expect(ns.singularity.connect(SpecialServers.DaedalusServer)).toStrictEqual(false); + expect(Player.getCurrentServer().hostname).not.toStrictEqual(SpecialServers.DaedalusServer); + }); + }); +});