Skip to content

Commit

Permalink
Merge pull request #251 from pelican-eggs/games_rust
Browse files Browse the repository at this point in the history
add rust image
  • Loading branch information
parkervcp authored Jul 18, 2024
2 parents 681ffc4 + 5035b0d commit bfe479f
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/workflows/games.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
- arma3
- dayz
- mohaa
- rust
- samp
- source
- valheim
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,11 @@ is tagged correctly.
* [`minetest`](/games/minetest)
* `ghcr.io/parkervcp/games:minetest`
* [`mohaa`](games/mohaa)
* `ghcr.io/pterodactyl/games:mohaa`
* `ghcr.io/parkervcp/games:mohaa`
* [`Multi Theft Auto: San Andreas`](games/mta)
* `ghcr.io/pterodactyl/games:mta`
* `ghcr.io/parkervcp/games:mta`
* [`Rust (dedicated server)`](games/rust)
* `ghcr.io/parkervcp/games:rust`
* [`samp`](/games/samp)
* `ghcr.io/parkervcp/games:samp`
* [`source`](/games/source)
Expand Down
23 changes: 23 additions & 0 deletions games/rust/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM --platform=$TARGETOS/$TARGETARCH debian:bookworm-slim

ENV DEBIAN_FRONTEND=noninteractive

RUN dpkg --add-architecture i386 \
&& apt update \
&& apt upgrade -y \
&& apt install -y lib32gcc-s1 lib32stdc++6 unzip curl iproute2 tzdata libgdiplus libsdl2-2.0-0:i386 \
&& curl -sL https://deb.nodesource.com/setup_16.x | bash - \
&& apt install -y nodejs \
&& mkdir /node_modules \
&& npm install --prefix / ws \
&& useradd -d /home/container -m container

USER container
ENV USER=container HOME=/home/container

WORKDIR /home/container

COPY ./entrypoint.sh /entrypoint.sh
COPY ./wrapper.js /wrapper.js

CMD [ "/bin/bash", "/entrypoint.sh" ]
48 changes: 48 additions & 0 deletions games/rust/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash
cd /home/container

# Make internal Docker IP address available to processes.
export INTERNAL_IP=`ip route get 1 | awk '{print $(NF-2);exit}'`

## if auto_update is not set or to 1 update
if [ -z ${AUTO_UPDATE} ] || [ "${AUTO_UPDATE}" == "1" ]; then
# Allow for the staging branch to also update itself
./steamcmd/steamcmd.sh +force_install_dir /home/container +login anonymous +app_update 258550 $( [[ -z ${SRCDS_BETAID} ]] || printf %s "-beta ${SRCDS_BETAID}" ) $( [[ -z ${SRCDS_BETAPASS} ]] || printf %s "-betapassword ${SRCDS_BETAPASS}" ) +quit
else
echo -e "Not updating game server as auto update was set to 0. Starting Server"
fi

# Replace Startup Variables
MODIFIED_STARTUP=`eval echo $(echo ${STARTUP} | sed -e 's/{{/${/g' -e 's/}}/}/g')`
echo ":/home/container$ ${MODIFIED_STARTUP}"

if [[ "${FRAMEWORK}" == "carbon" ]]; then
# Carbon: https://github.com/CarbonCommunity/Carbon.Core
echo "Updating Carbon..."
curl -sSL "https://github.com/CarbonCommunity/Carbon.Core/releases/download/production_build/Carbon.Linux.Release.tar.gz" | tar zx
echo "Done updating Carbon!"

export DOORSTOP_ENABLED=1
export DOORSTOP_TARGET_ASSEMBLY="$(pwd)/carbon/managed/Carbon.Preloader.dll"
MODIFIED_STARTUP="LD_PRELOAD=$(pwd)/libdoorstop.so ${MODIFIED_STARTUP}"
elif [[ "${FRAMEWORK}" == "oxide-staging" ]]; then
echo "updating oxide-staging"
curl -sSL -o oxide-staging.zip "https://downloads.oxidemod.com/artifacts/Oxide.Rust/staging/Oxide.Rust-linux.zip"
unzip -o -q oxide-staging.zip
rm oxide-staging.zip
echo "Done updating oxide Staging"
elif [[ "$OXIDE" == "1" ]] || [[ "${FRAMEWORK}" == "oxide" ]]; then
# Oxide: https://github.com/OxideMod/Oxide.Rust
echo "Updating uMod..."
curl -sSL "https://github.com/OxideMod/Oxide.Rust/releases/latest/download/Oxide.Rust-linux.zip" > umod.zip
unzip -o -q umod.zip
rm umod.zip
echo "Done updating uMod!"
# else Vanilla, do nothing
fi

# Fix for Rust not starting
export LD_LIBRARY_PATH=$(pwd)/RustDedicated_Data/Plugins/x86_64:$(pwd)

# Run the Server
wrapper "${MODIFIED_STARTUP}"
140 changes: 140 additions & 0 deletions games/rust/wrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/usr/bin/env node

var startupCmd = "";
const fs = require("fs");
fs.writeFile("latest.log", "", (err) => {
if (err) console.log("Callback error in appendFile:" + err);
});

var args = process.argv.splice(process.execArgv.length + 2);
for (var i = 0; i < args.length; i++) {
if (i === args.length - 1) {
startupCmd += args[i];
} else {
startupCmd += args[i] + " ";
}
}

if (startupCmd.length < 1) {
console.log("Error: Please specify a startup command.");
process.exit();
}

const seenPercentage = {};

function filter(data) {
const str = data.toString();
if (str.startsWith("Loading Prefab Bundle ")) { // Rust seems to spam the same percentage, so filter out any duplicates.
const percentage = str.substr("Loading Prefab Bundle ".length);
if (seenPercentage[percentage]) return;

seenPercentage[percentage] = true;
}

console.log(str);
}

var exec = require("child_process").exec;
console.log("Starting Rust...");

var exited = false;
const gameProcess = exec(startupCmd);
gameProcess.stdout.on('data', filter);
gameProcess.stderr.on('data', filter);
gameProcess.on('exit', function (code, signal) {
exited = true;

if (code) {
console.log("Main game process exited with code " + code);
// process.exit(code);
}
});

function initialListener(data) {
const command = data.toString().trim();
if (command === 'quit') {
gameProcess.kill('SIGTERM');
} else {
console.log('Unable to run "' + command + '" due to RCON not being connected yet.');
}
}
process.stdin.resume();
process.stdin.setEncoding("utf8");
process.stdin.on('data', initialListener);

process.on('exit', function (code) {
if (exited) return;

console.log("Received request to stop the process, stopping the game...");
gameProcess.kill('SIGTERM');
});

var waiting = true;
var poll = function () {
function createPacket(command) {
var packet = {
Identifier: -1,
Message: command,
Name: "WebRcon"
};
return JSON.stringify(packet);
}

var serverHostname = process.env.RCON_IP ? process.env.RCON_IP : "localhost";
var serverPort = process.env.RCON_PORT;
var serverPassword = process.env.RCON_PASS;
var WebSocket = require("ws");
var ws = new WebSocket("ws://" + serverHostname + ":" + serverPort + "/" + serverPassword);

ws.on("open", function open() {
console.log("Connected to RCON. Generating the map now. Please wait until the server status switches to \"Running\".");
waiting = false;

// Hack to fix broken console output
ws.send(createPacket('status'));

process.stdin.removeListener('data', initialListener);
gameProcess.stdout.removeListener('data', filter);
gameProcess.stderr.removeListener('data', filter);
process.stdin.on('data', function (text) {
ws.send(createPacket(text));
});
});

ws.on("message", function (data, flags) {
try {
var json = JSON.parse(data);
if (json !== undefined) {
if (json.Message !== undefined && json.Message.length > 0) {
console.log(json.Message);
const fs = require("fs");
fs.appendFile("latest.log", "\n" + json.Message, (err) => {
if (err) console.log("Callback error in appendFile:" + err);
});
}
} else {
console.log("Error: Invalid JSON received");
}
} catch (e) {
if (e) {
console.log(e);
}
}
});

ws.on("error", function (err) {
waiting = true;
console.log("Waiting for RCON to come up...");
setTimeout(poll, 5000);
});

ws.on("close", function () {
if (!waiting) {
console.log("Connection to server closed.");

exited = true;
process.exit();
}
});
}
poll();

0 comments on commit bfe479f

Please sign in to comment.