mirror of
https://github.com/uprightbass360/AzerothCore-RealmMaster.git
synced 2026-01-13 00:58:34 +00:00
import enhancements and npc spawn sketches
This commit is contained in:
@@ -135,6 +135,8 @@ DB_PLAYERBOTS_NAME=acore_playerbots
|
|||||||
BACKUP_RETENTION_DAYS=3
|
BACKUP_RETENTION_DAYS=3
|
||||||
BACKUP_RETENTION_HOURS=6
|
BACKUP_RETENTION_HOURS=6
|
||||||
BACKUP_DAILY_TIME=09
|
BACKUP_DAILY_TIME=09
|
||||||
|
# Optional comma/space separated schemas to include in automated backups
|
||||||
|
BACKUP_EXTRA_DATABASES=
|
||||||
BACKUP_HEALTHCHECK_MAX_MINUTES=1440
|
BACKUP_HEALTHCHECK_MAX_MINUTES=1440
|
||||||
BACKUP_HEALTHCHECK_GRACE_SECONDS=4500
|
BACKUP_HEALTHCHECK_GRACE_SECONDS=4500
|
||||||
BACKUP_HEALTHCHECK_INTERVAL=60s
|
BACKUP_HEALTHCHECK_INTERVAL=60s
|
||||||
|
|||||||
17
README.md
17
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)**
|
- [Complete Module Catalog](#complete-module-catalog) → **[docs/MODULES.md](docs/MODULES.md)**
|
||||||
- [Management & Operations](#management--operations) → **[docs/GETTING_STARTED.md](docs/GETTING_STARTED.md)**
|
- [Management & Operations](#management--operations) → **[docs/GETTING_STARTED.md](docs/GETTING_STARTED.md)**
|
||||||
- [Advanced Configuration](#advanced-configuration) → **[docs/ADVANCED.md](docs/ADVANCED.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)**
|
- [Script Reference](#script-reference) → **[docs/SCRIPTS.md](docs/SCRIPTS.md)**
|
||||||
- [Troubleshooting](#troubleshooting) → **[docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)**
|
- [Troubleshooting](#troubleshooting) → **[docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)**
|
||||||
- [Credits & Next Steps](#credits--next-steps)
|
- [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)**.
|
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
|
## Management & Operations
|
||||||
|
|
||||||
For common workflows, management commands, and database operations, see **[docs/GETTING_STARTED.md](docs/GETTING_STARTED.md)**.
|
For common workflows, management commands, and database operations, see **[docs/GETTING_STARTED.md](docs/GETTING_STARTED.md)**.
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
Place your database backup files here for automatic import during deployment.
|
Place your database backup files here for automatic import during deployment.
|
||||||
|
|
||||||
## Supported Files
|
## Supported Imports
|
||||||
- `.sql` files (uncompressed SQL dumps)
|
- `.sql` files (uncompressed SQL dumps)
|
||||||
- `.sql.gz` files (gzip compressed 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
|
## 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_auth_backup.sql.gz ./database-import/
|
||||||
cp my_world_backup.sql.gz ./database-import/
|
cp my_world_backup.sql.gz ./database-import/
|
||||||
cp my_characters_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:**
|
2. **Run deployment:**
|
||||||
@@ -25,13 +30,15 @@ Place your database backup files here for automatic import during deployment.
|
|||||||
## File Naming
|
## File Naming
|
||||||
- Any filename works - the system will auto-detect database type by content
|
- Any filename works - the system will auto-detect database type by content
|
||||||
- Recommended naming: `auth.sql.gz`, `world.sql.gz`, `characters.sql.gz`
|
- 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
|
## What Happens
|
||||||
- Files from this folder are copied to `local-storage/backups/daily/`
|
- Individual `.sql`/`.sql.gz` files are copied to `storage/backups/daily/` with a timestamped name
|
||||||
- Database import system automatically restores them
|
- Full backup directories or archives are staged in `storage/backups/ImportBackup/`
|
||||||
- Original files remain here for reference
|
- Database import system automatically restores the most recent matching backup
|
||||||
|
- Original files remain here for reference (archives are left untouched)
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
- Only processed on first deployment (when databases don't exist)
|
- 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
|
- Empty folder is ignored - no files, no import
|
||||||
|
|||||||
19
deploy.sh
19
deploy.sh
@@ -379,6 +379,13 @@ resolve_project_image(){
|
|||||||
echo "${project_name}:${tag}"
|
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(){
|
filter_empty_lines(){
|
||||||
awk '
|
awk '
|
||||||
/^[[:space:]]*$/ {
|
/^[[:space:]]*$/ {
|
||||||
@@ -423,10 +430,18 @@ detect_build_needed(){
|
|||||||
worldserver_modules_image="$(read_env AC_WORLDSERVER_IMAGE_MODULES "$(resolve_project_image "worldserver-modules-latest")")"
|
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
|
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
|
fi
|
||||||
if ! docker image inspect "$worldserver_modules_image" >/dev/null 2>&1; then
|
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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ services:
|
|||||||
MYSQL_MAX_CONNECTIONS: ${MYSQL_MAX_CONNECTIONS}
|
MYSQL_MAX_CONNECTIONS: ${MYSQL_MAX_CONNECTIONS}
|
||||||
MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_INNODB_BUFFER_POOL_SIZE}
|
MYSQL_INNODB_BUFFER_POOL_SIZE: ${MYSQL_INNODB_BUFFER_POOL_SIZE}
|
||||||
MYSQL_INNODB_LOG_FILE_SIZE: ${MYSQL_INNODB_LOG_FILE_SIZE}
|
MYSQL_INNODB_LOG_FILE_SIZE: ${MYSQL_INNODB_LOG_FILE_SIZE}
|
||||||
|
TZ: "${TZ}"
|
||||||
entrypoint:
|
entrypoint:
|
||||||
- /usr/local/bin/mysql-entrypoint.sh
|
- /usr/local/bin/mysql-entrypoint.sh
|
||||||
volumes:
|
volumes:
|
||||||
@@ -65,6 +66,7 @@ services:
|
|||||||
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
|
- ${STORAGE_PATH}/config:/azerothcore/env/dist/etc
|
||||||
- ${STORAGE_PATH}/logs:/azerothcore/logs
|
- ${STORAGE_PATH}/logs:/azerothcore/logs
|
||||||
- ${STORAGE_PATH_LOCAL}/mysql-data:/var/lib/mysql-persistent
|
- ${STORAGE_PATH_LOCAL}/mysql-data:/var/lib/mysql-persistent
|
||||||
|
- ${BACKUP_PATH}:/backups
|
||||||
- ./scripts/bash/db-import-conditional.sh:/tmp/db-import-conditional.sh:ro
|
- ./scripts/bash/db-import-conditional.sh:/tmp/db-import-conditional.sh:ro
|
||||||
environment:
|
environment:
|
||||||
AC_DATA_DIR: "/azerothcore/data"
|
AC_DATA_DIR: "/azerothcore/data"
|
||||||
@@ -160,6 +162,7 @@ services:
|
|||||||
DB_AUTH_NAME: ${DB_AUTH_NAME}
|
DB_AUTH_NAME: ${DB_AUTH_NAME}
|
||||||
DB_WORLD_NAME: ${DB_WORLD_NAME}
|
DB_WORLD_NAME: ${DB_WORLD_NAME}
|
||||||
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME}
|
DB_CHARACTERS_NAME: ${DB_CHARACTERS_NAME}
|
||||||
|
BACKUP_EXTRA_DATABASES: ${BACKUP_EXTRA_DATABASES}
|
||||||
TZ: ${TZ}
|
TZ: ${TZ}
|
||||||
CONTAINER_USER: ${CONTAINER_USER}
|
CONTAINER_USER: ${CONTAINER_USER}
|
||||||
volumes:
|
volumes:
|
||||||
@@ -449,6 +452,7 @@ services:
|
|||||||
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
|
AC_LOGIN_DATABASE_INFO: "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
|
||||||
AC_UPDATES_ENABLE_DATABASES: "0"
|
AC_UPDATES_ENABLE_DATABASES: "0"
|
||||||
AC_BIND_IP: "0.0.0.0"
|
AC_BIND_IP: "0.0.0.0"
|
||||||
|
TZ: "${TZ}"
|
||||||
AC_LOG_LEVEL: "1"
|
AC_LOG_LEVEL: "1"
|
||||||
AC_LOGGER_ROOT_CONFIG: "1,Console"
|
AC_LOGGER_ROOT_CONFIG: "1,Console"
|
||||||
AC_LOGGER_SERVER_CONFIG: "1,Console"
|
AC_LOGGER_SERVER_CONFIG: "1,Console"
|
||||||
@@ -527,6 +531,7 @@ services:
|
|||||||
AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD}"
|
AC_ELUNA_AUTO_RELOAD: "${AC_ELUNA_AUTO_RELOAD}"
|
||||||
AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE}"
|
AC_ELUNA_BYTECODE_CACHE: "${AC_ELUNA_BYTECODE_CACHE}"
|
||||||
AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH}"
|
AC_ELUNA_SCRIPT_PATH: "${AC_ELUNA_SCRIPT_PATH}"
|
||||||
|
TZ: "${TZ}"
|
||||||
AC_ELUNA_REQUIRE_PATHS: "${AC_ELUNA_REQUIRE_PATHS}"
|
AC_ELUNA_REQUIRE_PATHS: "${AC_ELUNA_REQUIRE_PATHS}"
|
||||||
AC_ELUNA_REQUIRE_CPATHS: "${AC_ELUNA_REQUIRE_CPATHS}"
|
AC_ELUNA_REQUIRE_CPATHS: "${AC_ELUNA_REQUIRE_CPATHS}"
|
||||||
AC_ELUNA_AUTO_RELOAD_INTERVAL: "${AC_ELUNA_AUTO_RELOAD_INTERVAL}"
|
AC_ELUNA_AUTO_RELOAD_INTERVAL: "${AC_ELUNA_AUTO_RELOAD_INTERVAL}"
|
||||||
|
|||||||
@@ -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.
|
`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.
|
To tweak MySQL settings, place `.cnf` snippets in `storage/config/mysql/conf.d`. Files in this directory map straight to `/etc/mysql/conf.d` inside `ac-mysql`, so you can re-enable binary logs or tune buffers without rebuilding images.
|
||||||
|
|
||||||
**Local Storage** (`STORAGE_PATH_LOCAL` - default: `./local-storage`)
|
**Local Storage** (`STORAGE_PATH_LOCAL` - default: `./local-storage`)
|
||||||
@@ -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.*
|
*This documentation is part of the AzerothCore RealmMaster project. For updates and contributions, visit the main project repository.*
|
||||||
|
|||||||
@@ -258,6 +258,23 @@ SET address = 'your-public-ip', port = 8215
|
|||||||
WHERE id = 1;
|
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
|
## Management & Operations
|
||||||
|
|||||||
374
docs/NPCS.md
Normal file
374
docs/NPCS.md
Normal 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*
|
||||||
24
scripts/admin/fix-silvermoon-npcs.sql
Normal file
24
scripts/admin/fix-silvermoon-npcs.sql
Normal 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);
|
||||||
31
scripts/admin/replace-silvermoon-envoys.sql
Normal file
31
scripts/admin/replace-silvermoon-envoys.sql
Normal 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
|
||||||
31
scripts/admin/replace-silvermoon-walk-of-elders.sql
Normal file
31
scripts/admin/replace-silvermoon-walk-of-elders.sql
Normal 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
|
||||||
52
scripts/admin/silvermoon-npc-line.sql
Normal file
52
scripts/admin/silvermoon-npc-line.sql
Normal 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)
|
||||||
72
scripts/admin/silvermoon-walk-of-elders-all-npcs.sql
Normal file
72
scripts/admin/silvermoon-walk-of-elders-all-npcs.sql
Normal 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
|
||||||
13
scripts/admin/simple-npc-line.sql
Normal file
13
scripts/admin/simple-npc-line.sql
Normal 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
222
scripts/admin/spawn-all-npcs.sh
Executable 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}"
|
||||||
@@ -452,10 +452,10 @@ else
|
|||||||
log "No conflicts detected"
|
log "No conflicts detected"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Calculate ID offsets
|
# Calculate ID offsets with proper spacing
|
||||||
ACCOUNT_OFFSET=$CURRENT_MAX_ACCOUNT_ID
|
ACCOUNT_OFFSET=$CURRENT_MAX_ACCOUNT_ID
|
||||||
CHAR_OFFSET=$CURRENT_MAX_CHAR_GUID
|
CHAR_OFFSET=$CURRENT_MAX_CHAR_GUID
|
||||||
ITEM_OFFSET=$CURRENT_MAX_ITEM_GUID
|
ITEM_OFFSET=$((CURRENT_MAX_ITEM_GUID + 10000))
|
||||||
|
|
||||||
info ""
|
info ""
|
||||||
info "ID remapping offsets:"
|
info "ID remapping offsets:"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# azerothcore-rm
|
# azerothcore-rm
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
BACKUP_DIR_BASE="/backups"
|
BACKUP_DIR_BASE="${BACKUP_DIR_BASE:-/backups}"
|
||||||
HOURLY_DIR="$BACKUP_DIR_BASE/hourly"
|
HOURLY_DIR="$BACKUP_DIR_BASE/hourly"
|
||||||
DAILY_DIR="$BACKUP_DIR_BASE/daily"
|
DAILY_DIR="$BACKUP_DIR_BASE/daily"
|
||||||
RETENTION_HOURS=${BACKUP_RETENTION_HOURS:-6}
|
RETENTION_HOURS=${BACKUP_RETENTION_HOURS:-6}
|
||||||
@@ -14,16 +14,56 @@ mkdir -p "$HOURLY_DIR" "$DAILY_DIR"
|
|||||||
|
|
||||||
log() { echo "[$(date '+%F %T')] $*"; }
|
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)
|
# Build database list from env (include optional acore_playerbots if present)
|
||||||
database_list() {
|
database_list() {
|
||||||
local dbs=("${DB_AUTH_NAME}" "${DB_WORLD_NAME}" "${DB_CHARACTERS_NAME}")
|
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")
|
dbs+=("acore_playerbots")
|
||||||
|
seen["acore_playerbots"]=1
|
||||||
log "Detected optional database: acore_playerbots (will be backed up)" >&2
|
log "Detected optional database: acore_playerbots (will be backed up)" >&2
|
||||||
fi
|
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[@]}"
|
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() {
|
run_backup() {
|
||||||
local tier_dir="$1" # hourly or daily dir
|
local tier_dir="$1" # hourly or daily dir
|
||||||
local tier_type="$2" # "hourly" or "daily"
|
local tier_type="$2" # "hourly" or "daily"
|
||||||
|
|||||||
@@ -305,12 +305,17 @@ echo "✅ Fresh databases created - proceeding with schema import"
|
|||||||
|
|
||||||
echo "📝 Creating dbimport configuration..."
|
echo "📝 Creating dbimport configuration..."
|
||||||
mkdir -p /azerothcore/env/dist/etc
|
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
|
cat > /azerothcore/env/dist/etc/dbimport.conf <<EOF
|
||||||
LoginDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_AUTH_NAME}"
|
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}"
|
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}"
|
CharacterDatabaseInfo = "${CONTAINER_MYSQL};${MYSQL_PORT};${MYSQL_USER};${MYSQL_ROOT_PASSWORD};${DB_CHARACTERS_NAME}"
|
||||||
Updates.EnableDatabases = 7
|
Updates.EnableDatabases = 7
|
||||||
Updates.AutoSetup = 1
|
Updates.AutoSetup = 1
|
||||||
|
TempDir = "${TEMP_DIR}"
|
||||||
|
MySQLExecutable = "${MYSQL_EXECUTABLE}"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "🚀 Running database import..."
|
echo "🚀 Running database import..."
|
||||||
|
|||||||
257
scripts/bash/fix-item-import.sh
Executable file
257
scripts/bash/fix-item-import.sh
Executable 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."
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Copy user database files from database-import/ to backup system
|
# Copy user database files or full backup archives from database-import/ to backup system
|
||||||
set -e
|
set -euo pipefail
|
||||||
|
|
||||||
# Source environment variables
|
# Source environment variables
|
||||||
if [ -f ".env" ]; then
|
if [ -f ".env" ]; then
|
||||||
@@ -13,14 +13,30 @@ IMPORT_DIR="./database-import"
|
|||||||
STORAGE_PATH="${STORAGE_PATH:-./storage}"
|
STORAGE_PATH="${STORAGE_PATH:-./storage}"
|
||||||
STORAGE_PATH_LOCAL="${STORAGE_PATH_LOCAL:-./local-storage}"
|
STORAGE_PATH_LOCAL="${STORAGE_PATH_LOCAL:-./local-storage}"
|
||||||
BACKUP_DIR="${STORAGE_PATH}/backups/daily"
|
BACKUP_DIR="${STORAGE_PATH}/backups/daily"
|
||||||
|
FULL_BACKUP_DIR="${STORAGE_PATH}/backups/ImportBackup"
|
||||||
TIMESTAMP=$(date +%Y-%m-%d)
|
TIMESTAMP=$(date +%Y-%m-%d)
|
||||||
|
|
||||||
# Exit if no import directory or empty
|
shopt -s nullglob
|
||||||
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"
|
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
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
shopt -u nullglob
|
||||||
|
|
||||||
# Exit if backup system already has databases restored
|
# Exit if backup system already has databases restored
|
||||||
if [ -f "${STORAGE_PATH_LOCAL}/mysql-data/.restore-completed" ]; then
|
if [ -f "${STORAGE_PATH_LOCAL}/mysql-data/.restore-completed" ]; then
|
||||||
echo "✅ Database already restored - skipping import"
|
echo "✅ Database already restored - skipping import"
|
||||||
@@ -31,10 +47,25 @@ echo "📥 Found database files in $IMPORT_DIR"
|
|||||||
echo "📂 Copying to backup system for import..."
|
echo "📂 Copying to backup system for import..."
|
||||||
|
|
||||||
# Ensure backup directory exists
|
# 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
|
# 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
|
[ -f "$file" ] || continue
|
||||||
|
|
||||||
filename=$(basename "$file")
|
filename=$(basename "$file")
|
||||||
@@ -62,7 +93,106 @@ for file in "$IMPORT_DIR"/*.sql "$IMPORT_DIR"/*.sql.gz; do
|
|||||||
|
|
||||||
echo "📋 Copying $filename → $target_name"
|
echo "📋 Copying $filename → $target_name"
|
||||||
cp "$file" "$target_path"
|
cp "$file" "$target_path"
|
||||||
|
copied_sql=$((copied_sql + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "✅ Database files copied to backup system"
|
stage_backup_directory(){
|
||||||
echo "💡 Files will be automatically imported during deployment"
|
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
|
||||||
|
|||||||
@@ -128,6 +128,13 @@ resolve_project_image(){
|
|||||||
echo "${project_name}:${tag}"
|
echo "${project_name}:${tag}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_project_local_image(){
|
||||||
|
local image="$1"
|
||||||
|
local project_name
|
||||||
|
project_name="$(resolve_project_name)"
|
||||||
|
[[ "$image" == "${project_name}:"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
canonical_path(){
|
canonical_path(){
|
||||||
local path="$1"
|
local path="$1"
|
||||||
if command -v realpath >/dev/null 2>&1; then
|
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
|
if [ "$TARGET_PROFILE" = "modules" ]; then
|
||||||
# Check if source image exists
|
# Check if source image exists
|
||||||
if ! docker image inspect "$TARGET_WORLDSERVER_IMAGE_MODULES" >/dev/null 2>&1; then
|
if ! docker image inspect "$TARGET_WORLDSERVER_IMAGE_MODULES" >/dev/null 2>&1; then
|
||||||
echo "📦 Modules image $TARGET_WORLDSERVER_IMAGE_MODULES not found - rebuild needed"
|
if is_project_local_image "$TARGET_WORLDSERVER_IMAGE_MODULES"; then
|
||||||
REBUILD_NEEDED=1
|
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
|
elif [ -f "$SENTINEL_FILE" ]; then
|
||||||
echo "🔄 Modules changed since last build - rebuild needed"
|
echo "🔄 Modules changed since last build - rebuild needed"
|
||||||
REBUILD_NEEDED=1
|
REBUILD_NEEDED=1
|
||||||
|
|||||||
Reference in New Issue
Block a user