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

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