mirror of
https://github.com/uprightbass360/AzerothCore-RealmMaster.git
synced 2026-01-13 00:58:34 +00:00
refactoring and adding automations
This commit is contained in:
128
.env
Normal file
128
.env
Normal file
@@ -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
|
||||||
168
.env.template
Normal file
168
.env.template
Normal file
@@ -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
|
||||||
6
V1/.gitignore
vendored
Normal file
6
V1/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
data/
|
||||||
|
backups/
|
||||||
|
local-data-tools/
|
||||||
|
storage/
|
||||||
|
.claude/
|
||||||
|
*custom.env
|
||||||
@@ -719,8 +719,8 @@ services:
|
|||||||
REBUILD_REQUIRED=0
|
REBUILD_REQUIRED=0
|
||||||
|
|
||||||
# Create current module state hash
|
# 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}"
|
eval "value=\$$$module_var"
|
||||||
CURRENT_STATE="$${CURRENT_STATE}$${module_var}=$${value}|"
|
CURRENT_STATE="$${CURRENT_STATE}$${module_var}=$${value}|"
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -809,6 +809,165 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- azerothcore
|
- 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:
|
networks:
|
||||||
azerothcore:
|
azerothcore:
|
||||||
external: true
|
external: true
|
||||||
@@ -24,15 +24,15 @@ services:
|
|||||||
# Auto-detect package manager and install dependencies (as root)
|
# Auto-detect package manager and install dependencies (as root)
|
||||||
if command -v apk >/dev/null 2>&1; then
|
if command -v apk >/dev/null 2>&1; then
|
||||||
# Alpine Linux - install full wget and bash for script compatibility
|
# 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
|
elif command -v apt-get >/dev/null 2>&1; then
|
||||||
# Ubuntu/Debian
|
# 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
|
elif command -v yum >/dev/null 2>&1; then
|
||||||
# CentOS/RHEL
|
# 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
|
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
184
V1/scripts/auto-post-install.sh
Executable file
184
V1/scripts/auto-post-install.sh
Executable file
@@ -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
|
||||||
57
V1/scripts/backup-scheduler.sh
Normal file
57
V1/scripts/backup-scheduler.sh
Normal file
@@ -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
|
||||||
331
V1/scripts/db-import-conditional.sh
Executable file
331
V1/scripts/db-import-conditional.sh
Executable file
@@ -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 <<EOF
|
||||||
|
LoginDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
|
||||||
|
WorldDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_WORLD_NAME}"
|
||||||
|
CharacterDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
|
||||||
|
Updates.EnableDatabases = 7
|
||||||
|
Updates.AutoSetup = 1
|
||||||
|
|
||||||
|
# Required configuration properties
|
||||||
|
MySQLExecutable = ""
|
||||||
|
TempDir = ""
|
||||||
|
SourceDirectory = ""
|
||||||
|
Updates.AllowedModules = "all"
|
||||||
|
LoginDatabase.WorkerThreads = 1
|
||||||
|
LoginDatabase.SynchThreads = 1
|
||||||
|
WorldDatabase.WorkerThreads = 1
|
||||||
|
WorldDatabase.SynchThreads = 1
|
||||||
|
CharacterDatabase.WorkerThreads = 1
|
||||||
|
CharacterDatabase.SynchThreads = 1
|
||||||
|
Updates.Redundancy = 1
|
||||||
|
Updates.AllowRehash = 1
|
||||||
|
Updates.ArchivedRedundancy = 0
|
||||||
|
Updates.CleanDeadRefMaxCount = 3
|
||||||
|
|
||||||
|
# Logging configuration
|
||||||
|
Appender.Console=1,3,6
|
||||||
|
Logger.root=3,Console
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "🚀 Running database import..."
|
||||||
|
cd /azerothcore/env/dist/bin
|
||||||
|
|
||||||
|
# Run dbimport with error handling
|
||||||
|
if ./dbimport; then
|
||||||
|
echo "✅ Database import completed successfully!"
|
||||||
|
|
||||||
|
# Create import completion marker
|
||||||
|
if touch "$RESTORE_STATUS_DIR/.import-completed" 2>/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!"
|
||||||
@@ -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"
|
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
|
# 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..."
|
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 worldserver to be healthy
|
||||||
wait_for_service "World Server" 24 "check_container_health ac-worldserver"
|
wait_for_service "World Server" 24 "check_container_health ac-worldserver"
|
||||||
@@ -349,6 +349,14 @@ deploy_stack() {
|
|||||||
# Deploy modules if enabled
|
# Deploy modules if enabled
|
||||||
if [ "$MODULES_ENABLED" = true ]; then
|
if [ "$MODULES_ENABLED" = true ]; then
|
||||||
print_status "INFO" "Step 3: Deploying modules layer..."
|
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"
|
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
|
# Wait for modules to be ready
|
||||||
249
V1/scripts/download-client-data.sh
Normal file
249
V1/scripts/download-client-data.sh
Normal file
@@ -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
|
||||||
197
V1/scripts/manage-modules-sql.sh
Normal file
197
V1/scripts/manage-modules-sql.sh
Normal file
@@ -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
|
||||||
|
}
|
||||||
685
V1/scripts/manage-modules.sh
Normal file
685
V1/scripts/manage-modules.sh
Normal file
@@ -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
|
||||||
128
V1/scripts/rebuild-with-modules.sh
Executable file
128
V1/scripts/rebuild-with-modules.sh
Executable file
@@ -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!"
|
||||||
178
V1/todo.md
Normal file
178
V1/todo.md
Normal file
@@ -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.
|
||||||
202
cleanup.sh
Executable file
202
cleanup.sh
Executable file
@@ -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 <<EOF
|
||||||
|
ac-compose Cleanup
|
||||||
|
|
||||||
|
Usage: $0 [CLEANUP_LEVEL] [OPTIONS]
|
||||||
|
|
||||||
|
CLEANUP LEVELS:
|
||||||
|
--soft Stop project containers (preserves data)
|
||||||
|
--hard Remove containers + networks (preserves volumes/images)
|
||||||
|
--nuclear Complete removal: containers, networks, volumes, images (DESTROYS DATA)
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
--dry-run Show actions without executing
|
||||||
|
--force Skip confirmation prompts
|
||||||
|
--preserve-backups Keep backups when nuking storage (moves them aside and restores)
|
||||||
|
-h, --help Show this help
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
# Flags
|
||||||
|
CLEANUP_LEVEL=""
|
||||||
|
DRY_RUN=false
|
||||||
|
FORCE=false
|
||||||
|
PRESERVE_BACKUPS=false
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--soft|--hard|--nuclear) CLEANUP_LEVEL="${1#--}"; shift;;
|
||||||
|
--dry-run) DRY_RUN=true; shift;;
|
||||||
|
--force) FORCE=true; shift;;
|
||||||
|
--preserve-backups) PRESERVE_BACKUPS=true; shift;;
|
||||||
|
-h|--help) usage; exit 0;;
|
||||||
|
*) echo "Unknown arg: $1"; usage; exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
execute_command() {
|
||||||
|
local description="$1"; shift
|
||||||
|
local cmd="$*"
|
||||||
|
if $DRY_RUN; then
|
||||||
|
print_status INFO "[DRY RUN] $description"
|
||||||
|
echo " $cmd"
|
||||||
|
else
|
||||||
|
print_status INFO "$description"
|
||||||
|
eval "$cmd" || print_status WARNING "Command failed or no action needed"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm() {
|
||||||
|
local msg="$1"
|
||||||
|
if $FORCE; then
|
||||||
|
print_status INFO "Force enabled; skipping confirmation"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo -e "${YELLOW}⚠️ ${msg}${NC}"
|
||||||
|
read -p "Are you sure? (yes/no): " ans
|
||||||
|
[[ "$ans" =~ ^(yes|y|YES|Y)$ ]] || { print_status INFO "Cancelled"; exit 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
show_resources() {
|
||||||
|
print_status HEADER "CURRENT PROJECT RESOURCES"
|
||||||
|
echo -e "${BLUE}Containers:${NC}"
|
||||||
|
docker compose -f "$COMPOSE_FILE" ps -a || true
|
||||||
|
echo -e "${BLUE}Networks:${NC}"
|
||||||
|
docker network ls --format 'table {{.Name}}\t{{.Driver}}' | grep -E "(^|\s)$(grep -oE '^NETWORK_NAME=.+$' "$ENV_FILE" 2>/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 "$@"
|
||||||
592
compose.yml
Normal file
592
compose.yml
Normal file
@@ -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}
|
||||||
186
deploy-and-check.sh
Executable file
186
deploy-and-check.sh
Executable file
@@ -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 <<EOF
|
||||||
|
Usage: $0 [--profiles p1,p2,...] [--env-file path] [--skip-deploy] [--quick]
|
||||||
|
Default profiles: db,services-standard,client-data,modules,tools
|
||||||
|
Examples:
|
||||||
|
$0 --profiles db,services-standard,client-data --env-file ./services.env
|
||||||
|
$0 --profiles db,services-playerbots,client-data-bots,modules,tools
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--profiles) IFS=',' read -r -a PROFILES <<< "$2"; shift 2;;
|
||||||
|
--env-file) ENV_FILE="$2"; shift 2;;
|
||||||
|
--skip-deploy) SKIP_DEPLOY=true; shift;;
|
||||||
|
--quick) QUICK=true; shift;;
|
||||||
|
-h|--help) usage; exit 0;;
|
||||||
|
*) err "Unknown arg: $1"; usage; exit 1;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
resolve_project_name(){
|
||||||
|
local env_path
|
||||||
|
if [ -n "$ENV_FILE" ]; then
|
||||||
|
env_path="$ENV_FILE"
|
||||||
|
else
|
||||||
|
env_path="$(dirname "$COMPOSE_FILE")/.env"
|
||||||
|
fi
|
||||||
|
local raw_name=""
|
||||||
|
if [ -f "$env_path" ]; then
|
||||||
|
raw_name="$(grep -E '^COMPOSE_PROJECT_NAME=' "$env_path" | tail -n1 | cut -d'=' -f2-)"
|
||||||
|
fi
|
||||||
|
if [ -z "$raw_name" ]; then
|
||||||
|
raw_name="acore-compose"
|
||||||
|
fi
|
||||||
|
local sanitized
|
||||||
|
sanitized="$(echo "$raw_name" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
sanitized="${sanitized// /-}"
|
||||||
|
sanitized="$(echo "$sanitized" | tr -cd 'a-z0-9_-')"
|
||||||
|
if [[ -z "$sanitized" ]]; then
|
||||||
|
sanitized="acore-compose"
|
||||||
|
elif [[ ! "$sanitized" =~ ^[a-z0-9] ]]; then
|
||||||
|
sanitized="ac${sanitized}"
|
||||||
|
fi
|
||||||
|
echo "$sanitized"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_compose(){
|
||||||
|
local compose_args=()
|
||||||
|
local project_name
|
||||||
|
project_name="$(resolve_project_name)"
|
||||||
|
compose_args+=(--project-name "$project_name")
|
||||||
|
if [ -n "$ENV_FILE" ]; then
|
||||||
|
compose_args+=(--env-file "$ENV_FILE")
|
||||||
|
fi
|
||||||
|
compose_args+=(-f "$COMPOSE_FILE")
|
||||||
|
docker compose "${compose_args[@]}" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
env_file_path(){
|
||||||
|
if [ -n "$ENV_FILE" ]; then
|
||||||
|
echo "$ENV_FILE"
|
||||||
|
else
|
||||||
|
echo "$(dirname "$COMPOSE_FILE")/.env"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
read_env_value(){
|
||||||
|
local key="$1" default="${2:-}"
|
||||||
|
local env_path value
|
||||||
|
env_path="$(env_file_path)"
|
||||||
|
if [ -f "$env_path" ]; then
|
||||||
|
value="$(grep -E "^${key}=" "$env_path" | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||||
|
fi
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="$default"
|
||||||
|
fi
|
||||||
|
echo "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_auto_rebuild(){
|
||||||
|
local storage_path
|
||||||
|
storage_path="$(read_env_value STORAGE_PATH "./storage")"
|
||||||
|
if [[ "$storage_path" != /* ]]; then
|
||||||
|
storage_path="$(dirname "$COMPOSE_FILE")/$storage_path"
|
||||||
|
fi
|
||||||
|
local sentinel="$storage_path/modules/.requires_rebuild"
|
||||||
|
[ -f "$sentinel" ] || return 0
|
||||||
|
|
||||||
|
info "Module rebuild required (detected $(realpath "$sentinel" 2>/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/tcp/127.0.0.1/$port" 2>/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 "$@"
|
||||||
@@ -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=
|
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# ac-compose
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "🚀 AzerothCore Auto Post-Install Configuration"
|
echo "🚀 AzerothCore Auto Post-Install Configuration"
|
||||||
echo "=============================================="
|
echo "=============================================="
|
||||||
|
|
||||||
# Install required packages
|
# 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
|
# Create install markers directory
|
||||||
mkdir -p /install-markers
|
mkdir -p /install-markers
|
||||||
@@ -15,7 +16,6 @@ if [ -f "/install-markers/post-install-completed" ]; then
|
|||||||
echo "✅ Post-install configuration already completed"
|
echo "✅ Post-install configuration already completed"
|
||||||
echo "ℹ️ Marker file found: /install-markers/post-install-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 "🔄 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 ""
|
||||||
echo "🏃 Keeping container alive for manual operations..."
|
echo "🏃 Keeping container alive for manual operations..."
|
||||||
tail -f /dev/null
|
tail -f /dev/null
|
||||||
@@ -50,8 +50,6 @@ else
|
|||||||
|
|
||||||
if [ ! -f "/azerothcore/config/authserver.conf" ] || [ ! -f "/azerothcore/config/worldserver.conf" ]; then
|
if [ ! -f "/azerothcore/config/authserver.conf" ] || [ ! -f "/azerothcore/config/worldserver.conf" ]; then
|
||||||
echo "❌ Configuration files not found after waiting"
|
echo "❌ Configuration files not found after waiting"
|
||||||
echo " Expected: /azerothcore/config/authserver.conf"
|
|
||||||
echo " Expected: /azerothcore/config/worldserver.conf"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -59,126 +57,34 @@ else
|
|||||||
echo ""
|
echo ""
|
||||||
echo "🔧 Step 1: Updating configuration files..."
|
echo "🔧 Step 1: Updating configuration files..."
|
||||||
|
|
||||||
# Download and execute update-config.sh
|
# Update DB connection lines and any necessary settings directly with sed
|
||||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/update-config.sh -o /tmp/update-config.sh
|
sed -i "s|^LoginDatabaseInfo *=.*|LoginDatabaseInfo = \"${MYSQL_HOST};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}\"|" /azerothcore/config/authserver.conf || true
|
||||||
chmod +x /tmp/update-config.sh
|
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
|
echo "✅ Configuration files updated"
|
||||||
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
|
# Step 2: Update realmlist table
|
||||||
echo ""
|
echo ""
|
||||||
echo "🌐 Step 2: Updating realmlist table..."
|
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
|
echo "✅ Realmlist updated"
|
||||||
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 ""
|
||||||
echo "ℹ️ Step 3: Restarting services to apply changes..."
|
echo "ℹ️ Step 3: (Optional) Restart services to apply changes — handled externally"
|
||||||
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
|
# Create completion marker
|
||||||
echo "$(date)" > /install-markers/post-install-completed
|
echo "$(date)" > /install-markers/post-install-completed
|
||||||
echo "NEW_INSTALL_DATE=$(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 "CONFIG_FILES_UPDATED=true" >> /install-markers/post-install-completed
|
||||||
echo "REALMLIST_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 ""
|
||||||
echo "🎉 Auto post-install configuration completed successfully!"
|
echo "🎉 Auto post-install configuration completed successfully!"
|
||||||
echo ""
|
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
|
tail -f /dev/null
|
||||||
fi
|
fi
|
||||||
133
scripts/backup-scheduler.sh
Normal file → Executable file
133
scripts/backup-scheduler.sh
Normal file → Executable file
@@ -1,57 +1,104 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# ac-compose
|
||||||
set -e
|
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)
|
mkdir -p "$HOURLY_DIR" "$DAILY_DIR"
|
||||||
# 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
|
log() { echo "[$(date '+%F %T')] $*"; }
|
||||||
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
|
# Build database list from env (include optional acore_playerbots if present)
|
||||||
echo "⏳ Waiting for MySQL to be ready..."
|
database_list() {
|
||||||
sleep 30
|
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
|
run_backup() {
|
||||||
echo "🚀 Running initial daily backup..."
|
local tier_dir="$1" # hourly or daily dir
|
||||||
/tmp/backup-daily.sh
|
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
|
local -a dbs
|
||||||
echo "⏰ Starting enhanced backup scheduler:"
|
mapfile -t dbs < <(database_list)
|
||||||
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
|
for db in "${dbs[@]}"; do
|
||||||
last_daily_hour=""
|
log "Backing up database: $db"
|
||||||
last_hourly_minute=""
|
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" <<EOF
|
||||||
|
{
|
||||||
|
"timestamp": "${ts}",
|
||||||
|
"type": "hourly",
|
||||||
|
"databases": [$(printf '"%s",' "${dbs[@]}" | sed 's/,$//')],
|
||||||
|
"backup_size": "${size}",
|
||||||
|
"retention_hours": ${RETENTION_HOURS},
|
||||||
|
"mysql_version": "${mysql_ver}"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat > "$target_dir/manifest.json" <<EOF
|
||||||
|
{
|
||||||
|
"timestamp": "${ts}",
|
||||||
|
"type": "daily",
|
||||||
|
"databases": [$(printf '"%s",' "${dbs[@]}" | sed 's/,$//')],
|
||||||
|
"backup_size": "${size}",
|
||||||
|
"retention_days": ${RETENTION_DAYS},
|
||||||
|
"mysql_version": "${mysql_ver}"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Backup complete: $target_dir (size ${size})"
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_old() {
|
||||||
|
find "$HOURLY_DIR" -mindepth 1 -maxdepth 1 -type d -mmin +$((RETENTION_HOURS*60)) -print -exec rm -rf {} + 2>/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
|
while true; do
|
||||||
current_hour=$(date +%H)
|
minute=$(date '+%M')
|
||||||
current_minute=$(date +%M)
|
hour=$(date '+%H')
|
||||||
current_time="$current_hour:$current_minute"
|
|
||||||
|
|
||||||
# Daily backup check (configurable time)
|
if [ "$minute" = "00" ]; then
|
||||||
if [ "$current_hour" = "${BACKUP_DAILY_TIME}" ] && [ "$current_minute" = "00" ] && [ "$last_daily_hour" != "$current_hour" ]; then
|
run_backup "$HOURLY_DIR" "hourly"
|
||||||
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
|
fi
|
||||||
|
|
||||||
|
if [ "$hour" = "$DAILY_TIME" ] && [ "$minute" = "00" ]; then
|
||||||
|
run_backup "$DAILY_DIR" "daily"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cleanup_old
|
||||||
|
sleep 60
|
||||||
done
|
done
|
||||||
@@ -1,6 +1,49 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# ac-compose
|
||||||
set -e
|
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 "🔧 Conditional AzerothCore Database Import"
|
||||||
echo "========================================"
|
echo "========================================"
|
||||||
|
|
||||||
@@ -12,7 +55,6 @@ RESTORE_FAILED_MARKER="$RESTORE_STATUS_DIR/.restore-failed"
|
|||||||
RESTORE_SUCCESS_MARKER_TMP="$MARKER_STATUS_DIR/.restore-completed"
|
RESTORE_SUCCESS_MARKER_TMP="$MARKER_STATUS_DIR/.restore-completed"
|
||||||
RESTORE_FAILED_MARKER_TMP="$MARKER_STATUS_DIR/.restore-failed"
|
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
|
mkdir -p "$RESTORE_STATUS_DIR" 2>/dev/null || true
|
||||||
if ! touch "$RESTORE_STATUS_DIR/.test-write" 2>/dev/null; then
|
if ! touch "$RESTORE_STATUS_DIR/.test-write" 2>/dev/null; then
|
||||||
echo "⚠️ Cannot write to $RESTORE_STATUS_DIR, using $MARKER_STATUS_DIR for markers"
|
echo "⚠️ Cannot write to $RESTORE_STATUS_DIR, using $MARKER_STATUS_DIR for markers"
|
||||||
@@ -24,23 +66,16 @@ fi
|
|||||||
|
|
||||||
echo "🔍 Checking restoration status..."
|
echo "🔍 Checking restoration status..."
|
||||||
|
|
||||||
# Check if backup was successfully restored
|
|
||||||
if [ -f "$RESTORE_SUCCESS_MARKER" ]; then
|
if [ -f "$RESTORE_SUCCESS_MARKER" ]; then
|
||||||
echo "✅ Backup restoration completed successfully"
|
echo "✅ Backup restoration completed successfully"
|
||||||
echo "📄 Restoration details:"
|
cat "$RESTORE_SUCCESS_MARKER" || true
|
||||||
cat "$RESTORE_SUCCESS_MARKER"
|
|
||||||
echo ""
|
|
||||||
echo "🚫 Skipping database import - data already restored from backup"
|
echo "🚫 Skipping database import - data already restored from backup"
|
||||||
echo "💡 This prevents overwriting restored data with fresh schema"
|
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if restoration failed (fresh databases created)
|
|
||||||
if [ -f "$RESTORE_FAILED_MARKER" ]; then
|
if [ -f "$RESTORE_FAILED_MARKER" ]; then
|
||||||
echo "ℹ️ No backup was restored - fresh databases detected"
|
echo "ℹ️ No backup was restored - fresh databases detected"
|
||||||
echo "📄 Database creation details:"
|
cat "$RESTORE_FAILED_MARKER" || true
|
||||||
cat "$RESTORE_FAILED_MARKER"
|
|
||||||
echo ""
|
|
||||||
echo "▶️ Proceeding with database import to populate fresh databases"
|
echo "▶️ Proceeding with database import to populate fresh databases"
|
||||||
else
|
else
|
||||||
echo "⚠️ No restoration status found - assuming fresh installation"
|
echo "⚠️ No restoration status found - assuming fresh installation"
|
||||||
@@ -50,66 +85,11 @@ fi
|
|||||||
echo ""
|
echo ""
|
||||||
echo "🔧 Starting database import process..."
|
echo "🔧 Starting database import process..."
|
||||||
|
|
||||||
# First attempt backup restoration
|
|
||||||
echo "🔍 Checking for backups to restore..."
|
echo "🔍 Checking for backups to restore..."
|
||||||
|
|
||||||
BACKUP_DIRS="/backups"
|
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=""
|
backup_path=""
|
||||||
|
|
||||||
# Priority 1: Legacy single backup file with content validation
|
|
||||||
echo "🔍 Checking for legacy backup file..."
|
echo "🔍 Checking for legacy backup file..."
|
||||||
if [ -f "/var/lib/mysql-persistent/backup.sql" ]; then
|
if [ -f "/var/lib/mysql-persistent/backup.sql" ]; then
|
||||||
echo "📄 Found legacy backup file, validating content..."
|
echo "📄 Found legacy backup file, validating content..."
|
||||||
@@ -123,52 +103,40 @@ else
|
|||||||
echo "🔍 No legacy backup found"
|
echo "🔍 No legacy backup found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Priority 2: Modern timestamped backups (only if no legacy backup found)
|
|
||||||
if [ -z "$backup_path" ] && [ -d "$BACKUP_DIRS" ]; then
|
if [ -z "$backup_path" ] && [ -d "$BACKUP_DIRS" ]; then
|
||||||
echo "📁 Backup directory exists, checking for timestamped backups..."
|
echo "📁 Backup directory exists, checking for timestamped backups..."
|
||||||
if [ "$(ls -A $BACKUP_DIRS 2>/dev/null | wc -l)" -gt 0 ]; then
|
if [ -n "$(ls -A "$BACKUP_DIRS" 2>/dev/null)" ]; then
|
||||||
# Check daily backups first
|
if [ -d "$BACKUP_DIRS/daily" ]; then
|
||||||
if [ -d "$BACKUP_DIRS/daily" ] && [ "$(ls -A $BACKUP_DIRS/daily 2>/dev/null | wc -l)" -gt 0 ]; then
|
echo "🔍 Checking for daily backups..."
|
||||||
echo "📅 Found daily backup directory, finding latest..."
|
latest_daily=$(ls -1t "$BACKUP_DIRS/daily" 2>/dev/null | head -n 1)
|
||||||
latest_daily=$(ls -1t $BACKUP_DIRS/daily 2>/dev/null | head -n 1)
|
|
||||||
if [ -n "$latest_daily" ] && [ -d "$BACKUP_DIRS/daily/$latest_daily" ]; then
|
if [ -n "$latest_daily" ] && [ -d "$BACKUP_DIRS/daily/$latest_daily" ]; then
|
||||||
echo "📦 Checking backup directory: $latest_daily"
|
echo "📦 Latest daily backup found: $latest_daily"
|
||||||
# Check if directory has .sql.gz files
|
for backup_file in "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz; do
|
||||||
if ls "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz >/dev/null 2>&1; then
|
if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then
|
||||||
# Validate at least one backup file has content
|
if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then
|
||||||
echo "🔍 Validating backup content..."
|
echo "✅ Valid daily backup file: $(basename "$backup_file")"
|
||||||
for backup_file in "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz; do
|
backup_path="$BACKUP_DIRS/daily/$latest_daily"
|
||||||
if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then
|
break
|
||||||
# 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
|
fi
|
||||||
done
|
fi
|
||||||
else
|
done
|
||||||
echo "⚠️ No .sql.gz files found in backup directory"
|
else
|
||||||
fi
|
echo "📅 No daily backup directory found"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "📅 No daily backup directory found"
|
echo "📅 No daily backup directory found"
|
||||||
# Check for timestamped backup directories (legacy format: YYYYMMDD_HHMMSS)
|
|
||||||
echo "🔍 Checking for timestamped backup directories..."
|
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)
|
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
|
if [ -n "$timestamped_backups" ]; then
|
||||||
latest_timestamped="$timestamped_backups"
|
latest_timestamped="$timestamped_backups"
|
||||||
echo "📦 Found timestamped backup: $latest_timestamped"
|
echo "📦 Found timestamped backup: $latest_timestamped"
|
||||||
if [ -d "$BACKUP_DIRS/$latest_timestamped" ]; then
|
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
|
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..."
|
echo "🔍 Validating timestamped backup content..."
|
||||||
for backup_file in "$BACKUP_DIRS/$latest_timestamped"/*.sql.gz; do
|
for backup_file in "$BACKUP_DIRS/$latest_timestamped"/*.sql.gz; do
|
||||||
if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then
|
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
|
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"
|
backup_path="$BACKUP_DIRS/$latest_timestamped"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
@@ -191,71 +159,47 @@ fi
|
|||||||
|
|
||||||
echo "🔄 Final backup path result: '$backup_path'"
|
echo "🔄 Final backup path result: '$backup_path'"
|
||||||
if [ -n "$backup_path" ]; then
|
if [ -n "$backup_path" ]; then
|
||||||
echo "📦 Found backup: $(basename $backup_path)"
|
echo "📦 Found backup: $(basename "$backup_path")"
|
||||||
if restore_from_directory "$backup_path"; then
|
if [ -d "$backup_path" ]; then
|
||||||
echo "✅ Database restoration completed successfully!"
|
echo "🔄 Restoring from backup directory: $backup_path"
|
||||||
echo "$(date): Backup successfully restored from $backup_path" > "$RESTORE_SUCCESS_MARKER"
|
restore_success=true
|
||||||
echo "🚫 Skipping schema import - data already restored from backup"
|
for backup_file in "$backup_path"/*.sql.gz; do
|
||||||
exit 0
|
if [ -f "$backup_file" ]; then
|
||||||
else
|
if timeout 300 zcat "$backup_file" | mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD}; then
|
||||||
echo "❌ Backup restoration failed - proceeding with fresh setup"
|
echo "✅ Restored $(basename "$backup_file")"
|
||||||
echo "$(date): Backup restoration failed - proceeding with fresh setup" > "$RESTORE_FAILED_MARKER"
|
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
|
fi
|
||||||
else
|
else
|
||||||
echo "ℹ️ No valid backups found - proceeding with fresh setup"
|
echo "ℹ️ No valid backups found - proceeding with fresh setup"
|
||||||
echo "$(date): No backup found - fresh setup needed" > "$RESTORE_FAILED_MARKER"
|
echo "$(date): No backup found - fresh setup needed" > "$RESTORE_FAILED_MARKER"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create fresh databases if restoration didn't happen
|
|
||||||
echo "🗄️ Creating fresh AzerothCore databases..."
|
echo "🗄️ Creating fresh AzerothCore databases..."
|
||||||
mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "
|
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_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_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;
|
CREATE DATABASE IF NOT EXISTS ${DB_CHARACTERS_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
SHOW DATABASES;" || {
|
SHOW DATABASES;" || { echo "❌ Failed to create databases"; exit 1; }
|
||||||
echo "❌ Failed to create databases"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
echo "✅ Fresh databases created - proceeding with schema import"
|
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..."
|
echo "📝 Creating dbimport configuration..."
|
||||||
mkdir -p /azerothcore/env/dist/etc
|
mkdir -p /azerothcore/env/dist/etc
|
||||||
cat > /azerothcore/env/dist/etc/dbimport.conf <<EOF
|
cat > /azerothcore/env/dist/etc/dbimport.conf <<EOF
|
||||||
@@ -264,67 +208,16 @@ WorldDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT
|
|||||||
CharacterDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
|
CharacterDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
|
||||||
Updates.EnableDatabases = 7
|
Updates.EnableDatabases = 7
|
||||||
Updates.AutoSetup = 1
|
Updates.AutoSetup = 1
|
||||||
|
|
||||||
# Required configuration properties
|
|
||||||
MySQLExecutable = ""
|
|
||||||
TempDir = ""
|
|
||||||
SourceDirectory = ""
|
|
||||||
Updates.AllowedModules = "all"
|
|
||||||
LoginDatabase.WorkerThreads = 1
|
|
||||||
LoginDatabase.SynchThreads = 1
|
|
||||||
WorldDatabase.WorkerThreads = 1
|
|
||||||
WorldDatabase.SynchThreads = 1
|
|
||||||
CharacterDatabase.WorkerThreads = 1
|
|
||||||
CharacterDatabase.SynchThreads = 1
|
|
||||||
Updates.Redundancy = 1
|
|
||||||
Updates.AllowRehash = 1
|
|
||||||
Updates.ArchivedRedundancy = 0
|
|
||||||
Updates.CleanDeadRefMaxCount = 3
|
|
||||||
|
|
||||||
# Logging configuration
|
|
||||||
Appender.Console=1,3,6
|
|
||||||
Logger.root=3,Console
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "🚀 Running database import..."
|
echo "🚀 Running database import..."
|
||||||
cd /azerothcore/env/dist/bin
|
cd /azerothcore/env/dist/bin
|
||||||
|
|
||||||
# Run dbimport with error handling
|
|
||||||
if ./dbimport; then
|
if ./dbimport; then
|
||||||
echo "✅ Database import completed successfully!"
|
echo "✅ Database import completed successfully!"
|
||||||
|
echo "$(date): Database import completed successfully" > "$RESTORE_STATUS_DIR/.import-completed" || echo "$(date): Database import completed successfully" > "$MARKER_STATUS_DIR/.import-completed"
|
||||||
# Create import completion marker
|
|
||||||
if touch "$RESTORE_STATUS_DIR/.import-completed" 2>/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
|
else
|
||||||
echo "❌ Database import failed!"
|
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" || echo "$(date): Database import failed" > "$MARKER_STATUS_DIR/.import-failed"
|
||||||
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
207
scripts/download-client-data.sh
Normal file → Executable file
207
scripts/download-client-data.sh
Normal file → Executable file
@@ -1,32 +1,40 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# ac-compose
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo '🚀 Starting AzerothCore game data setup...'
|
echo '🚀 Starting AzerothCore game data setup...'
|
||||||
|
|
||||||
# Get the latest release info from wowgaming/client-data
|
# Get the latest release info from wowgaming/client-data
|
||||||
echo '📡 Fetching latest client data release info...'
|
REQUESTED_TAG="${CLIENT_DATA_VERSION:-}"
|
||||||
RELEASE_INFO=$(wget -qO- https://api.github.com/repos/wowgaming/client-data/releases/latest 2>/dev/null)
|
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
|
if [ -n "$RELEASE_INFO" ]; then
|
||||||
LATEST_URL=$(echo "$RELEASE_INFO" | grep '"browser_download_url":' | grep '\.zip' | cut -d'"' -f4 | head -1)
|
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_TAG=$(echo "$RELEASE_INFO" | grep '"tag_name":' | cut -d'"' -f4)
|
||||||
LATEST_SIZE=$(echo "$RELEASE_INFO" | grep '"size":' | head -1 | grep -o '[0-9]*')
|
LATEST_SIZE=$(echo "$RELEASE_INFO" | grep '"size":' | head -1 | grep -o '[0-9]*')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$LATEST_URL" ]; then
|
if [ -z "$LATEST_URL" ]; then
|
||||||
echo '❌ Could not fetch latest release URL'
|
echo '❌ Could not fetch client-data release information. Aborting.'
|
||||||
echo '📥 Using fallback: direct download from v16 release'
|
exit 1
|
||||||
LATEST_URL='https://github.com/wowgaming/client-data/releases/download/v16/data.zip'
|
fi
|
||||||
LATEST_TAG='v16'
|
|
||||||
LATEST_SIZE='0'
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "📍 Latest release: $LATEST_TAG"
|
echo "📍 Latest release: $LATEST_TAG"
|
||||||
echo "📥 Download URL: $LATEST_URL"
|
echo "📥 Download URL: $LATEST_URL"
|
||||||
|
|
||||||
# Cache file paths
|
# Cache file paths
|
||||||
CACHE_FILE="/cache/client-data-$LATEST_TAG.zip"
|
CACHE_DIR="/cache"
|
||||||
VERSION_FILE="/cache/client-data-version.txt"
|
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
|
# Check if we have a cached version
|
||||||
if [ -f "$CACHE_FILE" ] && [ -f "$VERSION_FILE" ]; then
|
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}')"
|
echo "📊 Cached file size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')"
|
||||||
|
|
||||||
# Verify cache file integrity
|
# 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 "✅ Cache file integrity verified"
|
||||||
echo "⚡ Using cached download - skipping download phase"
|
echo "⚡ Using cached download - skipping download phase"
|
||||||
cp "$CACHE_FILE" data.zip
|
cp "$CACHE_FILE" data.zip
|
||||||
@@ -47,140 +70,90 @@ if [ -f "$CACHE_FILE" ] && [ -f "$VERSION_FILE" ]; then
|
|||||||
else
|
else
|
||||||
echo "📦 Cache version ($CACHED_VERSION) differs from latest ($LATEST_TAG)"
|
echo "📦 Cache version ($CACHED_VERSION) differs from latest ($LATEST_TAG)"
|
||||||
echo "🗑️ Removing old cache"
|
echo "🗑️ Removing old cache"
|
||||||
rm -f /cache/client-data-*.zip "$VERSION_FILE"
|
rm -f "${CACHE_DIR}"/client-data-*.zip "$VERSION_FILE"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Download if we don't have a valid cached file
|
# Download if we don't have a valid cached file
|
||||||
if [ ! -f "data.zip" ]; then
|
if [ ! -f "data.zip" ]; then
|
||||||
echo "📥 Downloading client data (~15GB, may take 10-30 minutes)..."
|
echo "📥 Downloading client data (~15GB)..."
|
||||||
echo "📍 Source: $LATEST_URL"
|
echo "📍 Source: $LATEST_URL"
|
||||||
|
|
||||||
# Download with clean progress indication
|
if command -v aria2c >/dev/null 2>&1; then
|
||||||
echo "📥 Starting download..."
|
aria2c --max-connection-per-server=8 --split=8 --min-split-size=10M \
|
||||||
wget --progress=dot:giga -O "$CACHE_FILE.tmp" "$LATEST_URL" 2>&1 | sed 's/^/📊 /' || {
|
--summary-interval=5 --download-result=hide \
|
||||||
echo '❌ wget failed, trying curl...'
|
--console-log-level=warn --show-console-readout=false \
|
||||||
curl -L --progress-bar -o "$CACHE_FILE.tmp" "$LATEST_URL" || {
|
--dir "$CACHE_DIR" -o "$(basename "$TMP_FILE")" "$LATEST_URL" || {
|
||||||
echo '❌ All download methods failed'
|
echo '⚠️ aria2c failed, falling back to wget...'
|
||||||
rm -f "$CACHE_FILE.tmp"
|
wget --progress=dot:giga -O "$TMP_FILE" "$LATEST_URL" 2>&1 | sed 's/^/📊 /' || {
|
||||||
exit 1
|
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
|
echo "🔍 Verifying download integrity..."
|
||||||
if unzip -t "$CACHE_FILE.tmp" > /dev/null 2>&1; then
|
INTEGRITY_OK=false
|
||||||
mv "$CACHE_FILE.tmp" "$CACHE_FILE"
|
|
||||||
|
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 "$LATEST_TAG" > "$VERSION_FILE"
|
||||||
echo '✅ Download completed and verified'
|
echo '✅ Download completed and verified'
|
||||||
echo "📊 File size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')"
|
echo "📊 File size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')"
|
||||||
cp "$CACHE_FILE" data.zip
|
cp "$CACHE_FILE" data.zip
|
||||||
else
|
else
|
||||||
echo '❌ Downloaded file is corrupted'
|
echo '❌ Downloaded file is corrupted'
|
||||||
rm -f "$CACHE_FILE.tmp"
|
rm -f "$TMP_FILE"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo '📂 Extracting client data (this may take 10-15 minutes)...'
|
echo '📂 Extracting client data (this may take some minutes)...'
|
||||||
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
|
rm -rf /azerothcore/data/maps /azerothcore/data/vmaps /azerothcore/data/mmaps /azerothcore/data/dbc
|
||||||
|
|
||||||
# Extract with detailed progress tracking
|
if command -v 7z >/dev/null 2>&1; then
|
||||||
echo '🔄 Starting extraction with progress monitoring...'
|
7z x -aoa -o/azerothcore/data/ data.zip >/dev/null 2>&1
|
||||||
|
else
|
||||||
# Start extraction in background with overwrite
|
unzip -o -q data.zip -d /azerothcore/data/
|
||||||
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
|
|
||||||
fi
|
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
|
rm -f data.zip
|
||||||
|
|
||||||
echo '✅ Client data extraction complete!'
|
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
|
for dir in maps vmaps mmaps dbc; do
|
||||||
if [ -d "/azerothcore/data/$dir" ] && [ -n "$(ls -A /azerothcore/data/$dir 2>/dev/null)" ]; then
|
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)
|
DIR_SIZE=$(du -sh /azerothcore/data/$dir 2>/dev/null | cut -f1)
|
||||||
echo "✅ $dir directory: OK ($DIR_SIZE)"
|
echo "✅ $dir directory: OK ($DIR_SIZE)"
|
||||||
else
|
else
|
||||||
echo "❌ $dir directory: MISSING or EMPTY"
|
echo "❌ $dir directory: MISSING or EMPTY"
|
||||||
ALL_GOOD=false
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$ALL_GOOD" = "true" ]; then
|
echo '🎉 Game data setup complete! AzerothCore worldserver can now start.'
|
||||||
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
|
|
||||||
|
|||||||
1
scripts/manage-modules-sql.sh
Normal file → Executable file
1
scripts/manage-modules-sql.sh
Normal file → Executable file
@@ -1,4 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# ac-compose
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Function to execute SQL files for a module
|
# Function to execute SQL files for a module
|
||||||
|
|||||||
84
scripts/manage-modules.sh
Normal file → Executable file
84
scripts/manage-modules.sh
Normal file → Executable file
@@ -1,10 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
# ac-compose
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo 'Setting up git user'
|
echo 'Setting up git user'
|
||||||
git config --global user.name "$GIT_USERNAME"
|
git config --global user.name "${GIT_USERNAME:-ac-compose}"
|
||||||
git config --global user.email "$GIT_EMAIL"
|
git config --global user.email "${GIT_EMAIL:-noreply@azerothcore.org}"
|
||||||
git config --global url.https://$GIT_PAT@github.com/.insteadOf https://github.com/
|
# PAT not needed for public repositories
|
||||||
|
|
||||||
echo 'Initializing module management...'
|
echo 'Initializing module management...'
|
||||||
cd /modules
|
cd /modules
|
||||||
@@ -538,18 +539,6 @@ if [ "$MODULE_LEVEL_GRANT" != "1" ]; then
|
|||||||
rm -f /azerothcore/env/dist/etc/levelGrant.conf*
|
rm -f /azerothcore/env/dist/etc/levelGrant.conf*
|
||||||
fi
|
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
|
# Install configuration files for enabled modules
|
||||||
for module_dir in mod-*; do
|
for module_dir in mod-*; do
|
||||||
if [ -d "$module_dir" ]; then
|
if [ -d "$module_dir" ]; then
|
||||||
@@ -558,15 +547,21 @@ for module_dir in mod-*; do
|
|||||||
fi
|
fi
|
||||||
done
|
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
|
# Execute SQLs for enabled modules (via helper)
|
||||||
source /scripts/manage-modules-sql.sh
|
if declare -f execute_module_sql_scripts >/dev/null 2>&1; then
|
||||||
|
echo 'Executing module SQL scripts...'
|
||||||
echo 'Executing module SQL scripts...'
|
execute_module_sql_scripts
|
||||||
execute_module_sql_scripts
|
echo 'SQL execution complete.'
|
||||||
|
fi
|
||||||
echo 'SQL execution complete.'
|
|
||||||
|
|
||||||
# Module state tracking and rebuild logic
|
# Module state tracking and rebuild logic
|
||||||
echo 'Checking for module changes that require rebuild...'
|
echo 'Checking for module changes that require rebuild...'
|
||||||
@@ -576,7 +571,7 @@ CURRENT_STATE=""
|
|||||||
REBUILD_REQUIRED=0
|
REBUILD_REQUIRED=0
|
||||||
|
|
||||||
# Create current module state hash
|
# 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"
|
eval "value=\$$module_var"
|
||||||
CURRENT_STATE="$CURRENT_STATE$module_var=$value|"
|
CURRENT_STATE="$CURRENT_STATE$module_var=$value|"
|
||||||
done
|
done
|
||||||
@@ -598,9 +593,9 @@ fi
|
|||||||
# Save current state
|
# Save current state
|
||||||
echo "$CURRENT_STATE" > "$MODULES_STATE_FILE"
|
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=""
|
ENABLED_MODULES=""
|
||||||
[ "$MODULE_PLAYERBOTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-playerbots"
|
|
||||||
[ "$MODULE_AOE_LOOT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-aoe-loot"
|
[ "$MODULE_AOE_LOOT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-aoe-loot"
|
||||||
[ "$MODULE_LEARN_SPELLS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-learn-spells"
|
[ "$MODULE_LEARN_SPELLS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-learn-spells"
|
||||||
[ "$MODULE_FIREWORKS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-fireworks-on-level"
|
[ "$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_AUTO_REVIVE" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-auto-revive"
|
||||||
[ "$MODULE_GAIN_HONOR_GUARD" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-gain-honor-guard"
|
[ "$MODULE_GAIN_HONOR_GUARD" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-gain-honor-guard"
|
||||||
[ "$MODULE_ELUNA" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-eluna"
|
[ "$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_TIME_IS_TIME" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-time-is-time"
|
||||||
[ "$MODULE_POCKET_PORTAL" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-pocket-portal"
|
[ "$MODULE_POCKET_PORTAL" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-pocket-portal"
|
||||||
[ "$MODULE_RANDOM_ENCHANTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-random-enchants"
|
[ "$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_NPC_ENCHANTER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-npc-enchanter"
|
||||||
[ "$MODULE_INSTANCE_RESET" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-instance-reset"
|
[ "$MODULE_INSTANCE_RESET" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-instance-reset"
|
||||||
[ "$MODULE_LEVEL_GRANT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-quest-count-level"
|
[ "$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
|
if [ -n "$ENABLED_MODULES" ]; then
|
||||||
ENABLED_COUNT=$(echo $ENABLED_MODULES | wc -w)
|
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 "Module configuration has changed. To integrate C++ modules into AzerothCore:"
|
||||||
echo ""
|
echo ""
|
||||||
echo "1. Stop current services:"
|
echo "1. Stop current services:"
|
||||||
echo " docker compose -f docker-compose-azerothcore-services.yml down"
|
echo " docker compose down"
|
||||||
echo ""
|
echo ""
|
||||||
echo "2. Build with source-based compilation:"
|
echo "2. Build with source-based compilation (external process)"
|
||||||
echo " docker compose -f /tmp/acore-dev-test/docker-compose.yml build"
|
echo " ./scripts/rebuild-with-modules.sh (if available)"
|
||||||
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 ""
|
||||||
echo "📋 NOTE: Source-based build will compile AzerothCore with all enabled modules"
|
echo "📋 NOTE: Source-based build will compile AzerothCore with all enabled modules"
|
||||||
echo "⏱️ Expected build time: 15-45 minutes depending on system performance"
|
echo "⏱️ Expected build time: 15-45 minutes depending on system performance"
|
||||||
@@ -665,21 +652,14 @@ fi
|
|||||||
|
|
||||||
echo 'Module management complete.'
|
echo 'Module management complete.'
|
||||||
|
|
||||||
# Download rebuild script from GitHub for local access
|
REBUILD_SENTINEL="/modules/.requires_rebuild"
|
||||||
echo '📥 Downloading rebuild-with-modules.sh from GitHub...'
|
if [ "$REBUILD_REQUIRED" = "1" ] && [ -n "$ENABLED_MODULES" ]; then
|
||||||
apk add --no-cache curl
|
echo "$ENABLED_MODULES" > "$REBUILD_SENTINEL"
|
||||||
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
|
else
|
||||||
echo '⚠️ Warning: rebuild-with-modules.sh not found in GitHub or locally'
|
rm -f "$REBUILD_SENTINEL" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo 'Keeping container alive...'
|
# Optional: keep container alive for inspection in CI/debug contexts
|
||||||
tail -f /dev/null
|
if [ "${MODULES_DEBUG_KEEPALIVE:-0}" = "1" ]; then
|
||||||
|
tail -f /dev/null
|
||||||
|
fi
|
||||||
|
|||||||
@@ -1,128 +1,195 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# AzerothCore Module Rebuild Script
|
# ac-compose helper to rebuild AzerothCore from source with enabled modules.
|
||||||
# Automates the process of rebuilding AzerothCore with enabled modules
|
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
echo "🔧 AzerothCore Module Rebuild Script"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
echo "==================================="
|
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
echo ""
|
ENV_FILE="$PROJECT_DIR/.env"
|
||||||
|
|
||||||
# Check if source repository exists
|
usage(){
|
||||||
SOURCE_COMPOSE="/tmp/acore-dev-test/docker-compose.yml"
|
cat <<EOF
|
||||||
|
Usage: $(basename "$0") [options]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--yes, -y Skip interactive confirmation prompts
|
||||||
|
--source PATH Override MODULES_REBUILD_SOURCE_PATH from .env
|
||||||
|
--skip-stop Do not run 'docker compose down' in the source tree before rebuilding
|
||||||
|
-h, --help Show this help
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
read_env(){
|
||||||
|
local key="$1" default="$2" env_path="$ENV_FILE" value
|
||||||
|
if [ -f "$env_path" ]; then
|
||||||
|
value="$(grep -E "^${key}=" "$env_path" | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||||
|
fi
|
||||||
|
if [ -z "$value" ]; then
|
||||||
|
value="$default"
|
||||||
|
fi
|
||||||
|
echo "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm(){
|
||||||
|
local prompt="$1" default="$2" reply
|
||||||
|
if [ "$ASSUME_YES" = "1" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
while true; do
|
||||||
|
if [ "$default" = "y" ]; then
|
||||||
|
read -r -p "$prompt [Y/n]: " reply
|
||||||
|
reply="${reply:-y}"
|
||||||
|
else
|
||||||
|
read -r -p "$prompt [y/N]: " reply
|
||||||
|
reply="${reply:-n}"
|
||||||
|
fi
|
||||||
|
case "$reply" in
|
||||||
|
[Yy]*) return 0 ;;
|
||||||
|
[Nn]*) return 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSUME_YES=0
|
||||||
|
SOURCE_OVERRIDE=""
|
||||||
|
SKIP_STOP=0
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--yes|-y) ASSUME_YES=1; shift;;
|
||||||
|
--source) SOURCE_OVERRIDE="$2"; shift 2;;
|
||||||
|
--skip-stop) SKIP_STOP=1; shift;;
|
||||||
|
-h|--help) usage; exit 0;;
|
||||||
|
*) echo "Unknown option: $1" >&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 <<EOF
|
||||||
|
❌ MODULES_REBUILD_SOURCE_PATH is not configured.
|
||||||
|
|
||||||
|
Set MODULES_REBUILD_SOURCE_PATH in .env to the AzerothCore source repository
|
||||||
|
that contains the Docker Compose file used for source builds, then rerun:
|
||||||
|
|
||||||
|
scripts/rebuild-with-modules.sh --yes
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$REBUILD_SOURCE_PATH" != /* ]]; then
|
||||||
|
REBUILD_SOURCE_PATH="$(realpath "$REBUILD_SOURCE_PATH" 2>/dev/null || echo "$REBUILD_SOURCE_PATH")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SOURCE_COMPOSE="$REBUILD_SOURCE_PATH/docker-compose.yml"
|
||||||
if [ ! -f "$SOURCE_COMPOSE" ]; then
|
if [ ! -f "$SOURCE_COMPOSE" ]; then
|
||||||
echo "❌ Error: Source-based Docker Compose file not found at $SOURCE_COMPOSE"
|
echo "❌ Source docker-compose.yml not found at $SOURCE_COMPOSE"
|
||||||
echo "Please ensure AzerothCore source repository is available for compilation."
|
exit 1
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check current module configuration
|
declare -A MODULE_REPO_MAP=(
|
||||||
echo "📋 Checking current module configuration..."
|
[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
|
compile_modules=()
|
||||||
ENABLED_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 [ ${#compile_modules[@]} -eq 0 ]; then
|
||||||
if [ -f "docker-compose-azerothcore-services.env" ]; then
|
echo "✅ No C++ modules enabled that require a source rebuild."
|
||||||
while IFS= read -r line; do
|
rm -f "$SENTINEL_FILE" 2>/dev/null || true
|
||||||
if echo "$line" | grep -q "^MODULE_.*=1$"; then
|
exit 0
|
||||||
MODULE_NAME=$(echo "$line" | cut -d'=' -f1)
|
fi
|
||||||
MODULES_ENABLED=$((MODULES_ENABLED + 1))
|
|
||||||
ENABLED_MODULES="$ENABLED_MODULES $MODULE_NAME"
|
echo "🔧 Modules requiring compilation:"
|
||||||
fi
|
for mod in "${compile_modules[@]}"; do
|
||||||
done < docker-compose-azerothcore-services.env
|
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
|
else
|
||||||
echo "⚠️ Warning: Environment file not found, checking default configuration..."
|
echo "⚠️ No modules directory found at $MODULES_DIR; continuing without sync."
|
||||||
fi
|
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..."
|
echo "🚀 Building AzerothCore with modules..."
|
||||||
docker compose build --no-cache
|
docker compose build --no-cache
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
echo "🟢 Starting source services..."
|
||||||
echo ""
|
docker compose up -d
|
||||||
echo "✅ Build completed successfully!"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Start services
|
popd >/dev/null
|
||||||
echo "🟢 Starting services with compiled modules..."
|
|
||||||
docker compose up -d
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
rm -f "$SENTINEL_FILE" 2>/dev/null || true
|
||||||
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 ""
|
||||||
echo "✅ Rebuild process complete!"
|
echo "🎉 SUCCESS! AzerothCore source build completed with modules."
|
||||||
|
|||||||
429
setup.sh
Executable file
429
setup.sh
Executable file
@@ -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" <<EOF
|
||||||
|
# Generated by ac-compose/setup.sh
|
||||||
|
|
||||||
|
COMPOSE_PROJECT_NAME=ac-compose
|
||||||
|
|
||||||
|
STORAGE_PATH=$STORAGE_PATH
|
||||||
|
TZ=UTC
|
||||||
|
|
||||||
|
# Database
|
||||||
|
MYSQL_IMAGE=mysql:8.0
|
||||||
|
CONTAINER_MYSQL=ac-mysql
|
||||||
|
MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD
|
||||||
|
MYSQL_ROOT_HOST=%
|
||||||
|
MYSQL_USER=root
|
||||||
|
MYSQL_PORT=3306
|
||||||
|
MYSQL_EXTERNAL_PORT=$MYSQL_EXTERNAL_PORT
|
||||||
|
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=$AUTH_EXTERNAL_PORT
|
||||||
|
AUTH_PORT=3724
|
||||||
|
WORLD_EXTERNAL_PORT=$REALM_PORT
|
||||||
|
WORLD_PORT=8085
|
||||||
|
SOAP_EXTERNAL_PORT=$SOAP_EXTERNAL_PORT
|
||||||
|
SOAP_PORT=7878
|
||||||
|
|
||||||
|
# Realm
|
||||||
|
SERVER_ADDRESS=$SERVER_ADDRESS
|
||||||
|
REALM_PORT=$REALM_PORT
|
||||||
|
|
||||||
|
# Backups
|
||||||
|
BACKUP_RETENTION_DAYS=$BACKUP_RETENTION_DAYS
|
||||||
|
BACKUP_RETENTION_HOURS=$BACKUP_RETENTION_HOURS
|
||||||
|
BACKUP_DAILY_TIME=$BACKUP_DAILY_TIME
|
||||||
|
|
||||||
|
# Container user
|
||||||
|
CONTAINER_USER=$CONTAINER_USER
|
||||||
|
|
||||||
|
# Modules
|
||||||
|
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_ARAC=$MODULE_ARAC
|
||||||
|
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_ASSISTANT=$MODULE_ASSISTANT
|
||||||
|
MODULE_REAGENT_BANK=$MODULE_REAGENT_BANK
|
||||||
|
MODULE_BLACK_MARKET_AUCTION_HOUSE=$MODULE_BLACK_MARKET_AUCTION_HOUSE
|
||||||
|
|
||||||
|
# Client data
|
||||||
|
CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-v16}
|
||||||
|
|
||||||
|
# Playerbot runtime
|
||||||
|
PLAYERBOT_ENABLED=$PLAYERBOT_ENABLED
|
||||||
|
PLAYERBOT_MAX_BOTS=$PLAYERBOT_MAX_BOTS
|
||||||
|
|
||||||
|
# Rebuild automation
|
||||||
|
AUTO_REBUILD_ON_DEPLOY=$AUTO_REBUILD_ON_DEPLOY
|
||||||
|
MODULES_REBUILD_SOURCE_PATH=$MODULES_REBUILD_SOURCE_PATH_VALUE
|
||||||
|
|
||||||
|
# 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
|
||||||
|
EOF
|
||||||
|
|
||||||
|
say SUCCESS ".env written to $ENV_OUT"
|
||||||
|
|
||||||
|
if [ "$RUN_REBUILD_NOW" = "1" ]; then
|
||||||
|
echo ""
|
||||||
|
say HEADER "MODULE REBUILD"
|
||||||
|
if [ -n "$MODULES_REBUILD_SOURCE_PATH_VALUE" ]; then
|
||||||
|
if ./scripts/rebuild-with-modules.sh --yes --source "$MODULES_REBUILD_SOURCE_PATH_VALUE"; then
|
||||||
|
say SUCCESS "Module rebuild completed"
|
||||||
|
else
|
||||||
|
warn "Module rebuild failed; run ./scripts/rebuild-with-modules.sh manually once issues are resolved."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Rebuild path was not provided; skipping automatic rebuild."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
say INFO "Run with profiles (examples):"
|
||||||
|
if [ "$MODULE_PLAYERBOTS" = "1" ]; then
|
||||||
|
echo " docker compose -f compose.yml --profile db --profile services-playerbots --profile client-data-bots --profile modules --profile tools up -d"
|
||||||
|
echo " ./deploy-and-check.sh --profiles db,services-playerbots,client-data-bots,modules,tools"
|
||||||
|
else
|
||||||
|
echo " docker compose -f compose.yml --profile db --profile services-standard --profile client-data --profile modules --profile tools up -d"
|
||||||
|
echo " ./deploy-and-check.sh --profiles db,services-standard,client-data,modules,tools"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
|
if [ "$MODULE_PLAYERBOTS" = "1" ]; then
|
||||||
|
PLAYERBOT_ENABLED=1
|
||||||
|
PLAYERBOT_MAX_BOTS=$(ask "Maximum concurrent playerbots" 40 validate_number)
|
||||||
|
fi
|
||||||
231
status.sh
Executable file
231
status.sh
Executable file
@@ -0,0 +1,231 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ac-compose condensed status view
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_DIR="$SCRIPT_DIR"
|
||||||
|
ENV_FILE="$PROJECT_DIR/.env"
|
||||||
|
|
||||||
|
cd "$PROJECT_DIR"
|
||||||
|
|
||||||
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||||
|
|
||||||
|
WATCH_MODE=false
|
||||||
|
LOG_LINES=5
|
||||||
|
SHOW_LOGS=false
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--watch|-w) WATCH_MODE=true; shift;;
|
||||||
|
--logs|-l) SHOW_LOGS=true; shift;;
|
||||||
|
--lines) LOG_LINES="$2"; shift 2;;
|
||||||
|
-h|--help)
|
||||||
|
cat <<EOF
|
||||||
|
ac-compose status
|
||||||
|
|
||||||
|
Usage: $0 [options]
|
||||||
|
-w, --watch Continuously refresh every 3s
|
||||||
|
-l, --logs Show trailing logs for each service
|
||||||
|
--lines N Number of log lines when --logs is used (default 5)
|
||||||
|
EOF
|
||||||
|
exit 0;;
|
||||||
|
*) echo "Unknown option: $1" >&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/tcp/127.0.0.1/${port}" >/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
|
||||||
129
todo.md
129
todo.md
@@ -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.
|
|
||||||
Reference in New Issue
Block a user