diff --git a/.env b/.env new file mode 100644 index 0000000..545c9f1 --- /dev/null +++ b/.env @@ -0,0 +1,128 @@ +# Generated by ac-compose/setup.sh + +COMPOSE_PROJECT_NAME=ac-compose + +STORAGE_PATH=./storage +TZ=UTC + +# Database +MYSQL_IMAGE=mysql:8.0 +CONTAINER_MYSQL=ac-mysql +MYSQL_ROOT_PASSWORD=azerothcore123 +MYSQL_ROOT_HOST=% +MYSQL_USER=root +MYSQL_PORT=3306 +MYSQL_EXTERNAL_PORT=64306 +MYSQL_CHARACTER_SET=utf8mb4 +MYSQL_COLLATION=utf8mb4_unicode_ci +MYSQL_MAX_CONNECTIONS=1000 +MYSQL_INNODB_BUFFER_POOL_SIZE=256M +MYSQL_INNODB_LOG_FILE_SIZE=64M +DB_AUTH_NAME=acore_auth +DB_WORLD_NAME=acore_world +DB_CHARACTERS_NAME=acore_characters +AC_DB_IMPORT_IMAGE=acore/ac-wotlk-db-import:14.0.0-dev + +# Services (images) +AC_AUTHSERVER_IMAGE=acore/ac-wotlk-authserver:14.0.0-dev +AC_WORLDSERVER_IMAGE=acore/ac-wotlk-worldserver:14.0.0-dev +AC_AUTHSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot +AC_WORLDSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot + +# Client data images +AC_CLIENT_DATA_IMAGE=acore/ac-wotlk-client-data:14.0.0-dev +AC_CLIENT_DATA_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:client-data-Playerbot + +# Ports +AUTH_EXTERNAL_PORT=3784 +AUTH_PORT=3724 +WORLD_EXTERNAL_PORT=8215 +WORLD_PORT=8085 +SOAP_EXTERNAL_PORT=7778 +SOAP_PORT=7878 + +# Realm +SERVER_ADDRESS=127.0.0.1 +REALM_PORT=8215 + +# Backups +BACKUP_RETENTION_DAYS=3 +BACKUP_RETENTION_HOURS=6 +BACKUP_DAILY_TIME=09 + +# Container user +CONTAINER_USER=0:0 + +# Modules +MODULE_PLAYERBOTS=1 +MODULE_AOE_LOOT=0 +MODULE_LEARN_SPELLS=1 +MODULE_FIREWORKS=1 +MODULE_INDIVIDUAL_PROGRESSION=0 +MODULE_AHBOT=1 +MODULE_AUTOBALANCE=1 +MODULE_TRANSMOG=1 +MODULE_NPC_BUFFER=1 +MODULE_DYNAMIC_XP=0 +MODULE_SOLO_LFG=1 +MODULE_1V1_ARENA=0 +MODULE_PHASED_DUELS=0 +MODULE_BREAKING_NEWS=0 +MODULE_BOSS_ANNOUNCER=0 +MODULE_ACCOUNT_ACHIEVEMENTS=0 +MODULE_AUTO_REVIVE=0 +MODULE_GAIN_HONOR_GUARD=0 +MODULE_ELUNA=1 +MODULE_ARAC=0 +MODULE_TIME_IS_TIME=0 +MODULE_POCKET_PORTAL=0 +MODULE_RANDOM_ENCHANTS=0 +MODULE_SOLOCRAFT=1 +MODULE_PVP_TITLES=0 +MODULE_NPC_BEASTMASTER=0 +MODULE_NPC_ENCHANTER=0 +MODULE_INSTANCE_RESET=0 +MODULE_LEVEL_GRANT=0 +MODULE_ASSISTANT=0 +MODULE_REAGENT_BANK=0 +MODULE_BLACK_MARKET_AUCTION_HOUSE=0 + +# Client data +CLIENT_DATA_VERSION=v16 + +# Playerbot runtime +PLAYERBOT_ENABLED=0 +PLAYERBOT_MAX_BOTS=40 + +# Rebuild automation +AUTO_REBUILD_ON_DEPLOY=0 +MODULES_REBUILD_SOURCE_PATH= + +# Eluna +AC_ELUNA_ENABLED=1 +AC_ELUNA_TRACE_BACK=1 +AC_ELUNA_AUTO_RELOAD=1 +AC_ELUNA_BYTECODE_CACHE=1 +AC_ELUNA_SCRIPT_PATH=lua_scripts +AC_ELUNA_REQUIRE_PATHS= +AC_ELUNA_REQUIRE_CPATHS= +AC_ELUNA_AUTO_RELOAD_INTERVAL=1 + +# Tools +PMA_HOST=ac-mysql +PMA_PORT=3306 +PMA_USER=root +PMA_EXTERNAL_PORT=8081 +PMA_ARBITRARY=1 +PMA_ABSOLUTE_URI= +PMA_UPLOAD_LIMIT=300M +PMA_MEMORY_LIMIT=512M +PMA_MAX_EXECUTION_TIME=600 +KEIRA3_EXTERNAL_PORT=4201 +KEIRA_DATABASE_HOST=ac-mysql +KEIRA_DATABASE_PORT=3306 + +# Networking +NETWORK_NAME=azerothcore +NETWORK_SUBNET=172.20.0.0/16 +NETWORK_GATEWAY=172.20.0.1 diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..1f724dc --- /dev/null +++ b/.env.template @@ -0,0 +1,168 @@ +# Copy this file to .env and adjust values for your environment. +# Docker Compose will auto-load .env in the same folder as compose.yml. +# Template for acore-compose profiles-based compose + +# Project name +COMPOSE_PROJECT_NAME=acore-compose + +# ===================== +# Storage & Timezone +# ===================== +STORAGE_PATH=./storage +TZ=UTC + +# ===================== +# MySQL / Database Layer +# ===================== +MYSQL_IMAGE=mysql:8.0 +CONTAINER_MYSQL=ac-mysql +MYSQL_ROOT_PASSWORD=azerothcore123 +MYSQL_ROOT_HOST=% +MYSQL_USER=root +MYSQL_PORT=3306 +MYSQL_EXTERNAL_PORT=64306 +MYSQL_CHARACTER_SET=utf8mb4 +MYSQL_COLLATION=utf8mb4_unicode_ci +MYSQL_MAX_CONNECTIONS=1000 +MYSQL_INNODB_BUFFER_POOL_SIZE=256M +MYSQL_INNODB_LOG_FILE_SIZE=64M + +# DB names +DB_AUTH_NAME=acore_auth +DB_WORLD_NAME=acore_world +DB_CHARACTERS_NAME=acore_characters + +# DB import image +AC_DB_IMPORT_IMAGE=acore/ac-wotlk-db-import:14.0.0-dev + +# ===================== +# Services (Standard) +# ===================== +AC_AUTHSERVER_IMAGE=acore/ac-wotlk-authserver:14.0.0-dev +AC_WORLDSERVER_IMAGE=acore/ac-wotlk-worldserver:14.0.0-dev + +# ===================== +# Services (Playerbots) +# ===================== +AC_AUTHSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot +AC_WORLDSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot + +# ===================== +# Client Data +# ===================== +AC_CLIENT_DATA_IMAGE=acore/ac-wotlk-client-data:14.0.0-dev +AC_CLIENT_DATA_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:client-data-Playerbot +CLIENT_DATA_VERSION=v16 + +# ===================== +# Ports +# ===================== +AUTH_EXTERNAL_PORT=3784 +AUTH_PORT=3724 +WORLD_EXTERNAL_PORT=8215 +WORLD_PORT=8085 +SOAP_EXTERNAL_PORT=7778 +SOAP_PORT=7878 + +# ===================== +# Server address / realm +# ===================== +SERVER_ADDRESS=127.0.0.1 +REALM_PORT=8215 + +# ===================== +# Playerbots runtime flags (used by worldserver env) +# ===================== +PLAYERBOT_ENABLED=0 +PLAYERBOT_MAX_BOTS=40 + +# ===================== +# Git for ac-modules (optional) +# ===================== + +# Playerbot runtime flags +PLAYERBOT_ENABLED=0 +PLAYERBOT_MAX_BOTS=40 + +# ===================== +# Module toggles (0/1) +# ===================== +MODULE_PLAYERBOTS=0 +MODULE_AOE_LOOT=0 +MODULE_LEARN_SPELLS=0 +MODULE_FIREWORKS=0 +MODULE_INDIVIDUAL_PROGRESSION=0 +MODULE_AHBOT=0 +MODULE_AUTOBALANCE=0 +MODULE_TRANSMOG=0 +MODULE_NPC_BUFFER=0 +MODULE_DYNAMIC_XP=0 +MODULE_SOLO_LFG=0 +MODULE_1V1_ARENA=0 +MODULE_PHASED_DUELS=0 +MODULE_BREAKING_NEWS=0 +MODULE_BOSS_ANNOUNCER=0 +MODULE_ACCOUNT_ACHIEVEMENTS=0 +MODULE_AUTO_REVIVE=0 +MODULE_GAIN_HONOR_GUARD=0 +MODULE_ELUNA=1 +MODULE_ARAC=0 +MODULE_TIME_IS_TIME=0 +MODULE_POCKET_PORTAL=0 +MODULE_RANDOM_ENCHANTS=0 +MODULE_SOLOCRAFT=0 +MODULE_PVP_TITLES=0 +MODULE_NPC_BEASTMASTER=0 +MODULE_NPC_ENCHANTER=0 +MODULE_INSTANCE_RESET=0 +MODULE_LEVEL_GRANT=0 +MODULE_ASSISTANT=0 +MODULE_REAGENT_BANK=0 +MODULE_BLACK_MARKET_AUCTION_HOUSE=0 + +# ===================== +# Rebuild automation +# ===================== +AUTO_REBUILD_ON_DEPLOY=0 +MODULES_REBUILD_SOURCE_PATH= + +# ===================== +# Eluna runtime (worldserver.conf overrides) +# ===================== +AC_ELUNA_ENABLED=1 +AC_ELUNA_TRACE_BACK=1 +AC_ELUNA_AUTO_RELOAD=1 +AC_ELUNA_BYTECODE_CACHE=1 +AC_ELUNA_SCRIPT_PATH=lua_scripts +AC_ELUNA_REQUIRE_PATHS= +AC_ELUNA_REQUIRE_CPATHS= +AC_ELUNA_AUTO_RELOAD_INTERVAL=1 + +# ===================== +# Tools (phpMyAdmin / Keira3) +# ===================== +PMA_HOST=ac-mysql +PMA_PORT=3306 +PMA_USER=root +PMA_EXTERNAL_PORT=8081 +PMA_ARBITRARY=1 +PMA_ABSOLUTE_URI= +PMA_UPLOAD_LIMIT=300M +PMA_MEMORY_LIMIT=512M +PMA_MAX_EXECUTION_TIME=600 + +KEIRA3_EXTERNAL_PORT=4201 +KEIRA_DATABASE_HOST=ac-mysql +KEIRA_DATABASE_PORT=3306 + +# ===================== +# Networking +# ===================== +NETWORK_NAME=azerothcore +NETWORK_SUBNET=172.20.0.0/16 +NETWORK_GATEWAY=172.20.0.1 + +# ===================== +# Container user mapping +# ===================== +CONTAINER_USER=0:0 diff --git a/V1/.gitignore b/V1/.gitignore new file mode 100644 index 0000000..5bca2d7 --- /dev/null +++ b/V1/.gitignore @@ -0,0 +1,6 @@ +data/ +backups/ +local-data-tools/ +storage/ +.claude/ +*custom.env diff --git a/.mcp.json b/V1/.mcp.json similarity index 100% rename from .mcp.json rename to V1/.mcp.json diff --git a/ENHANCED-BACKUP-SYSTEM.md b/V1/ENHANCED-BACKUP-SYSTEM.md similarity index 100% rename from ENHANCED-BACKUP-SYSTEM.md rename to V1/ENHANCED-BACKUP-SYSTEM.md diff --git a/README.md b/V1/README.md similarity index 100% rename from README.md rename to V1/README.md diff --git a/docker-compose-azerothcore-database.env b/V1/docker-compose-azerothcore-database.env similarity index 100% rename from docker-compose-azerothcore-database.env rename to V1/docker-compose-azerothcore-database.env diff --git a/docker-compose-azerothcore-database.yml b/V1/docker-compose-azerothcore-database.yml similarity index 100% rename from docker-compose-azerothcore-database.yml rename to V1/docker-compose-azerothcore-database.yml diff --git a/docker-compose-azerothcore-modules.env b/V1/docker-compose-azerothcore-modules.env similarity index 100% rename from docker-compose-azerothcore-modules.env rename to V1/docker-compose-azerothcore-modules.env diff --git a/docker-compose-azerothcore-modules.yml b/V1/docker-compose-azerothcore-modules.yml similarity index 82% rename from docker-compose-azerothcore-modules.yml rename to V1/docker-compose-azerothcore-modules.yml index 80d4806..0c0f911 100644 --- a/docker-compose-azerothcore-modules.yml +++ b/V1/docker-compose-azerothcore-modules.yml @@ -719,8 +719,8 @@ services: REBUILD_REQUIRED=0 # Create current module state hash - for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT; do - eval "value=\$$${module_var}" + for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK MODULE_BLACK_MARKET_AUCTION_HOUSE; do + eval "value=\$$$module_var" CURRENT_STATE="$${CURRENT_STATE}$${module_var}=$${value}|" done @@ -809,6 +809,165 @@ services: networks: - azerothcore + # Build Service for C++ Module Compilation + ac-build: + image: ubuntu:22.04 + pull_policy: ${IMAGE_PULL_POLICY} + container_name: ac-build + user: "${CONTAINER_USER}" + volumes: + - ${STORAGE_PATH}:/azerothcore + - ${STORAGE_PATH}/modules:/azerothcore/modules + - ${STORAGE_PATH}/config:/azerothcore/env/dist/etc + - /var/run/docker.sock:/var/run/docker.sock + environment: + - MYSQL_HOST=${MYSQL_HOST} + - MYSQL_PORT=${MYSQL_PORT} + - MYSQL_USER=${MYSQL_USER} + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + - DB_AUTH_NAME=${DB_AUTH_NAME} + - DB_WORLD_NAME=${DB_WORLD_NAME} + - DB_CHARACTERS_NAME=${DB_CHARACTERS_NAME} + - MODULE_PLAYERBOTS=${MODULE_PLAYERBOTS} + - MODULE_AOE_LOOT=${MODULE_AOE_LOOT} + - MODULE_LEARN_SPELLS=${MODULE_LEARN_SPELLS} + - MODULE_FIREWORKS=${MODULE_FIREWORKS} + - MODULE_INDIVIDUAL_PROGRESSION=${MODULE_INDIVIDUAL_PROGRESSION} + - MODULE_AHBOT=${MODULE_AHBOT} + - MODULE_AUTOBALANCE=${MODULE_AUTOBALANCE} + - MODULE_TRANSMOG=${MODULE_TRANSMOG} + - MODULE_NPC_BUFFER=${MODULE_NPC_BUFFER} + - MODULE_DYNAMIC_XP=${MODULE_DYNAMIC_XP} + - MODULE_SOLO_LFG=${MODULE_SOLO_LFG} + - MODULE_1V1_ARENA=${MODULE_1V1_ARENA} + - MODULE_PHASED_DUELS=${MODULE_PHASED_DUELS} + - MODULE_BREAKING_NEWS=${MODULE_BREAKING_NEWS} + - MODULE_BOSS_ANNOUNCER=${MODULE_BOSS_ANNOUNCER} + - MODULE_ACCOUNT_ACHIEVEMENTS=${MODULE_ACCOUNT_ACHIEVEMENTS} + - MODULE_AUTO_REVIVE=${MODULE_AUTO_REVIVE} + - MODULE_GAIN_HONOR_GUARD=${MODULE_GAIN_HONOR_GUARD} + - MODULE_ELUNA=${MODULE_ELUNA} + - MODULE_TIME_IS_TIME=${MODULE_TIME_IS_TIME} + - MODULE_POCKET_PORTAL=${MODULE_POCKET_PORTAL} + - MODULE_RANDOM_ENCHANTS=${MODULE_RANDOM_ENCHANTS} + - MODULE_SOLOCRAFT=${MODULE_SOLOCRAFT} + - MODULE_PVP_TITLES=${MODULE_PVP_TITLES} + - MODULE_NPC_BEASTMASTER=${MODULE_NPC_BEASTMASTER} + - MODULE_NPC_ENCHANTER=${MODULE_NPC_ENCHANTER} + - MODULE_INSTANCE_RESET=${MODULE_INSTANCE_RESET} + - MODULE_LEVEL_GRANT=${MODULE_LEVEL_GRANT} + - MODULE_ARAC=${MODULE_ARAC} + - MODULE_ASSISTANT=${MODULE_ASSISTANT} + - MODULE_REAGENT_BANK=${MODULE_REAGENT_BANK} + - MODULE_BLACK_MARKET_AUCTION_HOUSE=${MODULE_BLACK_MARKET_AUCTION_HOUSE} + working_dir: /azerothcore + command: > + sh -c " + echo '๐Ÿ”ง AzerothCore Build Service Starting...' + + # Check if rebuild is required by reading module state + MODULES_STATE_FILE='/azerothcore/modules/.modules_state' + if [ -f \"$$MODULES_STATE_FILE\" ]; then + # Check current module configuration + CURRENT_STATE='' + for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK MODULE_BLACK_MARKET_AUCTION_HOUSE; do + eval \"value=\\\$$$module_var\" + CURRENT_STATE=\"$${CURRENT_STATE}$${module_var}=$${value}|\" + done + + PREVIOUS_STATE=$$(cat \"$$MODULES_STATE_FILE\") + + # Check if any C++ modules are enabled and if no built binaries exist + BUILD_REQUIRED=0 + if [ \"$$CURRENT_STATE\" != \"$$PREVIOUS_STATE\" ]; then + echo '๐Ÿ”„ Module configuration changed - starting compilation...' + BUILD_REQUIRED=1 + elif [ ! -f '/azerothcore/server/bin/worldserver' ]; then + echo '๐Ÿ“ No compiled binaries found - starting initial compilation...' + BUILD_REQUIRED=1 + fi + + if [ \"$$BUILD_REQUIRED\" = \"1\" ]; then + + # Install required packages + apt-get update && apt-get install -y git cmake build-essential libssl-dev libreadline-dev zlib1g-dev libbz2-dev libncurses-dev mysql-client + + # Clone AzerothCore source + if [ ! -d '/azerothcore/azerothcore-wotlk' ]; then + echo '๐Ÿ“ฅ Cloning AzerothCore source...' + git clone --depth 1 --branch master https://github.com/azerothcore/azerothcore-wotlk.git + fi + + cd /azerothcore/azerothcore-wotlk + + # Setup modules directory and clone enabled modules + mkdir -p modules + cd modules + + # Clone enabled C++ modules + if [ \"$$MODULE_AOE_LOOT\" = \"1\" ]; then + [ ! -d \"mod-aoe-loot\" ] && git clone https://github.com/azerothcore/mod-aoe-loot.git + fi + if [ \"$$MODULE_LEARN_SPELLS\" = \"1\" ]; then + [ ! -d \"mod-learn-spells\" ] && git clone https://github.com/azerothcore/mod-learn-spells.git + fi + if [ \"$$MODULE_FIREWORKS\" = \"1\" ]; then + [ ! -d \"mod-fireworks-on-level\" ] && git clone https://github.com/azerothcore/mod-fireworks-on-level.git + fi + if [ \"$$MODULE_AHBOT\" = \"1\" ]; then + [ ! -d \"mod-ahbot\" ] && git clone https://github.com/azerothcore/mod-ahbot.git + fi + if [ \"$$MODULE_AUTOBALANCE\" = \"1\" ]; then + [ ! -d \"mod-autobalance\" ] && git clone https://github.com/azerothcore/mod-autobalance.git + fi + if [ \"$$MODULE_TRANSMOG\" = \"1\" ]; then + [ ! -d \"mod-transmog\" ] && git clone https://github.com/azerothcore/mod-transmog.git + fi + if [ \"$$MODULE_NPC_BUFFER\" = \"1\" ]; then + [ ! -d \"mod-npc-buffer\" ] && git clone https://github.com/azerothcore/mod-npc-buffer.git + fi + if [ \"$$MODULE_SOLO_LFG\" = \"1\" ]; then + [ ! -d \"mod-solo-lfg\" ] && git clone https://github.com/azerothcore/mod-solo-lfg.git + fi + if [ \"$$MODULE_SOLOCRAFT\" = \"1\" ]; then + [ ! -d \"mod-solocraft\" ] && git clone https://github.com/azerothcore/mod-solocraft.git + fi + + cd /azerothcore/azerothcore-wotlk + + # Configure and build + echo '๐Ÿ”จ Configuring build...' + mkdir -p build + cd build + + cmake .. -DCMAKE_INSTALL_PREFIX=/azerothcore/server -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DWITH_WARNINGS=1 -DTOOLS=0 -DSCRIPTS=static -DMODULES=static + + echo '๐Ÿ—๏ธ Starting compilation (this may take 15-45 minutes)...' + make -j$$(nproc) + + echo '๐Ÿ“ฆ Installing binaries...' + make install + + echo 'โœ… Build completed successfully!' + + # Update state file to prevent rebuilds + echo \"$$CURRENT_STATE\" > \"$$MODULES_STATE_FILE\" + + else + echo 'โœ… No module changes detected and binaries exist - build not required' + fi + else + echo 'โš ๏ธ Module state file not found - build service waiting for modules container' + fi + + echo '๐Ÿ Build service complete. Container will exit.' + " + restart: "no" + depends_on: + - ac-modules + networks: + - azerothcore + networks: azerothcore: external: true diff --git a/docker-compose-azerothcore-services.env b/V1/docker-compose-azerothcore-services.env similarity index 100% rename from docker-compose-azerothcore-services.env rename to V1/docker-compose-azerothcore-services.env diff --git a/docker-compose-azerothcore-services.yml b/V1/docker-compose-azerothcore-services.yml similarity index 97% rename from docker-compose-azerothcore-services.yml rename to V1/docker-compose-azerothcore-services.yml index 5d2664c..656c341 100644 --- a/docker-compose-azerothcore-services.yml +++ b/V1/docker-compose-azerothcore-services.yml @@ -24,15 +24,15 @@ services: # Auto-detect package manager and install dependencies (as root) if command -v apk >/dev/null 2>&1; then # Alpine Linux - install full wget and bash for script compatibility - apk add --no-cache curl unzip wget bash ca-certificates p7zip jq + apk add --no-cache curl unzip wget bash ca-certificates p7zip aria2 jq elif command -v apt-get >/dev/null 2>&1; then # Ubuntu/Debian - apt-get update && apt-get install -y --no-install-recommends curl unzip wget ca-certificates p7zip-full jq && rm -rf /var/lib/apt/lists/* + apt-get update && apt-get install -y --no-install-recommends curl unzip wget bash ca-certificates p7zip-full aria2 jq && rm -rf /var/lib/apt/lists/* elif command -v yum >/dev/null 2>&1; then # CentOS/RHEL - yum install -y curl unzip wget ca-certificates p7zip jq + yum install -y curl unzip wget bash ca-certificates p7zip aria2 jq else - echo "โŒ Unsupported package manager - please install: curl unzip wget ca-certificates p7zip jq" + echo "โŒ Unsupported package manager - please install: curl unzip wget bash ca-certificates p7zip aria2 jq" exit 1 fi diff --git a/docker-compose-azerothcore-tools.env b/V1/docker-compose-azerothcore-tools.env similarity index 100% rename from docker-compose-azerothcore-tools.env rename to V1/docker-compose-azerothcore-tools.env diff --git a/docker-compose-azerothcore-tools.yml b/V1/docker-compose-azerothcore-tools.yml similarity index 100% rename from docker-compose-azerothcore-tools.yml rename to V1/docker-compose-azerothcore-tools.yml diff --git a/docs/module-configuration-requirements.md b/V1/docs/module-configuration-requirements.md similarity index 100% rename from docs/module-configuration-requirements.md rename to V1/docs/module-configuration-requirements.md diff --git a/scripts/CLEANUP.md b/V1/scripts/CLEANUP.md similarity index 100% rename from scripts/CLEANUP.md rename to V1/scripts/CLEANUP.md diff --git a/scripts/DEPLOYMENT.md b/V1/scripts/DEPLOYMENT.md similarity index 100% rename from scripts/DEPLOYMENT.md rename to V1/scripts/DEPLOYMENT.md diff --git a/scripts/GITHUB-HOSTED-SCRIPTS.md b/V1/scripts/GITHUB-HOSTED-SCRIPTS.md similarity index 100% rename from scripts/GITHUB-HOSTED-SCRIPTS.md rename to V1/scripts/GITHUB-HOSTED-SCRIPTS.md diff --git a/scripts/README.md b/V1/scripts/README.md similarity index 100% rename from scripts/README.md rename to V1/scripts/README.md diff --git a/scripts/TEST-LOCAL-WORLDSERVER.md b/V1/scripts/TEST-LOCAL-WORLDSERVER.md similarity index 100% rename from scripts/TEST-LOCAL-WORLDSERVER.md rename to V1/scripts/TEST-LOCAL-WORLDSERVER.md diff --git a/V1/scripts/auto-post-install.sh b/V1/scripts/auto-post-install.sh new file mode 100755 index 0000000..5e8584d --- /dev/null +++ b/V1/scripts/auto-post-install.sh @@ -0,0 +1,184 @@ +#!/bin/bash +set -e + +echo "๐Ÿš€ AzerothCore Auto Post-Install Configuration" +echo "==============================================" + +# Install required packages +apk add --no-cache curl mysql-client bash docker-cli-compose jq + +# Create install markers directory +mkdir -p /install-markers + +# Check if this is a new installation +if [ -f "/install-markers/post-install-completed" ]; then + echo "โœ… Post-install configuration already completed" + echo "โ„น๏ธ Marker file found: /install-markers/post-install-completed" + echo "๐Ÿ”„ To re-run post-install configuration, delete the marker file and restart this container" + echo "๐Ÿ“ Command: docker exec ${CONTAINER_POST_INSTALL} rm -f /install-markers/post-install-completed" + echo "" + echo "๐Ÿƒ Keeping container alive for manual operations..." + tail -f /dev/null +else + echo "๐Ÿ†• New installation detected - running post-install configuration..." + echo "" + + # Wait for services to be ready + echo "โณ Waiting for required services to be ready..." + + # Wait for MySQL to be responsive + echo "๐Ÿ”Œ Waiting for MySQL to be ready..." + for i in $(seq 1 120); do + if mysql -h "${MYSQL_HOST}" -u"${MYSQL_USER}" -p"${MYSQL_ROOT_PASSWORD}" --skip-ssl-verify -e "SELECT 1;" >/dev/null 2>&1; then + echo "โœ… MySQL is ready" + break + fi + echo " โณ Attempt $i/120..." + sleep 5 + done + + # Wait for authserver and worldserver config files to exist + echo "๐Ÿ“ Waiting for configuration files..." + for i in $(seq 1 60); do + if [ -f "/azerothcore/config/authserver.conf" ] && [ -f "/azerothcore/config/worldserver.conf" ]; then + echo "โœ… Configuration files found" + break + fi + echo " โณ Waiting for config files... attempt $i/60" + sleep 5 + done + + if [ ! -f "/azerothcore/config/authserver.conf" ] || [ ! -f "/azerothcore/config/worldserver.conf" ]; then + echo "โŒ Configuration files not found after waiting" + echo " Expected: /azerothcore/config/authserver.conf" + echo " Expected: /azerothcore/config/worldserver.conf" + exit 1 + fi + + # Step 1: Update configuration files + echo "" + echo "๐Ÿ”ง Step 1: Updating configuration files..." + + # Download and execute update-config.sh + curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/update-config.sh -o /tmp/update-config.sh + chmod +x /tmp/update-config.sh + + # Modify script to use container environment + sed -i 's|docker-compose-azerothcore-services.env|/project/docker-compose-azerothcore-services.env|' /tmp/update-config.sh + sed -i 's|CONFIG_DIR="${STORAGE_PATH}/config"|CONFIG_DIR="/azerothcore/config"|' /tmp/update-config.sh + + # Execute update-config.sh + cd /project + /tmp/update-config.sh + + if [ $? -eq 0 ]; then + echo "โœ… Configuration files updated successfully" + else + echo "โŒ Failed to update configuration files" + exit 1 + fi + + # Step 2: Update realmlist table + echo "" + echo "๐ŸŒ Step 2: Updating realmlist table..." + + # Download and execute update-realmlist.sh + curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/update-realmlist.sh -o /tmp/update-realmlist.sh + chmod +x /tmp/update-realmlist.sh + + # Modify script to use container environment + sed -i 's|docker-compose-azerothcore-services.env|/project/docker-compose-azerothcore-services.env|' /tmp/update-realmlist.sh + + # Replace all docker exec mysql commands with direct mysql commands + sed -i "s|docker exec ac-mysql mysql -u \"\${MYSQL_USER}\" -p\"\${MYSQL_ROOT_PASSWORD}\" \"\${DB_AUTH_NAME}\"|mysql -h \"${MYSQL_HOST}\" -u\"${MYSQL_USER}\" -p\"${MYSQL_ROOT_PASSWORD}\" --skip-ssl-verify \"${DB_AUTH_NAME}\"|g" /tmp/update-realmlist.sh + sed -i "s|docker exec ac-mysql mysql -u \"\${MYSQL_USER}\" -p\"\${MYSQL_ROOT_PASSWORD}\"|mysql -h \"${MYSQL_HOST}\" -u\"${MYSQL_USER}\" -p\"${MYSQL_ROOT_PASSWORD}\" --skip-ssl-verify|g" /tmp/update-realmlist.sh + + # Execute update-realmlist.sh + cd /project + /tmp/update-realmlist.sh + + if [ $? -eq 0 ]; then + echo "โœ… Realmlist table updated successfully" + else + echo "โŒ Failed to update realmlist table" + exit 1 + fi + + # Step 3: Restart services to apply changes + echo "" + echo "โ„น๏ธ Step 3: Restarting services to apply changes..." + echo "๐Ÿ“ Configuration changes have been applied to files" + echo "๐Ÿ”„ Restarting authserver and worldserver to pick up new configuration..." + + # Detect container runtime (Docker or Podman) + CONTAINER_CMD="" + if command -v docker >/dev/null 2>&1; then + # Check if we can connect to Docker daemon + if docker version >/dev/null 2>&1; then + CONTAINER_CMD="docker" + echo "๐Ÿณ Detected Docker runtime" + fi + fi + + if [ -z "$CONTAINER_CMD" ] && command -v podman >/dev/null 2>&1; then + # Check if we can connect to Podman + if podman version >/dev/null 2>&1; then + CONTAINER_CMD="podman" + echo "๐Ÿฆญ Detected Podman runtime" + fi + fi + + if [ -z "$CONTAINER_CMD" ]; then + echo "โš ๏ธ No container runtime detected (docker/podman) - skipping restart" + else + # Restart authserver + if [ -n "$CONTAINER_AUTHSERVER" ]; then + echo "๐Ÿ”„ Restarting authserver container: $CONTAINER_AUTHSERVER" + if $CONTAINER_CMD restart "$CONTAINER_AUTHSERVER" 2>/dev/null; then + echo "โœ… Authserver restarted successfully" + else + echo "โš ๏ธ Failed to restart authserver (may not be running yet)" + fi + fi + + # Restart worldserver + if [ -n "$CONTAINER_WORLDSERVER" ]; then + echo "๐Ÿ”„ Restarting worldserver container: $CONTAINER_WORLDSERVER" + if $CONTAINER_CMD restart "$CONTAINER_WORLDSERVER" 2>/dev/null; then + echo "โœ… Worldserver restarted successfully" + else + echo "โš ๏ธ Failed to restart worldserver (may not be running yet)" + fi + fi + fi + + echo "โœ… Service restart completed" + + # Create completion marker + echo "$(date)" > /install-markers/post-install-completed + echo "NEW_INSTALL_DATE=$(date)" >> /install-markers/post-install-completed + echo "CONFIG_FILES_UPDATED=true" >> /install-markers/post-install-completed + echo "REALMLIST_UPDATED=true" >> /install-markers/post-install-completed + echo "SERVICES_RESTARTED=true" >> /install-markers/post-install-completed + + echo "" + echo "๐ŸŽ‰ Auto post-install configuration completed successfully!" + echo "" + echo "๐Ÿ“‹ Summary of changes:" + echo " โœ… AuthServer configured with production database settings" + echo " โœ… WorldServer configured with production database settings" + echo " โœ… Realmlist updated with server address: ${SERVER_ADDRESS}:${REALM_PORT}" + echo " โœ… Services restarted to apply changes" + echo " โœ… Completion marker created: /install-markers/post-install-completed" + echo "" + echo "๐ŸŽฎ Your AzerothCore server is now ready for production!" + echo " Players can connect to: ${SERVER_ADDRESS}:${REALM_PORT}" + echo "" + echo "๐Ÿ’ก Next steps:" + echo " 1. Create admin accounts using the worldserver console" + echo " 2. Test client connectivity" + echo " 3. Configure any additional modules as needed" + echo "" + echo "๐Ÿƒ Keeping container alive for future manual operations..." + tail -f /dev/null +fi \ No newline at end of file diff --git a/scripts/backup-daily.sh b/V1/scripts/backup-daily.sh similarity index 100% rename from scripts/backup-daily.sh rename to V1/scripts/backup-daily.sh diff --git a/scripts/backup-hourly.sh b/V1/scripts/backup-hourly.sh similarity index 100% rename from scripts/backup-hourly.sh rename to V1/scripts/backup-hourly.sh diff --git a/V1/scripts/backup-scheduler.sh b/V1/scripts/backup-scheduler.sh new file mode 100644 index 0000000..5d4fc09 --- /dev/null +++ b/V1/scripts/backup-scheduler.sh @@ -0,0 +1,57 @@ +#!/bin/bash +set -e + +echo "๐Ÿ”ง Starting enhanced backup service with hourly and daily schedules..." + +# Install curl if not available (handle different package managers) +# NOTE: curl is already available in mysql:8.0 base image, commenting out to fix operator precedence issue +# microdnf install -y curl || yum install -y curl || apt-get update && apt-get install -y curl + +# Download backup scripts from GitHub +echo "๐Ÿ“ฅ Downloading backup scripts from GitHub..." +curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup.sh -o /tmp/backup.sh +curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup-hourly.sh -o /tmp/backup-hourly.sh +curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup-daily.sh -o /tmp/backup-daily.sh +chmod +x /tmp/backup.sh /tmp/backup-hourly.sh /tmp/backup-daily.sh + +# Wait for MySQL to be ready before starting backup service +echo "โณ Waiting for MySQL to be ready..." +sleep 30 + +# Run initial daily backup +echo "๐Ÿš€ Running initial daily backup..." +/tmp/backup-daily.sh + +# Enhanced scheduler with hourly and daily backups +echo "โฐ Starting enhanced backup scheduler:" +echo " ๐Ÿ“… Daily backups: ${BACKUP_DAILY_TIME}:00 UTC (retention: ${BACKUP_RETENTION_DAYS} days)" +echo " โฐ Hourly backups: every hour (retention: ${BACKUP_RETENTION_HOURS} hours)" + +# Track last backup times to avoid duplicates +last_daily_hour="" +last_hourly_minute="" + +while true; do + current_hour=$(date +%H) + current_minute=$(date +%M) + current_time="$current_hour:$current_minute" + + # Daily backup check (configurable time) + if [ "$current_hour" = "${BACKUP_DAILY_TIME}" ] && [ "$current_minute" = "00" ] && [ "$last_daily_hour" != "$current_hour" ]; then + echo "๐Ÿ“… [$(date)] Daily backup time reached, running daily backup..." + /tmp/backup-daily.sh + last_daily_hour="$current_hour" + # Sleep for 2 minutes to avoid running multiple times + sleep 120 + # Hourly backup check (every hour at minute 0, except during daily backup) + elif [ "$current_minute" = "00" ] && [ "$current_hour" != "${BACKUP_DAILY_TIME}" ] && [ "$last_hourly_minute" != "$current_minute" ]; then + echo "โฐ [$(date)] Hourly backup time reached, running hourly backup..." + /tmp/backup-hourly.sh + last_hourly_minute="$current_minute" + # Sleep for 2 minutes to avoid running multiple times + sleep 120 + else + # Sleep for 1 minute before checking again + sleep 60 + fi +done \ No newline at end of file diff --git a/scripts/backup.sh b/V1/scripts/backup.sh similarity index 100% rename from scripts/backup.sh rename to V1/scripts/backup.sh diff --git a/scripts/cleanup.sh b/V1/scripts/cleanup.sh similarity index 100% rename from scripts/cleanup.sh rename to V1/scripts/cleanup.sh diff --git a/scripts/configure-modules.sh b/V1/scripts/configure-modules.sh similarity index 100% rename from scripts/configure-modules.sh rename to V1/scripts/configure-modules.sh diff --git a/V1/scripts/db-import-conditional.sh b/V1/scripts/db-import-conditional.sh new file mode 100755 index 0000000..d415f7d --- /dev/null +++ b/V1/scripts/db-import-conditional.sh @@ -0,0 +1,331 @@ +#!/bin/bash +set -e + +echo "๐Ÿ”ง Conditional AzerothCore Database Import" +echo "========================================" + +# Restoration status markers - use writable location +RESTORE_STATUS_DIR="/var/lib/mysql-persistent" +MARKER_STATUS_DIR="/tmp" +RESTORE_SUCCESS_MARKER="$RESTORE_STATUS_DIR/.restore-completed" +RESTORE_FAILED_MARKER="$RESTORE_STATUS_DIR/.restore-failed" +RESTORE_SUCCESS_MARKER_TMP="$MARKER_STATUS_DIR/.restore-completed" +RESTORE_FAILED_MARKER_TMP="$MARKER_STATUS_DIR/.restore-failed" + +# Ensure we can write to the status directory, fallback to tmp +mkdir -p "$RESTORE_STATUS_DIR" 2>/dev/null || true +if ! touch "$RESTORE_STATUS_DIR/.test-write" 2>/dev/null; then + echo "โš ๏ธ Cannot write to $RESTORE_STATUS_DIR, using $MARKER_STATUS_DIR for markers" + RESTORE_SUCCESS_MARKER="$RESTORE_SUCCESS_MARKER_TMP" + RESTORE_FAILED_MARKER="$RESTORE_FAILED_MARKER_TMP" +else + rm -f "$RESTORE_STATUS_DIR/.test-write" 2>/dev/null || true +fi + +echo "๐Ÿ” Checking restoration status..." + +# Check if backup was successfully restored +if [ -f "$RESTORE_SUCCESS_MARKER" ]; then + echo "โœ… Backup restoration completed successfully" + echo "๐Ÿ“„ Restoration details:" + cat "$RESTORE_SUCCESS_MARKER" + echo "" + echo "๐Ÿšซ Skipping database import - data already restored from backup" + echo "๐Ÿ’ก This prevents overwriting restored data with fresh schema" + exit 0 +fi + +# Check if restoration failed (fresh databases created) +if [ -f "$RESTORE_FAILED_MARKER" ]; then + echo "โ„น๏ธ No backup was restored - fresh databases detected" + echo "๐Ÿ“„ Database creation details:" + cat "$RESTORE_FAILED_MARKER" + echo "" + echo "โ–ถ๏ธ Proceeding with database import to populate fresh databases" +else + echo "โš ๏ธ No restoration status found - assuming fresh installation" + echo "โ–ถ๏ธ Proceeding with database import" +fi + +echo "" +echo "๐Ÿ”ง Starting database import process..." + +# First attempt backup restoration +echo "๐Ÿ” Checking for backups to restore..." + +BACKUP_DIRS="/backups" + + +# Function to restore from backup (directory or single file) +restore_from_directory() { + local backup_path="$1" + echo "๐Ÿ”„ Restoring from backup: $backup_path" + + local restore_success=true + + # Handle single .sql file (legacy backup) + if [ -f "$backup_path" ] && [[ "$backup_path" == *.sql ]]; then + echo "๐Ÿ“ฅ Restoring legacy backup file: $(basename "$backup_path")" + if timeout 300 mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} < "$backup_path"; then + echo "โœ… Successfully restored legacy backup" + return 0 + else + echo "โŒ Failed to restore legacy backup" + return 1 + fi + fi + + # Handle directory with .sql.gz files (modern timestamped backups) + if [ -d "$backup_path" ]; then + echo "๐Ÿ”„ Restoring from backup directory: $backup_path" + # Restore each database backup + for backup_file in "$backup_path"/*.sql.gz; do + if [ -f "$backup_file" ]; then + local db_name=$(basename "$backup_file" .sql.gz) + echo "๐Ÿ“ฅ Restoring database: $db_name" + + if timeout 300 zcat "$backup_file" | mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD}; then + echo "โœ… Successfully restored $db_name" + else + echo "โŒ Failed to restore $db_name" + restore_success=false + fi + fi + done + + if [ "$restore_success" = true ]; then + return 0 + else + return 1 + fi + fi + + # If we get here, backup_path is neither a valid .sql file nor a directory + echo "โŒ Invalid backup path: $backup_path (not a .sql file or directory)" + return 1 +} + +# Attempt backup restoration with full functionality restored +echo "๐Ÿ”„ Checking for backups..." +backup_path="" + +# Priority 1: Legacy single backup file with content validation +echo "๐Ÿ” Checking for legacy backup file..." +if [ -f "/var/lib/mysql-persistent/backup.sql" ]; then + echo "๐Ÿ“„ Found legacy backup file, validating content..." + if timeout 10 head -10 "/var/lib/mysql-persistent/backup.sql" 2>/dev/null | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then + echo "โœ… Legacy backup file validated" + backup_path="/var/lib/mysql-persistent/backup.sql" + else + echo "โš ๏ธ Legacy backup file exists but appears invalid or empty" + fi +else + echo "๐Ÿ” No legacy backup found" +fi + +# Priority 2: Modern timestamped backups (only if no legacy backup found) +if [ -z "$backup_path" ] && [ -d "$BACKUP_DIRS" ]; then + echo "๐Ÿ“ Backup directory exists, checking for timestamped backups..." + if [ "$(ls -A $BACKUP_DIRS 2>/dev/null | wc -l)" -gt 0 ]; then + # Check daily backups first + if [ -d "$BACKUP_DIRS/daily" ] && [ "$(ls -A $BACKUP_DIRS/daily 2>/dev/null | wc -l)" -gt 0 ]; then + echo "๐Ÿ“… Found daily backup directory, finding latest..." + latest_daily=$(ls -1t $BACKUP_DIRS/daily 2>/dev/null | head -n 1) + if [ -n "$latest_daily" ] && [ -d "$BACKUP_DIRS/daily/$latest_daily" ]; then + echo "๐Ÿ“ฆ Checking backup directory: $latest_daily" + # Check if directory has .sql.gz files + if ls "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz >/dev/null 2>&1; then + # Validate at least one backup file has content + echo "๐Ÿ” Validating backup content..." + for backup_file in "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz; do + if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then + # Use timeout to prevent hanging on zcat + if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then + echo "โœ… Valid backup found: $(basename $backup_file)" + backup_path="$BACKUP_DIRS/daily/$latest_daily" + break + fi + fi + done + else + echo "โš ๏ธ No .sql.gz files found in backup directory" + fi + fi + else + echo "๐Ÿ“… No daily backup directory found" + # Check for timestamped backup directories (legacy format: YYYYMMDD_HHMMSS) + echo "๐Ÿ” Checking for timestamped backup directories..." + timestamped_backups=$(ls -1t $BACKUP_DIRS 2>/dev/null | grep -E '^[0-9]{8}_[0-9]{6}$' | head -n 1) + if [ -n "$timestamped_backups" ]; then + latest_timestamped="$timestamped_backups" + echo "๐Ÿ“ฆ Found timestamped backup: $latest_timestamped" + if [ -d "$BACKUP_DIRS/$latest_timestamped" ]; then + # Check if directory has .sql.gz files + if ls "$BACKUP_DIRS/$latest_timestamped"/*.sql.gz >/dev/null 2>&1; then + # Validate at least one backup file has content + echo "๐Ÿ” Validating timestamped backup content..." + for backup_file in "$BACKUP_DIRS/$latest_timestamped"/*.sql.gz; do + if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then + # Use timeout to prevent hanging on zcat + if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then + echo "โœ… Valid timestamped backup found: $(basename $backup_file)" + backup_path="$BACKUP_DIRS/$latest_timestamped" + break + fi + fi + done + else + echo "โš ๏ธ No .sql.gz files found in timestamped backup directory" + fi + fi + else + echo "๐Ÿ“… No timestamped backup directories found" + fi + fi + else + echo "๐Ÿ“ Backup directory is empty" + fi +else + echo "๐Ÿ“ No backup directory found or legacy backup already selected" +fi + +echo "๐Ÿ”„ Final backup path result: '$backup_path'" +if [ -n "$backup_path" ]; then + echo "๐Ÿ“ฆ Found backup: $(basename $backup_path)" + if restore_from_directory "$backup_path"; then + echo "โœ… Database restoration completed successfully!" + echo "$(date): Backup successfully restored from $backup_path" > "$RESTORE_SUCCESS_MARKER" + echo "๐Ÿšซ Skipping schema import - data already restored from backup" + exit 0 + else + echo "โŒ Backup restoration failed - proceeding with fresh setup" + echo "$(date): Backup restoration failed - proceeding with fresh setup" > "$RESTORE_FAILED_MARKER" + fi +else + echo "โ„น๏ธ No valid backups found - proceeding with fresh setup" + echo "$(date): No backup found - fresh setup needed" > "$RESTORE_FAILED_MARKER" +fi + +# Create fresh databases if restoration didn't happen +echo "๐Ÿ—„๏ธ Creating fresh AzerothCore databases..." +mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e " +CREATE DATABASE IF NOT EXISTS ${DB_AUTH_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE DATABASE IF NOT EXISTS ${DB_WORLD_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE DATABASE IF NOT EXISTS ${DB_CHARACTERS_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +SHOW DATABASES;" || { + echo "โŒ Failed to create databases" + exit 1 +} +echo "โœ… Fresh databases created - proceeding with schema import" + +# Wait for databases to be ready (they should exist now) +echo "โณ Verifying databases are accessible..." +for i in $(seq 1 10); do + if mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "USE ${DB_AUTH_NAME}; USE ${DB_WORLD_NAME}; USE ${DB_CHARACTERS_NAME};" >/dev/null 2>&1; then + echo "โœ… All databases accessible" + break + fi + echo "โณ Waiting for databases... attempt $i/10" + sleep 2 +done + +# Verify databases are actually empty before importing +echo "๐Ÿ” Verifying databases are empty before import..." +check_table_count() { + local db_name="$1" + local count=$(mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e " + SELECT COUNT(*) FROM information_schema.tables + WHERE table_schema='$db_name' AND table_type='BASE TABLE';" -s -N 2>/dev/null || echo "0") + echo "$count" +} + +auth_tables=$(check_table_count "${DB_AUTH_NAME}") +world_tables=$(check_table_count "${DB_WORLD_NAME}") +char_tables=$(check_table_count "${DB_CHARACTERS_NAME}") + +echo "๐Ÿ“Š Current table counts:" +echo " ${DB_AUTH_NAME}: $auth_tables tables" +echo " ${DB_WORLD_NAME}: $world_tables tables" +echo " ${DB_CHARACTERS_NAME}: $char_tables tables" + +# Warn if databases appear to have data +if [ "$auth_tables" -gt 5 ] || [ "$world_tables" -gt 50 ] || [ "$char_tables" -gt 5 ]; then + echo "โš ๏ธ WARNING: Databases appear to contain data!" + echo "โš ๏ธ Import may overwrite existing data. Consider backing up first." + echo "โš ๏ธ Continuing in 10 seconds... (Ctrl+C to cancel)" + sleep 10 +fi + +echo "๐Ÿ“ Creating dbimport configuration..." +mkdir -p /azerothcore/env/dist/etc +cat > /azerothcore/env/dist/etc/dbimport.conf </dev/null; then + echo "$(date): Database import completed successfully" > "$RESTORE_STATUS_DIR/.import-completed" + else + echo "$(date): Database import completed successfully" > "$MARKER_STATUS_DIR/.import-completed" + echo "โš ๏ธ Using temporary location for completion marker" + fi + + # Verify import was successful + echo "๐Ÿ” Verifying import results..." + auth_tables_after=$(check_table_count "${DB_AUTH_NAME}") + world_tables_after=$(check_table_count "${DB_WORLD_NAME}") + char_tables_after=$(check_table_count "${DB_CHARACTERS_NAME}") + + echo "๐Ÿ“Š Post-import table counts:" + echo " ${DB_AUTH_NAME}: $auth_tables_after tables" + echo " ${DB_WORLD_NAME}: $world_tables_after tables" + echo " ${DB_CHARACTERS_NAME}: $char_tables_after tables" + + if [ "$auth_tables_after" -gt 0 ] && [ "$world_tables_after" -gt 0 ]; then + echo "โœ… Import verification successful - databases populated" + else + echo "โš ๏ธ Import verification failed - databases may be empty" + fi +else + echo "โŒ Database import failed!" + if touch "$RESTORE_STATUS_DIR/.import-failed" 2>/dev/null; then + echo "$(date): Database import failed" > "$RESTORE_STATUS_DIR/.import-failed" + else + echo "$(date): Database import failed" > "$MARKER_STATUS_DIR/.import-failed" + echo "โš ๏ธ Using temporary location for failed marker" + fi + exit 1 +fi + +echo "๐ŸŽ‰ Database import process complete!" \ No newline at end of file diff --git a/scripts/db-import.sh b/V1/scripts/db-import.sh similarity index 100% rename from scripts/db-import.sh rename to V1/scripts/db-import.sh diff --git a/scripts/db-init-enhanced.sh b/V1/scripts/db-init-enhanced.sh similarity index 100% rename from scripts/db-init-enhanced.sh rename to V1/scripts/db-init-enhanced.sh diff --git a/scripts/db-init.sh b/V1/scripts/db-init.sh similarity index 100% rename from scripts/db-init.sh rename to V1/scripts/db-init.sh diff --git a/scripts/deploy-and-check-distrobox.sh b/V1/scripts/deploy-and-check-distrobox.sh similarity index 100% rename from scripts/deploy-and-check-distrobox.sh rename to V1/scripts/deploy-and-check-distrobox.sh diff --git a/scripts/deploy-and-check.sh b/V1/scripts/deploy-and-check.sh similarity index 97% rename from scripts/deploy-and-check.sh rename to V1/scripts/deploy-and-check.sh index 17f64f4..713afa4 100755 --- a/scripts/deploy-and-check.sh +++ b/V1/scripts/deploy-and-check.sh @@ -339,9 +339,9 @@ deploy_stack() { docker compose --env-file "$SERVICES_ENV_FILE" -f ./docker-compose-azerothcore-services.yml up -d 2>&1 | grep -v "Found orphan containers" # Wait for client data extraction - print_status "INFO" "Waiting for client data download and extraction (this may take 15-25 minutes)..." + print_status "INFO" "Waiting for client data download and extraction (optimized: 8-15 minutes typical)..." print_status "INFO" "Press Ctrl+C to exit if needed..." - wait_for_service "Client Data" 480 "docker logs ac-client-data 2>/dev/null | grep -q 'Game data setup complete'" + wait_for_service "Client Data" 360 "docker logs ac-client-data 2>/dev/null | grep -q 'Game data setup complete'" # Wait for worldserver to be healthy wait_for_service "World Server" 24 "check_container_health ac-worldserver" @@ -349,6 +349,14 @@ deploy_stack() { # Deploy modules if enabled if [ "$MODULES_ENABLED" = true ]; then print_status "INFO" "Step 3: Deploying modules layer..." + + # Ensure ac-modules is recreated with the correct environment + # It may have been created earlier by the services layer using services env + if docker ps -a --format '{{.Names}}' | grep -q '^ac-modules$'; then + print_status "INFO" "Recreating ac-modules with modules env (removing existing container)" + docker rm -f ac-modules >/dev/null 2>&1 || true + fi + docker compose --env-file "$MODULES_ENV_FILE" -f ./docker-compose-azerothcore-modules.yml up -d 2>&1 | grep -v "Found orphan containers" # Wait for modules to be ready @@ -538,4 +546,4 @@ main() { } # Run main function -main "$@" \ No newline at end of file +main "$@" diff --git a/V1/scripts/download-client-data.sh b/V1/scripts/download-client-data.sh new file mode 100644 index 0000000..39098ed --- /dev/null +++ b/V1/scripts/download-client-data.sh @@ -0,0 +1,249 @@ +#!/bin/bash +set -e + +echo '๐Ÿš€ Starting AzerothCore game data setup...' + +# Get the latest release info from wowgaming/client-data +echo '๐Ÿ“ก Fetching latest client data release info...' +RELEASE_INFO=$(wget -qO- https://api.github.com/repos/wowgaming/client-data/releases/latest 2>/dev/null) + +if [ -n "$RELEASE_INFO" ]; then + LATEST_URL=$(echo "$RELEASE_INFO" | grep '"browser_download_url":' | grep '\.zip' | cut -d'"' -f4 | head -1) + LATEST_TAG=$(echo "$RELEASE_INFO" | grep '"tag_name":' | cut -d'"' -f4) + LATEST_SIZE=$(echo "$RELEASE_INFO" | grep '"size":' | head -1 | grep -o '[0-9]*') +fi + +if [ -z "$LATEST_URL" ]; then + echo 'โŒ Could not fetch latest release URL' + echo '๐Ÿ“ฅ Using fallback: direct download from v16 release' + LATEST_URL='https://github.com/wowgaming/client-data/releases/download/v16/data.zip' + LATEST_TAG='v16' + LATEST_SIZE='0' +fi + +echo "๐Ÿ“ Latest release: $LATEST_TAG" +echo "๐Ÿ“ฅ Download URL: $LATEST_URL" + +# Cache file paths +CACHE_FILE="/cache/client-data-$LATEST_TAG.zip" +VERSION_FILE="/cache/client-data-version.txt" + +# Check if we have a cached version +if [ -f "$CACHE_FILE" ] && [ -f "$VERSION_FILE" ]; then + CACHED_VERSION=$(cat "$VERSION_FILE" 2>/dev/null) + if [ "$CACHED_VERSION" = "$LATEST_TAG" ]; then + echo "โœ… Found cached client data version $LATEST_TAG" + echo "๐Ÿ“Š Cached file size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')" + + # Verify cache file integrity + echo "๐Ÿ” Verifying cached file integrity..." + CACHE_INTEGRITY_OK=false + + if command -v 7z >/dev/null 2>&1; then + # Use 7z for integrity check if available (faster and more reliable) + if 7z t "$CACHE_FILE" >/dev/null 2>&1; then + CACHE_INTEGRITY_OK=true + fi + fi + + # Fallback to unzip if 7z check failed or is not available + if [ "$CACHE_INTEGRITY_OK" = "false" ]; then + if unzip -t "$CACHE_FILE" > /dev/null 2>&1; then + CACHE_INTEGRITY_OK=true + fi + fi + + if [ "$CACHE_INTEGRITY_OK" = "true" ]; then + echo "โœ… Cache file integrity verified" + echo "โšก Using cached download - skipping download phase" + cp "$CACHE_FILE" data.zip + else + echo "โš ๏ธ Cache file corrupted, will re-download" + rm -f "$CACHE_FILE" "$VERSION_FILE" + fi + else + echo "๐Ÿ“ฆ Cache version ($CACHED_VERSION) differs from latest ($LATEST_TAG)" + echo "๐Ÿ—‘๏ธ Removing old cache" + rm -f /cache/client-data-*.zip "$VERSION_FILE" + fi +fi + +# Download if we don't have a valid cached file +if [ ! -f "data.zip" ]; then + echo "๐Ÿ“ฅ Downloading client data (~15GB, may take 5-20 minutes with multi-connection)..." + echo "๐Ÿ“ Source: $LATEST_URL" + + # Download with multi-connection support for speed + echo "๐Ÿ“ฅ Starting download with multi-connection support..." + if command -v aria2c >/dev/null 2>&1; then + echo "๐Ÿš€ Using aria2c for faster multi-connection download..." + aria2c --max-connection-per-server=8 --split=8 --min-split-size=10M \ + --summary-interval=5 --download-result=hide \ + --console-log-level=warn --show-console-readout=false \ + -o "$CACHE_FILE.tmp" "$LATEST_URL" || { + echo 'โš ๏ธ aria2c failed, falling back to wget...' + wget --progress=dot:giga -O "$CACHE_FILE.tmp" "$LATEST_URL" 2>&1 | sed 's/^/๐Ÿ“Š /' || { + echo 'โŒ wget failed, trying curl...' + curl -L --progress-bar -o "$CACHE_FILE.tmp" "$LATEST_URL" || { + echo 'โŒ All download methods failed' + rm -f "$CACHE_FILE.tmp" + exit 1 + } + } + } + else + echo "๐Ÿ“ฅ Using wget (aria2c not available)..." + wget --progress=dot:giga -O "$CACHE_FILE.tmp" "$LATEST_URL" 2>&1 | sed 's/^/๐Ÿ“Š /' || { + echo 'โŒ wget failed, trying curl...' + curl -L --progress-bar -o "$CACHE_FILE.tmp" "$LATEST_URL" || { + echo 'โŒ All download methods failed' + rm -f "$CACHE_FILE.tmp" + exit 1 + } + } + fi + + # Verify download integrity + echo "๐Ÿ” Verifying download integrity..." + INTEGRITY_OK=false + + if command -v 7z >/dev/null 2>&1; then + # Use 7z for integrity check if available (faster and more reliable) + if 7z t "$CACHE_FILE.tmp" >/dev/null 2>&1; then + INTEGRITY_OK=true + fi + fi + + # Fallback to unzip if 7z check failed or is not available + if [ "$INTEGRITY_OK" = "false" ]; then + if unzip -t "$CACHE_FILE.tmp" > /dev/null 2>&1; then + INTEGRITY_OK=true + fi + fi + + if [ "$INTEGRITY_OK" = "true" ]; then + mv "$CACHE_FILE.tmp" "$CACHE_FILE" + echo "$LATEST_TAG" > "$VERSION_FILE" + echo 'โœ… Download completed and verified' + echo "๐Ÿ“Š File size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')" + cp "$CACHE_FILE" data.zip + else + echo 'โŒ Downloaded file is corrupted' + rm -f "$CACHE_FILE.tmp" + exit 1 + fi +fi + +echo '๐Ÿ“‚ Extracting client data (this may take 5-10 minutes with parallel extraction)...' +echo 'โณ Please wait while extracting...' + +# Clear existing data if extraction failed previously +rm -rf /azerothcore/data/maps /azerothcore/data/vmaps /azerothcore/data/mmaps /azerothcore/data/dbc + +# Extract with detailed progress tracking using 7z for parallel processing +echo '๐Ÿ”„ Starting parallel extraction with progress monitoring...' + +# Use 7z if available for parallel extraction, fallback to unzip +if command -v 7z >/dev/null 2>&1; then + echo '๐Ÿš€ Using 7z for faster parallel extraction...' + # Start extraction in background with overwrite and parallel processing + 7z x -aoa -o/azerothcore/data/ data.zip >/dev/null 2>&1 & + EXTRACT_PID=$! + EXTRACT_CMD="7z" +else + echo '๐Ÿ“ฅ Using unzip (7z not available)...' + # Start extraction in background with overwrite + unzip -o -q data.zip -d /azerothcore/data/ & + EXTRACT_PID=$! + EXTRACT_CMD="unzip" +fi +LAST_CHECK_TIME=0 + +# Monitor progress with directory size checks +while kill -0 "$EXTRACT_PID" 2>/dev/null; do + CURRENT_TIME=$(date +%s) + if [ $((CURRENT_TIME - LAST_CHECK_TIME)) -ge 30 ]; then + LAST_CHECK_TIME=$CURRENT_TIME + + # Check what's been extracted so far + PROGRESS_MSG="๐Ÿ“Š Progress at $(date '+%H:%M:%S'):" + + if [ -d "/azerothcore/data/dbc" ] && [ -n "$(ls -A /azerothcore/data/dbc 2>/dev/null)" ]; then + DBC_SIZE=$(du -sh /azerothcore/data/dbc 2>/dev/null | cut -f1) + PROGRESS_MSG="$PROGRESS_MSG DBC($DBC_SIZE)" + fi + + if [ -d "/azerothcore/data/maps" ] && [ -n "$(ls -A /azerothcore/data/maps 2>/dev/null)" ]; then + MAPS_SIZE=$(du -sh /azerothcore/data/maps 2>/dev/null | cut -f1) + PROGRESS_MSG="$PROGRESS_MSG Maps($MAPS_SIZE)" + fi + + if [ -d "/azerothcore/data/vmaps" ] && [ -n "$(ls -A /azerothcore/data/vmaps 2>/dev/null)" ]; then + VMAPS_SIZE=$(du -sh /azerothcore/data/vmaps 2>/dev/null | cut -f1) + PROGRESS_MSG="$PROGRESS_MSG VMaps($VMAPS_SIZE)" + fi + + if [ -d "/azerothcore/data/mmaps" ] && [ -n "$(ls -A /azerothcore/data/mmaps 2>/dev/null)" ]; then + MMAPS_SIZE=$(du -sh /azerothcore/data/mmaps 2>/dev/null | cut -f1) + PROGRESS_MSG="$PROGRESS_MSG MMaps($MMAPS_SIZE)" + fi + + echo "$PROGRESS_MSG" + fi + sleep 5 +done + +wait "$EXTRACT_PID" +EXTRACT_EXIT_CODE=$? + +if [ $EXTRACT_EXIT_CODE -ne 0 ]; then + echo "โŒ Extraction failed ($EXTRACT_CMD returned exit code $EXTRACT_EXIT_CODE)" + rm -f data.zip + exit 1 +fi + +# Handle nested Data directory issue - move contents if extracted to Data subdirectory +if [ -d "/azerothcore/data/Data" ] && [ -n "$(ls -A /azerothcore/data/Data 2>/dev/null)" ]; then + echo '๐Ÿ”ง Fixing data directory structure (moving from Data/ subdirectory)...' + + # Move all contents from Data subdirectory to the root data directory + for item in /azerothcore/data/Data/*; do + if [ -e "$item" ]; then + mv "$item" /azerothcore/data/ 2>/dev/null || { + echo "โš ๏ธ Could not move $(basename "$item"), using copy instead..." + cp -r "$item" /azerothcore/data/ + rm -rf "$item" + } + fi + done + + # Remove empty Data directory + rmdir /azerothcore/data/Data 2>/dev/null || true + echo 'โœ… Data directory structure fixed' +fi + +# Clean up temporary extraction file (keep cached version) +rm -f data.zip + +echo 'โœ… Client data extraction complete!' +echo '๐Ÿ“ Verifying extracted directories:' + +# Verify required directories exist and have content +ALL_GOOD=true +for dir in maps vmaps mmaps dbc; do + if [ -d "/azerothcore/data/$dir" ] && [ -n "$(ls -A /azerothcore/data/$dir 2>/dev/null)" ]; then + DIR_SIZE=$(du -sh /azerothcore/data/$dir 2>/dev/null | cut -f1) + echo "โœ… $dir directory: OK ($DIR_SIZE)" + else + echo "โŒ $dir directory: MISSING or EMPTY" + ALL_GOOD=false + fi +done + +if [ "$ALL_GOOD" = "true" ]; then + echo '๐ŸŽ‰ Game data setup complete! AzerothCore worldserver can now start.' + echo "๐Ÿ’พ Cached version $LATEST_TAG for future use" +else + echo 'โŒ Some directories are missing or empty' + exit 1 +fi \ No newline at end of file diff --git a/V1/scripts/manage-modules-sql.sh b/V1/scripts/manage-modules-sql.sh new file mode 100644 index 0000000..0cfb5d7 --- /dev/null +++ b/V1/scripts/manage-modules-sql.sh @@ -0,0 +1,197 @@ +#!/bin/bash +set -e + +# Function to execute SQL files for a module +execute_module_sql() { + local module_dir="$1" + local module_name="$2" + + echo "Processing SQL scripts for $module_name..." + + # Find and execute SQL files in the module + if [ -d "$module_dir/data/sql" ]; then + # Execute world database scripts + if [ -d "$module_dir/data/sql/world" ]; then + find "$module_dir/data/sql/world" -name "*.sql" -type f | while read sql_file; do + echo " Executing world SQL: $(basename "$sql_file")" + if mariadb --ssl=false -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_WORLD_NAME}" < "$sql_file" >/dev/null 2>&1; then + echo " โœ… Successfully executed $(basename "$sql_file")" + else + echo " โŒ Failed to execute $sql_file" + fi + done + fi + + # Execute auth database scripts + if [ -d "$module_dir/data/sql/auth" ]; then + find "$module_dir/data/sql/auth" -name "*.sql" -type f | while read sql_file; do + echo " Executing auth SQL: $(basename "$sql_file")" + if mariadb --ssl=false -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_AUTH_NAME}" < "$sql_file" >/dev/null 2>&1; then + echo " โœ… Successfully executed $(basename "$sql_file")" + else + echo " โŒ Failed to execute $sql_file" + fi + done + fi + + # Execute character database scripts + if [ -d "$module_dir/data/sql/characters" ]; then + find "$module_dir/data/sql/characters" -name "*.sql" -type f | while read sql_file; do + echo " Executing characters SQL: $(basename "$sql_file")" + if mariadb --ssl=false -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_CHARACTERS_NAME}" < "$sql_file" >/dev/null 2>&1; then + echo " โœ… Successfully executed $(basename "$sql_file")" + else + echo " โŒ Failed to execute $sql_file" + fi + done + fi + + # Execute base SQL files (common pattern) + find "$module_dir/data/sql" -maxdepth 1 -name "*.sql" -type f | while read sql_file; do + echo " Executing base SQL: $(basename "$sql_file")" + mysql -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_WORLD_NAME}" < "$sql_file" 2>/dev/null || echo " Warning: Failed to execute $sql_file" + done + fi + + # Look for SQL files in other common locations + if [ -d "$module_dir/sql" ]; then + find "$module_dir/sql" -name "*.sql" -type f | while read sql_file; do + echo " Executing SQL: $(basename "$sql_file")" + mysql -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_WORLD_NAME}" < "$sql_file" 2>/dev/null || echo " Warning: Failed to execute $sql_file" + done + fi +} + +# Main function to execute SQL for all enabled modules +execute_module_sql_scripts() { + # Install MariaDB client if not available + which mariadb >/dev/null 2>&1 || { + echo "Installing MariaDB client..." + apk add --no-cache mariadb-client >/dev/null 2>&1 || echo "Warning: Could not install MariaDB client" + } + + # Execute SQL for enabled modules only + if [ "$MODULE_PLAYERBOTS" = "1" ] && [ -d "mod-playerbots" ]; then + execute_module_sql "mod-playerbots" "Playerbots" + fi + + if [ "$MODULE_AOE_LOOT" = "1" ] && [ -d "mod-aoe-loot" ]; then + execute_module_sql "mod-aoe-loot" "AoE Loot" + fi + + if [ "$MODULE_LEARN_SPELLS" = "1" ] && [ -d "mod-learn-spells" ]; then + execute_module_sql "mod-learn-spells" "Learn Spells" + fi + + if [ "$MODULE_FIREWORKS" = "1" ] && [ -d "mod-fireworks-on-level" ]; then + execute_module_sql "mod-fireworks-on-level" "Fireworks" + fi + + if [ "$MODULE_INDIVIDUAL_PROGRESSION" = "1" ] && [ -d "mod-individual-progression" ]; then + execute_module_sql "mod-individual-progression" "Individual Progression" + fi + + if [ "$MODULE_AHBOT" = "1" ] && [ -d "mod-ahbot" ]; then + execute_module_sql "mod-ahbot" "AHBot" + fi + + if [ "$MODULE_AUTOBALANCE" = "1" ] && [ -d "mod-autobalance" ]; then + execute_module_sql "mod-autobalance" "AutoBalance" + fi + + if [ "$MODULE_TRANSMOG" = "1" ] && [ -d "mod-transmog" ]; then + execute_module_sql "mod-transmog" "Transmog" + fi + + if [ "$MODULE_NPC_BUFFER" = "1" ] && [ -d "mod-npc-buffer" ]; then + execute_module_sql "mod-npc-buffer" "NPC Buffer" + fi + + if [ "$MODULE_DYNAMIC_XP" = "1" ] && [ -d "mod-dynamic-xp" ]; then + execute_module_sql "mod-dynamic-xp" "Dynamic XP" + fi + + if [ "$MODULE_SOLO_LFG" = "1" ] && [ -d "mod-solo-lfg" ]; then + execute_module_sql "mod-solo-lfg" "Solo LFG" + fi + + if [ "$MODULE_1V1_ARENA" = "1" ] && [ -d "mod-1v1-arena" ]; then + execute_module_sql "mod-1v1-arena" "1v1 Arena" + fi + + if [ "$MODULE_PHASED_DUELS" = "1" ] && [ -d "mod-phased-duels" ]; then + execute_module_sql "mod-phased-duels" "Phased Duels" + fi + + if [ "$MODULE_BREAKING_NEWS" = "1" ] && [ -d "mod-breaking-news-override" ]; then + execute_module_sql "mod-breaking-news-override" "Breaking News" + fi + + if [ "$MODULE_BOSS_ANNOUNCER" = "1" ] && [ -d "mod-boss-announcer" ]; then + execute_module_sql "mod-boss-announcer" "Boss Announcer" + fi + + if [ "$MODULE_ACCOUNT_ACHIEVEMENTS" = "1" ] && [ -d "mod-account-achievements" ]; then + execute_module_sql "mod-account-achievements" "Account Achievements" + fi + + if [ "$MODULE_AUTO_REVIVE" = "1" ] && [ -d "mod-auto-revive" ]; then + execute_module_sql "mod-auto-revive" "Auto Revive" + fi + + if [ "$MODULE_GAIN_HONOR_GUARD" = "1" ] && [ -d "mod-gain-honor-guard" ]; then + execute_module_sql "mod-gain-honor-guard" "Gain Honor Guard" + fi + + if [ "$MODULE_ELUNA" = "1" ] && [ -d "mod-eluna" ]; then + execute_module_sql "mod-eluna" "Eluna" + fi + if [ "$MODULE_ARAC" = "1" ] && [ -d "mod-arac" ]; then + execute_module_sql "mod-arac" "All Races All Classes" + fi + + if [ "$MODULE_TIME_IS_TIME" = "1" ] && [ -d "mod-TimeIsTime" ]; then + execute_module_sql "mod-TimeIsTime" "Time Is Time" + fi + + if [ "$MODULE_POCKET_PORTAL" = "1" ] && [ -d "mod-pocket-portal" ]; then + execute_module_sql "mod-pocket-portal" "Pocket Portal" + fi + + if [ "$MODULE_RANDOM_ENCHANTS" = "1" ] && [ -d "mod-random-enchants" ]; then + execute_module_sql "mod-random-enchants" "Random Enchants" + fi + + if [ "$MODULE_SOLOCRAFT" = "1" ] && [ -d "mod-solocraft" ]; then + execute_module_sql "mod-solocraft" "Solocraft" + fi + + if [ "$MODULE_PVP_TITLES" = "1" ] && [ -d "mod-pvp-titles" ]; then + execute_module_sql "mod-pvp-titles" "PvP Titles" + fi + + if [ "$MODULE_NPC_BEASTMASTER" = "1" ] && [ -d "mod-npc-beastmaster" ]; then + execute_module_sql "mod-npc-beastmaster" "NPC Beastmaster" + fi + + if [ "$MODULE_NPC_ENCHANTER" = "1" ] && [ -d "mod-npc-enchanter" ]; then + execute_module_sql "mod-npc-enchanter" "NPC Enchanter" + fi + + if [ "$MODULE_INSTANCE_RESET" = "1" ] && [ -d "mod-instance-reset" ]; then + execute_module_sql "mod-instance-reset" "Instance Reset" + fi + + if [ "$MODULE_LEVEL_GRANT" = "1" ] && [ -d "mod-quest-count-level" ]; then + execute_module_sql "mod-quest-count-level" "Level Grant" + fi + if [ "$MODULE_ASSISTANT" = "1" ] && [ -d "mod-assistant" ]; then + execute_module_sql "mod-assistant" "Assistant" + fi + if [ "$MODULE_REAGENT_BANK" = "1" ] && [ -d "mod-reagent-bank" ]; then + execute_module_sql "mod-reagent-bank" "Reagent Bank" + fi + if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" = "1" ] && [ -d "mod-black-market" ]; then + execute_module_sql "mod-black-market" "Black Market" + fi +} \ No newline at end of file diff --git a/V1/scripts/manage-modules.sh b/V1/scripts/manage-modules.sh new file mode 100644 index 0000000..feabe3c --- /dev/null +++ b/V1/scripts/manage-modules.sh @@ -0,0 +1,685 @@ +#!/bin/bash +set -e + +echo 'Setting up git user' +git config --global user.name "$GIT_USERNAME" +git config --global user.email "$GIT_EMAIL" +git config --global url.https://$GIT_PAT@github.com/.insteadOf https://github.com/ + +echo 'Initializing module management...' +cd /modules + +echo 'Cleaning up disabled modules...' + +# Remove modules if disabled +if [ "$MODULE_PLAYERBOTS" != "1" ] && [ -d "mod-playerbots" ]; then + echo 'Removing mod-playerbots (disabled)...' + rm -rf mod-playerbots +fi + +if [ "$MODULE_AOE_LOOT" != "1" ] && [ -d "mod-aoe-loot" ]; then + echo 'Removing mod-aoe-loot (disabled)...' + rm -rf mod-aoe-loot +fi + +if [ "$MODULE_LEARN_SPELLS" != "1" ] && [ -d "mod-learn-spells" ]; then + echo 'Removing mod-learn-spells (disabled)...' + rm -rf mod-learn-spells +fi + +if [ "$MODULE_FIREWORKS" != "1" ] && [ -d "mod-fireworks-on-level" ]; then + echo 'Removing mod-fireworks-on-level (disabled)...' + rm -rf mod-fireworks-on-level +fi + +if [ "$MODULE_INDIVIDUAL_PROGRESSION" != "1" ] && [ -d "mod-individual-progression" ]; then + echo 'Removing mod-individual-progression (disabled)...' + rm -rf mod-individual-progression +fi + +if [ "$MODULE_AHBOT" != "1" ] && [ -d "mod-ahbot" ]; then + echo 'Removing mod-ahbot (disabled)...' + rm -rf mod-ahbot +fi + +if [ "$MODULE_AUTOBALANCE" != "1" ] && [ -d "mod-autobalance" ]; then + echo 'Removing mod-autobalance (disabled)...' + rm -rf mod-autobalance +fi + +if [ "$MODULE_TRANSMOG" != "1" ] && [ -d "mod-transmog" ]; then + echo 'Removing mod-transmog (disabled)...' + rm -rf mod-transmog +fi + +if [ "$MODULE_NPC_BUFFER" != "1" ] && [ -d "mod-npc-buffer" ]; then + echo 'Removing mod-npc-buffer (disabled)...' + rm -rf mod-npc-buffer +fi + +if [ "$MODULE_DYNAMIC_XP" != "1" ] && [ -d "mod-dynamic-xp" ]; then + echo 'Removing mod-dynamic-xp (disabled)...' + rm -rf mod-dynamic-xp +fi + +if [ "$MODULE_SOLO_LFG" != "1" ] && [ -d "mod-solo-lfg" ]; then + echo 'Removing mod-solo-lfg (disabled)...' + rm -rf mod-solo-lfg +fi + +if [ "$MODULE_1V1_ARENA" != "1" ] && [ -d "mod-1v1-arena" ]; then + echo 'Removing mod-1v1-arena (disabled)...' + rm -rf mod-1v1-arena +fi + +if [ "$MODULE_PHASED_DUELS" != "1" ] && [ -d "mod-phased-duels" ]; then + echo 'Removing mod-phased-duels (disabled)...' + rm -rf mod-phased-duels +fi + +if [ "$MODULE_BREAKING_NEWS" != "1" ] && [ -d "mod-breaking-news-override" ]; then + echo 'Removing mod-breaking-news-override (disabled)...' + rm -rf mod-breaking-news-override +fi + +if [ "$MODULE_BOSS_ANNOUNCER" != "1" ] && [ -d "mod-boss-announcer" ]; then + echo 'Removing mod-boss-announcer (disabled)...' + rm -rf mod-boss-announcer +fi + +if [ "$MODULE_ACCOUNT_ACHIEVEMENTS" != "1" ] && [ -d "mod-account-achievements" ]; then + echo 'Removing mod-account-achievements (disabled)...' + rm -rf mod-account-achievements +fi + +if [ "$MODULE_AUTO_REVIVE" != "1" ] && [ -d "mod-auto-revive" ]; then + echo 'Removing mod-auto-revive (disabled)...' + rm -rf mod-auto-revive +fi + +if [ "$MODULE_GAIN_HONOR_GUARD" != "1" ] && [ -d "mod-gain-honor-guard" ]; then + echo 'Removing mod-gain-honor-guard (disabled)...' + rm -rf mod-gain-honor-guard +fi + +if [ "$MODULE_ELUNA" != "1" ] && [ -d "mod-eluna" ]; then + echo 'Removing mod-eluna (disabled)...' + rm -rf mod-eluna +fi +if [ "$MODULE_ARAC" != "1" ] && [ -d "mod-arac" ]; then + echo 'Removing mod-arac (disabled)...' + rm -rf mod-arac +fi + +if [ "$MODULE_TIME_IS_TIME" != "1" ] && [ -d "mod-TimeIsTime" ]; then + echo 'Removing mod-TimeIsTime (disabled)...' + rm -rf mod-TimeIsTime +fi + +if [ "$MODULE_POCKET_PORTAL" != "1" ] && [ -d "mod-pocket-portal" ]; then + echo 'Removing mod-pocket-portal (disabled)...' + rm -rf mod-pocket-portal +fi + +if [ "$MODULE_RANDOM_ENCHANTS" != "1" ] && [ -d "mod-random-enchants" ]; then + echo 'Removing mod-random-enchants (disabled)...' + rm -rf mod-random-enchants +fi + +if [ "$MODULE_SOLOCRAFT" != "1" ] && [ -d "mod-solocraft" ]; then + echo 'Removing mod-solocraft (disabled)...' + rm -rf mod-solocraft +fi + +if [ "$MODULE_PVP_TITLES" != "1" ] && [ -d "mod-pvp-titles" ]; then + echo 'Removing mod-pvp-titles (disabled)...' + rm -rf mod-pvp-titles +fi + +if [ "$MODULE_NPC_BEASTMASTER" != "1" ] && [ -d "mod-npc-beastmaster" ]; then + echo 'Removing mod-npc-beastmaster (disabled)...' + rm -rf mod-npc-beastmaster +fi + +if [ "$MODULE_NPC_ENCHANTER" != "1" ] && [ -d "mod-npc-enchanter" ]; then + echo 'Removing mod-npc-enchanter (disabled)...' + rm -rf mod-npc-enchanter +fi + +if [ "$MODULE_INSTANCE_RESET" != "1" ] && [ -d "mod-instance-reset" ]; then + echo 'Removing mod-instance-reset (disabled)...' + rm -rf mod-instance-reset +fi + +if [ "$MODULE_LEVEL_GRANT" != "1" ] && [ -d "mod-quest-count-level" ]; then + echo 'Removing mod-quest-count-level (disabled)...' + rm -rf mod-quest-count-level +fi +if [ "$MODULE_ASSISTANT" != "1" ] && [ -d "mod-assistant" ]; then + echo 'Removing mod-assistant (disabled)...' + rm -rf mod-assistant +fi +if [ "$MODULE_REAGENT_BANK" != "1" ] && [ -d "mod-reagent-bank" ]; then + echo 'Removing mod-reagent-bank (disabled)...' + rm -rf mod-reagent-bank +fi +if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" != "1" ] && [ -d "mod-black-market" ]; then + echo 'Removing mod-black-market (disabled)...' + rm -rf mod-black-market +fi + +echo 'Installing enabled modules...' + +# Install Playerbots if enabled +if [ "$MODULE_PLAYERBOTS" = "1" ] && [ ! -d "mod-playerbots" ]; then + echo '๐Ÿค– Installing mod-playerbots...' + echo ' ๐Ÿ“– Project: https://github.com/liyunfan1223/mod-playerbots' + echo ' ๐Ÿšจ CRITICAL: REQUIRES Custom AzerothCore branch (liyunfan1223/azerothcore-wotlk/tree/Playerbot)' + echo ' ๐Ÿšจ INCOMPATIBLE with standard AzerothCore - module will not function properly' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ“‹ POST-INSTALL: Requires manual account/character configuration' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/liyunfan1223/mod-playerbots.git mod-playerbots +fi + +# Install AOE Loot if enabled +if [ "$MODULE_AOE_LOOT" = "1" ] && [ ! -d "mod-aoe-loot" ]; then + echo '๐Ÿ’ฐ Installing mod-aoe-loot...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-aoe-loot' + echo ' โ„น๏ธ Allows looting multiple corpses with one action' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/azerothcore/mod-aoe-loot.git mod-aoe-loot +fi + +# Install Learn Spells if enabled +if [ "$MODULE_LEARN_SPELLS" = "1" ] && [ ! -d "mod-learn-spells" ]; then + echo '๐Ÿ“š Installing mod-learn-spells...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-learn-spells' + echo ' โ„น๏ธ Automatically teaches class spells on level up' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/azerothcore/mod-learn-spells.git mod-learn-spells +fi + +# Install Fireworks on Level if enabled +if [ "$MODULE_FIREWORKS" = "1" ] && [ ! -d "mod-fireworks-on-level" ]; then + echo '๐ŸŽ† Installing mod-fireworks-on-level...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-fireworks-on-level' + echo ' โ„น๏ธ Displays fireworks when players level up' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/azerothcore/mod-fireworks-on-level.git mod-fireworks-on-level +fi + +# Install Individual Progression if enabled +if [ "$MODULE_INDIVIDUAL_PROGRESSION" = "1" ] && [ ! -d "mod-individual-progression" ]; then + echo 'โณ Installing mod-individual-progression...' + echo ' ๐Ÿ“– Project: https://github.com/ZhengPeiRu21/mod-individual-progression' + echo ' โ„น๏ธ Simulates authentic Vanillaโ†’TBCโ†’WotLK progression per player' + echo ' โœ… AUTO-CONFIG: Automatically sets EnablePlayerSettings=1 and DBC.EnforceItemAttributes=0' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ“ Optional client files available in optional/ directory' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/ZhengPeiRu21/mod-individual-progression.git mod-individual-progression +fi + +# Quality of Life Modules +if [ "$MODULE_AHBOT" = "1" ] && [ ! -d "mod-ahbot" ]; then + echo '๐Ÿช Installing mod-ahbot...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-ahbot' + echo ' โ„น๏ธ Auction house bot that buys and sells items automatically' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ“‹ POST-INSTALL: Requires manual account/character setup in mod_ahbot.conf' + git clone https://github.com/azerothcore/mod-ahbot.git mod-ahbot +fi + +if [ "$MODULE_AUTOBALANCE" = "1" ] && [ ! -d "mod-autobalance" ]; then + echo 'โš–๏ธ Installing mod-autobalance...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-autobalance' + echo ' โ„น๏ธ Automatically adjusts dungeon difficulty based on party size' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + git clone https://github.com/azerothcore/mod-autobalance.git mod-autobalance +fi + +if [ "$MODULE_TRANSMOG" = "1" ] && [ ! -d "mod-transmog" ]; then + echo '๐ŸŽญ Installing mod-transmog...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-transmog' + echo ' โ„น๏ธ Allows appearance customization of equipment' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/azerothcore/mod-transmog.git mod-transmog +fi + +if [ "$MODULE_NPC_BUFFER" = "1" ] && [ ! -d "mod-npc-buffer" ]; then + echo 'Installing mod-npc-buffer...' + git clone https://github.com/azerothcore/mod-npc-buffer.git mod-npc-buffer +fi + +# Gameplay Enhancement Modules +if [ "$MODULE_DYNAMIC_XP" = "1" ] && [ ! -d "mod-dynamic-xp" ]; then + echo 'Installing mod-dynamic-xp...' + git clone https://github.com/azerothcore/mod-dynamic-xp.git mod-dynamic-xp +fi + +if [ "$MODULE_SOLO_LFG" = "1" ] && [ ! -d "mod-solo-lfg" ]; then + echo '๐Ÿ” Installing mod-solo-lfg...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-solo-lfg' + echo ' โ„น๏ธ Allows dungeon finder for solo players and small groups' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ’ก Pairs perfectly with mod-solocraft and mod-autobalance' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/azerothcore/mod-solo-lfg.git mod-solo-lfg +fi + +if [ "$MODULE_1V1_ARENA" = "1" ] && [ ! -d "mod-1v1-arena" ]; then + echo 'Installing mod-1v1-arena...' + git clone https://github.com/azerothcore/mod-1v1-arena.git mod-1v1-arena +fi + +if [ "$MODULE_PHASED_DUELS" = "1" ] && [ ! -d "mod-phased-duels" ]; then + echo 'Installing mod-phased-duels...' + git clone https://github.com/azerothcore/mod-phased-duels.git mod-phased-duels +fi + +# Server Management Modules +if [ "$MODULE_BREAKING_NEWS" = "1" ] && [ ! -d "mod-breaking-news-override" ]; then + echo '๐Ÿ“ฐ Installing mod-breaking-news-override...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-breaking-news-override' + echo ' โ„น๏ธ Displays custom breaking news on character selection screen' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ“‹ POST-INSTALL: Requires custom HTML file creation and path configuration' + git clone https://github.com/azerothcore/mod-breaking-news-override.git mod-breaking-news-override +fi + +if [ "$MODULE_BOSS_ANNOUNCER" = "1" ] && [ ! -d "mod-boss-announcer" ]; then + echo 'Installing mod-boss-announcer...' + git clone https://github.com/azerothcore/mod-boss-announcer.git mod-boss-announcer +fi + +if [ "$MODULE_ACCOUNT_ACHIEVEMENTS" = "1" ] && [ ! -d "mod-account-achievements" ]; then + echo 'Installing mod-account-achievements...' + git clone https://github.com/azerothcore/mod-account-achievements.git mod-account-achievements +fi + +# Additional Modules Found in Config +if [ "$MODULE_AUTO_REVIVE" = "1" ] && [ ! -d "mod-auto-revive" ]; then + echo 'Installing mod-auto-revive...' + git clone https://github.com/azerothcore/mod-auto-revive.git mod-auto-revive +fi + +if [ "$MODULE_GAIN_HONOR_GUARD" = "1" ] && [ ! -d "mod-gain-honor-guard" ]; then + echo 'Installing mod-gain-honor-guard...' + git clone https://github.com/azerothcore/mod-gain-honor-guard.git mod-gain-honor-guard +fi + +if [ "$MODULE_ELUNA" = "1" ] && [ ! -d "mod-eluna" ]; then + echo '๐Ÿ–ฅ๏ธ Installing mod-eluna...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-eluna' + echo ' โ„น๏ธ Lua scripting engine for custom server functionality' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/azerothcore/mod-eluna.git mod-eluna +fi +if [ "$MODULE_ARAC" = "1" ] && [ ! -d "mod-arac" ]; then + echo '๐ŸŒˆ Installing mod-arac...' + echo ' ๐Ÿ“– Project: https://github.com/heyitsbench/mod-arac' + echo ' โ„น๏ธ All Races All Classes - Removes class restrictions' + echo ' ๐Ÿšจ CRITICAL: Requires DBC file updates and client patch!' + echo ' ๐Ÿ“‹ POST-INSTALL: Apply Patch-A.MPQ to client WoW/Data/ directory' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/heyitsbench/mod-arac.git mod-arac +fi + +if [ "$MODULE_TIME_IS_TIME" = "1" ] && [ ! -d "mod-TimeIsTime" ]; then + echo 'Installing mod-TimeIsTime...' + git clone https://github.com/dunjeon/mod-TimeIsTime.git mod-TimeIsTime +fi + +if [ "$MODULE_POCKET_PORTAL" = "1" ] && [ ! -d "mod-pocket-portal" ]; then + echo 'Installing mod-pocket-portal...' + git clone https://github.com/azerothcore/mod-pocket-portal.git mod-pocket-portal +fi + +if [ "$MODULE_RANDOM_ENCHANTS" = "1" ] && [ ! -d "mod-random-enchants" ]; then + echo 'Installing mod-random-enchants...' + git clone https://github.com/azerothcore/mod-random-enchants.git mod-random-enchants +fi + +if [ "$MODULE_SOLOCRAFT" = "1" ] && [ ! -d "mod-solocraft" ]; then + echo '๐ŸŽฏ Installing mod-solocraft...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-solocraft' + echo ' โ„น๏ธ Scales dungeon/raid difficulty for solo players' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ’ก Works well with mod-autobalance and mod-solo-lfg' + git clone https://github.com/azerothcore/mod-solocraft.git mod-solocraft +fi + +if [ "$MODULE_PVP_TITLES" = "1" ] && [ ! -d "mod-pvp-titles" ]; then + echo 'Installing mod-pvp-titles...' + git clone https://github.com/azerothcore/mod-pvp-titles.git mod-pvp-titles +fi + +if [ "$MODULE_NPC_BEASTMASTER" = "1" ] && [ ! -d "mod-npc-beastmaster" ]; then + echo 'Installing mod-npc-beastmaster...' + git clone https://github.com/azerothcore/mod-npc-beastmaster.git mod-npc-beastmaster +fi + +if [ "$MODULE_NPC_ENCHANTER" = "1" ] && [ ! -d "mod-npc-enchanter" ]; then + echo 'โœจ Installing mod-npc-enchanter...' + echo ' ๐Ÿ“– Project: https://github.com/azerothcore/mod-npc-enchanter' + echo ' โ„น๏ธ NPC that provides enchanting services' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/azerothcore/mod-npc-enchanter.git mod-npc-enchanter +fi + +if [ "$MODULE_INSTANCE_RESET" = "1" ] && [ ! -d "mod-instance-reset" ]; then + echo 'Installing mod-instance-reset...' + git clone https://github.com/azerothcore/mod-instance-reset.git mod-instance-reset +fi + +if [ "$MODULE_LEVEL_GRANT" = "1" ] && [ ! -d "mod-quest-count-level" ]; then + echo 'Installing mod-quest-count-level...' + git clone https://github.com/michaeldelago/mod-quest-count-level.git mod-quest-count-level +fi +if [ "$MODULE_ASSISTANT" = "1" ] && [ ! -d "mod-assistant" ]; then + echo '๐Ÿค– Installing mod-assistant...' + echo ' ๐Ÿ“– Project: https://github.com/noisiver/mod-assistant' + echo ' โ„น๏ธ NPC (ID: 9000000) providing heirlooms, glyphs, gems, profession services' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/noisiver/mod-assistant.git mod-assistant +fi +if [ "$MODULE_REAGENT_BANK" = "1" ] && [ ! -d "mod-reagent-bank" ]; then + echo '๐Ÿฆ Installing mod-reagent-bank...' + echo ' ๐Ÿ“– Project: https://github.com/ZhengPeiRu21/mod-reagent-bank' + echo ' โ„น๏ธ Reagent banker NPC for storing crafting materials, frees bag space' + echo ' ๐Ÿ”ง REBUILD REQUIRED: Container must be rebuilt with source-based compilation' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/ZhengPeiRu21/mod-reagent-bank.git mod-reagent-bank +fi +if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" = "1" ] && [ ! -d "mod-black-market" ]; then + echo '๐Ÿดโ€โ˜ ๏ธ Installing mod-black-market...' + echo ' ๐Ÿ“– Project: https://github.com/Youpeoples/Black-Market-Auction-House' + echo ' โ„น๏ธ MoP Black Market Auction House backported using Eluna Lua engine' + echo ' โš ๏ธ SPECIAL MODULE: Uses Lua scripts, not C++ compilation' + echo ' ๐Ÿ”ง REQUIRES: mod-eluna must be enabled and functional' + echo ' ๐Ÿ”ฌ STATUS: IN TESTING - Currently under verification' + git clone https://github.com/Youpeoples/Black-Market-Auction-House.git mod-black-market + + # Special handling: Copy Lua scripts to lua_scripts directory + if [ "$MODULE_ELUNA" = "1" ] && [ -d "mod-black-market/Server Files/lua_scripts" ]; then + echo ' ๐Ÿ”ง Integrating Black Market Lua scripts with mod-eluna...' + mkdir -p /azerothcore/lua_scripts + cp -r mod-black-market/Server\ Files/lua_scripts/* /azerothcore/lua_scripts/ 2>/dev/null || true + echo ' โœ… Black Market Lua scripts copied to /azerothcore/lua_scripts directory' + ls -la /azerothcore/lua_scripts/ | grep -E "\.lua$" || echo " โ„น๏ธ No .lua files found after copy" + else + echo ' โš ๏ธ WARNING: mod-eluna not enabled - Black Market will not function' + fi +fi + +echo 'Managing configuration files...' + +# Remove configuration files for disabled modules +if [ "$MODULE_PLAYERBOTS" != "1" ]; then + rm -f /azerothcore/env/dist/etc/playerbots.conf* +fi + +if [ "$MODULE_AOE_LOOT" != "1" ]; then + rm -f /azerothcore/env/dist/etc/mod_aoe_loot.conf* +fi + +if [ "$MODULE_LEARN_SPELLS" != "1" ]; then + rm -f /azerothcore/env/dist/etc/mod_learnspells.conf* +fi + +if [ "$MODULE_FIREWORKS" != "1" ]; then + rm -f /azerothcore/env/dist/etc/mod_fireworks.conf* +fi + +if [ "$MODULE_INDIVIDUAL_PROGRESSION" != "1" ]; then + rm -f /azerothcore/env/dist/etc/individual_progression.conf* +fi + +if [ "$MODULE_AHBOT" != "1" ]; then + rm -f /azerothcore/env/dist/etc/mod_ahbot.conf* +fi + +if [ "$MODULE_AUTOBALANCE" != "1" ]; then + rm -f /azerothcore/env/dist/etc/AutoBalance.conf* +fi + +if [ "$MODULE_TRANSMOG" != "1" ]; then + rm -f /azerothcore/env/dist/etc/transmog.conf* +fi + +if [ "$MODULE_NPC_BUFFER" != "1" ]; then + rm -f /azerothcore/env/dist/etc/npc_buffer.conf* +fi + +if [ "$MODULE_DYNAMIC_XP" != "1" ]; then + rm -f /azerothcore/env/dist/etc/Individual-XP.conf* +fi + +if [ "$MODULE_SOLO_LFG" != "1" ]; then + rm -f /azerothcore/env/dist/etc/SoloLfg.conf* +fi + +if [ "$MODULE_1V1_ARENA" != "1" ]; then + rm -f /azerothcore/env/dist/etc/1v1arena.conf* +fi + +if [ "$MODULE_PHASED_DUELS" != "1" ]; then + rm -f /azerothcore/env/dist/etc/phasedduels.conf* +fi + +if [ "$MODULE_BREAKING_NEWS" != "1" ]; then + rm -f /azerothcore/env/dist/etc/breaking_news.conf* +fi + +if [ "$MODULE_BOSS_ANNOUNCER" != "1" ]; then + rm -f /azerothcore/env/dist/etc/boss_announcer.conf* +fi + +if [ "$MODULE_ACCOUNT_ACHIEVEMENTS" != "1" ]; then + rm -f /azerothcore/env/dist/etc/account_achievements.conf* +fi + +if [ "$MODULE_AUTO_REVIVE" != "1" ]; then + rm -f /azerothcore/env/dist/etc/AutoRevive.conf* +fi + +if [ "$MODULE_GAIN_HONOR_GUARD" != "1" ]; then + rm -f /azerothcore/env/dist/etc/GainHonorGuard.conf* +fi + +if [ "$MODULE_ELUNA" != "1" ]; then + rm -f /azerothcore/env/dist/etc/mod_eluna.conf* +fi +if [ "$MODULE_ARAC" != "1" ]; then + rm -f /azerothcore/env/dist/etc/arac.conf* +fi + +if [ "$MODULE_TIME_IS_TIME" != "1" ]; then + rm -f /azerothcore/env/dist/etc/mod-time_is_time.conf* +fi + +if [ "$MODULE_POCKET_PORTAL" != "1" ]; then + rm -f /azerothcore/env/dist/etc/pocketportal.conf* +fi + +if [ "$MODULE_RANDOM_ENCHANTS" != "1" ]; then + rm -f /azerothcore/env/dist/etc/RandomEnchants.conf* +fi + +if [ "$MODULE_SOLOCRAFT" != "1" ]; then + rm -f /azerothcore/env/dist/etc/Solocraft.conf* +fi + +if [ "$MODULE_PVP_TITLES" != "1" ]; then + rm -f /azerothcore/env/dist/etc/mod_pvptitles.conf* +fi + +if [ "$MODULE_NPC_BEASTMASTER" != "1" ]; then + rm -f /azerothcore/env/dist/etc/npc_beastmaster.conf* +fi + +if [ "$MODULE_NPC_ENCHANTER" != "1" ]; then + rm -f /azerothcore/env/dist/etc/npc_enchanter.conf* +fi + +if [ "$MODULE_INSTANCE_RESET" != "1" ]; then + rm -f /azerothcore/env/dist/etc/instance-reset.conf* +fi + +if [ "$MODULE_LEVEL_GRANT" != "1" ]; then + rm -f /azerothcore/env/dist/etc/levelGrant.conf* +fi + +if [ "$MODULE_ASSISTANT" != "1" ]; then + rm -f /azerothcore/env/dist/etc/mod_assistant.conf* +fi + +if [ "$MODULE_REAGENT_BANK" != "1" ]; then + rm -f /azerothcore/env/dist/etc/mod_reagent_bank.conf* +fi + +if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" != "1" ]; then + rm -f /azerothcore/env/dist/etc/mod_black_market.conf* +fi + +# Install configuration files for enabled modules +for module_dir in mod-*; do + if [ -d "$module_dir" ]; then + echo "Installing config files for $module_dir..." + find "$module_dir" -name "*.conf.dist" -exec cp {} /azerothcore/env/dist/etc/ \; 2>/dev/null || true + fi +done + +echo 'Configuration file management complete.' + +# Source the SQL module management functions +source /scripts/manage-modules-sql.sh + +echo 'Executing module SQL scripts...' +execute_module_sql_scripts + +echo 'SQL execution complete.' + +# Module state tracking and rebuild logic +echo 'Checking for module changes that require rebuild...' + +MODULES_STATE_FILE="/modules/.modules_state" +CURRENT_STATE="" +REBUILD_REQUIRED=0 + +# Create current module state hash +for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT; do + eval "value=\$$module_var" + CURRENT_STATE="$CURRENT_STATE$module_var=$value|" +done + +# Check if state has changed +if [ -f "$MODULES_STATE_FILE" ]; then + PREVIOUS_STATE=$(cat "$MODULES_STATE_FILE") + if [ "$CURRENT_STATE" != "$PREVIOUS_STATE" ]; then + echo "๐Ÿ”„ Module configuration has changed - rebuild required" + REBUILD_REQUIRED=1 + else + echo "โœ… No module changes detected" + fi +else + echo "๐Ÿ“ First run - establishing module state baseline" + REBUILD_REQUIRED=1 +fi + +# Save current state +echo "$CURRENT_STATE" > "$MODULES_STATE_FILE" + +# Check if any C++ modules are enabled (all current modules require compilation) +ENABLED_MODULES="" +[ "$MODULE_PLAYERBOTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-playerbots" +[ "$MODULE_AOE_LOOT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-aoe-loot" +[ "$MODULE_LEARN_SPELLS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-learn-spells" +[ "$MODULE_FIREWORKS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-fireworks-on-level" +[ "$MODULE_INDIVIDUAL_PROGRESSION" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-individual-progression" +[ "$MODULE_AHBOT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-ahbot" +[ "$MODULE_AUTOBALANCE" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-autobalance" +[ "$MODULE_TRANSMOG" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-transmog" +[ "$MODULE_NPC_BUFFER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-npc-buffer" +[ "$MODULE_DYNAMIC_XP" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-dynamic-xp" +[ "$MODULE_SOLO_LFG" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-solo-lfg" +[ "$MODULE_1V1_ARENA" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-1v1-arena" +[ "$MODULE_PHASED_DUELS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-phased-duels" +[ "$MODULE_BREAKING_NEWS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-breaking-news-override" +[ "$MODULE_BOSS_ANNOUNCER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-boss-announcer" +[ "$MODULE_ACCOUNT_ACHIEVEMENTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-account-achievements" +[ "$MODULE_AUTO_REVIVE" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-auto-revive" +[ "$MODULE_GAIN_HONOR_GUARD" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-gain-honor-guard" +[ "$MODULE_ELUNA" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-eluna" +[ "$MODULE_ARAC" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-arac" +[ "$MODULE_TIME_IS_TIME" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-time-is-time" +[ "$MODULE_POCKET_PORTAL" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-pocket-portal" +[ "$MODULE_RANDOM_ENCHANTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-random-enchants" +[ "$MODULE_SOLOCRAFT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-solocraft" +[ "$MODULE_PVP_TITLES" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-pvp-titles" +[ "$MODULE_NPC_BEASTMASTER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-npc-beastmaster" +[ "$MODULE_NPC_ENCHANTER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-npc-enchanter" +[ "$MODULE_INSTANCE_RESET" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-instance-reset" +[ "$MODULE_LEVEL_GRANT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-quest-count-level" +[ "$MODULE_ASSISTANT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-assistant" +[ "$MODULE_REAGENT_BANK" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-reagent-bank" +# Note: mod-black-market is Lua-based, doesn't need C++ compilation + +if [ -n "$ENABLED_MODULES" ]; then + ENABLED_COUNT=$(echo $ENABLED_MODULES | wc -w) + echo "๐Ÿ”ง Detected $ENABLED_COUNT enabled C++ modules requiring compilation:" + for mod in $ENABLED_MODULES; do + echo " โ€ข $mod" + done + + if [ "$REBUILD_REQUIRED" = "1" ]; then + echo "" + echo "๐Ÿšจ REBUILD REQUIRED ๐Ÿšจ" + echo "Module configuration has changed. To integrate C++ modules into AzerothCore:" + echo "" + echo "1. Stop current services:" + echo " docker compose -f docker-compose-azerothcore-services.yml down" + echo "" + echo "2. Build with source-based compilation:" + echo " docker compose -f /tmp/acore-dev-test/docker-compose.yml build" + echo " docker compose -f /tmp/acore-dev-test/docker-compose.yml up -d" + echo "" + echo "3. Or use the automated rebuild script (if available):" + echo " ./scripts/rebuild-with-modules.sh" + echo "" + echo "๐Ÿ“‹ NOTE: Source-based build will compile AzerothCore with all enabled modules" + echo "โฑ๏ธ Expected build time: 15-45 minutes depending on system performance" + echo "" + fi +else + echo "โœ… No C++ modules enabled - pre-built containers can be used" +fi + +echo 'Module management complete.' + +# Download rebuild script from GitHub for local access +echo '๐Ÿ“ฅ Downloading rebuild-with-modules.sh from GitHub...' +apk add --no-cache curl +if curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/rebuild-with-modules.sh -o /tmp/rebuild-with-modules.sh 2>/dev/null; then + echo 'โœ… Downloaded rebuild-with-modules.sh from GitHub' + chmod +x /tmp/rebuild-with-modules.sh + echo '๐Ÿ“ Script available at: /tmp/rebuild-with-modules.sh' +elif [ -f "/project/scripts/rebuild-with-modules.sh" ]; then + echo '๐Ÿ“ Using local rebuild-with-modules.sh for testing' + cp /project/scripts/rebuild-with-modules.sh /tmp/rebuild-with-modules.sh + chmod +x /tmp/rebuild-with-modules.sh + echo 'โœ… Copied to /tmp/rebuild-with-modules.sh' +else + echo 'โš ๏ธ Warning: rebuild-with-modules.sh not found in GitHub or locally' +fi + +echo 'Keeping container alive...' +tail -f /dev/null \ No newline at end of file diff --git a/scripts/mysql-startup.sh b/V1/scripts/mysql-startup.sh similarity index 100% rename from scripts/mysql-startup.sh rename to V1/scripts/mysql-startup.sh diff --git a/scripts/post-install-setup.sh b/V1/scripts/post-install-setup.sh similarity index 100% rename from scripts/post-install-setup.sh rename to V1/scripts/post-install-setup.sh diff --git a/V1/scripts/rebuild-with-modules.sh b/V1/scripts/rebuild-with-modules.sh new file mode 100755 index 0000000..e61f830 --- /dev/null +++ b/V1/scripts/rebuild-with-modules.sh @@ -0,0 +1,128 @@ +#!/bin/bash + +# AzerothCore Module Rebuild Script +# Automates the process of rebuilding AzerothCore with enabled modules + +set -e + +echo "๐Ÿ”ง AzerothCore Module Rebuild Script" +echo "===================================" +echo "" + +# Check if source repository exists +SOURCE_COMPOSE="/tmp/acore-dev-test/docker-compose.yml" +if [ ! -f "$SOURCE_COMPOSE" ]; then + echo "โŒ Error: Source-based Docker Compose file not found at $SOURCE_COMPOSE" + echo "Please ensure AzerothCore source repository is available for compilation." + exit 1 +fi + +# Check current module configuration +echo "๐Ÿ“‹ Checking current module configuration..." + +MODULES_ENABLED=0 +ENABLED_MODULES="" + +# Read environment file to check enabled modules +if [ -f "docker-compose-azerothcore-services.env" ]; then + while IFS= read -r line; do + if echo "$line" | grep -q "^MODULE_.*=1$"; then + MODULE_NAME=$(echo "$line" | cut -d'=' -f1) + MODULES_ENABLED=$((MODULES_ENABLED + 1)) + ENABLED_MODULES="$ENABLED_MODULES $MODULE_NAME" + fi + done < docker-compose-azerothcore-services.env +else + echo "โš ๏ธ Warning: Environment file not found, checking default configuration..." +fi + +echo "๐Ÿ” Found $MODULES_ENABLED enabled modules" + +if [ $MODULES_ENABLED -eq 0 ]; then + echo "โœ… No modules enabled - rebuild not required" + echo "You can use pre-built containers for better performance." + exit 0 +fi + +echo "๐Ÿ“ฆ Enabled modules:$ENABLED_MODULES" +echo "" + +# Confirm rebuild +read -p "๐Ÿค” Proceed with rebuild? This will take 15-45 minutes. (y/N): " -n 1 -r +echo "" +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "โŒ Rebuild cancelled" + exit 0 +fi + +echo "" +echo "๐Ÿ›‘ Stopping current services..." +docker compose -f docker-compose-azerothcore-services.yml down || echo "โš ๏ธ Services may not be running" + +echo "" +echo "๐Ÿ”ง Starting source-based compilation..." +echo "โฑ๏ธ This will take 15-45 minutes depending on your system..." +echo "" + +# Build with source +cd /tmp/acore-dev-test +echo "๐Ÿ“ Switched to source directory: $(pwd)" + +# Copy modules to source build +echo "๐Ÿ“‹ Copying modules to source build..." +if [ -d "/home/upb/src/acore-compose2/storage/azerothcore/modules" ]; then + # Ensure modules directory exists in source + mkdir -p modules + + # Copy enabled modules only + echo "๐Ÿ”„ Syncing enabled modules..." + for module_dir in /home/upb/src/acore-compose2/storage/azerothcore/modules/*/; do + if [ -d "$module_dir" ]; then + module_name=$(basename "$module_dir") + echo " Copying $module_name..." + cp -r "$module_dir" modules/ + fi + done +else + echo "โš ๏ธ Warning: No modules directory found" +fi + +# Start build process +echo "" +echo "๐Ÿš€ Building AzerothCore with modules..." +docker compose build --no-cache + +if [ $? -eq 0 ]; then + echo "" + echo "โœ… Build completed successfully!" + echo "" + + # Start services + echo "๐ŸŸข Starting services with compiled modules..." + docker compose up -d + + if [ $? -eq 0 ]; then + echo "" + echo "๐ŸŽ‰ SUCCESS! AzerothCore is now running with compiled modules." + echo "" + echo "๐Ÿ“Š Service status:" + docker compose ps + echo "" + echo "๐Ÿ“ To monitor logs:" + echo " docker compose logs -f" + echo "" + echo "๐ŸŒ Server should be available on configured ports once fully started." + else + echo "โŒ Failed to start services" + exit 1 + fi +else + echo "โŒ Build failed" + echo "" + echo "๐Ÿ” Check build logs for errors:" + echo " docker compose logs" + exit 1 +fi + +echo "" +echo "โœ… Rebuild process complete!" \ No newline at end of file diff --git a/scripts/restore.sh b/V1/scripts/restore.sh similarity index 100% rename from scripts/restore.sh rename to V1/scripts/restore.sh diff --git a/scripts/setup-eluna.sh b/V1/scripts/setup-eluna.sh similarity index 100% rename from scripts/setup-eluna.sh rename to V1/scripts/setup-eluna.sh diff --git a/scripts/setup-server.sh b/V1/scripts/setup-server.sh similarity index 100% rename from scripts/setup-server.sh rename to V1/scripts/setup-server.sh diff --git a/scripts/status.sh b/V1/scripts/status.sh similarity index 100% rename from scripts/status.sh rename to V1/scripts/status.sh diff --git a/scripts/test-backup-detection-enhanced.sh b/V1/scripts/test-backup-detection-enhanced.sh similarity index 100% rename from scripts/test-backup-detection-enhanced.sh rename to V1/scripts/test-backup-detection-enhanced.sh diff --git a/scripts/test-backup-detection.sh b/V1/scripts/test-backup-detection.sh similarity index 100% rename from scripts/test-backup-detection.sh rename to V1/scripts/test-backup-detection.sh diff --git a/scripts/test-local-worldserver.sh b/V1/scripts/test-local-worldserver.sh similarity index 100% rename from scripts/test-local-worldserver.sh rename to V1/scripts/test-local-worldserver.sh diff --git a/scripts/toggle-playerbots.sh b/V1/scripts/toggle-playerbots.sh similarity index 100% rename from scripts/toggle-playerbots.sh rename to V1/scripts/toggle-playerbots.sh diff --git a/scripts/update-config.sh b/V1/scripts/update-config.sh similarity index 100% rename from scripts/update-config.sh rename to V1/scripts/update-config.sh diff --git a/scripts/update-realmlist.sh b/V1/scripts/update-realmlist.sh similarity index 100% rename from scripts/update-realmlist.sh rename to V1/scripts/update-realmlist.sh diff --git a/scripts/wait-and-start-worldserver.sh b/V1/scripts/wait-and-start-worldserver.sh similarity index 100% rename from scripts/wait-and-start-worldserver.sh rename to V1/scripts/wait-and-start-worldserver.sh diff --git a/V1/todo.md b/V1/todo.md new file mode 100644 index 0000000..c02274e --- /dev/null +++ b/V1/todo.md @@ -0,0 +1,178 @@ +# AzerothCore Module System Validation TODO + +## Overview +Document findings from module system validation and plan for end-to-end testing to ensure proper deployment in both standard and playerbot configurations. + +## Key Findings + +### Container Architecture +- **Single worldserver container**: `ac-worldserver` +- **Base container selection**: Determined by `MODULE_PLAYERBOTS` flag + - `MODULE_PLAYERBOTS=1` โ†’ `uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot` + - `MODULE_PLAYERBOTS=0` โ†’ `acore/ac-wotlk-worldserver:14.0.0-dev` +- **Additional modules**: Compiled on top of selected base container via source compilation + +### Current Module Configuration +**Enabled Modules (modules-custom.env):** +1. `MODULE_PLAYERBOTS=1` (base container selection) +2. `MODULE_AOE_LOOT=1` (requires C++ compilation) +3. `MODULE_LEARN_SPELLS=1` (requires C++ compilation) +4. `MODULE_FIREWORKS=1` (requires C++ compilation) +5. `MODULE_AHBOT=1` (requires C++ compilation) +6. `MODULE_AUTOBALANCE=1` (requires C++ compilation) +7. `MODULE_TRANSMOG=1` (requires C++ compilation) +8. `MODULE_NPC_BUFFER=1` (requires C++ compilation) +9. `MODULE_SOLO_LFG=1` (requires C++ compilation) +10. `MODULE_SOLOCRAFT=1` (requires C++ compilation) + +### Rebuild Requirements +**Only ac-worldserver requires rebuild:** +- All C++ modules affect worldserver binary only +- ac-authserver remains compatible (playerbot images already include auth changes) +- No other containers need recompilation + +### Module Installation Components +1. **Module Manager**: `ac-modules` container (downloads/installs modules) +2. **Build Service**: `ac-build` container (handles C++ compilation when needed) +3. **State Tracking**: `/modules/.modules_state` file prevents unnecessary rebuilds +4. **Automated Scripts**: + - `scripts/manage-modules.sh` - Module installation and configuration + - `scripts/rebuild-with-modules.sh` - Automated rebuild process + - `scripts/deploy-and-check.sh` - Full stack deployment with validation + +## Configuration Issues Identified +1. **Conflicting Configurations**: + - `services-custom.env`: Only `MODULE_PLAYERBOTS=1` + - `modules-custom.env`: 10 modules enabled + - **Resolution needed**: Align configurations + +## Testing Plan: Two End-to-End Validation Tests + +### Test 1: Standard AzerothCore with Additional Modules +**Objective**: Validate deployment without Playerbots but with other C++ modules +**Configuration**: +```bash +# Base container +MODULE_PLAYERBOTS=0 +AC_WORLDSERVER_IMAGE=acore/ac-wotlk-worldserver:14.0.0-dev + +# Additional modules (subset for testing) +MODULE_AOE_LOOT=1 +MODULE_AUTOBALANCE=1 +MODULE_TRANSMOG=1 +``` + +**Expected Results**: +- Uses standard AzerothCore base +- Compiles 3 additional modules into worldserver +- No Playerbot functionality +- Validates source compilation process + +**Test Steps**: +1. Configure environment files for standard deployment +2. Run `scripts/deploy-and-check.sh` +3. Monitor `ac-modules` container output +4. Verify rebuild detection triggers +5. Execute `scripts/rebuild-with-modules.sh` +6. Validate all services are healthy +7. Test module functionality (AOE loot, autobalance, transmog) + +### Test 2: Playerbot AzerothCore with Additional Modules +**Objective**: Validate deployment with Playerbots + additional C++ modules +**Configuration**: +```bash +# Base container (current configuration) +MODULE_PLAYERBOTS=1 +AC_WORLDSERVER_IMAGE=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot + +# All additional modules +MODULE_AOE_LOOT=1 +MODULE_LEARN_SPELLS=1 +MODULE_FIREWORKS=1 +MODULE_AHBOT=1 +MODULE_AUTOBALANCE=1 +MODULE_TRANSMOG=1 +MODULE_NPC_BUFFER=1 +MODULE_SOLO_LFG=1 +MODULE_SOLOCRAFT=1 +``` + +**Expected Results**: +- Uses Playerbot base container +- Compiles 9 additional modules into worldserver +- Full Playerbot functionality maintained +- All additional modules functional + +**Test Steps**: +1. Use current modules-custom.env configuration +2. Run full deployment with `scripts/deploy-and-check.sh` +3. Monitor module installation and rebuild process +4. Validate Playerbot functionality +5. Test each additional module's functionality +6. Verify no conflicts between Playerbots and other modules + +## Validation Criteria + +### Deployment Success Criteria +- [ ] All containers start and pass health checks +- [ ] Database schemas properly created/updated +- [ ] Module configuration files properly installed +- [ ] No container restart loops +- [ ] Port connectivity tests pass + +### Module Functionality Criteria +- [ ] Playerbot commands work (if enabled) +- [ ] AOE looting functions +- [ ] Auto-spell learning on level up +- [ ] Fireworks display on level up +- [ ] Auction house bot operational +- [ ] Dungeon difficulty auto-balances +- [ ] Transmog system accessible +- [ ] NPC buffer provides services +- [ ] Solo LFG allows queue +- [ ] Solocraft scaling active + +### Performance Criteria +- [ ] Server startup time < 5 minutes +- [ ] Module rebuild time < 45 minutes +- [ ] No memory leaks or excessive resource usage +- [ ] Stable operation under load + +## Risk Mitigation +1. **Backup current working state** before testing +2. **Test in isolated environment** first +3. **Document rollback procedures** for each test +4. **Monitor logs continuously** during testing +5. **Have restore scripts ready** in case of failures + +## Next Steps +1. Create isolated test environments for both scenarios +2. Prepare configuration files for Test 1 (standard + modules) +3. Execute Test 1 and document results +4. Execute Test 2 and document results +5. Compare performance and stability between configurations +6. Document final recommendations for production deployment + +## Notes +- Each test should be run multiple times to ensure consistency +- Log all outputs for analysis +- Measure build times and resource usage +- Test both fresh deployments and configuration changes +- Validate that module state tracking prevents unnecessary rebuilds + +--- + +## Previous Deployment History (ARCHIVED) + +### โœ… **Major Fixes Completed:** +1. **Database Schema Issues** โœ… **RESOLVED** + - Added missing `emotetextsound_dbc.sql` to source project + - Imported all DBC tables - worldserver now starts successfully + - Worldserver status: `Up (healthy)` with Eluna scripts loaded + +2. **Container Script Compatibility** โœ… **RESOLVED** + - Fixed client-data container with multi-OS package manager detection + - Client data downloads working (15GB extracted successfully) + - Updated docker-compose with Alpine/Ubuntu compatibility + +**Status**: **MAJOR SUCCESS** โœ… - Core server functional, ready for module validation testing. \ No newline at end of file diff --git a/cleanup.sh b/cleanup.sh new file mode 100755 index 0000000..0202685 --- /dev/null +++ b/cleanup.sh @@ -0,0 +1,202 @@ +#!/bin/bash + +# ============================================== +# ac-compose Cleanup Script (project-scoped) +# ============================================== +# Usage: ./cleanup.sh [--soft] [--hard] [--nuclear] [--dry-run] [--force] [--preserve-backups] +# Project: ac-compose + +set -e + +# Resolve project dir and compose +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="${SCRIPT_DIR}" +COMPOSE_FILE="${PROJECT_DIR}/compose.yml" +ENV_FILE="${PROJECT_DIR}/.env" + +# Colors +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; MAGENTA='\033[0;35m'; NC='\033[0m' + +print_status() { + case "$1" in + INFO) echo -e "${BLUE}โ„น๏ธ ${2}${NC}";; + SUCCESS) echo -e "${GREEN}โœ… ${2}${NC}";; + WARNING) echo -e "${YELLOW}โš ๏ธ ${2}${NC}";; + ERROR) echo -e "${RED}โŒ ${2}${NC}";; + DANGER) echo -e "${RED}๐Ÿ’€ ${2}${NC}";; + HEADER) echo -e "\n${MAGENTA}=== ${2} ===${NC}";; + esac +} + +usage(){ + cat </dev/null | cut -d= -f2 | tr -d '\r' || echo 'azerothcore')($|\s)" || true + echo -e "${BLUE}Volumes:${NC}" + docker volume ls --format 'table {{.Name}}\t{{.Driver}}' | grep -E 'ac_|acore|azerothcore' || true +} + +# Load env for STORAGE_PATH etc. +STORAGE_PATH_DEFAULT="${PROJECT_DIR}/storage" +if [ -f "$ENV_FILE" ]; then + set -a; source "$ENV_FILE"; set +a +fi +STORAGE_PATH="${STORAGE_PATH:-$STORAGE_PATH_DEFAULT}" + +soft_cleanup() { + print_status HEADER "SOFT CLEANUP - Stop containers" + confirm "This will stop all project containers (data preserved)." + execute_command "Stopping containers" docker compose -f "$COMPOSE_FILE" down + print_status SUCCESS "Soft cleanup complete" +} + +hard_cleanup() { + print_status HEADER "HARD CLEANUP - Remove containers + networks" + confirm "This will remove containers and networks (volumes/images preserved)." + execute_command "Removing containers and networks" docker compose -f "$COMPOSE_FILE" down --remove-orphans + # Remove straggler containers matching ac-* (defensive) + execute_command "Remove stray ac-* containers" "docker ps -a --format '{{.Names}}' | grep -E '^ac-' | xargs -r docker rm -f" + # Remove project network if present and not automatically removed + if [ -n "${NETWORK_NAME:-}" ]; then + execute_command "Remove project network ${NETWORK_NAME}" "docker network rm ${NETWORK_NAME} 2>/dev/null || true" + fi + print_status SUCCESS "Hard cleanup complete" +} + +nuclear_cleanup() { + print_status HEADER "NUCLEAR CLEANUP - COMPLETE REMOVAL" + print_status DANGER "THIS WILL DESTROY ALL PROJECT DATA" + confirm "Proceed with complete removal?" + + # Down with volumes + execute_command "Removing containers, networks and volumes" docker compose -f "$COMPOSE_FILE" down --volumes --remove-orphans + + # 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 playerbots images" "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^uprightbass360/azerothcore-wotlk-playerbots' | 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) + if $PRESERVE_BACKUPS; then + print_status INFO "Preserving backups under ${STORAGE_PATH}/backups" + TMP_PRESERVE="${PROJECT_DIR}/.preserve-backups" + if [ -d "${STORAGE_PATH}/backups" ]; then + execute_command "Staging backups" "mkdir -p '${TMP_PRESERVE}' && cp -r '${STORAGE_PATH}/backups' '${TMP_PRESERVE}/'" + fi + execute_command "Removing storage" "rm -rf '${STORAGE_PATH}' 2>/dev/null || true" + if [ -d "${TMP_PRESERVE}/backups" ]; then + execute_command "Restoring backups" "mkdir -p '${STORAGE_PATH}' && mv '${TMP_PRESERVE}/backups' '${STORAGE_PATH}/backups' && rm -rf '${TMP_PRESERVE}'" + print_status SUCCESS "Backups preserved at ${STORAGE_PATH}/backups" + fi + else + execute_command "Removing storage and local backups" "rm -rf '${STORAGE_PATH}' '${PROJECT_DIR}/backups' 2>/dev/null || true" + fi + + # Optional system prune for project context + execute_command "Docker system prune (dangling)" "docker system prune -af --volumes" + print_status SUCCESS "Nuclear cleanup completed" +} + +show_summary() { + local lvl="$1" + print_status HEADER "CLEANUP SUMMARY" + case "$lvl" in + soft) + echo -e "${GREEN}โœ… Containers: Stopped${NC}"; echo -e "${BLUE}โ„น๏ธ Networks/Volumes/Images: Preserved${NC}";; + hard) + echo -e "${GREEN}โœ… Containers/Networks: Removed${NC}"; echo -e "${BLUE}โ„น๏ธ Volumes/Images: Preserved${NC}";; + nuclear) + echo -e "${RED}๐Ÿ’€ Containers/Networks/Volumes/Images: DESTROYED${NC}";; + esac +} + +main(){ + print_status HEADER "ac-compose CLEANUP" + + if ! command -v docker >/dev/null 2>&1; then + print_status ERROR "Docker not found" + exit 1 + fi + if [ ! -f "$COMPOSE_FILE" ]; then + print_status ERROR "Compose file not found at $COMPOSE_FILE" + exit 1 + fi + if [ -z "$CLEANUP_LEVEL" ]; then + usage; exit 1 + fi + + show_resources + + case "$CLEANUP_LEVEL" in + soft) soft_cleanup;; + hard) hard_cleanup;; + nuclear) nuclear_cleanup;; + *) usage; exit 1;; + esac + + show_summary "$CLEANUP_LEVEL" + print_status SUCCESS "๐Ÿงน Cleanup completed" +} + +main "$@" diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..8699d8e --- /dev/null +++ b/compose.yml @@ -0,0 +1,592 @@ +name: ${COMPOSE_PROJECT_NAME:-ac-compose} +services: + # ===================== + # Database Layer (db) + # ===================== + ac-mysql: + profiles: ["db"] + image: ${MYSQL_IMAGE:-mysql:8.0} + container_name: ${CONTAINER_MYSQL:-ac-mysql} + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123} + MYSQL_ROOT_HOST: '${MYSQL_ROOT_HOST:-%}' + MYSQL_ALLOW_EMPTY_PASSWORD: 'no' + MYSQL_DATADIR: /var/lib/mysql-runtime + MYSQL_CHARACTER_SET: ${MYSQL_CHARACTER_SET:-utf8mb4} + MYSQL_COLLATION: ${MYSQL_COLLATION:-utf8mb4_unicode_ci} + MYSQL_MAX_CONNECTIONS: ${MYSQL_MAX_CONNECTIONS:-1000} + MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_INNODB_BUFFER_POOL_SIZE:-256M} + MYSQL_INNODB_LOG_FILE_SIZE: ${MYSQL_INNODB_LOG_FILE_SIZE:-64M} + ports: + - "${MYSQL_EXTERNAL_PORT:-64306}:${MYSQL_PORT:-3306}" + volumes: + - ${STORAGE_PATH:-./storage}/mysql-data:/var/lib/mysql-persistent + - ${HOST_BACKUP_PATH:-${STORAGE_PATH:-./storage}/backups}:/backups + tmpfs: + - /var/lib/mysql-runtime:size=2G + command: + - mysqld + - --datadir=/var/lib/mysql-runtime + - --default-authentication-plugin=mysql_native_password + - --character-set-server=${MYSQL_CHARACTER_SET:-utf8mb4} + - --collation-server=${MYSQL_COLLATION:-utf8mb4_unicode_ci} + - --max_connections=${MYSQL_MAX_CONNECTIONS:-1000} + - --innodb-buffer-pool-size=${MYSQL_INNODB_BUFFER_POOL_SIZE:-256M} + - --innodb-log-file-size=${MYSQL_INNODB_LOG_FILE_SIZE:-64M} + restart: unless-stopped + healthcheck: + test: ["CMD", "sh", "-c", "mysqladmin ping -h localhost -u ${MYSQL_USER:-root} -p${MYSQL_ROOT_PASSWORD:-azerothcore123} --silent || exit 1"] + interval: ${MYSQL_HEALTHCHECK_INTERVAL:-20s} + timeout: ${MYSQL_HEALTHCHECK_TIMEOUT:-15s} + retries: ${MYSQL_HEALTHCHECK_RETRIES:-25} + start_period: ${MYSQL_HEALTHCHECK_START_PERIOD:-120s} + networks: + - azerothcore + + ac-db-import: + profiles: ["db"] + image: ${AC_DB_IMPORT_IMAGE:-acore/ac-wotlk-db-import:14.0.0-dev} + container_name: ${CONTAINER_DB_IMPORT:-ac-db-import} + user: "0:0" + depends_on: + ac-mysql: + condition: service_healthy + networks: + - azerothcore + volumes: + - ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc + - ${STORAGE_PATH:-./storage}/logs:/azerothcore/logs + - ${STORAGE_PATH:-./storage}/mysql-data:/var/lib/mysql-persistent + - ./scripts/db-import-conditional.sh:/tmp/db-import-conditional.sh:ro + environment: + AC_DATA_DIR: "/azerothcore/data" + AC_LOGS_DIR: "/azerothcore/logs" + AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}" + AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_WORLD_NAME:-acore_world}" + AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_CHARACTERS_NAME:-acore_characters}" + AC_CLOSE_IDLE_CONNECTIONS: "false" + AC_UPDATES_ENABLE_DATABASES: "7" + AC_UPDATES_AUTO_SETUP: "1" + CONTAINER_MYSQL: ${CONTAINER_MYSQL:-ac-mysql} + MYSQL_PORT: ${MYSQL_PORT:-3306} + MYSQL_USER: ${MYSQL_USER:-root} + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123} + DB_AUTH_NAME: ${DB_AUTH_NAME:-acore_auth} + DB_WORLD_NAME: ${DB_WORLD_NAME:-acore_world} + DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME:-acore_characters} + CONTAINER_USER: ${CONTAINER_USER:-0:0} + entrypoint: + - sh + - -c + - | + chown ${CONTAINER_USER:-0:0} /azerothcore/env/dist/etc 2>/dev/null || true + echo "๐Ÿ“ฅ Using local database import script..." + /tmp/db-import-conditional.sh + restart: "no" + + ac-db-init: + profiles: ["db"] + image: ${MYSQL_IMAGE:-mysql:8.0} + container_name: ${CONTAINER_DB_INIT:-ac-db-init} + depends_on: + ac-db-import: + condition: service_completed_successfully + volumes: + - ${STORAGE_PATH:-./storage}/mysql-data:/var/lib/mysql-persistent + - ${HOST_BACKUP_PATH:-${STORAGE_PATH:-./storage}/backups}:/backups + networks: + - azerothcore + environment: + MYSQL_PWD: ${MYSQL_ROOT_PASSWORD:-azerothcore123} + MYSQL_HOST: ${CONTAINER_MYSQL:-ac-mysql} + MYSQL_USER: ${MYSQL_USER:-root} + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123} + DB_WAIT_RETRIES: ${DB_WAIT_RETRIES:-60} + DB_WAIT_SLEEP: ${DB_WAIT_SLEEP:-10} + DB_AUTH_NAME: ${DB_AUTH_NAME:-acore_auth} + DB_WORLD_NAME: ${DB_WORLD_NAME:-acore_world} + DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME:-acore_characters} + MYSQL_CHARACTER_SET: ${MYSQL_CHARACTER_SET:-utf8mb4} + MYSQL_COLLATION: ${MYSQL_COLLATION:-utf8mb4_unicode_ci} + command: + - sh + - -c + - | + if [ -f "/var/lib/mysql-persistent/.restore-completed" ]; then + echo "โœ… Databases already restored from backup - init not needed"; exit 0; fi + if mysql -h ${MYSQL_HOST:-ac-mysql} -u${MYSQL_USER:-root} -p${MYSQL_ROOT_PASSWORD:-azerothcore123} -e " + SELECT COUNT(*) FROM information_schema.tables WHERE table_schema IN ('${DB_AUTH_NAME:-acore_auth}', '${DB_WORLD_NAME:-acore_world}', '${DB_CHARACTERS_NAME:-acore_characters}');" -s -N 2>/dev/null | grep -q -v '^0$'; then + echo "โœ… Databases already populated - init not needed"; exit 0; fi + echo "๐Ÿ”ง Creating fresh AzerothCore databases..." + microdnf install -y curl || yum install -y curl || (apt-get update && apt-get install -y curl) + mysql -h ${MYSQL_HOST:-ac-mysql} -u${MYSQL_USER:-root} -p${MYSQL_ROOT_PASSWORD:-azerothcore123} -e " + CREATE DATABASE IF NOT EXISTS ${DB_AUTH_NAME:-acore_auth} DEFAULT CHARACTER SET ${MYSQL_CHARACTER_SET:-utf8mb4} COLLATE ${MYSQL_COLLATION:-utf8mb4_unicode_ci}; + CREATE DATABASE IF NOT EXISTS ${DB_WORLD_NAME:-acore_world} DEFAULT CHARACTER SET ${MYSQL_CHARACTER_SET:-utf8mb4} COLLATE ${MYSQL_COLLATION:-utf8mb4_unicode_ci}; + CREATE DATABASE IF NOT EXISTS ${DB_CHARACTERS_NAME:-acore_characters} DEFAULT CHARACTER SET ${MYSQL_CHARACTER_SET:-utf8mb4} COLLATE ${MYSQL_COLLATION:-utf8mb4_unicode_ci}; + SHOW DATABASES;" || { echo "โŒ Failed to create databases"; exit 1; } + echo "$(date): Fresh databases created - import needed" > /var/lib/mysql-persistent/.restore-failed + echo "โœ… Fresh databases created!" + restart: "no" + + ac-backup: + profiles: ["db"] + image: ${MYSQL_IMAGE:-mysql:8.0} + container_name: ${CONTAINER_BACKUP:-ac-backup} + depends_on: + ac-db-import: + condition: service_completed_successfully + environment: + MYSQL_HOST: ${CONTAINER_MYSQL:-ac-mysql} + MYSQL_PORT: ${MYSQL_PORT:-3306} + MYSQL_USER: ${MYSQL_USER:-root} + MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123} + BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-3} + BACKUP_RETENTION_HOURS: ${BACKUP_RETENTION_HOURS:-6} + BACKUP_DAILY_TIME: ${BACKUP_DAILY_TIME:-09} + DB_AUTH_NAME: ${DB_AUTH_NAME:-acore_auth} + DB_WORLD_NAME: ${DB_WORLD_NAME:-acore_world} + DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME:-acore_characters} + TZ: ${TZ:-UTC} + volumes: + - ${HOST_BACKUP_PATH:-${STORAGE_PATH:-./storage}/backups}:/backups + - ./scripts:/tmp/scripts:ro + working_dir: /tmp + command: + - /bin/bash + - -c + - | + microdnf install -y curl || yum install -y curl || (apt-get update && apt-get install -y curl) + echo "๐Ÿ“ฅ Downloading backup scheduler script (local copy preferred if mounted)..." + if [ -f /tmp/scripts/backup-scheduler.sh ]; then + chmod +x /tmp/scripts/backup-scheduler.sh 2>/dev/null || true + bash /tmp/scripts/backup-scheduler.sh + else + echo "No local scheduler provided" + fi + restart: unless-stopped + networks: + - azerothcore + + # ===================== + # Client Data (client-data) + # ===================== + ac-client-data-standard: + profiles: ["client-data"] + image: ${AC_CLIENT_DATA_IMAGE:-acore/ac-wotlk-client-data:14.0.0-dev} + container_name: ac-client-data + user: "0:0" + volumes: + - ${STORAGE_PATH:-./storage}/data:/azerothcore/data + - ${STORAGE_PATH:-./storage}/cache:/cache + - ./scripts:/tmp/scripts:ro + working_dir: /tmp + environment: + - CONTAINER_USER=${CONTAINER_USER:-0:0} + - CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-} + command: + - sh + - -c + - | + if command -v apk >/dev/null 2>&1; then + apk add --no-cache curl unzip wget bash ca-certificates p7zip aria2 jq + elif command -v apt-get >/dev/null 2>&1; then + apt-get update && apt-get install -y --no-install-recommends curl unzip wget bash ca-certificates p7zip-full aria2 jq && rm -rf /var/lib/apt/lists/* + elif command -v yum >/dev/null 2>&1; then + yum install -y curl unzip wget bash ca-certificates p7zip aria2 jq + fi + mkdir -p /cache && chown ${CONTAINER_USER:-0:0} /cache /azerothcore/data 2>/dev/null || true + if [ -f /tmp/scripts/download-client-data.sh ]; then + chmod +x /tmp/scripts/download-client-data.sh 2>/dev/null || true + bash /tmp/scripts/download-client-data.sh + else + echo "No local client-data script" + fi + restart: "no" + networks: + - azerothcore + + ac-client-data-playerbots: + profiles: ["client-data-bots"] + image: ${AC_CLIENT_DATA_IMAGE_PLAYERBOTS:-uprightbass360/azerothcore-wotlk-playerbots:client-data-Playerbot} + container_name: ac-client-data + user: "0:0" + volumes: + - ${STORAGE_PATH:-./storage}/data:/azerothcore/data + - ${STORAGE_PATH:-./storage}/cache:/cache + - ./scripts:/tmp/scripts:ro + working_dir: /tmp + environment: + - CONTAINER_USER=${CONTAINER_USER:-0:0} + - CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-} + command: + - sh + - -c + - | + if command -v apk >/dev/null 2>&1; then + apk add --no-cache curl unzip wget bash ca-certificates p7zip aria2 jq + elif command -v apt-get >/dev/null 2>&1; then + apt-get update && apt-get install -y --no-install-recommends curl unzip wget bash ca-certificates p7zip-full aria2 jq && rm -rf /var/lib/apt/lists/* + elif command -v yum >/dev/null 2>&1; then + yum install -y curl unzip wget bash ca-certificates p7zip aria2 jq + fi + mkdir -p /cache && chown ${CONTAINER_USER:-0:0} /cache /azerothcore/data 2>/dev/null || true + if [ -f /tmp/scripts/download-client-data.sh ]; then + chmod +x /tmp/scripts/download-client-data.sh 2>/dev/null || true + bash /tmp/scripts/download-client-data.sh + else + echo "No local client-data script" + fi + restart: "no" + networks: + - azerothcore + + # ===================== + # Services - Standard (services-standard) + # ===================== + ac-authserver-standard: + profiles: ["services-standard"] + image: ${AC_AUTHSERVER_IMAGE:-acore/ac-wotlk-authserver:14.0.0-dev} + container_name: ac-authserver + user: "${CONTAINER_USER:-0:0}" + depends_on: + ac-mysql: + condition: service_healthy + ac-db-import: + condition: service_completed_successfully + ac-db-init: + condition: service_completed_successfully + environment: + AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}" + AC_UPDATES_ENABLE_DATABASES: "0" + AC_BIND_IP: "0.0.0.0" + AC_LOG_LEVEL: "1" + AC_LOGGER_ROOT_CONFIG: "1,Console" + AC_LOGGER_SERVER_CONFIG: "1,Console" + AC_APPENDER_CONSOLE_CONFIG: "1,2,0" + ports: + - "${AUTH_EXTERNAL_PORT:-3784}:${AUTH_PORT:-3724}" + restart: unless-stopped + networks: + - azerothcore + volumes: + - ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc + cap_add: ["SYS_NICE"] + healthcheck: + test: ["CMD", "sh", "-c", "ps aux | grep '[a]uthserver' | grep -v grep || exit 1"] + interval: ${AUTH_HEALTHCHECK_INTERVAL:-30s} + timeout: ${AUTH_HEALTHCHECK_TIMEOUT:-10s} + retries: ${AUTH_HEALTHCHECK_RETRIES:-3} + start_period: ${AUTH_HEALTHCHECK_START_PERIOD:-60s} + + ac-worldserver-standard: + profiles: ["services-standard"] + image: ${AC_WORLDSERVER_IMAGE:-acore/ac-wotlk-worldserver:14.0.0-dev} + container_name: ac-worldserver + user: "${CONTAINER_USER:-0:0}" + stdin_open: true + tty: true + depends_on: + - ac-authserver-standard + - ac-client-data-standard + environment: + AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}" + AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_WORLD_NAME:-acore_world}" + AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_CHARACTERS_NAME:-acore_characters}" + AC_UPDATES_ENABLE_DATABASES: "0" + AC_BIND_IP: "0.0.0.0" + AC_DATA_DIR: "/azerothcore/data" + AC_SOAP_PORT: "7878" + AC_PROCESS_PRIORITY: "0" + AC_ELUNA_ENABLED: "${AC_ELUNA_ENABLED:-1}" + AC_ELUNA_TRACE_BACK: "${AC_ELUNA_TRACE_BACK:-1}" + AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD:-1}" + AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE:-1}" + AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH:-lua_scripts}" + AC_ELUNA_REQUIRE_PATHS: "${AC_ELUNA_REQUIRE_PATHS:-}" + AC_ELUNA_REQUIRE_CPATHS: "${AC_ELUNA_REQUIRE_CPATHS:-}" + AC_ELUNA_AUTO_RELOAD_INTERVAL: "${AC_ELUNA_AUTO_RELOAD_INTERVAL:-1}" + PLAYERBOT_ENABLED: "${PLAYERBOT_ENABLED:-0}" + PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS:-40}" + AC_LOG_LEVEL: "2" + ports: + - "${WORLD_EXTERNAL_PORT:-8215}:${WORLD_PORT:-8085}" + - "${SOAP_EXTERNAL_PORT:-7778}:${SOAP_PORT:-7878}" + volumes: + - ${STORAGE_PATH:-./storage}/data:/azerothcore/data + - ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc + - ${STORAGE_PATH:-./storage}/logs:/azerothcore/logs + - ${STORAGE_PATH:-./storage}/modules:/azerothcore/modules + - ${STORAGE_PATH:-./storage}/lua_scripts:/azerothcore/lua_scripts + restart: unless-stopped + networks: + - azerothcore + cap_add: ["SYS_NICE"] + healthcheck: + test: ["CMD", "sh", "-c", "ps aux | grep '[w]orldserver' | grep -v grep || exit 1"] + interval: ${WORLD_HEALTHCHECK_INTERVAL:-30s} + timeout: ${WORLD_HEALTHCHECK_TIMEOUT:-10s} + retries: ${WORLD_HEALTHCHECK_RETRIES:-3} + start_period: ${WORLD_HEALTHCHECK_START_PERIOD:-120s} + + # ===================== + # Services - Playerbots (services-playerbots) + # ===================== + ac-authserver-playerbots: + profiles: ["services-playerbots"] + image: ${AC_AUTHSERVER_IMAGE_PLAYERBOTS:-uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot} + container_name: ac-authserver + user: "${CONTAINER_USER:-0:0}" + depends_on: + ac-mysql: + condition: service_healthy + ac-db-import: + condition: service_completed_successfully + ac-db-init: + condition: service_completed_successfully + environment: + AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}" + AC_UPDATES_ENABLE_DATABASES: "0" + AC_BIND_IP: "0.0.0.0" + AC_LOG_LEVEL: "1" + AC_LOGGER_ROOT_CONFIG: "1,Console" + AC_LOGGER_SERVER_CONFIG: "1,Console" + AC_APPENDER_CONSOLE_CONFIG: "1,2,0" + ports: + - "${AUTH_EXTERNAL_PORT:-3784}:${AUTH_PORT:-3724}" + restart: unless-stopped + networks: + - azerothcore + volumes: + - ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc + cap_add: ["SYS_NICE"] + healthcheck: + test: ["CMD", "sh", "-c", "ps aux | grep '[a]uthserver' | grep -v grep || exit 1"] + interval: ${AUTH_HEALTHCHECK_INTERVAL:-30s} + timeout: ${AUTH_HEALTHCHECK_TIMEOUT:-10s} + retries: ${AUTH_HEALTHCHECK_RETRIES:-3} + start_period: ${AUTH_HEALTHCHECK_START_PERIOD:-60s} + + ac-worldserver-playerbots: + profiles: ["services-playerbots"] + image: ${AC_WORLDSERVER_IMAGE_PLAYERBOTS:-uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot} + container_name: ac-worldserver + user: "${CONTAINER_USER:-0:0}" + stdin_open: true + tty: true + depends_on: + - ac-authserver-playerbots + - ac-client-data-playerbots + environment: + AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}" + AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_WORLD_NAME:-acore_world}" + AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_CHARACTERS_NAME:-acore_characters}" + AC_UPDATES_ENABLE_DATABASES: "0" + AC_BIND_IP: "0.0.0.0" + AC_DATA_DIR: "/azerothcore/data" + AC_SOAP_PORT: "7878" + AC_PROCESS_PRIORITY: "0" + AC_ELUNA_ENABLED: "${AC_ELUNA_ENABLED:-1}" + AC_ELUNA_TRACE_BACK: "${AC_ELUNA_TRACE_BACK:-1}" + AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD:-1}" + AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE:-1}" + AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH:-lua_scripts}" + AC_ELUNA_REQUIRE_PATHS: "${AC_ELUNA_REQUIRE_PATHS:-}" + AC_ELUNA_REQUIRE_CPATHS: "${AC_ELUNA_REQUIRE_CPATHS:-}" + AC_ELUNA_AUTO_RELOAD_INTERVAL: "${AC_ELUNA_AUTO_RELOAD_INTERVAL:-1}" + PLAYERBOT_ENABLED: "${PLAYERBOT_ENABLED:-1}" + PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS:-40}" + AC_LOG_LEVEL: "2" + ports: + - "${WORLD_EXTERNAL_PORT:-8215}:${WORLD_PORT:-8085}" + - "${SOAP_EXTERNAL_PORT:-7778}:${SOAP_PORT:-7878}" + volumes: + - ${STORAGE_PATH:-./storage}/data:/azerothcore/data + - ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc + - ${STORAGE_PATH:-./storage}/logs:/azerothcore/logs + - ${STORAGE_PATH:-./storage}/modules:/azerothcore/modules + - ${STORAGE_PATH:-./storage}/lua_scripts:/azerothcore/lua_scripts + restart: unless-stopped + networks: + - azerothcore + cap_add: ["SYS_NICE"] + healthcheck: + test: ["CMD", "sh", "-c", "ps aux | grep '[w]orldserver' | grep -v grep || exit 1"] + interval: ${WORLD_HEALTHCHECK_INTERVAL:-30s} + timeout: ${WORLD_HEALTHCHECK_TIMEOUT:-10s} + retries: ${WORLD_HEALTHCHECK_RETRIES:-3} + start_period: ${WORLD_HEALTHCHECK_START_PERIOD:-120s} + + # ===================== + # Modules & Post-install (modules) + # ===================== + ac-modules: + profiles: ["modules"] + image: ${ALPINE_GIT_IMAGE:-alpine/git:latest} + container_name: ${CONTAINER_MODULES:-ac-modules} + user: "0:0" + depends_on: + ac-mysql: + condition: service_healthy + ac-db-import: + condition: service_completed_successfully + ac-db-init: + condition: service_completed_successfully + volumes: + - ${STORAGE_PATH:-./storage}/modules:/modules + - ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc + - ./scripts:/tmp/scripts:ro + environment: + - MODULE_PLAYERBOTS=${MODULE_PLAYERBOTS:-0} + - MODULE_AOE_LOOT=${MODULE_AOE_LOOT:-0} + - MODULE_LEARN_SPELLS=${MODULE_LEARN_SPELLS:-0} + - MODULE_FIREWORKS=${MODULE_FIREWORKS:-0} + - MODULE_INDIVIDUAL_PROGRESSION=${MODULE_INDIVIDUAL_PROGRESSION:-0} + - MODULE_AHBOT=${MODULE_AHBOT:-0} + - MODULE_AUTOBALANCE=${MODULE_AUTOBALANCE:-0} + - MODULE_TRANSMOG=${MODULE_TRANSMOG:-0} + - MODULE_NPC_BUFFER=${MODULE_NPC_BUFFER:-0} + - MODULE_DYNAMIC_XP=${MODULE_DYNAMIC_XP:-0} + - MODULE_SOLO_LFG=${MODULE_SOLO_LFG:-0} + - MODULE_1V1_ARENA=${MODULE_1V1_ARENA:-0} + - MODULE_PHASED_DUELS=${MODULE_PHASED_DUELS:-0} + - MODULE_BREAKING_NEWS=${MODULE_BREAKING_NEWS:-0} + - MODULE_BOSS_ANNOUNCER=${MODULE_BOSS_ANNOUNCER:-0} + - MODULE_ACCOUNT_ACHIEVEMENTS=${MODULE_ACCOUNT_ACHIEVEMENTS:-0} + - MODULE_AUTO_REVIVE=${MODULE_AUTO_REVIVE:-0} + - MODULE_GAIN_HONOR_GUARD=${MODULE_GAIN_HONOR_GUARD:-0} + - MODULE_ELUNA=${MODULE_ELUNA:-0} + - MODULE_ARAC=${MODULE_ARAC:-0} + - MODULE_TIME_IS_TIME=${MODULE_TIME_IS_TIME:-0} + - MODULE_POCKET_PORTAL=${MODULE_POCKET_PORTAL:-0} + - MODULE_RANDOM_ENCHANTS=${MODULE_RANDOM_ENCHANTS:-0} + - MODULE_SOLOCRAFT=${MODULE_SOLOCRAFT:-0} + - MODULE_PVP_TITLES=${MODULE_PVP_TITLES:-0} + - MODULE_NPC_BEASTMASTER=${MODULE_NPC_BEASTMASTER:-0} + - MODULE_NPC_ENCHANTER=${MODULE_NPC_ENCHANTER:-0} + - MODULE_INSTANCE_RESET=${MODULE_INSTANCE_RESET:-0} + - MODULE_LEVEL_GRANT=${MODULE_LEVEL_GRANT:-0} + - MODULE_ASSISTANT=${MODULE_ASSISTANT:-0} + - MODULE_REAGENT_BANK=${MODULE_REAGENT_BANK:-0} + - MODULE_BLACK_MARKET_AUCTION_HOUSE=${MODULE_BLACK_MARKET_AUCTION_HOUSE:-0} + - CONTAINER_MYSQL=${CONTAINER_MYSQL:-ac-mysql} + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-azerothcore123} + - DB_AUTH_NAME=${DB_AUTH_NAME:-acore_auth} + - DB_WORLD_NAME=${DB_WORLD_NAME:-acore_world} + - DB_CHARACTERS_NAME=${DB_CHARACTERS_NAME:-acore_characters} + - CONTAINER_USER=${CONTAINER_USER:-0:0} + entrypoint: ["/bin/sh"] + command: + - -c + - | + apk add --no-cache curl bash && (chmod +x /tmp/scripts/manage-modules.sh /tmp/scripts/manage-modules-sql.sh 2>/dev/null || true) && /tmp/scripts/manage-modules.sh + restart: "no" + networks: + - azerothcore + + ac-post-install: + profiles: ["modules"] + image: ${ALPINE_IMAGE:-alpine:latest} + container_name: ${CONTAINER_POST_INSTALL:-ac-post-install} + user: "0:0" + volumes: + - ${STORAGE_PATH:-./storage}/config:/azerothcore/config + - ${STORAGE_PATH:-./storage}/install-markers:/install-markers + - ./scripts:/tmp/scripts:ro + - /var/run/docker.sock:/var/run/docker.sock:rw + working_dir: /tmp + environment: + MYSQL_HOST: ${CONTAINER_MYSQL:-ac-mysql} + MYSQL_PORT: ${MYSQL_PORT:-3306} + MYSQL_USER: ${MYSQL_USER:-root} + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123} + DB_AUTH_NAME: ${DB_AUTH_NAME:-acore_auth} + DB_WORLD_NAME: ${DB_WORLD_NAME:-acore_world} + DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME:-acore_characters} + STORAGE_PATH: ${STORAGE_PATH:-./storage} + SERVER_ADDRESS: ${SERVER_ADDRESS:-127.0.0.1} + REALM_PORT: ${REALM_PORT:-8215} + NETWORK_NAME: ${NETWORK_NAME:-azerothcore} + CONTAINER_AUTHSERVER: ac-authserver + CONTAINER_WORLDSERVER: ac-worldserver + CONTAINER_USER: ${CONTAINER_USER:-0:0} + depends_on: + ac-modules: + condition: service_completed_successfully + ac-mysql: + condition: service_healthy + command: + - sh + - -c + - | + apk add --no-cache bash curl docker-cli + chown ${CONTAINER_USER:-0:0} /azerothcore/config /install-markers 2>/dev/null || true + echo "๐Ÿ“ฅ Running local auto-post-install script..." + (chmod +x /tmp/scripts/auto-post-install.sh 2>/dev/null || true) && bash /tmp/scripts/auto-post-install.sh + restart: "no" + networks: + - azerothcore + + # ===================== + # Tools (tools) + # ===================== + ac-phpmyadmin: + profiles: ["tools"] + image: phpmyadmin/phpmyadmin:latest + container_name: ac-phpmyadmin + environment: + PMA_HOST: ${PMA_HOST:-ac-mysql} + PMA_PORT: ${PMA_PORT:-3306} + PMA_USER: ${PMA_USER:-root} + PMA_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123} + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123} + PMA_ARBITRARY: ${PMA_ARBITRARY:-1} + PMA_ABSOLUTE_URI: ${PMA_ABSOLUTE_URI:-} + UPLOAD_LIMIT: ${PMA_UPLOAD_LIMIT:-300M} + MEMORY_LIMIT: ${PMA_MEMORY_LIMIT:-512M} + MAX_EXECUTION_TIME: ${PMA_MAX_EXECUTION_TIME:-600} + ports: + - "${PMA_EXTERNAL_PORT:-8081}:80" + restart: unless-stopped + networks: + - azerothcore + + ac-keira3: + profiles: ["tools"] + image: uprightbass360/keira3:latest + container_name: ac-keira3 + restart: unless-stopped + environment: + - NODE_ENV=production + - KEIRA_PORT=8080 + - KEIRA_HOST=0.0.0.0 + - KEIRA_DATABASE_HOST=${KEIRA_DATABASE_HOST:-ac-mysql} + - KEIRA_DATABASE_PORT=${KEIRA_DATABASE_PORT:-3306} + - KEIRA_DATABASE_USER=root + - KEIRA_DATABASE_PASSWORD=${MYSQL_ROOT_PASSWORD:-azerothcore123} + - KEIRA_DATABASE_NAME=${DB_WORLD_NAME:-acore_world} + ports: + - "${KEIRA3_EXTERNAL_PORT:-4201}:8080" + healthcheck: + test: ["CMD", "sh", "-c", "curl -f http://localhost:8080/health || nc -z localhost 8080 || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + logging: + driver: json-file + options: + max-size: "10m" + max-file: "3" + security_opt: + - no-new-privileges:true + networks: + - azerothcore + +networks: + azerothcore: + name: ${NETWORK_NAME:-azerothcore} + driver: bridge + ipam: + config: + - subnet: ${NETWORK_SUBNET:-172.20.0.0/16} + gateway: ${NETWORK_GATEWAY:-172.20.0.1} diff --git a/deploy-and-check.sh b/deploy-and-check.sh new file mode 100755 index 0000000..22ee0b5 --- /dev/null +++ b/deploy-and-check.sh @@ -0,0 +1,186 @@ +#!/bin/bash +# Project: ac-compose +set -e + +# Simple profile-aware deploy + health check for profiles-verify/compose.yml + +BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m' +info(){ echo -e "${BLUE}โ„น๏ธ $*${NC}"; } +ok(){ echo -e "${GREEN}โœ… $*${NC}"; } +warn(){ echo -e "${YELLOW}โš ๏ธ $*${NC}"; } +err(){ echo -e "${RED}โŒ $*${NC}"; } + +COMPOSE_FILE="$(dirname "$0")/compose.yml" +ENV_FILE="" +PROFILES=(db services-standard client-data modules tools) +SKIP_DEPLOY=false +QUICK=false + +usage(){ + cat </dev/null || echo "$sentinel"))." + local auto_rebuild + auto_rebuild="$(read_env_value AUTO_REBUILD_ON_DEPLOY "0")" + if [ "$auto_rebuild" != "1" ]; then + warn "Run ./scripts/rebuild-with-modules.sh after preparing your source tree." + return 0 + fi + + local rebuild_source + rebuild_source="$(read_env_value MODULES_REBUILD_SOURCE_PATH "")" + info "AUTO_REBUILD_ON_DEPLOY=1; invoking ./scripts/rebuild-with-modules.sh." + local cmd=(./scripts/rebuild-with-modules.sh --yes) + if [ -n "$rebuild_source" ]; then + cmd+=(--source "$rebuild_source") + fi + if "${cmd[@]}"; then + info "Module rebuild completed." + else + warn "Automatic rebuild failed; run ./scripts/rebuild-with-modules.sh manually." + fi +} + +check_health(){ + local name="$1" + local status=$(docker inspect --format='{{.State.Health.Status}}' "$name" 2>/dev/null || echo "no-health-check") + if [ "$status" = "healthy" ]; then ok "$name: healthy"; return 0; fi + if docker ps --format '{{.Names}}' | grep -q "^${name}$"; then ok "$name: running"; return 0; fi + err "$name: not running"; return 1 +} + +wait_log(){ + local name="$1"; local needle="$2"; local attempts="${3:-360}"; local interval=5 + info "Waiting for $name log: '$needle' ... (timeout: $((attempts*interval))s)" + for i in $(seq 1 "$attempts"); do + if docker logs "$name" 2>/dev/null | grep -q "$needle"; then ok "$name ready"; return 0; fi + sleep "$interval" + done + warn "$name did not report '$needle'" + return 1 +} + +deploy(){ + info "Deploying profiles: ${PROFILES[*]}" + local args=() + for p in "${PROFILES[@]}"; do args+=(--profile "$p"); done + run_compose "${args[@]}" up -d +} + +health_checks(){ + info "Checking container health" + local failures=0 + check_health ac-mysql || ((failures++)) + check_health ac-authserver || ((failures++)) + check_health ac-worldserver || ((failures++)) + if [ "$QUICK" = false ]; then + info "Port checks" + for port in 64306 3784 8215 7778 8081 4201; do + if timeout 3 bash -c "/dev/null; then ok "port $port: open"; else warn "port $port: closed"; fi + done + fi + if [ $failures -eq 0 ]; then ok "All core services healthy"; else err "$failures service checks failed"; return 1; fi +} + +main(){ + if [ "$SKIP_DEPLOY" = false ]; then + deploy + # Wait for client-data completion if profile active + if printf '%s\n' "${PROFILES[@]}" | grep -q '^client-data$\|^client-data-bots$'; then + wait_log ac-client-data "Game data setup complete" || true + fi + # Give worldserver time to boot + sleep 10 + fi + health_checks + handle_auto_rebuild + info "Endpoints: MySQL:64306, Auth:3784, World:8215, SOAP:7778, phpMyAdmin:8081, Keira3:4201" +} + +main "$@" diff --git a/docker-compose-azerothcore-services.env.bak b/docker-compose-azerothcore-services.env.bak deleted file mode 100644 index 2154e1a..0000000 --- a/docker-compose-azerothcore-services.env.bak +++ /dev/null @@ -1,190 +0,0 @@ -# ============================================== -# AZEROTHCORE SERVICES ENVIRONMENT -# ============================================== -# Environment variables for auth server, world server, client data, modules, and optional services - -# ============================================== -# DEPLOYMENT CONFIGURATION -# ============================================== -# Storage root path - local: ./storage, production: /nfs/azerothcore or custom mount -STORAGE_ROOT=/nfs/azerothcore -# Storage configuration (must match database layer) -STORAGE_PATH=${STORAGE_ROOT} - -# ============================================== -# USER MAPPING CONFIGURATION (for NFS compatibility) -# ============================================== -# User and group IDs for container processes (PUID/PGID pattern) -# Set these to match your NFS server's user mapping -# Default: 1001:1000 (matches 'sharing' user on most systems) -PUID=1001 -PGID=1000 -SHARING_USER=${PUID}:${PGID} -# Legacy compatibility -CONTAINER_USER_ID=${PUID} -CONTAINER_GROUP_ID=${PGID} -CONTAINER_USER=${CONTAINER_USER_ID}:${CONTAINER_GROUP_ID} - -# ============================================== -# NETWORK CONFIGURATION -# ============================================== -# External ports for game services -AUTH_EXTERNAL_PORT=3784 -WORLD_EXTERNAL_PORT=8215 -SOAP_EXTERNAL_PORT=7778 - -# Server address for client connections (production) -# SERVER_ADDRESS=192.168.0.188 -# Server address for client connections (local) -SERVER_ADDRESS=192.168.0.188 -# Use WORLD_EXTERNAL_PORT for realmlist (client connection port) -REALM_PORT=8215 - -# Internal ports (container side) -AUTH_PORT=3724 -WORLD_PORT=8085 -SOAP_PORT=7878 - -# ============================================== -# DATABASE CONNECTION -# ============================================== -# Connect to database layer (must match database layer settings) -MYSQL_HOST=ac-mysql -MYSQL_PORT=3306 -MYSQL_USER=root -MYSQL_ROOT_PASSWORD=azerothcore123 - -# Database names (must match database layer) -DB_AUTH_NAME=acore_auth -DB_WORLD_NAME=acore_world -DB_CHARACTERS_NAME=acore_characters - -# ============================================== -# DOCKER IMAGES -# ============================================== -# Core service images - TO ENABLE PLAYERBOTS: swap _PLAYERBOTS with standard images -# STANDARD IMAGES (currently active): -AC_AUTHSERVER_IMAGE=uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot -AC_WORLDSERVER_IMAGE=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot -# PLAYERBOTS IMAGES (to enable, swap with lines above): -AC_AUTHSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot -AC_WORLDSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot -ALPINE_IMAGE=alpine:latest - -# Optional service images (from combined optional layer) -AC_ELUNA_IMAGE=acore/eluna-ts:master -ALPINE_GIT_IMAGE=alpine/git:latest - -# mod-playerbots compatible client data image -AC_CLIENT_DATA_IMAGE_DISABLED=uprightbass360/azerothcore-wotlk-playerbots:client-data-Playerbot -AC_CLIENT_DATA_IMAGE=alpine:latest - -# ============================================== -# IMAGE PULL POLICY -# ============================================== -IMAGE_PULL_POLICY=if_not_present - -# ============================================== -# CONTAINER HEALTH CHECKS -# ============================================== -# Auth server health check -AUTH_HEALTHCHECK_INTERVAL=30s -AUTH_HEALTHCHECK_TIMEOUT=10s -AUTH_HEALTHCHECK_RETRIES=3 -AUTH_HEALTHCHECK_START_PERIOD=60s - -# World server health check -WORLD_HEALTHCHECK_INTERVAL=30s -WORLD_HEALTHCHECK_TIMEOUT=10s -WORLD_HEALTHCHECK_RETRIES=3 -WORLD_HEALTHCHECK_START_PERIOD=120s - -# ============================================== -# CONTAINER NAMES -# ============================================== -# Core service container names -CONTAINER_AUTHSERVER=ac-authserver -CONTAINER_WORLDSERVER=ac-worldserver -CONTAINER_CLIENT_DATA=ac-client-data - -# Database container name (for external linking) -CONTAINER_MYSQL=ac-mysql - -# ============================================== -# NETWORK SETTINGS -# ============================================== -# Network must already exist from database layer -NETWORK_NAME=azerothcore - -# ============================================== -# CUSTOM MODULE SETTINGS -# ============================================== - -# Playerbot settings -PLAYERBOT_ENABLED=1 -PLAYERBOT_MAX_BOTS=40 - -# Module configuration - ENABLED MODULES -# Selected modules for enhanced gameplay experience -# -# TO ENABLE PLAYERBOTS: -# 1. Change MODULE_PLAYERBOTS=1 -# 2. Swap the image lines below (move _PLAYERBOTS to active, move standard to _STANDARD) -# 3. Redeploy services: docker compose -f docker-compose-azerothcore-services.yml up -d -# 4. No rebuild required - uses pre-built playerbots images! -MODULE_PLAYERBOTS=1 -MODULE_AOE_LOOT=0 -MODULE_LEARN_SPELLS=0 -MODULE_FIREWORKS=0 -MODULE_INDIVIDUAL_PROGRESSION=0 - -# Quality of Life Modules -# NOTE: mod-ahbot has linking issues - undefined reference to 'Addmod_ahbotScripts()' -MODULE_AHBOT=0 -MODULE_AUTOBALANCE=0 -MODULE_TRANSMOG=0 -MODULE_NPC_BUFFER=0 - -# Gameplay Enhancement Modules -MODULE_DYNAMIC_XP=0 -MODULE_SOLO_LFG=0 -MODULE_1V1_ARENA=0 -MODULE_PHASED_DUELS=0 - -# Server Management Modules -MODULE_BREAKING_NEWS=0 -MODULE_BOSS_ANNOUNCER=0 -MODULE_ACCOUNT_ACHIEVEMENTS=0 - -# Additional Modules Found in Config -MODULE_AUTO_REVIVE=0 -MODULE_GAIN_HONOR_GUARD=0 -MODULE_ELUNA=0 -MODULE_ARAC=0 -MODULE_TIME_IS_TIME=0 -MODULE_POCKET_PORTAL=0 -MODULE_RANDOM_ENCHANTS=0 -MODULE_SOLOCRAFT=0 -MODULE_PVP_TITLES=0 -MODULE_NPC_BEASTMASTER=0 -MODULE_NPC_ENCHANTER=0 -MODULE_INSTANCE_RESET=0 -MODULE_LEVEL_GRANT=0 -MODULE_ASSISTANT=0 -MODULE_REAGENT_BANK=0 -MODULE_BLACK_MARKET_AUCTION_HOUSE=0 - -# ============================================== -# ADDITIONAL CONTAINER NAMES -# ============================================== -# Optional service container names -CONTAINER_ELUNA=ac-eluna -CONTAINER_MODULES=ac-modules -CONTAINER_POST_INSTALL=ac-post-install - -# ============================================== -# MODULE MANAGEMENT -# ============================================== -GIT_USERNAME= -GIT_EMAIL= -GIT_PAT= \ No newline at end of file diff --git a/scripts/auto-post-install.sh b/scripts/auto-post-install.sh index 5e8584d..e9809ec 100755 --- a/scripts/auto-post-install.sh +++ b/scripts/auto-post-install.sh @@ -1,11 +1,12 @@ #!/bin/bash +# ac-compose set -e echo "๐Ÿš€ AzerothCore Auto Post-Install Configuration" echo "==============================================" # Install required packages -apk add --no-cache curl mysql-client bash docker-cli-compose jq +apk add --no-cache curl mysql-client bash docker-cli-compose jq || apk add --no-cache curl mysql-client bash jq # Create install markers directory mkdir -p /install-markers @@ -15,7 +16,6 @@ if [ -f "/install-markers/post-install-completed" ]; then echo "โœ… Post-install configuration already completed" echo "โ„น๏ธ Marker file found: /install-markers/post-install-completed" echo "๐Ÿ”„ To re-run post-install configuration, delete the marker file and restart this container" - echo "๐Ÿ“ Command: docker exec ${CONTAINER_POST_INSTALL} rm -f /install-markers/post-install-completed" echo "" echo "๐Ÿƒ Keeping container alive for manual operations..." tail -f /dev/null @@ -50,8 +50,6 @@ else if [ ! -f "/azerothcore/config/authserver.conf" ] || [ ! -f "/azerothcore/config/worldserver.conf" ]; then echo "โŒ Configuration files not found after waiting" - echo " Expected: /azerothcore/config/authserver.conf" - echo " Expected: /azerothcore/config/worldserver.conf" exit 1 fi @@ -59,126 +57,34 @@ else echo "" echo "๐Ÿ”ง Step 1: Updating configuration files..." - # Download and execute update-config.sh - curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/update-config.sh -o /tmp/update-config.sh - chmod +x /tmp/update-config.sh + # Update DB connection lines and any necessary settings directly with sed + sed -i "s|^LoginDatabaseInfo *=.*|LoginDatabaseInfo = \"${MYSQL_HOST};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}\"|" /azerothcore/config/authserver.conf || true + sed -i "s|^LoginDatabaseInfo *=.*|LoginDatabaseInfo = \"${MYSQL_HOST};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}\"|" /azerothcore/config/worldserver.conf || true + sed -i "s|^WorldDatabaseInfo *=.*|WorldDatabaseInfo = \"${MYSQL_HOST};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_WORLD_NAME}\"|" /azerothcore/config/worldserver.conf || true + sed -i "s|^CharacterDatabaseInfo *=.*|CharacterDatabaseInfo = \"${MYSQL_HOST};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}\"|" /azerothcore/config/worldserver.conf || true - # Modify script to use container environment - sed -i 's|docker-compose-azerothcore-services.env|/project/docker-compose-azerothcore-services.env|' /tmp/update-config.sh - sed -i 's|CONFIG_DIR="${STORAGE_PATH}/config"|CONFIG_DIR="/azerothcore/config"|' /tmp/update-config.sh - - # Execute update-config.sh - cd /project - /tmp/update-config.sh - - if [ $? -eq 0 ]; then - echo "โœ… Configuration files updated successfully" - else - echo "โŒ Failed to update configuration files" - exit 1 - fi + echo "โœ… Configuration files updated" # Step 2: Update realmlist table echo "" echo "๐ŸŒ Step 2: Updating realmlist table..." + mysql -h "${MYSQL_HOST}" -u"${MYSQL_USER}" -p"${MYSQL_ROOT_PASSWORD}" --skip-ssl-verify "${DB_AUTH_NAME}" -e " + UPDATE realmlist SET address='${SERVER_ADDRESS}', port=${REALM_PORT} WHERE id=1; + " || echo "โš ๏ธ Could not update realmlist table" - # Download and execute update-realmlist.sh - curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/update-realmlist.sh -o /tmp/update-realmlist.sh - chmod +x /tmp/update-realmlist.sh + echo "โœ… Realmlist updated" - # Modify script to use container environment - sed -i 's|docker-compose-azerothcore-services.env|/project/docker-compose-azerothcore-services.env|' /tmp/update-realmlist.sh - - # Replace all docker exec mysql commands with direct mysql commands - sed -i "s|docker exec ac-mysql mysql -u \"\${MYSQL_USER}\" -p\"\${MYSQL_ROOT_PASSWORD}\" \"\${DB_AUTH_NAME}\"|mysql -h \"${MYSQL_HOST}\" -u\"${MYSQL_USER}\" -p\"${MYSQL_ROOT_PASSWORD}\" --skip-ssl-verify \"${DB_AUTH_NAME}\"|g" /tmp/update-realmlist.sh - sed -i "s|docker exec ac-mysql mysql -u \"\${MYSQL_USER}\" -p\"\${MYSQL_ROOT_PASSWORD}\"|mysql -h \"${MYSQL_HOST}\" -u\"${MYSQL_USER}\" -p\"${MYSQL_ROOT_PASSWORD}\" --skip-ssl-verify|g" /tmp/update-realmlist.sh - - # Execute update-realmlist.sh - cd /project - /tmp/update-realmlist.sh - - if [ $? -eq 0 ]; then - echo "โœ… Realmlist table updated successfully" - else - echo "โŒ Failed to update realmlist table" - exit 1 - fi - - # Step 3: Restart services to apply changes echo "" - echo "โ„น๏ธ Step 3: Restarting services to apply changes..." - echo "๐Ÿ“ Configuration changes have been applied to files" - echo "๐Ÿ”„ Restarting authserver and worldserver to pick up new configuration..." - - # Detect container runtime (Docker or Podman) - CONTAINER_CMD="" - if command -v docker >/dev/null 2>&1; then - # Check if we can connect to Docker daemon - if docker version >/dev/null 2>&1; then - CONTAINER_CMD="docker" - echo "๐Ÿณ Detected Docker runtime" - fi - fi - - if [ -z "$CONTAINER_CMD" ] && command -v podman >/dev/null 2>&1; then - # Check if we can connect to Podman - if podman version >/dev/null 2>&1; then - CONTAINER_CMD="podman" - echo "๐Ÿฆญ Detected Podman runtime" - fi - fi - - if [ -z "$CONTAINER_CMD" ]; then - echo "โš ๏ธ No container runtime detected (docker/podman) - skipping restart" - else - # Restart authserver - if [ -n "$CONTAINER_AUTHSERVER" ]; then - echo "๐Ÿ”„ Restarting authserver container: $CONTAINER_AUTHSERVER" - if $CONTAINER_CMD restart "$CONTAINER_AUTHSERVER" 2>/dev/null; then - echo "โœ… Authserver restarted successfully" - else - echo "โš ๏ธ Failed to restart authserver (may not be running yet)" - fi - fi - - # Restart worldserver - if [ -n "$CONTAINER_WORLDSERVER" ]; then - echo "๐Ÿ”„ Restarting worldserver container: $CONTAINER_WORLDSERVER" - if $CONTAINER_CMD restart "$CONTAINER_WORLDSERVER" 2>/dev/null; then - echo "โœ… Worldserver restarted successfully" - else - echo "โš ๏ธ Failed to restart worldserver (may not be running yet)" - fi - fi - fi - - echo "โœ… Service restart completed" + echo "โ„น๏ธ Step 3: (Optional) Restart services to apply changes โ€” handled externally" # Create completion marker echo "$(date)" > /install-markers/post-install-completed echo "NEW_INSTALL_DATE=$(date)" >> /install-markers/post-install-completed echo "CONFIG_FILES_UPDATED=true" >> /install-markers/post-install-completed echo "REALMLIST_UPDATED=true" >> /install-markers/post-install-completed - echo "SERVICES_RESTARTED=true" >> /install-markers/post-install-completed echo "" echo "๐ŸŽ‰ Auto post-install configuration completed successfully!" echo "" - echo "๐Ÿ“‹ Summary of changes:" - echo " โœ… AuthServer configured with production database settings" - echo " โœ… WorldServer configured with production database settings" - echo " โœ… Realmlist updated with server address: ${SERVER_ADDRESS}:${REALM_PORT}" - echo " โœ… Services restarted to apply changes" - echo " โœ… Completion marker created: /install-markers/post-install-completed" - echo "" - echo "๐ŸŽฎ Your AzerothCore server is now ready for production!" - echo " Players can connect to: ${SERVER_ADDRESS}:${REALM_PORT}" - echo "" - echo "๐Ÿ’ก Next steps:" - echo " 1. Create admin accounts using the worldserver console" - echo " 2. Test client connectivity" - echo " 3. Configure any additional modules as needed" - echo "" - echo "๐Ÿƒ Keeping container alive for future manual operations..." tail -f /dev/null -fi \ No newline at end of file +fi diff --git a/scripts/backup-scheduler.sh b/scripts/backup-scheduler.sh old mode 100644 new mode 100755 index 5d4fc09..eb44b62 --- a/scripts/backup-scheduler.sh +++ b/scripts/backup-scheduler.sh @@ -1,57 +1,104 @@ #!/bin/bash +# ac-compose set -e -echo "๐Ÿ”ง Starting enhanced backup service with hourly and daily schedules..." +BACKUP_DIR_BASE="/backups" +HOURLY_DIR="$BACKUP_DIR_BASE/hourly" +DAILY_DIR="$BACKUP_DIR_BASE/daily" +RETENTION_HOURS=${BACKUP_RETENTION_HOURS:-6} +RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-3} +DAILY_TIME=${BACKUP_DAILY_TIME:-09} +MYSQL_PORT=${MYSQL_PORT:-3306} -# Install curl if not available (handle different package managers) -# NOTE: curl is already available in mysql:8.0 base image, commenting out to fix operator precedence issue -# microdnf install -y curl || yum install -y curl || apt-get update && apt-get install -y curl +mkdir -p "$HOURLY_DIR" "$DAILY_DIR" -# Download backup scripts from GitHub -echo "๐Ÿ“ฅ Downloading backup scripts from GitHub..." -curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup.sh -o /tmp/backup.sh -curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup-hourly.sh -o /tmp/backup-hourly.sh -curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup-daily.sh -o /tmp/backup-daily.sh -chmod +x /tmp/backup.sh /tmp/backup-hourly.sh /tmp/backup-daily.sh +log() { echo "[$(date '+%F %T')] $*"; } -# Wait for MySQL to be ready before starting backup service -echo "โณ Waiting for MySQL to be ready..." -sleep 30 +# Build database list from env (include optional acore_playerbots if present) +database_list() { + local dbs=("${DB_AUTH_NAME}" "${DB_WORLD_NAME}" "${DB_CHARACTERS_NAME}") + if mysql -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" -e "USE acore_playerbots;" >/dev/null 2>&1; then + dbs+=("acore_playerbots") + log "Detected optional database: acore_playerbots (will be backed up)" + fi + printf '%s\n' "${dbs[@]}" +} -# Run initial daily backup -echo "๐Ÿš€ Running initial daily backup..." -/tmp/backup-daily.sh +run_backup() { + local tier_dir="$1" # hourly or daily dir + local tier_type="$2" # "hourly" or "daily" + local ts=$(date '+%Y%m%d_%H%M%S') + local target_dir="$tier_dir/$ts" + mkdir -p "$target_dir" + log "Starting ${tier_type} backup to $target_dir" -# Enhanced scheduler with hourly and daily backups -echo "โฐ Starting enhanced backup scheduler:" -echo " ๐Ÿ“… Daily backups: ${BACKUP_DAILY_TIME}:00 UTC (retention: ${BACKUP_RETENTION_DAYS} days)" -echo " โฐ Hourly backups: every hour (retention: ${BACKUP_RETENTION_HOURS} hours)" + local -a dbs + mapfile -t dbs < <(database_list) -# Track last backup times to avoid duplicates -last_daily_hour="" -last_hourly_minute="" + for db in "${dbs[@]}"; do + log "Backing up database: $db" + if mysqldump \ + -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" \ + --single-transaction --routines --triggers --events \ + --hex-blob --quick --lock-tables=false \ + --add-drop-database --databases "$db" \ + | gzip -c > "$target_dir/${db}.sql.gz"; then + log "โœ… Successfully backed up $db" + else + log "โŒ Failed to back up $db" + fi + done + + # Create backup manifest (parity with scripts/backup.sh and backup-hourly.sh) + local size; size=$(du -sh "$target_dir" | cut -f1) + local mysql_ver; mysql_ver=$(mysql -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" -e 'SELECT VERSION();' -s -N 2>/dev/null || echo "unknown") + + if [ "$tier_type" = "hourly" ]; then + cat > "$target_dir/manifest.json" < "$target_dir/manifest.json" </dev/null || true + find "$DAILY_DIR" -mindepth 1 -maxdepth 1 -type d -mtime +$RETENTION_DAYS -print -exec rm -rf {} + 2>/dev/null || true +} + +log "Backup scheduler starting: hourly($RETENTION_HOURS h), daily($RETENTION_DAYS d at ${DAILY_TIME}:00)" while true; do - current_hour=$(date +%H) - current_minute=$(date +%M) - current_time="$current_hour:$current_minute" + minute=$(date '+%M') + hour=$(date '+%H') - # Daily backup check (configurable time) - if [ "$current_hour" = "${BACKUP_DAILY_TIME}" ] && [ "$current_minute" = "00" ] && [ "$last_daily_hour" != "$current_hour" ]; then - echo "๐Ÿ“… [$(date)] Daily backup time reached, running daily backup..." - /tmp/backup-daily.sh - last_daily_hour="$current_hour" - # Sleep for 2 minutes to avoid running multiple times - sleep 120 - # Hourly backup check (every hour at minute 0, except during daily backup) - elif [ "$current_minute" = "00" ] && [ "$current_hour" != "${BACKUP_DAILY_TIME}" ] && [ "$last_hourly_minute" != "$current_minute" ]; then - echo "โฐ [$(date)] Hourly backup time reached, running hourly backup..." - /tmp/backup-hourly.sh - last_hourly_minute="$current_minute" - # Sleep for 2 minutes to avoid running multiple times - sleep 120 - else - # Sleep for 1 minute before checking again - sleep 60 + if [ "$minute" = "00" ]; then + run_backup "$HOURLY_DIR" "hourly" fi -done \ No newline at end of file + + if [ "$hour" = "$DAILY_TIME" ] && [ "$minute" = "00" ]; then + run_backup "$DAILY_DIR" "daily" + fi + + cleanup_old + sleep 60 +done diff --git a/scripts/db-import-conditional.sh b/scripts/db-import-conditional.sh index d415f7d..ebb8f30 100755 --- a/scripts/db-import-conditional.sh +++ b/scripts/db-import-conditional.sh @@ -1,6 +1,49 @@ #!/bin/bash +# ac-compose set -e +print_help() { + cat <<'EOF' +Usage: db-import-conditional.sh [options] + +Description: + Conditionally restores AzerothCore databases from backups if available; + otherwise creates fresh databases and runs the dbimport tool to populate + schemas. Uses status markers to prevent overwriting restored data. + +Options: + -h, --help Show this help message and exit + +Environment variables: + CONTAINER_MYSQL Hostname of the MySQL container (default: ac-mysql) + MYSQL_PORT MySQL port (default: 3306) + MYSQL_USER MySQL user (default: root) + MYSQL_ROOT_PASSWORD MySQL password for the user above + DB_AUTH_NAME Auth DB name (default: acore_auth) + DB_WORLD_NAME World DB name (default: acore_world) + DB_CHARACTERS_NAME Characters DB name (default: acore_characters) + BACKUP DIRS Uses /backups/{daily,timestamped} if present + STATUS MARKERS Uses /var/lib/mysql-persistent/.restore-* + +Notes: + - If a valid backup is detected and successfully restored, schema import is skipped. + - On fresh setups, the script creates databases and runs dbimport. +EOF +} + +case "${1:-}" in + -h|--help) + print_help + exit 0 + ;; + "") ;; + *) + echo "Unknown option: $1" >&2 + print_help + exit 1 + ;; +esac + echo "๐Ÿ”ง Conditional AzerothCore Database Import" echo "========================================" @@ -12,7 +55,6 @@ RESTORE_FAILED_MARKER="$RESTORE_STATUS_DIR/.restore-failed" RESTORE_SUCCESS_MARKER_TMP="$MARKER_STATUS_DIR/.restore-completed" RESTORE_FAILED_MARKER_TMP="$MARKER_STATUS_DIR/.restore-failed" -# Ensure we can write to the status directory, fallback to tmp mkdir -p "$RESTORE_STATUS_DIR" 2>/dev/null || true if ! touch "$RESTORE_STATUS_DIR/.test-write" 2>/dev/null; then echo "โš ๏ธ Cannot write to $RESTORE_STATUS_DIR, using $MARKER_STATUS_DIR for markers" @@ -24,23 +66,16 @@ fi echo "๐Ÿ” Checking restoration status..." -# Check if backup was successfully restored if [ -f "$RESTORE_SUCCESS_MARKER" ]; then echo "โœ… Backup restoration completed successfully" - echo "๐Ÿ“„ Restoration details:" - cat "$RESTORE_SUCCESS_MARKER" - echo "" + cat "$RESTORE_SUCCESS_MARKER" || true echo "๐Ÿšซ Skipping database import - data already restored from backup" - echo "๐Ÿ’ก This prevents overwriting restored data with fresh schema" exit 0 fi -# Check if restoration failed (fresh databases created) if [ -f "$RESTORE_FAILED_MARKER" ]; then echo "โ„น๏ธ No backup was restored - fresh databases detected" - echo "๐Ÿ“„ Database creation details:" - cat "$RESTORE_FAILED_MARKER" - echo "" + cat "$RESTORE_FAILED_MARKER" || true echo "โ–ถ๏ธ Proceeding with database import to populate fresh databases" else echo "โš ๏ธ No restoration status found - assuming fresh installation" @@ -50,66 +85,11 @@ fi echo "" echo "๐Ÿ”ง Starting database import process..." -# First attempt backup restoration echo "๐Ÿ” Checking for backups to restore..." BACKUP_DIRS="/backups" - - -# Function to restore from backup (directory or single file) -restore_from_directory() { - local backup_path="$1" - echo "๐Ÿ”„ Restoring from backup: $backup_path" - - local restore_success=true - - # Handle single .sql file (legacy backup) - if [ -f "$backup_path" ] && [[ "$backup_path" == *.sql ]]; then - echo "๐Ÿ“ฅ Restoring legacy backup file: $(basename "$backup_path")" - if timeout 300 mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} < "$backup_path"; then - echo "โœ… Successfully restored legacy backup" - return 0 - else - echo "โŒ Failed to restore legacy backup" - return 1 - fi - fi - - # Handle directory with .sql.gz files (modern timestamped backups) - if [ -d "$backup_path" ]; then - echo "๐Ÿ”„ Restoring from backup directory: $backup_path" - # Restore each database backup - for backup_file in "$backup_path"/*.sql.gz; do - if [ -f "$backup_file" ]; then - local db_name=$(basename "$backup_file" .sql.gz) - echo "๐Ÿ“ฅ Restoring database: $db_name" - - if timeout 300 zcat "$backup_file" | mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD}; then - echo "โœ… Successfully restored $db_name" - else - echo "โŒ Failed to restore $db_name" - restore_success=false - fi - fi - done - - if [ "$restore_success" = true ]; then - return 0 - else - return 1 - fi - fi - - # If we get here, backup_path is neither a valid .sql file nor a directory - echo "โŒ Invalid backup path: $backup_path (not a .sql file or directory)" - return 1 -} - -# Attempt backup restoration with full functionality restored -echo "๐Ÿ”„ Checking for backups..." backup_path="" -# Priority 1: Legacy single backup file with content validation echo "๐Ÿ” Checking for legacy backup file..." if [ -f "/var/lib/mysql-persistent/backup.sql" ]; then echo "๐Ÿ“„ Found legacy backup file, validating content..." @@ -123,52 +103,40 @@ else echo "๐Ÿ” No legacy backup found" fi -# Priority 2: Modern timestamped backups (only if no legacy backup found) if [ -z "$backup_path" ] && [ -d "$BACKUP_DIRS" ]; then echo "๐Ÿ“ Backup directory exists, checking for timestamped backups..." - if [ "$(ls -A $BACKUP_DIRS 2>/dev/null | wc -l)" -gt 0 ]; then - # Check daily backups first - if [ -d "$BACKUP_DIRS/daily" ] && [ "$(ls -A $BACKUP_DIRS/daily 2>/dev/null | wc -l)" -gt 0 ]; then - echo "๐Ÿ“… Found daily backup directory, finding latest..." - latest_daily=$(ls -1t $BACKUP_DIRS/daily 2>/dev/null | head -n 1) + if [ -n "$(ls -A "$BACKUP_DIRS" 2>/dev/null)" ]; then + if [ -d "$BACKUP_DIRS/daily" ]; then + echo "๐Ÿ” Checking for daily backups..." + latest_daily=$(ls -1t "$BACKUP_DIRS/daily" 2>/dev/null | head -n 1) if [ -n "$latest_daily" ] && [ -d "$BACKUP_DIRS/daily/$latest_daily" ]; then - echo "๐Ÿ“ฆ Checking backup directory: $latest_daily" - # Check if directory has .sql.gz files - if ls "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz >/dev/null 2>&1; then - # Validate at least one backup file has content - echo "๐Ÿ” Validating backup content..." - for backup_file in "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz; do - if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then - # Use timeout to prevent hanging on zcat - if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then - echo "โœ… Valid backup found: $(basename $backup_file)" - backup_path="$BACKUP_DIRS/daily/$latest_daily" - break - fi + echo "๐Ÿ“ฆ Latest daily backup found: $latest_daily" + for backup_file in "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz; do + if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then + if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then + echo "โœ… Valid daily backup file: $(basename "$backup_file")" + backup_path="$BACKUP_DIRS/daily/$latest_daily" + break fi - done - else - echo "โš ๏ธ No .sql.gz files found in backup directory" - fi + fi + done + else + echo "๐Ÿ“… No daily backup directory found" fi else echo "๐Ÿ“… No daily backup directory found" - # Check for timestamped backup directories (legacy format: YYYYMMDD_HHMMSS) echo "๐Ÿ” Checking for timestamped backup directories..." timestamped_backups=$(ls -1t $BACKUP_DIRS 2>/dev/null | grep -E '^[0-9]{8}_[0-9]{6}$' | head -n 1) if [ -n "$timestamped_backups" ]; then latest_timestamped="$timestamped_backups" echo "๐Ÿ“ฆ Found timestamped backup: $latest_timestamped" if [ -d "$BACKUP_DIRS/$latest_timestamped" ]; then - # Check if directory has .sql.gz files if ls "$BACKUP_DIRS/$latest_timestamped"/*.sql.gz >/dev/null 2>&1; then - # Validate at least one backup file has content echo "๐Ÿ” Validating timestamped backup content..." for backup_file in "$BACKUP_DIRS/$latest_timestamped"/*.sql.gz; do if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then - # Use timeout to prevent hanging on zcat if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then - echo "โœ… Valid timestamped backup found: $(basename $backup_file)" + echo "โœ… Valid timestamped backup found: $(basename "$backup_file")" backup_path="$BACKUP_DIRS/$latest_timestamped" break fi @@ -191,71 +159,47 @@ fi echo "๐Ÿ”„ Final backup path result: '$backup_path'" if [ -n "$backup_path" ]; then - echo "๐Ÿ“ฆ Found backup: $(basename $backup_path)" - if restore_from_directory "$backup_path"; then - echo "โœ… Database restoration completed successfully!" - echo "$(date): Backup successfully restored from $backup_path" > "$RESTORE_SUCCESS_MARKER" - echo "๐Ÿšซ Skipping schema import - data already restored from backup" - exit 0 - else - echo "โŒ Backup restoration failed - proceeding with fresh setup" - echo "$(date): Backup restoration failed - proceeding with fresh setup" > "$RESTORE_FAILED_MARKER" + echo "๐Ÿ“ฆ Found backup: $(basename "$backup_path")" + if [ -d "$backup_path" ]; then + echo "๐Ÿ”„ Restoring from backup directory: $backup_path" + restore_success=true + for backup_file in "$backup_path"/*.sql.gz; do + if [ -f "$backup_file" ]; then + if timeout 300 zcat "$backup_file" | mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD}; then + echo "โœ… Restored $(basename "$backup_file")" + else + echo "โŒ Failed to restore $(basename "$backup_file")"; restore_success=false + fi + fi + done + if [ "$restore_success" = true ]; then + echo "$(date): Backup successfully restored from $backup_path" > "$RESTORE_SUCCESS_MARKER" + exit 0 + else + echo "$(date): Backup restoration failed - proceeding with fresh setup" > "$RESTORE_FAILED_MARKER" + fi + elif [ -f "$backup_path" ]; then + echo "๐Ÿ”„ Restoring from backup file: $backup_path" + if timeout 300 mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} < "$backup_path"; then + echo "$(date): Backup successfully restored from $backup_path" > "$RESTORE_SUCCESS_MARKER" + exit 0 + else + echo "$(date): Backup restoration failed - proceeding with fresh setup" > "$RESTORE_FAILED_MARKER" + fi fi else echo "โ„น๏ธ No valid backups found - proceeding with fresh setup" echo "$(date): No backup found - fresh setup needed" > "$RESTORE_FAILED_MARKER" fi -# Create fresh databases if restoration didn't happen echo "๐Ÿ—„๏ธ Creating fresh AzerothCore databases..." mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e " CREATE DATABASE IF NOT EXISTS ${DB_AUTH_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE IF NOT EXISTS ${DB_WORLD_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE DATABASE IF NOT EXISTS ${DB_CHARACTERS_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -SHOW DATABASES;" || { - echo "โŒ Failed to create databases" - exit 1 -} +SHOW DATABASES;" || { echo "โŒ Failed to create databases"; exit 1; } echo "โœ… Fresh databases created - proceeding with schema import" -# Wait for databases to be ready (they should exist now) -echo "โณ Verifying databases are accessible..." -for i in $(seq 1 10); do - if mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "USE ${DB_AUTH_NAME}; USE ${DB_WORLD_NAME}; USE ${DB_CHARACTERS_NAME};" >/dev/null 2>&1; then - echo "โœ… All databases accessible" - break - fi - echo "โณ Waiting for databases... attempt $i/10" - sleep 2 -done - -# Verify databases are actually empty before importing -echo "๐Ÿ” Verifying databases are empty before import..." -check_table_count() { - local db_name="$1" - local count=$(mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e " - SELECT COUNT(*) FROM information_schema.tables - WHERE table_schema='$db_name' AND table_type='BASE TABLE';" -s -N 2>/dev/null || echo "0") - echo "$count" -} - -auth_tables=$(check_table_count "${DB_AUTH_NAME}") -world_tables=$(check_table_count "${DB_WORLD_NAME}") -char_tables=$(check_table_count "${DB_CHARACTERS_NAME}") - -echo "๐Ÿ“Š Current table counts:" -echo " ${DB_AUTH_NAME}: $auth_tables tables" -echo " ${DB_WORLD_NAME}: $world_tables tables" -echo " ${DB_CHARACTERS_NAME}: $char_tables tables" - -# Warn if databases appear to have data -if [ "$auth_tables" -gt 5 ] || [ "$world_tables" -gt 50 ] || [ "$char_tables" -gt 5 ]; then - echo "โš ๏ธ WARNING: Databases appear to contain data!" - echo "โš ๏ธ Import may overwrite existing data. Consider backing up first." - echo "โš ๏ธ Continuing in 10 seconds... (Ctrl+C to cancel)" - sleep 10 -fi - echo "๐Ÿ“ Creating dbimport configuration..." mkdir -p /azerothcore/env/dist/etc cat > /azerothcore/env/dist/etc/dbimport.conf </dev/null; then - echo "$(date): Database import completed successfully" > "$RESTORE_STATUS_DIR/.import-completed" - else - echo "$(date): Database import completed successfully" > "$MARKER_STATUS_DIR/.import-completed" - echo "โš ๏ธ Using temporary location for completion marker" - fi - - # Verify import was successful - echo "๐Ÿ” Verifying import results..." - auth_tables_after=$(check_table_count "${DB_AUTH_NAME}") - world_tables_after=$(check_table_count "${DB_WORLD_NAME}") - char_tables_after=$(check_table_count "${DB_CHARACTERS_NAME}") - - echo "๐Ÿ“Š Post-import table counts:" - echo " ${DB_AUTH_NAME}: $auth_tables_after tables" - echo " ${DB_WORLD_NAME}: $world_tables_after tables" - echo " ${DB_CHARACTERS_NAME}: $char_tables_after tables" - - if [ "$auth_tables_after" -gt 0 ] && [ "$world_tables_after" -gt 0 ]; then - echo "โœ… Import verification successful - databases populated" - else - echo "โš ๏ธ Import verification failed - databases may be empty" - fi + echo "$(date): Database import completed successfully" > "$RESTORE_STATUS_DIR/.import-completed" || echo "$(date): Database import completed successfully" > "$MARKER_STATUS_DIR/.import-completed" else echo "โŒ Database import failed!" - if touch "$RESTORE_STATUS_DIR/.import-failed" 2>/dev/null; then - echo "$(date): Database import failed" > "$RESTORE_STATUS_DIR/.import-failed" - else - echo "$(date): Database import failed" > "$MARKER_STATUS_DIR/.import-failed" - echo "โš ๏ธ Using temporary location for failed marker" - fi + echo "$(date): Database import failed" > "$RESTORE_STATUS_DIR/.import-failed" || echo "$(date): Database import failed" > "$MARKER_STATUS_DIR/.import-failed" exit 1 fi -echo "๐ŸŽ‰ Database import process complete!" \ No newline at end of file +echo "๐ŸŽ‰ Database import process complete!" diff --git a/scripts/download-client-data.sh b/scripts/download-client-data.sh old mode 100644 new mode 100755 index 65a1b79..c89b64f --- a/scripts/download-client-data.sh +++ b/scripts/download-client-data.sh @@ -1,32 +1,40 @@ #!/bin/bash +# ac-compose set -e echo '๐Ÿš€ Starting AzerothCore game data setup...' # Get the latest release info from wowgaming/client-data -echo '๐Ÿ“ก Fetching latest client data release info...' -RELEASE_INFO=$(wget -qO- https://api.github.com/repos/wowgaming/client-data/releases/latest 2>/dev/null) +REQUESTED_TAG="${CLIENT_DATA_VERSION:-}" +if [ -n "$REQUESTED_TAG" ]; then + echo "๐Ÿ“Œ Using requested client data version: $REQUESTED_TAG" + LATEST_TAG="$REQUESTED_TAG" + LATEST_URL="https://github.com/wowgaming/client-data/releases/download/${REQUESTED_TAG}/data.zip" +else + echo '๐Ÿ“ก Fetching latest client data release info...' + RELEASE_INFO=$(wget -qO- https://api.github.com/repos/wowgaming/client-data/releases/latest 2>/dev/null) -if [ -n "$RELEASE_INFO" ]; then - LATEST_URL=$(echo "$RELEASE_INFO" | grep '"browser_download_url":' | grep '\.zip' | cut -d'"' -f4 | head -1) - LATEST_TAG=$(echo "$RELEASE_INFO" | grep '"tag_name":' | cut -d'"' -f4) - LATEST_SIZE=$(echo "$RELEASE_INFO" | grep '"size":' | head -1 | grep -o '[0-9]*') -fi + if [ -n "$RELEASE_INFO" ]; then + LATEST_URL=$(echo "$RELEASE_INFO" | grep '"browser_download_url":' | grep '\.zip' | cut -d'"' -f4 | head -1) + LATEST_TAG=$(echo "$RELEASE_INFO" | grep '"tag_name":' | cut -d'"' -f4) + LATEST_SIZE=$(echo "$RELEASE_INFO" | grep '"size":' | head -1 | grep -o '[0-9]*') + fi if [ -z "$LATEST_URL" ]; then - echo 'โŒ Could not fetch latest release URL' - echo '๐Ÿ“ฅ Using fallback: direct download from v16 release' - LATEST_URL='https://github.com/wowgaming/client-data/releases/download/v16/data.zip' - LATEST_TAG='v16' - LATEST_SIZE='0' + echo 'โŒ Could not fetch client-data release information. Aborting.' + exit 1 +fi fi echo "๐Ÿ“ Latest release: $LATEST_TAG" echo "๐Ÿ“ฅ Download URL: $LATEST_URL" # Cache file paths -CACHE_FILE="/cache/client-data-$LATEST_TAG.zip" -VERSION_FILE="/cache/client-data-version.txt" +CACHE_DIR="/cache" +mkdir -p "$CACHE_DIR" +CACHE_FILE="${CACHE_DIR}/client-data-${LATEST_TAG}.zip" +TMP_FILE="${CACHE_FILE}.tmp" +VERSION_FILE="${CACHE_DIR}/client-data-version.txt" # Check if we have a cached version if [ -f "$CACHE_FILE" ] && [ -f "$VERSION_FILE" ]; then @@ -36,7 +44,22 @@ if [ -f "$CACHE_FILE" ] && [ -f "$VERSION_FILE" ]; then echo "๐Ÿ“Š Cached file size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')" # Verify cache file integrity - if unzip -t "$CACHE_FILE" > /dev/null 2>&1; then + echo "๐Ÿ” Verifying cached file integrity..." + CACHE_INTEGRITY_OK=false + + if command -v 7z >/dev/null 2>&1; then + if 7z t "$CACHE_FILE" >/dev/null 2>&1; then + CACHE_INTEGRITY_OK=true + fi + fi + + if [ "$CACHE_INTEGRITY_OK" = "false" ]; then + if unzip -t "$CACHE_FILE" > /dev/null 2>&1; then + CACHE_INTEGRITY_OK=true + fi + fi + + if [ "$CACHE_INTEGRITY_OK" = "true" ]; then echo "โœ… Cache file integrity verified" echo "โšก Using cached download - skipping download phase" cp "$CACHE_FILE" data.zip @@ -47,140 +70,90 @@ if [ -f "$CACHE_FILE" ] && [ -f "$VERSION_FILE" ]; then else echo "๐Ÿ“ฆ Cache version ($CACHED_VERSION) differs from latest ($LATEST_TAG)" echo "๐Ÿ—‘๏ธ Removing old cache" - rm -f /cache/client-data-*.zip "$VERSION_FILE" + rm -f "${CACHE_DIR}"/client-data-*.zip "$VERSION_FILE" fi fi # Download if we don't have a valid cached file if [ ! -f "data.zip" ]; then - echo "๐Ÿ“ฅ Downloading client data (~15GB, may take 10-30 minutes)..." + echo "๐Ÿ“ฅ Downloading client data (~15GB)..." echo "๐Ÿ“ Source: $LATEST_URL" - # Download with clean progress indication - echo "๐Ÿ“ฅ Starting download..." - wget --progress=dot:giga -O "$CACHE_FILE.tmp" "$LATEST_URL" 2>&1 | sed 's/^/๐Ÿ“Š /' || { - echo 'โŒ wget failed, trying curl...' - curl -L --progress-bar -o "$CACHE_FILE.tmp" "$LATEST_URL" || { - echo 'โŒ All download methods failed' - rm -f "$CACHE_FILE.tmp" - exit 1 + if command -v aria2c >/dev/null 2>&1; then + aria2c --max-connection-per-server=8 --split=8 --min-split-size=10M \ + --summary-interval=5 --download-result=hide \ + --console-log-level=warn --show-console-readout=false \ + --dir "$CACHE_DIR" -o "$(basename "$TMP_FILE")" "$LATEST_URL" || { + echo 'โš ๏ธ aria2c failed, falling back to wget...' + wget --progress=dot:giga -O "$TMP_FILE" "$LATEST_URL" 2>&1 | sed 's/^/๐Ÿ“Š /' || { + echo 'โŒ wget failed, trying curl...' + curl -L --progress-bar -o "$TMP_FILE" "$LATEST_URL" || { + echo 'โŒ All download methods failed' + rm -f "$TMP_FILE" + exit 1 + } + } } - } + else + echo "๐Ÿ“ฅ Using wget (aria2c not available)..." + wget --progress=dot:giga -O "$TMP_FILE" "$LATEST_URL" 2>&1 | sed 's/^/๐Ÿ“Š /' || { + echo 'โŒ wget failed, trying curl...' + curl -L --progress-bar -o "$TMP_FILE" "$LATEST_URL" || { + echo 'โŒ All download methods failed' + rm -f "$TMP_FILE" + exit 1 + } + } + fi - # Verify download integrity - if unzip -t "$CACHE_FILE.tmp" > /dev/null 2>&1; then - mv "$CACHE_FILE.tmp" "$CACHE_FILE" + echo "๐Ÿ” Verifying download integrity..." + INTEGRITY_OK=false + + if command -v 7z >/dev/null 2>&1; then + if 7z t "$TMP_FILE" >/dev/null 2>&1; then + INTEGRITY_OK=true + fi + fi + + if [ "$INTEGRITY_OK" = "false" ]; then + if unzip -t "$TMP_FILE" > /dev/null 2>&1; then + INTEGRITY_OK=true + fi + fi + + if [ "$INTEGRITY_OK" = "true" ]; then + mv "$TMP_FILE" "$CACHE_FILE" echo "$LATEST_TAG" > "$VERSION_FILE" echo 'โœ… Download completed and verified' echo "๐Ÿ“Š File size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')" cp "$CACHE_FILE" data.zip else echo 'โŒ Downloaded file is corrupted' - rm -f "$CACHE_FILE.tmp" + rm -f "$TMP_FILE" exit 1 fi fi -echo '๐Ÿ“‚ Extracting client data (this may take 10-15 minutes)...' -echo 'โณ Please wait while extracting...' - -# Clear existing data if extraction failed previously +echo '๐Ÿ“‚ Extracting client data (this may take some minutes)...' rm -rf /azerothcore/data/maps /azerothcore/data/vmaps /azerothcore/data/mmaps /azerothcore/data/dbc -# Extract with detailed progress tracking -echo '๐Ÿ”„ Starting extraction with progress monitoring...' - -# Start extraction in background with overwrite -unzip -o -q data.zip -d /azerothcore/data/ & - -UNZIP_PID=$! -LAST_CHECK_TIME=0 - -# Monitor progress with directory size checks -while kill -0 "$UNZIP_PID" 2>/dev/null; do - CURRENT_TIME=$(date +%s) - if [ $((CURRENT_TIME - LAST_CHECK_TIME)) -ge 30 ]; then - LAST_CHECK_TIME=$CURRENT_TIME - - # Check what's been extracted so far - PROGRESS_MSG="๐Ÿ“Š Progress at $(date '+%H:%M:%S'):" - - if [ -d "/azerothcore/data/dbc" ] && [ -n "$(ls -A /azerothcore/data/dbc 2>/dev/null)" ]; then - DBC_SIZE=$(du -sh /azerothcore/data/dbc 2>/dev/null | cut -f1) - PROGRESS_MSG="$PROGRESS_MSG DBC($DBC_SIZE)" - fi - - if [ -d "/azerothcore/data/maps" ] && [ -n "$(ls -A /azerothcore/data/maps 2>/dev/null)" ]; then - MAPS_SIZE=$(du -sh /azerothcore/data/maps 2>/dev/null | cut -f1) - PROGRESS_MSG="$PROGRESS_MSG Maps($MAPS_SIZE)" - fi - - if [ -d "/azerothcore/data/vmaps" ] && [ -n "$(ls -A /azerothcore/data/vmaps 2>/dev/null)" ]; then - VMAPS_SIZE=$(du -sh /azerothcore/data/vmaps 2>/dev/null | cut -f1) - PROGRESS_MSG="$PROGRESS_MSG VMaps($VMAPS_SIZE)" - fi - - if [ -d "/azerothcore/data/mmaps" ] && [ -n "$(ls -A /azerothcore/data/mmaps 2>/dev/null)" ]; then - MMAPS_SIZE=$(du -sh /azerothcore/data/mmaps 2>/dev/null | cut -f1) - PROGRESS_MSG="$PROGRESS_MSG MMaps($MMAPS_SIZE)" - fi - - echo "$PROGRESS_MSG" - fi - sleep 5 -done - -wait "$UNZIP_PID" -UNZIP_EXIT_CODE=$? - -if [ $UNZIP_EXIT_CODE -ne 0 ]; then - echo 'โŒ Extraction failed' - rm -f data.zip - exit 1 +if command -v 7z >/dev/null 2>&1; then + 7z x -aoa -o/azerothcore/data/ data.zip >/dev/null 2>&1 +else + unzip -o -q data.zip -d /azerothcore/data/ fi -# Handle nested Data directory issue - move contents if extracted to Data subdirectory -if [ -d "/azerothcore/data/Data" ] && [ -n "$(ls -A /azerothcore/data/Data 2>/dev/null)" ]; then - echo '๐Ÿ”ง Fixing data directory structure (moving from Data/ subdirectory)...' - - # Move all contents from Data subdirectory to the root data directory - for item in /azerothcore/data/Data/*; do - if [ -e "$item" ]; then - mv "$item" /azerothcore/data/ 2>/dev/null || { - echo "โš ๏ธ Could not move $(basename "$item"), using copy instead..." - cp -r "$item" /azerothcore/data/ - rm -rf "$item" - } - fi - done - - # Remove empty Data directory - rmdir /azerothcore/data/Data 2>/dev/null || true - echo 'โœ… Data directory structure fixed' -fi - -# Clean up temporary extraction file (keep cached version) rm -f data.zip echo 'โœ… Client data extraction complete!' -echo '๐Ÿ“ Verifying extracted directories:' - -# Verify required directories exist and have content -ALL_GOOD=true for dir in maps vmaps mmaps dbc; do if [ -d "/azerothcore/data/$dir" ] && [ -n "$(ls -A /azerothcore/data/$dir 2>/dev/null)" ]; then DIR_SIZE=$(du -sh /azerothcore/data/$dir 2>/dev/null | cut -f1) echo "โœ… $dir directory: OK ($DIR_SIZE)" else echo "โŒ $dir directory: MISSING or EMPTY" - ALL_GOOD=false + exit 1 fi done -if [ "$ALL_GOOD" = "true" ]; then - echo '๐ŸŽ‰ Game data setup complete! AzerothCore worldserver can now start.' - echo "๐Ÿ’พ Cached version $LATEST_TAG for future use" -else - echo 'โŒ Some directories are missing or empty' - exit 1 -fi \ No newline at end of file +echo '๐ŸŽ‰ Game data setup complete! AzerothCore worldserver can now start.' diff --git a/scripts/manage-modules-sql.sh b/scripts/manage-modules-sql.sh old mode 100644 new mode 100755 index 0cfb5d7..859ff2e --- a/scripts/manage-modules-sql.sh +++ b/scripts/manage-modules-sql.sh @@ -1,4 +1,5 @@ #!/bin/bash +# ac-compose set -e # Function to execute SQL files for a module @@ -194,4 +195,4 @@ execute_module_sql_scripts() { if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" = "1" ] && [ -d "mod-black-market" ]; then execute_module_sql "mod-black-market" "Black Market" fi -} \ No newline at end of file +} diff --git a/scripts/manage-modules.sh b/scripts/manage-modules.sh old mode 100644 new mode 100755 index feabe3c..6065777 --- a/scripts/manage-modules.sh +++ b/scripts/manage-modules.sh @@ -1,10 +1,11 @@ #!/bin/bash +# ac-compose set -e echo 'Setting up git user' -git config --global user.name "$GIT_USERNAME" -git config --global user.email "$GIT_EMAIL" -git config --global url.https://$GIT_PAT@github.com/.insteadOf https://github.com/ +git config --global user.name "${GIT_USERNAME:-ac-compose}" +git config --global user.email "${GIT_EMAIL:-noreply@azerothcore.org}" +# PAT not needed for public repositories echo 'Initializing module management...' cd /modules @@ -538,18 +539,6 @@ if [ "$MODULE_LEVEL_GRANT" != "1" ]; then rm -f /azerothcore/env/dist/etc/levelGrant.conf* fi -if [ "$MODULE_ASSISTANT" != "1" ]; then - rm -f /azerothcore/env/dist/etc/mod_assistant.conf* -fi - -if [ "$MODULE_REAGENT_BANK" != "1" ]; then - rm -f /azerothcore/env/dist/etc/mod_reagent_bank.conf* -fi - -if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" != "1" ]; then - rm -f /azerothcore/env/dist/etc/mod_black_market.conf* -fi - # Install configuration files for enabled modules for module_dir in mod-*; do if [ -d "$module_dir" ]; then @@ -558,15 +547,21 @@ for module_dir in mod-*; do fi done -echo 'Configuration file management complete.' +# Load SQL runner if present +if [ -f "/scripts/manage-modules-sql.sh" ]; then + . /scripts/manage-modules-sql.sh +elif [ -f "/tmp/scripts/manage-modules-sql.sh" ]; then + . /tmp/scripts/manage-modules-sql.sh +else + echo "โš ๏ธ SQL helper not found, skipping module SQL execution" +fi -# Source the SQL module management functions -source /scripts/manage-modules-sql.sh - -echo 'Executing module SQL scripts...' -execute_module_sql_scripts - -echo 'SQL execution complete.' +# Execute SQLs for enabled modules (via helper) +if declare -f execute_module_sql_scripts >/dev/null 2>&1; then + echo 'Executing module SQL scripts...' + execute_module_sql_scripts + echo 'SQL execution complete.' +fi # Module state tracking and rebuild logic echo 'Checking for module changes that require rebuild...' @@ -576,7 +571,7 @@ CURRENT_STATE="" REBUILD_REQUIRED=0 # Create current module state hash -for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT; do +for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK MODULE_BLACK_MARKET_AUCTION_HOUSE; do eval "value=\$$module_var" CURRENT_STATE="$CURRENT_STATE$module_var=$value|" done @@ -598,9 +593,9 @@ fi # Save current state echo "$CURRENT_STATE" > "$MODULES_STATE_FILE" -# Check if any C++ modules are enabled (all current modules require compilation) +# Check if any C++ modules are enabled (modules requiring source compilation) +# NOTE: mod-playerbots uses pre-built images and doesn't require rebuild ENABLED_MODULES="" -[ "$MODULE_PLAYERBOTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-playerbots" [ "$MODULE_AOE_LOOT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-aoe-loot" [ "$MODULE_LEARN_SPELLS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-learn-spells" [ "$MODULE_FIREWORKS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-fireworks-on-level" @@ -619,7 +614,6 @@ ENABLED_MODULES="" [ "$MODULE_AUTO_REVIVE" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-auto-revive" [ "$MODULE_GAIN_HONOR_GUARD" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-gain-honor-guard" [ "$MODULE_ELUNA" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-eluna" -[ "$MODULE_ARAC" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-arac" [ "$MODULE_TIME_IS_TIME" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-time-is-time" [ "$MODULE_POCKET_PORTAL" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-pocket-portal" [ "$MODULE_RANDOM_ENCHANTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-random-enchants" @@ -629,9 +623,6 @@ ENABLED_MODULES="" [ "$MODULE_NPC_ENCHANTER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-npc-enchanter" [ "$MODULE_INSTANCE_RESET" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-instance-reset" [ "$MODULE_LEVEL_GRANT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-quest-count-level" -[ "$MODULE_ASSISTANT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-assistant" -[ "$MODULE_REAGENT_BANK" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-reagent-bank" -# Note: mod-black-market is Lua-based, doesn't need C++ compilation if [ -n "$ENABLED_MODULES" ]; then ENABLED_COUNT=$(echo $ENABLED_MODULES | wc -w) @@ -646,14 +637,10 @@ if [ -n "$ENABLED_MODULES" ]; then echo "Module configuration has changed. To integrate C++ modules into AzerothCore:" echo "" echo "1. Stop current services:" - echo " docker compose -f docker-compose-azerothcore-services.yml down" + echo " docker compose down" echo "" - echo "2. Build with source-based compilation:" - echo " docker compose -f /tmp/acore-dev-test/docker-compose.yml build" - echo " docker compose -f /tmp/acore-dev-test/docker-compose.yml up -d" - echo "" - echo "3. Or use the automated rebuild script (if available):" - echo " ./scripts/rebuild-with-modules.sh" + echo "2. Build with source-based compilation (external process)" + echo " ./scripts/rebuild-with-modules.sh (if available)" echo "" echo "๐Ÿ“‹ NOTE: Source-based build will compile AzerothCore with all enabled modules" echo "โฑ๏ธ Expected build time: 15-45 minutes depending on system performance" @@ -665,21 +652,14 @@ fi echo 'Module management complete.' -# Download rebuild script from GitHub for local access -echo '๐Ÿ“ฅ Downloading rebuild-with-modules.sh from GitHub...' -apk add --no-cache curl -if curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/rebuild-with-modules.sh -o /tmp/rebuild-with-modules.sh 2>/dev/null; then - echo 'โœ… Downloaded rebuild-with-modules.sh from GitHub' - chmod +x /tmp/rebuild-with-modules.sh - echo '๐Ÿ“ Script available at: /tmp/rebuild-with-modules.sh' -elif [ -f "/project/scripts/rebuild-with-modules.sh" ]; then - echo '๐Ÿ“ Using local rebuild-with-modules.sh for testing' - cp /project/scripts/rebuild-with-modules.sh /tmp/rebuild-with-modules.sh - chmod +x /tmp/rebuild-with-modules.sh - echo 'โœ… Copied to /tmp/rebuild-with-modules.sh' +REBUILD_SENTINEL="/modules/.requires_rebuild" +if [ "$REBUILD_REQUIRED" = "1" ] && [ -n "$ENABLED_MODULES" ]; then + echo "$ENABLED_MODULES" > "$REBUILD_SENTINEL" else - echo 'โš ๏ธ Warning: rebuild-with-modules.sh not found in GitHub or locally' + rm -f "$REBUILD_SENTINEL" 2>/dev/null || true fi -echo 'Keeping container alive...' -tail -f /dev/null \ No newline at end of file +# Optional: keep container alive for inspection in CI/debug contexts +if [ "${MODULES_DEBUG_KEEPALIVE:-0}" = "1" ]; then + tail -f /dev/null +fi diff --git a/scripts/rebuild-with-modules.sh b/scripts/rebuild-with-modules.sh index e61f830..ec8eb7a 100755 --- a/scripts/rebuild-with-modules.sh +++ b/scripts/rebuild-with-modules.sh @@ -1,128 +1,195 @@ #!/bin/bash -# AzerothCore Module Rebuild Script -# Automates the process of rebuilding AzerothCore with enabled modules +# ac-compose helper to rebuild AzerothCore from source with enabled modules. set -e -echo "๐Ÿ”ง AzerothCore Module Rebuild Script" -echo "===================================" -echo "" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" +ENV_FILE="$PROJECT_DIR/.env" -# Check if source repository exists -SOURCE_COMPOSE="/tmp/acore-dev-test/docker-compose.yml" +usage(){ + cat <&2; usage; exit 1;; + esac +done + +if ! command -v docker >/dev/null 2>&1; then + echo "โŒ Docker CLI not found in PATH." + exit 1 +fi + +STORAGE_PATH="$(read_env STORAGE_PATH "./storage")" +if [[ "$STORAGE_PATH" != /* ]]; then + STORAGE_PATH="$PROJECT_DIR/$STORAGE_PATH" +fi +MODULES_DIR="$STORAGE_PATH/modules" +SENTINEL_FILE="$MODULES_DIR/.requires_rebuild" + +REBUILD_SOURCE_PATH="$SOURCE_OVERRIDE" +if [ -z "$REBUILD_SOURCE_PATH" ]; then + REBUILD_SOURCE_PATH="$(read_env MODULES_REBUILD_SOURCE_PATH "")" +fi + +if [ -z "$REBUILD_SOURCE_PATH" ]; then + cat </dev/null || echo "$REBUILD_SOURCE_PATH")" +fi + +SOURCE_COMPOSE="$REBUILD_SOURCE_PATH/docker-compose.yml" if [ ! -f "$SOURCE_COMPOSE" ]; then - echo "โŒ Error: Source-based Docker Compose file not found at $SOURCE_COMPOSE" - echo "Please ensure AzerothCore source repository is available for compilation." - exit 1 + echo "โŒ Source docker-compose.yml not found at $SOURCE_COMPOSE" + exit 1 fi -# Check current module configuration -echo "๐Ÿ“‹ Checking current module configuration..." +declare -A MODULE_REPO_MAP=( + [MODULE_AOE_LOOT]=mod-aoe-loot + [MODULE_LEARN_SPELLS]=mod-learn-spells + [MODULE_FIREWORKS]=mod-fireworks-on-level + [MODULE_INDIVIDUAL_PROGRESSION]=mod-individual-progression + [MODULE_AHBOT]=mod-ahbot + [MODULE_AUTOBALANCE]=mod-autobalance + [MODULE_TRANSMOG]=mod-transmog + [MODULE_NPC_BUFFER]=mod-npc-buffer + [MODULE_DYNAMIC_XP]=mod-dynamic-xp + [MODULE_SOLO_LFG]=mod-solo-lfg + [MODULE_1V1_ARENA]=mod-1v1-arena + [MODULE_PHASED_DUELS]=mod-phased-duels + [MODULE_BREAKING_NEWS]=mod-breaking-news-override + [MODULE_BOSS_ANNOUNCER]=mod-boss-announcer + [MODULE_ACCOUNT_ACHIEVEMENTS]=mod-account-achievements + [MODULE_AUTO_REVIVE]=mod-auto-revive + [MODULE_GAIN_HONOR_GUARD]=mod-gain-honor-guard + [MODULE_ELUNA]=mod-eluna + [MODULE_TIME_IS_TIME]=mod-TimeIsTime + [MODULE_POCKET_PORTAL]=mod-pocket-portal + [MODULE_RANDOM_ENCHANTS]=mod-random-enchants + [MODULE_SOLOCRAFT]=mod-solocraft + [MODULE_PVP_TITLES]=mod-pvp-titles + [MODULE_NPC_BEASTMASTER]=mod-npc-beastmaster + [MODULE_NPC_ENCHANTER]=mod-npc-enchanter + [MODULE_INSTANCE_RESET]=mod-instance-reset + [MODULE_LEVEL_GRANT]=mod-quest-count-level +) -MODULES_ENABLED=0 -ENABLED_MODULES="" +compile_modules=() +for key in "${!MODULE_REPO_MAP[@]}"; do + if [ "$(read_env "$key" "0")" = "1" ]; then + compile_modules+=("${MODULE_REPO_MAP[$key]}") + fi +done -# Read environment file to check enabled modules -if [ -f "docker-compose-azerothcore-services.env" ]; then - while IFS= read -r line; do - if echo "$line" | grep -q "^MODULE_.*=1$"; then - MODULE_NAME=$(echo "$line" | cut -d'=' -f1) - MODULES_ENABLED=$((MODULES_ENABLED + 1)) - ENABLED_MODULES="$ENABLED_MODULES $MODULE_NAME" - fi - done < docker-compose-azerothcore-services.env +if [ ${#compile_modules[@]} -eq 0 ]; then + echo "โœ… No C++ modules enabled that require a source rebuild." + rm -f "$SENTINEL_FILE" 2>/dev/null || true + exit 0 +fi + +echo "๐Ÿ”ง Modules requiring compilation:" +for mod in "${compile_modules[@]}"; do + echo " โ€ข $mod" +done + +if [ ! -d "$MODULES_DIR" ]; then + echo "โš ๏ธ Modules directory not found at $MODULES_DIR" +fi + +if ! confirm "Proceed with source rebuild in $REBUILD_SOURCE_PATH? (15-45 minutes)" n; then + echo "โŒ Rebuild cancelled" + exit 1 +fi + +pushd "$REBUILD_SOURCE_PATH" >/dev/null + +if [ "$SKIP_STOP" != "1" ]; then + echo "๐Ÿ›‘ Stopping existing source services (if any)..." + docker compose down || true +fi + +if [ -d "$MODULES_DIR" ]; then + echo "๐Ÿ”„ Syncing enabled modules into source tree..." + mkdir -p modules + if command -v rsync >/dev/null 2>&1; then + rsync -a --delete "$MODULES_DIR"/ modules/ + else + rm -rf modules/* + cp -R "$MODULES_DIR"/. modules/ + fi else - echo "โš ๏ธ Warning: Environment file not found, checking default configuration..." + echo "โš ๏ธ No modules directory found at $MODULES_DIR; continuing without sync." fi -echo "๐Ÿ” Found $MODULES_ENABLED enabled modules" - -if [ $MODULES_ENABLED -eq 0 ]; then - echo "โœ… No modules enabled - rebuild not required" - echo "You can use pre-built containers for better performance." - exit 0 -fi - -echo "๐Ÿ“ฆ Enabled modules:$ENABLED_MODULES" -echo "" - -# Confirm rebuild -read -p "๐Ÿค” Proceed with rebuild? This will take 15-45 minutes. (y/N): " -n 1 -r -echo "" -if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo "โŒ Rebuild cancelled" - exit 0 -fi - -echo "" -echo "๐Ÿ›‘ Stopping current services..." -docker compose -f docker-compose-azerothcore-services.yml down || echo "โš ๏ธ Services may not be running" - -echo "" -echo "๐Ÿ”ง Starting source-based compilation..." -echo "โฑ๏ธ This will take 15-45 minutes depending on your system..." -echo "" - -# Build with source -cd /tmp/acore-dev-test -echo "๐Ÿ“ Switched to source directory: $(pwd)" - -# Copy modules to source build -echo "๐Ÿ“‹ Copying modules to source build..." -if [ -d "/home/upb/src/acore-compose2/storage/azerothcore/modules" ]; then - # Ensure modules directory exists in source - mkdir -p modules - - # Copy enabled modules only - echo "๐Ÿ”„ Syncing enabled modules..." - for module_dir in /home/upb/src/acore-compose2/storage/azerothcore/modules/*/; do - if [ -d "$module_dir" ]; then - module_name=$(basename "$module_dir") - echo " Copying $module_name..." - cp -r "$module_dir" modules/ - fi - done -else - echo "โš ๏ธ Warning: No modules directory found" -fi - -# Start build process -echo "" echo "๐Ÿš€ Building AzerothCore with modules..." docker compose build --no-cache -if [ $? -eq 0 ]; then - echo "" - echo "โœ… Build completed successfully!" - echo "" +echo "๐ŸŸข Starting source services..." +docker compose up -d - # Start services - echo "๐ŸŸข Starting services with compiled modules..." - docker compose up -d +popd >/dev/null - if [ $? -eq 0 ]; then - echo "" - echo "๐ŸŽ‰ SUCCESS! AzerothCore is now running with compiled modules." - echo "" - echo "๐Ÿ“Š Service status:" - docker compose ps - echo "" - echo "๐Ÿ“ To monitor logs:" - echo " docker compose logs -f" - echo "" - echo "๐ŸŒ Server should be available on configured ports once fully started." - else - echo "โŒ Failed to start services" - exit 1 - fi -else - echo "โŒ Build failed" - echo "" - echo "๐Ÿ” Check build logs for errors:" - echo " docker compose logs" - exit 1 -fi +rm -f "$SENTINEL_FILE" 2>/dev/null || true echo "" -echo "โœ… Rebuild process complete!" \ No newline at end of file +echo "๐ŸŽ‰ SUCCESS! AzerothCore source build completed with modules." diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..7329766 --- /dev/null +++ b/setup.sh @@ -0,0 +1,429 @@ +#!/bin/bash +set -e + +# ============================================== +# ac-compose - Interactive .env generator +# ============================================== +# Mirrors options from scripts/setup-server.sh but targets ac-compose/.env + +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; MAGENTA='\033[0;35m'; NC='\033[0m' +say(){ local t=$1; shift; case "$t" in + INFO) echo -e "${BLUE}โ„น๏ธ $*${NC}";; + SUCCESS) echo -e "${GREEN}โœ… $*${NC}";; + WARNING) echo -e "${YELLOW}โš ๏ธ $*${NC}";; + ERROR) echo -e "${RED}โŒ $*${NC}";; + HEADER) echo -e "\n${MAGENTA}=== $* ===${NC}";; +esac } + +validate_ip(){ [[ $1 =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; } +validate_port(){ [[ $1 =~ ^[0-9]+$ ]] && [ $1 -ge 1 ] && [ $1 -le 65535 ]; } +validate_number(){ [[ $1 =~ ^[0-9]+$ ]]; } + +ask(){ + local prompt="$1"; local def="$2"; local validator="$3"; local v + while true; do + if [ -n "$def" ]; then + read -p "$(echo -e "${YELLOW}๐Ÿ”ง ${prompt} [${def}]: ${NC}")" v; v=${v:-$def} + else + read -p "$(echo -e "${YELLOW}๐Ÿ”ง ${prompt}: ${NC}")" v + fi + if [ -z "$validator" ] || $validator "$v"; then echo "$v"; return 0; fi + say ERROR "Invalid input. Please try again." + done +} + +ask_yn(){ local p="$1"; local d="$2"; local v; while true; do + if [ "$d" = "y" ]; then read -p "$(echo -e "${YELLOW}๐Ÿ”ง ${p} [Y/n]: ${NC}")" v; v=${v:-y}; else read -p "$(echo -e "${YELLOW}๐Ÿ”ง ${p} [y/N]: ${NC}")" v; v=${v:-n}; fi + case "$v" in [Yy]*) echo 1; return 0;; [Nn]*) echo 0; return 0;; esac; say ERROR "Please answer y or n"; done; } + +main(){ + # Basic arg handling for help + if [[ $# -gt 0 ]]; then + case "$1" in + -h|--help) + cat <<'EOF' +Usage: ./setup.sh + +Description: + Interactive wizard that generates ac-compose/.env for the + profiles-based compose. Prompts for deployment type, ports, storage, + MySQL credentials, backup retention, and module presets or manual + toggles. + +Notes: + - The generated .env is read automatically by docker compose. + - Run deploy with: deploy-and-check.sh or docker compose --profile ... up -d +EOF + exit 0 + ;; + *) + echo "Unknown argument: $1" >&2 + echo "Use --help for usage" >&2 + exit 1 + ;; + esac + fi + say HEADER "AZEROTHCORE PROFILES SETUP (.env generator)" + say INFO "This will create ac-compose/.env for compose profiles." + + # Deployment type + say HEADER "DEPLOYMENT TYPE" + echo "1) Local Development (127.0.0.1, local storage)" + echo "2) LAN Server (local network IP)" + echo "3) Public Server (domain or public IP)" + local DEPLOYMENT_TYPE + while true; do + read -p "$(echo -e "${YELLOW}๐Ÿ”ง Select deployment type [1-3]: ${NC}")" x + case "$x" in + 1) DEPLOYMENT_TYPE=local; break;; + 2) DEPLOYMENT_TYPE=lan; break;; + 3) DEPLOYMENT_TYPE=public; break;; + *) say ERROR "Please select 1, 2, or 3";; + esac + done + + # Permission scheme + say HEADER "PERMISSION SCHEME" + echo "1) Local Dev (0:0)" + echo "2) NFS Server (1001:1000)" + echo "3) Custom" + local CONTAINER_USER + while true; do + read -p "$(echo -e "${YELLOW}๐Ÿ”ง Select permission scheme [1-3]: ${NC}")" x + case "$x" in + 1) CONTAINER_USER="0:0"; break;; + 2) CONTAINER_USER="1001:1000"; break;; + 3) local uid gid; uid=$(ask "Enter PUID (user id)" 1000 validate_number); gid=$(ask "Enter PGID (group id)" 1000 validate_number); CONTAINER_USER="${uid}:${gid}"; break;; + *) say ERROR "Please select 1, 2, or 3";; + esac + done + + # Server config + say HEADER "SERVER CONFIGURATION" + local SERVER_ADDRESS + if [ "$DEPLOYMENT_TYPE" = "local" ]; then + SERVER_ADDRESS=127.0.0.1 + elif [ "$DEPLOYMENT_TYPE" = "lan" ]; then + local LAN_IP; LAN_IP=$(ip route get 1.1.1.1 2>/dev/null | awk 'NR==1{print $7}') + SERVER_ADDRESS=$(ask "Enter server IP address" "${LAN_IP:-192.168.1.100}" validate_ip) + else + SERVER_ADDRESS=$(ask "Enter server address (IP or domain)" "your-domain.com" ) + fi + + local REALM_PORT AUTH_EXTERNAL_PORT SOAP_EXTERNAL_PORT MYSQL_EXTERNAL_PORT + REALM_PORT=$(ask "Enter client connection port" 8215 validate_port) + AUTH_EXTERNAL_PORT=$(ask "Enter auth server port" 3784 validate_port) + SOAP_EXTERNAL_PORT=$(ask "Enter SOAP API port" 7778 validate_port) + MYSQL_EXTERNAL_PORT=$(ask "Enter MySQL external port" 64306 validate_port) + + # DB config + say HEADER "DATABASE CONFIGURATION" + local MYSQL_ROOT_PASSWORD; MYSQL_ROOT_PASSWORD=$(ask "Enter MySQL root password" "azerothcore123") + + # Storage + say HEADER "STORAGE CONFIGURATION" + local STORAGE_PATH + if [ "$DEPLOYMENT_TYPE" = "local" ]; then + STORAGE_PATH=./storage + else + echo "1) ./storage (local)" + echo "2) /nfs/azerothcore (NFS)" + echo "3) Custom" + while true; do + read -p "$(echo -e "${YELLOW}๐Ÿ”ง Select storage option [1-3]: ${NC}")" s + case "$s" in + 1) STORAGE_PATH=./storage; break;; + 2) STORAGE_PATH=/nfs/azerothcore; break;; + 3) STORAGE_PATH=$(ask "Enter custom storage path" "/mnt/azerothcore-data"); break;; + *) say ERROR "Please select 1, 2, or 3";; + esac + done + fi + + # Backup + say HEADER "BACKUP CONFIGURATION" + local BACKUP_RETENTION_DAYS BACKUP_RETENTION_HOURS BACKUP_DAILY_TIME + BACKUP_RETENTION_DAYS=$(ask "Daily backups retention (days)" 3 validate_number) + BACKUP_RETENTION_HOURS=$(ask "Hourly backups retention (hours)" 6 validate_number) + BACKUP_DAILY_TIME=$(ask "Daily backup hour (00-23, UTC)" 09 validate_number) + + # Module config + say HEADER "MODULE PRESET" + echo "1) Suggested Modules" + echo "2) Playerbots + Suggested modules" + echo "3) Manual selection" + echo "4) No modules" + local MODE; while true; do + read -p "$(echo -e "${YELLOW}๐Ÿ”ง Select module configuration [1-4]: ${NC}")" MODE + case "$MODE" in 1|2|3|4) break;; *) say ERROR "Please select 1, 2, 3, or 4";; esac + done + + # Initialize toggles + local MODULE_PLAYERBOTS=0 MODULE_AOE_LOOT=0 MODULE_LEARN_SPELLS=0 MODULE_FIREWORKS=0 MODULE_INDIVIDUAL_PROGRESSION=0 \ + MODULE_AHBOT=0 MODULE_AUTOBALANCE=0 MODULE_TRANSMOG=0 MODULE_NPC_BUFFER=0 MODULE_DYNAMIC_XP=0 MODULE_SOLO_LFG=0 \ + MODULE_1V1_ARENA=0 MODULE_PHASED_DUELS=0 MODULE_BREAKING_NEWS=0 MODULE_BOSS_ANNOUNCER=0 MODULE_ACCOUNT_ACHIEVEMENTS=0 \ + MODULE_AUTO_REVIVE=0 MODULE_GAIN_HONOR_GUARD=0 MODULE_ELUNA=1 MODULE_TIME_IS_TIME=0 MODULE_POCKET_PORTAL=0 \ + MODULE_RANDOM_ENCHANTS=0 MODULE_SOLOCRAFT=0 MODULE_PVP_TITLES=0 MODULE_NPC_BEASTMASTER=0 MODULE_NPC_ENCHANTER=0 \ + MODULE_INSTANCE_RESET=0 MODULE_LEVEL_GRANT=0 MODULE_ASSISTANT=0 MODULE_REAGENT_BANK=0 MODULE_BLACK_MARKET_AUCTION_HOUSE=0 MODULE_ARAC=0 + + local PLAYERBOT_ENABLED=0 PLAYERBOT_MAX_BOTS=40 + + local AUTO_REBUILD_ON_DEPLOY=0 + local MODULES_REBUILD_SOURCE_PATH_VALUE="" + local RUN_REBUILD_NOW=0 + local NEEDS_CXX_REBUILD=0 + + if [ "$MODE" = "1" ]; then + MODULE_SOLO_LFG=1; MODULE_SOLOCRAFT=1; MODULE_AUTOBALANCE=1; MODULE_AHBOT=1; MODULE_TRANSMOG=1; MODULE_NPC_BUFFER=1; MODULE_LEARN_SPELLS=1; MODULE_FIREWORKS=1 + elif [ "$MODE" = "2" ]; then + MODULE_PLAYERBOTS=1; MODULE_SOLO_LFG=1; MODULE_SOLOCRAFT=1; MODULE_AUTOBALANCE=1; MODULE_AHBOT=1; MODULE_TRANSMOG=1; MODULE_NPC_BUFFER=1; MODULE_LEARN_SPELLS=1; MODULE_FIREWORKS=1 + elif [ "$MODE" = "3" ]; then + say INFO "Answer y/n for each module" + # Core Gameplay + MODULE_PLAYERBOTS=$(ask_yn "Playerbots - AI companions" n) + MODULE_SOLO_LFG=$(ask_yn "Solo LFG - Solo dungeon finder" n) + MODULE_SOLOCRAFT=$(ask_yn "Solocraft - Scale dungeons/raids for solo" n) + MODULE_AUTOBALANCE=$(ask_yn "Autobalance - Dynamic difficulty" n) + # QoL + MODULE_TRANSMOG=$(ask_yn "Transmog - Appearance changes" n) + MODULE_NPC_BUFFER=$(ask_yn "NPC Buffer - Buff NPCs" n) + MODULE_LEARN_SPELLS=$(ask_yn "Learn Spells - Auto-learn" n) + MODULE_AOE_LOOT=$(ask_yn "AOE Loot - Multi-corpse loot" n) + MODULE_FIREWORKS=$(ask_yn "Fireworks - Level-up FX" n) + MODULE_ASSISTANT=$(ask_yn "Assistant - Multi-service NPC" n) + # Economy + MODULE_AHBOT=$(ask_yn "AH Bot - Auction automation" n) + MODULE_REAGENT_BANK=$(ask_yn "Reagent Bank - Materials storage" n) + MODULE_BLACK_MARKET_AUCTION_HOUSE=$(ask_yn "Black Market - MoP-style" n) + # PvP + MODULE_1V1_ARENA=$(ask_yn "1v1 Arena" n) + MODULE_PHASED_DUELS=$(ask_yn "Phased Duels" n) + MODULE_PVP_TITLES=$(ask_yn "PvP Titles" n) + # Progression + MODULE_INDIVIDUAL_PROGRESSION=$(ask_yn "Individual Progression (Vanillaโ†’TBCโ†’WotLK)" n) + MODULE_DYNAMIC_XP=$(ask_yn "Dynamic XP" n) + MODULE_LEVEL_GRANT=$(ask_yn "Level Grant" n) + MODULE_ACCOUNT_ACHIEVEMENTS=$(ask_yn "Account Achievements" n) + # Server Features + MODULE_BREAKING_NEWS=$(ask_yn "Breaking News" n) + MODULE_BOSS_ANNOUNCER=$(ask_yn "Boss Announcer" n) + MODULE_AUTO_REVIVE=$(ask_yn "Auto Revive" n) + # Utility + MODULE_NPC_BEASTMASTER=$(ask_yn "NPC Beastmaster" n) + MODULE_NPC_ENCHANTER=$(ask_yn "NPC Enchanter" n) + MODULE_RANDOM_ENCHANTS=$(ask_yn "Random Enchants" n) + MODULE_POCKET_PORTAL=$(ask_yn "Pocket Portal" n) + MODULE_INSTANCE_RESET=$(ask_yn "Instance Reset" n) + MODULE_TIME_IS_TIME=$(ask_yn "Time is Time" n) + MODULE_GAIN_HONOR_GUARD=$(ask_yn "Gain Honor Guard" n) + MODULE_ARAC=$(ask_yn "All Races All Classes (requires client patch)" n) + fi + + for mod_var in MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK MODULE_BLACK_MARKET_AUCTION_HOUSE; do + eval "value=\$$mod_var" + if [ "$value" = "1" ]; then + NEEDS_CXX_REBUILD=1 + break + fi + done + + # Summary + say HEADER "SUMMARY" + printf " %-18s %s\n" "Server Address:" "$SERVER_ADDRESS" + printf " %-18s Realm:%s Auth:%s SOAP:%s MySQL:%s\n" "Ports:" "$REALM_PORT" "$AUTH_EXTERNAL_PORT" "$SOAP_EXTERNAL_PORT" "$MYSQL_EXTERNAL_PORT" + printf " %-18s %s\n" "Storage Path:" "$STORAGE_PATH" + printf " %-18s %s\n" "Container User:" "$CONTAINER_USER" + printf " %-18s Daily %s:00 UTC, keep %sd/%sh\n" "Backups:" "$BACKUP_DAILY_TIME" "$BACKUP_RETENTION_DAYS" "$BACKUP_RETENTION_HOURS" + printf " %-18s preset %s (playerbots=%s solo_lfg=%s autobalance=%s transmog=%s ahbot=%s npc_buffer=%s learn_spells=%s fireworks=%s)\n" \ + "Modules:" "$MODE" "$MODULE_PLAYERBOTS" "$MODULE_SOLO_LFG" "$MODULE_AUTOBALANCE" "$MODULE_TRANSMOG" "$MODULE_AHBOT" "$MODULE_NPC_BUFFER" "$MODULE_LEARN_SPELLS" "$MODULE_FIREWORKS" + printf " %-18s enabled by default (edit .env to disable)\n" "Eluna:" + if [ "$NEEDS_CXX_REBUILD" = "1" ]; then + printf " %-18s detected (source rebuild required)\n" "C++ modules:" + fi + + if [ "$NEEDS_CXX_REBUILD" = "1" ]; then + echo "" + say WARNING "These modules require compiling AzerothCore from source." + RUN_REBUILD_NOW=$(ask_yn "Run module rebuild immediately?" n) + AUTO_REBUILD_ON_DEPLOY=$(ask_yn "Enable automatic rebuild during future deploys?" n) + if [ "$RUN_REBUILD_NOW" = "1" ] || [ "$AUTO_REBUILD_ON_DEPLOY" = "1" ]; then + if [ -z "$MODULES_REBUILD_SOURCE_PATH_VALUE" ]; then + read -p "$(echo -e "${YELLOW}๐Ÿ”ง Path to AzerothCore source compose (optional): ${NC}")" MODULES_REBUILD_SOURCE_PATH_VALUE + fi + if [ -z "$MODULES_REBUILD_SOURCE_PATH_VALUE" ]; then + say WARNING "No source path provided; skipping rebuild automation." + RUN_REBUILD_NOW=0 + AUTO_REBUILD_ON_DEPLOY=0 + fi + fi + fi + + # Confirm write + local ENV_OUT="$(dirname "$0")/.env" + if [ -f "$ENV_OUT" ]; then + say WARNING ".env already exists at $(realpath "$ENV_OUT" 2>/dev/null || echo "$ENV_OUT"). It will be overwritten." + local cont; cont=$(ask_yn "Continue and overwrite?" n); [ "$cont" = "1" ] || { say ERROR "Aborted"; exit 1; } + fi + + cat > "$ENV_OUT" <&2; exit 1;; + esac +done + +command -v docker >/dev/null 2>&1 || { echo "Docker CLI not found" >&2; exit 1; } +docker info >/dev/null 2>&1 || { echo "Docker daemon unavailable" >&2; exit 1; } + +read_env(){ + local key="$1" default="$2" value + if [ -f "$ENV_FILE" ]; then + value="$(grep -E "^${key}=" "$ENV_FILE" 2>/dev/null | tail -n1 | cut -d'=' -f2- | tr -d '\r')" + fi + if [ -z "$value" ]; then + value="$default" + fi + echo "$value" +} + +PROJECT_NAME="$(read_env COMPOSE_PROJECT_NAME ac-compose)" +NETWORK_NAME="$(read_env NETWORK_NAME azerothcore)" +AUTH_PORT="$(read_env AUTH_EXTERNAL_PORT 3784)" +WORLD_PORT="$(read_env WORLD_EXTERNAL_PORT 8215)" +SOAP_PORT="$(read_env SOAP_EXTERNAL_PORT 7778)" +MYSQL_PORT="$(read_env MYSQL_EXTERNAL_PORT 64306)" +PMA_PORT="$(read_env PMA_EXTERNAL_PORT 8081)" +KEIRA_PORT="$(read_env KEIRA3_EXTERNAL_PORT 4201)" +ELUNA_ENABLED="$(read_env AC_ELUNA_ENABLED 1)" + +container_exists(){ + docker ps -a --format '{{.Names}}' | grep -qx "$1" +} + +container_running(){ + docker ps --format '{{.Names}}' | grep -qx "$1" +} + +format_state(){ + local status="$1" health="$2" started="$3" exit_code="$4" + case "$status" in + running) + local desc="running" colour="$GREEN" + if [ "$health" = "healthy" ]; then + desc="healthy" + elif [ "$health" = "none" ]; then + desc="running" + else + desc="$health"; colour="$YELLOW" + [ "$health" = "unhealthy" ] && colour="$RED" + fi + echo -e "${colour}โ—${NC} ${desc} (since ${started%:*})" + ;; + exited) + local colour="$YELLOW" + [ "$exit_code" != "0" ] && colour="$RED" + echo -e "${colour}โ—‹${NC} completed" + ;; + restarting) + echo -e "${YELLOW}โ—${NC} restarting" + ;; + created) + echo -e "${CYAN}โ—‹${NC} created" + ;; + *) + echo -e "${RED}โ—‹${NC} $status" + ;; + esac +} + +short_image(){ + local img="$1" + if [[ "$img" != */* ]]; then + echo "$img" + return + fi + local repo="${img%%/*}" + local rest="${img#*/}" + local name="${rest%%:*}" + local tag="${img##*:}" + local has_tag="true" + [[ "$img" != *":"* ]] && has_tag="false" + local last="${name##*/}" + if [ "$has_tag" = "true" ]; then + if [[ "$tag" =~ ^[0-9] ]] || [ "$tag" = "latest" ]; then + echo "$repo/$last" + else + echo "$repo/$tag" + fi + else + echo "$repo/$last" + fi +} + +print_service(){ + local container="$1" label="$2" + if container_exists "$container"; then + local status health started exit_code image + status="$(docker inspect --format='{{.State.Status}}' "$container" 2>/dev/null || echo "unknown")" + health="$(docker inspect --format='{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$container" 2>/dev/null || echo "none")" + started="$(docker inspect --format='{{.State.StartedAt}}' "$container" 2>/dev/null | cut -c12-19 2>/dev/null || echo "--:--:--")" + exit_code="$(docker inspect --format='{{.State.ExitCode}}' "$container" 2>/dev/null || echo "?")" + image="$(docker inspect --format='{{.Config.Image}}' "$container" 2>/dev/null || echo "-")" + printf "%-20s %-28s %s\n" "$label" "$(format_state "$status" "$health" "$started" "$exit_code")" "$(short_image "$image")" + if [ "$SHOW_LOGS" = true ]; then + docker logs "$container" --tail "$LOG_LINES" 2>/dev/null | sed 's/^/ /' || printf " (no logs available)\n" + fi + else + printf "%-20s ${RED}โ—‹${NC} missing -\n" "$label" + fi +} + +module_summary(){ + if [ ! -f "$ENV_FILE" ]; then + echo "MODULES: (env not found)" + return + fi + local module_vars + module_vars="$(grep -E '^MODULE_[A-Z_]+=1' "$ENV_FILE" 2>/dev/null | cut -d'=' -f1)" + if [ -n "$module_vars" ]; then + local arr=() + while IFS= read -r mod; do + [ -z "$mod" ] && continue + local pretty="${mod#MODULE_}" + pretty="$(echo "$pretty" | tr '[:upper:]' '[:lower:]' | tr '_' ' ')" + arr+=("$pretty") + done <<< "$module_vars" + local joined="" + for item in "${arr[@]}"; do + joined+="$item, " + done + joined="${joined%, }" + echo "MODULES: $joined" + else + echo "MODULES: none" + fi + + if container_running "ac-worldserver"; then + local ws_image="$(docker inspect --format='{{.Config.Image}}' ac-worldserver 2>/dev/null || echo "")" + local playerbot="disabled" + [[ "$ws_image" == *playerbots* ]] && playerbot="running" + local eluna="disabled" + [ "$ELUNA_ENABLED" = "1" ] && eluna="running" + echo "RUNTIME: playerbots $playerbot | eluna $eluna" + fi +} + +ports_summary(){ + local names=("Auth" "World" "SOAP" "MySQL" "phpMyAdmin" "Keira3") + local ports=("$AUTH_PORT" "$WORLD_PORT" "$SOAP_PORT" "$MYSQL_PORT" "$PMA_PORT" "$KEIRA_PORT") + printf "PORTS:\n" + for i in "${!names[@]}"; do + local svc="${names[$i]}" + local port="${ports[$i]}" + if timeout 1 bash -c "/dev/null 2>&1; then + printf " %-10s %-6s %bโ—%b reachable\n" "$svc" "$port" "$GREEN" "$NC" + else + printf " %-10s %-6s %bโ—‹%b unreachable\n" "$svc" "$port" "$RED" "$NC" + fi + done +} + +network_summary(){ + if docker network ls --format '{{.Name}}' | grep -qx "$NETWORK_NAME"; then + echo "DOCKER NET: $NETWORK_NAME" + else + echo "DOCKER NET: missing ($NETWORK_NAME)" + fi +} + +print_status(){ + clear 2>/dev/null || printf '\033[2J\033[H' + printf "TIME %s PROJECT %s\n\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$PROJECT_NAME" + printf "%-20s %-28s %s\n" "SERVICE" "STATE" "IMAGE" + printf "%-20s %-28s %s\n" "--------------------" "----------------------------" "------------------------------" + print_service ac-mysql "MySQL" + print_service ac-backup "Backup" + print_service ac-db-init "DB Init" + print_service ac-db-import "DB Import" + print_service ac-authserver "Auth Server" + print_service ac-worldserver "World Server" + print_service ac-client-data "Client Data" + print_service ac-modules "Module Manager" + print_service ac-post-install "Post Install" + print_service ac-phpmyadmin "phpMyAdmin" + print_service ac-keira3 "Keira3" + echo "" + module_summary + echo "" + echo "$(ports_summary)" + echo "$(network_summary)" +} + +if [ "$WATCH_MODE" = true ]; then + while true; do + print_status + sleep 3 + done +else + print_status +fi diff --git a/todo.md b/todo.md deleted file mode 100644 index 1aecc82..0000000 --- a/todo.md +++ /dev/null @@ -1,129 +0,0 @@ -# AzerothCore Deployment Issues - Todo List - -## Deployment Summary & Status - -### โœ… **Completed:** -- [x] Find and execute wizard deployment script -- [x] Configure deployment for 13 module version (suggested preset: 8 modules) -- [x] Monitor deployment process for warnings/errors -- [x] Report any issues found for bug fixing - -### โœ… **Critical Issues RESOLVED:** - -#### 1. **Database Schema Missing** โœ… **FIXED** -- **Issue**: `[1146] Table 'acore_world.charsections_dbc' doesn't exist` -- **Resolution**: - - [x] Added missing `emotetextsound_dbc.sql` to source project - - [x] Imported all DBC tables to database (111 tables) - - [x] Worldserver now starts successfully - - [x] Created fix in playerbot source repository - -#### 2. **Container Image Compatibility Issues** โœ… **FIXED** -- **Issue**: Multiple containers failing with exit code 127 -- **Resolution**: - - [x] Fixed client-data container with multi-OS package manager detection - - [x] Client data now downloads successfully (15GB) - - [x] Modules container working correctly - - [x] Created backward-compatible Alpine/Ubuntu scripts - -#### 3. **Environment Variable Configuration** โœ… **FIXED** -- **Issue**: Multiple undefined variables in modules deployment -- **Resolution**: - - [x] Wizard generates proper custom environment files - - [x] All 8 suggested modules configured correctly - - [x] Variable substitution working properly - -#### 4. **Network/Script Download Failures** โœ… **FIXED** -- **Issue**: Module management scripts failing to download -- **Resolution**: - - [x] Network connectivity working - - [x] Scripts download successfully - - [x] Multi-OS compatibility implemented - -### โš ๏ธ **Remaining Issues:** - -#### 5. **Backup Container Restart Loop** (ACTIVE) -- **Issue**: `ac-backup` container restarting with exit code 127 -- **Status**: Under investigation -- **Action**: - - [ ] Check backup container logs - - [ ] Verify backup script compatibility - - [ ] Fix container startup issues - -### ๐Ÿ“‹ **Next Steps:** -1. **Immediate**: Check `ac-db-import` container completion status -2. **Priority**: Fix database schema issues to enable worldserver startup -3. **Follow-up**: Address container image compatibility for full deployment -4. **Testing**: Verify all services start and communicate properly - -### ๐Ÿ› ๏ธ **Commands Used:** -```bash -# Wizard execution -echo -e "1\n8215\n3784\n7778\n64306\nazerothcore123\n3\n6\n09\nUTC\n1\ny" | ./scripts/setup-server.sh - -# Database deployment -docker compose --env-file docker-compose-azerothcore-database-custom.env -f docker-compose-azerothcore-database.yml up -d - -# Services deployment -docker compose --env-file docker-compose-azerothcore-services-custom.env -f docker-compose-azerothcore-services.yml up -d - -# Modules deployment -docker compose --env-file docker-compose-azerothcore-modules-custom.env -f docker-compose-azerothcore-modules.yml up -d -``` - -### ๐Ÿ” **Diagnostic Commands:** -```bash -# Check container status -docker ps -a - -# Check specific logs -docker logs ac-worldserver -docker logs ac-db-import -docker logs ac-client-data -docker logs ac-modules - -# Check database connectivity -docker exec ac-mysql mysql -u root -p -e "SHOW DATABASES;" -``` - -## ๐Ÿ” **Root Cause Analysis Found:** - -### **Database Schema Version Mismatch** -- Database has 298 tables imported successfully -- Missing specific table: `charsections_dbc` (and possibly other DBC tables) -- Playerbot database schema appears incomplete or outdated -- Worldserver expects newer/different schema than what was imported - -### **Container Image Issues Identified** -1. **client-data container**: Ubuntu-based but script tries to use Alpine `apk` package manager -2. **modules container**: curl download failures - network/permission issues -3. **Base images**: uprightbass360 images use Ubuntu 22.04 base, scripts expect Alpine - -### **Immediate Fixes Needed** -- [ ] Update database schema to include missing DBC tables -- [ ] Fix client-data container to use `apt` instead of `apk` -- [ ] Resolve module script download issues -- [ ] Verify schema compatibility between playerbot build and database - -## ๐Ÿ†• **UPDATES - Issues Resolved:** - -### โœ… **Major Fixes Completed:** -1. **Database Schema Issues** โœ… **RESOLVED** - - Added missing `emotetextsound_dbc.sql` to source project - - Imported all DBC tables - worldserver now starts successfully - - Worldserver status: `Up (healthy)` with Eluna scripts loaded - -2. **Container Script Compatibility** โœ… **RESOLVED** - - Fixed client-data container with multi-OS package manager detection - - Client data downloads working (15GB extracted successfully) - - Updated docker-compose with Alpine/Ubuntu compatibility - -3. **Source Project Improvements** โœ… **COMPLETED** - - Updated cleanup script for current deployment structure - - Ready to push fixes back to azerothcore-wotlk-playerbots repository - -### โš ๏ธ **Active Issue Identified:** -- **Backup Container**: `ac-backup` in restart loop with exit code 127 - **INVESTIGATING** - ---- -**Status**: **MAJOR SUCCESS** โœ… - Core server functional, investigating remaining backup issue. \ No newline at end of file