mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-13 03:32:28 -04:00
feat(waypoint-panel): Add waypoint visualization, teleport, and highlighting
- Add split view layout for waypoint panel (list top, details bottom) - Add Teleport button to teleport to selected waypoint with correct orientation - Add waypoint marker highlighting (scales up selected marker) - Add GM button sync on panel show - Fix waypoint panel scrollbar and content visibility issues - Add HighlightWaypointMarker and ClearWaypointMarkerAuras C++ functions - Add TELEPORT_TO_WAYPOINT server handler - Fix creature visual updates requiring client refresh (DestroyForNearbyPlayers) - Add Smallfolk serialization for shared data in admin_handlers
This commit is contained in:
188
araxiaonline/WAYPOINT_DETAILS_IMPLEMENTATION.md
Normal file
188
araxiaonline/WAYPOINT_DETAILS_IMPLEMENTATION.md
Normal file
@@ -0,0 +1,188 @@
|
||||
# Waypoint Detail Panel Implementation
|
||||
|
||||
**Date:** November 30, 2025
|
||||
**Status:** Complete - Ready for Testing
|
||||
**Requires:** Server rebuild (C++ changes)
|
||||
|
||||
## Overview
|
||||
|
||||
Implemented comprehensive waypoint visualization and inspection system allowing admins to:
|
||||
- View all waypoints for a creature path in a clickable list
|
||||
- See detailed information about each waypoint (position, orientation, delay, etc.)
|
||||
- Click waypoints in the list to highlight them in the world
|
||||
- Target waypoint markers in the world to auto-select them in the UI
|
||||
- Keep NPC panel focused while inspecting waypoints
|
||||
|
||||
## Architecture
|
||||
|
||||
### Client-Server Communication
|
||||
|
||||
**New AMS Handlers (Server → Client):**
|
||||
- `GET_WAYPOINT_DETAILS` - Request all nodes for a path
|
||||
- `SELECT_WAYPOINT` - Highlight a specific waypoint
|
||||
- `GET_WAYPOINT_FOR_GUID` - Lookup waypoint from creature GUID
|
||||
|
||||
**New AMS Responses (Client ← Server):**
|
||||
- `WAYPOINT_DETAILS_RESPONSE` - Array of waypoint nodes with full data
|
||||
- `WAYPOINT_SELECTED_RESPONSE` - Confirmation of waypoint selection
|
||||
- `WAYPOINT_FOR_GUID_RESPONSE` - Path/node IDs for a visual waypoint GUID
|
||||
|
||||
### C++ Bindings
|
||||
|
||||
**New WaypointManager Methods:**
|
||||
```cpp
|
||||
bool GetPathAndNodeByVisualGUID(ObjectGuid guid, uint32& outPathId, uint32& outNodeId) const;
|
||||
```
|
||||
|
||||
**New Global Lua Function:**
|
||||
```lua
|
||||
pathId, nodeId = GetWaypointNodeForVisualGUID(guidLow)
|
||||
```
|
||||
|
||||
## UI Components
|
||||
|
||||
### Waypoints Tab Layout
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Waypoint List (Top 50%) │
|
||||
├─────────────────────────────────────┤
|
||||
│ Waypoint Details (Bottom 50%) │
|
||||
│ [Deselect] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**List Features:**
|
||||
- Clickable node entries (Node 1, Node 2, etc.)
|
||||
- Highlighted selected node (green background)
|
||||
- Scrollable for paths with many nodes
|
||||
- Auto-populated when "Show Waypoints" is clicked
|
||||
|
||||
**Detail Panel Features:**
|
||||
- Node ID and detailed information
|
||||
- Position (X, Y, Z coordinates)
|
||||
- Orientation angle
|
||||
- Delay in milliseconds
|
||||
- Move type and action IDs
|
||||
- Deselect button to close detail view
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Panel Locking
|
||||
|
||||
When waypoints are shown:
|
||||
1. `panelLockedToNPC` flag is set to `true`
|
||||
2. NPC panel data remains loaded even when targeting other creatures
|
||||
3. Targeting waypoint markers doesn't unload NPC info
|
||||
4. Flag is cleared when "Hide Waypoints" is clicked
|
||||
|
||||
### Waypoint Target Detection
|
||||
|
||||
When panel is locked and player targets a creature:
|
||||
1. Extract GUID from target
|
||||
2. Send `GET_WAYPOINT_FOR_GUID` to server
|
||||
3. Server looks up path/node IDs using `GetPathAndNodeByVisualGUID`
|
||||
4. Client receives response and auto-selects waypoint in list
|
||||
5. Waypoints tab automatically switches to show detail
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
User clicks "Show Waypoints"
|
||||
↓
|
||||
SHOW_WAYPOINTS sent to server
|
||||
↓
|
||||
Server visualizes path (spawns markers)
|
||||
↓
|
||||
WAYPOINTS_RESPONSE received
|
||||
↓
|
||||
GET_WAYPOINT_DETAILS sent to server
|
||||
↓
|
||||
WAYPOINT_DETAILS_RESPONSE received with all nodes
|
||||
↓
|
||||
Waypoints tab populated with clickable list
|
||||
↓
|
||||
User clicks waypoint in list
|
||||
↓
|
||||
Detail panel shows (split view)
|
||||
↓
|
||||
User targets waypoint marker in world
|
||||
↓
|
||||
GET_WAYPOINT_FOR_GUID sent to server
|
||||
↓
|
||||
WAYPOINT_FOR_GUID_RESPONSE received
|
||||
↓
|
||||
Waypoint auto-selected in list, detail shown
|
||||
```
|
||||
|
||||
## Files Modified
|
||||
|
||||
### C++ (Requires Rebuild)
|
||||
|
||||
**`WaypointManager.h`**
|
||||
- Added `GetPathAndNodeByVisualGUID()` declaration
|
||||
|
||||
**`WaypointManager.cpp`**
|
||||
- Implemented `GetPathAndNodeByVisualGUID()` to lookup path/node from visual creature GUID
|
||||
|
||||
**`GlobalMethods.h`**
|
||||
- Added `GetWaypointNodeForVisualGUID()` Lua binding
|
||||
- Registered in method table
|
||||
|
||||
### Server Lua
|
||||
|
||||
**`admin_handlers.lua`**
|
||||
- Added `GET_WAYPOINT_DETAILS` handler - returns array of waypoint nodes
|
||||
- Added `SELECT_WAYPOINT` handler - highlights waypoint in world
|
||||
- Added `GET_WAYPOINT_FOR_GUID` handler - looks up path/node from creature GUID
|
||||
|
||||
### Client Lua
|
||||
|
||||
**`NPCInfoPanel.lua`**
|
||||
- Implemented waypoint list UI with scrollable frame
|
||||
- Implemented waypoint detail panel with split view
|
||||
- Added `UpdateWaypointList()` and `UpdateWaypointDetail()` functions
|
||||
- Added `RequestWaypointDetails()` to fetch data from server
|
||||
- Added `WAYPOINT_DETAILS_RESPONSE` handler
|
||||
- Added `WAYPOINT_FOR_GUID_RESPONSE` handler
|
||||
- Integrated panel locking when showing waypoints
|
||||
- Enhanced `PLAYER_TARGET_CHANGED` to detect waypoint markers
|
||||
- Added waypoint detail request when showing waypoints
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Server compiles without errors
|
||||
- [ ] Server loads admin_handlers.lua successfully
|
||||
- [ ] Target NPC with waypoints
|
||||
- [ ] Click "Show Waypoints" button
|
||||
- [ ] Waypoints tab populates with node list
|
||||
- [ ] Click a waypoint in the list
|
||||
- [ ] Detail panel shows with waypoint information
|
||||
- [ ] Target a waypoint marker in the world
|
||||
- [ ] Waypoint auto-selects in the list
|
||||
- [ ] NPC panel data remains loaded during waypoint inspection
|
||||
- [ ] Click "Hide Waypoints" to deactivate
|
||||
- [ ] Panel lock is cleared
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- Visual spell effects for waypoint highlighting not yet implemented (placeholder)
|
||||
- Waypoint modification/creation not yet implemented
|
||||
- No persistence of waypoint data between sessions (by design)
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. Add visual spell effects to highlight selected waypoints
|
||||
2. Implement waypoint creation/editing UI
|
||||
3. Add waypoint deletion functionality
|
||||
4. Persist waypoint inspection state in SavedVariables
|
||||
5. Add waypoint search/filter functionality
|
||||
6. Implement waypoint path visualization (lines between nodes)
|
||||
|
||||
## Notes for Developer
|
||||
|
||||
- The `panelLockedToNPC` flag is crucial for keeping NPC data loaded
|
||||
- GUID extraction from `UnitGUID()` uses pattern matching - ensure it matches creature GUID format
|
||||
- Waypoint nodes are 1-indexed in the UI but use their actual IDs from the database
|
||||
- The split view resizes dynamically - ensure scroll frames handle height changes
|
||||
- Always call `UpdateWaypointList()` after `UpdateWaypointDetail()` to refresh highlighting
|
||||
@@ -91,6 +91,24 @@ local function UpdateGMButton()
|
||||
end
|
||||
end
|
||||
|
||||
-- Function to sync GM state from server
|
||||
local function SyncGMState()
|
||||
if not AMS then return end
|
||||
|
||||
-- Request current GM state from server
|
||||
AMS.Send("GET_PLAYER_DATA", {})
|
||||
end
|
||||
|
||||
-- Handler for player data response
|
||||
if AMS then
|
||||
AMS.RegisterHandler("PLAYER_DATA_RESPONSE", function(data)
|
||||
if data and data.success and data.isGM ~= nil then
|
||||
_G.AraxiaTrinityAdminGMMode = data.isGM
|
||||
UpdateGMButton()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
gmButton:SetScript("OnClick", function()
|
||||
-- Toggle GM mode
|
||||
_G.AraxiaTrinityAdminGMMode = not _G.AraxiaTrinityAdminGMMode
|
||||
@@ -117,6 +135,14 @@ end)
|
||||
|
||||
UpdateGMButton()
|
||||
|
||||
-- Sync GM state on panel show
|
||||
npcPanel:HookScript("OnShow", function()
|
||||
SyncGMState()
|
||||
end)
|
||||
|
||||
-- Initial sync
|
||||
SyncGMState()
|
||||
|
||||
-- ============================================================================
|
||||
-- Tab Buttons
|
||||
-- ============================================================================
|
||||
@@ -385,17 +411,260 @@ local waypointContent = CreateFrame("Frame", nil, rightContentFrame)
|
||||
waypointContent:SetAllPoints(rightContentFrame)
|
||||
waypointContent:Hide()
|
||||
|
||||
local waypointTitle = waypointContent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
waypointTitle:SetPoint("TOP", waypointContent, "TOP", 0, -8)
|
||||
waypointTitle:SetText("Waypoint Editor")
|
||||
-- Waypoint data storage
|
||||
local currentWaypointPathId = nil
|
||||
local currentWaypointNodes = {}
|
||||
local selectedWaypointNodeId = nil
|
||||
local panelLockedToNPC = false -- Lock panel to NPC when showing waypoints
|
||||
|
||||
-- Waypoint info text area
|
||||
local waypointInfoText = waypointContent:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
||||
waypointInfoText:SetPoint("TOPLEFT", waypointContent, "TOPLEFT", 12, -35)
|
||||
waypointInfoText:SetPoint("TOPRIGHT", waypointContent, "TOPRIGHT", -12, -35)
|
||||
waypointInfoText:SetJustifyH("LEFT")
|
||||
waypointInfoText:SetJustifyV("TOP")
|
||||
waypointInfoText:SetText("|cFF888888No creature selected.|r\n\nSelect a creature to view waypoint options.")
|
||||
-- Waypoint list (top half - 60% of height)
|
||||
local waypointListContainer = CreateFrame("Frame", nil, waypointContent)
|
||||
waypointListContainer:SetPoint("TOPLEFT", waypointContent, "TOPLEFT", 8, -8)
|
||||
waypointListContainer:SetPoint("RIGHT", waypointContent, "RIGHT", -8, 0)
|
||||
waypointListContainer:SetHeight(200)
|
||||
|
||||
local waypointListScroll = CreateFrame("ScrollFrame", nil, waypointListContainer, "UIPanelScrollFrameTemplate")
|
||||
waypointListScroll:SetPoint("TOPLEFT", waypointListContainer, "TOPLEFT", 0, 0)
|
||||
waypointListScroll:SetPoint("BOTTOMRIGHT", waypointListContainer, "BOTTOMRIGHT", -22, 0)
|
||||
|
||||
local waypointListChild = CreateFrame("Frame", nil, waypointListScroll)
|
||||
waypointListChild:SetWidth(280)
|
||||
waypointListChild:SetHeight(100)
|
||||
waypointListScroll:SetScrollChild(waypointListChild)
|
||||
|
||||
-- Divider line between list and detail
|
||||
local waypointDivider = waypointContent:CreateTexture(nil, "ARTWORK")
|
||||
waypointDivider:SetHeight(1)
|
||||
waypointDivider:SetPoint("TOPLEFT", waypointListContainer, "BOTTOMLEFT", 0, -4)
|
||||
waypointDivider:SetPoint("RIGHT", waypointContent, "RIGHT", -8, 0)
|
||||
waypointDivider:SetColorTexture(0.4, 0.4, 0.4, 0.8)
|
||||
|
||||
-- Detail panel (bottom half - always visible when waypoint selected)
|
||||
local waypointDetailPanel = CreateFrame("Frame", nil, waypointContent, "BackdropTemplate")
|
||||
waypointDetailPanel:SetPoint("TOPLEFT", waypointDivider, "BOTTOMLEFT", 0, -4)
|
||||
waypointDetailPanel:SetPoint("BOTTOMRIGHT", waypointContent, "BOTTOMRIGHT", -8, 8)
|
||||
waypointDetailPanel:SetBackdrop({
|
||||
bgFile = "Interface/Tooltips/UI-Tooltip-Background",
|
||||
edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 12,
|
||||
insets = { left = 3, right = 3, top = 3, bottom = 3 }
|
||||
})
|
||||
waypointDetailPanel:SetBackdropColor(0.1, 0.1, 0.1, 0.8)
|
||||
waypointDetailPanel:SetBackdropBorderColor(0.3, 0.3, 0.3, 1)
|
||||
|
||||
-- Detail panel content
|
||||
local detailTitle = waypointDetailPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
detailTitle:SetPoint("TOPLEFT", waypointDetailPanel, "TOPLEFT", 10, -8)
|
||||
detailTitle:SetText("Select a waypoint above")
|
||||
|
||||
-- Detail info text
|
||||
local detailInfoText = waypointDetailPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
||||
detailInfoText:SetPoint("TOPLEFT", waypointDetailPanel, "TOPLEFT", 10, -26)
|
||||
detailInfoText:SetPoint("RIGHT", waypointDetailPanel, "RIGHT", -80, 0)
|
||||
detailInfoText:SetJustifyH("LEFT")
|
||||
detailInfoText:SetJustifyV("TOP")
|
||||
detailInfoText:SetText("")
|
||||
|
||||
-- Action buttons container (right side of detail panel)
|
||||
local detailActionsContainer = CreateFrame("Frame", nil, waypointDetailPanel)
|
||||
detailActionsContainer:SetPoint("TOPRIGHT", waypointDetailPanel, "TOPRIGHT", -8, -8)
|
||||
detailActionsContainer:SetSize(65, 100)
|
||||
|
||||
-- Teleport button
|
||||
local teleportBtn = CreateFrame("Button", nil, detailActionsContainer, "UIPanelButtonTemplate")
|
||||
teleportBtn:SetSize(60, 22)
|
||||
teleportBtn:SetPoint("TOP", detailActionsContainer, "TOP", 0, 0)
|
||||
teleportBtn:SetText("Teleport")
|
||||
teleportBtn:Disable()
|
||||
|
||||
teleportBtn:SetScript("OnClick", function()
|
||||
if not selectedWaypointNodeId or not currentWaypointPathId then return end
|
||||
|
||||
-- Find the selected node data
|
||||
local node = nil
|
||||
for _, n in ipairs(currentWaypointNodes) do
|
||||
if n.id == selectedWaypointNodeId then
|
||||
node = n
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if node and AMS then
|
||||
print("|cFF00FF00[ATA]|r Teleporting to waypoint " .. node.id)
|
||||
AMS.Send("TELEPORT_TO_WAYPOINT", {
|
||||
x = node.x,
|
||||
y = node.y,
|
||||
z = node.z,
|
||||
orientation = node.orientation
|
||||
})
|
||||
end
|
||||
end)
|
||||
|
||||
teleportBtn:SetScript("OnEnter", function(self)
|
||||
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
|
||||
GameTooltip:AddLine("Teleport to Waypoint", 1, 1, 1)
|
||||
GameTooltip:AddLine("Teleports you to this waypoint location", 0.7, 0.7, 0.7)
|
||||
GameTooltip:Show()
|
||||
end)
|
||||
|
||||
teleportBtn:SetScript("OnLeave", function()
|
||||
GameTooltip:Hide()
|
||||
end)
|
||||
|
||||
-- Buttons to hold waypoint node entries
|
||||
local waypointNodeButtons = {}
|
||||
|
||||
-- Forward declare functions
|
||||
local UpdateWaypointList
|
||||
local UpdateWaypointDetail
|
||||
|
||||
-- Function to update waypoint detail display
|
||||
UpdateWaypointDetail = function()
|
||||
if not selectedWaypointNodeId then
|
||||
detailTitle:SetText("Select a waypoint above")
|
||||
detailInfoText:SetText("")
|
||||
teleportBtn:Disable()
|
||||
return
|
||||
end
|
||||
|
||||
local node = nil
|
||||
for _, n in ipairs(currentWaypointNodes) do
|
||||
if n.id == selectedWaypointNodeId then
|
||||
node = n
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not node then
|
||||
teleportBtn:Disable()
|
||||
return
|
||||
end
|
||||
|
||||
detailTitle:SetText("Node " .. node.id)
|
||||
|
||||
local detailStr = string.format(
|
||||
"|cFFFFD700Position:|r %.1f, %.1f, %.1f\n" ..
|
||||
"|cFFFFD700Orientation:|r %.2f\n" ..
|
||||
"|cFFFFD700Delay:|r %dms\n" ..
|
||||
"|cFFFFD700Move Type:|r %d",
|
||||
node.x, node.y, node.z,
|
||||
node.orientation,
|
||||
node.delay,
|
||||
node.moveType
|
||||
)
|
||||
|
||||
detailInfoText:SetText(detailStr)
|
||||
teleportBtn:Enable()
|
||||
end
|
||||
|
||||
-- Function to update waypoint list display
|
||||
UpdateWaypointList = function()
|
||||
print("|cFF00FF00[ATA]|r UpdateWaypointList called: pathId=" .. (currentWaypointPathId or 0) .. ", nodes=" .. #currentWaypointNodes)
|
||||
|
||||
-- Hide all existing buttons
|
||||
for _, btn in ipairs(waypointNodeButtons) do
|
||||
btn:Hide()
|
||||
end
|
||||
|
||||
if not currentWaypointPathId or #currentWaypointNodes == 0 then
|
||||
-- Show empty message
|
||||
print("|cFFFF0000[ATA]|r No waypoint data to display")
|
||||
waypointListChild:SetHeight(40)
|
||||
return
|
||||
end
|
||||
|
||||
-- Create/update buttons for each node
|
||||
for i, node in ipairs(currentWaypointNodes) do
|
||||
local btn = waypointNodeButtons[i]
|
||||
if not btn then
|
||||
btn = CreateFrame("Button", nil, waypointListChild)
|
||||
btn:SetHeight(24)
|
||||
btn:EnableMouse(true)
|
||||
btn:RegisterForClicks("AnyUp")
|
||||
btn:SetHighlightTexture("Interface/QuestFrame/UI-QuestTitleHighlight", "ADD")
|
||||
|
||||
btn.bg = btn:CreateTexture(nil, "BACKGROUND")
|
||||
btn.bg:SetAllPoints()
|
||||
btn.bg:SetColorTexture(0.2, 0.2, 0.2, 0.5)
|
||||
|
||||
btn.text = btn:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
btn.text:SetPoint("LEFT", btn, "LEFT", 8, 0)
|
||||
btn.text:SetJustifyH("LEFT")
|
||||
|
||||
btn:SetScript("OnClick", function(self)
|
||||
local clickedNode = self.nodeData
|
||||
if not clickedNode then return end
|
||||
|
||||
selectedWaypointNodeId = clickedNode.id
|
||||
UpdateWaypointDetail()
|
||||
UpdateWaypointList() -- Refresh to show selection highlight
|
||||
|
||||
-- Send SELECT_WAYPOINT to server to highlight in world
|
||||
if AMS and currentWaypointPathId then
|
||||
print("|cFF00FF00[ATA]|r Sending SELECT_WAYPOINT: path=" .. currentWaypointPathId .. " node=" .. clickedNode.id)
|
||||
AMS.Send("SELECT_WAYPOINT", { pathId = currentWaypointPathId, nodeId = clickedNode.id })
|
||||
end
|
||||
end)
|
||||
|
||||
waypointNodeButtons[i] = btn
|
||||
end
|
||||
|
||||
btn.nodeData = node
|
||||
btn:ClearAllPoints()
|
||||
btn:SetPoint("TOPLEFT", waypointListChild, "TOPLEFT", 0, -((i-1) * 26))
|
||||
btn:SetPoint("RIGHT", waypointListChild, "RIGHT", 0, 0)
|
||||
|
||||
-- Highlight selected node
|
||||
if node.id == selectedWaypointNodeId then
|
||||
btn.bg:SetColorTexture(0.3, 0.5, 0.3, 0.7)
|
||||
btn.text:SetTextColor(1, 1, 1, 1)
|
||||
else
|
||||
btn.bg:SetColorTexture(0.2, 0.2, 0.2, 0.5)
|
||||
btn.text:SetTextColor(1, 0.82, 0, 1)
|
||||
end
|
||||
|
||||
btn.text:SetText("Node " .. node.id)
|
||||
btn:Show()
|
||||
end
|
||||
|
||||
-- Update scroll child size to fit all buttons
|
||||
local totalHeight = #currentWaypointNodes * 26
|
||||
waypointListChild:SetHeight(totalHeight)
|
||||
print("|cFF00FF00[ATA]|r Set scroll child height to " .. totalHeight)
|
||||
end
|
||||
|
||||
-- Deselect button no longer needed in split view layout
|
||||
-- (kept for code compatibility but hidden)
|
||||
|
||||
-- Request waypoint details from server
|
||||
local function RequestWaypointDetails(pathId)
|
||||
if not AMS then return end
|
||||
|
||||
currentWaypointPathId = pathId
|
||||
currentWaypointNodes = {}
|
||||
selectedWaypointNodeId = nil
|
||||
|
||||
AMS.Send("GET_WAYPOINT_DETAILS", { pathId = pathId })
|
||||
end
|
||||
|
||||
-- Handler for waypoint details response
|
||||
if AMS then
|
||||
AMS.RegisterHandler("WAYPOINT_DETAILS_RESPONSE", function(data)
|
||||
if not data or not data.success then
|
||||
print("|cFFFF0000[ATA]|r Failed to get waypoint details: " .. (data.error or "Unknown error"))
|
||||
return
|
||||
end
|
||||
|
||||
print("|cFF00FF00[ATA]|r Received waypoint details: pathId=" .. (data.pathId or 0) .. ", nodes=" .. #(data.nodes or {}))
|
||||
|
||||
currentWaypointPathId = data.pathId
|
||||
currentWaypointNodes = data.nodes or {}
|
||||
selectedWaypointNodeId = nil
|
||||
|
||||
print("|cFF00FF00[ATA]|r Updating waypoint list with " .. #currentWaypointNodes .. " nodes")
|
||||
UpdateWaypointList()
|
||||
end)
|
||||
end
|
||||
|
||||
-- Waypoint action buttons container
|
||||
local waypointButtonContainer = CreateFrame("Frame", nil, waypointContent)
|
||||
@@ -1053,6 +1322,12 @@ function npcPanel:Update(requestServerData, forceRefresh)
|
||||
-- Enable waypoint button if creature has a waypoint path
|
||||
if data and data.movement and data.movement.waypointPath then
|
||||
waypointButton:Enable()
|
||||
|
||||
-- Auto-load waypoint details for the Waypoints tab
|
||||
local pathId = data.movement.waypointPath.pathId
|
||||
if pathId and pathId > 0 then
|
||||
RequestWaypointDetails(pathId)
|
||||
end
|
||||
else
|
||||
waypointButton:Disable()
|
||||
end
|
||||
@@ -1072,40 +1347,8 @@ function npcPanel:Update(requestServerData, forceRefresh)
|
||||
npcModel:SetModel("interface/buttons/talktomequestionmark.m2")
|
||||
end
|
||||
|
||||
-- Update Waypoint tab content
|
||||
if npcData then
|
||||
local waypointLines = {}
|
||||
table.insert(waypointLines, "|cFFFFD700" .. (npcData.name or "Unknown") .. "|r")
|
||||
table.insert(waypointLines, "Entry: " .. (npcData.npcID or "?"))
|
||||
table.insert(waypointLines, "")
|
||||
|
||||
if serverData and serverData.movement and serverData.movement.waypointPath then
|
||||
local wp = serverData.movement.waypointPath
|
||||
local pathId = wp.pathId or 0
|
||||
if pathId > 0 then
|
||||
table.insert(waypointLines, "|cFF00FF00Has Waypoint Path|r")
|
||||
table.insert(waypointLines, "Path ID: " .. pathId)
|
||||
table.insert(waypointLines, "Nodes: " .. (wp.nodeCount or 0))
|
||||
table.insert(waypointLines, "")
|
||||
table.insert(waypointLines, "|cFF888888Use the 'Show Waypoints' button|r")
|
||||
table.insert(waypointLines, "|cFF888888to visualize the path in 3D.|r")
|
||||
else
|
||||
table.insert(waypointLines, "|cFFFF8800No Waypoint Path|r")
|
||||
table.insert(waypointLines, "")
|
||||
table.insert(waypointLines, "|cFF888888This creature does not have|r")
|
||||
table.insert(waypointLines, "|cFF888888a defined waypoint path.|r")
|
||||
end
|
||||
elseif isLoadingServerData then
|
||||
table.insert(waypointLines, "|cFF888888Loading waypoint data...|r")
|
||||
else
|
||||
table.insert(waypointLines, "|cFF888888Server data not loaded.|r")
|
||||
table.insert(waypointLines, "|cFF888888Click Refresh to load.|r")
|
||||
end
|
||||
|
||||
waypointInfoText:SetText(table.concat(waypointLines, "\n"))
|
||||
else
|
||||
waypointInfoText:SetText("|cFF888888No creature selected.|r\n\nSelect a creature to view waypoint options.")
|
||||
end
|
||||
-- Waypoint tab is now handled by the new list/detail UI
|
||||
-- No additional update needed here
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
@@ -1163,12 +1406,14 @@ waypointButton:SetScript("OnClick", function()
|
||||
print("|cFF00FF00[ATA]|r Hiding waypoint markers...")
|
||||
waypointButton:SetText("Working...")
|
||||
waypointButton:Disable()
|
||||
panelLockedToNPC = false
|
||||
AMS.Send("HIDE_WAYPOINTS", { guid = npcData.guid })
|
||||
else
|
||||
-- Show waypoints
|
||||
-- Show waypoints and lock panel to this NPC
|
||||
print("|cFF00FF00[ATA]|r Spawning waypoint markers in 3D space...")
|
||||
waypointButton:SetText("Working...")
|
||||
waypointButton:Disable()
|
||||
panelLockedToNPC = true -- Lock panel to prevent target changes from unloading NPC data
|
||||
AMS.Send("SHOW_WAYPOINTS", { guid = npcData.guid })
|
||||
end
|
||||
end)
|
||||
@@ -1198,6 +1443,11 @@ local function InitWaypointHandler()
|
||||
nodeCount = pendingWaypointRequest.nodeCount
|
||||
}
|
||||
print("|cFF00FF00[ATA]|r Tracking path for: " .. pendingWaypointRequest.name)
|
||||
|
||||
-- Request waypoint details for the Waypoints tab
|
||||
if data.pathId then
|
||||
RequestWaypointDetails(data.pathId)
|
||||
end
|
||||
elseif pendingWaypointRequest.action == "hide" then
|
||||
-- Remove from tracked paths
|
||||
if trackedPaths[pendingWaypointRequest.guid] then
|
||||
@@ -1223,6 +1473,19 @@ local updateFrame = CreateFrame("Frame")
|
||||
updateFrame:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||
updateFrame:SetScript("OnEvent", function()
|
||||
if npcPanel:IsShown() then
|
||||
-- Check if targeting a waypoint marker (visual waypoint creature)
|
||||
local targetGUID = UnitGUID("target")
|
||||
if targetGUID and panelLockedToNPC then
|
||||
-- Panel is locked to an NPC, check if we targeted a waypoint marker
|
||||
local guidLow = tonumber(string.match(targetGUID, "Creature%-0%-0%-0%-(%d+)")) or 0
|
||||
if guidLow > 0 and AMS then
|
||||
-- Request waypoint info for this GUID
|
||||
AMS.Send("GET_WAYPOINT_FOR_GUID", { guid = guidLow })
|
||||
return -- Don't update NPC panel
|
||||
end
|
||||
end
|
||||
|
||||
-- Normal NPC targeting behavior
|
||||
serverData = nil
|
||||
isLoadingServerData = false
|
||||
|
||||
@@ -1240,10 +1503,40 @@ updateFrame:SetScript("OnEvent", function()
|
||||
currentTargetGUID = npcData and npcData.guid or nil
|
||||
end
|
||||
waypointButton:Disable() -- Will be enabled by Update() if creature has waypoints
|
||||
npcPanel:Update(true)
|
||||
npcPanel:Update(true, true) -- Request server data and force refresh from cache
|
||||
end
|
||||
end)
|
||||
|
||||
-- Handler for waypoint selection response (with visual highlighting)
|
||||
if AMS then
|
||||
AMS.RegisterHandler("WAYPOINT_SELECTED_RESPONSE", function(data)
|
||||
if data and data.success then
|
||||
print("|cFF00FF00[ATA]|r Waypoint selected: node " .. data.nodeId .. " at " .. data.x .. ", " .. data.y .. ", " .. data.z)
|
||||
|
||||
-- The waypoint is already visualized as a creature marker in the world
|
||||
-- The highlighting happens through the UI selection (green background on the button)
|
||||
-- Future: Could add a spell effect or other visual indicator here
|
||||
end
|
||||
end)
|
||||
|
||||
AMS.RegisterHandler("WAYPOINT_FOR_GUID_RESPONSE", function(data)
|
||||
if data and data.success then
|
||||
-- Select this waypoint in the Waypoints tab
|
||||
selectedWaypointNodeId = data.nodeId
|
||||
currentWaypointPathId = data.pathId
|
||||
|
||||
-- Switch to Waypoints tab to show the detail
|
||||
ShowRightTab("Waypoints")
|
||||
|
||||
-- Update the display
|
||||
UpdateWaypointList()
|
||||
UpdateWaypointDetail()
|
||||
|
||||
print("|cFF00FF00[ATA]|r Selected waypoint node " .. data.nodeId)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- Initialization
|
||||
-- ============================================================================
|
||||
|
||||
@@ -13,6 +13,9 @@ if not AMS then
|
||||
return
|
||||
end
|
||||
|
||||
-- Load Smallfolk for serialization (used by shared data)
|
||||
local Smallfolk = require("smallfolk")
|
||||
|
||||
-- ============================================================================
|
||||
-- Helper Functions
|
||||
-- ============================================================================
|
||||
@@ -371,6 +374,159 @@ AMS.RegisterHandler("CLEAR_ALL_WAYPOINT_MARKERS", function(player, data)
|
||||
AMS.Send(player, "CLEAR_WAYPOINTS_RESPONSE", { success = true })
|
||||
end)
|
||||
|
||||
-- Get detailed waypoint data for a path
|
||||
AMS.RegisterHandler("GET_WAYPOINT_DETAILS", function(player, data)
|
||||
if not data or not data.pathId then
|
||||
print("[Admin Handlers] GET_WAYPOINT_DETAILS: No pathId provided")
|
||||
AMS.Send(player, "WAYPOINT_DETAILS_RESPONSE", { success = false, error = "No pathId" })
|
||||
return
|
||||
end
|
||||
|
||||
local pathId = data.pathId
|
||||
print("[Admin Handlers] GET_WAYPOINT_DETAILS: Fetching details for path " .. pathId)
|
||||
|
||||
-- Get the waypoint path using the C++ binding
|
||||
local path = GetWaypointPath(pathId)
|
||||
if not path or not path.nodes then
|
||||
print("[Admin Handlers] GET_WAYPOINT_DETAILS: Path not found")
|
||||
AMS.Send(player, "WAYPOINT_DETAILS_RESPONSE", { success = false, error = "Path not found" })
|
||||
return
|
||||
end
|
||||
|
||||
print("[Admin Handlers] GET_WAYPOINT_DETAILS: Sending " .. #path.nodes .. " nodes")
|
||||
AMS.Send(player, "WAYPOINT_DETAILS_RESPONSE", {
|
||||
success = true,
|
||||
pathId = pathId,
|
||||
nodes = path.nodes
|
||||
})
|
||||
end)
|
||||
|
||||
-- Highlight a specific waypoint in the world
|
||||
AMS.RegisterHandler("SELECT_WAYPOINT", function(player, data)
|
||||
if not data or not data.pathId or not data.nodeId then
|
||||
print("[Admin Handlers] SELECT_WAYPOINT: Missing pathId or nodeId")
|
||||
return
|
||||
end
|
||||
|
||||
local pathId = data.pathId
|
||||
local nodeId = data.nodeId
|
||||
print("[Admin Handlers] SELECT_WAYPOINT: Highlighting path " .. pathId .. " node " .. nodeId)
|
||||
|
||||
-- Get the waypoint path
|
||||
local path = GetWaypointPath(pathId)
|
||||
if not path or not path.nodes then
|
||||
print("[Admin Handlers] SELECT_WAYPOINT: Path not found")
|
||||
return
|
||||
end
|
||||
|
||||
-- Find the node
|
||||
local node = nil
|
||||
for _, n in ipairs(path.nodes) do
|
||||
if n.id == nodeId then
|
||||
node = n
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not node then
|
||||
print("[Admin Handlers] SELECT_WAYPOINT: Node not found")
|
||||
return
|
||||
end
|
||||
|
||||
-- Notify player of selection
|
||||
print("[Admin Handlers] SELECT_WAYPOINT: Node " .. nodeId .. " at " .. node.x .. ", " .. node.y .. ", " .. node.z)
|
||||
|
||||
-- Clear previous highlight if any (stored in shared data per player)
|
||||
local playerKey = "waypoint_highlight_" .. tostring(player:GetGUIDLow())
|
||||
local prevData = GetSharedData(playerKey)
|
||||
if prevData then
|
||||
local prev = Smallfolk.loads(prevData)
|
||||
if prev and prev.pathId and prev.nodeId then
|
||||
ClearWaypointMarkerAuras(player, prev.pathId, prev.nodeId)
|
||||
end
|
||||
end
|
||||
|
||||
-- Highlight the new waypoint marker by changing its display
|
||||
-- Display IDs to try: 17519 (red orb), 17188 (blue orb), 26754 (green flame), 11686 (purple crystal)
|
||||
local highlightDisplayId = 17519 -- Red glowing orb - very visible
|
||||
local success = HighlightWaypointMarker(player, pathId, nodeId, highlightDisplayId)
|
||||
|
||||
if success then
|
||||
print("[Admin Handlers] SELECT_WAYPOINT: Highlighted marker with displayId " .. highlightDisplayId)
|
||||
-- Store current selection for later cleanup
|
||||
SetSharedData(playerKey, Smallfolk.dumps({ pathId = pathId, nodeId = nodeId }))
|
||||
else
|
||||
print("[Admin Handlers] SELECT_WAYPOINT: Could not find marker to highlight")
|
||||
end
|
||||
|
||||
player:SendBroadcastMessage("Waypoint " .. nodeId .. " selected")
|
||||
|
||||
-- Send response with node position
|
||||
AMS.Send(player, "WAYPOINT_SELECTED_RESPONSE", {
|
||||
success = true,
|
||||
pathId = pathId,
|
||||
nodeId = nodeId,
|
||||
x = node.x,
|
||||
y = node.y,
|
||||
z = node.z
|
||||
})
|
||||
end)
|
||||
|
||||
-- Get waypoint node info from a visual waypoint GUID (when targeting a waypoint marker)
|
||||
AMS.RegisterHandler("GET_WAYPOINT_FOR_GUID", function(player, data)
|
||||
if not data or not data.guid then
|
||||
print("[Admin Handlers] GET_WAYPOINT_FOR_GUID: No GUID provided")
|
||||
return
|
||||
end
|
||||
|
||||
local pathId, nodeId = GetWaypointNodeForVisualGUID(data.guid)
|
||||
if pathId == 0 or nodeId == 0 then
|
||||
print("[Admin Handlers] GET_WAYPOINT_FOR_GUID: GUID not found in waypoint system")
|
||||
AMS.Send(player, "WAYPOINT_FOR_GUID_RESPONSE", { success = false })
|
||||
return
|
||||
end
|
||||
|
||||
print("[Admin Handlers] GET_WAYPOINT_FOR_GUID: Found path " .. pathId .. " node " .. nodeId)
|
||||
AMS.Send(player, "WAYPOINT_FOR_GUID_RESPONSE", {
|
||||
success = true,
|
||||
pathId = pathId,
|
||||
nodeId = nodeId
|
||||
})
|
||||
end)
|
||||
|
||||
-- Get player data (GM state, etc.)
|
||||
AMS.RegisterHandler("GET_PLAYER_DATA", function(player, data)
|
||||
if not player then
|
||||
return
|
||||
end
|
||||
|
||||
-- Send player data including GM state (IsGM is the correct Eluna method)
|
||||
AMS.Send(player, "PLAYER_DATA_RESPONSE", {
|
||||
success = true,
|
||||
isGM = player:IsGM()
|
||||
})
|
||||
end)
|
||||
|
||||
-- Teleport player to a waypoint location
|
||||
AMS.RegisterHandler("TELEPORT_TO_WAYPOINT", function(player, data)
|
||||
if not data or not data.x or not data.y or not data.z then
|
||||
print("[Admin Handlers] TELEPORT_TO_WAYPOINT: Missing coordinates")
|
||||
return
|
||||
end
|
||||
|
||||
local x = data.x
|
||||
local y = data.y
|
||||
local z = data.z
|
||||
local orientation = data.orientation or 0
|
||||
|
||||
print("[Admin Handlers] TELEPORT_TO_WAYPOINT: Teleporting to " .. x .. ", " .. y .. ", " .. z .. " facing " .. orientation)
|
||||
|
||||
-- Teleport player to the waypoint location with correct orientation
|
||||
player:Teleport(player:GetMapId(), x, y, z, orientation)
|
||||
|
||||
player:SendBroadcastMessage("Teleported to waypoint")
|
||||
end)
|
||||
|
||||
-- ============================================================================
|
||||
-- Initialization
|
||||
-- ============================================================================
|
||||
@@ -382,3 +538,8 @@ print(" - SHOW_WAYPOINTS")
|
||||
print(" - HIDE_WAYPOINTS")
|
||||
print(" - HIDE_WAYPOINTS_BY_GUID")
|
||||
print(" - CLEAR_ALL_WAYPOINT_MARKERS")
|
||||
print(" - GET_WAYPOINT_DETAILS")
|
||||
print(" - SELECT_WAYPOINT")
|
||||
print(" - GET_WAYPOINT_FOR_GUID")
|
||||
print(" - GET_PLAYER_DATA")
|
||||
print(" - TELEPORT_TO_WAYPOINT")
|
||||
|
||||
@@ -1806,7 +1806,7 @@ namespace LuaCreature
|
||||
// Spells
|
||||
lua_pushstring(L, "spells");
|
||||
lua_newtable(L);
|
||||
for (int i = 0; i < MAX_CREATURE_SPELLS; ++i)
|
||||
for (uint32 i = 0; i < MAX_CREATURE_SPELLS; ++i)
|
||||
{
|
||||
if (cTemplate->spells[i] != 0)
|
||||
{
|
||||
|
||||
@@ -3346,6 +3346,193 @@ namespace LuaGlobalFunctions
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets waypoint path data by path ID.
|
||||
* Returns a table with all nodes and their properties.
|
||||
*
|
||||
* @param uint32 pathId : the waypoint path ID
|
||||
* @return table path : table with nodes array, or nil if not found
|
||||
*/
|
||||
int GetWaypointPath(Eluna* E)
|
||||
{
|
||||
uint32 pathId = E->CHECKVAL<uint32>(1);
|
||||
WaypointPath const* path = sWaypointMgr->GetPath(pathId);
|
||||
|
||||
if (!path)
|
||||
{
|
||||
E->Push(); // Push nil
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_State* L = E->L;
|
||||
lua_newtable(L); // Create path table
|
||||
|
||||
// Create nodes array
|
||||
lua_newtable(L);
|
||||
int nodeIndex = 1;
|
||||
for (WaypointNode const& node : path->Nodes)
|
||||
{
|
||||
lua_newtable(L); // Create node table
|
||||
|
||||
lua_pushinteger(L, node.Id);
|
||||
lua_setfield(L, -2, "id");
|
||||
|
||||
lua_pushnumber(L, node.X);
|
||||
lua_setfield(L, -2, "x");
|
||||
|
||||
lua_pushnumber(L, node.Y);
|
||||
lua_setfield(L, -2, "y");
|
||||
|
||||
lua_pushnumber(L, node.Z);
|
||||
lua_setfield(L, -2, "z");
|
||||
|
||||
// Orientation is Optional<float>
|
||||
if (node.Orientation)
|
||||
{
|
||||
lua_pushnumber(L, *node.Orientation);
|
||||
lua_setfield(L, -2, "orientation");
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushnumber(L, 0.0);
|
||||
lua_setfield(L, -2, "orientation");
|
||||
}
|
||||
|
||||
// Delay is Optional<Milliseconds>
|
||||
if (node.Delay)
|
||||
{
|
||||
lua_pushinteger(L, node.Delay->count());
|
||||
lua_setfield(L, -2, "delay");
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushinteger(L, 0);
|
||||
lua_setfield(L, -2, "delay");
|
||||
}
|
||||
|
||||
// MoveType is WaypointMoveType enum
|
||||
lua_pushinteger(L, static_cast<int>(node.MoveType));
|
||||
lua_setfield(L, -2, "moveType");
|
||||
|
||||
lua_rawseti(L, -2, nodeIndex++);
|
||||
}
|
||||
|
||||
lua_setfield(L, -2, "nodes");
|
||||
|
||||
lua_pushinteger(L, path->Id);
|
||||
lua_setfield(L, -2, "id");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path ID and node ID for a visual waypoint creature GUID.
|
||||
* Used to identify which waypoint a creature marker represents.
|
||||
*
|
||||
* @param uint64 counter : the counter/low part of the creature GUID
|
||||
* @return uint32 pathId : the waypoint path ID (0 if not found)
|
||||
* @return uint32 nodeId : the node ID within the path (0 if not found)
|
||||
*/
|
||||
int GetWaypointNodeForVisualGUID(Eluna* E)
|
||||
{
|
||||
uint64 counter = E->CHECKVAL<uint64>(1);
|
||||
// Create a creature GUID using the factory method
|
||||
// We use mapId=0, entry=1 (VISUAL_WAYPOINT), and the counter from the client
|
||||
ObjectGuid guid = ObjectGuid::Create<HighGuid::Creature>(0, 1, counter);
|
||||
|
||||
uint32 pathId = 0, nodeId = 0;
|
||||
sWaypointMgr->GetPathAndNodeByVisualGUID(guid, pathId, nodeId);
|
||||
|
||||
E->Push(pathId);
|
||||
E->Push(nodeId);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlights a visual waypoint marker by changing its display ID.
|
||||
* Used to visually indicate the selected waypoint in the world.
|
||||
*
|
||||
* @param Player player : the player (used to find the creature in their map)
|
||||
* @param uint32 pathId : the waypoint path ID
|
||||
* @param uint32 nodeId : the node ID within the path
|
||||
* @param uint32 displayId : the display ID to use for highlighting
|
||||
* @return bool success : true if the marker was changed
|
||||
*/
|
||||
int HighlightWaypointMarker(Eluna* E)
|
||||
{
|
||||
Player* player = E->CHECKOBJ<Player>(1);
|
||||
uint32 pathId = E->CHECKVAL<uint32>(2);
|
||||
uint32 nodeId = E->CHECKVAL<uint32>(3);
|
||||
uint32 displayId = E->CHECKVAL<uint32>(4);
|
||||
|
||||
ObjectGuid const& markerGuid = sWaypointMgr->GetVisualGUIDByNode(pathId, nodeId);
|
||||
if (markerGuid.IsEmpty())
|
||||
{
|
||||
E->Push(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Creature* marker = ObjectAccessor::GetCreature(*player, markerGuid);
|
||||
if (!marker)
|
||||
{
|
||||
E->Push(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Change display to highlight model and scale up
|
||||
marker->SetDisplayId(displayId);
|
||||
marker->SetObjectScale(3.0f); // Scale up significantly
|
||||
marker->DestroyForNearbyPlayers(); // Force client update
|
||||
marker->UpdateObjectVisibilityOnCreate(); // Recreate for players
|
||||
|
||||
E->Push(true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a visual waypoint marker to its original display.
|
||||
* Used to remove highlighting from a previously selected waypoint.
|
||||
*
|
||||
* @param Player player : the player (used to find the creature in their map)
|
||||
* @param uint32 pathId : the waypoint path ID
|
||||
* @param uint32 nodeId : the node ID within the path
|
||||
* @param uint32 originalDisplayId : the original display ID to restore
|
||||
* @return bool success : true if marker was reset
|
||||
*/
|
||||
int ClearWaypointMarkerAuras(Eluna* E)
|
||||
{
|
||||
Player* player = E->CHECKOBJ<Player>(1);
|
||||
uint32 pathId = E->CHECKVAL<uint32>(2);
|
||||
uint32 nodeId = E->CHECKVAL<uint32>(3);
|
||||
uint32 originalDisplayId = E->CHECKVAL<uint32>(4, 0);
|
||||
|
||||
ObjectGuid const& markerGuid = sWaypointMgr->GetVisualGUIDByNode(pathId, nodeId);
|
||||
if (markerGuid.IsEmpty())
|
||||
{
|
||||
E->Push(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Creature* marker = ObjectAccessor::GetCreature(*player, markerGuid);
|
||||
if (!marker)
|
||||
{
|
||||
E->Push(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Reset to original display and scale
|
||||
if (originalDisplayId > 0)
|
||||
marker->SetDisplayId(originalDisplayId);
|
||||
else
|
||||
marker->SetDisplayId(marker->GetNativeDisplayId());
|
||||
marker->SetObjectScale(1.0f);
|
||||
marker->DestroyForNearbyPlayers(); // Force client update
|
||||
marker->UpdateObjectVisibilityOnCreate(); // Recreate for players
|
||||
|
||||
E->Push(true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all shared data keys.
|
||||
* Useful for debugging cross-state data.
|
||||
@@ -3499,7 +3686,13 @@ namespace LuaGlobalFunctions
|
||||
{ "ClearSharedData", &LuaGlobalFunctions::ClearSharedData },
|
||||
{ "HasSharedData", &LuaGlobalFunctions::HasSharedData },
|
||||
{ "ClearAllSharedData", &LuaGlobalFunctions::ClearAllSharedData },
|
||||
{ "GetSharedDataKeys", &LuaGlobalFunctions::GetSharedDataKeys }
|
||||
{ "GetSharedDataKeys", &LuaGlobalFunctions::GetSharedDataKeys },
|
||||
|
||||
// Waypoint utilities
|
||||
{ "GetWaypointPath", &LuaGlobalFunctions::GetWaypointPath },
|
||||
{ "GetWaypointNodeForVisualGUID", &LuaGlobalFunctions::GetWaypointNodeForVisualGUID },
|
||||
{ "HighlightWaypointMarker", &LuaGlobalFunctions::HighlightWaypointMarker },
|
||||
{ "ClearWaypointMarkerAuras", &LuaGlobalFunctions::ClearWaypointMarkerAuras }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4265,7 +4265,7 @@ namespace LuaPlayer
|
||||
* This removes stale tracking state and despawns any remaining marker creatures.
|
||||
* Useful for cleaning up after CLEAR_ALL_WAYPOINT_MARKERS or Eluna reload.
|
||||
*/
|
||||
int ClearAllWaypointVisualizations(Eluna* E, Player* player)
|
||||
int ClearAllWaypointVisualizations(Eluna* /*E*/, Player* player)
|
||||
{
|
||||
sWaypointMgr->ClearAllVisualizations(player);
|
||||
return 0;
|
||||
|
||||
@@ -398,3 +398,14 @@ void WaypointPath::BuildSegments()
|
||||
ContinuousSegments.emplace_back(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool WaypointMgr::GetPathAndNodeByVisualGUID(ObjectGuid guid, uint32& outPathId, uint32& outNodeId) const
|
||||
{
|
||||
auto itr = _visualWaypointGUIDToNodeMap.find(guid);
|
||||
if (itr == _visualWaypointGUIDToNodeMap.end())
|
||||
return false;
|
||||
|
||||
outPathId = itr->second.first->Id;
|
||||
outNodeId = itr->second.second->Id;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,9 @@ class TC_GAME_API WaypointMgr
|
||||
WaypointPath const* GetPathByVisualGUID(ObjectGuid guid) const;
|
||||
WaypointNode const* GetNodeByVisualGUID(ObjectGuid guid) const;
|
||||
ObjectGuid const& GetVisualGUIDByNode(uint32 pathId, uint32 nodeId) const;
|
||||
|
||||
// Get path and node IDs from a visual waypoint GUID
|
||||
bool GetPathAndNodeByVisualGUID(ObjectGuid guid, uint32& outPathId, uint32& outNodeId) const;
|
||||
|
||||
private:
|
||||
WaypointMgr();
|
||||
|
||||
Reference in New Issue
Block a user