Compare commits
1 Commits
develop
...
laptop-bac
Author | SHA1 | Date | |
---|---|---|---|
ff4cc47e60 |
@ -1,49 +1,49 @@
|
||||
import {ArgParser} from "/scripts/lib/arg-parser";
|
||||
|
||||
/**
|
||||
* Display an ASCII banner, optionally automatically after reboots.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
*/
|
||||
export async function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
const argParser = new ArgParser('banner.js', 'Display an ASCII banner.', [
|
||||
{name: 'reboot', desc: 'Automatically display after game reboots', flags: ['-r', '--reboot'], default: false}
|
||||
]);
|
||||
const args = argParser.parse(ns.args);
|
||||
|
||||
// Help
|
||||
if(args['help'] || args['_error'].length)
|
||||
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
|
||||
|
||||
ns.tprint(`
|
||||
|
||||
&&&&&&&& O &&&&&&&&
|
||||
&&& & && CDDDD &&&&&&&&&&
|
||||
&&&& &&& && &&& &&&&&&&&&&&&&
|
||||
&&&&& && && & .&&&. &&&&&&&&&&&&&&
|
||||
&&&&&&&&&& && && &&&&& &&&&&&&&&&&&&&&
|
||||
&&&&&&&& && & &&&&& &&&&&&&&&&&&&&&&
|
||||
&&&&&&&&&& &&& &&&&& &&&&&&&&&&&&&&&&
|
||||
&&&&&&&&&&&&&&&& *&&&* *&&&&&&&&&&&&&&&
|
||||
&&&&&&&&&&&&& &&&&&&&&& *&&&&&&* .&&
|
||||
&&&&&&&&&&& &&& & & &&& &&* .&&&
|
||||
&&&&&&&&&& & & ,,,,,* .&&&&
|
||||
&&&&& & & &&&&&&&&&&&&&&&&
|
||||
&& &&&& & & & &&&&&&&&&&&&&&
|
||||
&& &&&&&&& & & & &&&&&* &&&&&
|
||||
&& &&&&&&&& & & &&&&&&&* &&&*
|
||||
&& &&&&&&&&&&& & & &&&& &*
|
||||
&& &&&&&&&&& & & && &&
|
||||
&&& &&&&&& & & && &&
|
||||
&&& &&&& & & && &&
|
||||
&&&& &&& & & && &&
|
||||
&&&&&&& \\&/ && &&
|
||||
&&&&&& V &* &*
|
||||
|
||||
`);
|
||||
|
||||
// Prevent from exiting so the banner will automatically display on startup.
|
||||
if(args['reboot']) while(true) { await ns.sleep(1000 * 60); }
|
||||
}
|
||||
import {ArgParser} from "/scripts/lib/arg-parser";
|
||||
|
||||
/**
|
||||
* Display an ASCII banner, optionally automatically after reboots.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
*/
|
||||
export async function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
const argParser = new ArgParser('banner.js', 'Display an ASCII banner.', [
|
||||
{name: 'reboot', desc: 'Automatically display after game reboots', flags: ['-r', '--reboot'], default: false}
|
||||
]);
|
||||
const args = argParser.parse(ns.args);
|
||||
|
||||
// Help
|
||||
if(args['help'] || args['_error'].length)
|
||||
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
|
||||
|
||||
ns.tprint(`
|
||||
|
||||
&&&&&&&& O &&&&&&&&
|
||||
&&& & && CDDDD &&&&&&&&&&
|
||||
&&&& &&& && &&& &&&&&&&&&&&&&
|
||||
&&&&& && && & .&&&. &&&&&&&&&&&&&&
|
||||
&&&&&&&&&& && && &&&&& &&&&&&&&&&&&&&&
|
||||
&&&&&&&& && & &&&&& &&&&&&&&&&&&&&&&
|
||||
&&&&&&&&&& &&& &&&&& &&&&&&&&&&&&&&&&
|
||||
&&&&&&&&&&&&&&&& *&&&* *&&&&&&&&&&&&&&&
|
||||
&&&&&&&&&&&&& &&&&&&&&& *&&&&&&* .&&
|
||||
&&&&&&&&&&& &&& & & &&& &&* .&&&
|
||||
&&&&&&&&&& & & ,,,,,* .&&&&
|
||||
&&&&& & & &&&&&&&&&&&&&&&&
|
||||
&& &&&& & & & &&&&&&&&&&&&&&
|
||||
&& &&&&&&& & & & &&&&&* &&&&&
|
||||
&& &&&&&&&& & & &&&&&&&* &&&*
|
||||
&& &&&&&&&&&&& & & &&&& &*
|
||||
&& &&&&&&&&& & & && &&
|
||||
&&& &&&&&& & & && &&
|
||||
&&& &&&& & & && &&
|
||||
&&&& &&& & & && &&
|
||||
&&&&&&& \\&/ && &&
|
||||
&&&&&& V &* &*
|
||||
|
||||
`);
|
||||
|
||||
// Prevent from exiting so the banner will automatically display on startup.
|
||||
if(args['reboot']) while(true) { await ns.sleep(1000 * 60); }
|
||||
}
|
||||
|
34
scripts/bitburner.js
Normal file
34
scripts/bitburner.js
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Automatically complete the current BitNode.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
*/
|
||||
export function main(ns) {
|
||||
let modules = [
|
||||
'auto-root',
|
||||
'auto-hack',
|
||||
'botnet-manager',
|
||||
'hacknet-manager',
|
||||
'server-manager'
|
||||
];
|
||||
|
||||
// Banner
|
||||
ns.run('/scripts/banner.js', 1, '-r');
|
||||
ns.tprint(`Starting BitBurner with ${modules.length} enabled: `);
|
||||
ns.tprint(modules.join(', '));
|
||||
|
||||
// botnet-manager
|
||||
|
||||
// hacknet-manager
|
||||
ns.run('/scripts/hacknet-manager', 1, '-a');
|
||||
|
||||
// server-manager
|
||||
ns.run('/scripts/server-manager', 1, '');
|
||||
|
||||
while(true) {
|
||||
// auto-hack
|
||||
|
||||
|
||||
ns.sleep(1000);
|
||||
}
|
||||
}
|
@ -1,16 +1,20 @@
|
||||
import {ArgParser} from '/scripts/lib/arg-parser';
|
||||
import {Config} from '/scripts/lib/data-file';
|
||||
import {Logger} from '/scripts/lib/logger';
|
||||
import {copyWithDependencies} from '/scripts/copy';
|
||||
|
||||
const configPath = '/etc/botnet.txt';
|
||||
const port = 1;
|
||||
|
||||
class Manager {
|
||||
running;
|
||||
workers = [];
|
||||
|
||||
constructor(ns, device, port, config = '/conf/botnet.txt') {
|
||||
async constructor(ns, hostname) {
|
||||
ns.disableLog('ALL');
|
||||
this.ns = ns;
|
||||
this.config = config;
|
||||
this.device = device;
|
||||
this.config = new Config(configPath);
|
||||
this.hostname = hostname;
|
||||
this.logger = new Logger(this.ns, [
|
||||
() => `Botnet: ${device}`,
|
||||
() => `Workers: ${this.workers.length}\tCores: ${this.workers.reduce((acc, w) => acc + w.cpuCores, 0)}\tRAM: ${this.workers.reduce((acc, w) => acc + w.maxRam, 0)} GB`
|
||||
@ -124,7 +128,8 @@ class Manager {
|
||||
export async function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
const hostname = ns.getHostname(), portNum = 1;
|
||||
const config = await new Config(ns, configPath).load();
|
||||
const hostname = ns.getHostname();
|
||||
const argParser = new ArgParser('botnet-manager.js', 'Connect & manage a network of servers to launch distributed attacks.', [
|
||||
new ArgParser('copy', 'Copy file & dependencies to botnet', [
|
||||
{name: 'file', desc: 'File to copy', default: false},
|
||||
@ -139,6 +144,7 @@ export async function main(ns) {
|
||||
new ArgParser('leave', 'Disconnect worker node from swarm', [
|
||||
{name: 'device', desc: 'Device to disconnect, defaults to the current machine', optional: true, default: hostname}
|
||||
]),
|
||||
new ArgParser('list', 'List connected worker nodes'),
|
||||
new ArgParser('run', 'Copy & run script on the botnet', [
|
||||
{name: 'script', desc: 'Script to copy & execute', type: 'string'},
|
||||
{name: 'args', desc: 'Arguments for script. Forward the current target with: {{TARGET}}', optional: true, extras: true},
|
||||
@ -154,9 +160,9 @@ export async function main(ns) {
|
||||
|
||||
// Run command
|
||||
if(args['_command'] == 'start') { // Start botnet manager
|
||||
ns.tprint(`Starting ${hostname} as botnet manager`);
|
||||
ns.tprint(`Connect more nodes with: run botnet-manager.js join [SERVER]`);
|
||||
await new Manager(ns, hostname, portNum).start();
|
||||
ns.tprint(`Starting botnet controller on: ${hostname}`);
|
||||
ns.tprint(`Connect workers to botnet with: run botnet-manager.js join [SERVER]`);
|
||||
await new Manager(ns, hostname).start();
|
||||
} else if(args['_command'] == 'copy') { // Issue copy command
|
||||
await ns.writePort(portNum, JSON.stringify({
|
||||
command: 'copy',
|
||||
@ -176,6 +182,9 @@ export async function main(ns) {
|
||||
command: 'leave',
|
||||
value: args['device']
|
||||
}));
|
||||
} else if(args['_command'] == 'list') {
|
||||
ns.tprint('Botnet workers:');
|
||||
ns.tprint(config['workers'].map(worker => worker.hostname).join(', '));
|
||||
} else if(args['_command'] == 'run') { // Issue run command
|
||||
await ns.writePort(portNum, JSON.stringify({
|
||||
command: 'run',
|
||||
|
214
scripts/copy.js
214
scripts/copy.js
@ -1,107 +1,107 @@
|
||||
import {ArgParser} from '/scripts/lib/arg-parser';
|
||||
import {maxThreads, progressBar} from '/scripts/lib/utils';
|
||||
|
||||
/**
|
||||
* Copy a file & it's dependencies to a server.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
* @param {string} src - File to scan & copy
|
||||
* @param {string} server - Device to copy files to
|
||||
* @returns {Promise<string[]>} - Array of copied files
|
||||
*/
|
||||
export async function copyWithDependencies(ns, src, server) {
|
||||
const queue = [src], found = [src];
|
||||
while(queue.length) {
|
||||
const file = queue.splice(0, 1)[0];
|
||||
const imports = new RegExp(/from ["']\.?(\/.+)["']/g);
|
||||
const script = await ns.read(file);
|
||||
let match;
|
||||
while((match = imports.exec(script)) != null) {
|
||||
const path = `${match[1]}.js`;
|
||||
if(!found.includes(path)) found.push(path);
|
||||
queue.push(path);
|
||||
}
|
||||
}
|
||||
await ns.scp(found, server);
|
||||
return found.reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a file & it's dependencies to a server.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
*/
|
||||
export async function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
const argParser = new ArgParser('copy.js', 'Copy a file & it\'s dependencies to a server.', [
|
||||
{name: 'file', desc: 'File to copy'},
|
||||
{name: 'server', desc: 'Server to copy file(s) to'},
|
||||
{name: 'args', desc: 'Arguments to start file/script with', optional: true, extras: true},
|
||||
{name: 'cpu', desc: 'Number of CPU threads to start script with, will use maximum if not specified', flags: ['-c', '--cpu']},
|
||||
{name: 'execute', desc: 'Start script after copying', flags: ['-e', '--execute'], default: false},
|
||||
{name: 'noDeps', desc: 'Skip copying dependencies', flags: ['-n', '--no-deps'], default: false},
|
||||
{name: 'quite', desc: 'Suppress program output', flags: ['-q', '--quite'], default: false},
|
||||
]);
|
||||
const args = argParser.parse(ns.args);
|
||||
|
||||
// Help
|
||||
if(args['help'] || args['_error'].length)
|
||||
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
|
||||
|
||||
// Banner
|
||||
if(!args['quite']) {
|
||||
ns.tprint('===================================================');
|
||||
ns.tprint(`Copying: ${args['server']}`);
|
||||
ns.tprint('===================================================');
|
||||
ns.tprint('');
|
||||
ns.tprint('Copying Files:');
|
||||
await ns.sleep(500);
|
||||
}
|
||||
|
||||
// Copy files & create download bar
|
||||
if(args['noDeps']) {
|
||||
await ns.scp(args['file'], args['server']);
|
||||
if(!args['quite']) await progressBar(ns, args['file']);
|
||||
} else {
|
||||
const files = await copyWithDependencies(ns, args['file'], args['server']);
|
||||
if(!args['quite']) {
|
||||
for(let file of files) {
|
||||
await progressBar(ns, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run the script if requested
|
||||
if(args['execute']) {
|
||||
const threads = args['cpu'] || maxThreads(ns, args['file'], args['server']) || 1;
|
||||
if(!args['quite']) {
|
||||
ns.tprint('');
|
||||
ns.tprint(`Executing with ${threads} thread${threads > 1 ? 's' : ''}...`);
|
||||
await ns.sleep(500);
|
||||
}
|
||||
ns.killall(args['server']);
|
||||
const pid = ns.exec(args['file'], args['server'], threads, ...args['args']);
|
||||
if(!args['quite']) {
|
||||
ns.tprint(!!pid ? 'Done!' : 'Failed to start');
|
||||
ns.tprint('');
|
||||
}
|
||||
}
|
||||
|
||||
// Done message
|
||||
if(!args['quite']) {
|
||||
ns.tprint('');
|
||||
ns.tprint('Done!');
|
||||
ns.tprint('');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BitBurner autocomplete.
|
||||
*
|
||||
* @param {{servers: string[], txts: string[], scripts: string[], flags: string[]}} data - Contextual information
|
||||
* @returns {string[]} - Pool of autocomplete options
|
||||
*/
|
||||
export function autocomplete(data) {
|
||||
return [...data.servers, ...data.scripts];
|
||||
}
|
||||
import {ArgParser} from '/scripts/lib/arg-parser';
|
||||
import {maxThreads, progressBar} from '/scripts/lib/utils';
|
||||
|
||||
/**
|
||||
* Copy a file & it's dependencies to a server.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
* @param {string} src - File to scan & copy
|
||||
* @param {string} server - Device to copy files to
|
||||
* @returns {Promise<string[]>} - Array of copied files
|
||||
*/
|
||||
export async function copyWithDependencies(ns, src, server) {
|
||||
const queue = [src], found = [src];
|
||||
while(queue.length) {
|
||||
const file = queue.splice(0, 1)[0];
|
||||
const imports = new RegExp(/from ["']\.?(\/.+)["']/g);
|
||||
const script = await ns.read(file);
|
||||
let match;
|
||||
while((match = imports.exec(script)) != null) {
|
||||
const path = `${match[1]}.js`;
|
||||
if(!found.includes(path)) found.push(path);
|
||||
queue.push(path);
|
||||
}
|
||||
}
|
||||
await ns.scp(found, server);
|
||||
return found.reverse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a file & it's dependencies to a server.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
*/
|
||||
export async function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
const argParser = new ArgParser('copy.js', 'Copy a file & it\'s dependencies to a server.', [
|
||||
{name: 'file', desc: 'File to copy'},
|
||||
{name: 'server', desc: 'Server to copy file(s) to'},
|
||||
{name: 'args', desc: 'Arguments to start file/script with', optional: true, extras: true},
|
||||
{name: 'cpu', desc: 'Number of CPU threads to start script with, will use maximum if not specified', flags: ['-c', '--cpu']},
|
||||
{name: 'execute', desc: 'Start script after copying', flags: ['-e', '--execute'], default: false},
|
||||
{name: 'noDeps', desc: 'Skip copying dependencies', flags: ['-n', '--no-deps'], default: false},
|
||||
{name: 'quite', desc: 'Suppress program output', flags: ['-q', '--quite'], default: false},
|
||||
]);
|
||||
const args = argParser.parse(ns.args);
|
||||
|
||||
// Help
|
||||
if(args['help'] || args['_error'].length)
|
||||
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
|
||||
|
||||
// Banner
|
||||
if(!args['quite']) {
|
||||
ns.tprint('===================================================');
|
||||
ns.tprint(`Copying: ${args['server']}`);
|
||||
ns.tprint('===================================================');
|
||||
ns.tprint('');
|
||||
ns.tprint('Copying Files:');
|
||||
await ns.sleep(500);
|
||||
}
|
||||
|
||||
// Copy files & create download bar
|
||||
if(args['noDeps']) {
|
||||
await ns.scp(args['file'], args['server']);
|
||||
if(!args['quite']) await progressBar(ns, args['file']);
|
||||
} else {
|
||||
const files = await copyWithDependencies(ns, args['file'], args['server']);
|
||||
if(!args['quite']) {
|
||||
for(let file of files) {
|
||||
await progressBar(ns, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run the script if requested
|
||||
if(args['execute']) {
|
||||
const threads = args['cpu'] || maxThreads(ns, args['file'], args['server']) || 1;
|
||||
if(!args['quite']) {
|
||||
ns.tprint('');
|
||||
ns.tprint(`Executing with ${threads} thread${threads > 1 ? 's' : ''}...`);
|
||||
await ns.sleep(500);
|
||||
}
|
||||
ns.killall(args['server']);
|
||||
const pid = ns.exec(args['file'], args['server'], threads, ...args['args']);
|
||||
if(!args['quite']) {
|
||||
ns.tprint(!!pid ? 'Done!' : 'Failed to start');
|
||||
ns.tprint('');
|
||||
}
|
||||
}
|
||||
|
||||
// Done message
|
||||
if(!args['quite']) {
|
||||
ns.tprint('');
|
||||
ns.tprint('Done!');
|
||||
ns.tprint('');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BitBurner autocomplete.
|
||||
*
|
||||
* @param {{servers: string[], txts: string[], scripts: string[], flags: string[]}} data - Contextual information
|
||||
* @returns {string[]} - Pool of autocomplete options
|
||||
*/
|
||||
export function autocomplete(data) {
|
||||
return [...data.servers, ...data.scripts];
|
||||
}
|
||||
|
@ -1,68 +1,68 @@
|
||||
import {ArgParser} from '/scripts/lib/arg-parser';
|
||||
import {toCurrency} from '/scripts/lib/utils';
|
||||
import {scanNetwork} from '/scripts/crawler';
|
||||
|
||||
/**
|
||||
* Sort array of servers based on the potential return/yield.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
* @param {string[]} servers - List of servers to sort based on yield
|
||||
* @returns {[string, number][]} - Sorted list of servers & their potential yield per minute
|
||||
*/
|
||||
export function bestTarget(ns, servers) {
|
||||
return servers.map(s => [s, serverYield(ns, s)]).sort((a, b) => {
|
||||
if(a[1] < b[1]) return 1;
|
||||
if(a[1] > b[1]) return -1;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the average return per minute when hacking a server.
|
||||
*
|
||||
* **Disclaimer:** Does not take into account security or weaken time.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
* @param {string} server - Server to calculate yield for
|
||||
* @returns {number} - $/minute
|
||||
*/
|
||||
export function serverYield(ns, server) {
|
||||
return (ns.hackAnalyze(server) * ns.getServerMaxMoney(server))
|
||||
* ((60 / (ns.getHackTime(server) / 1000)) * ns.hackAnalyzeChance(server));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the network for the best server(s) to hack.
|
||||
*
|
||||
* @param ns {NS} - BitBurner API
|
||||
* @returns {*}
|
||||
*/
|
||||
export function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
const argParser = new ArgParser('find-target.js', 'Scan the network for the best servers(s) to hack.',[
|
||||
{name: 'count', desc: 'Number of servers to return', flags: ['-c', '--count'], default: Infinity},
|
||||
{name: 'rooted', desc: 'Only servers that have been rooted', flags: ['-r', '--rooted'], default: false},
|
||||
{name: 'notRooted', desc: 'Only servers that have not been rooted', flags: ['-n', '--not-rooted'], default: false},
|
||||
{name: 'verbose', desc: 'Display the estimated income per minute per core', flags: ['-v', '--verbose'], default: false},
|
||||
]);
|
||||
const args = argParser.parse(ns.args);
|
||||
|
||||
// Help
|
||||
if(args['help'] || args['_error'].length)
|
||||
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
|
||||
|
||||
// Banner
|
||||
ns.tprint('===================================================');
|
||||
ns.tprint(`Finding Targets:`);
|
||||
ns.tprint('===================================================');
|
||||
|
||||
// Search & display results
|
||||
const [servers, ignore] = scanNetwork(ns);
|
||||
bestTarget(ns, servers).map(s => [...s, ns.hasRootAccess(s[0])])
|
||||
.filter(s => (!args['rooted'] || s[2]) || (!args['notRooted'] || !s[2]))
|
||||
.filter((s, i) => i < args['count'])
|
||||
.map(s => `${s[0]}${args['verbose'] ? ` (~${toCurrency(s[1])}/min)` : ''}`)
|
||||
.forEach((s, i) => ns.tprint(`${i + 1}) ${s}`));
|
||||
ns.tprint('');
|
||||
}
|
||||
import {ArgParser} from '/scripts/lib/arg-parser';
|
||||
import {toCurrency} from '/scripts/lib/utils';
|
||||
import {scanNetwork} from '/scripts/crawler';
|
||||
|
||||
/**
|
||||
* Sort array of servers based on the potential return/yield.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
* @param {string[]} servers - List of servers to sort based on yield
|
||||
* @returns {[string, number][]} - Sorted list of servers & their potential yield per minute
|
||||
*/
|
||||
export function bestTarget(ns, servers) {
|
||||
return servers.map(s => [s, serverYield(ns, s)]).sort((a, b) => {
|
||||
if(a[1] < b[1]) return 1;
|
||||
if(a[1] > b[1]) return -1;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the average return per minute when hacking a server.
|
||||
*
|
||||
* **Disclaimer:** Does not take into account security or weaken time.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
* @param {string} server - Server to calculate yield for
|
||||
* @returns {number} - $/minute
|
||||
*/
|
||||
export function serverYield(ns, server) {
|
||||
return (ns.hackAnalyze(server) * ns.getServerMaxMoney(server))
|
||||
* ((60 / (ns.getHackTime(server) / 1000)) * ns.hackAnalyzeChance(server));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the network for the best server(s) to hack.
|
||||
*
|
||||
* @param ns {NS} - BitBurner API
|
||||
* @returns {*}
|
||||
*/
|
||||
export function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
const argParser = new ArgParser('find-target.js', 'Scan the network for the best servers(s) to hack.',[
|
||||
{name: 'count', desc: 'Number of servers to return', flags: ['-c', '--count'], default: Infinity},
|
||||
{name: 'rooted', desc: 'Only servers that have been rooted', flags: ['-r', '--rooted'], default: false},
|
||||
{name: 'notRooted', desc: 'Only servers that have not been rooted', flags: ['-n', '--not-rooted'], default: false},
|
||||
{name: 'verbose', desc: 'Display the estimated income per minute per core', flags: ['-v', '--verbose'], default: false},
|
||||
]);
|
||||
const args = argParser.parse(ns.args);
|
||||
|
||||
// Help
|
||||
if(args['help'] || args['_error'].length)
|
||||
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
|
||||
|
||||
// Banner
|
||||
ns.tprint('===================================================');
|
||||
ns.tprint(`Finding Targets:`);
|
||||
ns.tprint('===================================================');
|
||||
|
||||
// Search & display results
|
||||
const [servers, ignore] = scanNetwork(ns);
|
||||
bestTarget(ns, servers).map(s => [...s, ns.hasRootAccess(s[0])])
|
||||
.filter(s => (!args['rooted'] || s[2]) || (!args['notRooted'] || !s[2]))
|
||||
.filter((s, i) => i < args['count'])
|
||||
.map(s => `${s[0]}${args['verbose'] ? ` (~${toCurrency(s[1])}/min)` : ''}`)
|
||||
.forEach((s, i) => ns.tprint(`${i + 1}) ${s}`));
|
||||
ns.tprint('');
|
||||
}
|
||||
|
31
scripts/lib/data-file.js
Normal file
31
scripts/lib/data-file.js
Normal file
@ -0,0 +1,31 @@
|
||||
export class DataFile {
|
||||
/**
|
||||
* Read & write data to a JSON file.
|
||||
*
|
||||
* @param {NS} ns - Bitburner API
|
||||
* @param path - Path to config file
|
||||
*/
|
||||
constructor(ns, path) {
|
||||
this.ns = ns;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data file
|
||||
*
|
||||
* @returns {Promise<any>} - Saved data
|
||||
*/
|
||||
async load() {
|
||||
return JSON.parse(await this.ns.read(this.path) || 'null');
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data to file
|
||||
*
|
||||
* @param values - Data to save
|
||||
* @returns {Promise<void>} - Save complete
|
||||
*/
|
||||
async save(values) {
|
||||
await this.ns.write(this.path, JSON.stringify(values), 'w');
|
||||
}
|
||||
}
|
42
scripts/lib/port-helper.js
Normal file
42
scripts/lib/port-helper.js
Normal file
@ -0,0 +1,42 @@
|
||||
export class PortHelper {
|
||||
/**
|
||||
*
|
||||
* @param ns
|
||||
* @param port
|
||||
* @param host
|
||||
*/
|
||||
constructor(ns, port, host) {
|
||||
this.ns = ns;
|
||||
this.host = host;
|
||||
this.portNum = port;
|
||||
this.port = ns.getPortHandle(port);
|
||||
this.callbacks = {};
|
||||
}
|
||||
|
||||
check() {
|
||||
const pending = [];
|
||||
while(!this.port.empty()) pending.push(this.port.read());
|
||||
pending.filter(p => {
|
||||
try {
|
||||
const payload = JSON.parse(p);
|
||||
if(this.callbacks[payload.subject]) return !this.callbacks[payload.subject](payload.value);
|
||||
if(this.callbacks['*']) return !this.callbacks['*'](payload.value);
|
||||
return true;
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}).forEach(p => this.port.write(p));
|
||||
}
|
||||
|
||||
subscribe(subject, callback) { if(typeof callback == 'function') this.callbacks[subject] = callback; }
|
||||
|
||||
send(subject, value) {
|
||||
this.ns.writePort(this.portNum, JSON.stringify({
|
||||
from: this.host,
|
||||
subject,
|
||||
value
|
||||
}));
|
||||
}
|
||||
|
||||
unsubscribe(subject) { delete this.callbacks[subject]; }
|
||||
}
|
@ -1,39 +1,39 @@
|
||||
import {ArgParser} from '/scripts/lib/arg-parser';
|
||||
|
||||
/**
|
||||
* Recursively delete files inside a path. Equivalent to the Unix "rm -r".
|
||||
* @param {NS} ns - BitBurner API
|
||||
*/
|
||||
export function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
const argParser = new ArgParser('rm.js', 'Recursively delete files inside a directory', [
|
||||
{name: 'path', desc: 'Path to recursively search'},
|
||||
{name: 'server', desc: 'Run on remote server', optional: true, default: ns.getHostname()},
|
||||
{name: 'force', desc: 'Remove game files (.exe, .lit, .msg)', flags: ['-f', '--force'], default: false},
|
||||
{name: 'recursive', desc: 'Delete everything inside directory', flags: ['-r', '--recursive'], default: true}
|
||||
]);
|
||||
const args = argParser.parse(ns.args);
|
||||
|
||||
// Help
|
||||
if(args['help'] || args['_error'].length)
|
||||
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
|
||||
|
||||
// Run
|
||||
ns.ls(args['server'], args['path'])
|
||||
.filter(f => new RegExp(/\.(exe|lit|msg)$/g).test(f) ? args['force'] : true)
|
||||
.forEach(f => ns.rm(f, args['server']));
|
||||
}
|
||||
|
||||
/**
|
||||
* BitBurner autocomplete.
|
||||
*
|
||||
* @param {{servers: string[], txts: string[], scripts: string[], flags: string[]}} data - Contextual information
|
||||
* @returns {string[]} - Pool of autocomplete options
|
||||
*/
|
||||
export function autocomplete(data) {
|
||||
return [...data.txts, ...data.scripts]
|
||||
.map(file => file.split('/').slice(0, -1).join('/'))
|
||||
.filter((path, i, arr) => arr.indexOf(path) == i)
|
||||
.concat(data.txts, data.scripts);
|
||||
}
|
||||
import {ArgParser} from '/scripts/lib/arg-parser';
|
||||
|
||||
/**
|
||||
* Recursively delete files inside a path. Equivalent to the Unix "rm -r".
|
||||
* @param {NS} ns - BitBurner API
|
||||
*/
|
||||
export function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
const argParser = new ArgParser('rm.js', 'Recursively delete files inside a directory', [
|
||||
{name: 'path', desc: 'Path to recursively search'},
|
||||
{name: 'server', desc: 'Run on remote server', optional: true, default: ns.getHostname()},
|
||||
{name: 'force', desc: 'Remove game files (.exe, .lit, .msg)', flags: ['-f', '--force'], default: false},
|
||||
{name: 'recursive', desc: 'Delete everything inside directory', flags: ['-r', '--recursive'], default: true}
|
||||
]);
|
||||
const args = argParser.parse(ns.args);
|
||||
|
||||
// Help
|
||||
if(args['help'] || args['_error'].length)
|
||||
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
|
||||
|
||||
// Run
|
||||
ns.ls(args['server'], args['path'])
|
||||
.filter(f => new RegExp(/\.(exe|lit|msg)$/g).test(f) ? args['force'] : true)
|
||||
.forEach(f => ns.rm(f, args['server']));
|
||||
}
|
||||
|
||||
/**
|
||||
* BitBurner autocomplete.
|
||||
*
|
||||
* @param {{servers: string[], txts: string[], scripts: string[], flags: string[]}} data - Contextual information
|
||||
* @returns {string[]} - Pool of autocomplete options
|
||||
*/
|
||||
export function autocomplete(data) {
|
||||
return [...data.txts, ...data.scripts]
|
||||
.map(file => file.split('/').slice(0, -1).join('/'))
|
||||
.filter((path, i, arr) => arr.indexOf(path) == i)
|
||||
.concat(data.txts, data.scripts);
|
||||
}
|
||||
|
@ -1,87 +1,87 @@
|
||||
import {ArgParser} from '/scripts/lib/arg-parser';
|
||||
import {Logger} from '/scripts/lib/logger';
|
||||
import {maxThreads, toCurrency} from '/scripts/lib/utils';
|
||||
import {copyWithDependencies} from "/scripts/copy";
|
||||
|
||||
/**
|
||||
* Automate the buying & upgrading of servers.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
*/
|
||||
export async function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
let servers = ns.getPurchasedServers();
|
||||
const logger = new Logger(ns, [
|
||||
() => `Server Manager: ${servers.length}`
|
||||
]);
|
||||
const argParser = new ArgParser('server-manager.js', 'Automate the buying & upgrading of servers. Automatically starts script after purchase. Tail for live updates.', [
|
||||
{name: 'script', desc: 'Script to copy & execute', optional: true},
|
||||
{name: 'args', desc: 'Arguments for script. Forward the discovered server with: {{SERVER}}', optional: true, extras: true},
|
||||
{name: 'balance', desc: 'Prevent spending bellow point', flags: ['-b', '--balance'], default: 0},
|
||||
{name: 'cpu', desc: 'Number of CPU threads to start script with, will use maximum if not specified', flags: ['-c', '--cpu'], default: false},
|
||||
{name: 'limit', desc: 'Limit the number of servers that can be purchased, defaults to 25', flags: ['-l', '--limit'], default: 25},
|
||||
{name: 'ram', desc: 'Amount of RAM to purchase new servers with, defaults to 8 GB', flags: ['-r', '--ram'], default: 8},
|
||||
{name: 'sleep', desc: 'Amount of time to wait between purchases, defaults to 1 (second)', flags: ['-s', '--sleep'], default: 1}
|
||||
]);
|
||||
const args = argParser.parse(ns.args);
|
||||
const serverPrefix = 'botnet_'
|
||||
const maxRam = ns.getPurchasedServerMaxRam();
|
||||
const minRamCost = ns.getPurchasedServerCost(args['ram']);
|
||||
|
||||
async function startScript(server) {
|
||||
await copyWithDependencies(ns, args['script'], server);
|
||||
const threads = args['cpu'] || maxThreads(ns, args['script'], server) || 1;
|
||||
const pid = ns.exec(args['script'], server, threads, ...args['args']);
|
||||
logger.log(`Starting "${args['script']}" with ${threads} thread${threads > 1 ? 's' : ''}`);
|
||||
logger[pid == -1 ? 'warn' : 'log'](pid == -1 ? 'Done!' : 'Failed to start');
|
||||
}
|
||||
|
||||
// Help
|
||||
if(args['help'] || args['_error'].length)
|
||||
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
|
||||
|
||||
// Main loop
|
||||
// noinspection InfiniteLoopJS
|
||||
while(true) {
|
||||
servers = ns.getPurchasedServers();
|
||||
const balance = ns.getServerMoneyAvailable('home');
|
||||
// Purchase new server if we can afford it
|
||||
if(servers.length < args['limit'] && balance - minRamCost > args['balance']) {
|
||||
logger.log(`Buying server (${args['ram']} GB): ${toCurrency(minRamCost)}`);
|
||||
ns.purchaseServer(`${serverPrefix}${servers.length}`, args['ram']);
|
||||
|
||||
// Run the script if requested
|
||||
if(args['script']) await startScript(`${serverPrefix}${servers.length}`);
|
||||
} else { // Check for upgrades
|
||||
let upgrades = servers.map(server => {
|
||||
// Calculate next RAM upgrades (must be a power of two: 2, 4, 8, 16, 32...)
|
||||
let ram = Math.pow(2, Math.log2(ns.getServerMaxRam(server)) + 1);
|
||||
if(ram > maxRam) ram = null;
|
||||
return {
|
||||
server,
|
||||
ram,
|
||||
cost: ram ? ns.getPurchasedServerCost(ram) : null
|
||||
}
|
||||
});
|
||||
upgrades = upgrades.sort((a, b) => { // Sort by price
|
||||
if(a.cost < b.cost) return 1;
|
||||
if(a.cost < b.cost) return -1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Do the cheapest upgrade if we can afford it
|
||||
const upgrade = upgrades[0];
|
||||
if(upgrade && !!upgrade.ram && balance - upgrade.cost > args['balance']) {
|
||||
logger.log(`Upgrading ${upgrade.server}: ${upgrade.ram} GB / ${toCurrency(upgrade.cost)}`);
|
||||
ns.killall(upgrade.server);
|
||||
ns.deleteServer(upgrade.server);
|
||||
ns.purchaseServer(upgrade.server, upgrade.ram);
|
||||
|
||||
// Run the script if requested
|
||||
if(args['script']) await startScript(upgrade.server);
|
||||
}
|
||||
}
|
||||
await ns.sleep(args['sleep'] * 1000);
|
||||
}
|
||||
}
|
||||
import {ArgParser} from '/scripts/lib/arg-parser';
|
||||
import {Logger} from '/scripts/lib/logger';
|
||||
import {maxThreads, toCurrency} from '/scripts/lib/utils';
|
||||
import {copyWithDependencies} from "/scripts/copy";
|
||||
|
||||
/**
|
||||
* Automate the buying & upgrading of servers.
|
||||
*
|
||||
* @param {NS} ns - BitBurner API
|
||||
*/
|
||||
export async function main(ns) {
|
||||
// Setup
|
||||
ns.disableLog('ALL');
|
||||
let servers = ns.getPurchasedServers();
|
||||
const logger = new Logger(ns, [
|
||||
() => `Server Manager: ${servers.length}`
|
||||
]);
|
||||
const argParser = new ArgParser('server-manager.js', 'Automate the buying & upgrading of servers. Automatically starts script after purchase. Tail for live updates.', [
|
||||
{name: 'script', desc: 'Script to copy & execute', optional: true},
|
||||
{name: 'args', desc: 'Arguments for script. Forward the discovered server with: {{SERVER}}', optional: true, extras: true},
|
||||
{name: 'balance', desc: 'Prevent spending bellow point', flags: ['-b', '--balance'], default: 0},
|
||||
{name: 'cpu', desc: 'Number of CPU threads to start script with, will use maximum if not specified', flags: ['-c', '--cpu'], default: false},
|
||||
{name: 'limit', desc: 'Limit the number of servers that can be purchased, defaults to 25', flags: ['-l', '--limit'], default: 25},
|
||||
{name: 'ram', desc: 'Amount of RAM to purchase new servers with, defaults to 8 GB', flags: ['-r', '--ram'], default: 8},
|
||||
{name: 'sleep', desc: 'Amount of time to wait between purchases, defaults to 1 (second)', flags: ['-s', '--sleep'], default: 1}
|
||||
]);
|
||||
const args = argParser.parse(ns.args);
|
||||
const serverPrefix = 'botnet_'
|
||||
const maxRam = ns.getPurchasedServerMaxRam();
|
||||
const minRamCost = ns.getPurchasedServerCost(args['ram']);
|
||||
|
||||
async function startScript(server) {
|
||||
await copyWithDependencies(ns, args['script'], server);
|
||||
const threads = args['cpu'] || maxThreads(ns, args['script'], server) || 1;
|
||||
const pid = ns.exec(args['script'], server, threads, ...args['args']);
|
||||
logger.log(`Starting "${args['script']}" with ${threads} thread${threads > 1 ? 's' : ''}`);
|
||||
logger[pid == -1 ? 'warn' : 'log'](pid == -1 ? 'Done!' : 'Failed to start');
|
||||
}
|
||||
|
||||
// Help
|
||||
if(args['help'] || args['_error'].length)
|
||||
return ns.tprint(argParser.help(args['help'] ? null : args['_error'][0], args['_command']));
|
||||
|
||||
// Main loop
|
||||
// noinspection InfiniteLoopJS
|
||||
while(true) {
|
||||
servers = ns.getPurchasedServers();
|
||||
const balance = ns.getServerMoneyAvailable('home');
|
||||
// Purchase new server if we can afford it
|
||||
if(servers.length < args['limit'] && balance - minRamCost > args['balance']) {
|
||||
logger.log(`Buying server (${args['ram']} GB): ${toCurrency(minRamCost)}`);
|
||||
ns.purchaseServer(`${serverPrefix}${servers.length}`, args['ram']);
|
||||
|
||||
// Run the script if requested
|
||||
if(args['script']) await startScript(`${serverPrefix}${servers.length}`);
|
||||
} else { // Check for upgrades
|
||||
let upgrades = servers.map(server => {
|
||||
// Calculate next RAM upgrades (must be a power of two: 2, 4, 8, 16, 32...)
|
||||
let ram = Math.pow(2, Math.log2(ns.getServerMaxRam(server)) + 1);
|
||||
if(ram > maxRam) ram = null;
|
||||
return {
|
||||
server,
|
||||
ram,
|
||||
cost: ram ? ns.getPurchasedServerCost(ram) : null
|
||||
}
|
||||
});
|
||||
upgrades = upgrades.sort((a, b) => { // Sort by price
|
||||
if(a.cost < b.cost) return 1;
|
||||
if(a.cost < b.cost) return -1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Do the cheapest upgrade if we can afford it
|
||||
const upgrade = upgrades[0];
|
||||
if(upgrade && !!upgrade.ram && balance - upgrade.cost > args['balance']) {
|
||||
logger.log(`Upgrading ${upgrade.server}: ${upgrade.ram} GB / ${toCurrency(upgrade.cost)}`);
|
||||
ns.killall(upgrade.server);
|
||||
ns.deleteServer(upgrade.server);
|
||||
ns.purchaseServer(upgrade.server, upgrade.ram);
|
||||
|
||||
// Run the script if requested
|
||||
if(args['script']) await startScript(upgrade.server);
|
||||
}
|
||||
}
|
||||
await ns.sleep(args['sleep'] * 1000);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user