/** @param {NS} ns */ export async function main(ns) { ns.tprint("This is just a function library, it doesn't do anything."); } // Custom color coding. const cCyan = "\u001b[36m"; const cGreen = "\u001b[32m"; const cRed = "\u001b[31m"; const cReset = "\u001b[0m"; /** @param {NS} ns */ export function getCracks(ns) { let cracks = {}; if (ns.fileExists("BruteSSH.exe", "home")) { cracks["BruteSSH.exe"] = ns.brutessh; }; if (ns.fileExists("FTPCrack.exe", "home")) { cracks["FTPCrack.exe"] = ns.ftpcrack; }; if (ns.fileExists("relaySMTP.exe", "home")) { cracks["relaySMTP.exe"] = ns.relaysmtp; }; if (ns.fileExists("HTTPWorm.exe", "home")) { cracks["HTTPWorm.exe"] = ns.httpworm; }; if (ns.fileExists("SQLInject.exe", "home")) { cracks["SQLInject.exe"] = ns.sqlinject; }; return cracks; } /** @param {NS} ns */ export function scanServerList(ns) { const home = "home"; let serverList = []; let unscanned = []; unscanned.push(home); while (unscanned.length > 0) { let currentServer = unscanned.pop(); if (!serverList.some(obj => obj["serverName"] === currentServer)) { let maxRam = ns.getServerMaxRam(currentServer); let minPorts = ns.getServerNumPortsRequired(currentServer); let minSecLevel = ns.getServerMinSecurityLevel(currentServer); let minHackLevel = ns.getServerRequiredHackingLevel(currentServer); let rootAccess = ns.hasRootAccess(currentServer); let serverMoney = ns.getServerMaxMoney(currentServer); let serverFiles = ns.ls(currentServer); let serverStats = ns.getServer(currentServer); let serverOrgs = serverStats.organizationName; let serverCores = serverStats.cpuCores; serverList.push({ serverName: currentServer, maxRam: maxRam, maxMoney: serverMoney, minSec: minSecLevel, minPorts: minPorts, minHackLvl: minHackLevel, rootAccess: rootAccess, openPorts: 0, serverOrgs: serverOrgs, serverCores: serverCores, serverFiles: serverFiles, }); let neighbours = ns.scan(currentServer); for (let i = 0; i < neighbours.length; i++) { let neighbour = neighbours[i]; if (serverList.some(obj => obj["serverName"] === neighbour)) { continue } unscanned.push(neighbour); } } } ns.write("serverList.txt", JSON.stringify(serverList), "w"); } /** @param {NS} ns */ export function findBestTarget(ns, maxSec, maxPorts, currentHackLevel, manualTargetOverride) { if (!ns.fileExists("serverList.txt", "home")) scanServerList(); let serverList = JSON.parse(ns.read("serverList.txt")); let bestEntry = ""; if (manualTargetOverride && manualTargetOverride.length > 0) { bestEntry = manualTargetOverride; } else { bestEntry = null; let nMaxMoneyPerChance = 0; let nBestMoneyPerChance = 0; serverList.forEach((entry) => { if (entry.minSec <= maxSec && entry.minPorts <= maxPorts && entry.minHackLvl <= currentHackLevel) { nMaxMoneyPerChance = (entry.maxMoney * ns.hackAnalyzeChance(entry.serverName)) / entry.minSec; if (nMaxMoneyPerChance > nBestMoneyPerChance) { nBestMoneyPerChance = nMaxMoneyPerChance; bestEntry = entry.serverName; } } }) } ns.write("bestTarget.txt", JSON.stringify(serverList.find((entry) => entry.serverName === bestEntry)), "w"); } /** @param {NS} ns */ export function crackingAndRooting(ns, cracks) { if (!ns.fileExists("serverList.txt", "home")) scanServerList(); let serverList = JSON.parse(ns.read("serverList.txt")); let newServerList = serverList.map((entry) => { let cracked = false; let openPorts = entry.openPorts || 0; if (entry.minPorts === 0 || (entry.minPorts > openPorts && entry.minPorts <= Object.keys(cracks).length)) { for (let k = 0; k < entry.minPorts; k++) { cracks[Object.keys(cracks)[k]](entry.serverName); entry.openPorts = k; } cracked = true; } if (!ns.hasRootAccess(entry.serverName) && cracked === true) { ns.nuke(entry.serverName); if (ns.hasRootAccess(entry.serverName)) { entry.rootAccess = true; } } return entry }) ns.write("serverList.txt", JSON.stringify(newServerList), "w"); ns.tprint("Cracking and rooting done"); } /** @param {NS} ns */ export function copyAndRunScript(ns, funnyScript, currentServer) { let bestTarget = JSON.parse(ns.read("bestTarget.txt")); let serverList = JSON.parse(ns.read("serverList.txt")); let bestEntry = serverList.find((entry) => entry.serverName === bestTarget.serverName) let currentEntry = serverList.find((entry) => entry.serverName === currentServer) if (currentEntry.rootAccess === true && bestEntry.rootAccess === true) { if (currentEntry.serverName !== "home") { ns.print("killed threads on: " + currentEntry.serverName + ns.killall(currentEntry.serverName, true)); } else { ns.print("killed threads on: " + currentEntry.serverName + ns.scriptKill(funnyScript[0], currentEntry.serverName)); }; if (currentEntry.maxRam > 0) { ns.scp(funnyScript, currentEntry.serverName, "home"); let maxProcesses = 1; if (currentEntry.maxRam >= 8) { maxProcesses = Math.max(Math.floor((currentEntry.maxRam) / 8), 1); } else { maxProcesses = 1 }; for (let n = 1; n <= maxProcesses; n++) { ns.exec(funnyScript[0], currentEntry.serverName, 1, bestTarget.serverName); } } } } /** @param {NS} ns */ export async function purchaseAndUpgradeServers(ns) { ns.disableLog("sleep"); ns.disableLog("getServerMoneyAvailable"); ns.disableLog("getServerMaxRam"); let maxPurchasedServers = ns.getPurchasedServerLimit(); let purchasedServers = []; let pServcount = listPurchasedServers(ns).length; let currentMoney = 0; let serverList = []; while (pServcount < maxPurchasedServers) { purchasedServers = listPurchasedServers(ns); currentMoney = ns.getServerMoneyAvailable("home"); let targetRamInitial = 16; if (ns.getPurchasedServerCost(targetRamInitial) < currentMoney) { let sFrontZero = "0"; if (pServcount > 9) { sFrontZero = ""; } let hostname = ns.purchaseServer("pserv-" + sFrontZero + pServcount, targetRamInitial); ns.tprint("Purchased " + cCyan + hostname + cReset); ns.toast("Purchased " + hostname, "info", 10000); pServcount = listPurchasedServers(ns).length; serverList = JSON.parse(ns.read("serverList.txt")); serverList.push({ serverName: hostname, maxRam: 16, maxMoney: 0, minSec: 0, minPorts: 5, minHackLvl: 1, rootAccess: true, openPorts: 0, }); ns.write("serverList.txt", JSON.stringify(serverList), "w"); continue } else { await ns.sleep(5000); } } let i = 5; while (i < 21) { let targetRam = 2 ** i; purchasedServers = listPurchasedServers(ns); for (let currentServer of purchasedServers) { currentMoney = ns.getServerMoneyAvailable("home"); if (ns.getServerMaxRam(currentServer) < targetRam) { if (ns.getPurchasedServerUpgradeCost(currentServer, targetRam) < currentMoney) { if (ns.upgradePurchasedServer(currentServer, targetRam)) { ns.print(currentServer + " upgraded to " + targetRam + " GB RAM"); serverList = JSON.parse(ns.read("serverList.txt")); let newServerList = serverList.map((entry) => { if (entry.serverName === currentServer) { entry.maxRam = targetRam } return entry }); ns.write("serverList.txt", JSON.stringify(newServerList), "w"); ns.tprint(cCyan + "Server: " + currentServer + " upgraded to: " + targetRam.toLocaleString() + " GB" + cReset); ns.toast("Server: " + currentServer + " upgraded to: " + targetRam.toLocaleString() + " GB", "info", 10000); } } else { await ns.sleep(5000); continue } }; } ++i; } ns.tprint("Extiting purchaseServers script!") } /** @param {NS} ns */ export function listPurchasedServers(ns) { return ns.getPurchasedServers(); } /** @param {NS} ns */ export function getSetting(ns, sSetting) { let oSettings = JSON.parse(ns.read("settings.txt")); let settingEntry = oSettings.setting[sSetting]; //ns.tprint(oSettings.setting[sSetting]) //ns.tprint("settingEntry = "+settingEntry); return settingEntry; } /** @param {NS} ns */ export function getGrowThreads(ns, sTarget, nHackThreads, nCores) { let nHackAmountPercent = ns.hackAnalyze(sTarget) * nHackThreads; let nGrowthThreads = ns.growthAnalyze(sTarget, 1 + nHackAmountPercent, nCores); return nGrowthThreads; } /** @param {NS} ns */ export async function ExecuteAndWait(ns, sScript, ...args) { if (!ns.isRunning(sScript, ...args)) { ns.exec(sScript, ...args); } while (ns.isRunning(sScript, ...args)) { await ns.sleep(100); } } /** @param {NS} ns */ export async function RunAndWait(ns, sScript, ...args) { if (!ns.isRunning(sScript, ...args)) { ns.run(sScript, ...args); } while (ns.isRunning(sScript, ...args)) { await ns.sleep(100); } } /** @param {NS} ns */ export function listWorkServers(ns) { ns.disableLog("ALL"); const sFileName = "serverList.txt"; if (!ns.fileExists(sFileName, "home")) { ns.print(`ERROR ${sFileName} does not exist.`); return false; }; let serverList = JSON.parse(ns.read(sFileName)); let sortedList = sortJsonArrayByKey(serverList, "serverCores", "maxRam").reverse(); let nTotalWorkerRAM = 0; let nTotalFreeRAM = 0; const nServerColumnWidth = 20; const nValueColumnWidth = 10; const nCoresWidth = 5; ns.printRaw("┏━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┓"); ns.printRaw("┃ Server ┃ Free / Max RAM ┃ Cores ┃"); ns.printRaw("┣━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━┫"); sortedList.forEach((entry) => { if (entry.rootAccess && entry.maxRam >= 1) { let sServerName = entry.serverName.padEnd(nServerColumnWidth, ' '); let nFreeRAM = entry.maxRam - ns.getServerUsedRam(entry.serverName); let sFreeRAM = ns.formatRam(nFreeRAM).padStart(nValueColumnWidth, ' '); let sMaxRam = ns.formatRam(entry.maxRam).padStart(nValueColumnWidth, ' '); let sCores = entry.serverCores.toLocaleString("en-US").padStart(nCoresWidth, ' '); ns.printRaw(`┃ ${sServerName} ┃ ${sFreeRAM} / ${sMaxRam} ┃ ${sCores} ┃`); nTotalWorkerRAM += entry.maxRam; nTotalFreeRAM += nFreeRAM; } }); ns.printRaw("┗━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━┛"); ns.printRaw(`Total Free: ${Math.floor(nTotalFreeRAM).toLocaleString("en-US")} / ${nTotalWorkerRAM.toLocaleString("en-US")} GB`); } export function sortJsonArrayByKey(array, primaryKey, secondaryKey) { if (typeof (array) === "string") { array = JSON.parse(array); } return array.sort((a, b) => { const xPrimary = a[primaryKey]; const yPrimary = b[primaryKey]; // Handle null or undefined values for primary key if (xPrimary === null || yPrimary === null || xPrimary === undefined || yPrimary === undefined) { return 0; } // Compare primary keys const primaryComparison = compareValues(xPrimary, yPrimary); if (primaryComparison !== 0) { return primaryComparison; } // If primary keys are equal, compare secondary keys const xSecondary = a[secondaryKey]; const ySecondary = b[secondaryKey]; // Handle null or undefined values for secondary key if (xSecondary === null || ySecondary === null || xSecondary === undefined || ySecondary === undefined) { return 0; } return compareValues(xSecondary, ySecondary); }); function compareValues(x, y) { // Handle numeric and string comparisons differently if (typeof x === 'string' && typeof y === 'string') { return x.localeCompare(y); // For string comparison } else { return x - y; // For numeric comparison } } } /** @param {NS} ns */ export async function distributeScript(ns, sScript, nThreads, [...args]) { //ns.tail(); ns.disableLog("ALL"); const sListName = "serverList.txt"; if (!ns.fileExists(sListName, "home")) { ns.print(`ERROR ${sListName} does not exist.`); return false; }; let sServerList = ns.read(sListName); let aSortedList = sortJsonArrayByKey(sServerList, "serverCores", "maxRam").reverse(); ns.print(sScript); ns.print(nThreads); ns.print(...args); const nScriptSize = ns.getScriptRam(sScript, "home"); let nTotalSize = nScriptSize * nThreads; ns.print("nScriptSize = " + nScriptSize); ns.print("nTotalSize = " + nTotalSize); aSortedList.forEach((entry) => { let sHost = entry.serverName; ns.print("sHost = " + sHost) let nFreeRAM = ns.getServerMaxRam(entry.serverName) - ns.getServerUsedRam(entry.serverName); if (nThreads >= 1 && entry.rootAccess && nFreeRAM >= nTotalSize) { ns.scp(sScript, sHost); ns.exec(sScript, sHost, nThreads, ...args); nThreads = 0; nFreeRAM = ns.getServerMaxRam(entry.serverName) - ns.getServerUsedRam(entry.serverName); } else if (nThreads >= 1 && entry.rootAccess && nFreeRAM >= nScriptSize) { let nThreadsDist = Math.floor(nFreeRAM / nScriptSize); ns.scp(sScript, sHost); ns.print("room for : " + nThreadsDist + " scripts"); ns.exec(sScript, sHost, nThreadsDist, ...args); nThreads -= nThreadsDist; nFreeRAM = ns.getServerMaxRam(entry.serverName) - ns.getServerUsedRam(entry.serverName); } }); }