mirror of
https://github.com/uprightbass360/AzerothCore-RealmMaster.git
synced 2026-01-13 00:58:34 +00:00
179
.env.template
Normal file
179
.env.template
Normal file
@@ -0,0 +1,179 @@
|
||||
# Copy this file to .env and adjust values for your environment.
|
||||
# Docker Compose will auto-load .env in the same folder as compose.yml.
|
||||
# Template for acore-compose profiles-based compose
|
||||
|
||||
# Project name
|
||||
COMPOSE_PROJECT_NAME=acore-compose
|
||||
|
||||
# =====================
|
||||
# Storage & Timezone
|
||||
# =====================
|
||||
STORAGE_PATH=./storage
|
||||
HOST_ZONEINFO_PATH=/usr/share/zoneinfo
|
||||
TZ=UTC
|
||||
|
||||
# =====================
|
||||
# MySQL / Database Layer
|
||||
# =====================
|
||||
MYSQL_IMAGE=mysql:8.0
|
||||
CONTAINER_MYSQL=ac-mysql
|
||||
MYSQL_ROOT_PASSWORD=azerothcore123
|
||||
MYSQL_ROOT_HOST=%
|
||||
MYSQL_USER=root
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_EXTERNAL_PORT=64306
|
||||
MYSQL_CHARACTER_SET=utf8mb4
|
||||
MYSQL_COLLATION=utf8mb4_unicode_ci
|
||||
MYSQL_MAX_CONNECTIONS=1000
|
||||
MYSQL_INNODB_BUFFER_POOL_SIZE=256M
|
||||
MYSQL_INNODB_LOG_FILE_SIZE=64M
|
||||
MYSQL_INNODB_REDO_LOG_CAPACITY=512M
|
||||
MYSQL_RUNTIME_TMPFS_SIZE=8G
|
||||
|
||||
# DB names
|
||||
DB_AUTH_NAME=acore_auth
|
||||
DB_WORLD_NAME=acore_world
|
||||
DB_CHARACTERS_NAME=acore_characters
|
||||
DB_PLAYERBOTS_NAME=acore_playerbots
|
||||
|
||||
# DB import image
|
||||
AC_DB_IMPORT_IMAGE=acore/ac-wotlk-db-import:14.0.0-dev
|
||||
|
||||
# =====================
|
||||
# Services (Standard)
|
||||
# =====================
|
||||
AC_AUTHSERVER_IMAGE=acore/ac-wotlk-authserver:14.0.0-dev
|
||||
AC_WORLDSERVER_IMAGE=acore/ac-wotlk-worldserver:14.0.0-dev
|
||||
|
||||
# =====================
|
||||
# Services (Playerbots)
|
||||
# =====================
|
||||
AC_AUTHSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot
|
||||
AC_WORLDSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot
|
||||
|
||||
# =====================
|
||||
# Client Data
|
||||
# =====================
|
||||
AC_CLIENT_DATA_IMAGE=acore/ac-wotlk-client-data:14.0.0-dev
|
||||
AC_CLIENT_DATA_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:client-data-Playerbot
|
||||
CLIENT_DATA_VERSION=v16
|
||||
|
||||
# =====================
|
||||
# Ports
|
||||
# =====================
|
||||
AUTH_EXTERNAL_PORT=3784
|
||||
AUTH_PORT=3724
|
||||
WORLD_EXTERNAL_PORT=8215
|
||||
WORLD_PORT=8085
|
||||
SOAP_EXTERNAL_PORT=7778
|
||||
SOAP_PORT=7878
|
||||
|
||||
# =====================
|
||||
# Server address / realm
|
||||
# =====================
|
||||
SERVER_ADDRESS=127.0.0.1
|
||||
REALM_PORT=8215
|
||||
|
||||
# =====================
|
||||
# Playerbots runtime flags (used by worldserver env)
|
||||
# =====================
|
||||
PLAYERBOT_ENABLED=0
|
||||
PLAYERBOT_MAX_BOTS=40
|
||||
|
||||
# =====================
|
||||
# Git for ac-modules (optional)
|
||||
# =====================
|
||||
|
||||
# Playerbot runtime flags
|
||||
PLAYERBOT_ENABLED=0
|
||||
PLAYERBOT_MAX_BOTS=40
|
||||
|
||||
# =====================
|
||||
# Module toggles (0/1)
|
||||
# =====================
|
||||
MODULE_PLAYERBOTS=0
|
||||
MODULE_AOE_LOOT=0
|
||||
MODULE_LEARN_SPELLS=0
|
||||
MODULE_FIREWORKS=0
|
||||
# Requires worldserver.conf tweaks (EnablePlayerSettings=1, DBC.EnforceItemAttributes=0)
|
||||
MODULE_INDIVIDUAL_PROGRESSION=0
|
||||
MODULE_AHBOT=0
|
||||
MODULE_AUTOBALANCE=0
|
||||
MODULE_TRANSMOG=0
|
||||
MODULE_NPC_BUFFER=0
|
||||
MODULE_DYNAMIC_XP=0
|
||||
MODULE_SOLO_LFG=0
|
||||
MODULE_1V1_ARENA=0
|
||||
MODULE_PHASED_DUELS=0
|
||||
# Needs BreakingNews HTML asset configured (BreakingNews.HtmlPath)
|
||||
MODULE_BREAKING_NEWS=0
|
||||
MODULE_BOSS_ANNOUNCER=0
|
||||
MODULE_ACCOUNT_ACHIEVEMENTS=0
|
||||
MODULE_AUTO_REVIVE=0
|
||||
MODULE_GAIN_HONOR_GUARD=0
|
||||
MODULE_ARAC=0
|
||||
# Requires optional SQL/DBC patches; leave off by default
|
||||
MODULE_TIME_IS_TIME=0
|
||||
# Requires in-game NPC placement/config; leave off by default
|
||||
MODULE_POCKET_PORTAL=0
|
||||
# Pending upstream verification; leave disabled until tested
|
||||
MODULE_RANDOM_ENCHANTS=0
|
||||
MODULE_SOLOCRAFT=0
|
||||
MODULE_PVP_TITLES=0
|
||||
# Custom NPC modules pending compatibility validation
|
||||
MODULE_NPC_BEASTMASTER=0
|
||||
MODULE_NPC_ENCHANTER=0
|
||||
MODULE_INSTANCE_RESET=0
|
||||
# mod-quest-count-level currently fails (uses removed sConfigMgr::GetBoolDefault)
|
||||
MODULE_LEVEL_GRANT=0
|
||||
MODULE_ASSISTANT=0
|
||||
MODULE_REAGENT_BANK=0
|
||||
MODULE_BLACK_MARKET_AUCTION_HOUSE=0
|
||||
|
||||
# =====================
|
||||
# Rebuild automation
|
||||
# =====================
|
||||
AUTO_REBUILD_ON_DEPLOY=0
|
||||
# Default AzerothCore source checkout used for module rebuilds
|
||||
MODULES_REBUILD_SOURCE_PATH=./source/azerothcore
|
||||
|
||||
# =====================
|
||||
# Eluna runtime (worldserver.conf overrides)
|
||||
# =====================
|
||||
AC_ELUNA_ENABLED=1 # Power users may set to 0 to turn off bundled Eluna runtime
|
||||
AC_ELUNA_TRACE_BACK=1
|
||||
AC_ELUNA_AUTO_RELOAD=1
|
||||
AC_ELUNA_BYTECODE_CACHE=1
|
||||
AC_ELUNA_SCRIPT_PATH=lua_scripts
|
||||
AC_ELUNA_REQUIRE_PATHS=
|
||||
AC_ELUNA_REQUIRE_CPATHS=
|
||||
AC_ELUNA_AUTO_RELOAD_INTERVAL=1
|
||||
|
||||
# =====================
|
||||
# Tools (phpMyAdmin / Keira3)
|
||||
# =====================
|
||||
PMA_HOST=ac-mysql
|
||||
PMA_PORT=3306
|
||||
PMA_USER=root
|
||||
PMA_EXTERNAL_PORT=8081
|
||||
PMA_ARBITRARY=1
|
||||
PMA_ABSOLUTE_URI=
|
||||
PMA_UPLOAD_LIMIT=300M
|
||||
PMA_MEMORY_LIMIT=512M
|
||||
PMA_MAX_EXECUTION_TIME=600
|
||||
|
||||
KEIRA3_EXTERNAL_PORT=4201
|
||||
KEIRA_DATABASE_HOST=ac-mysql
|
||||
KEIRA_DATABASE_PORT=3306
|
||||
|
||||
# =====================
|
||||
# Networking
|
||||
# =====================
|
||||
NETWORK_NAME=azerothcore
|
||||
NETWORK_SUBNET=172.20.0.0/16
|
||||
NETWORK_GATEWAY=172.20.0.1
|
||||
|
||||
# =====================
|
||||
# Container user mapping
|
||||
# =====================
|
||||
CONTAINER_USER=0:0
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,5 +2,7 @@ data/
|
||||
backups/
|
||||
local-data-tools/
|
||||
storage/
|
||||
source/
|
||||
.claude/
|
||||
*custom.env
|
||||
.env
|
||||
|
||||
|
||||
BIN
ImportBackup/acore_auth.sql.gz
Normal file
BIN
ImportBackup/acore_auth.sql.gz
Normal file
Binary file not shown.
BIN
ImportBackup/acore_characters.sql.gz
Normal file
BIN
ImportBackup/acore_characters.sql.gz
Normal file
Binary file not shown.
7
ImportBackup/manifest.json
Normal file
7
ImportBackup/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"generated_at": "2025-10-19T14:18:18-04:00",
|
||||
"databases": {
|
||||
"auth": "acore_auth",
|
||||
"characters": "acore_characters"
|
||||
}
|
||||
}
|
||||
533
README.md
533
README.md
@@ -1,6 +1,6 @@
|
||||
# AzerothCore Docker/Podman Stack
|
||||
# AzerothCore Docker/Compose Stack
|
||||
|
||||
A complete containerized deployment of AzerothCore WoW 3.3.5a (Wrath of the Lich King) private server with 13 enhanced modules, automated management, and production-ready features.
|
||||
A complete containerized deployment of AzerothCore WoW 3.3.5a (Wrath of the Lich King) private server with 20+ enhanced modules, intelligent automation, and production-ready features.
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
@@ -19,15 +19,12 @@ cd acore-compose
|
||||
|
||||
**2. Run Interactive Setup**
|
||||
```bash
|
||||
./scripts/setup-server.sh
|
||||
./setup.sh
|
||||
```
|
||||
|
||||
**3. Deploy Server**
|
||||
**3. Deploy Your Realm**
|
||||
```bash
|
||||
# Use the generated custom environment files
|
||||
docker compose --env-file docker-compose-azerothcore-database-custom.env -f docker-compose-azerothcore-database.yml up -d
|
||||
docker compose --env-file docker-compose-azerothcore-services-custom.env -f docker-compose-azerothcore-services.yml up -d
|
||||
docker compose --env-file docker-compose-azerothcore-tools-custom.env -f docker-compose-azerothcore-tools.yml up -d
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
**4. Create Admin Account**
|
||||
@@ -70,64 +67,12 @@ set realmlist your-domain.com 8215
|
||||
set realmlist 203.0.113.100 8215
|
||||
```
|
||||
|
||||
**6. Access Your Server**
|
||||
**6. Access Your Realm**
|
||||
- **Game Server**: `your-server-ip:8215` (or port you configured)
|
||||
- **Database Admin**: http://localhost:8081 (phpMyAdmin)
|
||||
- **Game Content Editor**: http://localhost:4201 (Keira3)
|
||||
|
||||
✅ **That's it!** Your server is ready with all 13 modules installed and configured.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Manual Setup (Advanced Users)
|
||||
|
||||
### Step 1: Clone Repository
|
||||
```bash
|
||||
git clone https://github.com/uprightbass360/acore-compose.git
|
||||
cd acore-compose
|
||||
```
|
||||
|
||||
### Step 2: Configure Environment Files
|
||||
Edit these files to match your setup:
|
||||
- `docker-compose-azerothcore-database.env`
|
||||
- `docker-compose-azerothcore-services.env`
|
||||
- `docker-compose-azerothcore-tools.env`
|
||||
|
||||
Key settings to modify:
|
||||
```bash
|
||||
# Server network configuration
|
||||
SERVER_ADDRESS=your-server-ip
|
||||
REALM_PORT=8215
|
||||
AUTH_EXTERNAL_PORT=3784
|
||||
|
||||
# Storage location
|
||||
STORAGE_ROOT=./storage # Local setup
|
||||
# STORAGE_ROOT=/nfs/azerothcore # NFS/network storage
|
||||
|
||||
# Database settings
|
||||
MYSQL_ROOT_PASSWORD=your-secure-password
|
||||
```
|
||||
|
||||
### Step 3: Deploy Layers in Order
|
||||
```bash
|
||||
# 1. Database layer (MySQL + backup system)
|
||||
docker compose --env-file docker-compose-azerothcore-database.env -f docker-compose-azerothcore-database.yml up -d
|
||||
|
||||
# 2. Services layer (auth/world servers + modules)
|
||||
docker compose --env-file docker-compose-azerothcore-services.env -f docker-compose-azerothcore-services.yml up -d
|
||||
|
||||
# 3. Tools layer (phpMyAdmin + Keira3)
|
||||
docker compose --env-file docker-compose-azerothcore-tools.env -f docker-compose-azerothcore-tools.yml up -d
|
||||
```
|
||||
|
||||
### Step 4: Monitor Deployment
|
||||
```bash
|
||||
# Watch post-install configuration
|
||||
docker logs ac-post-install -f
|
||||
|
||||
# Check all services are healthy
|
||||
docker ps
|
||||
```
|
||||
✅ **That's it!** Your realm is ready with all enabled modules installed and configured.
|
||||
|
||||
---
|
||||
|
||||
@@ -136,163 +81,116 @@ docker ps
|
||||
### ✅ Core Server Components
|
||||
- **AzerothCore 3.3.5a** - WotLK server application
|
||||
- **MySQL 8.0** - Database with intelligent initialization and restoration
|
||||
- **Smart Backup System** - Automated hourly/daily backups with intelligent restoration
|
||||
- **Smart Module System** - Automated module management and source builds
|
||||
- **phpMyAdmin** - Web-based database administration
|
||||
- **Keira3** - Game content editor and developer tools
|
||||
|
||||
### ✅ 13 Enhanced Modules (✅ VERIFIED INTEGRATED)
|
||||
All modules are automatically downloaded, configured, and SQL scripts executed:
|
||||
### ✅ Available Enhanced Modules
|
||||
|
||||
| Module | Description | Status |
|
||||
|--------|-------------|---------|
|
||||
| **mod-playerbots** | AI companions for solo play | ✅ INTEGRATED |
|
||||
| **mod-aoe-loot** | Streamlined loot collection | ✅ INTEGRATED |
|
||||
| **mod-learn-spells** | Automatic spell learning | ✅ INTEGRATED |
|
||||
| **mod-fireworks** | Level-up celebrations | ✅ INTEGRATED |
|
||||
| **mod-individual-progression** | Personal advancement system | ✅ INTEGRATED |
|
||||
| **mod-transmog** | Appearance customization | ✅ INTEGRATED |
|
||||
| **mod-solo-lfg** | Solo dungeon access | ✅ INTEGRATED |
|
||||
| **mod-eluna** | Lua scripting engine | ✅ INTEGRATED |
|
||||
| **mod-arac** | All races/classes unlocked | ✅ INTEGRATED |
|
||||
| **mod-npc-enchanter** | Enchanting services | ✅ INTEGRATED |
|
||||
| **mod-assistant** | AI automation features | ✅ INTEGRATED |
|
||||
| **mod-reagent-bank** | Reagent storage system | ✅ INTEGRATED |
|
||||
| **mod-black-market** | Rare item auctions | ✅ INTEGRATED |
|
||||
All modules are automatically downloaded, configured, and SQL scripts executed when enabled:
|
||||
|
||||
| Module | Description | Default Status |
|
||||
|--------|-------------|----------------|
|
||||
| **mod-solo-lfg** | Solo dungeon finder access | ✅ ENABLED |
|
||||
| **mod-solocraft** | Dynamic instance scaling for solo play | ✅ ENABLED |
|
||||
| **mod-autobalance** | Automatic raid/dungeon balancing | ✅ ENABLED |
|
||||
| **mod-transmog** | Appearance customization system | ✅ ENABLED |
|
||||
| **mod-npc-buffer** | NPC buffing services | ✅ ENABLED |
|
||||
| **mod-learn-spells** | Automatic spell learning | ✅ ENABLED |
|
||||
| **mod-fireworks** | Level-up celebrations | ✅ ENABLED |
|
||||
| **mod-playerbots** | AI companions for solo play | 🔧 OPTIONAL |
|
||||
| **mod-aoe-loot** | Streamlined loot collection | 🔧 OPTIONAL |
|
||||
| **mod-individual-progression** | Personal advancement system | ❌ DISABLED* |
|
||||
| **mod-ahbot** | Auction house bot | ❌ DISABLED* |
|
||||
| **mod-dynamic-xp** | Dynamic experience rates | 🔧 OPTIONAL |
|
||||
| **mod-1v1-arena** | Solo arena battles | 🔧 OPTIONAL |
|
||||
| **mod-phased-duels** | Phased dueling system | 🔧 OPTIONAL |
|
||||
| **mod-breaking-news** | Server announcement system | ❌ DISABLED* |
|
||||
| **mod-boss-announcer** | Boss kill announcements | 🔧 OPTIONAL |
|
||||
| **mod-account-achievements** | Account-wide achievements | 🔧 OPTIONAL |
|
||||
| **mod-auto-revive** | Automatic resurrection | 🔧 OPTIONAL |
|
||||
| **mod-gain-honor-guard** | Honor from guard kills | 🔧 OPTIONAL |
|
||||
| **mod-arac** | All races/classes unlocked | 🔧 OPTIONAL |
|
||||
| **mod-time-is-time** | Time manipulation | ❌ DISABLED* |
|
||||
| **mod-pocket-portal** | Portal convenience | ❌ DISABLED* |
|
||||
| **mod-random-enchants** | Random item enchantments | 🔧 OPTIONAL |
|
||||
| **mod-pvp-titles** | PvP title system | 🔧 OPTIONAL |
|
||||
| **mod-npc-beastmaster** | Pet management NPC | ❌ DISABLED* |
|
||||
| **mod-npc-enchanter** | Enchanting services NPC | ❌ DISABLED* |
|
||||
| **mod-assistant** | AI automation features | 🔧 OPTIONAL |
|
||||
| **mod-reagent-bank** | Reagent storage system | 🔧 OPTIONAL |
|
||||
| **mod-black-market** | Rare item auctions | 🔧 OPTIONAL |
|
||||
| **mod-instance-reset** | Instance reset controls | ❌ DISABLED* |
|
||||
|
||||
*\* Disabled modules require additional configuration or have compatibility issues*
|
||||
|
||||
### ✅ Automated Configuration
|
||||
- **Intelligent Database Setup** - Smart backup detection, restoration, and conditional schema import
|
||||
- **Backup Management** - Automated scheduling, retention policies, and integrity validation
|
||||
- **Backup Management** - Automated hourly/daily backups with intelligent restoration
|
||||
- **Module Integration** - Automatic source builds when C++ modules are enabled
|
||||
- **Realmlist Configuration** - Server address and port setup
|
||||
- **Module Integration** - SQL scripts execution and config deployment
|
||||
- **Service Restart** - Automatic restart to apply configurations
|
||||
- **Service Orchestration** - Profile-based deployment (standard/playerbots/modules)
|
||||
- **Health Monitoring** - Container health checks and restart policies
|
||||
|
||||
### ✅ Lua Scripting Environment
|
||||
- **Example Scripts** - Welcome messages, level rewards, server info commands
|
||||
- **Volume Mounting** - Scripts automatically loaded from `storage/lua_scripts/`
|
||||
- **Eluna Engine** - Built-in Lua scripting support with TypeScript compilation
|
||||
- **Script Auto-loading** - Scripts automatically loaded from `storage/lua_scripts/`
|
||||
- **Development Tools** - Script reloading with `.reload eluna` command
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Manual Configuration Required
|
||||
|
||||
While most setup is automated, some modules require manual configuration:
|
||||
|
||||
### ✅ Module Integration Verification
|
||||
|
||||
**mod-playerbots Integration Status**
|
||||
- **RESOLVED**: Now using compatible Docker images
|
||||
- **Images**: `uprightbass360/azerothcore-wotlk-playerbots:*-Playerbot`
|
||||
- **Branch**: AzerothCore Playerbot branch (confirmed in logs)
|
||||
- **Database**: Playerbot tables created (`playerbots_rpg_races`)
|
||||
- **Status**: Fully integrated and operational
|
||||
|
||||
**Module System Verification (All 13 modules)**
|
||||
- **Binary Integration**: ✅ Compiled into WorldServer (Playerbot branch)
|
||||
- **File System**: ✅ All modules present in `/azerothcore/modules/`
|
||||
- **Database**: ✅ Module tables and SQL scripts executed
|
||||
- **Configuration**: ✅ Module framework active in worldserver.conf
|
||||
- **Process**: ✅ WorldServer running with 1.9GB RAM (normal for module build)
|
||||
|
||||
**Technical Verification Details**
|
||||
- **Server Version**: `AzerothCore rev. 509eb73e0115+ (Playerbot branch)`
|
||||
- **Docker Images**: All using `uprightbass360/azerothcore-wotlk-playerbots:*-Playerbot`
|
||||
- **VMap Errors**: Non-critical cosmetic 3D model loading (safe to ignore)
|
||||
- **Module Tables**: `module_string`, `module_string_locale`, `playerbots_rpg_races`
|
||||
- **Lua Scripting**: Active with TypeScript compilation via ac-eluna container
|
||||
|
||||
### 📦 Client-Side Patches Required
|
||||
|
||||
**mod-individual-progression**
|
||||
- **Required**: `patch-V.mpq` (Vanilla crafting/recipes)
|
||||
- **Optional**: `patch-J.mpq`, `patch-U.mpq`
|
||||
- **Location**: `storage/azerothcore/modules/mod-individual-progression/optional/`
|
||||
- **Install**: Copy patches to client `WoW/Data/` directory
|
||||
|
||||
**mod-arac (All Races All Classes)**
|
||||
- **Required**: `Patch-A.MPQ`
|
||||
- **Location**: `storage/azerothcore/modules/mod-arac/patch-contents/`
|
||||
- **Install**: Copy to client `WoW/Data/` directory
|
||||
|
||||
### ⚙️ Server Configuration Changes
|
||||
|
||||
**mod-individual-progression** requires worldserver.conf updates:
|
||||
```ini
|
||||
# Required settings in storage/azerothcore/config/worldserver.conf
|
||||
EnablePlayerSettings = 1
|
||||
DBC.EnforceItemAttributes = 0
|
||||
```
|
||||
|
||||
**mod-aoe-loot** optimization:
|
||||
```ini
|
||||
# Prevent corpse cleanup issues
|
||||
Rate.Corpse.Decay.Looted = 0.01
|
||||
```
|
||||
|
||||
### 🤖 NPC Spawning Required
|
||||
|
||||
Several modules need NPCs spawned with GM commands:
|
||||
```bash
|
||||
# Transmog NPC
|
||||
.npc add 190010
|
||||
|
||||
# Reagent Bank NPC
|
||||
.npc add 290011
|
||||
|
||||
# NPC Enchanter (check module docs for ID)
|
||||
.npc add [enchanter_id]
|
||||
```
|
||||
|
||||
### 📋 Configuration Analysis Tool
|
||||
|
||||
Check your setup for missing configurations:
|
||||
```bash
|
||||
./scripts/configure-modules.sh
|
||||
```
|
||||
|
||||
This script analyzes your enabled modules and provides specific guidance for resolving configuration issues.
|
||||
- **Volume Mounting** - Hot-reload development environment
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture Overview
|
||||
|
||||
### Container Layers
|
||||
### Container Profiles
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Tools Layer │
|
||||
│ Tools Profile │
|
||||
│ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ phpMyAdmin │ │ Keira3 │ │
|
||||
│ │ :8081 │ │ :4201 │ │
|
||||
│ └─────────────┘ └─────────────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Services Layer │
|
||||
│ Services Profiles │
|
||||
│ Standard | Playerbots | Modules │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Auth │ │ World │ │ Modules │ │
|
||||
│ │ :3784 │ │ :8215 │ │ Manager │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Client │ │ Eluna │ │Post-Inst │ │
|
||||
│ │ Data │ │TypeScript│ │ Config │ │
|
||||
│ │ Auth │ │ World │ │ Client │ │
|
||||
│ │ :3784 │ │ :8215 │ │ Data │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Database Layer │
|
||||
│ Database & Modules │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ MySQL │ │ DB-Init │ │ Backup │ │
|
||||
│ │ :64306 │ │ (setup) │ │ System │ │
|
||||
│ │ MySQL │ │ Module │ │ DB-Init │ │
|
||||
│ │ :64306 │ │ Manager │ │ & Imp. │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Service Inventory & Ports
|
||||
|
||||
| Service / Container | Role | Ports (host → container) | Profile |
|
||||
|---------------------|------|--------------------------|---------|
|
||||
| `ac-mysql` | MySQL 8.0 database | `64306 → 3306` | `db` |
|
||||
| `ac-authserver` | Auth server (standard) | `3784 → 3724` | `services-standard` |
|
||||
| `ac-worldserver` | World server (standard) | `8215 → 8085`, `7778 → 7878` | `services-standard` |
|
||||
| `ac-authserver-playerbots` | Playerbots auth | `3784 → 3724` | `services-playerbots` |
|
||||
| `ac-worldserver-playerbots` | Playerbots world | `8215 → 8085`, `7778 → 7878` | `services-playerbots` |
|
||||
| `ac-authserver-modules` | Custom build auth | `3784 → 3724` | `services-modules` |
|
||||
| `ac-worldserver-modules` | Custom build world | `8215 → 8085`, `7778 → 7878` | `services-modules` |
|
||||
| `ac-client-data` | Client data fetcher | – | `client-data` |
|
||||
| `ac-modules` | Module manager | – | `modules` |
|
||||
| `ac-phpmyadmin` | Database admin UI | `8081 → 80` | `tools` |
|
||||
| `ac-keira3` | Game content editor | `4201 → 8080` | `tools` |
|
||||
|
||||
### Storage Structure
|
||||
```
|
||||
storage/azerothcore/
|
||||
storage/
|
||||
├── config/ # Server configuration files
|
||||
├── data/ # Game client data (maps, DBC files)
|
||||
├── logs/ # Server log files
|
||||
├── modules/ # Module source code and configs
|
||||
├── lua_scripts/ # Eluna Lua scripts
|
||||
├── mysql-data/ # Database files
|
||||
└── backups/ # Automated database backups
|
||||
```
|
||||
@@ -303,28 +201,38 @@ storage/azerothcore/
|
||||
|
||||
### Health Monitoring
|
||||
```bash
|
||||
# Check all containers
|
||||
docker ps
|
||||
# Check realm status
|
||||
./status.sh
|
||||
|
||||
# Watch services continuously
|
||||
./status.sh --watch
|
||||
|
||||
# View service logs
|
||||
docker logs ac-worldserver -f
|
||||
docker logs ac-authserver -f
|
||||
docker logs ac-post-install -f
|
||||
|
||||
# Check module installation
|
||||
# Check module management
|
||||
docker logs ac-modules --tail 50
|
||||
```
|
||||
|
||||
### Module Management
|
||||
```bash
|
||||
# Analyze module configuration
|
||||
./scripts/configure-modules.sh
|
||||
# Reconfigure modules via interactive setup
|
||||
./setup.sh
|
||||
|
||||
# Setup Lua scripting environment
|
||||
./scripts/setup-eluna.sh
|
||||
# Deploy with specific profile
|
||||
./deploy.sh --profile standard # Standard AzerothCore
|
||||
./deploy.sh --profile playerbots # Playerbots branch
|
||||
./deploy.sh --profile modules # Custom modules build
|
||||
|
||||
# Test Eluna scripts
|
||||
docker exec ac-worldserver /bin/bash -c 'echo "reload eluna"'
|
||||
# Force source rebuild
|
||||
./scripts/rebuild-with-modules.sh --yes
|
||||
|
||||
# Stage services without full deployment
|
||||
./scripts/stage-modules.sh
|
||||
|
||||
# Launch management tooling (phpMyAdmin + Keira3)
|
||||
./scripts/deploy-tools.sh
|
||||
```
|
||||
|
||||
### Database Operations
|
||||
@@ -335,66 +243,77 @@ open http://localhost:8081
|
||||
# Direct MySQL access
|
||||
docker exec -it ac-mysql mysql -u root -p
|
||||
|
||||
# Manual backup
|
||||
./scripts/backup.sh
|
||||
# Manual backup operations
|
||||
./scripts/backup.sh # Create immediate backup
|
||||
./scripts/restore.sh YYYYMMDD_HHMMSS # Restore from specific backup
|
||||
|
||||
# View backup status and restore options
|
||||
ls -la storage/azerothcore/backups/
|
||||
# View available backups
|
||||
ls -la storage/backups/
|
||||
```
|
||||
|
||||
### Backup and Restoration System
|
||||
|
||||
The stack includes an intelligent backup and restoration system that automatically:
|
||||
|
||||
**Automated Backup Schedule**
|
||||
- **Hourly backups**: Retained for 6 hours (configurable via `BACKUP_RETENTION_HOURS`)
|
||||
- **Daily backups**: Retained for 3 days (configurable via `BACKUP_RETENTION_DAYS`)
|
||||
- **Automatic cleanup**: Old backups removed based on retention policies
|
||||
|
||||
**Smart Backup Detection**
|
||||
- **Multiple format support**: Detects daily, hourly, and legacy timestamped backups
|
||||
- **Priority-based selection**: Automatically selects the most recent available backup
|
||||
- **Integrity validation**: Verifies backup files before attempting restoration
|
||||
|
||||
**Intelligent Startup Process**
|
||||
- **Automatic restoration**: Detects and restores from existing backups on startup
|
||||
- **Conditional import**: Skips database import when backup restoration succeeds
|
||||
- **Data protection**: Prevents overwriting restored data with fresh schema
|
||||
- **Status tracking**: Creates markers to communicate restoration status between services
|
||||
|
||||
**Backup Structure**
|
||||
```
|
||||
storage/azerothcore/backups/
|
||||
├── daily/
|
||||
│ └── YYYYMMDD_HHMMSS/ # Daily backup directories
|
||||
│ ├── acore_auth.sql.gz
|
||||
│ ├── acore_characters.sql.gz
|
||||
│ ├── acore_world.sql.gz
|
||||
│ └── manifest.json
|
||||
└── hourly/
|
||||
└── YYYYMMDD_HHMMSS/ # Hourly backup directories
|
||||
├── acore_auth.sql.gz
|
||||
├── acore_characters.sql.gz
|
||||
└── acore_world.sql.gz
|
||||
```
|
||||
|
||||
**Manual Backup Operations**
|
||||
### Deployment Verification
|
||||
```bash
|
||||
# Create immediate backup
|
||||
./scripts/backup.sh
|
||||
# Quick health check
|
||||
./verify-deployment.sh --skip-deploy --quick
|
||||
|
||||
# Restore from specific backup (interactive)
|
||||
./scripts/restore.sh YYYYMMDD_HHMMSS
|
||||
|
||||
# View backup contents
|
||||
zcat storage/azerothcore/backups/daily/20241004_090000/acore_world.sql.gz | head
|
||||
|
||||
# Check restoration status
|
||||
cat storage/azerothcore/mysql-data/.restore-completed
|
||||
# Full deployment verification
|
||||
./verify-deployment.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Advanced Configuration
|
||||
|
||||
### Module-Specific Requirements
|
||||
|
||||
Some modules require additional manual configuration after deployment:
|
||||
|
||||
#### mod-playerbots
|
||||
- Requires playerbots-specific AzerothCore branch
|
||||
- Automatically handled when `MODULE_PLAYERBOTS=1` is set in setup
|
||||
|
||||
#### mod-individual-progression
|
||||
- **Client patches required**: `patch-V.mpq` (found in module storage)
|
||||
- **Server config**: Add `EnablePlayerSettings = 1` and `DBC.EnforceItemAttributes = 0` to worldserver.conf
|
||||
|
||||
#### mod-transmog / mod-npc-* modules
|
||||
- **NPC spawning required**: Use GM commands to spawn service NPCs
|
||||
- Examples:
|
||||
```bash
|
||||
.npc add 190010 # Transmog NPC
|
||||
.npc add 290011 # Reagent Bank NPC
|
||||
# Check module docs for enchanter/beastmaster NPC IDs
|
||||
```
|
||||
|
||||
#### mod-arac (All Races All Classes)
|
||||
- **Client patches required**: `Patch-A.MPQ` (found in module storage)
|
||||
- **Installation**: Players must copy to `WoW/Data/` directory
|
||||
- **Server-side**: DBC files automatically applied during module installation
|
||||
|
||||
### Profile Selection
|
||||
|
||||
The deployment system automatically selects profiles based on enabled modules:
|
||||
|
||||
- **services-standard**: No special modules enabled
|
||||
- **services-playerbots**: `MODULE_PLAYERBOTS=1` enabled
|
||||
- **services-modules**: Any C++ modules enabled (requires source rebuild)
|
||||
|
||||
### Custom Builds
|
||||
|
||||
When C++ modules are enabled, the system automatically:
|
||||
1. Clones/updates AzerothCore source
|
||||
2. Syncs enabled modules into source tree
|
||||
3. Rebuilds server images with modules compiled in
|
||||
4. Tags custom images for deployment
|
||||
|
||||
### MySQL Runtime Storage & Timezone Data
|
||||
|
||||
- `MYSQL_RUNTIME_TMPFS_SIZE` controls the in-memory datadir used by the MySQL container. Increase this value if you see `No space left on device` errors inside `/var/lib/mysql-runtime`.
|
||||
- `MYSQL_INNODB_REDO_LOG_CAPACITY` increases redo log headroom (defaults to `512M`). Raise it further if logs report `log_checkpointer` lag.
|
||||
- `HOST_ZONEINFO_PATH` should point to a host directory containing timezone definitions (defaults to `/usr/share/zoneinfo`). The path is mounted read-only so the container can load timezone tables without extra image customization. Set it to a valid directory on your host if your OS stores zoneinfo elsewhere.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
@@ -413,83 +332,135 @@ ss -tulpn | grep -E "(3784|8215|8081|4201)"
|
||||
|
||||
**Module not working**
|
||||
```bash
|
||||
# Check if module is enabled
|
||||
grep MODULE_NAME docker-compose-azerothcore-services.env
|
||||
# Check if module is enabled in environment
|
||||
grep MODULE_NAME .env
|
||||
|
||||
# Verify module installation
|
||||
ls storage/azerothcore/modules/
|
||||
ls storage/modules/
|
||||
|
||||
# Check configuration files
|
||||
ls storage/azerothcore/config/mod_*.conf*
|
||||
# Check module-specific configuration
|
||||
ls storage/config/mod_*.conf*
|
||||
```
|
||||
|
||||
**Database connection issues**
|
||||
```bash
|
||||
# Verify MySQL is running
|
||||
# Verify MySQL is running and responsive
|
||||
docker exec ac-mysql mysql -u root -p -e "SELECT 1;"
|
||||
|
||||
# Check database initialization and backup detection
|
||||
# Check database initialization
|
||||
docker logs ac-db-init
|
||||
|
||||
# Check conditional import status
|
||||
docker logs ac-db-import
|
||||
```
|
||||
|
||||
**Backup and restoration issues**
|
||||
**Source rebuild issues**
|
||||
```bash
|
||||
# Check backup detection and restoration status
|
||||
docker logs ac-db-init | grep -E "(backup|restore)"
|
||||
# Check rebuild logs
|
||||
docker logs ac-modules | grep -A20 -B5 "rebuild"
|
||||
|
||||
# Verify backup directory contents
|
||||
ls -la storage/azerothcore/backups/
|
||||
# Verify source path exists
|
||||
ls -la ./source/azerothcore/
|
||||
|
||||
# Check restoration status markers
|
||||
ls -la storage/azerothcore/mysql-data/.restore-*
|
||||
cat storage/azerothcore/mysql-data/.restore-completed
|
||||
|
||||
# Force fresh database import (if needed)
|
||||
rm -f storage/azerothcore/mysql-data/.restore-*
|
||||
docker compose -f docker-compose-azerothcore-database.yml restart ac-db-init
|
||||
# Force source setup
|
||||
./scripts/setup-source.sh
|
||||
```
|
||||
|
||||
### Getting Help
|
||||
|
||||
Run the configuration analysis tool for specific guidance:
|
||||
```bash
|
||||
./scripts/configure-modules.sh
|
||||
1. **Check service status**: `./status.sh --watch`
|
||||
2. **Review logs**: `docker logs <service-name> -f`
|
||||
3. **Verify configuration**: Check `.env` file for proper module toggles
|
||||
4. **Clean deployment**: Stop all services and redeploy with `./deploy.sh`
|
||||
|
||||
### Backup and Restoration System
|
||||
|
||||
The stack includes an intelligent backup and restoration system:
|
||||
|
||||
**Automated Backup Schedule**
|
||||
- **Hourly backups**: Retained for 6 hours (configurable via `BACKUP_RETENTION_HOURS`)
|
||||
- **Daily backups**: Retained for 3 days (configurable via `BACKUP_RETENTION_DAYS`)
|
||||
- **Automatic cleanup**: Old backups removed based on retention policies
|
||||
|
||||
**Smart Backup Detection**
|
||||
- **Multiple format support**: Detects daily, hourly, and legacy timestamped backups
|
||||
- **Priority-based selection**: Automatically selects the most recent available backup
|
||||
- **Integrity validation**: Verifies backup files before attempting restoration
|
||||
|
||||
**Intelligent Startup Process**
|
||||
- **Automatic restoration**: Detects and restores from existing backups on startup
|
||||
- **Conditional import**: Skips database import when backup restoration succeeds
|
||||
- **Data protection**: Prevents overwriting restored data with fresh schema
|
||||
|
||||
**Backup Structure**
|
||||
```
|
||||
storage/backups/
|
||||
├── daily/
|
||||
│ └── YYYYMMDD_HHMMSS/ # Daily backup directories
|
||||
│ ├── acore_auth.sql.gz
|
||||
│ ├── acore_characters.sql.gz
|
||||
│ ├── acore_world.sql.gz
|
||||
│ └── manifest.json
|
||||
└── hourly/
|
||||
└── YYYYMMDD_HHMMSS/ # Hourly backup directories
|
||||
├── acore_auth.sql.gz
|
||||
├── acore_characters.sql.gz
|
||||
└── acore_world.sql.gz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Documentation
|
||||
## 📚 Advanced Deployment Options
|
||||
|
||||
- **[Module Configuration Requirements](docs/module-configuration-requirements.md)** - Detailed manual setup steps
|
||||
- **[Lua Scripting Guide](storage/azerothcore/lua_scripts/README.md)** - Eluna development
|
||||
- **[Deployment Scripts](scripts/README.md)** - Automation tools reference
|
||||
- **[GitHub-Hosted Scripts](scripts/GITHUB-HOSTED-SCRIPTS.md)** - Service script documentation
|
||||
- **[Deployment Guide](scripts/DEPLOYMENT.md)** - Complete deployment procedures
|
||||
- **[Cleanup Guide](scripts/CLEANUP.md)** - Resource management procedures
|
||||
### Custom Environment Configuration
|
||||
```bash
|
||||
# Generate environment with custom settings
|
||||
./setup.sh
|
||||
|
||||
# Deploy with specific options
|
||||
./deploy.sh --profile modules --no-watch --keep-running
|
||||
```
|
||||
|
||||
### Source Management
|
||||
```bash
|
||||
# Setup/update AzerothCore source
|
||||
./scripts/setup-source.sh
|
||||
|
||||
# Rebuild with modules (manual)
|
||||
./scripts/rebuild-with-modules.sh --yes --source ./custom/path
|
||||
```
|
||||
|
||||
### Cleanup Operations
|
||||
```bash
|
||||
# Stop all services
|
||||
docker compose --profile db --profile services-standard \
|
||||
--profile services-playerbots --profile services-modules \
|
||||
--profile client-data --profile modules --profile tools down
|
||||
|
||||
# Clean rebuild (modules changed)
|
||||
rm -f storage/modules/.requires_rebuild
|
||||
./deploy.sh --profile modules
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps After Installation
|
||||
|
||||
1. **Test Client Connection** - Connect with WoW 3.3.5a client
|
||||
2. **Spawn Required NPCs** - Use GM commands for service modules
|
||||
3. **Apply Client Patches** - For mod-arac and mod-individual-progression
|
||||
4. **Test Module Functionality** - Verify each module works as expected
|
||||
1. **Test Client Connection** - Connect with WoW 3.3.5a client using configured realmlist
|
||||
2. **Create Characters** - Test account creation and character creation
|
||||
3. **Verify Modules** - Test enabled module functionality in-game
|
||||
4. **Configure Optional Features** - Enable additional modules as needed
|
||||
5. **Set Up Backups** - Configure automated backup retention policies
|
||||
|
||||
---
|
||||
|
||||
## 📄 Implementation Credits
|
||||
## 📄 Project Credits
|
||||
|
||||
This project builds upon:
|
||||
- **[AzerothCore](https://github.com/azerothcore/azerothcore-wotlk)** - Core server application
|
||||
- **[AzerothCore Docker Setup](https://github.com/coc0nut/AzerothCore-with-Playerbots-Docker-Setup)** - Initial containerization approach
|
||||
- **[AzerothCore Module Community](https://github.com/azerothcore)** - Enhanced gameplay modules
|
||||
|
||||
### Key Improvements
|
||||
- ✅ **Fully Automated Setup** - Interactive configuration script
|
||||
- ✅ **13 Enhanced Modules** - Complete gameplay enhancement suite
|
||||
### Key Features
|
||||
- ✅ **Fully Automated Setup** - Interactive configuration and deployment
|
||||
- ✅ **Intelligent Module System** - Automatic source builds and profile selection
|
||||
- ✅ **Production Ready** - Health checks, backups, monitoring
|
||||
- ✅ **Cross-Platform** - Docker and Podman support
|
||||
- ✅ **Comprehensive Documentation** - Clear setup and troubleshooting guides
|
||||
- ✅ **Comprehensive Documentation** - Clear setup and troubleshooting guides
|
||||
|
||||
6
V1/.gitignore
vendored
Normal file
6
V1/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
data/
|
||||
backups/
|
||||
local-data-tools/
|
||||
storage/
|
||||
.claude/
|
||||
*custom.env
|
||||
495
V1/README.md
Normal file
495
V1/README.md
Normal file
@@ -0,0 +1,495 @@
|
||||
# AzerothCore Docker/Podman Stack
|
||||
|
||||
A complete containerized deployment of AzerothCore WoW 3.3.5a (Wrath of the Lich King) private server with 13 enhanced modules, automated management, and production-ready features.
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
- **Docker** or **Podman** with Docker Compose
|
||||
- **4GB+ RAM** and **20GB+ storage**
|
||||
- **Linux/macOS/WSL2** (Windows with WSL2 recommended)
|
||||
|
||||
### ⚡ Automated Setup (Recommended)
|
||||
|
||||
**1. Get the Code**
|
||||
```bash
|
||||
git clone https://github.com/uprightbass360/acore-compose.git
|
||||
cd acore-compose
|
||||
```
|
||||
|
||||
**2. Run Interactive Setup**
|
||||
```bash
|
||||
./scripts/setup-server.sh
|
||||
```
|
||||
|
||||
**3. Deploy Server**
|
||||
```bash
|
||||
# Use the generated custom environment files
|
||||
docker compose --env-file docker-compose-azerothcore-database-custom.env -f docker-compose-azerothcore-database.yml up -d
|
||||
docker compose --env-file docker-compose-azerothcore-services-custom.env -f docker-compose-azerothcore-services.yml up -d
|
||||
docker compose --env-file docker-compose-azerothcore-tools-custom.env -f docker-compose-azerothcore-tools.yml up -d
|
||||
```
|
||||
|
||||
**4. Create Admin Account**
|
||||
|
||||
Once the worldserver is running:
|
||||
|
||||
```bash
|
||||
# Attach to worldserver console
|
||||
docker attach ac-worldserver
|
||||
|
||||
# In the worldserver console, create admin account:
|
||||
account create admin yourpassword
|
||||
account set gmlevel admin 3 -1
|
||||
server info
|
||||
|
||||
# Detach from console without stopping: Ctrl+P, Ctrl+Q
|
||||
```
|
||||
|
||||
**5. Configure Game Client**
|
||||
|
||||
**Client Connection Instructions**:
|
||||
|
||||
1. **Locate your WoW 3.3.5a client directory**
|
||||
2. **Edit `realmlist.wtf` file** (in your WoW client folder):
|
||||
```
|
||||
set realmlist SERVER_ADDRESS
|
||||
```
|
||||
|
||||
**Examples based on your server configuration**:
|
||||
```bash
|
||||
# Local development
|
||||
set realmlist 127.0.0.1
|
||||
|
||||
# LAN server
|
||||
set realmlist 192.168.1.100
|
||||
|
||||
# Public server with custom port
|
||||
set realmlist your-domain.com 8215
|
||||
# or for IP with custom port
|
||||
set realmlist 203.0.113.100 8215
|
||||
```
|
||||
|
||||
**6. Access Your Server**
|
||||
- **Game Server**: `your-server-ip:8215` (or port you configured)
|
||||
- **Database Admin**: http://localhost:8081 (phpMyAdmin)
|
||||
- **Game Content Editor**: http://localhost:4201 (Keira3)
|
||||
|
||||
✅ **That's it!** Your server is ready with all 13 modules installed and configured.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Manual Setup (Advanced Users)
|
||||
|
||||
### Step 1: Clone Repository
|
||||
```bash
|
||||
git clone https://github.com/uprightbass360/acore-compose.git
|
||||
cd acore-compose
|
||||
```
|
||||
|
||||
### Step 2: Configure Environment Files
|
||||
Edit these files to match your setup:
|
||||
- `docker-compose-azerothcore-database.env`
|
||||
- `docker-compose-azerothcore-services.env`
|
||||
- `docker-compose-azerothcore-tools.env`
|
||||
|
||||
Key settings to modify:
|
||||
```bash
|
||||
# Server network configuration
|
||||
SERVER_ADDRESS=your-server-ip
|
||||
REALM_PORT=8215
|
||||
AUTH_EXTERNAL_PORT=3784
|
||||
|
||||
# Storage location
|
||||
STORAGE_ROOT=./storage # Local setup
|
||||
# STORAGE_ROOT=/nfs/azerothcore # NFS/network storage
|
||||
|
||||
# Database settings
|
||||
MYSQL_ROOT_PASSWORD=your-secure-password
|
||||
```
|
||||
|
||||
### Step 3: Deploy Layers in Order
|
||||
```bash
|
||||
# 1. Database layer (MySQL + backup system)
|
||||
docker compose --env-file docker-compose-azerothcore-database.env -f docker-compose-azerothcore-database.yml up -d
|
||||
|
||||
# 2. Services layer (auth/world servers + modules)
|
||||
docker compose --env-file docker-compose-azerothcore-services.env -f docker-compose-azerothcore-services.yml up -d
|
||||
|
||||
# 3. Tools layer (phpMyAdmin + Keira3)
|
||||
docker compose --env-file docker-compose-azerothcore-tools.env -f docker-compose-azerothcore-tools.yml up -d
|
||||
```
|
||||
|
||||
### Step 4: Monitor Deployment
|
||||
```bash
|
||||
# Watch post-install configuration
|
||||
docker logs ac-post-install -f
|
||||
|
||||
# Check all services are healthy
|
||||
docker ps
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 What Gets Installed Automatically
|
||||
|
||||
### ✅ Core Server Components
|
||||
- **AzerothCore 3.3.5a** - WotLK server application
|
||||
- **MySQL 8.0** - Database with intelligent initialization and restoration
|
||||
- **Smart Backup System** - Automated hourly/daily backups with intelligent restoration
|
||||
- **phpMyAdmin** - Web-based database administration
|
||||
- **Keira3** - Game content editor and developer tools
|
||||
|
||||
### ✅ 13 Enhanced Modules (✅ VERIFIED INTEGRATED)
|
||||
All modules are automatically downloaded, configured, and SQL scripts executed:
|
||||
|
||||
| Module | Description | Status |
|
||||
|--------|-------------|---------|
|
||||
| **mod-playerbots** | AI companions for solo play | ✅ INTEGRATED |
|
||||
| **mod-aoe-loot** | Streamlined loot collection | ✅ INTEGRATED |
|
||||
| **mod-learn-spells** | Automatic spell learning | ✅ INTEGRATED |
|
||||
| **mod-fireworks** | Level-up celebrations | ✅ INTEGRATED |
|
||||
| **mod-individual-progression** | Personal advancement system | ✅ INTEGRATED |
|
||||
| **mod-transmog** | Appearance customization | ✅ INTEGRATED |
|
||||
| **mod-solo-lfg** | Solo dungeon access | ✅ INTEGRATED |
|
||||
| **mod-eluna** | Lua scripting engine | ✅ INTEGRATED |
|
||||
| **mod-arac** | All races/classes unlocked | ✅ INTEGRATED |
|
||||
| **mod-npc-enchanter** | Enchanting services | ✅ INTEGRATED |
|
||||
| **mod-assistant** | AI automation features | ✅ INTEGRATED |
|
||||
| **mod-reagent-bank** | Reagent storage system | ✅ INTEGRATED |
|
||||
| **mod-black-market** | Rare item auctions | ✅ INTEGRATED |
|
||||
|
||||
### ✅ Automated Configuration
|
||||
- **Intelligent Database Setup** - Smart backup detection, restoration, and conditional schema import
|
||||
- **Backup Management** - Automated scheduling, retention policies, and integrity validation
|
||||
- **Realmlist Configuration** - Server address and port setup
|
||||
- **Module Integration** - SQL scripts execution and config deployment
|
||||
- **Service Restart** - Automatic restart to apply configurations
|
||||
- **Health Monitoring** - Container health checks and restart policies
|
||||
|
||||
### ✅ Lua Scripting Environment
|
||||
- **Example Scripts** - Welcome messages, level rewards, server info commands
|
||||
- **Volume Mounting** - Scripts automatically loaded from `storage/lua_scripts/`
|
||||
- **Development Tools** - Script reloading with `.reload eluna` command
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Manual Configuration Required
|
||||
|
||||
While most setup is automated, some modules require manual configuration:
|
||||
|
||||
### ✅ Module Integration Verification
|
||||
|
||||
**mod-playerbots Integration Status**
|
||||
- **RESOLVED**: Now using compatible Docker images
|
||||
- **Images**: `uprightbass360/azerothcore-wotlk-playerbots:*-Playerbot`
|
||||
- **Branch**: AzerothCore Playerbot branch (confirmed in logs)
|
||||
- **Database**: Playerbot tables created (`playerbots_rpg_races`)
|
||||
- **Status**: Fully integrated and operational
|
||||
|
||||
**Module System Verification (All 13 modules)**
|
||||
- **Binary Integration**: ✅ Compiled into WorldServer (Playerbot branch)
|
||||
- **File System**: ✅ All modules present in `/azerothcore/modules/`
|
||||
- **Database**: ✅ Module tables and SQL scripts executed
|
||||
- **Configuration**: ✅ Module framework active in worldserver.conf
|
||||
- **Process**: ✅ WorldServer running with 1.9GB RAM (normal for module build)
|
||||
|
||||
**Technical Verification Details**
|
||||
- **Server Version**: `AzerothCore rev. 509eb73e0115+ (Playerbot branch)`
|
||||
- **Docker Images**: All using `uprightbass360/azerothcore-wotlk-playerbots:*-Playerbot`
|
||||
- **VMap Errors**: Non-critical cosmetic 3D model loading (safe to ignore)
|
||||
- **Module Tables**: `module_string`, `module_string_locale`, `playerbots_rpg_races`
|
||||
- **Lua Scripting**: Active with TypeScript compilation via ac-eluna container
|
||||
|
||||
### 📦 Client-Side Patches Required
|
||||
|
||||
**mod-individual-progression**
|
||||
- **Required**: `patch-V.mpq` (Vanilla crafting/recipes)
|
||||
- **Optional**: `patch-J.mpq`, `patch-U.mpq`
|
||||
- **Location**: `storage/azerothcore/modules/mod-individual-progression/optional/`
|
||||
- **Install**: Copy patches to client `WoW/Data/` directory
|
||||
|
||||
**mod-arac (All Races All Classes)**
|
||||
- **Required**: `Patch-A.MPQ`
|
||||
- **Location**: `storage/azerothcore/modules/mod-arac/patch-contents/`
|
||||
- **Install**: Copy to client `WoW/Data/` directory
|
||||
|
||||
### ⚙️ Server Configuration Changes
|
||||
|
||||
**mod-individual-progression** requires worldserver.conf updates:
|
||||
```ini
|
||||
# Required settings in storage/azerothcore/config/worldserver.conf
|
||||
EnablePlayerSettings = 1
|
||||
DBC.EnforceItemAttributes = 0
|
||||
```
|
||||
|
||||
**mod-aoe-loot** optimization:
|
||||
```ini
|
||||
# Prevent corpse cleanup issues
|
||||
Rate.Corpse.Decay.Looted = 0.01
|
||||
```
|
||||
|
||||
### 🤖 NPC Spawning Required
|
||||
|
||||
Several modules need NPCs spawned with GM commands:
|
||||
```bash
|
||||
# Transmog NPC
|
||||
.npc add 190010
|
||||
|
||||
# Reagent Bank NPC
|
||||
.npc add 290011
|
||||
|
||||
# NPC Enchanter (check module docs for ID)
|
||||
.npc add [enchanter_id]
|
||||
```
|
||||
|
||||
### 📋 Configuration Analysis Tool
|
||||
|
||||
Check your setup for missing configurations:
|
||||
```bash
|
||||
./scripts/configure-modules.sh
|
||||
```
|
||||
|
||||
This script analyzes your enabled modules and provides specific guidance for resolving configuration issues.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture Overview
|
||||
|
||||
### Container Layers
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Tools Layer │
|
||||
│ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ phpMyAdmin │ │ Keira3 │ │
|
||||
│ │ :8081 │ │ :4201 │ │
|
||||
│ └─────────────┘ └─────────────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Services Layer │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Auth │ │ World │ │ Modules │ │
|
||||
│ │ :3784 │ │ :8215 │ │ Manager │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Client │ │ Eluna │ │Post-Inst │ │
|
||||
│ │ Data │ │TypeScript│ │ Config │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Database Layer │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ MySQL │ │ DB-Init │ │ Backup │ │
|
||||
│ │ :64306 │ │ (setup) │ │ System │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
└─────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Storage Structure
|
||||
```
|
||||
storage/azerothcore/
|
||||
├── config/ # Server configuration files
|
||||
├── data/ # Game client data (maps, DBC files)
|
||||
├── logs/ # Server log files
|
||||
├── modules/ # Module source code and configs
|
||||
├── lua_scripts/ # Eluna Lua scripts
|
||||
├── mysql-data/ # Database files
|
||||
└── backups/ # Automated database backups
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Management Commands
|
||||
|
||||
### Health Monitoring
|
||||
```bash
|
||||
# Check all containers
|
||||
docker ps
|
||||
|
||||
# View service logs
|
||||
docker logs ac-worldserver -f
|
||||
docker logs ac-authserver -f
|
||||
docker logs ac-post-install -f
|
||||
|
||||
# Check module installation
|
||||
docker logs ac-modules --tail 50
|
||||
```
|
||||
|
||||
### Module Management
|
||||
```bash
|
||||
# Analyze module configuration
|
||||
./scripts/configure-modules.sh
|
||||
|
||||
# Setup Lua scripting environment
|
||||
./scripts/setup-eluna.sh
|
||||
|
||||
# Test Eluna scripts
|
||||
docker exec ac-worldserver /bin/bash -c 'echo "reload eluna"'
|
||||
```
|
||||
|
||||
### Database Operations
|
||||
```bash
|
||||
# Access database via phpMyAdmin
|
||||
open http://localhost:8081
|
||||
|
||||
# Direct MySQL access
|
||||
docker exec -it ac-mysql mysql -u root -p
|
||||
|
||||
# Manual backup
|
||||
./scripts/backup.sh
|
||||
|
||||
# View backup status and restore options
|
||||
ls -la storage/azerothcore/backups/
|
||||
```
|
||||
|
||||
### Backup and Restoration System
|
||||
|
||||
The stack includes an intelligent backup and restoration system that automatically:
|
||||
|
||||
**Automated Backup Schedule**
|
||||
- **Hourly backups**: Retained for 6 hours (configurable via `BACKUP_RETENTION_HOURS`)
|
||||
- **Daily backups**: Retained for 3 days (configurable via `BACKUP_RETENTION_DAYS`)
|
||||
- **Automatic cleanup**: Old backups removed based on retention policies
|
||||
|
||||
**Smart Backup Detection**
|
||||
- **Multiple format support**: Detects daily, hourly, and legacy timestamped backups
|
||||
- **Priority-based selection**: Automatically selects the most recent available backup
|
||||
- **Integrity validation**: Verifies backup files before attempting restoration
|
||||
|
||||
**Intelligent Startup Process**
|
||||
- **Automatic restoration**: Detects and restores from existing backups on startup
|
||||
- **Conditional import**: Skips database import when backup restoration succeeds
|
||||
- **Data protection**: Prevents overwriting restored data with fresh schema
|
||||
- **Status tracking**: Creates markers to communicate restoration status between services
|
||||
|
||||
**Backup Structure**
|
||||
```
|
||||
storage/azerothcore/backups/
|
||||
├── daily/
|
||||
│ └── YYYYMMDD_HHMMSS/ # Daily backup directories
|
||||
│ ├── acore_auth.sql.gz
|
||||
│ ├── acore_characters.sql.gz
|
||||
│ ├── acore_world.sql.gz
|
||||
│ └── manifest.json
|
||||
└── hourly/
|
||||
└── YYYYMMDD_HHMMSS/ # Hourly backup directories
|
||||
├── acore_auth.sql.gz
|
||||
├── acore_characters.sql.gz
|
||||
└── acore_world.sql.gz
|
||||
```
|
||||
|
||||
**Manual Backup Operations**
|
||||
```bash
|
||||
# Create immediate backup
|
||||
./scripts/backup.sh
|
||||
|
||||
# Restore from specific backup (interactive)
|
||||
./scripts/restore.sh YYYYMMDD_HHMMSS
|
||||
|
||||
# View backup contents
|
||||
zcat storage/azerothcore/backups/daily/20241004_090000/acore_world.sql.gz | head
|
||||
|
||||
# Check restoration status
|
||||
cat storage/azerothcore/mysql-data/.restore-completed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Containers failing to start**
|
||||
```bash
|
||||
# Check container logs
|
||||
docker logs <container_name>
|
||||
|
||||
# Verify network connectivity
|
||||
docker network ls | grep azerothcore
|
||||
|
||||
# Check port conflicts
|
||||
ss -tulpn | grep -E "(3784|8215|8081|4201)"
|
||||
```
|
||||
|
||||
**Module not working**
|
||||
```bash
|
||||
# Check if module is enabled
|
||||
grep MODULE_NAME docker-compose-azerothcore-services.env
|
||||
|
||||
# Verify module installation
|
||||
ls storage/azerothcore/modules/
|
||||
|
||||
# Check configuration files
|
||||
ls storage/azerothcore/config/mod_*.conf*
|
||||
```
|
||||
|
||||
**Database connection issues**
|
||||
```bash
|
||||
# Verify MySQL is running
|
||||
docker exec ac-mysql mysql -u root -p -e "SELECT 1;"
|
||||
|
||||
# Check database initialization and backup detection
|
||||
docker logs ac-db-init
|
||||
|
||||
# Check conditional import status
|
||||
docker logs ac-db-import
|
||||
```
|
||||
|
||||
**Backup and restoration issues**
|
||||
```bash
|
||||
# Check backup detection and restoration status
|
||||
docker logs ac-db-init | grep -E "(backup|restore)"
|
||||
|
||||
# Verify backup directory contents
|
||||
ls -la storage/azerothcore/backups/
|
||||
|
||||
# Check restoration status markers
|
||||
ls -la storage/azerothcore/mysql-data/.restore-*
|
||||
cat storage/azerothcore/mysql-data/.restore-completed
|
||||
|
||||
# Force fresh database import (if needed)
|
||||
rm -f storage/azerothcore/mysql-data/.restore-*
|
||||
docker compose -f docker-compose-azerothcore-database.yml restart ac-db-init
|
||||
```
|
||||
|
||||
### Getting Help
|
||||
|
||||
Run the configuration analysis tool for specific guidance:
|
||||
```bash
|
||||
./scripts/configure-modules.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Documentation
|
||||
|
||||
- **[Module Configuration Requirements](docs/module-configuration-requirements.md)** - Detailed manual setup steps
|
||||
- **[Lua Scripting Guide](storage/azerothcore/lua_scripts/README.md)** - Eluna development
|
||||
- **[Deployment Scripts](scripts/README.md)** - Automation tools reference
|
||||
- **[GitHub-Hosted Scripts](scripts/GITHUB-HOSTED-SCRIPTS.md)** - Service script documentation
|
||||
- **[Deployment Guide](scripts/DEPLOYMENT.md)** - Complete deployment procedures
|
||||
- **[Cleanup Guide](scripts/CLEANUP.md)** - Resource management procedures
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps After Installation
|
||||
|
||||
1. **Test Client Connection** - Connect with WoW 3.3.5a client
|
||||
2. **Spawn Required NPCs** - Use GM commands for service modules
|
||||
3. **Apply Client Patches** - For mod-arac and mod-individual-progression
|
||||
4. **Test Module Functionality** - Verify each module works as expected
|
||||
|
||||
---
|
||||
|
||||
## 📄 Implementation Credits
|
||||
|
||||
This project builds upon:
|
||||
- **[AzerothCore](https://github.com/azerothcore/azerothcore-wotlk)** - Core server application
|
||||
- **[AzerothCore Docker Setup](https://github.com/coc0nut/AzerothCore-with-Playerbots-Docker-Setup)** - Initial containerization approach
|
||||
|
||||
### Key Improvements
|
||||
- ✅ **Fully Automated Setup** - Interactive configuration script
|
||||
- ✅ **13 Enhanced Modules** - Complete gameplay enhancement suite
|
||||
- ✅ **Production Ready** - Health checks, backups, monitoring
|
||||
- ✅ **Cross-Platform** - Docker and Podman support
|
||||
- ✅ **Comprehensive Documentation** - Clear setup and troubleshooting guides
|
||||
@@ -719,8 +719,8 @@ services:
|
||||
REBUILD_REQUIRED=0
|
||||
|
||||
# Create current module state hash
|
||||
for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT; do
|
||||
eval "value=\$$${module_var}"
|
||||
for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK MODULE_BLACK_MARKET_AUCTION_HOUSE; do
|
||||
eval "value=\$$$module_var"
|
||||
CURRENT_STATE="$${CURRENT_STATE}$${module_var}=$${value}|"
|
||||
done
|
||||
|
||||
@@ -809,6 +809,165 @@ services:
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
# Build Service for C++ Module Compilation
|
||||
ac-build:
|
||||
image: ubuntu:22.04
|
||||
pull_policy: ${IMAGE_PULL_POLICY}
|
||||
container_name: ac-build
|
||||
user: "${CONTAINER_USER}"
|
||||
volumes:
|
||||
- ${STORAGE_PATH}:/azerothcore
|
||||
- ${STORAGE_PATH}/modules:/azerothcore/modules
|
||||
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
- MYSQL_HOST=${MYSQL_HOST}
|
||||
- MYSQL_PORT=${MYSQL_PORT}
|
||||
- MYSQL_USER=${MYSQL_USER}
|
||||
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
||||
- DB_AUTH_NAME=${DB_AUTH_NAME}
|
||||
- DB_WORLD_NAME=${DB_WORLD_NAME}
|
||||
- DB_CHARACTERS_NAME=${DB_CHARACTERS_NAME}
|
||||
- MODULE_PLAYERBOTS=${MODULE_PLAYERBOTS}
|
||||
- MODULE_AOE_LOOT=${MODULE_AOE_LOOT}
|
||||
- MODULE_LEARN_SPELLS=${MODULE_LEARN_SPELLS}
|
||||
- MODULE_FIREWORKS=${MODULE_FIREWORKS}
|
||||
- MODULE_INDIVIDUAL_PROGRESSION=${MODULE_INDIVIDUAL_PROGRESSION}
|
||||
- MODULE_AHBOT=${MODULE_AHBOT}
|
||||
- MODULE_AUTOBALANCE=${MODULE_AUTOBALANCE}
|
||||
- MODULE_TRANSMOG=${MODULE_TRANSMOG}
|
||||
- MODULE_NPC_BUFFER=${MODULE_NPC_BUFFER}
|
||||
- MODULE_DYNAMIC_XP=${MODULE_DYNAMIC_XP}
|
||||
- MODULE_SOLO_LFG=${MODULE_SOLO_LFG}
|
||||
- MODULE_1V1_ARENA=${MODULE_1V1_ARENA}
|
||||
- MODULE_PHASED_DUELS=${MODULE_PHASED_DUELS}
|
||||
- MODULE_BREAKING_NEWS=${MODULE_BREAKING_NEWS}
|
||||
- MODULE_BOSS_ANNOUNCER=${MODULE_BOSS_ANNOUNCER}
|
||||
- MODULE_ACCOUNT_ACHIEVEMENTS=${MODULE_ACCOUNT_ACHIEVEMENTS}
|
||||
- MODULE_AUTO_REVIVE=${MODULE_AUTO_REVIVE}
|
||||
- MODULE_GAIN_HONOR_GUARD=${MODULE_GAIN_HONOR_GUARD}
|
||||
- MODULE_ELUNA=${MODULE_ELUNA}
|
||||
- MODULE_TIME_IS_TIME=${MODULE_TIME_IS_TIME}
|
||||
- MODULE_POCKET_PORTAL=${MODULE_POCKET_PORTAL}
|
||||
- MODULE_RANDOM_ENCHANTS=${MODULE_RANDOM_ENCHANTS}
|
||||
- MODULE_SOLOCRAFT=${MODULE_SOLOCRAFT}
|
||||
- MODULE_PVP_TITLES=${MODULE_PVP_TITLES}
|
||||
- MODULE_NPC_BEASTMASTER=${MODULE_NPC_BEASTMASTER}
|
||||
- MODULE_NPC_ENCHANTER=${MODULE_NPC_ENCHANTER}
|
||||
- MODULE_INSTANCE_RESET=${MODULE_INSTANCE_RESET}
|
||||
- MODULE_LEVEL_GRANT=${MODULE_LEVEL_GRANT}
|
||||
- MODULE_ARAC=${MODULE_ARAC}
|
||||
- MODULE_ASSISTANT=${MODULE_ASSISTANT}
|
||||
- MODULE_REAGENT_BANK=${MODULE_REAGENT_BANK}
|
||||
- MODULE_BLACK_MARKET_AUCTION_HOUSE=${MODULE_BLACK_MARKET_AUCTION_HOUSE}
|
||||
working_dir: /azerothcore
|
||||
command: >
|
||||
sh -c "
|
||||
echo '🔧 AzerothCore Build Service Starting...'
|
||||
|
||||
# Check if rebuild is required by reading module state
|
||||
MODULES_STATE_FILE='/azerothcore/modules/.modules_state'
|
||||
if [ -f \"$$MODULES_STATE_FILE\" ]; then
|
||||
# Check current module configuration
|
||||
CURRENT_STATE=''
|
||||
for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK MODULE_BLACK_MARKET_AUCTION_HOUSE; do
|
||||
eval \"value=\\\$$$module_var\"
|
||||
CURRENT_STATE=\"$${CURRENT_STATE}$${module_var}=$${value}|\"
|
||||
done
|
||||
|
||||
PREVIOUS_STATE=$$(cat \"$$MODULES_STATE_FILE\")
|
||||
|
||||
# Check if any C++ modules are enabled and if no built binaries exist
|
||||
BUILD_REQUIRED=0
|
||||
if [ \"$$CURRENT_STATE\" != \"$$PREVIOUS_STATE\" ]; then
|
||||
echo '🔄 Module configuration changed - starting compilation...'
|
||||
BUILD_REQUIRED=1
|
||||
elif [ ! -f '/azerothcore/server/bin/worldserver' ]; then
|
||||
echo '📝 No compiled binaries found - starting initial compilation...'
|
||||
BUILD_REQUIRED=1
|
||||
fi
|
||||
|
||||
if [ \"$$BUILD_REQUIRED\" = \"1\" ]; then
|
||||
|
||||
# Install required packages
|
||||
apt-get update && apt-get install -y git cmake build-essential libssl-dev libreadline-dev zlib1g-dev libbz2-dev libncurses-dev mysql-client
|
||||
|
||||
# Clone AzerothCore source
|
||||
if [ ! -d '/azerothcore/azerothcore-wotlk' ]; then
|
||||
echo '📥 Cloning AzerothCore source...'
|
||||
git clone --depth 1 --branch master https://github.com/azerothcore/azerothcore-wotlk.git
|
||||
fi
|
||||
|
||||
cd /azerothcore/azerothcore-wotlk
|
||||
|
||||
# Setup modules directory and clone enabled modules
|
||||
mkdir -p modules
|
||||
cd modules
|
||||
|
||||
# Clone enabled C++ modules
|
||||
if [ \"$$MODULE_AOE_LOOT\" = \"1\" ]; then
|
||||
[ ! -d \"mod-aoe-loot\" ] && git clone https://github.com/azerothcore/mod-aoe-loot.git
|
||||
fi
|
||||
if [ \"$$MODULE_LEARN_SPELLS\" = \"1\" ]; then
|
||||
[ ! -d \"mod-learn-spells\" ] && git clone https://github.com/azerothcore/mod-learn-spells.git
|
||||
fi
|
||||
if [ \"$$MODULE_FIREWORKS\" = \"1\" ]; then
|
||||
[ ! -d \"mod-fireworks-on-level\" ] && git clone https://github.com/azerothcore/mod-fireworks-on-level.git
|
||||
fi
|
||||
if [ \"$$MODULE_AHBOT\" = \"1\" ]; then
|
||||
[ ! -d \"mod-ahbot\" ] && git clone https://github.com/azerothcore/mod-ahbot.git
|
||||
fi
|
||||
if [ \"$$MODULE_AUTOBALANCE\" = \"1\" ]; then
|
||||
[ ! -d \"mod-autobalance\" ] && git clone https://github.com/azerothcore/mod-autobalance.git
|
||||
fi
|
||||
if [ \"$$MODULE_TRANSMOG\" = \"1\" ]; then
|
||||
[ ! -d \"mod-transmog\" ] && git clone https://github.com/azerothcore/mod-transmog.git
|
||||
fi
|
||||
if [ \"$$MODULE_NPC_BUFFER\" = \"1\" ]; then
|
||||
[ ! -d \"mod-npc-buffer\" ] && git clone https://github.com/azerothcore/mod-npc-buffer.git
|
||||
fi
|
||||
if [ \"$$MODULE_SOLO_LFG\" = \"1\" ]; then
|
||||
[ ! -d \"mod-solo-lfg\" ] && git clone https://github.com/azerothcore/mod-solo-lfg.git
|
||||
fi
|
||||
if [ \"$$MODULE_SOLOCRAFT\" = \"1\" ]; then
|
||||
[ ! -d \"mod-solocraft\" ] && git clone https://github.com/azerothcore/mod-solocraft.git
|
||||
fi
|
||||
|
||||
cd /azerothcore/azerothcore-wotlk
|
||||
|
||||
# Configure and build
|
||||
echo '🔨 Configuring build...'
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=/azerothcore/server -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DWITH_WARNINGS=1 -DTOOLS=0 -DSCRIPTS=static -DMODULES=static
|
||||
|
||||
echo '🏗️ Starting compilation (this may take 15-45 minutes)...'
|
||||
make -j$$(nproc)
|
||||
|
||||
echo '📦 Installing binaries...'
|
||||
make install
|
||||
|
||||
echo '✅ Build completed successfully!'
|
||||
|
||||
# Update state file to prevent rebuilds
|
||||
echo \"$$CURRENT_STATE\" > \"$$MODULES_STATE_FILE\"
|
||||
|
||||
else
|
||||
echo '✅ No module changes detected and binaries exist - build not required'
|
||||
fi
|
||||
else
|
||||
echo '⚠️ Module state file not found - build service waiting for modules container'
|
||||
fi
|
||||
|
||||
echo '🏁 Build service complete. Container will exit.'
|
||||
"
|
||||
restart: "no"
|
||||
depends_on:
|
||||
- ac-modules
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
networks:
|
||||
azerothcore:
|
||||
external: true
|
||||
@@ -24,15 +24,15 @@ services:
|
||||
# Auto-detect package manager and install dependencies (as root)
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
# Alpine Linux - install full wget and bash for script compatibility
|
||||
apk add --no-cache curl unzip wget bash ca-certificates p7zip jq
|
||||
apk add --no-cache curl unzip wget bash ca-certificates p7zip aria2 jq
|
||||
elif command -v apt-get >/dev/null 2>&1; then
|
||||
# Ubuntu/Debian
|
||||
apt-get update && apt-get install -y --no-install-recommends curl unzip wget ca-certificates p7zip-full jq && rm -rf /var/lib/apt/lists/*
|
||||
apt-get update && apt-get install -y --no-install-recommends curl unzip wget bash ca-certificates p7zip-full aria2 jq && rm -rf /var/lib/apt/lists/*
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
# CentOS/RHEL
|
||||
yum install -y curl unzip wget ca-certificates p7zip jq
|
||||
yum install -y curl unzip wget bash ca-certificates p7zip aria2 jq
|
||||
else
|
||||
echo "❌ Unsupported package manager - please install: curl unzip wget ca-certificates p7zip jq"
|
||||
echo "❌ Unsupported package manager - please install: curl unzip wget bash ca-certificates p7zip aria2 jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
184
V1/scripts/auto-post-install.sh
Executable file
184
V1/scripts/auto-post-install.sh
Executable file
@@ -0,0 +1,184 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🚀 AzerothCore Auto Post-Install Configuration"
|
||||
echo "=============================================="
|
||||
|
||||
# Install required packages
|
||||
apk add --no-cache curl mysql-client bash docker-cli-compose jq
|
||||
|
||||
# Create install markers directory
|
||||
mkdir -p /install-markers
|
||||
|
||||
# Check if this is a new installation
|
||||
if [ -f "/install-markers/post-install-completed" ]; then
|
||||
echo "✅ Post-install configuration already completed"
|
||||
echo "ℹ️ Marker file found: /install-markers/post-install-completed"
|
||||
echo "🔄 To re-run post-install configuration, delete the marker file and restart this container"
|
||||
echo "📝 Command: docker exec ${CONTAINER_POST_INSTALL} rm -f /install-markers/post-install-completed"
|
||||
echo ""
|
||||
echo "🏃 Keeping container alive for manual operations..."
|
||||
tail -f /dev/null
|
||||
else
|
||||
echo "🆕 New installation detected - running post-install configuration..."
|
||||
echo ""
|
||||
|
||||
# Wait for services to be ready
|
||||
echo "⏳ Waiting for required services to be ready..."
|
||||
|
||||
# Wait for MySQL to be responsive
|
||||
echo "🔌 Waiting for MySQL to be ready..."
|
||||
for i in $(seq 1 120); do
|
||||
if mysql -h "${MYSQL_HOST}" -u"${MYSQL_USER}" -p"${MYSQL_ROOT_PASSWORD}" --skip-ssl-verify -e "SELECT 1;" >/dev/null 2>&1; then
|
||||
echo "✅ MySQL is ready"
|
||||
break
|
||||
fi
|
||||
echo " ⏳ Attempt $i/120..."
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# Wait for authserver and worldserver config files to exist
|
||||
echo "📁 Waiting for configuration files..."
|
||||
for i in $(seq 1 60); do
|
||||
if [ -f "/azerothcore/config/authserver.conf" ] && [ -f "/azerothcore/config/worldserver.conf" ]; then
|
||||
echo "✅ Configuration files found"
|
||||
break
|
||||
fi
|
||||
echo " ⏳ Waiting for config files... attempt $i/60"
|
||||
sleep 5
|
||||
done
|
||||
|
||||
if [ ! -f "/azerothcore/config/authserver.conf" ] || [ ! -f "/azerothcore/config/worldserver.conf" ]; then
|
||||
echo "❌ Configuration files not found after waiting"
|
||||
echo " Expected: /azerothcore/config/authserver.conf"
|
||||
echo " Expected: /azerothcore/config/worldserver.conf"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 1: Update configuration files
|
||||
echo ""
|
||||
echo "🔧 Step 1: Updating configuration files..."
|
||||
|
||||
# Download and execute update-config.sh
|
||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/update-config.sh -o /tmp/update-config.sh
|
||||
chmod +x /tmp/update-config.sh
|
||||
|
||||
# Modify script to use container environment
|
||||
sed -i 's|docker-compose-azerothcore-services.env|/project/docker-compose-azerothcore-services.env|' /tmp/update-config.sh
|
||||
sed -i 's|CONFIG_DIR="${STORAGE_PATH}/config"|CONFIG_DIR="/azerothcore/config"|' /tmp/update-config.sh
|
||||
|
||||
# Execute update-config.sh
|
||||
cd /project
|
||||
/tmp/update-config.sh
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Configuration files updated successfully"
|
||||
else
|
||||
echo "❌ Failed to update configuration files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 2: Update realmlist table
|
||||
echo ""
|
||||
echo "🌐 Step 2: Updating realmlist table..."
|
||||
|
||||
# Download and execute update-realmlist.sh
|
||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/update-realmlist.sh -o /tmp/update-realmlist.sh
|
||||
chmod +x /tmp/update-realmlist.sh
|
||||
|
||||
# Modify script to use container environment
|
||||
sed -i 's|docker-compose-azerothcore-services.env|/project/docker-compose-azerothcore-services.env|' /tmp/update-realmlist.sh
|
||||
|
||||
# Replace all docker exec mysql commands with direct mysql commands
|
||||
sed -i "s|docker exec ac-mysql mysql -u \"\${MYSQL_USER}\" -p\"\${MYSQL_ROOT_PASSWORD}\" \"\${DB_AUTH_NAME}\"|mysql -h \"${MYSQL_HOST}\" -u\"${MYSQL_USER}\" -p\"${MYSQL_ROOT_PASSWORD}\" --skip-ssl-verify \"${DB_AUTH_NAME}\"|g" /tmp/update-realmlist.sh
|
||||
sed -i "s|docker exec ac-mysql mysql -u \"\${MYSQL_USER}\" -p\"\${MYSQL_ROOT_PASSWORD}\"|mysql -h \"${MYSQL_HOST}\" -u\"${MYSQL_USER}\" -p\"${MYSQL_ROOT_PASSWORD}\" --skip-ssl-verify|g" /tmp/update-realmlist.sh
|
||||
|
||||
# Execute update-realmlist.sh
|
||||
cd /project
|
||||
/tmp/update-realmlist.sh
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Realmlist table updated successfully"
|
||||
else
|
||||
echo "❌ Failed to update realmlist table"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 3: Restart services to apply changes
|
||||
echo ""
|
||||
echo "ℹ️ Step 3: Restarting services to apply changes..."
|
||||
echo "📝 Configuration changes have been applied to files"
|
||||
echo "🔄 Restarting authserver and worldserver to pick up new configuration..."
|
||||
|
||||
# Detect container runtime (Docker or Podman)
|
||||
CONTAINER_CMD=""
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
# Check if we can connect to Docker daemon
|
||||
if docker version >/dev/null 2>&1; then
|
||||
CONTAINER_CMD="docker"
|
||||
echo "🐳 Detected Docker runtime"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$CONTAINER_CMD" ] && command -v podman >/dev/null 2>&1; then
|
||||
# Check if we can connect to Podman
|
||||
if podman version >/dev/null 2>&1; then
|
||||
CONTAINER_CMD="podman"
|
||||
echo "🦭 Detected Podman runtime"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$CONTAINER_CMD" ]; then
|
||||
echo "⚠️ No container runtime detected (docker/podman) - skipping restart"
|
||||
else
|
||||
# Restart authserver
|
||||
if [ -n "$CONTAINER_AUTHSERVER" ]; then
|
||||
echo "🔄 Restarting authserver container: $CONTAINER_AUTHSERVER"
|
||||
if $CONTAINER_CMD restart "$CONTAINER_AUTHSERVER" 2>/dev/null; then
|
||||
echo "✅ Authserver restarted successfully"
|
||||
else
|
||||
echo "⚠️ Failed to restart authserver (may not be running yet)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Restart worldserver
|
||||
if [ -n "$CONTAINER_WORLDSERVER" ]; then
|
||||
echo "🔄 Restarting worldserver container: $CONTAINER_WORLDSERVER"
|
||||
if $CONTAINER_CMD restart "$CONTAINER_WORLDSERVER" 2>/dev/null; then
|
||||
echo "✅ Worldserver restarted successfully"
|
||||
else
|
||||
echo "⚠️ Failed to restart worldserver (may not be running yet)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✅ Service restart completed"
|
||||
|
||||
# Create completion marker
|
||||
echo "$(date)" > /install-markers/post-install-completed
|
||||
echo "NEW_INSTALL_DATE=$(date)" >> /install-markers/post-install-completed
|
||||
echo "CONFIG_FILES_UPDATED=true" >> /install-markers/post-install-completed
|
||||
echo "REALMLIST_UPDATED=true" >> /install-markers/post-install-completed
|
||||
echo "SERVICES_RESTARTED=true" >> /install-markers/post-install-completed
|
||||
|
||||
echo ""
|
||||
echo "🎉 Auto post-install configuration completed successfully!"
|
||||
echo ""
|
||||
echo "📋 Summary of changes:"
|
||||
echo " ✅ AuthServer configured with production database settings"
|
||||
echo " ✅ WorldServer configured with production database settings"
|
||||
echo " ✅ Realmlist updated with server address: ${SERVER_ADDRESS}:${REALM_PORT}"
|
||||
echo " ✅ Services restarted to apply changes"
|
||||
echo " ✅ Completion marker created: /install-markers/post-install-completed"
|
||||
echo ""
|
||||
echo "🎮 Your AzerothCore server is now ready for production!"
|
||||
echo " Players can connect to: ${SERVER_ADDRESS}:${REALM_PORT}"
|
||||
echo ""
|
||||
echo "💡 Next steps:"
|
||||
echo " 1. Create admin accounts using the worldserver console"
|
||||
echo " 2. Test client connectivity"
|
||||
echo " 3. Configure any additional modules as needed"
|
||||
echo ""
|
||||
echo "🏃 Keeping container alive for future manual operations..."
|
||||
tail -f /dev/null
|
||||
fi
|
||||
57
V1/scripts/backup-scheduler.sh
Normal file
57
V1/scripts/backup-scheduler.sh
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🔧 Starting enhanced backup service with hourly and daily schedules..."
|
||||
|
||||
# Install curl if not available (handle different package managers)
|
||||
# NOTE: curl is already available in mysql:8.0 base image, commenting out to fix operator precedence issue
|
||||
# microdnf install -y curl || yum install -y curl || apt-get update && apt-get install -y curl
|
||||
|
||||
# Download backup scripts from GitHub
|
||||
echo "📥 Downloading backup scripts from GitHub..."
|
||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup.sh -o /tmp/backup.sh
|
||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup-hourly.sh -o /tmp/backup-hourly.sh
|
||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup-daily.sh -o /tmp/backup-daily.sh
|
||||
chmod +x /tmp/backup.sh /tmp/backup-hourly.sh /tmp/backup-daily.sh
|
||||
|
||||
# Wait for MySQL to be ready before starting backup service
|
||||
echo "⏳ Waiting for MySQL to be ready..."
|
||||
sleep 30
|
||||
|
||||
# Run initial daily backup
|
||||
echo "🚀 Running initial daily backup..."
|
||||
/tmp/backup-daily.sh
|
||||
|
||||
# Enhanced scheduler with hourly and daily backups
|
||||
echo "⏰ Starting enhanced backup scheduler:"
|
||||
echo " 📅 Daily backups: ${BACKUP_DAILY_TIME}:00 UTC (retention: ${BACKUP_RETENTION_DAYS} days)"
|
||||
echo " ⏰ Hourly backups: every hour (retention: ${BACKUP_RETENTION_HOURS} hours)"
|
||||
|
||||
# Track last backup times to avoid duplicates
|
||||
last_daily_hour=""
|
||||
last_hourly_minute=""
|
||||
|
||||
while true; do
|
||||
current_hour=$(date +%H)
|
||||
current_minute=$(date +%M)
|
||||
current_time="$current_hour:$current_minute"
|
||||
|
||||
# Daily backup check (configurable time)
|
||||
if [ "$current_hour" = "${BACKUP_DAILY_TIME}" ] && [ "$current_minute" = "00" ] && [ "$last_daily_hour" != "$current_hour" ]; then
|
||||
echo "📅 [$(date)] Daily backup time reached, running daily backup..."
|
||||
/tmp/backup-daily.sh
|
||||
last_daily_hour="$current_hour"
|
||||
# Sleep for 2 minutes to avoid running multiple times
|
||||
sleep 120
|
||||
# Hourly backup check (every hour at minute 0, except during daily backup)
|
||||
elif [ "$current_minute" = "00" ] && [ "$current_hour" != "${BACKUP_DAILY_TIME}" ] && [ "$last_hourly_minute" != "$current_minute" ]; then
|
||||
echo "⏰ [$(date)] Hourly backup time reached, running hourly backup..."
|
||||
/tmp/backup-hourly.sh
|
||||
last_hourly_minute="$current_minute"
|
||||
# Sleep for 2 minutes to avoid running multiple times
|
||||
sleep 120
|
||||
else
|
||||
# Sleep for 1 minute before checking again
|
||||
sleep 60
|
||||
fi
|
||||
done
|
||||
331
V1/scripts/db-import-conditional.sh
Executable file
331
V1/scripts/db-import-conditional.sh
Executable file
@@ -0,0 +1,331 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🔧 Conditional AzerothCore Database Import"
|
||||
echo "========================================"
|
||||
|
||||
# Restoration status markers - use writable location
|
||||
RESTORE_STATUS_DIR="/var/lib/mysql-persistent"
|
||||
MARKER_STATUS_DIR="/tmp"
|
||||
RESTORE_SUCCESS_MARKER="$RESTORE_STATUS_DIR/.restore-completed"
|
||||
RESTORE_FAILED_MARKER="$RESTORE_STATUS_DIR/.restore-failed"
|
||||
RESTORE_SUCCESS_MARKER_TMP="$MARKER_STATUS_DIR/.restore-completed"
|
||||
RESTORE_FAILED_MARKER_TMP="$MARKER_STATUS_DIR/.restore-failed"
|
||||
|
||||
# Ensure we can write to the status directory, fallback to tmp
|
||||
mkdir -p "$RESTORE_STATUS_DIR" 2>/dev/null || true
|
||||
if ! touch "$RESTORE_STATUS_DIR/.test-write" 2>/dev/null; then
|
||||
echo "⚠️ Cannot write to $RESTORE_STATUS_DIR, using $MARKER_STATUS_DIR for markers"
|
||||
RESTORE_SUCCESS_MARKER="$RESTORE_SUCCESS_MARKER_TMP"
|
||||
RESTORE_FAILED_MARKER="$RESTORE_FAILED_MARKER_TMP"
|
||||
else
|
||||
rm -f "$RESTORE_STATUS_DIR/.test-write" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "🔍 Checking restoration status..."
|
||||
|
||||
# Check if backup was successfully restored
|
||||
if [ -f "$RESTORE_SUCCESS_MARKER" ]; then
|
||||
echo "✅ Backup restoration completed successfully"
|
||||
echo "📄 Restoration details:"
|
||||
cat "$RESTORE_SUCCESS_MARKER"
|
||||
echo ""
|
||||
echo "🚫 Skipping database import - data already restored from backup"
|
||||
echo "💡 This prevents overwriting restored data with fresh schema"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if restoration failed (fresh databases created)
|
||||
if [ -f "$RESTORE_FAILED_MARKER" ]; then
|
||||
echo "ℹ️ No backup was restored - fresh databases detected"
|
||||
echo "📄 Database creation details:"
|
||||
cat "$RESTORE_FAILED_MARKER"
|
||||
echo ""
|
||||
echo "▶️ Proceeding with database import to populate fresh databases"
|
||||
else
|
||||
echo "⚠️ No restoration status found - assuming fresh installation"
|
||||
echo "▶️ Proceeding with database import"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🔧 Starting database import process..."
|
||||
|
||||
# First attempt backup restoration
|
||||
echo "🔍 Checking for backups to restore..."
|
||||
|
||||
BACKUP_DIRS="/backups"
|
||||
|
||||
|
||||
# Function to restore from backup (directory or single file)
|
||||
restore_from_directory() {
|
||||
local backup_path="$1"
|
||||
echo "🔄 Restoring from backup: $backup_path"
|
||||
|
||||
local restore_success=true
|
||||
|
||||
# Handle single .sql file (legacy backup)
|
||||
if [ -f "$backup_path" ] && [[ "$backup_path" == *.sql ]]; then
|
||||
echo "📥 Restoring legacy backup file: $(basename "$backup_path")"
|
||||
if timeout 300 mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} < "$backup_path"; then
|
||||
echo "✅ Successfully restored legacy backup"
|
||||
return 0
|
||||
else
|
||||
echo "❌ Failed to restore legacy backup"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Handle directory with .sql.gz files (modern timestamped backups)
|
||||
if [ -d "$backup_path" ]; then
|
||||
echo "🔄 Restoring from backup directory: $backup_path"
|
||||
# Restore each database backup
|
||||
for backup_file in "$backup_path"/*.sql.gz; do
|
||||
if [ -f "$backup_file" ]; then
|
||||
local db_name=$(basename "$backup_file" .sql.gz)
|
||||
echo "📥 Restoring database: $db_name"
|
||||
|
||||
if timeout 300 zcat "$backup_file" | mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD}; then
|
||||
echo "✅ Successfully restored $db_name"
|
||||
else
|
||||
echo "❌ Failed to restore $db_name"
|
||||
restore_success=false
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$restore_success" = true ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we get here, backup_path is neither a valid .sql file nor a directory
|
||||
echo "❌ Invalid backup path: $backup_path (not a .sql file or directory)"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Attempt backup restoration with full functionality restored
|
||||
echo "🔄 Checking for backups..."
|
||||
backup_path=""
|
||||
|
||||
# Priority 1: Legacy single backup file with content validation
|
||||
echo "🔍 Checking for legacy backup file..."
|
||||
if [ -f "/var/lib/mysql-persistent/backup.sql" ]; then
|
||||
echo "📄 Found legacy backup file, validating content..."
|
||||
if timeout 10 head -10 "/var/lib/mysql-persistent/backup.sql" 2>/dev/null | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then
|
||||
echo "✅ Legacy backup file validated"
|
||||
backup_path="/var/lib/mysql-persistent/backup.sql"
|
||||
else
|
||||
echo "⚠️ Legacy backup file exists but appears invalid or empty"
|
||||
fi
|
||||
else
|
||||
echo "🔍 No legacy backup found"
|
||||
fi
|
||||
|
||||
# Priority 2: Modern timestamped backups (only if no legacy backup found)
|
||||
if [ -z "$backup_path" ] && [ -d "$BACKUP_DIRS" ]; then
|
||||
echo "📁 Backup directory exists, checking for timestamped backups..."
|
||||
if [ "$(ls -A $BACKUP_DIRS 2>/dev/null | wc -l)" -gt 0 ]; then
|
||||
# Check daily backups first
|
||||
if [ -d "$BACKUP_DIRS/daily" ] && [ "$(ls -A $BACKUP_DIRS/daily 2>/dev/null | wc -l)" -gt 0 ]; then
|
||||
echo "📅 Found daily backup directory, finding latest..."
|
||||
latest_daily=$(ls -1t $BACKUP_DIRS/daily 2>/dev/null | head -n 1)
|
||||
if [ -n "$latest_daily" ] && [ -d "$BACKUP_DIRS/daily/$latest_daily" ]; then
|
||||
echo "📦 Checking backup directory: $latest_daily"
|
||||
# Check if directory has .sql.gz files
|
||||
if ls "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz >/dev/null 2>&1; then
|
||||
# Validate at least one backup file has content
|
||||
echo "🔍 Validating backup content..."
|
||||
for backup_file in "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz; do
|
||||
if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then
|
||||
# Use timeout to prevent hanging on zcat
|
||||
if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then
|
||||
echo "✅ Valid backup found: $(basename $backup_file)"
|
||||
backup_path="$BACKUP_DIRS/daily/$latest_daily"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "⚠️ No .sql.gz files found in backup directory"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "📅 No daily backup directory found"
|
||||
# Check for timestamped backup directories (legacy format: YYYYMMDD_HHMMSS)
|
||||
echo "🔍 Checking for timestamped backup directories..."
|
||||
timestamped_backups=$(ls -1t $BACKUP_DIRS 2>/dev/null | grep -E '^[0-9]{8}_[0-9]{6}$' | head -n 1)
|
||||
if [ -n "$timestamped_backups" ]; then
|
||||
latest_timestamped="$timestamped_backups"
|
||||
echo "📦 Found timestamped backup: $latest_timestamped"
|
||||
if [ -d "$BACKUP_DIRS/$latest_timestamped" ]; then
|
||||
# Check if directory has .sql.gz files
|
||||
if ls "$BACKUP_DIRS/$latest_timestamped"/*.sql.gz >/dev/null 2>&1; then
|
||||
# Validate at least one backup file has content
|
||||
echo "🔍 Validating timestamped backup content..."
|
||||
for backup_file in "$BACKUP_DIRS/$latest_timestamped"/*.sql.gz; do
|
||||
if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then
|
||||
# Use timeout to prevent hanging on zcat
|
||||
if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then
|
||||
echo "✅ Valid timestamped backup found: $(basename $backup_file)"
|
||||
backup_path="$BACKUP_DIRS/$latest_timestamped"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "⚠️ No .sql.gz files found in timestamped backup directory"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "📅 No timestamped backup directories found"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "📁 Backup directory is empty"
|
||||
fi
|
||||
else
|
||||
echo "📁 No backup directory found or legacy backup already selected"
|
||||
fi
|
||||
|
||||
echo "🔄 Final backup path result: '$backup_path'"
|
||||
if [ -n "$backup_path" ]; then
|
||||
echo "📦 Found backup: $(basename $backup_path)"
|
||||
if restore_from_directory "$backup_path"; then
|
||||
echo "✅ Database restoration completed successfully!"
|
||||
echo "$(date): Backup successfully restored from $backup_path" > "$RESTORE_SUCCESS_MARKER"
|
||||
echo "🚫 Skipping schema import - data already restored from backup"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ Backup restoration failed - proceeding with fresh setup"
|
||||
echo "$(date): Backup restoration failed - proceeding with fresh setup" > "$RESTORE_FAILED_MARKER"
|
||||
fi
|
||||
else
|
||||
echo "ℹ️ No valid backups found - proceeding with fresh setup"
|
||||
echo "$(date): No backup found - fresh setup needed" > "$RESTORE_FAILED_MARKER"
|
||||
fi
|
||||
|
||||
# Create fresh databases if restoration didn't happen
|
||||
echo "🗄️ Creating fresh AzerothCore databases..."
|
||||
mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "
|
||||
CREATE DATABASE IF NOT EXISTS ${DB_AUTH_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE DATABASE IF NOT EXISTS ${DB_WORLD_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE DATABASE IF NOT EXISTS ${DB_CHARACTERS_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
SHOW DATABASES;" || {
|
||||
echo "❌ Failed to create databases"
|
||||
exit 1
|
||||
}
|
||||
echo "✅ Fresh databases created - proceeding with schema import"
|
||||
|
||||
# Wait for databases to be ready (they should exist now)
|
||||
echo "⏳ Verifying databases are accessible..."
|
||||
for i in $(seq 1 10); do
|
||||
if mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "USE ${DB_AUTH_NAME}; USE ${DB_WORLD_NAME}; USE ${DB_CHARACTERS_NAME};" >/dev/null 2>&1; then
|
||||
echo "✅ All databases accessible"
|
||||
break
|
||||
fi
|
||||
echo "⏳ Waiting for databases... attempt $i/10"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Verify databases are actually empty before importing
|
||||
echo "🔍 Verifying databases are empty before import..."
|
||||
check_table_count() {
|
||||
local db_name="$1"
|
||||
local count=$(mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "
|
||||
SELECT COUNT(*) FROM information_schema.tables
|
||||
WHERE table_schema='$db_name' AND table_type='BASE TABLE';" -s -N 2>/dev/null || echo "0")
|
||||
echo "$count"
|
||||
}
|
||||
|
||||
auth_tables=$(check_table_count "${DB_AUTH_NAME}")
|
||||
world_tables=$(check_table_count "${DB_WORLD_NAME}")
|
||||
char_tables=$(check_table_count "${DB_CHARACTERS_NAME}")
|
||||
|
||||
echo "📊 Current table counts:"
|
||||
echo " ${DB_AUTH_NAME}: $auth_tables tables"
|
||||
echo " ${DB_WORLD_NAME}: $world_tables tables"
|
||||
echo " ${DB_CHARACTERS_NAME}: $char_tables tables"
|
||||
|
||||
# Warn if databases appear to have data
|
||||
if [ "$auth_tables" -gt 5 ] || [ "$world_tables" -gt 50 ] || [ "$char_tables" -gt 5 ]; then
|
||||
echo "⚠️ WARNING: Databases appear to contain data!"
|
||||
echo "⚠️ Import may overwrite existing data. Consider backing up first."
|
||||
echo "⚠️ Continuing in 10 seconds... (Ctrl+C to cancel)"
|
||||
sleep 10
|
||||
fi
|
||||
|
||||
echo "📝 Creating dbimport configuration..."
|
||||
mkdir -p /azerothcore/env/dist/etc
|
||||
cat > /azerothcore/env/dist/etc/dbimport.conf <<EOF
|
||||
LoginDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
|
||||
WorldDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_WORLD_NAME}"
|
||||
CharacterDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
|
||||
Updates.EnableDatabases = 7
|
||||
Updates.AutoSetup = 1
|
||||
|
||||
# Required configuration properties
|
||||
MySQLExecutable = ""
|
||||
TempDir = ""
|
||||
SourceDirectory = ""
|
||||
Updates.AllowedModules = "all"
|
||||
LoginDatabase.WorkerThreads = 1
|
||||
LoginDatabase.SynchThreads = 1
|
||||
WorldDatabase.WorkerThreads = 1
|
||||
WorldDatabase.SynchThreads = 1
|
||||
CharacterDatabase.WorkerThreads = 1
|
||||
CharacterDatabase.SynchThreads = 1
|
||||
Updates.Redundancy = 1
|
||||
Updates.AllowRehash = 1
|
||||
Updates.ArchivedRedundancy = 0
|
||||
Updates.CleanDeadRefMaxCount = 3
|
||||
|
||||
# Logging configuration
|
||||
Appender.Console=1,3,6
|
||||
Logger.root=3,Console
|
||||
EOF
|
||||
|
||||
echo "🚀 Running database import..."
|
||||
cd /azerothcore/env/dist/bin
|
||||
|
||||
# Run dbimport with error handling
|
||||
if ./dbimport; then
|
||||
echo "✅ Database import completed successfully!"
|
||||
|
||||
# Create import completion marker
|
||||
if touch "$RESTORE_STATUS_DIR/.import-completed" 2>/dev/null; then
|
||||
echo "$(date): Database import completed successfully" > "$RESTORE_STATUS_DIR/.import-completed"
|
||||
else
|
||||
echo "$(date): Database import completed successfully" > "$MARKER_STATUS_DIR/.import-completed"
|
||||
echo "⚠️ Using temporary location for completion marker"
|
||||
fi
|
||||
|
||||
# Verify import was successful
|
||||
echo "🔍 Verifying import results..."
|
||||
auth_tables_after=$(check_table_count "${DB_AUTH_NAME}")
|
||||
world_tables_after=$(check_table_count "${DB_WORLD_NAME}")
|
||||
char_tables_after=$(check_table_count "${DB_CHARACTERS_NAME}")
|
||||
|
||||
echo "📊 Post-import table counts:"
|
||||
echo " ${DB_AUTH_NAME}: $auth_tables_after tables"
|
||||
echo " ${DB_WORLD_NAME}: $world_tables_after tables"
|
||||
echo " ${DB_CHARACTERS_NAME}: $char_tables_after tables"
|
||||
|
||||
if [ "$auth_tables_after" -gt 0 ] && [ "$world_tables_after" -gt 0 ]; then
|
||||
echo "✅ Import verification successful - databases populated"
|
||||
else
|
||||
echo "⚠️ Import verification failed - databases may be empty"
|
||||
fi
|
||||
else
|
||||
echo "❌ Database import failed!"
|
||||
if touch "$RESTORE_STATUS_DIR/.import-failed" 2>/dev/null; then
|
||||
echo "$(date): Database import failed" > "$RESTORE_STATUS_DIR/.import-failed"
|
||||
else
|
||||
echo "$(date): Database import failed" > "$MARKER_STATUS_DIR/.import-failed"
|
||||
echo "⚠️ Using temporary location for failed marker"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🎉 Database import process complete!"
|
||||
@@ -339,9 +339,9 @@ deploy_stack() {
|
||||
docker compose --env-file "$SERVICES_ENV_FILE" -f ./docker-compose-azerothcore-services.yml up -d 2>&1 | grep -v "Found orphan containers"
|
||||
|
||||
# Wait for client data extraction
|
||||
print_status "INFO" "Waiting for client data download and extraction (this may take 15-25 minutes)..."
|
||||
print_status "INFO" "Waiting for client data download and extraction (optimized: 8-15 minutes typical)..."
|
||||
print_status "INFO" "Press Ctrl+C to exit if needed..."
|
||||
wait_for_service "Client Data" 480 "docker logs ac-client-data 2>/dev/null | grep -q 'Game data setup complete'"
|
||||
wait_for_service "Client Data" 360 "docker logs ac-client-data 2>/dev/null | grep -q 'Game data setup complete'"
|
||||
|
||||
# Wait for worldserver to be healthy
|
||||
wait_for_service "World Server" 24 "check_container_health ac-worldserver"
|
||||
@@ -349,6 +349,14 @@ deploy_stack() {
|
||||
# Deploy modules if enabled
|
||||
if [ "$MODULES_ENABLED" = true ]; then
|
||||
print_status "INFO" "Step 3: Deploying modules layer..."
|
||||
|
||||
# Ensure ac-modules is recreated with the correct environment
|
||||
# It may have been created earlier by the services layer using services env
|
||||
if docker ps -a --format '{{.Names}}' | grep -q '^ac-modules$'; then
|
||||
print_status "INFO" "Recreating ac-modules with modules env (removing existing container)"
|
||||
docker rm -f ac-modules >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
docker compose --env-file "$MODULES_ENV_FILE" -f ./docker-compose-azerothcore-modules.yml up -d 2>&1 | grep -v "Found orphan containers"
|
||||
|
||||
# Wait for modules to be ready
|
||||
@@ -538,4 +546,4 @@ main() {
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
main "$@"
|
||||
249
V1/scripts/download-client-data.sh
Normal file
249
V1/scripts/download-client-data.sh
Normal file
@@ -0,0 +1,249 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo '🚀 Starting AzerothCore game data setup...'
|
||||
|
||||
# Get the latest release info from wowgaming/client-data
|
||||
echo '📡 Fetching latest client data release info...'
|
||||
RELEASE_INFO=$(wget -qO- https://api.github.com/repos/wowgaming/client-data/releases/latest 2>/dev/null)
|
||||
|
||||
if [ -n "$RELEASE_INFO" ]; then
|
||||
LATEST_URL=$(echo "$RELEASE_INFO" | grep '"browser_download_url":' | grep '\.zip' | cut -d'"' -f4 | head -1)
|
||||
LATEST_TAG=$(echo "$RELEASE_INFO" | grep '"tag_name":' | cut -d'"' -f4)
|
||||
LATEST_SIZE=$(echo "$RELEASE_INFO" | grep '"size":' | head -1 | grep -o '[0-9]*')
|
||||
fi
|
||||
|
||||
if [ -z "$LATEST_URL" ]; then
|
||||
echo '❌ Could not fetch latest release URL'
|
||||
echo '📥 Using fallback: direct download from v16 release'
|
||||
LATEST_URL='https://github.com/wowgaming/client-data/releases/download/v16/data.zip'
|
||||
LATEST_TAG='v16'
|
||||
LATEST_SIZE='0'
|
||||
fi
|
||||
|
||||
echo "📍 Latest release: $LATEST_TAG"
|
||||
echo "📥 Download URL: $LATEST_URL"
|
||||
|
||||
# Cache file paths
|
||||
CACHE_FILE="/cache/client-data-$LATEST_TAG.zip"
|
||||
VERSION_FILE="/cache/client-data-version.txt"
|
||||
|
||||
# Check if we have a cached version
|
||||
if [ -f "$CACHE_FILE" ] && [ -f "$VERSION_FILE" ]; then
|
||||
CACHED_VERSION=$(cat "$VERSION_FILE" 2>/dev/null)
|
||||
if [ "$CACHED_VERSION" = "$LATEST_TAG" ]; then
|
||||
echo "✅ Found cached client data version $LATEST_TAG"
|
||||
echo "📊 Cached file size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')"
|
||||
|
||||
# Verify cache file integrity
|
||||
echo "🔍 Verifying cached file integrity..."
|
||||
CACHE_INTEGRITY_OK=false
|
||||
|
||||
if command -v 7z >/dev/null 2>&1; then
|
||||
# Use 7z for integrity check if available (faster and more reliable)
|
||||
if 7z t "$CACHE_FILE" >/dev/null 2>&1; then
|
||||
CACHE_INTEGRITY_OK=true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback to unzip if 7z check failed or is not available
|
||||
if [ "$CACHE_INTEGRITY_OK" = "false" ]; then
|
||||
if unzip -t "$CACHE_FILE" > /dev/null 2>&1; then
|
||||
CACHE_INTEGRITY_OK=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$CACHE_INTEGRITY_OK" = "true" ]; then
|
||||
echo "✅ Cache file integrity verified"
|
||||
echo "⚡ Using cached download - skipping download phase"
|
||||
cp "$CACHE_FILE" data.zip
|
||||
else
|
||||
echo "⚠️ Cache file corrupted, will re-download"
|
||||
rm -f "$CACHE_FILE" "$VERSION_FILE"
|
||||
fi
|
||||
else
|
||||
echo "📦 Cache version ($CACHED_VERSION) differs from latest ($LATEST_TAG)"
|
||||
echo "🗑️ Removing old cache"
|
||||
rm -f /cache/client-data-*.zip "$VERSION_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Download if we don't have a valid cached file
|
||||
if [ ! -f "data.zip" ]; then
|
||||
echo "📥 Downloading client data (~15GB, may take 5-20 minutes with multi-connection)..."
|
||||
echo "📍 Source: $LATEST_URL"
|
||||
|
||||
# Download with multi-connection support for speed
|
||||
echo "📥 Starting download with multi-connection support..."
|
||||
if command -v aria2c >/dev/null 2>&1; then
|
||||
echo "🚀 Using aria2c for faster multi-connection download..."
|
||||
aria2c --max-connection-per-server=8 --split=8 --min-split-size=10M \
|
||||
--summary-interval=5 --download-result=hide \
|
||||
--console-log-level=warn --show-console-readout=false \
|
||||
-o "$CACHE_FILE.tmp" "$LATEST_URL" || {
|
||||
echo '⚠️ aria2c failed, falling back to wget...'
|
||||
wget --progress=dot:giga -O "$CACHE_FILE.tmp" "$LATEST_URL" 2>&1 | sed 's/^/📊 /' || {
|
||||
echo '❌ wget failed, trying curl...'
|
||||
curl -L --progress-bar -o "$CACHE_FILE.tmp" "$LATEST_URL" || {
|
||||
echo '❌ All download methods failed'
|
||||
rm -f "$CACHE_FILE.tmp"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
echo "📥 Using wget (aria2c not available)..."
|
||||
wget --progress=dot:giga -O "$CACHE_FILE.tmp" "$LATEST_URL" 2>&1 | sed 's/^/📊 /' || {
|
||||
echo '❌ wget failed, trying curl...'
|
||||
curl -L --progress-bar -o "$CACHE_FILE.tmp" "$LATEST_URL" || {
|
||||
echo '❌ All download methods failed'
|
||||
rm -f "$CACHE_FILE.tmp"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
fi
|
||||
|
||||
# Verify download integrity
|
||||
echo "🔍 Verifying download integrity..."
|
||||
INTEGRITY_OK=false
|
||||
|
||||
if command -v 7z >/dev/null 2>&1; then
|
||||
# Use 7z for integrity check if available (faster and more reliable)
|
||||
if 7z t "$CACHE_FILE.tmp" >/dev/null 2>&1; then
|
||||
INTEGRITY_OK=true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fallback to unzip if 7z check failed or is not available
|
||||
if [ "$INTEGRITY_OK" = "false" ]; then
|
||||
if unzip -t "$CACHE_FILE.tmp" > /dev/null 2>&1; then
|
||||
INTEGRITY_OK=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$INTEGRITY_OK" = "true" ]; then
|
||||
mv "$CACHE_FILE.tmp" "$CACHE_FILE"
|
||||
echo "$LATEST_TAG" > "$VERSION_FILE"
|
||||
echo '✅ Download completed and verified'
|
||||
echo "📊 File size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')"
|
||||
cp "$CACHE_FILE" data.zip
|
||||
else
|
||||
echo '❌ Downloaded file is corrupted'
|
||||
rm -f "$CACHE_FILE.tmp"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo '📂 Extracting client data (this may take 5-10 minutes with parallel extraction)...'
|
||||
echo '⏳ Please wait while extracting...'
|
||||
|
||||
# Clear existing data if extraction failed previously
|
||||
rm -rf /azerothcore/data/maps /azerothcore/data/vmaps /azerothcore/data/mmaps /azerothcore/data/dbc
|
||||
|
||||
# Extract with detailed progress tracking using 7z for parallel processing
|
||||
echo '🔄 Starting parallel extraction with progress monitoring...'
|
||||
|
||||
# Use 7z if available for parallel extraction, fallback to unzip
|
||||
if command -v 7z >/dev/null 2>&1; then
|
||||
echo '🚀 Using 7z for faster parallel extraction...'
|
||||
# Start extraction in background with overwrite and parallel processing
|
||||
7z x -aoa -o/azerothcore/data/ data.zip >/dev/null 2>&1 &
|
||||
EXTRACT_PID=$!
|
||||
EXTRACT_CMD="7z"
|
||||
else
|
||||
echo '📥 Using unzip (7z not available)...'
|
||||
# Start extraction in background with overwrite
|
||||
unzip -o -q data.zip -d /azerothcore/data/ &
|
||||
EXTRACT_PID=$!
|
||||
EXTRACT_CMD="unzip"
|
||||
fi
|
||||
LAST_CHECK_TIME=0
|
||||
|
||||
# Monitor progress with directory size checks
|
||||
while kill -0 "$EXTRACT_PID" 2>/dev/null; do
|
||||
CURRENT_TIME=$(date +%s)
|
||||
if [ $((CURRENT_TIME - LAST_CHECK_TIME)) -ge 30 ]; then
|
||||
LAST_CHECK_TIME=$CURRENT_TIME
|
||||
|
||||
# Check what's been extracted so far
|
||||
PROGRESS_MSG="📊 Progress at $(date '+%H:%M:%S'):"
|
||||
|
||||
if [ -d "/azerothcore/data/dbc" ] && [ -n "$(ls -A /azerothcore/data/dbc 2>/dev/null)" ]; then
|
||||
DBC_SIZE=$(du -sh /azerothcore/data/dbc 2>/dev/null | cut -f1)
|
||||
PROGRESS_MSG="$PROGRESS_MSG DBC($DBC_SIZE)"
|
||||
fi
|
||||
|
||||
if [ -d "/azerothcore/data/maps" ] && [ -n "$(ls -A /azerothcore/data/maps 2>/dev/null)" ]; then
|
||||
MAPS_SIZE=$(du -sh /azerothcore/data/maps 2>/dev/null | cut -f1)
|
||||
PROGRESS_MSG="$PROGRESS_MSG Maps($MAPS_SIZE)"
|
||||
fi
|
||||
|
||||
if [ -d "/azerothcore/data/vmaps" ] && [ -n "$(ls -A /azerothcore/data/vmaps 2>/dev/null)" ]; then
|
||||
VMAPS_SIZE=$(du -sh /azerothcore/data/vmaps 2>/dev/null | cut -f1)
|
||||
PROGRESS_MSG="$PROGRESS_MSG VMaps($VMAPS_SIZE)"
|
||||
fi
|
||||
|
||||
if [ -d "/azerothcore/data/mmaps" ] && [ -n "$(ls -A /azerothcore/data/mmaps 2>/dev/null)" ]; then
|
||||
MMAPS_SIZE=$(du -sh /azerothcore/data/mmaps 2>/dev/null | cut -f1)
|
||||
PROGRESS_MSG="$PROGRESS_MSG MMaps($MMAPS_SIZE)"
|
||||
fi
|
||||
|
||||
echo "$PROGRESS_MSG"
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
|
||||
wait "$EXTRACT_PID"
|
||||
EXTRACT_EXIT_CODE=$?
|
||||
|
||||
if [ $EXTRACT_EXIT_CODE -ne 0 ]; then
|
||||
echo "❌ Extraction failed ($EXTRACT_CMD returned exit code $EXTRACT_EXIT_CODE)"
|
||||
rm -f data.zip
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Handle nested Data directory issue - move contents if extracted to Data subdirectory
|
||||
if [ -d "/azerothcore/data/Data" ] && [ -n "$(ls -A /azerothcore/data/Data 2>/dev/null)" ]; then
|
||||
echo '🔧 Fixing data directory structure (moving from Data/ subdirectory)...'
|
||||
|
||||
# Move all contents from Data subdirectory to the root data directory
|
||||
for item in /azerothcore/data/Data/*; do
|
||||
if [ -e "$item" ]; then
|
||||
mv "$item" /azerothcore/data/ 2>/dev/null || {
|
||||
echo "⚠️ Could not move $(basename "$item"), using copy instead..."
|
||||
cp -r "$item" /azerothcore/data/
|
||||
rm -rf "$item"
|
||||
}
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove empty Data directory
|
||||
rmdir /azerothcore/data/Data 2>/dev/null || true
|
||||
echo '✅ Data directory structure fixed'
|
||||
fi
|
||||
|
||||
# Clean up temporary extraction file (keep cached version)
|
||||
rm -f data.zip
|
||||
|
||||
echo '✅ Client data extraction complete!'
|
||||
echo '📁 Verifying extracted directories:'
|
||||
|
||||
# Verify required directories exist and have content
|
||||
ALL_GOOD=true
|
||||
for dir in maps vmaps mmaps dbc; do
|
||||
if [ -d "/azerothcore/data/$dir" ] && [ -n "$(ls -A /azerothcore/data/$dir 2>/dev/null)" ]; then
|
||||
DIR_SIZE=$(du -sh /azerothcore/data/$dir 2>/dev/null | cut -f1)
|
||||
echo "✅ $dir directory: OK ($DIR_SIZE)"
|
||||
else
|
||||
echo "❌ $dir directory: MISSING or EMPTY"
|
||||
ALL_GOOD=false
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$ALL_GOOD" = "true" ]; then
|
||||
echo '🎉 Game data setup complete! AzerothCore worldserver can now start.'
|
||||
echo "💾 Cached version $LATEST_TAG for future use"
|
||||
else
|
||||
echo '❌ Some directories are missing or empty'
|
||||
exit 1
|
||||
fi
|
||||
197
V1/scripts/manage-modules-sql.sh
Normal file
197
V1/scripts/manage-modules-sql.sh
Normal file
@@ -0,0 +1,197 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Function to execute SQL files for a module
|
||||
execute_module_sql() {
|
||||
local module_dir="$1"
|
||||
local module_name="$2"
|
||||
|
||||
echo "Processing SQL scripts for $module_name..."
|
||||
|
||||
# Find and execute SQL files in the module
|
||||
if [ -d "$module_dir/data/sql" ]; then
|
||||
# Execute world database scripts
|
||||
if [ -d "$module_dir/data/sql/world" ]; then
|
||||
find "$module_dir/data/sql/world" -name "*.sql" -type f | while read sql_file; do
|
||||
echo " Executing world SQL: $(basename "$sql_file")"
|
||||
if mariadb --ssl=false -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_WORLD_NAME}" < "$sql_file" >/dev/null 2>&1; then
|
||||
echo " ✅ Successfully executed $(basename "$sql_file")"
|
||||
else
|
||||
echo " ❌ Failed to execute $sql_file"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Execute auth database scripts
|
||||
if [ -d "$module_dir/data/sql/auth" ]; then
|
||||
find "$module_dir/data/sql/auth" -name "*.sql" -type f | while read sql_file; do
|
||||
echo " Executing auth SQL: $(basename "$sql_file")"
|
||||
if mariadb --ssl=false -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_AUTH_NAME}" < "$sql_file" >/dev/null 2>&1; then
|
||||
echo " ✅ Successfully executed $(basename "$sql_file")"
|
||||
else
|
||||
echo " ❌ Failed to execute $sql_file"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Execute character database scripts
|
||||
if [ -d "$module_dir/data/sql/characters" ]; then
|
||||
find "$module_dir/data/sql/characters" -name "*.sql" -type f | while read sql_file; do
|
||||
echo " Executing characters SQL: $(basename "$sql_file")"
|
||||
if mariadb --ssl=false -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_CHARACTERS_NAME}" < "$sql_file" >/dev/null 2>&1; then
|
||||
echo " ✅ Successfully executed $(basename "$sql_file")"
|
||||
else
|
||||
echo " ❌ Failed to execute $sql_file"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Execute base SQL files (common pattern)
|
||||
find "$module_dir/data/sql" -maxdepth 1 -name "*.sql" -type f | while read sql_file; do
|
||||
echo " Executing base SQL: $(basename "$sql_file")"
|
||||
mysql -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_WORLD_NAME}" < "$sql_file" 2>/dev/null || echo " Warning: Failed to execute $sql_file"
|
||||
done
|
||||
fi
|
||||
|
||||
# Look for SQL files in other common locations
|
||||
if [ -d "$module_dir/sql" ]; then
|
||||
find "$module_dir/sql" -name "*.sql" -type f | while read sql_file; do
|
||||
echo " Executing SQL: $(basename "$sql_file")"
|
||||
mysql -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_WORLD_NAME}" < "$sql_file" 2>/dev/null || echo " Warning: Failed to execute $sql_file"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Main function to execute SQL for all enabled modules
|
||||
execute_module_sql_scripts() {
|
||||
# Install MariaDB client if not available
|
||||
which mariadb >/dev/null 2>&1 || {
|
||||
echo "Installing MariaDB client..."
|
||||
apk add --no-cache mariadb-client >/dev/null 2>&1 || echo "Warning: Could not install MariaDB client"
|
||||
}
|
||||
|
||||
# Execute SQL for enabled modules only
|
||||
if [ "$MODULE_PLAYERBOTS" = "1" ] && [ -d "mod-playerbots" ]; then
|
||||
execute_module_sql "mod-playerbots" "Playerbots"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AOE_LOOT" = "1" ] && [ -d "mod-aoe-loot" ]; then
|
||||
execute_module_sql "mod-aoe-loot" "AoE Loot"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_LEARN_SPELLS" = "1" ] && [ -d "mod-learn-spells" ]; then
|
||||
execute_module_sql "mod-learn-spells" "Learn Spells"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_FIREWORKS" = "1" ] && [ -d "mod-fireworks-on-level" ]; then
|
||||
execute_module_sql "mod-fireworks-on-level" "Fireworks"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_INDIVIDUAL_PROGRESSION" = "1" ] && [ -d "mod-individual-progression" ]; then
|
||||
execute_module_sql "mod-individual-progression" "Individual Progression"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AHBOT" = "1" ] && [ -d "mod-ahbot" ]; then
|
||||
execute_module_sql "mod-ahbot" "AHBot"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AUTOBALANCE" = "1" ] && [ -d "mod-autobalance" ]; then
|
||||
execute_module_sql "mod-autobalance" "AutoBalance"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_TRANSMOG" = "1" ] && [ -d "mod-transmog" ]; then
|
||||
execute_module_sql "mod-transmog" "Transmog"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_BUFFER" = "1" ] && [ -d "mod-npc-buffer" ]; then
|
||||
execute_module_sql "mod-npc-buffer" "NPC Buffer"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_DYNAMIC_XP" = "1" ] && [ -d "mod-dynamic-xp" ]; then
|
||||
execute_module_sql "mod-dynamic-xp" "Dynamic XP"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_SOLO_LFG" = "1" ] && [ -d "mod-solo-lfg" ]; then
|
||||
execute_module_sql "mod-solo-lfg" "Solo LFG"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_1V1_ARENA" = "1" ] && [ -d "mod-1v1-arena" ]; then
|
||||
execute_module_sql "mod-1v1-arena" "1v1 Arena"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_PHASED_DUELS" = "1" ] && [ -d "mod-phased-duels" ]; then
|
||||
execute_module_sql "mod-phased-duels" "Phased Duels"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_BREAKING_NEWS" = "1" ] && [ -d "mod-breaking-news-override" ]; then
|
||||
execute_module_sql "mod-breaking-news-override" "Breaking News"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_BOSS_ANNOUNCER" = "1" ] && [ -d "mod-boss-announcer" ]; then
|
||||
execute_module_sql "mod-boss-announcer" "Boss Announcer"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_ACCOUNT_ACHIEVEMENTS" = "1" ] && [ -d "mod-account-achievements" ]; then
|
||||
execute_module_sql "mod-account-achievements" "Account Achievements"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AUTO_REVIVE" = "1" ] && [ -d "mod-auto-revive" ]; then
|
||||
execute_module_sql "mod-auto-revive" "Auto Revive"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_GAIN_HONOR_GUARD" = "1" ] && [ -d "mod-gain-honor-guard" ]; then
|
||||
execute_module_sql "mod-gain-honor-guard" "Gain Honor Guard"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_ELUNA" = "1" ] && [ -d "mod-eluna" ]; then
|
||||
execute_module_sql "mod-eluna" "Eluna"
|
||||
fi
|
||||
if [ "$MODULE_ARAC" = "1" ] && [ -d "mod-arac" ]; then
|
||||
execute_module_sql "mod-arac" "All Races All Classes"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_TIME_IS_TIME" = "1" ] && [ -d "mod-TimeIsTime" ]; then
|
||||
execute_module_sql "mod-TimeIsTime" "Time Is Time"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_POCKET_PORTAL" = "1" ] && [ -d "mod-pocket-portal" ]; then
|
||||
execute_module_sql "mod-pocket-portal" "Pocket Portal"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_RANDOM_ENCHANTS" = "1" ] && [ -d "mod-random-enchants" ]; then
|
||||
execute_module_sql "mod-random-enchants" "Random Enchants"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_SOLOCRAFT" = "1" ] && [ -d "mod-solocraft" ]; then
|
||||
execute_module_sql "mod-solocraft" "Solocraft"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_PVP_TITLES" = "1" ] && [ -d "mod-pvp-titles" ]; then
|
||||
execute_module_sql "mod-pvp-titles" "PvP Titles"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_BEASTMASTER" = "1" ] && [ -d "mod-npc-beastmaster" ]; then
|
||||
execute_module_sql "mod-npc-beastmaster" "NPC Beastmaster"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_ENCHANTER" = "1" ] && [ -d "mod-npc-enchanter" ]; then
|
||||
execute_module_sql "mod-npc-enchanter" "NPC Enchanter"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_INSTANCE_RESET" = "1" ] && [ -d "mod-instance-reset" ]; then
|
||||
execute_module_sql "mod-instance-reset" "Instance Reset"
|
||||
fi
|
||||
|
||||
if [ "$MODULE_LEVEL_GRANT" = "1" ] && [ -d "mod-quest-count-level" ]; then
|
||||
execute_module_sql "mod-quest-count-level" "Level Grant"
|
||||
fi
|
||||
if [ "$MODULE_ASSISTANT" = "1" ] && [ -d "mod-assistant" ]; then
|
||||
execute_module_sql "mod-assistant" "Assistant"
|
||||
fi
|
||||
if [ "$MODULE_REAGENT_BANK" = "1" ] && [ -d "mod-reagent-bank" ]; then
|
||||
execute_module_sql "mod-reagent-bank" "Reagent Bank"
|
||||
fi
|
||||
if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" = "1" ] && [ -d "mod-black-market" ]; then
|
||||
execute_module_sql "mod-black-market" "Black Market"
|
||||
fi
|
||||
}
|
||||
685
V1/scripts/manage-modules.sh
Normal file
685
V1/scripts/manage-modules.sh
Normal file
@@ -0,0 +1,685 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo 'Setting up git user'
|
||||
git config --global user.name "$GIT_USERNAME"
|
||||
git config --global user.email "$GIT_EMAIL"
|
||||
git config --global url.https://$GIT_PAT@github.com/.insteadOf https://github.com/
|
||||
|
||||
echo 'Initializing module management...'
|
||||
cd /modules
|
||||
|
||||
echo 'Cleaning up disabled modules...'
|
||||
|
||||
# Remove modules if disabled
|
||||
if [ "$MODULE_PLAYERBOTS" != "1" ] && [ -d "mod-playerbots" ]; then
|
||||
echo 'Removing mod-playerbots (disabled)...'
|
||||
rm -rf mod-playerbots
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AOE_LOOT" != "1" ] && [ -d "mod-aoe-loot" ]; then
|
||||
echo 'Removing mod-aoe-loot (disabled)...'
|
||||
rm -rf mod-aoe-loot
|
||||
fi
|
||||
|
||||
if [ "$MODULE_LEARN_SPELLS" != "1" ] && [ -d "mod-learn-spells" ]; then
|
||||
echo 'Removing mod-learn-spells (disabled)...'
|
||||
rm -rf mod-learn-spells
|
||||
fi
|
||||
|
||||
if [ "$MODULE_FIREWORKS" != "1" ] && [ -d "mod-fireworks-on-level" ]; then
|
||||
echo 'Removing mod-fireworks-on-level (disabled)...'
|
||||
rm -rf mod-fireworks-on-level
|
||||
fi
|
||||
|
||||
if [ "$MODULE_INDIVIDUAL_PROGRESSION" != "1" ] && [ -d "mod-individual-progression" ]; then
|
||||
echo 'Removing mod-individual-progression (disabled)...'
|
||||
rm -rf mod-individual-progression
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AHBOT" != "1" ] && [ -d "mod-ahbot" ]; then
|
||||
echo 'Removing mod-ahbot (disabled)...'
|
||||
rm -rf mod-ahbot
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AUTOBALANCE" != "1" ] && [ -d "mod-autobalance" ]; then
|
||||
echo 'Removing mod-autobalance (disabled)...'
|
||||
rm -rf mod-autobalance
|
||||
fi
|
||||
|
||||
if [ "$MODULE_TRANSMOG" != "1" ] && [ -d "mod-transmog" ]; then
|
||||
echo 'Removing mod-transmog (disabled)...'
|
||||
rm -rf mod-transmog
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_BUFFER" != "1" ] && [ -d "mod-npc-buffer" ]; then
|
||||
echo 'Removing mod-npc-buffer (disabled)...'
|
||||
rm -rf mod-npc-buffer
|
||||
fi
|
||||
|
||||
if [ "$MODULE_DYNAMIC_XP" != "1" ] && [ -d "mod-dynamic-xp" ]; then
|
||||
echo 'Removing mod-dynamic-xp (disabled)...'
|
||||
rm -rf mod-dynamic-xp
|
||||
fi
|
||||
|
||||
if [ "$MODULE_SOLO_LFG" != "1" ] && [ -d "mod-solo-lfg" ]; then
|
||||
echo 'Removing mod-solo-lfg (disabled)...'
|
||||
rm -rf mod-solo-lfg
|
||||
fi
|
||||
|
||||
if [ "$MODULE_1V1_ARENA" != "1" ] && [ -d "mod-1v1-arena" ]; then
|
||||
echo 'Removing mod-1v1-arena (disabled)...'
|
||||
rm -rf mod-1v1-arena
|
||||
fi
|
||||
|
||||
if [ "$MODULE_PHASED_DUELS" != "1" ] && [ -d "mod-phased-duels" ]; then
|
||||
echo 'Removing mod-phased-duels (disabled)...'
|
||||
rm -rf mod-phased-duels
|
||||
fi
|
||||
|
||||
if [ "$MODULE_BREAKING_NEWS" != "1" ] && [ -d "mod-breaking-news-override" ]; then
|
||||
echo 'Removing mod-breaking-news-override (disabled)...'
|
||||
rm -rf mod-breaking-news-override
|
||||
fi
|
||||
|
||||
if [ "$MODULE_BOSS_ANNOUNCER" != "1" ] && [ -d "mod-boss-announcer" ]; then
|
||||
echo 'Removing mod-boss-announcer (disabled)...'
|
||||
rm -rf mod-boss-announcer
|
||||
fi
|
||||
|
||||
if [ "$MODULE_ACCOUNT_ACHIEVEMENTS" != "1" ] && [ -d "mod-account-achievements" ]; then
|
||||
echo 'Removing mod-account-achievements (disabled)...'
|
||||
rm -rf mod-account-achievements
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AUTO_REVIVE" != "1" ] && [ -d "mod-auto-revive" ]; then
|
||||
echo 'Removing mod-auto-revive (disabled)...'
|
||||
rm -rf mod-auto-revive
|
||||
fi
|
||||
|
||||
if [ "$MODULE_GAIN_HONOR_GUARD" != "1" ] && [ -d "mod-gain-honor-guard" ]; then
|
||||
echo 'Removing mod-gain-honor-guard (disabled)...'
|
||||
rm -rf mod-gain-honor-guard
|
||||
fi
|
||||
|
||||
if [ "$MODULE_ELUNA" != "1" ] && [ -d "mod-eluna" ]; then
|
||||
echo 'Removing mod-eluna (disabled)...'
|
||||
rm -rf mod-eluna
|
||||
fi
|
||||
if [ "$MODULE_ARAC" != "1" ] && [ -d "mod-arac" ]; then
|
||||
echo 'Removing mod-arac (disabled)...'
|
||||
rm -rf mod-arac
|
||||
fi
|
||||
|
||||
if [ "$MODULE_TIME_IS_TIME" != "1" ] && [ -d "mod-TimeIsTime" ]; then
|
||||
echo 'Removing mod-TimeIsTime (disabled)...'
|
||||
rm -rf mod-TimeIsTime
|
||||
fi
|
||||
|
||||
if [ "$MODULE_POCKET_PORTAL" != "1" ] && [ -d "mod-pocket-portal" ]; then
|
||||
echo 'Removing mod-pocket-portal (disabled)...'
|
||||
rm -rf mod-pocket-portal
|
||||
fi
|
||||
|
||||
if [ "$MODULE_RANDOM_ENCHANTS" != "1" ] && [ -d "mod-random-enchants" ]; then
|
||||
echo 'Removing mod-random-enchants (disabled)...'
|
||||
rm -rf mod-random-enchants
|
||||
fi
|
||||
|
||||
if [ "$MODULE_SOLOCRAFT" != "1" ] && [ -d "mod-solocraft" ]; then
|
||||
echo 'Removing mod-solocraft (disabled)...'
|
||||
rm -rf mod-solocraft
|
||||
fi
|
||||
|
||||
if [ "$MODULE_PVP_TITLES" != "1" ] && [ -d "mod-pvp-titles" ]; then
|
||||
echo 'Removing mod-pvp-titles (disabled)...'
|
||||
rm -rf mod-pvp-titles
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_BEASTMASTER" != "1" ] && [ -d "mod-npc-beastmaster" ]; then
|
||||
echo 'Removing mod-npc-beastmaster (disabled)...'
|
||||
rm -rf mod-npc-beastmaster
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_ENCHANTER" != "1" ] && [ -d "mod-npc-enchanter" ]; then
|
||||
echo 'Removing mod-npc-enchanter (disabled)...'
|
||||
rm -rf mod-npc-enchanter
|
||||
fi
|
||||
|
||||
if [ "$MODULE_INSTANCE_RESET" != "1" ] && [ -d "mod-instance-reset" ]; then
|
||||
echo 'Removing mod-instance-reset (disabled)...'
|
||||
rm -rf mod-instance-reset
|
||||
fi
|
||||
|
||||
if [ "$MODULE_LEVEL_GRANT" != "1" ] && [ -d "mod-quest-count-level" ]; then
|
||||
echo 'Removing mod-quest-count-level (disabled)...'
|
||||
rm -rf mod-quest-count-level
|
||||
fi
|
||||
if [ "$MODULE_ASSISTANT" != "1" ] && [ -d "mod-assistant" ]; then
|
||||
echo 'Removing mod-assistant (disabled)...'
|
||||
rm -rf mod-assistant
|
||||
fi
|
||||
if [ "$MODULE_REAGENT_BANK" != "1" ] && [ -d "mod-reagent-bank" ]; then
|
||||
echo 'Removing mod-reagent-bank (disabled)...'
|
||||
rm -rf mod-reagent-bank
|
||||
fi
|
||||
if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" != "1" ] && [ -d "mod-black-market" ]; then
|
||||
echo 'Removing mod-black-market (disabled)...'
|
||||
rm -rf mod-black-market
|
||||
fi
|
||||
|
||||
echo 'Installing enabled modules...'
|
||||
|
||||
# Install Playerbots if enabled
|
||||
if [ "$MODULE_PLAYERBOTS" = "1" ] && [ ! -d "mod-playerbots" ]; then
|
||||
echo '🤖 Installing mod-playerbots...'
|
||||
echo ' 📖 Project: https://github.com/liyunfan1223/mod-playerbots'
|
||||
echo ' 🚨 CRITICAL: REQUIRES Custom AzerothCore branch (liyunfan1223/azerothcore-wotlk/tree/Playerbot)'
|
||||
echo ' 🚨 INCOMPATIBLE with standard AzerothCore - module will not function properly'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 📋 POST-INSTALL: Requires manual account/character configuration'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/liyunfan1223/mod-playerbots.git mod-playerbots
|
||||
fi
|
||||
|
||||
# Install AOE Loot if enabled
|
||||
if [ "$MODULE_AOE_LOOT" = "1" ] && [ ! -d "mod-aoe-loot" ]; then
|
||||
echo '💰 Installing mod-aoe-loot...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-aoe-loot'
|
||||
echo ' ℹ️ Allows looting multiple corpses with one action'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/azerothcore/mod-aoe-loot.git mod-aoe-loot
|
||||
fi
|
||||
|
||||
# Install Learn Spells if enabled
|
||||
if [ "$MODULE_LEARN_SPELLS" = "1" ] && [ ! -d "mod-learn-spells" ]; then
|
||||
echo '📚 Installing mod-learn-spells...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-learn-spells'
|
||||
echo ' ℹ️ Automatically teaches class spells on level up'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/azerothcore/mod-learn-spells.git mod-learn-spells
|
||||
fi
|
||||
|
||||
# Install Fireworks on Level if enabled
|
||||
if [ "$MODULE_FIREWORKS" = "1" ] && [ ! -d "mod-fireworks-on-level" ]; then
|
||||
echo '🎆 Installing mod-fireworks-on-level...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-fireworks-on-level'
|
||||
echo ' ℹ️ Displays fireworks when players level up'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/azerothcore/mod-fireworks-on-level.git mod-fireworks-on-level
|
||||
fi
|
||||
|
||||
# Install Individual Progression if enabled
|
||||
if [ "$MODULE_INDIVIDUAL_PROGRESSION" = "1" ] && [ ! -d "mod-individual-progression" ]; then
|
||||
echo '⏳ Installing mod-individual-progression...'
|
||||
echo ' 📖 Project: https://github.com/ZhengPeiRu21/mod-individual-progression'
|
||||
echo ' ℹ️ Simulates authentic Vanilla→TBC→WotLK progression per player'
|
||||
echo ' ✅ AUTO-CONFIG: Automatically sets EnablePlayerSettings=1 and DBC.EnforceItemAttributes=0'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 📁 Optional client files available in optional/ directory'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/ZhengPeiRu21/mod-individual-progression.git mod-individual-progression
|
||||
fi
|
||||
|
||||
# Quality of Life Modules
|
||||
if [ "$MODULE_AHBOT" = "1" ] && [ ! -d "mod-ahbot" ]; then
|
||||
echo '🏪 Installing mod-ahbot...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-ahbot'
|
||||
echo ' ℹ️ Auction house bot that buys and sells items automatically'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 📋 POST-INSTALL: Requires manual account/character setup in mod_ahbot.conf'
|
||||
git clone https://github.com/azerothcore/mod-ahbot.git mod-ahbot
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AUTOBALANCE" = "1" ] && [ ! -d "mod-autobalance" ]; then
|
||||
echo '⚖️ Installing mod-autobalance...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-autobalance'
|
||||
echo ' ℹ️ Automatically adjusts dungeon difficulty based on party size'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
git clone https://github.com/azerothcore/mod-autobalance.git mod-autobalance
|
||||
fi
|
||||
|
||||
if [ "$MODULE_TRANSMOG" = "1" ] && [ ! -d "mod-transmog" ]; then
|
||||
echo '🎭 Installing mod-transmog...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-transmog'
|
||||
echo ' ℹ️ Allows appearance customization of equipment'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/azerothcore/mod-transmog.git mod-transmog
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_BUFFER" = "1" ] && [ ! -d "mod-npc-buffer" ]; then
|
||||
echo 'Installing mod-npc-buffer...'
|
||||
git clone https://github.com/azerothcore/mod-npc-buffer.git mod-npc-buffer
|
||||
fi
|
||||
|
||||
# Gameplay Enhancement Modules
|
||||
if [ "$MODULE_DYNAMIC_XP" = "1" ] && [ ! -d "mod-dynamic-xp" ]; then
|
||||
echo 'Installing mod-dynamic-xp...'
|
||||
git clone https://github.com/azerothcore/mod-dynamic-xp.git mod-dynamic-xp
|
||||
fi
|
||||
|
||||
if [ "$MODULE_SOLO_LFG" = "1" ] && [ ! -d "mod-solo-lfg" ]; then
|
||||
echo '🔍 Installing mod-solo-lfg...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-solo-lfg'
|
||||
echo ' ℹ️ Allows dungeon finder for solo players and small groups'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 💡 Pairs perfectly with mod-solocraft and mod-autobalance'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/azerothcore/mod-solo-lfg.git mod-solo-lfg
|
||||
fi
|
||||
|
||||
if [ "$MODULE_1V1_ARENA" = "1" ] && [ ! -d "mod-1v1-arena" ]; then
|
||||
echo 'Installing mod-1v1-arena...'
|
||||
git clone https://github.com/azerothcore/mod-1v1-arena.git mod-1v1-arena
|
||||
fi
|
||||
|
||||
if [ "$MODULE_PHASED_DUELS" = "1" ] && [ ! -d "mod-phased-duels" ]; then
|
||||
echo 'Installing mod-phased-duels...'
|
||||
git clone https://github.com/azerothcore/mod-phased-duels.git mod-phased-duels
|
||||
fi
|
||||
|
||||
# Server Management Modules
|
||||
if [ "$MODULE_BREAKING_NEWS" = "1" ] && [ ! -d "mod-breaking-news-override" ]; then
|
||||
echo '📰 Installing mod-breaking-news-override...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-breaking-news-override'
|
||||
echo ' ℹ️ Displays custom breaking news on character selection screen'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 📋 POST-INSTALL: Requires custom HTML file creation and path configuration'
|
||||
git clone https://github.com/azerothcore/mod-breaking-news-override.git mod-breaking-news-override
|
||||
fi
|
||||
|
||||
if [ "$MODULE_BOSS_ANNOUNCER" = "1" ] && [ ! -d "mod-boss-announcer" ]; then
|
||||
echo 'Installing mod-boss-announcer...'
|
||||
git clone https://github.com/azerothcore/mod-boss-announcer.git mod-boss-announcer
|
||||
fi
|
||||
|
||||
if [ "$MODULE_ACCOUNT_ACHIEVEMENTS" = "1" ] && [ ! -d "mod-account-achievements" ]; then
|
||||
echo 'Installing mod-account-achievements...'
|
||||
git clone https://github.com/azerothcore/mod-account-achievements.git mod-account-achievements
|
||||
fi
|
||||
|
||||
# Additional Modules Found in Config
|
||||
if [ "$MODULE_AUTO_REVIVE" = "1" ] && [ ! -d "mod-auto-revive" ]; then
|
||||
echo 'Installing mod-auto-revive...'
|
||||
git clone https://github.com/azerothcore/mod-auto-revive.git mod-auto-revive
|
||||
fi
|
||||
|
||||
if [ "$MODULE_GAIN_HONOR_GUARD" = "1" ] && [ ! -d "mod-gain-honor-guard" ]; then
|
||||
echo 'Installing mod-gain-honor-guard...'
|
||||
git clone https://github.com/azerothcore/mod-gain-honor-guard.git mod-gain-honor-guard
|
||||
fi
|
||||
|
||||
if [ "$MODULE_ELUNA" = "1" ] && [ ! -d "mod-eluna" ]; then
|
||||
echo '🖥️ Installing mod-eluna...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-eluna'
|
||||
echo ' ℹ️ Lua scripting engine for custom server functionality'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/azerothcore/mod-eluna.git mod-eluna
|
||||
fi
|
||||
if [ "$MODULE_ARAC" = "1" ] && [ ! -d "mod-arac" ]; then
|
||||
echo '🌈 Installing mod-arac...'
|
||||
echo ' 📖 Project: https://github.com/heyitsbench/mod-arac'
|
||||
echo ' ℹ️ All Races All Classes - Removes class restrictions'
|
||||
echo ' 🚨 CRITICAL: Requires DBC file updates and client patch!'
|
||||
echo ' 📋 POST-INSTALL: Apply Patch-A.MPQ to client WoW/Data/ directory'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/heyitsbench/mod-arac.git mod-arac
|
||||
fi
|
||||
|
||||
if [ "$MODULE_TIME_IS_TIME" = "1" ] && [ ! -d "mod-TimeIsTime" ]; then
|
||||
echo 'Installing mod-TimeIsTime...'
|
||||
git clone https://github.com/dunjeon/mod-TimeIsTime.git mod-TimeIsTime
|
||||
fi
|
||||
|
||||
if [ "$MODULE_POCKET_PORTAL" = "1" ] && [ ! -d "mod-pocket-portal" ]; then
|
||||
echo 'Installing mod-pocket-portal...'
|
||||
git clone https://github.com/azerothcore/mod-pocket-portal.git mod-pocket-portal
|
||||
fi
|
||||
|
||||
if [ "$MODULE_RANDOM_ENCHANTS" = "1" ] && [ ! -d "mod-random-enchants" ]; then
|
||||
echo 'Installing mod-random-enchants...'
|
||||
git clone https://github.com/azerothcore/mod-random-enchants.git mod-random-enchants
|
||||
fi
|
||||
|
||||
if [ "$MODULE_SOLOCRAFT" = "1" ] && [ ! -d "mod-solocraft" ]; then
|
||||
echo '🎯 Installing mod-solocraft...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-solocraft'
|
||||
echo ' ℹ️ Scales dungeon/raid difficulty for solo players'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 💡 Works well with mod-autobalance and mod-solo-lfg'
|
||||
git clone https://github.com/azerothcore/mod-solocraft.git mod-solocraft
|
||||
fi
|
||||
|
||||
if [ "$MODULE_PVP_TITLES" = "1" ] && [ ! -d "mod-pvp-titles" ]; then
|
||||
echo 'Installing mod-pvp-titles...'
|
||||
git clone https://github.com/azerothcore/mod-pvp-titles.git mod-pvp-titles
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_BEASTMASTER" = "1" ] && [ ! -d "mod-npc-beastmaster" ]; then
|
||||
echo 'Installing mod-npc-beastmaster...'
|
||||
git clone https://github.com/azerothcore/mod-npc-beastmaster.git mod-npc-beastmaster
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_ENCHANTER" = "1" ] && [ ! -d "mod-npc-enchanter" ]; then
|
||||
echo '✨ Installing mod-npc-enchanter...'
|
||||
echo ' 📖 Project: https://github.com/azerothcore/mod-npc-enchanter'
|
||||
echo ' ℹ️ NPC that provides enchanting services'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/azerothcore/mod-npc-enchanter.git mod-npc-enchanter
|
||||
fi
|
||||
|
||||
if [ "$MODULE_INSTANCE_RESET" = "1" ] && [ ! -d "mod-instance-reset" ]; then
|
||||
echo 'Installing mod-instance-reset...'
|
||||
git clone https://github.com/azerothcore/mod-instance-reset.git mod-instance-reset
|
||||
fi
|
||||
|
||||
if [ "$MODULE_LEVEL_GRANT" = "1" ] && [ ! -d "mod-quest-count-level" ]; then
|
||||
echo 'Installing mod-quest-count-level...'
|
||||
git clone https://github.com/michaeldelago/mod-quest-count-level.git mod-quest-count-level
|
||||
fi
|
||||
if [ "$MODULE_ASSISTANT" = "1" ] && [ ! -d "mod-assistant" ]; then
|
||||
echo '🤖 Installing mod-assistant...'
|
||||
echo ' 📖 Project: https://github.com/noisiver/mod-assistant'
|
||||
echo ' ℹ️ NPC (ID: 9000000) providing heirlooms, glyphs, gems, profession services'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/noisiver/mod-assistant.git mod-assistant
|
||||
fi
|
||||
if [ "$MODULE_REAGENT_BANK" = "1" ] && [ ! -d "mod-reagent-bank" ]; then
|
||||
echo '🏦 Installing mod-reagent-bank...'
|
||||
echo ' 📖 Project: https://github.com/ZhengPeiRu21/mod-reagent-bank'
|
||||
echo ' ℹ️ Reagent banker NPC for storing crafting materials, frees bag space'
|
||||
echo ' 🔧 REBUILD REQUIRED: Container must be rebuilt with source-based compilation'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/ZhengPeiRu21/mod-reagent-bank.git mod-reagent-bank
|
||||
fi
|
||||
if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" = "1" ] && [ ! -d "mod-black-market" ]; then
|
||||
echo '🏴☠️ Installing mod-black-market...'
|
||||
echo ' 📖 Project: https://github.com/Youpeoples/Black-Market-Auction-House'
|
||||
echo ' ℹ️ MoP Black Market Auction House backported using Eluna Lua engine'
|
||||
echo ' ⚠️ SPECIAL MODULE: Uses Lua scripts, not C++ compilation'
|
||||
echo ' 🔧 REQUIRES: mod-eluna must be enabled and functional'
|
||||
echo ' 🔬 STATUS: IN TESTING - Currently under verification'
|
||||
git clone https://github.com/Youpeoples/Black-Market-Auction-House.git mod-black-market
|
||||
|
||||
# Special handling: Copy Lua scripts to lua_scripts directory
|
||||
if [ "$MODULE_ELUNA" = "1" ] && [ -d "mod-black-market/Server Files/lua_scripts" ]; then
|
||||
echo ' 🔧 Integrating Black Market Lua scripts with mod-eluna...'
|
||||
mkdir -p /azerothcore/lua_scripts
|
||||
cp -r mod-black-market/Server\ Files/lua_scripts/* /azerothcore/lua_scripts/ 2>/dev/null || true
|
||||
echo ' ✅ Black Market Lua scripts copied to /azerothcore/lua_scripts directory'
|
||||
ls -la /azerothcore/lua_scripts/ | grep -E "\.lua$" || echo " ℹ️ No .lua files found after copy"
|
||||
else
|
||||
echo ' ⚠️ WARNING: mod-eluna not enabled - Black Market will not function'
|
||||
fi
|
||||
fi
|
||||
|
||||
echo 'Managing configuration files...'
|
||||
|
||||
# Remove configuration files for disabled modules
|
||||
if [ "$MODULE_PLAYERBOTS" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/playerbots.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AOE_LOOT" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_aoe_loot.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_LEARN_SPELLS" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_learnspells.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_FIREWORKS" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_fireworks.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_INDIVIDUAL_PROGRESSION" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/individual_progression.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AHBOT" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_ahbot.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AUTOBALANCE" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/AutoBalance.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_TRANSMOG" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/transmog.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_BUFFER" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/npc_buffer.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_DYNAMIC_XP" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/Individual-XP.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_SOLO_LFG" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/SoloLfg.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_1V1_ARENA" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/1v1arena.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_PHASED_DUELS" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/phasedduels.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_BREAKING_NEWS" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/breaking_news.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_BOSS_ANNOUNCER" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/boss_announcer.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_ACCOUNT_ACHIEVEMENTS" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/account_achievements.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_AUTO_REVIVE" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/AutoRevive.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_GAIN_HONOR_GUARD" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/GainHonorGuard.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_ELUNA" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_eluna.conf*
|
||||
fi
|
||||
if [ "$MODULE_ARAC" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/arac.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_TIME_IS_TIME" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod-time_is_time.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_POCKET_PORTAL" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/pocketportal.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_RANDOM_ENCHANTS" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/RandomEnchants.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_SOLOCRAFT" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/Solocraft.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_PVP_TITLES" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_pvptitles.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_BEASTMASTER" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/npc_beastmaster.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_NPC_ENCHANTER" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/npc_enchanter.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_INSTANCE_RESET" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/instance-reset.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_LEVEL_GRANT" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/levelGrant.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_ASSISTANT" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_assistant.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_REAGENT_BANK" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_reagent_bank.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_black_market.conf*
|
||||
fi
|
||||
|
||||
# Install configuration files for enabled modules
|
||||
for module_dir in mod-*; do
|
||||
if [ -d "$module_dir" ]; then
|
||||
echo "Installing config files for $module_dir..."
|
||||
find "$module_dir" -name "*.conf.dist" -exec cp {} /azerothcore/env/dist/etc/ \; 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
echo 'Configuration file management complete.'
|
||||
|
||||
# Source the SQL module management functions
|
||||
source /scripts/manage-modules-sql.sh
|
||||
|
||||
echo 'Executing module SQL scripts...'
|
||||
execute_module_sql_scripts
|
||||
|
||||
echo 'SQL execution complete.'
|
||||
|
||||
# Module state tracking and rebuild logic
|
||||
echo 'Checking for module changes that require rebuild...'
|
||||
|
||||
MODULES_STATE_FILE="/modules/.modules_state"
|
||||
CURRENT_STATE=""
|
||||
REBUILD_REQUIRED=0
|
||||
|
||||
# Create current module state hash
|
||||
for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT; do
|
||||
eval "value=\$$module_var"
|
||||
CURRENT_STATE="$CURRENT_STATE$module_var=$value|"
|
||||
done
|
||||
|
||||
# Check if state has changed
|
||||
if [ -f "$MODULES_STATE_FILE" ]; then
|
||||
PREVIOUS_STATE=$(cat "$MODULES_STATE_FILE")
|
||||
if [ "$CURRENT_STATE" != "$PREVIOUS_STATE" ]; then
|
||||
echo "🔄 Module configuration has changed - rebuild required"
|
||||
REBUILD_REQUIRED=1
|
||||
else
|
||||
echo "✅ No module changes detected"
|
||||
fi
|
||||
else
|
||||
echo "📝 First run - establishing module state baseline"
|
||||
REBUILD_REQUIRED=1
|
||||
fi
|
||||
|
||||
# Save current state
|
||||
echo "$CURRENT_STATE" > "$MODULES_STATE_FILE"
|
||||
|
||||
# Check if any C++ modules are enabled (all current modules require compilation)
|
||||
ENABLED_MODULES=""
|
||||
[ "$MODULE_PLAYERBOTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-playerbots"
|
||||
[ "$MODULE_AOE_LOOT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-aoe-loot"
|
||||
[ "$MODULE_LEARN_SPELLS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-learn-spells"
|
||||
[ "$MODULE_FIREWORKS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-fireworks-on-level"
|
||||
[ "$MODULE_INDIVIDUAL_PROGRESSION" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-individual-progression"
|
||||
[ "$MODULE_AHBOT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-ahbot"
|
||||
[ "$MODULE_AUTOBALANCE" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-autobalance"
|
||||
[ "$MODULE_TRANSMOG" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-transmog"
|
||||
[ "$MODULE_NPC_BUFFER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-npc-buffer"
|
||||
[ "$MODULE_DYNAMIC_XP" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-dynamic-xp"
|
||||
[ "$MODULE_SOLO_LFG" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-solo-lfg"
|
||||
[ "$MODULE_1V1_ARENA" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-1v1-arena"
|
||||
[ "$MODULE_PHASED_DUELS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-phased-duels"
|
||||
[ "$MODULE_BREAKING_NEWS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-breaking-news-override"
|
||||
[ "$MODULE_BOSS_ANNOUNCER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-boss-announcer"
|
||||
[ "$MODULE_ACCOUNT_ACHIEVEMENTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-account-achievements"
|
||||
[ "$MODULE_AUTO_REVIVE" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-auto-revive"
|
||||
[ "$MODULE_GAIN_HONOR_GUARD" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-gain-honor-guard"
|
||||
[ "$MODULE_ELUNA" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-eluna"
|
||||
[ "$MODULE_ARAC" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-arac"
|
||||
[ "$MODULE_TIME_IS_TIME" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-time-is-time"
|
||||
[ "$MODULE_POCKET_PORTAL" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-pocket-portal"
|
||||
[ "$MODULE_RANDOM_ENCHANTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-random-enchants"
|
||||
[ "$MODULE_SOLOCRAFT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-solocraft"
|
||||
[ "$MODULE_PVP_TITLES" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-pvp-titles"
|
||||
[ "$MODULE_NPC_BEASTMASTER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-npc-beastmaster"
|
||||
[ "$MODULE_NPC_ENCHANTER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-npc-enchanter"
|
||||
[ "$MODULE_INSTANCE_RESET" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-instance-reset"
|
||||
[ "$MODULE_LEVEL_GRANT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-quest-count-level"
|
||||
[ "$MODULE_ASSISTANT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-assistant"
|
||||
[ "$MODULE_REAGENT_BANK" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-reagent-bank"
|
||||
# Note: mod-black-market is Lua-based, doesn't need C++ compilation
|
||||
|
||||
if [ -n "$ENABLED_MODULES" ]; then
|
||||
ENABLED_COUNT=$(echo $ENABLED_MODULES | wc -w)
|
||||
echo "🔧 Detected $ENABLED_COUNT enabled C++ modules requiring compilation:"
|
||||
for mod in $ENABLED_MODULES; do
|
||||
echo " • $mod"
|
||||
done
|
||||
|
||||
if [ "$REBUILD_REQUIRED" = "1" ]; then
|
||||
echo ""
|
||||
echo "🚨 REBUILD REQUIRED 🚨"
|
||||
echo "Module configuration has changed. To integrate C++ modules into AzerothCore:"
|
||||
echo ""
|
||||
echo "1. Stop current services:"
|
||||
echo " docker compose -f docker-compose-azerothcore-services.yml down"
|
||||
echo ""
|
||||
echo "2. Build with source-based compilation:"
|
||||
echo " docker compose -f /tmp/acore-dev-test/docker-compose.yml build"
|
||||
echo " docker compose -f /tmp/acore-dev-test/docker-compose.yml up -d"
|
||||
echo ""
|
||||
echo "3. Or use the automated rebuild script (if available):"
|
||||
echo " ./scripts/rebuild-with-modules.sh"
|
||||
echo ""
|
||||
echo "📋 NOTE: Source-based build will compile AzerothCore with all enabled modules"
|
||||
echo "⏱️ Expected build time: 15-45 minutes depending on system performance"
|
||||
echo ""
|
||||
fi
|
||||
else
|
||||
echo "✅ No C++ modules enabled - pre-built containers can be used"
|
||||
fi
|
||||
|
||||
echo 'Module management complete.'
|
||||
|
||||
# Download rebuild script from GitHub for local access
|
||||
echo '📥 Downloading rebuild-with-modules.sh from GitHub...'
|
||||
apk add --no-cache curl
|
||||
if curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/rebuild-with-modules.sh -o /tmp/rebuild-with-modules.sh 2>/dev/null; then
|
||||
echo '✅ Downloaded rebuild-with-modules.sh from GitHub'
|
||||
chmod +x /tmp/rebuild-with-modules.sh
|
||||
echo '📍 Script available at: /tmp/rebuild-with-modules.sh'
|
||||
elif [ -f "/project/scripts/rebuild-with-modules.sh" ]; then
|
||||
echo '📁 Using local rebuild-with-modules.sh for testing'
|
||||
cp /project/scripts/rebuild-with-modules.sh /tmp/rebuild-with-modules.sh
|
||||
chmod +x /tmp/rebuild-with-modules.sh
|
||||
echo '✅ Copied to /tmp/rebuild-with-modules.sh'
|
||||
else
|
||||
echo '⚠️ Warning: rebuild-with-modules.sh not found in GitHub or locally'
|
||||
fi
|
||||
|
||||
echo 'Keeping container alive...'
|
||||
tail -f /dev/null
|
||||
128
V1/scripts/rebuild-with-modules.sh
Executable file
128
V1/scripts/rebuild-with-modules.sh
Executable file
@@ -0,0 +1,128 @@
|
||||
#!/bin/bash
|
||||
|
||||
# AzerothCore Module Rebuild Script
|
||||
# Automates the process of rebuilding AzerothCore with enabled modules
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔧 AzerothCore Module Rebuild Script"
|
||||
echo "==================================="
|
||||
echo ""
|
||||
|
||||
# Check if source repository exists
|
||||
SOURCE_COMPOSE="/tmp/acore-dev-test/docker-compose.yml"
|
||||
if [ ! -f "$SOURCE_COMPOSE" ]; then
|
||||
echo "❌ Error: Source-based Docker Compose file not found at $SOURCE_COMPOSE"
|
||||
echo "Please ensure AzerothCore source repository is available for compilation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check current module configuration
|
||||
echo "📋 Checking current module configuration..."
|
||||
|
||||
MODULES_ENABLED=0
|
||||
ENABLED_MODULES=""
|
||||
|
||||
# Read environment file to check enabled modules
|
||||
if [ -f "docker-compose-azerothcore-services.env" ]; then
|
||||
while IFS= read -r line; do
|
||||
if echo "$line" | grep -q "^MODULE_.*=1$"; then
|
||||
MODULE_NAME=$(echo "$line" | cut -d'=' -f1)
|
||||
MODULES_ENABLED=$((MODULES_ENABLED + 1))
|
||||
ENABLED_MODULES="$ENABLED_MODULES $MODULE_NAME"
|
||||
fi
|
||||
done < docker-compose-azerothcore-services.env
|
||||
else
|
||||
echo "⚠️ Warning: Environment file not found, checking default configuration..."
|
||||
fi
|
||||
|
||||
echo "🔍 Found $MODULES_ENABLED enabled modules"
|
||||
|
||||
if [ $MODULES_ENABLED -eq 0 ]; then
|
||||
echo "✅ No modules enabled - rebuild not required"
|
||||
echo "You can use pre-built containers for better performance."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "📦 Enabled modules:$ENABLED_MODULES"
|
||||
echo ""
|
||||
|
||||
# Confirm rebuild
|
||||
read -p "🤔 Proceed with rebuild? This will take 15-45 minutes. (y/N): " -n 1 -r
|
||||
echo ""
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "❌ Rebuild cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🛑 Stopping current services..."
|
||||
docker compose -f docker-compose-azerothcore-services.yml down || echo "⚠️ Services may not be running"
|
||||
|
||||
echo ""
|
||||
echo "🔧 Starting source-based compilation..."
|
||||
echo "⏱️ This will take 15-45 minutes depending on your system..."
|
||||
echo ""
|
||||
|
||||
# Build with source
|
||||
cd /tmp/acore-dev-test
|
||||
echo "📁 Switched to source directory: $(pwd)"
|
||||
|
||||
# Copy modules to source build
|
||||
echo "📋 Copying modules to source build..."
|
||||
if [ -d "/home/upb/src/acore-compose2/storage/azerothcore/modules" ]; then
|
||||
# Ensure modules directory exists in source
|
||||
mkdir -p modules
|
||||
|
||||
# Copy enabled modules only
|
||||
echo "🔄 Syncing enabled modules..."
|
||||
for module_dir in /home/upb/src/acore-compose2/storage/azerothcore/modules/*/; do
|
||||
if [ -d "$module_dir" ]; then
|
||||
module_name=$(basename "$module_dir")
|
||||
echo " Copying $module_name..."
|
||||
cp -r "$module_dir" modules/
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "⚠️ Warning: No modules directory found"
|
||||
fi
|
||||
|
||||
# Start build process
|
||||
echo ""
|
||||
echo "🚀 Building AzerothCore with modules..."
|
||||
docker compose build --no-cache
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ""
|
||||
echo "✅ Build completed successfully!"
|
||||
echo ""
|
||||
|
||||
# Start services
|
||||
echo "🟢 Starting services with compiled modules..."
|
||||
docker compose up -d
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ""
|
||||
echo "🎉 SUCCESS! AzerothCore is now running with compiled modules."
|
||||
echo ""
|
||||
echo "📊 Service status:"
|
||||
docker compose ps
|
||||
echo ""
|
||||
echo "📝 To monitor logs:"
|
||||
echo " docker compose logs -f"
|
||||
echo ""
|
||||
echo "🌐 Server should be available on configured ports once fully started."
|
||||
else
|
||||
echo "❌ Failed to start services"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "❌ Build failed"
|
||||
echo ""
|
||||
echo "🔍 Check build logs for errors:"
|
||||
echo " docker compose logs"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ Rebuild process complete!"
|
||||
178
V1/todo.md
Normal file
178
V1/todo.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# AzerothCore Module System Validation TODO
|
||||
|
||||
## Overview
|
||||
Document findings from module system validation and plan for end-to-end testing to ensure proper deployment in both standard and playerbot configurations.
|
||||
|
||||
## Key Findings
|
||||
|
||||
### Container Architecture
|
||||
- **Single worldserver container**: `ac-worldserver`
|
||||
- **Base container selection**: Determined by `MODULE_PLAYERBOTS` flag
|
||||
- `MODULE_PLAYERBOTS=1` → `uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot`
|
||||
- `MODULE_PLAYERBOTS=0` → `acore/ac-wotlk-worldserver:14.0.0-dev`
|
||||
- **Additional modules**: Compiled on top of selected base container via source compilation
|
||||
|
||||
### Current Module Configuration
|
||||
**Enabled Modules (modules-custom.env):**
|
||||
1. `MODULE_PLAYERBOTS=1` (base container selection)
|
||||
2. `MODULE_AOE_LOOT=1` (requires C++ compilation)
|
||||
3. `MODULE_LEARN_SPELLS=1` (requires C++ compilation)
|
||||
4. `MODULE_FIREWORKS=1` (requires C++ compilation)
|
||||
5. `MODULE_AHBOT=1` (requires C++ compilation)
|
||||
6. `MODULE_AUTOBALANCE=1` (requires C++ compilation)
|
||||
7. `MODULE_TRANSMOG=1` (requires C++ compilation)
|
||||
8. `MODULE_NPC_BUFFER=1` (requires C++ compilation)
|
||||
9. `MODULE_SOLO_LFG=1` (requires C++ compilation)
|
||||
10. `MODULE_SOLOCRAFT=1` (requires C++ compilation)
|
||||
|
||||
### Rebuild Requirements
|
||||
**Only ac-worldserver requires rebuild:**
|
||||
- All C++ modules affect worldserver binary only
|
||||
- ac-authserver remains compatible (playerbot images already include auth changes)
|
||||
- No other containers need recompilation
|
||||
|
||||
### Module Installation Components
|
||||
1. **Module Manager**: `ac-modules` container (downloads/installs modules)
|
||||
2. **Build Service**: `ac-build` container (handles C++ compilation when needed)
|
||||
3. **State Tracking**: `/modules/.modules_state` file prevents unnecessary rebuilds
|
||||
4. **Automated Scripts**:
|
||||
- `scripts/manage-modules.sh` - Module installation and configuration
|
||||
- `scripts/rebuild-with-modules.sh` - Automated rebuild process
|
||||
- `scripts/deploy-and-check.sh` - Full stack deployment with validation
|
||||
|
||||
## Configuration Issues Identified
|
||||
1. **Conflicting Configurations**:
|
||||
- `services-custom.env`: Only `MODULE_PLAYERBOTS=1`
|
||||
- `modules-custom.env`: 10 modules enabled
|
||||
- **Resolution needed**: Align configurations
|
||||
|
||||
## Testing Plan: Two End-to-End Validation Tests
|
||||
|
||||
### Test 1: Standard AzerothCore with Additional Modules
|
||||
**Objective**: Validate deployment without Playerbots but with other C++ modules
|
||||
**Configuration**:
|
||||
```bash
|
||||
# Base container
|
||||
MODULE_PLAYERBOTS=0
|
||||
AC_WORLDSERVER_IMAGE=acore/ac-wotlk-worldserver:14.0.0-dev
|
||||
|
||||
# Additional modules (subset for testing)
|
||||
MODULE_AOE_LOOT=1
|
||||
MODULE_AUTOBALANCE=1
|
||||
MODULE_TRANSMOG=1
|
||||
```
|
||||
|
||||
**Expected Results**:
|
||||
- Uses standard AzerothCore base
|
||||
- Compiles 3 additional modules into worldserver
|
||||
- No Playerbot functionality
|
||||
- Validates source compilation process
|
||||
|
||||
**Test Steps**:
|
||||
1. Configure environment files for standard deployment
|
||||
2. Run `scripts/deploy-and-check.sh`
|
||||
3. Monitor `ac-modules` container output
|
||||
4. Verify rebuild detection triggers
|
||||
5. Execute `scripts/rebuild-with-modules.sh`
|
||||
6. Validate all services are healthy
|
||||
7. Test module functionality (AOE loot, autobalance, transmog)
|
||||
|
||||
### Test 2: Playerbot AzerothCore with Additional Modules
|
||||
**Objective**: Validate deployment with Playerbots + additional C++ modules
|
||||
**Configuration**:
|
||||
```bash
|
||||
# Base container (current configuration)
|
||||
MODULE_PLAYERBOTS=1
|
||||
AC_WORLDSERVER_IMAGE=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot
|
||||
|
||||
# All additional modules
|
||||
MODULE_AOE_LOOT=1
|
||||
MODULE_LEARN_SPELLS=1
|
||||
MODULE_FIREWORKS=1
|
||||
MODULE_AHBOT=1
|
||||
MODULE_AUTOBALANCE=1
|
||||
MODULE_TRANSMOG=1
|
||||
MODULE_NPC_BUFFER=1
|
||||
MODULE_SOLO_LFG=1
|
||||
MODULE_SOLOCRAFT=1
|
||||
```
|
||||
|
||||
**Expected Results**:
|
||||
- Uses Playerbot base container
|
||||
- Compiles 9 additional modules into worldserver
|
||||
- Full Playerbot functionality maintained
|
||||
- All additional modules functional
|
||||
|
||||
**Test Steps**:
|
||||
1. Use current modules-custom.env configuration
|
||||
2. Run full deployment with `scripts/deploy-and-check.sh`
|
||||
3. Monitor module installation and rebuild process
|
||||
4. Validate Playerbot functionality
|
||||
5. Test each additional module's functionality
|
||||
6. Verify no conflicts between Playerbots and other modules
|
||||
|
||||
## Validation Criteria
|
||||
|
||||
### Deployment Success Criteria
|
||||
- [ ] All containers start and pass health checks
|
||||
- [ ] Database schemas properly created/updated
|
||||
- [ ] Module configuration files properly installed
|
||||
- [ ] No container restart loops
|
||||
- [ ] Port connectivity tests pass
|
||||
|
||||
### Module Functionality Criteria
|
||||
- [ ] Playerbot commands work (if enabled)
|
||||
- [ ] AOE looting functions
|
||||
- [ ] Auto-spell learning on level up
|
||||
- [ ] Fireworks display on level up
|
||||
- [ ] Auction house bot operational
|
||||
- [ ] Dungeon difficulty auto-balances
|
||||
- [ ] Transmog system accessible
|
||||
- [ ] NPC buffer provides services
|
||||
- [ ] Solo LFG allows queue
|
||||
- [ ] Solocraft scaling active
|
||||
|
||||
### Performance Criteria
|
||||
- [ ] Server startup time < 5 minutes
|
||||
- [ ] Module rebuild time < 45 minutes
|
||||
- [ ] No memory leaks or excessive resource usage
|
||||
- [ ] Stable operation under load
|
||||
|
||||
## Risk Mitigation
|
||||
1. **Backup current working state** before testing
|
||||
2. **Test in isolated environment** first
|
||||
3. **Document rollback procedures** for each test
|
||||
4. **Monitor logs continuously** during testing
|
||||
5. **Have restore scripts ready** in case of failures
|
||||
|
||||
## Next Steps
|
||||
1. Create isolated test environments for both scenarios
|
||||
2. Prepare configuration files for Test 1 (standard + modules)
|
||||
3. Execute Test 1 and document results
|
||||
4. Execute Test 2 and document results
|
||||
5. Compare performance and stability between configurations
|
||||
6. Document final recommendations for production deployment
|
||||
|
||||
## Notes
|
||||
- Each test should be run multiple times to ensure consistency
|
||||
- Log all outputs for analysis
|
||||
- Measure build times and resource usage
|
||||
- Test both fresh deployments and configuration changes
|
||||
- Validate that module state tracking prevents unnecessary rebuilds
|
||||
|
||||
---
|
||||
|
||||
## Previous Deployment History (ARCHIVED)
|
||||
|
||||
### ✅ **Major Fixes Completed:**
|
||||
1. **Database Schema Issues** ✅ **RESOLVED**
|
||||
- Added missing `emotetextsound_dbc.sql` to source project
|
||||
- Imported all DBC tables - worldserver now starts successfully
|
||||
- Worldserver status: `Up (healthy)` with Eluna scripts loaded
|
||||
|
||||
2. **Container Script Compatibility** ✅ **RESOLVED**
|
||||
- Fixed client-data container with multi-OS package manager detection
|
||||
- Client data downloads working (15GB extracted successfully)
|
||||
- Updated docker-compose with Alpine/Ubuntu compatibility
|
||||
|
||||
**Status**: **MAJOR SUCCESS** ✅ - Core server functional, ready for module validation testing.
|
||||
246
cleanup.sh
Executable file
246
cleanup.sh
Executable file
@@ -0,0 +1,246 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==============================================
|
||||
# ac-compose Cleanup Script (project-scoped)
|
||||
# ==============================================
|
||||
# Usage: ./cleanup.sh [--soft] [--hard] [--nuclear] [--dry-run] [--force] [--preserve-backups]
|
||||
# Project: ac-compose
|
||||
|
||||
set -e
|
||||
|
||||
# Resolve project dir and compose
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="${SCRIPT_DIR}"
|
||||
COMPOSE_FILE="${PROJECT_DIR}/compose.yml"
|
||||
ENV_FILE="${PROJECT_DIR}/.env"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; MAGENTA='\033[0;35m'; NC='\033[0m'
|
||||
|
||||
print_status() {
|
||||
case "$1" in
|
||||
INFO) echo -e "${BLUE}ℹ️ ${2}${NC}";;
|
||||
SUCCESS) echo -e "${GREEN}✅ ${2}${NC}";;
|
||||
WARNING) echo -e "${YELLOW}⚠️ ${2}${NC}";;
|
||||
ERROR) echo -e "${RED}❌ ${2}${NC}";;
|
||||
DANGER) echo -e "${RED}💀 ${2}${NC}";;
|
||||
HEADER) echo -e "\n${MAGENTA}=== ${2} ===${NC}";;
|
||||
esac
|
||||
}
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
Usage: $0 [CLEANUP_LEVEL] [OPTIONS]
|
||||
|
||||
CLEANUP LEVELS:
|
||||
--soft Stop project containers (preserves data)
|
||||
--hard Remove containers + networks (preserves volumes/images)
|
||||
--nuclear Complete removal: containers, networks, volumes, images (DESTROYS DATA)
|
||||
|
||||
OPTIONS:
|
||||
--dry-run Show actions without executing
|
||||
--force Skip confirmation prompts
|
||||
--preserve-backups Keep backups when nuking storage (moves them aside and restores)
|
||||
-h, --help Show this help
|
||||
EOF
|
||||
}
|
||||
|
||||
# Flags
|
||||
CLEANUP_LEVEL=""
|
||||
DRY_RUN=false
|
||||
FORCE=false
|
||||
PRESERVE_BACKUPS=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--soft|--hard|--nuclear) CLEANUP_LEVEL="${1#--}"; shift;;
|
||||
--dry-run) DRY_RUN=true; shift;;
|
||||
--force) FORCE=true; shift;;
|
||||
--preserve-backups) PRESERVE_BACKUPS=true; shift;;
|
||||
-h|--help) usage; exit 0;;
|
||||
*) echo "Unknown arg: $1"; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
execute_command() {
|
||||
local description="$1"; shift
|
||||
local cmd="$*"
|
||||
if $DRY_RUN; then
|
||||
print_status INFO "[DRY RUN] $description"
|
||||
echo " $cmd"
|
||||
else
|
||||
print_status INFO "$description"
|
||||
eval "$cmd" || print_status WARNING "Command failed or no action needed"
|
||||
fi
|
||||
}
|
||||
|
||||
confirm() {
|
||||
local msg="$1"
|
||||
if $FORCE; then
|
||||
print_status INFO "Force enabled; skipping confirmation"
|
||||
return 0
|
||||
fi
|
||||
echo -e "${YELLOW}⚠️ ${msg}${NC}"
|
||||
read -p "Are you sure? (yes/no): " ans
|
||||
[[ "$ans" =~ ^(yes|y|YES|Y)$ ]] || { print_status INFO "Cancelled"; exit 0; }
|
||||
}
|
||||
|
||||
show_resources() {
|
||||
print_status HEADER "CURRENT PROJECT RESOURCES"
|
||||
echo -e "${BLUE}Containers:${NC}"
|
||||
docker compose -f "$COMPOSE_FILE" ps -a || true
|
||||
echo -e "${BLUE}Networks:${NC}"
|
||||
docker network ls --format 'table {{.Name}}\t{{.Driver}}' | grep -E "(^|\s)$(grep -oE '^NETWORK_NAME=.+$' "$ENV_FILE" 2>/dev/null | cut -d= -f2 | tr -d '\r' || echo 'azerothcore')($|\s)" || true
|
||||
echo -e "${BLUE}Volumes:${NC}"
|
||||
docker volume ls --format 'table {{.Name}}\t{{.Driver}}' | grep -E 'ac_|acore|azerothcore' || true
|
||||
}
|
||||
|
||||
# Load env for STORAGE_PATH etc.
|
||||
STORAGE_PATH_DEFAULT="${PROJECT_DIR}/storage"
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
set -a; source "$ENV_FILE"; set +a
|
||||
fi
|
||||
STORAGE_PATH="${STORAGE_PATH:-$STORAGE_PATH_DEFAULT}"
|
||||
PROJECT_NAME="${COMPOSE_PROJECT_NAME:-ac-compose}"
|
||||
|
||||
remove_storage_dir(){
|
||||
local path="$1"
|
||||
if [ -d "$path" ]; then
|
||||
rm -rf "$path" 2>/dev/null || sudo rm -rf "$path" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
remove_project_volumes(){
|
||||
docker volume ls --format '{{.Name}}' \
|
||||
| grep -E "^${PROJECT_NAME}|^azerothcore" \
|
||||
| xargs -r docker volume rm >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
soft_cleanup() {
|
||||
print_status HEADER "SOFT CLEANUP - Stop runtime stack"
|
||||
confirm "This will stop all project containers (data preserved)."
|
||||
local profiles=(
|
||||
--profile services-standard
|
||||
--profile services-playerbots
|
||||
--profile services-modules
|
||||
--profile client-data
|
||||
--profile client-data-bots
|
||||
--profile modules
|
||||
--profile tools
|
||||
--profile db
|
||||
)
|
||||
execute_command "Stopping runtime profiles" docker compose -f "$COMPOSE_FILE" "${profiles[@]}" down
|
||||
print_status SUCCESS "Soft cleanup complete"
|
||||
}
|
||||
|
||||
hard_cleanup() {
|
||||
print_status HEADER "HARD CLEANUP - Remove containers + networks"
|
||||
confirm "This will remove containers and networks (volumes/images preserved)."
|
||||
local profiles=(
|
||||
--profile services-standard
|
||||
--profile services-playerbots
|
||||
--profile services-modules
|
||||
--profile client-data
|
||||
--profile client-data-bots
|
||||
--profile modules
|
||||
--profile tools
|
||||
--profile db
|
||||
)
|
||||
execute_command "Removing containers and networks" docker compose -f "$COMPOSE_FILE" "${profiles[@]}" down --remove-orphans
|
||||
execute_command "Remove project volumes" remove_project_volumes
|
||||
# Remove straggler containers matching project name (defensive)
|
||||
execute_command "Remove stray project containers" "docker ps -a --format '{{.Names}}' | grep -E '^ac-' | xargs -r docker rm -f"
|
||||
# Remove project network if present and not automatically removed
|
||||
if [ -n "${NETWORK_NAME:-}" ]; then
|
||||
execute_command "Remove project network ${NETWORK_NAME}" "docker network rm ${NETWORK_NAME} 2>/dev/null || true"
|
||||
fi
|
||||
print_status SUCCESS "Hard cleanup complete"
|
||||
}
|
||||
|
||||
nuclear_cleanup() {
|
||||
print_status HEADER "NUCLEAR CLEANUP - COMPLETE REMOVAL"
|
||||
print_status DANGER "THIS WILL DESTROY ALL PROJECT DATA"
|
||||
confirm "Proceed with complete removal?"
|
||||
|
||||
# Down with volumes
|
||||
local profiles=(
|
||||
--profile services-standard
|
||||
--profile services-playerbots
|
||||
--profile services-modules
|
||||
--profile client-data
|
||||
--profile client-data-bots
|
||||
--profile modules
|
||||
--profile tools
|
||||
--profile db
|
||||
)
|
||||
execute_command "Removing containers, networks and volumes" docker compose -f "$COMPOSE_FILE" "${profiles[@]}" down --volumes --remove-orphans
|
||||
execute_command "Remove leftover volumes" remove_project_volumes
|
||||
|
||||
# Remove project images (server/tool images typical to this project)
|
||||
execute_command "Remove acore images" "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^acore/' | xargs -r docker rmi"
|
||||
execute_command "Remove playerbots images" "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E '^uprightbass360/azerothcore-wotlk-playerbots' | xargs -r docker rmi"
|
||||
execute_command "Remove tool images" "docker images --format '{{.Repository}}:{{.Tag}}' | grep -E 'phpmyadmin|uprightbass360/keira3' | xargs -r docker rmi"
|
||||
|
||||
# Storage cleanup (preserve backups if requested)
|
||||
if $PRESERVE_BACKUPS; then
|
||||
print_status INFO "Preserving backups under ${STORAGE_PATH}/backups"
|
||||
TMP_PRESERVE="${PROJECT_DIR}/.preserve-backups"
|
||||
if [ -d "${STORAGE_PATH}/backups" ]; then
|
||||
execute_command "Staging backups" "mkdir -p '${TMP_PRESERVE}' && cp -a '${STORAGE_PATH}/backups' '${TMP_PRESERVE}/'"
|
||||
fi
|
||||
execute_command "Removing storage" "remove_storage_dir '${STORAGE_PATH}'"
|
||||
if [ -d "${TMP_PRESERVE}/backups" ]; then
|
||||
execute_command "Restoring backups" "mkdir -p '${STORAGE_PATH}' && mv '${TMP_PRESERVE}/backups' '${STORAGE_PATH}/backups' && rm -rf '${TMP_PRESERVE}'"
|
||||
print_status SUCCESS "Backups preserved at ${STORAGE_PATH}/backups"
|
||||
fi
|
||||
else
|
||||
execute_command "Removing storage and local backups" "remove_storage_dir '${STORAGE_PATH}'; remove_storage_dir '${PROJECT_DIR}/backups'"
|
||||
fi
|
||||
|
||||
# Optional system prune for project context
|
||||
execute_command "Docker system prune (dangling)" "docker system prune -af --volumes"
|
||||
print_status SUCCESS "Nuclear cleanup completed"
|
||||
}
|
||||
|
||||
show_summary() {
|
||||
local lvl="$1"
|
||||
print_status HEADER "CLEANUP SUMMARY"
|
||||
case "$lvl" in
|
||||
soft)
|
||||
echo -e "${GREEN}✅ Containers: Stopped${NC}"; echo -e "${BLUE}ℹ️ Networks/Volumes/Images: Preserved${NC}";;
|
||||
hard)
|
||||
echo -e "${GREEN}✅ Containers/Networks: Removed${NC}"; echo -e "${BLUE}ℹ️ Volumes/Images: Preserved${NC}";;
|
||||
nuclear)
|
||||
echo -e "${RED}💀 Containers/Networks/Volumes/Images: DESTROYED${NC}";;
|
||||
esac
|
||||
}
|
||||
|
||||
main(){
|
||||
print_status HEADER "ac-compose CLEANUP"
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
print_status ERROR "Docker not found"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$COMPOSE_FILE" ]; then
|
||||
print_status ERROR "Compose file not found at $COMPOSE_FILE"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$CLEANUP_LEVEL" ]; then
|
||||
usage; exit 1
|
||||
fi
|
||||
|
||||
show_resources
|
||||
|
||||
case "$CLEANUP_LEVEL" in
|
||||
soft) soft_cleanup;;
|
||||
hard) hard_cleanup;;
|
||||
nuclear) nuclear_cleanup;;
|
||||
*) usage; exit 1;;
|
||||
esac
|
||||
|
||||
show_summary "$CLEANUP_LEVEL"
|
||||
print_status SUCCESS "🧹 Cleanup completed"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
691
compose.yml
Normal file
691
compose.yml
Normal file
@@ -0,0 +1,691 @@
|
||||
name: ${COMPOSE_PROJECT_NAME:-ac-compose}
|
||||
services:
|
||||
# =====================
|
||||
# Database Layer (db)
|
||||
# =====================
|
||||
ac-mysql:
|
||||
profiles: ["db"]
|
||||
image: ${MYSQL_IMAGE:-mysql:8.0}
|
||||
container_name: ${CONTAINER_MYSQL:-ac-mysql}
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123}
|
||||
MYSQL_ROOT_HOST: '${MYSQL_ROOT_HOST:-%}'
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
|
||||
MYSQL_DATADIR: /var/lib/mysql-runtime
|
||||
MYSQL_CHARACTER_SET: ${MYSQL_CHARACTER_SET:-utf8mb4}
|
||||
MYSQL_COLLATION: ${MYSQL_COLLATION:-utf8mb4_unicode_ci}
|
||||
MYSQL_MAX_CONNECTIONS: ${MYSQL_MAX_CONNECTIONS:-1000}
|
||||
MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_INNODB_BUFFER_POOL_SIZE:-256M}
|
||||
MYSQL_INNODB_LOG_FILE_SIZE: ${MYSQL_INNODB_LOG_FILE_SIZE:-64M}
|
||||
ports:
|
||||
- "${MYSQL_EXTERNAL_PORT:-64306}:${MYSQL_PORT:-3306}"
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/mysql-data:/var/lib/mysql-persistent
|
||||
- ${HOST_BACKUP_PATH:-${STORAGE_PATH:-./storage}/backups}:/backups
|
||||
- ${HOST_ZONEINFO_PATH:-/usr/share/zoneinfo}:/usr/share/zoneinfo:ro
|
||||
tmpfs:
|
||||
- /var/lib/mysql-runtime:size=${MYSQL_RUNTIME_TMPFS_SIZE:-8G}
|
||||
command:
|
||||
- mysqld
|
||||
- --datadir=/var/lib/mysql-runtime
|
||||
- --default-authentication-plugin=mysql_native_password
|
||||
- --character-set-server=${MYSQL_CHARACTER_SET:-utf8mb4}
|
||||
- --collation-server=${MYSQL_COLLATION:-utf8mb4_unicode_ci}
|
||||
- --max_connections=${MYSQL_MAX_CONNECTIONS:-1000}
|
||||
- --innodb-buffer-pool-size=${MYSQL_INNODB_BUFFER_POOL_SIZE:-256M}
|
||||
- --innodb-log-file-size=${MYSQL_INNODB_LOG_FILE_SIZE:-64M}
|
||||
- --innodb-redo-log-capacity=${MYSQL_INNODB_REDO_LOG_CAPACITY:-512M}
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "mysqladmin ping -h localhost -u ${MYSQL_USER:-root} -p${MYSQL_ROOT_PASSWORD:-azerothcore123} --silent || exit 1"]
|
||||
interval: ${MYSQL_HEALTHCHECK_INTERVAL:-20s}
|
||||
timeout: ${MYSQL_HEALTHCHECK_TIMEOUT:-15s}
|
||||
retries: ${MYSQL_HEALTHCHECK_RETRIES:-25}
|
||||
start_period: ${MYSQL_HEALTHCHECK_START_PERIOD:-120s}
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
ac-db-import:
|
||||
profiles: ["db"]
|
||||
image: ${AC_DB_IMPORT_IMAGE:-acore/ac-wotlk-db-import:14.0.0-dev}
|
||||
container_name: ${CONTAINER_DB_IMPORT:-ac-db-import}
|
||||
user: "0:0"
|
||||
depends_on:
|
||||
ac-mysql:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- azerothcore
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc
|
||||
- ${STORAGE_PATH:-./storage}/logs:/azerothcore/logs
|
||||
- ${STORAGE_PATH:-./storage}/mysql-data:/var/lib/mysql-persistent
|
||||
- ./scripts/db-import-conditional.sh:/tmp/db-import-conditional.sh:ro
|
||||
environment:
|
||||
AC_DATA_DIR: "/azerothcore/data"
|
||||
AC_LOGS_DIR: "/azerothcore/logs"
|
||||
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}"
|
||||
AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_WORLD_NAME:-acore_world}"
|
||||
AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_CHARACTERS_NAME:-acore_characters}"
|
||||
AC_CLOSE_IDLE_CONNECTIONS: "false"
|
||||
AC_UPDATES_ENABLE_DATABASES: "7"
|
||||
AC_UPDATES_AUTO_SETUP: "1"
|
||||
CONTAINER_MYSQL: ${CONTAINER_MYSQL:-ac-mysql}
|
||||
MYSQL_PORT: ${MYSQL_PORT:-3306}
|
||||
MYSQL_USER: ${MYSQL_USER:-root}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123}
|
||||
DB_AUTH_NAME: ${DB_AUTH_NAME:-acore_auth}
|
||||
DB_WORLD_NAME: ${DB_WORLD_NAME:-acore_world}
|
||||
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME:-acore_characters}
|
||||
CONTAINER_USER: ${CONTAINER_USER:-0:0}
|
||||
entrypoint:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
chown ${CONTAINER_USER:-0:0} /azerothcore/env/dist/etc 2>/dev/null || true
|
||||
echo "📥 Using local database import script..."
|
||||
/tmp/db-import-conditional.sh
|
||||
restart: "no"
|
||||
|
||||
ac-db-init:
|
||||
profiles: ["db"]
|
||||
image: ${MYSQL_IMAGE:-mysql:8.0}
|
||||
container_name: ${CONTAINER_DB_INIT:-ac-db-init}
|
||||
depends_on:
|
||||
ac-db-import:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/mysql-data:/var/lib/mysql-persistent
|
||||
- ${HOST_BACKUP_PATH:-${STORAGE_PATH:-./storage}/backups}:/backups
|
||||
networks:
|
||||
- azerothcore
|
||||
environment:
|
||||
MYSQL_PWD: ${MYSQL_ROOT_PASSWORD:-azerothcore123}
|
||||
MYSQL_HOST: ${CONTAINER_MYSQL:-ac-mysql}
|
||||
MYSQL_USER: ${MYSQL_USER:-root}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123}
|
||||
DB_WAIT_RETRIES: ${DB_WAIT_RETRIES:-60}
|
||||
DB_WAIT_SLEEP: ${DB_WAIT_SLEEP:-10}
|
||||
DB_AUTH_NAME: ${DB_AUTH_NAME:-acore_auth}
|
||||
DB_WORLD_NAME: ${DB_WORLD_NAME:-acore_world}
|
||||
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME:-acore_characters}
|
||||
MYSQL_CHARACTER_SET: ${MYSQL_CHARACTER_SET:-utf8mb4}
|
||||
MYSQL_COLLATION: ${MYSQL_COLLATION:-utf8mb4_unicode_ci}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
if [ -f "/var/lib/mysql-persistent/.restore-completed" ]; then
|
||||
echo "✅ Databases already restored from backup - init not needed"; exit 0; fi
|
||||
if mysql -h ${MYSQL_HOST:-ac-mysql} -u${MYSQL_USER:-root} -p${MYSQL_ROOT_PASSWORD:-azerothcore123} -e "
|
||||
SELECT COUNT(*) FROM information_schema.tables WHERE table_schema IN ('${DB_AUTH_NAME:-acore_auth}', '${DB_WORLD_NAME:-acore_world}', '${DB_CHARACTERS_NAME:-acore_characters}');" -s -N 2>/dev/null | grep -q -v '^0$'; then
|
||||
echo "✅ Databases already populated - init not needed"; exit 0; fi
|
||||
echo "🔧 Creating fresh AzerothCore databases..."
|
||||
microdnf install -y curl || yum install -y curl || (apt-get update && apt-get install -y curl)
|
||||
mysql -h ${MYSQL_HOST:-ac-mysql} -u${MYSQL_USER:-root} -p${MYSQL_ROOT_PASSWORD:-azerothcore123} -e "
|
||||
CREATE DATABASE IF NOT EXISTS ${DB_AUTH_NAME:-acore_auth} DEFAULT CHARACTER SET ${MYSQL_CHARACTER_SET:-utf8mb4} COLLATE ${MYSQL_COLLATION:-utf8mb4_unicode_ci};
|
||||
CREATE DATABASE IF NOT EXISTS ${DB_WORLD_NAME:-acore_world} DEFAULT CHARACTER SET ${MYSQL_CHARACTER_SET:-utf8mb4} COLLATE ${MYSQL_COLLATION:-utf8mb4_unicode_ci};
|
||||
CREATE DATABASE IF NOT EXISTS ${DB_CHARACTERS_NAME:-acore_characters} DEFAULT CHARACTER SET ${MYSQL_CHARACTER_SET:-utf8mb4} COLLATE ${MYSQL_COLLATION:-utf8mb4_unicode_ci};
|
||||
SHOW DATABASES;" || { echo "❌ Failed to create databases"; exit 1; }
|
||||
echo "$(date): Fresh databases created - import needed" > /var/lib/mysql-persistent/.restore-failed
|
||||
echo "✅ Fresh databases created!"
|
||||
restart: "no"
|
||||
|
||||
ac-backup:
|
||||
profiles: ["db"]
|
||||
image: ${MYSQL_IMAGE:-mysql:8.0}
|
||||
container_name: ${CONTAINER_BACKUP:-ac-backup}
|
||||
depends_on:
|
||||
ac-db-import:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
MYSQL_HOST: ${CONTAINER_MYSQL:-ac-mysql}
|
||||
MYSQL_PORT: ${MYSQL_PORT:-3306}
|
||||
MYSQL_USER: ${MYSQL_USER:-root}
|
||||
MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123}
|
||||
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-3}
|
||||
BACKUP_RETENTION_HOURS: ${BACKUP_RETENTION_HOURS:-6}
|
||||
BACKUP_DAILY_TIME: ${BACKUP_DAILY_TIME:-09}
|
||||
DB_AUTH_NAME: ${DB_AUTH_NAME:-acore_auth}
|
||||
DB_WORLD_NAME: ${DB_WORLD_NAME:-acore_world}
|
||||
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME:-acore_characters}
|
||||
TZ: ${TZ:-UTC}
|
||||
volumes:
|
||||
- ${HOST_BACKUP_PATH:-${STORAGE_PATH:-./storage}/backups}:/backups
|
||||
- ./scripts:/tmp/scripts:ro
|
||||
working_dir: /tmp
|
||||
command:
|
||||
- /bin/bash
|
||||
- -c
|
||||
- |
|
||||
microdnf install -y curl || yum install -y curl || (apt-get update && apt-get install -y curl)
|
||||
echo "📥 Downloading backup scheduler script (local copy preferred if mounted)..."
|
||||
if [ -f /tmp/scripts/backup-scheduler.sh ]; then
|
||||
chmod +x /tmp/scripts/backup-scheduler.sh 2>/dev/null || true
|
||||
bash /tmp/scripts/backup-scheduler.sh
|
||||
else
|
||||
echo "No local scheduler provided"
|
||||
fi
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
# =====================
|
||||
# Client Data (client-data)
|
||||
# =====================
|
||||
ac-client-data-standard:
|
||||
profiles: ["client-data"]
|
||||
image: ${AC_CLIENT_DATA_IMAGE:-acore/ac-wotlk-client-data:14.0.0-dev}
|
||||
container_name: ac-client-data
|
||||
user: "0:0"
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/data:/azerothcore/data
|
||||
- ${STORAGE_PATH:-./storage}/cache:/cache
|
||||
- ./scripts:/tmp/scripts:ro
|
||||
working_dir: /tmp
|
||||
environment:
|
||||
- CONTAINER_USER=${CONTAINER_USER:-0:0}
|
||||
- CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
apk add --no-cache curl unzip wget bash ca-certificates p7zip aria2 jq
|
||||
elif command -v apt-get >/dev/null 2>&1; then
|
||||
apt-get update && apt-get install -y --no-install-recommends curl unzip wget bash ca-certificates p7zip-full aria2 jq && rm -rf /var/lib/apt/lists/*
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
yum install -y curl unzip wget bash ca-certificates p7zip aria2 jq
|
||||
fi
|
||||
mkdir -p /cache && chown ${CONTAINER_USER:-0:0} /cache /azerothcore/data 2>/dev/null || true
|
||||
if [ -f /tmp/scripts/download-client-data.sh ]; then
|
||||
chmod +x /tmp/scripts/download-client-data.sh 2>/dev/null || true
|
||||
bash /tmp/scripts/download-client-data.sh
|
||||
else
|
||||
echo "No local client-data script"
|
||||
fi
|
||||
restart: "no"
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
ac-client-data-playerbots:
|
||||
profiles: ["client-data-bots"]
|
||||
image: ${AC_CLIENT_DATA_IMAGE_PLAYERBOTS:-uprightbass360/azerothcore-wotlk-playerbots:client-data-Playerbot}
|
||||
container_name: ac-client-data
|
||||
user: "0:0"
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/data:/azerothcore/data
|
||||
- ${STORAGE_PATH:-./storage}/cache:/cache
|
||||
- ./scripts:/tmp/scripts:ro
|
||||
working_dir: /tmp
|
||||
environment:
|
||||
- CONTAINER_USER=${CONTAINER_USER:-0:0}
|
||||
- CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-}
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
if command -v apk >/dev/null 2>&1; then
|
||||
apk add --no-cache curl unzip wget bash ca-certificates p7zip aria2 jq
|
||||
elif command -v apt-get >/dev/null 2>&1; then
|
||||
apt-get update && apt-get install -y --no-install-recommends curl unzip wget bash ca-certificates p7zip-full aria2 jq && rm -rf /var/lib/apt/lists/*
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
yum install -y curl unzip wget bash ca-certificates p7zip aria2 jq
|
||||
fi
|
||||
mkdir -p /cache && chown ${CONTAINER_USER:-0:0} /cache /azerothcore/data 2>/dev/null || true
|
||||
if [ -f /tmp/scripts/download-client-data.sh ]; then
|
||||
chmod +x /tmp/scripts/download-client-data.sh 2>/dev/null || true
|
||||
bash /tmp/scripts/download-client-data.sh
|
||||
else
|
||||
echo "No local client-data script"
|
||||
fi
|
||||
restart: "no"
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
# =====================
|
||||
# Services - Standard (services-standard)
|
||||
# =====================
|
||||
ac-authserver-standard:
|
||||
profiles: ["services-standard"]
|
||||
image: ${AC_AUTHSERVER_IMAGE:-acore/ac-wotlk-authserver:14.0.0-dev}
|
||||
container_name: ac-authserver
|
||||
user: "${CONTAINER_USER:-0:0}"
|
||||
depends_on:
|
||||
ac-mysql:
|
||||
condition: service_healthy
|
||||
ac-db-import:
|
||||
condition: service_completed_successfully
|
||||
ac-db-init:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}"
|
||||
AC_UPDATES_ENABLE_DATABASES: "0"
|
||||
AC_BIND_IP: "0.0.0.0"
|
||||
AC_LOG_LEVEL: "1"
|
||||
AC_LOGGER_ROOT_CONFIG: "1,Console"
|
||||
AC_LOGGER_SERVER_CONFIG: "1,Console"
|
||||
AC_APPENDER_CONSOLE_CONFIG: "1,2,0"
|
||||
ports:
|
||||
- "${AUTH_EXTERNAL_PORT:-3784}:${AUTH_PORT:-3724}"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- azerothcore
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc
|
||||
cap_add: ["SYS_NICE"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "ps aux | grep '[a]uthserver' | grep -v grep || exit 1"]
|
||||
interval: ${AUTH_HEALTHCHECK_INTERVAL:-30s}
|
||||
timeout: ${AUTH_HEALTHCHECK_TIMEOUT:-10s}
|
||||
retries: ${AUTH_HEALTHCHECK_RETRIES:-3}
|
||||
start_period: ${AUTH_HEALTHCHECK_START_PERIOD:-60s}
|
||||
|
||||
ac-worldserver-standard:
|
||||
profiles: ["services-standard"]
|
||||
image: ${AC_WORLDSERVER_IMAGE:-acore/ac-wotlk-worldserver:14.0.0-dev}
|
||||
container_name: ac-worldserver
|
||||
user: "${CONTAINER_USER:-0:0}"
|
||||
stdin_open: true
|
||||
tty: true
|
||||
depends_on:
|
||||
- ac-authserver-standard
|
||||
- ac-client-data-standard
|
||||
environment:
|
||||
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}"
|
||||
AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_WORLD_NAME:-acore_world}"
|
||||
AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_CHARACTERS_NAME:-acore_characters}"
|
||||
AC_UPDATES_ENABLE_DATABASES: "0"
|
||||
AC_BIND_IP: "0.0.0.0"
|
||||
AC_DATA_DIR: "/azerothcore/data"
|
||||
AC_SOAP_PORT: "7878"
|
||||
AC_PROCESS_PRIORITY: "0"
|
||||
AC_ELUNA_ENABLED: "${AC_ELUNA_ENABLED:-1}"
|
||||
AC_ELUNA_TRACE_BACK: "${AC_ELUNA_TRACE_BACK:-1}"
|
||||
AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD:-1}"
|
||||
AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE:-1}"
|
||||
AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH:-lua_scripts}"
|
||||
AC_ELUNA_REQUIRE_PATHS: "${AC_ELUNA_REQUIRE_PATHS:-}"
|
||||
AC_ELUNA_REQUIRE_CPATHS: "${AC_ELUNA_REQUIRE_CPATHS:-}"
|
||||
AC_ELUNA_AUTO_RELOAD_INTERVAL: "${AC_ELUNA_AUTO_RELOAD_INTERVAL:-1}"
|
||||
PLAYERBOT_ENABLED: "${PLAYERBOT_ENABLED:-0}"
|
||||
PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS:-40}"
|
||||
AC_LOG_LEVEL: "2"
|
||||
ports:
|
||||
- "${WORLD_EXTERNAL_PORT:-8215}:${WORLD_PORT:-8085}"
|
||||
- "${SOAP_EXTERNAL_PORT:-7778}:${SOAP_PORT:-7878}"
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/data:/azerothcore/data
|
||||
- ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc
|
||||
- ${STORAGE_PATH:-./storage}/logs:/azerothcore/logs
|
||||
- ${STORAGE_PATH:-./storage}/modules:/azerothcore/modules
|
||||
- ${STORAGE_PATH:-./storage}/lua_scripts:/azerothcore/lua_scripts
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- azerothcore
|
||||
cap_add: ["SYS_NICE"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "ps aux | grep '[w]orldserver' | grep -v grep || exit 1"]
|
||||
interval: ${WORLD_HEALTHCHECK_INTERVAL:-30s}
|
||||
timeout: ${WORLD_HEALTHCHECK_TIMEOUT:-10s}
|
||||
retries: ${WORLD_HEALTHCHECK_RETRIES:-3}
|
||||
start_period: ${WORLD_HEALTHCHECK_START_PERIOD:-120s}
|
||||
|
||||
# =====================
|
||||
# Services - Playerbots (services-playerbots)
|
||||
# =====================
|
||||
ac-authserver-playerbots:
|
||||
profiles: ["services-playerbots"]
|
||||
image: ${AC_AUTHSERVER_IMAGE_PLAYERBOTS:-uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot}
|
||||
container_name: ac-authserver
|
||||
user: "${CONTAINER_USER:-0:0}"
|
||||
depends_on:
|
||||
ac-mysql:
|
||||
condition: service_healthy
|
||||
ac-db-import:
|
||||
condition: service_completed_successfully
|
||||
ac-db-init:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}"
|
||||
AC_UPDATES_ENABLE_DATABASES: "0"
|
||||
AC_BIND_IP: "0.0.0.0"
|
||||
AC_LOG_LEVEL: "1"
|
||||
AC_LOGGER_ROOT_CONFIG: "1,Console"
|
||||
AC_LOGGER_SERVER_CONFIG: "1,Console"
|
||||
AC_APPENDER_CONSOLE_CONFIG: "1,2,0"
|
||||
ports:
|
||||
- "${AUTH_EXTERNAL_PORT:-3784}:${AUTH_PORT:-3724}"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- azerothcore
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc
|
||||
cap_add: ["SYS_NICE"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "ps aux | grep '[a]uthserver' | grep -v grep || exit 1"]
|
||||
interval: ${AUTH_HEALTHCHECK_INTERVAL:-30s}
|
||||
timeout: ${AUTH_HEALTHCHECK_TIMEOUT:-10s}
|
||||
retries: ${AUTH_HEALTHCHECK_RETRIES:-3}
|
||||
start_period: ${AUTH_HEALTHCHECK_START_PERIOD:-60s}
|
||||
|
||||
ac-authserver-modules:
|
||||
profiles: ["services-modules"]
|
||||
image: ${AC_AUTHSERVER_IMAGE_MODULES:-acore/ac-wotlk-authserver:modules-latest}
|
||||
container_name: ac-authserver
|
||||
user: "${CONTAINER_USER:-0:0}"
|
||||
depends_on:
|
||||
ac-mysql:
|
||||
condition: service_healthy
|
||||
ac-db-import:
|
||||
condition: service_completed_successfully
|
||||
ac-db-init:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}"
|
||||
AC_UPDATES_ENABLE_DATABASES: "0"
|
||||
AC_BIND_IP: "0.0.0.0"
|
||||
AC_LOG_LEVEL: "1"
|
||||
AC_LOGGER_ROOT_CONFIG: "1,Console"
|
||||
AC_LOGGER_SERVER_CONFIG: "1,Console"
|
||||
AC_APPENDER_CONSOLE_CONFIG: "1,2,0"
|
||||
ports:
|
||||
- "${AUTH_EXTERNAL_PORT:-3784}:${AUTH_PORT:-3724}"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- azerothcore
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc
|
||||
cap_add: ["SYS_NICE"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "ps aux | grep '[a]uthserver' | grep -v grep || exit 1"]
|
||||
interval: ${AUTH_HEALTHCHECK_INTERVAL:-30s}
|
||||
timeout: ${AUTH_HEALTHCHECK_TIMEOUT:-10s}
|
||||
retries: ${AUTH_HEALTHCHECK_RETRIES:-3}
|
||||
start_period: ${AUTH_HEALTHCHECK_START_PERIOD:-60s}
|
||||
|
||||
ac-worldserver-playerbots:
|
||||
profiles: ["services-playerbots"]
|
||||
image: ${AC_WORLDSERVER_IMAGE_PLAYERBOTS:-uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot}
|
||||
container_name: ac-worldserver
|
||||
user: "${CONTAINER_USER:-0:0}"
|
||||
stdin_open: true
|
||||
tty: true
|
||||
depends_on:
|
||||
- ac-authserver-playerbots
|
||||
- ac-client-data-playerbots
|
||||
environment:
|
||||
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}"
|
||||
AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_WORLD_NAME:-acore_world}"
|
||||
AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_CHARACTERS_NAME:-acore_characters}"
|
||||
AC_UPDATES_ENABLE_DATABASES: "0"
|
||||
AC_BIND_IP: "0.0.0.0"
|
||||
AC_DATA_DIR: "/azerothcore/data"
|
||||
AC_SOAP_PORT: "7878"
|
||||
AC_PROCESS_PRIORITY: "0"
|
||||
AC_ELUNA_ENABLED: "${AC_ELUNA_ENABLED:-1}"
|
||||
AC_ELUNA_TRACE_BACK: "${AC_ELUNA_TRACE_BACK:-1}"
|
||||
AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD:-1}"
|
||||
AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE:-1}"
|
||||
AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH:-lua_scripts}"
|
||||
AC_ELUNA_REQUIRE_PATHS: "${AC_ELUNA_REQUIRE_PATHS:-}"
|
||||
AC_ELUNA_REQUIRE_CPATHS: "${AC_ELUNA_REQUIRE_CPATHS:-}"
|
||||
AC_ELUNA_AUTO_RELOAD_INTERVAL: "${AC_ELUNA_AUTO_RELOAD_INTERVAL:-1}"
|
||||
PLAYERBOT_ENABLED: "${PLAYERBOT_ENABLED:-1}"
|
||||
PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS:-40}"
|
||||
AC_LOG_LEVEL: "2"
|
||||
ports:
|
||||
- "${WORLD_EXTERNAL_PORT:-8215}:${WORLD_PORT:-8085}"
|
||||
- "${SOAP_EXTERNAL_PORT:-7778}:${SOAP_PORT:-7878}"
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/data:/azerothcore/data
|
||||
- ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc
|
||||
- ${STORAGE_PATH:-./storage}/logs:/azerothcore/logs
|
||||
- ${STORAGE_PATH:-./storage}/modules:/azerothcore/modules
|
||||
- ${STORAGE_PATH:-./storage}/lua_scripts:/azerothcore/lua_scripts
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- azerothcore
|
||||
cap_add: ["SYS_NICE"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "ps aux | grep '[w]orldserver' | grep -v grep || exit 1"]
|
||||
interval: ${WORLD_HEALTHCHECK_INTERVAL:-30s}
|
||||
timeout: ${WORLD_HEALTHCHECK_TIMEOUT:-10s}
|
||||
retries: ${WORLD_HEALTHCHECK_RETRIES:-3}
|
||||
start_period: ${WORLD_HEALTHCHECK_START_PERIOD:-120s}
|
||||
|
||||
ac-worldserver-modules:
|
||||
profiles: ["services-modules"]
|
||||
image: ${AC_WORLDSERVER_IMAGE_MODULES:-acore/ac-wotlk-worldserver:modules-latest}
|
||||
container_name: ac-worldserver
|
||||
user: "${CONTAINER_USER:-0:0}"
|
||||
stdin_open: true
|
||||
tty: true
|
||||
depends_on:
|
||||
- ac-authserver-modules
|
||||
- ac-client-data-standard
|
||||
environment:
|
||||
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_AUTH_NAME:-acore_auth}"
|
||||
AC_WORLD_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_WORLD_NAME:-acore_world}"
|
||||
AC_CHARACTER_DATABASE_INFO: "${CONTAINER_MYSQL:-ac-mysql};${MYSQL_PORT:-3306};${MYSQL_USER:-root};${MYSQL_ROOT_PASSWORD:-azerothcore123};${DB_CHARACTERS_NAME:-acore_characters}"
|
||||
AC_UPDATES_ENABLE_DATABASES: "0"
|
||||
AC_BIND_IP: "0.0.0.0"
|
||||
AC_DATA_DIR: "/azerothcore/data"
|
||||
AC_SOAP_PORT: "7878"
|
||||
AC_PROCESS_PRIORITY: "0"
|
||||
AC_ELUNA_ENABLED: "${AC_ELUNA_ENABLED:-1}"
|
||||
AC_ELUNA_TRACE_BACK: "${AC_ELUNA_TRACE_BACK:-1}"
|
||||
AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD:-1}"
|
||||
AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE:-1}"
|
||||
AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH:-lua_scripts}"
|
||||
AC_ELUNA_REQUIRE_PATHS: "${AC_ELUNA_REQUIRE_PATHS:-}"
|
||||
AC_ELUNA_REQUIRE_CPATHS: "${AC_ELUNA_REQUIRE_CPATHS:-}"
|
||||
AC_ELUNA_AUTO_RELOAD_INTERVAL: "${AC_ELUNA_AUTO_RELOAD_INTERVAL:-1}"
|
||||
PLAYERBOT_ENABLED: "${PLAYERBOT_ENABLED:-0}"
|
||||
PLAYERBOT_MAX_BOTS: "${PLAYERBOT_MAX_BOTS:-40}"
|
||||
AC_LOG_LEVEL: "2"
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/data:/azerothcore/data
|
||||
- ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc
|
||||
- ${STORAGE_PATH:-./storage}/logs:/azerothcore/logs
|
||||
- ${STORAGE_PATH:-./storage}/modules:/azerothcore/modules
|
||||
- ${STORAGE_PATH:-./storage}/lua_scripts:/azerothcore/lua_scripts
|
||||
networks:
|
||||
- azerothcore
|
||||
ports:
|
||||
- "${WORLD_EXTERNAL_PORT:-8215}:${WORLD_PORT:-8085}"
|
||||
- "${SOAP_EXTERNAL_PORT:-7778}:${SOAP_PORT:-7878}"
|
||||
restart: unless-stopped
|
||||
cap_add: ["SYS_NICE"]
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "ps aux | grep '[w]orldserver' | grep -v grep || exit 1"]
|
||||
interval: ${WORLD_HEALTHCHECK_INTERVAL:-30s}
|
||||
timeout: ${WORLD_HEALTHCHECK_TIMEOUT:-10s}
|
||||
retries: ${WORLD_HEALTHCHECK_RETRIES:-3}
|
||||
start_period: ${WORLD_HEALTHCHECK_START_PERIOD:-120s}
|
||||
|
||||
# =====================
|
||||
# Modules & Post-install (modules)
|
||||
# =====================
|
||||
ac-modules:
|
||||
profiles: ["modules"]
|
||||
image: ${ALPINE_GIT_IMAGE:-alpine/git:latest}
|
||||
container_name: ${CONTAINER_MODULES:-ac-modules}
|
||||
user: "0:0"
|
||||
depends_on:
|
||||
ac-mysql:
|
||||
condition: service_healthy
|
||||
ac-db-import:
|
||||
condition: service_completed_successfully
|
||||
ac-db-init:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/modules:/modules
|
||||
- ${STORAGE_PATH:-./storage}/config:/azerothcore/env/dist/etc
|
||||
- ./scripts:/tmp/scripts:ro
|
||||
environment:
|
||||
- MODULE_PLAYERBOTS=${MODULE_PLAYERBOTS:-0}
|
||||
- MODULE_AOE_LOOT=${MODULE_AOE_LOOT:-0}
|
||||
- MODULE_LEARN_SPELLS=${MODULE_LEARN_SPELLS:-0}
|
||||
- MODULE_FIREWORKS=${MODULE_FIREWORKS:-0}
|
||||
- MODULE_INDIVIDUAL_PROGRESSION=${MODULE_INDIVIDUAL_PROGRESSION:-0}
|
||||
- MODULE_AHBOT=${MODULE_AHBOT:-0}
|
||||
- MODULE_AUTOBALANCE=${MODULE_AUTOBALANCE:-0}
|
||||
- MODULE_TRANSMOG=${MODULE_TRANSMOG:-0}
|
||||
- MODULE_NPC_BUFFER=${MODULE_NPC_BUFFER:-0}
|
||||
- MODULE_DYNAMIC_XP=${MODULE_DYNAMIC_XP:-0}
|
||||
- MODULE_SOLO_LFG=${MODULE_SOLO_LFG:-0}
|
||||
- MODULE_1V1_ARENA=${MODULE_1V1_ARENA:-0}
|
||||
- MODULE_PHASED_DUELS=${MODULE_PHASED_DUELS:-0}
|
||||
- MODULE_BREAKING_NEWS=${MODULE_BREAKING_NEWS:-0}
|
||||
- MODULE_BOSS_ANNOUNCER=${MODULE_BOSS_ANNOUNCER:-0}
|
||||
- MODULE_ACCOUNT_ACHIEVEMENTS=${MODULE_ACCOUNT_ACHIEVEMENTS:-0}
|
||||
- MODULE_AUTO_REVIVE=${MODULE_AUTO_REVIVE:-0}
|
||||
- MODULE_GAIN_HONOR_GUARD=${MODULE_GAIN_HONOR_GUARD:-0}
|
||||
- MODULE_ELUNA=${MODULE_ELUNA:-0}
|
||||
- MODULE_ARAC=${MODULE_ARAC:-0}
|
||||
- MODULE_TIME_IS_TIME=${MODULE_TIME_IS_TIME:-0}
|
||||
- MODULE_POCKET_PORTAL=${MODULE_POCKET_PORTAL:-0}
|
||||
- MODULE_RANDOM_ENCHANTS=${MODULE_RANDOM_ENCHANTS:-0}
|
||||
- MODULE_SOLOCRAFT=${MODULE_SOLOCRAFT:-0}
|
||||
- MODULE_PVP_TITLES=${MODULE_PVP_TITLES:-0}
|
||||
- MODULE_NPC_BEASTMASTER=${MODULE_NPC_BEASTMASTER:-0}
|
||||
- MODULE_NPC_ENCHANTER=${MODULE_NPC_ENCHANTER:-0}
|
||||
- MODULE_INSTANCE_RESET=${MODULE_INSTANCE_RESET:-0}
|
||||
- MODULE_LEVEL_GRANT=${MODULE_LEVEL_GRANT:-0}
|
||||
- MODULE_ASSISTANT=${MODULE_ASSISTANT:-0}
|
||||
- MODULE_REAGENT_BANK=${MODULE_REAGENT_BANK:-0}
|
||||
- MODULE_BLACK_MARKET_AUCTION_HOUSE=${MODULE_BLACK_MARKET_AUCTION_HOUSE:-0}
|
||||
- CONTAINER_MYSQL=${CONTAINER_MYSQL:-ac-mysql}
|
||||
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-azerothcore123}
|
||||
- DB_AUTH_NAME=${DB_AUTH_NAME:-acore_auth}
|
||||
- DB_WORLD_NAME=${DB_WORLD_NAME:-acore_world}
|
||||
- DB_CHARACTERS_NAME=${DB_CHARACTERS_NAME:-acore_characters}
|
||||
- DB_PLAYERBOTS_NAME=${DB_PLAYERBOTS_NAME:-acore_playerbots}
|
||||
- MYSQL_CHARACTER_SET=${MYSQL_CHARACTER_SET:-utf8mb4}
|
||||
- MYSQL_COLLATION=${MYSQL_COLLATION:-utf8mb4_unicode_ci}
|
||||
- CONTAINER_USER=${CONTAINER_USER:-0:0}
|
||||
entrypoint: ["/bin/sh"]
|
||||
command:
|
||||
- -c
|
||||
- |
|
||||
apk add --no-cache curl bash && (chmod +x /tmp/scripts/manage-modules.sh /tmp/scripts/manage-modules-sql.sh 2>/dev/null || true) && /tmp/scripts/manage-modules.sh
|
||||
restart: "no"
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
ac-post-install:
|
||||
profiles: ["modules"]
|
||||
image: ${ALPINE_IMAGE:-alpine:latest}
|
||||
container_name: ${CONTAINER_POST_INSTALL:-ac-post-install}
|
||||
user: "0:0"
|
||||
volumes:
|
||||
- ${STORAGE_PATH:-./storage}/config:/azerothcore/config
|
||||
- ${STORAGE_PATH:-./storage}/install-markers:/install-markers
|
||||
- ./scripts:/tmp/scripts:ro
|
||||
- /var/run/docker.sock:/var/run/docker.sock:rw
|
||||
working_dir: /tmp
|
||||
environment:
|
||||
MYSQL_HOST: ${CONTAINER_MYSQL:-ac-mysql}
|
||||
MYSQL_PORT: ${MYSQL_PORT:-3306}
|
||||
MYSQL_USER: ${MYSQL_USER:-root}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123}
|
||||
DB_AUTH_NAME: ${DB_AUTH_NAME:-acore_auth}
|
||||
DB_WORLD_NAME: ${DB_WORLD_NAME:-acore_world}
|
||||
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME:-acore_characters}
|
||||
DB_PLAYERBOTS_NAME: ${DB_PLAYERBOTS_NAME:-acore_playerbots}
|
||||
MYSQL_CHARACTER_SET: ${MYSQL_CHARACTER_SET:-utf8mb4}
|
||||
MYSQL_COLLATION: ${MYSQL_COLLATION:-utf8mb4_unicode_ci}
|
||||
STORAGE_PATH: ${STORAGE_PATH:-./storage}
|
||||
SERVER_ADDRESS: ${SERVER_ADDRESS:-127.0.0.1}
|
||||
REALM_PORT: ${REALM_PORT:-8215}
|
||||
NETWORK_NAME: ${NETWORK_NAME:-azerothcore}
|
||||
CONTAINER_AUTHSERVER: ac-authserver
|
||||
CONTAINER_WORLDSERVER: ac-worldserver
|
||||
CONTAINER_USER: ${CONTAINER_USER:-0:0}
|
||||
depends_on:
|
||||
ac-modules:
|
||||
condition: service_completed_successfully
|
||||
ac-mysql:
|
||||
condition: service_healthy
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
apk add --no-cache bash curl docker-cli
|
||||
chown ${CONTAINER_USER:-0:0} /azerothcore/config /install-markers 2>/dev/null || true
|
||||
echo "📥 Running local auto-post-install script..."
|
||||
(chmod +x /tmp/scripts/auto-post-install.sh 2>/dev/null || true) && bash /tmp/scripts/auto-post-install.sh
|
||||
restart: "no"
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
# =====================
|
||||
# Tools (tools)
|
||||
# =====================
|
||||
ac-phpmyadmin:
|
||||
profiles: ["tools"]
|
||||
image: phpmyadmin/phpmyadmin:latest
|
||||
container_name: ac-phpmyadmin
|
||||
environment:
|
||||
PMA_HOST: ${PMA_HOST:-ac-mysql}
|
||||
PMA_PORT: ${PMA_PORT:-3306}
|
||||
PMA_USER: ${PMA_USER:-root}
|
||||
PMA_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123}
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-azerothcore123}
|
||||
PMA_ARBITRARY: ${PMA_ARBITRARY:-1}
|
||||
PMA_ABSOLUTE_URI: ${PMA_ABSOLUTE_URI:-}
|
||||
UPLOAD_LIMIT: ${PMA_UPLOAD_LIMIT:-300M}
|
||||
MEMORY_LIMIT: ${PMA_MEMORY_LIMIT:-512M}
|
||||
MAX_EXECUTION_TIME: ${PMA_MAX_EXECUTION_TIME:-600}
|
||||
ports:
|
||||
- "${PMA_EXTERNAL_PORT:-8081}:80"
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "curl -fsS http://localhost:80/ || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
ac-keira3:
|
||||
profiles: ["tools"]
|
||||
image: uprightbass360/keira3:latest
|
||||
container_name: ac-keira3
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- KEIRA_PORT=8080
|
||||
- KEIRA_HOST=0.0.0.0
|
||||
- KEIRA_DATABASE_HOST=${KEIRA_DATABASE_HOST:-ac-mysql}
|
||||
- KEIRA_DATABASE_PORT=${KEIRA_DATABASE_PORT:-3306}
|
||||
- KEIRA_DATABASE_USER=root
|
||||
- KEIRA_DATABASE_PASSWORD=${MYSQL_ROOT_PASSWORD:-azerothcore123}
|
||||
- KEIRA_DATABASE_NAME=${DB_WORLD_NAME:-acore_world}
|
||||
ports:
|
||||
- "${KEIRA3_EXTERNAL_PORT:-4201}:8080"
|
||||
healthcheck:
|
||||
test: ["CMD", "sh", "-c", "curl -f http://localhost:8080/health || nc -z localhost 8080 || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
networks:
|
||||
- azerothcore
|
||||
|
||||
networks:
|
||||
azerothcore:
|
||||
name: ${NETWORK_NAME:-azerothcore}
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: ${NETWORK_SUBNET:-172.20.0.0/16}
|
||||
gateway: ${NETWORK_GATEWAY:-172.20.0.1}
|
||||
361
deploy.sh
Executable file
361
deploy.sh
Executable file
@@ -0,0 +1,361 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# High-level orchestrator for module-aware deployments.
|
||||
# 1. Ensures AzerothCore source repo is present
|
||||
# 2. Runs ac-modules to sync/clean module checkout and configs
|
||||
# 3. Rebuilds source images when C++ modules demand it
|
||||
# 4. Stages target compose profile and optionally tails worldserver logs
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
COMPOSE_FILE="$ROOT_DIR/compose.yml"
|
||||
ENV_PATH="$ROOT_DIR/.env"
|
||||
TARGET_PROFILE=""
|
||||
WATCH_LOGS=1
|
||||
KEEP_RUNNING=0
|
||||
SKIP_REBUILD=0
|
||||
WORLD_LOG_SINCE=""
|
||||
|
||||
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}"; }
|
||||
ok(){ printf '%b\n' "${GREEN}✅ $*${NC}"; }
|
||||
warn(){ printf '%b\n' "${YELLOW}⚠️ $*${NC}"; }
|
||||
err(){ printf '%b\n' "${RED}❌ $*${NC}"; }
|
||||
|
||||
show_deployment_header(){
|
||||
printf '\n%b\n' "${BLUE}⚔️ AZEROTHCORE REALM DEPLOYMENT ⚔️${NC}"
|
||||
printf '%b\n' "${BLUE}════════════════════════════════════════${NC}"
|
||||
printf '%b\n\n' "${BLUE}🏰 Bringing Your Realm Online 🏰${NC}"
|
||||
}
|
||||
|
||||
show_step(){
|
||||
local step="$1" total="$2" message="$3"
|
||||
printf '%b\n' "${YELLOW}🔧 Step ${step}/${total}: ${message}...${NC}"
|
||||
}
|
||||
|
||||
show_realm_ready(){
|
||||
printf '\n%b\n' "${GREEN}⚔️ The realm has been forged! ⚔️${NC}"
|
||||
printf '%b\n' "${GREEN}🏰 Adventurers may now enter your world${NC}"
|
||||
printf '%b\n\n' "${GREEN}🗡️ May your server bring epic adventures!${NC}"
|
||||
}
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [options]
|
||||
|
||||
Options:
|
||||
--profile {standard|playerbots|modules} Force target profile (default: auto-detect)
|
||||
--no-watch Do not tail worldserver logs after staging
|
||||
--keep-running Do not pre-stop runtime stack before rebuild
|
||||
--skip-rebuild Skip source rebuild even if modules require it
|
||||
-h, --help Show this help
|
||||
|
||||
This command automates the module workflow (sync modules, rebuild source if needed,
|
||||
stage the correct compose profile, and optionally watch worldserver logs).
|
||||
EOF
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--profile) TARGET_PROFILE="$2"; shift 2;;
|
||||
--no-watch) WATCH_LOGS=0; shift;;
|
||||
--keep-running) KEEP_RUNNING=1; shift;;
|
||||
--skip-rebuild) SKIP_REBUILD=1; shift;;
|
||||
-h|--help) usage; exit 0;;
|
||||
*) err "Unknown option: $1"; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
require_cmd(){
|
||||
command -v "$1" >/dev/null 2>&1 || { err "Missing required command: $1"; exit 1; }
|
||||
}
|
||||
|
||||
require_cmd docker
|
||||
|
||||
read_env(){
|
||||
local key="$1" default="${2:-}"
|
||||
local value=""
|
||||
if [ -f "$ENV_PATH" ]; then
|
||||
value="$(grep -E "^${key}=" "$ENV_PATH" | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||
fi
|
||||
if [ -z "$value" ]; then
|
||||
value="$default"
|
||||
fi
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
resolve_project_name(){
|
||||
local raw_name="$(read_env COMPOSE_PROJECT_NAME "acore-compose")"
|
||||
local sanitized
|
||||
sanitized="$(echo "$raw_name" | tr '[:upper:]' '[:lower:]')"
|
||||
sanitized="${sanitized// /-}"
|
||||
sanitized="$(echo "$sanitized" | tr -cd 'a-z0-9_-')"
|
||||
if [[ -z "$sanitized" ]]; then
|
||||
sanitized="acore-compose"
|
||||
elif [[ ! "$sanitized" =~ ^[a-z0-9] ]]; then
|
||||
sanitized="ac${sanitized}"
|
||||
fi
|
||||
echo "$sanitized"
|
||||
}
|
||||
|
||||
compose(){
|
||||
local project_name
|
||||
project_name="$(resolve_project_name)"
|
||||
docker compose --project-name "$project_name" -f "$COMPOSE_FILE" "$@"
|
||||
}
|
||||
|
||||
ensure_source_repo(){
|
||||
local src_path
|
||||
src_path="$(read_env MODULES_REBUILD_SOURCE_PATH "./source/azerothcore")"
|
||||
if [[ "$src_path" != /* ]]; then
|
||||
src_path="$ROOT_DIR/$src_path"
|
||||
fi
|
||||
if [ -d "$src_path/.git" ]; then
|
||||
echo "$src_path"
|
||||
return
|
||||
fi
|
||||
warn "AzerothCore source not found at $src_path; running setup-source.sh"
|
||||
(cd "$ROOT_DIR" && ./scripts/setup-source.sh)
|
||||
echo "$src_path"
|
||||
}
|
||||
|
||||
stop_runtime_stack(){
|
||||
info "Stopping runtime stack to avoid container name conflicts"
|
||||
compose \
|
||||
--profile services-standard \
|
||||
--profile services-playerbots \
|
||||
--profile services-modules \
|
||||
--profile db \
|
||||
--profile client-data \
|
||||
--profile client-data-bots \
|
||||
--profile modules \
|
||||
down 2>/dev/null || true
|
||||
}
|
||||
|
||||
sync_modules(){
|
||||
info "Synchronising modules (ac-modules)"
|
||||
compose --profile db --profile modules up ac-modules
|
||||
compose --profile db --profile modules down >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
modules_need_rebuild(){
|
||||
local storage_path
|
||||
storage_path="$(read_env STORAGE_PATH "./storage")"
|
||||
if [[ "$storage_path" != /* ]]; then
|
||||
storage_path="$ROOT_DIR/$storage_path"
|
||||
fi
|
||||
local sentinel="$storage_path/modules/.requires_rebuild"
|
||||
[[ -f "$sentinel" ]]
|
||||
}
|
||||
|
||||
determine_profile(){
|
||||
if [ -n "$TARGET_PROFILE" ]; then
|
||||
echo "$TARGET_PROFILE"
|
||||
return
|
||||
fi
|
||||
|
||||
local module_playerbots
|
||||
local playerbot_enabled
|
||||
module_playerbots="$(read_env MODULE_PLAYERBOTS "0")"
|
||||
playerbot_enabled="$(read_env PLAYERBOT_ENABLED "0")"
|
||||
if [ "$module_playerbots" = "1" ] || [ "$playerbot_enabled" = "1" ]; then
|
||||
echo "playerbots"
|
||||
return
|
||||
fi
|
||||
|
||||
local compile_vars=(
|
||||
MODULE_AOE_LOOT
|
||||
MODULE_LEARN_SPELLS
|
||||
MODULE_FIREWORKS
|
||||
MODULE_INDIVIDUAL_PROGRESSION
|
||||
MODULE_AHBOT
|
||||
MODULE_AUTOBALANCE
|
||||
MODULE_TRANSMOG
|
||||
MODULE_NPC_BUFFER
|
||||
MODULE_DYNAMIC_XP
|
||||
MODULE_SOLO_LFG
|
||||
MODULE_1V1_ARENA
|
||||
MODULE_PHASED_DUELS
|
||||
MODULE_BREAKING_NEWS
|
||||
MODULE_BOSS_ANNOUNCER
|
||||
MODULE_ACCOUNT_ACHIEVEMENTS
|
||||
MODULE_AUTO_REVIVE
|
||||
MODULE_GAIN_HONOR_GUARD
|
||||
MODULE_TIME_IS_TIME
|
||||
MODULE_POCKET_PORTAL
|
||||
MODULE_RANDOM_ENCHANTS
|
||||
MODULE_SOLOCRAFT
|
||||
MODULE_PVP_TITLES
|
||||
MODULE_NPC_BEASTMASTER
|
||||
MODULE_NPC_ENCHANTER
|
||||
MODULE_INSTANCE_RESET
|
||||
MODULE_LEVEL_GRANT
|
||||
)
|
||||
|
||||
local var
|
||||
for var in "${compile_vars[@]}"; do
|
||||
if [ "$(read_env "$var" "0")" = "1" ]; then
|
||||
echo "modules"
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
echo "standard"
|
||||
}
|
||||
|
||||
rebuild_source(){
|
||||
local src_dir="$1"
|
||||
local compose_file="$src_dir/docker-compose.yml"
|
||||
if [ ! -f "$compose_file" ]; then
|
||||
warn "Source docker-compose.yml missing at $compose_file; running setup-source.sh"
|
||||
(cd "$ROOT_DIR" && ./scripts/setup-source.sh)
|
||||
fi
|
||||
if [ ! -f "$compose_file" ]; then
|
||||
err "Source docker-compose.yml missing at $compose_file"
|
||||
return 1
|
||||
fi
|
||||
info "Rebuilding AzerothCore source with modules (this may take a while)"
|
||||
docker compose -f "$compose_file" down --remove-orphans >/dev/null 2>&1 || true
|
||||
if (cd "$ROOT_DIR" && ./scripts/rebuild-with-modules.sh --yes); then
|
||||
ok "Source rebuild completed"
|
||||
else
|
||||
err "Source rebuild failed"
|
||||
return 1
|
||||
fi
|
||||
docker compose -f "$compose_file" down --remove-orphans >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
tag_module_images(){
|
||||
local source_world="acore/ac-wotlk-worldserver:master"
|
||||
local source_auth="acore/ac-wotlk-authserver:master"
|
||||
local target_world
|
||||
local target_auth
|
||||
target_world="$(read_env AC_WORLDSERVER_IMAGE_MODULES "acore/ac-wotlk-worldserver:modules-latest")"
|
||||
target_auth="$(read_env AC_AUTHSERVER_IMAGE_MODULES "acore/ac-wotlk-authserver:modules-latest")"
|
||||
|
||||
if docker image inspect "$source_world" >/dev/null 2>&1; then
|
||||
docker tag "$source_world" "$target_world"
|
||||
ok "Tagged $target_world from $source_world"
|
||||
else
|
||||
warn "Source image $source_world not found; skipping tag"
|
||||
fi
|
||||
|
||||
if docker image inspect "$source_auth" >/dev/null 2>&1; then
|
||||
docker tag "$source_auth" "$target_auth"
|
||||
ok "Tagged $target_auth from $source_auth"
|
||||
else
|
||||
warn "Source image $source_auth not found; skipping tag"
|
||||
fi
|
||||
}
|
||||
|
||||
stage_runtime(){
|
||||
local args=(--yes)
|
||||
if [ -n "$TARGET_PROFILE" ]; then
|
||||
args+=("$TARGET_PROFILE")
|
||||
fi
|
||||
info "Staging runtime environment via stage-modules.sh ${args[*]}"
|
||||
(cd "$ROOT_DIR" && ./scripts/stage-modules.sh "${args[@]}")
|
||||
}
|
||||
|
||||
tail_world_logs(){
|
||||
info "Tailing worldserver logs (Ctrl+C to stop)"
|
||||
local args=(--follow)
|
||||
if [ -n "$WORLD_LOG_SINCE" ]; then
|
||||
args+=(--since "$WORLD_LOG_SINCE")
|
||||
fi
|
||||
local tail_opt="${WORLD_LOG_TAIL:-0}"
|
||||
args+=(--tail "$tail_opt")
|
||||
if ! docker logs "${args[@]}" ac-worldserver; then
|
||||
warn "Worldserver logs unavailable; container may not be running."
|
||||
fi
|
||||
}
|
||||
|
||||
wait_for_worldserver_ready(){
|
||||
local timeout="${WORLD_READY_TIMEOUT:-180}" start
|
||||
start="$(date +%s)"
|
||||
info "Waiting for worldserver to become healthy (timeout: ${timeout}s)"
|
||||
while true; do
|
||||
if ! docker ps --format '{{.Names}}' | grep -qx "ac-worldserver"; then
|
||||
info "Worldserver container is not running yet; retrying..."
|
||||
else
|
||||
local health
|
||||
health="$(docker inspect --format='{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' ac-worldserver 2>/dev/null || echo none)"
|
||||
case "$health" in
|
||||
healthy)
|
||||
WORLD_LOG_SINCE="$(docker inspect --format='{{.State.StartedAt}}' ac-worldserver 2>/dev/null)"
|
||||
ok "Worldserver reported healthy"
|
||||
return 0
|
||||
;;
|
||||
none)
|
||||
if docker inspect --format='{{.State.Status}}' ac-worldserver 2>/dev/null | grep -q '^running$'; then
|
||||
WORLD_LOG_SINCE="$(docker inspect --format='{{.State.StartedAt}}' ac-worldserver 2>/dev/null)"
|
||||
ok "Worldserver running (no healthcheck configured)"
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
unhealthy)
|
||||
warn "Worldserver healthcheck reports unhealthy; logs recommended"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [ $(( $(date +%s) - start )) -ge "$timeout" ]; then
|
||||
warn "Timed out waiting for worldserver health"
|
||||
return 1
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
}
|
||||
|
||||
main(){
|
||||
show_deployment_header
|
||||
|
||||
local src_dir
|
||||
local resolved_profile
|
||||
show_step 1 5 "Setting up source repository"
|
||||
src_dir="$(ensure_source_repo)"
|
||||
|
||||
resolved_profile="$(determine_profile)"
|
||||
|
||||
if [ "$KEEP_RUNNING" -ne 1 ]; then
|
||||
show_step 2 5 "Stopping runtime stack"
|
||||
stop_runtime_stack
|
||||
fi
|
||||
|
||||
show_step 3 5 "Syncing modules"
|
||||
sync_modules
|
||||
|
||||
if modules_need_rebuild; then
|
||||
if [ "$SKIP_REBUILD" -eq 1 ]; then
|
||||
warn "Modules require rebuild, but --skip-rebuild was provided."
|
||||
else
|
||||
show_step 4 5 "Building realm with modules (this may take 15-45 minutes)"
|
||||
rebuild_source "$src_dir"
|
||||
fi
|
||||
else
|
||||
info "No module rebuild required."
|
||||
fi
|
||||
|
||||
if [ "$resolved_profile" = "modules" ]; then
|
||||
tag_module_images
|
||||
fi
|
||||
|
||||
show_step 5 5 "Bringing your realm online"
|
||||
stage_runtime
|
||||
|
||||
show_realm_ready
|
||||
|
||||
if [ "$WATCH_LOGS" -eq 1 ]; then
|
||||
if wait_for_worldserver_ready; then
|
||||
info "Watching your realm come to life (Ctrl+C to stop watching)"
|
||||
tail_world_logs
|
||||
else
|
||||
warn "Skipping log tail; worldserver not healthy. Use './status.sh --once' or 'docker logs ac-worldserver'."
|
||||
fi
|
||||
else
|
||||
ok "Realm deployment completed. Use './status.sh' to monitor your realm."
|
||||
fi
|
||||
}
|
||||
|
||||
main
|
||||
@@ -1,190 +0,0 @@
|
||||
# ==============================================
|
||||
# AZEROTHCORE SERVICES ENVIRONMENT
|
||||
# ==============================================
|
||||
# Environment variables for auth server, world server, client data, modules, and optional services
|
||||
|
||||
# ==============================================
|
||||
# DEPLOYMENT CONFIGURATION
|
||||
# ==============================================
|
||||
# Storage root path - local: ./storage, production: /nfs/azerothcore or custom mount
|
||||
STORAGE_ROOT=/nfs/azerothcore
|
||||
# Storage configuration (must match database layer)
|
||||
STORAGE_PATH=${STORAGE_ROOT}
|
||||
|
||||
# ==============================================
|
||||
# USER MAPPING CONFIGURATION (for NFS compatibility)
|
||||
# ==============================================
|
||||
# User and group IDs for container processes (PUID/PGID pattern)
|
||||
# Set these to match your NFS server's user mapping
|
||||
# Default: 1001:1000 (matches 'sharing' user on most systems)
|
||||
PUID=1001
|
||||
PGID=1000
|
||||
SHARING_USER=${PUID}:${PGID}
|
||||
# Legacy compatibility
|
||||
CONTAINER_USER_ID=${PUID}
|
||||
CONTAINER_GROUP_ID=${PGID}
|
||||
CONTAINER_USER=${CONTAINER_USER_ID}:${CONTAINER_GROUP_ID}
|
||||
|
||||
# ==============================================
|
||||
# NETWORK CONFIGURATION
|
||||
# ==============================================
|
||||
# External ports for game services
|
||||
AUTH_EXTERNAL_PORT=3784
|
||||
WORLD_EXTERNAL_PORT=8215
|
||||
SOAP_EXTERNAL_PORT=7778
|
||||
|
||||
# Server address for client connections (production)
|
||||
# SERVER_ADDRESS=192.168.0.188
|
||||
# Server address for client connections (local)
|
||||
SERVER_ADDRESS=192.168.0.188
|
||||
# Use WORLD_EXTERNAL_PORT for realmlist (client connection port)
|
||||
REALM_PORT=8215
|
||||
|
||||
# Internal ports (container side)
|
||||
AUTH_PORT=3724
|
||||
WORLD_PORT=8085
|
||||
SOAP_PORT=7878
|
||||
|
||||
# ==============================================
|
||||
# DATABASE CONNECTION
|
||||
# ==============================================
|
||||
# Connect to database layer (must match database layer settings)
|
||||
MYSQL_HOST=ac-mysql
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_USER=root
|
||||
MYSQL_ROOT_PASSWORD=azerothcore123
|
||||
|
||||
# Database names (must match database layer)
|
||||
DB_AUTH_NAME=acore_auth
|
||||
DB_WORLD_NAME=acore_world
|
||||
DB_CHARACTERS_NAME=acore_characters
|
||||
|
||||
# ==============================================
|
||||
# DOCKER IMAGES
|
||||
# ==============================================
|
||||
# Core service images - TO ENABLE PLAYERBOTS: swap _PLAYERBOTS with standard images
|
||||
# STANDARD IMAGES (currently active):
|
||||
AC_AUTHSERVER_IMAGE=uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot
|
||||
AC_WORLDSERVER_IMAGE=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot
|
||||
# PLAYERBOTS IMAGES (to enable, swap with lines above):
|
||||
AC_AUTHSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot
|
||||
AC_WORLDSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot
|
||||
ALPINE_IMAGE=alpine:latest
|
||||
|
||||
# Optional service images (from combined optional layer)
|
||||
AC_ELUNA_IMAGE=acore/eluna-ts:master
|
||||
ALPINE_GIT_IMAGE=alpine/git:latest
|
||||
|
||||
# mod-playerbots compatible client data image
|
||||
AC_CLIENT_DATA_IMAGE_DISABLED=uprightbass360/azerothcore-wotlk-playerbots:client-data-Playerbot
|
||||
AC_CLIENT_DATA_IMAGE=alpine:latest
|
||||
|
||||
# ==============================================
|
||||
# IMAGE PULL POLICY
|
||||
# ==============================================
|
||||
IMAGE_PULL_POLICY=if_not_present
|
||||
|
||||
# ==============================================
|
||||
# CONTAINER HEALTH CHECKS
|
||||
# ==============================================
|
||||
# Auth server health check
|
||||
AUTH_HEALTHCHECK_INTERVAL=30s
|
||||
AUTH_HEALTHCHECK_TIMEOUT=10s
|
||||
AUTH_HEALTHCHECK_RETRIES=3
|
||||
AUTH_HEALTHCHECK_START_PERIOD=60s
|
||||
|
||||
# World server health check
|
||||
WORLD_HEALTHCHECK_INTERVAL=30s
|
||||
WORLD_HEALTHCHECK_TIMEOUT=10s
|
||||
WORLD_HEALTHCHECK_RETRIES=3
|
||||
WORLD_HEALTHCHECK_START_PERIOD=120s
|
||||
|
||||
# ==============================================
|
||||
# CONTAINER NAMES
|
||||
# ==============================================
|
||||
# Core service container names
|
||||
CONTAINER_AUTHSERVER=ac-authserver
|
||||
CONTAINER_WORLDSERVER=ac-worldserver
|
||||
CONTAINER_CLIENT_DATA=ac-client-data
|
||||
|
||||
# Database container name (for external linking)
|
||||
CONTAINER_MYSQL=ac-mysql
|
||||
|
||||
# ==============================================
|
||||
# NETWORK SETTINGS
|
||||
# ==============================================
|
||||
# Network must already exist from database layer
|
||||
NETWORK_NAME=azerothcore
|
||||
|
||||
# ==============================================
|
||||
# CUSTOM MODULE SETTINGS
|
||||
# ==============================================
|
||||
|
||||
# Playerbot settings
|
||||
PLAYERBOT_ENABLED=1
|
||||
PLAYERBOT_MAX_BOTS=40
|
||||
|
||||
# Module configuration - ENABLED MODULES
|
||||
# Selected modules for enhanced gameplay experience
|
||||
#
|
||||
# TO ENABLE PLAYERBOTS:
|
||||
# 1. Change MODULE_PLAYERBOTS=1
|
||||
# 2. Swap the image lines below (move _PLAYERBOTS to active, move standard to _STANDARD)
|
||||
# 3. Redeploy services: docker compose -f docker-compose-azerothcore-services.yml up -d
|
||||
# 4. No rebuild required - uses pre-built playerbots images!
|
||||
MODULE_PLAYERBOTS=1
|
||||
MODULE_AOE_LOOT=0
|
||||
MODULE_LEARN_SPELLS=0
|
||||
MODULE_FIREWORKS=0
|
||||
MODULE_INDIVIDUAL_PROGRESSION=0
|
||||
|
||||
# Quality of Life Modules
|
||||
# NOTE: mod-ahbot has linking issues - undefined reference to 'Addmod_ahbotScripts()'
|
||||
MODULE_AHBOT=0
|
||||
MODULE_AUTOBALANCE=0
|
||||
MODULE_TRANSMOG=0
|
||||
MODULE_NPC_BUFFER=0
|
||||
|
||||
# Gameplay Enhancement Modules
|
||||
MODULE_DYNAMIC_XP=0
|
||||
MODULE_SOLO_LFG=0
|
||||
MODULE_1V1_ARENA=0
|
||||
MODULE_PHASED_DUELS=0
|
||||
|
||||
# Server Management Modules
|
||||
MODULE_BREAKING_NEWS=0
|
||||
MODULE_BOSS_ANNOUNCER=0
|
||||
MODULE_ACCOUNT_ACHIEVEMENTS=0
|
||||
|
||||
# Additional Modules Found in Config
|
||||
MODULE_AUTO_REVIVE=0
|
||||
MODULE_GAIN_HONOR_GUARD=0
|
||||
MODULE_ELUNA=0
|
||||
MODULE_ARAC=0
|
||||
MODULE_TIME_IS_TIME=0
|
||||
MODULE_POCKET_PORTAL=0
|
||||
MODULE_RANDOM_ENCHANTS=0
|
||||
MODULE_SOLOCRAFT=0
|
||||
MODULE_PVP_TITLES=0
|
||||
MODULE_NPC_BEASTMASTER=0
|
||||
MODULE_NPC_ENCHANTER=0
|
||||
MODULE_INSTANCE_RESET=0
|
||||
MODULE_LEVEL_GRANT=0
|
||||
MODULE_ASSISTANT=0
|
||||
MODULE_REAGENT_BANK=0
|
||||
MODULE_BLACK_MARKET_AUCTION_HOUSE=0
|
||||
|
||||
# ==============================================
|
||||
# ADDITIONAL CONTAINER NAMES
|
||||
# ==============================================
|
||||
# Optional service container names
|
||||
CONTAINER_ELUNA=ac-eluna
|
||||
CONTAINER_MODULES=ac-modules
|
||||
CONTAINER_POST_INSTALL=ac-post-install
|
||||
|
||||
# ==============================================
|
||||
# MODULE MANAGEMENT
|
||||
# ==============================================
|
||||
GIT_USERNAME=
|
||||
GIT_EMAIL=
|
||||
GIT_PAT=
|
||||
55
export-user-backup.sh
Executable file
55
export-user-backup.sh
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
# Export auth and character databases to ExportBackup_<timestamp>/
|
||||
set -euo pipefail
|
||||
|
||||
MYSQL_PW="${MYSQL_ROOT_PASSWORD:-azerothcore123}"
|
||||
DB_AUTH="${DB_AUTH_NAME:-acore_auth}"
|
||||
DB_CHAR="${DB_CHARACTERS_NAME:-acore_characters}"
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
Usage: ./export-user-backup.sh [output_dir]
|
||||
|
||||
Creates a timestamped backup of the auth and character databases.
|
||||
If output_dir is provided, places the timestamped folder inside it
|
||||
(default: .).
|
||||
|
||||
Outputs:
|
||||
ExportBackup_YYYYMMDD_HHMMSS/
|
||||
acore_auth.sql.gz
|
||||
acore_characters.sql.gz
|
||||
manifest.json
|
||||
|
||||
Services stay online; backup uses mysqldump.
|
||||
EOF
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
-h|--help) usage; exit 0;;
|
||||
esac
|
||||
|
||||
DEST_PARENT="${1:-.}"
|
||||
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
|
||||
DEST_DIR="${DEST_PARENT%/}/ExportBackup_${TIMESTAMP}"
|
||||
mkdir -p "$DEST_DIR"
|
||||
|
||||
dump_db(){
|
||||
local db="$1" outfile="$2"
|
||||
echo "Dumping $db -> $outfile"
|
||||
docker exec ac-mysql mysqldump -uroot -p"$MYSQL_PW" "$db" | gzip > "$outfile"
|
||||
}
|
||||
|
||||
dump_db "$DB_AUTH" "$DEST_DIR/acore_auth.sql.gz"
|
||||
dump_db "$DB_CHAR" "$DEST_DIR/acore_characters.sql.gz"
|
||||
|
||||
cat > "$DEST_DIR/manifest.json" <<JSON
|
||||
{
|
||||
"generated_at": "$(date --iso-8601=seconds)",
|
||||
"databases": {
|
||||
"auth": "$DB_AUTH",
|
||||
"characters": "$DB_CHAR"
|
||||
}
|
||||
}
|
||||
JSON
|
||||
|
||||
echo "Backups saved under $DEST_DIR"
|
||||
125
import-user-backup.sh
Executable file
125
import-user-backup.sh
Executable file
@@ -0,0 +1,125 @@
|
||||
#!/bin/bash
|
||||
# Restore auth and character databases from ImportBackup/ and verify service health.
|
||||
set -euo pipefail
|
||||
|
||||
BACKUP_DIR="${1:-ImportBackup}"
|
||||
MYSQL_PW="${MYSQL_ROOT_PASSWORD:-azerothcore123}"
|
||||
DB_AUTH="${DB_AUTH_NAME:-acore_auth}"
|
||||
DB_CHAR="${DB_CHARACTERS_NAME:-acore_characters}"
|
||||
DB_WORLD="${DB_WORLD_NAME:-acore_world}"
|
||||
|
||||
COLOR_RED='\033[0;31m'
|
||||
COLOR_GREEN='\033[0;32m'
|
||||
COLOR_YELLOW='\033[1;33m'
|
||||
COLOR_RESET='\033[0m'
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
Usage: ./import-user-backup.sh [backup_dir]
|
||||
|
||||
Restores user accounts and characters from a backup folder.
|
||||
|
||||
Default backup directory: ImportBackup/
|
||||
Required files:
|
||||
acore_auth.sql or acore_auth.sql.gz
|
||||
acore_characters.sql or acore_characters.sql.gz
|
||||
Optional file (will prompt):
|
||||
acore_world.sql or acore_world.sql.gz
|
||||
|
||||
Steps performed:
|
||||
1. Stop world/auth services
|
||||
2. Back up current auth/character DBs to manual-backups/
|
||||
3. Import provided dumps
|
||||
4. Re-run module SQL to restore customizations
|
||||
5. Restart services and show status summary
|
||||
EOF
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
-h|--help) usage; exit 0;;
|
||||
esac
|
||||
|
||||
log(){ printf '%b\n' "${COLOR_GREEN}$*${COLOR_RESET}"; }
|
||||
warn(){ printf '%b\n' "${COLOR_YELLOW}$*${COLOR_RESET}"; }
|
||||
err(){ printf '%b\n' "${COLOR_RED}$*${COLOR_RESET}"; }
|
||||
|
||||
require_file(){
|
||||
local file="$1"
|
||||
[[ -f "$file" ]] || { err "Missing required backup file: $file"; exit 1; }
|
||||
}
|
||||
|
||||
if [[ ! -d "$BACKUP_DIR" ]]; then
|
||||
err "Backup directory not found: $BACKUP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
AUTH_DUMP=$(find "$BACKUP_DIR" -maxdepth 1 -name 'acore_auth.sql*' | head -n1 || true)
|
||||
CHAR_DUMP=$(find "$BACKUP_DIR" -maxdepth 1 -name 'acore_characters.sql*' | head -n1 || true)
|
||||
WORLD_DUMP=$(find "$BACKUP_DIR" -maxdepth 1 -name 'acore_world.sql*' | head -n1 || true)
|
||||
|
||||
require_file "$AUTH_DUMP"
|
||||
require_file "$CHAR_DUMP"
|
||||
|
||||
timestamp(){ date +%Y%m%d_%H%M%S; }
|
||||
|
||||
backup_db(){
|
||||
local db="$1"
|
||||
local out="manual-backups/${db}-pre-import-$(timestamp).sql"
|
||||
mkdir -p manual-backups
|
||||
log "Backing up current $db to $out"
|
||||
docker exec ac-mysql mysqldump -uroot -p"$MYSQL_PW" "$db" > "$out"
|
||||
}
|
||||
|
||||
restore(){
|
||||
local db="$1"
|
||||
local dump="$2"
|
||||
log "Importing $dump into $db"
|
||||
case "$dump" in
|
||||
*.gz) gzip -dc "$dump" ;;
|
||||
*.sql) cat "$dump" ;;
|
||||
*) err "Unsupported dump format: $dump"; exit 1;;
|
||||
esac | docker exec -i ac-mysql mysql -uroot -p"$MYSQL_PW" "$db"
|
||||
}
|
||||
|
||||
log "Stopping world/auth services"
|
||||
docker stop ac-worldserver ac-authserver >/dev/null || warn "Services already stopped"
|
||||
|
||||
backup_db "$DB_AUTH"
|
||||
restore "$DB_AUTH" "$AUTH_DUMP"
|
||||
|
||||
backup_db "$DB_CHAR"
|
||||
restore "$DB_CHAR" "$CHAR_DUMP"
|
||||
|
||||
if [[ -n "$WORLD_DUMP" ]]; then
|
||||
read -rp "World dump detected (${WORLD_DUMP##*/}). Restore it as well? [y/N]: " ANSWER
|
||||
if [[ "$ANSWER" =~ ^[Yy]$ ]]; then
|
||||
backup_db "$DB_WORLD"
|
||||
restore "$DB_WORLD" "$WORLD_DUMP"
|
||||
else
|
||||
warn "Skipping world database restore"
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Reapplying module SQL patches"
|
||||
docker compose --profile db --profile modules run --rm \
|
||||
--entrypoint /bin/sh ac-modules \
|
||||
-c 'apk add --no-cache bash curl >/dev/null && bash /tmp/scripts/manage-modules.sh >/tmp/mm.log && cat /tmp/mm.log' || warn "Module SQL run exited with non-zero status"
|
||||
|
||||
log "Restarting services"
|
||||
docker start ac-authserver ac-worldserver >/dev/null
|
||||
|
||||
sleep 5
|
||||
|
||||
count_rows(){
|
||||
docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -N -B -e "$1"
|
||||
}
|
||||
|
||||
ACCOUNTS=$(count_rows "SELECT COUNT(*) FROM ${DB_AUTH}.account;")
|
||||
CHARS=$(count_rows "SELECT COUNT(*) FROM ${DB_CHAR}.characters;")
|
||||
|
||||
log "Accounts: $ACCOUNTS"
|
||||
log "Characters: $CHARS"
|
||||
|
||||
./status.sh --once || warn "status.sh reported issues; inspect manually."
|
||||
|
||||
log "Import completed."
|
||||
550
manual-backups/acore_auth-pre-import-20251019_142213.sql
Normal file
550
manual-backups/acore_auth-pre-import-20251019_142213.sql
Normal file
@@ -0,0 +1,550 @@
|
||||
-- MySQL dump 10.13 Distrib 8.0.43, for Linux (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: acore_auth
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 8.0.43
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!50503 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `account`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `account`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `account` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifier',
|
||||
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`salt` binary(32) NOT NULL,
|
||||
`verifier` binary(32) NOT NULL,
|
||||
`session_key` binary(40) DEFAULT NULL,
|
||||
`totp_secret` varbinary(128) DEFAULT NULL,
|
||||
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`reg_mail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`joindate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`last_ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`last_attempt_ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`failed_logins` int unsigned NOT NULL DEFAULT '0',
|
||||
`locked` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`lock_country` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '00',
|
||||
`last_login` timestamp NULL DEFAULT NULL,
|
||||
`online` int unsigned NOT NULL DEFAULT '0',
|
||||
`expansion` tinyint unsigned NOT NULL DEFAULT '2',
|
||||
`Flags` int unsigned NOT NULL DEFAULT '0',
|
||||
`mutetime` bigint NOT NULL DEFAULT '0',
|
||||
`mutereason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`muteby` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`locale` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`os` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`recruiter` int unsigned NOT NULL DEFAULT '0',
|
||||
`totaltime` int unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_username` (`username`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Account System';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `account`
|
||||
--
|
||||
|
||||
LOCK TABLES `account` WRITE;
|
||||
/*!40000 ALTER TABLE `account` DISABLE KEYS */;
|
||||
INSERT INTO `account` VALUES (1,'ARTIMAGE',_binary '<EFBFBD>\ß/g¿\Ù_:\Å/œ¥ZG4ÜŒ:x\ô¼Djf¡hÉ™.',_binary '¦<EFBFBD>4•!–€ ¡ˆ]&|.Jª\È\êfÈ¢\ÇÌš9(D*„',_binary 'F>\nÅš39\Í\Ä4‰TJºÁ\ì<03>9>~&\'\ö@x‚‚\Þ\ržHš1²',NULL,'','','2025-10-04 02:21:35','192.168.0.168','192.168.0.168',0,0,'00','2025-10-04 04:34:13',0,2,1,0,'','',0,'Win',0,6678),(2,'HAMSAMMY',_binary '±,\ë#zLЖ׉T3ù¡oaU\Ê\÷\'\÷=w\Óq\â',_binary '™?¨~!¦\íÜ—%ýŽ\Z-nr¢Ÿ]”F\ä@%©eû€@A',_binary '<\ð+U’tX˜²ÇŒhC\åJv\Ñpj5F*¯®.E}$ki®V \Õ)0p¡',NULL,'','','2025-10-04 03:03:40','192.168.0.152','192.168.0.152',0,0,'00','2025-10-04 04:34:01',0,2,1,0,'','',0,'Win',0,3592);
|
||||
/*!40000 ALTER TABLE `account` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `account_access`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `account_access`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `account_access` (
|
||||
`id` int unsigned NOT NULL,
|
||||
`gmlevel` tinyint unsigned NOT NULL,
|
||||
`RealmID` int NOT NULL DEFAULT '-1',
|
||||
`comment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '',
|
||||
PRIMARY KEY (`id`,`RealmID`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `account_access`
|
||||
--
|
||||
|
||||
LOCK TABLES `account_access` WRITE;
|
||||
/*!40000 ALTER TABLE `account_access` DISABLE KEYS */;
|
||||
INSERT INTO `account_access` VALUES (1,3,-1,''),(2,3,-1,'');
|
||||
/*!40000 ALTER TABLE `account_access` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `account_banned`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `account_banned`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `account_banned` (
|
||||
`id` int unsigned NOT NULL DEFAULT '0' COMMENT 'Account id',
|
||||
`bandate` int unsigned NOT NULL DEFAULT '0',
|
||||
`unbandate` int unsigned NOT NULL DEFAULT '0',
|
||||
`bannedby` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`banreason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`active` tinyint unsigned NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`id`,`bandate`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Ban List';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `account_banned`
|
||||
--
|
||||
|
||||
LOCK TABLES `account_banned` WRITE;
|
||||
/*!40000 ALTER TABLE `account_banned` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `account_banned` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `account_muted`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `account_muted`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `account_muted` (
|
||||
`guid` int unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
|
||||
`mutedate` int unsigned NOT NULL DEFAULT '0',
|
||||
`mutetime` int unsigned NOT NULL DEFAULT '0',
|
||||
`mutedby` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`mutereason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`guid`,`mutedate`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='mute List';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `account_muted`
|
||||
--
|
||||
|
||||
LOCK TABLES `account_muted` WRITE;
|
||||
/*!40000 ALTER TABLE `account_muted` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `account_muted` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `acore_cms_subscriptions`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `acore_cms_subscriptions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `acore_cms_subscriptions` (
|
||||
`account_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`membership_level` int NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `acore_cms_subscriptions`
|
||||
--
|
||||
|
||||
LOCK TABLES `acore_cms_subscriptions` WRITE;
|
||||
/*!40000 ALTER TABLE `acore_cms_subscriptions` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `acore_cms_subscriptions` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `autobroadcast`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `autobroadcast`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `autobroadcast` (
|
||||
`realmid` int NOT NULL DEFAULT '-1',
|
||||
`id` tinyint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`weight` tinyint unsigned DEFAULT '1',
|
||||
`text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`id`,`realmid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `autobroadcast`
|
||||
--
|
||||
|
||||
LOCK TABLES `autobroadcast` WRITE;
|
||||
/*!40000 ALTER TABLE `autobroadcast` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `autobroadcast` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `autobroadcast_locale`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `autobroadcast_locale`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `autobroadcast_locale` (
|
||||
`realmid` int NOT NULL,
|
||||
`id` int NOT NULL,
|
||||
`locale` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`realmid`,`id`,`locale`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `autobroadcast_locale`
|
||||
--
|
||||
|
||||
LOCK TABLES `autobroadcast_locale` WRITE;
|
||||
/*!40000 ALTER TABLE `autobroadcast_locale` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `autobroadcast_locale` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `build_info`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `build_info`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `build_info` (
|
||||
`build` int NOT NULL,
|
||||
`majorVersion` int DEFAULT NULL,
|
||||
`minorVersion` int DEFAULT NULL,
|
||||
`bugfixVersion` int DEFAULT NULL,
|
||||
`hotfixVersion` char(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`winAuthSeed` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`win64AuthSeed` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`mac64AuthSeed` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`winChecksumSeed` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`macChecksumSeed` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
PRIMARY KEY (`build`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `build_info`
|
||||
--
|
||||
|
||||
LOCK TABLES `build_info` WRITE;
|
||||
/*!40000 ALTER TABLE `build_info` DISABLE KEYS */;
|
||||
INSERT INTO `build_info` VALUES (5875,1,12,1,NULL,NULL,NULL,NULL,'95EDB27C7823B363CBDDAB56A392E7CB73FCCA20','8D173CC381961EEBABF336F5E6675B101BB513E5'),(6005,1,12,2,NULL,NULL,NULL,NULL,NULL,NULL),(6141,1,12,3,NULL,NULL,NULL,NULL,NULL,NULL),(8606,2,4,3,NULL,NULL,NULL,NULL,'319AFAA3F2559682F9FF658BE01456255F456FB1','D8B0ECFE534BC1131E19BAD1D4C0E813EEE4994F'),(9947,3,1,3,NULL,NULL,NULL,NULL,NULL,NULL),(10505,3,2,2,'a',NULL,NULL,NULL,NULL,NULL),(11159,3,3,0,'a',NULL,NULL,NULL,NULL,NULL),(11403,3,3,2,NULL,NULL,NULL,NULL,NULL,NULL),(11723,3,3,3,'a',NULL,NULL,NULL,NULL,NULL),(12340,3,3,5,'a',NULL,NULL,NULL,'CDCBBD5188315E6B4D19449D492DBCFAF156A347','B706D13FF2F4018839729461E3F8A0E2B5FDC034'),(13930,3,3,5,'a',NULL,NULL,NULL,NULL,NULL);
|
||||
/*!40000 ALTER TABLE `build_info` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `ip_banned`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `ip_banned`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `ip_banned` (
|
||||
`ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`bandate` int unsigned NOT NULL,
|
||||
`unbandate` int unsigned NOT NULL,
|
||||
`bannedby` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '[Console]',
|
||||
`banreason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'no reason',
|
||||
PRIMARY KEY (`ip`,`bandate`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Banned IPs';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `ip_banned`
|
||||
--
|
||||
|
||||
LOCK TABLES `ip_banned` WRITE;
|
||||
/*!40000 ALTER TABLE `ip_banned` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `ip_banned` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `logs`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `logs`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `logs` (
|
||||
`time` int unsigned NOT NULL,
|
||||
`realm` int unsigned NOT NULL,
|
||||
`type` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`level` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`string` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `logs`
|
||||
--
|
||||
|
||||
LOCK TABLES `logs` WRITE;
|
||||
/*!40000 ALTER TABLE `logs` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `logs` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `logs_ip_actions`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `logs_ip_actions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `logs_ip_actions` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Unique Identifier',
|
||||
`account_id` int unsigned NOT NULL COMMENT 'Account ID',
|
||||
`character_guid` int unsigned NOT NULL COMMENT 'Character Guid',
|
||||
`type` tinyint unsigned NOT NULL,
|
||||
`ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`systemnote` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'Notes inserted by system',
|
||||
`unixtime` int unsigned NOT NULL COMMENT 'Unixtime',
|
||||
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Timestamp',
|
||||
`comment` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'Allows users to add a comment',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Used to log ips of individual actions';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `logs_ip_actions`
|
||||
--
|
||||
|
||||
LOCK TABLES `logs_ip_actions` WRITE;
|
||||
/*!40000 ALTER TABLE `logs_ip_actions` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `logs_ip_actions` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `motd`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `motd`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `motd` (
|
||||
`realmid` int NOT NULL,
|
||||
`text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
PRIMARY KEY (`realmid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `motd`
|
||||
--
|
||||
|
||||
LOCK TABLES `motd` WRITE;
|
||||
/*!40000 ALTER TABLE `motd` DISABLE KEYS */;
|
||||
INSERT INTO `motd` VALUES (-1,'Welcome to an AzerothCore server.');
|
||||
/*!40000 ALTER TABLE `motd` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `motd_localized`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `motd_localized`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `motd_localized` (
|
||||
`realmid` int NOT NULL,
|
||||
`locale` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
PRIMARY KEY (`realmid`,`locale`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `motd_localized`
|
||||
--
|
||||
|
||||
LOCK TABLES `motd_localized` WRITE;
|
||||
/*!40000 ALTER TABLE `motd_localized` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `motd_localized` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `realmcharacters`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `realmcharacters`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `realmcharacters` (
|
||||
`realmid` int unsigned NOT NULL DEFAULT '0',
|
||||
`acctid` int unsigned NOT NULL,
|
||||
`numchars` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`realmid`,`acctid`),
|
||||
KEY `acctid` (`acctid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Realm Character Tracker';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `realmcharacters`
|
||||
--
|
||||
|
||||
LOCK TABLES `realmcharacters` WRITE;
|
||||
/*!40000 ALTER TABLE `realmcharacters` DISABLE KEYS */;
|
||||
INSERT INTO `realmcharacters` VALUES (1,1,2),(1,2,1);
|
||||
/*!40000 ALTER TABLE `realmcharacters` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `realmlist`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `realmlist`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `realmlist` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`localAddress` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`localSubnetMask` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '255.255.255.0',
|
||||
`port` smallint unsigned NOT NULL DEFAULT '8085',
|
||||
`icon` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`flag` tinyint unsigned NOT NULL DEFAULT '2',
|
||||
`timezone` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`allowedSecurityLevel` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`population` float NOT NULL DEFAULT '0',
|
||||
`gamebuild` int unsigned NOT NULL DEFAULT '12340',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_name` (`name`),
|
||||
CONSTRAINT `realmlist_chk_1` CHECK ((`population` >= 0))
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Realm System';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `realmlist`
|
||||
--
|
||||
|
||||
LOCK TABLES `realmlist` WRITE;
|
||||
/*!40000 ALTER TABLE `realmlist` DISABLE KEYS */;
|
||||
INSERT INTO `realmlist` VALUES (1,'AzerothCore','192.168.0.188','127.0.0.1','255.255.255.0',8215,0,2,1,0,0,12340);
|
||||
/*!40000 ALTER TABLE `realmlist` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `secret_digest`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `secret_digest`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `secret_digest` (
|
||||
`id` int unsigned NOT NULL,
|
||||
`digest` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `secret_digest`
|
||||
--
|
||||
|
||||
LOCK TABLES `secret_digest` WRITE;
|
||||
/*!40000 ALTER TABLE `secret_digest` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `secret_digest` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `updates`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `updates`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `updates` (
|
||||
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'filename with extension of the update.',
|
||||
`hash` char(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'sha1 hash of the sql file.',
|
||||
`state` enum('RELEASED','CUSTOM','MODULE','ARCHIVED','PENDING') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if an update is released or archived.',
|
||||
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'timestamp when the query was applied.',
|
||||
`speed` int unsigned NOT NULL DEFAULT '0' COMMENT 'time the query takes to apply in ms.',
|
||||
PRIMARY KEY (`name`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='List of all applied updates in this database.';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `updates`
|
||||
--
|
||||
|
||||
LOCK TABLES `updates` WRITE;
|
||||
/*!40000 ALTER TABLE `updates` DISABLE KEYS */;
|
||||
INSERT INTO `updates` VALUES ('2023_04_24_00.sql','D164A70B22B2462464484614018C3218B3259AE4','ARCHIVED','2024-01-20 14:23:45',26),('2024_01_20_00.sql','41678119235D993DEF719C168B20867F781A3A5F','RELEASED','2024-01-20 14:23:45',36),('2024_11_15_00.sql','7F15CD3FF0C3D98918DA8860BC3CFB6B9D5146BB','RELEASED','2024-12-17 21:51:20',93),('2024_12_15_00.sql','8CC811CF48ADF26D279E4A8F2D06AD94C11F43BE','RELEASED','2024-12-17 21:55:57',133),('2025_01_26_00.sql','CA6884F4BDBBC60C08CD52480FD4B3FAC945C3CF','RELEASED','2025-07-19 10:16:14',166),('2025_02_16_00.sql','D59DF568B412F0A17B0ACC5C350420B81C87AAB2','RELEASED','2025-07-19 10:16:15',148),('2025_02_16_01.sql','6788795A29BFD097EE5D00E548EFF3831F9CFBCF','RELEASED','2025-07-19 10:16:15',103),('2025_07_03_00.sql','C28996618006B516134EC7FA4E1D58F2DF410548','RELEASED','2025-07-19 10:16:15',135),('2025_07_24_00.sql','FCC937F180EFFAA5B991D9B7CF9E2223B6C0C4D3','RELEASED','2025-10-04 00:30:46',18);
|
||||
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `updates_include`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `updates_include`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `updates_include` (
|
||||
`path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'directory to include. $ means relative to the source directory.',
|
||||
`state` enum('RELEASED','ARCHIVED','CUSTOM','PENDING') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if the directory contains released or archived updates.',
|
||||
PRIMARY KEY (`path`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='List of directories where we want to include sql updates.';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `updates_include`
|
||||
--
|
||||
|
||||
LOCK TABLES `updates_include` WRITE;
|
||||
/*!40000 ALTER TABLE `updates_include` DISABLE KEYS */;
|
||||
INSERT INTO `updates_include` VALUES ('$/data/sql/archive/db_auth','ARCHIVED'),('$/data/sql/custom/db_auth','CUSTOM'),('$/data/sql/updates/db_auth','RELEASED'),('$/data/sql/updates/pending_db_auth','PENDING');
|
||||
/*!40000 ALTER TABLE `updates_include` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `uptime`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `uptime`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `uptime` (
|
||||
`realmid` int unsigned NOT NULL,
|
||||
`starttime` int unsigned NOT NULL DEFAULT '0',
|
||||
`uptime` int unsigned NOT NULL DEFAULT '0',
|
||||
`maxplayers` smallint unsigned NOT NULL DEFAULT '0',
|
||||
`revision` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'AzerothCore',
|
||||
PRIMARY KEY (`realmid`,`starttime`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Uptime system';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `uptime`
|
||||
--
|
||||
|
||||
LOCK TABLES `uptime` WRITE;
|
||||
/*!40000 ALTER TABLE `uptime` DISABLE KEYS */;
|
||||
INSERT INTO `uptime` VALUES (1,1721169877,0,0,'AzerothCore rev. bdf204f1eb0c 2024-07-16 16:28:59 +0000 (time-for-A-SQUASH branch) (Win64, RelWithDebInfo, Static)'),(1,1734468956,0,0,'AzerothCore rev. 2923a4aa43d0 2024-12-17 12:28:46 -0300 (master branch) (Win64, RelWithDebInfo, Static)'),(1,1734470333,0,0,'AzerothCore rev. 2923a4aa43d0 2024-12-17 12:28:46 -0300 (master branch) (Win64, RelWithDebInfo, Static)'),(1,1734471110,0,0,'AzerothCore rev. 2923a4aa43d0 2024-12-17 12:28:46 -0300 (master branch) (Win64, RelWithDebInfo, Static)'),(1,1752912822,0,0,'AzerothCore rev. 9415d1bef80d 2025-07-05 11:29:15 +0200 (whisper-something-something branch) (Win64, RelWithDebInfo, Static)'),(1,1752913079,0,0,'AzerothCore rev. 9415d1bef80d 2025-07-05 11:29:15 +0200 (whisper-something-something branch) (Win64, RelWithDebInfo, Static)'),(1,1752919589,0,0,'AzerothCore rev. 9415d1bef80d 2025-07-05 11:29:15 +0200 (whisper-something-something branch) (Win64, RelWithDebInfo, Static)'),(1,1759539715,1209,0,'AzerothCore rev. b82857748ee7+ 2025-09-22 15:04:50 -0300 (master branch) (Unix, RelWithDebInfo, Static)'),(1,1759541210,1808,0,'AzerothCore rev. b82857748ee7+ 2025-09-22 15:04:50 -0300 (master branch) (Unix, RelWithDebInfo, Static)'),(1,1759543594,24609,2,'AzerothCore rev. b82857748ee7+ 2025-09-22 15:04:50 -0300 (master branch) (Unix, RelWithDebInfo, Static)'),(1,1760897078,0,0,'AzerothCore rev. 1424995f3bc5+ 2025-10-12 02:28:49 -0400 (Playerbot branch) (Unix, RelWithDebInfo, Static)'),(1,1760897263,576,0,'AzerothCore rev. 1424995f3bc5+ 2025-10-12 02:28:49 -0400 (Playerbot branch) (Unix, RelWithDebInfo, Static)');
|
||||
/*!40000 ALTER TABLE `uptime` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2025-10-19 18:22:14
|
||||
547
manual-backups/acore_auth-pre-import.sql
Normal file
547
manual-backups/acore_auth-pre-import.sql
Normal file
@@ -0,0 +1,547 @@
|
||||
-- MySQL dump 10.13 Distrib 8.0.43, for Linux (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: acore_auth
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 8.0.43
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!50503 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `account`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `account`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `account` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifier',
|
||||
`username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`salt` binary(32) NOT NULL,
|
||||
`verifier` binary(32) NOT NULL,
|
||||
`session_key` binary(40) DEFAULT NULL,
|
||||
`totp_secret` varbinary(128) DEFAULT NULL,
|
||||
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`reg_mail` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`joindate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`last_ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`last_attempt_ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`failed_logins` int unsigned NOT NULL DEFAULT '0',
|
||||
`locked` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`lock_country` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '00',
|
||||
`last_login` timestamp NULL DEFAULT NULL,
|
||||
`online` int unsigned NOT NULL DEFAULT '0',
|
||||
`expansion` tinyint unsigned NOT NULL DEFAULT '2',
|
||||
`Flags` int unsigned NOT NULL DEFAULT '0',
|
||||
`mutetime` bigint NOT NULL DEFAULT '0',
|
||||
`mutereason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`muteby` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`locale` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`os` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`recruiter` int unsigned NOT NULL DEFAULT '0',
|
||||
`totaltime` int unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_username` (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Account System';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `account`
|
||||
--
|
||||
|
||||
LOCK TABLES `account` WRITE;
|
||||
/*!40000 ALTER TABLE `account` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `account` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `account_access`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `account_access`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `account_access` (
|
||||
`id` int unsigned NOT NULL,
|
||||
`gmlevel` tinyint unsigned NOT NULL,
|
||||
`RealmID` int NOT NULL DEFAULT '-1',
|
||||
`comment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '',
|
||||
PRIMARY KEY (`id`,`RealmID`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `account_access`
|
||||
--
|
||||
|
||||
LOCK TABLES `account_access` WRITE;
|
||||
/*!40000 ALTER TABLE `account_access` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `account_access` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `account_banned`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `account_banned`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `account_banned` (
|
||||
`id` int unsigned NOT NULL DEFAULT '0' COMMENT 'Account id',
|
||||
`bandate` int unsigned NOT NULL DEFAULT '0',
|
||||
`unbandate` int unsigned NOT NULL DEFAULT '0',
|
||||
`bannedby` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`banreason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`active` tinyint unsigned NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`id`,`bandate`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Ban List';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `account_banned`
|
||||
--
|
||||
|
||||
LOCK TABLES `account_banned` WRITE;
|
||||
/*!40000 ALTER TABLE `account_banned` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `account_banned` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `account_muted`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `account_muted`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `account_muted` (
|
||||
`guid` int unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
|
||||
`mutedate` int unsigned NOT NULL DEFAULT '0',
|
||||
`mutetime` int unsigned NOT NULL DEFAULT '0',
|
||||
`mutedby` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`mutereason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`guid`,`mutedate`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='mute List';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `account_muted`
|
||||
--
|
||||
|
||||
LOCK TABLES `account_muted` WRITE;
|
||||
/*!40000 ALTER TABLE `account_muted` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `account_muted` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `acore_cms_subscriptions`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `acore_cms_subscriptions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `acore_cms_subscriptions` (
|
||||
`account_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`membership_level` int NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `acore_cms_subscriptions`
|
||||
--
|
||||
|
||||
LOCK TABLES `acore_cms_subscriptions` WRITE;
|
||||
/*!40000 ALTER TABLE `acore_cms_subscriptions` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `acore_cms_subscriptions` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `autobroadcast`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `autobroadcast`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `autobroadcast` (
|
||||
`realmid` int NOT NULL DEFAULT '-1',
|
||||
`id` tinyint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`weight` tinyint unsigned DEFAULT '1',
|
||||
`text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`id`,`realmid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `autobroadcast`
|
||||
--
|
||||
|
||||
LOCK TABLES `autobroadcast` WRITE;
|
||||
/*!40000 ALTER TABLE `autobroadcast` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `autobroadcast` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `autobroadcast_locale`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `autobroadcast_locale`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `autobroadcast_locale` (
|
||||
`realmid` int NOT NULL,
|
||||
`id` int NOT NULL,
|
||||
`locale` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`realmid`,`id`,`locale`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `autobroadcast_locale`
|
||||
--
|
||||
|
||||
LOCK TABLES `autobroadcast_locale` WRITE;
|
||||
/*!40000 ALTER TABLE `autobroadcast_locale` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `autobroadcast_locale` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `build_info`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `build_info`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `build_info` (
|
||||
`build` int NOT NULL,
|
||||
`majorVersion` int DEFAULT NULL,
|
||||
`minorVersion` int DEFAULT NULL,
|
||||
`bugfixVersion` int DEFAULT NULL,
|
||||
`hotfixVersion` char(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`winAuthSeed` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`win64AuthSeed` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`mac64AuthSeed` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`winChecksumSeed` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`macChecksumSeed` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
PRIMARY KEY (`build`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `build_info`
|
||||
--
|
||||
|
||||
LOCK TABLES `build_info` WRITE;
|
||||
/*!40000 ALTER TABLE `build_info` DISABLE KEYS */;
|
||||
INSERT INTO `build_info` VALUES (5875,1,12,1,NULL,NULL,NULL,NULL,'95EDB27C7823B363CBDDAB56A392E7CB73FCCA20','8D173CC381961EEBABF336F5E6675B101BB513E5'),(6005,1,12,2,NULL,NULL,NULL,NULL,NULL,NULL),(6141,1,12,3,NULL,NULL,NULL,NULL,NULL,NULL),(8606,2,4,3,NULL,NULL,NULL,NULL,'319AFAA3F2559682F9FF658BE01456255F456FB1','D8B0ECFE534BC1131E19BAD1D4C0E813EEE4994F'),(9947,3,1,3,NULL,NULL,NULL,NULL,NULL,NULL),(10505,3,2,2,'a',NULL,NULL,NULL,NULL,NULL),(11159,3,3,0,'a',NULL,NULL,NULL,NULL,NULL),(11403,3,3,2,NULL,NULL,NULL,NULL,NULL,NULL),(11723,3,3,3,'a',NULL,NULL,NULL,NULL,NULL),(12340,3,3,5,'a',NULL,NULL,NULL,'CDCBBD5188315E6B4D19449D492DBCFAF156A347','B706D13FF2F4018839729461E3F8A0E2B5FDC034'),(13930,3,3,5,'a',NULL,NULL,NULL,NULL,NULL);
|
||||
/*!40000 ALTER TABLE `build_info` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `ip_banned`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `ip_banned`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `ip_banned` (
|
||||
`ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`bandate` int unsigned NOT NULL,
|
||||
`unbandate` int unsigned NOT NULL,
|
||||
`bannedby` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '[Console]',
|
||||
`banreason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'no reason',
|
||||
PRIMARY KEY (`ip`,`bandate`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Banned IPs';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `ip_banned`
|
||||
--
|
||||
|
||||
LOCK TABLES `ip_banned` WRITE;
|
||||
/*!40000 ALTER TABLE `ip_banned` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `ip_banned` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `logs`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `logs`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `logs` (
|
||||
`time` int unsigned NOT NULL,
|
||||
`realm` int unsigned NOT NULL,
|
||||
`type` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`level` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`string` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `logs`
|
||||
--
|
||||
|
||||
LOCK TABLES `logs` WRITE;
|
||||
/*!40000 ALTER TABLE `logs` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `logs` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `logs_ip_actions`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `logs_ip_actions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `logs_ip_actions` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'Unique Identifier',
|
||||
`account_id` int unsigned NOT NULL COMMENT 'Account ID',
|
||||
`character_guid` int unsigned NOT NULL COMMENT 'Character Guid',
|
||||
`type` tinyint unsigned NOT NULL,
|
||||
`ip` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`systemnote` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'Notes inserted by system',
|
||||
`unixtime` int unsigned NOT NULL COMMENT 'Unixtime',
|
||||
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Timestamp',
|
||||
`comment` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'Allows users to add a comment',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Used to log ips of individual actions';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `logs_ip_actions`
|
||||
--
|
||||
|
||||
LOCK TABLES `logs_ip_actions` WRITE;
|
||||
/*!40000 ALTER TABLE `logs_ip_actions` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `logs_ip_actions` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `motd`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `motd`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `motd` (
|
||||
`realmid` int NOT NULL,
|
||||
`text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
PRIMARY KEY (`realmid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `motd`
|
||||
--
|
||||
|
||||
LOCK TABLES `motd` WRITE;
|
||||
/*!40000 ALTER TABLE `motd` DISABLE KEYS */;
|
||||
INSERT INTO `motd` VALUES (-1,'Welcome to an AzerothCore server.');
|
||||
/*!40000 ALTER TABLE `motd` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `motd_localized`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `motd_localized`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `motd_localized` (
|
||||
`realmid` int NOT NULL,
|
||||
`locale` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`text` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
PRIMARY KEY (`realmid`,`locale`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `motd_localized`
|
||||
--
|
||||
|
||||
LOCK TABLES `motd_localized` WRITE;
|
||||
/*!40000 ALTER TABLE `motd_localized` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `motd_localized` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `realmcharacters`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `realmcharacters`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `realmcharacters` (
|
||||
`realmid` int unsigned NOT NULL DEFAULT '0',
|
||||
`acctid` int unsigned NOT NULL,
|
||||
`numchars` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`realmid`,`acctid`),
|
||||
KEY `acctid` (`acctid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Realm Character Tracker';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `realmcharacters`
|
||||
--
|
||||
|
||||
LOCK TABLES `realmcharacters` WRITE;
|
||||
/*!40000 ALTER TABLE `realmcharacters` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `realmcharacters` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `realmlist`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `realmlist`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `realmlist` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
`address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`localAddress` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1',
|
||||
`localSubnetMask` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '255.255.255.0',
|
||||
`port` smallint unsigned NOT NULL DEFAULT '8085',
|
||||
`icon` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`flag` tinyint unsigned NOT NULL DEFAULT '2',
|
||||
`timezone` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`allowedSecurityLevel` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`population` float NOT NULL DEFAULT '0',
|
||||
`gamebuild` int unsigned NOT NULL DEFAULT '12340',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `idx_name` (`name`),
|
||||
CONSTRAINT `realmlist_chk_1` CHECK ((`population` >= 0))
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Realm System';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `realmlist`
|
||||
--
|
||||
|
||||
LOCK TABLES `realmlist` WRITE;
|
||||
/*!40000 ALTER TABLE `realmlist` DISABLE KEYS */;
|
||||
INSERT INTO `realmlist` VALUES (1,'AzerothCore','127.0.0.1','127.0.0.1','255.255.255.0',8085,0,2,1,0,0,12340);
|
||||
/*!40000 ALTER TABLE `realmlist` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `secret_digest`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `secret_digest`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `secret_digest` (
|
||||
`id` int unsigned NOT NULL,
|
||||
`digest` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `secret_digest`
|
||||
--
|
||||
|
||||
LOCK TABLES `secret_digest` WRITE;
|
||||
/*!40000 ALTER TABLE `secret_digest` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `secret_digest` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `updates`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `updates`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `updates` (
|
||||
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'filename with extension of the update.',
|
||||
`hash` char(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT 'sha1 hash of the sql file.',
|
||||
`state` enum('RELEASED','CUSTOM','MODULE','ARCHIVED','PENDING') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if an update is released or archived.',
|
||||
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'timestamp when the query was applied.',
|
||||
`speed` int unsigned NOT NULL DEFAULT '0' COMMENT 'time the query takes to apply in ms.',
|
||||
PRIMARY KEY (`name`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='List of all applied updates in this database.';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `updates`
|
||||
--
|
||||
|
||||
LOCK TABLES `updates` WRITE;
|
||||
/*!40000 ALTER TABLE `updates` DISABLE KEYS */;
|
||||
INSERT INTO `updates` VALUES ('2023_04_24_00.sql','D164A70B22B2462464484614018C3218B3259AE4','ARCHIVED','2024-01-20 14:23:45',26),('2024_01_20_00.sql','41678119235D993DEF719C168B20867F781A3A5F','RELEASED','2024-01-20 14:23:45',36),('2024_11_15_00.sql','7F15CD3FF0C3D98918DA8860BC3CFB6B9D5146BB','RELEASED','2024-12-17 21:51:20',93),('2024_12_15_00.sql','8CC811CF48ADF26D279E4A8F2D06AD94C11F43BE','RELEASED','2024-12-17 21:55:57',133),('2025_01_26_00.sql','CA6884F4BDBBC60C08CD52480FD4B3FAC945C3CF','RELEASED','2025-07-19 10:16:14',166),('2025_02_16_00.sql','D59DF568B412F0A17B0ACC5C350420B81C87AAB2','RELEASED','2025-07-19 10:16:15',148),('2025_02_16_01.sql','6788795A29BFD097EE5D00E548EFF3831F9CFBCF','RELEASED','2025-07-19 10:16:15',103),('2025_07_03_00.sql','C28996618006B516134EC7FA4E1D58F2DF410548','RELEASED','2025-07-19 10:16:15',135),('2025_07_24_00.sql','FCC937F180EFFAA5B991D9B7CF9E2223B6C0C4D3','RELEASED','2025-10-19 10:26:51',14);
|
||||
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `updates_include`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `updates_include`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `updates_include` (
|
||||
`path` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'directory to include. $ means relative to the source directory.',
|
||||
`state` enum('RELEASED','ARCHIVED','CUSTOM','PENDING') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'RELEASED' COMMENT 'defines if the directory contains released or archived updates.',
|
||||
PRIMARY KEY (`path`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='List of directories where we want to include sql updates.';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `updates_include`
|
||||
--
|
||||
|
||||
LOCK TABLES `updates_include` WRITE;
|
||||
/*!40000 ALTER TABLE `updates_include` DISABLE KEYS */;
|
||||
INSERT INTO `updates_include` VALUES ('$/data/sql/archive/db_auth','ARCHIVED'),('$/data/sql/custom/db_auth','CUSTOM'),('$/data/sql/updates/db_auth','RELEASED'),('$/data/sql/updates/pending_db_auth','PENDING');
|
||||
/*!40000 ALTER TABLE `updates_include` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `uptime`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `uptime`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `uptime` (
|
||||
`realmid` int unsigned NOT NULL,
|
||||
`starttime` int unsigned NOT NULL DEFAULT '0',
|
||||
`uptime` int unsigned NOT NULL DEFAULT '0',
|
||||
`maxplayers` smallint unsigned NOT NULL DEFAULT '0',
|
||||
`revision` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'AzerothCore',
|
||||
PRIMARY KEY (`realmid`,`starttime`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Uptime system';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `uptime`
|
||||
--
|
||||
|
||||
LOCK TABLES `uptime` WRITE;
|
||||
/*!40000 ALTER TABLE `uptime` DISABLE KEYS */;
|
||||
INSERT INTO `uptime` VALUES (1,1721169877,0,0,'AzerothCore rev. bdf204f1eb0c 2024-07-16 16:28:59 +0000 (time-for-A-SQUASH branch) (Win64, RelWithDebInfo, Static)'),(1,1734468956,0,0,'AzerothCore rev. 2923a4aa43d0 2024-12-17 12:28:46 -0300 (master branch) (Win64, RelWithDebInfo, Static)'),(1,1734470333,0,0,'AzerothCore rev. 2923a4aa43d0 2024-12-17 12:28:46 -0300 (master branch) (Win64, RelWithDebInfo, Static)'),(1,1734471110,0,0,'AzerothCore rev. 2923a4aa43d0 2024-12-17 12:28:46 -0300 (master branch) (Win64, RelWithDebInfo, Static)'),(1,1752912822,0,0,'AzerothCore rev. 9415d1bef80d 2025-07-05 11:29:15 +0200 (whisper-something-something branch) (Win64, RelWithDebInfo, Static)'),(1,1752913079,0,0,'AzerothCore rev. 9415d1bef80d 2025-07-05 11:29:15 +0200 (whisper-something-something branch) (Win64, RelWithDebInfo, Static)'),(1,1752919589,0,0,'AzerothCore rev. 9415d1bef80d 2025-07-05 11:29:15 +0200 (whisper-something-something branch) (Win64, RelWithDebInfo, Static)'),(1,1760869638,27203,0,'AzerothCore rev. 1424995f3bc5+ 2025-10-12 02:28:49 -0400 (Playerbot branch) (Unix, RelWithDebInfo, Static)');
|
||||
/*!40000 ALTER TABLE `uptime` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2025-10-19 18:04:19
|
||||
3276
manual-backups/acore_characters-pre-import-20251019_142214.sql
Normal file
3276
manual-backups/acore_characters-pre-import-20251019_142214.sql
Normal file
File diff suppressed because one or more lines are too long
3256
manual-backups/acore_characters-pre-import.sql
Normal file
3256
manual-backups/acore_characters-pre-import.sql
Normal file
File diff suppressed because one or more lines are too long
@@ -1,11 +1,44 @@
|
||||
#!/bin/bash
|
||||
# ac-compose
|
||||
set -e
|
||||
|
||||
echo "🚀 AzerothCore Auto Post-Install Configuration"
|
||||
echo "=============================================="
|
||||
GREEN='\033[0;32m'; BLUE='\033[0;34m'; NC='\033[0m'
|
||||
|
||||
show_post_install_header(){
|
||||
echo -e "\n${BLUE} ⚔️ REALM POST-INSTALL CONFIGURATION ⚔️${NC}"
|
||||
echo -e "${BLUE} ══════════════════════════════════════════${NC}"
|
||||
echo -e "${BLUE} 🏯 Blessing Your Realm with Final Touches 🏯${NC}\n"
|
||||
}
|
||||
|
||||
show_post_install_header
|
||||
|
||||
# Install required packages
|
||||
apk add --no-cache curl mysql-client bash docker-cli-compose jq
|
||||
apk add --no-cache curl mysql-client bash docker-cli-compose jq || apk add --no-cache curl mysql-client bash jq
|
||||
|
||||
ensure_playerbots_db(){
|
||||
local db_name="${DB_PLAYERBOTS_NAME:-acore_playerbots}"
|
||||
local charset="${MYSQL_CHARACTER_SET:-utf8mb4}"
|
||||
local collation="${MYSQL_COLLATION:-utf8mb4_unicode_ci}"
|
||||
echo "🔐 Ensuring playerbots database '${db_name}' exists..."
|
||||
if mysql -h "${MYSQL_HOST}" -u"${MYSQL_USER}" -p"${MYSQL_ROOT_PASSWORD}" --skip-ssl-verify -e "CREATE DATABASE IF NOT EXISTS \`${db_name}\` CHARACTER SET ${charset} COLLATE ${collation};" >/dev/null 2>&1; then
|
||||
echo "✅ Playerbots database ready"
|
||||
else
|
||||
echo "⚠️ Failed to guarantee playerbots database"
|
||||
fi
|
||||
}
|
||||
|
||||
update_playerbots_conf(){
|
||||
local target="$1"
|
||||
if [ ! -f "$target" ]; then
|
||||
return 0
|
||||
fi
|
||||
if sed -i "s|^PlayerbotsDatabaseInfo *=.*|PlayerbotsDatabaseInfo = \"${MYSQL_HOST};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_PLAYERBOTS_NAME}\"|" "$target"; then
|
||||
echo " 🔁 Updated $(basename "$target")"
|
||||
else
|
||||
echo " ⚠️ Could not update $(basename "$target")"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Create install markers directory
|
||||
mkdir -p /install-markers
|
||||
@@ -15,7 +48,6 @@ if [ -f "/install-markers/post-install-completed" ]; then
|
||||
echo "✅ Post-install configuration already completed"
|
||||
echo "ℹ️ Marker file found: /install-markers/post-install-completed"
|
||||
echo "🔄 To re-run post-install configuration, delete the marker file and restart this container"
|
||||
echo "📝 Command: docker exec ${CONTAINER_POST_INSTALL} rm -f /install-markers/post-install-completed"
|
||||
echo ""
|
||||
echo "🏃 Keeping container alive for manual operations..."
|
||||
tail -f /dev/null
|
||||
@@ -31,6 +63,7 @@ else
|
||||
for i in $(seq 1 120); do
|
||||
if mysql -h "${MYSQL_HOST}" -u"${MYSQL_USER}" -p"${MYSQL_ROOT_PASSWORD}" --skip-ssl-verify -e "SELECT 1;" >/dev/null 2>&1; then
|
||||
echo "✅ MySQL is ready"
|
||||
ensure_playerbots_db
|
||||
break
|
||||
fi
|
||||
echo " ⏳ Attempt $i/120..."
|
||||
@@ -50,8 +83,6 @@ else
|
||||
|
||||
if [ ! -f "/azerothcore/config/authserver.conf" ] || [ ! -f "/azerothcore/config/worldserver.conf" ]; then
|
||||
echo "❌ Configuration files not found after waiting"
|
||||
echo " Expected: /azerothcore/config/authserver.conf"
|
||||
echo " Expected: /azerothcore/config/worldserver.conf"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -59,126 +90,40 @@ else
|
||||
echo ""
|
||||
echo "🔧 Step 1: Updating configuration files..."
|
||||
|
||||
# Download and execute update-config.sh
|
||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/update-config.sh -o /tmp/update-config.sh
|
||||
chmod +x /tmp/update-config.sh
|
||||
# Update DB connection lines and any necessary settings directly with sed
|
||||
sed -i "s|^LoginDatabaseInfo *=.*|LoginDatabaseInfo = \"${MYSQL_HOST};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}\"|" /azerothcore/config/authserver.conf || true
|
||||
sed -i "s|^LoginDatabaseInfo *=.*|LoginDatabaseInfo = \"${MYSQL_HOST};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}\"|" /azerothcore/config/worldserver.conf || true
|
||||
sed -i "s|^WorldDatabaseInfo *=.*|WorldDatabaseInfo = \"${MYSQL_HOST};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_WORLD_NAME}\"|" /azerothcore/config/worldserver.conf || true
|
||||
sed -i "s|^CharacterDatabaseInfo *=.*|CharacterDatabaseInfo = \"${MYSQL_HOST};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}\"|" /azerothcore/config/worldserver.conf || true
|
||||
update_playerbots_conf /azerothcore/config/playerbots.conf
|
||||
update_playerbots_conf /azerothcore/config/playerbots.conf.dist
|
||||
update_playerbots_conf /azerothcore/config/modules/playerbots.conf
|
||||
update_playerbots_conf /azerothcore/config/modules/playerbots.conf.dist
|
||||
|
||||
# Modify script to use container environment
|
||||
sed -i 's|docker-compose-azerothcore-services.env|/project/docker-compose-azerothcore-services.env|' /tmp/update-config.sh
|
||||
sed -i 's|CONFIG_DIR="${STORAGE_PATH}/config"|CONFIG_DIR="/azerothcore/config"|' /tmp/update-config.sh
|
||||
|
||||
# Execute update-config.sh
|
||||
cd /project
|
||||
/tmp/update-config.sh
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Configuration files updated successfully"
|
||||
else
|
||||
echo "❌ Failed to update configuration files"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Configuration files updated"
|
||||
|
||||
# Step 2: Update realmlist table
|
||||
echo ""
|
||||
echo "🌐 Step 2: Updating realmlist table..."
|
||||
mysql -h "${MYSQL_HOST}" -u"${MYSQL_USER}" -p"${MYSQL_ROOT_PASSWORD}" --skip-ssl-verify "${DB_AUTH_NAME}" -e "
|
||||
UPDATE realmlist SET address='${SERVER_ADDRESS}', port=${REALM_PORT} WHERE id=1;
|
||||
" || echo "⚠️ Could not update realmlist table"
|
||||
|
||||
# Download and execute update-realmlist.sh
|
||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/update-realmlist.sh -o /tmp/update-realmlist.sh
|
||||
chmod +x /tmp/update-realmlist.sh
|
||||
echo "✅ Realmlist updated"
|
||||
|
||||
# Modify script to use container environment
|
||||
sed -i 's|docker-compose-azerothcore-services.env|/project/docker-compose-azerothcore-services.env|' /tmp/update-realmlist.sh
|
||||
|
||||
# Replace all docker exec mysql commands with direct mysql commands
|
||||
sed -i "s|docker exec ac-mysql mysql -u \"\${MYSQL_USER}\" -p\"\${MYSQL_ROOT_PASSWORD}\" \"\${DB_AUTH_NAME}\"|mysql -h \"${MYSQL_HOST}\" -u\"${MYSQL_USER}\" -p\"${MYSQL_ROOT_PASSWORD}\" --skip-ssl-verify \"${DB_AUTH_NAME}\"|g" /tmp/update-realmlist.sh
|
||||
sed -i "s|docker exec ac-mysql mysql -u \"\${MYSQL_USER}\" -p\"\${MYSQL_ROOT_PASSWORD}\"|mysql -h \"${MYSQL_HOST}\" -u\"${MYSQL_USER}\" -p\"${MYSQL_ROOT_PASSWORD}\" --skip-ssl-verify|g" /tmp/update-realmlist.sh
|
||||
|
||||
# Execute update-realmlist.sh
|
||||
cd /project
|
||||
/tmp/update-realmlist.sh
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ Realmlist table updated successfully"
|
||||
else
|
||||
echo "❌ Failed to update realmlist table"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 3: Restart services to apply changes
|
||||
echo ""
|
||||
echo "ℹ️ Step 3: Restarting services to apply changes..."
|
||||
echo "📝 Configuration changes have been applied to files"
|
||||
echo "🔄 Restarting authserver and worldserver to pick up new configuration..."
|
||||
|
||||
# Detect container runtime (Docker or Podman)
|
||||
CONTAINER_CMD=""
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
# Check if we can connect to Docker daemon
|
||||
if docker version >/dev/null 2>&1; then
|
||||
CONTAINER_CMD="docker"
|
||||
echo "🐳 Detected Docker runtime"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$CONTAINER_CMD" ] && command -v podman >/dev/null 2>&1; then
|
||||
# Check if we can connect to Podman
|
||||
if podman version >/dev/null 2>&1; then
|
||||
CONTAINER_CMD="podman"
|
||||
echo "🦭 Detected Podman runtime"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$CONTAINER_CMD" ]; then
|
||||
echo "⚠️ No container runtime detected (docker/podman) - skipping restart"
|
||||
else
|
||||
# Restart authserver
|
||||
if [ -n "$CONTAINER_AUTHSERVER" ]; then
|
||||
echo "🔄 Restarting authserver container: $CONTAINER_AUTHSERVER"
|
||||
if $CONTAINER_CMD restart "$CONTAINER_AUTHSERVER" 2>/dev/null; then
|
||||
echo "✅ Authserver restarted successfully"
|
||||
else
|
||||
echo "⚠️ Failed to restart authserver (may not be running yet)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Restart worldserver
|
||||
if [ -n "$CONTAINER_WORLDSERVER" ]; then
|
||||
echo "🔄 Restarting worldserver container: $CONTAINER_WORLDSERVER"
|
||||
if $CONTAINER_CMD restart "$CONTAINER_WORLDSERVER" 2>/dev/null; then
|
||||
echo "✅ Worldserver restarted successfully"
|
||||
else
|
||||
echo "⚠️ Failed to restart worldserver (may not be running yet)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✅ Service restart completed"
|
||||
echo "ℹ️ Step 3: (Optional) Restart services to apply changes — handled externally"
|
||||
|
||||
# Create completion marker
|
||||
echo "$(date)" > /install-markers/post-install-completed
|
||||
echo "NEW_INSTALL_DATE=$(date)" >> /install-markers/post-install-completed
|
||||
echo "CONFIG_FILES_UPDATED=true" >> /install-markers/post-install-completed
|
||||
echo "REALMLIST_UPDATED=true" >> /install-markers/post-install-completed
|
||||
echo "SERVICES_RESTARTED=true" >> /install-markers/post-install-completed
|
||||
|
||||
echo ""
|
||||
echo "🎉 Auto post-install configuration completed successfully!"
|
||||
echo -e "${GREEN}⚔️ Your realm has been blessed and configured! ⚔️${NC}"
|
||||
echo -e "${GREEN}🏰 All post-installation rituals completed${NC}"
|
||||
echo -e "${GREEN}🗡️ Your realm awaits brave adventurers!${NC}"
|
||||
echo ""
|
||||
echo "📋 Summary of changes:"
|
||||
echo " ✅ AuthServer configured with production database settings"
|
||||
echo " ✅ WorldServer configured with production database settings"
|
||||
echo " ✅ Realmlist updated with server address: ${SERVER_ADDRESS}:${REALM_PORT}"
|
||||
echo " ✅ Services restarted to apply changes"
|
||||
echo " ✅ Completion marker created: /install-markers/post-install-completed"
|
||||
echo ""
|
||||
echo "🎮 Your AzerothCore server is now ready for production!"
|
||||
echo " Players can connect to: ${SERVER_ADDRESS}:${REALM_PORT}"
|
||||
echo ""
|
||||
echo "💡 Next steps:"
|
||||
echo " 1. Create admin accounts using the worldserver console"
|
||||
echo " 2. Test client connectivity"
|
||||
echo " 3. Configure any additional modules as needed"
|
||||
echo ""
|
||||
echo "🏃 Keeping container alive for future manual operations..."
|
||||
tail -f /dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
135
scripts/backup-scheduler.sh
Normal file → Executable file
135
scripts/backup-scheduler.sh
Normal file → Executable file
@@ -1,57 +1,104 @@
|
||||
#!/bin/bash
|
||||
# ac-compose
|
||||
set -e
|
||||
|
||||
echo "🔧 Starting enhanced backup service with hourly and daily schedules..."
|
||||
BACKUP_DIR_BASE="/backups"
|
||||
HOURLY_DIR="$BACKUP_DIR_BASE/hourly"
|
||||
DAILY_DIR="$BACKUP_DIR_BASE/daily"
|
||||
RETENTION_HOURS=${BACKUP_RETENTION_HOURS:-6}
|
||||
RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-3}
|
||||
DAILY_TIME=${BACKUP_DAILY_TIME:-09}
|
||||
MYSQL_PORT=${MYSQL_PORT:-3306}
|
||||
|
||||
# Install curl if not available (handle different package managers)
|
||||
# NOTE: curl is already available in mysql:8.0 base image, commenting out to fix operator precedence issue
|
||||
# microdnf install -y curl || yum install -y curl || apt-get update && apt-get install -y curl
|
||||
mkdir -p "$HOURLY_DIR" "$DAILY_DIR"
|
||||
|
||||
# Download backup scripts from GitHub
|
||||
echo "📥 Downloading backup scripts from GitHub..."
|
||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup.sh -o /tmp/backup.sh
|
||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup-hourly.sh -o /tmp/backup-hourly.sh
|
||||
curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/backup-daily.sh -o /tmp/backup-daily.sh
|
||||
chmod +x /tmp/backup.sh /tmp/backup-hourly.sh /tmp/backup-daily.sh
|
||||
log() { echo "[$(date '+%F %T')] $*"; }
|
||||
|
||||
# Wait for MySQL to be ready before starting backup service
|
||||
echo "⏳ Waiting for MySQL to be ready..."
|
||||
sleep 30
|
||||
# Build database list from env (include optional acore_playerbots if present)
|
||||
database_list() {
|
||||
local dbs=("${DB_AUTH_NAME}" "${DB_WORLD_NAME}" "${DB_CHARACTERS_NAME}")
|
||||
if mysql -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" -e "USE acore_playerbots;" >/dev/null 2>&1; then
|
||||
dbs+=("acore_playerbots")
|
||||
log "Detected optional database: acore_playerbots (will be backed up)"
|
||||
fi
|
||||
printf '%s\n' "${dbs[@]}"
|
||||
}
|
||||
|
||||
# Run initial daily backup
|
||||
echo "🚀 Running initial daily backup..."
|
||||
/tmp/backup-daily.sh
|
||||
run_backup() {
|
||||
local tier_dir="$1" # hourly or daily dir
|
||||
local tier_type="$2" # "hourly" or "daily"
|
||||
local ts=$(date '+%Y%m%d_%H%M%S')
|
||||
local target_dir="$tier_dir/$ts"
|
||||
mkdir -p "$target_dir"
|
||||
log "Starting ${tier_type} backup to $target_dir"
|
||||
|
||||
# Enhanced scheduler with hourly and daily backups
|
||||
echo "⏰ Starting enhanced backup scheduler:"
|
||||
echo " 📅 Daily backups: ${BACKUP_DAILY_TIME}:00 UTC (retention: ${BACKUP_RETENTION_DAYS} days)"
|
||||
echo " ⏰ Hourly backups: every hour (retention: ${BACKUP_RETENTION_HOURS} hours)"
|
||||
local -a dbs
|
||||
mapfile -t dbs < <(database_list)
|
||||
|
||||
# Track last backup times to avoid duplicates
|
||||
last_daily_hour=""
|
||||
last_hourly_minute=""
|
||||
for db in "${dbs[@]}"; do
|
||||
log "Backing up database: $db"
|
||||
if mysqldump \
|
||||
-h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" \
|
||||
--single-transaction --routines --triggers --events \
|
||||
--hex-blob --quick --lock-tables=false \
|
||||
--add-drop-database --databases "$db" \
|
||||
| gzip -c > "$target_dir/${db}.sql.gz"; then
|
||||
log "✅ Successfully backed up $db"
|
||||
else
|
||||
log "❌ Failed to back up $db"
|
||||
fi
|
||||
done
|
||||
|
||||
# Create backup manifest (parity with scripts/backup.sh and backup-hourly.sh)
|
||||
local size; size=$(du -sh "$target_dir" | cut -f1)
|
||||
local mysql_ver; mysql_ver=$(mysql -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" -e 'SELECT VERSION();' -s -N 2>/dev/null || echo "unknown")
|
||||
|
||||
if [ "$tier_type" = "hourly" ]; then
|
||||
cat > "$target_dir/manifest.json" <<EOF
|
||||
{
|
||||
"timestamp": "${ts}",
|
||||
"type": "hourly",
|
||||
"databases": [$(printf '"%s",' "${dbs[@]}" | sed 's/,$//')],
|
||||
"backup_size": "${size}",
|
||||
"retention_hours": ${RETENTION_HOURS},
|
||||
"mysql_version": "${mysql_ver}"
|
||||
}
|
||||
EOF
|
||||
else
|
||||
cat > "$target_dir/manifest.json" <<EOF
|
||||
{
|
||||
"timestamp": "${ts}",
|
||||
"type": "daily",
|
||||
"databases": [$(printf '"%s",' "${dbs[@]}" | sed 's/,$//')],
|
||||
"backup_size": "${size}",
|
||||
"retention_days": ${RETENTION_DAYS},
|
||||
"mysql_version": "${mysql_ver}"
|
||||
}
|
||||
EOF
|
||||
fi
|
||||
|
||||
log "Backup complete: $target_dir (size ${size})"
|
||||
}
|
||||
|
||||
cleanup_old() {
|
||||
find "$HOURLY_DIR" -mindepth 1 -maxdepth 1 -type d -mmin +$((RETENTION_HOURS*60)) -print -exec rm -rf {} + 2>/dev/null || true
|
||||
find "$DAILY_DIR" -mindepth 1 -maxdepth 1 -type d -mtime +$RETENTION_DAYS -print -exec rm -rf {} + 2>/dev/null || true
|
||||
}
|
||||
|
||||
log "Backup scheduler starting: hourly($RETENTION_HOURS h), daily($RETENTION_DAYS d at ${DAILY_TIME}:00)"
|
||||
|
||||
while true; do
|
||||
current_hour=$(date +%H)
|
||||
current_minute=$(date +%M)
|
||||
current_time="$current_hour:$current_minute"
|
||||
minute=$(date '+%M')
|
||||
hour=$(date '+%H')
|
||||
|
||||
# Daily backup check (configurable time)
|
||||
if [ "$current_hour" = "${BACKUP_DAILY_TIME}" ] && [ "$current_minute" = "00" ] && [ "$last_daily_hour" != "$current_hour" ]; then
|
||||
echo "📅 [$(date)] Daily backup time reached, running daily backup..."
|
||||
/tmp/backup-daily.sh
|
||||
last_daily_hour="$current_hour"
|
||||
# Sleep for 2 minutes to avoid running multiple times
|
||||
sleep 120
|
||||
# Hourly backup check (every hour at minute 0, except during daily backup)
|
||||
elif [ "$current_minute" = "00" ] && [ "$current_hour" != "${BACKUP_DAILY_TIME}" ] && [ "$last_hourly_minute" != "$current_minute" ]; then
|
||||
echo "⏰ [$(date)] Hourly backup time reached, running hourly backup..."
|
||||
/tmp/backup-hourly.sh
|
||||
last_hourly_minute="$current_minute"
|
||||
# Sleep for 2 minutes to avoid running multiple times
|
||||
sleep 120
|
||||
else
|
||||
# Sleep for 1 minute before checking again
|
||||
sleep 60
|
||||
if [ "$minute" = "00" ]; then
|
||||
run_backup "$HOURLY_DIR" "hourly"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$hour" = "$DAILY_TIME" ] && [ "$minute" = "00" ]; then
|
||||
run_backup "$DAILY_DIR" "daily"
|
||||
fi
|
||||
|
||||
cleanup_old
|
||||
sleep 60
|
||||
done
|
||||
|
||||
@@ -1,6 +1,49 @@
|
||||
#!/bin/bash
|
||||
# ac-compose
|
||||
set -e
|
||||
|
||||
print_help() {
|
||||
cat <<'EOF'
|
||||
Usage: db-import-conditional.sh [options]
|
||||
|
||||
Description:
|
||||
Conditionally restores AzerothCore databases from backups if available;
|
||||
otherwise creates fresh databases and runs the dbimport tool to populate
|
||||
schemas. Uses status markers to prevent overwriting restored data.
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message and exit
|
||||
|
||||
Environment variables:
|
||||
CONTAINER_MYSQL Hostname of the MySQL container (default: ac-mysql)
|
||||
MYSQL_PORT MySQL port (default: 3306)
|
||||
MYSQL_USER MySQL user (default: root)
|
||||
MYSQL_ROOT_PASSWORD MySQL password for the user above
|
||||
DB_AUTH_NAME Auth DB name (default: acore_auth)
|
||||
DB_WORLD_NAME World DB name (default: acore_world)
|
||||
DB_CHARACTERS_NAME Characters DB name (default: acore_characters)
|
||||
BACKUP DIRS Uses /backups/{daily,timestamped} if present
|
||||
STATUS MARKERS Uses /var/lib/mysql-persistent/.restore-*
|
||||
|
||||
Notes:
|
||||
- If a valid backup is detected and successfully restored, schema import is skipped.
|
||||
- On fresh setups, the script creates databases and runs dbimport.
|
||||
EOF
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
-h|--help)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
"") ;;
|
||||
*)
|
||||
echo "Unknown option: $1" >&2
|
||||
print_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "🔧 Conditional AzerothCore Database Import"
|
||||
echo "========================================"
|
||||
|
||||
@@ -12,7 +55,6 @@ RESTORE_FAILED_MARKER="$RESTORE_STATUS_DIR/.restore-failed"
|
||||
RESTORE_SUCCESS_MARKER_TMP="$MARKER_STATUS_DIR/.restore-completed"
|
||||
RESTORE_FAILED_MARKER_TMP="$MARKER_STATUS_DIR/.restore-failed"
|
||||
|
||||
# Ensure we can write to the status directory, fallback to tmp
|
||||
mkdir -p "$RESTORE_STATUS_DIR" 2>/dev/null || true
|
||||
if ! touch "$RESTORE_STATUS_DIR/.test-write" 2>/dev/null; then
|
||||
echo "⚠️ Cannot write to $RESTORE_STATUS_DIR, using $MARKER_STATUS_DIR for markers"
|
||||
@@ -24,23 +66,16 @@ fi
|
||||
|
||||
echo "🔍 Checking restoration status..."
|
||||
|
||||
# Check if backup was successfully restored
|
||||
if [ -f "$RESTORE_SUCCESS_MARKER" ]; then
|
||||
echo "✅ Backup restoration completed successfully"
|
||||
echo "📄 Restoration details:"
|
||||
cat "$RESTORE_SUCCESS_MARKER"
|
||||
echo ""
|
||||
cat "$RESTORE_SUCCESS_MARKER" || true
|
||||
echo "🚫 Skipping database import - data already restored from backup"
|
||||
echo "💡 This prevents overwriting restored data with fresh schema"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if restoration failed (fresh databases created)
|
||||
if [ -f "$RESTORE_FAILED_MARKER" ]; then
|
||||
echo "ℹ️ No backup was restored - fresh databases detected"
|
||||
echo "📄 Database creation details:"
|
||||
cat "$RESTORE_FAILED_MARKER"
|
||||
echo ""
|
||||
cat "$RESTORE_FAILED_MARKER" || true
|
||||
echo "▶️ Proceeding with database import to populate fresh databases"
|
||||
else
|
||||
echo "⚠️ No restoration status found - assuming fresh installation"
|
||||
@@ -50,66 +85,11 @@ fi
|
||||
echo ""
|
||||
echo "🔧 Starting database import process..."
|
||||
|
||||
# First attempt backup restoration
|
||||
echo "🔍 Checking for backups to restore..."
|
||||
|
||||
BACKUP_DIRS="/backups"
|
||||
|
||||
|
||||
# Function to restore from backup (directory or single file)
|
||||
restore_from_directory() {
|
||||
local backup_path="$1"
|
||||
echo "🔄 Restoring from backup: $backup_path"
|
||||
|
||||
local restore_success=true
|
||||
|
||||
# Handle single .sql file (legacy backup)
|
||||
if [ -f "$backup_path" ] && [[ "$backup_path" == *.sql ]]; then
|
||||
echo "📥 Restoring legacy backup file: $(basename "$backup_path")"
|
||||
if timeout 300 mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} < "$backup_path"; then
|
||||
echo "✅ Successfully restored legacy backup"
|
||||
return 0
|
||||
else
|
||||
echo "❌ Failed to restore legacy backup"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Handle directory with .sql.gz files (modern timestamped backups)
|
||||
if [ -d "$backup_path" ]; then
|
||||
echo "🔄 Restoring from backup directory: $backup_path"
|
||||
# Restore each database backup
|
||||
for backup_file in "$backup_path"/*.sql.gz; do
|
||||
if [ -f "$backup_file" ]; then
|
||||
local db_name=$(basename "$backup_file" .sql.gz)
|
||||
echo "📥 Restoring database: $db_name"
|
||||
|
||||
if timeout 300 zcat "$backup_file" | mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD}; then
|
||||
echo "✅ Successfully restored $db_name"
|
||||
else
|
||||
echo "❌ Failed to restore $db_name"
|
||||
restore_success=false
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$restore_success" = true ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we get here, backup_path is neither a valid .sql file nor a directory
|
||||
echo "❌ Invalid backup path: $backup_path (not a .sql file or directory)"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Attempt backup restoration with full functionality restored
|
||||
echo "🔄 Checking for backups..."
|
||||
backup_path=""
|
||||
|
||||
# Priority 1: Legacy single backup file with content validation
|
||||
echo "🔍 Checking for legacy backup file..."
|
||||
if [ -f "/var/lib/mysql-persistent/backup.sql" ]; then
|
||||
echo "📄 Found legacy backup file, validating content..."
|
||||
@@ -123,52 +103,40 @@ else
|
||||
echo "🔍 No legacy backup found"
|
||||
fi
|
||||
|
||||
# Priority 2: Modern timestamped backups (only if no legacy backup found)
|
||||
if [ -z "$backup_path" ] && [ -d "$BACKUP_DIRS" ]; then
|
||||
echo "📁 Backup directory exists, checking for timestamped backups..."
|
||||
if [ "$(ls -A $BACKUP_DIRS 2>/dev/null | wc -l)" -gt 0 ]; then
|
||||
# Check daily backups first
|
||||
if [ -d "$BACKUP_DIRS/daily" ] && [ "$(ls -A $BACKUP_DIRS/daily 2>/dev/null | wc -l)" -gt 0 ]; then
|
||||
echo "📅 Found daily backup directory, finding latest..."
|
||||
latest_daily=$(ls -1t $BACKUP_DIRS/daily 2>/dev/null | head -n 1)
|
||||
if [ -n "$(ls -A "$BACKUP_DIRS" 2>/dev/null)" ]; then
|
||||
if [ -d "$BACKUP_DIRS/daily" ]; then
|
||||
echo "🔍 Checking for daily backups..."
|
||||
latest_daily=$(ls -1t "$BACKUP_DIRS/daily" 2>/dev/null | head -n 1)
|
||||
if [ -n "$latest_daily" ] && [ -d "$BACKUP_DIRS/daily/$latest_daily" ]; then
|
||||
echo "📦 Checking backup directory: $latest_daily"
|
||||
# Check if directory has .sql.gz files
|
||||
if ls "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz >/dev/null 2>&1; then
|
||||
# Validate at least one backup file has content
|
||||
echo "🔍 Validating backup content..."
|
||||
for backup_file in "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz; do
|
||||
if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then
|
||||
# Use timeout to prevent hanging on zcat
|
||||
if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then
|
||||
echo "✅ Valid backup found: $(basename $backup_file)"
|
||||
backup_path="$BACKUP_DIRS/daily/$latest_daily"
|
||||
break
|
||||
fi
|
||||
echo "📦 Latest daily backup found: $latest_daily"
|
||||
for backup_file in "$BACKUP_DIRS/daily/$latest_daily"/*.sql.gz; do
|
||||
if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then
|
||||
if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then
|
||||
echo "✅ Valid daily backup file: $(basename "$backup_file")"
|
||||
backup_path="$BACKUP_DIRS/daily/$latest_daily"
|
||||
break
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "⚠️ No .sql.gz files found in backup directory"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "📅 No daily backup directory found"
|
||||
fi
|
||||
else
|
||||
echo "📅 No daily backup directory found"
|
||||
# Check for timestamped backup directories (legacy format: YYYYMMDD_HHMMSS)
|
||||
echo "🔍 Checking for timestamped backup directories..."
|
||||
timestamped_backups=$(ls -1t $BACKUP_DIRS 2>/dev/null | grep -E '^[0-9]{8}_[0-9]{6}$' | head -n 1)
|
||||
if [ -n "$timestamped_backups" ]; then
|
||||
latest_timestamped="$timestamped_backups"
|
||||
echo "📦 Found timestamped backup: $latest_timestamped"
|
||||
if [ -d "$BACKUP_DIRS/$latest_timestamped" ]; then
|
||||
# Check if directory has .sql.gz files
|
||||
if ls "$BACKUP_DIRS/$latest_timestamped"/*.sql.gz >/dev/null 2>&1; then
|
||||
# Validate at least one backup file has content
|
||||
echo "🔍 Validating timestamped backup content..."
|
||||
for backup_file in "$BACKUP_DIRS/$latest_timestamped"/*.sql.gz; do
|
||||
if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then
|
||||
# Use timeout to prevent hanging on zcat
|
||||
if timeout 10 zcat "$backup_file" 2>/dev/null | head -20 | grep -q "CREATE DATABASE\|INSERT INTO\|CREATE TABLE"; then
|
||||
echo "✅ Valid timestamped backup found: $(basename $backup_file)"
|
||||
echo "✅ Valid timestamped backup found: $(basename "$backup_file")"
|
||||
backup_path="$BACKUP_DIRS/$latest_timestamped"
|
||||
break
|
||||
fi
|
||||
@@ -191,71 +159,47 @@ fi
|
||||
|
||||
echo "🔄 Final backup path result: '$backup_path'"
|
||||
if [ -n "$backup_path" ]; then
|
||||
echo "📦 Found backup: $(basename $backup_path)"
|
||||
if restore_from_directory "$backup_path"; then
|
||||
echo "✅ Database restoration completed successfully!"
|
||||
echo "$(date): Backup successfully restored from $backup_path" > "$RESTORE_SUCCESS_MARKER"
|
||||
echo "🚫 Skipping schema import - data already restored from backup"
|
||||
exit 0
|
||||
else
|
||||
echo "❌ Backup restoration failed - proceeding with fresh setup"
|
||||
echo "$(date): Backup restoration failed - proceeding with fresh setup" > "$RESTORE_FAILED_MARKER"
|
||||
echo "📦 Found backup: $(basename "$backup_path")"
|
||||
if [ -d "$backup_path" ]; then
|
||||
echo "🔄 Restoring from backup directory: $backup_path"
|
||||
restore_success=true
|
||||
for backup_file in "$backup_path"/*.sql.gz; do
|
||||
if [ -f "$backup_file" ]; then
|
||||
if timeout 300 zcat "$backup_file" | mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD}; then
|
||||
echo "✅ Restored $(basename "$backup_file")"
|
||||
else
|
||||
echo "❌ Failed to restore $(basename "$backup_file")"; restore_success=false
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ "$restore_success" = true ]; then
|
||||
echo "$(date): Backup successfully restored from $backup_path" > "$RESTORE_SUCCESS_MARKER"
|
||||
exit 0
|
||||
else
|
||||
echo "$(date): Backup restoration failed - proceeding with fresh setup" > "$RESTORE_FAILED_MARKER"
|
||||
fi
|
||||
elif [ -f "$backup_path" ]; then
|
||||
echo "🔄 Restoring from backup file: $backup_path"
|
||||
if timeout 300 mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} < "$backup_path"; then
|
||||
echo "$(date): Backup successfully restored from $backup_path" > "$RESTORE_SUCCESS_MARKER"
|
||||
exit 0
|
||||
else
|
||||
echo "$(date): Backup restoration failed - proceeding with fresh setup" > "$RESTORE_FAILED_MARKER"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "ℹ️ No valid backups found - proceeding with fresh setup"
|
||||
echo "$(date): No backup found - fresh setup needed" > "$RESTORE_FAILED_MARKER"
|
||||
fi
|
||||
|
||||
# Create fresh databases if restoration didn't happen
|
||||
echo "🗄️ Creating fresh AzerothCore databases..."
|
||||
mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "
|
||||
CREATE DATABASE IF NOT EXISTS ${DB_AUTH_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE DATABASE IF NOT EXISTS ${DB_WORLD_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE DATABASE IF NOT EXISTS ${DB_CHARACTERS_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
SHOW DATABASES;" || {
|
||||
echo "❌ Failed to create databases"
|
||||
exit 1
|
||||
}
|
||||
SHOW DATABASES;" || { echo "❌ Failed to create databases"; exit 1; }
|
||||
echo "✅ Fresh databases created - proceeding with schema import"
|
||||
|
||||
# Wait for databases to be ready (they should exist now)
|
||||
echo "⏳ Verifying databases are accessible..."
|
||||
for i in $(seq 1 10); do
|
||||
if mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "USE ${DB_AUTH_NAME}; USE ${DB_WORLD_NAME}; USE ${DB_CHARACTERS_NAME};" >/dev/null 2>&1; then
|
||||
echo "✅ All databases accessible"
|
||||
break
|
||||
fi
|
||||
echo "⏳ Waiting for databases... attempt $i/10"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Verify databases are actually empty before importing
|
||||
echo "🔍 Verifying databases are empty before import..."
|
||||
check_table_count() {
|
||||
local db_name="$1"
|
||||
local count=$(mysql -h ${CONTAINER_MYSQL} -u${MYSQL_USER} -p${MYSQL_ROOT_PASSWORD} -e "
|
||||
SELECT COUNT(*) FROM information_schema.tables
|
||||
WHERE table_schema='$db_name' AND table_type='BASE TABLE';" -s -N 2>/dev/null || echo "0")
|
||||
echo "$count"
|
||||
}
|
||||
|
||||
auth_tables=$(check_table_count "${DB_AUTH_NAME}")
|
||||
world_tables=$(check_table_count "${DB_WORLD_NAME}")
|
||||
char_tables=$(check_table_count "${DB_CHARACTERS_NAME}")
|
||||
|
||||
echo "📊 Current table counts:"
|
||||
echo " ${DB_AUTH_NAME}: $auth_tables tables"
|
||||
echo " ${DB_WORLD_NAME}: $world_tables tables"
|
||||
echo " ${DB_CHARACTERS_NAME}: $char_tables tables"
|
||||
|
||||
# Warn if databases appear to have data
|
||||
if [ "$auth_tables" -gt 5 ] || [ "$world_tables" -gt 50 ] || [ "$char_tables" -gt 5 ]; then
|
||||
echo "⚠️ WARNING: Databases appear to contain data!"
|
||||
echo "⚠️ Import may overwrite existing data. Consider backing up first."
|
||||
echo "⚠️ Continuing in 10 seconds... (Ctrl+C to cancel)"
|
||||
sleep 10
|
||||
fi
|
||||
|
||||
echo "📝 Creating dbimport configuration..."
|
||||
mkdir -p /azerothcore/env/dist/etc
|
||||
cat > /azerothcore/env/dist/etc/dbimport.conf <<EOF
|
||||
@@ -264,68 +208,17 @@ WorldDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT
|
||||
CharacterDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
|
||||
Updates.EnableDatabases = 7
|
||||
Updates.AutoSetup = 1
|
||||
|
||||
# Required configuration properties
|
||||
MySQLExecutable = ""
|
||||
TempDir = ""
|
||||
SourceDirectory = ""
|
||||
Updates.AllowedModules = "all"
|
||||
LoginDatabase.WorkerThreads = 1
|
||||
LoginDatabase.SynchThreads = 1
|
||||
WorldDatabase.WorkerThreads = 1
|
||||
WorldDatabase.SynchThreads = 1
|
||||
CharacterDatabase.WorkerThreads = 1
|
||||
CharacterDatabase.SynchThreads = 1
|
||||
Updates.Redundancy = 1
|
||||
Updates.AllowRehash = 1
|
||||
Updates.ArchivedRedundancy = 0
|
||||
Updates.CleanDeadRefMaxCount = 3
|
||||
|
||||
# Logging configuration
|
||||
Appender.Console=1,3,6
|
||||
Logger.root=3,Console
|
||||
EOF
|
||||
|
||||
echo "🚀 Running database import..."
|
||||
cd /azerothcore/env/dist/bin
|
||||
|
||||
# Run dbimport with error handling
|
||||
if ./dbimport; then
|
||||
echo "✅ Database import completed successfully!"
|
||||
|
||||
# Create import completion marker
|
||||
if touch "$RESTORE_STATUS_DIR/.import-completed" 2>/dev/null; then
|
||||
echo "$(date): Database import completed successfully" > "$RESTORE_STATUS_DIR/.import-completed"
|
||||
else
|
||||
echo "$(date): Database import completed successfully" > "$MARKER_STATUS_DIR/.import-completed"
|
||||
echo "⚠️ Using temporary location for completion marker"
|
||||
fi
|
||||
|
||||
# Verify import was successful
|
||||
echo "🔍 Verifying import results..."
|
||||
auth_tables_after=$(check_table_count "${DB_AUTH_NAME}")
|
||||
world_tables_after=$(check_table_count "${DB_WORLD_NAME}")
|
||||
char_tables_after=$(check_table_count "${DB_CHARACTERS_NAME}")
|
||||
|
||||
echo "📊 Post-import table counts:"
|
||||
echo " ${DB_AUTH_NAME}: $auth_tables_after tables"
|
||||
echo " ${DB_WORLD_NAME}: $world_tables_after tables"
|
||||
echo " ${DB_CHARACTERS_NAME}: $char_tables_after tables"
|
||||
|
||||
if [ "$auth_tables_after" -gt 0 ] && [ "$world_tables_after" -gt 0 ]; then
|
||||
echo "✅ Import verification successful - databases populated"
|
||||
else
|
||||
echo "⚠️ Import verification failed - databases may be empty"
|
||||
fi
|
||||
echo "$(date): Database import completed successfully" > "$RESTORE_STATUS_DIR/.import-completed" || echo "$(date): Database import completed successfully" > "$MARKER_STATUS_DIR/.import-completed"
|
||||
else
|
||||
echo "❌ Database import failed!"
|
||||
if touch "$RESTORE_STATUS_DIR/.import-failed" 2>/dev/null; then
|
||||
echo "$(date): Database import failed" > "$RESTORE_STATUS_DIR/.import-failed"
|
||||
else
|
||||
echo "$(date): Database import failed" > "$MARKER_STATUS_DIR/.import-failed"
|
||||
echo "⚠️ Using temporary location for failed marker"
|
||||
fi
|
||||
echo "$(date): Database import failed" > "$RESTORE_STATUS_DIR/.import-failed" || echo "$(date): Database import failed" > "$MARKER_STATUS_DIR/.import-failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🎉 Database import process complete!"
|
||||
echo "🎉 Database import process complete!"
|
||||
|
||||
116
scripts/deploy-tools.sh
Executable file
116
scripts/deploy-tools.sh
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ac-compose helper to deploy phpMyAdmin and Keira3 tooling.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.."
|
||||
COMPOSE_FILE="$ROOT_DIR/compose.yml"
|
||||
ENV_FILE="$ROOT_DIR/.env"
|
||||
|
||||
BLUE='\033[0;34m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
info(){ echo -e "${BLUE}ℹ️ $*${NC}"; }
|
||||
ok(){ echo -e "${GREEN}✅ $*${NC}"; }
|
||||
warn(){ echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||||
err(){ echo -e "${RED}❌ $*${NC}"; }
|
||||
|
||||
read_env(){
|
||||
local key="$1" default="${2:-}" value=""
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
value="$(grep -E "^${key}=" "$ENV_FILE" 2>/dev/null | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||
fi
|
||||
if [ -z "$value" ]; then
|
||||
value="$default"
|
||||
fi
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
resolve_project_name(){
|
||||
local raw_name sanitized
|
||||
raw_name="$(read_env COMPOSE_PROJECT_NAME "acore-compose")"
|
||||
sanitized="$(echo "$raw_name" | tr '[:upper:]' '[:lower:]')"
|
||||
sanitized="${sanitized// /-}"
|
||||
sanitized="$(echo "$sanitized" | tr -cd 'a-z0-9_-')"
|
||||
if [[ -z "$sanitized" ]]; then
|
||||
sanitized="acore-compose"
|
||||
elif [[ ! "$sanitized" =~ ^[a-z0-9] ]]; then
|
||||
sanitized="ac${sanitized}"
|
||||
fi
|
||||
echo "$sanitized"
|
||||
}
|
||||
|
||||
compose(){
|
||||
docker compose --project-name "$PROJECT_NAME" -f "$COMPOSE_FILE" "$@"
|
||||
}
|
||||
|
||||
show_header(){
|
||||
echo -e "\n${BLUE} 🛠️ TOOLING DEPLOYMENT 🛠️${NC}"
|
||||
echo -e "${BLUE} ═══════════════════════════${NC}"
|
||||
echo -e "${BLUE} 📊 Enabling Management UIs 📊${NC}\n"
|
||||
}
|
||||
|
||||
ensure_command(){
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
err "Required command '$1' not found in PATH."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_mysql_running(){
|
||||
local mysql_service="ac-mysql"
|
||||
local mysql_container
|
||||
mysql_container="$(read_env CONTAINER_MYSQL "ac-mysql")"
|
||||
if docker ps --format '{{.Names}}' | grep -qx "$mysql_container"; then
|
||||
info "MySQL container '$mysql_container' already running."
|
||||
return
|
||||
fi
|
||||
info "Starting database service '$mysql_service'..."
|
||||
compose --profile db up -d "$mysql_service" >/dev/null
|
||||
ok "Database service ready."
|
||||
}
|
||||
|
||||
start_tools(){
|
||||
info "Starting phpMyAdmin and Keira3..."
|
||||
compose --profile tools up --detach --quiet-pull >/dev/null
|
||||
ok "Tooling services are online."
|
||||
}
|
||||
|
||||
show_endpoints(){
|
||||
local pma_port keira_port
|
||||
pma_port="$(read_env PMA_EXTERNAL_PORT 8081)"
|
||||
keira_port="$(read_env KEIRA3_EXTERNAL_PORT 4201)"
|
||||
echo ""
|
||||
echo -e "${GREEN}Accessible endpoints:${NC}"
|
||||
echo " • phpMyAdmin : http://localhost:${pma_port}"
|
||||
echo " • Keira3 : http://localhost:${keira_port}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
main(){
|
||||
if [[ "${1:-}" == "--help" ]]; then
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0")
|
||||
|
||||
Ensures the database service is running and launches the tooling profile
|
||||
containing phpMyAdmin and Keira3 dashboards.
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ensure_command docker
|
||||
docker info >/dev/null 2>&1 || { err "Docker daemon unavailable."; exit 1; }
|
||||
|
||||
PROJECT_NAME="$(resolve_project_name)"
|
||||
|
||||
show_header
|
||||
ensure_mysql_running
|
||||
start_tools
|
||||
show_endpoints
|
||||
}
|
||||
|
||||
main "$@"
|
||||
207
scripts/download-client-data.sh
Normal file → Executable file
207
scripts/download-client-data.sh
Normal file → Executable file
@@ -1,32 +1,40 @@
|
||||
#!/bin/bash
|
||||
# ac-compose
|
||||
set -e
|
||||
|
||||
echo '🚀 Starting AzerothCore game data setup...'
|
||||
|
||||
# Get the latest release info from wowgaming/client-data
|
||||
echo '📡 Fetching latest client data release info...'
|
||||
RELEASE_INFO=$(wget -qO- https://api.github.com/repos/wowgaming/client-data/releases/latest 2>/dev/null)
|
||||
REQUESTED_TAG="${CLIENT_DATA_VERSION:-}"
|
||||
if [ -n "$REQUESTED_TAG" ]; then
|
||||
echo "📌 Using requested client data version: $REQUESTED_TAG"
|
||||
LATEST_TAG="$REQUESTED_TAG"
|
||||
LATEST_URL="https://github.com/wowgaming/client-data/releases/download/${REQUESTED_TAG}/data.zip"
|
||||
else
|
||||
echo '📡 Fetching latest client data release info...'
|
||||
RELEASE_INFO=$(wget -qO- https://api.github.com/repos/wowgaming/client-data/releases/latest 2>/dev/null)
|
||||
|
||||
if [ -n "$RELEASE_INFO" ]; then
|
||||
LATEST_URL=$(echo "$RELEASE_INFO" | grep '"browser_download_url":' | grep '\.zip' | cut -d'"' -f4 | head -1)
|
||||
LATEST_TAG=$(echo "$RELEASE_INFO" | grep '"tag_name":' | cut -d'"' -f4)
|
||||
LATEST_SIZE=$(echo "$RELEASE_INFO" | grep '"size":' | head -1 | grep -o '[0-9]*')
|
||||
fi
|
||||
if [ -n "$RELEASE_INFO" ]; then
|
||||
LATEST_URL=$(echo "$RELEASE_INFO" | grep '"browser_download_url":' | grep '\.zip' | cut -d'"' -f4 | head -1)
|
||||
LATEST_TAG=$(echo "$RELEASE_INFO" | grep '"tag_name":' | cut -d'"' -f4)
|
||||
LATEST_SIZE=$(echo "$RELEASE_INFO" | grep '"size":' | head -1 | grep -o '[0-9]*')
|
||||
fi
|
||||
|
||||
if [ -z "$LATEST_URL" ]; then
|
||||
echo '❌ Could not fetch latest release URL'
|
||||
echo '📥 Using fallback: direct download from v16 release'
|
||||
LATEST_URL='https://github.com/wowgaming/client-data/releases/download/v16/data.zip'
|
||||
LATEST_TAG='v16'
|
||||
LATEST_SIZE='0'
|
||||
echo '❌ Could not fetch client-data release information. Aborting.'
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "📍 Latest release: $LATEST_TAG"
|
||||
echo "📥 Download URL: $LATEST_URL"
|
||||
|
||||
# Cache file paths
|
||||
CACHE_FILE="/cache/client-data-$LATEST_TAG.zip"
|
||||
VERSION_FILE="/cache/client-data-version.txt"
|
||||
CACHE_DIR="/cache"
|
||||
mkdir -p "$CACHE_DIR"
|
||||
CACHE_FILE="${CACHE_DIR}/client-data-${LATEST_TAG}.zip"
|
||||
TMP_FILE="${CACHE_FILE}.tmp"
|
||||
VERSION_FILE="${CACHE_DIR}/client-data-version.txt"
|
||||
|
||||
# Check if we have a cached version
|
||||
if [ -f "$CACHE_FILE" ] && [ -f "$VERSION_FILE" ]; then
|
||||
@@ -36,7 +44,22 @@ if [ -f "$CACHE_FILE" ] && [ -f "$VERSION_FILE" ]; then
|
||||
echo "📊 Cached file size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')"
|
||||
|
||||
# Verify cache file integrity
|
||||
if unzip -t "$CACHE_FILE" > /dev/null 2>&1; then
|
||||
echo "🔍 Verifying cached file integrity..."
|
||||
CACHE_INTEGRITY_OK=false
|
||||
|
||||
if command -v 7z >/dev/null 2>&1; then
|
||||
if 7z t "$CACHE_FILE" >/dev/null 2>&1; then
|
||||
CACHE_INTEGRITY_OK=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$CACHE_INTEGRITY_OK" = "false" ]; then
|
||||
if unzip -t "$CACHE_FILE" > /dev/null 2>&1; then
|
||||
CACHE_INTEGRITY_OK=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$CACHE_INTEGRITY_OK" = "true" ]; then
|
||||
echo "✅ Cache file integrity verified"
|
||||
echo "⚡ Using cached download - skipping download phase"
|
||||
cp "$CACHE_FILE" data.zip
|
||||
@@ -47,140 +70,90 @@ if [ -f "$CACHE_FILE" ] && [ -f "$VERSION_FILE" ]; then
|
||||
else
|
||||
echo "📦 Cache version ($CACHED_VERSION) differs from latest ($LATEST_TAG)"
|
||||
echo "🗑️ Removing old cache"
|
||||
rm -f /cache/client-data-*.zip "$VERSION_FILE"
|
||||
rm -f "${CACHE_DIR}"/client-data-*.zip "$VERSION_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Download if we don't have a valid cached file
|
||||
if [ ! -f "data.zip" ]; then
|
||||
echo "📥 Downloading client data (~15GB, may take 10-30 minutes)..."
|
||||
echo "📥 Downloading client data (~15GB)..."
|
||||
echo "📍 Source: $LATEST_URL"
|
||||
|
||||
# Download with clean progress indication
|
||||
echo "📥 Starting download..."
|
||||
wget --progress=dot:giga -O "$CACHE_FILE.tmp" "$LATEST_URL" 2>&1 | sed 's/^/📊 /' || {
|
||||
echo '❌ wget failed, trying curl...'
|
||||
curl -L --progress-bar -o "$CACHE_FILE.tmp" "$LATEST_URL" || {
|
||||
echo '❌ All download methods failed'
|
||||
rm -f "$CACHE_FILE.tmp"
|
||||
exit 1
|
||||
if command -v aria2c >/dev/null 2>&1; then
|
||||
aria2c --max-connection-per-server=8 --split=8 --min-split-size=10M \
|
||||
--summary-interval=5 --download-result=hide \
|
||||
--console-log-level=warn --show-console-readout=false \
|
||||
--dir "$CACHE_DIR" -o "$(basename "$TMP_FILE")" "$LATEST_URL" || {
|
||||
echo '⚠️ aria2c failed, falling back to wget...'
|
||||
wget --progress=dot:giga -O "$TMP_FILE" "$LATEST_URL" 2>&1 | sed 's/^/📊 /' || {
|
||||
echo '❌ wget failed, trying curl...'
|
||||
curl -L --progress-bar -o "$TMP_FILE" "$LATEST_URL" || {
|
||||
echo '❌ All download methods failed'
|
||||
rm -f "$TMP_FILE"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
echo "📥 Using wget (aria2c not available)..."
|
||||
wget --progress=dot:giga -O "$TMP_FILE" "$LATEST_URL" 2>&1 | sed 's/^/📊 /' || {
|
||||
echo '❌ wget failed, trying curl...'
|
||||
curl -L --progress-bar -o "$TMP_FILE" "$LATEST_URL" || {
|
||||
echo '❌ All download methods failed'
|
||||
rm -f "$TMP_FILE"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
fi
|
||||
|
||||
# Verify download integrity
|
||||
if unzip -t "$CACHE_FILE.tmp" > /dev/null 2>&1; then
|
||||
mv "$CACHE_FILE.tmp" "$CACHE_FILE"
|
||||
echo "🔍 Verifying download integrity..."
|
||||
INTEGRITY_OK=false
|
||||
|
||||
if command -v 7z >/dev/null 2>&1; then
|
||||
if 7z t "$TMP_FILE" >/dev/null 2>&1; then
|
||||
INTEGRITY_OK=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$INTEGRITY_OK" = "false" ]; then
|
||||
if unzip -t "$TMP_FILE" > /dev/null 2>&1; then
|
||||
INTEGRITY_OK=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$INTEGRITY_OK" = "true" ]; then
|
||||
mv "$TMP_FILE" "$CACHE_FILE"
|
||||
echo "$LATEST_TAG" > "$VERSION_FILE"
|
||||
echo '✅ Download completed and verified'
|
||||
echo "📊 File size: $(ls -lh "$CACHE_FILE" | awk '{print $5}')"
|
||||
cp "$CACHE_FILE" data.zip
|
||||
else
|
||||
echo '❌ Downloaded file is corrupted'
|
||||
rm -f "$CACHE_FILE.tmp"
|
||||
rm -f "$TMP_FILE"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo '📂 Extracting client data (this may take 10-15 minutes)...'
|
||||
echo '⏳ Please wait while extracting...'
|
||||
|
||||
# Clear existing data if extraction failed previously
|
||||
echo '📂 Extracting client data (this may take some minutes)...'
|
||||
rm -rf /azerothcore/data/maps /azerothcore/data/vmaps /azerothcore/data/mmaps /azerothcore/data/dbc
|
||||
|
||||
# Extract with detailed progress tracking
|
||||
echo '🔄 Starting extraction with progress monitoring...'
|
||||
|
||||
# Start extraction in background with overwrite
|
||||
unzip -o -q data.zip -d /azerothcore/data/ &
|
||||
|
||||
UNZIP_PID=$!
|
||||
LAST_CHECK_TIME=0
|
||||
|
||||
# Monitor progress with directory size checks
|
||||
while kill -0 "$UNZIP_PID" 2>/dev/null; do
|
||||
CURRENT_TIME=$(date +%s)
|
||||
if [ $((CURRENT_TIME - LAST_CHECK_TIME)) -ge 30 ]; then
|
||||
LAST_CHECK_TIME=$CURRENT_TIME
|
||||
|
||||
# Check what's been extracted so far
|
||||
PROGRESS_MSG="📊 Progress at $(date '+%H:%M:%S'):"
|
||||
|
||||
if [ -d "/azerothcore/data/dbc" ] && [ -n "$(ls -A /azerothcore/data/dbc 2>/dev/null)" ]; then
|
||||
DBC_SIZE=$(du -sh /azerothcore/data/dbc 2>/dev/null | cut -f1)
|
||||
PROGRESS_MSG="$PROGRESS_MSG DBC($DBC_SIZE)"
|
||||
fi
|
||||
|
||||
if [ -d "/azerothcore/data/maps" ] && [ -n "$(ls -A /azerothcore/data/maps 2>/dev/null)" ]; then
|
||||
MAPS_SIZE=$(du -sh /azerothcore/data/maps 2>/dev/null | cut -f1)
|
||||
PROGRESS_MSG="$PROGRESS_MSG Maps($MAPS_SIZE)"
|
||||
fi
|
||||
|
||||
if [ -d "/azerothcore/data/vmaps" ] && [ -n "$(ls -A /azerothcore/data/vmaps 2>/dev/null)" ]; then
|
||||
VMAPS_SIZE=$(du -sh /azerothcore/data/vmaps 2>/dev/null | cut -f1)
|
||||
PROGRESS_MSG="$PROGRESS_MSG VMaps($VMAPS_SIZE)"
|
||||
fi
|
||||
|
||||
if [ -d "/azerothcore/data/mmaps" ] && [ -n "$(ls -A /azerothcore/data/mmaps 2>/dev/null)" ]; then
|
||||
MMAPS_SIZE=$(du -sh /azerothcore/data/mmaps 2>/dev/null | cut -f1)
|
||||
PROGRESS_MSG="$PROGRESS_MSG MMaps($MMAPS_SIZE)"
|
||||
fi
|
||||
|
||||
echo "$PROGRESS_MSG"
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
|
||||
wait "$UNZIP_PID"
|
||||
UNZIP_EXIT_CODE=$?
|
||||
|
||||
if [ $UNZIP_EXIT_CODE -ne 0 ]; then
|
||||
echo '❌ Extraction failed'
|
||||
rm -f data.zip
|
||||
exit 1
|
||||
if command -v 7z >/dev/null 2>&1; then
|
||||
7z x -aoa -o/azerothcore/data/ data.zip >/dev/null 2>&1
|
||||
else
|
||||
unzip -o -q data.zip -d /azerothcore/data/
|
||||
fi
|
||||
|
||||
# Handle nested Data directory issue - move contents if extracted to Data subdirectory
|
||||
if [ -d "/azerothcore/data/Data" ] && [ -n "$(ls -A /azerothcore/data/Data 2>/dev/null)" ]; then
|
||||
echo '🔧 Fixing data directory structure (moving from Data/ subdirectory)...'
|
||||
|
||||
# Move all contents from Data subdirectory to the root data directory
|
||||
for item in /azerothcore/data/Data/*; do
|
||||
if [ -e "$item" ]; then
|
||||
mv "$item" /azerothcore/data/ 2>/dev/null || {
|
||||
echo "⚠️ Could not move $(basename "$item"), using copy instead..."
|
||||
cp -r "$item" /azerothcore/data/
|
||||
rm -rf "$item"
|
||||
}
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove empty Data directory
|
||||
rmdir /azerothcore/data/Data 2>/dev/null || true
|
||||
echo '✅ Data directory structure fixed'
|
||||
fi
|
||||
|
||||
# Clean up temporary extraction file (keep cached version)
|
||||
rm -f data.zip
|
||||
|
||||
echo '✅ Client data extraction complete!'
|
||||
echo '📁 Verifying extracted directories:'
|
||||
|
||||
# Verify required directories exist and have content
|
||||
ALL_GOOD=true
|
||||
for dir in maps vmaps mmaps dbc; do
|
||||
if [ -d "/azerothcore/data/$dir" ] && [ -n "$(ls -A /azerothcore/data/$dir 2>/dev/null)" ]; then
|
||||
DIR_SIZE=$(du -sh /azerothcore/data/$dir 2>/dev/null | cut -f1)
|
||||
echo "✅ $dir directory: OK ($DIR_SIZE)"
|
||||
else
|
||||
echo "❌ $dir directory: MISSING or EMPTY"
|
||||
ALL_GOOD=false
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$ALL_GOOD" = "true" ]; then
|
||||
echo '🎉 Game data setup complete! AzerothCore worldserver can now start.'
|
||||
echo "💾 Cached version $LATEST_TAG for future use"
|
||||
else
|
||||
echo '❌ Some directories are missing or empty'
|
||||
exit 1
|
||||
fi
|
||||
echo '🎉 Game data setup complete! AzerothCore worldserver can now start.'
|
||||
|
||||
46
scripts/import-backup.sh
Executable file
46
scripts/import-backup.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
# Restore auth/characters/world databases from a backup folder.
|
||||
set -euo pipefail
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
Usage: $0 <backup_dir>
|
||||
<backup_dir> should contain acore_auth.sql.gz, acore_characters.sql.gz, acore_world.sql.gz
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
usage; exit 1
|
||||
fi
|
||||
|
||||
BACKUP_DIR="$1"
|
||||
MYSQL_PW="${MYSQL_ROOT_PASSWORD:-azerothcore123}"
|
||||
DB_AUTH="${DB_AUTH_NAME:-acore_auth}"
|
||||
DB_CHAR="${DB_CHARACTERS_NAME:-acore_characters}"
|
||||
DB_WORLD="${DB_WORLD_NAME:-acore_world}"
|
||||
|
||||
[[ -d "$BACKUP_DIR" ]] || { echo "Backup dir not found: $BACKUP_DIR" >&2; exit 1; }
|
||||
|
||||
restore(){
|
||||
local db="$1" file="$2"
|
||||
if [[ ! -f "$file" ]]; then
|
||||
echo "Skipping $db (missing $file)"; return
|
||||
fi
|
||||
echo "Importing $file into $db"
|
||||
case "$file" in
|
||||
*.sql.gz) gzip -dc "$file" ;;
|
||||
*.sql) cat "$file" ;;
|
||||
*) echo "Unsupported file type: $file" >&2; return ;;
|
||||
esac | docker exec -i ac-mysql mysql -uroot -p"$MYSQL_PW" "$db"
|
||||
}
|
||||
|
||||
restore "$DB_AUTH" "$BACKUP_DIR/acore_auth.sql.gz"
|
||||
restore "$DB_CHAR" "$BACKUP_DIR/acore_characters.sql.gz"
|
||||
# optional world restore
|
||||
if [[ -f "$BACKUP_DIR/acore_world.sql.gz" ]]; then
|
||||
echo "World dump found. Restore? [y/N]"
|
||||
read -r ans
|
||||
if [[ "$ans" =~ ^[Yy]$ ]]; then
|
||||
restore "$DB_WORLD" "$BACKUP_DIR/acore_world.sql.gz"
|
||||
fi
|
||||
fi
|
||||
82
scripts/manage-modules-sql.sh
Normal file → Executable file
82
scripts/manage-modules-sql.sh
Normal file → Executable file
@@ -1,13 +1,72 @@
|
||||
#!/bin/bash
|
||||
# ac-compose
|
||||
set -e
|
||||
trap 'echo " ❌ SQL helper error (line ${LINENO}): ${BASH_COMMAND}" >&2' ERR
|
||||
|
||||
CUSTOM_SQL_ROOT="/tmp/scripts/sql/custom"
|
||||
ALT_CUSTOM_SQL_ROOT="/scripts/sql/custom"
|
||||
|
||||
run_custom_sql_group(){
|
||||
local subdir="$1" target_db="$2" label="$3"
|
||||
local dir="${CUSTOM_SQL_ROOT}/${subdir}"
|
||||
if [ ! -d "$dir" ] && [ -d "${ALT_CUSTOM_SQL_ROOT}/${subdir}" ]; then
|
||||
dir="${ALT_CUSTOM_SQL_ROOT}/${subdir}"
|
||||
fi
|
||||
[ -d "$dir" ] || return 0
|
||||
LC_ALL=C find "$dir" -type f -name "*.sql" | sort | while read -r sql_file; do
|
||||
local base_name
|
||||
base_name="$(basename "$sql_file")"
|
||||
echo " Executing ${label}: ${base_name}"
|
||||
if mariadb --ssl=false -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${target_db}" < "$sql_file" >/dev/null 2>&1; then
|
||||
echo " ✅ Successfully executed ${base_name}"
|
||||
else
|
||||
echo " ❌ Failed to execute $sql_file"
|
||||
fi
|
||||
done || true
|
||||
}
|
||||
|
||||
# Function to execute SQL files for a module
|
||||
execute_module_sql() {
|
||||
local module_dir="$1"
|
||||
local module_name="$2"
|
||||
local playerbots_db="${DB_PLAYERBOTS_NAME:-acore_playerbots}"
|
||||
local character_set="${MYSQL_CHARACTER_SET:-utf8mb4}"
|
||||
local collation="${MYSQL_COLLATION:-utf8mb4_unicode_ci}"
|
||||
local run_sorted_sql
|
||||
|
||||
run_sorted_sql() {
|
||||
local dir="$1"
|
||||
local target_db="$2"
|
||||
local label="$3"
|
||||
local skip_regex="${4:-}"
|
||||
[ -d "$dir" ] || return
|
||||
LC_ALL=C find "$dir" -type f -name "*.sql" | sort | while read -r sql_file; do
|
||||
local base_name
|
||||
base_name="$(basename "$sql_file")"
|
||||
if [ -n "$skip_regex" ] && [[ "$base_name" =~ $skip_regex ]]; then
|
||||
echo " Skipping ${label}: ${base_name}"
|
||||
continue
|
||||
fi
|
||||
echo " Executing ${label}: ${base_name}"
|
||||
if mariadb --ssl=false -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${target_db}" < "$sql_file" >/dev/null 2>&1; then
|
||||
echo " ✅ Successfully executed ${base_name}"
|
||||
else
|
||||
echo " ❌ Failed to execute $sql_file"
|
||||
fi
|
||||
done || true
|
||||
}
|
||||
|
||||
echo "Processing SQL scripts for $module_name..."
|
||||
|
||||
if [ "$module_name" = "Playerbots" ]; then
|
||||
echo " Ensuring database ${playerbots_db} exists..."
|
||||
if mariadb --ssl=false -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" -e "CREATE DATABASE IF NOT EXISTS \`${playerbots_db}\` CHARACTER SET ${character_set} COLLATE ${collation};" >/dev/null 2>&1; then
|
||||
echo " ✅ Playerbots database ready"
|
||||
else
|
||||
echo " ❌ Failed to ensure playerbots database"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Find and execute SQL files in the module
|
||||
if [ -d "$module_dir/data/sql" ]; then
|
||||
# Execute world database scripts
|
||||
@@ -21,6 +80,7 @@ execute_module_sql() {
|
||||
fi
|
||||
done
|
||||
fi
|
||||
run_sorted_sql "$module_dir/data/sql/db-world" "${DB_WORLD_NAME}" "world SQL"
|
||||
|
||||
# Execute auth database scripts
|
||||
if [ -d "$module_dir/data/sql/auth" ]; then
|
||||
@@ -33,6 +93,7 @@ execute_module_sql() {
|
||||
fi
|
||||
done
|
||||
fi
|
||||
run_sorted_sql "$module_dir/data/sql/db-auth" "${DB_AUTH_NAME}" "auth SQL"
|
||||
|
||||
# Execute character database scripts
|
||||
if [ -d "$module_dir/data/sql/characters" ]; then
|
||||
@@ -45,6 +106,17 @@ execute_module_sql() {
|
||||
fi
|
||||
done
|
||||
fi
|
||||
run_sorted_sql "$module_dir/data/sql/db-characters" "${DB_CHARACTERS_NAME}" "characters SQL"
|
||||
|
||||
# Execute playerbots database scripts
|
||||
if [ "$module_name" = "Playerbots" ] && [ -d "$module_dir/data/sql/playerbots" ]; then
|
||||
local pb_root="$module_dir/data/sql/playerbots"
|
||||
run_sorted_sql "$pb_root/base" "$playerbots_db" "playerbots SQL"
|
||||
run_sorted_sql "$pb_root/custom" "$playerbots_db" "playerbots SQL"
|
||||
run_sorted_sql "$pb_root/updates" "$playerbots_db" "playerbots SQL"
|
||||
run_sorted_sql "$pb_root/archive" "$playerbots_db" "playerbots SQL"
|
||||
echo " Skipping playerbots create scripts (handled by automation)"
|
||||
fi
|
||||
|
||||
# Execute base SQL files (common pattern)
|
||||
find "$module_dir/data/sql" -maxdepth 1 -name "*.sql" -type f | while read sql_file; do
|
||||
@@ -60,6 +132,8 @@ execute_module_sql() {
|
||||
mysql -h "${CONTAINER_MYSQL}" -P 3306 -u root -p"${MYSQL_ROOT_PASSWORD}" "${DB_WORLD_NAME}" < "$sql_file" 2>/dev/null || echo " Warning: Failed to execute $sql_file"
|
||||
done
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Main function to execute SQL for all enabled modules
|
||||
@@ -194,4 +268,10 @@ execute_module_sql_scripts() {
|
||||
if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" = "1" ] && [ -d "mod-black-market" ]; then
|
||||
execute_module_sql "mod-black-market" "Black Market"
|
||||
fi
|
||||
}
|
||||
|
||||
run_custom_sql_group world "${DB_WORLD_NAME}" "custom world SQL"
|
||||
run_custom_sql_group auth "${DB_AUTH_NAME}" "custom auth SQL"
|
||||
run_custom_sql_group characters "${DB_CHARACTERS_NAME}" "custom characters SQL"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
100
scripts/manage-modules.sh
Normal file → Executable file
100
scripts/manage-modules.sh
Normal file → Executable file
@@ -1,10 +1,11 @@
|
||||
#!/bin/bash
|
||||
# ac-compose
|
||||
set -e
|
||||
|
||||
echo 'Setting up git user'
|
||||
git config --global user.name "$GIT_USERNAME"
|
||||
git config --global user.email "$GIT_EMAIL"
|
||||
git config --global url.https://$GIT_PAT@github.com/.insteadOf https://github.com/
|
||||
git config --global user.name "${GIT_USERNAME:-ac-compose}"
|
||||
git config --global user.email "${GIT_EMAIL:-noreply@azerothcore.org}"
|
||||
# PAT not needed for public repositories
|
||||
|
||||
echo 'Initializing module management...'
|
||||
cd /modules
|
||||
@@ -538,18 +539,6 @@ if [ "$MODULE_LEVEL_GRANT" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/levelGrant.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_ASSISTANT" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_assistant.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_REAGENT_BANK" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_reagent_bank.conf*
|
||||
fi
|
||||
|
||||
if [ "$MODULE_BLACK_MARKET_AUCTION_HOUSE" != "1" ]; then
|
||||
rm -f /azerothcore/env/dist/etc/mod_black_market.conf*
|
||||
fi
|
||||
|
||||
# Install configuration files for enabled modules
|
||||
for module_dir in mod-*; do
|
||||
if [ -d "$module_dir" ]; then
|
||||
@@ -558,15 +547,33 @@ for module_dir in mod-*; do
|
||||
fi
|
||||
done
|
||||
|
||||
echo 'Configuration file management complete.'
|
||||
if [ "$MODULE_AUTOBALANCE" = "1" ]; then
|
||||
if [ -f "/azerothcore/env/dist/etc/AutoBalance.conf.dist" ]; then
|
||||
sed -i 's/^AutoBalance\.LevelScaling\.EndGameBoost.*/AutoBalance.LevelScaling.EndGameBoost = false # disabled pending proper implementation/' \
|
||||
/azerothcore/env/dist/etc/AutoBalance.conf.dist || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Source the SQL module management functions
|
||||
source /scripts/manage-modules-sql.sh
|
||||
# Load SQL runner if present
|
||||
if [ -f "/scripts/manage-modules-sql.sh" ]; then
|
||||
. /scripts/manage-modules-sql.sh
|
||||
elif [ -f "/tmp/scripts/manage-modules-sql.sh" ]; then
|
||||
. /tmp/scripts/manage-modules-sql.sh
|
||||
else
|
||||
echo "⚠️ SQL helper not found, skipping module SQL execution"
|
||||
fi
|
||||
|
||||
echo 'Executing module SQL scripts...'
|
||||
execute_module_sql_scripts
|
||||
|
||||
echo 'SQL execution complete.'
|
||||
# Execute SQLs for enabled modules (via helper)
|
||||
SQL_EXECUTION_FAILED=0
|
||||
if declare -f execute_module_sql_scripts >/dev/null 2>&1; then
|
||||
echo 'Executing module SQL scripts...'
|
||||
if execute_module_sql_scripts; then
|
||||
echo 'SQL execution complete.'
|
||||
else
|
||||
echo '⚠️ Module SQL scripts reported errors'
|
||||
SQL_EXECUTION_FAILED=1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Module state tracking and rebuild logic
|
||||
echo 'Checking for module changes that require rebuild...'
|
||||
@@ -576,7 +583,7 @@ CURRENT_STATE=""
|
||||
REBUILD_REQUIRED=0
|
||||
|
||||
# Create current module state hash
|
||||
for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT; do
|
||||
for module_var in MODULE_PLAYERBOTS MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_ELUNA MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK MODULE_BLACK_MARKET_AUCTION_HOUSE; do
|
||||
eval "value=\$$module_var"
|
||||
CURRENT_STATE="$CURRENT_STATE$module_var=$value|"
|
||||
done
|
||||
@@ -598,9 +605,9 @@ fi
|
||||
# Save current state
|
||||
echo "$CURRENT_STATE" > "$MODULES_STATE_FILE"
|
||||
|
||||
# Check if any C++ modules are enabled (all current modules require compilation)
|
||||
# Check if any C++ modules are enabled (modules requiring source compilation)
|
||||
# NOTE: mod-playerbots uses pre-built images and doesn't require rebuild
|
||||
ENABLED_MODULES=""
|
||||
[ "$MODULE_PLAYERBOTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-playerbots"
|
||||
[ "$MODULE_AOE_LOOT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-aoe-loot"
|
||||
[ "$MODULE_LEARN_SPELLS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-learn-spells"
|
||||
[ "$MODULE_FIREWORKS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-fireworks-on-level"
|
||||
@@ -619,7 +626,6 @@ ENABLED_MODULES=""
|
||||
[ "$MODULE_AUTO_REVIVE" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-auto-revive"
|
||||
[ "$MODULE_GAIN_HONOR_GUARD" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-gain-honor-guard"
|
||||
[ "$MODULE_ELUNA" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-eluna"
|
||||
[ "$MODULE_ARAC" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-arac"
|
||||
[ "$MODULE_TIME_IS_TIME" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-time-is-time"
|
||||
[ "$MODULE_POCKET_PORTAL" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-pocket-portal"
|
||||
[ "$MODULE_RANDOM_ENCHANTS" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-random-enchants"
|
||||
@@ -629,9 +635,6 @@ ENABLED_MODULES=""
|
||||
[ "$MODULE_NPC_ENCHANTER" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-npc-enchanter"
|
||||
[ "$MODULE_INSTANCE_RESET" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-instance-reset"
|
||||
[ "$MODULE_LEVEL_GRANT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-quest-count-level"
|
||||
[ "$MODULE_ASSISTANT" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-assistant"
|
||||
[ "$MODULE_REAGENT_BANK" = "1" ] && ENABLED_MODULES="$ENABLED_MODULES mod-reagent-bank"
|
||||
# Note: mod-black-market is Lua-based, doesn't need C++ compilation
|
||||
|
||||
if [ -n "$ENABLED_MODULES" ]; then
|
||||
ENABLED_COUNT=$(echo $ENABLED_MODULES | wc -w)
|
||||
@@ -646,14 +649,10 @@ if [ -n "$ENABLED_MODULES" ]; then
|
||||
echo "Module configuration has changed. To integrate C++ modules into AzerothCore:"
|
||||
echo ""
|
||||
echo "1. Stop current services:"
|
||||
echo " docker compose -f docker-compose-azerothcore-services.yml down"
|
||||
echo " docker compose down"
|
||||
echo ""
|
||||
echo "2. Build with source-based compilation:"
|
||||
echo " docker compose -f /tmp/acore-dev-test/docker-compose.yml build"
|
||||
echo " docker compose -f /tmp/acore-dev-test/docker-compose.yml up -d"
|
||||
echo ""
|
||||
echo "3. Or use the automated rebuild script (if available):"
|
||||
echo " ./scripts/rebuild-with-modules.sh"
|
||||
echo "2. Build with source-based compilation (external process)"
|
||||
echo " ./scripts/rebuild-with-modules.sh (if available)"
|
||||
echo ""
|
||||
echo "📋 NOTE: Source-based build will compile AzerothCore with all enabled modules"
|
||||
echo "⏱️ Expected build time: 15-45 minutes depending on system performance"
|
||||
@@ -665,21 +664,18 @@ fi
|
||||
|
||||
echo 'Module management complete.'
|
||||
|
||||
# Download rebuild script from GitHub for local access
|
||||
echo '📥 Downloading rebuild-with-modules.sh from GitHub...'
|
||||
apk add --no-cache curl
|
||||
if curl -fsSL https://raw.githubusercontent.com/uprightbass360/acore-compose/main/scripts/rebuild-with-modules.sh -o /tmp/rebuild-with-modules.sh 2>/dev/null; then
|
||||
echo '✅ Downloaded rebuild-with-modules.sh from GitHub'
|
||||
chmod +x /tmp/rebuild-with-modules.sh
|
||||
echo '📍 Script available at: /tmp/rebuild-with-modules.sh'
|
||||
elif [ -f "/project/scripts/rebuild-with-modules.sh" ]; then
|
||||
echo '📁 Using local rebuild-with-modules.sh for testing'
|
||||
cp /project/scripts/rebuild-with-modules.sh /tmp/rebuild-with-modules.sh
|
||||
chmod +x /tmp/rebuild-with-modules.sh
|
||||
echo '✅ Copied to /tmp/rebuild-with-modules.sh'
|
||||
else
|
||||
echo '⚠️ Warning: rebuild-with-modules.sh not found in GitHub or locally'
|
||||
REBUILD_SENTINEL="/modules/.requires_rebuild"
|
||||
if [ "$SQL_EXECUTION_FAILED" = "1" ]; then
|
||||
echo "⚠️ SQL execution encountered issues; review logs above."
|
||||
fi
|
||||
|
||||
echo 'Keeping container alive...'
|
||||
tail -f /dev/null
|
||||
if [ "$REBUILD_REQUIRED" = "1" ] && [ -n "$ENABLED_MODULES" ]; then
|
||||
echo "$ENABLED_MODULES" > "$REBUILD_SENTINEL"
|
||||
else
|
||||
rm -f "$REBUILD_SENTINEL" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Optional: keep container alive for inspection in CI/debug contexts
|
||||
if [ "${MODULES_DEBUG_KEEPALIVE:-0}" = "1" ]; then
|
||||
tail -f /dev/null
|
||||
fi
|
||||
|
||||
114
scripts/migrate-stack.sh
Executable file
114
scripts/migrate-stack.sh
Executable file
@@ -0,0 +1,114 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Utility to migrate the current acore-compose stack to a remote host.
|
||||
# It assumes the module images have already been rebuilt locally.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") --host HOST --user USER [options]
|
||||
|
||||
Options:
|
||||
--host HOST Remote hostname or IP address (required)
|
||||
--user USER SSH username on remote host (required)
|
||||
--port PORT SSH port (default: 22)
|
||||
--identity PATH SSH private key (passed to scp/ssh)
|
||||
--project-dir DIR Remote directory for the project (default: ~/acore-compose)
|
||||
--tarball PATH Output path for the image tar (default: ./acore-modules-images.tar)
|
||||
--storage PATH Remote storage directory (default: <project-dir>/storage)
|
||||
--skip-images Do not export/import Docker images
|
||||
--help Show this help
|
||||
|
||||
Example:
|
||||
$(basename "$0") --host wow.example.com --user deploy --identity ~/.ssh/id_ed25519 \
|
||||
--project-dir /opt/acore-compose
|
||||
EOF
|
||||
}
|
||||
|
||||
HOST=""
|
||||
USER=""
|
||||
PORT=22
|
||||
IDENTITY=""
|
||||
PROJECT_DIR=""
|
||||
TARBALL=""
|
||||
REMOTE_STORAGE=""
|
||||
SKIP_IMAGES=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--host) HOST="$2"; shift 2;;
|
||||
--user) USER="$2"; shift 2;;
|
||||
--port) PORT="$2"; shift 2;;
|
||||
--identity) IDENTITY="$2"; shift 2;;
|
||||
--project-dir) PROJECT_DIR="$2"; shift 2;;
|
||||
--tarball) TARBALL="$2"; shift 2;;
|
||||
--storage) REMOTE_STORAGE="$2"; shift 2;;
|
||||
--skip-images) SKIP_IMAGES=1; shift;;
|
||||
--help|-h) usage; exit 0;;
|
||||
*) echo "Unknown option: $1" >&2; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$HOST" || -z "$USER" ]]; then
|
||||
echo "--host and --user are required" >&2
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROJECT_DIR="${PROJECT_DIR:-/home/${USER}/acore-compose}"
|
||||
REMOTE_STORAGE="${REMOTE_STORAGE:-${PROJECT_DIR}/storage}"
|
||||
TARBALL="${TARBALL:-$(pwd)/acore-modules-images.tar}"
|
||||
|
||||
SCP_OPTS=(-P "$PORT")
|
||||
SSH_OPTS=(-p "$PORT")
|
||||
if [[ -n "$IDENTITY" ]]; then
|
||||
SCP_OPTS+=(-i "$IDENTITY")
|
||||
SSH_OPTS+=(-i "$IDENTITY")
|
||||
fi
|
||||
|
||||
run_ssh(){
|
||||
ssh "${SSH_OPTS[@]}" "$USER@$HOST" "$@"
|
||||
}
|
||||
|
||||
run_scp(){
|
||||
scp "${SCP_OPTS[@]}" "$@"
|
||||
}
|
||||
|
||||
echo "⋅ Preparing project archive"
|
||||
TMP_PROJECT_ARCHIVE="$(mktemp -u acore-compose-XXXXXX.tar.gz)"
|
||||
tar --exclude '.git' --exclude 'storage/backups' --exclude 'storage/logs' \
|
||||
--exclude 'acore-modules-images.tar' -czf "$TMP_PROJECT_ARCHIVE" -C "$(pwd)/.." "$(basename "$(pwd)")"
|
||||
|
||||
if [[ $SKIP_IMAGES -eq 0 ]]; then
|
||||
echo "⋅ Exporting module images to $TARBALL"
|
||||
docker image save \
|
||||
acore/ac-wotlk-worldserver:modules-latest \
|
||||
acore/ac-wotlk-authserver:modules-latest \
|
||||
> "$TARBALL"
|
||||
fi
|
||||
|
||||
echo "⋅ Removing rebuild sentinel"
|
||||
rm -f storage/modules/.requires_rebuild || true
|
||||
|
||||
echo "⋅ Syncing project to remote $USER@$HOST:$PROJECT_DIR"
|
||||
run_ssh "mkdir -p '$PROJECT_DIR'"
|
||||
run_scp "$TMP_PROJECT_ARCHIVE" "$USER@$HOST:/tmp/acore-compose.tar.gz"
|
||||
run_ssh "tar -xzf /tmp/acore-compose.tar.gz -C '$PROJECT_DIR' --strip-components=1 && rm /tmp/acore-compose.tar.gz"
|
||||
|
||||
echo "⋅ Syncing storage to remote"
|
||||
run_ssh "mkdir -p '$REMOTE_STORAGE'"
|
||||
run_scp -r storage/* "$USER@$HOST:$REMOTE_STORAGE/"
|
||||
|
||||
if [[ $SKIP_IMAGES -eq 0 ]]; then
|
||||
echo "⋅ Transferring docker images"
|
||||
run_scp "$TARBALL" "$USER@$HOST:/tmp/acore-modules-images.tar"
|
||||
run_ssh "docker load < /tmp/acore-modules-images.tar && rm /tmp/acore-modules-images.tar"
|
||||
fi
|
||||
|
||||
echo "⋅ Remote prepares completed"
|
||||
echo "Run the following on the remote host to deploy:"
|
||||
echo " cd $PROJECT_DIR && ./deploy.sh --skip-rebuild --no-watch"
|
||||
|
||||
rm -f "$TMP_PROJECT_ARCHIVE"
|
||||
echo "Migration script finished"
|
||||
@@ -1,128 +1,216 @@
|
||||
#!/bin/bash
|
||||
|
||||
# AzerothCore Module Rebuild Script
|
||||
# Automates the process of rebuilding AzerothCore with enabled modules
|
||||
# ac-compose helper to rebuild AzerothCore from source with enabled modules.
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔧 AzerothCore Module Rebuild Script"
|
||||
echo "==================================="
|
||||
echo ""
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
ENV_FILE="$PROJECT_DIR/.env"
|
||||
|
||||
# Check if source repository exists
|
||||
SOURCE_COMPOSE="/tmp/acore-dev-test/docker-compose.yml"
|
||||
BLUE='\033[0;34m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
show_rebuild_step(){
|
||||
local step="$1" total="$2" message="$3"
|
||||
echo -e "${YELLOW}🔧 Step ${step}/${total}: ${message}...${NC}"
|
||||
}
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [options]
|
||||
|
||||
Options:
|
||||
--yes, -y Skip interactive confirmation prompts
|
||||
--source PATH Override MODULES_REBUILD_SOURCE_PATH from .env
|
||||
--skip-stop Do not run 'docker compose down' in the source tree before rebuilding
|
||||
-h, --help Show this help
|
||||
EOF
|
||||
}
|
||||
|
||||
read_env(){
|
||||
local key="$1" default="$2" env_path="$ENV_FILE" value
|
||||
if [ -f "$env_path" ]; then
|
||||
value="$(grep -E "^${key}=" "$env_path" | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||
fi
|
||||
if [ -z "$value" ]; then
|
||||
value="$default"
|
||||
fi
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
confirm(){
|
||||
local prompt="$1" default="$2" reply
|
||||
if [ "$ASSUME_YES" = "1" ]; then
|
||||
return 0
|
||||
fi
|
||||
while true; do
|
||||
if [ "$default" = "y" ]; then
|
||||
read -r -p "$prompt [Y/n]: " reply
|
||||
reply="${reply:-y}"
|
||||
else
|
||||
read -r -p "$prompt [y/N]: " reply
|
||||
reply="${reply:-n}"
|
||||
fi
|
||||
case "$reply" in
|
||||
[Yy]*) return 0 ;;
|
||||
[Nn]*) return 1 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
ASSUME_YES=0
|
||||
SOURCE_OVERRIDE=""
|
||||
SKIP_STOP=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--yes|-y) ASSUME_YES=1; shift;;
|
||||
--source) SOURCE_OVERRIDE="$2"; shift 2;;
|
||||
--skip-stop) SKIP_STOP=1; shift;;
|
||||
-h|--help) usage; exit 0;;
|
||||
*) echo "Unknown option: $1" >&2; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo "❌ Docker CLI not found in PATH."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
STORAGE_PATH="$(read_env STORAGE_PATH "./storage")"
|
||||
if [[ "$STORAGE_PATH" != /* ]]; then
|
||||
STORAGE_PATH="$PROJECT_DIR/$STORAGE_PATH"
|
||||
fi
|
||||
MODULES_DIR="$STORAGE_PATH/modules"
|
||||
SENTINEL_FILE="$MODULES_DIR/.requires_rebuild"
|
||||
|
||||
REBUILD_SOURCE_PATH="$SOURCE_OVERRIDE"
|
||||
if [ -z "$REBUILD_SOURCE_PATH" ]; then
|
||||
REBUILD_SOURCE_PATH="$(read_env MODULES_REBUILD_SOURCE_PATH "./source/azerothcore")"
|
||||
fi
|
||||
|
||||
if [ -z "$REBUILD_SOURCE_PATH" ]; then
|
||||
REBUILD_SOURCE_PATH="./source/azerothcore"
|
||||
fi
|
||||
|
||||
if [[ "$REBUILD_SOURCE_PATH" != /* ]]; then
|
||||
REBUILD_SOURCE_PATH="$(realpath "$REBUILD_SOURCE_PATH" 2>/dev/null || echo "$REBUILD_SOURCE_PATH")"
|
||||
fi
|
||||
|
||||
SOURCE_COMPOSE="$REBUILD_SOURCE_PATH/docker-compose.yml"
|
||||
if [ ! -f "$SOURCE_COMPOSE" ]; then
|
||||
echo "❌ Error: Source-based Docker Compose file not found at $SOURCE_COMPOSE"
|
||||
echo "Please ensure AzerothCore source repository is available for compilation."
|
||||
exit 1
|
||||
echo "❌ Source docker-compose.yml not found at $SOURCE_COMPOSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check current module configuration
|
||||
echo "📋 Checking current module configuration..."
|
||||
declare -A MODULE_REPO_MAP=(
|
||||
[MODULE_AOE_LOOT]=mod-aoe-loot
|
||||
[MODULE_LEARN_SPELLS]=mod-learn-spells
|
||||
[MODULE_FIREWORKS]=mod-fireworks-on-level
|
||||
[MODULE_INDIVIDUAL_PROGRESSION]=mod-individual-progression
|
||||
[MODULE_AHBOT]=mod-ahbot
|
||||
[MODULE_AUTOBALANCE]=mod-autobalance
|
||||
[MODULE_TRANSMOG]=mod-transmog
|
||||
[MODULE_NPC_BUFFER]=mod-npc-buffer
|
||||
[MODULE_DYNAMIC_XP]=mod-dynamic-xp
|
||||
[MODULE_SOLO_LFG]=mod-solo-lfg
|
||||
[MODULE_1V1_ARENA]=mod-1v1-arena
|
||||
[MODULE_PHASED_DUELS]=mod-phased-duels
|
||||
[MODULE_BREAKING_NEWS]=mod-breaking-news-override
|
||||
[MODULE_BOSS_ANNOUNCER]=mod-boss-announcer
|
||||
[MODULE_ACCOUNT_ACHIEVEMENTS]=mod-account-achievements
|
||||
[MODULE_AUTO_REVIVE]=mod-auto-revive
|
||||
[MODULE_GAIN_HONOR_GUARD]=mod-gain-honor-guard
|
||||
[MODULE_TIME_IS_TIME]=mod-TimeIsTime
|
||||
[MODULE_POCKET_PORTAL]=mod-pocket-portal
|
||||
[MODULE_RANDOM_ENCHANTS]=mod-random-enchants
|
||||
[MODULE_SOLOCRAFT]=mod-solocraft
|
||||
[MODULE_PVP_TITLES]=mod-pvp-titles
|
||||
[MODULE_NPC_BEASTMASTER]=mod-npc-beastmaster
|
||||
[MODULE_NPC_ENCHANTER]=mod-npc-enchanter
|
||||
[MODULE_INSTANCE_RESET]=mod-instance-reset
|
||||
[MODULE_LEVEL_GRANT]=mod-quest-count-level
|
||||
)
|
||||
|
||||
MODULES_ENABLED=0
|
||||
ENABLED_MODULES=""
|
||||
compile_modules=()
|
||||
for key in "${!MODULE_REPO_MAP[@]}"; do
|
||||
if [ "$(read_env "$key" "0")" = "1" ]; then
|
||||
compile_modules+=("${MODULE_REPO_MAP[$key]}")
|
||||
fi
|
||||
done
|
||||
|
||||
# Read environment file to check enabled modules
|
||||
if [ -f "docker-compose-azerothcore-services.env" ]; then
|
||||
while IFS= read -r line; do
|
||||
if echo "$line" | grep -q "^MODULE_.*=1$"; then
|
||||
MODULE_NAME=$(echo "$line" | cut -d'=' -f1)
|
||||
MODULES_ENABLED=$((MODULES_ENABLED + 1))
|
||||
ENABLED_MODULES="$ENABLED_MODULES $MODULE_NAME"
|
||||
fi
|
||||
done < docker-compose-azerothcore-services.env
|
||||
if [ ${#compile_modules[@]} -eq 0 ]; then
|
||||
echo "✅ No C++ modules enabled that require a source rebuild."
|
||||
rm -f "$SENTINEL_FILE" 2>/dev/null || true
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "🔧 Modules requiring compilation:"
|
||||
for mod in "${compile_modules[@]}"; do
|
||||
echo " • $mod"
|
||||
done
|
||||
|
||||
if [ ! -d "$MODULES_DIR" ]; then
|
||||
echo "⚠️ Modules directory not found at $MODULES_DIR"
|
||||
fi
|
||||
|
||||
if ! confirm "Proceed with source rebuild in $REBUILD_SOURCE_PATH? (15-45 minutes)" n; then
|
||||
echo "❌ Rebuild cancelled"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pushd "$REBUILD_SOURCE_PATH" >/dev/null
|
||||
|
||||
if [ "$SKIP_STOP" != "1" ]; then
|
||||
echo "🛑 Stopping existing source services (if any)..."
|
||||
docker compose down || true
|
||||
fi
|
||||
|
||||
if [ -d "$MODULES_DIR" ]; then
|
||||
echo "🔄 Syncing enabled modules into source tree..."
|
||||
mkdir -p modules
|
||||
find modules -mindepth 1 -maxdepth 1 -type d -name 'mod-*' -exec rm -rf {} + 2>/dev/null || true
|
||||
if command -v rsync >/dev/null 2>&1; then
|
||||
rsync -a "$MODULES_DIR"/ modules/
|
||||
else
|
||||
cp -R "$MODULES_DIR"/. modules/
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Warning: Environment file not found, checking default configuration..."
|
||||
echo "⚠️ No modules directory found at $MODULES_DIR; continuing without sync."
|
||||
fi
|
||||
|
||||
echo "🔍 Found $MODULES_ENABLED enabled modules"
|
||||
|
||||
if [ $MODULES_ENABLED -eq 0 ]; then
|
||||
echo "✅ No modules enabled - rebuild not required"
|
||||
echo "You can use pre-built containers for better performance."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "📦 Enabled modules:$ENABLED_MODULES"
|
||||
echo ""
|
||||
|
||||
# Confirm rebuild
|
||||
read -p "🤔 Proceed with rebuild? This will take 15-45 minutes. (y/N): " -n 1 -r
|
||||
echo ""
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "❌ Rebuild cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🛑 Stopping current services..."
|
||||
docker compose -f docker-compose-azerothcore-services.yml down || echo "⚠️ Services may not be running"
|
||||
|
||||
echo ""
|
||||
echo "🔧 Starting source-based compilation..."
|
||||
echo "⏱️ This will take 15-45 minutes depending on your system..."
|
||||
echo ""
|
||||
|
||||
# Build with source
|
||||
cd /tmp/acore-dev-test
|
||||
echo "📁 Switched to source directory: $(pwd)"
|
||||
|
||||
# Copy modules to source build
|
||||
echo "📋 Copying modules to source build..."
|
||||
if [ -d "/home/upb/src/acore-compose2/storage/azerothcore/modules" ]; then
|
||||
# Ensure modules directory exists in source
|
||||
mkdir -p modules
|
||||
|
||||
# Copy enabled modules only
|
||||
echo "🔄 Syncing enabled modules..."
|
||||
for module_dir in /home/upb/src/acore-compose2/storage/azerothcore/modules/*/; do
|
||||
if [ -d "$module_dir" ]; then
|
||||
module_name=$(basename "$module_dir")
|
||||
echo " Copying $module_name..."
|
||||
cp -r "$module_dir" modules/
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "⚠️ Warning: No modules directory found"
|
||||
fi
|
||||
|
||||
# Start build process
|
||||
echo ""
|
||||
echo "🚀 Building AzerothCore with modules..."
|
||||
docker compose build --no-cache
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ""
|
||||
echo "✅ Build completed successfully!"
|
||||
echo ""
|
||||
show_rebuild_step 5 5 "Cleaning up build containers"
|
||||
echo "🧹 Cleaning up source build containers..."
|
||||
docker compose down --remove-orphans >/dev/null 2>&1 || true
|
||||
|
||||
# Start services
|
||||
echo "🟢 Starting services with compiled modules..."
|
||||
docker compose up -d
|
||||
popd >/dev/null
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ""
|
||||
echo "🎉 SUCCESS! AzerothCore is now running with compiled modules."
|
||||
echo ""
|
||||
echo "📊 Service status:"
|
||||
docker compose ps
|
||||
echo ""
|
||||
echo "📝 To monitor logs:"
|
||||
echo " docker compose logs -f"
|
||||
echo ""
|
||||
echo "🌐 Server should be available on configured ports once fully started."
|
||||
else
|
||||
echo "❌ Failed to start services"
|
||||
exit 1
|
||||
if [ -n "$SENTINEL_FILE" ]; then
|
||||
if ! rm -f "$SENTINEL_FILE" 2>/dev/null; then
|
||||
if [ -f "$SENTINEL_FILE" ] && command -v docker >/dev/null 2>&1; then
|
||||
DB_IMPORT_IMAGE="$(read_env AC_DB_IMPORT_IMAGE "acore/ac-wotlk-db-import:14.0.0-dev")"
|
||||
if docker image inspect "$DB_IMPORT_IMAGE" >/dev/null 2>&1; then
|
||||
docker run --rm \
|
||||
--entrypoint /bin/sh \
|
||||
--user 0:0 \
|
||||
-v "$MODULES_DIR":/modules \
|
||||
"$DB_IMPORT_IMAGE" \
|
||||
-c 'rm -f /modules/.requires_rebuild' >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "❌ Build failed"
|
||||
echo ""
|
||||
echo "🔍 Check build logs for errors:"
|
||||
echo " docker compose logs"
|
||||
exit 1
|
||||
fi
|
||||
if [ -f "$SENTINEL_FILE" ]; then
|
||||
echo "⚠️ Unable to remove rebuild sentinel at $SENTINEL_FILE. Remove manually if rebuild detection persists."
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ Rebuild process complete!"
|
||||
echo -e "${GREEN}⚔️ Module build forged successfully! ⚔️${NC}"
|
||||
echo -e "${GREEN}🏰 Your custom AzerothCore images are ready${NC}"
|
||||
echo -e "${GREEN}🗡️ Time to stage your enhanced realm!${NC}"
|
||||
|
||||
78
scripts/setup-source.sh
Executable file
78
scripts/setup-source.sh
Executable file
@@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
# ac-compose source repository setup
|
||||
set -e
|
||||
|
||||
echo '🔧 Setting up AzerothCore source repository...'
|
||||
|
||||
# Load environment variables if .env exists
|
||||
if [ -f .env ]; then
|
||||
source .env
|
||||
fi
|
||||
|
||||
# Default values
|
||||
SOURCE_PATH="${MODULES_REBUILD_SOURCE_PATH:-./source/azerothcore}"
|
||||
|
||||
# Convert to absolute path if relative
|
||||
if [[ "$SOURCE_PATH" != /* ]]; then
|
||||
SOURCE_PATH="$(pwd)/$SOURCE_PATH"
|
||||
fi
|
||||
MODULE_PLAYERBOTS="${MODULE_PLAYERBOTS:-0}"
|
||||
|
||||
# Repository and branch selection based on playerbots mode
|
||||
if [ "$MODULE_PLAYERBOTS" = "1" ]; then
|
||||
REPO_URL="https://github.com/liyunfan1223/azerothcore-wotlk.git"
|
||||
BRANCH="Playerbot"
|
||||
echo "📌 Playerbots mode: Using liyunfan1223 fork, Playerbot branch"
|
||||
else
|
||||
REPO_URL="https://github.com/azerothcore/azerothcore-wotlk.git"
|
||||
BRANCH="master"
|
||||
echo "📌 Standard mode: Using official AzerothCore, master branch"
|
||||
fi
|
||||
|
||||
echo "📍 Repository: $REPO_URL"
|
||||
echo "🌿 Branch: $BRANCH"
|
||||
echo "📂 Source path: $SOURCE_PATH"
|
||||
|
||||
# Create source directory if it doesn't exist
|
||||
mkdir -p "$(dirname "$SOURCE_PATH")"
|
||||
|
||||
# Clone or update repository
|
||||
if [ -d "$SOURCE_PATH/.git" ]; then
|
||||
echo "📂 Existing repository found, updating..."
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
# Check if we're on the correct repository
|
||||
CURRENT_REMOTE=$(git remote get-url origin 2>/dev/null || echo "")
|
||||
if [ "$CURRENT_REMOTE" != "$REPO_URL" ]; then
|
||||
echo "🔄 Repository URL changed, re-cloning..."
|
||||
cd ..
|
||||
rm -rf "$(basename "$SOURCE_PATH")"
|
||||
git clone "$REPO_URL" "$(basename "$SOURCE_PATH")"
|
||||
cd "$(basename "$SOURCE_PATH")"
|
||||
fi
|
||||
|
||||
# Fetch latest changes
|
||||
git fetch origin
|
||||
|
||||
# Switch to target branch
|
||||
git checkout "$BRANCH"
|
||||
git pull origin "$BRANCH"
|
||||
|
||||
echo "✅ Repository updated to latest $BRANCH"
|
||||
else
|
||||
echo "📥 Cloning repository..."
|
||||
git clone -b "$BRANCH" "$REPO_URL" "$SOURCE_PATH"
|
||||
echo "✅ Repository cloned successfully"
|
||||
fi
|
||||
|
||||
cd "$SOURCE_PATH"
|
||||
|
||||
# Display current status
|
||||
CURRENT_COMMIT=$(git rev-parse --short HEAD)
|
||||
CURRENT_BRANCH=$(git branch --show-current)
|
||||
echo "📊 Current status:"
|
||||
echo " Branch: $CURRENT_BRANCH"
|
||||
echo " Commit: $CURRENT_COMMIT"
|
||||
echo " Last commit: $(git log -1 --pretty=format:'%s (%an, %ar)')"
|
||||
|
||||
echo '🎉 Source repository setup complete!'
|
||||
50
scripts/sql/custom/world/2025-10-19-smartai-fixes.sql
Normal file
50
scripts/sql/custom/world/2025-10-19-smartai-fixes.sql
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
-- Normalize Start Waypoint boolean flags that were set to invalid values (e.g., 2 instead of 0/1).
|
||||
UPDATE smart_scripts
|
||||
SET action_param1 = 1
|
||||
WHERE action_type = 53
|
||||
AND source_type IN (0, 9)
|
||||
AND action_param1 NOT IN (0, 1);
|
||||
|
||||
UPDATE smart_scripts
|
||||
SET action_param1 = 1
|
||||
WHERE source_type = 9
|
||||
AND action_type = 53
|
||||
AND action_param1 = 2
|
||||
AND entryorguid IN (
|
||||
2576200, 2658200, 2658201, 2681404, 2740900, 2741100,
|
||||
2748001, 2762600, 2819200, 2821700, 2821701, 2830800,
|
||||
2866500, 2866900
|
||||
);
|
||||
|
||||
-- Remove obsolete “Set Active” actions linked to event 12 that generate SmartAI warnings.
|
||||
DELETE FROM smart_scripts
|
||||
WHERE source_type = 0
|
||||
AND entryorguid IN (18948, 18950, 18965, 18970, 18972, 18986)
|
||||
AND event_type IN (11, 36)
|
||||
AND id IN (42, 43)
|
||||
AND action_type = 48;
|
||||
|
||||
-- Clear dangling linked events for Dalaran Pilgrims to silence "Link Event 3" warnings.
|
||||
UPDATE smart_scripts
|
||||
SET link = 0
|
||||
WHERE source_type = 0
|
||||
AND entryorguid IN (32596, 32597, 32598, 32600, 32601, 32602)
|
||||
AND id = 2
|
||||
AND link = 3;
|
||||
|
||||
-- Remove Link Event 12 references on the Darkshore defenders to avoid fallback errors.
|
||||
UPDATE smart_scripts
|
||||
SET link = 0
|
||||
WHERE source_type = 0
|
||||
AND entryorguid IN (18948, 18950, 18965, 18970, 18972, 18986)
|
||||
AND id = 2
|
||||
AND link = 12;
|
||||
|
||||
-- Clear Link Event 6 usage for entry 31702, which produces log spam.
|
||||
UPDATE smart_scripts
|
||||
SET link = 0
|
||||
WHERE source_type = 0
|
||||
AND entryorguid = 31702
|
||||
AND id = 5
|
||||
AND link = 6;
|
||||
235
scripts/stage-modules.sh
Executable file
235
scripts/stage-modules.sh
Executable file
@@ -0,0 +1,235 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ac-compose helper to automatically stage modules and trigger source builds when needed.
|
||||
|
||||
set -e
|
||||
|
||||
BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
||||
|
||||
show_staging_header(){
|
||||
printf '\n%b\n' "${BLUE}⚔️ REALM STAGING SYSTEM ⚔️${NC}"
|
||||
printf '%b\n' "${BLUE}══════════════════════════════${NC}"
|
||||
printf '%b\n\n' "${BLUE}🎯 Configuring Your Realm 🎯${NC}"
|
||||
}
|
||||
|
||||
show_staging_step(){
|
||||
local step="$1" message="$2"
|
||||
printf '%b\n' "${YELLOW}🔧 ${step}: ${message}...${NC}"
|
||||
}
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
ENV_FILE="$PROJECT_DIR/.env"
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [options] [PROFILE]
|
||||
|
||||
Automatically detect and stage modules for AzerothCore.
|
||||
|
||||
Arguments:
|
||||
PROFILE Target profile (standard, playerbots, or auto-detect)
|
||||
|
||||
Options:
|
||||
--force-rebuild Force a source rebuild even if not needed
|
||||
--yes, -y Skip interactive confirmation prompts
|
||||
-h, --help Show this help
|
||||
|
||||
Examples:
|
||||
$(basename "$0") # Auto-detect profile based on enabled modules
|
||||
$(basename "$0") playerbots # Force playerbots profile
|
||||
$(basename "$0") --force-rebuild # Force rebuild and auto-detect
|
||||
EOF
|
||||
}
|
||||
|
||||
read_env(){
|
||||
local key="$1" default="$2" env_path="$ENV_FILE" value
|
||||
if [ -f "$env_path" ]; then
|
||||
value="$(grep -E "^${key}=" "$env_path" | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||
fi
|
||||
if [ -z "$value" ]; then
|
||||
value="$default"
|
||||
fi
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
confirm(){
|
||||
local prompt="$1" default="$2" reply
|
||||
if [ "$ASSUME_YES" = "1" ]; then
|
||||
return 0
|
||||
fi
|
||||
while true; do
|
||||
if [ "$default" = "y" ]; then
|
||||
read -r -p "$prompt [Y/n]: " reply
|
||||
reply="${reply:-y}"
|
||||
else
|
||||
read -r -p "$prompt [y/N]: " reply
|
||||
reply="${reply:-n}"
|
||||
fi
|
||||
case "$reply" in
|
||||
[Yy]*) return 0 ;;
|
||||
[Nn]*) return 1 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
ASSUME_YES=0
|
||||
FORCE_REBUILD=0
|
||||
TARGET_PROFILE=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--yes|-y) ASSUME_YES=1; shift;;
|
||||
--force-rebuild) FORCE_REBUILD=1; shift;;
|
||||
-h|--help) usage; exit 0;;
|
||||
standard|playerbots) TARGET_PROFILE="$1"; shift;;
|
||||
*) echo "Unknown option: $1" >&2; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo "❌ Docker CLI not found in PATH."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
STORAGE_PATH="$(read_env STORAGE_PATH "./storage")"
|
||||
if [[ "$STORAGE_PATH" != /* ]]; then
|
||||
STORAGE_PATH="$PROJECT_DIR/$STORAGE_PATH"
|
||||
fi
|
||||
MODULES_DIR="$STORAGE_PATH/modules"
|
||||
SENTINEL_FILE="$MODULES_DIR/.requires_rebuild"
|
||||
|
||||
# Define module mappings (from rebuild-with-modules.sh)
|
||||
declare -A MODULE_REPO_MAP=(
|
||||
[MODULE_AOE_LOOT]=mod-aoe-loot
|
||||
[MODULE_LEARN_SPELLS]=mod-learn-spells
|
||||
[MODULE_FIREWORKS]=mod-fireworks-on-level
|
||||
[MODULE_INDIVIDUAL_PROGRESSION]=mod-individual-progression
|
||||
[MODULE_AHBOT]=mod-ahbot
|
||||
[MODULE_AUTOBALANCE]=mod-autobalance
|
||||
[MODULE_TRANSMOG]=mod-transmog
|
||||
[MODULE_NPC_BUFFER]=mod-npc-buffer
|
||||
[MODULE_DYNAMIC_XP]=mod-dynamic-xp
|
||||
[MODULE_SOLO_LFG]=mod-solo-lfg
|
||||
[MODULE_1V1_ARENA]=mod-1v1-arena
|
||||
[MODULE_PHASED_DUELS]=mod-phased-duels
|
||||
[MODULE_BREAKING_NEWS]=mod-breaking-news-override
|
||||
[MODULE_BOSS_ANNOUNCER]=mod-boss-announcer
|
||||
[MODULE_ACCOUNT_ACHIEVEMENTS]=mod-account-achievements
|
||||
[MODULE_AUTO_REVIVE]=mod-auto-revive
|
||||
[MODULE_GAIN_HONOR_GUARD]=mod-gain-honor-guard
|
||||
[MODULE_TIME_IS_TIME]=mod-TimeIsTime
|
||||
[MODULE_POCKET_PORTAL]=mod-pocket-portal
|
||||
[MODULE_RANDOM_ENCHANTS]=mod-random-enchants
|
||||
[MODULE_SOLOCRAFT]=mod-solocraft
|
||||
[MODULE_PVP_TITLES]=mod-pvp-titles
|
||||
[MODULE_NPC_BEASTMASTER]=mod-npc-beastmaster
|
||||
[MODULE_NPC_ENCHANTER]=mod-npc-enchanter
|
||||
[MODULE_INSTANCE_RESET]=mod-instance-reset
|
||||
[MODULE_LEVEL_GRANT]=mod-quest-count-level
|
||||
)
|
||||
|
||||
show_staging_header
|
||||
|
||||
# Check for enabled C++ modules that require compilation
|
||||
compile_modules=()
|
||||
for key in "${!MODULE_REPO_MAP[@]}"; do
|
||||
if [ "$(read_env "$key" "0")" = "1" ]; then
|
||||
compile_modules+=("${MODULE_REPO_MAP[$key]}")
|
||||
fi
|
||||
done
|
||||
|
||||
# Check for playerbots mode
|
||||
PLAYERBOT_ENABLED="$(read_env PLAYERBOT_ENABLED "0")"
|
||||
MODULE_PLAYERBOTS="$(read_env MODULE_PLAYERBOTS "0")"
|
||||
|
||||
# Determine target profile if not specified
|
||||
if [ -z "$TARGET_PROFILE" ]; then
|
||||
show_staging_step "Profile Detection" "Analyzing enabled modules"
|
||||
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$PLAYERBOT_ENABLED" = "1" ]; then
|
||||
TARGET_PROFILE="playerbots"
|
||||
echo "🤖 Playerbot profile enabled"
|
||||
if [ ${#compile_modules[@]} -gt 0 ]; then
|
||||
echo " ⚠️ Detected ${#compile_modules[@]} C++ modules. Ensure your playerbot images include these features."
|
||||
fi
|
||||
elif [ ${#compile_modules[@]} -gt 0 ]; then
|
||||
echo "🔧 Detected ${#compile_modules[@]} C++ modules requiring compilation:"
|
||||
for mod in "${compile_modules[@]}"; do
|
||||
echo " • $mod"
|
||||
done
|
||||
TARGET_PROFILE="modules"
|
||||
echo "🧩 Using modules profile for custom source build"
|
||||
else
|
||||
TARGET_PROFILE="standard"
|
||||
echo "✅ No special modules detected - using standard profile"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "🎯 Target profile: services-$TARGET_PROFILE"
|
||||
|
||||
# Check if source rebuild is needed for modules profile
|
||||
REBUILD_NEEDED=0
|
||||
if [ "$TARGET_PROFILE" = "modules" ]; then
|
||||
# Check if source image exists
|
||||
if ! docker image inspect "acore/ac-wotlk-worldserver:modules-latest" >/dev/null 2>&1; then
|
||||
echo "📦 Custom worldserver image not found - rebuild needed"
|
||||
REBUILD_NEEDED=1
|
||||
elif [ -f "$SENTINEL_FILE" ]; then
|
||||
echo "🔄 Modules changed since last build - rebuild needed"
|
||||
REBUILD_NEEDED=1
|
||||
elif [ "$FORCE_REBUILD" = "1" ]; then
|
||||
echo "🔧 Force rebuild requested"
|
||||
REBUILD_NEEDED=1
|
||||
fi
|
||||
|
||||
if [ "$REBUILD_NEEDED" = "1" ]; then
|
||||
show_staging_step "Source Rebuild" "Preparing custom build with modules"
|
||||
echo "🚀 Triggering source rebuild with modules..."
|
||||
if confirm "Proceed with source rebuild? (15-45 minutes)" n; then
|
||||
"$SCRIPT_DIR/rebuild-with-modules.sh" ${ASSUME_YES:+--yes}
|
||||
else
|
||||
echo "❌ Rebuild cancelled"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "✅ Custom worldserver image up to date"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Stage the services
|
||||
show_staging_step "Service Orchestration" "Preparing realm services"
|
||||
echo "🎬 Staging services with profile: services-$TARGET_PROFILE"
|
||||
|
||||
# Stop any currently running services
|
||||
echo "🛑 Stopping current services..."
|
||||
docker compose \
|
||||
--profile services-standard \
|
||||
--profile services-playerbots \
|
||||
--profile services-modules \
|
||||
--profile tools \
|
||||
--profile client-data \
|
||||
--profile client-data-bots \
|
||||
down 2>/dev/null || true
|
||||
|
||||
# Build list of profiles to start
|
||||
PROFILE_ARGS=(--profile "services-$TARGET_PROFILE" --profile db --profile modules --profile tools)
|
||||
case "$TARGET_PROFILE" in
|
||||
standard) PROFILE_ARGS+=(--profile client-data) ;;
|
||||
playerbots) PROFILE_ARGS+=(--profile client-data-bots) ;;
|
||||
modules) PROFILE_ARGS+=(--profile client-data) ;;
|
||||
esac
|
||||
|
||||
# Start the target profile
|
||||
show_staging_step "Realm Activation" "Bringing services online"
|
||||
echo "🟢 Starting services-$TARGET_PROFILE profile..."
|
||||
docker compose "${PROFILE_ARGS[@]}" up -d
|
||||
|
||||
printf '\n%b\n' "${GREEN}⚔️ Realm staging completed successfully! ⚔️${NC}"
|
||||
printf '%b\n' "${GREEN}🏰 Profile: services-$TARGET_PROFILE${NC}"
|
||||
printf '%b\n' "${GREEN}🗡️ Your realm is ready for adventure!${NC}"
|
||||
|
||||
# Show status
|
||||
printf '\n'
|
||||
echo "📊 Service Status:"
|
||||
docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" | grep -E "(ac-worldserver|ac-authserver|ac-phpmyadmin|ac-keira3|NAME)" || true
|
||||
450
setup.sh
Executable file
450
setup.sh
Executable file
@@ -0,0 +1,450 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# ==============================================
|
||||
# ac-compose - Interactive .env generator
|
||||
# ==============================================
|
||||
# Mirrors options from scripts/setup-server.sh but targets ac-compose/.env
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; MAGENTA='\033[0;35m'; NC='\033[0m'
|
||||
say(){ local t=$1; shift; case "$t" in
|
||||
INFO) echo -e "${BLUE}ℹ️ $*${NC}";;
|
||||
SUCCESS) echo -e "${GREEN}✅ $*${NC}";;
|
||||
WARNING) echo -e "${YELLOW}⚠️ $*${NC}";;
|
||||
ERROR) echo -e "${RED}❌ $*${NC}";;
|
||||
HEADER) echo -e "\n${MAGENTA}=== $* ===${NC}";;
|
||||
esac }
|
||||
|
||||
validate_ip(){ [[ $1 =~ ^[0-9]{1,3}(\.[0-9]{1,3}){3}$ ]]; }
|
||||
validate_port(){ [[ $1 =~ ^[0-9]+$ ]] && [ $1 -ge 1 ] && [ $1 -le 65535 ]; }
|
||||
validate_number(){ [[ $1 =~ ^[0-9]+$ ]]; }
|
||||
|
||||
ask(){
|
||||
local prompt="$1"; local def="$2"; local validator="$3"; local v
|
||||
while true; do
|
||||
if [ -n "$def" ]; then
|
||||
read -p "$(echo -e "${YELLOW}🔧 ${prompt} [${def}]: ${NC}")" v; v=${v:-$def}
|
||||
else
|
||||
read -p "$(echo -e "${YELLOW}🔧 ${prompt}: ${NC}")" v
|
||||
fi
|
||||
if [ -z "$validator" ] || $validator "$v"; then echo "$v"; return 0; fi
|
||||
say ERROR "Invalid input. Please try again."
|
||||
done
|
||||
}
|
||||
|
||||
ask_yn(){ local p="$1"; local d="$2"; local v; while true; do
|
||||
if [ "$d" = "y" ]; then read -p "$(echo -e "${YELLOW}🔧 ${p} [Y/n]: ${NC}")" v; v=${v:-y}; else read -p "$(echo -e "${YELLOW}🔧 ${p} [y/N]: ${NC}")" v; v=${v:-n}; fi
|
||||
case "$v" in [Yy]*) echo 1; return 0;; [Nn]*) echo 0; return 0;; esac; say ERROR "Please answer y or n"; done; }
|
||||
|
||||
show_wow_header(){
|
||||
echo -e "\n${BLUE} ⚔️ AZEROTHCORE DEPLOYMENT SYSTEM ⚔️${NC}"
|
||||
echo -e "${BLUE} ═══════════════════════════════════════${NC}"
|
||||
echo -e "${BLUE} 🏰 Build Your Own WoW Server 🏰${NC}\n"
|
||||
}
|
||||
|
||||
show_realm_configured(){
|
||||
echo -e "\n${GREEN}⚔️ Your realm configuration has been forged! ⚔️${NC}"
|
||||
echo -e "${GREEN}🏰 Ready to deploy your World of Warcraft server${NC}"
|
||||
echo -e "${GREEN}🗡️ May your realm bring epic adventures!${NC}\n"
|
||||
}
|
||||
|
||||
main(){
|
||||
# Basic arg handling for help
|
||||
if [[ $# -gt 0 ]]; then
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
cat <<'EOF'
|
||||
Usage: ./setup.sh
|
||||
|
||||
Description:
|
||||
Interactive wizard that generates ac-compose/.env for the
|
||||
profiles-based compose. Prompts for deployment type, ports, storage,
|
||||
MySQL credentials, backup retention, and module presets or manual
|
||||
toggles.
|
||||
|
||||
Notes:
|
||||
- The generated .env is read automatically by docker compose.
|
||||
- Run deploy with: deploy.sh or docker compose --profile ... up -d
|
||||
EOF
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1" >&2
|
||||
echo "Use --help for usage" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
show_wow_header
|
||||
say INFO "This will create ac-compose/.env for compose profiles."
|
||||
|
||||
# Deployment type
|
||||
say HEADER "DEPLOYMENT TYPE"
|
||||
echo "1) 🏠 Local Development (127.0.0.1, local storage)"
|
||||
echo "2) 🌐 LAN Server (local network IP)"
|
||||
echo "3) ☁️ Public Server (domain or public IP)"
|
||||
local DEPLOYMENT_TYPE
|
||||
while true; do
|
||||
read -p "$(echo -e "${YELLOW}🔧 Select deployment type [1-3]: ${NC}")" x
|
||||
case "$x" in
|
||||
1) DEPLOYMENT_TYPE=local; break;;
|
||||
2) DEPLOYMENT_TYPE=lan; break;;
|
||||
3) DEPLOYMENT_TYPE=public; break;;
|
||||
*) say ERROR "Please select 1, 2, or 3";;
|
||||
esac
|
||||
done
|
||||
|
||||
# Permission scheme
|
||||
say HEADER "PERMISSION SCHEME"
|
||||
echo "1) 🏠 Local Dev (0:0)"
|
||||
echo "2) 🗂️ NFS Server (1001:1000)"
|
||||
echo "3) ⚙️ Custom"
|
||||
local CONTAINER_USER
|
||||
while true; do
|
||||
read -p "$(echo -e "${YELLOW}🔧 Select permission scheme [1-3]: ${NC}")" x
|
||||
case "$x" in
|
||||
1) CONTAINER_USER="0:0"; break;;
|
||||
2) CONTAINER_USER="1001:1000"; break;;
|
||||
3) local uid gid; uid=$(ask "Enter PUID (user id)" 1000 validate_number); gid=$(ask "Enter PGID (group id)" 1000 validate_number); CONTAINER_USER="${uid}:${gid}"; break;;
|
||||
*) say ERROR "Please select 1, 2, or 3";;
|
||||
esac
|
||||
done
|
||||
|
||||
# Server config
|
||||
say HEADER "SERVER CONFIGURATION"
|
||||
local SERVER_ADDRESS
|
||||
if [ "$DEPLOYMENT_TYPE" = "local" ]; then
|
||||
SERVER_ADDRESS=127.0.0.1
|
||||
elif [ "$DEPLOYMENT_TYPE" = "lan" ]; then
|
||||
local LAN_IP; LAN_IP=$(ip route get 1.1.1.1 2>/dev/null | awk 'NR==1{print $7}')
|
||||
SERVER_ADDRESS=$(ask "Enter server IP address" "${LAN_IP:-192.168.1.100}" validate_ip)
|
||||
else
|
||||
SERVER_ADDRESS=$(ask "Enter server address (IP or domain)" "your-domain.com" )
|
||||
fi
|
||||
|
||||
local REALM_PORT AUTH_EXTERNAL_PORT SOAP_EXTERNAL_PORT MYSQL_EXTERNAL_PORT
|
||||
REALM_PORT=$(ask "Enter client connection port" 8215 validate_port)
|
||||
AUTH_EXTERNAL_PORT=$(ask "Enter auth server port" 3784 validate_port)
|
||||
SOAP_EXTERNAL_PORT=$(ask "Enter SOAP API port" 7778 validate_port)
|
||||
MYSQL_EXTERNAL_PORT=$(ask "Enter MySQL external port" 64306 validate_port)
|
||||
|
||||
# DB config
|
||||
say HEADER "DATABASE CONFIGURATION"
|
||||
local MYSQL_ROOT_PASSWORD; MYSQL_ROOT_PASSWORD=$(ask "Enter MySQL root password" "azerothcore123")
|
||||
|
||||
# Storage
|
||||
say HEADER "STORAGE CONFIGURATION"
|
||||
local STORAGE_PATH
|
||||
if [ "$DEPLOYMENT_TYPE" = "local" ]; then
|
||||
STORAGE_PATH=./storage
|
||||
else
|
||||
echo "1) 💾 ./storage (local)"
|
||||
echo "2) 🌐 /nfs/azerothcore (NFS)"
|
||||
echo "3) 📁 Custom"
|
||||
while true; do
|
||||
read -p "$(echo -e "${YELLOW}🔧 Select storage option [1-3]: ${NC}")" s
|
||||
case "$s" in
|
||||
1) STORAGE_PATH=./storage; break;;
|
||||
2) STORAGE_PATH=/nfs/azerothcore; break;;
|
||||
3) STORAGE_PATH=$(ask "Enter custom storage path" "/mnt/azerothcore-data"); break;;
|
||||
*) say ERROR "Please select 1, 2, or 3";;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# Backup
|
||||
say HEADER "BACKUP CONFIGURATION"
|
||||
local BACKUP_RETENTION_DAYS BACKUP_RETENTION_HOURS BACKUP_DAILY_TIME
|
||||
BACKUP_RETENTION_DAYS=$(ask "Daily backups retention (days)" 3 validate_number)
|
||||
BACKUP_RETENTION_HOURS=$(ask "Hourly backups retention (hours)" 6 validate_number)
|
||||
BACKUP_DAILY_TIME=$(ask "Daily backup hour (00-23, UTC)" 09 validate_number)
|
||||
|
||||
# Module config
|
||||
say HEADER "MODULE PRESET"
|
||||
echo "1) ⭐ Suggested Modules"
|
||||
echo "2) 🤖 Playerbots + Suggested modules"
|
||||
echo "3) ⚙️ Manual selection"
|
||||
echo "4) 🚫 No modules"
|
||||
local MODE; while true; do
|
||||
read -p "$(echo -e "${YELLOW}🔧 Select module configuration [1-4]: ${NC}")" MODE
|
||||
case "$MODE" in 1|2|3|4) break;; *) say ERROR "Please select 1, 2, 3, or 4";; esac
|
||||
done
|
||||
|
||||
# Initialize toggles
|
||||
local MODULE_PLAYERBOTS=0 MODULE_AOE_LOOT=0 MODULE_LEARN_SPELLS=0 MODULE_FIREWORKS=0 MODULE_INDIVIDUAL_PROGRESSION=0 \
|
||||
MODULE_AHBOT=0 MODULE_AUTOBALANCE=0 MODULE_TRANSMOG=0 MODULE_NPC_BUFFER=0 MODULE_DYNAMIC_XP=0 MODULE_SOLO_LFG=0 \
|
||||
MODULE_1V1_ARENA=0 MODULE_PHASED_DUELS=0 MODULE_BREAKING_NEWS=0 MODULE_BOSS_ANNOUNCER=0 MODULE_ACCOUNT_ACHIEVEMENTS=0 \
|
||||
MODULE_AUTO_REVIVE=0 MODULE_GAIN_HONOR_GUARD=0 MODULE_TIME_IS_TIME=0 MODULE_POCKET_PORTAL=0 \
|
||||
MODULE_RANDOM_ENCHANTS=0 MODULE_SOLOCRAFT=0 MODULE_PVP_TITLES=0 MODULE_NPC_BEASTMASTER=0 MODULE_NPC_ENCHANTER=0 \
|
||||
MODULE_INSTANCE_RESET=0 MODULE_LEVEL_GRANT=0 MODULE_ASSISTANT=0 MODULE_REAGENT_BANK=0 MODULE_BLACK_MARKET_AUCTION_HOUSE=0 MODULE_ARAC=0
|
||||
|
||||
declare -A DISABLED_MODULE_REASONS=(
|
||||
[MODULE_AHBOT]="Requires upstream Addmod_ahbotScripts symbol (fails link)"
|
||||
[MODULE_LEVEL_GRANT]="QuestCountLevel module relies on removed ConfigMgr APIs and fails to build"
|
||||
)
|
||||
|
||||
local PLAYERBOT_ENABLED=0 PLAYERBOT_MAX_BOTS=40
|
||||
|
||||
local AUTO_REBUILD_ON_DEPLOY=0
|
||||
local MODULES_REBUILD_SOURCE_PATH_VALUE=""
|
||||
local RUN_REBUILD_NOW=0
|
||||
local NEEDS_CXX_REBUILD=0
|
||||
|
||||
if [ "$MODE" = "1" ]; then
|
||||
MODULE_SOLO_LFG=1; MODULE_SOLOCRAFT=1; MODULE_AUTOBALANCE=1; MODULE_TRANSMOG=1; MODULE_NPC_BUFFER=1; MODULE_LEARN_SPELLS=1; MODULE_FIREWORKS=1
|
||||
elif [ "$MODE" = "2" ]; then
|
||||
MODULE_PLAYERBOTS=1; MODULE_SOLO_LFG=1; MODULE_SOLOCRAFT=1; MODULE_AUTOBALANCE=1; MODULE_TRANSMOG=1; MODULE_NPC_BUFFER=1; MODULE_LEARN_SPELLS=1; MODULE_FIREWORKS=1
|
||||
elif [ "$MODE" = "3" ]; then
|
||||
say INFO "Answer y/n for each module"
|
||||
for key in "${!DISABLED_MODULE_REASONS[@]}"; do
|
||||
say WARNING "${key#MODULE_}: ${DISABLED_MODULE_REASONS[$key]}"
|
||||
done
|
||||
# Core Gameplay
|
||||
MODULE_PLAYERBOTS=$(ask_yn "Playerbots - AI companions" n)
|
||||
MODULE_SOLO_LFG=$(ask_yn "Solo LFG - Solo dungeon finder" n)
|
||||
MODULE_SOLOCRAFT=$(ask_yn "Solocraft - Scale dungeons/raids for solo" n)
|
||||
MODULE_AUTOBALANCE=$(ask_yn "Autobalance - Dynamic difficulty" n)
|
||||
# QoL
|
||||
MODULE_TRANSMOG=$(ask_yn "Transmog - Appearance changes" n)
|
||||
MODULE_NPC_BUFFER=$(ask_yn "NPC Buffer - Buff NPCs" n)
|
||||
MODULE_LEARN_SPELLS=$(ask_yn "Learn Spells - Auto-learn" n)
|
||||
MODULE_AOE_LOOT=$(ask_yn "AOE Loot - Multi-corpse loot" n)
|
||||
MODULE_FIREWORKS=$(ask_yn "Fireworks - Level-up FX" n)
|
||||
MODULE_ASSISTANT=$(ask_yn "Assistant - Multi-service NPC" n)
|
||||
# Economy
|
||||
MODULE_AHBOT=$(ask_yn "AH Bot - Auction automation" n)
|
||||
MODULE_REAGENT_BANK=$(ask_yn "Reagent Bank - Materials storage" n)
|
||||
MODULE_BLACK_MARKET_AUCTION_HOUSE=$(ask_yn "Black Market - MoP-style" n)
|
||||
# PvP
|
||||
MODULE_1V1_ARENA=$(ask_yn "1v1 Arena" n)
|
||||
MODULE_PHASED_DUELS=$(ask_yn "Phased Duels" n)
|
||||
MODULE_PVP_TITLES=$(ask_yn "PvP Titles" n)
|
||||
# Progression
|
||||
MODULE_INDIVIDUAL_PROGRESSION=$(ask_yn "Individual Progression (Vanilla→TBC→WotLK)" n)
|
||||
MODULE_DYNAMIC_XP=$(ask_yn "Dynamic XP" n)
|
||||
MODULE_ACCOUNT_ACHIEVEMENTS=$(ask_yn "Account Achievements" n)
|
||||
# Server Features
|
||||
MODULE_BREAKING_NEWS=$(ask_yn "Breaking News" n)
|
||||
MODULE_BOSS_ANNOUNCER=$(ask_yn "Boss Announcer" n)
|
||||
MODULE_AUTO_REVIVE=$(ask_yn "Auto Revive" n)
|
||||
# Utility
|
||||
MODULE_NPC_BEASTMASTER=$(ask_yn "NPC Beastmaster" n)
|
||||
MODULE_NPC_ENCHANTER=$(ask_yn "NPC Enchanter" n)
|
||||
MODULE_RANDOM_ENCHANTS=$(ask_yn "Random Enchants" n)
|
||||
MODULE_POCKET_PORTAL=$(ask_yn "Pocket Portal" n)
|
||||
MODULE_INSTANCE_RESET=$(ask_yn "Instance Reset" n)
|
||||
MODULE_TIME_IS_TIME=$(ask_yn "Time is Time" n)
|
||||
MODULE_GAIN_HONOR_GUARD=$(ask_yn "Gain Honor Guard" n)
|
||||
MODULE_ARAC=$(ask_yn "All Races All Classes (requires client patch)" n)
|
||||
fi
|
||||
|
||||
for mod_var in MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK MODULE_BLACK_MARKET_AUCTION_HOUSE; do
|
||||
eval "value=\$$mod_var"
|
||||
if [ "$value" = "1" ]; then
|
||||
NEEDS_CXX_REBUILD=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Summary
|
||||
say HEADER "SUMMARY"
|
||||
printf " %-18s %s\n" "Server Address:" "$SERVER_ADDRESS"
|
||||
printf " %-18s Realm:%s Auth:%s SOAP:%s MySQL:%s\n" "Ports:" "$REALM_PORT" "$AUTH_EXTERNAL_PORT" "$SOAP_EXTERNAL_PORT" "$MYSQL_EXTERNAL_PORT"
|
||||
printf " %-18s %s\n" "Storage Path:" "$STORAGE_PATH"
|
||||
printf " %-18s %s\n" "Container User:" "$CONTAINER_USER"
|
||||
printf " %-18s Daily %s:00 UTC, keep %sd/%sh\n" "Backups:" "$BACKUP_DAILY_TIME" "$BACKUP_RETENTION_DAYS" "$BACKUP_RETENTION_HOURS"
|
||||
printf " %-18s preset %s (playerbots=%s solo_lfg=%s autobalance=%s transmog=%s npc_buffer=%s learn_spells=%s fireworks=%s)\n" \
|
||||
"Modules:" "$MODE" "$MODULE_PLAYERBOTS" "$MODULE_SOLO_LFG" "$MODULE_AUTOBALANCE" "$MODULE_TRANSMOG" "$MODULE_NPC_BUFFER" "$MODULE_LEARN_SPELLS" "$MODULE_FIREWORKS"
|
||||
if [ "$NEEDS_CXX_REBUILD" = "1" ]; then
|
||||
printf " %-18s detected (source rebuild required)\n" "C++ modules:"
|
||||
fi
|
||||
|
||||
if [ "$NEEDS_CXX_REBUILD" = "1" ]; then
|
||||
echo ""
|
||||
say WARNING "These modules require compiling AzerothCore from source."
|
||||
RUN_REBUILD_NOW=$(ask_yn "Run module rebuild immediately?" n)
|
||||
AUTO_REBUILD_ON_DEPLOY=$(ask_yn "Enable automatic rebuild during future deploys?" n)
|
||||
if [ "$RUN_REBUILD_NOW" = "1" ] || [ "$AUTO_REBUILD_ON_DEPLOY" = "1" ]; then
|
||||
if [ -z "$MODULES_REBUILD_SOURCE_PATH_VALUE" ]; then
|
||||
MODULES_REBUILD_SOURCE_PATH_VALUE="./source/azerothcore"
|
||||
say INFO "Using default source path: ${MODULES_REBUILD_SOURCE_PATH_VALUE}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Confirm write
|
||||
local ENV_OUT="$(dirname "$0")/.env"
|
||||
if [ -f "$ENV_OUT" ]; then
|
||||
say WARNING ".env already exists at $(realpath "$ENV_OUT" 2>/dev/null || echo "$ENV_OUT"). It will be overwritten."
|
||||
local cont; cont=$(ask_yn "Continue and overwrite?" n); [ "$cont" = "1" ] || { say ERROR "Aborted"; exit 1; }
|
||||
fi
|
||||
|
||||
if [ -z "$MODULES_REBUILD_SOURCE_PATH_VALUE" ]; then
|
||||
MODULES_REBUILD_SOURCE_PATH_VALUE="./source/azerothcore"
|
||||
fi
|
||||
|
||||
DB_PLAYERBOTS_NAME=${DB_PLAYERBOTS_NAME:-acore_playerbots}
|
||||
|
||||
cat > "$ENV_OUT" <<EOF
|
||||
# Generated by ac-compose/setup.sh
|
||||
|
||||
COMPOSE_PROJECT_NAME=ac-compose
|
||||
|
||||
STORAGE_PATH=$STORAGE_PATH
|
||||
TZ=UTC
|
||||
|
||||
# Database
|
||||
MYSQL_IMAGE=mysql:8.0
|
||||
CONTAINER_MYSQL=ac-mysql
|
||||
MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD
|
||||
MYSQL_ROOT_HOST=%
|
||||
MYSQL_USER=root
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_EXTERNAL_PORT=$MYSQL_EXTERNAL_PORT
|
||||
MYSQL_CHARACTER_SET=utf8mb4
|
||||
MYSQL_COLLATION=utf8mb4_unicode_ci
|
||||
MYSQL_MAX_CONNECTIONS=1000
|
||||
MYSQL_INNODB_BUFFER_POOL_SIZE=256M
|
||||
MYSQL_INNODB_LOG_FILE_SIZE=64M
|
||||
DB_AUTH_NAME=acore_auth
|
||||
DB_WORLD_NAME=acore_world
|
||||
DB_CHARACTERS_NAME=acore_characters
|
||||
DB_PLAYERBOTS_NAME=$DB_PLAYERBOTS_NAME
|
||||
AC_DB_IMPORT_IMAGE=acore/ac-wotlk-db-import:14.0.0-dev
|
||||
|
||||
# Services (images)
|
||||
AC_AUTHSERVER_IMAGE=acore/ac-wotlk-authserver:14.0.0-dev
|
||||
AC_WORLDSERVER_IMAGE=acore/ac-wotlk-worldserver:14.0.0-dev
|
||||
AC_AUTHSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:authserver-Playerbot
|
||||
AC_WORLDSERVER_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:worldserver-Playerbot
|
||||
|
||||
# Client data images
|
||||
AC_CLIENT_DATA_IMAGE=acore/ac-wotlk-client-data:14.0.0-dev
|
||||
AC_CLIENT_DATA_IMAGE_PLAYERBOTS=uprightbass360/azerothcore-wotlk-playerbots:client-data-Playerbot
|
||||
|
||||
# Ports
|
||||
AUTH_EXTERNAL_PORT=$AUTH_EXTERNAL_PORT
|
||||
AUTH_PORT=3724
|
||||
WORLD_EXTERNAL_PORT=$REALM_PORT
|
||||
WORLD_PORT=8085
|
||||
SOAP_EXTERNAL_PORT=$SOAP_EXTERNAL_PORT
|
||||
SOAP_PORT=7878
|
||||
|
||||
# Realm
|
||||
SERVER_ADDRESS=$SERVER_ADDRESS
|
||||
REALM_PORT=$REALM_PORT
|
||||
|
||||
# Backups
|
||||
BACKUP_RETENTION_DAYS=$BACKUP_RETENTION_DAYS
|
||||
BACKUP_RETENTION_HOURS=$BACKUP_RETENTION_HOURS
|
||||
BACKUP_DAILY_TIME=$BACKUP_DAILY_TIME
|
||||
|
||||
# Container user
|
||||
CONTAINER_USER=$CONTAINER_USER
|
||||
|
||||
# Modules
|
||||
MODULE_PLAYERBOTS=$MODULE_PLAYERBOTS
|
||||
MODULE_AOE_LOOT=$MODULE_AOE_LOOT
|
||||
MODULE_LEARN_SPELLS=$MODULE_LEARN_SPELLS
|
||||
MODULE_FIREWORKS=$MODULE_FIREWORKS
|
||||
MODULE_INDIVIDUAL_PROGRESSION=$MODULE_INDIVIDUAL_PROGRESSION
|
||||
MODULE_AHBOT=$MODULE_AHBOT
|
||||
MODULE_AUTOBALANCE=$MODULE_AUTOBALANCE
|
||||
MODULE_TRANSMOG=$MODULE_TRANSMOG
|
||||
MODULE_NPC_BUFFER=$MODULE_NPC_BUFFER
|
||||
MODULE_DYNAMIC_XP=$MODULE_DYNAMIC_XP
|
||||
MODULE_SOLO_LFG=$MODULE_SOLO_LFG
|
||||
MODULE_1V1_ARENA=$MODULE_1V1_ARENA
|
||||
MODULE_PHASED_DUELS=$MODULE_PHASED_DUELS
|
||||
MODULE_BREAKING_NEWS=$MODULE_BREAKING_NEWS
|
||||
MODULE_BOSS_ANNOUNCER=$MODULE_BOSS_ANNOUNCER
|
||||
MODULE_ACCOUNT_ACHIEVEMENTS=$MODULE_ACCOUNT_ACHIEVEMENTS
|
||||
MODULE_AUTO_REVIVE=$MODULE_AUTO_REVIVE
|
||||
MODULE_GAIN_HONOR_GUARD=$MODULE_GAIN_HONOR_GUARD
|
||||
MODULE_ARAC=$MODULE_ARAC
|
||||
MODULE_TIME_IS_TIME=$MODULE_TIME_IS_TIME
|
||||
MODULE_POCKET_PORTAL=$MODULE_POCKET_PORTAL
|
||||
MODULE_RANDOM_ENCHANTS=$MODULE_RANDOM_ENCHANTS
|
||||
MODULE_SOLOCRAFT=$MODULE_SOLOCRAFT
|
||||
MODULE_PVP_TITLES=$MODULE_PVP_TITLES
|
||||
MODULE_NPC_BEASTMASTER=$MODULE_NPC_BEASTMASTER
|
||||
MODULE_NPC_ENCHANTER=$MODULE_NPC_ENCHANTER
|
||||
MODULE_INSTANCE_RESET=$MODULE_INSTANCE_RESET
|
||||
MODULE_LEVEL_GRANT=$MODULE_LEVEL_GRANT
|
||||
MODULE_ASSISTANT=$MODULE_ASSISTANT
|
||||
MODULE_REAGENT_BANK=$MODULE_REAGENT_BANK
|
||||
MODULE_BLACK_MARKET_AUCTION_HOUSE=$MODULE_BLACK_MARKET_AUCTION_HOUSE
|
||||
|
||||
# Client data
|
||||
CLIENT_DATA_VERSION=${CLIENT_DATA_VERSION:-v16}
|
||||
|
||||
# Playerbot runtime
|
||||
PLAYERBOT_ENABLED=$PLAYERBOT_ENABLED
|
||||
PLAYERBOT_MAX_BOTS=$PLAYERBOT_MAX_BOTS
|
||||
|
||||
# Rebuild automation
|
||||
AUTO_REBUILD_ON_DEPLOY=$AUTO_REBUILD_ON_DEPLOY
|
||||
MODULES_REBUILD_SOURCE_PATH=$MODULES_REBUILD_SOURCE_PATH_VALUE
|
||||
|
||||
# Eluna
|
||||
AC_ELUNA_ENABLED=1
|
||||
AC_ELUNA_TRACE_BACK=1
|
||||
AC_ELUNA_AUTO_RELOAD=1
|
||||
AC_ELUNA_BYTECODE_CACHE=1
|
||||
AC_ELUNA_SCRIPT_PATH=lua_scripts
|
||||
AC_ELUNA_REQUIRE_PATHS=
|
||||
AC_ELUNA_REQUIRE_CPATHS=
|
||||
AC_ELUNA_AUTO_RELOAD_INTERVAL=1
|
||||
|
||||
# Tools
|
||||
PMA_HOST=ac-mysql
|
||||
PMA_PORT=3306
|
||||
PMA_USER=root
|
||||
PMA_EXTERNAL_PORT=8081
|
||||
PMA_ARBITRARY=1
|
||||
PMA_ABSOLUTE_URI=
|
||||
PMA_UPLOAD_LIMIT=300M
|
||||
PMA_MEMORY_LIMIT=512M
|
||||
PMA_MAX_EXECUTION_TIME=600
|
||||
KEIRA3_EXTERNAL_PORT=4201
|
||||
KEIRA_DATABASE_HOST=ac-mysql
|
||||
KEIRA_DATABASE_PORT=3306
|
||||
|
||||
# Networking
|
||||
NETWORK_NAME=azerothcore
|
||||
NETWORK_SUBNET=172.20.0.0/16
|
||||
NETWORK_GATEWAY=172.20.0.1
|
||||
EOF
|
||||
|
||||
say SUCCESS ".env written to $ENV_OUT"
|
||||
show_realm_configured
|
||||
|
||||
if [ "$RUN_REBUILD_NOW" = "1" ]; then
|
||||
echo ""
|
||||
say HEADER "MODULE REBUILD"
|
||||
if [ -n "$MODULES_REBUILD_SOURCE_PATH_VALUE" ]; then
|
||||
if ./scripts/rebuild-with-modules.sh --yes --source "$MODULES_REBUILD_SOURCE_PATH_VALUE"; then
|
||||
say SUCCESS "Module rebuild completed"
|
||||
else
|
||||
say WARNING "Module rebuild failed; run ./scripts/rebuild-with-modules.sh manually once issues are resolved."
|
||||
fi
|
||||
else
|
||||
say WARNING "Rebuild path was not provided; skipping automatic rebuild."
|
||||
fi
|
||||
fi
|
||||
|
||||
say INFO "Ready to bring your realm online:"
|
||||
if [ "$MODULE_PLAYERBOTS" = "1" ]; then
|
||||
echo " 🚀 Quick deploy: ./deploy.sh"
|
||||
echo " 🔧 Manual: docker compose --profile db --profile services-playerbots --profile client-data-bots --profile modules up -d"
|
||||
else
|
||||
echo " 🚀 Quick deploy: ./deploy.sh"
|
||||
echo " 🔧 Manual: docker compose --profile db --profile services-standard --profile client-data --profile modules up -d"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
if [ "$MODULE_PLAYERBOTS" = "1" ]; then
|
||||
PLAYERBOT_ENABLED=1
|
||||
PLAYERBOT_MAX_BOTS=$(ask "Maximum concurrent playerbots" 40 validate_number)
|
||||
fi
|
||||
303
status.sh
Executable file
303
status.sh
Executable file
@@ -0,0 +1,303 @@
|
||||
#!/bin/bash
|
||||
# ac-compose condensed realm status view
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$SCRIPT_DIR"
|
||||
ENV_FILE="$PROJECT_DIR/.env"
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; BLUE='\033[0;34m'; NC='\033[0m'
|
||||
|
||||
WATCH_MODE=true
|
||||
LOG_LINES=5
|
||||
SHOW_LOGS=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--watch|-w) WATCH_MODE=true; shift;;
|
||||
--once) WATCH_MODE=false; shift;;
|
||||
--logs|-l) SHOW_LOGS=true; shift;;
|
||||
--lines) LOG_LINES="$2"; shift 2;;
|
||||
-h|--help)
|
||||
cat <<EOF
|
||||
ac-compose realm status
|
||||
|
||||
Usage: $0 [options]
|
||||
-w, --watch Continuously refresh every 3s (default)
|
||||
--once Show a single snapshot then exit
|
||||
-l, --logs Show trailing logs for each service
|
||||
--lines N Number of log lines when --logs is used (default 5)
|
||||
EOF
|
||||
exit 0;;
|
||||
*) echo "Unknown option: $1" >&2; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
command -v docker >/dev/null 2>&1 || { echo "Docker CLI not found" >&2; exit 1; }
|
||||
docker info >/dev/null 2>&1 || { echo "Docker daemon unavailable" >&2; exit 1; }
|
||||
|
||||
read_env(){
|
||||
local key="$1" default="$2" value
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
value="$(grep -E "^${key}=" "$ENV_FILE" 2>/dev/null | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||
fi
|
||||
if [ -z "$value" ]; then
|
||||
value="$default"
|
||||
fi
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
PROJECT_NAME="$(read_env COMPOSE_PROJECT_NAME ac-compose)"
|
||||
NETWORK_NAME="$(read_env NETWORK_NAME azerothcore)"
|
||||
AUTH_PORT="$(read_env AUTH_EXTERNAL_PORT 3784)"
|
||||
WORLD_PORT="$(read_env WORLD_EXTERNAL_PORT 8215)"
|
||||
SOAP_PORT="$(read_env SOAP_EXTERNAL_PORT 7778)"
|
||||
MYSQL_PORT="$(read_env MYSQL_EXTERNAL_PORT 64306)"
|
||||
PMA_PORT="$(read_env PMA_EXTERNAL_PORT 8081)"
|
||||
KEIRA_PORT="$(read_env KEIRA3_EXTERNAL_PORT 4201)"
|
||||
ELUNA_ENABLED="$(read_env AC_ELUNA_ENABLED 1)"
|
||||
|
||||
container_exists(){
|
||||
docker ps -a --format '{{.Names}}' | grep -qx "$1"
|
||||
}
|
||||
|
||||
container_running(){
|
||||
docker ps --format '{{.Names}}' | grep -qx "$1"
|
||||
}
|
||||
|
||||
format_state(){
|
||||
local status="$1" health="$2" started="$3" exit_code="$4"
|
||||
local started_fmt
|
||||
if [ -n "$started" ] && [[ "$started" != "--:--:--" ]]; then
|
||||
started_fmt="$(date -d "$started" '+%H:%M:%S' 2>/dev/null || echo "")"
|
||||
if [ -z "$started_fmt" ]; then
|
||||
started_fmt="$(echo "$started" | cut -c12-19)"
|
||||
fi
|
||||
[ -z "$started_fmt" ] && started_fmt="--:--:--"
|
||||
else
|
||||
started_fmt="--:--:--"
|
||||
fi
|
||||
case "$status" in
|
||||
running)
|
||||
local desc="running (since $started_fmt)" colour="$GREEN"
|
||||
if [ "$health" = "healthy" ]; then
|
||||
desc="healthy (since $started_fmt)"
|
||||
elif [ "$health" = "none" ]; then
|
||||
desc="running (since $started_fmt)"
|
||||
else
|
||||
desc="$health (since $started_fmt)"; colour="$YELLOW"
|
||||
[ "$health" = "unhealthy" ] && colour="$RED"
|
||||
fi
|
||||
echo "${colour}|● ${desc}"
|
||||
;;
|
||||
exited)
|
||||
local colour="$YELLOW"
|
||||
[ "$exit_code" != "0" ] && colour="$RED"
|
||||
echo "${colour}|○ exited (code $exit_code)"
|
||||
;;
|
||||
restarting)
|
||||
echo "${YELLOW}|● restarting"
|
||||
;;
|
||||
created)
|
||||
echo "${CYAN}|○ created"
|
||||
;;
|
||||
*)
|
||||
echo "${RED}|○ $status"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
short_image(){
|
||||
local img="$1"
|
||||
if [[ "$img" != */* ]]; then
|
||||
echo "$img"
|
||||
return
|
||||
fi
|
||||
local repo="${img%%/*}"
|
||||
local rest="${img#*/}"
|
||||
local name="${rest%%:*}"
|
||||
local tag="${img##*:}"
|
||||
local has_tag="true"
|
||||
[[ "$img" != *":"* ]] && has_tag="false"
|
||||
local last="${name##*/}"
|
||||
if [ "$has_tag" = "true" ]; then
|
||||
if [[ "$tag" =~ ^[0-9] ]] || [ "$tag" = "latest" ]; then
|
||||
echo "$repo/$last"
|
||||
else
|
||||
echo "$repo/$tag"
|
||||
fi
|
||||
else
|
||||
echo "$repo/$last"
|
||||
fi
|
||||
}
|
||||
|
||||
print_service(){
|
||||
local container="$1" label="$2"
|
||||
if container_exists "$container"; then
|
||||
local status health started exit_code image
|
||||
status="$(docker inspect --format='{{.State.Status}}' "$container" 2>/dev/null || echo "unknown")"
|
||||
health="$(docker inspect --format='{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$container" 2>/dev/null || echo "none")"
|
||||
started="$(docker inspect --format='{{.State.StartedAt}}' "$container" 2>/dev/null | cut -c12-19 2>/dev/null || echo "--:--:--")"
|
||||
exit_code="$(docker inspect --format='{{.State.ExitCode}}' "$container" 2>/dev/null || echo "?")"
|
||||
image="$(docker inspect --format='{{.Config.Image}}' "$container" 2>/dev/null || echo "-")"
|
||||
local state_info colour text
|
||||
state_info="$(format_state "$status" "$health" "$started" "$exit_code")"
|
||||
colour="${state_info%%|*}"
|
||||
text="${state_info#*|}"
|
||||
printf "%-20s %b%-30s%b %s\n" "$label" "$colour" "$text" "$NC" "$(short_image "$image")"
|
||||
if [ "$SHOW_LOGS" = true ]; then
|
||||
docker logs "$container" --tail "$LOG_LINES" 2>/dev/null | sed 's/^/ /' || printf " (no logs available)\n"
|
||||
fi
|
||||
else
|
||||
printf "%-20s %b%-30s%b %s\n" "$label" "$RED" "○ missing" "$NC" "-"
|
||||
fi
|
||||
}
|
||||
|
||||
module_summary(){
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "MODULES: (env not found)"
|
||||
return
|
||||
fi
|
||||
local module_vars
|
||||
module_vars="$(grep -E '^MODULE_[A-Z_]+=1' "$ENV_FILE" 2>/dev/null | cut -d'=' -f1)"
|
||||
if [ -n "$module_vars" ]; then
|
||||
local arr=()
|
||||
while IFS= read -r mod; do
|
||||
[ -z "$mod" ] && continue
|
||||
local pretty="${mod#MODULE_}"
|
||||
pretty="$(echo "$pretty" | tr '[:upper:]' '[:lower:]' | tr '_' ' ')"
|
||||
arr+=("$pretty")
|
||||
done <<< "$module_vars"
|
||||
local joined=""
|
||||
for item in "${arr[@]}"; do
|
||||
joined+="$item, "
|
||||
done
|
||||
joined="${joined%, }"
|
||||
echo "MODULES: $joined"
|
||||
else
|
||||
echo "MODULES: none"
|
||||
fi
|
||||
|
||||
if container_running "ac-worldserver"; then
|
||||
local playerbot="disabled"
|
||||
local module_playerbots
|
||||
module_playerbots="$(read_env MODULE_PLAYERBOTS 0)"
|
||||
if [ "$module_playerbots" = "1" ]; then
|
||||
playerbot="enabled"
|
||||
if docker inspect --format='{{.State.Status}}' ac-worldserver 2>/dev/null | grep -q "running"; then
|
||||
playerbot="running"
|
||||
fi
|
||||
fi
|
||||
local eluna="disabled"
|
||||
[ "$ELUNA_ENABLED" = "1" ] && eluna="running"
|
||||
echo "RUNTIME: playerbots $playerbot | eluna $eluna"
|
||||
fi
|
||||
}
|
||||
|
||||
user_stats(){
|
||||
if ! container_running "ac-mysql"; then
|
||||
printf "USERS: %sDatabase offline%s\n" "$RED" "$NC"
|
||||
return
|
||||
fi
|
||||
|
||||
local mysql_pw db_auth db_characters
|
||||
mysql_pw="$(read_env MYSQL_ROOT_PASSWORD azerothcore123)"
|
||||
db_auth="$(read_env DB_AUTH_NAME acore_auth)"
|
||||
db_characters="$(read_env DB_CHARACTERS_NAME acore_characters)"
|
||||
|
||||
local exec_mysql
|
||||
exec_mysql(){
|
||||
local database="$1" query="$2"
|
||||
docker exec ac-mysql mysql -N -B -u root -p"${mysql_pw}" "$database" -e "$query" 2>/dev/null | tail -n1
|
||||
}
|
||||
|
||||
local account_total account_online character_total last_week
|
||||
account_total="$(exec_mysql "$db_auth" "SELECT COUNT(*) FROM account;")"
|
||||
account_online="$(exec_mysql "$db_auth" "SELECT COUNT(*) FROM account WHERE online = 1;")"
|
||||
character_total="$(exec_mysql "$db_characters" "SELECT COUNT(*) FROM characters;")"
|
||||
last_week="$(exec_mysql "$db_auth" "SELECT COUNT(*) FROM account WHERE last_login >= DATE_SUB(UTC_TIMESTAMP(), INTERVAL 7 DAY);")"
|
||||
|
||||
[[ -z "$account_total" ]] && account_total="0"
|
||||
[[ -z "$account_online" ]] && account_online="0"
|
||||
[[ -z "$character_total" ]] && character_total="0"
|
||||
[[ -z "$last_week" ]] && last_week="0"
|
||||
|
||||
printf "USERS: Accounts %b%s%b | Online %b%s%b | Characters %b%s%b | Active 7d %b%s%b\n" \
|
||||
"$GREEN" "$account_total" "$NC" \
|
||||
"$YELLOW" "$account_online" "$NC" \
|
||||
"$CYAN" "$character_total" "$NC" \
|
||||
"$BLUE" "$last_week" "$NC"
|
||||
}
|
||||
|
||||
ports_summary(){
|
||||
local names=("Auth" "World" "SOAP" "MySQL" "phpMyAdmin" "Keira3")
|
||||
local ports=("$AUTH_PORT" "$WORLD_PORT" "$SOAP_PORT" "$MYSQL_PORT" "$PMA_PORT" "$KEIRA_PORT")
|
||||
printf "PORTS:\n"
|
||||
for i in "${!names[@]}"; do
|
||||
local svc="${names[$i]}"
|
||||
local port="${ports[$i]}"
|
||||
if timeout 1 bash -c "</dev/tcp/127.0.0.1/${port}" >/dev/null 2>&1; then
|
||||
printf " %-10s %-6s %b●%b reachable\n" "$svc" "$port" "$GREEN" "$NC"
|
||||
else
|
||||
printf " %-10s %-6s %b○%b unreachable\n" "$svc" "$port" "$RED" "$NC"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
network_summary(){
|
||||
if docker network ls --format '{{.Name}}' | grep -qx "$NETWORK_NAME"; then
|
||||
echo "DOCKER NET: $NETWORK_NAME"
|
||||
else
|
||||
echo "DOCKER NET: missing ($NETWORK_NAME)"
|
||||
fi
|
||||
}
|
||||
|
||||
show_realm_status_header(){
|
||||
echo -e "${BLUE}🏰 REALM STATUS DASHBOARD 🏰${NC}"
|
||||
echo -e "${BLUE}═══════════════════════════${NC}"
|
||||
}
|
||||
|
||||
render_snapshot(){
|
||||
show_realm_status_header
|
||||
printf "\nTIME %s PROJECT %s\n\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$PROJECT_NAME"
|
||||
printf "%-20s %-28s %s\n" "SERVICE" "STATE" "IMAGE"
|
||||
printf "%-20s %-28s %s\n" "--------------------" "----------------------------" "------------------------------"
|
||||
print_service ac-mysql "MySQL"
|
||||
print_service ac-backup "Backup"
|
||||
print_service ac-db-init "DB Init"
|
||||
print_service ac-db-import "DB Import"
|
||||
print_service ac-authserver "Auth Server"
|
||||
print_service ac-worldserver "World Server"
|
||||
print_service ac-client-data "Client Data"
|
||||
print_service ac-modules "Module Manager"
|
||||
print_service ac-post-install "Post Install"
|
||||
print_service ac-phpmyadmin "phpMyAdmin"
|
||||
print_service ac-keira3 "Keira3"
|
||||
echo ""
|
||||
module_summary
|
||||
user_stats
|
||||
echo ""
|
||||
echo "$(ports_summary)"
|
||||
echo "$(network_summary)"
|
||||
}
|
||||
|
||||
display_snapshot(){
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
render_snapshot >"$tmp"
|
||||
clear 2>/dev/null || printf '\033[2J\033[H'
|
||||
cat "$tmp"
|
||||
rm -f "$tmp"
|
||||
}
|
||||
|
||||
if [ "$WATCH_MODE" = true ]; then
|
||||
while true; do
|
||||
display_snapshot
|
||||
sleep 3
|
||||
done
|
||||
else
|
||||
display_snapshot
|
||||
fi
|
||||
129
todo.md
129
todo.md
@@ -1,129 +0,0 @@
|
||||
# AzerothCore Deployment Issues - Todo List
|
||||
|
||||
## Deployment Summary & Status
|
||||
|
||||
### ✅ **Completed:**
|
||||
- [x] Find and execute wizard deployment script
|
||||
- [x] Configure deployment for 13 module version (suggested preset: 8 modules)
|
||||
- [x] Monitor deployment process for warnings/errors
|
||||
- [x] Report any issues found for bug fixing
|
||||
|
||||
### ✅ **Critical Issues RESOLVED:**
|
||||
|
||||
#### 1. **Database Schema Missing** ✅ **FIXED**
|
||||
- **Issue**: `[1146] Table 'acore_world.charsections_dbc' doesn't exist`
|
||||
- **Resolution**:
|
||||
- [x] Added missing `emotetextsound_dbc.sql` to source project
|
||||
- [x] Imported all DBC tables to database (111 tables)
|
||||
- [x] Worldserver now starts successfully
|
||||
- [x] Created fix in playerbot source repository
|
||||
|
||||
#### 2. **Container Image Compatibility Issues** ✅ **FIXED**
|
||||
- **Issue**: Multiple containers failing with exit code 127
|
||||
- **Resolution**:
|
||||
- [x] Fixed client-data container with multi-OS package manager detection
|
||||
- [x] Client data now downloads successfully (15GB)
|
||||
- [x] Modules container working correctly
|
||||
- [x] Created backward-compatible Alpine/Ubuntu scripts
|
||||
|
||||
#### 3. **Environment Variable Configuration** ✅ **FIXED**
|
||||
- **Issue**: Multiple undefined variables in modules deployment
|
||||
- **Resolution**:
|
||||
- [x] Wizard generates proper custom environment files
|
||||
- [x] All 8 suggested modules configured correctly
|
||||
- [x] Variable substitution working properly
|
||||
|
||||
#### 4. **Network/Script Download Failures** ✅ **FIXED**
|
||||
- **Issue**: Module management scripts failing to download
|
||||
- **Resolution**:
|
||||
- [x] Network connectivity working
|
||||
- [x] Scripts download successfully
|
||||
- [x] Multi-OS compatibility implemented
|
||||
|
||||
### ⚠️ **Remaining Issues:**
|
||||
|
||||
#### 5. **Backup Container Restart Loop** (ACTIVE)
|
||||
- **Issue**: `ac-backup` container restarting with exit code 127
|
||||
- **Status**: Under investigation
|
||||
- **Action**:
|
||||
- [ ] Check backup container logs
|
||||
- [ ] Verify backup script compatibility
|
||||
- [ ] Fix container startup issues
|
||||
|
||||
### 📋 **Next Steps:**
|
||||
1. **Immediate**: Check `ac-db-import` container completion status
|
||||
2. **Priority**: Fix database schema issues to enable worldserver startup
|
||||
3. **Follow-up**: Address container image compatibility for full deployment
|
||||
4. **Testing**: Verify all services start and communicate properly
|
||||
|
||||
### 🛠️ **Commands Used:**
|
||||
```bash
|
||||
# Wizard execution
|
||||
echo -e "1\n8215\n3784\n7778\n64306\nazerothcore123\n3\n6\n09\nUTC\n1\ny" | ./scripts/setup-server.sh
|
||||
|
||||
# Database deployment
|
||||
docker compose --env-file docker-compose-azerothcore-database-custom.env -f docker-compose-azerothcore-database.yml up -d
|
||||
|
||||
# Services deployment
|
||||
docker compose --env-file docker-compose-azerothcore-services-custom.env -f docker-compose-azerothcore-services.yml up -d
|
||||
|
||||
# Modules deployment
|
||||
docker compose --env-file docker-compose-azerothcore-modules-custom.env -f docker-compose-azerothcore-modules.yml up -d
|
||||
```
|
||||
|
||||
### 🔍 **Diagnostic Commands:**
|
||||
```bash
|
||||
# Check container status
|
||||
docker ps -a
|
||||
|
||||
# Check specific logs
|
||||
docker logs ac-worldserver
|
||||
docker logs ac-db-import
|
||||
docker logs ac-client-data
|
||||
docker logs ac-modules
|
||||
|
||||
# Check database connectivity
|
||||
docker exec ac-mysql mysql -u root -p -e "SHOW DATABASES;"
|
||||
```
|
||||
|
||||
## 🔍 **Root Cause Analysis Found:**
|
||||
|
||||
### **Database Schema Version Mismatch**
|
||||
- Database has 298 tables imported successfully
|
||||
- Missing specific table: `charsections_dbc` (and possibly other DBC tables)
|
||||
- Playerbot database schema appears incomplete or outdated
|
||||
- Worldserver expects newer/different schema than what was imported
|
||||
|
||||
### **Container Image Issues Identified**
|
||||
1. **client-data container**: Ubuntu-based but script tries to use Alpine `apk` package manager
|
||||
2. **modules container**: curl download failures - network/permission issues
|
||||
3. **Base images**: uprightbass360 images use Ubuntu 22.04 base, scripts expect Alpine
|
||||
|
||||
### **Immediate Fixes Needed**
|
||||
- [ ] Update database schema to include missing DBC tables
|
||||
- [ ] Fix client-data container to use `apt` instead of `apk`
|
||||
- [ ] Resolve module script download issues
|
||||
- [ ] Verify schema compatibility between playerbot build and database
|
||||
|
||||
## 🆕 **UPDATES - Issues Resolved:**
|
||||
|
||||
### ✅ **Major Fixes Completed:**
|
||||
1. **Database Schema Issues** ✅ **RESOLVED**
|
||||
- Added missing `emotetextsound_dbc.sql` to source project
|
||||
- Imported all DBC tables - worldserver now starts successfully
|
||||
- Worldserver status: `Up (healthy)` with Eluna scripts loaded
|
||||
|
||||
2. **Container Script Compatibility** ✅ **RESOLVED**
|
||||
- Fixed client-data container with multi-OS package manager detection
|
||||
- Client data downloads working (15GB extracted successfully)
|
||||
- Updated docker-compose with Alpine/Ubuntu compatibility
|
||||
|
||||
3. **Source Project Improvements** ✅ **COMPLETED**
|
||||
- Updated cleanup script for current deployment structure
|
||||
- Ready to push fixes back to azerothcore-wotlk-playerbots repository
|
||||
|
||||
### ⚠️ **Active Issue Identified:**
|
||||
- **Backup Container**: `ac-backup` in restart loop with exit code 127 - **INVESTIGATING**
|
||||
|
||||
---
|
||||
**Status**: **MAJOR SUCCESS** ✅ - Core server functional, investigating remaining backup issue.
|
||||
186
verify-deployment.sh
Executable file
186
verify-deployment.sh
Executable file
@@ -0,0 +1,186 @@
|
||||
#!/bin/bash
|
||||
# Project: ac-compose
|
||||
set -e
|
||||
|
||||
# Simple profile-aware deploy + health check for profiles-verify/compose.yml
|
||||
|
||||
BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
|
||||
info(){ echo -e "${BLUE}ℹ️ $*${NC}"; }
|
||||
ok(){ echo -e "${GREEN}✅ $*${NC}"; }
|
||||
warn(){ echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||||
err(){ echo -e "${RED}❌ $*${NC}"; }
|
||||
|
||||
COMPOSE_FILE="$(dirname "$0")/compose.yml"
|
||||
ENV_FILE=""
|
||||
PROFILES=(db services-standard client-data modules tools)
|
||||
SKIP_DEPLOY=false
|
||||
QUICK=false
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
Usage: $0 [--profiles p1,p2,...] [--env-file path] [--skip-deploy] [--quick]
|
||||
Default profiles: db,services-standard,client-data,modules,tools
|
||||
Examples:
|
||||
$0 --profiles db,services-standard,client-data --env-file ./services.env
|
||||
$0 --profiles db,services-playerbots,client-data-bots,modules,tools
|
||||
EOF
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--profiles) IFS=',' read -r -a PROFILES <<< "$2"; shift 2;;
|
||||
--env-file) ENV_FILE="$2"; shift 2;;
|
||||
--skip-deploy) SKIP_DEPLOY=true; shift;;
|
||||
--quick) QUICK=true; shift;;
|
||||
-h|--help) usage; exit 0;;
|
||||
*) err "Unknown arg: $1"; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
resolve_project_name(){
|
||||
local env_path
|
||||
if [ -n "$ENV_FILE" ]; then
|
||||
env_path="$ENV_FILE"
|
||||
else
|
||||
env_path="$(dirname "$COMPOSE_FILE")/.env"
|
||||
fi
|
||||
local raw_name=""
|
||||
if [ -f "$env_path" ]; then
|
||||
raw_name="$(grep -E '^COMPOSE_PROJECT_NAME=' "$env_path" | tail -n1 | cut -d'=' -f2-)"
|
||||
fi
|
||||
if [ -z "$raw_name" ]; then
|
||||
raw_name="acore-compose"
|
||||
fi
|
||||
local sanitized
|
||||
sanitized="$(echo "$raw_name" | tr '[:upper:]' '[:lower:]')"
|
||||
sanitized="${sanitized// /-}"
|
||||
sanitized="$(echo "$sanitized" | tr -cd 'a-z0-9_-')"
|
||||
if [[ -z "$sanitized" ]]; then
|
||||
sanitized="acore-compose"
|
||||
elif [[ ! "$sanitized" =~ ^[a-z0-9] ]]; then
|
||||
sanitized="ac${sanitized}"
|
||||
fi
|
||||
echo "$sanitized"
|
||||
}
|
||||
|
||||
run_compose(){
|
||||
local compose_args=()
|
||||
local project_name
|
||||
project_name="$(resolve_project_name)"
|
||||
compose_args+=(--project-name "$project_name")
|
||||
if [ -n "$ENV_FILE" ]; then
|
||||
compose_args+=(--env-file "$ENV_FILE")
|
||||
fi
|
||||
compose_args+=(-f "$COMPOSE_FILE")
|
||||
docker compose "${compose_args[@]}" "$@"
|
||||
}
|
||||
|
||||
env_file_path(){
|
||||
if [ -n "$ENV_FILE" ]; then
|
||||
echo "$ENV_FILE"
|
||||
else
|
||||
echo "$(dirname "$COMPOSE_FILE")/.env"
|
||||
fi
|
||||
}
|
||||
|
||||
read_env_value(){
|
||||
local key="$1" default="${2:-}"
|
||||
local env_path value
|
||||
env_path="$(env_file_path)"
|
||||
if [ -f "$env_path" ]; then
|
||||
value="$(grep -E "^${key}=" "$env_path" | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||
fi
|
||||
if [ -z "$value" ]; then
|
||||
value="$default"
|
||||
fi
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
handle_auto_rebuild(){
|
||||
local storage_path
|
||||
storage_path="$(read_env_value STORAGE_PATH "./storage")"
|
||||
if [[ "$storage_path" != /* ]]; then
|
||||
storage_path="$(dirname "$COMPOSE_FILE")/$storage_path"
|
||||
fi
|
||||
local sentinel="$storage_path/modules/.requires_rebuild"
|
||||
[ -f "$sentinel" ] || return 0
|
||||
|
||||
info "Module rebuild required (detected $(realpath "$sentinel" 2>/dev/null || echo "$sentinel"))."
|
||||
local auto_rebuild
|
||||
auto_rebuild="$(read_env_value AUTO_REBUILD_ON_DEPLOY "0")"
|
||||
if [ "$auto_rebuild" != "1" ]; then
|
||||
warn "Run ./scripts/rebuild-with-modules.sh after preparing your source tree."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local rebuild_source
|
||||
rebuild_source="$(read_env_value MODULES_REBUILD_SOURCE_PATH "")"
|
||||
info "AUTO_REBUILD_ON_DEPLOY=1; invoking ./scripts/rebuild-with-modules.sh."
|
||||
local cmd=(./scripts/rebuild-with-modules.sh --yes)
|
||||
if [ -n "$rebuild_source" ]; then
|
||||
cmd+=(--source "$rebuild_source")
|
||||
fi
|
||||
if "${cmd[@]}"; then
|
||||
info "Module rebuild completed."
|
||||
else
|
||||
warn "Automatic rebuild failed; run ./scripts/rebuild-with-modules.sh manually."
|
||||
fi
|
||||
}
|
||||
|
||||
check_health(){
|
||||
local name="$1"
|
||||
local status=$(docker inspect --format='{{.State.Health.Status}}' "$name" 2>/dev/null || echo "no-health-check")
|
||||
if [ "$status" = "healthy" ]; then ok "$name: healthy"; return 0; fi
|
||||
if docker ps --format '{{.Names}}' | grep -q "^${name}$"; then ok "$name: running"; return 0; fi
|
||||
err "$name: not running"; return 1
|
||||
}
|
||||
|
||||
wait_log(){
|
||||
local name="$1"; local needle="$2"; local attempts="${3:-360}"; local interval=5
|
||||
info "Waiting for $name log: '$needle' ... (timeout: $((attempts*interval))s)"
|
||||
for i in $(seq 1 "$attempts"); do
|
||||
if docker logs "$name" 2>/dev/null | grep -q "$needle"; then ok "$name ready"; return 0; fi
|
||||
sleep "$interval"
|
||||
done
|
||||
warn "$name did not report '$needle'"
|
||||
return 1
|
||||
}
|
||||
|
||||
deploy(){
|
||||
info "Deploying profiles: ${PROFILES[*]}"
|
||||
local args=()
|
||||
for p in "${PROFILES[@]}"; do args+=(--profile "$p"); done
|
||||
run_compose "${args[@]}" up -d
|
||||
}
|
||||
|
||||
health_checks(){
|
||||
info "Checking container health"
|
||||
local failures=0
|
||||
check_health ac-mysql || ((failures++))
|
||||
check_health ac-authserver || ((failures++))
|
||||
check_health ac-worldserver || ((failures++))
|
||||
if [ "$QUICK" = false ]; then
|
||||
info "Port checks"
|
||||
for port in 64306 3784 8215 7778 8081 4201; do
|
||||
if timeout 3 bash -c "</dev/tcp/127.0.0.1/$port" 2>/dev/null; then ok "port $port: open"; else warn "port $port: closed"; fi
|
||||
done
|
||||
fi
|
||||
if [ $failures -eq 0 ]; then ok "All core services healthy"; else err "$failures service checks failed"; return 1; fi
|
||||
}
|
||||
|
||||
main(){
|
||||
if [ "$SKIP_DEPLOY" = false ]; then
|
||||
deploy
|
||||
# Wait for client-data completion if profile active
|
||||
if printf '%s\n' "${PROFILES[@]}" | grep -q '^client-data$\|^client-data-bots$'; then
|
||||
wait_log ac-client-data "Game data setup complete" || true
|
||||
fi
|
||||
# Give worldserver time to boot
|
||||
sleep 10
|
||||
fi
|
||||
health_checks
|
||||
handle_auto_rebuild
|
||||
info "Endpoints: MySQL:64306, Auth:3784, World:8215, SOAP:7778, phpMyAdmin:8081, Keira3:4201"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user