From 727d71a6628639032c441d6d63a77489bdfd2ac9 Mon Sep 17 00:00:00 2001 From: Quinten <67589015+QuintenQVD0@users.noreply.github.com> Date: Wed, 26 Jun 2024 08:59:24 +0200 Subject: [PATCH 1/2] add rust image --- .github/workflows/games.yml | 1 + games/rust/Dockerfile | 23 ++++++ games/rust/entrypoint.sh | 48 +++++++++++++ games/rust/wrapper.js | 140 ++++++++++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+) create mode 100644 games/rust/Dockerfile create mode 100644 games/rust/entrypoint.sh create mode 100644 games/rust/wrapper.js diff --git a/.github/workflows/games.yml b/.github/workflows/games.yml index cafebf7df..65f899ea3 100644 --- a/.github/workflows/games.yml +++ b/.github/workflows/games.yml @@ -20,6 +20,7 @@ jobs: - arma3 - dayz - mohaa + - rust - samp - source - valheim diff --git a/games/rust/Dockerfile b/games/rust/Dockerfile new file mode 100644 index 000000000..87628ac04 --- /dev/null +++ b/games/rust/Dockerfile @@ -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" ] diff --git a/games/rust/entrypoint.sh b/games/rust/entrypoint.sh new file mode 100644 index 000000000..e7c7dbf66 --- /dev/null +++ b/games/rust/entrypoint.sh @@ -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}" \ No newline at end of file diff --git a/games/rust/wrapper.js b/games/rust/wrapper.js new file mode 100644 index 000000000..ad79ced94 --- /dev/null +++ b/games/rust/wrapper.js @@ -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(); \ No newline at end of file From 5035b0d4df6f50285d05067102e1db606358428c Mon Sep 17 00:00:00 2001 From: Quinten <67589015+QuintenQVD0@users.noreply.github.com> Date: Wed, 26 Jun 2024 09:02:17 +0200 Subject: [PATCH 2/2] add to readme --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e809df2ad..f0a211ca5 100644 --- a/README.md +++ b/README.md @@ -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)