diff --git a/markdown/bitburner.darknet.unleashstormseed.md b/markdown/bitburner.darknet.unleashstormseed.md index 274faa2c6..276eea6cb 100644 --- a/markdown/bitburner.darknet.unleashstormseed.md +++ b/markdown/bitburner.darknet.unleashstormseed.md @@ -17,7 +17,7 @@ unleashStormSeed(): DarknetResult; [DarknetResult](./bitburner.darknetresult.md) -A promise that resolves to a [DarknetResult](./bitburner.darknetresult.md) object. +A [DarknetResult](./bitburner.darknetresult.md) object. ## Remarks diff --git a/markdown/bitburner.ns.getserverusedram.md b/markdown/bitburner.ns.getserverusedram.md index 85bf28dff..9c3845b18 100644 --- a/markdown/bitburner.ns.getserverusedram.md +++ b/markdown/bitburner.ns.getserverusedram.md @@ -4,7 +4,7 @@ ## NS.getServerUsedRam() method -Get the used RAM on a server. +Get the used RAM on a server. This includes ram used by running scripts as well as blocked ram on darknet servers. **Signature:** diff --git a/markdown/bitburner.ns.md b/markdown/bitburner.ns.md index 43c291e42..83d3074f3 100644 --- a/markdown/bitburner.ns.md +++ b/markdown/bitburner.ns.md @@ -1037,7 +1037,7 @@ Get server security level. -Get the used RAM on a server. +Get the used RAM on a server. This includes ram used by running scripts as well as blocked ram on darknet servers. diff --git a/markdown/bitburner.ns.scp.md b/markdown/bitburner.ns.scp.md index d625135d1..5f7f5e622 100644 --- a/markdown/bitburner.ns.scp.md +++ b/markdown/bitburner.ns.scp.md @@ -112,5 +112,5 @@ const server = ns.args[0]; const files = ["hack.js", "weaken.js", "grow.js"]; ns.scp(files, server, "home"); ``` -For password-protected servers (such as darknet servers), a session must be established with the destination server before using this function. +For password-protected servers (such as darknet servers), a session must be established with the destination server before using this function. (The source server does not require a session.) diff --git a/src/DarkNet/controllers/NetworkGenerator.ts b/src/DarkNet/controllers/NetworkGenerator.ts index e0e8f1add..957f5172b 100644 --- a/src/DarkNet/controllers/NetworkGenerator.ts +++ b/src/DarkNet/controllers/NetworkGenerator.ts @@ -181,17 +181,19 @@ export const addRandomConnections = (server: DarknetServer) => { const x = server.depth; const y = server.leftOffset; const horizontalNeighbors = getNeighborsOnRow(x, y); + const lateralConnectionChance = HORIZONTAL_CONNECTION_CHANCE * (1.1 - server.depth * 0.01); horizontalNeighbors.forEach((neighbor) => { - if (Math.random() < HORIZONTAL_CONNECTION_CHANCE) { + if (Math.random() < lateralConnectionChance) { connectServers(server, neighbor); } }); const serversAbove = getServersOnRowAbove(x); const serversBelow = getServersOnRowBelow(x); + const verticalConnectionChance = VERTICAL_CONNECTION_CHANCE * (1.1 - server.depth * 0.01); [...serversAbove, ...serversBelow].forEach((neighbor) => { const distance = Math.abs(neighbor.depth ?? x - x) + 1; - if (Math.random() < VERTICAL_CONNECTION_CHANCE / distance) { + if (Math.random() < verticalConnectionChance / distance) { connectServers(server, neighbor); } }); diff --git a/src/DarkNet/controllers/NetworkMovement.ts b/src/DarkNet/controllers/NetworkMovement.ts index 1e00b8750..e40ab05c0 100644 --- a/src/DarkNet/controllers/NetworkMovement.ts +++ b/src/DarkNet/controllers/NetworkMovement.ts @@ -111,7 +111,7 @@ export const mutateDarknet = (): void => { restartRandomServer(); } - if (Math.random() < 0.5) { + if (Math.random() < 0.3) { moveRandomDarknetServers(3); } diff --git a/src/DarkNet/effects/effects.ts b/src/DarkNet/effects/effects.ts index 59a172595..fbfff3dca 100644 --- a/src/DarkNet/effects/effects.ts +++ b/src/DarkNet/effects/effects.ts @@ -62,22 +62,24 @@ export const handleFailedAuth = (server: DarknetServer, threads: number) => { * @param person - the player's character * @param attemptedPassword - the password being attempted * @param threads - the number of threads used for the password attempt (which speeds up the process) + * @param linear - if true, the time scaling is linear with the number of threads instead of having diminishing returns */ export const calculateAuthenticationTime = ( darknetServerData: DarknetServerData, person: IPerson = Player, threads = 1, attemptedPassword = "", + linear = false, ) => { const chaRequired = darknetServerData.requiredCharismaSkill; const difficulty = darknetServerData.difficulty; const baseDiff = (difficulty + 1) * 100; const diffFactor = 5; - const baseTime = 500; + const baseTime = 850; - const threadsFactor = 1 / (1 + 0.2 * (threads - 1)); - const skillFactor = (diffFactor * chaRequired + baseDiff) / (person.skills.charisma + 100); + const threadsFactor = 1 / (linear ? threads : 1 + 0.2 * (threads - 1)); + const skillFactor = (diffFactor * chaRequired + baseDiff) / (person.skills.charisma + 150); const backdoorFactor = getBackdoorAuthTimeDebuff(); const applyUnderleveledFactor = person.skills.charisma <= chaRequired && darknetServerData.depth > 1; const underleveledFactor = applyUnderleveledFactor ? 1.5 + (chaRequired + 50) / (person.skills.charisma + 50) : 1; @@ -128,10 +130,9 @@ export const getMultiplierFromCharisma = (scalar = 1) => { ); }; -// TODO: balance xp gain export const calculatePasswordAttemptChaGain = (server: DarknetServerData, threads: number = 1, success = false) => { const baseXpGain = 3; - const difficultyBase = 1.12; + const difficultyBase = 0.8; const xpGain = baseXpGain + difficultyBase ** server.difficulty; const alreadyHackedMult = server.hasAdminRights ? 0.2 : 1; const successMult = success && !server.hasAdminRights ? 10 : 1; diff --git a/src/DarkNet/models/packetSniffing.ts b/src/DarkNet/models/packetSniffing.ts index 3f40ec04e..488e7bf71 100644 --- a/src/DarkNet/models/packetSniffing.ts +++ b/src/DarkNet/models/packetSniffing.ts @@ -4,7 +4,7 @@ import { generateDarknetServerName, isPasswordResponse, type PasswordResponse } import { LocationName } from "@enums"; import { getServerState, LogEntry } from "./DarknetState"; import { ModelIds } from "../Enums"; -import { getDarknetServer } from "../utils/darknetServerUtils"; +import { getDarknetServer, getDarknetServerOrThrow } from "../utils/darknetServerUtils"; import { getAllMovableDarknetServers } from "../utils/darknetNetworkUtils"; import { getExactCorrectChars, getTwoCharsInPassword } from "../utils/darknetAuthUtils"; import type { DarknetServer } from "../../Server/DarknetServer"; @@ -200,8 +200,8 @@ const getLogNoise = (server: DarknetServer, logDate: Date): LogEntry => { return log(`--${randomServer.password}--`); } - if (server.modelId === ModelIds.packetSniffer && Math.random() < 0.5 / (server.difficulty + 1)) { - return log("Authentication successful: " + server.password); + if (server.modelId === ModelIds.packetSniffer && Math.random() < 0.7 - server.difficulty * 0.01) { + return addPacketSnifferNoise(server); } return log(`${logDate.toLocaleTimeString()}: ${server.hostname} - heartbeat check (alive)`); @@ -212,6 +212,18 @@ const log = (message: string, pid = -1) => ({ pid, }); +const addPacketSnifferNoise = (server: DarknetServer) => { + const connectedServers = server.serversOnNetwork; + // If the server becomes disconnected while the UI is open and has no neighbors but still + // has logs being populated, fall back to showing the current password + if (Math.random() < 0.3 || connectedServers.length === 0) { + return log(`Logging in with passcode: ${server.password} ...`); + } + const randomServerName = connectedServers[Math.floor(Math.random() * connectedServers.length)]; + const randomServer = getDarknetServerOrThrow(randomServerName); + return log(`Connecting to ${randomServer.hostname}:${randomServer.password} ...`); +}; + export const getMostRecentAuthLog = (hostname: string) => { for (const log of getServerState(hostname).serverLogs) { if (!isPasswordResponse(log.message)) { diff --git a/src/DarkNet/utils/darknetNetworkUtils.ts b/src/DarkNet/utils/darknetNetworkUtils.ts index 8415598f9..d330b3b60 100644 --- a/src/DarkNet/utils/darknetNetworkUtils.ts +++ b/src/DarkNet/utils/darknetNetworkUtils.ts @@ -4,11 +4,13 @@ import { AIR_GAP_DEPTH, MS_PER_MUTATION_PER_ROW, NET_WIDTH } from "../Enums"; import { GetAllServers } from "../../Server/AllServers"; import { getNetDepth } from "../effects/labyrinth"; import { CONSTANTS } from "../../Constants"; +import { Player } from "@player"; export const getDarknetCyclesPerMutation = () => { const depth = getNetDepth(); const cycleRate = MS_PER_MUTATION_PER_ROW / CONSTANTS.MilliPerCycle; - return cycleRate / depth; + const rateMultiplier = Player.bitNodeN !== 15 ? 2 : 1; + return (rateMultiplier * cycleRate) / depth; }; export const getAllOpenPositions = (minDepth: number, maxDepth: number): [number, number][] => { diff --git a/src/NetscriptFunctions/Darknet.ts b/src/NetscriptFunctions/Darknet.ts index 3489a0504..7c41332d5 100644 --- a/src/NetscriptFunctions/Darknet.ts +++ b/src/NetscriptFunctions/Darknet.ts @@ -425,7 +425,8 @@ export function NetscriptDarknet(): InternalAPI { } const server = serverCheck.server; - const networkDelay = calculateAuthenticationTime(server, Player, ctx.workerScript.scriptRef.threads) * 4; + const networkDelay = + calculateAuthenticationTime(server, Player, ctx.workerScript.scriptRef.threads, "", true) * 4; const xp = formatNumber(calculatePasswordAttemptChaGain(server, ctx.workerScript.scriptRef.threads), 1); logger(ctx)(`Captured some outgoing transmissions from ${server.hostname}. (Gained ${xp} cha xp)`); diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 26f9afd2f..b0cbeac96 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -4619,7 +4619,7 @@ export interface Darknet { * @remarks * RAM cost: 0.1 GB * - * @returns A promise that resolves to a {@link DarknetResult} object. + * @returns A {@link DarknetResult} object. */ unleashStormSeed(): DarknetResult; @@ -7953,7 +7953,7 @@ export interface NS { * ns.scp(files, server, "home"); * ``` * - * For password-protected servers (such as darknet servers), a session must be established with the destination server before using this function. + * For password-protected servers (such as darknet servers), a session must be established with the destination server before using this function. (The source server does not require a session.) * * @param files - Filename or an array of filenames of script/literature files to copy. Note that if a file is located in a subdirectory, the filename must include the leading `/`. * @param destination - Hostname/IP of the destination server, which is the server to which the file will be copied. @@ -8185,7 +8185,7 @@ export interface NS { */ getServerMaxRam(host?: string): number; /** - * Get the used RAM on a server. + * Get the used RAM on a server. This includes ram used by running scripts as well as blocked ram on darknet servers. * @remarks * RAM cost: 0.05 GB * diff --git a/test/jest/Netscript/Darknet.test.ts b/test/jest/Netscript/Darknet.test.ts index ae91f3779..15da05e4a 100644 --- a/test/jest/Netscript/Darknet.test.ts +++ b/test/jest/Netscript/Darknet.test.ts @@ -17,7 +17,7 @@ import { } from "../Utilities"; import type { ScriptFilePath } from "../../../src/Paths/ScriptFilePath"; import { DarknetState, getServerState, triggerNextUpdate } from "../../../src/DarkNet/models/DarknetState"; -import { getDarknetServerOrThrow } from "../../../src/DarkNet/utils/darknetServerUtils"; +import { getDarknetServer, getDarknetServerOrThrow } from "../../../src/DarkNet/utils/darknetServerUtils"; import { ModelIds, ResponseCodeEnum } from "../../../src/DarkNet/Enums"; import { getAllMovableDarknetServers } from "../../../src/DarkNet/utils/darknetNetworkUtils"; import { expectRunningOnDarknetServer } from "../../../src/DarkNet/effects/offlineServerHandling"; @@ -878,9 +878,19 @@ describe("Non-darkweb darknet server", () => { test("authenticate from darkweb", async () => { const ns = getNsOnDarkWeb(); const target = getFirstDarknetServerAdjacentToDarkWeb(); - const result = await ns.dnet.authenticate(target, getDarknetServerOrThrow(target).password); - expect(result.success).toStrictEqual(true); + const server = getDarknetServerOrThrow(target); + const result = await ns.dnet.authenticate(target, server.password); + // Logging details for debugging flaky test + if (!result.success) { + console.log("Server details grabbed before auth:"); + console.log(server); + console.log("result:"); + console.log(result); + console.log("currentServerDetails:"); + console.log(getDarknetServer(target)); + } expect(result.code).toStrictEqual(ResponseCodeEnum.Success); + expect(result.success).toStrictEqual(true); }); test("authenticate itself", async () => { const ns = getNsOnNonDarkwebDarknetServer();