Bitburner: Post-BN9 Hacknet Script (V2.2.1)

Current Version of Bitburner v2.2.1
Simple first Version of a modified Script capable of simple ‘fire and forget’ earning money via the hacknet after visiting BN9.

 

Intro – Why is Post-BN9 different?

With the advent of Hashes the cost of upgrades goes way up. Before BN9 it is possible for a system of hacknet-servers to pay for themself in a short amount of time. After BN9 that may takes ages, so we want to limit the amount we spent up to a certain point.
I have enabled a ‘first run’ system in which the script takes the hacknet-servers to a certain point. At the moment it is on the requirements for the ‘Netburner-Faction’ if the hacking level is also high enough. During that ‘first run’ we also sell hashes for money in order to not need to wait for the cache to run full.
After the ‘first run’ has passed we go into maintenance mode. The amount of money spent on updates is determined by a MRF factor, adjustable in the script or with an arg[0] during the script call.

Memory Usage

[home ~/]> mem hacknet-manager.js
This script requires 6.70GB of RAM to run for 1 thread(s)
4.00GB | hacknet (ns)
1.60GB | baseCost (misc)
1.00GB | getMoneySources (fn)
100.00MB | getServerMoneyAvailable (fn)

Import from ‘myFunction.js’

// function myMoney(ns) : amount of money to always keep and not pay for anything
const KEEPSAKE = 1e6;

export function myMoney(ns) {
  let amount = (ns.getServerMoneyAvailable("home") - KEEPSAKE);
  if (amount > 0) return amount;
  return 0;
}

 

Main script ‘hacknet-manager.js’ Imports and Constants

/** @param {NS} ns */

// ******************
// imported functions
// ******************

import { myMoney } from "./myFunctions.js"

export async function main(ns) {

  // *********
  // constants
  // *********

  // Do Not Change

  const SLEEP_TIME = 1000;	// amount of time between updates in ms
  const MAX_NODES = 20;		// only needed for 'done' to end this script

  const hacknet = ns.hacknet;

  // Possible to change to suit your needs

  // During a 'first run' we want only enough to enable joining Netburners-Faction
  // regardless of money already earned from the hacknet-servers
  const FR_MAX_NODES = 4;  // 4 nodes to keep the investment down
  const FR_MAX_LEVEL = 25; // 25x4=100
  const FR_MAX_RAM   = 2;  //  2x4=  8
  const FR_MAX_CORES = 1;  //  1x4=  4

  // Change based on the comment possible

  // change MRF to 0 in order to terminate after the 'first run'
  // a MRF greater 1 simply invests up to all money available, but ...
  // that may make the report faulty
  const DEFAULT_MRF = 0.5; // Money Reinvest Factor between 1 for 100% and 0 for 0%
  const MRF = (ns.args[0] === undefined ? DEFAULT_MRF : ns.args[0]);

  // If we only want $ out of the Hacknet-hashes,
  // increasing the cache is not needed.
  // true = Upgrading Cache  -vs-  false = not Upgrading Cache
  const UPGRADE_CACHE = false;

 

Main Script ‘hacknet-manager.js’ functions

// *********
// functions
// *********

function moneyEarnedHacknet(ns){
  return ns.getMoneySources().sinceInstall.hacknet;
}

function moneySpentHacknet(ns) {
  return ns.getMoneySources().sinceInstall.hacknet_expenses;
}

function moneyBalanceHacknet2(ns) {
  // money balance weighted by the Reinvestment Factor
  return ((moneyEarnedHacknet(ns) * MRF) + moneySpentHacknet(ns));
}

function myMoneyHacknet(ns) {
  // since we want to limit how much money we spent
  if (moneyBalanceHacknet2(ns) < 0 ) return 0;
  if (myMoney(ns) < moneyBalanceHacknet2(ns)) return myMoney(ns);
  return moneyBalanceHacknet2(ns);
}

function currentNodes(ns) {
  return (hacknet.numNodes());
}

function currentHashes(ns){
  return hacknet.numHashes();
}

 

Main Script ‘hacknet-manager.js’ report

function moneyBalanceHacknet(ns) {
  // true count only for the report
  return (moneyEarnedHacknet(ns) + moneySpentHacknet(ns));
}

function totalProductionHashes(ns) {
  let sumHashes = 0;
  for (var i = 0; i < currentNodes(ns); i++) {
    sumHashes += hacknet.getNodeStats(i).totalProduction;
  }
  return sumHashes;
}

function report(ns) {
  // just a clear summary of things mostly also found elsewhere
  ns.clearLog();
  if (!doneFR(ns)) ns.print("First Run active.");
  ns.print("Hashes available:    # ", ns.nFormat(currentHashes(ns), '0.000a'));
  ns.print("Possible from Sales: $ ", ns.nFormat(currentHashes(ns)/4*1e6, '0.000a'))
  ns.print("--------------------------------");
  ns.print("Hashes produced:     # ", ns.nFormat(totalProductionHashes(ns), '0.000a'));
  ns.print("Brutto Money earned: $ ", ns.nFormat(moneyEarnedHacknet(ns), '0.000a'));
  ns.print("Money spent:         $ ", ns.nFormat(moneySpentHacknet(ns), '0.000a'));
  ns.print("Netto Money earned:  $ ", ns.nFormat(moneyBalanceHacknet(ns), '0.000a'));
  ns.print("--------------------------------");
  ns.print("------ Waiting for enough ------");
  ns.print("Money to ReInvest:   $ ", ns.nFormat(myMoneyHacknet(ns), '0.000a'));
  return;
}

 

Main script ‘hacknet-manager.js’ first run part

function sellHashes(ns){
  //Divide hashes by 4 and round down
  var count = Math.trunc(currentHashes(ns)/4);
  ns.hacknet.spendHashes("Sell for Money", "mustBeFilled", count);
  return;
}

function upgradeFR(ns) {
  // upgrades during 'first run'
  // - with the original myMoney
  // and without upgrading hash-cache capacity
  for (var i = 0; i < currentNodes(ns); i++) {
    if ((myMoney(ns) > hacknet.getLevelUpgradeCost(i, 1)) &&
        (hacknet.getNodeStats(i).level < FR_MAX_LEVEL)) {
      hacknet.upgradeLevel(i, 1);
    }
    if ((myMoney(ns) > hacknet.getRamUpgradeCost(i, 1)) &&
        (hacknet.getNodeStats(i).ram < FR_MAX_RAM)) {
      hacknet.upgradeRam(i, 1);
    }
    if ((myMoney(ns) > hacknet.getCoreUpgradeCost(i, 1)) &&
        (hacknet.getNodeStats(i).cores < FR_MAX_CORES)) {
      hacknet.upgradeCore(i, 1);
    }
  }
  if ((myMoney(ns) > hacknet.getPurchaseNodeCost()) &&
      (currentNodes(ns) < FR_MAX_NODES)) {
    hacknet.purchaseNode();
  }
  sellHashes(ns);
  report(ns);
  return;
}

function doneFR(ns) {
  // simple logic to look out if the 'first run' is still currently active
  let ind = ((FR_MAX_NODES -1) >= currentNodes(ns) ? (currentNodes(ns) -1) : (FR_MAX_NODES -1));
  if (currentNodes(ns) == 0) return false;
  if ((currentNodes(ns) >= ind) &&
      (hacknet.getNodeStats(ind).level >= FR_MAX_LEVEL) &&
      (hacknet.getNodeStats(ind).ram >= FR_MAX_RAM) &&
      (hacknet.getNodeStats(ind).cores >= FR_MAX_CORES)){
    return true;
  }
  return false;
}

 

Main script ‘hacknet-manager.js’ find cheapest option

function findCULevel(ns) {
  // finds Cheapest Upgrade Level and returns the index of the node
  var cl = 0;
  for (var i = 1; i < currentNodes(ns); i++) {
    if (hacknet.getLevelUpgradeCost(i, 1) < hacknet.getLevelUpgradeCost(i-1, 1)) cl = i;
  }
  return cl;
}

function findCURam(ns) {
  // finds Cheapest Upgrade Ram and returns the index of the node
  var cr = 0;
  for (var i = 1; i < currentNodes(ns); i++) {
    if (hacknet.getRamUpgradeCost(i, 1) < hacknet.getRamUpgradeCost(i-1, 1)) cr = i;
  }
  return cr;
}

function findCUCore(ns) {
  // finds Cheapest Upgrade Core and returns the index of the node
  var cc = 0;
  for (var i = 1; i < currentNodes(ns); i++) {
    if (hacknet.getCoreUpgradeCost(i, 1) < hacknet.getCoreUpgradeCost(i-1, 1)) cc = i;
  }
  return cc;
}

function findCUCache(ns) {
  // returns the index of the cheapest level-upgrade node
  var cca = 0;
  for (var i = 1; i < currentNodes(ns); i++) {
    if (hacknet.getCacheUpgradeCost(i, 1) < hacknet.getCacheUpgradeCost(i-1, 1)) cca = i;
  }
  return cca;
}

function findCheapest(ns) {
  // returns a string determining which to upgrade
  let cheapestObject = "n";
  let cheapestPrice = hacknet.getPurchaseNodeCost();
  if (hacknet.getLevelUpgradeCost(findCULevel(ns), 1) < cheapestPrice) {
    cheapestObject = "l";
    cheapestPrice = hacknet.getLevelUpgradeCost(findCULevel(ns), 1);
  }
  if (hacknet.getRamUpgradeCost(findCURam(ns), 1) < cheapestPrice) {
    cheapestObject = "r";
    cheapestPrice = hacknet.getRamUpgradeCost(findCURam(ns), 1);
  }
  if (hacknet.getCoreUpgradeCost(findCUCore(ns), 1) < cheapestPrice) {
    cheapestObject = "c";
    cheapestPrice = hacknet.getCoreUpgradeCost(findCUCore(ns), 1);
  }
  if (UPGRADE_CACHE && 
     (hacknet.getCacheUpgradeCost(findCUCache(ns), 1) < cheapestPrice)) {
    cheapestObject = "ca";
  }
  return cheapestObject;
}

 

Main script ‘hacknet-manager.js’ upgradeReport and done

function upgradeReport(ns) {
  // returns a printable string as an upgrade to report
  // would produce errors during 'first run'
  let urs = "";
  let tar2 = findCheapest(ns);
  if (tar2 == "n") urs = ("Next Upgrade Node for $ " + ns.nFormat(hacknet.getPurchaseNodeCost(), '0.000a'));
  if (tar2 == "l") urs = ("Next Upgrade Level for $ " + ns.nFormat(hacknet.getLevelUpgradeCost(findCULevel(ns), 1), '0.000a'));
  if (tar2 == "r") urs = ("Next Upgrade RAM for $ " + ns.nFormat(hacknet.getRamUpgradeCost(findCURam(ns), 1), '0.000a'));
  if (tar2 == "c") urs = ("Next Upgrade Core for $ " + ns.nFormat(hacknet.getCoreUpgradeCost(findCUCore(ns), 1), '0.000a'));
  if (tar2 == "ca") urs = ("Next Upgrade Cache for $ " + ns.nFormat(hacknet.getCacheUpgradeCost(findCUCache(ns), 1), '0.000a'));
  return urs;
}

function upgrade(ns) {
  let tar = findCheapest(ns);
  if (tar == "n" && 
      myMoneyHacknet(ns) > hacknet.getPurchaseNodeCost()) {
    hacknet.purchaseNode();
  } else if (tar == "l" &&
           myMoneyHacknet(ns) > hacknet.getLevelUpgradeCost(findCULevel(ns), 1)) {
    hacknet.upgradeLevel(findCULevel(ns), 1);
  } else if (tar == "r" &&
            myMoneyHacknet(ns) > hacknet.getRamUpgradeCost(findCURam(ns), 1)) {
    hacknet.upgradeRam(findCURam(ns), 1);
  } else if (tar == "c" &&
            myMoneyHacknet(ns) > hacknet.getCoreUpgradeCost(findCUCore(ns), 1)) {
    hacknet.upgradeCore(findCUCore(ns), 1);
  } else if (tar == "ca" &&
            myMoneyHacknet(ns) > hacknet.getCacheUpgradeCost(findCUCache(ns), 1)) {
    hacknet.upgradeCache(findCUCache(ns), 1);
  }
  report(ns);
  ns.print(upgradeReport(ns));
  return;
}

function done(ns) {
  if ((hacknet.getPurchaseNodeCost() == Infinity) &&
      (hacknet.getCoreUpgradeCost(MAX_NODES - 1, 1) == Infinity) &&
      (hacknet.getRamUpgradeCost(MAX_NODES - 1, 1) == Infinity) &&
      (hacknet.getLevelUpgradeCost(MAX_NODES - 1, 1) == Infinity) &&
      (hacknet.getCacheUpgradeCost(MAX_NODES - 1, 1) == Infinity)) {
    // case is the 'normal' way to end this script
    ns.tprint("All Nodes bought and completly upgraded!");
    return true;
  } else if ((MRF == 0) && (doneFR(ns))) {
    // case with only enough hacknet capacity for Netburners faction
    return true;
  } else return false;	// default case - keep running the script
}

 

Main script ‘hacknet-manager.js’ Configuration and Main Loop

  // *************
  // configuration
  // *************

  ns.tail();
  ns.disableLog("sleep");
  ns.disableLog("getServerMoneyAvailable");

  // *********
  // main loop
  // *********

  while(!done(ns)) {
    if (!doneFR(ns)) upgradeFR(ns);
    else upgrade(ns);
    await ns.sleep(SLEEP_TIME);
  }
}

 

Final Thoughts

The script is not using objects. That would be my biggest planed update. But so far it does exactly what it was build to do. 🙂

Thanks to SilentKnight for his excellent guide, all credits belong to his effort. if this guide helps you, please support and rate it via Steam Community. enjoy the game.

Related Posts:

About Robins Chew

I'm Robins, who love to play the mobile games from Google Play, I will share the gift codes in this website, if you also love mobile games, come play with me. Besides, I will also play some video games relresed from Steam.

Leave a Comment