From 68dc21d5efdf10efabf31ebb5ae068f7cef6ef0b Mon Sep 17 00:00:00 2001 From: uprightbass360 Date: Mon, 10 Nov 2025 01:59:47 -0500 Subject: [PATCH] import enhancements and npc spawn sketches --- .env.template | 2 + README.md | 17 + database-import/README.md | 19 +- deploy.sh | 19 +- docker-compose.yml | 5 + docs/ADVANCED.md | 4 +- docs/GETTING_STARTED.md | 17 + docs/NPCS.md | 374 ++++++++++++++++++ scripts/admin/fix-silvermoon-npcs.sql | 24 ++ scripts/admin/replace-silvermoon-envoys.sql | 31 ++ .../replace-silvermoon-walk-of-elders.sql | 31 ++ scripts/admin/silvermoon-npc-line.sql | 52 +++ .../silvermoon-walk-of-elders-all-npcs.sql | 72 ++++ scripts/admin/simple-npc-line.sql | 13 + scripts/admin/spawn-all-npcs.sh | 222 +++++++++++ scripts/bash/backup-merge.sh | 4 +- scripts/bash/backup-scheduler.sh | 44 ++- scripts/bash/db-import-conditional.sh | 5 + scripts/bash/fix-item-import.sh | 257 ++++++++++++ scripts/bash/import-database-files.sh | 148 ++++++- scripts/bash/stage-modules.sh | 15 +- 21 files changed, 1351 insertions(+), 24 deletions(-) create mode 100644 docs/NPCS.md create mode 100644 scripts/admin/fix-silvermoon-npcs.sql create mode 100644 scripts/admin/replace-silvermoon-envoys.sql create mode 100644 scripts/admin/replace-silvermoon-walk-of-elders.sql create mode 100644 scripts/admin/silvermoon-npc-line.sql create mode 100644 scripts/admin/silvermoon-walk-of-elders-all-npcs.sql create mode 100644 scripts/admin/simple-npc-line.sql create mode 100755 scripts/admin/spawn-all-npcs.sh create mode 100755 scripts/bash/fix-item-import.sh diff --git a/.env.template b/.env.template index 32f93bb..0e28897 100644 --- a/.env.template +++ b/.env.template @@ -135,6 +135,8 @@ DB_PLAYERBOTS_NAME=acore_playerbots BACKUP_RETENTION_DAYS=3 BACKUP_RETENTION_HOURS=6 BACKUP_DAILY_TIME=09 +# Optional comma/space separated schemas to include in automated backups +BACKUP_EXTRA_DATABASES= BACKUP_HEALTHCHECK_MAX_MINUTES=1440 BACKUP_HEALTHCHECK_GRACE_SECONDS=4500 BACKUP_HEALTHCHECK_INTERVAL=60s diff --git a/README.md b/README.md index e2dbf6a..c0fae5d 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ A complete containerized deployment of AzerothCore WoW 3.3.5a (Wrath of the Lich - [Complete Module Catalog](#complete-module-catalog) → **[docs/MODULES.md](docs/MODULES.md)** - [Management & Operations](#management--operations) → **[docs/GETTING_STARTED.md](docs/GETTING_STARTED.md)** - [Advanced Configuration](#advanced-configuration) → **[docs/ADVANCED.md](docs/ADVANCED.md)** +- [Custom NPCs Guide](#custom-npcs-guide) → **[docs/NPCS.md](docs/NPCS.md)** - [Script Reference](#script-reference) → **[docs/SCRIPTS.md](docs/SCRIPTS.md)** - [Troubleshooting](#troubleshooting) → **[docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)** - [Credits & Next Steps](#credits--next-steps) @@ -88,6 +89,22 @@ Choose from **93+ enhanced modules** spanning automation, quality-of-life improv Browse the complete catalog with descriptions at **[docs/MODULES.md](docs/MODULES.md)**. +--- + +## Custom NPCs Guide + +The server includes **14 custom NPCs** providing enhanced functionality including profession training, enchantments, arena services, and more. All NPCs are spawnable through GM commands and designed for permanent placement. + +**Available NPCs:** +- **Service NPCs** - Profession training, reagent banking, instance resets +- **Enhancement NPCs** - Enchanting, buffing, pet management, transmog +- **PvP NPCs** - 1v1 arena battlemaster +- **Guild House NPCs** - Property management and services + +For complete spawn commands, coordinates, and functionality details, see **[docs/NPCS.md](docs/NPCS.md)**. + +--- + ## Management & Operations For common workflows, management commands, and database operations, see **[docs/GETTING_STARTED.md](docs/GETTING_STARTED.md)**. diff --git a/database-import/README.md b/database-import/README.md index c20b107..6eff209 100644 --- a/database-import/README.md +++ b/database-import/README.md @@ -2,9 +2,11 @@ Place your database backup files here for automatic import during deployment. -## Supported Files +## Supported Imports - `.sql` files (uncompressed SQL dumps) - `.sql.gz` files (gzip compressed SQL dumps) +- **Full backup directories** (e.g., `ExportBackup_YYYYMMDD_HHMMSS/` containing multiple dumps) +- **Full backup archives** (`.tar`, `.tar.gz`, `.tgz`, `.zip`) that contain the files above ## How to Use @@ -13,6 +15,9 @@ Place your database backup files here for automatic import during deployment. cp my_auth_backup.sql.gz ./database-import/ cp my_world_backup.sql.gz ./database-import/ cp my_characters_backup.sql.gz ./database-import/ + # or drop an entire ExportBackup folder / archive + cp -r ExportBackup_20241029_120000 ./database-import/ + cp ExportBackup_20241029_120000.tar.gz ./database-import/ ``` 2. **Run deployment:** @@ -25,13 +30,15 @@ Place your database backup files here for automatic import during deployment. ## File Naming - Any filename works - the system will auto-detect database type by content - Recommended naming: `auth.sql.gz`, `world.sql.gz`, `characters.sql.gz` +- Full backups keep their original directory/archive name so you can track multiple copies ## What Happens -- Files from this folder are copied to `local-storage/backups/daily/` -- Database import system automatically restores them -- Original files remain here for reference +- Individual `.sql`/`.sql.gz` files are copied to `storage/backups/daily/` with a timestamped name +- Full backup directories or archives are staged in `storage/backups/ImportBackup/` +- Database import system automatically restores the most recent matching backup +- Original files remain here for reference (archives are left untouched) ## Notes - Only processed on first deployment (when databases don't exist) -- Files are copied with timestamp to backup directory -- Empty folder is ignored - no files, no import \ No newline at end of file +- Files/directories are copied once; existing restored databases will skip import +- Empty folder is ignored - no files, no import diff --git a/deploy.sh b/deploy.sh index ec2d7d7..f51dd25 100755 --- a/deploy.sh +++ b/deploy.sh @@ -379,6 +379,13 @@ resolve_project_image(){ echo "${project_name}:${tag}" } +is_project_local_image(){ + local image="$1" + local project_name + project_name="$(resolve_project_name)" + [[ "$image" == "${project_name}:"* ]] +} + filter_empty_lines(){ awk ' /^[[:space:]]*$/ { @@ -423,10 +430,18 @@ detect_build_needed(){ worldserver_modules_image="$(read_env AC_WORLDSERVER_IMAGE_MODULES "$(resolve_project_image "worldserver-modules-latest")")" if ! docker image inspect "$authserver_modules_image" >/dev/null 2>&1; then - reasons+=("C++ modules enabled but authserver modules image $authserver_modules_image is missing") + if is_project_local_image "$authserver_modules_image"; then + reasons+=("C++ modules enabled but authserver modules image $authserver_modules_image is missing") + else + info "Authserver modules image $authserver_modules_image missing locally but not tagged with project prefix; assuming compose will pull from registry." + fi fi if ! docker image inspect "$worldserver_modules_image" >/dev/null 2>&1; then - reasons+=("C++ modules enabled but worldserver modules image $worldserver_modules_image is missing") + if is_project_local_image "$worldserver_modules_image"; then + reasons+=("C++ modules enabled but worldserver modules image $worldserver_modules_image is missing") + else + info "Worldserver modules image $worldserver_modules_image missing locally but not tagged with project prefix; assuming compose will pull from registry." + fi fi fi diff --git a/docker-compose.yml b/docker-compose.yml index 8b472b6..7a96c76 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,6 +18,7 @@ services: MYSQL_MAX_CONNECTIONS: ${MYSQL_MAX_CONNECTIONS} MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_INNODB_BUFFER_POOL_SIZE} MYSQL_INNODB_LOG_FILE_SIZE: ${MYSQL_INNODB_LOG_FILE_SIZE} + TZ: "${TZ}" entrypoint: - /usr/local/bin/mysql-entrypoint.sh volumes: @@ -65,6 +66,7 @@ services: - ${STORAGE_PATH}/config:/azerothcore/env/dist/etc - ${STORAGE_PATH}/logs:/azerothcore/logs - ${STORAGE_PATH_LOCAL}/mysql-data:/var/lib/mysql-persistent + - ${BACKUP_PATH}:/backups - ./scripts/bash/db-import-conditional.sh:/tmp/db-import-conditional.sh:ro environment: AC_DATA_DIR: "/azerothcore/data" @@ -160,6 +162,7 @@ services: DB_AUTH_NAME: ${DB_AUTH_NAME} DB_WORLD_NAME: ${DB_WORLD_NAME} DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME} + BACKUP_EXTRA_DATABASES: ${BACKUP_EXTRA_DATABASES} TZ: ${TZ} CONTAINER_USER: ${CONTAINER_USER} volumes: @@ -449,6 +452,7 @@ services: AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}" AC_UPDATES_ENABLE_DATABASES: "0" AC_BIND_IP: "0.0.0.0" + TZ: "${TZ}" AC_LOG_LEVEL: "1" AC_LOGGER_ROOT_CONFIG: "1,Console" AC_LOGGER_SERVER_CONFIG: "1,Console" @@ -527,6 +531,7 @@ services: AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD}" AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE}" AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH}" + TZ: "${TZ}" 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}" diff --git a/docs/ADVANCED.md b/docs/ADVANCED.md index 7195c0d..d97164f 100644 --- a/docs/ADVANCED.md +++ b/docs/ADVANCED.md @@ -156,6 +156,8 @@ storage/ `storage/client-data` is bind-mounted into every world/auth/client-data container. Drop patched `dbc`, `maps`, `vmaps`, or `mmaps` files directly into that folder (e.g., `storage/client-data/dbc/SkillLine.dbc`) and the containers will read them immediately—perfect for modules like Individual Progression or mod-worgoblin that need to overwrite Blizzard data. +Need to capture more than the default `auth/world/characters` schemas? Set `BACKUP_EXTRA_DATABASES` in `.env` (comma or space separated) and the `ac-backup` scheduler will validate each schema before adding it to the hourly/daily dump rotation. The long-standing auto-detection for `acore_playerbots` still works, and any missing optional schemas are logged and skipped instead of breaking the backup run. + To tweak MySQL settings, place `.cnf` snippets in `storage/config/mysql/conf.d`. Files in this directory map straight to `/etc/mysql/conf.d` inside `ac-mysql`, so you can re-enable binary logs or tune buffers without rebuilding images. **Local Storage** (`STORAGE_PATH_LOCAL` - default: `./local-storage`) @@ -204,4 +206,4 @@ For additional information, see the following documents: --- -*This documentation is part of the AzerothCore RealmMaster project. For updates and contributions, visit the main project repository.* \ No newline at end of file +*This documentation is part of the AzerothCore RealmMaster project. For updates and contributions, visit the main project repository.* diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 16b6dd0..88f6b45 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -258,6 +258,23 @@ SET address = 'your-public-ip', port = 8215 WHERE id = 1; ``` +### Spawn Custom NPCs + +The server includes 14 custom NPCs providing enhanced functionality. Use GM commands to spawn them at appropriate locations: + +```bash +# Quick reference - spawn essential NPCs +.npc add 199999 # Kaylub - Free Professions +.npc add 601015 # Beauregard - Enchanter +.npc add 601016 # Buffmaster - Player Buffs +.npc add 601026 # White Fang - BeastMaster +.npc add 190010 # Warpweaver - Transmog + +# See complete guide with coordinates and functions +``` + +**📖 For complete spawn commands, coordinates, and NPC functionality details, see [docs/NPCS.md](docs/NPCS.md)** + --- ## Management & Operations diff --git a/docs/NPCS.md b/docs/NPCS.md new file mode 100644 index 0000000..fdac035 --- /dev/null +++ b/docs/NPCS.md @@ -0,0 +1,374 @@ +# AzerothCore Custom NPCs Guide + +This guide provides comprehensive documentation for all spawnable custom NPCs available through enabled modules on your AzerothCore server. + +## Table of Contents +- [Overview](#overview) +- [Quick Spawn Reference](#quick-spawn-reference) +- [NPC Categories](#npc-categories) +- [Detailed NPC Information](#detailed-npc-information) +- [Spawn Commands](#spawn-commands) +- [Recommended Locations](#recommended-locations) +- [Admin Commands](#admin-commands) + +## Overview + +The AzerothCore server includes 14 custom NPCs through various enabled modules. These NPCs provide enhanced functionality including profession training, enchantments, pet management, arena services, and more. + +**All NPCs are designed to:** +- Be level 80 with neutral faction (35) for universal access +- Remain permanent when spawned (deletion-protected) +- Provide user-friendly gossip interfaces +- Maintain thematic consistency with appropriate models and equipment + +## Quick Spawn Reference + +| NPC Name | Entry ID | Function | Spawn Command | +|----------|----------|----------|---------------| +| Kaylub | 199999 | Professions | `.npc add 199999` | +| Ling | 290011 | Reagent Banking | `.npc add 290011` | +| Cromi | 300000 | Instance Reset | `.npc add 300000` | +| Talamortis | 500030 | Guild House Seller | `.npc add 500030` | +| Xrispins | 500031 | Guild House Butler | `.npc add 500031` | +| Innkeeper Monica | 500032 | Guild House Innkeeper | `.npc add 500032` | +| Beauregard Boneglitter | 601015 | Enchanter | `.npc add 601015` | +| Buffmaster Hasselhoof | 601016 | Buffer | `.npc add 601016` | +| White Fang | 601026 | BeastMaster | `.npc add 601026` | +| Cet Keres | 601072 | Polymorphologist | `.npc add 601072` | +| Warpweaver | 190010 | Transmog | `.npc add 190010` | +| Ethereal Warpweaver | 190011 | Transmog | `.npc add 190011` | +| Arena Battlemaster 1v1 | 999991 | 1v1 Arena | `.npc add 999991` | +| Gabriella | 9000000 | Assistant | `.npc add 9000000` | + +## NPC Categories + +### 🔧 Core Service NPCs +Essential utility NPCs for everyday server functions. + +### 🏰 Guild House NPCs +NPCs related to guild house functionality and management. + +### ⚡ Enhancement & Utility NPCs +NPCs providing character enhancement services. + +### ⚔️ PvP & Arena NPCs +NPCs for player vs player content and arena management. + +### 👤 Assistant NPCs +General assistance and administrative NPCs. + +## Detailed NPC Information + +### Core Service NPCs + +#### Kaylub (Entry: 199999) +- **Title:** Professions NPC +- **Function:** Provides free profession training and spells +- **Model:** High-quality character model (ID: 31833) +- **Features:** + - Purple-colored subname for easy identification + - Comprehensive profession training without cost + - Spell learning capabilities +- **Module:** mod-npc-free-professions +- **Script:** npc_free_professions + +#### Ling (Entry: 290011) +- **Title:** Reagent Banker +- **Function:** Specialized banking for reagents and crafting materials +- **Model:** Ethereal-style model (ID: 15965) +- **Features:** + - Separate storage for crafting reagents + - Enhanced inventory management + - Quick access to frequently used materials +- **Module:** mod-reagent-bank +- **Script:** npc_reagent_banker + +#### Cromi (Entry: 300000) +- **Title:** Instance Reset +- **Function:** Allows players to reset dungeon and raid instances +- **Features:** + - Reset individual instances + - Manage lockout timers + - Bypass normal reset restrictions +- **Module:** mod-instance-reset + +### Guild House NPCs + +#### Talamortis (Entry: 500030) +- **Title:** Guild House Seller +- **Function:** Manages guild house purchases and sales +- **Features:** + - Guild house acquisition + - Property management + - Pricing and availability information +- **Module:** mod-guildhouse + +#### Xrispins (Entry: 500031) +- **Title:** Guild House Butler +- **Function:** Provides guild house services and management +- **Features:** + - House maintenance services + - Utility management + - Guild house customization +- **Module:** mod-guildhouse + +#### Innkeeper Monica (Entry: 500032) +- **Title:** Guild House Innkeeper +- **Function:** Sets hearthstone locations within guild houses +- **Features:** + - Hearthstone binding within guild properties + - Rest area designation + - Inn services within guild houses +- **Module:** mod-guildhouse + +### Enhancement & Utility NPCs + +#### Beauregard Boneglitter (Entry: 601015) +- **Title:** Enchanter +- **Function:** Provides gear enchantments +- **Model:** Undead Necromancer (ID: 9353) +- **Equipment:** Black/Purple Staff (ID: 11343) +- **Features:** + - Comprehensive enchantment services + - All expansion enchantments available + - Professional necromancer appearance +- **Module:** mod-npc-enchanter +- **Script:** npc_enchantment + +#### Buffmaster Hasselhoof (Entry: 601016) +- **Title:** Buffer +- **Function:** Provides player buffs and blessings +- **Model:** Tauren Warmaster (ID: 14612) +- **Equipment:** Torch (ID: 1906) +- **Features:** + - Comprehensive buff packages + - Long-duration buffs + - Class-specific enhancements +- **Module:** mod-npc-buffer +- **Script:** buff_npc + +#### White Fang (Entry: 601026) +- **Title:** BeastMaster +- **Function:** Hunter pet management and taming services +- **Model:** Northrend Worgen White (ID: 26314) +- **Equipment:** Haunch of Meat (ID: 2196), Torch (ID: 1906) +- **Features:** + - Exotic pet taming + - Pet food vendor (35+ different food items) + - Pet stable services + - Rare pet acquisition +- **Module:** mod-npc-beastmaster +- **Script:** BeastMaster +- **Vendor Items:** Includes all pet food types from bread to exotic meats + +#### Cet Keres (Entry: 601072) +- **Title:** Polymorphologist +- **Function:** Summon appearance modification +- **Model:** Custom ethereal model (ID: 15665) +- **Features:** + - Warlock pet morphing + - Summoned creature appearance changes + - Felguard weapon customization + - Multiple polymorph options +- **Module:** mod-morphsummon +- **Script:** npc_morphsummon + +### PvP & Arena NPCs + +#### Arena Battlemaster 1v1 (Entry: 999991) +- **Title:** Arena Battlemaster +- **Function:** 1v1 arena matches and team management +- **Model:** Arena Battlemaster (ID: 7110) +- **Features:** + - Rated 1v1 arena matches + - Unrated 1v1 practice matches + - Automatic team creation + - Arena statistics tracking +- **Module:** mod-1v1-arena +- **Script:** npc_1v1arena +- **Commands Available:** + - `.q1v1 rated` - Join rated 1v1 arena + - `.q1v1 unrated` - Join unrated 1v1 arena + +### Transmog NPCs + +#### Warpweaver (Entry: 190010) +- **Title:** Transmogrifier +- **Function:** Standard transmogrification services +- **Features:** + - Equipment appearance modification + - Transmog collection management + - Standard WotLK transmog functionality +- **Module:** mod-transmog + +#### Ethereal Warpweaver (Entry: 190011) +- **Title:** Transmogrifier +- **Function:** Alternative transmog NPC with ethereal appearance +- **Features:** + - Same functionality as standard Warpweaver + - Ethereal-themed appearance + - Alternative location option +- **Module:** mod-transmog + +### Assistant NPCs + +#### Gabriella (Entry: 9000000) +- **Title:** The Assistant +- **Function:** General assistance and utility functions +- **Features:** + - General server information + - Player assistance services + - Administrative support functions +- **Module:** mod-assistant + +## Spawn Commands + +### Basic Spawning +To spawn any NPC, use the following command format: +``` +.npc add [entry_id] +``` + +### Advanced Spawning Options +```bash +# Spawn NPC facing specific direction +.npc add [entry_id] [orientation] + +# Spawn NPC with specific spawn time +.npc add [entry_id] [spawntime_in_seconds] + +# Get your current coordinates for documentation +.gps +``` + +### Example Commands +```bash +# Spawn the BeastMaster at current location +.npc add 601026 + +# Spawn Enchanter facing north (0 orientation) +.npc add 601015 0 + +# Spawn Professions NPC with 1-hour spawn time +.npc add 199999 3600 +``` + +## Recommended Locations + +### Major Cities - Central Services +**Stormwind City:** +- **Coordinates:** 83.2, 68.4, 18.4 (Trade District) +- **Recommended NPCs:** Kaylub (Professions), Beauregard (Enchanter), Buffmaster +- **Reason:** High traffic area with easy access + +**Orgrimmar:** +- **Coordinates:** 54.2, 73.4, 18.2 (Valley of Strength) +- **Recommended NPCs:** Kaylub (Professions), Beauregard (Enchanter), Buffmaster +- **Reason:** Central location with bank proximity + +### Specialized Areas + +**Dalaran:** +- **Coordinates:** 40.8, 62.1, 504.2 (Runeweaver Square) +- **Recommended NPCs:** All Transmog NPCs, Cet Keres (Polymorphologist) +- **Reason:** Neutral city, thematic fit for magical services + +**Shattrath City:** +- **Coordinates:** 64.0, 41.4, -0.5 (Lower City) +- **Recommended NPCs:** Arena Battlemaster, Ethereal Warpweaver +- **Reason:** Neutral territory, appropriate for PvP services + +**Guild House Locations:** +- **Recommended NPCs:** Talamortis, Xrispins, Innkeeper Monica +- **Coordinates:** Within purchased guild houses only + +### Hunter Outposts +**Recommended for White Fang (BeastMaster):** +- **Un'Goro Crater:** 41.9, 2.6, 116.8 (Marshal's Refuge) +- **Winterspring:** 31.3, 45.2, 1.4 (Everlook) +- **Reason:** Thematic locations with nearby rare pets + +## Admin Commands + +### NPC Management +```bash +# Delete specific NPC (use GUID from .npc near) +.npc delete [guid] + +# Move NPC to your location +.npc move [guid] + +# Get information about nearby NPCs +.npc near + +# Make NPC face you +.npc set face + +# Set NPC movement type +.npc set movetype [0=idle, 1=random, 2=waypoint] +``` + +### Database Operations +```bash +# Save NPC spawn to database +.npc add [entry] [spawntime] [save_to_db] + +# Reload NPC data from database +.reload creature_template + +# Check NPC entry information +.lookup creature [name_or_entry] +``` + +### Troubleshooting Commands +```bash +# If NPC appears but doesn't function: +.reload creature_template +.reload gossip_menu +.reload npc_vendor + +# If NPC model is wrong: +.reload creature_template_model + +# If scripts don't work: +.reload scripts +``` + +## Module Dependencies + +| NPC | Required Module | Configuration File | +|-----|----------------|--------------------| +| Kaylub | mod-npc-free-professions | [Module Config] | +| Ling | mod-reagent-bank | [Module Config] | +| Cromi | mod-instance-reset | [Module Config] | +| Guild House NPCs | mod-guildhouse | [Module Config] | +| Beauregard | mod-npc-enchanter | [Module Config] | +| Buffmaster | mod-npc-buffer | [Module Config] | +| White Fang | mod-npc-beastmaster | [Module Config] | +| Cet Keres | mod-morphsummon | [Module Config] | +| Arena Battlemaster | mod-1v1-arena | [Module Config] | +| Transmog NPCs | mod-transmog | [Module Config] | +| Gabriella | mod-assistant | [Module Config] | + +## Notes + +- **All NPCs require GM access level 1 or higher to spawn** +- **NPCs will persist through server restarts once saved to database** +- **Some NPCs may require specific client-side files for full functionality** +- **Module configurations can be found in the respective module directories** +- **Always test NPC functionality after spawning** + +## Support + +For issues with specific NPCs: +1. Check that the corresponding module is enabled +2. Verify the NPC was saved to the database +3. Reload relevant database tables +4. Check server logs for script errors +5. Consult module-specific documentation + +--- + +*Last updated: November 2024* +*AzerothCore Version: 3.3.5a* +*Module versions may vary - check individual module documentation for specific features* \ No newline at end of file diff --git a/scripts/admin/fix-silvermoon-npcs.sql b/scripts/admin/fix-silvermoon-npcs.sql new file mode 100644 index 0000000..140cb34 --- /dev/null +++ b/scripts/admin/fix-silvermoon-npcs.sql @@ -0,0 +1,24 @@ +-- Fix Silvermoon Walk of Elders NPCs - Step by step approach + +-- Remove old Eye of the Storm Envoys +DELETE FROM creature WHERE guid IN (208304, 208305); + +-- Add the two main NPCs first +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(208304, 199999, 530, 9513.94, -7302.81, 14.5485, 3.14, 300), +(208305, 601015, 530, 9514.06, -7298.59, 14.5415, 0.0, 300); + +-- Add remaining NPCs with new GUIDs +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(999911, 601016, 530, 9514.0, -7295.0, 14.5, 4.71, 300), +(999912, 601026, 530, 9518.0, -7297.0, 14.5, 3.93, 300), +(999913, 601072, 530, 9519.0, -7300.5, 14.5, 3.14, 300), +(999914, 190010, 530, 9518.0, -7304.0, 14.5, 2.36, 300), +(999915, 190011, 530, 9514.0, -7306.0, 14.5, 1.57, 300), +(999916, 290011, 530, 9510.0, -7304.0, 14.5, 0.79, 300), +(999917, 300000, 530, 9509.0, -7300.5, 14.5, 0.0, 300), +(999918, 999991, 530, 9510.0, -7297.0, 14.5, 5.50, 300), +(999919, 9000000, 530, 9514.0, -7292.0, 14.5, 4.71, 300), +(999920, 500030, 530, 9522.0, -7300.5, 14.5, 3.14, 300), +(999921, 500031, 530, 9514.0, -7310.0, 14.5, 1.57, 300), +(999922, 500032, 530, 9506.0, -7300.5, 14.5, 0.0, 300); \ No newline at end of file diff --git a/scripts/admin/replace-silvermoon-envoys.sql b/scripts/admin/replace-silvermoon-envoys.sql new file mode 100644 index 0000000..69fd823 --- /dev/null +++ b/scripts/admin/replace-silvermoon-envoys.sql @@ -0,0 +1,31 @@ +-- Replace Eye of the Storm Envoys in Silvermoon Walk of Elders District +-- with Custom NPCs from AzerothCore modules + +-- Remove existing Eye of the Storm Envoy spawns in likely Walk of Elders area +-- Based on coordinates, these appear to be in central Silvermoon districts + +-- Delete Eye of the Storm Envoys that appear to be in pairs in central areas +DELETE FROM creature WHERE id1 = 22015 AND map = 530 AND + ((position_x BETWEEN -1670 AND -1665 AND position_y BETWEEN 5188 AND 5193) OR + (position_x BETWEEN -1870 AND -1865 AND position_y BETWEEN 5144 AND 5150)); + +-- Add Kaylub (Professions NPC) - First location in central area +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999901, 199999, 0, 0, 530, 3487, 3487, 1, 1, 0, -1668.0, 5190.0, -42.0, 3.14, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Kaylub - Free Professions NPC - Silvermoon Walk of Elders'); + +-- Add Beauregard Boneglitter (Enchanter) - Second location in central area +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999902, 601015, 0, 0, 530, 3487, 3487, 1, 1, 1, -1866.5, 5146.5, -42.8, 0.0, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Beauregard Boneglitter - Enchanter - Silvermoon Walk of Elders'); + +-- Alternative: If you want different NPCs, uncomment these and comment out above + +-- Add White Fang (BeastMaster) instead of Kaylub +-- INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +-- (999901, 601026, 0, 0, 530, 3487, 3487, 1, 1, 1, -1668.0, 5190.0, -42.0, 3.14, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'White Fang - BeastMaster - Silvermoon Walk of Elders'); + +-- Add Buffmaster Hasselhoof (Buffer) instead of Beauregard +-- INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +-- (999902, 601016, 0, 0, 530, 3487, 3487, 1, 1, 1, -1866.5, 5146.5, -42.8, 0.0, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Buffmaster Hasselhoof - Buffer - Silvermoon Walk of Elders'); + +-- Reload creature spawns to apply changes +-- Note: You may need to restart the worldserver or use .reload creature command \ No newline at end of file diff --git a/scripts/admin/replace-silvermoon-walk-of-elders.sql b/scripts/admin/replace-silvermoon-walk-of-elders.sql new file mode 100644 index 0000000..b5d314b --- /dev/null +++ b/scripts/admin/replace-silvermoon-walk-of-elders.sql @@ -0,0 +1,31 @@ +-- Replace Eye of the Storm Envoys in Silvermoon Walk of Elders District +-- Location: Eastern Silvermoon (x:~9514, y:~-7300) +-- GUID: 208304 and 208305 + +-- Remove the specific Eye of the Storm Envoys at Walk of Elders +DELETE FROM creature WHERE guid IN (208304, 208305); + +-- Replace with Kaylub (Free Professions NPC) at first location +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(208304, 199999, 0, 0, 530, 3487, 3431, 1, 1, 0, 9513.94, -7302.81, 14.5485, 3.14, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Kaylub - Free Professions - Silvermoon Walk of Elders'); + +-- Replace with Beauregard Boneglitter (Enchanter) at second location +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(208305, 601015, 0, 0, 530, 3487, 3431, 1, 1, 1, 9514.06, -7298.59, 14.5415, 0.0, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Beauregard Boneglitter - Enchanter - Silvermoon Walk of Elders'); + +-- Alternative NPC combinations (uncomment desired option and comment above): + +-- Option 2: Professions + Buffer +-- INSERT INTO creature VALUES (208304, 199999, 0, 0, 530, 3487, 3431, 1, 1, 0, 9513.94, -7302.81, 14.5485, 3.14, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Kaylub - Free Professions'); +-- INSERT INTO creature VALUES (208305, 601016, 0, 0, 530, 3487, 3431, 1, 1, 1, 9514.06, -7298.59, 14.5415, 0.0, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Buffmaster Hasselhoof - Buffer'); + +-- Option 3: Enchanter + Transmog +-- INSERT INTO creature VALUES (208304, 601015, 0, 0, 530, 3487, 3431, 1, 1, 1, 9513.94, -7302.81, 14.5485, 3.14, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Beauregard Boneglitter - Enchanter'); +-- INSERT INTO creature VALUES (208305, 190011, 0, 0, 530, 3487, 3431, 1, 1, 0, 9514.06, -7298.59, 14.5415, 0.0, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Ethereal Warpweaver - Transmog'); + +-- Option 4: BeastMaster + Assistant +-- INSERT INTO creature VALUES (208304, 601026, 0, 0, 530, 3487, 3431, 1, 1, 1, 9513.94, -7302.81, 14.5485, 3.14, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'White Fang - BeastMaster'); +-- INSERT INTO creature VALUES (208305, 9000000, 0, 0, 530, 3487, 3431, 1, 1, 0, 9514.06, -7298.59, 14.5415, 0.0, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Gabriella - The Assistant'); + +-- Execute this to apply changes immediately (run in-game): +-- .reload creature \ No newline at end of file diff --git a/scripts/admin/silvermoon-npc-line.sql b/scripts/admin/silvermoon-npc-line.sql new file mode 100644 index 0000000..b43184a --- /dev/null +++ b/scripts/admin/silvermoon-npc-line.sql @@ -0,0 +1,52 @@ +-- Spawn 11 Custom NPCs in a line in Silvermoon Walk of Elders +-- Center Point: x:9507.111, y:-7301.0264, z:14.117673 +-- Line extends 15 units each direction from center (30 units total) +-- 3 unit spacing between each NPC + +-- Clear the area first (remove any existing NPCs in this line) +DELETE FROM creature WHERE map = 530 AND position_x BETWEEN 9492 AND 9522 AND position_y BETWEEN -7316 AND -7286; + +-- NPC Line Layout (West to East, 11 NPCs total) +-- Position 1: x:9492.111 (center - 15) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800001, 199999, 530, 9492.111, -7301.0264, 14.117673, 3.060474, 300); -- Kaylub (Professions) + +-- Position 2: x:9495.111 (center - 12) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800002, 290011, 530, 9495.111, -7301.0264, 14.117673, 3.060474, 300); -- Ling (Reagent Banker) + +-- Position 3: x:9498.111 (center - 9) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800003, 300000, 530, 9498.111, -7301.0264, 14.117673, 3.060474, 300); -- Cromi (Instance Reset) + +-- Position 4: x:9501.111 (center - 6) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800004, 601015, 530, 9501.111, -7301.0264, 14.117673, 3.060474, 300); -- Beauregard Boneglitter (Enchanter) + +-- Position 5: x:9504.111 (center - 3) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800005, 601016, 530, 9504.111, -7301.0264, 14.117673, 3.060474, 300); -- Buffmaster Hasselhoof (Buffer) + +-- Position 6: x:9507.111 (CENTER POINT) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800006, 601026, 530, 9507.111, -7301.0264, 14.117673, 3.060474, 300); -- White Fang (BeastMaster) + +-- Position 7: x:9510.111 (center + 3) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800007, 601072, 530, 9510.111, -7301.0264, 14.117673, 3.060474, 300); -- Cet Keres (Polymorphologist) + +-- Position 8: x:9513.111 (center + 6) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800008, 190010, 530, 9513.111, -7301.0264, 14.117673, 3.060474, 300); -- Warpweaver (Transmog) + +-- Position 9: x:9516.111 (center + 9) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800009, 190011, 530, 9516.111, -7301.0264, 14.117673, 3.060474, 300); -- Ethereal Warpweaver (Transmog) + +-- Position 10: x:9519.111 (center + 12) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800010, 999991, 530, 9519.111, -7301.0264, 14.117673, 3.060474, 300); -- Arena Battlemaster 1v1 + +-- Position 11: x:9522.111 (center + 15) +INSERT INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800011, 9000000, 530, 9522.111, -7301.0264, 14.117673, 3.060474, 300); -- Gabriella (The Assistant) \ No newline at end of file diff --git a/scripts/admin/silvermoon-walk-of-elders-all-npcs.sql b/scripts/admin/silvermoon-walk-of-elders-all-npcs.sql new file mode 100644 index 0000000..d74c97e --- /dev/null +++ b/scripts/admin/silvermoon-walk-of-elders-all-npcs.sql @@ -0,0 +1,72 @@ +-- Replace Eye of the Storm Envoys and spawn all custom NPCs in Silvermoon Walk of Elders District +-- Base location: x:~9514, y:~-7300, z:~14.5 +-- Map: 530 (Outland), Zone: 3487 (Eversong Woods), Area: 3431 (Silvermoon City) + +-- Remove the existing Eye of the Storm Envoys (already done, but included for completeness) +DELETE FROM creature WHERE guid IN (208304, 208305); + +-- Core Service NPCs (Central placement) +-- Kaylub - Free Professions (replaces first envoy) +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(208304, 199999, 0, 0, 530, 3487, 3431, 1, 1, 0, 9513.94, -7302.81, 14.5485, 3.14, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Kaylub - Free Professions - Walk of Elders'); + +-- Beauregard Boneglitter - Enchanter (replaces second envoy) +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(208305, 601015, 0, 0, 530, 3487, 3431, 1, 1, 1, 9514.06, -7298.59, 14.5415, 0.0, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Beauregard Boneglitter - Enchanter - Walk of Elders'); + +-- Enhancement & Utility NPCs (Arranged in a circle around the center) +-- Buffmaster Hasselhoof - Buffer (North) +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999911, 601016, 0, 0, 530, 3487, 3431, 1, 1, 1, 9514.0, -7295.0, 14.5, 4.71, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Buffmaster Hasselhoof - Buffer - Walk of Elders'); + +-- White Fang - BeastMaster (Northeast) +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999912, 601026, 0, 0, 530, 3487, 3431, 1, 1, 1, 9518.0, -7297.0, 14.5, 3.93, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'White Fang - BeastMaster - Walk of Elders'); + +-- Cet Keres - Polymorphologist (East) +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999913, 601072, 0, 0, 530, 3487, 3431, 1, 1, 0, 9519.0, -7300.5, 14.5, 3.14, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Cet Keres - Polymorphologist - Walk of Elders'); + +-- Transmog NPCs (Southeast) +-- Warpweaver - Transmogrifier +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999914, 190010, 0, 0, 530, 3487, 3431, 1, 1, 0, 9518.0, -7304.0, 14.5, 2.36, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Warpweaver - Transmogrifier - Walk of Elders'); + +-- Ethereal Warpweaver - Transmogrifier (South) +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999915, 190011, 0, 0, 530, 3487, 3431, 1, 1, 0, 9514.0, -7306.0, 14.5, 1.57, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Ethereal Warpweaver - Transmogrifier - Walk of Elders'); + +-- Utility NPCs (Southwest) +-- Ling - Reagent Banker +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999916, 290011, 0, 0, 530, 3487, 3431, 1, 1, 0, 9510.0, -7304.0, 14.5, 0.79, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Ling - Reagent Banker - Walk of Elders'); + +-- Cromi - Instance Reset (West) +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999917, 300000, 0, 0, 530, 3487, 3431, 1, 1, 0, 9509.0, -7300.5, 14.5, 0.0, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Cromi - Instance Reset - Walk of Elders'); + +-- PvP & Arena NPC (Northwest) +-- Arena Battlemaster 1v1 +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999918, 999991, 0, 0, 530, 3487, 3431, 1, 1, 0, 9510.0, -7297.0, 14.5, 5.50, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Arena Battlemaster 1v1 - Arena - Walk of Elders'); + +-- Assistant NPC (Center-North) +-- Gabriella - The Assistant +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999919, 9000000, 0, 0, 530, 3487, 3431, 1, 1, 0, 9514.0, -7292.0, 14.5, 4.71, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Gabriella - The Assistant - Walk of Elders'); + +-- Guild House NPCs (Outer ring - slightly further from center) +-- Talamortis - Guild House Seller (Far East) +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999920, 500030, 0, 0, 530, 3487, 3431, 1, 1, 0, 9522.0, -7300.5, 14.5, 3.14, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Talamortis - Guild House Seller - Walk of Elders'); + +-- Xrispins - Guild House Butler (Far South) +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999921, 500031, 0, 0, 530, 3487, 3431, 1, 1, 0, 9514.0, -7310.0, 14.5, 1.57, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Xrispins - Guild House Butler - Walk of Elders'); + +-- Innkeeper Monica - Guild House Innkeeper (Far West) +INSERT INTO creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES +(999922, 500032, 0, 0, 530, 3487, 3431, 1, 1, 0, 9506.0, -7300.5, 14.5, 0.0, 300, 0, 0, 42750, 0, 0, 0, 0, 0, '', 0, 0, 'Innkeeper Monica - Guild House Innkeeper - Walk of Elders'); + +-- Reload creatures to apply changes +-- Execute in-game: .reload creature \ No newline at end of file diff --git a/scripts/admin/simple-npc-line.sql b/scripts/admin/simple-npc-line.sql new file mode 100644 index 0000000..98c33b5 --- /dev/null +++ b/scripts/admin/simple-npc-line.sql @@ -0,0 +1,13 @@ +-- Simple NPC Line insertion without complex deletes +INSERT IGNORE INTO creature (guid, id1, map, position_x, position_y, position_z, orientation, spawntimesecs) VALUES +(800001, 199999, 530, 9492.111, -7301.0264, 14.117673, 3.060474, 300), +(800002, 290011, 530, 9495.111, -7301.0264, 14.117673, 3.060474, 300), +(800003, 300000, 530, 9498.111, -7301.0264, 14.117673, 3.060474, 300), +(800004, 601015, 530, 9501.111, -7301.0264, 14.117673, 3.060474, 300), +(800005, 601016, 530, 9504.111, -7301.0264, 14.117673, 3.060474, 300), +(800006, 601026, 530, 9507.111, -7301.0264, 14.117673, 3.060474, 300), +(800007, 601072, 530, 9510.111, -7301.0264, 14.117673, 3.060474, 300), +(800008, 190010, 530, 9513.111, -7301.0264, 14.117673, 3.060474, 300), +(800009, 190011, 530, 9516.111, -7301.0264, 14.117673, 3.060474, 300), +(800010, 999991, 530, 9519.111, -7301.0264, 14.117673, 3.060474, 300), +(800011, 9000000, 530, 9522.111, -7301.0264, 14.117673, 3.060474, 300); \ No newline at end of file diff --git a/scripts/admin/spawn-all-npcs.sh b/scripts/admin/spawn-all-npcs.sh new file mode 100755 index 0000000..73745c7 --- /dev/null +++ b/scripts/admin/spawn-all-npcs.sh @@ -0,0 +1,222 @@ +#!/bin/bash +# AzerothCore Custom NPC Spawn Script +# Spawns all custom NPCs to recommended locations +# +# Usage: ./spawn-all-npcs.sh [location] +# Locations: stormwind, orgrimmar, dalaran, shattrath, all +# +# Prerequisites: +# - GM access level 1 or higher +# - Server must be running +# - Execute in-game using .server script run or as GM commands + +set -euo pipefail + +# Color codes for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# NPC Entry IDs and Names +declare -A NPCS=( + ["199999"]="Kaylub|Professions NPC" + ["290011"]="Ling|Reagent Banker" + ["300000"]="Cromi|Instance Reset" + ["500030"]="Talamortis|Guild House Seller" + ["500031"]="Xrispins|Guild House Butler" + ["500032"]="Monica|Guild House Innkeeper" + ["601015"]="Beauregard Boneglitter|Enchanter" + ["601016"]="Buffmaster Hasselhoof|Buffer" + ["601026"]="White Fang|BeastMaster" + ["601072"]="Cet Keres|Polymorphologist" + ["190010"]="Warpweaver|Transmogrifier" + ["190011"]="Ethereal Warpweaver|Transmogrifier" + ["999991"]="Arena Battlemaster 1v1|Arena" + ["9000000"]="Gabriella|The Assistant" +) + +# Location coordinates (map x y z orientation) +declare -A STORMWIND=( + ["199999"]="0 -8829.0 622.5 94.0 3.14" # Kaylub - Trade District + ["601015"]="0 -8831.0 618.5 94.0 0.0" # Beauregard - Trade District + ["601016"]="0 -8827.0 626.5 94.0 1.57" # Buffmaster - Trade District + ["190010"]="0 -8825.0 614.5 94.0 4.71" # Warpweaver - Trade District + ["9000000"]="0 -8833.0 630.0 94.0 2.35" # Gabriella - Trade District +) + +declare -A ORGRIMMAR=( + ["199999"]="1 1633.0 -4439.0 15.4 3.14" # Kaylub - Valley of Strength + ["601015"]="1 1629.0 -4443.0 15.4 0.0" # Beauregard - Valley of Strength + ["601016"]="1 1637.0 -4435.0 15.4 1.57" # Buffmaster - Valley of Strength + ["190011"]="1 1625.0 -4447.0 15.4 4.71" # Ethereal Warpweaver - Valley of Strength + ["9000000"]="1 1641.0 -4431.0 15.4 2.35" # Gabriella - Valley of Strength +) + +declare -A DALARAN=( + ["601072"]="571 5804.0 624.0 647.8 3.14" # Cet Keres - Runeweaver Square + ["190010"]="571 5800.0 628.0 647.8 0.0" # Warpweaver - Runeweaver Square + ["190011"]="571 5808.0 620.0 647.8 1.57" # Ethereal Warpweaver - Runeweaver Square + ["300000"]="571 5796.0 632.0 647.8 4.71" # Cromi - Runeweaver Square +) + +declare -A SHATTRATH=( + ["999991"]="530 -1838.0 5301.0 -12.4 3.14" # Arena Battlemaster - Lower City + ["290011"]="530 -1842.0 5297.0 -12.4 0.0" # Ling - Lower City +) + +usage() { + echo -e "${BLUE}AzerothCore Custom NPC Spawn Script${NC}" + echo -e "${YELLOW}Usage: $0 [location]${NC}" + echo "" + echo "Available locations:" + echo " stormwind - Spawn Alliance-focused NPCs in Stormwind" + echo " orgrimmar - Spawn Horde-focused NPCs in Orgrimmar" + echo " dalaran - Spawn magical service NPCs in Dalaran" + echo " shattrath - Spawn specialized NPCs in Shattrath" + echo " all - Spawn all NPCs in their recommended locations" + echo "" + echo "Examples:" + echo " $0 stormwind" + echo " $0 all" +} + +generate_commands() { + local location=$1 + local commands_file="/tmp/npc_spawn_commands.txt" + + > "$commands_file" + + case $location in + "stormwind") + echo -e "${GREEN}Generating Stormwind NPC spawn commands...${NC}" + for entry in "${!STORMWIND[@]}"; do + coords="${STORMWIND[$entry]}" + npc_info="${NPCS[$entry]}" + name=$(echo "$npc_info" | cut -d'|' -f1) + title=$(echo "$npc_info" | cut -d'|' -f2) + echo ".go xyz $coords" >> "$commands_file" + echo ".npc add $entry" >> "$commands_file" + echo ".npc set face" >> "$commands_file" + echo "# Spawned $name ($title) at Stormwind Trade District" >> "$commands_file" + echo "" >> "$commands_file" + done + ;; + "orgrimmar") + echo -e "${GREEN}Generating Orgrimmar NPC spawn commands...${NC}" + for entry in "${!ORGRIMMAR[@]}"; do + coords="${ORGRIMMAR[$entry]}" + npc_info="${NPCS[$entry]}" + name=$(echo "$npc_info" | cut -d'|' -f1) + title=$(echo "$npc_info" | cut -d'|' -f2) + echo ".go xyz $coords" >> "$commands_file" + echo ".npc add $entry" >> "$commands_file" + echo ".npc set face" >> "$commands_file" + echo "# Spawned $name ($title) at Orgrimmar Valley of Strength" >> "$commands_file" + echo "" >> "$commands_file" + done + ;; + "dalaran") + echo -e "${GREEN}Generating Dalaran NPC spawn commands...${NC}" + for entry in "${!DALARAN[@]}"; do + coords="${DALARAN[$entry]}" + npc_info="${NPCS[$entry]}" + name=$(echo "$npc_info" | cut -d'|' -f1) + title=$(echo "$npc_info" | cut -d'|' -f2) + echo ".go xyz $coords" >> "$commands_file" + echo ".npc add $entry" >> "$commands_file" + echo ".npc set face" >> "$commands_file" + echo "# Spawned $name ($title) at Dalaran Runeweaver Square" >> "$commands_file" + echo "" >> "$commands_file" + done + ;; + "shattrath") + echo -e "${GREEN}Generating Shattrath NPC spawn commands...${NC}" + for entry in "${!SHATTRATH[@]}"; do + coords="${SHATTRATH[$entry]}" + npc_info="${NPCS[$entry]}" + name=$(echo "$npc_info" | cut -d'|' -f1) + title=$(echo "$npc_info" | cut -d'|' -f2) + echo ".go xyz $coords" >> "$commands_file" + echo ".npc add $entry" >> "$commands_file" + echo ".npc set face" >> "$commands_file" + echo "# Spawned $name ($title) at Shattrath Lower City" >> "$commands_file" + echo "" >> "$commands_file" + done + ;; + "all") + echo -e "${GREEN}Generating ALL NPC spawn commands...${NC}" + generate_commands "stormwind" + generate_commands "orgrimmar" + generate_commands "dalaran" + generate_commands "shattrath" + return + ;; + *) + echo -e "${RED}Invalid location: $location${NC}" + usage + exit 1 + ;; + esac + + echo -e "${YELLOW}Commands generated in: $commands_file${NC}" + echo "" + echo -e "${BLUE}To execute these commands:${NC}" + echo "1. Copy the commands from $commands_file" + echo "2. Paste them into your GM console in-game" + echo "3. Or use .server script run if available" + echo "" + echo -e "${BLUE}Generated commands for $location:${NC}" + cat "$commands_file" +} + +generate_quick_reference() { + echo -e "${BLUE}AzerothCore Custom NPCs Quick Reference${NC}" + echo "" + printf "%-10s %-25s %-20s %-15s\n" "Entry ID" "NPC Name" "Function" "Spawn Command" + echo "--------------------------------------------------------------------------------" + + for entry in $(echo "${!NPCS[@]}" | tr ' ' '\n' | sort -n); do + npc_info="${NPCS[$entry]}" + name=$(echo "$npc_info" | cut -d'|' -f1) + title=$(echo "$npc_info" | cut -d'|' -f2) + printf "%-10s %-25s %-20s %-15s\n" "$entry" "$name" "$title" ".npc add $entry" + done + + echo "" + echo -e "${YELLOW}Special NPCs requiring specific locations:${NC}" + echo "- Guild House NPCs (500030, 500031, 500032): Only spawn within guild houses" + echo "- White Fang (601026): Recommended in hunter areas like Un'Goro or Winterspring" + echo "- Arena Battlemaster (999991): Best in neutral cities or PvP areas" + echo "" + echo -e "${GREEN}All NPCs are level 80, neutral faction, and deletion-protected${NC}" +} + +# Main execution +if [[ $# -eq 0 ]]; then + echo -e "${YELLOW}No location specified. Showing quick reference...${NC}" + echo "" + generate_quick_reference + echo "" + usage + exit 0 +fi + +case $1 in + "-h"|"--help"|"help") + usage + exit 0 + ;; + "reference"|"ref"|"list") + generate_quick_reference + exit 0 + ;; + *) + generate_commands "$1" + ;; +esac + +echo "" +echo -e "${GREEN}Script completed successfully!${NC}" +echo -e "${BLUE}Remember to save spawned NPCs to database using appropriate GM commands${NC}" \ No newline at end of file diff --git a/scripts/bash/backup-merge.sh b/scripts/bash/backup-merge.sh index 725ee8a..0f08087 100755 --- a/scripts/bash/backup-merge.sh +++ b/scripts/bash/backup-merge.sh @@ -452,10 +452,10 @@ else log "No conflicts detected" fi -# Calculate ID offsets +# Calculate ID offsets with proper spacing ACCOUNT_OFFSET=$CURRENT_MAX_ACCOUNT_ID CHAR_OFFSET=$CURRENT_MAX_CHAR_GUID -ITEM_OFFSET=$CURRENT_MAX_ITEM_GUID +ITEM_OFFSET=$((CURRENT_MAX_ITEM_GUID + 10000)) info "" info "ID remapping offsets:" diff --git a/scripts/bash/backup-scheduler.sh b/scripts/bash/backup-scheduler.sh index fbf4092..a04532c 100755 --- a/scripts/bash/backup-scheduler.sh +++ b/scripts/bash/backup-scheduler.sh @@ -2,7 +2,7 @@ # azerothcore-rm set -e -BACKUP_DIR_BASE="/backups" +BACKUP_DIR_BASE="${BACKUP_DIR_BASE:-/backups}" HOURLY_DIR="$BACKUP_DIR_BASE/hourly" DAILY_DIR="$BACKUP_DIR_BASE/daily" RETENTION_HOURS=${BACKUP_RETENTION_HOURS:-6} @@ -14,16 +14,56 @@ mkdir -p "$HOURLY_DIR" "$DAILY_DIR" log() { echo "[$(date '+%F %T')] $*"; } +db_exists() { + local name="$1" + [ -z "$name" ] && return 1 + local sanitized="${name//\`/}" + if mysql -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASSWORD}" -e "USE \`${sanitized}\`;" >/dev/null 2>&1; then + return 0 + fi + return 1 +} + # 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 + declare -A seen=() + for base in "${dbs[@]}"; do + [ -n "$base" ] && seen["$base"]=1 + done + + if db_exists "acore_playerbots" && [ -z "${seen[acore_playerbots]}" ]; then dbs+=("acore_playerbots") + seen["acore_playerbots"]=1 log "Detected optional database: acore_playerbots (will be backed up)" >&2 fi + + if [ -n "${BACKUP_EXTRA_DATABASES:-}" ]; then + local normalized="${BACKUP_EXTRA_DATABASES//,/ }" + for extra in $normalized; do + [ -z "$extra" ] && continue + if [ -n "${seen[$extra]}" ]; then + continue + fi + if db_exists "$extra"; then + dbs+=("$extra") + seen["$extra"]=1 + log "Configured extra database '${extra}' added to backup rotation" >&2 + else + log "⚠️ Configured extra database '${extra}' not found (skipping)" >&2 + fi + done + fi + printf '%s\n' "${dbs[@]}" } +if [ "${BACKUP_SCHEDULER_LIST_ONLY:-0}" = "1" ]; then + mapfile -t _dbs < <(database_list) + printf '%s\n' "${_dbs[@]}" + exit 0 +fi + run_backup() { local tier_dir="$1" # hourly or daily dir local tier_type="$2" # "hourly" or "daily" diff --git a/scripts/bash/db-import-conditional.sh b/scripts/bash/db-import-conditional.sh index 1f5dc5c..0932362 100755 --- a/scripts/bash/db-import-conditional.sh +++ b/scripts/bash/db-import-conditional.sh @@ -305,12 +305,17 @@ echo "✅ Fresh databases created - proceeding with schema import" echo "📝 Creating dbimport configuration..." mkdir -p /azerothcore/env/dist/etc +TEMP_DIR="/azerothcore/env/dist/temp" +mkdir -p "$TEMP_DIR" +MYSQL_EXECUTABLE="$(command -v mysql || echo '/usr/bin/mysql')" cat > /azerothcore/env/dist/etc/dbimport.conf </dev/null +} + +mysql_query(){ + local db="$1" + local query="$2" + docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -N -B "$db" -e "$query" 2>/dev/null +} + +log "═══════════════════════════════════════════════════════════" +log " FIXING ITEM IMPORT FOR BACKUP-MERGED CHARACTERS" +log "═══════════════════════════════════════════════════════════" + +# Find characters that were imported from the backup (accounts 451, 452) +log "Finding characters that need item restoration..." +IMPORTED_CHARS=$(mysql_query "$CHARACTERS_DB" "SELECT name, guid FROM characters WHERE account IN (451, 452);") + +if [[ -z "$IMPORTED_CHARS" ]]; then + fatal "No imported characters found (accounts 451, 452)" +fi + +info "Found imported characters:" +echo "$IMPORTED_CHARS" | while read -r char_name char_guid; do + info " $char_name (guid: $char_guid)" +done + +# Check current item count for these characters +CURRENT_ITEM_COUNT=$(mysql_query "$CHARACTERS_DB" "SELECT COUNT(*) FROM item_instance WHERE owner_guid IN (4501, 4502, 4503);") +info "Current items for imported characters: $CURRENT_ITEM_COUNT" + +if [[ "$CURRENT_ITEM_COUNT" != "0" ]]; then + warn "Characters already have items. Exiting." + exit 0 +fi + +# Extract backup files +log "Extracting backup files..." +CHARACTERS_DUMP="" +for pattern in "acore_characters.sql.gz" "characters.sql.gz" "acore_characters.sql" "characters.sql"; do + if [[ -f "$BACKUP_DIR/$pattern" ]]; then + CHARACTERS_DUMP="$BACKUP_DIR/$pattern" + break + fi +done + +[[ -n "$CHARACTERS_DUMP" ]] || fatal "Characters database dump not found in $BACKUP_DIR" + +info "Found characters dump: ${CHARACTERS_DUMP##*/}" + +# Extract dump to temp file +if [[ "$CHARACTERS_DUMP" == *.gz ]]; then + zcat "$CHARACTERS_DUMP" > "$TEMP_DIR/characters.sql" +else + cp "$CHARACTERS_DUMP" "$TEMP_DIR/characters.sql" +fi + +# Create staging database +log "Creating staging database..." +STAGE_CHARS_DB="fix_stage_chars_$$" + +# Drop any existing staging database +docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -e "DROP DATABASE IF EXISTS $STAGE_CHARS_DB;" 2>/dev/null || true + +# Create staging database +docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -e "CREATE DATABASE $STAGE_CHARS_DB;" 2>/dev/null + +# Cleanup staging database on exit +cleanup_staging(){ + if [[ -n "${STAGE_CHARS_DB:-}" ]]; then + docker exec ac-mysql mysql -uroot -p"$MYSQL_PW" -e "DROP DATABASE IF EXISTS $STAGE_CHARS_DB;" 2>/dev/null || true + fi +} +trap 'cleanup_staging; rm -rf "$TEMP_DIR"' EXIT + +# Load backup into staging database +info "Loading backup into staging database..." +sed "s/\`acore_characters\`/\`$STAGE_CHARS_DB\`/g; s/USE \`acore_characters\`;/USE \`$STAGE_CHARS_DB\`;/g" "$TEMP_DIR/characters.sql" | \ + docker exec -i ac-mysql mysql -uroot -p"$MYSQL_PW" 2>/dev/null + +# Get current database state +CURRENT_MAX_ITEM_GUID=$(mysql_query "$CHARACTERS_DB" "SELECT COALESCE(MAX(guid), 0) FROM item_instance;") +ITEM_OFFSET=$((CURRENT_MAX_ITEM_GUID + 10000)) + +info "Current max item GUID: $CURRENT_MAX_ITEM_GUID" +info "Item GUID offset: +$ITEM_OFFSET" + +# Create character mapping for the imported characters +log "Creating character mapping..." +mysql_exec "$STAGE_CHARS_DB" </dev/null 2>&1 || warn "Services already stopped" + +# Import items +log "Importing character items..." + +# Import item_instance +ITEM_SQL=$(cat <&1) +if echo "$ITEM_RESULT" | grep -q "ERROR"; then + err "Item import failed:" + echo "$ITEM_RESULT" | grep "ERROR" >&2 + fatal "Item import failed" +fi + +# Import character_inventory +INV_SQL=$(cat <&1) +if echo "$INV_RESULT" | grep -q "ERROR"; then + err "Inventory import failed:" + echo "$INV_RESULT" | grep "ERROR" >&2 + fatal "Inventory import failed" +fi + +# Report counts +ITEMS_IMPORTED=$(mysql_query "$CHARACTERS_DB" "SELECT COUNT(*) FROM item_instance WHERE owner_guid IN (4501, 4502, 4503);") +INV_IMPORTED=$(mysql_query "$CHARACTERS_DB" "SELECT COUNT(*) FROM character_inventory WHERE guid IN (4501, 4502, 4503);") + +info "Items imported: $ITEMS_IMPORTED" +info "Inventory slots imported: $INV_IMPORTED" + +# Restart services +log "Restarting services..." +docker restart ac-authserver ac-worldserver >/dev/null 2>&1 + +log "Waiting for services to initialize..." +sleep 5 + +for i in {1..30}; do + if docker exec ac-worldserver pgrep worldserver >/dev/null 2>&1 && docker exec ac-authserver pgrep authserver >/dev/null 2>&1; then + log "✓ Services running" + break + fi + if [ $i -eq 30 ]; then + warn "Services took longer than expected to start" + fi + sleep 2 +done + +log "" +log "═══════════════════════════════════════════════════════════" +log " ITEM IMPORT FIX COMPLETE" +log "═══════════════════════════════════════════════════════════" +log "Items successfully restored for imported characters!" +log "Players can now log in with their complete characters and items." \ No newline at end of file diff --git a/scripts/bash/import-database-files.sh b/scripts/bash/import-database-files.sh index 0a7ecb0..78cdbca 100755 --- a/scripts/bash/import-database-files.sh +++ b/scripts/bash/import-database-files.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copy user database files from database-import/ to backup system -set -e +# Copy user database files or full backup archives from database-import/ to backup system +set -euo pipefail # Source environment variables if [ -f ".env" ]; then @@ -13,14 +13,30 @@ IMPORT_DIR="./database-import" STORAGE_PATH="${STORAGE_PATH:-./storage}" STORAGE_PATH_LOCAL="${STORAGE_PATH_LOCAL:-./local-storage}" BACKUP_DIR="${STORAGE_PATH}/backups/daily" +FULL_BACKUP_DIR="${STORAGE_PATH}/backups/ImportBackup" TIMESTAMP=$(date +%Y-%m-%d) -# Exit if no import directory or empty -if [ ! -d "$IMPORT_DIR" ] || [ -z "$(ls -A "$IMPORT_DIR" 2>/dev/null | grep -E '\.(sql|sql\.gz)$')" ]; then - echo "📁 No database files found in $IMPORT_DIR - skipping import" +shopt -s nullglob + +sql_files=("$IMPORT_DIR"/*.sql "$IMPORT_DIR"/*.sql.gz) +archive_files=("$IMPORT_DIR"/*.tar "$IMPORT_DIR"/*.tar.gz "$IMPORT_DIR"/*.tgz "$IMPORT_DIR"/*.zip) + +declare -a full_backup_dirs=() +for dir in "$IMPORT_DIR"/*/; do + dir="${dir%/}" + # Skip if no dump-like files inside + if compgen -G "$dir"/*.sql >/dev/null || compgen -G "$dir"/*.sql.gz >/dev/null; then + full_backup_dirs+=("$dir") + fi +done + +if [ ! -d "$IMPORT_DIR" ] || { [ ${#sql_files[@]} -eq 0 ] && [ ${#archive_files[@]} -eq 0 ] && [ ${#full_backup_dirs[@]} -eq 0 ]; }; then + echo "📁 No database files or full backups found in $IMPORT_DIR - skipping import" exit 0 fi +shopt -u nullglob + # Exit if backup system already has databases restored if [ -f "${STORAGE_PATH_LOCAL}/mysql-data/.restore-completed" ]; then echo "✅ Database already restored - skipping import" @@ -31,10 +47,25 @@ echo "📥 Found database files in $IMPORT_DIR" echo "📂 Copying to backup system for import..." # Ensure backup directory exists -mkdir -p "$BACKUP_DIR" +mkdir -p "$BACKUP_DIR" "$FULL_BACKUP_DIR" + +generate_unique_path(){ + local target="$1" + local base="$target" + local counter=2 + while [ -e "$target" ]; do + target="${base}_${counter}" + counter=$((counter + 1)) + done + printf '%s\n' "$target" +} + +copied_sql=0 +staged_dirs=0 +staged_archives=0 # Copy files with smart naming -for file in "$IMPORT_DIR"/*.sql "$IMPORT_DIR"/*.sql.gz; do +for file in "${sql_files[@]:-}"; do [ -f "$file" ] || continue filename=$(basename "$file") @@ -62,7 +93,106 @@ for file in "$IMPORT_DIR"/*.sql "$IMPORT_DIR"/*.sql.gz; do echo "📋 Copying $filename → $target_name" cp "$file" "$target_path" + copied_sql=$((copied_sql + 1)) done -echo "✅ Database files copied to backup system" -echo "💡 Files will be automatically imported during deployment" \ No newline at end of file +stage_backup_directory(){ + local src_dir="$1" + local dirname + dirname="$(basename "$src_dir")" + local dest="$FULL_BACKUP_DIR/$dirname" + dest="$(generate_unique_path "$dest")" + echo "📦 Staging full backup directory $(basename "$src_dir") → $(basename "$dest")" + cp -a "$src_dir" "$dest" + staged_dirs=$((staged_dirs + 1)) +} + +extract_archive(){ + local archive="$1" + local base_name + base_name="$(basename "$archive")" + local tmp_dir + tmp_dir="$(mktemp -d)" + local extracted=0 + + cleanup_tmp(){ + rm -rf "$tmp_dir" + } + + case "$archive" in + *.tar.gz|*.tgz) + if tar -xzf "$archive" -C "$tmp_dir"; then + extracted=1 + fi + ;; + *.tar) + if tar -xf "$archive" -C "$tmp_dir"; then + extracted=1 + fi + ;; + *.zip) + if ! command -v unzip >/dev/null 2>&1; then + echo "⚠️ unzip not found; cannot extract $base_name" + elif unzip -q "$archive" -d "$tmp_dir"; then + extracted=1 + fi + ;; + *) + echo "⚠️ Unsupported archive format for $base_name" + ;; + esac + + if [ "$extracted" -ne 1 ]; then + cleanup_tmp + return + fi + + mapfile -d '' entries < <(find "$tmp_dir" -mindepth 1 -maxdepth 1 -print0) || true + local dest="" + if [ ${#entries[@]} -eq 1 ] && [ -d "${entries[0]}" ]; then + local inner_name + inner_name="$(basename "${entries[0]}")" + dest="$FULL_BACKUP_DIR/$inner_name" + dest="$(generate_unique_path "$dest")" + mv "${entries[0]}" "$dest" + else + local base="${base_name%.*}" + base="${base%.*}" # handle double extensions like .tar.gz + dest="$(generate_unique_path "$FULL_BACKUP_DIR/$base")" + mkdir -p "$dest" + if [ ${#entries[@]} -gt 0 ]; then + mv "${entries[@]}" "$dest"/ + fi + fi + echo "🗂️ Extracted $base_name → $(basename "$dest")" + staged_archives=$((staged_archives + 1)) + cleanup_tmp +} + +for dir in "${full_backup_dirs[@]:-}"; do + stage_backup_directory "$dir" +done + +for archive in "${archive_files[@]:-}"; do + extract_archive "$archive" +done + +if [ "$copied_sql" -gt 0 ]; then + echo "✅ $copied_sql database file(s) copied to $BACKUP_DIR" +fi +if [ "$staged_dirs" -gt 0 ]; then + dir_label="directories" + [ "$staged_dirs" -eq 1 ] && dir_label="directory" + echo "✅ $staged_dirs full backup $dir_label staged in $FULL_BACKUP_DIR" +fi +if [ "$staged_archives" -gt 0 ]; then + archive_label="archives" + [ "$staged_archives" -eq 1 ] && archive_label="archive" + echo "✅ $staged_archives backup $archive_label extracted to $FULL_BACKUP_DIR" +fi + +if [ "$copied_sql" -eq 0 ] && [ "$staged_dirs" -eq 0 ] && [ "$staged_archives" -eq 0 ]; then + echo "⚠️ No valid files or backups were staged. Ensure your dumps are .sql/.sql.gz or packaged in directories/archives." +else + echo "💡 Files will be automatically imported during deployment" +fi diff --git a/scripts/bash/stage-modules.sh b/scripts/bash/stage-modules.sh index f5588f7..d19e61b 100755 --- a/scripts/bash/stage-modules.sh +++ b/scripts/bash/stage-modules.sh @@ -128,6 +128,13 @@ resolve_project_image(){ echo "${project_name}:${tag}" } +is_project_local_image(){ + local image="$1" + local project_name + project_name="$(resolve_project_name)" + [[ "$image" == "${project_name}:"* ]] +} + canonical_path(){ local path="$1" if command -v realpath >/dev/null 2>&1; then @@ -300,8 +307,12 @@ TARGET_WORLDSERVER_IMAGE_MODULES="$(read_env AC_WORLDSERVER_IMAGE_MODULES "$(res if [ "$TARGET_PROFILE" = "modules" ]; then # Check if source image exists if ! docker image inspect "$TARGET_WORLDSERVER_IMAGE_MODULES" >/dev/null 2>&1; then - echo "📦 Modules image $TARGET_WORLDSERVER_IMAGE_MODULES not found - rebuild needed" - REBUILD_NEEDED=1 + if is_project_local_image "$TARGET_WORLDSERVER_IMAGE_MODULES"; then + echo "📦 Modules image $TARGET_WORLDSERVER_IMAGE_MODULES not found - rebuild needed" + REBUILD_NEEDED=1 + else + echo "ℹ️ Modules image $TARGET_WORLDSERVER_IMAGE_MODULES missing locally but not tagged with the project prefix; assuming compose will pull from your registry." + fi elif [ -f "$SENTINEL_FILE" ]; then echo "🔄 Modules changed since last build - rebuild needed" REBUILD_NEEDED=1