astroneer-rcon-client

2.2.9 • Public • Published

AstroneerRconClient

Version: 2.2.9
A client for the Astroneer RCON server built with Node.JS
NOTE: This library might no longer work with the latest RCON server versions and is outdated in Node.js's best practices. This library should be mainly used as an example of how to build your own RCON client for the Astroneer Dedicated server. If you have questions, you can reach me via email eemil@esinko.net.

Table of contents

Please take a moment to look at this list to find what you are looking for!

How it works

In-depth documentation on how the remote console works.

Sending and receiving data
Command reference
Usage

The documentation of this library. If you want to know how to use this library, start here!

Quickstart
Type definitions
ClientOptions
PlayerQuery
PlayerCategory
CreativeConfig
Client class
Constructor
Functions
Events
AstroLauncher Link class
Errors and Bugs

How-it-works

How does RCON work in the Astroneer Dedicated server?
First to enable RCON for a server, set the ConsolePort value in the AstroServerSettings.ini in Astro/Saved/Config within the server folder.
It is also recommended to set ConsolePassword to a random secure password, that the RCON client will use to connect.

What is it?

It is simply a tcp socket server that accepts one client to connect.

Before we continue...

Here is some stuff you need to know before reading this:

Guid = An unique identifier for each player calculated using MurMurHash x86_64-bit based on unknown arguments (perhaps Steam/Microsoft account id). This value never changes.

RCON = Remote Console

< x > = Anything between <> tags is a placeholder for a variable (user input) (with the <> tags marking the placeholder)

Sending-and-receiving-data

Commands are sent to the server as strings followed by a newline (\n), encoded into raw binary bytes. You will simply connect with a tcp socket client and start sending commands to the server.
If the server requires a password, send the password in the same encoded format and with it a following (\n) newline to allow commands to be executed.
The server will respond after command execution with the requested data, result of execution or with an error. For some reason, not all the commands return responses, but most of them return JSON.
Here are some examples of basic responses after command execution:

{ _message: "Some error occurred!", status: false} // Something went wrong :/
{ _message: "Success!", status: true} // It worked!

It's pretty easy to understand the basic structure of a response right? If the status JSON value is false, the _message value will contain an error. If the status value is true, the _message value contains a success message.
Now it's important to understand a key difference between commands with responses and commands with data. Commands with responses, such as "DSSetPlayerCategoryForPlayerName" return a standard response JSON object. If the command "has" data, which means you're requesting some data from the server, it will contain a command specific JSON response object. As an example "DSListPlayers" will return a JSON object, which has a "playerInfo" array, which contains information about each known player with it's command specific structure.
Due to the nature of the tcp socket, the RCON server can also return responses to multiple requests at once. Responses are always separated by \r\n.
The same applies for sending commands. You can send multiple commands separated by \n.

Command-reference

The basic structure is this:

<command> <arguments,...>

First there is the command part, which is the command. Then there is the arguments part, which is a list of arguments separated by spaces.
If an argument contains a space, use " in the start and at the end of the argument.
Here's a list of commands exposed to the RCON client and how to use them. Not all of these work due to bugs, or they might be disabled.
The (?) symbol in the description means that the use case of the function (command) is unknown.
(The arguments format below works like this <ArgumentName>(<Type>))
Written for server version 1.17.89.0 (9.1.2021)

Name Arguments Description Functional? Returns
DSRemote <ConsoleCommand>(String) (?) Execute an in-game command in the in-game console No Unknown
DSClearFavoritesList None (?) Unknown No Unknown
DSRemoveFavorite <ServerUrl>(String, <ip>:<port>) (?) Unknown No Unknown
DSAddFavorite <ServerUrl>(String, <ip>:<port>) <NickName>(String) (?) Unknown No Unknown
DSGetFavoritesList None (?) Unknown No Unknown
DSClearRecentsList None (?) Unknown No Unknown
DSGetRecentsList None (?) Unknown No Unknown
DSBackupSaveGames None (?) Backup the server's saves No Unknown
DSSetBackupSaveGamesInterval <Seconds>(Number) (?) Set the backup interval in seconds No Unknown
DSSetPlayerCategoryForPlayerName <PlayerName>(String) <Category>(String, PlayerCategory) Set a player's category based on the player's name. See the type definition of PlayerCategory for more details on what the Category argument can be. Yes Unknown
DSSetPlayerCategory <Player>(String?) <Category>(String, PlayerCategory) <Index>(Number?) (?) Set a player's category based on the player object? No Unknown
DSSetPlayerCategoryGuid <PlayerGuid> <Category> Set a player's category based on the player's guid. No (Bug!) Standard:
{"_message":"updated entry: player=<PlayerName>, playerGuid=<PlayerGuid>, category=<PlayerGuid>","status":true}
DSSetPlayerCategoryIdx <PlayerIndex> <Category> Set a player's category based on their index in the known players list. Please not the index can change, so it's better to use the guid equivalent for this command No (Bug!) Standard:
{"_message":"updated entry: player=<PlayerName>, playerGuid=<PlayerGuid>, category=<PlayerGuid>","status":true}
DSSetDenyUnlisted <Boolean>(Boolean) Enable or disable the whitelist Yes Special:
(UAstroServerCommExecutor::DSSetDenyUnlisted: SetDenyUnlistedPlayers <unchanged/changed>: <0/1>\r\n
DSSetSaveGameInterval <Seconds>(Number) Set the autosave internal in seconds No Unknown
DSSetActivityTimeout <Seconds>(Number) Set the afk timeout in seconds No Unknown
DSTravelPass <ServerName>(String?) <Password>(String) (Number?) (?) No Unknown
DSTravelName <ServerName>(String?) <Index>(Number?) <Password>(String) (?) No Unknown
DSTravel <ServerIndex>(Number?) <Password>(String) (?) Maybe to connect to some other server? This is for clients, so I have no idea... No Unknown
DSSetPassword <Password>(String) Set the server password No Unknown
DSKickPlayer <PlayerIndex>(Number) Kick a player based on their index in the known players list No Unknown
DSKickPlayerGuid <PlayerGuid>(Number) Kick a player based on their guid Yes Special:
UAstroServerCommExecutor::DSKickPlayerGuid: request to kick player <PlayerGuid> ???\<d/ >\r\n' The variable here on the end of the data is either "d" or nothing. It is "d" for success.
DSGetServerList None Unknown No Unknown
DSSetBackpackPowerUnlimitedCreative <Boolean>(Boolean) (?) Disable or enable backpack power limits No Unknown
DSSetInvisibleToHazardsCreative <Boolean>(Boolean) (?) Make the players invincible to hazards No Unknown
DSSetInvincibleCreative <Boolean>(Boolean) (?) Make the player invincible to any damage No Unknown
DSSetOxygenFreeCreative <Boolean>(Boolean) (?) Disable / Enable oxygen limitations No Unknown
DSSetFuelFreeCreative <Boolean>(Boolean) (?) Disable / Enable fuel limitations No Unknown
DSCreativeMode <Boolean>(Boolean) (?) Enable creative mode for the active save No Unknown
DSGetProperties None Unknown No Unknown
DSServerStatistics() None Get information about the server Yes Special: {"build":"<ServerVersion>","ownerName":"<ServerOwnerName>","maxInGamePlayers":<ServerPlayerLimit>,"playersInGame":<PlayersInGame>,"playersKnownToGame":<KnownPlayers>,"saveGameName":"<ActiveSave>","playerActivityTimeout":<AfkTimeout>,"secondsInGame":<SecondsPlayed>,"serverName":<ServerRegistryServerName>,"serverURL":<ServerUrl>,"averageFPS":<ServerFps/TickSpeed>,"hasServerPassword":<HasPassword>,"isEnforcingWhitelist":<HasWhitelistEnabled>,"creativeMode":<ActiveSaveIsCreative>,"isAchievementProgressionDisabled":<NoAchievements>}\r\n
DSListPlayers None Get the known players list Yes Special: {"playerInfo":[{"playerGuid":"<PlayerGuid>","playerCategory":<PlayerCategory>,"playerName":<PlayerName>,"inGame":<PlayeRCONnected>,"index":<PlayerIndex>}, ...]}\r\n
DSRenameGame <Oldname>(String) <NewName>(String) Rename a save No Unknown
DSDeleteGame <SaveName>(String) Delete a save No Unknown
DSLoadGame <SaveName>(String) Load a new save and set it as the active save for the server Yes None
DSSaveGame <Unknown>(String, Optional) Save the game instantly Yes None
DSNewGame <NewSaveName>(String) Create a new save and set it as active. All players will be forced to reload. Yes None
DSServerShutdown None Shutdown the server gracefully Yes None
DSListGames None List all the saves available Yes Special: {"activeSaveName":"<ActiveSave>","gameList":[{"name":"<SaveName>","date":"<LastEdited, YYYY.MM.DD-hh.mm.ss>9,"bHasBeenFlaggedAsCreativeModeSave":<IsCreative>}, ...]}\r\n
DSTravelURL <ServerUrl> <Password> <Index> (?) Go to another server? Again, this is for clients usually No Unknown
DSTravelFriend <FriendName> <Password> <Index> (?) Go/Connect to a friend? This is used to in clients to connect to a CoOp server usually No Unknown

Usage

This library is written in Node.Js and is to be used in Node.Js applications as a CommonJS module.
This module exports an object which contains the client class and the link class known as the Astrolauncher link class.
Both classes implement same functionality, but the client class connects to the actual server, while the link class uses Astrolauncher's API to send commands to the server.
You can read more about it in the How-it-works section above.

Quickstart

As both exported classes implement the same functionality, but execute them in different ways. This quickstart applies for both, with minor modifications depending on what you need to use.
In short. If you are using AstroLauncher you need to create a new instance of the Link class, if you're not using anything that already connects to the server RCON socket use, the Client class.
In this quickstart we will be using the Client class, but you may switch it by changing the end of the first line to .link, instead of .client.

Step 1

First you need to download the library. You can do it with NPM (astroneer-rcon-client, clone of this repo):

npm install astroneer-rcon-client

Then you need to import the CommonJs module, you can do that with:

const AstroneerRcon = require("astroneer-rcon-client").client
// Tip: If we are operating in the same directory replace the variable in the file path with a dot (.), or if AstroneerRcon is in a folder in your projects working directory. You may use ./<The folder you installed this lib with>/AstroneerRcon.js

If AstroneerRcon is undefined, or you get an error, make sure your filepath is correct.

Step 2

Now that the library has been imported, you need to connect to the server (or the AstroLauncher api, this quickstart works for both!)
First you need to create a new instance of the client/link and call .connect() with the constructor appropriate parameters.
AstroneerRcon is event driven. You can register listeners for multiple things happening in the server and in the client.
There are a few good ones to include, like "connected" and "error".

const AstroneerRcon = require("astroneer-rcon-client").client
let myInstance = new client({
    // Here is the important part, the client configuration.
    ip: "127.0.0.1", // Your server ip
    port: 1234, // Your server port
    password: "MyVerySecureRandomPassword" // This is the server password, if required. You can make it as long as you want.
    // Always use a password for security reasons, if possible!!!
})
// Register event listeners
myInstance.on("error", async error => {
    console.log("An error occurred!\n", error)
    // It is very important you handle this. All unexpected errors will trigger this function, so you can handle it in your application.
})

myInstance.on("connected", async () => {
    console.log("Connected to server!")
    // This function gets ran when the connection to the server is established.
    // Your app code should live here.
})

myInstance.connect() // Connect to the server, keep this line last if possible. At least below all the event listener registrations. As they may not be registered correctly, if the client is already connecting or connected.

That's pretty much it! You can now start executing commands and gathering data from the server!

Step 3

To execute commands, refer to the Client class functions list. Which can be found from the "Table of contents" above.
Here we simply get some basic data about the server.

const AstroneerRcon = require("astroneer-rcon-client").client
let myInstance = new client({
    // Here is the important part, the client configuration.
    ip: "127.0.0.1", // Your server ip
    port: 1234, // Your server port
    password: "MyVerySecureRandomPassword" // This is the server password, if required. You can make it as long as you want.
    // Always use a password for security reasons, if possible!!!
})
// Register event listeners
myInstance.on("error", async error => {
    console.log("An error occurred!\n", error)
    // It is very important you handle this. All unexpected errors will trigger this function, so you can handle it in your application.
})

myInstance.on("connected", async () => {
    console.log("Connected to server!")

    let server = await myInstance.getInfo()
    console.log("Got this information about the server:\n", server)
})

myInstance.connect() // Connect to the server, keep this line last if possible. At least below all the event listener registrations. As they may not be registered correctly, if the client is already connecting or connected.

That's pretty much all there is to know about the basic usage of this library.
Refer to the Client class section for more details on what you can do with this library!

Client-class

The client class is where the RCON client lives. It contains all the commands you can execute against the server and it formats the data for easier usage.
Such as handling dates better (as JavasScript Date objects) and building cleaner response objects.

Type-definitions

These are written using JSDoc.
In markdown:

ClientOptions

{ip: String, port: Number, password?: String, timeout?: Number}

Property: ip,
Type: String,
Description: The IP-address to connect to

Property: port,
Type: Number,
Description: The port number the server is listening for RCON

Property: password,
Type: String,
Description: The RCON password, leave empty if the server does not require an RCON password

Property: timeout,
Type: Number,
Description: The timeout limit in ms. If not set, will default to 15000

Property: delivery_delay,
Type: Number,
Description: The possible delay while starting and ending a "packet". A "packet" can arrive in multiple parts This value is the amount of time to wait for the next part of the "packet". By default 90(ms).

PlayerQuery

{guid?: String, name?: String, index?: Number}

Property: ?guid,
Type: String,
Description: A player guid. This is a string id unique for each player, which never changes

Property: ?name,
Type: String,
Description: The IP-address to connect to

Property: ?index,
Type: Number,
Description: The player index (in the known players list)

PlayerCategory

"Unlisted" or "Blacklisted" or "Whitelisted" or "Admin" or "Pending" or "Owner"

Definitions:
- Unlisted = No permissions, blocked by whitelist if enabled
- Blacklisted = Same as banned
- Whitelisted = No permissions, allowed by whitelist if enabled
- Admin = Max permissions possible for anyone but the owner
- Pending = Not yet set, will be automatically set to Unlisted on next connect if not changed by then
- Owner = The owner, all permissions

CreativeConfig

{fuel: Boolean, invincible: Boolean, hazards: Boolean, oxygen: Boolean, backpackpower: Boolean}

Property: fuel,
Type: Boolean,
Description: Should fuel consumption be enabled?

Property: invincible,
Type: Boolean,
Description: Should invincibility be enabled?

Property: hazards,
Type: Boolean,
Description: Should hazards be enabled?

Property: oxygen,
Type: Boolean,
Description: Should oxygen system be enabled?

Property: backpackpower,
Type: Boolean,
Description: Should the backpack power limit be enabled?

Constructor

This is the constructor, which is in this case used to configure the client and to define internal variables

Reference

/**
 * Create a new RCON client instance
 * @param {ClientOptions} options The client options
*/
constructor(options){...}

The options object is an instance of ClientOptions. Look in the Type definitions section for more details.

Internal variables

Constructor parameters

ip
This is the IP used to connect to the server
port
This is the port used to connect to the server
password
This is the password to connect to the server with
timeout
This is the server timeout limit, which is by default 15 seconds

Libraries

net = require("net")
This is the only used library, which is native to Node.Js

Internal memory object

_

queue: [], | The request queue

handler: null | The current response callback handler

socket: null | The TCP socket

General constants

const

permissionCategories: ["Unlisted", "Blacklisted", "Whitelisted", "Admin", "Pending", "Owner"]
All the possible categories
commandPrefix: "DS"
Append this to start of every command

Events

This library also provides multiple events for things happening on the server. Here is a list of events and their meanings:

  • "playerjoin", Emitted when a player joins the server. Arguments: Object
  • "playerleft", Emitted when a player has left the server. Arguments: Object
  • "newplayer", Emitted when a new player joins the server. Arguments: Object
  • "save", Emitted when the game is saved. Arguments: Object
  • "setsave", Emitted when the active save changes. Arguments: Object
  • "connecting", Emitted when the client is connecting to the server. Arguments: None
  • "connected", Emitted when the client has connected to the server. Arguments: None
  • "disconnect", Emitted when the client has disconnected from the server. Arguments: None
  • "timeout", The server did not respond in time. Will also emit an error. Arguments: None This list does not include the "error" event. For more information about that see: Errors and bugs

Functions

List of functions in the Client class

.connect()

Use: Connect to the server
Returns: Promise<\void>
Triggers events: connecting, connected, disconnect
Usage:

<instance>.connect()

.disconnect()

Use: Disconnect from the server
Returns: Promise<\void>
Triggers events: disconnect
Usage:

<instance>.disconnect().then(() => {
    console.log("Disconnected!")
}).catch((err) => {
    console.log("Failed to disconnect:", err)
})

.listPlayers()

Use: Get the known players list
Returns: Promise<Array>
Triggers events: none
Usage:

let list = await <instance>.listPlayers()
// "list" will be the known players list

.getPlayer(player: PlayerQuery)

Use: Get information about a specific player
Returns: Promise<Object|Array>
Triggers events: none
Usage:

let myPlayer = await <instance>.getPlayer({ guid: "<SomePlayerGuid>" })
// This function returns an object when data is queried with precise means
// If you query the known players list with a player name, it will return
// an array with all matches.

.kick(player: PlayerQuery)

Use: Kick a player from the server
Returns: Promise<void>
Triggers events: kick
Usage:

<instance>.kick({ guid: "<SomePlayerGuid>"}).then(() => {
    console.log("Player kicked!)
}).catch(err => {
    console.log("Failed to kick:", err)
})

.kickAll()

Use: Kick all the players from the server
Returns: Promise<void>
Triggers events:
Usage:

<instance>.kickAll().then(() => {
    console.log("Players kicked!)
}).catch(err => {
    console.log("Failed to kickAll:", err)
})

.setPlayerCategory(player: PlayerQuery, category: PlayerCategory)

Use:
Returns:
Triggers events:
Usage:

<instance>.setPlayerCategory({guid: "<SomePlayerGuid>"}, "<SomePlayerCategory>).then(() => {
    console.log("Category set! It will be applied on next join.")
}).catch((err) => {
    console.log("Failed to apply category:", err)
})

.listSaves()

Use: List the saves of the server
Returns: Promise<Object>
Triggers events: none
Usage:

let savesList = await <instance>.listSaves()
console.log(savesList) // Will contain the active save and then a saves array as a property

.save(?name)

Use: Save the game with an optional new name
Returns: Promise<void>
Triggers events: save
Usage:

<instance>.save()
//or
//<instance>.save("My-New-Save-Name")

.shutdown(force: Boolean)

Use: Shutdown the server while saving before complete shutdown
Returns: Promise<void>
Triggers events: save, disconnect
Usage:

<instance>.shutdown()
//<instance>.shutdown(true)
// ^ That won't save!

.renameSave(name, newname)

This function is not yet implemented, due to the limitations of the server.
Use: Rename a save
Returns: none
Triggers events: none
Usage:

none

.deleteSave(name)

This function is not yet implemented, due to the limitations of the server.
Use: Delete a save
Returns: none
Triggers events: none
Usage:

none

.setSaveInterval(ms)

This function is not yet implemented, due to the limitations of the server.
Use: Set the autosave interval
Returns: none
Triggers events: none
Usage:

none

.setPassword(password)

This function is not yet implemented, due to the limitations of the server.
Use: Set the server password
Returns: none
Triggers events: none
Usage:

none

.setActivityTimeout()

This function is not yet implemented, due to the limitations of the server.
Use: Set the player activity/idle timeout
Returns: none
Triggers events: none
Usage:

none

.setCreative(options: CreativeConfig)

This function is not yet implemented, due to the limitations of the server.
Use: Make the active save a creative save (one time use).
Returns: none
Triggers events: none
Usage:

none

.createSave(name: String, ?activate: Boolean)

Use: Create a new save
Returns: Promise<void>
Triggers events: save, setsave, newsave
Usage:

<instance>.createSave("MyNewSave", true)
// If you don't want the new save to become the active save, set the last parameter to false.

.setWhitelist(boolean: Boolean)

Use: Enable/Disable the whitelist. The whitelist makes users with the Unlisted category unable to connect.
Returns: Promise<void>
Triggers events: none
Usage:

<instance>.setWhitelist(true).then(() => {
    console.log("Whitelist activated")
}).catch(err => {
    console.log("Failed to enable whitelist:", err)
})

.getInfo()

Use: Get general information about the server
Returns: Promise<Object>
Triggers events: none
Usage:

let myServer = await <instance>.getInfo()
console.log("My server:\n", myserver)

AstroLauncher-link-class

This is the second class exported by the library. It implements the same functionality as above, but instead connects to the AstroLauncher API to send commands to the server.
The command reference for this class is the same instead the constructor is a bit different. Instead of taking the server port, ip and console password. It want's the ip, port and password of your AstroLauncher web-panel.
Please note, that some features of RCON that are yet to be implemented in AstroLauncher's api, will of course not be usable.

Errors-and-bugs

Error handling is very important. In this library all errors are handled with the "error" event. If this event has no listeners, the error will be thrown in to global scope.
If you encounter any bugs, or anything unexpected. Don't hesitate to create a new issue.

Copyright

 * By: @Esinko
 * 
 * Github: https://github.com/Esinko/
 * 
 * License: SEE "LICENSE" FILE
 * (Copyright 2020 Esinko. Licensed under the Apache License, Version 2.0)

Package Sidebar

Install

npm i astroneer-rcon-client

Weekly Downloads

2

Version

2.2.9

License

Apache 2.0 (see LICENSE file)

Unpacked Size

94.5 kB

Total Files

4

Last publish

Collaborators

  • esinko