Skip to content

NETSCRIPT: Add functionality and support to fully allow Players to use IP addresses in place of hostnames #1990

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Apr 11, 2025

Conversation

NagaOuroboros
Copy link
Contributor

@NagaOuroboros NagaOuroboros commented Mar 2, 2025

Motivation

While looking through the source code, I noticed that the game widely has the ability to accept IPs where it accepts hostnames. This intrigued me since IPs are randomly assigned at reset/install, making them dynamic as opposed to the static hostnames.

I began considering the idea of using primarily IPs instead of Hostnames as a challenge/aesthetic option, but quickly hit a few obstacles to doing so:

  1. The connect terminal/Singularity command fails to properly use IP addresses
  2. There is no IP equivalent to the hostname terminal command
  3. The only way to get an IP address from a hostname in a script is to use the very expensive ns.getServer("hostname").ip
  4. Core methods, like ns.scan(), return only hostnames, even though the terminal equivalent displays both hostname and IP
  5. Many API methods that take a hostname can also properly handle taking an IP in its place, but then assume later in the logic that the player passed a hostname without verifying and error/fail at these assumption points, preventing the use of IPs.
  6. The documentation and source code variable naming conventions do not properly differentiate between functions that can take either an IP or hostname, and those that can only take one or the other.

Scope

This PR's goal is to remedy these obstacles so that IPs can be consistently accessed and used across the game at the Player's option. In pursuit of this, I took the following approach:

  • In most cases, a simple documentation change and edit to variable names to indicate an IP address is a viable input was all that was needed.

  • In cases where a new method made the most sense, I implemented them with functional parity to their hostname counterparts where applicable.

  • Where it made no sense to pass an IP address instead of a hostname, I instead shored up the string checking to ensure an IP cannot be successfully passed.

  • In all cases, I ensured proper and consistent use between 'host', 'hostname', and 'ip' in both documentation and player-facing code.

Splitting this task into multiple PRs would not make sense, in my opinion, as the individual changes do not stand on their own and are more properly rolled into a single feature. This PR should be feature positive and make no regressions or major breaking changes.

New Terminal Command

  • ipaddr - Prints the current server's IP to the terminal

New API Methods

  • ns.getIP() - Returns the IP address of the script's current server
  • ns.scanByIP(host) - Functionally identical to ns.scan, but returns IP addresses
  • ns.getPurchasedServersByIP() - Functionally identical to ns.getPurchasedServers, but returns IP addresses
  • ns.dnsLookup(host) - Given a hostname, returns its IP address; or given an IP address, returns its hostname

Major Changes

  • connect - Both the terminal command and ns.singularity.connect(host) now allow IP addresses as arguments
  • ns.purchaseServer(hostname, ram) - Will not accept an IP-formatted string as a hostname
  • ns.renamePurchasedServer(hostname, newName) - Will not accept IP-formatted strings in either argument

Considerations

  • An argument could be made that dealing with the dynamic nature of the game's random IPs could merit a cheaper RAM cost than the equivalent hostname methods as a trade-off, however this PR defaults to parity in RAM cost.

  • The new ns.dnsLookup method is given a RAM cost of 0. Given that you must already have an IP or Hostname to use this method, the bidirectional conversion should be costless, as there's no functional difference in gameplay.

  • An argument could be made that ns.dnsLookup should be split into ns.dnsLookup and ns.dnsReverseLookup, which is more true-to-life. However, given the simplicity of the actual operation being performed, I found making one method instead of two was the more ergonomic choice.

  • The name for the new terminal command ipaddr is not necessarily final. Suggestions for an alternative, more 'CLI-flavored' name are welcome, and I'll happily change the name to conform whatever is more desired.

Demo Script for new NS functionality

https://gist.github.com/NagaOuroboros/6c27c61f2f478f8cb22f71c1ba894d05

@Alpheus
Copy link
Contributor

Alpheus commented Mar 2, 2025

This is a great addition, kuddos for the attention to documentation

@NagaOuroboros
Copy link
Contributor Author

Rebased onto version 2.8.0 final release.

@NagaOuroboros
Copy link
Contributor Author

NagaOuroboros commented Mar 8, 2025

Summary of cumulative changes

Removed from PR

ns.scanByIP - see new ns.scan signature
ns.getPurchasedServersByIP - see new ns.getPurchasedServers signature

New Terminal Command

  • ipaddr - Prints the current server's IP to the terminal

New API Methods

  • ns.getIP() - Returns the IP address of the script's current server
  • ns.dnsLookup(host) - Given a hostname, returns its IP address; or given an IP address, returns its hostname

Changed API Signatures

  • interface HostReturnOptions - A new @public type to control how a server identifier (hostname or IP address) is returned.
  • ns.scan(host?, returnOpts?) - New returnOpts parameter is a HostReturnOptions object. host can be null, allowing returnOpts to be used with host's default behavior.
  • ns.getPurchasedServers(returnOpts?) - New returnOpts parameter is a HostReturnOptions object.
  • ns.singularity.getCurrentServer(returnOpts?) - New returnOpts parameter is a HostReturnOptions object.

New NetscriptHelper Functions

interface CompleteHostReturnOptions - an interface with non-optional, type-validated members of the HostReturnOptions type.
helpers.hostReturnOptions(returnOpts) - validates returnOpts as a HostReturnOptions object, returning the default values for empty fields as a CompleteHostReturnOptions type.
helpers.returnServerID(server, returnOpts) - changes which identifier (hostname or IP) is returned, based on the returnOpts object, which must be of the CompleteHostReturnOptions type.

Other Changes

  • All API methods that take host as a parameter will now accept either an IP or hostname
  • connect - Both the terminal command and ns.singularity.connect(host) now allow IP addresses as arguments
  • ns.purchaseServer(hostname, ram) - Will not accept an IP-formatted string as a hostname
  • ns.renamePurchasedServer(hostname, newName) - Will not accept IP-formatted strings in either argument

Considerations

  • The name for the new terminal command ipaddr is not necessarily final. Suggestions for an alternative, more 'CLI-flavored' name are welcome, and I'll happily change the name to conform to whatever is more desired.

  • The new ns.dnsLookup method is given a RAM cost of 0. Given that you must already have an IP or Hostname to use this method, the bidirectional conversion should be costless, as there's no functional difference in gameplay.

  • An argument could be made that ns.dnsLookup should be split into ns.dnsLookup and ns.dnsReverseLookup, which is more true-to-life. However, given the simplicity of the actual operation being performed, I found making one method instead of two was the more ergonomic choice.

New Demo Script

https://gist.github.com/NagaOuroboros/552ce05724831e5368592f89ba8e6d1a

@d0sboots
Copy link
Collaborator

d0sboots commented Mar 13, 2025

Design-wise, I think I have only one major quibble left:

ns.getIP() is duplicating ns.singularity.getCurrentServer, and given the existence of ns.dnsLookup it also makes it obsolete. I don't think it should be added; knowing what server you're connected to is a singularity API thing, and already sufficiently covered.

I think I would like a small-but-positive cost on dnsLookup, since it can be used to probe for the existence of servers. Other than that, names and design of function/commands seem good, I'll try to get to a detailed review soon.

@NagaOuroboros
Copy link
Contributor Author

NagaOuroboros commented Mar 14, 2025

ns.getIP() is meant to be the IP companion to ns.getHostname(), not ns.singularity.getCurrentServer, as they have different applications: the former being for the Script context (what server the Script is running on), the latter being the Terminal context (what server the Terminal is connected to). While I do concede that it's technically unneeded with the existence of ns.dnsLookup + ns.self().server, it still has its own justification, especially if ns.dnsLookup is to receive a positive cost.

If ns.dnsLookup(ns.getHostname()) costs more than ns.getHostname(), then there's a cost imbalance between the two identifiers. I am not on principle opposed to this—especially since ns.self().server can be used to mediate the total cost, and that kind of puzzle-solving/optimization should be rewarding—but I think such an imbalance should be deliberate, rather than incidental, so I just want to confirm that this would be considered a designed cost imbalance that favors using hostnames before a final decision on ns.getIP() is reached.

As a side-note, and related to the cost of ns.dnsLookup, I specifically did not touch ns.self().server due to how the RunningScript object is used on the back-end, so no matter what, it will always be cheaper to get the hostname of the running script's context if ns.dnsLookup gets a non-zero cost.

Because of this, I would argue in favor of ns.dnsLookup receiving a cost of 0.05 GB. This will at least mean that ns.dnsLookup(ns.self().server) has the same RAM cost as ns.getHostname(), regardless of if ns.getIP() is dropped or not. Bringing the cost up to even 0.1 GB (to match ns.serverExists, for example) would only further justify keeping ns.getIP(), so I would not suggest it if ns.getIP() isn't going to make it into the final merge.

@NagaOuroboros
Copy link
Contributor Author

Resolved conflict with PR#1999.

@NagaOuroboros
Copy link
Contributor Author

Resolved conflict with PR#2036.

Copy link
Collaborator

@d0sboots d0sboots left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Some comments may have already been addressed by your latest commit.

@NagaOuroboros
Copy link
Contributor Author

Everything should be squared away now!

@d0sboots d0sboots merged commit 0aaa280 into bitburner-official:dev Apr 11, 2025
5 checks passed
@NagaOuroboros NagaOuroboros deleted the ip-support branch April 11, 2025 01:56
antoinedube pushed a commit to antoinedube/bitburner-source that referenced this pull request Apr 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants