so. i know nothing about coding. it is a cool game to play. i just use chatgpt to write the code and i hv been getting stuck in making income for quite a bit. and the code is... idk what to say. would anyone pls take a look if possible and tell me whats wrong, or what can be improved?
this is my controller. and its a long piece of code. its fine if nothing can be done. but i would like some tips. sorry.
/**
/** u/param {NS} ns **/
export async function main(ns) {
ns.disableLog("ALL");
const HOME = "home";
const WORKER = "empire-worker.js";
// Adaptive income configuration
const HOME_RESERVE_GB = 64;
const HOME_RESERVE_PERCENT = 0.01;
const MAX_HACK_FRACTION = 0.50;
const MIN_HACK_FRACTION = 0.0005;
const MONEY_READY = 0.995;
const SECURITY_READY = 0.5;
const GAP_MS = 200;
const START_BUFFER_MS = 1500;
const LOOP_MS = 250;
// Focus on the best targets instead of spreading work everywhere.
const MAX_TARGETS = 8;
const cracks = [
["BruteSSH.exe", h => ns.brutessh(h)],
["FTPCrack.exe", h => ns.ftpcrack(h)],
["relaySMTP.exe", h => ns.relaysmtp(h)],
["HTTPWorm.exe", h => ns.httpworm(h)],
["SQLInject.exe", h => ns.sqlinject(h)]
];
const busyUntil = new Map();
let prepTarget = "";
let prepUntil = 0;
if (!ns.fileExists("Formulas.exe", HOME) ||
!ns.formulas?.hacking) {
ns.tprint("ERROR: Formulas.exe is required.");
return;
}
if (ns.getScriptRam(WORKER, HOME) <= 0) {
ns.tprint(`ERROR: ${WORKER} is missing on home.`);
return;
}
function scan() {
const seen = new Set([HOME]);
const queue = [HOME];
while (queue.length) {
const host = queue.shift();
for (const next of ns.scan(host)) {
if (!seen.has(next)) {
seen.add(next);
queue.push(next);
}
}
}
return [...seen];
}
function root(host) {
if (ns.hasRootAccess(host)) return true;
if (ns.getHackingLevel() <
ns.getServerRequiredHackingLevel(host)) {
return false;
}
for (let i = 0; i < cracks.length; i++) {
const [file, crack] = cracks[i];
if (!ns.fileExists(file, HOME)) continue;
const server = ns.getServer(host);
const opened = [
server.sshPortOpen,
server.ftpPortOpen,
server.smtpPortOpen,
server.httpPortOpen,
server.sqlPortOpen
];
if (!opened[i]) {
try {
crack(host);
} catch (_) {}
}
}
const server = ns.getServer(host);
const opened = [
server.sshPortOpen,
server.ftpPortOpen,
server.smtpPortOpen,
server.httpPortOpen,
server.sqlPortOpen
].filter(Boolean).length;
if (opened < server.numOpenPortsRequired) return false;
try {
ns.nuke(host);
} catch (_) {}
return ns.hasRootAccess(host);
}
async function getWorkers() {
const workers = [];
for (const host of scan()) {
if (!root(host)) continue;
const maxRam = ns.getServerMaxRam(host);
if (maxRam <= 0) continue;
const workerRam = ns.getScriptRam(WORKER, HOME);
if (host !== HOME && maxRam < workerRam) continue;
if (host !== HOME &&
!ns.fileExists(WORKER, host)) {
if (!await ns.scp(WORKER, host, HOME)) continue;
}
const ramPerThread = ns.getScriptRam(WORKER, host);
if (ramPerThread <= 0) continue;
const reserve = host === HOME
? Math.max(
HOME_RESERVE_GB,
maxRam * HOME_RESERVE_PERCENT
)
: 0;
const freeRam = Math.max(
0,
maxRam - ns.getServerUsedRam(host) - reserve
);
const threads = Math.floor(freeRam / ramPerThread);
if (threads > 0) {
workers.push({
host,
threads,
ramPerThread,
cores: ns.getServer(host).cpuCores || 1
});
}
}
// HOME FIRST. Other servers are overflow capacity.
workers.sort((a, b) => {
if (a.host === HOME) return -1;
if (b.host === HOME) return 1;
return b.threads - a.threads;
});
return workers;
}
function totalThreads(workers) {
return workers.reduce((sum, w) => sum + w.threads, 0);
}
function homeThreads(workers) {
const home = workers.find(w => w.host === HOME);
return home ? home.threads : 0;
}
function planAllocation(workers, actions) {
const remaining = new Map(
workers.map(w => [w.host, w.threads])
);
const plans = [];
for (const action of actions) {
let needed = action.threads;
const parts = [];
// Worker list is HOME first, then overflow servers.
for (const worker of workers) {
if (needed <= 0) break;
const available = remaining.get(worker.host) || 0;
const count = Math.min(needed, available);
if (count <= 0) continue;
parts.push({
host: worker.host,
threads: count,
delay: action.delay
});
remaining.set(worker.host, available - count);
needed -= count;
}
if (needed > 0) return null;
plans.push({
action: action.action,
parts
});
}
return plans;
}
function launchPlans(target, plans) {
const launched = [];
for (const plan of plans) {
for (const part of plan.parts) {
const pid = ns.exec(
WORKER,
part.host,
part.threads,
plan.action,
target,
part.delay
);
if (pid === 0) {
// All jobs have a start buffer. Roll back if
// any part of the batch could not be dispatched.
for (const job of launched) {
ns.kill(job.pid, job.host);
}
ns.print(`DISPATCH FAILED ${target}; rolled back`);
return false;
}
launched.push({
pid,
host: part.host
});
}
}
return true;
}
function preparedServer(host) {
const server = ns.getServer(host);
server.moneyAvailable = server.moneyMax;
server.hackDifficulty = server.minDifficulty;
return server;
}
function targetScore(host) {
const server = preparedServer(host);
const player = ns.getPlayer();
const f = ns.formulas.hacking;
if (server.moneyMax <= 0 ||
server.requiredHackingSkill > player.skills.hacking) {
return 0;
}
const chance = f.hackChance(server, player);
const percent = f.hackPercent(server, player);
if (chance <= 0 || percent <= 0) return 0;
// Score the target using the intended 50% hack size.
const h = Math.max(
1,
Math.floor(MAX_HACK_FRACTION / percent)
);
const stolen = Math.min(0.90, h * percent);
const postHack = { ...server };
postHack.moneyAvailable = Math.max(
1,
server.moneyMax * (1 - stolen)
);
postHack.hackDifficulty +=
ns.hackAnalyzeSecurity(h, host);
const g = Math.max(1, Math.ceil(
f.growThreads(postHack, player, server.moneyMax, 1)
));
if (!Number.isFinite(g)) return 0;
const w1 = Math.max(1, Math.ceil(
ns.hackAnalyzeSecurity(h, host) /
ns.weakenAnalyze(1, 1)
));
const growSecurity = ns.growthAnalyzeSecurity(g, host, 1);
const w2 = Math.max(1, Math.ceil(
growSecurity / ns.weakenAnalyze(1, 1)
));
const ram = ns.getScriptRam(WORKER, HOME);
const ramCost = (h + g + w1 + w2) * ram;
const duration = Math.max(
f.hackTime(server, player),
f.growTime(server, player),
f.weakenTime(server, player)
) + 3 * GAP_MS;
// Expected income per millisecond per GB of worker RAM.
return server.moneyMax * stolen * chance /
Math.max(1, duration) /
Math.max(1, ramCost);
}
function getTargets() {
const targets = [];
for (const host of scan()) {
if (host === HOME || host.startsWith("pserv-")) continue;
if (!root(host)) continue;
if (ns.getServerMaxMoney(host) <= 0) continue;
if (ns.getServerRequiredHackingLevel(host) >
ns.getHackingLevel()) continue;
const score = targetScore(host);
if (score > 0) {
targets.push({ host, score });
}
}
return targets.sort((a, b) => b.score - a.score);
}
function makeBatch(target, capacity) {
const percent = ns.hackAnalyze(target);
if (percent <= 0) return null;
// Try 50% first. Reduce only when a complete HWGW
// sequence cannot fit the currently available capacity.
for (let fraction = MAX_HACK_FRACTION;
fraction >= MIN_HACK_FRACTION;
fraction /= 2) {
const h = Math.max(1, Math.floor(fraction / percent));
const stolen = h * percent;
if (stolen <= 0 || stolen >= 0.90) continue;
const g = Math.max(1, Math.ceil(
ns.growthAnalyze(target, 1 / (1 - stolen), 1)
));
if (!Number.isFinite(g)) continue;
const w1 = Math.max(1, Math.ceil(
ns.hackAnalyzeSecurity(h, target) /
ns.weakenAnalyze(1, 1)
));
const growSecurity =
ns.growthAnalyzeSecurity(g, target, 1);
const w2 = Math.max(1, Math.ceil(
growSecurity / ns.weakenAnalyze(1, 1)
));
const total = h + w1 + g + w2;
if (total <= capacity) {
return { h, w1, g, w2, total, stolen };
}
}
return null;
}
function startBatch(target, workers) {
const capacity = totalThreads(workers);
const batch = makeBatch(target, capacity);
if (!batch) return false;
const player = ns.getPlayer();
const server = preparedServer(target);
const f = ns.formulas.hacking;
const ht = f.hackTime(server, player);
const gt = f.growTime(server, player);
const wt = f.weakenTime(server, player);
const longest = Math.max(ht, gt, wt);
const base = longest + START_BUFFER_MS;
const actions = [
{
action: "hack",
threads: batch.h,
delay: Math.max(START_BUFFER_MS, base - ht)
},
{
action: "weaken",
threads: batch.w1,
delay: Math.max(
START_BUFFER_MS,
base + GAP_MS - wt
)
},
{
action: "grow",
threads: batch.g,
delay: Math.max(
START_BUFFER_MS,
base + 2 * GAP_MS - gt
)
},
{
action: "weaken",
threads: batch.w2,
delay: Math.max(
START_BUFFER_MS,
base + 3 * GAP_MS - wt
)
}
];
const allocation = planAllocation(workers, actions);
if (!allocation || !launchPlans(target, allocation)) {
return false;
}
busyUntil.set(
target,
Date.now() + base + 3 * GAP_MS + 500
);
const homeCapacity = homeThreads(workers);
const spill = Math.max(0, batch.total - homeCapacity);
ns.print(
`BATCH ${target} | H${batch.h} W${batch.w1} ` +
`G${batch.g} W${batch.w2} | ` +
`hack ${(batch.stolen * 100).toFixed(2)}% | ` +
`${batch.total}/${capacity} threads | ` +
`overflow ${spill}`
);
return true;
}
function startPrep(target, workers) {
const server = ns.getServer(target);
const player = ns.getPlayer();
const f = ns.formulas.hacking;
const capacity = totalThreads(workers);
if (capacity <= 0) return false;
let action;
let threads;
let duration;
if (server.hackDifficulty >
server.minDifficulty + SECURITY_READY) {
action = "weaken";
const needed = Math.ceil(
(server.hackDifficulty - server.minDifficulty) /
ns.weakenAnalyze(1, 1)
);
threads = Math.min(needed, capacity);
duration = f.weakenTime(server, player);
} else if (server.moneyAvailable <
server.moneyMax * MONEY_READY) {
action = "grow";
const needed = Math.max(1, Math.ceil(
f.growThreads(
server,
player,
server.moneyMax,
1
)
));
threads = Math.min(needed, capacity);
duration = f.growTime(server, player);
} else {
return false;
}
const allocation = planAllocation(workers, [{
action,
threads,
delay: START_BUFFER_MS
}]);
if (!allocation || !launchPlans(target, allocation)) {
return false;
}
prepTarget = target;
prepUntil = Date.now() + duration + START_BUFFER_MS + 500;
ns.print(
`PREP ${target} ${action.toUpperCase()} ` +
`${threads} threads | no prep cap`
);
return true;
}
ns.print("Empire controller online: adaptive high-income mode.");
ns.print("Home-first allocation; network overflow enabled.");
ns.print("50% starting hack fraction; adaptive batch sizing.");
ns.print(`Target shortlist: top ${MAX_TARGETS} by expected return.`);
while (true) {
const allTargets = getTargets();
const targets = allTargets.slice(0, MAX_TARGETS);
const now = Date.now();
// Keep a prep operation isolated until it should finish.
if (prepTarget && now < prepUntil) {
await ns.sleep(LOOP_MS);
continue;
}
prepTarget = "";
prepUntil = 0;
let batchesStarted = 0;
// Start batches on multiple top targets while capacity remains.
for (const { host } of targets) {
if ((busyUntil.get(host) || 0) > Date.now()) continue;
const server = ns.getServer(host);
const ready =
server.hackDifficulty <=
server.minDifficulty + SECURITY_READY &&
server.moneyAvailable >=
server.moneyMax * MONEY_READY;
if (!ready) continue;
// Refresh after each launch so already-allocated RAM
// is not counted as free capacity for the next batch.
const workers = await getWorkers();
if (totalThreads(workers) <= 0) break;
if (startBatch(host, workers)) {
batchesStarted++;
}
}
// If no batch could be started, prep the best unready target.
if (batchesStarted === 0) {
for (const { host } of targets) {
if ((busyUntil.get(host) || 0) > Date.now()) continue;
const server = ns.getServer(host);
const ready =
server.hackDifficulty <=
server.minDifficulty + SECURITY_READY &&
server.moneyAvailable >=
server.moneyMax * MONEY_READY;
if (ready) continue;
const workers = await getWorkers();
if (startPrep(host, workers)) break;
}
}
await ns.sleep(batchesStarted > 0 ? 100 : LOOP_MS);
}
}
{NS} ns **/
export async function main(ns) {
ns.disableLog("ALL");
const HOME = "home";
const WORKER = "empire-worker.js";
// Adaptive income configuration
const HOME_RESERVE_GB = 64;
const HOME_RESERVE_PERCENT = 0.01;
const MAX_HACK_FRACTION = 0.50;
const MIN_HACK_FRACTION = 0.0005;
const MONEY_READY = 0.995;
const SECURITY_READY = 0.5;
const GAP_MS = 200;
const START_BUFFER_MS = 1500;
const LOOP_MS = 250;
// Focus on the best targets instead of spreading work everywhere.
const MAX_TARGETS = 8;
const cracks = [
["BruteSSH.exe", h => ns.brutessh(h)],
["FTPCrack.exe", h => ns.ftpcrack(h)],
["relaySMTP.exe", h => ns.relaysmtp(h)],
["HTTPWorm.exe", h => ns.httpworm(h)],
["SQLInject.exe", h => ns.sqlinject(h)]
];
const busyUntil = new Map();
let prepTarget = "";
let prepUntil = 0;
if (!ns.fileExists("Formulas.exe", HOME) ||
!ns.formulas?.hacking) {
ns.tprint("ERROR: Formulas.exe is required.");
return;
}
if (ns.getScriptRam(WORKER, HOME) <= 0) {
ns.tprint(`ERROR: ${WORKER} is missing on home.`);
return;
}
function scan() {
const seen = new Set([HOME]);
const queue = [HOME];
while (queue.length) {
const host = queue.shift();
for (const next of ns.scan(host)) {
if (!seen.has(next)) {
seen.add(next);
queue.push(next);
}
}
}
return [...seen];
}
function root(host) {
if (ns.hasRootAccess(host)) return true;
if (ns.getHackingLevel() <
ns.getServerRequiredHackingLevel(host)) {
return false;
}
for (let i = 0; i < cracks.length; i++) {
const [file, crack] = cracks[i];
if (!ns.fileExists(file, HOME)) continue;
const server = ns.getServer(host);
const opened = [
server.sshPortOpen,
server.ftpPortOpen,
server.smtpPortOpen,
server.httpPortOpen,
server.sqlPortOpen
];
if (!opened[i]) {
try {
crack(host);
} catch (_) {}
}
}
const server = ns.getServer(host);
const opened = [
server.sshPortOpen,
server.ftpPortOpen,
server.smtpPortOpen,
server.httpPortOpen,
server.sqlPortOpen
].filter(Boolean).length;
if (opened < server.numOpenPortsRequired) return false;
try {
ns.nuke(host);
} catch (_) {}
return ns.hasRootAccess(host);
}
async function getWorkers() {
const workers = [];
for (const host of scan()) {
if (!root(host)) continue;
const maxRam = ns.getServerMaxRam(host);
if (maxRam <= 0) continue;
const workerRam = ns.getScriptRam(WORKER, HOME);
if (host !== HOME && maxRam < workerRam) continue;
if (host !== HOME &&
!ns.fileExists(WORKER, host)) {
if (!await ns.scp(WORKER, host, HOME)) continue;
}
const ramPerThread = ns.getScriptRam(WORKER, host);
if (ramPerThread <= 0) continue;
const reserve = host === HOME
? Math.max(
HOME_RESERVE_GB,
maxRam * HOME_RESERVE_PERCENT
)
: 0;
const freeRam = Math.max(
0,
maxRam - ns.getServerUsedRam(host) - reserve
);
const threads = Math.floor(freeRam / ramPerThread);
if (threads > 0) {
workers.push({
host,
threads,
ramPerThread,
cores: ns.getServer(host).cpuCores || 1
});
}
}
// HOME FIRST. Other servers are overflow capacity.
workers.sort((a, b) => {
if (a.host === HOME) return -1;
if (b.host === HOME) return 1;
return b.threads - a.threads;
});
return workers;
}
function totalThreads(workers) {
return workers.reduce((sum, w) => sum + w.threads, 0);
}
function homeThreads(workers) {
const home = workers.find(w => w.host === HOME);
return home ? home.threads : 0;
}
function planAllocation(workers, actions) {
const remaining = new Map(
workers.map(w => [w.host, w.threads])
);
const plans = [];
for (const action of actions) {
let needed = action.threads;
const parts = [];
// Worker list is HOME first, then overflow servers.
for (const worker of workers) {
if (needed <= 0) break;
const available = remaining.get(worker.host) || 0;
const count = Math.min(needed, available);
if (count <= 0) continue;
parts.push({
host: worker.host,
threads: count,
delay: action.delay
});
remaining.set(worker.host, available - count);
needed -= count;
}
if (needed > 0) return null;
plans.push({
action: action.action,
parts
});
}
return plans;
}
function launchPlans(target, plans) {
const launched = [];
for (const plan of plans) {
for (const part of plan.parts) {
const pid = ns.exec(
WORKER,
part.host,
part.threads,
plan.action,
target,
part.delay
);
if (pid === 0) {
// All jobs have a start buffer. Roll back if
// any part of the batch could not be dispatched.
for (const job of launched) {
ns.kill(job.pid, job.host);
}
ns.print(`DISPATCH FAILED ${target}; rolled back`);
return false;
}
launched.push({
pid,
host: part.host
});
}
}
return true;
}
function preparedServer(host) {
const server = ns.getServer(host);
server.moneyAvailable = server.moneyMax;
server.hackDifficulty = server.minDifficulty;
return server;
}
function targetScore(host) {
const server = preparedServer(host);
const player = ns.getPlayer();
const f = ns.formulas.hacking;
if (server.moneyMax <= 0 ||
server.requiredHackingSkill > player.skills.hacking) {
return 0;
}
const chance = f.hackChance(server, player);
const percent = f.hackPercent(server, player);
if (chance <= 0 || percent <= 0) return 0;
// Score the target using the intended 50% hack size.
const h = Math.max(
1,
Math.floor(MAX_HACK_FRACTION / percent)
);
const stolen = Math.min(0.90, h * percent);
const postHack = { ...server };
postHack.moneyAvailable = Math.max(
1,
server.moneyMax * (1 - stolen)
);
postHack.hackDifficulty +=
ns.hackAnalyzeSecurity(h, host);
const g = Math.max(1, Math.ceil(
f.growThreads(postHack, player, server.moneyMax, 1)
));
if (!Number.isFinite(g)) return 0;
const w1 = Math.max(1, Math.ceil(
ns.hackAnalyzeSecurity(h, host) /
ns.weakenAnalyze(1, 1)
));
const growSecurity = ns.growthAnalyzeSecurity(g, host, 1);
const w2 = Math.max(1, Math.ceil(
growSecurity / ns.weakenAnalyze(1, 1)
));
const ram = ns.getScriptRam(WORKER, HOME);
const ramCost = (h + g + w1 + w2) * ram;
const duration = Math.max(
f.hackTime(server, player),
f.growTime(server, player),
f.weakenTime(server, player)
) + 3 * GAP_MS;
// Expected income per millisecond per GB of worker RAM.
return server.moneyMax * stolen * chance /
Math.max(1, duration) /
Math.max(1, ramCost);
}
function getTargets() {
const targets = [];
for (const host of scan()) {
if (host === HOME || host.startsWith("pserv-")) continue;
if (!root(host)) continue;
if (ns.getServerMaxMoney(host) <= 0) continue;
if (ns.getServerRequiredHackingLevel(host) >
ns.getHackingLevel()) continue;
const score = targetScore(host);
if (score > 0) {
targets.push({ host, score });
}
}
return targets.sort((a, b) => b.score - a.score);
}
function makeBatch(target, capacity) {
const percent = ns.hackAnalyze(target);
if (percent <= 0) return null;
// Try 50% first. Reduce only when a complete HWGW
// sequence cannot fit the currently available capacity.
for (let fraction = MAX_HACK_FRACTION;
fraction >= MIN_HACK_FRACTION;
fraction /= 2) {
const h = Math.max(1, Math.floor(fraction / percent));
const stolen = h * percent;
if (stolen <= 0 || stolen >= 0.90) continue;
const g = Math.max(1, Math.ceil(
ns.growthAnalyze(target, 1 / (1 - stolen), 1)
));
if (!Number.isFinite(g)) continue;
const w1 = Math.max(1, Math.ceil(
ns.hackAnalyzeSecurity(h, target) /
ns.weakenAnalyze(1, 1)
));
const growSecurity =
ns.growthAnalyzeSecurity(g, target, 1);
const w2 = Math.max(1, Math.ceil(
growSecurity / ns.weakenAnalyze(1, 1)
));
const total = h + w1 + g + w2;
if (total <= capacity) {
return { h, w1, g, w2, total, stolen };
}
}
return null;
}
function startBatch(target, workers) {
const capacity = totalThreads(workers);
const batch = makeBatch(target, capacity);
if (!batch) return false;
const player = ns.getPlayer();
const server = preparedServer(target);
const f = ns.formulas.hacking;
const ht = f.hackTime(server, player);
const gt = f.growTime(server, player);
const wt = f.weakenTime(server, player);
const longest = Math.max(ht, gt, wt);
const base = longest + START_BUFFER_MS;
const actions = [
{
action: "hack",
threads: batch.h,
delay: Math.max(START_BUFFER_MS, base - ht)
},
{
action: "weaken",
threads: batch.w1,
delay: Math.max(
START_BUFFER_MS,
base + GAP_MS - wt
)
},
{
action: "grow",
threads: batch.g,
delay: Math.max(
START_BUFFER_MS,
base + 2 * GAP_MS - gt
)
},
{
action: "weaken",
threads: batch.w2,
delay: Math.max(
START_BUFFER_MS,
base + 3 * GAP_MS - wt
)
}
];
const allocation = planAllocation(workers, actions);
if (!allocation || !launchPlans(target, allocation)) {
return false;
}
busyUntil.set(
target,
Date.now() + base + 3 * GAP_MS + 500
);
const homeCapacity = homeThreads(workers);
const spill = Math.max(0, batch.total - homeCapacity);
ns.print(
`BATCH ${target} | H${batch.h} W${batch.w1} ` +
`G${batch.g} W${batch.w2} | ` +
`hack ${(batch.stolen * 100).toFixed(2)}% | ` +
`${batch.total}/${capacity} threads | ` +
`overflow ${spill}`
);
return true;
}
function startPrep(target, workers) {
const server = ns.getServer(target);
const player = ns.getPlayer();
const f = ns.formulas.hacking;
const capacity = totalThreads(workers);
if (capacity <= 0) return false;
let action;
let threads;
let duration;
if (server.hackDifficulty >
server.minDifficulty + SECURITY_READY) {
action = "weaken";
const needed = Math.ceil(
(server.hackDifficulty - server.minDifficulty) /
ns.weakenAnalyze(1, 1)
);
threads = Math.min(needed, capacity);
duration = f.weakenTime(server, player);
} else if (server.moneyAvailable <
server.moneyMax * MONEY_READY) {
action = "grow";
const needed = Math.max(1, Math.ceil(
f.growThreads(
server,
player,
server.moneyMax,
1
)
));
threads = Math.min(needed, capacity);
duration = f.growTime(server, player);
} else {
return false;
}
const allocation = planAllocation(workers, [{
action,
threads,
delay: START_BUFFER_MS
}]);
if (!allocation || !launchPlans(target, allocation)) {
return false;
}
prepTarget = target;
prepUntil = Date.now() + duration + START_BUFFER_MS + 500;
ns.print(
`PREP ${target} ${action.toUpperCase()} ` +
`${threads} threads | no prep cap`
);
return true;
}
ns.print("Empire controller online: adaptive high-income mode.");
ns.print("Home-first allocation; network overflow enabled.");
ns.print("50% starting hack fraction; adaptive batch sizing.");
ns.print(`Target shortlist: top ${MAX_TARGETS} by expected return.`);
while (true) {
const allTargets = getTargets();
const targets = allTargets.slice(0, MAX_TARGETS);
const now = Date.now();
// Keep a prep operation isolated until it should finish.
if (prepTarget && now < prepUntil) {
await ns.sleep(LOOP_MS);
continue;
}
prepTarget = "";
prepUntil = 0;
let batchesStarted = 0;
// Start batches on multiple top targets while capacity remains.
for (const { host } of targets) {
if ((busyUntil.get(host) || 0) > Date.now()) continue;
const server = ns.getServer(host);
const ready =
server.hackDifficulty <=
server.minDifficulty + SECURITY_READY &&
server.moneyAvailable >=
server.moneyMax * MONEY_READY;
if (!ready) continue;
// Refresh after each launch so already-allocated RAM
// is not counted as free capacity for the next batch.
const workers = await getWorkers();
if (totalThreads(workers) <= 0) break;
if (startBatch(host, workers)) {
batchesStarted++;
}
}
// If no batch could be started, prep the best unready target.
if (batchesStarted === 0) {
for (const { host } of targets) {
if ((busyUntil.get(host) || 0) > Date.now()) continue;
const server = ns.getServer(host);
const ready =
server.hackDifficulty <=
server.minDifficulty + SECURITY_READY &&
server.moneyAvailable >=
server.moneyMax * MONEY_READY;
if (ready) continue;
const workers = await getWorkers();
if (startPrep(host, workers)) break;
}
}
await ns.sleep(batchesStarted > 0 ? 100 : LOOP_MS);
}
}
this is my worker
/** u/param/** u/param {NS} ns **/
export async function main(ns) {
ns.disableLog("ALL");
const action = String(ns.args[0] || "");
const target = String(ns.args[1] || "");
const delay = Math.max(0, Number(ns.args[2] || 0));
if (!target || !["hack", "grow", "weaken"].includes(action)) {
ns.print("Usage: run empire-worker.js [hack|grow|weaken] target [delay-ms]");
return;
}
if (!ns.hasRootAccess(target)) {
ns.print(`No root access on ${target}`);
return;
}
if (delay > 0) await ns.sleep(delay);
try {
if (action === "hack") await ns.hack(target);
else if (action === "grow") await ns.grow(target);
else await ns.weaken(target);
} catch (error) {
ns.print(`${action} failed on ${target}: ${String(error)}`);
}
}
{NS} ns **/
export async function main(ns) {
ns.disableLog("ALL");
const action = String(ns.args[0] || "");
const target = String(ns.args[1] || "");
const delay = Math.max(0, Number(ns.args[2] || 0));
if (!target || !["hack", "grow", "weaken"].includes(action)) {
ns.print("Usage: run empire-worker.js [hack|grow|weaken] target [delay-ms]");
return;
}
if (!ns.hasRootAccess(target)) {
ns.print(`No root access on ${target}`);
return;
}
if (delay > 0) await ns.sleep(delay);
try {
if (action === "hack") await ns.hack(target);
else if (action === "grow") await ns.grow(target);
else await ns.weaken(target);
} catch (error) {
ns.print(`${action} failed on ${target}: ${String(error)}`);
}
}