Bitburner

Bitburner

33 ratings
Kupos automated HWGW Manager - centralized prep and farm of one or many servers
By Kupo
Find out how a HWGW manager is built, what you need for it, and see a complete, well-functioning implementation.
Besides in-line comments, the guide aims to help you build, improve or start your own HWGW manager.
3
   
Award
Favorite
Favorited
Unfavorite
Introduction - guide content
In this guide you will find all the code and explanations needed to get the HWGW Manager up and running. This includes the one-shot scripts needed and simple data/code to provide the necessary basics to make the script work, even if you don't have your own solution for it yet.

You will also find some explanations in this guide and inline comments in the code itself.

This code is written so that you can understand the manager and adapt or extend it to your needs. If you are unable to do so with the information given, please let me know.

Disclaimers:
This is my first manager script, also my first guide, and furthermore I have not been playing BitBurner for months, but rather weeks.
I am also in no way a professional programmer, which you don't need to be for this game though.
I have done 'special' things like the ? : operation very rarely and instead used few typical programming structures to make it easy to follow what the manager is actually doing.
Feel free to let me know your thoughts on how to improve the code quality.

I'm also not a native English speaker and haven't checked the content of this guide with a translator, so there may be some strange expressions. Just give me a hint so I can correct them.

As the code had a few changes, also the variable names, always be careful when using parts of screenshots. These images are just so you can focus on what is going on, not meant to be typed out. Make sure to doublecheck you always use the code in the big section or pastebin code.
What is...
Depending on your playing time and experience with BitBurner, you may have a few questions straight away, so let's go through the basics again:

What is HWGW?
HWGW Batching means that you queue together the following:
- a hack,
- a weaken to counter the hack,
- a grow to counter the hack,
- and another weaken to counter the grow

This, if done correctly, results in no change to the money available and the security level on the target server. This in turn makes our lives much easier because we can do the same things effectively over and over again.
To learn more about HWGW, read this if you haven't already:
https://bitburner.readthedocs.io/en/latest/advancedgameplay/hackingalgorithms.html#batch-algorithms-hgw-hwgw-or-cycles

What do you mean, centralized?
The manager script works much like a command-and-control (C2) server and runs in a single thread on your machine. It acts as a manager, orchestrating what you want the other servers to do. Therefore, the management is only on one server and not on all servers, resulting in less RAM consumption and better management (no need to communicate with the other 25 servers).
All other servers will only use one-shot scripts.

One-shot what?
These are one-time only scripts that wait a set amount of time, start hack/grow/weaken and finish at the same time as all other scripts in the batch. They do not contain while(true) loops.
This is very effective as only the threads that are needed at the time are running. No need to terminate loops or waste actions that are no longer needed.

prep and farm, what is it?
To farm your goal efficiently, you want to grow the money to the maximum and reduce the security level to the minimum.
Getting the server into this state is called prepping (at least that's what I call it).
Farming is done on a well-prepped server, where we only hack enough to compensate by growing and weakening at the same time.
The manager does both automatically, prepping servers that need it and farming servers that are ready.
RAM Usage
The manager currently uses 11.10GB of RAM on your home computer.
This increases by 0.3 GB if you include the opening/cracking system.


If you want, you can easily outsource the 2.25 GB from the purchase server search.
You can hardcode it or use an external script that runs it once every x minutes and saves it in a txt file.
You can also reduce the script by another 3 GB and hardcode weakenAnalyze, growthAnalyzeSecurity and hackAnalyzeSecurity as they are static.
Prerequisite 1: One-Shot-Scripts
These are the scripts that do the actual work.
They need to be located on your home server, in the 'shared' folder.
To create them, just type/paste the command above the snippets in your terminal, and then the code in the editor, and save.

nano /shared/hack.js
/** @param {NS} ns **/ export async function main(ns) { //sleep for given amount const sleep = ns.args[1] || 1; await ns.sleep(sleep); //and then hack! await ns.hack(ns.args[0]); }

nano /shared/grow.js
/** @param {NS} ns **/ export async function main(ns) { //sleep for given amount const sleep = ns.args[1] || 1; await ns.sleep(sleep); //and then grow! await ns.grow(ns.args[0]); }

nano /shared/weaken.js
/** @param {NS} ns **/ export async function main(ns) { //sleep for given amount const sleep = ns.args[1] || 1; await ns.sleep(sleep); //and then weaken! await ns.weaken(ns.args[0]); }
Prerequisite 2: Gathering a target server list and/or the best target
For now I will assume you have a servercrawler orsome other solution that will scan the network for good targets.You can of course just manually scout targets with scan-analyze, although this should be automated by you eventually.
If automated, your script should either store them in a txt file with a filehandler, or you can just hardcode an array with all servers you know in our script (you do not need to filter based on root access/hack level).

Example:
const targets = ["n00dles","foodnstuff","sigma-cosmetics","joesguns","hong-fang-tea","harakiri-sushi","iron-gym","darkweb","home","zer0"]; // and all other servers you found

The same goes for a single best target. If you are early in your game, you may want to hack only one server instead of all of them. Chosing the best server is not yet done by the manager, BUT you will find a section in this guide with exactly that function you can just insert.
Of course you can also just hardcode your best target into the manager.

Example:
const primeTarget = "foodnstuff"; // or any else good server

Note for the primeTarget:
If you give the manager a target you cannot hack (because you cant get root access or do not have the required Hacklevel), nothing will happen.
The manager will just ignore the target, because it can't be hacked. You won't get a warning or a crash, so make sure to doublecheck if you hardcode a server here.

I did include these hardcoded examples in the manager script, so you just need to swap which lines should be a comment and which not.

original:

change it to:

If you prefer the HWGW Manager chosing the best target, see the targeter section.
Prerequisite 3: Opening target servers and script distribution
The manager uses a list of servers (or a single server) that is already nuked.
Also the one-shot files also need to be on the servers you want to farm.

I have a seperate servercrawler script, which saves the servers in a txt file, takes care of all that.
I recommend you to do the same, but this is for now out of scope.

If you do not have this kind of thing, no problem, take this and insert it into the manager script:

await ns.scp([ "/shared/weaken.js", "/shared/grow.js", "/shared/hack.js" ], server); if (!ns.hasRootAccess(server)) { let openPorts = 0; if (ns.fileExists("BruteSSH.exe")) { ns.brutessh(server); openPorts++; } if (ns.fileExists("FTPCrack.exe")) { ns.ftpcrack(server); openPorts++; } if (ns.fileExists("RelaySMTP.exe")) { ns.relaysmtp(server); openPorts++; } if (ns.fileExists("HTTPWorm.exe")) { ns.httpworm(server); openPorts++; } if (ns.fileExists("SQLInject.exe")) { ns.sqlinject(server); openPorts++; } if (ns.getServerNumPortsRequired(server) <= openPorts) { ns.nuke(server); } }
this is one possible solution showcased in Suikoudans Scripting 101 guide

This snippet needs to go below
for (let target of targets) { // ...we stick with THE BEST one. Adjust the criteria to your liking. if (earlyGameCheck) target = primeTarget;
and above
//Is our given server even useable? if (!ns.serverExists(target) || !ns.hasRootAccess(target) || ns.getServerMaxMoney(target) < 1) continue;
The HWGW Manager - Part 1
Alright, here it is, the manager itself.

I tried to comment every part more or less helpfully, if something misses, just tell me.
I do not explain the calculation in my code, so this will be in another chapter.

If you do not like the steam guide format for the code, here is a pastebin: https://pastebin.com/ZedF1fLf

Because of steam guide limitations i need to split the code in 2 parts.
Be sure to double check if you got it together the correct way.

And now on to the code (you can use whatever name and folder you like)
nano kuposhwgwmanager.js
/** @param {NS} ns **/ // Used for importing targets from other scripts import { FileHandler } from "/data/file-handler.js"; export async function main(ns) { //Logs are nice to know whats going on ns.disableLog('sleep'); ns.disableLog('getServerMaxRam'); ns.disableLog('getServerUsedRam'); ns.disableLog('getServerSecurityLevel'); ns.disableLog('getServerMinSecurityLevel'); ns.disableLog('getServerMaxMoney'); ns.disableLog('getServerMoneyAvailable'); ns.disableLog('getHackingLevel'); // If you do not want an open tail window with information what this script is doing on every start, you can remove/comment the tail line below. ns.tail(); // Used for importing targets from other scripts const FILEHANDLER_SERVERS = new FileHandler(ns, "/database/servers.txt"); const FILEHANDLER_TARGET = new FileHandler(ns, "/database/target.txt"); const RAM_PER_THREAD = ns.getScriptRam("/shared/weaken.js"); // So many weaken threads are needed to counter one hack/grow thread. let WEAKEN_PER_THREAD = ns.weakenAnalyze(1); let HW_THREADS = ns.hackAnalyzeSecurity(1) / WEAKEN_PER_THREAD; let GW_THREADS = ns.growthAnalyzeSecurity(1) / WEAKEN_PER_THREAD; const RESERVED_HOME_RAM = 50; //GB - change if you want to reserve more of you home ram const SLEEP_ITERATION = 1; // ms - reduce if you need to go even faster, or raise if you get lag spikes const PAUSE_ITERATION = 10 // seconds - Pause after the script did touch every server and every target - how often should it run again // This will be used to make sure that every batch goes through and is not blocked my "script already running with same arguments" let randomArgument = 1; while (true) { // read (new) targets - if you do not use fileHandlers like i do, just throw in an array of targets or a function or anything really. // If desperate or no clue, use the commented lines instead and change target to your highest/best target you currently have const TARGETS = await FILEHANDLER_SERVERS.read(); //const TARGETS = ["n00dles","foodnstuff","sigma-cosmetics","joesguns","hong-fang-tea","harakiri-sushi","iron-gym","darkweb","home","zer0","CSEC","nectar-net","max-hardware","neo-net","silver-helix","phantasy","omega-net","computek","netlink","johnson-ortho","the-hub","crush-fitness","avmnite-02h","catalyst","I.I.I.I","summit-uni","syscore","rothman-uni","zb-institute","lexo-corp","rho-construction","millenium-fitness","alpha-ent","aevum-police","aerocorp","snap-fitness","galactic-cyber","global-pharm","omnia","deltaone","unitalife","solaris","defcomm","icarus","univ-energy","zeus-med","taiyang-digital","zb-def","infocomm","nova-med","titan-labs","applied-energetics","microdyne","run4theh111z","stormtech","helios","vitalife","fulcrumtech","4sigma","kuai-gong",".","omnitek","b-and-a","powerhouse-fitness","nwo","clarkinc","blade","ecorp","megacorp","fulcrumassets","The-Cave"]; // The best server we know for our current state. Or just a random one you can tackle. const PRIME_TARGET = await FILEHANDLER_TARGET.read(); //const PRIME_TARGET = "foodnstuff"; // For this manager we only use home + purchased servers. Other servers have almost no RAM. let servers = ns.getPurchasedServers(); servers = servers.concat("home"); // If we are so early in the game that we can't even effectively farm ALL servers... const GOOD_HACK_LEVEL = 750; let earlyGameCheck = false; if (ns.getHackingLevel() < GOOD_HACK_LEVEL && ns.serverExists(PRIME_TARGET) && ns.hasRootAccess(PRIME_TARGET) && ns.getServerMaxMoney(PRIME_TARGET) > 1) earlyGameCheck = true; for (let target of TARGETS) { // ...we stick with THE BEST one. Adjust the criteria to your liking. if (earlyGameCheck) target = PRIME_TARGET; if (!ns.serverExists(target) || !ns.hasRootAccess(target) || ns.getServerMaxMoney(target) < 1) continue; const S_MAX_MONEY = ns.getServerMaxMoney(target); const S_MIN_SEC_LEVEL = ns.getServerMinSecurityLevel(target); let currentSecLevel = ns.getServerSecurityLevel(target); let availableMoney = Math.max(1, ns.getServerMoneyAvailable(target)); let growthCalculated = false; let requiredGrowThreads = 0; let batchDelay = 0; for (let server of servers) { if (!ns.serverExists(server) || !ns.hasRootAccess(server)) continue; //Calculate possible threads - If "home", we want some spare some RAM let threadsToUse = Math.floor((ns.getServerMaxRam(server) - ns.getServerUsedRam(server) - (server == "home" ? RESERVED_HOME_RAM : 0)) / RAM_PER_THREAD); if (threadsToUse < 1) continue; // Home multi-core support let S_CORES = 1; if (server == "home") { S_CORES = ns.getServer("home").cpuCores; HW_THREADS = ns.hackAnalyzeSecurity(1) / WEAKEN_PER_THREAD; GW_THREADS = ns.growthAnalyzeSecurity(1, target, S_CORES) / WEAKEN_PER_THREAD; } WEAKEN_PER_THREAD = ns.weakenAnalyze(1, S_CORES); // Weaken the server down to minimum sec level if (currentSecLevel > S_MIN_SEC_LEVEL) { const REDUCED_SEC_LEVEL = WEAKEN_PER_THREAD * threadsToUse; // Only use needed threads if (currentSecLevel - REDUCED_SEC_LEVEL < S_MIN_SEC_LEVEL) { threadsToUse = Math.ceil((currentSecLevel - S_MIN_SEC_LEVEL) / WEAKEN_PER_THREAD); currentSecLevel = S_MIN_SEC_LEVEL; } else currentSecLevel -= REDUCED_SEC_LEVEL; ns.exec("/shared/weaken.js", server, threadsToUse, target, 0, randomArgument++); } // Grow the server to the maximum money else if (availableMoney < S_MAX_MONEY && (requiredGrowThreads != 0 || !growthCalculated)) { if (!growthCalculated) { requiredGrowThreads = Math.ceil(ns.growthAnalyze(target, S_MAX_MONEY / availableMoney, S_CORES)); growthCalculated = true; } // Do not use more than needed threadsToUse = Math.min(requiredGrowThreads, threadsToUse) // Save still needed threads, if any, for this iteration requiredGrowThreads -= threadsToUse; // Factor in the raise in security level. currentSecLevel += ns.growthAnalyzeSecurity(threadsToUse, target, S_CORES); ns.exec("/shared/grow.js", server, threadsToUse, target, 0, randomArgument++); } // Fully prepped - Let's do batching else { //PASTE PART 2 HERE
The HWGW Manager - Part 2
// else { // PART 1 SHOULD BE ABOVE THIS LINE const HACK_MONEY_PERCENTAGE = ns.hackAnalyze(target); if (HACK_MONEY_PERCENTAGE == 0) continue; // Thread calculation let hackThreads = Math.ceil(threadsToUse / 8); let growThreads, weakenThreads, weakenThreads2, goLower = false; while (true) { // Do not use more threads than needed for emptying a target if (HACK_MONEY_PERCENTAGE * hackThreads > 1) hackThreads = Math.ceil(1 / HACK_MONEY_PERCENTAGE); // Calculate grow threads and weaken threads for the hackThreads amount growThreads = Math.ceil(ns.growthAnalyze(target, 1 / (1 - Math.min(0.99, HACK_MONEY_PERCENTAGE * hackThreads)), S_CORES)); weakenThreads = Math.ceil(HW_THREADS * hackThreads); weakenThreads2 = Math.max(1, Math.ceil(GW_THREADS * growThreads)); // GW_THREADS could be 0 // How much percent of threads would this take? let threadUsage = (hackThreads + growThreads + weakenThreads + weakenThreads2) / threadsToUse; // If too much, reduce and calculate again, or stop if we cant go lower. if (threadUsage > 1) { if (hackThreads > 1) { hackThreads--; goLower = true; } else break; } // If we have enough free processes, lets raise hackThreads and calculate again else if (Math.floor((1 - threadUsage) * hackThreads) > 1) { hackThreads += Math.floor((1 - threadUsage) * hackThreads / 2); if (goLower) break; //This is to prevent a softlock going up and down 1 thread. } else // This is perfect. Get out with perfect thread amounts. break; await ns.sleep(1); } const THREAD_DELAY = 100; //ms ns.exec("/shared/weaken.js", server, weakenThreads, target, batchDelay, randomArgument); ns.exec("/shared/weaken.js", server, weakenThreads2, target, batchDelay + THREAD_DELAY * 2, randomArgument); ns.exec("/shared/grow.js", server, growThreads, target, batchDelay + THREAD_DELAY + ns.getWeakenTime(target) - ns.getGrowTime(target), randomArgument); ns.exec("/shared/hack.js", server, hackThreads, target, batchDelay - THREAD_DELAY + ns.getWeakenTime(target) - ns.getHackTime(target), randomArgument++); // If we would fire the next HWGW without this batchDelay, they might intersect batchDelay += 4 * THREAD_DELAY; } await ns.sleep(SLEEP_ITERATION); } await ns.sleep(SLEEP_ITERATION); } await ns.sleep(PAUSE_ITERATION * 1000); } }

Again, i recommend to use the pastebin for easy copy pasting and better read with syntax highlighting, which I linked above part 1.
Nice-to-have: best single target selection
Since my target system is not particularly spectacular and I can well imagine that some do not have one at all, I am making mine available below.
This code snippet can simply be inserted into the manager where a file is otherwise read out via the file manager.
You can limit the best target to be hackable in x minutes via the maxminutes variable.

old code, remove (should be L43-45):
// The best server we know for our current state. Or just a random one you can tackle. const PRIME_TARGET = await FILEHANDLER_TARGET.read(); //const PRIME_TARGET = "foodnstuff";

new code, insert same place:
let primescore = 0; let primetarget; for (let target of targets) { const maxminutes = 30; if (!ns.serverExists(target) || ns.getServerMaxMoney(target) == 0 || ns.getServerRequiredHackingLevel(target) > ns.getHackingLevel() || !ns.hasRootAccess(target) || ns.getWeakenTime(target) > 1000 * 60 * maxminutes) continue; const newscore = ns.getServerMaxMoney(target) / ns.getServerMinSecurityLevel(target); if (newscore > primescore) { primescore = newscore; primetarget = target; } await ns.sleep(1); }
Nice-to-have: alias and service
This is completely optional and probably only useful, if you adjust and expand the manager to your liking.
With alias you can create a new, easier command for use.
Type or copy the following command in your terminal:
alias nanoman="nano kuposhwgwmanager.js"
change the name 'nanoman' to whatever you like. If you changed the name or path of the manager script, make sure to also use the correct one in your alias.

You can create another alias for (re)starting the manager script like that:
alias startman="kill kuposhwgwmanager.js;run kuposhwgwmanager.js"

also i recommend having a startup script, which starts all scripts you use.
This can be as simple as that:
nano start.js
/** @param {NS} ns */ export async function main(ns) { while(true) { if(!ns.isRunning("kuposhwgwmanager.js","home")) ns.run("kuposhwgwmanager.js",1); await ns.sleep(60000); } }

if you have more scripts, you can expand it like that:
/** @param {NS} ns */ export async function main(ns) { sleepPause = 60; //seconds while (true) { if (!ns.isRunning("servercrawler.js", "home")) ns.run("servercrawler.js", 1); ns.run("/v1/targeter.js", 1); if (!ns.isRunning("purchase-server.js", "home") && ns.getServerMoneyAvailable("home") > 11000000) ns.run("purchase-server.js", 1); if(!ns.isRunning("kuposhwgwmanager.js","home")) ns.run("kuposhwgwmanager.js",1); if (!ns.isRunning("hacknetmanager.js", "home") && ns.getServerMoneyAvailable("home") > 25000000) ns.run("hacknetmanager.js", 1); await ns.sleep(sleepPause * 1000); } }
With that you only need to use "run start.js" after a crash or a fresh start, you could even write alias for that too.
Nice-to-have: Log-Tail (or how to disable the window opening on startup)
If you are struggling to get this script to run or if you are expanding and adjusting the script it is always good to have the script log open.

For this i do have this part in the script, you can find it right below
export async function main(ns) {

The log partin the manager script is this:
//Logs are nice to know whats going on ns.disableLog('sleep'); ns.disableLog('getServerMaxRam'); ns.disableLog('getServerUsedRam'); ns.disableLog('getServerSecurityLevel'); ns.disableLog('getServerMinSecurityLevel'); ns.disableLog('getServerMaxMoney'); ns.disableLog('getServerMoneyAvailable'); ns.disableLog('getHackingLevel'); // If you do not want an open tail window with information what this script is doing on every start, you can remove/comment the tail line below. ns.tail();

If you are annoyed by it, you can simply comment the last line.
You can also adjust what you want to get shown in your log by changing the disable logs above.
Inspiration for this guide
I started out by using the guide "Scripting 101" by Suikoudan.
If you did not read that guide yet, i heavily recommend to do so.

You will learn how to build your own servercrawler and also how to do the filemanager thing.
Or at least get a good idea, how to do it yourself.
The opening of the server is also from that guide.
Details, Explanations, Calculations
In this section I will give some additional information about selected parts of the script.
If you miss something, feel free to ask for it in the comments.

Targeting - when to use a target.
Either a single, currently best target is used as a target, or all servers are used quasi parallel.
For now, the manager only checks your hacking level and matches it with the "goodHackingLevel" number, which is 750.
This could be done much better, but since I just made it up a few days ago, it will do for now.
I hope to improve this check in the future so that the script switches between a single goal or all goals exactly when the best time is. Share your thoughts on how to improve it.

Loops
By default, the manager will make an infinite loop with a pause of 10 seconds.
In each loop, it will select each target once.
And for each target, the manager will enter the necessary tasks on all your available servers.

Prepping.
Because of the rotation, prepping is simple and is done by the manager.
The script will take any server you have to reduce the security level to a minimum, but will not use more threads or servers than necessary.
Similar to the security level, the money is also increased to the maximum on all available servers without using more threads or servers than necessary.
The manager will also calculate the increase in security level, so the next of your servers will do it with another weakening.

Restriction: storage cross-loop.
Currently, the script only remembers the growth and security level of a server for one loop.
After that, it recalculates the required threads and forgets the started scripts that have not yet completed.
There will of course be improvements to address this in the future, but for now this will at worst waste a weakening/growth timeframe per unprepared target.

Limitation: growing and weakening from the same server.
The manager will not use the same server to grow and weaken while preparing the target server.
So it may happen that only half of the server's memory is used for weakening and then the next server is selected for growing.
I don't think this is a big problem because the server that is only half used is also considered for the next target and in the next loop (which happens after 10s by default). So there is no thread or excessive time wastage.

HWGW Thread Distribution
In the meantime, I was able to design a new algorithm for the calculation, which I think is very good.
It initially takes 1/8 of the available threads, and then calculates exactly how many threads would be needed for weakening and growing.
If this results in too many or too few threads, the whole process is recalculated with an adjusted value. The whole process continues until all threads are used optimally.
Of course, it is ensured that no deadlock occurs.
From my point of view, this process is also carried out very quickly, regardless of whether there are few or many threads.
In this way, the memory still available on each available server is used ideally.

Built-in fail-safes
One goal of this script was to programme it safely and without crashes.
To this end, all calculations are double-checked so you don't get annoying 0 or infinite thread warnings on exec or other crash causes.
If you manage to crash the script in the default configuration or with small changes to the variables, please let me know so I can improve it.
This is also why you will find a lot of Math.floor, Math.ceil, Math.min, Math.max and even more continue commands in it.
When creating this manager, I preferred to play it safe and may have accepted a few percent performance loss to do so.

Limitation: HWGW timing
Although I have checked my timing of the batch several times, I have rarely received reports from users who saw the batch not arriving in the desired order (but as HGWW, which is still acceptable and not a big loss).
If you find an error in my timing, please let me know.
Otherwise, threadDelay and/or batchDelay can be used to try to achieve an optimal configuration.
You can do this by editing the one-shot scripts to get an ns.tprint() with the appropriate values and check in the terminal how the prints arrive. I recommend this for debugging and improvement purposes only.
If your server crawler always copies the files on the servers, not just when they are first discovered/cracked, you can simply edit and save the scripts on your home server and all future scripts on all target servers will be updated with a delay. This also applies if you have copied the bit in the chapter directly into the manager.
FAQ
I will post some questions asked in here for better visibility.
If you have a question or feedback, you will surely not be the only one and I may just have done an error or failed to explain it clearly, so go ahead and leave all your feedback in the comments.
Thank you!
Changelog
V1.0.0 June 25th 2022
Initial release of the guide

V1.0.1 June 26th 2022
Added RAM Usage info

V1.1.0 June 26th 2022
Improved thread distribution with a nice new algorithm (L125-150)

V1.2.0 June 29th 2022
Multi-core support added.
Added optional "best single targeting" code chapter.
Minor code improvements.
the end
As I have said way too much in this guide, i am happy to get all kinds of feedback.
- You would change a phrasing?
- Got an improvement to the guide or the code?
- You doubt things stated in this guide are correct?
- The guide failed to explain something you need to understand for this script?
- You just want to leave your experience for others?

Just put it all in the comments so others know if this guide was actually helpful or just trash.

Thanks for reading and i hope this will help you on your BitBurner journey.

Apart from giving feedback i also encourage you to rate this guide, that would be very great!

8 Comments
SuperHero 13 Jan, 2024 @ 3:09pm 
now all i need to do is test it
hhaddow 3 Apr, 2023 @ 1:41pm 
I'm finding that when there is just one target the script will quite often spam grow/weaken prep commands because the loop has run during a HWGW action

I'm working on my own solution that will work something like this

>if target_flag not set
-->target_flag = 0 target is not prepped

>if not min sec
-->Launch threads to weaken the target to minimum

>Set target_flag = 1, the target is ready to grow

>if not max money
-->calculate if the current server can grow to maximum then reduce security to zero
-->if it can
---->run the G/W threads needed timed to occur after the initial weaken
-->else
---->calculate G/W ratio that can be run, run max G/W threads needed, precede to the next server and try to finish the G/W prep

>Set target_flag = 2, the target is ready for HWGW

>if target_flag == 2
-->run HWGW (might need a check that prevents the HWGW occurring before the prep)
rehajel 23 Jan, 2023 @ 11:01pm 
hey, don't worry about it.

I fixed it by breaking out of the loop once the hackamount becomes greater than 0.7 or something like that.
Merely asked because I thought you maybe accounted for that issue and I missed it ;)
It sure is a fascinating 'game'.

Have a nice day!
Kupo  [author] 23 Jan, 2023 @ 12:25pm 
@rehajel
I am sorry that i did not updated this as i didn't play that much lately.
But i am still glad you made the effort to think it through and noticed a problem i also encountered.

For your actual question about crashing i can only guess.
Always make sure you do have failsafes when using functions that can crash your script.
For example you can see that when i use growthAnalyze that there is a Math.min function in it to make sure there will never be a zero.
Print debugging helps to see what line and function may be the problem.
You can also send me your code and i may have a look into it.
Kupo  [author] 23 Jan, 2023 @ 12:25pm 
@rehajel Hi there, i am glad you want to learn for your own and do find my manager a helpful inspiration.
First off, calculation of threads and the timing of batches are complex problems that have not much to do with programming, so there is a variety of possible solutions.
I updated this particular calculation several times and have to admit that this is still not perfect.
I just checked my script and noticed that i updated this exact problem with 2 lines:

if (HACK_MONEY_PERCENTAGE * hackThreads > 1)
hackThreads = Math.ceil(1 / HACK_MONEY_PERCENTAGE);

this goes right at the top of the calculation loop and should fix what you describe, as this is an easy way to calculate how to get all of the money with minimum threads.

Please note that this is not optimal in earlier stages of the game as you surely do not want to empty a server.
rehajel 22 Jan, 2023 @ 7:56am 
I'm trying to build something similar based on your script. (trying to learn instead of just implementing a copied solution).
I'm currently trying to write the calculations for the number of threads for grow/hack/weaken.
As far as I can tell you do not account for the possibility that you have more threads available than you need to reduce the target to 0 (or below if it were possible) in your while(true) loop.
When I try to find the hackThreads, I end up crashing my program because of this.
Did I miss something?
Kupo  [author] 18 Aug, 2022 @ 4:55pm 
@Geeky Meerkat Wow great catch! You are absolutely right, i didn't notice until now! Kudos to you and i changed the code to simply move the rewrite out of the if statement. Thx again :)
Geeky Meerkat 15 Aug, 2022 @ 6:27pm 
Noticed a little mistake in your code. Early on in your code outside the loop you do a: let WEAKEN_PER_THREAD = ns.weakenAnalyze(1);

But inside the loop you check to see if the server you are getting set up is the Home server and if it is you set WEAKEN_PER_THREAD = ns.weakenAnalyze(1, S_CORES); but after that you never reset it back to ns.weakenAnalyze(1).

This means that after the first time your code does the Home server that all your other servers are using the wrong WEAKEN_PER_THREAD value.