Refactor deploy/push scripts and enhance game docs generator

- Add comprehensive headers to deploy_gsp.sh and push_to_github.sh
- Make scripts configurable via environment variables
- Update push_to_github.sh to support GITHUB_TOKEN env var
- Enhance generate_game_docs.py with:
  * Command-line argument support (--games, --force, --todo-only)
  * Extraction of detailed startup parameters from XML
  * Prevention of overwriting existing files unless --force is used
  * Comprehensive parameter documentation with options and defaults

Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-11-22 22:35:31 +00:00
parent d3c83c33b1
commit f8ae24e87b
4 changed files with 498 additions and 108 deletions

View file

@ -1,4 +1,40 @@
#!/usr/bin/env bash
#
# GSP Deployment Script
# =====================
# This script deploys the Game Server Panel (GSP) from GitHub to a web server.
#
# HOW IT WORKS:
# 1. Clones/updates the GSP repository to a staging directory
# 2. Syncs files to the web root using rsync (preserving configs)
# 3. Sets proper permissions for OGP panel operation
#
# CONFIGURATION:
# All settings can be configured via environment variables or by editing
# the defaults in the "Config" section below.
#
# ENVIRONMENT VARIABLES:
# - REPO_URL: Git repository URL (default: https://github.com/GameServerPanel/GSP.git)
# - STAGE_DIR: Staging directory for git clone (default: $HOME/gsp_stage)
# - WEB_ROOT: Live web server directory (default: /var/www/html/panel)
# - OWNER: File owner user (default: www-data)
# - GROUP: File owner group (default: www-data)
# - SUDO: Command prefix for privilege escalation (default: sudo, set empty to skip)
# - DRY_RUN: Set to 1 to test without making changes (default: 0)
#
# EXAMPLE USAGE:
# # Use defaults:
# ./deploy_gsp.sh
#
# # Custom web root:
# WEB_ROOT=/home/panel/public_html ./deploy_gsp.sh
#
# # Dry run to test:
# DRY_RUN=1 ./deploy_gsp.sh
#
# # Different user/group:
# OWNER=apache GROUP=apache ./deploy_gsp.sh
#
set -Eeuo pipefail
umask 022

View file

@ -26,7 +26,7 @@
<h2 id="quick-info">Quick Info</h2>
<div style="background: #1e3a5f; padding: 20px; border-left: 4px solid #3b82f6; margin: 20px 0; border-radius: 4px;">
<ul style="color: #e5e7eb; line-height: 1.8; margin: 0;">
<li><strong style="color: #ffffff;">Default Port:</strong> <code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">28015</code></li>
<li><strong style="color: #ffffff;">Default Port:</strong> <code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">Varies (see configuration)</code></li>
<li><strong style="color: #ffffff;">Protocol:</strong> TCP/UDP</li>
<li><strong style="color: #ffffff;">Minimum RAM:</strong> 1GB</li>
<li><strong style="color: #ffffff;">Engine:</strong> Various</li>
@ -38,33 +38,7 @@
<h2 id="ports">🔌 Network Ports</h2>
<div style="background: #1e3a5f; padding: 20px; border-left: 4px solid #3b82f6; margin: 20px 0; border-radius: 4px;">
<h3 style="color: #ffffff; margin-top: 0;">Required Ports</h3>
<p style="color: #e5e7eb;">The following ports are used by this game server:</p>
<table style="width: 100%; color: #e5e7eb; border-collapse: collapse;">
<thead>
<tr style="background: #0f172a;">
<th style="padding: 10px; text-align: left; color: #ffffff;">Port</th>
<th style="padding: 10px; text-align: left; color: #ffffff;">Protocol</th>
<th style="padding: 10px; text-align: left; color: #ffffff;">Purpose</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom: 1px solid #374151;">
<td style="padding: 10px;"><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">28015</code></td>
<td style="padding: 10px;">UDP</td>
<td style="padding: 10px;">Game port</td>
</tr>
<tr style="border-bottom: 1px solid #374151;">
<td style="padding: 10px;"><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">28016</code></td>
<td style="padding: 10px;">TCP</td>
<td style="padding: 10px;">RCON</td>
</tr>
<tr style="border-bottom: 1px solid #374151;">
<td style="padding: 10px;"><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">28082</code></td>
<td style="padding: 10px;">TCP</td>
<td style="padding: 10px;">Web panel (if enabled)</td>
</tr>
</tbody>
</table>
<p style="color: #e5e7eb;">The Rust server typically uses a configurable port. Check your server configuration files for the specific port settings.</p>
<h3 style="color: #ffffff; margin-top: 20px;">Firewall Configuration</h3>
<p style="color: #e5e7eb;">Allow server ports through your firewall:</p>
@ -194,68 +168,116 @@ setadminpassword [password]
<h2 id="parameters">⚙️ Startup Parameters</h2>
<h3>Basic Startup</h3>
<pre><code># Generic startup command structure
./server_executable [parameters]
</code></pre>
<h3>Command Line Template</h3>
<p>The server uses the following command line template:</p>
<pre><code>-batchmode -nographics +server.ip %IP% %PORT% %QUERY_PORT% %PLAYERS% %HOSTNAME% %IDENTITY% %DESCRIPTION% %WORLDSIZE% %SEED% %SALT% %TICKRATE% %MAP% %BCK% %SAVEINTERNAL% %SECURE% %RCONWEB% %CONTROL_PASSWORD% -logfile output.txt</code></pre>
<h3>Common Parameters</h3>
<ul>
<li><code>-port [number]</code> - Set the server port</li>
<li><code>-maxplayers [number]</code> - Maximum player slots</li>
<li><code>-map [name]</code> - Starting map/level</li>
<li><code>-console</code> - Enable console output</li>
<li><code>-nographics</code> - Run without graphics (headless mode)</li>
</ul>
<h3>Available Startup Parameters</h3>
<p>The following parameters can be configured when starting the server:</p>
<h3>Creating a Start Script</h3>
<div style="background: #1e3a5f; padding: 20px; border-left: 4px solid #3b82f6; margin: 20px 0; border-radius: 4px;">
<p><strong>Linux (start.sh):</strong></p>
<pre><code>#!/bin/bash
cd /path/to/server
./server_executable [parameters] 2>&1 | tee server.log
</code></pre>
<pre><code>chmod +x start.sh
./start.sh
</code></pre>
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">+server.identity</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - +server.identity</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">Changes path to your server data (e.g. rust/server/my_server_identity).</p>
<p style="color: #fbbf24;"><strong>Default:</strong> <code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">server_identity</code></p>
</div>
<p><strong>Windows (start.bat):</strong></p>
<pre><code>@echo off
cd /d "%~dp0"
server_executable.exe [parameters]
pause
</code></pre>
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">+server.description</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - +server.description</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">Server Description shown on server browser</p>
<p style="color: #fbbf24;"><strong>Default:</strong> <code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">Plain old Rust Server</code></p>
</div>
<h3>Running as a Service</h3>
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">+server.worldsize</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - +server.worldsize</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">Defines the size of the map generated (min 1000, max 8000).</p>
<p style="color: #fbbf24;"><strong>Default:</strong> <code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">1000</code></p>
</div>
<p><strong>Linux (systemd):</strong></p>
<pre><code># Create service file: /etc/systemd/system/gameserver.service
[Unit]
Description=Rust Server
After=network.target
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">+server.seed</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - +server.seed</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">Defines the map generation seed.</p>
<p style="color: #fbbf24;"><strong>Default:</strong> <code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">0</code></p>
</div>
[Service]
Type=simple
User=gameserver
WorkingDirectory=/home/gameserver/server
ExecStart=/home/gameserver/server/start.sh
Restart=on-failure
RestartSec=10
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">+server.salt</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - +server.salt</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">Defines the randomization to mining resources.</p>
<p style="color: #fbbf24;"><strong>Default:</strong> <code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">0</code></p>
</div>
[Install]
WantedBy=multi-user.target
</code></pre>
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">+server.tickrate</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - +server.tickrate</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">Defines the server tickrate (going higher than 30 is not recommended).</p>
<p style="color: #fbbf24;"><strong>Default:</strong> <code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">30</code></p>
</div>
<pre><code># Enable and start service
sudo systemctl daemon-reload
sudo systemctl enable gameserver
sudo systemctl start gameserver
sudo systemctl status gameserver
</code></pre>
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">+server.level</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - +server.level</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">Defines the map of the server.</p>
<p style="color: #e5e7eb;"><strong>Options:</strong></p>
<ul style="color: #e5e7eb; margin-left: 20px;">
<li><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">Barren</code> - Barren</li>
<li><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">CraggyIsland</code> - Craggy Island</li>
<li><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">HapisIsland</code> - Hapis Island</li>
<li><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">Procedural Map</code> - Procedural Map</li>
<li><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">SavasIsland</code> - Savas Island</li>
<li><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">SavasIsland_koth</code> - Savas Island KoTH</li>
</ul>
</div>
<h2 id="troubleshooting">🔧 Troubleshooting</h2>
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">+backup</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - +backup</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">Enable automatic backups.</p>
</div>
<h3>Server Won't Start</h3>
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">+server.saveinterval</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - +server.saveinterval</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">Interval between the server saves the map.</p>
<p style="color: #fbbf24;"><strong>Default:</strong> <code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">600</code></p>
</div>
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">+rcon.web</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - +rcon.web</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">If set to enabled, use websocket RCON. If set to disabled, use legacy source engine RCON.</p>
<p style="color: #e5e7eb;"><strong>Options:</strong></p>
<ul style="color: #e5e7eb; margin-left: 20px;">
<li><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">0</code> - Disabled</li>
<li><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">1</code> - Enabled</li>
</ul>
</div>
</div>
<h4>Check Server Logs</h4>
<pre><code># View recent log entries

View file

@ -1,26 +1,82 @@
#!/usr/bin/env bash
#
# GSP GitHub Push Script
# ======================
# This script commits local changes in your GSP panel directory and pushes
# them to GitHub via a Pull Request.
#
# HOW IT WORKS:
# 1. Initializes git in the panel directory (if needed)
# 2. Commits all changes (excluding sensitive files like config.inc.php)
# 3. Creates a timestamped branch
# 4. Attempts to push to upstream repo (requires write access)
# 5. If no write access, creates/uses a fork and submits PR from there
#
# CONFIGURATION:
# Configure settings via environment variables or by editing the defaults below.
#
# ENVIRONMENT VARIABLES:
# - PANEL_DIR: Path to your GSP panel installation (default: /var/www/html/panel)
# - TOKEN_FILE: File containing GitHub Personal Access Token (default: ~/.github-token)
# - GITHUB_TOKEN: GitHub token directly (used if TOKEN_FILE doesn't exist)
# - UPSTREAM_REPO: Target repository in "owner/repo" format (default: GameServerPanel/GSP)
# - BR_PREFIX: Branch name prefix for PRs (default: panel-sync)
# - GIT_USER_NAME: Git commit author name (default: Server Sync Bot)
# - GIT_USER_EMAIL: Git commit author email (default: server-sync@local)
#
# GITHUB TOKEN SETUP:
# You need a GitHub Personal Access Token with 'repo' scope.
# Create one at: https://github.com/settings/tokens
#
# Option 1: Store in file (recommended):
# echo "your_token_here" > ~/.github-token
# chmod 600 ~/.github-token
#
# Option 2: Use environment variable:
# export GITHUB_TOKEN="your_token_here"
#
# EXAMPLE USAGE:
# # Use defaults:
# ./push_to_github.sh
#
# # Custom panel directory:
# PANEL_DIR=/home/panel/public_html ./push_to_github.sh
#
# # Using environment token:
# GITHUB_TOKEN="ghp_xxxx" ./push_to_github.sh
#
set -Eeuo pipefail
umask 022
# ---------- HARD-CODED PROJECT SETTINGS ----------
PANEL_DIR="/var/www/html/panel"
TOKEN_FILE="/home/gameserver/git.token"
# ---------- CONFIGURABLE SETTINGS ----------
PANEL_DIR="${PANEL_DIR:-/var/www/html/panel}"
TOKEN_FILE="${TOKEN_FILE:-$HOME/.github-token}"
UPSTREAM_REPO="GameServerPanel/GSP" # owner/repo
UPSTREAM_REPO="${UPSTREAM_REPO:-GameServerPanel/GSP}" # owner/repo
UPSTREAM_URL="https://github.com/${UPSTREAM_REPO}.git"
BR_PREFIX="panel-sync" # branch prefix for PRs
GIT_USER_NAME="Server Sync Bot"
GIT_USER_EMAIL="server-sync@local"
BR_PREFIX="${BR_PREFIX:-panel-sync}" # branch prefix for PRs
GIT_USER_NAME="${GIT_USER_NAME:-Server Sync Bot}"
GIT_USER_EMAIL="${GIT_USER_EMAIL:-server-sync@local}"
log(){ printf '[%s] %s\n' "$(date +'%F %T')" "$*"; }
die(){ echo "ERROR: $*" >&2; exit 1; }
# ---------- PRECHECKS ----------
[[ -d "$PANEL_DIR" ]] || die "Panel dir not found: $PANEL_DIR"
[[ -s "$TOKEN_FILE" ]] || die "Token file missing/empty: $TOKEN_FILE"
TOKEN="$(<"$TOKEN_FILE")"
[[ ${#TOKEN} -ge 10 ]] || die "Token in $TOKEN_FILE looks invalid"
# Try to get token from file or environment
TOKEN=""
if [[ -s "$TOKEN_FILE" ]]; then
TOKEN="$(<"$TOKEN_FILE")"
elif [[ -n "${GITHUB_TOKEN:-}" ]]; then
TOKEN="$GITHUB_TOKEN"
else
die "GitHub token not found. Set GITHUB_TOKEN env var or create $TOKEN_FILE with your token.
Get a token at: https://github.com/settings/tokens (requires 'repo' scope)"
fi
[[ ${#TOKEN} -ge 10 ]] || die "Token looks invalid (too short)"
cd "$PANEL_DIR"
if [[ ! -d ".git" ]]; then

View file

@ -1,8 +1,42 @@
#!/usr/bin/env python3
"""
Comprehensive Game Server Documentation Generator for GSP
Generates PHP documentation files for all games in the "todo" category
Based on the Minecraft template structure
This script generates PHP documentation files for game servers in the GSP billing module.
USAGE:
# Generate docs for all incomplete games:
python3 generate_game_docs.py
# Generate docs for specific game(s):
python3 generate_game_docs.py --games minecraft csgo rust
# Regenerate docs (overwrite existing):
python3 generate_game_docs.py --games minecraft --force
# Process all "todo" category games:
python3 generate_game_docs.py --todo-only
OPTIONS:
--games GAME1 GAME2 ... Generate docs for specific game folder names
--force Overwrite existing documentation files
--todo-only Only process games with category="todo"
--help Show this help message
The generator extracts information from:
- XML configurations (modules/config_games/server_configs/*.xml)
- YAML knowledgepack (modules/billing/docs/gameserver_knowledgepack_v2.yaml)
- Existing metadata.json files
Generated documentation includes:
- Quick info (ports, RAM, Steam App ID)
- Network ports and firewall configuration
- Installation steps with SteamCMD commands
- Server configuration files and settings
- Detailed startup parameters from XML
- Comprehensive troubleshooting guide
- Performance optimization tips
- Security best practices
"""
import os
@ -10,6 +44,7 @@ import sys
import json
import yaml
import re
import argparse
from pathlib import Path
from datetime import datetime
import xml.etree.ElementTree as ET
@ -115,6 +150,68 @@ class GameDocGenerator:
return ports
def extract_startup_parameters_from_xml(self, xml_root):
"""Extract detailed startup parameters from XML server_params section"""
startup_params = []
# Get CLI template and params
cli_template = xml_root.find('cli_template')
cli_template_text = cli_template.text if cli_template is not None else ""
cli_params_elem = xml_root.find('cli_params')
cli_params_info = {}
if cli_params_elem is not None:
for param in cli_params_elem.findall('cli_param'):
param_id = param.get('id', '')
cli_string = param.get('cli_string', '')
options = param.get('options', '')
if param_id:
cli_params_info[param_id] = {
'cli_string': cli_string,
'options': options
}
# Extract server_params - these are the configurable startup parameters
server_params = xml_root.find('server_params')
if server_params is not None:
for param in server_params.findall('param'):
param_key = param.get('key', '')
param_id = param.get('id', '')
param_type = param.get('type', 'text')
# Get caption and description
caption_elem = param.find('caption')
desc_elem = param.find('desc')
default_elem = param.find('default')
caption = caption_elem.text if caption_elem is not None else param_key
description = desc_elem.text if desc_elem is not None else "No description available"
default_value = default_elem.text if default_elem is not None else None
# For select type, get options
options = []
if param_type == 'select':
for option in param.findall('option'):
opt_value = option.get('value', '')
opt_text = option.text if option.text else opt_value
options.append({'value': opt_value, 'text': opt_text})
startup_params.append({
'key': param_key,
'id': param_id,
'type': param_type,
'caption': caption,
'description': description,
'default': default_value,
'options': options
})
return {
'cli_template': cli_template_text,
'cli_params': cli_params_info,
'server_params': startup_params
}
def extract_config_files_from_xml(self, xml_root):
"""Extract configuration file paths from XML"""
config_files = []
@ -139,15 +236,17 @@ class GameDocGenerator:
kb_info = self.get_game_info_from_knowledgepack(game_name)
xml_config = self.get_xml_config(folder_name)
# Extract ports and configs
# Extract ports, configs, and startup parameters
ports_info = []
config_files = []
startup_params_data = {}
if xml_config is not None:
ports_info = self.extract_ports_from_xml(xml_config)
config_files = self.extract_config_files_from_xml(xml_config)
startup_params_data = self.extract_startup_parameters_from_xml(xml_config)
# Build the PHP document
php_content = self.build_php_content(game_name, folder_name, kb_info, xml_config, ports_info, config_files)
php_content = self.build_php_content(game_name, folder_name, kb_info, xml_config, ports_info, config_files, startup_params_data)
return php_content
@ -180,7 +279,7 @@ class GameDocGenerator:
return 'N/A'
def build_php_content(self, game_name, folder_name, kb_info, xml_config, ports_info, config_files):
def build_php_content(self, game_name, folder_name, kb_info, xml_config, ports_info, config_files, startup_params_data):
"""Build the complete PHP documentation content"""
# Extract data from various sources
@ -495,21 +594,81 @@ setadminpassword [password]
</code></pre>
<h2 id="parameters"> Startup Parameters</h2>
'''
# Add detailed startup parameters from XML if available
if startup_params_data and startup_params_data.get('server_params'):
server_params = startup_params_data['server_params']
cli_template = startup_params_data.get('cli_template', '')
if cli_template:
php_doc += f'''
<h3>Command Line Template</h3>
<p>The server uses the following command line template:</p>
<pre><code>{cli_template}</code></pre>
'''
php_doc += '''
<h3>Available Startup Parameters</h3>
<p>The following parameters can be configured when starting the server:</p>
<div style="background: #1e3a5f; padding: 20px; border-left: 4px solid #3b82f6; margin: 20px 0; border-radius: 4px;">
'''
for param in server_params:
param_key = param['key']
caption = param['caption']
description = param['description']
param_type = param['type']
default = param.get('default')
options = param.get('options', [])
# Clean HTML from description
description_clean = re.sub(r'<[^>]+>', '', description) if description else "No description available"
php_doc += f'''
<div style="margin-bottom: 20px; padding-bottom: 20px; border-bottom: 1px solid #374151;">
<h4 style="color: #ffffff; margin-top: 0;">
<code style="background: #0f172a; padding: 4px 8px; border-radius: 3px; color: #a5b4fc;">{param_key}</code>
<span style="color: #e5e7eb; font-weight: normal; font-size: 0.9em;"> - {caption}</span>
</h4>
<p style="color: #e5e7eb; margin: 10px 0;">{description_clean}</p>
'''
if param_type == 'select' and options:
php_doc += ''' <p style="color: #e5e7eb;"><strong>Options:</strong></p>
<ul style="color: #e5e7eb; margin-left: 20px;">
'''
for opt in options:
php_doc += f''' <li><code style="background: #0f172a; padding: 2px 6px; border-radius: 3px; color: #a5b4fc;">{opt['value']}</code> - {opt['text']}</li>\n'''
php_doc += ''' </ul>
'''
if default:
php_doc += f''' <p style="color: #fbbf24;"><strong>Default:</strong> <code style="background: #0f172a; padding: 2px 6px; border-radius: 3px;">{default}</code></p>
'''
php_doc += ''' </div>
'''
php_doc += '''</div>
'''
else:
# Fallback to generic parameters if no XML data
php_doc += '''
<h3>Basic Startup</h3>
'''
if startup_cmd:
php_doc += f'''<pre><code>{startup_cmd}
if startup_cmd:
php_doc += f'''<pre><code>{startup_cmd}
</code></pre>
'''
else:
php_doc += '''<pre><code># Generic startup command structure
else:
php_doc += '''<pre><code># Generic startup command structure
./server_executable [parameters]
</code></pre>
'''
php_doc += '''
php_doc += '''
<h3>Common Parameters</h3>
<ul>
<li><code>-port [number]</code> - Set the server port</li>
@ -892,8 +1051,103 @@ sudo ufw enable
errors.append(error_msg)
return processed, errors
def process_specific_games(self, game_names, force_overwrite=False):
"""Process specific game folders by name"""
processed = 0
skipped = 0
errors = []
for game_name in game_names:
folder = self.docs_dir / game_name
if not folder.is_dir():
error_msg = f"Game folder not found: {game_name}"
print(f"{error_msg}")
errors.append(error_msg)
continue
metadata_file = folder / 'metadata.json'
index_file = folder / 'index.php'
if not metadata_file.exists():
error_msg = f"metadata.json not found for {game_name}"
print(f"{error_msg}")
errors.append(error_msg)
continue
try:
# Read metadata
with open(metadata_file, 'r', encoding='utf-8') as f:
content = f.read()
content = content.lstrip('\ufeff')
metadata = json.loads(content)
# Check if we should skip
if index_file.exists() and not force_overwrite:
print(f"Skipping {game_name} (file exists, use --force to overwrite)")
skipped += 1
continue
print(f"Processing: {game_name}")
# Generate new documentation
php_content = self.generate_php_doc(folder.name, metadata)
# Write the new index.php
with open(index_file, 'w', encoding='utf-8') as f:
f.write(php_content)
# Update metadata if it was todo
if metadata.get('category', '').lower() == 'todo':
metadata['category'] = 'game'
# Mark as complete
metadata['complete'] = True
with open(metadata_file, 'w', encoding='utf-8') as f:
json.dump(metadata, f, indent=4, ensure_ascii=False)
processed += 1
print(f" ✓ Generated documentation for {game_name}")
except Exception as e:
error_msg = f"Error processing {game_name}: {e}"
print(f"{error_msg}")
errors.append(error_msg)
return processed, skipped, errors
def main():
# Parse command line arguments
parser = argparse.ArgumentParser(
description='Generate comprehensive game server documentation for GSP',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Generate docs for all incomplete games:
python3 generate_game_docs.py
# Generate docs for specific game(s):
python3 generate_game_docs.py --games minecraft csgo rust
# Regenerate docs (overwrite existing):
python3 generate_game_docs.py --games minecraft --force
# Process all "todo" category games:
python3 generate_game_docs.py --todo-only
"""
)
parser.add_argument('--games', nargs='+', metavar='GAME',
help='Generate docs for specific game folder names')
parser.add_argument('--force', action='store_true',
help='Overwrite existing documentation files')
parser.add_argument('--todo-only', action='store_true',
help='Only process games with category="todo"')
args = parser.parse_args()
docs_dir = "/home/runner/work/GSP/GSP/modules/billing/docs"
config_dir = "/home/runner/work/GSP/GSP/modules/config_games/server_configs"
knowledgepack = "/home/runner/work/GSP/GSP/modules/billing/docs/gameserver_knowledgepack_v2.yaml"
@ -908,15 +1162,37 @@ def main():
generator.load_knowledgepack()
generator.load_xml_configs()
print("\n" + "="*70)
print("Processing INCOMPLETE game documentation...")
print("="*70)
processed, skipped, errors = generator.process_incomplete_games()
processed = 0
skipped = 0
errors = []
# Determine which mode to run
if args.games:
# Process specific games
print("\n" + "="*70)
print(f"Processing {len(args.games)} specified game(s)...")
if args.force:
print("FORCE mode: Will overwrite existing files")
print("="*70)
processed, skipped, errors = generator.process_specific_games(args.games, args.force)
elif args.todo_only:
# Process only todo category games
print("\n" + "="*70)
print("Processing TODO category games...")
print("="*70)
processed, errors = generator.process_todo_folders()
else:
# Process incomplete games (default)
print("\n" + "="*70)
print("Processing INCOMPLETE game documentation...")
print("="*70)
processed, skipped, errors = generator.process_incomplete_games()
print(f"\n{'='*70}")
print(f"Documentation generation complete!")
print(f" ✓ Processed: {processed}")
print(f" → Skipped (already complete): {skipped}")
if skipped > 0:
print(f" → Skipped: {skipped}")
print(f" ✗ Errors: {len(errors)}")
if errors:
@ -926,12 +1202,12 @@ def main():
if len(errors) > 10:
print(f" ... and {len(errors) - 10} more")
print(f"\nAll documentation has been enhanced with:")
print(f" • Actual port information (not 'Check server configuration')")
print(f"\nGenerated documentation includes:")
print(f" • Actual port information from XML configs")
print(f" • Steam App IDs and exact SteamCMD commands")
print(f" • Configuration file details from XML configs")
print(f"Startup parameters extracted from XML")
print(f"Troubleshooting info from knowledgepack")
print(f"DETAILED startup parameters extracted from XML")
print(f"Comprehensive troubleshooting sections")
print("="*70)
return 0 if not errors else 1