Bitburner – Post-BN9 Hacknet Script

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?

Note: Credit goes to SilentKnight

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);
  }
}
Helena Stamatina
About Helena Stamatina 3201 Articles
I love two things in life, games and sports. Although sports were my earliest interest, it was video games that got me completely addicted (in a good way). My first game was Crash Bandicoot (PS1) from the legendary studio Naughty Dog back in 1996. I turned my passion for gaming into a job back in 2019 when I transformed my geek blog (Re-actor) into the gaming website it is today.

Be the first to comment

Leave a Reply

Your email address will not be published.


*