import enhancements and npc spawn sketches

This commit is contained in:
uprightbass360
2025-11-10 01:59:47 -05:00
parent fbf6b23f56
commit 68dc21d5ef
21 changed files with 1351 additions and 24 deletions

View File

@@ -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

View File

@@ -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)**.

View File

@@ -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
- Files/directories are copied once; existing restored databases will skip import
- Empty folder is ignored - no files, no import

View File

@@ -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

View File

@@ -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}"

View File

@@ -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`)

View File

@@ -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

374
docs/NPCS.md Normal file
View File

@@ -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*

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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);

222
scripts/admin/spawn-all-npcs.sh Executable file
View File

@@ -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}"

View File

@@ -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:"

View File

@@ -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"

View File

@@ -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 <<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
TempDir = "${TEMP_DIR}"
MySQLExecutable = "${MYSQL_EXECUTABLE}"
EOF
echo "🚀 Running database import..."

257
scripts/bash/fix-item-import.sh Executable file
View File

@@ -0,0 +1,257 @@
#!/bin/bash
# Fix item import for backup-merged characters
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
COLOR_RED='\033[0;31m'
COLOR_GREEN='\033[0;32m'
COLOR_YELLOW='\033[1;33m'
COLOR_BLUE='\033[0;34m'
COLOR_CYAN='\033[0;36m'
COLOR_RESET='\033[0m'
log(){ printf '%b\n' "${COLOR_GREEN}$*${COLOR_RESET}"; }
info(){ printf '%b\n' "${COLOR_CYAN}$*${COLOR_RESET}"; }
warn(){ printf '%b\n' "${COLOR_YELLOW}$*${COLOR_RESET}"; }
err(){ printf '%b\n' "${COLOR_RED}$*${COLOR_RESET}"; }
fatal(){ err "$*"; exit 1; }
MYSQL_PW="azerothcore123"
BACKUP_DIR="/nfs/containers/ac-backup"
AUTH_DB="acore_auth"
CHARACTERS_DB="acore_characters"
# Verify parameters
[[ -d "$BACKUP_DIR" ]] || fatal "Backup directory not found: $BACKUP_DIR"
# Setup temp directory
TEMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TEMP_DIR"' EXIT
# MySQL connection helper
mysql_exec(){
local db="$1"
docker exec -i ac-mysql mysql -uroot -p"$MYSQL_PW" "$db" 2>/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" <<EOF
CREATE TABLE character_guid_map (
old_guid INT UNSIGNED PRIMARY KEY,
new_guid INT UNSIGNED,
name VARCHAR(12)
);
INSERT INTO character_guid_map (old_guid, new_guid, name)
VALUES
(1, 4501, 'Artimage'),
(2, 4502, 'Flombey'),
(3, 4503, 'Hammertime');
EOF
# Create item GUID mapping
mysql_exec "$STAGE_CHARS_DB" <<EOF
CREATE TABLE item_guid_map (
old_guid INT UNSIGNED PRIMARY KEY,
new_guid INT UNSIGNED,
owner_guid INT UNSIGNED
);
INSERT INTO item_guid_map (old_guid, new_guid, owner_guid)
SELECT
i.guid,
i.guid + $ITEM_OFFSET,
i.owner_guid
FROM item_instance i
INNER JOIN character_guid_map cm ON i.owner_guid = cm.old_guid;
EOF
# Check how many items will be imported
ITEMS_TO_IMPORT=$(mysql_query "$STAGE_CHARS_DB" "SELECT COUNT(*) FROM item_guid_map;")
info "Items to import: $ITEMS_TO_IMPORT"
if [[ "$ITEMS_TO_IMPORT" == "0" ]]; then
warn "No items found for the imported characters in backup"
exit 0
fi
# Stop services
log "Stopping world/auth services..."
docker stop ac-worldserver ac-authserver >/dev/null 2>&1 || warn "Services already stopped"
# Import items
log "Importing character items..."
# Import item_instance
ITEM_SQL=$(cat <<EOSQL
INSERT INTO item_instance (guid, itemEntry, owner_guid, creatorGuid, giftCreatorGuid, count,
duration, charges, flags, enchantments, randomPropertyId, durability,
playedTime, text)
SELECT
im.new_guid,
ii.itemEntry,
cm.new_guid,
ii.creatorGuid,
ii.giftCreatorGuid,
ii.count,
ii.duration,
ii.charges,
ii.flags,
ii.enchantments,
ii.randomPropertyId,
ii.durability,
ii.playedTime,
ii.text
FROM $STAGE_CHARS_DB.item_instance ii
INNER JOIN $STAGE_CHARS_DB.item_guid_map im ON ii.guid = im.old_guid
INNER JOIN $STAGE_CHARS_DB.character_guid_map cm ON ii.owner_guid = cm.old_guid;
EOSQL
)
ITEM_SQL_EXPANDED=$(echo "$ITEM_SQL" | sed "s/STAGE_CHARS_DB/$STAGE_CHARS_DB/g")
ITEM_RESULT=$(echo "$ITEM_SQL_EXPANDED" | docker exec -i ac-mysql mysql -uroot -p"$MYSQL_PW" "$CHARACTERS_DB" 2>&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 <<EOSQL
INSERT INTO character_inventory (guid, bag, slot, item)
SELECT
cm.new_guid,
ci.bag,
ci.slot,
im.new_guid
FROM $STAGE_CHARS_DB.character_inventory ci
INNER JOIN $STAGE_CHARS_DB.character_guid_map cm ON ci.guid = cm.old_guid
INNER JOIN $STAGE_CHARS_DB.item_guid_map im ON ci.item = im.old_guid;
EOSQL
)
INV_SQL_EXPANDED=$(echo "$INV_SQL" | sed "s/STAGE_CHARS_DB/$STAGE_CHARS_DB/g")
INV_RESULT=$(echo "$INV_SQL_EXPANDED" | docker exec -i ac-mysql mysql -uroot -p"$MYSQL_PW" "$CHARACTERS_DB" 2>&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."

View File

@@ -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"
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

View File

@@ -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