- Add automatic tcmalloc disable in start scripts to prevent 'large alloc' segfaults - Add warnings and documentation about workshop COLLECTION vs addon IDs - Expand troubleshooting section with solutions for common crashes - Document that -authkey deprecation warning can be safely ignored Fixes: - tcmalloc: large alloc XXXXXXX bytes == (nil) followed by Segmentation fault - Item is not a collection! error when using addon ID instead of collection ID - Missing 32-bit libraries warning with installation instructions
207 lines
7.2 KiB
Bash
Executable File
207 lines
7.2 KiB
Bash
Executable File
#!/bin/bash
|
|
#===============================================================================
|
|
# Garry's Mod PropHunt Server - Docker Entrypoint
|
|
#===============================================================================
|
|
|
|
SERVER_DIR="/home/gmod/serverfiles"
|
|
STEAMCMD_DIR="/home/gmod/steamcmd"
|
|
CFG_TEMPLATE="/home/gmod/cfg-template"
|
|
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
|
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
|
|
echo -e "${GREEN}"
|
|
echo "╔═══════════════════════════════════════════════════════════════╗"
|
|
echo "║ 🎮 Garry's Mod PropHunt Server Starting 🎮 ║"
|
|
echo "╚═══════════════════════════════════════════════════════════════╝"
|
|
echo -e "${NC}"
|
|
|
|
# Check if server is installed
|
|
install_server() {
|
|
log_info "Installing/Updating Garry's Mod server..."
|
|
cd "$STEAMCMD_DIR"
|
|
./steamcmd.sh +@sSteamCmdForcePlatformType linux \
|
|
+force_install_dir "$SERVER_DIR" \
|
|
+login anonymous \
|
|
+app_update 4020 validate \
|
|
+quit
|
|
|
|
if [[ $? -ne 0 ]]; then
|
|
log_error "Failed to install server. Retrying..."
|
|
./steamcmd.sh +@sSteamCmdForcePlatformType linux \
|
|
+force_install_dir "$SERVER_DIR" \
|
|
+login anonymous \
|
|
+app_update 4020 \
|
|
+quit
|
|
fi
|
|
}
|
|
|
|
install_addons() {
|
|
log_info "Installing MetaMod, SourceMod, and ULX..."
|
|
|
|
cd /tmp
|
|
|
|
# Install MetaMod
|
|
METAMOD_VER=$(curl -s "https://mms.alliedmods.net/mmsdrop/1.11/" | grep -oP 'mmsource-[\d.]+-git\d+-linux\.tar\.gz' | tail -1)
|
|
if [[ -n "$METAMOD_VER" ]]; then
|
|
wget -q "https://mms.alliedmods.net/mmsdrop/1.11/${METAMOD_VER}" -O metamod.tar.gz
|
|
tar -xzf metamod.tar.gz -C "$SERVER_DIR/garrysmod/"
|
|
rm -f metamod.tar.gz
|
|
log_success "MetaMod installed."
|
|
fi
|
|
|
|
# Install SourceMod
|
|
SOURCEMOD_VER=$(curl -s "https://sm.alliedmods.net/smdrop/1.11/" | grep -oP 'sourcemod-[\d.]+-git\d+-linux\.tar\.gz' | tail -1)
|
|
if [[ -n "$SOURCEMOD_VER" ]]; then
|
|
wget -q "https://sm.alliedmods.net/smdrop/1.11/${SOURCEMOD_VER}" -O sourcemod.tar.gz
|
|
tar -xzf sourcemod.tar.gz -C "$SERVER_DIR/garrysmod/"
|
|
rm -f sourcemod.tar.gz
|
|
log_success "SourceMod installed."
|
|
fi
|
|
|
|
# Install ULib
|
|
if [[ ! -d "$SERVER_DIR/garrysmod/addons/ulib" ]]; then
|
|
wget -q "https://github.com/TeamUlysses/ulib/archive/refs/heads/master.zip" -O ulib.zip
|
|
unzip -q ulib.zip -d "$SERVER_DIR/garrysmod/addons/"
|
|
mv "$SERVER_DIR/garrysmod/addons/ulib-master" "$SERVER_DIR/garrysmod/addons/ulib"
|
|
rm -f ulib.zip
|
|
log_success "ULib installed."
|
|
fi
|
|
|
|
# Install ULX
|
|
if [[ ! -d "$SERVER_DIR/garrysmod/addons/ulx" ]]; then
|
|
wget -q "https://github.com/TeamUlysses/ulx/archive/refs/heads/master.zip" -O ulx.zip
|
|
unzip -q ulx.zip -d "$SERVER_DIR/garrysmod/addons/"
|
|
mv "$SERVER_DIR/garrysmod/addons/ulx-master" "$SERVER_DIR/garrysmod/addons/ulx"
|
|
rm -f ulx.zip
|
|
log_success "ULX installed."
|
|
fi
|
|
}
|
|
|
|
apply_configs() {
|
|
log_info "Applying configuration files..."
|
|
|
|
# Copy default configs if they don't exist
|
|
if [[ -d "$CFG_TEMPLATE" ]]; then
|
|
mkdir -p "$SERVER_DIR/garrysmod/cfg"
|
|
for file in "$CFG_TEMPLATE"/*; do
|
|
if [[ -f "$file" ]]; then
|
|
filename=$(basename "$file")
|
|
if [[ ! -f "$SERVER_DIR/garrysmod/cfg/$filename" ]]; then
|
|
cp "$file" "$SERVER_DIR/garrysmod/cfg/"
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
|
|
log_success "Configuration applied."
|
|
}
|
|
|
|
# Check if server needs installation
|
|
if [[ ! -f "$SERVER_DIR/srcds_run" ]]; then
|
|
log_info "Server not found. Installing..."
|
|
install_server
|
|
install_addons
|
|
apply_configs
|
|
elif [[ "${AUTO_UPDATE:-true}" == "true" ]]; then
|
|
log_info "Checking for updates..."
|
|
install_server
|
|
fi
|
|
|
|
# Ensure addons are installed
|
|
if [[ ! -d "$SERVER_DIR/garrysmod/addons/ulx" ]]; then
|
|
install_addons
|
|
fi
|
|
|
|
apply_configs
|
|
|
|
cd "$SERVER_DIR"
|
|
|
|
# Build command line arguments
|
|
ARGS="-game garrysmod"
|
|
ARGS="$ARGS -console"
|
|
ARGS="$ARGS -port ${PORT:-27015}"
|
|
ARGS="$ARGS +maxplayers ${MAX_PLAYERS:-24}"
|
|
ARGS="$ARGS +map ${MAP:-gm_construct}"
|
|
ARGS="$ARGS +gamemode ${GAMEMODE:-prop_hunt}"
|
|
ARGS="$ARGS -tickrate ${TICKRATE:-66}"
|
|
ARGS="$ARGS +hostname \"${SERVER_NAME:-PropHunt Server}\""
|
|
|
|
# Add Steam token if provided
|
|
if [[ -n "$SRCDS_TOKEN" ]]; then
|
|
ARGS="$ARGS +sv_setsteamaccount $SRCDS_TOKEN"
|
|
log_success "Steam token configured."
|
|
else
|
|
log_warning "No SRCDS_TOKEN set. Server won't be listed publicly."
|
|
log_warning "Get a token at: https://steamcommunity.com/dev/managegameservers"
|
|
fi
|
|
|
|
# Add RCON password
|
|
if [[ -n "$RCON_PASSWORD" && "$RCON_PASSWORD" != "changeme" ]]; then
|
|
ARGS="$ARGS +rcon_password \"$RCON_PASSWORD\""
|
|
fi
|
|
|
|
# Add workshop collection if provided
|
|
# NOTE: Make sure WORKSHOP_COLLECTION is a COLLECTION ID, not an individual item ID!
|
|
# You can verify at: https://steamcommunity.com/sharedfiles/filedetails/?id=YOUR_ID
|
|
# If it says "Collection" it's valid. If it says "Addon" it will fail.
|
|
if [[ -n "$WORKSHOP_COLLECTION" ]]; then
|
|
ARGS="$ARGS +host_workshop_collection $WORKSHOP_COLLECTION"
|
|
log_info "Workshop collection: $WORKSHOP_COLLECTION"
|
|
log_warning "Ensure this is a Collection ID, not an individual addon ID!"
|
|
fi
|
|
|
|
# Display configuration
|
|
echo ""
|
|
log_info "Server Configuration:"
|
|
echo " • Server Name: ${SERVER_NAME:-PropHunt Server}"
|
|
echo " • Map: ${MAP:-gm_construct}"
|
|
echo " • Max Players: ${MAX_PLAYERS:-24}"
|
|
echo " • Port: ${PORT:-27015}"
|
|
echo " • Gamemode: ${GAMEMODE:-prop_hunt}"
|
|
echo " • Tickrate: ${TICKRATE:-66}"
|
|
echo ""
|
|
|
|
log_info "Starting server..."
|
|
|
|
# Handle shutdown signals
|
|
cleanup() {
|
|
log_info "Shutting down server..."
|
|
if [[ -n "$SERVER_PID" ]]; then
|
|
kill -SIGTERM $SERVER_PID 2>/dev/null
|
|
wait $SERVER_PID 2>/dev/null
|
|
fi
|
|
exit 0
|
|
}
|
|
trap cleanup SIGTERM SIGINT
|
|
|
|
# Add -disableluarefresh to prevent lua refresh issues
|
|
ARGS="$ARGS -disableluarefresh"
|
|
|
|
# Disable tcmalloc which causes segfaults with large memory allocations in Docker
|
|
# This is a known issue with Source engine games in containers
|
|
# The error "tcmalloc: large alloc XXXXXXX bytes == (nil)" indicates memory allocation failure
|
|
export LD_PRELOAD=""
|
|
unset LD_PRELOAD
|
|
|
|
# Use the included 32-bit glibc directly
|
|
export LD_LIBRARY_PATH="$SERVER_DIR/bin:$LD_LIBRARY_PATH"
|
|
|
|
# Disable tcmalloc by renaming the library if it exists (fallback to system malloc)
|
|
if [[ -f "$SERVER_DIR/bin/libtcmalloc_minimal.so.4" ]]; then
|
|
log_info "Disabling tcmalloc to prevent memory allocation crashes..."
|
|
mv "$SERVER_DIR/bin/libtcmalloc_minimal.so.4" "$SERVER_DIR/bin/libtcmalloc_minimal.so.4.disabled" 2>/dev/null || true
|
|
fi
|
|
|
|
# Start the server directly (not via srcds_run to avoid script issues)
|
|
cd "$SERVER_DIR"
|
|
exec ./srcds_linux $ARGS -norestart -nohltv -condebug
|