Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions PBM/PBM_ClassTabs.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
PBM = PBM or {}
PBM = PBM or {}
PBM.State = PBM.State or {}

-- ── Class-tab drag-to-reorder state (mirrors LichborneTracker) ────
Expand Down Expand Up @@ -344,6 +344,12 @@ function PBM.OpenNameMenu(row)
-- class (unscanned/empty) simply have no menu.
local _rd = row.dbIndex and LichborneTrackerDB.rows[row.dbIndex]
if not _rd then return end
if not _rd.name or _rd.name == "" then
if LichborneAddStatus then
LichborneAddStatus:SetText("|cffffaa44Empty slot. Sync the roster or add a target/group first.|r")
end
return
end
local opener = CLASS_MENU_OPEN[_rd.cls]
if not (opener and PBM[opener]) then return end

Expand Down Expand Up @@ -918,8 +924,12 @@ function PBM.RefreshRows()
-- Delete
row.delBtn:SetScript("OnClick", function()
local srcData = LichborneTrackerDB.rows[di]
if not srcData or not srcData.name or srcData.name == "" then return end
PBM.RemoveCharacterReferences(srcData.name)
if not srcData then return end
if srcData.name and srcData.name ~= "" then
PBM.RemoveCharacterReferences(srcData.name)
else
table.remove(LichborneTrackerDB.rows, di)
end
PBM.RefreshRows()
if PBM.State.overviewRowFrames and #PBM.State.overviewRowFrames > 0 then PBM.RefreshOverviewRows() end
if PBM.State.raidRowFrames and #PBM.State.raidRowFrames > 0 then PBM.RefreshRaidRows() end
Expand Down
113 changes: 113 additions & 0 deletions PBM/PBM_RosterSync.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
local function Trim(value)
return (value:gsub("^%s+", ""):gsub("%s+$", ""))
end

local function NormalizeClass(name)
name = Trim(name)
if name == "DeathKnight" then name = "Death Knight" end
return PBM.CLASS_COLORS[name] and name or nil
end

local function FindTrackedBot(name)
local wanted = name:lower()
for _, row in ipairs(LichborneTrackerDB.rows or {}) do
if row.name and row.name ~= "" and row.name:lower() == wanted then
return row
end
end
end

local function AddTrackedBot(name, cls)
local existing = FindTrackedBot(name)
if existing then return false end

PBM.EnsureClass(cls)
local slot
for _, row in ipairs(LichborneTrackerDB.rows) do
if row.cls == cls and (not row.name or row.name == "") then
slot = row
break
end
end
if not slot then
slot = PBM.DefaultRow(cls)
table.insert(LichborneTrackerDB.rows, slot)
end

slot.name = name
return true
end

-- Parse the exact response emitted by mod-playerbots ListBots():
-- Bot roster: +OnlineName Class, -OfflineName Class
-- Returns recognized, numberAdded, numberListed.
function PBM.ImportBotRosterMessage(message)
if type(message) ~= "string" then return false end

local clean = message:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "")
local payload = clean:match("^Bot roster:%s*(.*)$")
if payload == nil then return false end

local added, total = 0, 0
for rawEntry in payload:gmatch("([^,]+)") do
local entry = Trim(rawEntry)
local _, name, rawClass = entry:match("^([+-])(%S+)%s+(.+)$")
local cls = rawClass and NormalizeClass(rawClass)
if name and cls then
total = total + 1
if AddTrackedBot(name, cls) then added = added + 1 end
end
end

if PBM.RefreshRows then PBM.RefreshRows() end
if PBM.State.overviewRowFrames and #PBM.State.overviewRowFrames > 0 and PBM.RefreshOverviewRows then
PBM.RefreshOverviewRows()
end

return true, added, total
end

function PBM.RequestBotRoster()
SendChatMessage(".playerbots bot list", "SAY")
end

local rosterTimerFrame
local rosterScheduleGeneration = 0

function PBM.ScheduleBotRosterRequest(delay)
rosterScheduleGeneration = rosterScheduleGeneration + 1
local generation = rosterScheduleGeneration
local function requestRoster()
if generation == rosterScheduleGeneration then PBM.RequestBotRoster() end
end

if C_Timer and C_Timer.After then
C_Timer.After(delay, requestRoster)
return
end

if not rosterTimerFrame then rosterTimerFrame = CreateFrame("Frame") end
local elapsed = 0
rosterTimerFrame:SetScript("OnUpdate", function(self, delta)
elapsed = elapsed + delta
if elapsed >= delay then
self:SetScript("OnUpdate", nil)
requestRoster()
end
end)
end

local rosterEventFrame = CreateFrame and CreateFrame("Frame", "PBMRosterSyncEventFrame")
if rosterEventFrame then
rosterEventFrame:RegisterEvent("CHAT_MSG_SYSTEM")
rosterEventFrame:SetScript("OnEvent", function(_, _, message)
local matched, added, total = PBM.ImportBotRosterMessage(message)
if not matched then return end

local status = "|cff44ff44Roster synced: " .. total .. " found, " .. added .. " added.|r"
if LichborneAddStatus then LichborneAddStatus:SetText(status) end
if LichborneOutput then
LichborneOutput("|cffC69B3APBM:|r Roster synced: " .. total .. " found, " .. added .. " added.", 1, 0.85, 0)
end
end)
end
12 changes: 9 additions & 3 deletions PBM/PBM_TrackerCore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ local function OnFirstShow()
if PBM.State.setupDone then return end
PBM.State.setupDone = true
local f = LichborneTrackerFrame
f:SetToplevel(true)
local fl = f:GetFrameLevel()

-- Tabs (centered in frame)
Expand Down Expand Up @@ -1122,13 +1123,18 @@ local function OnFirstShow()

local loginBtn = MakeSimpleBtn("LichborneLoginBtn", "|cffd4af37Log in All Bots|r",
0.1, 0.6, 0.2, 335, 110,
155, {{"Log in All Bots",0.78,0.61,0.23},{".playerbots bot add *",0.8,0.8,0.8}})
loginBtn:SetScript("OnClick", function() SendChatMessage(".playerbots bot add *", "PARTY") end)
155, {{"Log in All Bots",0.78,0.61,0.23},{"Logs in bots, then syncs the server roster.",0.8,0.8,0.8}})
loginBtn:SetScript("OnClick", function()
if LichborneAddStatus then LichborneAddStatus:SetText("|cffffff88Logging in bots and requesting roster...|r") end
-- Use SAY to reach handler outside groups
SendChatMessage(".playerbots bot add *", "SAY")
PBM.ScheduleBotRosterRequest(0.75)
end)

local logoutBtn = MakeSimpleBtn("LichborneLogoutBtn", "|cffd4af37Log Out All Bots|r",
0.90, 0.20, 0.20, 335, 76,
155, {{"Log Out All Bots",0.78,0.61,0.23},{".playerbots bot remove *",0.8,0.8,0.8}})
logoutBtn:SetScript("OnClick", function() SendChatMessage(".playerbots bot remove *", "PARTY") end)
logoutBtn:SetScript("OnClick", function() SendChatMessage(".playerbots bot remove *", "SAY") end)

-- ── Remove Orphaned Bots button ────────────────────────────
-- Sends .playerbots bot remove <name> for every character in the Overview tab roster
Expand Down
1 change: 1 addition & 0 deletions PlayerBotManager.toc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ LichborneTracker.xml
PBM\PBM_Constants.lua
PBM\IPTiersColor.lua
PBM\PBM_Database.lua
PBM\PBM_RosterSync.lua
PBM\PBM_GearScore.lua
PBM\PBM_Needs.lua
PBM\PBM_Sort.lua
Expand Down