astroneer-rcon-client
v2.2.9
Published
A Remote console client for the Astroneer Dedicated server built with Node.JS
Downloads
13
Maintainers
Readme
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 [email protected]
.
Table of contents
Please take a moment to look at this list to find what you are looking for!
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:
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.
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
PlayerQuery
PlayerCategory
CreativeConfig
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
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)