mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-13 03:32:28 -04:00
fix(waypoints): Display configuration and client refresh
- Fix waypoint markers showing as human models in 11.2.5 client - Use Elven Wisp (displayId 1824) which renders correctly - Add runtime display config via Lua shared data (no recompile needed) - Add client refresh (DestroyForNearbyPlayers + UpdateObjectVisibilityOnCreate) - Graceful MySQL error handling (no crash on bad MCP queries) - Fix displayId arg parsing in VisualizeWaypointPath - Add documentation for display IDs and configuration
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
# Waypoint Display Configuration
|
||||
|
||||
## Overview
|
||||
|
||||
Waypoint markers are visual indicators spawned at each node of a creature's patrol path. They use the `VISUAL_WAYPOINT` creature entry (ID 1) and are only visible to GMs.
|
||||
|
||||
## Display IDs for 11.2.5 Client
|
||||
|
||||
**Working Display IDs:**
|
||||
| ID | Name | Description |
|
||||
|----|------|-------------|
|
||||
| 1824 | Elven Wisp | Blue floating wisp - **recommended for waypoints** |
|
||||
| 169 | Rock Elemental | Small rock creature |
|
||||
| 31366 | Green Circle | Targeting circle - used for spawn markers |
|
||||
|
||||
**Non-Working Display IDs:**
|
||||
| ID | Name | Issue |
|
||||
|----|------|-------|
|
||||
| 17188 | Blue Skull | Shows as human model in 11.2.5 |
|
||||
| 17519 | Red Orb | Shows as human model in 11.2.5 |
|
||||
| 10045 | Wisp | Shows as human model in 11.2.5 |
|
||||
|
||||
## Runtime Configuration via Lua Shared Data
|
||||
|
||||
Display IDs are configurable at runtime without recompiling:
|
||||
|
||||
```lua
|
||||
-- In admin_handlers.lua
|
||||
local DEFAULT_DISPLAYS = {
|
||||
waypoint_marker = 1824, -- Elven Wisp
|
||||
waypoint_highlight = 1824, -- Same, differentiated by scale
|
||||
spawn_marker = 31366, -- Green targeting circle
|
||||
}
|
||||
```
|
||||
|
||||
### Changing via MCP
|
||||
|
||||
```
|
||||
-- Set waypoint marker to rock elemental
|
||||
mcp0_shared_data_write(key="config_display_waypoint_marker", value="169")
|
||||
|
||||
-- Then reload Lua and hide/show waypoints
|
||||
.reload eluna
|
||||
```
|
||||
|
||||
### Pattern for Configurable Values
|
||||
|
||||
```lua
|
||||
local function GetDisplayId(key)
|
||||
local sharedKey = "config_display_" .. key
|
||||
local value = GetSharedData(sharedKey)
|
||||
if value and value ~= "" then
|
||||
local num = tonumber(value)
|
||||
if num then return num end
|
||||
end
|
||||
return DEFAULT_DISPLAYS[key] or 1824
|
||||
end
|
||||
```
|
||||
|
||||
## C++ Client Refresh Pattern
|
||||
|
||||
**Critical:** `SetDisplayId()` alone does NOT update creatures already visible to the client. You must force a refresh:
|
||||
|
||||
```cpp
|
||||
summon->SetDisplayId(displayId, true);
|
||||
summon->SetObjectScale(0.5f);
|
||||
|
||||
// Force client to see the change
|
||||
summon->DestroyForNearbyPlayers();
|
||||
summon->UpdateObjectVisibilityOnCreate();
|
||||
```
|
||||
|
||||
Without these calls, the client shows cached appearance from when the creature spawned.
|
||||
|
||||
## Files Modified
|
||||
|
||||
### C++ Changes
|
||||
- `src/server/game/Movement/Waypoints/WaypointManager.cpp`
|
||||
- Added client refresh after SetDisplayId
|
||||
- Default display: 1824 (Elven Wisp)
|
||||
|
||||
- `src/server/game/LuaEngine/methods/TrinityCore/CreatureMethods.h`
|
||||
- Fixed displayId arg parsing for `VisualizeWaypointPath(player, displayId)`
|
||||
|
||||
- `src/server/database/Database/MySQLConnection.cpp`
|
||||
- Graceful handling of `ER_BAD_FIELD_ERROR`, `ER_NO_SUCH_TABLE`, `ER_PARSE_ERROR`
|
||||
- No longer crashes server on bad MCP queries
|
||||
|
||||
### Lua Changes
|
||||
- `lua_scripts/admin_handlers.lua`
|
||||
- Added `DEFAULT_DISPLAYS` table
|
||||
- Added `GetDisplayId()`, `SetDisplayIdConfig()`, `InitDisplayConfigs()`
|
||||
- AMS handlers: `SET_DISPLAY_CONFIG`, `GET_DISPLAY_CONFIGS`
|
||||
|
||||
### Database Changes
|
||||
- `creature_template_model` for `CreatureID = 1` set to `CreatureDisplayID = 1824`
|
||||
|
||||
## Lessons Learned
|
||||
|
||||
1. **Client version matters** - Display IDs from older WoW versions may not render correctly in modern clients
|
||||
|
||||
2. **Test displays in-game** - Use `.npc add <entry>` to spawn creatures and verify their appearance before using displayIds
|
||||
|
||||
3. **Client caches creature appearance** - Must force refresh with `DestroyForNearbyPlayers()` + `UpdateObjectVisibilityOnCreate()`
|
||||
|
||||
4. **Prefer Lua for config values** - Allows testing without 5+ minute recompiles. Use MCP to change values at runtime.
|
||||
|
||||
5. **Shared data clears on restart** - `InitDisplayConfigs()` re-initializes defaults on server start
|
||||
@@ -592,17 +592,15 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/)
|
||||
case ER_DUP_ENTRY:
|
||||
return false;
|
||||
|
||||
// Outdated table or database structure - terminate core
|
||||
// Outdated table or database structure - log error but don't terminate
|
||||
// (Changed from ABORT to allow recovery from bad external queries like MCP)
|
||||
case ER_BAD_FIELD_ERROR:
|
||||
case ER_NO_SUCH_TABLE:
|
||||
TC_LOG_ERROR("sql.sql", "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders.");
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
ABORT();
|
||||
TC_LOG_ERROR("sql.sql", "Database structure error (bad field or missing table). Query failed but server will continue.");
|
||||
TC_LOG_ERROR("sql.sql", "If this is a schema issue, run sql/updates. If from external query (MCP), fix the query.");
|
||||
return false;
|
||||
case ER_PARSE_ERROR:
|
||||
TC_LOG_ERROR("sql.sql", "Error while parsing SQL. Core fix required.");
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
ABORT();
|
||||
TC_LOG_ERROR("sql.sql", "Error while parsing SQL. Query failed but server will continue.");
|
||||
return false;
|
||||
default:
|
||||
TC_LOG_ERROR("sql.sql", "Unhandled MySQL errno {}. Unexpected behaviour possible.", errNo);
|
||||
|
||||
@@ -1575,12 +1575,16 @@ namespace LuaCreature
|
||||
// Optional player parameter for phase inheritance (arg 2)
|
||||
Player* phaseSource = E->CHECKOBJ<Player>(2, false);
|
||||
|
||||
// Optional display ID parameter (arg 3, or arg 2 if no player provided)
|
||||
// Display ID is always arg 3 when player is provided
|
||||
Optional<uint32> displayId;
|
||||
int displayIdArg = phaseSource ? 3 : 2;
|
||||
if (!lua_isnoneornil(E->L, displayIdArg))
|
||||
if (!lua_isnoneornil(E->L, 3))
|
||||
{
|
||||
displayId = E->CHECKVAL<uint32>(displayIdArg);
|
||||
displayId = E->CHECKVAL<uint32>(3);
|
||||
}
|
||||
else if (!phaseSource && !lua_isnoneornil(E->L, 2) && lua_isnumber(E->L, 2))
|
||||
{
|
||||
// If no player but arg 2 is a number, use it as displayId
|
||||
displayId = E->CHECKVAL<uint32>(2);
|
||||
}
|
||||
|
||||
sWaypointMgr->VisualizePath(creature, path, displayId);
|
||||
|
||||
@@ -237,11 +237,15 @@ void WaypointMgr::VisualizePath(Unit* owner, WaypointPath const* path, Optional<
|
||||
if (!summon)
|
||||
continue;
|
||||
|
||||
if (displayId)
|
||||
{
|
||||
summon->SetDisplayId(*displayId, true);
|
||||
summon->SetObjectScale(0.5f);
|
||||
}
|
||||
// Always set display - use passed displayId or default to Elven Wisp (1824)
|
||||
constexpr uint32 DEFAULT_WAYPOINT_DISPLAY = 1824; // Elven Wisp - works in 11.2.5
|
||||
summon->SetDisplayId(displayId.value_or(DEFAULT_WAYPOINT_DISPLAY), true);
|
||||
summon->SetObjectScale(0.5f);
|
||||
|
||||
// Force client to refresh the creature's appearance
|
||||
// (SetDisplayId alone doesn't update already-spawned creatures on client)
|
||||
summon->DestroyForNearbyPlayers();
|
||||
summon->UpdateObjectVisibilityOnCreate();
|
||||
|
||||
_nodeToVisualWaypointGUIDsMap[pathNodePair] = summon->GetGUID();
|
||||
_visualWaypointGUIDToNodeMap[summon->GetGUID()] = std::pair<WaypointPath const*, WaypointNode const*>(path, &node);
|
||||
|
||||
Reference in New Issue
Block a user