Multiplayer - Direct Connect through in-game UI

#1

Please, I understand that the game’s active development is going to be winding down, but is there any way we can get an in-game main menu UI option to direct connect to an IP address?

Please?

#2

the game is pretymuch dead in the water except for mods. unless someone figures out how to mod it in: its not going to happen unfortunatelly. now to be fair we still have one or two absolute grandlevel wizards of modding shuffeling around, but this sounds like a bridge too far to me.

#3

Yeah, I was hoping for one more last-ditch dev effort - considering the game isn’t going to be supported, being able to have multiplayer host/connect functions wired into the UI bypassing steam seems the best way to “open it up”.

#4

Should be possible. It’s all just user_settings.json configuration, which you can do through the API. Opening the port in your firewall or figuring out peer IP from some other contact info is the hard part which isn’t possible through a mod alone.

1 Like
#5

I guess the real point is the idea that I can try repeatedly through the menu to hash out connection problems, rather than restarting the game each time.

Kind of a pain … not to mention it’s not very user-friendly. :man_shrugging:

1 Like
#6

Unfortunately since there’s no way to call BeginConnect from lua, the easiest way to do this would be through a separate launcher. A hypothetical launcher would:

  1. Fetch a list of IP/ports that are currently hosting a game of Stonehearth from a 3rd party server that hosts game meta data.
  2. Display that list, with join buttons & metadata
  3. When a join button is clicked, launch Stonehearth with these options:
Stonehearth.exe --steam.enabled=false --multiplayer.remote_server.enabled=true --multiplayer.remote_server.ip='192.168.1.1' multiplayer.remote_server.port=42

With multiplayer.remote_server.ip & multiplayer.remote_server.port set to whatever the server’s IP:Port combo is. Also, the single quotes around the IP address are important, double quotes don’t work.

If the launcher was written with electron, the launch function could look like this:

const { spawn } = require('child_process');

function launchStonehearth(ip, port) {
  let args = [
    `--steam.enabled=false`,
    `--multiplayer.remote_server.enabled=true`,
    `--multiplayer.remote_server.ip='${ip}'`,
    `--multiplayer.remote_server.port=${port}`
  ];
  spawn("Stonehearth", args, { shell:true });
}

Assuming the launcher lived in the same folder as Stonehearth. I’ve attached an empty-ish electron app to help anyone interested get started: stonehearth-launcher.zip (43.4 KB)

In the end, the tricky part is not launching the game, it’s maintaining the server list. I think @Bolune made good progress on a headless mode a while ago, I’m not sure where it ended up but it was very impressive.

Depending on where he got with that, you could have a list of headless servers that run on AWS or something that you can connect to. That would make managing the list of available servers a little less painful. A cheap hack for that might be a google spreadsheet that the launcher pulls the data from.

I understand this is waaay less than ideal, but I hope it helps someone or is mildly interesting!

3 Likes
#7

I did consider making an external launcher but I disliked the idea that people would need to load up an exe file that isn’t apart of Stonehearth so I didn’t bother.

Sounds like my multiplayer.remote_server.ip issue was because I used double quote.

Headless mode does work. I ran it on a variety of AWS instances. You do not need the GPU addon. For AWS, I used either c5.xlarge or c5.2xlarge.

Saving the game works if you use a pre-loaded save.

You can check out the README for notes and the mod code to enable multiplayer settings at run time for (auto generated worlds)

2 Likes
#8

Awesome! I’m really happy you put that together and hosted it on github!

Sorry about the double quotes thing, I thought they should work because I specifically had to write a hack to support them at one point: boost::algorithm::trim_if(remoteServerHost, boost::algorithm::is_any_of("\"'")); So technically you don’t even need the second quote, it’s just a hack to get the argument parser to treat the address as a string.

Anyway I had another thought as I drifted off to sleep last night, one could use firebase to keep track of hosts, and just let the launcher declare new hosts. Slightly more involved than a google sheet though: Firebase Realtime Database | Store and sync data in real time  |  Firebase

1 Like
#9

Firebase is a great suggestion. Free SSL and html hosting. For low traffic sites, I always recommend to use firebase since you can get away with the free plan or by adding in a credit card to increase the basic limits.

1 Like
#10

Creating a master server should be relatively easy. You just need to specify the protocol, for which I’d suggest “borrowing” the one I’ve seen a few years ago in another game.

Basically, there’s a client and a masterserver, which holds the list. The masterserver has a few operations:

  • List: Shows the list of currently running games.
  • Add: Adds a game to the list.
  • Update: Updates a game on the list.
  • Remove: Removes a game on the list.

Update is necessary to avoid having “dead” games. If a game doesn’t send an update within a reasonable timeframe (30s-5min), it’s considered dead and de-listed.

Each game information contains the necessary meta-information, such as the IP/Port of the server/player (preferably determined by the server, i.e. the client just sends 0.0.0.0 and the master server replaces it with the remote IP from the request), game name, player name, player count, and other data that could be relevant, such as playtime, or players that are playing in said game. Of course, a mod list might also be useful to enable/acquire or just list mods prior to joining.

In order for the announcement part to work, you’d need to HTTP to the server though - which isn’t that difficult, if you’re willing to break some rules (cough HHH). Since the hosting/announcing would probably work independent of any launcher (and could be done for local hosted games as well), you could easily separate the actions. Launcher lists games and launches the game; game itself announces itself on the server and keeps tab on it.

Bonus: If you are already breaching the game’s sandbox by allowing HTTP calls, you could have the launcher host a local http server (bound to localhost to avoid external exploits) to issue commands. That would allow an in-game server browser in the following, very hacky style:

  1. Game contacts master server, lists games to player.
  2. Player selects a game and clicks join.
  3. Game contacts launcher; passes the necessary game information as content. After the request is done, game exits itself.
  4. Launcher waits until the process is dead, then starts Stonehearth again, passing the necessary args to join the game.

Not exactly nice, but could work.

2 Likes