NS2

The improved version of Netscript that allows users to write full-fledged Javascript code in their scripts, while still being able to access the Netscript functions.

ns2 was developed primarily by Github user jaguilar

On top of having almost all of the features and capabilities of JavaScript, ns2 is also significantly faster than ns1.

This documentation will not go over any of the additional features of ns2, since there is plenty of documentation on Javascript available on the web.

Browser compatibility

As of the time of writing this, a few browsers do not support dynamic import functionality and therefore cannot run ns2 scripts. These browsers will thus only be capable of using ns1.

How to use ns2

Working with ns2 scripts is the same as ns1 scripts. The only difference is that ns2 scripts use the “.js” extension rather than “.script”. E.g.:

$ nano foo.js
$ run foo.js -t 100 arg1 arg2 arg3
exec("foo.js", "purchasedServer1", "100", "randomArg");

The caveat when using ns2 to write scripts is that your code must be asynchronous. Furthermore, instead of using the global scope and executing your code sequentially, ns2 uses a main() function as an entry point.

Furthermore, the “Netscript environment” must be passed into a ns2 script through the main function. This environment includes all of the pre-defined Netscript functions (hack(), exec, etc.) as well as the arguments you pass to the script.

Therefore, the signature of the main() function must be:

export async function main(ns) {
    ns.print("Starting script here");
    await ns.hack("foodnstuff"); //Use Netscript hack function
    ns.print(ns.args);           //The script arguments must be prefaced with ns as well
}

Here is a summary of all rules you need to follow when writing Netscript JS code:

  • Write await before any call to the following Netscript functions:

    • hack
    • grow
    • weaken
    • sleep
    • prompt
    • wget
    • scp
    • write
    • writePort
  • Any function that contains await must be declared as async

  • Always await any function that is marked as async

  • Any functions that you want to be visible from other scripts must be marked with export.

  • Do not write any infinite loops without using a sleep or one of the timed Netscript functions like hack. Doing so will freeze your game.

  • Any global variable declared in a ns2 script is shared between all instances of that script. For example, assume you write a script foo.js and declared a global variable like so:

    //foo.js
    let globalVariable;
    
    export async function main(ns) {
        globalVariable = ns.args.length;
        while(true) {
            ns.tprint(globalVariable);
            await ns.sleep(3000);
        }
    }
    

    Then, you ran multiple instances of foo.js:

    $ run foo.js 1
    $ run foo.js 1 2 3
    $ run foo.js 1 2 3 4 5
    

    Then all three instances of foo.js will share the same instance of globalVariable. (In this example, the value of globalVariable will be set to 5 because the last instance of foo.js to run has 5 arguments. This means that all three instances of the script will repeatedly print the value 5).

    These global variables can be thought of as C++ static class members, where a ns2 script is a class and a global variable is a static member within that class.

Example

early-hack-template.script

var target = args[0];
var moneyThresh = getServerMaxMoney(target) * 0.75;
var securityThresh = getServerMinSecurityLevel(target) + 5;
if (fileExists("BruteSSH.exe", "home")) {
    brutessh(target);
}
nuke(target);
while(true) {
    if (getServerSecurityLevel(target) > securityThresh) {
        weaken(target);
    } else if (getServerMoneyAvailable(target) < moneyThresh) {
        grow(target);
    } else {
        hack(target);
    }
}

early-hack-template.js

export async function main(ns) {
    var target = ns.args[0];
    var moneyThresh = ns.getServerMaxMoney(target) * 0.75;
    var securityThresh = ns.getServerMinSecurityLevel(target) + 5;
    if (ns.fileExists("BruteSSH.exe", "home")) {
        ns.brutessh(target);
    }
    ns.nuke(target);
    while(true) {
        if (ns.getServerSecurityLevel(target) > securityThresh) {
            await ns.weaken(target);
        } else if (ns.getServerMoneyAvailable(target) < moneyThresh) {
            await ns.grow(target);
        } else {
            await ns.hack(target);
        }
    }
}

What’s with the weird comment

You may have noticed that every new ns2 file will contains the following comment.

/**
* @param {NS} ns
**/

This comment is used to help the text editor autocomplete functions in the Netscript API. You can enable it by pressing ctrl+space after ns.

../_images/autocomplete.png

The comment can be safely removed but it is recommended to keep it as it will help you.