2 Commits

Author SHA1 Message Date
uprightbass360
179c486f73 mod-ale finnagling 2026-01-02 18:33:10 -05:00
uprightbass360
a497f2844c cleanup: better variable handling 2026-01-02 16:18:25 -05:00
13 changed files with 405 additions and 33 deletions

View File

@@ -14,7 +14,7 @@ COMPOSE_OVERRIDE_WORLDSERVER_DEBUG_LOGGING_ENABLED=0
# Project name
# =====================
# Customize this to match your deployment slug (used for container names/tags)
COMPOSE_PROJECT_NAME=azerothcore-stack
COMPOSE_PROJECT_NAME=azerothcore-realmmaster
# =====================
# Storage & Timezone
@@ -96,15 +96,15 @@ AC_DB_IMPORT_IMAGE=acore/ac-wotlk-db-import:master
AC_AUTHSERVER_IMAGE=acore/ac-wotlk-authserver:master
AC_WORLDSERVER_IMAGE=acore/ac-wotlk-worldserver:master
# Services (Playerbots)
AC_AUTHSERVER_IMAGE_PLAYERBOTS=azerothcore-realmmaster:authserver-playerbots
AC_WORLDSERVER_IMAGE_PLAYERBOTS=azerothcore-realmmaster:worldserver-playerbots
AC_AUTHSERVER_IMAGE_PLAYERBOTS=${COMPOSE_PROJECT_NAME}:authserver-playerbots
AC_WORLDSERVER_IMAGE_PLAYERBOTS=${COMPOSE_PROJECT_NAME}:worldserver-playerbots
# Services (Module Build Tags)
# Images used during module compilation and tagging
AC_AUTHSERVER_IMAGE_MODULES=azerothcore-realmmaster:authserver-modules-latest
AC_WORLDSERVER_IMAGE_MODULES=azerothcore-realmmaster:worldserver-modules-latest
AC_AUTHSERVER_IMAGE_MODULES=${COMPOSE_PROJECT_NAME}:authserver-modules-latest
AC_WORLDSERVER_IMAGE_MODULES=${COMPOSE_PROJECT_NAME}:worldserver-modules-latest
# Client Data
AC_CLIENT_DATA_IMAGE=acore/ac-wotlk-client-data:master
AC_CLIENT_DATA_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:client-data-Playerbot
AC_CLIENT_DATA_IMAGE_PLAYERBOTS=${COMPOSE_PROJECT_NAME}:client-data-playerbots
# Build artifacts
DOCKER_IMAGE_TAG=master
AC_AUTHSERVER_IMAGE_BASE=acore/ac-wotlk-authserver

1
.gitignore vendored
View File

@@ -13,6 +13,7 @@ images/
node_modules/
.mcp*/
scripts/__pycache__/*
scripts/bash/__pycache__/*
scripts/python/__pycache__/*
.env
package-lock.json

View File

@@ -38,6 +38,7 @@ Build AzerothCore with custom modules and create deployment-ready images.
Options:
--yes, -y Auto-confirm all prompts
--force Force rebuild even if no changes detected
--force-update Force update source repository to latest commits
--source-path PATH Custom source repository path
--skip-source-setup Skip automatic source repository setup
-h, --help Show this help
@@ -53,6 +54,7 @@ Examples:
./build.sh Interactive build
./build.sh --yes Auto-confirm build
./build.sh --force Force rebuild regardless of state
./build.sh --force-update Update source to latest and build
EOF
}
@@ -60,6 +62,7 @@ while [[ $# -gt 0 ]]; do
case "$1" in
--yes|-y) ASSUME_YES=1; shift;;
--force) FORCE_REBUILD=1; shift;;
--force-update) FORCE_UPDATE=1; shift;;
--source-path) CUSTOM_SOURCE_PATH="$2"; shift 2;;
--skip-source-setup) SKIP_SOURCE_SETUP=1; shift;;
-h|--help) usage; exit 0;;
@@ -240,6 +243,13 @@ ensure_source_repo(){
src_path="${src_path//\/.\//\/}"
if [ -d "$src_path/.git" ]; then
if [ "${FORCE_UPDATE:-0}" = "1" ]; then
info "Force update requested - updating source repository to latest" >&2
if ! (cd "$ROOT_DIR" && ./scripts/bash/setup-source.sh) >&2; then
err "Failed to update source repository" >&2
exit 1
fi
fi
echo "$src_path"
return
fi
@@ -540,6 +550,10 @@ stage_modules(){
rm -f "$staging_modules_dir/.modules_state" "$staging_modules_dir/.requires_rebuild" 2>/dev/null || true
fi
# Export environment variables needed by module hooks
export STACK_SOURCE_VARIANT="$(read_env STACK_SOURCE_VARIANT "core")"
export MODULES_REBUILD_SOURCE_PATH="$(read_env MODULES_REBUILD_SOURCE_PATH "")"
if ! (cd "$local_modules_dir" && bash "$ROOT_DIR/scripts/bash/manage-modules.sh"); then
err "Module staging failed; aborting build"
return 1

View File

@@ -99,7 +99,36 @@ done
# Get last build time from container metadata
get_last_build_time() {
local containers=("ac-worldserver" "ac-authserver")
local images=("azerothcore-stack:worldserver-playerbots" "azerothcore-stack:authserver-playerbots")
local images=()
# Require COMPOSE_PROJECT_NAME to be set
if [[ -z "${COMPOSE_PROJECT_NAME:-}" ]]; then
warn "COMPOSE_PROJECT_NAME not set in environment"
return 1
fi
# Use actual image names from environment
# Detect variant to check appropriate images
if [[ "${STACK_IMAGE_MODE:-standard}" == "playerbots" ]] || [[ "${MODULE_PLAYERBOTS:-0}" == "1" ]] || [[ "${PLAYERBOT_ENABLED:-0}" == "1" ]] || [[ "${STACK_SOURCE_VARIANT:-}" == "playerbots" ]]; then
if [[ -z "${AC_WORLDSERVER_IMAGE_PLAYERBOTS:-}" ]] || [[ -z "${AC_AUTHSERVER_IMAGE_PLAYERBOTS:-}" ]]; then
warn "Playerbots mode detected but AC_WORLDSERVER_IMAGE_PLAYERBOTS or AC_AUTHSERVER_IMAGE_PLAYERBOTS not set"
return 1
fi
images=(
"${AC_WORLDSERVER_IMAGE_PLAYERBOTS}"
"${AC_AUTHSERVER_IMAGE_PLAYERBOTS}"
)
else
if [[ -z "${AC_WORLDSERVER_IMAGE:-}" ]] || [[ -z "${AC_AUTHSERVER_IMAGE:-}" ]]; then
warn "Standard mode detected but AC_WORLDSERVER_IMAGE or AC_AUTHSERVER_IMAGE not set"
return 1
fi
images=(
"${AC_WORLDSERVER_IMAGE}"
"${AC_AUTHSERVER_IMAGE}"
)
fi
local latest_date=""
# Try to get build timestamp from containers and images
@@ -143,7 +172,7 @@ if [[ -n "$SINCE_DATE" ]]; then
DATE_DESC="since $SINCE_DATE"
else
# Try to use last build time as default
LAST_BUILD_DATE=$(get_last_build_time)
LAST_BUILD_DATE=$(get_last_build_time 2>/dev/null) || LAST_BUILD_DATE=""
if [[ -n "$LAST_BUILD_DATE" ]]; then
SINCE_OPTION="--since=$LAST_BUILD_DATE"
@@ -194,11 +223,17 @@ detect_source_config() {
$VERBOSE && log "Switched to playerbots variant" >&2
fi
# Repository URLs from environment or defaults
local standard_repo="${ACORE_REPO_STANDARD:-https://github.com/azerothcore/azerothcore-wotlk.git}"
local standard_branch="${ACORE_BRANCH_STANDARD:-master}"
local playerbots_repo="${ACORE_REPO_PLAYERBOTS:-https://github.com/mod-playerbots/azerothcore-wotlk.git}"
local playerbots_branch="${ACORE_BRANCH_PLAYERBOTS:-Playerbot}"
# Repository URLs from environment (required)
local standard_repo="${ACORE_REPO_STANDARD}"
local standard_branch="${ACORE_BRANCH_STANDARD}"
local playerbots_repo="${ACORE_REPO_PLAYERBOTS}"
local playerbots_branch="${ACORE_BRANCH_PLAYERBOTS}"
if [[ -z "$standard_repo" ]] || [[ -z "$standard_branch" ]] || [[ -z "$playerbots_repo" ]] || [[ -z "$playerbots_branch" ]]; then
warn "Repository configuration missing from environment"
warn "Required: ACORE_REPO_STANDARD, ACORE_BRANCH_STANDARD, ACORE_REPO_PLAYERBOTS, ACORE_BRANCH_PLAYERBOTS"
return 1
fi
if [[ "$variant" == "playerbots" ]]; then
echo "$playerbots_repo|$playerbots_branch|$LOCAL_STORAGE_ROOT/source/azerothcore-playerbots"

View File

@@ -146,8 +146,6 @@ sanitize_project_name(){
project_name::sanitize "$1"
}
PROJECT_IMAGE_PREFIX="$(sanitize_project_name "${COMPOSE_PROJECT_NAME:-$DEFAULT_PROJECT_NAME}")"
remove_storage_dir(){
local path="$1"
if [ -d "$path" ]; then
@@ -223,8 +221,7 @@ nuclear_cleanup() {
# Remove project images (server/tool images typical to this project)
execute_command "Remove acore images" "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^acore/' | xargs -r docker rmi"
execute_command "Remove local project images" "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^${PROJECT_IMAGE_PREFIX}:' | xargs -r docker rmi"
execute_command "Remove legacy playerbots images" "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^uprightbass360/azerothcore-wotlk-playerbots' | xargs -r docker rmi"
execute_command "Remove project-specific images" "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E \"^${PROJECT_NAME}:\" | xargs -r docker rmi"
execute_command "Remove tool images" "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E 'phpmyadmin|uprightbass360/keira3' | xargs -r docker rmi"
# Storage cleanup (preserve backups if requested)

View File

@@ -142,7 +142,7 @@ MODULES_ENABLED="mod-playerbots mod-aoe-loot ..."
**What Gets Built:**
- AzerothCore with playerbots branch
- 93 modules compiled and integrated in this run (current manifest: 348 total / 221 supported)
- Custom Docker images: `acore-compose:worldserver-modules-latest` etc.
- Custom Docker images: `${COMPOSE_PROJECT_NAME}:worldserver-modules-latest` etc.
### Deployment Status: READY TO DEPLOY 🚀

View File

@@ -141,6 +141,10 @@ run_post_install_hooks(){
export MODULES_ROOT="${MODULES_ROOT:-/modules}"
export LUA_SCRIPTS_TARGET="/azerothcore/lua_scripts"
# Pass build environment variables to hooks
export STACK_SOURCE_VARIANT="${STACK_SOURCE_VARIANT:-}"
export MODULES_REBUILD_SOURCE_PATH="${MODULES_REBUILD_SOURCE_PATH:-}"
# Execute the hook script
if "$hook_script"; then
ok "Hook '$hook' completed successfully"

View File

@@ -4,6 +4,7 @@ import os
import re
import socket
import subprocess
import sys
import time
from pathlib import Path
@@ -468,8 +469,14 @@ def docker_stats():
def main():
env = load_env()
project = read_env(env, "COMPOSE_PROJECT_NAME", "acore-compose")
network = read_env(env, "NETWORK_NAME", "azerothcore")
project = read_env(env, "COMPOSE_PROJECT_NAME")
if not project:
print(json.dumps({"error": "COMPOSE_PROJECT_NAME not set in environment"}), file=sys.stderr)
sys.exit(1)
network = read_env(env, "NETWORK_NAME")
if not network:
print(json.dumps({"error": "NETWORK_NAME not set in environment"}), file=sys.stderr)
sys.exit(1)
services = [
("ac-mysql", "MySQL"),

301
scripts/bash/validate-env.sh Executable file
View File

@@ -0,0 +1,301 @@
#!/bin/bash
# Validate environment configuration for AzerothCore RealmMaster
# Usage: ./scripts/bash/validate-env.sh [--strict] [--quiet]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
ENV_FILE="$PROJECT_ROOT/.env"
TEMPLATE_FILE="$PROJECT_ROOT/.env.template"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Flags
STRICT_MODE=false
QUIET_MODE=false
EXIT_CODE=0
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
--strict)
STRICT_MODE=true
shift
;;
--quiet)
QUIET_MODE=true
shift
;;
-h|--help)
cat <<EOF
Usage: $0 [OPTIONS]
Validates environment configuration for required variables.
OPTIONS:
--strict Fail on missing optional variables
--quiet Only show errors, suppress info/success messages
-h, --help Show this help
EXIT CODES:
0 - All required variables present
1 - Missing required variables
2 - Missing optional variables (only in --strict mode)
REQUIRED VARIABLES:
Project Configuration:
COMPOSE_PROJECT_NAME - Project name for containers/images
NETWORK_NAME - Docker network name
Repository Configuration:
ACORE_REPO_STANDARD - Standard AzerothCore repository URL
ACORE_BRANCH_STANDARD - Standard AzerothCore branch name
ACORE_REPO_PLAYERBOTS - Playerbots repository URL
ACORE_BRANCH_PLAYERBOTS - Playerbots branch name
Storage Paths:
STORAGE_PATH - Main storage path
STORAGE_PATH_LOCAL - Local storage path
Database Configuration:
MYSQL_ROOT_PASSWORD - MySQL root password
MYSQL_USER - MySQL user (typically root)
MYSQL_PORT - MySQL port (typically 3306)
MYSQL_HOST - MySQL hostname
DB_AUTH_NAME - Auth database name
DB_WORLD_NAME - World database name
DB_CHARACTERS_NAME - Characters database name
DB_PLAYERBOTS_NAME - Playerbots database name
Container Configuration:
CONTAINER_MYSQL - MySQL container name
CONTAINER_USER - Container user (format: uid:gid)
OPTIONAL VARIABLES (checked with --strict):
MySQL Performance:
MYSQL_INNODB_BUFFER_POOL_SIZE - InnoDB buffer pool size
MYSQL_INNODB_LOG_FILE_SIZE - InnoDB log file size
MYSQL_INNODB_REDO_LOG_CAPACITY - InnoDB redo log capacity
Database Connection:
DB_RECONNECT_SECONDS - Database reconnection delay
DB_RECONNECT_ATTEMPTS - Database reconnection attempts
Build Configuration:
MODULES_REBUILD_SOURCE_PATH - Path to source for module builds
Backup Configuration:
BACKUP_PATH - Backup storage path
BACKUP_RETENTION_DAYS - Daily backup retention
BACKUP_RETENTION_HOURS - Hourly backup retention
Image Configuration:
AC_AUTHSERVER_IMAGE - Auth server Docker image
AC_WORLDSERVER_IMAGE - World server Docker image
AC_DB_IMPORT_IMAGE - Database import Docker image
EXAMPLES:
$0 # Basic validation
$0 --strict # Strict validation (check optional vars)
$0 --quiet # Only show errors
EOF
exit 0
;;
*)
echo -e "${RED}Unknown option: $1${NC}" >&2
exit 1
;;
esac
done
log_info() {
$QUIET_MODE || echo -e "${BLUE} $*${NC}"
}
log_success() {
$QUIET_MODE || echo -e "${GREEN}$*${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ $*${NC}" >&2
}
log_error() {
echo -e "${RED}$*${NC}" >&2
}
# Load environment
load_env() {
local file="$1"
if [[ ! -f "$file" ]]; then
return 1
fi
set -a
# shellcheck disable=SC1090
source "$file" 2>/dev/null || return 1
set +a
return 0
}
# Check if variable is set and non-empty
check_var() {
local var_name="$1"
local var_value="${!var_name:-}"
if [[ -z "$var_value" ]]; then
return 1
fi
return 0
}
# Validate required variables
validate_required() {
local missing=()
local required_vars=(
# Project Configuration
"COMPOSE_PROJECT_NAME"
"NETWORK_NAME"
# Repository Configuration
"ACORE_REPO_STANDARD"
"ACORE_BRANCH_STANDARD"
"ACORE_REPO_PLAYERBOTS"
"ACORE_BRANCH_PLAYERBOTS"
# Storage Paths
"STORAGE_PATH"
"STORAGE_PATH_LOCAL"
# Database Configuration
"MYSQL_ROOT_PASSWORD"
"MYSQL_USER"
"MYSQL_PORT"
"MYSQL_HOST"
"DB_AUTH_NAME"
"DB_WORLD_NAME"
"DB_CHARACTERS_NAME"
"DB_PLAYERBOTS_NAME"
# Container Configuration
"CONTAINER_MYSQL"
"CONTAINER_USER"
)
log_info "Checking required variables..."
for var in "${required_vars[@]}"; do
if check_var "$var"; then
log_success "$var=${!var}"
else
log_error "$var is not set"
missing+=("$var")
fi
done
if [[ ${#missing[@]} -gt 0 ]]; then
log_error "Missing required variables: ${missing[*]}"
return 1
fi
log_success "All required variables are set"
return 0
}
# Validate optional variables (strict mode)
validate_optional() {
local missing=()
local optional_vars=(
# MySQL Performance Tuning
"MYSQL_INNODB_BUFFER_POOL_SIZE"
"MYSQL_INNODB_LOG_FILE_SIZE"
"MYSQL_INNODB_REDO_LOG_CAPACITY"
# Database Connection Settings
"DB_RECONNECT_SECONDS"
"DB_RECONNECT_ATTEMPTS"
# Build Configuration
"MODULES_REBUILD_SOURCE_PATH"
# Backup Configuration
"BACKUP_PATH"
"BACKUP_RETENTION_DAYS"
"BACKUP_RETENTION_HOURS"
# Image Configuration
"AC_AUTHSERVER_IMAGE"
"AC_WORLDSERVER_IMAGE"
"AC_DB_IMPORT_IMAGE"
)
log_info "Checking optional variables..."
for var in "${optional_vars[@]}"; do
if check_var "$var"; then
log_success "$var is set"
else
log_warning "$var is not set (using default)"
missing+=("$var")
fi
done
if [[ ${#missing[@]} -gt 0 ]]; then
log_warning "Optional variables not set: ${missing[*]}"
return 2
fi
log_success "All optional variables are set"
return 0
}
# Main validation
main() {
log_info "Validating environment configuration..."
echo ""
# Check if .env exists
if [[ ! -f "$ENV_FILE" ]]; then
log_error ".env file not found at $ENV_FILE"
log_info "Copy .env.template to .env and configure it:"
log_info " cp $TEMPLATE_FILE $ENV_FILE"
exit 1
fi
# Load environment
if ! load_env "$ENV_FILE"; then
log_error "Failed to load $ENV_FILE"
exit 1
fi
log_success "Loaded environment from $ENV_FILE"
echo ""
# Validate required variables
if ! validate_required; then
EXIT_CODE=1
fi
echo ""
# Validate optional variables if strict mode
if $STRICT_MODE; then
if ! validate_optional; then
[[ $EXIT_CODE -eq 0 ]] && EXIT_CODE=2
fi
echo ""
fi
# Final summary
if [[ $EXIT_CODE -eq 0 ]]; then
log_success "Environment validation passed ✨"
elif [[ $EXIT_CODE -eq 1 ]]; then
log_error "Environment validation failed (missing required variables)"
elif [[ $EXIT_CODE -eq 2 ]]; then
log_warning "Environment validation passed with warnings (missing optional variables)"
fi
exit $EXIT_CODE
}
main "$@"

View File

@@ -1,4 +1,4 @@
module acore-compose/statusdash
module azerothcore-realmmaster/statusdash
go 1.22

View File

@@ -10,11 +10,19 @@ MODULE_NAME="${MODULE_NAME:-}"
# Detect if we're building with playerbots fork
IS_PLAYERBOTS_FORK=0
if [ -n "$MODULE_DIR" ]; then
# Check if the parent directory structure indicates playerbots fork
if echo "$MODULE_DIR" | grep -q "azerothcore-playerbots"; then
# Method 1: Check STACK_SOURCE_VARIANT environment variable
if [ "${STACK_SOURCE_VARIANT:-}" = "playerbots" ]; then
IS_PLAYERBOTS_FORK=1
fi
echo " ✅ Playerbots detected via STACK_SOURCE_VARIANT"
# Method 2: Check MODULES_REBUILD_SOURCE_PATH
elif [ -n "${MODULES_REBUILD_SOURCE_PATH:-}" ] && echo "${MODULES_REBUILD_SOURCE_PATH}" | grep -q "azerothcore-playerbots"; then
IS_PLAYERBOTS_FORK=1
echo " ✅ Playerbots detected via MODULES_REBUILD_SOURCE_PATH"
else
echo " ❌ Playerbots fork not detected"
echo " 🔍 Debug: STACK_SOURCE_VARIANT='${STACK_SOURCE_VARIANT:-}'"
echo " 🔍 Debug: MODULES_REBUILD_SOURCE_PATH='${MODULES_REBUILD_SOURCE_PATH:-}'"
fi
# Feature flags (set to 0 to disable specific patches)
@@ -69,10 +77,10 @@ apply_sendtrainerlist_patch() {
return 1
fi
# Check if the buggy code exists (without GET_GUID())
# Check if the buggy code exists (without GetGUID())
if grep -q 'player->GetSession()->SendTrainerList(obj);' "$target_file"; then
# Apply the fix by adding ->GET_GUID()
if sed -i 's/player->GetSession()->SendTrainerList(obj);/player->GetSession()->SendTrainerList(obj->GET_GUID());/' "$target_file"; then
# Apply the fix by adding ->GetGUID()
if sed -i 's/player->GetSession()->SendTrainerList(obj);/player->GetSession()->SendTrainerList(obj->GetGUID());/' "$target_file"; then
echo " ✅ Applied SendTrainerList compatibility fix"
return 0
else

View File

@@ -46,7 +46,7 @@ CATEGORY_BY_TYPE = {
"data": "data",
"cpp": "uncategorized",
}
USER_AGENT = "acore-compose-module-manifest"
USER_AGENT = "azerothcore-realmmaster-module-manifest"
def parse_args(argv: Sequence[str]) -> argparse.Namespace:

View File

@@ -1487,11 +1487,16 @@ fi
MODULES_CPP_LIST="$(IFS=','; printf '%s' "${enabled_cpp_module_keys[*]}")"
fi
local STACK_IMAGE_MODE="standard"
# Determine source variant based ONLY on playerbots module
local STACK_SOURCE_VARIANT="core"
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$PLAYERBOT_ENABLED" = "1" ]; then
STACK_IMAGE_MODE="playerbots"
STACK_SOURCE_VARIANT="playerbots"
fi
# Determine image mode based on source variant and build requirements
local STACK_IMAGE_MODE="standard"
if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
STACK_IMAGE_MODE="playerbots"
elif [ "$NEEDS_CXX_REBUILD" = "1" ]; then
STACK_IMAGE_MODE="modules"
fi
@@ -1587,7 +1592,7 @@ fi
fi
local default_source_rel="${LOCAL_STORAGE_ROOT}/source/azerothcore"
if [ "$MODULE_PLAYERBOTS" = "1" ]; then
if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
default_source_rel="${LOCAL_STORAGE_ROOT}/source/azerothcore-playerbots"
fi