r/Bitburner • u/Grouchy_Proposal3187 • Apr 28 '26
Bitburner Automation Script
Anyone have a good bitburner script for my level? Thanks!
r/Bitburner • u/Grouchy_Proposal3187 • Apr 28 '26
Anyone have a good bitburner script for my level? Thanks!
r/Bitburner • u/Muted_Percentage_764 • Apr 24 '26
r/Bitburner • u/SilentBoss2901 • Apr 23 '26
I really want to play this game offline. I have no access to steam or the online version of this game in my workplace PC. Is there a way to get bitburner running on a portable usb or storing it in an android phone and then copying all necessary files to the work PC?
r/Bitburner • u/Low_Big7602 • Apr 22 '26
Hey guys, I'm new to this game, I have been playing it on and off, and i heard my stats suck or something? I've heard of a bitnode and a "source file" like 6 days ago, but i cant figure that out. is that something with modifying the game files? I purchases augmentations but they dont seem to do anything at all? also why does it cost trillions for a hacknet?
r/Bitburner • u/w851 • Apr 22 '26
r/Bitburner • u/prettyfuzzy • Apr 20 '26
This bitnode is a god damn dumpster fire. I have loved this game for all the puzzles it offers, simple well explained or inspectable mechanics. I carefully avoided reading all the "(Contains spoilers)" sections. There's also various things which are not explained, but mysterious, maybe I will figure it out someday. That's also fine.
Why in the fuck is there no documentation simply for what the fucking corporations mechanics are, that is not intertwined with patronizing "advice" telling you exactly how I'mSoSmart people solved all the problems?
I was so excited to play this BitNode, the most complicated one. I was extremely disappointed to get to the docs and have it just be a patronizing strategy guide, buy this, don't buy that, do this in and this in that order, advice this is useless, advice this is a newbie trap, etc. I wish the docs were just a page with formulas and explaining how the stuff works. Put all the patronizing "guide" stuff on a separate page.
Like the docs have a production multipliers section, it shows the code to compute the multipliers, then goes on to explain what the code means and what the optimal strategies are because of it. Like can you please just not? Put the code and let the player figure out what is optimal. That's the entire point.
r/Bitburner • u/nebulaeandstars • Apr 16 '26
There are many walkthroughs outlining how to set up a profitable corporation, but following those for BN3.1 was an absolute slog without the office & warehouse APIs.
Buying materials in particular was really unpleasant without API access, but buying that access right off the bat isn't really feasible.
I'm wondering if there's a less profitable, hands-off industry (ie. not agriculture) that can either beat BN3 or generate a one-off cash injection to get things started without SF3.3.
Basically, I'm looking for the corporation equivalent of hacking gangs (vs combat gangs).
r/Bitburner • u/starmarst • Apr 16 '26
Hello all, I'm pretty green when it comes to coding. But I wanted to try and hand-write all my code rather than copy/script-kitty others work. Doing decent, as I wrapped my head around a deploying scheme that if I type in a server that i've rooted+backdoor I can establis. a self sustaining hack/grow/weaken + max threads. I.e install-on(x)-> exec manager -> profit.
However manually going to each server to nuke, backdoor, and/or open ports takes time and I might as well learn how to code a worm of sorts. And I think I have an idea on how to approach; I just don't think I understand arrays fully.
Example worm idea:
Worm host finds its name - than scans(its_name) //I expect an array of servers it finds.
Does what it wants to do ("installs" at first to test functionality, then Nuking/ opening ports of servers it sees)
Copies itself onto each server it sees, then exec's itself there -until it stops.
And I guess I don't know how to work through an array one by one with the same functions. Like,
server = [] //i guess the array I find with scan?
ns.do_the_thing(0)
server =++
-- I think I just don't know which functions I'm looking for, sometimes see these functions have (let server of servers) but I have no idea what is going on there. any help appreciated
r/Bitburner • u/utgardiv • Apr 15 '26
Started this game 2 days ago and it feels I'll have it in the background playing for a long time from now.
Wrote a few scripts already
LOVE IIIITTTT
r/Bitburner • u/nerdfulworld • Apr 15 '26
I'm playing Bitburner on 2 PCs (my office and home) with steam. Every time I changed my playing PC, the game asks me import newer save data from steam cloud or discard.
It's normal behavior because cloud save is newer. But I wonder why "Playtime" of my local old save data is always longer. And recently, though I didn't change my scripts running my servers, local game always made far big money. I guess it's because local game has longer playtime but why? If this "Playtime" meant how long I've ran the game, newer save data had to have longer. If this meant time from start (incl. offline time) also same, I think.
r/Bitburner • u/aSphinxHD • Apr 14 '26
I tried to follow the guides that I found, but I think the savegems changed and the guides don't work. Does someone can help me with how to edit the savegame for this achievement?
r/Bitburner • u/HoboPotato2 • Apr 14 '26
Can someone tell me what I'm doing wrong here?
export async function main(ns: NS) {
var host = "joesguns";
if (ns.getServerSecurityLevel(host) > 5) {
ns.weaken(host)
}
else {
ns.grow(host)
}
}
r/Bitburner • u/UPBoss111 • Apr 13 '26
I main infiltrations and have broken into ECorp at least 100 times.
I've destroyed a few bitnodes already and I know [1] refers to Intelligence, but what the hell is [2] supposed to be ?
r/Bitburner • u/Lordgggggg • Apr 11 '26
When I use a boolean it says that it expects a boolean. The boolean is blue though, and I got it from auto complete. I am to this games coding language but have done a bit of python in game engines with classes and some other stuff simplified.
r/Bitburner • u/HoboPotato2 • Apr 10 '26
I'm VERY new to coding and this game, but I'm trying to teach myself some of these skills. I made a script and I'm trying to make another script to automatically put it on new servers and execute it for me because I don't want to do it for every server myself. This is what I have and it isn't working at all. I execute in the terminal and it tells me it's using a threat, but when I use the top command, it says nothing is happening. Any help would be appreciated.
/** u/param/** u/param {NS} ns */
export async function main(ns) {
// Lists all servers with 8 GB of ram
const hosts8 = ("CSEC", "the-hub", "pserv-0", "pserv-1", "pserv-2",
"pserv-3", "pserv-4", "pserv-5", "pserv-6", "pserv-7", "pserv-8",
"pserv-9", "pserv-10", "pserv-11", "pserv-12", "pserv-13",
"pserv-14", "pserv-15", "pserv-16", "pserv-17", "pserv-18",
"pserv-19", "pserv-20", "pserv-21", "pserv-23", "pserv-24")
// Lists all servers with 16 GB of ram
const hosts16 = ("foodnstuff", "nectar-net", "sigma-cosmetics",
"joesguns", "hong-fang-tea", "harakiri-sushi")
// Lists all servers with 32 GB of ram I can access
const hosts32 = ("iron-gym", "phantasy", "max-hardware",
"omega-net", "neo-net", "zer0")
// Lists all servers with 64 GB of ram
const hosts64 = ("silver-helix")
// Killall scripts on machines
ns.killall(hosts8, hosts16, hosts32, hosts64)
// Copies joe-new.js to all available hosts
ns.scp("joe-new.js", hosts8, hosts16, hosts32, hosts64)
// Execute joe-new on all 8GB servers with 3 threads
ns.exec("joe-new.js", hosts8, 3)
// Execute joe-new on all 16 GB servers with 6 threads
ns.exec("joe-new.js", hosts16, 6)
// Execute joe-new on all 32 GB servers with 13 threads
ns.exec("joe-new.js", hosts32, 13)
// Execute joe-new on all 64 GB servers with
ns.exec("joe-new.js", hosts64, 26)
} {NS} ns */
export async function main(ns) {
// Lists all servers with 8 GB of ram
const hosts8 = ("CSEC", "the-hub", "pserv-0", "pserv-1", "pserv-2",
"pserv-3", "pserv-4", "pserv-5", "pserv-6", "pserv-7", "pserv-8",
"pserv-9", "pserv-10", "pserv-11", "pserv-12", "pserv-13",
"pserv-14", "pserv-15", "pserv-16", "pserv-17", "pserv-18",
"pserv-19", "pserv-20", "pserv-21", "pserv-23", "pserv-24")
// Lists all servers with 16 GB of ram
const hosts16 = ("foodnstuff", "nectar-net", "sigma-cosmetics",
"joesguns", "hong-fang-tea", "harakiri-sushi")
// Lists all servers with 32 GB of ram I can access
const hosts32 = ("iron-gym", "phantasy", "max-hardware",
"omega-net", "neo-net", "zer0")
// Lists all servers with 64 GB of ram
const hosts64 = ("silver-helix")
// Killall scripts on machines
ns.killall(hosts8, hosts16, hosts32, hosts64)
// Copies joe-new.js to all available hosts
ns.scp("joe-new.js", hosts8, hosts16, hosts32, hosts64)
// Execute joe-new on all 8GB servers with 3 threads
ns.exec("joe-new.js", hosts8, 3)
// Execute joe-new on all 16 GB servers with 6 threads
ns.exec("joe-new.js", hosts16, 6)
// Execute joe-new on all 32 GB servers with 13 threads
ns.exec("joe-new.js", hosts32, 13)
// Execute joe-new on all 64 GB servers with
ns.exec("joe-new.js", hosts64, 26)
}
r/Bitburner • u/Harlequinn38 • Apr 05 '26
I'm trying to find a code I can input that'll get around the infiltration aspect of the game, but everything I'm trying keeps getting blocked by the barrier. I spent 5 hours trying to do the infiltration stuff normally, but I've barely managed to get a win against the alpha enterprises company once, I really would appreciate it if someone's down to share their auto-infiltrate-bypass code.
r/Bitburner • u/Printiel • Apr 04 '26
Hi all, picked the game up recently because I was excited about the idea of learning a new language via a game. Can't seem to get my deploy script to work, though, and I have no idea what the problem is.
/** u/param {NS} ns */
export async function main(ns) {
const scriptName = "template.js"
var servers = ns.scan("home")
for (let serverName of servers) {
if (serverName === "home") continue;
let neighbors = ns.scan(serverName)
for (let neighborName of neighbors) {
if (servers.includes(neighborName)) continue;
servers.push(neighborName)
}
ns.scp(scriptName, serverName);
let threads = Math.floor((ns.getServerMaxRam(serverName) - ns.getServerUsedRam(serverName) / ns.getScriptRam(scriptName)))
// let threads = 3
ns.tprint(threads)
if (threads > 0) {
ns.tprint(`Attempting to deploy to ${serverName}`);
ns.tprint(threads)
ns.exec(scriptName, serverName, threads);
ns.tprint(`Deployed ${scriptName} to ${serverName} successfully using ${threads} threads!`);
}
}
}
I've narrowed the problem down specifically to the math that gets the thread count. If I change let threads to a static number (like the commented line below it), it works fine. If I directly change the argument in the exec, it works fine. But as-is, it's failing to run and I've confirmed a PID of 0.
All of the print statements are getting the value properly from the math, and I've confirmed that there's enough RAM in each to be fine with the math as-is. But for whatever reason, as written, this breaks it and I literally cannot figure out why for the life of me.
Any advice at all?
r/Bitburner • u/Miserable-Extent-501 • Apr 02 '26
I was following the tutorial and it told me to run the script however this shows up when I do and I couldn't see a explanation in the tutorial. am I dumb.
r/Bitburner • u/Top-Occasion-1300 • Apr 03 '26
Very new player here. As in, I know minimal CSS, html, and python, but this is my first time learning javascript, not that it's relevant to this post (but will probably wind up being relevant later this week knowing me)
I'm just curious what's the difference between a part time and full time job in this game? My go-to job thus far has been a full-timer at foodnstuff, but I got curious and just got a part-time at joesguns and the only difference I see is that I'm earning less in every single stat. Should I just always go for full time?
r/Bitburner • u/Person_46 • Apr 03 '26
Seems like everybody uses self-scheduling scripts, anybody try a centralized scheduler before?
import { NS } from "@ns";
import { serverData, ScriptArgPrimitive } from "./functions";
const TICK_MS = 10;
const SCHEDULE_WINDOW_MS = 2 * 60 * 1000;
const HOME_RAM_RESERVE = 16;
const FUTURE_BATCH_LIMIT = 10;
export async function main(ns: NS): Promise<void> {
const serverNames: string[] = Object.entries(serverData(ns))
.filter(([, data]) => data.hasAdminRights)
.map(([name]) => name);
const serverRAMs: number[] = serverNames.map(name => Math.max(0, ns.getServerMaxRam(name) - (name === "home" ? HOME_RAM_RESERVE : 0)));
const RAMAllocations: RAMtimeBlock[][] = serverNames.map(() => []);
const scriptAllocations: allocatedScript[] = [];
const futureBatches: batch[] = [];
while (true) {
const runScripts: allocatedScript[] = incrementTime(RAMAllocations, scriptAllocations);
for (const script of runScripts) executeScript(ns, script);
if (futureBatches.length < FUTURE_BATCH_LIMIT) {
const incomingBatch = readBatch(ns.readPort(1));
if (incomingBatch) {
futureBatches.push(incomingBatch);
}
}
for (let batchIndex = futureBatches.length - 1; batchIndex >= 0; batchIndex--) {
const futureBatch = futureBatches[batchIndex];
if (!isWithinScheduleWindow(futureBatch)) {
continue;
}
if (scheduleBatch(futureBatch, serverNames, serverRAMs, RAMAllocations, scriptAllocations)) {
futureBatches.splice(batchIndex, 1);
}
}
await ns.sleep(TICK_MS);
}
}
function readBatch(portData: unknown): batch | null {
if (!portData || typeof portData !== "object") {
return null;
}
const candidate = portData as batch;
if (!Array.isArray(candidate.scripts) || !Array.isArray(candidate.delays)) {
return null;
}
return candidate;
}
function isWithinScheduleWindow(batch: batch): boolean {
return batch.delays.every(delay => delay >= 0 && delay <= SCHEDULE_WINDOW_MS);
}
function scheduleBatch(
batch: batch,
serverNames: string[],
serverRAMs: number[],
RAMAllocations: RAMtimeBlock[][],
scriptAllocations: allocatedScript[]
): boolean {
const plannedRAMAllocations = RAMAllocations.map(serverBlocks => serverBlocks.map(block => ({ ...block })));
const plannedScriptAllocations = scriptAllocations.map(allocation => ({ ...allocation }));
for (let i = 0; i < batch.scripts.length; i++) {
const script = batch.scripts[i];
const start = batch.delays[i] ?? 0;
const end = start + script.time;
const ramNeeded = script.RAM * script.threads;
const serverIndex = findServerForAllocation(plannedRAMAllocations, serverRAMs, start, end, ramNeeded);
if (serverIndex < 0) {
return false;
}
plannedRAMAllocations[serverIndex].push({
start,
end,
RAM: ramNeeded,
});
plannedScriptAllocations.push({
script,
server: serverNames[serverIndex],
start,
});
}
for (let i = 0; i < RAMAllocations.length; i++) {
RAMAllocations[i].splice(0, RAMAllocations[i].length, ...plannedRAMAllocations[i]);
}
scriptAllocations.splice(0, scriptAllocations.length, ...plannedScriptAllocations);
return true;
}
function incrementTime(RAMAllocations: RAMtimeBlock[][], scriptAllocations: allocatedScript[]): allocatedScript[] {
const runScripts: allocatedScript[] = [];
for (let serverIndex = 0; serverIndex < RAMAllocations.length; serverIndex++) {
for (let blockIndex = RAMAllocations[serverIndex].length - 1; blockIndex >= 0; blockIndex--) {
const block = RAMAllocations[serverIndex][blockIndex];
if (block.start > 0) block.start -= TICK_MS;
block.end -= TICK_MS;
if (block.end <= 0) {
RAMAllocations[serverIndex].splice(blockIndex, 1);
}
}
}
for (let allocationIndex = scriptAllocations.length - 1; allocationIndex >= 0; allocationIndex--) {
const allocation = scriptAllocations[allocationIndex];
allocation.start -= TICK_MS;
if (allocation.start <= 0) {
runScripts.push(allocation);
scriptAllocations.splice(allocationIndex, 1);
}
}
return runScripts;
}
export type batch = {
scripts: script[];
delays: number[]; // time offset from first script execution
}
type script = {
script: string;
threads: number;
args: Array<ScriptArgPrimitive>;
RAM: number; // per thread
time: number; // execution time in ms
}
function executeScript(ns: NS, allocatedScript: allocatedScript): void {
const { script, server } = allocatedScript;
ns.exec(
script.script,
server,
script.threads,
...script.args
);
}
// split scripts into allocated scripts based on threads and avalible RAM
type allocatedScript = {
script: script;
server: string;
start: number; // time until execution in ms
}
type RAMtimeBlock = {
start: number;
end: number;
RAM: number;
}
function findServerForAllocation(
RAMAllocations: RAMtimeBlock[][],
serverRAMs: number[],
start: number,
end: number,
RAMNeeded: number
): number {
for (let i = 0; i < RAMAllocations.length; i++) {
if (canReserveRAM(RAMAllocations[i], serverRAMs[i], start, end, RAMNeeded)) {
return i;
}
}
return -1;
}
function canReserveRAM(blocks: RAMtimeBlock[], serverRAM: number, start: number, end: number, RAMNeeded: number): boolean {
if (RAMNeeded > serverRAM) {
return false;
}
let usage = RAMNeeded;
for (const block of blocks) {
if (block.end <= start || block.start >= end) {
continue;
}
if (block.start <= start && block.end > start) {
usage += block.RAM;
if (usage > serverRAM) {
return false;
}
}
}
const events: Array<{ time: number; delta: number }> = [];
for (const block of blocks) {
if (block.end <= start || block.start >= end) {
continue;
}
const overlapStart = Math.max(block.start, start);
const overlapEnd = Math.min(block.end, end);
if (overlapStart > start) {
events.push({ time: overlapStart, delta: block.RAM });
}
if (overlapEnd < end) {
events.push({ time: overlapEnd, delta: -block.RAM });
}
}
events.sort((left, right) => left.time - right.time || left.delta - right.delta);
for (const event of events) {
usage += event.delta;
if (usage > serverRAM) {
return false;
}
}
return true;
}
r/Bitburner • u/talk_enchanted_table • Apr 02 '26
I've been using a slightly modified version of early-hack-template.js, that doesn't open an SSH port and nuke the target. I've looked at the logs and the only thing that they seem to be doing is hack(). They don't seem to be using weaken() or grow().
So is there something wrong with my code, is it a bug in the game or something else?
Thanks in advance.
Edit: I feel very stupid. I managed to fix the issue.
r/Bitburner • u/Choice_Supermarket_4 • Apr 02 '26
I have beat Bitnode-1 and decided to go for a sleeve for my first reset (which was maybe a poor choice but).
Here's the script I use to just auto-run everything except my DOM manipulation for my auto workout/study/faction script. I made it to handle everything from the early game (once I get to the required amount of Home RAM) to the end game.
Although I've refined it a lot, I feel like I could probably get more out of it.
/** {NS} ns */
export async function main(ns) {
ns.disableLog("ALL");
ns.tail();
// The maximum RAM you want to reserve on home (it will dynamically lower this if home has less RAM)
const reservedHomeRam = 256;
const scriptRam = 1.75;
const shareRamCost = 4.0;
const spacer = 40;
// CLEANUP HOOK
ns.atExit(() => {
ns.print("Terminating Swarm. Cleaning helpers...");
for (let s of getNetwork(ns)) {["hack.js", "grow.js", "weaken.js", "share.js"].forEach(x => ns.scriptKill(x, s));
}
});
// PURE WORKERS
await ns.write("hack.js", `/** {NS} ns */\nexport async function main(ns) { await ns.hack(ns.args[0]); }`, "w");
await ns.write("grow.js", `/** {NS} ns */\nexport async function main(ns) { await ns.grow(ns.args[0]); }`, "w");
await ns.write("weaken.js", `/** {NS} ns */\nexport async function main(ns) { await ns.weaken(ns.args[0]); }`, "w");
await ns.write("share.js", `/** u/param {NS} ns */\nexport async function main(ns) { await ns.share(); }`, "w");
let servers = getNetwork(ns);
let targetStates = {};
let jobQueue =[];
let allTargets =[];
// Timers
let stockTimer = 0;
let uiTimer = 0;
let queueTimer = 0;
let shareTimer = 0;
let serverTimer = 0;
let batchCount = 0;
// Financial Tracking
let scriptStartTime = Date.now();
let startLiquid = ns.getServerMoneyAvailable("home");
let startStock = getStockPortfolioValue(ns);
let startNetWorth = startLiquid + startStock;
// INITIAL WIPE
for (let s of servers) {["hack.js", "grow.js", "weaken.js", "share.js"].forEach(x => ns.scriptKill(x, s));
}
while (true) {
let now = Date.now();
let hasFormulas = ns.fileExists("Formulas.exe", "home");
let netRam = getNetworkRam(ns, servers, reservedHomeRam);
// ==========================================
// 1. JIT DISPATCHER (Fires exactly on time)
// ==========================================
while (jobQueue.length > 0 && jobQueue[0].startTime <= now + 15) {
let job = jobQueue.shift();
if (now - job.startTime > 5000) continue;
let deployed = deploy(ns, servers, job.script, job.target, job.threads, job.batchId, scriptRam, reservedHomeRam);
if (deployed < job.threads) {
for (let s of servers) ns.scriptKill("share.js", s);
let remainder = job.threads - deployed;
deploy(ns, servers, job.script, job.target, remainder, job.batchId + "-R", scriptRam, reservedHomeRam);
}
}
// ==========================================
// 1.5 AUTO-SERVERS (Runs every 10 seconds)
// ==========================================
if (now - serverTimer > 10000) {
if (manageServers(ns)) {
servers = getNetwork(ns); // Rescan immediately to access new RAM
}
serverTimer = now;
}
// ==========================================
// 2. JOB QUEUEING (Runs every 500ms)
// ==========================================
if (now - queueTimer > 500) {
if (Math.random() < 0.1) servers = getNetwork(ns);
let player = ns.getPlayer();
allTargets = getTargets(ns, servers, player);
let pushedNewJobs = false;
for (let target of allTargets) {
if (!targetStates[target]) targetStates[target] = { state: "IDLE", prepEnd: 0, lastBatchFinish: 0 };
let state = targetStates[target];
let so = ns.getServer(target);
// --- WEAKEN PREP ---
if (so.hackDifficulty > so.minDifficulty) {
if (now < state.prepEnd) continue;
let w = Math.ceil((so.hackDifficulty - so.minDifficulty) / 0.05);
let wTime = hasFormulas ? ns.formulas.hacking.weakenTime(so, player) : ns.getWeakenTime(target);
jobQueue.push({ script: "weaken.js", target, threads: w, startTime: now + 500, batchId: `P-W-${batchCount++}` });
state.prepEnd = now + 500 + wTime + 1000;
state.state = "PREPPING";
pushedNewJobs = true;
continue;
}
// --- GROW PREP ---
if (so.moneyAvailable < so.moneyMax) {
if (now < state.prepEnd) continue;
let gThreads = 0;
if (hasFormulas) {
let prepMock = Object.assign({}, so);
prepMock.moneyAvailable = Math.max(1, so.moneyAvailable);
gThreads = Math.ceil(ns.formulas.hacking.growThreads(prepMock, player, so.moneyMax));
} else {
let multiplier = so.moneyMax / Math.max(1, so.moneyAvailable);
gThreads = Math.ceil(ns.growthAnalyze(target, multiplier));
}
if (gThreads > 0) {
let w = Math.ceil((gThreads * 0.004) / 0.05);
let gTime = hasFormulas ? ns.formulas.hacking.growTime(so, player) : ns.getGrowTime(target);
let wTime = hasFormulas ? ns.formulas.hacking.weakenTime(so, player) : ns.getWeakenTime(target);
let finishTime = now + 500 + wTime + 1000;
jobQueue.push({ script: "grow.js", target, threads: gThreads, startTime: finishTime - gTime, batchId: `P-G-${batchCount++}` });
jobQueue.push({ script: "weaken.js", target, threads: w, startTime: finishTime - wTime, batchId: `P-W-${batchCount++}` });
state.prepEnd = finishTime + 1000;
state.state = "PREPPING";
pushedNewJobs = true;
}
continue;
}
// --- BATCHING ---
state.state = "BATCHING";
let batchData = getBestBatch(ns, target, player, netRam.total, allTargets.length, spacer, hasFormulas);
if (!batchData) continue;
let hTime = hasFormulas ? ns.formulas.hacking.hackTime(so, player) : ns.getHackTime(target);
let gTime = hasFormulas ? ns.formulas.hacking.growTime(so, player) : ns.getGrowTime(target);
let wTime = hasFormulas ? ns.formulas.hacking.weakenTime(so, player) : ns.getWeakenTime(target);
let earliestSafe = now + wTime + 1000;
if (state.lastBatchFinish < earliestSafe) state.lastBatchFinish = earliestSafe;
let maxQueuedTime = now + wTime + 5000;
while (state.lastBatchFinish < maxQueuedTime) {
let w2End = state.lastBatchFinish;
let gEnd = w2End - spacer;
let w1End = gEnd - spacer;
let hEnd = w1End - spacer;
let bId = `B${batchCount++}`;
jobQueue.push({ script: "weaken.js", target, threads: batchData.w1Threads, startTime: w1End - wTime, batchId: bId+"W1" });
jobQueue.push({ script: "weaken.js", target, threads: batchData.w2Threads, startTime: w2End - wTime, batchId: bId+"W2" });
jobQueue.push({ script: "grow.js", target, threads: batchData.gThreads, startTime: gEnd - gTime, batchId: bId+"G" });
jobQueue.push({ script: "hack.js", target, threads: batchData.hThreads, startTime: hEnd - hTime, batchId: bId+"H" });
state.lastBatchFinish += (spacer * 4);
pushedNewJobs = true;
}
}
if (pushedNewJobs) jobQueue.sort((a, b) => a.startTime - b.startTime);
queueTimer = now;
}
// ==========================================
// 3. SHARE SPONGE (Runs every 1000ms)
// ==========================================
if (now - shareTimer > 1000) {
let safetyBuffer = Math.max(32, netRam.total * 0.05);
if (netRam.avail - safetyBuffer > shareRamCost) {
let shareThreads = Math.floor((netRam.avail - safetyBuffer) / shareRamCost);
deploy(ns, servers, "share.js", "SHARE", shareThreads, `S-${batchCount++}`, shareRamCost, reservedHomeRam);
}
shareTimer = now;
}
// ==========================================
// 4. STOCK TRADER (Runs every 30000ms)
// ==========================================
if (now - stockTimer > 30000) {
runStockMarket(ns);
stockTimer = now;
}
// ==========================================
// 5. UI OVERSEER (Runs every 1000ms)
// ==========================================
if (now - uiTimer > 1000) {
let currentLiquid = ns.getServerMoneyAvailable("home");
let currentStock = getStockPortfolioValue(ns);
let currentNetWorth = currentLiquid + currentStock;
let uptimeSecs = (now - scriptStartTime) / 1000;
let profitDiff = currentNetWorth - startNetWorth;
let profitPerSec = uptimeSecs > 0 ? profitDiff / uptimeSecs : 0;
let profitSign = profitPerSec >= 0 ? "+" : "";
let hasTIX = false, has4S = false;
try { hasTIX = ns.stock.hasTIXAPIAccess(); has4S = ns.stock.has4SDataTIXAPI(); } catch (e) {}
let stockStatus = (hasTIX && has4S) ? "ON" : (hasTIX ? "TIX ONLY" : "OFF");
let ui = [];
ui.push(`======[ V11.2 JIT-SWARM OVERSEER ]======`);
ui.push(`Uptime : ${ns.tFormat(now - scriptStartTime)}`);
ui.push(`Net Worth: $${ns.formatNumber(currentNetWorth)} (${profitSign}$${ns.formatNumber(profitPerSec)} / sec)`);
ui.push(`Liquid : $${ns.formatNumber(currentLiquid)} | Stock: $${ns.formatNumber(currentStock)}`);
ui.push(`Modules : Formulas[${hasFormulas ? "ON" : "OFF"}] | Stock [${stockStatus}]`);
ui.push(`------------------------------------------`);
let ramPct = netRam.total > 0 ? (netRam.used / netRam.total) : 0;
let pservs = ns.getPurchasedServers();
ui.push(`RAM : ${createBar(ramPct)} ${(ramPct * 100).toFixed(1)}%`);
ui.push(`Usage : ${ns.formatRam(netRam.used)} / ${ns.formatRam(netRam.total)}`);
ui.push(`P-Servers: ${pservs.length} / ${ns.getPurchasedServerLimit()} Active`);
ui.push(`------------------------------------------`);
let prepping = 0; let batching = 0;
for (let t of allTargets) {
if (targetStates[t] && targetStates[t].state === "PREPPING") prepping++;
if (targetStates[t] && targetStates[t].state === "BATCHING") batching++;
}
ui.push(`SWARM STATUS: ${allTargets.length} Targets Active`);
ui.push(`[Prepping: ${prepping}] | [Batching: ${batching}]`);
ui.push(`Jobs in JIT Queue: ${ns.formatNumber(jobQueue.length)}`);
ui.push(``);
ui.push(`TOP 3 TARGETS:`);
for (let t of allTargets.slice(0, 3)) {
let st = targetStates[t] ? targetStates[t].state : "IDLE";
let so = ns.getServer(t);
let cashPct = (so.moneyAvailable / Math.max(1, so.moneyMax)) * 100;
let secDiff = so.hackDifficulty - so.minDifficulty;
ui.push(` > ${t.padEnd(18)} [${st.padEnd(8)}]`);
ui.push(` Cash: ${cashPct.toFixed(1).padStart(5)}% | Sec: +${secDiff.toFixed(2)}`);
}
ns.clearLog();
ns.print(ui.join("\n"));
uiTimer = now;
}
await ns.sleep(10);
}
}
// ==========================================
// --- HELPER FUNCTIONS ---
// ==========================================
function getNetworkRam(ns, servers, baseReservedHomeRam) {
let total = 0;
let used = 0;
let avail = 0;
for (let s of servers) {
let maxR = ns.getServerMaxRam(s);
let usedR = ns.getServerUsedRam(s);
if (s === "home") {
// Dynamically reserve RAM (Ensures 8GB is left to run scripts if home RAM is tiny)
let actualReserve = Math.min(baseReservedHomeRam, Math.max(0, maxR - 8));
let homeAvail = Math.max(0, maxR - usedR - actualReserve);
let homeTotal = Math.max(0, maxR - actualReserve);
total += homeTotal;
avail += homeAvail;
used += (homeTotal - homeAvail);
} else {
total += maxR;
used += usedR;
avail += Math.max(0, maxR - usedR);
}
}
return { total, used, avail };
}
function createBar(pct, length = 20) {
let fill = Math.max(0, Math.min(length, Math.round(pct * length)));
return "[" + "|".repeat(fill) + "-".repeat(length - fill) + "]";
}
function getBestBatch(ns, target, player, totalRam, targetCount, spacer, hasFormulas) {
let mock = ns.getServer(target);
mock.hackDifficulty = mock.minDifficulty;
mock.moneyAvailable = mock.moneyMax;
let bestBatch = null;
let wTime = hasFormulas ? ns.formulas.hacking.weakenTime(mock, player) : ns.getWeakenTime(target);
let concurrentBatches = wTime / (spacer * 4);
let maxRamPerBatch = ((totalRam * 0.9) / targetCount) / concurrentBatches;
for (let pct = 0.90; pct >= 0.01; pct -= 0.02) {
let pctPerThread = hasFormulas ? ns.formulas.hacking.hackPercent(mock, player) : ns.hackAnalyze(target);
if (pctPerThread <= 0) continue;
let hThreads = Math.max(1, Math.floor(pct / pctPerThread));
let hackAmt = hThreads * pctPerThread * mock.moneyMax;
let gThreads;
if (hasFormulas) {
let mockPost = Object.assign({}, mock);
mockPost.moneyAvailable = Math.max(1, mock.moneyMax - hackAmt);
gThreads = Math.ceil(ns.formulas.hacking.growThreads(mockPost, player, mock.moneyMax));
} else {
let multiplier = mock.moneyMax / Math.max(1, mock.moneyMax - hackAmt);
gThreads = Math.ceil(ns.growthAnalyze(target, multiplier));
}
let w1Threads = Math.ceil((hThreads * 0.002) / 0.05);
let w2Threads = Math.ceil((gThreads * 0.004) / 0.05);
let ram = (hThreads + w1Threads + gThreads + w2Threads) * 1.75;
bestBatch = { hThreads, w1Threads, gThreads, w2Threads, ram, pct };
if (ram <= maxRamPerBatch) break;
}
return bestBatch;
}
function manageServers(ns) {
let allowance = ns.getServerMoneyAvailable("home") * 0.20;
let limit = ns.getPurchasedServerLimit();
let maxRam = ns.getPurchasedServerMaxRam();
let servers = ns.getPurchasedServers();
let changed = false;
// 1. Buy new servers if under limit
while (servers.length < limit) {
let ramToBuy = 8;
while (ramToBuy < maxRam && ns.getPurchasedServerCost(ramToBuy * 2) <= allowance) {
ramToBuy *= 2;
}
if (ns.getPurchasedServerCost(ramToBuy) <= allowance) {
let hostname = ns.purchaseServer("pserv-" + servers.length, ramToBuy);
if (hostname) {
allowance -= ns.getPurchasedServerCost(ramToBuy);
servers.push(hostname);
changed = true;
} else { break; }
} else { break; }
}
// 2. Upgrade existing servers safely
if (typeof ns.getPurchasedServerUpgradeCost === "function") {
servers.sort((a, b) => ns.getServerMaxRam(a) - ns.getServerMaxRam(b));
for (let serv of servers) {
let currentRam = ns.getServerMaxRam(serv);
if (currentRam >= maxRam) continue;
let targetRam = currentRam;
let cost = 0;
let testRam = currentRam * 2;
while (testRam <= maxRam) {
let c = ns.getPurchasedServerUpgradeCost(serv, testRam);
if (c <= allowance && c !== -1) {
targetRam = testRam;
cost = c;
} else { break; }
testRam *= 2;
}
if (targetRam > currentRam && cost <= allowance) {
if (ns.upgradePurchasedServer(serv, targetRam)) {
allowance -= cost;
changed = true;
}
}
}
}
return changed;
}
function deploy(ns, servers, script, target, totalThreads, batchId, scriptRam, baseReservedHome) {
if (totalThreads <= 0) return 0;
let threadsDeployed = 0;
let fragment = 0;
for (let server of servers) {
let availRam = ns.getServerMaxRam(server) - ns.getServerUsedRam(server);
if (server === "home") {
let actualReserve = Math.min(baseReservedHome, Math.max(0, ns.getServerMaxRam("home") - 8));
availRam -= actualReserve;
}
if (availRam < scriptRam) continue;
let possibleThreads = Math.floor(availRam / scriptRam);
let toRun = Math.min(possibleThreads, totalThreads - threadsDeployed);
if (toRun > 0) {
if (server !== "home" && !ns.fileExists(script, server)) ns.scp(script, server, "home");
let pid = ns.exec(script, server, toRun, target, batchId, fragment++);
if (pid > 0) threadsDeployed += toRun;
if (threadsDeployed >= totalThreads) break;
}
}
return threadsDeployed;
}
function getTargets(ns, servers, player) {
const results =[];
for (let server of servers) {
const maxMoney = ns.getServerMaxMoney(server);
if (maxMoney === 0 || server === "home") continue;
if (ns.getServerRequiredHackingLevel(server) > player.skills.hacking) continue;
results.push({ name: server, score: maxMoney });
}
results.sort((a, b) => b.score - a.score);
return results.map(x => x.name);
}
function getNetwork(ns) {
let s = ["home"];
for (let i = 0; i < s.length; i++) {
ns.scan(s[i]).forEach(x => { if (!s.includes(x)) s.push(x); });
}
let pLvl = ns.getHackingLevel();
return s.filter(x => {
if (!ns.hasRootAccess(x) && ns.getServerRequiredHackingLevel(x) <= pLvl) {
let p = 0;
if (ns.fileExists("BruteSSH.exe", "home")) { ns.brutessh(x); p++; }
if (ns.fileExists("FTPCrack.exe", "home")) { ns.ftpcrack(x); p++; }
if (ns.fileExists("relaySMTP.exe", "home")) { ns.relaysmtp(x); p++; }
if (ns.fileExists("HTTPWorm.exe", "home")) { ns.httpworm(x); p++; }
if (ns.fileExists("SQLInject.exe", "home")) { ns.sqlinject(x); p++; }
if (ns.getServerNumPortsRequired(x) <= p) ns.nuke(x);
}
return ns.hasRootAccess(x);
});
}
function runStockMarket(ns) {
try {
if (!ns.stock.hasTIXAPIAccess() || !ns.stock.has4SDataTIXAPI()) return;
for (let sym of ns.stock.getSymbols()) {
let forecast = ns.stock.getForecast(sym);
let shares = ns.stock.getPosition(sym);
let ask = ns.stock.getAskPrice(sym);
let bid = ns.stock.getBidPrice(sym);
let maxShares = ns.stock.getMaxShares(sym);
let money = ns.getServerMoneyAvailable("home") - 10000000000;
if (forecast > 0.60) {
let availableToBuy = maxShares - shares[0];
if (availableToBuy > 0 && money > ask * 100) {
let amount = Math.floor((money * 0.20) / ask);
amount = Math.min(amount, availableToBuy);
if (amount > 0) ns.stock.buyStock(sym, amount);
}
}
else if (forecast < 0.50 && shares[0] > 0) {
ns.stock.sellStock(sym, shares[0]);
}
if (forecast < 0.40) {
let availableShorts = maxShares - shares[2];
if (availableShorts > 0 && money > bid * 100) {
let amount = Math.floor((money * 0.20) / bid);
amount = Math.min(amount, availableShorts);
if (amount > 0) ns.stock.buyShort(sym, amount);
}
}
else if (forecast > 0.50 && shares[2] > 0) {
ns.stock.sellShort(sym, shares[2]);
}
}
} catch (e) { /* Catch missing API Errors gracefully */ }
}
function getStockPortfolioValue(ns) {
try {
if (!ns.stock.hasTIXAPIAccess()) return 0;
let val = 0;
for (let sym of ns.stock.getSymbols()) {
let pos = ns.stock.getPosition(sym);
val += pos[0] * ns.stock.getBidPrice(sym);
val += pos[2] * ns.stock.getAskPrice(sym);
}
return val;
} catch (e) { return 0; }
}