Manual

for version 1.0.0

Intro

Carsa's Companion is a website used to supplement and improve Carsa's Commands (a management addon for Stormworks: Build and Rescue). It allows an easier to use and visual way to use the functions offered by the management addon (which normally only works via chat messages). The Companion relies on the logic, data and permission system of the management addon which runs in the game.

If you are short on time, use the Quickstart Guide.

Features

The companion allows access to all the management addon functionality in a visual and interactive way. On top of the already existing functionality, the companion offers additional functions:

Manual Sections

This manual is split into several sections:

For Users for people that play on the server
For Admins / Owners for people that run and administrate the server
For Developers for people that want to change the code of this program

Information on privacy and data visibility

Data that is available / visible on the website of this program is the same as the data available / visible when you connect to the game server via Stormworks: Build and Rescue. This includes (amongst others) the player names, their steamid, chat messages.

Additionally, in order to detect the public IP of the companion server, an external service (run by CrazyFluffyPony, one of the authors of this program) will be contacted. No data is being shared with this service, the service only uses the anonymized request to count how many times the program has been started in order to know if the program is being used and deserves updates and new features.

Quickstart Guide

This is meant for server owners. If you are a user, checkout this.
  1. Download the executable here
  2. Place it in a folder you like (e.g. Desktop/C2-Companion)
  3. Run executable (double click)
  4. Open this URL in your browser: http://localhost:3366/
  5. Read through the section Customizable setings.
  6. Go to settings and adjust the settings to your liking
  7. Enable the companion in the game: Enter into the chat: ?setPref companion true

For Users

Permissions / Who can do what

Permissions depend on the roles you have in the game (special case: if you access the website from a browser on the same machine this webserver is running on: localhost). Those permissions will be the same in the companion. A user that has the permision to kick via ?kickPlayer in the game also can click the kick button in the companion and it will work.

For the additional functions of the companion the permissions work as follows:

players vehicles roles rules preferences gamesettings chat logs settings map gameserver tests
Not logged in user r r r r r r - - - (r) - -
Logged in user (without Owner role) r+ r+ r+ r+ r+ r+ rw - - (r+) - -
Owner rw rw rw rw rw rw rw rw rw rw rw rw
localhost r r r r r r rw rw rw r rw -

Pages

Home

Shows version information and includes important links.

Players

Shows a list of players. Users that have the necessary permisions can kick/ban or change the roles of those players.

Vehicles

Shows a list of vehicles. Users that have the necessary permisions can despawn those vehicles.

Roles

Manage roles: Add, delete, change members, access to commands and permissions of each role.

Rules

Manage rules: Add, delete, change.

Preferences

Change Carsa's Commands preferences.

Game Settings

Change game settings (from custom menu in the game).

Chat

Shows the chat from the server and allows to send chat messages (both only when logged in).

Logs

Shows Carsa's Commands logs from the server (only the ones generated while the companion website is visited).

Settings

Change Webserver Settings (for the companion Webserver). Read more here.

Map

Show the map (Matches game seed). Shows current players and vehicles (live). Players can be kicked/banned and vehicles can be despawned by clicking on their markers.

GameServer Management

Start and stop the dedicated gameserver executable and view its console output.

Tests (must be enabled in settings)

Allows to remotely enable debugging of Carsa's Commands, allows to run some connectivity and performance tests, allows to test several UI components. Read more here.

For Admins / Owners

Customizable Settings

This is only the settings for the companion, of course a lot of stuff is customizable through the role system (that is part of the management addon already but can be accessed in the companion too)

By default, the companion is only accessible on the local network (e.g. your LAN and WLAN network at home). With some simple clicks on the settings the owner can change:


If you want players to receive the companion welcome message (read more below) when the join the game, enable the preference companionInfoOnJoin on the preferences. This welcome message includes the website URL of the companion and the token required to login,

Security

The code for the executable that runs the companion is open source, you can check it for errors and build the executables yourself (see readme). The code uses a minimal amount of third party libraries, all served as a static copy within the git repository. The code was written to have minimal functionality outside of the Stormworks game (only read and write some log files and a settings file, only able to start and terminate an executable specified by the owner of the machine). Two seperate Webservers are used for the website and the connection to the game to further sandbox functionality. The creator of the code has followed best practices (e.g. OWASP) to keep risks as low as possible. If you find any problems, we are happy to contact us, create an issue or even a pull request with a fix.

In terms of permissions in the game, the companion relies 100% on the management addon (the only exception is a browser on the same machine who is allowed to change settings of only the companion). In order to identify players and their permissions, a player can obtain a unique token while writing into the chat in the game (only needs to be done once). Tokens are random enough to prevent being guessed, additionally, logins are rate-limited to prevent a brute force attack.

How to report errors

If you find any errors, please contact us or create an issue. Do not forget to include the logs:

How to debug or test

If you are interested in debugging or testing yourself, go to the settings and activate the enable-test-mode setting. This will allow you to access the tests. The Developer Console of the browser will allow you to checkout all the logs of the browser code. For the webserver logs of the companion, you have to download the sourcecode and start the program with node app.js loglevel=X where X stands for a log level:

1 show errors
2 + show warnings
3 + show infos
4 + show logs
5 + show debugs

Allowing external access to companion

This requires you to set the setting allow-external-access on settings to enabled.

If you run the companion on your PC (e.g. behind a router in your home network) you need to enable port forwarding in your routers settings if you want others on the internet to access the companion website.

You must forward the following ports (if you use a different incoming port then some links might not work):

3366 TCP
3367 TCP

For Developers

This is meant for people who want to change the source code of this program. We would like to document this even better, but time is limited, especially for a hobby project.

Favorable Skills

These skills / knowledges are not 100% required, but definitely helpful and might sometimes be mandatory to understand what is going on.

Tech Stack

Backend
Node.js JavaScript runtime (server)
Express (Node.js) Webserver framework (Basic Webserver)
Handlebars Templating Framework (Assemble page HTML)
Compass CSS Framework (Assemble CSS)
Frontend
Vue.js User Interface Framework (Single Page Application)
Vuex State Management Library for Vue.js (Central Datastorage)
jQuery JavaScript Library (Utility)
WebSocket Real-Time Communication (Two-Way Server-Client Communication)

Setup build tools

  • if you are on windows you will need a command line tool, i suggest the official one from git: gitforwindows.org/
  • install node (e.g. v16) nodejs.org
  • install compass (use git bash for this): $ gem install compass
  • install nodemon (use git bash for this): $ npm install -g nodemon

Nodemon is optional, but it will automatically restart the server when any source file loaded and make your life easier.

git hooks for versioning

After you cloned this repository, run $ sh setup_git_hooks.sh. This will install the git hooks, so it sets the content of commit.txt to be the current commit hash. You can also trigger it manually by doing a checkout on the current select branch (e.g. $ git checkout master)

Coding

  • command line tool 1 (e.g. git bash): $ cd compass & compass watch
  • command line tool 2 (e.g. git bash): $ nodemon or for debugging $ nodemon -- loglevel=3 (3 = info, 4 = log, 5= debug)

Upgrading the version

Just edit the file public_static/version.txt

Upgrading vue.js and vuex library

Visit https://unpkg.com/browse/vue@3.2.29/dist/ and select the most recent version. Download the vue.global.js (for testing) or vue.global.prod.js (for production). Replace /public_static/scripts/lib/vue.js with whatever you downloaded.

Procedure is similar for vuex (https://unpkg.com/browse/vuex@4.0.2/dist/).

Updating manual

Simply edit manual.html directly. All scripts, styles, images are included in this single file.

If you make any changes to the styling (inside compass/sass/manual.scss) you must recompile the stylesheets (via compass), take the output from public_static/stylesheets/manual.css and replace the <style> tag inside the manual.html file.

Creating executable

Install pkg: $ npm i pkg -g

run $ pkg .

The executables can be found in /dist

Update playlist.xml (locations) for the management addon (Carsa's companion)

For every map tile, we define a zone, which is required to show the tiles in the webclient live map at the right position. The ingame script finds all those zones and their positions. In case new tiles are added (game update), you need to update the playlist.xml (automated with a script of course).

After you did build the playlist.xml (see Readme of Carsas-CommandsV2) then you can run $ node build-tools/make-playlist-with-zones.js

The above command will read %appdata%/Roaming/Stormworks/data/missions/Carsa's Commands/playlist.xml inject the env_mods/locations and write the ouput to %appdata%/Roaming/Stormworks/data/missions/Carsa's Commands/playlist_with_zones.xml

Now you have to replace the original playlist.xml file with the playlist_with_zones.xml file.

Folder Structure

.githooks contains code that creates the file "public_static/commit.txt" with the current git commit hash
build-tools contains build tools and scripts
c2 contains source code for the Node.js webserver
compass contains source code of sass/compass that will later be compiled into css files
dist contains generated standalone executables
node-modules contains all the npm dependencies (as source code)
public-static contains files served by the webserver (as "/static/...") which are required for the website (including javascript files, compiled css, images, tile images, etc.
views contains handlebar templates for all the html pages
app.js the main server application file
setup_git_hooks.sh Used to setup githooks that create the "public_static/commit.txt" file

Other files not mentioned in this table are either explained later, in the readme or are self explanatory.

Concepts

Message types

For the messages that are being sent from the Frontend: message types starting with command- are always messages that are sent from the Frontend to the Game. All other messages that are being sent from the Frontend are only meant for the Backend and not forwarded to the Game.

For the messages that are being sent from the Game: message types starting with sync- are messages containing data of syncables. Those will be forwarded to all clients. For other message types, individual rules apply. Sometimes, the message is only forwared to clients with certain permissions, ...

Syncables

Syncables are special data, both defined on the management addon and in the frontend code. The management addon will send those data updates when the data changes (and whenever a client connects freshly to the server). In the frontend, components that trigger a command (of the management addon) will often wait until a certain sync (defined per component) arrives. In the meanwhile, they will lock themselves so the user cannot try to trigger that command again before he is being displayed the new current state.

Message Flow

These are several examples for different variants of message flows. They should help you to understand the message/event oriented flow. Both the connection Webclient <-> Backend and Backend <-> Game are full duplex. Both sides can send messages. Each message contains an id (counted individual for every side). Every message requires a response (a message with the same individual id). This response can either be sent immediately (e.g. when Game sends request to backend) or asynchronously after some time (e.g. when Webclient sends command to backend and backend sends to game and then back the whole chain once the game triggers another HTTP request containing the response).

The duplex HTTP connection between Game and Backend is different from the duplex WebSocket connection between Frontend and Backend: The game can only send requests to the backend, but the backend cannot send requests to the game. Instead the backend has to wait for the game to do another request and then include its own request inside the response of that HTTP request. This means a bit of delay. To minimize this delay, the heartbeat happens very often. Every hearbeat (and every other request) the GameHTTPHandler checks if there is a message (from Backend to Game) in the queue, if so, it will add this message to the response. If there is still more messages in the clue, a flag will be set, that indicates the management addon to immediately start another HTTP request to pickup the other messages in the queue.

Game -> Backend

Example: Tokens

The management addon sends the current companion tokens of all players to the backend (initially and when a token changes or a new player joins). The ModuleCore registers a message handler for token-sync and receives the tokens as an object (because the game sent it away as a json object). The parsing happened inside the GameHttpHandler.

Game -> Backend -> Frontend

Example: Heartbeat

The management addon sends a heartbeat (small message) that tells the backend the management addont is still running. The Backend will then forward this message to all webclients (currently only used for status bar blinking). The ModuleCore reigsters a message handler for heartbeat and receives an object or string, if it equals first that means the management addon has just started or the server has just started, if it is an object, it contains the current length of the message sending queue, which can be used to display a warning if this queue is filling up (normally due to a bug). After that, the message is sent to all webclients (ignoring if it actually reached them). On the webclient, the C2 code will receive that message, dispatch an event and the status-bar component will listen to it and flash the status indicator circle.

Backend -> Frontend

Example: Initial game connection state

When a new WebSocket connection is being opened in WebInterface, it dispatches an event, C2 listens to that event and sends a message to all webclients with the current connection state of the management addon.

Frontend -> Backend -> Frontend

Example: Server Settings

If a user changes a server setting on the settings he triggers the sending of a message of type set-server-setting, in ModuleCore, a handler for this type has been registered which now checks if the client has the permission to perform this action (either is localhost or logged in by token and has the Owner role). Depending on the result, the ModuleCore will then respond to the request. The WebSocketHandler will send a message to the webclient which is marked as being a response to a previous message and it contains either the error message or the success message (in this case the new current server settings). The Frontend can now either display the error message or a success message and update the server settings in the central storage.

Frontend -> Backend -> Game -> Backend -> Frontend

Example: Kick Player

In the Frontend, the user clicks a button inside a component which triggers the kickPlayer command. This also locks the button. The Frontend sends a message of type command-kickPlayer to the Backend, the Backend relays this message to the Game. The Game will respond at some point (either accept, if the client has that permission and the target player id is valid, or deny and respond with an error message) and the Backend will relay the information back to the Frontend. The Frontend will now either display an error message or a success message. Because this command has changed the players data, the management addon will send a sync-players message including the new current player data. The Frontend will receive this data and update the central storage. This will emit an event and the component that triggered the kickPlayer command will listen to it and unlock itself.

Backend Code Structure

app.js

The main application file initializes the express webserver, sets up the routes and pages and loads the C2 code.

C2.js

This class loads all the modules and provides some APIs for them. Each module can use those APIs to send messages to either game or webclients, can register callbacks/handlers for specific message types from either the game or the webclients.

C2_ConsoleLogger.js

This class intercepts logs and writes them to the logfile.

C2_Utility.js

This class provides utility functions for logging and an event system.

C2GameHttpHandler.js

This class handles HTTP requests coming from the Stormworks game and request that other C2 code wants to send to the game. It is a seperate webserver that runs on a different port then the main webserver. This class handles new requests and responses to existing requests (full duplex system) but the basis is only HTTP requests coming from the Stormworks game (more precise: from the management addon). It is able to split huge messages into several parts and also merge back together those parts. If a the reponse to a request runs into a timeout, this class fails that request automatically. The class communicates with the management addon via JSON, the payload/data inside the JSON is always (this is different to the WebSocketHandler) a JSON string, which means JSOn will be parsed automatically. The payload/data will be forwarded to other parts of C2 code (e.g. as the response to an answer) as some kind of an object (Object, Array, string, boolean, whatever the JSON.parse() output is)!

C2GameInterface.js

This class is the streamlined connection between any C2 code and the GameHTTPHandler. It also detects wether the management addon is connected (using a heartbeat system).

C2WebSocketHandler.js

This class handles WebSocket connections and request coming from webclients as well as request that other C2 code wants to send to webclients. This class handles new requests and responses to existing requests (full duplex system). This class communicates with the webclients code via JSON, the payload/data inside the JSON is often a JSON string but does not have to. The payload/data will be forwarded to other parts of C2 code (e.g. as the response to an answer) as a string! The C2 code has to handle/parse the payload/data itself (if the payload/data is forwarded to the game, no parsing happens, since the parsing will happen in the game code).

C2WebInterface.js

This class is the streamlined connection between any C2 code and the WebSocketHTTPHandler.

C2GameWebServer.js

This class is responsible for the second webserver which is only responsible for accepting HTTP request from the Stormworks game (more precise: the management addon).

C2Module_Core.js

This class is responsible for setting up the core functionality:

  • Backend permission management (filter data coming from game and sent to webclient, control access to webserver settings management)
  • Version Checks
  • Notifications for the user (not 100% implemented and only used for version checks)
  • Rate-limit logins (via token)
  • Relay commands between WebInterface <-> GameInterface
  • Webserver settings management

C2Module_Map.js

This class is responsible for functionality around the map (forward map updates from GameInterface -> WebInterface).

C2Module_Test.js

This class is responsible for functionality around the tests (run connectivity and performance tests).

C2Module_Gameserver.js

This class is responsible for managing the dedicated game server executable (Stormworks). It relays information between the WebInterface and the GameServerManager.

C2GameServerManager.js

This class is responsible of starting and stoping the game server executable. It utilizes GameServerProcess which is spawned as a child process and relays console output from that child process back to the Module_Gameserver. It also handles state events of the child process (e.g. errors, exit, etc). It also constantly checks if a process that matches the game server executable is currently running and can kill that process.

C2GameServerProcess.js

This class is responsible of spawning a cmd process that executes the game server executable. This cmd process is then able to continue running on its own (even if the companion application stops). This class also relays console output from the executable back to the GameServerManager.

Frontend Code Structure

C2.js

This class initializes Vue.js and the Vuex store. It provides an API for modules to register message callbacks/handlers, storables, syncables, components and pages and an API for showing notifications. Displays error popup as a fallback for Vue.js internal error handling (of the components themselves).

C2_ConsoleLogger.js

This class is responsible to intercept logs, cache them and later provide them for error messages displayed to the user.

C2_Utility.js

This class provides utility functions for logging and an event system. It also provides mixins components can use for logging, sending messages or commands. It also provides some basic components (e.g. lockables, extendables, buttons, icons, ...)

C2WebClient.js

This class is just a small wrapper for the WebSock. It takes care of converting data into lua format (undefined and null are converted into nil, an array is converted into a space seperated text (to represent an argument string)).

C2WebSock.js

This class provides functions to easily send messages and receive responses. It enhances the default WebSocket class by automatically trying to reconnect. It can also trigger the page reload, if the Backend requested a force reload (e.g. after server restart).

C2Module_Core.js

This class is responsible for setting up the core functionality

  • Notifications
  • Status bar
  • Login and user state
  • home
  • players
  • vehicles
  • roles
  • rules
  • preferences
  • gamesettings
  • logs
  • chat
  • settings

C2Module_Map.js

This class is responsible for the map and receiving updates of the live players and vehicles.

C2Module_Test.js

This class is responsible for the tests and starting several connectivity and performance tests.

C2Module_Gameserver.js

This class is responsible for the gameserver and starting/stopping the dedicated game server.