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_USER=root
MYSQL_PORT=3306 MYSQL_PORT=3306
MYSQL_EXTERNAL_PORT=64306 MYSQL_EXTERNAL_PORT=64306
MYSQL_EXPOSE_PORT=0
MYSQL_CHARACTER_SET=utf8mb4 MYSQL_CHARACTER_SET=utf8mb4
MYSQL_COLLATION=utf8mb4_unicode_ci MYSQL_COLLATION=utf8mb4_unicode_ci
MYSQL_MAX_CONNECTIONS=1000 MYSQL_MAX_CONNECTIONS=1000
@@ -108,6 +109,8 @@ MYSQL_INNODB_BUFFER_POOL_SIZE=256M
MYSQL_INNODB_LOG_FILE_SIZE=64M MYSQL_INNODB_LOG_FILE_SIZE=64M
MYSQL_INNODB_REDO_LOG_CAPACITY=512M MYSQL_INNODB_REDO_LOG_CAPACITY=512M
MYSQL_RUNTIME_TMPFS_SIZE=8G MYSQL_RUNTIME_TMPFS_SIZE=8G
MYSQL_DISABLE_BINLOG=1
MYSQL_CONFIG_DIR=${STORAGE_PATH}/config/mysql/conf.d
DB_WAIT_RETRIES=60 DB_WAIT_RETRIES=60
DB_WAIT_SLEEP=10 DB_WAIT_SLEEP=10
@@ -137,13 +140,19 @@ BACKUP_HEALTHCHECK_START_PERIOD=120s
PLAYERBOT_ENABLED=0 PLAYERBOT_ENABLED=0
PLAYERBOT_MIN_BOTS=40 PLAYERBOT_MIN_BOTS=40
PLAYERBOT_MAX_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 Settings
# ===================== # =====================
CLIENT_DATA_VERSION=v17 CLIENT_DATA_VERSION=v18
CLIENT_DATA_CACHE_PATH=${STORAGE_PATH_LOCAL}/client-data-cache 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) # Module toggles (0/1)

View File

@@ -116,7 +116,7 @@ The setup wizard will guide you through:
**Required when:** **Required when:**
- Playerbots enabled (`MODULE_PLAYERBOTS=1`) - 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:** **Build process:**
1. Clones AzerothCore source to `local-storage/source/` 1. Clones AzerothCore source to `local-storage/source/`
@@ -757,7 +757,7 @@ flowchart TB
| Service / Container | Role | Ports (host → container) | Profile | | 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-init` | Database schema initialization | | `db` |
| `ac-db-import` | Database content import | | `db` | | `ac-db-import` | Database content import | | `db` |
| `ac-backup` | Automated backup system | | `db` | | `ac-backup` | Automated backup system | | `db` |
@@ -773,6 +773,12 @@ flowchart TB
| `ac-phpmyadmin` | Database admin UI | `8081 → 80` | `tools` | | `ac-phpmyadmin` | Database admin UI | `8081 → 80` | `tools` |
| `ac-keira3` | Game content editor | `4201 → 8080` | `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 ### Storage Structure
The project uses a dual-storage approach for optimal performance: 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/ storage/
├── config/ # Server configuration files (.conf) ├── 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 ├── logs/ # Server log files
├── modules/ # Downloaded module source code ├── modules/ # Downloaded module source code
├── lua_scripts/ # Eluna Lua scripts (auto-loaded) ├── lua_scripts/ # Eluna Lua scripts (auto-loaded)
@@ -790,6 +799,10 @@ storage/
└── hourly/ # Hourly backups (retained per BACKUP_RETENTION_HOURS) └── 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** (`STORAGE_PATH_LOCAL` - default: `./local-storage`)
``` ```
local-storage/ local-storage/
@@ -800,8 +813,7 @@ local-storage/
└── images/ # Exported Docker images for remote deployment └── images/ # Exported Docker images for remote deployment
``` ```
**Docker Volumes** **Docker Volume**
- `ac-client-data` - Unpacked game client data (DBC, maps, vmaps, mmaps)
- `client-data-cache` - Temporary storage for client data downloads - `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. 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) - `3784` (authserver)
- `8215` (worldserver) - `8215` (worldserver)
- Configure NAT/port forwarding for public access - Configure NAT/port forwarding for public access

View File

@@ -199,6 +199,37 @@ ensure_source_repo(){
echo "$src_path" 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) # Build state detection (extracted from setup.sh and deploy.sh)
modules_need_rebuild(){ modules_need_rebuild(){
local storage_path local storage_path
@@ -576,6 +607,7 @@ main(){
info "Step 1/6: Setting up source repository" info "Step 1/6: Setting up source repository"
src_dir="$(ensure_source_repo)" src_dir="$(ensure_source_repo)"
show_client_data_requirement "$src_dir"
info "Step 2/6: Detecting build requirements" info "Step 2/6: Detecting build requirements"
readarray -t rebuild_reasons < <(detect_rebuild_reasons) readarray -t rebuild_reasons < <(detect_rebuild_reasons)

View File

@@ -11,7 +11,7 @@ set -e
# Resolve project dir and compose # Resolve project dir and compose
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="${SCRIPT_DIR}" PROJECT_DIR="${SCRIPT_DIR}"
COMPOSE_FILE="${PROJECT_DIR}/docker-compose.yml" DEFAULT_COMPOSE_FILE="${PROJECT_DIR}/docker-compose.yml"
ENV_FILE="${PROJECT_DIR}/.env" ENV_FILE="${PROJECT_DIR}/.env"
# Colors # Colors
@@ -87,7 +87,7 @@ confirm() {
format_container_table() { format_container_table() {
local containers 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 if [ -n "$containers" ]; then
echo "$containers" | head -1 echo "$containers" | head -1
echo "$containers" | tail -n +2 | while IFS=$'\t' read -r name status service image; do 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 if [ -f "$ENV_FILE" ]; then
set -a; source "$ENV_FILE"; set +a set -a; source "$ENV_FILE"; set +a
fi 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="${STORAGE_PATH:-$STORAGE_PATH_DEFAULT}"
STORAGE_PATH_LOCAL="${STORAGE_PATH_LOCAL:-$STORAGE_PATH_LOCAL_DEFAULT}" STORAGE_PATH_LOCAL="${STORAGE_PATH_LOCAL:-$STORAGE_PATH_LOCAL_DEFAULT}"
PROJECT_NAME="${COMPOSE_PROJECT_NAME:-ac-compose}" PROJECT_NAME="${COMPOSE_PROJECT_NAME:-ac-compose}"
@@ -170,7 +185,7 @@ soft_cleanup() {
--profile tools --profile tools
--profile db --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" print_status SUCCESS "Soft cleanup complete"
} }
@@ -187,7 +202,7 @@ hard_cleanup() {
--profile tools --profile tools
--profile db --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 execute_command "Remove project volumes" remove_project_volumes
# Remove straggler containers matching project name (defensive) # 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" 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 tools
--profile db --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 execute_command "Remove leftover volumes" remove_project_volumes
# Remove project images (server/tool images typical to this project) # Remove project images (server/tool images typical to this project)
@@ -266,8 +281,8 @@ main(){
print_status ERROR "Docker not found" print_status ERROR "Docker not found"
exit 1 exit 1
fi fi
if [ ! -f "$COMPOSE_FILE" ]; then if [ ! -f "$DEFAULT_COMPOSE_FILE" ]; then
print_status ERROR "Compose file not found at $COMPOSE_FILE" print_status ERROR "Compose file not found at $DEFAULT_COMPOSE_FILE"
exit 1 exit 1
fi fi
if [ -z "$CLEANUP_LEVEL" ]; then if [ -z "$CLEANUP_LEVEL" ]; then

View File

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

View File

@@ -9,7 +9,7 @@
set -euo pipefail set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 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" ENV_PATH="$ROOT_DIR/.env"
TARGET_PROFILE="" TARGET_PROFILE=""
WATCH_LOGS=1 WATCH_LOGS=1
@@ -29,6 +29,7 @@ REMOTE_ARGS_PROVIDED=0
MODULE_HELPER="$ROOT_DIR/scripts/modules.py" MODULE_HELPER="$ROOT_DIR/scripts/modules.py"
MODULE_STATE_INITIALIZED=0 MODULE_STATE_INITIALIZED=0
declare -a MODULES_COMPILE_LIST=() 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' 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}"; } info(){ printf '%b\n' "${BLUE} $*${NC}"; }
@@ -278,6 +279,22 @@ read_env(){
echo "$value" 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(){ resolve_local_storage_path(){
local path local path
path="$(read_env STORAGE_PATH_LOCAL "./local-storage")" path="$(read_env STORAGE_PATH_LOCAL "./local-storage")"
@@ -376,7 +393,7 @@ compose(){
local project_name local project_name
project_name="$(resolve_project_name)" project_name="$(resolve_project_name)"
# Add --quiet for less verbose output, filter excessive empty lines # 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 # 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_MAX_CONNECTIONS: ${MYSQL_MAX_CONNECTIONS}
MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_INNODB_BUFFER_POOL_SIZE} MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_INNODB_BUFFER_POOL_SIZE}
MYSQL_INNODB_LOG_FILE_SIZE: ${MYSQL_INNODB_LOG_FILE_SIZE} MYSQL_INNODB_LOG_FILE_SIZE: ${MYSQL_INNODB_LOG_FILE_SIZE}
ports:
- "${MYSQL_EXTERNAL_PORT}:${MYSQL_PORT}"
entrypoint: entrypoint:
- /usr/local/bin/mysql-entrypoint.sh - /usr/local/bin/mysql-entrypoint.sh
volumes: volumes:
@@ -27,6 +25,7 @@ services:
- ${STORAGE_PATH_LOCAL}/mysql-data:/var/lib/mysql-persistent - ${STORAGE_PATH_LOCAL}/mysql-data:/var/lib/mysql-persistent
- ${BACKUP_PATH}:/backups - ${BACKUP_PATH}:/backups
- ${HOST_ZONEINFO_PATH}:/usr/share/zoneinfo:ro - ${HOST_ZONEINFO_PATH}:/usr/share/zoneinfo:ro
- ${MYSQL_CONFIG_DIR:-${STORAGE_PATH}/config/mysql/conf.d}:/etc/mysql/conf.d
tmpfs: tmpfs:
- /var/lib/mysql-runtime:size=${MYSQL_RUNTIME_TMPFS_SIZE} - /var/lib/mysql-runtime:size=${MYSQL_RUNTIME_TMPFS_SIZE}
command: command:
@@ -210,12 +209,13 @@ services:
container_name: ac-volume-init container_name: ac-volume-init
user: "0:0" user: "0:0"
volumes: volumes:
- ac-client-data:/azerothcore/data - ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- client-data-cache:/cache - client-data-cache:/cache
command: command:
- sh - sh
- -c - -c
- | - |
mkdir -p /azerothcore/data
echo "🔧 Fixing Docker volume permissions..." echo "🔧 Fixing Docker volume permissions..."
chown -R ${CONTAINER_USER} /azerothcore/data /cache chown -R ${CONTAINER_USER} /azerothcore/data /cache
chmod -R 755 /azerothcore/data /cache chmod -R 755 /azerothcore/data /cache
@@ -236,6 +236,8 @@ services:
- | - |
echo "🔧 Initializing storage directories with proper permissions..." 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 /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 mkdir -p /storage-root/backups /local-storage-root/mysql-data
# Fix ownership of root directories and all contents # Fix ownership of root directories and all contents
chown -R ${CONTAINER_USER} /storage-root /local-storage-root chown -R ${CONTAINER_USER} /storage-root /local-storage-root
@@ -255,7 +257,7 @@ services:
ac-volume-init: ac-volume-init:
condition: service_completed_successfully condition: service_completed_successfully
volumes: volumes:
- ac-client-data:/azerothcore/data - ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- client-data-cache:/cache - client-data-cache:/cache
- ./scripts:/tmp/scripts:ro - ./scripts:/tmp/scripts:ro
working_dir: /tmp working_dir: /tmp
@@ -286,7 +288,7 @@ services:
ac-volume-init: ac-volume-init:
condition: service_completed_successfully condition: service_completed_successfully
volumes: volumes:
- ac-client-data:/azerothcore/data - ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- client-data-cache:/cache - client-data-cache:/cache
- ./scripts:/tmp/scripts:ro - ./scripts:/tmp/scripts:ro
working_dir: /tmp working_dir: /tmp
@@ -380,7 +382,7 @@ services:
- "${WORLD_EXTERNAL_PORT}:${WORLD_PORT}" - "${WORLD_EXTERNAL_PORT}:${WORLD_PORT}"
- "${SOAP_EXTERNAL_PORT}:${SOAP_PORT}" - "${SOAP_EXTERNAL_PORT}:${SOAP_PORT}"
volumes: volumes:
- ac-client-data:/azerothcore/data - ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc - ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs - ${STORAGE_PATH}/logs:/azerothcore/logs
- ${STORAGE_PATH}/modules:/azerothcore/modules - ${STORAGE_PATH}/modules:/azerothcore/modules
@@ -503,7 +505,7 @@ services:
- "${WORLD_EXTERNAL_PORT}:${WORLD_PORT}" - "${WORLD_EXTERNAL_PORT}:${WORLD_PORT}"
- "${SOAP_EXTERNAL_PORT}:${SOAP_PORT}" - "${SOAP_EXTERNAL_PORT}:${SOAP_PORT}"
volumes: volumes:
- ac-client-data:/azerothcore/data - ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc - ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs - ${STORAGE_PATH}/logs:/azerothcore/logs
- ${STORAGE_PATH}/modules:/azerothcore/modules - ${STORAGE_PATH}/modules:/azerothcore/modules
@@ -550,7 +552,7 @@ services:
PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS}" PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS}"
AC_LOG_LEVEL: "2" AC_LOG_LEVEL: "2"
volumes: volumes:
- ac-client-data:/azerothcore/data - ${CLIENT_DATA_PATH:-${STORAGE_PATH}/client-data}:/azerothcore/data
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc - ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
- ${STORAGE_PATH}/logs:/azerothcore/logs - ${STORAGE_PATH}/logs:/azerothcore/logs
- ${STORAGE_PATH}/modules:/azerothcore/modules - ${STORAGE_PATH}/modules:/azerothcore/modules
@@ -723,9 +725,6 @@ services:
- azerothcore - azerothcore
volumes: volumes:
ac-client-data:
name: ${CLIENT_DATA_VOLUME}
driver: local
client-data-cache: client-data-cache:
driver: local driver: local

View File

@@ -5,8 +5,9 @@
set -euo pipefail set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.." 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" ENV_FILE="$ROOT_DIR/.env"
declare -a COMPOSE_FILE_ARGS=()
BLUE='\033[0;34m' BLUE='\033[0;34m'
GREEN='\033[0;32m' GREEN='\033[0;32m'
@@ -44,8 +45,22 @@ resolve_project_name(){
echo "$sanitized" 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(){ compose(){
docker compose --project-name "$PROJECT_NAME" -f "$COMPOSE_FILE" "$@" docker compose --project-name "$PROJECT_NAME" "${COMPOSE_FILE_ARGS[@]}" "$@"
} }
show_header(){ 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: def requires_playerbot_source(self) -> bool:
module_map = {m.key: m for m in self.modules} module_map = {m.key: m for m in self.modules}
playerbots_enabled = module_map.get("MODULE_PLAYERBOTS") playerbots_enabled = module_map.get("MODULE_PLAYERBOTS")
playerbots = bool(playerbots_enabled and playerbots_enabled.enabled_effective) return 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 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: 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"] key = entry["key"]
name = entry["name"] name = entry["name"]
repo = entry["repo"] repo = entry["repo"]
needs_build = bool(entry.get("needs_build", False))
module_type = str(entry.get("type", "cpp")) 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 [] requires = entry.get("requires") or []
if not isinstance(requires, list): if not isinstance(requires, list):
raise ValueError(f"Manifest entry {key} has non-list 'requires'") 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] = [] enabled_names: List[str] = []
compile_names: List[str] = [] compile_names: List[str] = []
enabled_keys: List[str] = []
compile_keys: List[str] = []
for module in state.modules: for module in state.modules:
env_lines.append(f"export {module.key}={module.value}") env_lines.append(f"export {module.key}={module.value}")
if module.enabled_effective: if module.enabled_effective:
enabled_names.append(module.name) enabled_names.append(module.name)
enabled_keys.append(module.key)
if module.enabled_effective and module.needs_build: if module.enabled_effective and module.needs_build:
compile_names.append(module.name) 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_ENABLED="{ " ".join(enabled_names) }"'.rstrip())
env_lines.append(f'export MODULES_COMPILE="{ " ".join(compile_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( env_lines.append(
f"export MODULES_REQUIRES_PLAYERBOT_SOURCE=" f"export MODULES_REQUIRES_PLAYERBOT_SOURCE="
f'{"1" if state.requires_playerbot_source() else "0"}' 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_WARNING_COUNT={len(state.warnings)}")
env_lines.append(f"export MODULES_ERROR_COUNT={len(state.errors)}") 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()], "enabled_modules": [module.name for module in state.enabled_modules()],
"compile_modules": [module.name for module in state.compile_modules()], "compile_modules": [module.name for module in state.compile_modules()],
"requires_playerbot_source": state.requires_playerbot_source(), "requires_playerbot_source": state.requires_playerbot_source(),
"requires_custom_build": state.requires_custom_build(),
} }
modules_state_path = output_dir / "modules-state.json" 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") 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: def print_state(state: ModuleCollectionState, fmt: str) -> None:
payload = { payload = {
"generated_at": state.generated_at.isoformat(), "generated_at": state.generated_at.isoformat(),
@@ -485,6 +506,18 @@ def configure_parser() -> argparse.ArgumentParser:
rps_parser.set_defaults(func=handle_requires_playerbot) 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 = subparsers.add_parser("dump", help="Dump module state (JSON format)")
dump_parser.add_argument( dump_parser.add_argument(
"--format", "--format",

View File

@@ -79,4 +79,18 @@ for path in /var/lib/mysql-runtime /var/lib/mysql /var/lib/mysql-persistent /bac
fi fi
done 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" "$@" exec "$ORIGINAL_ENTRYPOINT" "$@"

View File

@@ -14,36 +14,55 @@ PROJECT_ROOT="$(pwd)"
# Default values # Default values
MODULE_PLAYERBOTS="${MODULE_PLAYERBOTS:-0}" MODULE_PLAYERBOTS="${MODULE_PLAYERBOTS:-0}"
NEEDS_CXX_REBUILD="${NEEDS_CXX_REBUILD:-0}" PLAYERBOT_ENABLED="${PLAYERBOT_ENABLED:-0}"
STACK_SOURCE_VARIANT="${STACK_SOURCE_VARIANT:-}"
COMPILE_MODULE_KEYS=( if [ -z "$STACK_SOURCE_VARIANT" ]; then
MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$PLAYERBOT_ENABLED" = "1" ]; then
MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS STACK_SOURCE_VARIANT="playerbots"
MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD else
MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER STACK_SOURCE_VARIANT="core"
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
fi fi
done
fi fi
LOCAL_STORAGE_ROOT="${STORAGE_PATH_LOCAL:-./local-storage}" LOCAL_STORAGE_ROOT="${STORAGE_PATH_LOCAL:-./local-storage}"
DEFAULT_STANDARD_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore" DEFAULT_STANDARD_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore"
DEFAULT_PLAYERBOTS_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore-playerbots" DEFAULT_PLAYERBOTS_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore-playerbots"
SOURCE_PATH_DEFAULT="$DEFAULT_STANDARD_PATH" 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" SOURCE_PATH_DEFAULT="$DEFAULT_PLAYERBOTS_PATH"
fi fi
SOURCE_PATH="${MODULES_REBUILD_SOURCE_PATH:-$SOURCE_PATH_DEFAULT}" 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}" STORAGE_PATH_VALUE="${STORAGE_PATH:-./storage}"
if [[ "$STORAGE_PATH_VALUE" != /* ]]; then if [[ "$STORAGE_PATH_VALUE" != /* ]]; then
STORAGE_PATH_ABS="$PROJECT_ROOT/${STORAGE_PATH_VALUE#./}" 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_REPO_PLAYERBOTS="${ACORE_REPO_PLAYERBOTS:-https://github.com/mod-playerbots/azerothcore-wotlk.git}"
ACORE_BRANCH_PLAYERBOTS="${ACORE_BRANCH_PLAYERBOTS:-Playerbot}" ACORE_BRANCH_PLAYERBOTS="${ACORE_BRANCH_PLAYERBOTS:-Playerbot}"
# Repository and branch selection based on playerbots mode # Repository and branch selection based on source variant
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$NEEDS_CXX_REBUILD" = "1" ]; then if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
REPO_URL="$ACORE_REPO_PLAYERBOTS" REPO_URL="$ACORE_REPO_PLAYERBOTS"
BRANCH="$ACORE_BRANCH_PLAYERBOTS" BRANCH="$ACORE_BRANCH_PLAYERBOTS"
echo "📌 Playerbots mode: Using $REPO_URL, branch $BRANCH" echo "📌 Playerbots mode: Using $REPO_URL, branch $BRANCH"
@@ -130,5 +149,6 @@ echo "📊 Current status:"
echo " Branch: $CURRENT_BRANCH" echo " Branch: $CURRENT_BRANCH"
echo " Commit: $CURRENT_COMMIT" echo " Commit: $CURRENT_COMMIT"
echo " Last commit: $(git log -1 --pretty=format:'%s (%an, %ar)')" echo " Last commit: $(git log -1 --pretty=format:'%s (%an, %ar)')"
show_client_data_requirement "$SOURCE_PATH"
echo '🎉 Source repository setup complete!' echo '🎉 Source repository setup complete!'

View File

@@ -58,8 +58,13 @@ def cmd_metadata(manifest_path: str) -> None:
for entry in iter_modules(manifest): for entry in iter_modules(manifest):
key = entry["key"] key = entry["key"]
name = clean(entry.get("name", key)) name = clean(entry.get("name", key))
needs_build = "1" if entry.get("needs_build") else "0" module_type_raw = entry.get("type", "")
module_type = clean(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")) status = clean(entry.get("status", "active"))
block_reason = clean(entry.get("block_reason", "")) block_reason = clean(entry.get("block_reason", ""))
requires = unique_preserve_order(entry.get("requires") or []) 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)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")" PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="$PROJECT_DIR/.env" ENV_FILE="$PROJECT_DIR/.env"
DEFAULT_COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
EXTRA_COMPOSE_FILE="$PROJECT_DIR/docker-compose.mysql-expose.yml"
usage(){ usage(){
cat <<EOF cat <<EOF
@@ -112,6 +114,19 @@ resolve_project_name(){
echo "$sanitized" 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(){ resolve_project_image(){
local tag="$1" local tag="$1"
local project_name local project_name

View File

@@ -10,7 +10,8 @@ ok(){ echo -e "${GREEN}✅ $*${NC}"; }
warn(){ echo -e "${YELLOW}⚠️ $*${NC}"; } warn(){ echo -e "${YELLOW}⚠️ $*${NC}"; }
err(){ echo -e "${RED}$*${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="" ENV_FILE=""
PROFILES=(db services-standard client-data modules tools) PROFILES=(db services-standard client-data modules tools)
SKIP_DEPLOY=false SKIP_DEPLOY=false
@@ -72,6 +73,15 @@ run_compose(){
compose_args+=(--env-file "$ENV_FILE") compose_args+=(--env-file "$ENV_FILE")
fi fi
compose_args+=(-f "$COMPOSE_FILE") 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[@]}" "$@" docker compose "${compose_args[@]}" "$@"
} }

View File

@@ -68,6 +68,7 @@ declare -A TEMPLATE_VALUE_MAP=(
[DEFAULT_AUTH_PORT]=AUTH_EXTERNAL_PORT [DEFAULT_AUTH_PORT]=AUTH_EXTERNAL_PORT
[DEFAULT_SOAP_PORT]=SOAP_EXTERNAL_PORT [DEFAULT_SOAP_PORT]=SOAP_EXTERNAL_PORT
[DEFAULT_MYSQL_PORT]=MYSQL_EXTERNAL_PORT [DEFAULT_MYSQL_PORT]=MYSQL_EXTERNAL_PORT
[DEFAULT_MYSQL_EXPOSE_PORT]=MYSQL_EXPOSE_PORT
[DEFAULT_PLAYERBOT_MIN]=PLAYERBOT_MIN_BOTS [DEFAULT_PLAYERBOT_MIN]=PLAYERBOT_MIN_BOTS
[DEFAULT_PLAYERBOT_MAX]=PLAYERBOT_MAX_BOTS [DEFAULT_PLAYERBOT_MAX]=PLAYERBOT_MAX_BOTS
[DEFAULT_LOCAL_STORAGE]=STORAGE_PATH [DEFAULT_LOCAL_STORAGE]=STORAGE_PATH
@@ -112,7 +113,7 @@ declare -A TEMPLATE_VALUE_MAP=(
[DEFAULT_CONTAINER_MODULES]=CONTAINER_MODULES [DEFAULT_CONTAINER_MODULES]=CONTAINER_MODULES
[DEFAULT_CONTAINER_POST_INSTALL]=CONTAINER_POST_INSTALL [DEFAULT_CONTAINER_POST_INSTALL]=CONTAINER_POST_INSTALL
[DEFAULT_COMPOSE_PROJECT_NAME]=COMPOSE_PROJECT_NAME [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_CACHE_PATH]=CLIENT_DATA_CACHE_PATH
[DEFAULT_CLIENT_DATA_VERSION]=CLIENT_DATA_VERSION [DEFAULT_CLIENT_DATA_VERSION]=CLIENT_DATA_VERSION
[DEFAULT_NETWORK_NAME]=NETWORK_NAME [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_LOG_FILE_SIZE]=MYSQL_INNODB_LOG_FILE_SIZE
[DEFAULT_MYSQL_INNODB_REDO_LOG_CAPACITY]=MYSQL_INNODB_REDO_LOG_CAPACITY [DEFAULT_MYSQL_INNODB_REDO_LOG_CAPACITY]=MYSQL_INNODB_REDO_LOG_CAPACITY
[DEFAULT_MYSQL_RUNTIME_TMPFS_SIZE]=MYSQL_RUNTIME_TMPFS_SIZE [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_MYSQL_HOST]=MYSQL_HOST
[DEFAULT_DB_WAIT_RETRIES]=DB_WAIT_RETRIES [DEFAULT_DB_WAIT_RETRIES]=DB_WAIT_RETRIES
[DEFAULT_DB_WAIT_SLEEP]=DB_WAIT_SLEEP [DEFAULT_DB_WAIT_SLEEP]=DB_WAIT_SLEEP
@@ -902,10 +905,7 @@ fi
local STORAGE_PATH local STORAGE_PATH
if [ -n "$CLI_STORAGE_PATH" ]; then if [ -n "$CLI_STORAGE_PATH" ]; then
STORAGE_PATH="$CLI_STORAGE_PATH" STORAGE_PATH="$CLI_STORAGE_PATH"
elif [ "$DEPLOYMENT_TYPE" = "local" ]; then elif [ "$NON_INTERACTIVE" = "1" ]; then
STORAGE_PATH=$DEFAULT_LOCAL_STORAGE
else
if [ "$NON_INTERACTIVE" = "1" ]; then
STORAGE_PATH=$DEFAULT_MOUNT_STORAGE STORAGE_PATH=$DEFAULT_MOUNT_STORAGE
else else
echo "1) 💾 ./storage (local)" echo "1) 💾 ./storage (local)"
@@ -921,7 +921,6 @@ fi
esac esac
done done
fi fi
fi
# Backup # Backup
say HEADER "BACKUP CONFIGURATION" say HEADER "BACKUP CONFIGURATION"
@@ -1300,6 +1299,42 @@ fi
fi fi
done 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 export NEEDS_CXX_REBUILD
local SUMMARY_MODE_TEXT="$module_mode_label" local SUMMARY_MODE_TEXT="$module_mode_label"
@@ -1419,7 +1454,10 @@ fi
HOST_ZONEINFO_PATH=${HOST_ZONEINFO_PATH:-$DEFAULT_HOST_ZONEINFO_PATH} 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_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} 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_MAX_MINUTES=${BACKUP_HEALTHCHECK_MAX_MINUTES:-$DEFAULT_BACKUP_HEALTHCHECK_MAX_MINUTES}
BACKUP_HEALTHCHECK_GRACE_SECONDS=${BACKUP_HEALTHCHECK_GRACE_SECONDS:-$DEFAULT_BACKUP_HEALTHCHECK_GRACE_SECONDS} BACKUP_HEALTHCHECK_GRACE_SECONDS=${BACKUP_HEALTHCHECK_GRACE_SECONDS:-$DEFAULT_BACKUP_HEALTHCHECK_GRACE_SECONDS}
DB_WAIT_RETRIES=${DB_WAIT_RETRIES:-$DEFAULT_DB_WAIT_RETRIES} DB_WAIT_RETRIES=${DB_WAIT_RETRIES:-$DEFAULT_DB_WAIT_RETRIES}
@@ -1446,7 +1484,7 @@ fi
local project_image_prefix local project_image_prefix
project_image_prefix="$(sanitize_project_name "$DEFAULT_COMPOSE_PROJECT_NAME")" 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_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_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")" 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_USER=$DEFAULT_MYSQL_USER
MYSQL_PORT=$DEFAULT_MYSQL_INTERNAL_PORT MYSQL_PORT=$DEFAULT_MYSQL_INTERNAL_PORT
MYSQL_EXTERNAL_PORT=$MYSQL_EXTERNAL_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_CHARACTER_SET=$DEFAULT_MYSQL_CHARACTER_SET
MYSQL_COLLATION=$DEFAULT_MYSQL_COLLATION MYSQL_COLLATION=$DEFAULT_MYSQL_COLLATION
MYSQL_MAX_CONNECTIONS=$DEFAULT_MYSQL_MAX_CONNECTIONS 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=$DEFAULT_AC_CLIENT_DATA_IMAGE
AC_CLIENT_DATA_IMAGE_PLAYERBOTS=$AC_CLIENT_DATA_IMAGE_PLAYERBOTS_VALUE AC_CLIENT_DATA_IMAGE_PLAYERBOTS=$AC_CLIENT_DATA_IMAGE_PLAYERBOTS_VALUE
CLIENT_DATA_CACHE_PATH=$DEFAULT_CLIENT_DATA_CACHE_PATH 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 # Build artifacts
DOCKER_IMAGE_TAG=$DEFAULT_DOCKER_IMAGE_TAG 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_ENABLED=$PLAYERBOT_ENABLED
PLAYERBOT_MIN_BOTS=$PLAYERBOT_MIN_BOTS PLAYERBOT_MIN_BOTS=$PLAYERBOT_MIN_BOTS
PLAYERBOT_MAX_BOTS=$PLAYERBOT_MAX_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 # Rebuild automation
AUTO_REBUILD_ON_DEPLOY=$AUTO_REBUILD_ON_DEPLOY 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)" WORLD_PORT="$(read_env WORLD_EXTERNAL_PORT)"
SOAP_PORT="$(read_env SOAP_EXTERNAL_PORT)" SOAP_PORT="$(read_env SOAP_EXTERNAL_PORT)"
MYSQL_PORT="$(read_env MYSQL_EXTERNAL_PORT)" MYSQL_PORT="$(read_env MYSQL_EXTERNAL_PORT)"
MYSQL_EXPOSE_PORT="$(read_env MYSQL_EXPOSE_PORT)"
PMA_PORT="$(read_env PMA_EXTERNAL_PORT)" PMA_PORT="$(read_env PMA_EXTERNAL_PORT)"
KEIRA_PORT="$(read_env KEIRA3_EXTERNAL_PORT)" KEIRA_PORT="$(read_env KEIRA3_EXTERNAL_PORT)"
ELUNA_ENABLED="$(read_env AC_ELUNA_ENABLED)" ELUNA_ENABLED="$(read_env AC_ELUNA_ENABLED)"
@@ -254,12 +255,20 @@ ports_summary(){
for i in "${!names[@]}"; do for i in "${!names[@]}"; do
local svc="${names[$i]}" local svc="${names[$i]}"
local port="${ports[$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 if [ -z "$port" ]; then
printf " %-10s %-6s %b○%b not set\n" "$svc" "--" "$YELLOW" "$NC" printf " %-10s %-6s %b○%b not set\n" "$svc" "--" "$YELLOW" "$NC"
continue continue
fi fi
if timeout 1 bash -c "</dev/tcp/127.0.0.1/${port}" >/dev/null 2>&1; then 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" printf " %-10s %-6s %b●%b reachable\n" "$svc" "$port" "$GREEN" "$NC"
fi
else else
printf " %-10s %-6s %b○%b unreachable\n" "$svc" "$port" "$RED" "$NC" printf " %-10s %-6s %b○%b unreachable\n" "$svc" "$port" "$RED" "$NC"
fi fi