feat: add mysql exposure toggle and client data bind

This commit is contained in:
uprightbass360
2025-11-07 20:56:00 -05:00
committed by Deckard
parent ce02a547ee
commit d99dad025a
18 changed files with 431 additions and 183 deletions

View File

@@ -101,6 +101,7 @@ MYSQL_ROOT_HOST=%
MYSQL_USER=root
MYSQL_PORT=3306
MYSQL_EXTERNAL_PORT=64306
MYSQL_EXPOSE_PORT=0
MYSQL_CHARACTER_SET=utf8mb4
MYSQL_COLLATION=utf8mb4_unicode_ci
MYSQL_MAX_CONNECTIONS=1000
@@ -108,6 +109,8 @@ MYSQL_INNODB_BUFFER_POOL_SIZE=256M
MYSQL_INNODB_LOG_FILE_SIZE=64M
MYSQL_INNODB_REDO_LOG_CAPACITY=512M
MYSQL_RUNTIME_TMPFS_SIZE=8G
MYSQL_DISABLE_BINLOG=1
MYSQL_CONFIG_DIR=${STORAGE_PATH}/config/mysql/conf.d
DB_WAIT_RETRIES=60
DB_WAIT_SLEEP=10
@@ -137,13 +140,19 @@ BACKUP_HEALTHCHECK_START_PERIOD=120s
PLAYERBOT_ENABLED=0
PLAYERBOT_MIN_BOTS=40
PLAYERBOT_MAX_BOTS=40
STACK_IMAGE_MODE=standard
STACK_SOURCE_VARIANT=core
MODULES_ENABLED_LIST=
MODULES_CPP_LIST=
MODULES_REQUIRES_CUSTOM_BUILD=0
MODULES_REQUIRES_PLAYERBOT_SOURCE=0
# =====================
# Client Data Settings
# =====================
CLIENT_DATA_VERSION=v17
CLIENT_DATA_VERSION=v18
CLIENT_DATA_CACHE_PATH=${STORAGE_PATH_LOCAL}/client-data-cache
CLIENT_DATA_VOLUME=ac-client-data
CLIENT_DATA_PATH=${STORAGE_PATH}/client-data
# =====================
# Module toggles (0/1)

View File

@@ -116,7 +116,7 @@ The setup wizard will guide you through:
**Required when:**
- Playerbots enabled (`MODULE_PLAYERBOTS=1`)
- Any C++ module enabled (check `needs_build: true` in `config/modules.json`)
- Any C++ module enabled (modules with `"type": "cpp"` in `config/modules.json`)
**Build process:**
1. Clones AzerothCore source to `local-storage/source/`
@@ -757,7 +757,7 @@ flowchart TB
| Service / Container | Role | Ports (host → container) | Profile |
|---------------------|------|--------------------------|---------|
| `ac-mysql` | MySQL 8.0 database | `64306 → 3306` | `db` |
| `ac-mysql` | MySQL 8.0 database | *(optional)* `64306 → 3306` (`MYSQL_EXPOSE_PORT=1`) | `db` |
| `ac-db-init` | Database schema initialization | | `db` |
| `ac-db-import` | Database content import | | `db` |
| `ac-backup` | Automated backup system | | `db` |
@@ -773,6 +773,12 @@ flowchart TB
| `ac-phpmyadmin` | Database admin UI | `8081 → 80` | `tools` |
| `ac-keira3` | Game content editor | `4201 → 8080` | `tools` |
### Database Hardening
- **MySQL port exposure** By default `MYSQL_EXPOSE_PORT=0`, so `ac-mysql` is reachable only from the internal Docker network. Set `MYSQL_EXPOSE_PORT=1` to publish `${MYSQL_EXTERNAL_PORT}` on the host; RealmMaster scripts automatically include `docker-compose.mysql-expose.yml` so the override Just Works. If you invoke Compose manually, remember to add `-f docker-compose.mysql-expose.yml`.
- **Binary logging toggle** `MYSQL_DISABLE_BINLOG=1` appends `--skip-log-bin` via the MySQL wrapper entrypoint to keep disk churn low (and match Playerbot guidance). Flip the flag to `0` to re-enable binlogs for debugging or replication.
- **Drop-in configs** Any `.cnf` placed in `${STORAGE_PATH}/config/mysql/conf.d` (exposed via `MYSQL_CONFIG_DIR`) is mounted into `/etc/mysql/conf.d`. Use this to add custom tunables or temporarily override the binlog setting without touching the image.
### Storage Structure
The project uses a dual-storage approach for optimal performance:
@@ -781,6 +787,9 @@ The project uses a dual-storage approach for optimal performance:
```
storage/
├── config/ # Server configuration files (.conf)
│ └── mysql/
│ └── conf.d/ # Drop-in MySQL overrides (mapped to /etc/mysql/conf.d)
├── client-data/ # Unpacked WoW client data & DBC overrides
├── logs/ # Server log files
├── modules/ # Downloaded module source code
├── lua_scripts/ # Eluna Lua scripts (auto-loaded)
@@ -790,6 +799,10 @@ storage/
└── hourly/ # Hourly backups (retained per BACKUP_RETENTION_HOURS)
```
`storage/client-data` is bind-mounted into every world/auth/client-data container. Drop patched `dbc`, `maps`, `vmaps`, or `mmaps` files directly into that folder (e.g., `storage/client-data/dbc/SkillLine.dbc`) and the containers will read them immediately—perfect for modules like Individual Progression or mod-worgoblin that need to overwrite Blizzard data.
To tweak MySQL settings, place `.cnf` snippets in `storage/config/mysql/conf.d`. Files in this directory map straight to `/etc/mysql/conf.d` inside `ac-mysql`, so you can re-enable binary logs or tune buffers without rebuilding images.
**Local Storage** (`STORAGE_PATH_LOCAL` - default: `./local-storage`)
```
local-storage/
@@ -800,8 +813,7 @@ local-storage/
└── images/ # Exported Docker images for remote deployment
```
**Docker Volumes**
- `ac-client-data` - Unpacked game client data (DBC, maps, vmaps, mmaps)
**Docker Volume**
- `client-data-cache` - Temporary storage for client data downloads
This separation ensures database and build artifacts stay on fast local storage while configuration, modules, and backups can be shared across hosts via NFS.
@@ -1261,4 +1273,3 @@ This project builds upon:
- `3784` (authserver)
- `8215` (worldserver)
- Configure NAT/port forwarding for public access

View File

@@ -199,6 +199,37 @@ ensure_source_repo(){
echo "$src_path"
}
show_client_data_requirement(){
local repo_path="$1"
local detector="$ROOT_DIR/scripts/detect-client-data-version.sh"
if [ ! -x "$detector" ]; then
return
fi
local detection
if ! detection="$("$detector" --no-header "$repo_path" 2>/dev/null | head -n1)"; then
warn "Could not detect client data version for $repo_path"
return
fi
local detected_repo raw_version normalized_version
IFS=$'\t' read -r detected_repo raw_version normalized_version <<< "$detection"
if [ -z "$normalized_version" ] || [ "$normalized_version" = "<unknown>" ]; then
warn "Could not detect client data version for $repo_path"
return
fi
local env_value
env_value="$(read_env CLIENT_DATA_VERSION)"
if [ -n "$env_value" ] && [ "$env_value" != "$normalized_version" ]; then
warn "Source at $repo_path expects client data ${normalized_version} (raw ${raw_version}) but .env specifies ${env_value}. Update CLIENT_DATA_VERSION to avoid mismatched maps."
elif [ -n "$env_value" ]; then
info "Client data requirement satisfied: ${normalized_version} (raw ${raw_version})"
else
info "Detected client data requirement: ${normalized_version} (raw ${raw_version}). Set CLIENT_DATA_VERSION in .env to avoid mismatches."
fi
}
# Build state detection (extracted from setup.sh and deploy.sh)
modules_need_rebuild(){
local storage_path
@@ -576,6 +607,7 @@ main(){
info "Step 1/6: Setting up source repository"
src_dir="$(ensure_source_repo)"
show_client_data_requirement "$src_dir"
info "Step 2/6: Detecting build requirements"
readarray -t rebuild_reasons < <(detect_rebuild_reasons)

View File

@@ -11,7 +11,7 @@ set -e
# Resolve project dir and compose
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="${SCRIPT_DIR}"
COMPOSE_FILE="${PROJECT_DIR}/docker-compose.yml"
DEFAULT_COMPOSE_FILE="${PROJECT_DIR}/docker-compose.yml"
ENV_FILE="${PROJECT_DIR}/.env"
# Colors
@@ -87,7 +87,7 @@ confirm() {
format_container_table() {
local containers
containers="$(docker compose -f "$COMPOSE_FILE" ps -a --format 'table {{.Name}}\t{{.Status}}\t{{.Service}}\t{{.Image}}' 2>/dev/null || echo "")"
containers="$($COMPOSE_BASE ps -a --format 'table {{.Name}}\t{{.Status}}\t{{.Service}}\t{{.Image}}' 2>/dev/null || echo "")"
if [ -n "$containers" ]; then
echo "$containers" | head -1
echo "$containers" | tail -n +2 | while IFS=$'\t' read -r name status service image; do
@@ -124,6 +124,21 @@ STORAGE_PATH_LOCAL_DEFAULT="${PROJECT_DIR}/local-storage"
if [ -f "$ENV_FILE" ]; then
set -a; source "$ENV_FILE"; set +a
fi
COMPOSE_FILE_ARGS=(-f "$DEFAULT_COMPOSE_FILE")
if [ "${MYSQL_EXPOSE_PORT:-0}" = "1" ]; then
EXTRA_COMPOSE_FILE="${PROJECT_DIR}/docker-compose.mysql-expose.yml"
if [ -f "$EXTRA_COMPOSE_FILE" ]; then
COMPOSE_FILE_ARGS+=(-f "$EXTRA_COMPOSE_FILE")
else
print_status WARNING "MYSQL_EXPOSE_PORT=1 but $EXTRA_COMPOSE_FILE missing; skipping port exposure override."
fi
fi
COMPOSE_FILE_ARGS_STR=""
for arg in "${COMPOSE_FILE_ARGS[@]}"; do
COMPOSE_FILE_ARGS_STR+=" ${arg}"
done
COMPOSE_BASE="docker compose${COMPOSE_FILE_ARGS_STR}"
STORAGE_PATH="${STORAGE_PATH:-$STORAGE_PATH_DEFAULT}"
STORAGE_PATH_LOCAL="${STORAGE_PATH_LOCAL:-$STORAGE_PATH_LOCAL_DEFAULT}"
PROJECT_NAME="${COMPOSE_PROJECT_NAME:-ac-compose}"
@@ -170,7 +185,7 @@ soft_cleanup() {
--profile tools
--profile db
)
execute_command "Stopping runtime profiles" docker compose -f "$COMPOSE_FILE" "${profiles[@]}" down
execute_command "Stopping runtime profiles" $COMPOSE_BASE "${profiles[@]}" down
print_status SUCCESS "Soft cleanup complete"
}
@@ -187,7 +202,7 @@ hard_cleanup() {
--profile tools
--profile db
)
execute_command "Removing containers and networks" docker compose -f "$COMPOSE_FILE" "${profiles[@]}" down --remove-orphans
execute_command "Removing containers and networks" $COMPOSE_BASE "${profiles[@]}" down --remove-orphans
execute_command "Remove project volumes" remove_project_volumes
# Remove straggler containers matching project name (defensive)
execute_command "Remove stray project containers" "docker ps -a --format '{{.Names}}' | grep -E '^ac-' | xargs -r docker rm -f"
@@ -214,7 +229,7 @@ nuclear_cleanup() {
--profile tools
--profile db
)
execute_command "Removing containers, networks and volumes" docker compose -f "$COMPOSE_FILE" "${profiles[@]}" down --volumes --remove-orphans
execute_command "Removing containers, networks and volumes" $COMPOSE_BASE "${profiles[@]}" down --volumes --remove-orphans
execute_command "Remove leftover volumes" remove_project_volumes
# Remove project images (server/tool images typical to this project)
@@ -266,8 +281,8 @@ main(){
print_status ERROR "Docker not found"
exit 1
fi
if [ ! -f "$COMPOSE_FILE" ]; then
print_status ERROR "Compose file not found at $COMPOSE_FILE"
if [ ! -f "$DEFAULT_COMPOSE_FILE" ]; then
print_status ERROR "Compose file not found at $DEFAULT_COMPOSE_FILE"
exit 1
fi
if [ -z "$CLEANUP_LEVEL" ]; then

View File

@@ -5,7 +5,6 @@
"name": "mod-playerbots",
"repo": "https://github.com/mod-playerbots/mod-playerbots.git",
"description": "Adds scriptable playerbot characters that can form dungeon parties, raid, and PvP with humans",
"needs_build": false,
"type": "data",
"notes": "Installs SQL/config assets; core functionality is built into playerbot images",
"post_install_hooks": [],
@@ -14,14 +13,13 @@
],
"category": "automation",
"order": 1,
"special_message": "🤖 Foundation module: Enables AI-powered companions for solo and group content"
"special_message": "\ud83e\udd16 Foundation module: Enables AI-powered companions for solo and group content"
},
{
"key": "MODULE_AOE_LOOT",
"name": "mod-aoe-loot",
"repo": "https://github.com/azerothcore/mod-aoe-loot.git",
"description": "Lets characters loot multiple corpses with one click for faster farming",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -34,7 +32,6 @@
"name": "mod-learn-spells",
"repo": "https://github.com/azerothcore/mod-learn-spells.git",
"description": "Teaches class spells automatically at the correct level to streamline leveling",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -47,7 +44,6 @@
"name": "mod-fireworks-on-level",
"repo": "https://github.com/azerothcore/mod-fireworks-on-level.git",
"description": "Spawns celebratory fireworks whenever a player dings a new level",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -60,7 +56,6 @@
"name": "mod-individual-progression",
"repo": "https://github.com/ZhengPeiRu21/mod-individual-progression.git",
"description": "Tracks each character through Vanilla \u2192 TBC \u2192 WotLK progression, unlocking content sequentially",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -73,7 +68,6 @@
"name": "mod-ahbot",
"repo": "https://github.com/azerothcore/mod-ahbot.git",
"description": "Populates the auction house with configurable buying/selling behavior to keep markets active",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -85,7 +79,6 @@
"key": "MODULE_AUTOBALANCE",
"name": "mod-autobalance",
"repo": "https://github.com/azerothcore/mod-autobalance.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -98,7 +91,6 @@
"key": "MODULE_TRANSMOG",
"name": "mod-transmog",
"repo": "https://github.com/azerothcore/mod-transmog.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -111,7 +103,6 @@
"key": "MODULE_NPC_BUFFER",
"name": "mod-npc-buffer",
"repo": "https://github.com/azerothcore/mod-npc-buffer.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -124,7 +115,6 @@
"key": "MODULE_DYNAMIC_XP",
"name": "mod-dynamic-xp",
"repo": "https://github.com/azerothcore/mod-dynamic-xp.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -137,7 +127,6 @@
"key": "MODULE_SOLO_LFG",
"name": "mod-solo-lfg",
"repo": "https://github.com/azerothcore/mod-solo-lfg.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -150,7 +139,6 @@
"key": "MODULE_1V1_ARENA",
"name": "mod-1v1-arena",
"repo": "https://github.com/azerothcore/mod-1v1-arena.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -163,7 +151,6 @@
"key": "MODULE_PHASED_DUELS",
"name": "mod-phased-duels",
"repo": "https://github.com/azerothcore/mod-phased-duels.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -176,7 +163,6 @@
"key": "MODULE_BREAKING_NEWS",
"name": "mod-breaking-news-override",
"repo": "https://github.com/azerothcore/mod-breaking-news-override.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -189,7 +175,6 @@
"key": "MODULE_BOSS_ANNOUNCER",
"name": "mod-boss-announcer",
"repo": "https://github.com/azerothcore/mod-boss-announcer.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -202,7 +187,6 @@
"key": "MODULE_ACCOUNT_ACHIEVEMENTS",
"name": "mod-account-achievements",
"repo": "https://github.com/azerothcore/mod-account-achievements.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -215,7 +199,6 @@
"key": "MODULE_AUTO_REVIVE",
"name": "mod-auto-revive",
"repo": "https://github.com/azerothcore/mod-auto-revive.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -228,7 +211,6 @@
"key": "MODULE_GAIN_HONOR_GUARD",
"name": "mod-gain-honor-guard",
"repo": "https://github.com/azerothcore/mod-gain-honor-guard.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -241,7 +223,6 @@
"key": "MODULE_ELUNA",
"name": "mod-ale",
"repo": "https://github.com/azerothcore/mod-ale.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [
"mod-ale-patches"
@@ -252,13 +233,12 @@
"description": "Adds Eluna Lua scripting engine for creating custom gameplay mechanics",
"category": "scripting",
"order": 9998,
"special_message": " Advanced scripting: Required by many Lua-based modules. Enable this first if you plan to use scripted features"
"special_message": "\u26a1 Advanced scripting: Required by many Lua-based modules. Enable this first if you plan to use scripted features"
},
{
"key": "MODULE_TIME_IS_TIME",
"name": "mod-TimeIsTime",
"repo": "https://github.com/dunjeon/mod-TimeIsTime.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -271,7 +251,6 @@
"key": "MODULE_POCKET_PORTAL",
"name": "mod-pocket-portal",
"repo": "https://github.com/azerothcore/mod-pocket-portal.git",
"needs_build": true,
"type": "cpp",
"status": "blocked",
"block_reason": "Requires C++20 std::format support patch before enabling",
@@ -286,7 +265,6 @@
"key": "MODULE_RANDOM_ENCHANTS",
"name": "mod-random-enchants",
"repo": "https://github.com/azerothcore/mod-random-enchants.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -299,7 +277,6 @@
"key": "MODULE_SOLOCRAFT",
"name": "mod-solocraft",
"repo": "https://github.com/azerothcore/mod-solocraft.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -312,7 +289,6 @@
"key": "MODULE_PVP_TITLES",
"name": "mod-pvp-titles",
"repo": "https://github.com/azerothcore/mod-pvp-titles.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -328,7 +304,6 @@
"key": "MODULE_NPC_BEASTMASTER",
"name": "mod-npc-beastmaster",
"repo": "https://github.com/azerothcore/mod-npc-beastmaster.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [
"fix-beastmaster-sql"
@@ -343,7 +318,6 @@
"key": "MODULE_NPC_ENCHANTER",
"name": "mod-npc-enchanter",
"repo": "https://github.com/azerothcore/mod-npc-enchanter.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -356,7 +330,6 @@
"key": "MODULE_INSTANCE_RESET",
"name": "mod-instance-reset",
"repo": "https://github.com/azerothcore/mod-instance-reset.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -369,7 +342,6 @@
"key": "MODULE_LEVEL_GRANT",
"name": "mod-quest-count-level",
"repo": "https://github.com/michaeldelago/mod-quest-count-level.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -382,7 +354,6 @@
"key": "MODULE_ARAC",
"name": "mod-arac",
"repo": "https://github.com/heyitsbench/mod-arac.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -395,7 +366,6 @@
"key": "MODULE_ASSISTANT",
"name": "mod-assistant",
"repo": "https://github.com/noisiver/mod-assistant.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"description": "Spawns an all-purpose assistant NPC with heirlooms, professions, and convenience commands",
@@ -405,7 +375,6 @@
"key": "MODULE_REAGENT_BANK",
"name": "mod-reagent-bank",
"repo": "https://github.com/ZhengPeiRu21/mod-reagent-bank.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"description": "Lets players stash crafting reagents with a dedicated banker NPC",
@@ -415,7 +384,6 @@
"key": "MODULE_BLACK_MARKET_AUCTION_HOUSE",
"name": "mod-black-market",
"repo": "https://github.com/Youpeoples/Black-Market-Auction-House.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -430,7 +398,6 @@
"key": "MODULE_CHALLENGE_MODES",
"name": "mod-challenge-modes",
"repo": "https://github.com/ZhengPeiRu21/mod-challenge-modes.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"description": "Implements keystone-style timed runs with leaderboards and scaling modifiers",
@@ -440,7 +407,6 @@
"key": "MODULE_OLLAMA_CHAT",
"name": "mod-ollama-chat",
"repo": "https://github.com/DustinHendrickson/mod-ollama-chat.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"description": "Connects playerbots to an Ollama LLM so they can chat with humans organically",
@@ -450,7 +416,6 @@
"key": "MODULE_PLAYER_BOT_LEVEL_BRACKETS",
"name": "mod-player-bot-level-brackets",
"repo": "https://github.com/DustinHendrickson/mod-player-bot-level-brackets.git",
"needs_build": true,
"type": "cpp",
"requires": [
"MODULE_PLAYERBOTS"
@@ -463,7 +428,6 @@
"key": "MODULE_STATBOOSTER",
"name": "StatBooster",
"repo": "https://github.com/AnchyDev/StatBooster.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [
"fix-statbooster-api"
@@ -475,7 +439,6 @@
"key": "MODULE_DUNGEON_RESPAWN",
"name": "DungeonRespawn",
"repo": "https://github.com/AnchyDev/DungeonRespawn.git",
"needs_build": true,
"type": "cpp",
"status": "blocked",
"block_reason": "Upstream override signature mismatch (OnBeforeTeleport); awaiting fix",
@@ -487,7 +450,6 @@
"key": "MODULE_SKELETON_MODULE",
"name": "skeleton-module",
"repo": "https://github.com/azerothcore/skeleton-module.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"description": "Provides a minimal AzerothCore module scaffold for building new features",
@@ -497,7 +459,6 @@
"key": "MODULE_BG_SLAVERYVALLEY",
"name": "mod-bg-slaveryvalley",
"repo": "https://github.com/Helias/mod-bg-slaveryvalley.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"description": "Adds the Slavery Valley battleground complete with objectives and queue hooks",
@@ -510,7 +471,6 @@
"key": "MODULE_AZEROTHSHARD",
"name": "mod-azerothshard",
"repo": "https://github.com/azerothcore/mod-azerothshard.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"description": "Bundles AzerothShard tweaks: utility NPCs, scripted events, and gameplay improvements",
@@ -520,7 +480,6 @@
"key": "MODULE_WORGOBLIN",
"name": "mod-worgoblin",
"repo": "https://github.com/heyitsbench/mod-worgoblin.git",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"description": "Enables Worgen and Goblin characters with DB/DBC adjustments",
@@ -533,7 +492,6 @@
"key": "MODULE_ELUNA_TS",
"name": "eluna-ts",
"repo": "https://github.com/azerothcore/eluna-ts.git",
"needs_build": false,
"type": "tool",
"requires": [
"MODULE_ELUNA"
@@ -546,20 +504,18 @@
"key": "MODULE_AIO",
"name": "mod-aio",
"repo": "https://github.com/Rochet2/AIO.git",
"needs_build": true,
"type": "cpp",
"notes": "Azeroth Interface Override - enables client-server interface communication",
"post_install_hooks": [],
"description": "Pure Lua server-client communication system for bidirectional data transmission",
"category": "scripting",
"order": 9999,
"special_message": "🌉 UI Bridge: Enables advanced client-server interfaces. Most users don't need this unless using AIO-based modules"
"special_message": "\ud83c\udf09 UI Bridge: Enables advanced client-server interfaces. Most users don't need this unless using AIO-based modules"
},
{
"key": "MODULE_ELUNA_SCRIPTS",
"name": "eluna-scripts",
"repo": "https://github.com/Isidorsson/Eluna-scripts.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -574,7 +530,6 @@
"key": "MODULE_TRANSMOG_AIO",
"name": "azerothcore-transmog-3.3.5a",
"repo": "https://github.com/DanieltheDeveloper/azerothcore-transmog-3.3.5a.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_AIO"
@@ -589,7 +544,6 @@
"key": "MODULE_EVENT_SCRIPTS",
"name": "acore-eventscripts",
"repo": "https://github.com/55Honey/Acore_eventScripts.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -604,7 +558,6 @@
"key": "MODULE_LEVEL_UP_REWARD",
"name": "acore-levelupreward",
"repo": "https://github.com/55Honey/Acore_LevelUpReward.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -619,7 +572,6 @@
"key": "MODULE_ACCOUNTWIDE_SYSTEMS",
"name": "azerothcore-eluna-accountwide",
"repo": "https://github.com/Aldori15/azerothcore-eluna-accountwide.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -634,7 +586,6 @@
"key": "MODULE_EXCHANGE_NPC",
"name": "acore-exchangenpc",
"repo": "https://github.com/55Honey/Acore_ExchangeNpc.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -649,7 +600,6 @@
"key": "MODULE_RECRUIT_A_FRIEND",
"name": "acore-recruitafriend",
"repo": "https://github.com/55Honey/Acore_RecruitAFriend.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -664,7 +614,6 @@
"key": "MODULE_PRESTIGE_DRAFT_MODE",
"name": "prestige-and-draft-mode",
"repo": "https://github.com/Youpeoples/Prestige-and-Draft-Mode.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -679,7 +628,6 @@
"key": "MODULE_LUA_AH_BOT",
"name": "azerothcore-lua-ah-bot",
"repo": "https://github.com/mostlynick3/azerothcore-lua-ah-bot.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -694,7 +642,6 @@
"key": "MODULE_HARDCORE_MODE",
"name": "lua-hardcoremode",
"repo": "https://github.com/HellionOP/Lua-HardcoreMode.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -709,7 +656,6 @@
"key": "MODULE_NPCBOT_EXTENDED_COMMANDS",
"name": "npcbot-extended-commands",
"repo": "https://github.com/Day36512/Npcbot_Extended_Commands.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -724,7 +670,6 @@
"key": "MODULE_MULTIVENDOR",
"name": "azerothcore-lua-multivendor",
"repo": "https://github.com/Shadowveil-WotLK/AzerothCore-lua-MultiVendor.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -739,7 +684,6 @@
"key": "MODULE_TREASURE_CHEST_SYSTEM",
"name": "treasure-chest-system",
"repo": "https://github.com/zyggy123/Treasure-Chest-System.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -754,7 +698,6 @@
"key": "MODULE_ACTIVE_CHAT",
"name": "activechat",
"repo": "https://github.com/Day36512/ActiveChat.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -769,7 +712,6 @@
"key": "MODULE_ULTIMATE_FULL_LOOT_PVP",
"name": "ultimate-full-loot-pvp",
"repo": "https://github.com/Youpeoples/Ultimate-Full-Loot-Pvp.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -784,7 +726,6 @@
"key": "MODULE_HORADRIC_CUBE",
"name": "horadric-cube-for-world-of-warcraft",
"repo": "https://github.com/TITIaio/Horadric-Cube-for-World-of-Warcraft.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -799,7 +740,6 @@
"key": "MODULE_CARBON_COPY",
"name": "acore-carboncopy",
"repo": "https://github.com/55Honey/Acore_CarbonCopy.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -814,7 +754,6 @@
"key": "MODULE_TEMP_ANNOUNCEMENTS",
"name": "acore-tempannouncements",
"repo": "https://github.com/55Honey/Acore_TempAnnouncements.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -829,7 +768,6 @@
"key": "MODULE_ZONE_CHECK",
"name": "acore-zonecheck",
"repo": "https://github.com/55Honey/Acore_Zonecheck.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -844,7 +782,6 @@
"key": "MODULE_AIO_BLACKJACK",
"name": "aio-blackjack",
"repo": "https://github.com/Manmadedrummer/AIO-Blackjack.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_AIO"
@@ -859,7 +796,6 @@
"key": "MODULE_SEND_AND_BIND",
"name": "acore-sendandbind",
"repo": "https://github.com/55Honey/Acore_SendAndBind.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -874,7 +810,6 @@
"key": "MODULE_DYNAMIC_TRADER",
"name": "dynamic-trader",
"repo": "https://github.com/Day36512/Dynamic-Trader.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -889,7 +824,6 @@
"key": "MODULE_LOTTERY_LUA",
"name": "lottery-lua",
"repo": "https://github.com/zyggy123/lottery-lua.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -904,7 +838,6 @@
"key": "MODULE_DISCORD_NOTIFIER",
"name": "acore-discordnotifier",
"repo": "https://github.com/0xCiBeR/Acore_DiscordNotifier.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -919,7 +852,6 @@
"key": "MODULE_GLOBAL_MAIL_BANKING_AUCTIONS",
"name": "azerothcore-global-mail-banking-auctions",
"repo": "https://github.com/Aldori15/azerothcore-global-mail_banking_auctions.git",
"needs_build": false,
"type": "lua",
"requires": [
"MODULE_ELUNA"
@@ -935,7 +867,6 @@
"name": "mod-guildhouse",
"repo": "https://github.com/azerothcore/mod-guildhouse.git",
"description": "Phased guild house system allowing guild members to visit their private guild house",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -948,7 +879,6 @@
"name": "mod-progression-system",
"repo": "https://github.com/azerothcore/mod-progression-system.git",
"description": "Allows for the automatic loading of scripts and SQL files based on level brackets",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -962,7 +892,6 @@
"name": "mod-npc-free-professions",
"repo": "https://github.com/azerothcore/mod-npc-free-professions.git",
"description": "Makes a ProfessionsNPC who gives 2 free professions (full with recipes) to player",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -973,7 +902,6 @@
"name": "mod-duel-reset",
"repo": "https://github.com/azerothcore/mod-duel-reset.git",
"description": "Adds some duel reset features",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -986,7 +914,6 @@
"name": "mod-zone-difficulty",
"repo": "https://github.com/azerothcore/mod-zone-difficulty.git",
"description": "Support module for mod-progression-system, handles nerfs and debuffs per zone",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -998,7 +925,6 @@
"name": "mod-morphsummon",
"repo": "https://github.com/azerothcore/mod-morphsummon.git",
"description": "Change appearance of summoned permanent creatures",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -1012,7 +938,6 @@
"name": "mod-spell-regulator",
"repo": "https://github.com/azerothcore/mod-spell-regulator.git",
"description": "Modify the percentage of the spells by regulating in the best way",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -1024,7 +949,6 @@
"name": "mod-weekend-xp",
"repo": "https://github.com/azerothcore/mod-weekend-xp.git",
"description": "XP module that allows server owner to select how much XP players can receive on the weekend via config file",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -1037,7 +961,6 @@
"name": "mod-reward-played-time",
"repo": "https://github.com/azerothcore/mod-reward-played-time.git",
"description": "Adds items for players that have stayed logged in for x amount of time",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -1050,7 +973,6 @@
"name": "mod-resurrection-scroll",
"repo": "https://github.com/azerothcore/mod-resurrection-scroll.git",
"description": "Allows users to grant rested XP bonuses to players who have not logged in X days",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -1062,7 +984,6 @@
"name": "mod-item-level-up",
"repo": "https://github.com/azerothcore/mod-item-level-up.git",
"description": "Creates an item that allows you to level up (id = 701001)",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -1073,7 +994,6 @@
"name": "mod-npc-talent-template",
"repo": "https://github.com/azerothcore/mod-npc-talent-template.git",
"description": "An NPC that allows players to instantly apply pre-configured character templates that gear up, gem, set talents, and apply glyphs for any class",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -1085,7 +1005,6 @@
"name": "mod-global-chat",
"repo": "https://github.com/azerothcore/mod-global-chat.git",
"description": "Simple global chat for AzerothCore enabling worldserver-wide messaging functionality",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -1098,7 +1017,6 @@
"name": "mod-premium",
"repo": "https://github.com/azerothcore/mod-premium.git",
"description": "Adds Premium account features to players",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -1112,7 +1030,6 @@
"name": "mod-system-vip",
"repo": "https://github.com/azerothcore/mod-system-vip.git",
"description": "System offering VIP features and benefits to players",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -1125,7 +1042,6 @@
"name": "mod-acore-subscriptions",
"repo": "https://github.com/azerothcore/mod-acore-subscriptions.git",
"description": "Handles the subscription logic, no longer requires modules or services to have subscription logic in their code",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -1136,7 +1052,6 @@
"name": "mod-keep-out",
"repo": "https://github.com/azerothcore/mod-keep-out.git",
"description": "Keeps players who are non-GM from entering a zone/map",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -1148,7 +1063,6 @@
"name": "mod-server-auto-shutdown",
"repo": "https://github.com/azerothcore/mod-server-auto-shutdown.git",
"description": "Establishes a daily restart with configurable time, notification period, and custom messages",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -1159,7 +1073,6 @@
"name": "mod-who-logged",
"repo": "https://github.com/azerothcore/mod-who-logged.git",
"description": "Outputs to the console when a player logs into the world",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -1172,7 +1085,6 @@
"name": "mod-account-mounts",
"repo": "https://github.com/azerothcore/mod-account-mounts.git",
"description": "Goes through the list of characters on an account to obtain playerGuids and store mount spells that all characters know",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -1183,7 +1095,6 @@
"name": "mod-antifarming",
"repo": "https://github.com/azerothcore/mod-antifarming.git",
"description": "Port of the AntiFarming Script from SymbolixDEV's repo to AzerothCore",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -1196,7 +1107,6 @@
"name": "mod-arena-replay",
"repo": "https://github.com/azerothcore/mod-arena-replay.git",
"description": "Allows you to watch a replay of rated arena games",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -1208,7 +1118,6 @@
"name": "mod-tic-tac-toe",
"repo": "https://github.com/azerothcore/mod-tic-tac-toe.git",
"description": "Allows players to play Tic Tac Toe between players and against different AI",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [],
@@ -1220,7 +1129,6 @@
"name": "mod-war-effort",
"repo": "https://github.com/azerothcore/mod-war-effort.git",
"description": "Brings back the war effort of the two factions for the opening of the gates of Ahn'Qiraj",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [
@@ -1233,7 +1141,6 @@
"name": "mod-promotion-azerothcore",
"repo": "https://github.com/azerothcore/mod-promotion-azerothcore.git",
"description": "Allows player to receive a promotion consisting of a level 90 character, backpacks, gold, armor, and a mount",
"needs_build": true,
"type": "cpp",
"post_install_hooks": [],
"config_cleanup": [

View File

@@ -9,7 +9,7 @@
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
DEFAULT_COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
ENV_PATH="$ROOT_DIR/.env"
TARGET_PROFILE=""
WATCH_LOGS=1
@@ -29,6 +29,7 @@ REMOTE_ARGS_PROVIDED=0
MODULE_HELPER="$ROOT_DIR/scripts/modules.py"
MODULE_STATE_INITIALIZED=0
declare -a MODULES_COMPILE_LIST=()
declare -a COMPOSE_FILE_ARGS=()
BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
info(){ printf '%b\n' "${BLUE} $*${NC}"; }
@@ -278,6 +279,22 @@ read_env(){
echo "$value"
}
init_compose_files(){
local expose_port
expose_port="$(read_env MYSQL_EXPOSE_PORT "0")"
COMPOSE_FILE_ARGS=(-f "$DEFAULT_COMPOSE_FILE")
if [ "$expose_port" = "1" ]; then
local extra_file="$ROOT_DIR/docker-compose.mysql-expose.yml"
if [ -f "$extra_file" ]; then
COMPOSE_FILE_ARGS+=(-f "$extra_file")
else
warn "MYSQL_EXPOSE_PORT=1 but $extra_file not found; skipping port override"
fi
fi
}
init_compose_files
resolve_local_storage_path(){
local path
path="$(read_env STORAGE_PATH_LOCAL "./local-storage")"
@@ -376,7 +393,7 @@ compose(){
local project_name
project_name="$(resolve_project_name)"
# Add --quiet for less verbose output, filter excessive empty lines
docker compose --project-name "$project_name" -f "$COMPOSE_FILE" "$@" | filter_empty_lines
docker compose --project-name "$project_name" "${COMPOSE_FILE_ARGS[@]}" "$@" | filter_empty_lines
}
# Build detection logic

View File

@@ -0,0 +1,5 @@
services:
ac-mysql:
# Optional override that publishes the MySQL port when MYSQL_EXPOSE_PORT=1
ports:
- "${MYSQL_EXTERNAL_PORT}:${MYSQL_PORT}"

View File

@@ -18,8 +18,6 @@ services:
MYSQL_MAX_CONNECTIONS: ${MYSQL_MAX_CONNECTIONS}
MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_INNODB_BUFFER_POOL_SIZE}
MYSQL_INNODB_LOG_FILE_SIZE: ${MYSQL_INNODB_LOG_FILE_SIZE}
ports:
- "${MYSQL_EXTERNAL_PORT}:${MYSQL_PORT}"
entrypoint:
- /usr/local/bin/mysql-entrypoint.sh
volumes:
@@ -27,6 +25,7 @@ services:
- ${STORAGE_PATH_LOCAL}/mysql-data:/var/lib/mysql-persistent
- ${BACKUP_PATH}:/backups
- ${HOST_ZONEINFO_PATH}:/usr/share/zoneinfo:ro
- ${MYSQL_CONFIG_DIR:-${STORAGE_PATH}/config/mysql/conf.d}:/etc/mysql/conf.d
tmpfs:
- /var/lib/mysql-runtime:size=${MYSQL_RUNTIME_TMPFS_SIZE}
command:
@@ -210,12 +209,13 @@ services:
container_name: ac-volume-init
user: "0:0"
volumes:
- ac-client-data:/azerothcore/data
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- client-data-cache:/cache
command:
- sh
- -c
- |
mkdir -p /azerothcore/data
echo "🔧 Fixing Docker volume permissions..."
chown -R ${CONTAINER_USER} /azerothcore/data /cache
chmod -R 755 /azerothcore/data /cache
@@ -236,6 +236,8 @@ services:
- |
echo "🔧 Initializing storage directories with proper permissions..."
mkdir -p /storage-root/config /storage-root/logs /storage-root/modules /storage-root/lua_scripts /storage-root/install-markers
mkdir -p /storage-root/config/mysql/conf.d
mkdir -p /storage-root/client-data
mkdir -p /storage-root/backups /local-storage-root/mysql-data
# Fix ownership of root directories and all contents
chown -R ${CONTAINER_USER} /storage-root /local-storage-root
@@ -255,7 +257,7 @@ services:
ac-volume-init:
condition: service_completed_successfully
volumes:
- ac-client-data:/azerothcore/data
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- client-data-cache:/cache
- ./scripts:/tmp/scripts:ro
working_dir: /tmp
@@ -286,7 +288,7 @@ services:
ac-volume-init:
condition: service_completed_successfully
volumes:
- ac-client-data:/azerothcore/data
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- client-data-cache:/cache
- ./scripts:/tmp/scripts:ro
working_dir: /tmp
@@ -380,7 +382,7 @@ services:
- "${WORLD_EXTERNAL_PORT}:${WORLD_PORT}"
- "${SOAP_EXTERNAL_PORT}:${SOAP_PORT}"
volumes:
- ac-client-data:/azerothcore/data
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs
- ${STORAGE_PATH}/modules:/azerothcore/modules
@@ -503,7 +505,7 @@ services:
- "${WORLD_EXTERNAL_PORT}:${WORLD_PORT}"
- "${SOAP_EXTERNAL_PORT}:${SOAP_PORT}"
volumes:
- ac-client-data:/azerothcore/data
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs
- ${STORAGE_PATH}/modules:/azerothcore/modules
@@ -550,7 +552,7 @@ services:
PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS}"
AC_LOG_LEVEL: "2"
volumes:
- ac-client-data:/azerothcore/data
- ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs
- ${STORAGE_PATH}/modules:/azerothcore/modules
@@ -723,9 +725,6 @@ services:
- azerothcore
volumes:
ac-client-data:
name: ${CLIENT_DATA_VOLUME}
driver: local
client-data-cache:
driver: local

View File

@@ -5,8 +5,9 @@
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.."
COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
DEFAULT_COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
ENV_FILE="$ROOT_DIR/.env"
declare -a COMPOSE_FILE_ARGS=()
BLUE='\033[0;34m'
GREEN='\033[0;32m'
@@ -44,8 +45,22 @@ resolve_project_name(){
echo "$sanitized"
}
init_compose_files(){
COMPOSE_FILE_ARGS=(-f "$DEFAULT_COMPOSE_FILE")
if [ "$(read_env MYSQL_EXPOSE_PORT "0")" = "1" ]; then
local extra_file="$ROOT_DIR/docker-compose.mysql-expose.yml"
if [ -f "$extra_file" ]; then
COMPOSE_FILE_ARGS+=(-f "$extra_file")
else
warn "MYSQL_EXPOSE_PORT=1 but $extra_file missing; skipping port override."
fi
fi
}
init_compose_files
compose(){
docker compose --project-name "$PROJECT_NAME" -f "$COMPOSE_FILE" "$@"
docker compose --project-name "$PROJECT_NAME" "${COMPOSE_FILE_ARGS[@]}" "$@"
}
show_header(){

View File

@@ -0,0 +1,85 @@
#!/usr/bin/env bash
#
# Detect which wowgaming/client-data release an AzerothCore checkout expects.
# Currently inspects apps/installer/includes/functions.sh for the
# inst_download_client_data version marker, but can be extended with new
# heuristics if needed.
set -euo pipefail
print_usage() {
cat <<'EOF'
Usage: scripts/detect-client-data-version.sh [--no-header] <repo-path> [...]
Outputs a tab-separated list of repository path, raw version token found in the
source tree, and a normalized CLIENT_DATA_VERSION (e.g., v18).
EOF
}
if [[ "${1:-}" == "--help" ]]; then
print_usage
exit 0
fi
show_header=1
if [[ "${1:-}" == "--no-header" ]]; then
show_header=0
shift
fi
if [[ $# -lt 1 ]]; then
print_usage >&2
exit 1
fi
normalize_version() {
local token="$1"
token="${token//$'\r'/}"
token="${token//\"/}"
token="${token//\'/}"
token="${token// /}"
token="${token%%#*}"
token="${token%%;*}"
token="${token%%\)*}"
token="${token%%\}*}"
echo "$token"
}
detect_from_installer() {
local repo_path="$1"
local installer_file="$repo_path/apps/installer/includes/functions.sh"
[[ -f "$installer_file" ]] || return 1
local raw
raw="$(grep -E 'local[[:space:]]+VERSION=' "$installer_file" | head -n1 | cut -d'=' -f2-)"
[[ -n "$raw" ]] || return 1
echo "$raw"
}
detect_version() {
local repo_path="$1"
if [[ ! -d "$repo_path" ]]; then
printf '%s\t%s\t%s\n' "$repo_path" "<missing>" "<unknown>"
return
fi
local raw=""
if raw="$(detect_from_installer "$repo_path")"; then
:
elif [[ -f "$repo_path/.env" ]]; then
raw="$(grep -E '^CLIENT_DATA_VERSION=' "$repo_path/.env" | head -n1 | cut -d'=' -f2-)"
fi
if [[ -z "$raw" ]]; then
printf '%s\t%s\t%s\n' "$repo_path" "<unknown>" "<unknown>"
return
fi
local normalized
normalized="$(normalize_version "$raw")"
printf '%s\t%s\t%s\n' "$repo_path" "$raw" "$normalized"
}
[[ "$show_header" -eq 0 ]] || printf 'repo\traw\tclient_data_version\n'
for repo in "$@"; do
detect_version "$repo"
done

View File

@@ -131,9 +131,10 @@ class ModuleCollectionState:
def requires_playerbot_source(self) -> bool:
module_map = {m.key: m for m in self.modules}
playerbots_enabled = module_map.get("MODULE_PLAYERBOTS")
playerbots = bool(playerbots_enabled and playerbots_enabled.enabled_effective)
needs_cpp = any(module.needs_build and module.enabled_effective for module in self.modules)
return playerbots or needs_cpp
return bool(playerbots_enabled and playerbots_enabled.enabled_effective)
def requires_custom_build(self) -> bool:
return any(module.needs_build and module.enabled_effective for module in self.modules)
def build_state(env_path: Path, manifest_path: Path) -> ModuleCollectionState:
@@ -150,8 +151,12 @@ def build_state(env_path: Path, manifest_path: Path) -> ModuleCollectionState:
key = entry["key"]
name = entry["name"]
repo = entry["repo"]
needs_build = bool(entry.get("needs_build", False))
module_type = str(entry.get("type", "cpp"))
needs_build_flag = entry.get("needs_build")
if needs_build_flag is None:
needs_build = module_type.lower() == "cpp"
else:
needs_build = bool(needs_build_flag)
requires = entry.get("requires") or []
if not isinstance(requires, list):
raise ValueError(f"Manifest entry {key} has non-list 'requires'")
@@ -263,20 +268,30 @@ def write_outputs(state: ModuleCollectionState, output_dir: Path) -> None:
enabled_names: List[str] = []
compile_names: List[str] = []
enabled_keys: List[str] = []
compile_keys: List[str] = []
for module in state.modules:
env_lines.append(f"export {module.key}={module.value}")
if module.enabled_effective:
enabled_names.append(module.name)
enabled_keys.append(module.key)
if module.enabled_effective and module.needs_build:
compile_names.append(module.name)
compile_keys.append(module.key)
env_lines.append(f'export MODULES_ENABLED="{ " ".join(enabled_names) }"'.rstrip())
env_lines.append(f'export MODULES_COMPILE="{ " ".join(compile_names) }"'.rstrip())
env_lines.append(f'export MODULES_ENABLED_LIST="{",".join(enabled_keys)}"')
env_lines.append(f'export MODULES_CPP_LIST="{",".join(compile_keys)}"')
env_lines.append(
f"export MODULES_REQUIRES_PLAYERBOT_SOURCE="
f'{"1" if state.requires_playerbot_source() else "0"}'
)
env_lines.append(
f"export MODULES_REQUIRES_CUSTOM_BUILD="
f'{"1" if state.requires_custom_build() else "0"}'
)
env_lines.append(f"export MODULES_WARNING_COUNT={len(state.warnings)}")
env_lines.append(f"export MODULES_ERROR_COUNT={len(state.errors)}")
@@ -301,6 +316,7 @@ def write_outputs(state: ModuleCollectionState, output_dir: Path) -> None:
"enabled_modules": [module.name for module in state.enabled_modules()],
"compile_modules": [module.name for module in state.compile_modules()],
"requires_playerbot_source": state.requires_playerbot_source(),
"requires_custom_build": state.requires_custom_build(),
}
modules_state_path = output_dir / "modules-state.json"
@@ -342,6 +358,11 @@ def print_requires_playerbot(state: ModuleCollectionState) -> None:
print("1" if state.requires_playerbot_source() else "0")
def print_requires_custom_build(state: ModuleCollectionState) -> None:
print("1" if state.requires_custom_build() else "0")
def print_state(state: ModuleCollectionState, fmt: str) -> None:
payload = {
"generated_at": state.generated_at.isoformat(),
@@ -485,6 +506,18 @@ def configure_parser() -> argparse.ArgumentParser:
rps_parser.set_defaults(func=handle_requires_playerbot)
rcb_parser = subparsers.add_parser(
"requires-custom-build",
help="Print 1 if a custom source build is required else 0",
)
def handle_requires_custom_build(args: argparse.Namespace) -> int:
state = build_state(Path(args.env_path).resolve(), Path(args.manifest).resolve())
print_requires_custom_build(state)
return 1 if state.errors else 0
rcb_parser.set_defaults(func=handle_requires_custom_build)
dump_parser = subparsers.add_parser("dump", help="Dump module state (JSON format)")
dump_parser.add_argument(
"--format",

View File

@@ -79,4 +79,18 @@ for path in /var/lib/mysql-runtime /var/lib/mysql /var/lib/mysql-persistent /bac
fi
done
disable_binlog="${MYSQL_DISABLE_BINLOG:-}"
if [ "${disable_binlog}" = "1" ]; then
add_skip_flag=1
for arg in "$@"; do
if [ "$arg" = "--skip-log-bin" ] || [[ "$arg" == --log-bin* ]]; then
add_skip_flag=0
break
fi
done
if [ "$add_skip_flag" -eq 1 ]; then
set -- "$@" --skip-log-bin
fi
fi
exec "$ORIGINAL_ENTRYPOINT" "$@"

View File

@@ -14,36 +14,55 @@ PROJECT_ROOT="$(pwd)"
# Default values
MODULE_PLAYERBOTS="${MODULE_PLAYERBOTS:-0}"
NEEDS_CXX_REBUILD="${NEEDS_CXX_REBUILD:-0}"
COMPILE_MODULE_KEYS=(
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_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_CHALLENGE_MODES MODULE_OLLAMA_CHAT MODULE_PLAYER_BOT_LEVEL_BRACKETS MODULE_STATBOOSTER MODULE_DUNGEON_RESPAWN
MODULE_SKELETON_MODULE MODULE_BG_SLAVERYVALLEY MODULE_AZEROTHSHARD MODULE_WORGOBLIN
)
if [ "$NEEDS_CXX_REBUILD" != "1" ]; then
for key in "${COMPILE_MODULE_KEYS[@]}"; do
if [ "${!key:-0}" = "1" ]; then
NEEDS_CXX_REBUILD=1
break
PLAYERBOT_ENABLED="${PLAYERBOT_ENABLED:-0}"
STACK_SOURCE_VARIANT="${STACK_SOURCE_VARIANT:-}"
if [ -z "$STACK_SOURCE_VARIANT" ]; then
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$PLAYERBOT_ENABLED" = "1" ]; then
STACK_SOURCE_VARIANT="playerbots"
else
STACK_SOURCE_VARIANT="core"
fi
done
fi
LOCAL_STORAGE_ROOT="${STORAGE_PATH_LOCAL:-./local-storage}"
DEFAULT_STANDARD_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore"
DEFAULT_PLAYERBOTS_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore-playerbots"
SOURCE_PATH_DEFAULT="$DEFAULT_STANDARD_PATH"
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$NEEDS_CXX_REBUILD" = "1" ]; then
if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
SOURCE_PATH_DEFAULT="$DEFAULT_PLAYERBOTS_PATH"
fi
SOURCE_PATH="${MODULES_REBUILD_SOURCE_PATH:-$SOURCE_PATH_DEFAULT}"
show_client_data_requirement(){
local repo_path="$1"
local detector="$PROJECT_ROOT/scripts/detect-client-data-version.sh"
if [ ! -x "$detector" ]; then
return
fi
local detection
if ! detection="$("$detector" --no-header "$repo_path" 2>/dev/null | head -n1)"; then
echo "⚠️ Could not detect client data version for $repo_path"
return
fi
local detected_repo raw_version normalized_version
IFS=$'\t' read -r detected_repo raw_version normalized_version <<< "$detection"
if [ -z "$normalized_version" ] || [ "$normalized_version" = "<unknown>" ]; then
echo "⚠️ Could not detect client data version for $repo_path"
return
fi
local env_value="${CLIENT_DATA_VERSION:-}"
if [ -n "$env_value" ] && [ "$env_value" != "$normalized_version" ]; then
echo "⚠️ Source requires client data ${normalized_version} (raw ${raw_version}) but .env specifies ${env_value}. Update CLIENT_DATA_VERSION to avoid mismatched maps."
elif [ -n "$env_value" ]; then
echo "📦 Client data requirement satisfied: ${normalized_version} (raw ${raw_version})"
else
echo " Detected client data requirement: ${normalized_version} (raw ${raw_version}). Set CLIENT_DATA_VERSION in .env to avoid mismatches."
fi
}
STORAGE_PATH_VALUE="${STORAGE_PATH:-./storage}"
if [[ "$STORAGE_PATH_VALUE" != /* ]]; then
STORAGE_PATH_ABS="$PROJECT_ROOT/${STORAGE_PATH_VALUE#./}"
@@ -72,8 +91,8 @@ ACORE_BRANCH_STANDARD="${ACORE_BRANCH_STANDARD:-master}"
ACORE_REPO_PLAYERBOTS="${ACORE_REPO_PLAYERBOTS:-https://github.com/mod-playerbots/azerothcore-wotlk.git}"
ACORE_BRANCH_PLAYERBOTS="${ACORE_BRANCH_PLAYERBOTS:-Playerbot}"
# Repository and branch selection based on playerbots mode
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$NEEDS_CXX_REBUILD" = "1" ]; then
# Repository and branch selection based on source variant
if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
REPO_URL="$ACORE_REPO_PLAYERBOTS"
BRANCH="$ACORE_BRANCH_PLAYERBOTS"
echo "📌 Playerbots mode: Using $REPO_URL, branch $BRANCH"
@@ -130,5 +149,6 @@ echo "📊 Current status:"
echo " Branch: $CURRENT_BRANCH"
echo " Commit: $CURRENT_COMMIT"
echo " Last commit: $(git log -1 --pretty=format:'%s (%an, %ar)')"
show_client_data_requirement "$SOURCE_PATH"
echo '🎉 Source repository setup complete!'

View File

@@ -58,8 +58,13 @@ def cmd_metadata(manifest_path: str) -> None:
for entry in iter_modules(manifest):
key = entry["key"]
name = clean(entry.get("name", key))
needs_build = "1" if entry.get("needs_build") else "0"
module_type = clean(entry.get("type", ""))
module_type_raw = entry.get("type", "")
module_type = clean(module_type_raw)
needs_build_flag = entry.get("needs_build")
if needs_build_flag is None:
needs_build = "1" if str(module_type_raw).lower() == "cpp" else "0"
else:
needs_build = "1" if needs_build_flag else "0"
status = clean(entry.get("status", "active"))
block_reason = clean(entry.get("block_reason", ""))
requires = unique_preserve_order(entry.get("requires") or [])

View File

@@ -64,6 +64,8 @@ sync_local_staging(){
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="$PROJECT_DIR/.env"
DEFAULT_COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
EXTRA_COMPOSE_FILE="$PROJECT_DIR/docker-compose.mysql-expose.yml"
usage(){
cat <<EOF
@@ -112,6 +114,19 @@ resolve_project_name(){
echo "$sanitized"
}
if [ -z "${COMPOSE_FILE:-}" ]; then
compose_files=("$DEFAULT_COMPOSE_FILE")
if [ "$(read_env MYSQL_EXPOSE_PORT "0")" = "1" ]; then
if [ -f "$EXTRA_COMPOSE_FILE" ]; then
compose_files+=("$EXTRA_COMPOSE_FILE")
else
echo "⚠️ MYSQL_EXPOSE_PORT=1 but ${EXTRA_COMPOSE_FILE} not found; continuing without port exposure override."
fi
fi
COMPOSE_FILE="$(IFS=:; echo "${compose_files[*]}")"
export COMPOSE_FILE
fi
resolve_project_image(){
local tag="$1"
local project_name

View File

@@ -10,7 +10,8 @@ ok(){ echo -e "${GREEN}✅ $*${NC}"; }
warn(){ echo -e "${YELLOW}⚠️ $*${NC}"; }
err(){ echo -e "${RED}$*${NC}"; }
COMPOSE_FILE="$(dirname "$0")/docker-compose.yml"
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
ENV_FILE=""
PROFILES=(db services-standard client-data modules tools)
SKIP_DEPLOY=false
@@ -72,6 +73,15 @@ run_compose(){
compose_args+=(--env-file "$ENV_FILE")
fi
compose_args+=(-f "$COMPOSE_FILE")
if [ "$(read_env_value MYSQL_EXPOSE_PORT "0")" = "1" ]; then
local extra_file
extra_file="$(dirname "$COMPOSE_FILE")/docker-compose.mysql-expose.yml"
if [ -f "$extra_file" ]; then
compose_args+=(-f "$extra_file")
else
warn "MYSQL_EXPOSE_PORT=1 but ${extra_file} missing; skipping port exposure override."
fi
fi
docker compose "${compose_args[@]}" "$@"
}

View File

@@ -68,6 +68,7 @@ declare -A TEMPLATE_VALUE_MAP=(
[DEFAULT_AUTH_PORT]=AUTH_EXTERNAL_PORT
[DEFAULT_SOAP_PORT]=SOAP_EXTERNAL_PORT
[DEFAULT_MYSQL_PORT]=MYSQL_EXTERNAL_PORT
[DEFAULT_MYSQL_EXPOSE_PORT]=MYSQL_EXPOSE_PORT
[DEFAULT_PLAYERBOT_MIN]=PLAYERBOT_MIN_BOTS
[DEFAULT_PLAYERBOT_MAX]=PLAYERBOT_MAX_BOTS
[DEFAULT_LOCAL_STORAGE]=STORAGE_PATH
@@ -112,7 +113,7 @@ declare -A TEMPLATE_VALUE_MAP=(
[DEFAULT_CONTAINER_MODULES]=CONTAINER_MODULES
[DEFAULT_CONTAINER_POST_INSTALL]=CONTAINER_POST_INSTALL
[DEFAULT_COMPOSE_PROJECT_NAME]=COMPOSE_PROJECT_NAME
[DEFAULT_CLIENT_DATA_VOLUME]=CLIENT_DATA_VOLUME
[DEFAULT_CLIENT_DATA_PATH]=CLIENT_DATA_PATH
[DEFAULT_CLIENT_DATA_CACHE_PATH]=CLIENT_DATA_CACHE_PATH
[DEFAULT_CLIENT_DATA_VERSION]=CLIENT_DATA_VERSION
[DEFAULT_NETWORK_NAME]=NETWORK_NAME
@@ -125,6 +126,8 @@ declare -A TEMPLATE_VALUE_MAP=(
[DEFAULT_MYSQL_INNODB_LOG_FILE_SIZE]=MYSQL_INNODB_LOG_FILE_SIZE
[DEFAULT_MYSQL_INNODB_REDO_LOG_CAPACITY]=MYSQL_INNODB_REDO_LOG_CAPACITY
[DEFAULT_MYSQL_RUNTIME_TMPFS_SIZE]=MYSQL_RUNTIME_TMPFS_SIZE
[DEFAULT_MYSQL_DISABLE_BINLOG]=MYSQL_DISABLE_BINLOG
[DEFAULT_MYSQL_CONFIG_DIR]=MYSQL_CONFIG_DIR
[DEFAULT_MYSQL_HOST]=MYSQL_HOST
[DEFAULT_DB_WAIT_RETRIES]=DB_WAIT_RETRIES
[DEFAULT_DB_WAIT_SLEEP]=DB_WAIT_SLEEP
@@ -902,10 +905,7 @@ fi
local STORAGE_PATH
if [ -n "$CLI_STORAGE_PATH" ]; then
STORAGE_PATH="$CLI_STORAGE_PATH"
elif [ "$DEPLOYMENT_TYPE" = "local" ]; then
STORAGE_PATH=$DEFAULT_LOCAL_STORAGE
else
if [ "$NON_INTERACTIVE" = "1" ]; then
elif [ "$NON_INTERACTIVE" = "1" ]; then
STORAGE_PATH=$DEFAULT_MOUNT_STORAGE
else
echo "1) 💾 ./storage (local)"
@@ -921,7 +921,6 @@ fi
esac
done
fi
fi
# Backup
say HEADER "BACKUP CONFIGURATION"
@@ -1300,6 +1299,42 @@ fi
fi
done
local enabled_module_keys=()
local enabled_cpp_module_keys=()
for mod_var in "${MODULE_KEYS[@]}"; do
eval "value=\${$mod_var:-0}"
if [ "$value" = "1" ]; then
enabled_module_keys+=("$mod_var")
if [ "${MODULE_NEEDS_BUILD_MAP[$mod_var]}" = "1" ]; then
enabled_cpp_module_keys+=("$mod_var")
fi
fi
done
local MODULES_ENABLED_LIST=""
local MODULES_CPP_LIST=""
if [ ${#enabled_module_keys[@]} -gt 0 ]; then
MODULES_ENABLED_LIST="$(IFS=','; printf '%s' "${enabled_module_keys[*]}")"
fi
if [ ${#enabled_cpp_module_keys[@]} -gt 0 ]; then
MODULES_CPP_LIST="$(IFS=','; printf '%s' "${enabled_cpp_module_keys[*]}")"
fi
local STACK_IMAGE_MODE="standard"
local STACK_SOURCE_VARIANT="core"
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$PLAYERBOT_ENABLED" = "1" ]; then
STACK_IMAGE_MODE="playerbots"
STACK_SOURCE_VARIANT="playerbots"
elif [ "$NEEDS_CXX_REBUILD" = "1" ]; then
STACK_IMAGE_MODE="modules"
fi
local MODULES_REQUIRES_CUSTOM_BUILD="$NEEDS_CXX_REBUILD"
local MODULES_REQUIRES_PLAYERBOT_SOURCE="0"
if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
MODULES_REQUIRES_PLAYERBOT_SOURCE="1"
fi
export NEEDS_CXX_REBUILD
local SUMMARY_MODE_TEXT="$module_mode_label"
@@ -1419,7 +1454,10 @@ fi
HOST_ZONEINFO_PATH=${HOST_ZONEINFO_PATH:-$DEFAULT_HOST_ZONEINFO_PATH}
MYSQL_INNODB_REDO_LOG_CAPACITY=${MYSQL_INNODB_REDO_LOG_CAPACITY:-$DEFAULT_MYSQL_INNODB_REDO_LOG_CAPACITY}
MYSQL_RUNTIME_TMPFS_SIZE=${MYSQL_RUNTIME_TMPFS_SIZE:-$DEFAULT_MYSQL_RUNTIME_TMPFS_SIZE}
CLIENT_DATA_VOLUME=${CLIENT_DATA_VOLUME:-$DEFAULT_CLIENT_DATA_VOLUME}
MYSQL_EXPOSE_PORT=${MYSQL_EXPOSE_PORT:-$DEFAULT_MYSQL_EXPOSE_PORT}
MYSQL_DISABLE_BINLOG=${MYSQL_DISABLE_BINLOG:-$DEFAULT_MYSQL_DISABLE_BINLOG}
MYSQL_CONFIG_DIR=${MYSQL_CONFIG_DIR:-$DEFAULT_MYSQL_CONFIG_DIR}
CLIENT_DATA_PATH=${CLIENT_DATA_PATH:-$DEFAULT_CLIENT_DATA_PATH}
BACKUP_HEALTHCHECK_MAX_MINUTES=${BACKUP_HEALTHCHECK_MAX_MINUTES:-$DEFAULT_BACKUP_HEALTHCHECK_MAX_MINUTES}
BACKUP_HEALTHCHECK_GRACE_SECONDS=${BACKUP_HEALTHCHECK_GRACE_SECONDS:-$DEFAULT_BACKUP_HEALTHCHECK_GRACE_SECONDS}
DB_WAIT_RETRIES=${DB_WAIT_RETRIES:-$DEFAULT_DB_WAIT_RETRIES}
@@ -1446,7 +1484,7 @@ fi
local project_image_prefix
project_image_prefix="$(sanitize_project_name "$DEFAULT_COMPOSE_PROJECT_NAME")"
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$NEEDS_CXX_REBUILD" = "1" ]; then
if [ "$STACK_IMAGE_MODE" = "playerbots" ]; then
AC_AUTHSERVER_IMAGE_PLAYERBOTS_VALUE="$(resolve_project_image_tag "$project_image_prefix" "authserver-playerbots")"
AC_WORLDSERVER_IMAGE_PLAYERBOTS_VALUE="$(resolve_project_image_tag "$project_image_prefix" "worldserver-playerbots")"
AC_DB_IMPORT_IMAGE_VALUE="$(resolve_project_image_tag "$project_image_prefix" "db-import-playerbots")"
@@ -1478,6 +1516,9 @@ MYSQL_ROOT_HOST=$DEFAULT_MYSQL_ROOT_HOST
MYSQL_USER=$DEFAULT_MYSQL_USER
MYSQL_PORT=$DEFAULT_MYSQL_INTERNAL_PORT
MYSQL_EXTERNAL_PORT=$MYSQL_EXTERNAL_PORT
MYSQL_EXPOSE_PORT=${MYSQL_EXPOSE_PORT:-$DEFAULT_MYSQL_EXPOSE_PORT}
MYSQL_DISABLE_BINLOG=${MYSQL_DISABLE_BINLOG:-$DEFAULT_MYSQL_DISABLE_BINLOG}
MYSQL_CONFIG_DIR=${MYSQL_CONFIG_DIR:-$DEFAULT_MYSQL_CONFIG_DIR}
MYSQL_CHARACTER_SET=$DEFAULT_MYSQL_CHARACTER_SET
MYSQL_COLLATION=$DEFAULT_MYSQL_COLLATION
MYSQL_MAX_CONNECTIONS=$DEFAULT_MYSQL_MAX_CONNECTIONS
@@ -1506,7 +1547,7 @@ AC_WORLDSERVER_IMAGE_MODULES=${AC_WORLDSERVER_IMAGE_MODULES_VALUE}
AC_CLIENT_DATA_IMAGE=$DEFAULT_AC_CLIENT_DATA_IMAGE
AC_CLIENT_DATA_IMAGE_PLAYERBOTS=$AC_CLIENT_DATA_IMAGE_PLAYERBOTS_VALUE
CLIENT_DATA_CACHE_PATH=$DEFAULT_CLIENT_DATA_CACHE_PATH
CLIENT_DATA_VOLUME=${CLIENT_DATA_VOLUME:-$DEFAULT_CLIENT_DATA_VOLUME}
CLIENT_DATA_PATH=$CLIENT_DATA_PATH
# Build artifacts
DOCKER_IMAGE_TAG=$DEFAULT_DOCKER_IMAGE_TAG
@@ -1560,6 +1601,12 @@ CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-$DEFAULT_CLIENT_DATA_VERSION}
PLAYERBOT_ENABLED=$PLAYERBOT_ENABLED
PLAYERBOT_MIN_BOTS=$PLAYERBOT_MIN_BOTS
PLAYERBOT_MAX_BOTS=$PLAYERBOT_MAX_BOTS
STACK_IMAGE_MODE=$STACK_IMAGE_MODE
STACK_SOURCE_VARIANT=$STACK_SOURCE_VARIANT
MODULES_ENABLED_LIST=$MODULES_ENABLED_LIST
MODULES_CPP_LIST=$MODULES_CPP_LIST
MODULES_REQUIRES_CUSTOM_BUILD=$MODULES_REQUIRES_CUSTOM_BUILD
MODULES_REQUIRES_PLAYERBOT_SOURCE=$MODULES_REQUIRES_PLAYERBOT_SOURCE
# Rebuild automation
AUTO_REBUILD_ON_DEPLOY=$AUTO_REBUILD_ON_DEPLOY

View File

@@ -53,6 +53,7 @@ AUTH_PORT="$(read_env AUTH_EXTERNAL_PORT)"
WORLD_PORT="$(read_env WORLD_EXTERNAL_PORT)"
SOAP_PORT="$(read_env SOAP_EXTERNAL_PORT)"
MYSQL_PORT="$(read_env MYSQL_EXTERNAL_PORT)"
MYSQL_EXPOSE_PORT="$(read_env MYSQL_EXPOSE_PORT)"
PMA_PORT="$(read_env PMA_EXTERNAL_PORT)"
KEIRA_PORT="$(read_env KEIRA3_EXTERNAL_PORT)"
ELUNA_ENABLED="$(read_env AC_ELUNA_ENABLED)"
@@ -254,12 +255,20 @@ ports_summary(){
for i in "${!names[@]}"; do
local svc="${names[$i]}"
local port="${ports[$i]}"
if [ "$svc" = "MySQL" ] && [ "${MYSQL_EXPOSE_PORT}" != "1" ]; then
printf " %-10s %-6s %b○%b not exposed\n" "$svc" "--" "$CYAN" "$NC"
continue
fi
if [ -z "$port" ]; then
printf " %-10s %-6s %b○%b not set\n" "$svc" "--" "$YELLOW" "$NC"
continue
fi
if timeout 1 bash -c "</dev/tcp/127.0.0.1/${port}" >/dev/null 2>&1; then
if [ "$svc" = "MySQL" ]; then
printf " %-10s %-6s %b●%b reachable %b!note%b exposed\n" "$svc" "$port" "$GREEN" "$NC" "$YELLOW" "$NC"
else
printf " %-10s %-6s %b●%b reachable\n" "$svc" "$port" "$GREEN" "$NC"
fi
else
printf " %-10s %-6s %b○%b unreachable\n" "$svc" "$port" "$RED" "$NC"
fi