You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1673 lines
68 KiB
1673 lines
68 KiB
|
|
--Notes:
|
|
--[=[
|
|
player name usage:
|
|
For the same realm: the player name only, example: "Tercio"
|
|
For different realm: is used the 'none' ambiguation with no realm normalizarion: "Tercio-RealmName"
|
|
|
|
Non normalizated player-realom names is used by the game on comm receive event as the 'sender' parameter
|
|
It also is the result from GetUnitName(unitId, true) or Ambiguate(playerName, 'none')
|
|
|
|
to be implemented:
|
|
- pvp talents
|
|
- raid lockouts normal-heroic-mythic
|
|
- make GUID to be used when passing the player name
|
|
- make "player" unit information always be available even not in a group
|
|
--]=]
|
|
|
|
|
|
|
|
local major = "LibOpenRaid-1.0"
|
|
local CONST_LIB_VERSION = 22
|
|
LIB_OPEN_RAID_CAN_LOAD = false
|
|
|
|
--declae the library within the LibStub
|
|
local libStub = _G.LibStub
|
|
local openRaidLib = libStub:NewLibrary(major, CONST_LIB_VERSION)
|
|
if (not openRaidLib) then
|
|
return
|
|
end
|
|
|
|
LIB_OPEN_RAID_CAN_LOAD = true
|
|
|
|
--default values
|
|
openRaidLib.inGroup = false
|
|
|
|
--print failures (when the function return an error) results to chat
|
|
local CONST_DIAGNOSTIC_ERRORS = false
|
|
--print the data to be sent and data received from comm
|
|
local CONST_DIAGNOSTIC_COMM = false
|
|
|
|
local CONST_COMM_PREFIX = "LRS"
|
|
local CONST_COMM_FULLINFO_PREFIX = "F"
|
|
local CONST_COMM_COOLDOWNUPDATE_PREFIX = "U"
|
|
local CONST_COMM_COOLDOWNFULLLIST_PREFIX = "C"
|
|
local CONST_COMM_GEARINFO_FULL_PREFIX = "G"
|
|
local CONST_COMM_GEARINFO_DURABILITY_PREFIX = "R"
|
|
local CONST_COMM_PLAYER_DEAD_PREFIX = "D"
|
|
local CONST_COMM_PLAYER_ALIVE_PREFIX = "A"
|
|
local CONST_COMM_PLAYERINFO_PREFIX = "P"
|
|
local CONST_COMM_PLAYERINFO_TALENTS_PREFIX = "T"
|
|
|
|
local CONST_ONE_SECOND = 1.0
|
|
local CONST_TWO_SECONDS = 2.0
|
|
local CONST_THREE_SECONDS = 3.0
|
|
local CONST_FRACTION_OF_A_SECOND = 0.01
|
|
|
|
local CONST_COOLDOWN_CHECK_INTERVAL = CONST_THREE_SECONDS
|
|
local CONST_COOLDOWN_TIMELEFT_HAS_CHANGED = CONST_THREE_SECONDS
|
|
|
|
local diagnosticError = function(msg, ...)
|
|
if (CONST_DIAGNOSTIC_ERRORS) then
|
|
print("|cFFFF9922OpenRaidLib|r:", msg, ...)
|
|
end
|
|
end
|
|
|
|
local diagnosticComm = function(msg, ...)
|
|
if (CONST_DIAGNOSTIC_COMM) then
|
|
print("|cFFFF9922OpenRaidLib|r:", msg, ...)
|
|
end
|
|
end
|
|
|
|
local isTimewalkWoW = function()
|
|
local gameVersion = GetBuildInfo()
|
|
if (gameVersion:match("%d") == "1" or gameVersion:match("%d") == "2") then
|
|
return true
|
|
end
|
|
end
|
|
|
|
--return the current specId of the player
|
|
function openRaidLib.GetPlayerSpecId()
|
|
if (isTimewalkWoW()) then
|
|
return 0
|
|
end
|
|
|
|
local spec = GetSpecialization()
|
|
if (spec) then
|
|
local specId = GetSpecializationInfo(spec)
|
|
if (specId and specId > 0) then
|
|
return specId
|
|
end
|
|
end
|
|
end
|
|
|
|
function openRaidLib.UpdatePlayerAliveStatus(onLogin)
|
|
if (UnitIsDeadOrGhost("player")) then
|
|
if (openRaidLib.playerAlive) then
|
|
openRaidLib.playerAlive = false
|
|
|
|
--trigger event if this isn't from login
|
|
if (not onLogin) then
|
|
openRaidLib.internalCallback.TriggerEvent("onPlayerDeath")
|
|
end
|
|
end
|
|
else
|
|
if (not openRaidLib.playerAlive) then
|
|
openRaidLib.playerAlive = true
|
|
|
|
--trigger event if this isn't from login
|
|
if (not onLogin) then
|
|
openRaidLib.internalCallback.TriggerEvent("onPlayerRess")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--creates two tables, one with indexed talents and another with pairs values ([talentId] = true)
|
|
function openRaidLib.GetPlayerTalents()
|
|
local talentsPairs = {}
|
|
local talentsIndex = {}
|
|
for i = 1, 7 do
|
|
for o = 1, 3 do
|
|
local talentId, _, _, selected = GetTalentInfo(i, o, 1)
|
|
if (selected) then
|
|
talentsPairs[talentId] = true
|
|
talentsIndex[#talentsIndex+1] = talentId
|
|
break
|
|
end
|
|
end
|
|
end
|
|
return talentsPairs, talentsIndex
|
|
end
|
|
|
|
--simple non recursive table copy
|
|
function openRaidLib.TCopy(tableToReceive, tableToCopy)
|
|
for key, value in pairs(tableToCopy) do
|
|
tableToReceive[key] = value
|
|
end
|
|
end
|
|
|
|
--transform a table index into a string dividing values with a comma
|
|
--@table: an indexed table with unknown size
|
|
function openRaidLib.PackTable(table)
|
|
local tableSize = #table
|
|
local newString = "" .. tableSize .. ","
|
|
for i = 1, tableSize do
|
|
newString = newString .. table[i] .. ","
|
|
end
|
|
|
|
newString = newString:gsub(",$", "")
|
|
return newString
|
|
end
|
|
|
|
--return is a number is almost equal to another within a tolerance range
|
|
function openRaidLib.isNearlyEqual(value1, value2, tolerance)
|
|
tolerance = tolerance or CONST_FRACTION_OF_A_SECOND
|
|
return abs(value1 - value2) <= tolerance
|
|
end
|
|
|
|
--return true if the lib is allowed to receive comms from other players
|
|
function openRaidLib.IsCommAllowed()
|
|
return IsInGroup() or IsInRaid()
|
|
end
|
|
|
|
--stract some indexes of a table
|
|
local selectIndexes = function(table, startIndex, amountIndexes)
|
|
local values = {}
|
|
for i = startIndex, startIndex+amountIndexes do
|
|
values[#values+1] = tonumber(table[i]) or 0
|
|
end
|
|
return values
|
|
end
|
|
|
|
--transform a string table into a regular table
|
|
--@table: a table with unknown values
|
|
--@index: where in the table is the information we want
|
|
--@isPair: if true treat the table as pairs(), ipairs() otherwise
|
|
--@valueAsTable: return {value1, value2, value3}
|
|
--@amountOfValues: for the parameter above
|
|
function openRaidLib.UnpackTable(table, index, isPair, valueIsTable, amountOfValues)
|
|
local result = {}
|
|
local reservedIndexes = table[index]
|
|
if (not reservedIndexes) then
|
|
return result
|
|
end
|
|
local indexStart = index+1
|
|
local indexEnd = reservedIndexes+index
|
|
|
|
if (isPair) then
|
|
amountOfValues = amountOfValues or 2
|
|
for i = indexStart, indexEnd, amountOfValues do
|
|
if (valueIsTable) then
|
|
local key = tonumber(table[i])
|
|
local values = selectIndexes(table, i+1, max(amountOfValues-2, 1))
|
|
result[key] = values
|
|
else
|
|
local key = tonumber(table[i])
|
|
local value = tonumber(table[i+1])
|
|
result[key] = value
|
|
end
|
|
end
|
|
else
|
|
for i = indexStart, indexEnd do
|
|
local value = tonumber(table[i])
|
|
result[#result+1] = value
|
|
end
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
--returns if the player is in group
|
|
function openRaidLib.IsInGroup()
|
|
local inParty = IsInGroup()
|
|
local inRaid = IsInRaid()
|
|
return inParty or inRaid
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--> ~comms
|
|
openRaidLib.commHandler = {}
|
|
|
|
function openRaidLib.commHandler.OnReceiveComm(self, event, prefix, text, channel, sender, target, zoneChannelID, localID, name, instanceID)
|
|
|
|
--check if the data belong to us
|
|
if (prefix == CONST_COMM_PREFIX) then
|
|
--check if the lib can receive comms
|
|
if (not openRaidLib.IsCommAllowed()) then
|
|
return
|
|
end
|
|
|
|
sender = Ambiguate(sender, "none")
|
|
|
|
--don't receive comms from the player it self
|
|
local playerName = UnitName("player")
|
|
if (playerName == sender) then
|
|
--return --commented for debug
|
|
end
|
|
|
|
local data = text
|
|
local LibDeflate = LibStub:GetLibrary("LibDeflate")
|
|
local dataCompressed = LibDeflate:DecodeForWoWAddonChannel(data)
|
|
data = LibDeflate:DecompressDeflate(dataCompressed)
|
|
|
|
--get the first byte of the data, it indicates what type of data was transmited
|
|
local dataTypePrefix = data:match("^.")
|
|
--get the table with functions regitered for this type of data
|
|
local callbackTable = openRaidLib.commHandler.commCallback[dataTypePrefix]
|
|
--convert to table
|
|
local dataAsTable = {strsplit(",", data)}
|
|
|
|
--remove the first index (prefix)
|
|
tremove(dataAsTable, 1)
|
|
|
|
--trigger callbacks
|
|
for i = 1, #callbackTable do
|
|
callbackTable[i](dataAsTable, sender)
|
|
end
|
|
end
|
|
end
|
|
|
|
C_ChatInfo.RegisterAddonMessagePrefix(CONST_COMM_PREFIX)
|
|
openRaidLib.commHandler.eventFrame = CreateFrame("frame")
|
|
openRaidLib.commHandler.eventFrame:RegisterEvent("CHAT_MSG_ADDON")
|
|
openRaidLib.commHandler.eventFrame:SetScript("OnEvent", openRaidLib.commHandler.OnReceiveComm)
|
|
|
|
openRaidLib.commHandler.commCallback = {
|
|
--when transmiting
|
|
[CONST_COMM_FULLINFO_PREFIX] = {}, --update all
|
|
[CONST_COMM_COOLDOWNFULLLIST_PREFIX] = {}, --all cooldowns of a player
|
|
[CONST_COMM_COOLDOWNUPDATE_PREFIX] = {}, --an update of a single cooldown
|
|
[CONST_COMM_GEARINFO_FULL_PREFIX] = {}, --an update of gear information
|
|
[CONST_COMM_GEARINFO_DURABILITY_PREFIX] = {}, --an update of the player gear durability
|
|
[CONST_COMM_PLAYER_DEAD_PREFIX] = {}, --player is dead
|
|
[CONST_COMM_PLAYER_ALIVE_PREFIX] = {}, --player is alive
|
|
[CONST_COMM_PLAYERINFO_PREFIX] = {}, --info about the player
|
|
[CONST_COMM_PLAYERINFO_TALENTS_PREFIX] = {}, --cooldown info
|
|
}
|
|
|
|
function openRaidLib.commHandler.RegisterComm(prefix, func)
|
|
--the table for the prefix need to be declared at the 'openRaidLib.commHandler.commCallback' table
|
|
tinsert(openRaidLib.commHandler.commCallback[prefix], func)
|
|
end
|
|
|
|
function openRaidLib.commHandler.SendCommData(data)
|
|
local LibDeflate = LibStub:GetLibrary("LibDeflate")
|
|
local dataCompressed = LibDeflate:CompressDeflate(data, {level = 9})
|
|
local dataEncoded = LibDeflate:EncodeForWoWAddonChannel(dataCompressed)
|
|
|
|
if (IsInGroup() and not IsInRaid()) then --in party only
|
|
C_ChatInfo.SendAddonMessage(CONST_COMM_PREFIX, dataEncoded, IsInGroup(LE_PARTY_CATEGORY_INSTANCE) and "INSTANCE_CHAT" or "PARTY")
|
|
|
|
elseif (IsInRaid()) then
|
|
C_ChatInfo.SendAddonMessage(CONST_COMM_PREFIX, dataEncoded, IsInRaid(LE_PARTY_CATEGORY_INSTANCE) and "INSTANCE_CHAT" or "RAID")
|
|
end
|
|
end
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--> ~schedule ~timers
|
|
|
|
openRaidLib.Schedules = {
|
|
registeredUniqueTimers = {}
|
|
}
|
|
|
|
--run a scheduled function with its payload
|
|
local triggerScheduledTick = function(tickerObject)
|
|
local payload = tickerObject.payload
|
|
local callback = tickerObject.callback
|
|
|
|
local result, errortext = pcall(callback, _G.unpack(payload))
|
|
if (not result) then
|
|
print("openRaidLib: error on scheduler:", tickerObject.scheduleName, tickerObject.stack, errortext)
|
|
end
|
|
|
|
if (tickerObject.isUnique) then
|
|
local namespace = tickerObject.namespace
|
|
local scheduleName = tickerObject.scheduleName
|
|
openRaidLib.Schedules.CancelUniqueTimer(namespace, scheduleName)
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
--create a new schedule
|
|
function openRaidLib.Schedules.NewTimer(time, callback, ...)
|
|
local payload = {...}
|
|
local newTimer = C_Timer.NewTimer(time, triggerScheduledTick)
|
|
newTimer.payload = payload
|
|
newTimer.callback = callback
|
|
newTimer.stack = debugstack()
|
|
return newTimer
|
|
end
|
|
|
|
--create an unique schedule
|
|
--if a schedule already exists, cancels it and make a new
|
|
function openRaidLib.Schedules.NewUniqueTimer(time, callback, namespace, scheduleName, ...)
|
|
openRaidLib.Schedules.CancelUniqueTimer(namespace, scheduleName)
|
|
|
|
local newTimer = openRaidLib.Schedules.NewTimer(time, callback, ...)
|
|
newTimer.namespace = namespace
|
|
newTimer.scheduleName = scheduleName
|
|
newTimer.stack = debugstack()
|
|
newTimer.isUnique = true
|
|
|
|
local registeredUniqueTimers = openRaidLib.Schedules.registeredUniqueTimers
|
|
registeredUniqueTimers[namespace] = registeredUniqueTimers[namespace] or {}
|
|
registeredUniqueTimers[namespace][scheduleName] = newTimer
|
|
end
|
|
|
|
--cancel an unique schedule
|
|
function openRaidLib.Schedules.CancelUniqueTimer(namespace, scheduleName)
|
|
local registeredUniqueTimers = openRaidLib.Schedules.registeredUniqueTimers
|
|
local currentSchedule = registeredUniqueTimers[namespace] and registeredUniqueTimers[namespace][scheduleName]
|
|
|
|
if (currentSchedule) then
|
|
if (not currentSchedule._cancelled) then
|
|
currentSchedule:Cancel()
|
|
end
|
|
registeredUniqueTimers[namespace][scheduleName] = nil
|
|
end
|
|
end
|
|
|
|
--cancel all unique timers
|
|
function openRaidLib.Schedules.CancelAllUniqueTimers()
|
|
local registeredUniqueTimers = openRaidLib.Schedules.registeredUniqueTimers
|
|
for namespace, schedulesTable in pairs(registeredUniqueTimers) do
|
|
for scheduleName, timerObject in pairs (schedulesTable) do
|
|
if (timerObject and not timerObject._cancelled) then
|
|
timerObject:Cancel()
|
|
end
|
|
end
|
|
end
|
|
table.wipe(registeredUniqueTimers)
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--> ~public ~callbacks
|
|
--these are the events where other addons can register and receive calls
|
|
local allPublicCallbacks = {
|
|
"CooldownListUpdate",
|
|
"CooldownListWiped",
|
|
"CooldownUpdate",
|
|
"OnPlayerDeath",
|
|
"OnPlayerRess",
|
|
"GearListWiped",
|
|
"GearUpdate",
|
|
"GearDurabilityUpdate",
|
|
"PlayerUpdate",
|
|
"TalentUpdate",
|
|
}
|
|
|
|
--save build the table to avoid lose registered events on older versions
|
|
openRaidLib.publicCallback = openRaidLib.publicCallback or {}
|
|
openRaidLib.publicCallback.events = openRaidLib.publicCallback.events or {}
|
|
for _, callbackName in ipairs(allPublicCallbacks) do
|
|
openRaidLib.publicCallback.events[callbackName] = openRaidLib.publicCallback.events[callbackName] or {}
|
|
end
|
|
|
|
local checkRegisterDataIntegrity = function(addonObject, event, callbackMemberName)
|
|
--check of integrity
|
|
if (type(addonObject) == "string") then
|
|
addonObject = _G[addonObject]
|
|
end
|
|
|
|
if (type(addonObject) ~= "table") then
|
|
return 1
|
|
end
|
|
|
|
if (not openRaidLib.publicCallback.events[event]) then
|
|
return 2
|
|
|
|
elseif (not addonObject[callbackMemberName]) then
|
|
return 3
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
--call the registered function within the addon namespace
|
|
--payload is sent together within the call
|
|
function openRaidLib.publicCallback.TriggerCallback(event, ...)
|
|
local callbacks = openRaidLib.publicCallback.events[event]
|
|
|
|
for i = 1, #callbacks do
|
|
local addonObject = callbacks[i][1]
|
|
local functionName = callbacks[i][2]
|
|
local func = addonObject[functionName]
|
|
|
|
if (func) then
|
|
--using pcall at the moment, should get a better caller in the future
|
|
local okay, errorMessage = pcall(func, ...)
|
|
if (not okay) then
|
|
print("error:", errorMessage)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function openRaidLib.RegisterCallback(addonObject, event, callbackMemberName)
|
|
--check of integrity
|
|
local integrity = checkRegisterDataIntegrity(addonObject, event, callbackMemberName)
|
|
if (integrity and type(integrity) ~= "boolean") then
|
|
return integrity
|
|
end
|
|
|
|
--register
|
|
tinsert(openRaidLib.publicCallback.events[event], {addonObject, callbackMemberName})
|
|
return true
|
|
end
|
|
|
|
function openRaidLib.UnregisterCallback(addonObject, event, callbackMemberName)
|
|
--check of integrity
|
|
local integrity = checkRegisterDataIntegrity(addonObject, event, callbackMemberName)
|
|
if (integrity and type(integrity) ~= "boolean") then
|
|
return integrity
|
|
end
|
|
|
|
for i = 1, #openRaidLib.publicCallback.events[event] do
|
|
local registeredCallback = openRaidLib.publicCallback.events[event][i]
|
|
if (registeredCallback[1] == addonObject and registeredCallback[2] == callbackMemberName) then
|
|
tremove(openRaidLib.publicCallback.events[event], i)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--> ~internal ~callbacks
|
|
--internally, each module can register events through the internal callback to be notified when something happens in the game
|
|
|
|
openRaidLib.internalCallback = {}
|
|
openRaidLib.internalCallback.events = {
|
|
["onEnterGroup"] = {},
|
|
["onLeaveGroup"] = {},
|
|
["playerCast"] = {},
|
|
["onEnterWorld"] = {},
|
|
["talentUpdate"] = {},
|
|
["onPlayerDeath"] = {},
|
|
["onPlayerRess"] = {},
|
|
}
|
|
|
|
openRaidLib.internalCallback.RegisterCallback = function(event, func)
|
|
tinsert(openRaidLib.internalCallback.events[event], func)
|
|
end
|
|
|
|
openRaidLib.internalCallback.UnRegisterCallback = function(event, func)
|
|
local container = openRaidLib.internalCallback.events[event]
|
|
for i = 1, #container do
|
|
if (container[i] == func) then
|
|
tremove(container, i)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
function openRaidLib.internalCallback.TriggerEvent(event, ...)
|
|
local container = openRaidLib.internalCallback.events[event]
|
|
for i = 1, #container do
|
|
container[i](event, ...)
|
|
end
|
|
end
|
|
|
|
--create the frame for receiving game events
|
|
local eventFrame = _G.OpenRaidLibFrame
|
|
if (not eventFrame) then
|
|
eventFrame = CreateFrame("frame", "OpenRaidLibFrame", UIParent)
|
|
end
|
|
|
|
local eventFunctions = {
|
|
--check if the player joined a group
|
|
["GROUP_ROSTER_UPDATE"] = function()
|
|
local eventTriggered = false
|
|
if (openRaidLib.IsInGroup()) then
|
|
if (not openRaidLib.inGroup) then
|
|
openRaidLib.inGroup = true
|
|
openRaidLib.internalCallback.TriggerEvent("onEnterGroup")
|
|
eventTriggered = true
|
|
end
|
|
else
|
|
if (openRaidLib.inGroup) then
|
|
openRaidLib.inGroup = false
|
|
openRaidLib.internalCallback.TriggerEvent("onLeaveGroup")
|
|
eventTriggered = true
|
|
end
|
|
end
|
|
|
|
if (not eventTriggered and openRaidLib.IsInGroup()) then --the player didn't left or enter a group
|
|
--the group has changed, trigger a long timer to send full data
|
|
--as the timer is unique, a new change to the group will replace and refresh the time
|
|
--using random time, players won't trigger all at the same time
|
|
local randomTime = 1.0 + math.random(1.0, 5.5)
|
|
openRaidLib.Schedules.NewUniqueTimer(randomTime, openRaidLib.mainControl.SendFullData, "mainControl", "sendFullData_Schedule")
|
|
end
|
|
end,
|
|
|
|
["UNIT_SPELLCAST_SUCCEEDED"] = function(...)
|
|
local unitId, castGUID, spellId = ...
|
|
C_Timer.After(0.1, function()
|
|
openRaidLib.internalCallback.TriggerEvent("playerCast", spellId)
|
|
end)
|
|
end,
|
|
|
|
["PLAYER_ENTERING_WORLD"] = function(...)
|
|
openRaidLib.internalCallback.TriggerEvent("onEnterWorld")
|
|
end,
|
|
|
|
--["PLAYER_SPECIALIZATION_CHANGED"] = function(...) end, --on changing spec, the talent_update event is also triggered
|
|
["PLAYER_TALENT_UPDATE"] = function(...)
|
|
openRaidLib.internalCallback.TriggerEvent("talentUpdate")
|
|
end,
|
|
|
|
["PLAYER_DEAD"] = function(...)
|
|
openRaidLib.UpdatePlayerAliveStatus()
|
|
end,
|
|
["PLAYER_ALIVE"] = function(...)
|
|
openRaidLib.UpdatePlayerAliveStatus()
|
|
end,
|
|
["PLAYER_UNGHOST"] = function(...)
|
|
openRaidLib.UpdatePlayerAliveStatus()
|
|
end,
|
|
|
|
["PLAYER_REGEN_DISABLED"] = function(...)
|
|
--entered in combat
|
|
end,
|
|
|
|
["PLAYER_REGEN_ENABLED"] = function(...)
|
|
--left combat
|
|
--when left encounter, share everything
|
|
--small hack, pretend to have just entered in the group, hence send all data
|
|
openRaidLib.internalCallback.TriggerEvent("onEnterGroup")
|
|
end,
|
|
|
|
["UPDATE_INVENTORY_DURABILITY"] = function(...)
|
|
--an item has changed its durability
|
|
--do not trigger this event while in combat
|
|
if (not InCombatLockdown()) then
|
|
openRaidLib.Schedules.NewUniqueTimer(5 + math.random(0, 4), openRaidLib.gearManager.SendDurability, "gearManager", "sendDurability_Schedule")
|
|
end
|
|
end,
|
|
|
|
["PLAYER_EQUIPMENT_CHANGED"] = function(...)
|
|
--player changed an equipment
|
|
openRaidLib.Schedules.NewUniqueTimer(4 + math.random(0, 5), openRaidLib.gearManager.SendAllGearInfo, "gearManager", "sendAllGearInfo_Schedule")
|
|
end,
|
|
|
|
["ENCOUNTER_END"] = function()
|
|
|
|
end,
|
|
}
|
|
|
|
eventFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
|
|
eventFrame:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player")
|
|
eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
eventFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
|
|
eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
|
|
eventFrame:RegisterEvent("UPDATE_INVENTORY_DURABILITY")
|
|
eventFrame:RegisterEvent("PLAYER_EQUIPMENT_CHANGED")
|
|
|
|
--eventFrame:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
|
|
if (not isTimewalkWoW()) then
|
|
eventFrame:RegisterEvent("PLAYER_TALENT_UPDATE")
|
|
eventFrame:RegisterEvent("ENCOUNTER_END")
|
|
end
|
|
|
|
eventFrame:RegisterEvent("PLAYER_DEAD")
|
|
eventFrame:RegisterEvent("PLAYER_ALIVE")
|
|
eventFrame:RegisterEvent("PLAYER_UNGHOST")
|
|
|
|
eventFrame:SetScript("OnEvent", function(self, event, ...)
|
|
eventFunctions[event](...)
|
|
end)
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--> ~main ~control
|
|
|
|
openRaidLib.mainControl = {
|
|
playerAliveStatus = {},
|
|
}
|
|
|
|
--send full data (all data available)
|
|
function openRaidLib.mainControl.SendFullData()
|
|
|
|
--send cooldown data
|
|
openRaidLib.cooldownManager.SendAllCooldowns()
|
|
|
|
--send gear data
|
|
openRaidLib.gearManager.SendAllGearInfo()
|
|
|
|
--send player data
|
|
openRaidLib.playerInfoManager.SendAllPlayerInfo()
|
|
end
|
|
|
|
openRaidLib.mainControl.onEnterWorld = function()
|
|
--update the alive status of the player
|
|
openRaidLib.UpdatePlayerAliveStatus(true)
|
|
|
|
--the game client is fully loadded and all information is available
|
|
if (openRaidLib.IsInGroup()) then
|
|
openRaidLib.Schedules.NewUniqueTimer(1.0, openRaidLib.mainControl.SendFullData, "mainControl", "sendFullData_Schedule")
|
|
end
|
|
end
|
|
|
|
openRaidLib.mainControl.OnEnterGroup = function()
|
|
--the player entered in a group
|
|
--schedule to send data
|
|
openRaidLib.Schedules.NewUniqueTimer(1.0, openRaidLib.mainControl.SendFullData, "mainControl", "sendFullData_Schedule")
|
|
end
|
|
|
|
openRaidLib.mainControl.OnLeftGroup = function()
|
|
--the player left a group
|
|
--wipe group data (each module registers the OnLeftGroup)
|
|
|
|
--cancel all schedules
|
|
openRaidLib.Schedules.CancelAllUniqueTimers()
|
|
|
|
--wipe alive status
|
|
table.wipe(openRaidLib.mainControl.playerAliveStatus)
|
|
|
|
--toggle off comms
|
|
end
|
|
|
|
openRaidLib.mainControl.OnPlayerDeath = function()
|
|
local playerName = UnitName("player")
|
|
openRaidLib.mainControl.playerAliveStatus[playerName] = false
|
|
|
|
local dataToSend = CONST_COMM_PLAYER_DEAD_PREFIX
|
|
openRaidLib.commHandler.SendCommData(dataToSend)
|
|
diagnosticComm("OnPlayerDeath| " .. dataToSend) --debug
|
|
|
|
openRaidLib.publicCallback.TriggerCallback("OnPlayerDeath", playerName)
|
|
end
|
|
|
|
openRaidLib.mainControl.OnPlayerRess = function()
|
|
local playerName = UnitName("player")
|
|
openRaidLib.mainControl.playerAliveStatus[playerName] = true
|
|
|
|
local dataToSend = CONST_COMM_PLAYER_ALIVE_PREFIX
|
|
openRaidLib.commHandler.SendCommData(dataToSend)
|
|
diagnosticComm("OnPlayerRess| " .. dataToSend) --debug
|
|
|
|
openRaidLib.publicCallback.TriggerCallback("OnPlayerRess", playerName)
|
|
end
|
|
|
|
openRaidLib.internalCallback.RegisterCallback("onEnterWorld", openRaidLib.mainControl.onEnterWorld)
|
|
openRaidLib.internalCallback.RegisterCallback("onEnterGroup", openRaidLib.mainControl.OnEnterGroup)
|
|
openRaidLib.internalCallback.RegisterCallback("onLeaveGroup", openRaidLib.mainControl.OnLeftGroup)
|
|
openRaidLib.internalCallback.RegisterCallback("onPlayerDeath", openRaidLib.mainControl.OnPlayerDeath)
|
|
openRaidLib.internalCallback.RegisterCallback("onPlayerRess", openRaidLib.mainControl.OnPlayerRess)
|
|
|
|
--a player in the group died
|
|
openRaidLib.commHandler.RegisterComm(CONST_COMM_PLAYER_DEAD_PREFIX, function(data, sourceName)
|
|
openRaidLib.mainControl.playerAliveStatus[sourceName] = false
|
|
openRaidLib.publicCallback.TriggerCallback("OnPlayerDeath", sourceName)
|
|
end)
|
|
|
|
--a player in the group is now alive
|
|
openRaidLib.commHandler.RegisterComm(CONST_COMM_PLAYER_ALIVE_PREFIX, function(data, sourceName)
|
|
openRaidLib.mainControl.playerAliveStatus[sourceName] = true
|
|
openRaidLib.publicCallback.TriggerCallback("OnPlayerRess", sourceName)
|
|
end)
|
|
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--> ~all, request data from all players
|
|
|
|
--send a request to all player to send their data
|
|
function openRaidLib.RequestAllPlayersInfo()
|
|
if (not IsInGroup()) then
|
|
return
|
|
end
|
|
|
|
openRaidLib.requestAllInfoCooldown = openRaidLib.requestAllInfoCooldown or 0
|
|
|
|
if (openRaidLib.requestAllInfoCooldown > GetTime()) then
|
|
return
|
|
end
|
|
|
|
openRaidLib.commHandler.SendCommData(CONST_COMM_FULLINFO_PREFIX)
|
|
diagnosticComm("RequestAllInfo| " .. CONST_COMM_FULLINFO_PREFIX) --debug
|
|
|
|
openRaidLib.requestAllInfoCooldown = GetTime() + 5
|
|
return true
|
|
end
|
|
|
|
openRaidLib.commHandler.RegisterComm(CONST_COMM_FULLINFO_PREFIX, function(data, sourceName)
|
|
openRaidLib.sendRequestedAllInfoCooldown = openRaidLib.sendRequestedAllInfoCooldown or 0
|
|
|
|
--some player in the group requested all information from all players
|
|
if (openRaidLib.sendRequestedAllInfoCooldown > GetTime()) then
|
|
return
|
|
end
|
|
|
|
openRaidLib.Schedules.NewUniqueTimer(random() + math.random(0, 3), openRaidLib.mainControl.SendFullData, "mainControl", "sendFullData_Schedule")
|
|
openRaidLib.sendRequestedAllInfoCooldown = GetTime() + 5
|
|
end)
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--> ~cooldowns
|
|
openRaidLib.cooldownManager = {
|
|
playerData = {}, --stores the list of cooldowns each player has sent
|
|
playerCurrentCooldowns = {},
|
|
cooldownTickers = {}, --store C_Timer.NewTicker
|
|
}
|
|
|
|
--check if a cooldown has changed or done
|
|
local cooldownTimeLeftCheck = function(tickerObject)
|
|
local spellId = tickerObject.spellId
|
|
tickerObject.cooldownTimeLeft = tickerObject.cooldownTimeLeft - CONST_COOLDOWN_CHECK_INTERVAL
|
|
local timeLeft, charges, startTime, duration = openRaidLib.cooldownManager.GetCooldownStatus(spellId)
|
|
|
|
--is the spell ready to use?
|
|
if (timeLeft == 0) then
|
|
--it's ready
|
|
openRaidLib.cooldownManager.SendCooldownUpdate(spellId, 0, charges, 0, 0)
|
|
openRaidLib.cooldownManager.cooldownTickers[spellId] = nil
|
|
tickerObject:Cancel()
|
|
else
|
|
--check if the time left has changed
|
|
if (not openRaidLib.isNearlyEqual(tickerObject.cooldownTimeLeft, timeLeft, CONST_COOLDOWN_TIMELEFT_HAS_CHANGED)) then
|
|
--there's a deviation, send a comm to communicate the change in the time left
|
|
openRaidLib.cooldownManager.SendCooldownUpdate(spellId, timeLeft, charges, startTime, duration)
|
|
tickerObject.cooldownTimeLeft = timeLeft
|
|
end
|
|
end
|
|
end
|
|
|
|
--after a spell is casted by the player, start a ticker to check its cooldown
|
|
local cooldownStartTicker = function(spellId, cooldownTimeLeft)
|
|
local existingTicker = openRaidLib.cooldownManager.cooldownTickers[spellId]
|
|
if (existingTicker) then
|
|
--is a ticker already exists, might be the cooldown of a charge
|
|
--if the ticker isn't about to expire, just keep the timer
|
|
--when the ticker finishes it'll check again for charges
|
|
if (existingTicker.startTime + existingTicker.cooldownTimeLeft - GetTime() > 2) then
|
|
return
|
|
end
|
|
|
|
--cancel the existing ticker
|
|
if (not existingTicker._cancelled) then
|
|
existingTicker:Cancel()
|
|
end
|
|
end
|
|
|
|
--create a new ticker
|
|
local maxTicks = ceil(cooldownTimeLeft / CONST_COOLDOWN_CHECK_INTERVAL)
|
|
local newTicker = C_Timer.NewTicker(CONST_COOLDOWN_CHECK_INTERVAL, cooldownTimeLeftCheck, maxTicks)
|
|
|
|
--store the ticker
|
|
openRaidLib.cooldownManager.cooldownTickers[spellId] = newTicker
|
|
newTicker.spellId = spellId
|
|
newTicker.cooldownTimeLeft = cooldownTimeLeft
|
|
newTicker.startTime = GetTime()
|
|
newTicker.endTime = GetTime() + cooldownTimeLeft
|
|
end
|
|
|
|
local cooldownGetUnitTable = function(unitName, shouldWipe)
|
|
local unitCooldownTable = openRaidLib.cooldownManager.playerData[unitName]
|
|
--check if the unit has a cooldownTable
|
|
if (not unitCooldownTable) then
|
|
unitCooldownTable = {}
|
|
openRaidLib.cooldownManager.playerData[unitName] = unitCooldownTable
|
|
else
|
|
--as the unit could have changed a talent or spec, wipe the table before using it
|
|
if (shouldWipe) then
|
|
table.wipe(unitCooldownTable)
|
|
end
|
|
end
|
|
|
|
return unitCooldownTable
|
|
end
|
|
|
|
--update a single spell time and charges
|
|
--called when the player casted a cooldown and when received a cooldown update from another player
|
|
--only update the db, no other action is taken
|
|
local singleCooldownUpdate = function(unitName, spellId, newTimeLeft, newCharges, startTime, duration)
|
|
local unitCooldownTable = cooldownGetUnitTable(unitName)
|
|
local spellIdTable = unitCooldownTable[spellId] or {}
|
|
spellIdTable[1] = newTimeLeft
|
|
spellIdTable[2] = newCharges
|
|
spellIdTable[3] = startTime
|
|
spellIdTable[4] = duration
|
|
unitCooldownTable[spellId] = spellIdTable
|
|
end
|
|
|
|
function openRaidLib.cooldownManager.GetAllPlayersCooldown()
|
|
return openRaidLib.cooldownManager.playerData
|
|
end
|
|
|
|
--@playerName: name of the player
|
|
function openRaidLib.cooldownManager.GetPlayerCooldowns(playerName)
|
|
return openRaidLib.cooldownManager.playerData[playerName]
|
|
end
|
|
|
|
function openRaidLib.cooldownManager.OnPlayerCast(event, spellId)
|
|
--player casted a spell, check if the spell is registered as cooldown
|
|
local playerSpec = openRaidLib.GetPlayerSpecId()
|
|
if (playerSpec) then
|
|
if (LIB_OPEN_RAID_COOLDOWNS_BY_SPEC[playerSpec] and LIB_OPEN_RAID_COOLDOWNS_BY_SPEC[playerSpec][spellId]) then
|
|
--get the cooldown time for this spell
|
|
local timeLeft, charges, startTime, duration = openRaidLib.cooldownManager.GetCooldownStatus(spellId)
|
|
local playerName = UnitName("player")
|
|
local playerCooldownTable = openRaidLib.cooldownManager.GetPlayerCooldowns(playerName)
|
|
|
|
--update the time left
|
|
singleCooldownUpdate(playerName, spellId, timeLeft, charges, startTime, duration)
|
|
|
|
--trigger a public callback
|
|
openRaidLib.publicCallback.TriggerCallback("CooldownUpdate", playerName, spellId, timeLeft, charges, startTime, duration, playerCooldownTable, openRaidLib.cooldownManager.playerData)
|
|
|
|
--send to comm
|
|
openRaidLib.cooldownManager.SendCooldownUpdate(spellId, timeLeft, charges, startTime, duration)
|
|
|
|
--create a timer to monitor the time of this cooldown
|
|
--as there's just a few of them to monitor, there's no issue on creating one timer per spell
|
|
cooldownStartTicker(spellId, timeLeft)
|
|
end
|
|
end
|
|
end
|
|
openRaidLib.internalCallback.RegisterCallback("playerCast", openRaidLib.cooldownManager.OnPlayerCast)
|
|
|
|
--received a cooldown update from another unit (sent by the function above)
|
|
openRaidLib.commHandler.RegisterComm(CONST_COMM_COOLDOWNUPDATE_PREFIX, function(data, sourceName)
|
|
--get data
|
|
local dataAsArray = data
|
|
local spellId = tonumber(dataAsArray[1])
|
|
local cooldownTimer = tonumber(dataAsArray[2])
|
|
local charges = tonumber(dataAsArray[3])
|
|
local startTime = tonumber(dataAsArray[4])
|
|
local duration = tonumber(dataAsArray[5])
|
|
|
|
--check integraty
|
|
if (not spellId or spellId == 0) then
|
|
return diagnosticError("cooldownManager|comm received|spellId is invalid")
|
|
|
|
elseif (not cooldownTimer) then
|
|
return diagnosticError("cooldownManager|comm received|cooldownTimer is invalid")
|
|
|
|
elseif (not charges) then
|
|
return diagnosticError("cooldownManager|comm received|charges is invalid")
|
|
|
|
elseif (not startTime) then
|
|
return diagnosticError("cooldownManager|comm received|startTime is invalid")
|
|
|
|
elseif (not duration) then
|
|
return diagnosticError("cooldownManager|comm received|duration is invalid")
|
|
end
|
|
|
|
--update
|
|
singleCooldownUpdate(sourceName, spellId, cooldownTimer, charges, startTime, duration)
|
|
|
|
--trigger a public callback
|
|
openRaidLib.publicCallback.TriggerCallback("CooldownUpdate", sourceName, spellId, cooldownTimer, charges, startTime, duration, openRaidLib.cooldownManager.playerData)
|
|
end)
|
|
|
|
--when the player is ressed while in a group, send the cooldown list
|
|
function openRaidLib.cooldownManager.OnPlayerRess()
|
|
--check if is in group
|
|
if (openRaidLib.IsInGroup()) then
|
|
openRaidLib.Schedules.NewUniqueTimer(1.0 + math.random(0.0, 6.0), openRaidLib.cooldownManager.SendAllCooldowns, "cooldownManager", "sendAllCooldowns_Schedule")
|
|
end
|
|
end
|
|
openRaidLib.internalCallback.RegisterCallback("onPlayerRess", openRaidLib.cooldownManager.OnPlayerRess)
|
|
|
|
--clear data stored
|
|
function openRaidLib.cooldownManager.EraseData()
|
|
table.wipe(openRaidLib.cooldownManager.playerData)
|
|
end
|
|
|
|
function openRaidLib.cooldownManager.OnLeaveGroup()
|
|
--clear the data
|
|
openRaidLib.cooldownManager.EraseData()
|
|
|
|
--trigger a public callback
|
|
openRaidLib.publicCallback.TriggerCallback("CooldownListWiped", openRaidLib.cooldownManager.playerData)
|
|
end
|
|
openRaidLib.internalCallback.RegisterCallback("onLeaveGroup", openRaidLib.cooldownManager.OnLeaveGroup)
|
|
|
|
--adds a list of cooldowns for another player in the group
|
|
--this is called from the received cooldown list from comm
|
|
function openRaidLib.cooldownManager.AddUnitCooldownsList(unitName, cooldownsTable)
|
|
local unitCooldownTable = cooldownGetUnitTable(unitName, true)
|
|
openRaidLib.TCopy(unitCooldownTable, cooldownsTable)
|
|
|
|
--trigger a public callback
|
|
openRaidLib.publicCallback.TriggerCallback("CooldownListUpdate", unitName, unitCooldownTable, openRaidLib.cooldownManager.playerData)
|
|
end
|
|
|
|
--check if a player cooldown is ready or if is in cooldown
|
|
--@spellId: the spellId to check for cooldown
|
|
function openRaidLib.cooldownManager.GetCooldownStatus(spellId)
|
|
--check if is a charge spell
|
|
local cooldownInfo = LIB_OPEN_RAID_COOLDOWNS_INFO[spellId]
|
|
if (cooldownInfo) then
|
|
if (cooldownInfo.charges and cooldownInfo.charges > 1) then
|
|
local chargesAvailable, chargesTotal, start, duration = GetSpellCharges(spellId)
|
|
|
|
if (chargesAvailable == chargesTotal) then
|
|
return 0, chargesTotal, 0, 0 --all charges are ready to use
|
|
else
|
|
--return the time to the next charge
|
|
local timeLeft = start + duration - GetTime()
|
|
local startTimeOffset = start - GetTime()
|
|
return ceil(timeLeft), chargesAvailable, startTimeOffset, duration --time left, charges, startTime
|
|
end
|
|
|
|
else
|
|
local start, duration = GetSpellCooldown(spellId)
|
|
if (start == 0) then --cooldown is ready
|
|
return 0, 1, 0, 0 --time left, charges, startTime
|
|
else
|
|
local timeLeft = start + duration - GetTime()
|
|
local startTimeOffset = start - GetTime()
|
|
return ceil(timeLeft), 0, ceil(startTimeOffset), duration --time left, charges, startTime, duration
|
|
end
|
|
end
|
|
else
|
|
return diagnosticError("cooldownManager|GetCooldownStatus()|cooldownInfo not found|", spellId)
|
|
end
|
|
end
|
|
|
|
--send to comm all cooldowns available for the player
|
|
function openRaidLib.cooldownManager.SendAllCooldowns()
|
|
--get the full cooldown list
|
|
local playerCooldownList = openRaidLib.cooldownManager.GetPlayerCooldownList()
|
|
local dataToSend = CONST_COMM_COOLDOWNFULLLIST_PREFIX .. ","
|
|
|
|
--pack
|
|
local playerCooldownString = openRaidLib.PackTable(playerCooldownList)
|
|
dataToSend = dataToSend .. playerCooldownString
|
|
|
|
--send the data
|
|
openRaidLib.commHandler.SendCommData(dataToSend)
|
|
diagnosticComm("SendAllCooldowns| " .. dataToSend) --debug
|
|
end
|
|
|
|
--send to comm a specific cooldown that was just used, a charge got available or its cooldown is over (ready to use)
|
|
function openRaidLib.cooldownManager.SendCooldownUpdate(spellId, cooldownTimeLeft, charges, startTime, duration)
|
|
local dataToSend = CONST_COMM_COOLDOWNUPDATE_PREFIX .. "," .. spellId .. "," .. cooldownTimeLeft .. "," .. charges .. "," .. startTime .. "," .. duration
|
|
openRaidLib.commHandler.SendCommData(dataToSend)
|
|
diagnosticComm("SendCooldownUpdate| " .. dataToSend) --debug
|
|
end
|
|
|
|
--triggered when the lib receives a full list of cooldowns from another player in the raid
|
|
--@data: table received from comm
|
|
--@source: player name
|
|
function openRaidLib.cooldownManager.OnReceiveCooldowns(data, source)
|
|
--unpack the table as a pairs table | the cooldown info uses 5 indexes
|
|
local unpackedTable = openRaidLib.UnpackTable(data, 1, true, true, 5)
|
|
--add the list of cooldowns
|
|
openRaidLib.cooldownManager.AddUnitCooldownsList(source, unpackedTable)
|
|
end
|
|
openRaidLib.commHandler.RegisterComm(CONST_COMM_COOLDOWNFULLLIST_PREFIX, openRaidLib.cooldownManager.OnReceiveCooldowns)
|
|
|
|
|
|
--build a list with the local player cooldowns
|
|
function openRaidLib.cooldownManager.GetPlayerCooldownList()
|
|
--get the player specId
|
|
local specId = openRaidLib.GetPlayerSpecId()
|
|
if (specId) then
|
|
--get the cooldowns for the specialization
|
|
local playerCooldowns = LIB_OPEN_RAID_COOLDOWNS_BY_SPEC[specId]
|
|
if (not playerCooldowns) then
|
|
diagnosticError("cooldownManager|GetPlayerCooldownList|can't find player cooldowns for specId:", specId)
|
|
return {}
|
|
end
|
|
|
|
local cooldowns = {}
|
|
local talentsHash, talentsIndex = openRaidLib.GetPlayerTalents()
|
|
|
|
for cooldownSpellId, cooldownType in pairs(playerCooldowns) do
|
|
--get all the information about this cooldow
|
|
local cooldownInfo = LIB_OPEN_RAID_COOLDOWNS_INFO[cooldownSpellId]
|
|
if (cooldownInfo) then
|
|
--does this cooldown is based on a talent?
|
|
local talentId = cooldownInfo.talent
|
|
if (talentId) then
|
|
--check if the player has the talent selected
|
|
if (talentsHash[talentId]) then
|
|
cooldowns[#cooldowns+1] = cooldownSpellId
|
|
local timeLeft, charges, startTime, duration = openRaidLib.cooldownManager.GetCooldownStatus(cooldownSpellId)
|
|
cooldowns[#cooldowns+1] = timeLeft
|
|
cooldowns[#cooldowns+1] = charges
|
|
cooldowns[#cooldowns+1] = startTime
|
|
cooldowns[#cooldowns+1] = duration
|
|
end
|
|
else
|
|
cooldowns[#cooldowns+1] = cooldownSpellId
|
|
local timeLeft, charges, startTime, duration = openRaidLib.cooldownManager.GetCooldownStatus(cooldownSpellId)
|
|
cooldowns[#cooldowns+1] = timeLeft
|
|
cooldowns[#cooldowns+1] = charges
|
|
cooldowns[#cooldowns+1] = startTime
|
|
cooldowns[#cooldowns+1] = duration
|
|
end
|
|
end
|
|
end
|
|
return cooldowns
|
|
else
|
|
return {}
|
|
end
|
|
end
|
|
|
|
--> vintage cooldown tracker
|
|
C_Timer.After(0.1, function()
|
|
local vintageCDTrackerFrame = CreateFrame("frame")
|
|
vintageCDTrackerFrame:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
|
|
local allCooldownsFromLib = LIB_OPEN_RAID_COOLDOWNS_INFO
|
|
local recentCastedSpells = {}
|
|
|
|
vintageCDTrackerFrame:SetScript("OnEvent", function(self, event, ...)
|
|
if (event == "UNIT_SPELLCAST_SUCCEEDED") then
|
|
local unit, castGUID, spellId = ...
|
|
if (UnitInParty(unit) or UnitInRaid(unit)) then
|
|
local unitName = UnitName(unit)
|
|
local cooldownInfo = allCooldownsFromLib[spellId]
|
|
if (cooldownInfo and unitName and not openRaidLib.cooldownManager.GetPlayerCooldowns(unitName)) then
|
|
--check for cast_success spam from channel spells
|
|
local unitCastCooldown = recentCastedSpells[UnitGUID(unit)]
|
|
if (not unitCastCooldown) then
|
|
unitCastCooldown = {}
|
|
recentCastedSpells[UnitGUID(unit)] = unitCastCooldown
|
|
end
|
|
|
|
if (not unitCastCooldown[spellId] or unitCastCooldown[spellId]+5 < GetTime()) then
|
|
unitCastCooldown[spellId] = GetTime()
|
|
--trigger a cooldown usage
|
|
|
|
local duration = cooldownInfo.duration
|
|
--time left, charges, startTimeDeviation, duration
|
|
singleCooldownUpdate(unitName, spellId, duration, 0, 0, duration)
|
|
|
|
--trigger a public callback
|
|
openRaidLib.publicCallback.TriggerCallback("CooldownUpdate", unitName, spellId, duration, 0, 0, duration, openRaidLib.cooldownManager.playerData)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
end)
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--> ~equipment
|
|
|
|
openRaidLib.gearManager = {
|
|
--structure:
|
|
--[playerName] = {ilevel = 100, durability = 100, weaponEnchant = 0, noGems = {}, noEnchants = {}}
|
|
playerData = {},
|
|
}
|
|
|
|
function openRaidLib.gearManager.GetAllPlayersGear()
|
|
return openRaidLib.gearManager.playerData
|
|
end
|
|
|
|
function openRaidLib.gearManager.GetPlayerGear(playerName, createNew)
|
|
local playerGearInfo = openRaidLib.gearManager.playerData[playerName]
|
|
if (not playerGearInfo and createNew) then
|
|
playerGearInfo = {
|
|
ilevel = 0,
|
|
durability = 0,
|
|
weaponEnchant = 0,
|
|
noGems = {},
|
|
noEnchants = {},
|
|
}
|
|
openRaidLib.gearManager.playerData[playerName] = playerGearInfo
|
|
end
|
|
return playerGearInfo
|
|
end
|
|
|
|
--return an integer between zero and one hundret indicating the player gear durability
|
|
function openRaidLib.gearManager.GetGearDurability()
|
|
local durabilityTotalPercent, totalItems = 0, 0
|
|
for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
|
|
local durability, maxDurability = GetInventoryItemDurability(i)
|
|
if (durability and maxDurability) then
|
|
local itemDurability = durability / maxDurability * 100
|
|
durabilityTotalPercent = durabilityTotalPercent + itemDurability
|
|
totalItems = totalItems + 1
|
|
end
|
|
end
|
|
|
|
if (totalItems == 0) then
|
|
return 100
|
|
end
|
|
|
|
return floor(durabilityTotalPercent / totalItems)
|
|
end
|
|
|
|
--clear data stored
|
|
function openRaidLib.gearManager.EraseData()
|
|
table.wipe(openRaidLib.gearManager.playerData)
|
|
end
|
|
|
|
function openRaidLib.gearManager.OnLeaveGroup()
|
|
--clear the data
|
|
openRaidLib.gearManager.EraseData()
|
|
|
|
--trigger a public callback
|
|
openRaidLib.publicCallback.TriggerCallback("GearListWiped", openRaidLib.gearManager.playerData)
|
|
end
|
|
openRaidLib.internalCallback.RegisterCallback("onLeaveGroup", openRaidLib.gearManager.OnLeaveGroup)
|
|
|
|
--when the player is ressed while in a group, send the cooldown list
|
|
function openRaidLib.gearManager.OnPlayerRess()
|
|
--check if is in group
|
|
if (openRaidLib.IsInGroup()) then
|
|
openRaidLib.Schedules.NewUniqueTimer(1.0 + math.random(0.0, 6.0), openRaidLib.gearManager.SendDurability, "gearManager", "sendDurability_Schedule")
|
|
end
|
|
end
|
|
openRaidLib.internalCallback.RegisterCallback("onPlayerRess", openRaidLib.gearManager.OnPlayerRess)
|
|
|
|
--send only the gear durability
|
|
function openRaidLib.gearManager.SendDurability()
|
|
local dataToSend = CONST_COMM_GEARINFO_DURABILITY_PREFIX .. ","
|
|
local playerGearDurability = openRaidLib.gearManager.GetGearDurability()
|
|
|
|
dataToSend = dataToSend .. playerGearDurability
|
|
|
|
--send the data
|
|
openRaidLib.commHandler.SendCommData(dataToSend)
|
|
diagnosticComm("SendGearDurabilityData| " .. dataToSend) --debug
|
|
end
|
|
|
|
function openRaidLib.gearManager.OnReceiveGearDurability(data, source)
|
|
local durability = tonumber(data[1])
|
|
openRaidLib.gearManager.UpdateUnitGearDurability(source, durability)
|
|
end
|
|
openRaidLib.commHandler.RegisterComm(CONST_COMM_GEARINFO_DURABILITY_PREFIX, openRaidLib.gearManager.OnReceiveGearDurability)
|
|
|
|
--on receive the durability (sent when the player get a ress)
|
|
function openRaidLib.gearManager.UpdateUnitGearDurability(playerName, durability)
|
|
local playerGearInfo = openRaidLib.gearManager.GetPlayerGear(playerName)
|
|
if (playerGearInfo) then
|
|
playerGearInfo.durability = durability
|
|
openRaidLib.publicCallback.TriggerCallback("GearDurabilityUpdate", playerName, durability, playerGearInfo, openRaidLib.gearManager.GetAllPlayersGear())
|
|
end
|
|
end
|
|
|
|
--get gear information from what the player has equipped at the moment
|
|
function openRaidLib.gearManager.GetPlayerGearInfo()
|
|
|
|
--get the player class and specId
|
|
local _, playerClass = UnitClass("player")
|
|
local specId = openRaidLib.GetPlayerSpecId()
|
|
--get which attribute the spec uses
|
|
local specMainAttribute = openRaidLib.specAttribute[playerClass][specId] --1 int, 2 dex, 3 str
|
|
|
|
if (not specId or not specMainAttribute) then
|
|
return {0, 0, 0, {}, {}}
|
|
end
|
|
|
|
--item level
|
|
local itemLevel
|
|
if (_G.GetAverageItemLevel) then
|
|
local _, _itemLevel = GetAverageItemLevel()
|
|
itemLevel = floor(_itemLevel)
|
|
else
|
|
itemLevel = 0
|
|
end
|
|
|
|
--repair status
|
|
local gearDurability = openRaidLib.gearManager.GetGearDurability()
|
|
|
|
--get weapon enchant
|
|
local weaponEnchant = 0
|
|
local _, _, _, mainHandEnchantId, _, _, _, offHandEnchantId = GetWeaponEnchantInfo()
|
|
if (LIB_OPEN_RAID_WEAPON_ENCHANT_IDS[mainHandEnchantId]) then
|
|
weaponEnchant = 1
|
|
|
|
elseif(LIB_OPEN_RAID_WEAPON_ENCHANT_IDS[offHandEnchantId]) then
|
|
weaponEnchant = 1
|
|
end
|
|
|
|
--enchants and gems
|
|
--hold equipmentSlotId of equipment with a gem socket but it's empty
|
|
local slotsWithoutGems = {}
|
|
--hold equipmentSlotId of equipments without an enchant
|
|
local slotsWithoutEnchant = {}
|
|
|
|
for equipmentSlotId = 1, 17 do
|
|
|
|
local itemLink = GetInventoryItemLink("player", equipmentSlotId)
|
|
|
|
if (itemLink) then
|
|
--get the information from the item
|
|
local _, itemId, enchantId, gemId1, gemId2, gemId3, gemId4, suffixId, uniqueId, levelOfTheItem, specId, upgradeInfo, instanceDifficultyId, numBonusIds, restLink = strsplit(":", itemLink)
|
|
local gemsIds = {gemId1, gemId2, gemId3, gemId4}
|
|
|
|
--enchant
|
|
--check if the slot can receive enchat and if the equipment has an enchant
|
|
local enchantAttribute = LIB_OPEN_RAID_ENCHANT_SLOTS[equipmentSlotId]
|
|
if (enchantAttribute) then --this slot can receive an enchat
|
|
|
|
--check if this slot is relevant for the class, some slots can have enchants only for Agility which won't matter for Priests as an example
|
|
--if the value is an integer it points to an attribute (int, dex, str), otherwise it's true (boolean)
|
|
local slotIsRelevant = true
|
|
if (type (enchantAttribute) == "number") then
|
|
if (specMainAttribute ~= enchantAttribute) then
|
|
slotIsRelevant = false
|
|
end
|
|
end
|
|
|
|
if (slotIsRelevant) then
|
|
--does the slot has any enchant?
|
|
if (not enchantId or enchantId == "0" or enchantId == "") then
|
|
slotsWithoutEnchant[#slotsWithoutEnchant+1] = equipmentSlotId
|
|
|
|
else
|
|
--convert to integer
|
|
local enchantIdInt = tonumber(enchantId)
|
|
if (enchantIdInt) then
|
|
--does the enchant is relevent for the character?
|
|
if (not LIB_OPEN_RAID_ENCHANT_IDS[enchantIdInt]) then
|
|
slotsWithoutEnchant[#slotsWithoutEnchant+1] = equipmentSlotId
|
|
end
|
|
|
|
else
|
|
--the enchat has an invalid id
|
|
slotsWithoutEnchant[#slotsWithoutEnchant+1] = equipmentSlotId
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--gems
|
|
local itemStatsTable = {}
|
|
--fill the table above with information about the item
|
|
GetItemStats(itemLink, itemStatsTable)
|
|
|
|
--check if the item has a socket
|
|
if (itemStatsTable.EMPTY_SOCKET_PRISMATIC) then
|
|
--check if the socket is empty
|
|
for i = 1, itemStatsTable.EMPTY_SOCKET_PRISMATIC do
|
|
local gemId = tonumber(gemsIds[i])
|
|
if (not gemId or gemId == 0) then
|
|
slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
|
|
|
|
--check if the gem is not a valid gem (deprecated gem)
|
|
elseif (not LIB_OPEN_RAID_GEM_IDS[gemId]) then
|
|
slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end --end of enchants and gems
|
|
|
|
--build the table with the gear information
|
|
local playerGearInfo = {}
|
|
playerGearInfo[#playerGearInfo+1] = itemLevel --[1]
|
|
playerGearInfo[#playerGearInfo+1] = gearDurability --[2]
|
|
playerGearInfo[#playerGearInfo+1] = weaponEnchant --[3]
|
|
playerGearInfo[#playerGearInfo+1] = slotsWithoutEnchant --[4]
|
|
playerGearInfo[#playerGearInfo+1] = slotsWithoutGems --[5]
|
|
|
|
--update the player table
|
|
openRaidLib.gearManager.AddUnitGearInfoList(UnitName("player"), itemLevel, gearDurability, weaponEnchant, slotsWithoutEnchant, slotsWithoutGems)
|
|
|
|
return playerGearInfo
|
|
end
|
|
|
|
--when received the gear update from another player, store it and trigger a callback
|
|
function openRaidLib.gearManager.AddUnitGearInfoList(playerName, itemLevel, durability, weaponEnchant, noEnchantTable, noGemsTable)
|
|
local playerGearInfo = openRaidLib.gearManager.GetPlayerGear(playerName, true)
|
|
|
|
playerGearInfo.ilevel = itemLevel
|
|
playerGearInfo.durability = durability
|
|
playerGearInfo.weaponEnchant = weaponEnchant
|
|
playerGearInfo.noGems = noGemsTable
|
|
playerGearInfo.noEnchants = noEnchantTable
|
|
|
|
openRaidLib.publicCallback.TriggerCallback("GearUpdate", playerName, playerGearInfo, openRaidLib.gearManager.GetAllPlayersGear())
|
|
end
|
|
|
|
--triggered when the lib receives a gear information from another player in the raid
|
|
--@data: table received from comm
|
|
--@source: player name
|
|
function openRaidLib.gearManager.OnReceiveGearFullInfo(data, source)
|
|
local itemLevel = tonumber(data[1])
|
|
local durability = tonumber(data[2])
|
|
local weaponEnchant = tonumber(data[3])
|
|
|
|
local noEnchantTableSize = tonumber(data[4])
|
|
local noGemsTableIndex = tonumber(noEnchantTableSize + 5)
|
|
local noGemsTableSize = data[noGemsTableIndex]
|
|
|
|
--openRaidLib.UnpackTable(table, index, isPair, valueIsTable, amountOfValues)
|
|
|
|
--unpack the enchant data as a ipairs table
|
|
local noEnchantTableUnpacked = openRaidLib.UnpackTable(data, 4, false, false, noEnchantTableSize)
|
|
--unpack the enchant data as a ipairs table
|
|
local noGemsTableUnpacked = openRaidLib.UnpackTable(data, noGemsTableIndex, false, false, noGemsTableSize)
|
|
|
|
--add to the list of gear information
|
|
openRaidLib.gearManager.AddUnitGearInfoList(source, itemLevel, durability, weaponEnchant, noEnchantTableUnpacked, noGemsTableUnpacked)
|
|
end
|
|
openRaidLib.commHandler.RegisterComm(CONST_COMM_GEARINFO_FULL_PREFIX, openRaidLib.gearManager.OnReceiveGearFullInfo)
|
|
|
|
function openRaidLib.gearManager.SendAllGearInfo()
|
|
--get gear information, gear info has 4 indexes:
|
|
--[1] int item level
|
|
--[2] int durability
|
|
--[3] int weapon enchant
|
|
--[3] table with integers of equipSlot without enchant
|
|
--[4] table with integers of equipSlot which has a gem slot but the slot is empty
|
|
|
|
local dataToSend = CONST_COMM_GEARINFO_FULL_PREFIX .. ","
|
|
local playerGearInfo = openRaidLib.gearManager.GetPlayerGearInfo()
|
|
|
|
dataToSend = dataToSend .. playerGearInfo[1] .. "," --item level
|
|
dataToSend = dataToSend .. playerGearInfo[2] .. "," --durability
|
|
dataToSend = dataToSend .. playerGearInfo[3] .. "," --weapon enchant
|
|
dataToSend = dataToSend .. openRaidLib.PackTable(playerGearInfo[4]) .. "," --slots without enchant
|
|
dataToSend = dataToSend .. openRaidLib.PackTable(playerGearInfo[5]) -- slots with empty gem sockets
|
|
|
|
--send the data
|
|
openRaidLib.commHandler.SendCommData(dataToSend)
|
|
diagnosticComm("SendGearFullData| " .. dataToSend) --debug
|
|
end
|
|
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--> ~player general ~info
|
|
|
|
openRaidLib.playerInfoManager = {
|
|
--structure:
|
|
--[playerName] = {ilevel = 100, durability = 100, weaponEnchant = 0, noGems = {}, noEnchants = {}}
|
|
playerData = {},
|
|
}
|
|
|
|
function openRaidLib.playerInfoManager.GetAllPlayersInfo()
|
|
return openRaidLib.playerInfoManager.playerData
|
|
end
|
|
|
|
function openRaidLib.playerInfoManager.GetPlayerInfo(playerName, createNew)
|
|
local playerInfo = openRaidLib.playerInfoManager.playerData[playerName]
|
|
if (not playerInfo and createNew) then
|
|
playerInfo = {
|
|
specId = 0,
|
|
renown = 1,
|
|
covenantId = 0,
|
|
talents = {},
|
|
conduits = {},
|
|
}
|
|
openRaidLib.playerInfoManager.playerData[playerName] = playerInfo
|
|
end
|
|
return playerInfo
|
|
end
|
|
|
|
function openRaidLib.playerInfoManager.AddPlayerInfo(playerName, specId, renown, covenantId, talentsTableUnpacked, conduitsTableUnpacked)
|
|
local playerInfo = openRaidLib.playerInfoManager.GetPlayerInfo(playerName, true)
|
|
|
|
playerInfo.specId = specId
|
|
playerInfo.renown = renown
|
|
playerInfo.covenantId = covenantId
|
|
playerInfo.talents = talentsTableUnpacked
|
|
playerInfo.conduits = conduitsTableUnpacked
|
|
|
|
openRaidLib.publicCallback.TriggerCallback("PlayerUpdate", playerName, openRaidLib.playerInfoManager.playerData[playerName], openRaidLib.playerInfoManager.GetAllPlayersInfo())
|
|
end
|
|
|
|
--triggered when the lib receives a gear information from another player in the raid
|
|
--@data: table received from comm
|
|
--@source: player name
|
|
function openRaidLib.playerInfoManager.OnReceivePlayerFullInfo(data, source)
|
|
local specId = tonumber(data[1])
|
|
local renown = tonumber(data[2])
|
|
local covenantId = tonumber(data[3])
|
|
local talentsSize = tonumber(data[4])
|
|
local conduitsTableIndex = tonumber((talentsSize + 1) + 3) + 1 -- +3 = specIndex renowIndex covenantIdIndex | talentSizeIndex + talentSize | +1
|
|
local conduitsSize = data[conduitsTableIndex]
|
|
|
|
--unpack the talents data as a ipairs table
|
|
local talentsTableUnpacked = openRaidLib.UnpackTable(data, 4, false, false, talentsSize)
|
|
|
|
--unpack the conduits data as a ipairs table
|
|
local conduitsTableUnpacked = openRaidLib.UnpackTable(data, conduitsTableIndex, false, false, conduitsSize)
|
|
|
|
--add to the list of players information and also trigger a public callback
|
|
openRaidLib.playerInfoManager.AddPlayerInfo(source, specId, renown, covenantId, talentsTableUnpacked, conduitsTableUnpacked)
|
|
end
|
|
openRaidLib.commHandler.RegisterComm(CONST_COMM_PLAYERINFO_PREFIX, openRaidLib.playerInfoManager.OnReceivePlayerFullInfo)
|
|
|
|
function openRaidLib.playerInfoManager.SendAllPlayerInfo()
|
|
local playerInfo = openRaidLib.playerInfoManager.GetPlayerFullInfo()
|
|
|
|
local dataToSend = CONST_COMM_PLAYERINFO_PREFIX .. ","
|
|
dataToSend = dataToSend .. playerInfo[1] .. "," --spec id
|
|
dataToSend = dataToSend .. playerInfo[2] .. "," --renown
|
|
dataToSend = dataToSend .. playerInfo[3] .. "," --covenantId
|
|
dataToSend = dataToSend .. openRaidLib.PackTable(playerInfo[4]) .. "," --talents
|
|
dataToSend = dataToSend .. openRaidLib.PackTable(playerInfo[5]) .. "," --conduits
|
|
|
|
--send the data
|
|
openRaidLib.commHandler.SendCommData(dataToSend)
|
|
diagnosticComm("SendGetPlayerInfoFullData| " .. dataToSend) --debug
|
|
end
|
|
|
|
function openRaidLib.playerInfoManager.GetPlayerFullInfo()
|
|
local playerInfo = {}
|
|
|
|
if (isTimewalkWoW()) then
|
|
--indexes: specId, renown, covenant, talent, conduits
|
|
--return a placeholder table
|
|
return {0, 0, 0, {0, 0, 0, 0, 0, 0, 0}, {0, 0}}
|
|
end
|
|
|
|
--spec
|
|
local specId = 0
|
|
local selectedSpecialization = GetSpecialization()
|
|
if (selectedSpecialization) then
|
|
specId = GetSpecializationInfo(selectedSpecialization) or 0
|
|
end
|
|
playerInfo[1] = specId
|
|
|
|
--renown
|
|
local renown = C_CovenantSanctumUI.GetRenownLevel() or 1
|
|
playerInfo[2] = renown
|
|
|
|
--covenant
|
|
local covenant = C_Covenants.GetActiveCovenantID()
|
|
playerInfo[3] = covenant
|
|
|
|
--talents
|
|
local talents = {0, 0, 0, 0, 0, 0, 0}
|
|
for talentTier = 1, 7 do
|
|
for talentColumn = 1, 3 do
|
|
local talentId, name, texture, selected, available = GetTalentInfo(talentTier, talentColumn, 1)
|
|
if (selected) then
|
|
talents[talentTier] = talentId
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
playerInfo[4] = talents
|
|
|
|
--conduits
|
|
local conduits = {}
|
|
local soulbindID = C_Soulbinds.GetActiveSoulbindID()
|
|
if (soulbindID ~= 0) then
|
|
local soulbindData = C_Soulbinds.GetSoulbindData(soulbindID)
|
|
if (soulbindData ~= 0) then
|
|
local tree = soulbindData.tree
|
|
local nodes = tree.nodes
|
|
|
|
table.sort(nodes, function(t1, t2) return t1.row < t2.row end)
|
|
local C_Soulbinds_GetConduitCollectionData = C_Soulbinds.GetConduitCollectionData
|
|
for nodeId, nodeInfo in ipairs(nodes) do
|
|
--check if the node is a conduit placed by the player
|
|
|
|
if (nodeInfo.state == Enum.SoulbindNodeState.Selected) then
|
|
local conduitId = nodeInfo.conduitID
|
|
local conduitRank = nodeInfo.conduitRank
|
|
|
|
if (conduitId and conduitRank) then
|
|
--have spell id when it's a default conduit from the game
|
|
local spellId = nodeInfo.spellID
|
|
--have conduit id when is a conduid placed by the player
|
|
local conduitId = nodeInfo.conduitID
|
|
|
|
if (spellId == 0) then
|
|
--is player conduit
|
|
spellId = C_Soulbinds.GetConduitSpellID(nodeInfo.conduitID, nodeInfo.conduitRank)
|
|
conduits[#conduits+1] = spellId
|
|
local collectionData = C_Soulbinds_GetConduitCollectionData(conduitId)
|
|
conduits[#conduits+1] = collectionData and collectionData.conduitItemLevel or 0
|
|
else
|
|
--is default conduit
|
|
conduits[#conduits+1] = spellId
|
|
conduits[#conduits+1] = 0
|
|
end
|
|
|
|
--local link = C_Soulbinds.GetConduitHyperlink( conduitId, conduitRank )
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
playerInfo[5] = conduits
|
|
|
|
return playerInfo
|
|
|
|
--/run Details:Dump (Enum.SoulbindNodeState)
|
|
--/run Details:Dump ( nodes )
|
|
|
|
--[=[
|
|
["Selectable"] = 2
|
|
["Unavailable"] = 0
|
|
["Unselected"] = 1
|
|
["Selected"] = 3
|
|
--]=]
|
|
|
|
--[=[
|
|
[1] = table {
|
|
["conduitID"] = 195
|
|
["conduitType"] = 1
|
|
["state"] = 3
|
|
["icon"] = 463891
|
|
["parentNodeIDs"] = table {
|
|
["1"] = 1316
|
|
}
|
|
["column"] = 0
|
|
["ID"] = 1305
|
|
["conduitRank"] = 4
|
|
["row"] = 1
|
|
["spellID"] = 0
|
|
}
|
|
--]=]
|
|
end
|
|
|
|
function openRaidLib.playerInfoManager.onEnterWorld()
|
|
openRaidLib.playerInfoManager.GetPlayerFullInfo()
|
|
end
|
|
openRaidLib.internalCallback.RegisterCallback("onEnterWorld", openRaidLib.playerInfoManager.onEnterWorld)
|
|
|
|
--talent update
|
|
function openRaidLib.playerInfoManager.sendTalentUpdate()
|
|
--talents
|
|
local talentsToSend = {0, 0, 0, 0, 0, 0, 0}
|
|
for talentTier = 1, 7 do
|
|
for talentColumn = 1, 3 do
|
|
local talentId, name, texture, selected, available = GetTalentInfo(talentTier, talentColumn, 1)
|
|
if (selected) then
|
|
talentsToSend[talentTier] = talentId
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
local dataToSend = CONST_COMM_PLAYERINFO_TALENTS_PREFIX .. ","
|
|
local talentsString = openRaidLib.PackTable(talentsToSend)
|
|
dataToSend = dataToSend .. talentsString
|
|
|
|
--send the data
|
|
openRaidLib.commHandler.SendCommData(dataToSend)
|
|
diagnosticComm("SendTalentUpdateData| " .. dataToSend) --debug
|
|
end
|
|
|
|
function openRaidLib.playerInfoManager.scheduleTalentUpdate()
|
|
openRaidLib.Schedules.NewUniqueTimer(1 + math.random(0, 1), openRaidLib.playerInfoManager.sendTalentUpdate, "playerInfoManager", "sendTalent_Schedule")
|
|
end
|
|
openRaidLib.internalCallback.RegisterCallback("talentUpdate", openRaidLib.playerInfoManager.scheduleTalentUpdate)
|
|
|
|
function openRaidLib.playerInfoManager.OnReceiveTalentsUpdate(data, source)
|
|
local talentsTableUnpacked = openRaidLib.UnpackTable(data, 1, false, false, 7)
|
|
|
|
local playerInfo = openRaidLib.playerInfoManager.GetPlayerInfo(source)
|
|
if (playerInfo) then
|
|
playerInfo.talents = talentsTableUnpacked
|
|
|
|
--trigger public callback event
|
|
openRaidLib.publicCallback.TriggerCallback("TalentUpdate", source, playerInfo, openRaidLib.playerInfoManager.GetAllPlayersInfo())
|
|
end
|
|
end
|
|
openRaidLib.commHandler.RegisterComm(CONST_COMM_PLAYERINFO_TALENTS_PREFIX, openRaidLib.playerInfoManager.OnReceiveTalentsUpdate)
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------
|
|
--> data
|
|
|
|
--which is the main attribute of each spec
|
|
--1 Intellect
|
|
--2 Agility
|
|
--3 Strenth
|
|
openRaidLib.specAttribute = {
|
|
["DEMONHUNTER"] = {
|
|
[577] = 2,
|
|
[581] = 2,
|
|
},
|
|
["DEATHKNIGHT"] = {
|
|
[250] = 3,
|
|
[251] = 3,
|
|
[252] = 3,
|
|
},
|
|
["WARRIOR"] = {
|
|
[71] = 3,
|
|
[72] = 3,
|
|
[73] = 3,
|
|
},
|
|
["MAGE"] = {
|
|
[62] = 1,
|
|
[63] = 1,
|
|
[64] = 1,
|
|
},
|
|
["ROGUE"] = {
|
|
[259] = 2,
|
|
[260] = 2,
|
|
[261] = 2,
|
|
},
|
|
["DRUID"] = {
|
|
[102] = 1,
|
|
[103] = 2,
|
|
[104] = 2,
|
|
[105] = 1,
|
|
},
|
|
["HUNTER"] = {
|
|
[253] = 2,
|
|
[254] = 2,
|
|
[255] = 2,
|
|
},
|
|
["SHAMAN"] = {
|
|
[262] = 1,
|
|
[263] = 2,
|
|
[264] = 1,
|
|
},
|
|
["PRIEST"] = {
|
|
[256] = 1,
|
|
[257] = 1,
|
|
[258] = 1,
|
|
},
|
|
["WARLOCK"] = {
|
|
[265] = 1,
|
|
[266] = 1,
|
|
[267] =1 ,
|
|
},
|
|
["PALADIN"] = {
|
|
[65] = 1,
|
|
[66] = 3,
|
|
[70] = 3,
|
|
},
|
|
["MONK"] = {
|
|
[268] = 2,
|
|
[269] = 2,
|
|
[270] = 1,
|
|
}
|
|
}
|
|
|