Complete C# server cutover

This commit is contained in:
Nomads_Reach
2026-08-16 02:36:32 -04:00
parent ddadf87423
commit 757e614cdd
79 changed files with 923 additions and 13129 deletions
Regular → Executable
+47 -180
View File
@@ -9,204 +9,71 @@ else
fi
cd -- "${SCRIPT_DIR}"
SERVER_DIR="${SCRIPT_DIR}"
VENV_DIR="${SERVER_DIR}/.venv"
REQUIREMENTS_FILE="${SERVER_DIR}/requirements-server.txt"
REQUIREMENTS_HASH_FILE="${VENV_DIR}/.requirements-server.sha256"
CONFIG_FILE="${SERVER_DIR}/commonwealth-server.json"
ENTRY_POINT="${SERVER_DIR}/consumer_server_cli.py"
CONFIG_FILE="${SCRIPT_DIR}/commonwealth-server.json"
UPDATE_DEPENDENCIES=0
SERVER_ARGS=()
ARGS=("$@")
ARG_INDEX=0
while [[ ${ARG_INDEX} -lt ${#ARGS[@]} ]]; do
arg="${ARGS[${ARG_INDEX}]}"
INDEX=0
while [[ ${INDEX} -lt ${#ARGS[@]} ]]; do
arg="${ARGS[${INDEX}]}"
case "${arg}" in
--update-dependencies)
UPDATE_DEPENDENCIES=1
;;
--update-dependencies) UPDATE_DEPENDENCIES=1 ;;
--config|-c)
ARG_INDEX=$((ARG_INDEX + 1))
if [[ ${ARG_INDEX} -ge ${#ARGS[@]} ]]; then
echo "ERROR: ${arg} requires a config file path." >&2
exit 1
fi
CONFIG_FILE="${ARGS[${ARG_INDEX}]}"
;;
--config=*)
CONFIG_FILE="${arg#--config=}"
;;
--host|--port|-H|-p|--interactive|-i)
SERVER_ARGS+=("${arg}")
if [[ "${arg}" == "--host" || "${arg}" == "-H" || "${arg}" == "--port" || "${arg}" == "-p" ]]; then
ARG_INDEX=$((ARG_INDEX + 1))
if [[ ${ARG_INDEX} -ge ${#ARGS[@]} ]]; then
echo "ERROR: ${arg} requires a value." >&2
exit 1
fi
SERVER_ARGS+=("${ARGS[${ARG_INDEX}]}")
fi
;;
--host=*|--port=*)
SERVER_ARGS+=("${arg}")
;;
*.json)
# File managers / "Open with" often pass the config path as $1.
CONFIG_FILE="${arg}"
;;
-*)
echo "ERROR: Unknown option: ${arg}" >&2
echo "Supported: --update-dependencies, --config PATH, --host HOST, --port PORT, --interactive" >&2
exit 1
;;
*)
if [[ -f "${arg}" ]]; then
CONFIG_FILE="${arg}"
else
echo "ERROR: Unexpected argument: ${arg}" >&2
exit 1
fi
;;
INDEX=$((INDEX + 1)); [[ ${INDEX} -lt ${#ARGS[@]} ]] || { echo "ERROR: ${arg} requires a path" >&2; exit 1; }
CONFIG_FILE="${ARGS[${INDEX}]}" ;;
--config=*) CONFIG_FILE="${arg#--config=}" ;;
--host|--port|-H|-p)
SERVER_ARGS+=("${arg}"); INDEX=$((INDEX + 1)); [[ ${INDEX} -lt ${#ARGS[@]} ]] || { echo "ERROR: ${arg} requires a value" >&2; exit 1; }
SERVER_ARGS+=("${ARGS[${INDEX}]}") ;;
--host=*|--port=*|--interactive|-i) SERVER_ARGS+=("${arg}") ;;
*.json) CONFIG_FILE="${arg}" ;;
-*) echo "ERROR: Unknown option: ${arg}" >&2; exit 1 ;;
*) [[ -f "${arg}" ]] && CONFIG_FILE="${arg}" || { echo "ERROR: Unexpected argument: ${arg}" >&2; exit 1; } ;;
esac
ARG_INDEX=$((ARG_INDEX + 1))
INDEX=$((INDEX + 1))
done
echo
echo "================================================================================"
echo " Commonwealth Online Server - Start Script"
echo "================================================================================"
echo
if [[ "${CONFIG_FILE}" != /* ]]; then CONFIG_FILE="${SCRIPT_DIR}/${CONFIG_FILE}"; fi
CONFIG_FILE="$(cd -- "$(dirname -- "${CONFIG_FILE}")" && pwd)/$(basename -- "${CONFIG_FILE}")"
die() {
echo "ERROR: $*" >&2
exit 1
}
detect_python() {
local candidate
for candidate in python3 python; do
if command -v "${candidate}" >/dev/null 2>&1; then
if "${candidate}" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 9) else 1)'; then
echo "${candidate}"
return 0
fi
fi
done
resolve_server() {
local apphost="${SCRIPT_DIR}/CommonwealthOnline.Server"
local dll="${SCRIPT_DIR}/CommonwealthOnline.Server.dll"
local project="${SCRIPT_DIR}/CommonwealthOnline.Server.csproj"
if [[ -f "${apphost}" ]]; then
chmod +x "${apphost}" 2>/dev/null || true
SERVER_CMD=("${apphost}")
return 0
fi
if [[ -f "${dll}" ]] && command -v dotnet >/dev/null 2>&1; then
SERVER_CMD=(dotnet "${dll}")
return 0
fi
if [[ -f "${project}" ]] && command -v dotnet >/dev/null 2>&1; then
SERVER_CMD=(dotnet run --project "${project}" -c Release --no-launch-profile --)
return 0
fi
return 1
}
if [[ ! -f "${REQUIREMENTS_FILE}" ]]; then
die "Missing requirements file: ${REQUIREMENTS_FILE}"
if ! resolve_server; then
echo "ERROR: CommonwealthOnline.Server is not published and the .NET 8 SDK/runtime is unavailable." >&2
exit 1
fi
if [[ ! -f "${ENTRY_POINT}" ]]; then
die "Missing server entry point: ${ENTRY_POINT}"
if [[ ${UPDATE_DEPENDENCIES} -eq 1 ]]; then
command -v dotnet >/dev/null 2>&1 || { echo "ERROR: --update-dependencies requires the .NET SDK" >&2; exit 1; }
dotnet restore "${SCRIPT_DIR}/CommonwealthOnline.Server.csproj"
fi
if ! BASE_PYTHON="$(detect_python)"; then
die "Python 3.9+ is required. Install python3 (and python3-venv on Debian/Ubuntu)."
fi
echo "Using system interpreter: ${BASE_PYTHON} ($("${BASE_PYTHON}" --version 2>&1))"
if [[ ! -x "${VENV_DIR}/bin/python" ]]; then
echo "Creating virtual environment at ${VENV_DIR}..."
if ! "${BASE_PYTHON}" -m venv "${VENV_DIR}"; then
die "Failed to create virtual environment. On Debian/Ubuntu install python3-venv."
fi
fi
VENV_PYTHON="${VENV_DIR}/bin/python"
if [[ ! -x "${VENV_PYTHON}" ]]; then
die "Virtual environment interpreter missing: ${VENV_PYTHON}"
fi
if ! "${VENV_PYTHON}" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 9) else 1)'; then
die "Virtual environment Python is older than 3.9."
fi
hash_requirements() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum -- "${REQUIREMENTS_FILE}" | awk '{print $1}'
else
"${VENV_PYTHON}" - <<'PY'
from hashlib import sha256
from pathlib import Path
print(sha256(Path("requirements-server.txt").read_bytes()).hexdigest())
PY
fi
}
CURRENT_HASH="$(hash_requirements)"
STORED_HASH=""
if [[ -f "${REQUIREMENTS_HASH_FILE}" ]]; then
STORED_HASH="$(tr -d '[:space:]' < "${REQUIREMENTS_HASH_FILE}")"
fi
NEED_INSTALL=0
if [[ ! -f "${REQUIREMENTS_HASH_FILE}" ]]; then
NEED_INSTALL=1
elif [[ "${CURRENT_HASH}" != "${STORED_HASH}" ]]; then
NEED_INSTALL=1
elif [[ "${UPDATE_DEPENDENCIES}" -eq 1 ]]; then
NEED_INSTALL=1
fi
if [[ "${NEED_INSTALL}" -eq 1 ]]; then
echo "Installing dedicated-server dependencies into .venv..."
if ! "${VENV_PYTHON}" -m pip install --upgrade pip >/dev/null 2>&1; then
echo "WARNING: Could not upgrade pip quietly; continuing with existing pip."
fi
if ! "${VENV_PYTHON}" -m pip install -r "${REQUIREMENTS_FILE}"; then
die "Failed to install dependencies from ${REQUIREMENTS_FILE}."
fi
printf '%s\n' "${CURRENT_HASH}" > "${REQUIREMENTS_HASH_FILE}"
echo "Dependencies installed."
else
echo "Dependencies are up to date."
fi
echo
if [[ ! -f "${CONFIG_FILE}" ]]; then
echo "Generating default configuration file..."
if ! "${VENV_PYTHON}" -u "${ENTRY_POINT}" config init "${CONFIG_FILE}"; then
die "Failed to generate config file."
fi
echo
echo "Generating default configuration: ${CONFIG_FILE}"
"${SERVER_CMD[@]}" config init "${CONFIG_FILE}"
fi
INTERACTIVE_ARGS=()
if [[ -t 0 && -t 1 ]]; then
INTERACTIVE_ARGS+=(--interactive)
echo "Starting Commonwealth Online Server (interactive)..."
echo "Type help for commands. Type quit or press Ctrl+C to stop."
else
echo "Starting Commonwealth Online Server (non-interactive)..."
echo "Manage the server with: ${VENV_PYTHON} -u consumer_server_cli.py status"
if [[ -t 0 && -t 1 ]] && [[ ! " ${SERVER_ARGS[*]} " =~ " --interactive " ]] && [[ ! " ${SERVER_ARGS[*]} " =~ " -i " ]]; then
SERVER_ARGS+=(--interactive)
fi
echo
# Resolve config to an absolute path after cd'ing into the server directory.
if [[ "${CONFIG_FILE}" != /* ]]; then
CONFIG_FILE="${SERVER_DIR}/${CONFIG_FILE}"
fi
CONFIG_FILE="$(cd -- "$(dirname -- "${CONFIG_FILE}")" && pwd)/$(basename -- "${CONFIG_FILE}")"
# Do not source .venv/bin/activate — invoke the venv interpreter directly.
# Always pass --config explicitly so a bare path is never a positional serve arg.
CMD=(
"${VENV_PYTHON}"
-u
"${ENTRY_POINT}"
serve
--config
"${CONFIG_FILE}"
)
if [[ ${#INTERACTIVE_ARGS[@]} -gt 0 ]]; then
CMD+=("${INTERACTIVE_ARGS[@]}")
fi
if [[ ${#SERVER_ARGS[@]} -gt 0 ]]; then
CMD+=("${SERVER_ARGS[@]}")
fi
exec "${CMD[@]}"
echo "Starting Commonwealth Online C# server"
exec "${SERVER_CMD[@]}" serve --config "${CONFIG_FILE}" "${SERVER_ARGS[@]}"