319 lines
8.3 KiB
Lua
319 lines
8.3 KiB
Lua
GuildRecipesOcto = GuildRecipesOcto or {}
|
|
|
|
---@class GuildRecipesOcto
|
|
local m = GuildRecipesOcto
|
|
|
|
if m.MessageHandler then return end
|
|
|
|
---@type MessageCommand
|
|
local MessageCommand = {
|
|
RequestTradeskill = "RTS",
|
|
Tradeskill = "TS",
|
|
Ping = "PING",
|
|
Pong = "PONG",
|
|
VersionCheck = "VERSIONCHECK",
|
|
Version = "VERSION",
|
|
}
|
|
|
|
---@alias MessageCommand
|
|
---| "RTS"
|
|
---| "TS"
|
|
---| "PING"
|
|
---| "PONG"
|
|
---| "VERSIONCHECK"
|
|
---| "VERSION"
|
|
|
|
---@class MessageHandler
|
|
---@field send_tradeskill fun( tradeskill: string )
|
|
---@field request_tradeskill fun( tradeskill: string )
|
|
---@field request_tradeskills fun()
|
|
---@field version_check fun()
|
|
|
|
local M = {}
|
|
|
|
---@param ace_timer AceTimer
|
|
---@param ace_serializer AceSerializer
|
|
---@param ace_comm AceComm
|
|
function M.new( ace_timer, ace_serializer, ace_comm )
|
|
local pinging = false
|
|
local best_ping = {}
|
|
local var_names = {
|
|
n = "name",
|
|
q = "quality",
|
|
c = "count",
|
|
p = "players",
|
|
d = "data",
|
|
i = "items",
|
|
ts = "tradeskill",
|
|
h = "hashes",
|
|
lu = "last_update",
|
|
--tlu = "tradeskills_last_update",
|
|
Alc = "Alchemy",
|
|
Bla = "Blacksmithing",
|
|
Eng = "Engineering",
|
|
Enc = "Enchanting",
|
|
Lea = "Leatherworking",
|
|
Tai = "Tailoring",
|
|
Jew = "Jewelcrafting",
|
|
|
|
}
|
|
setmetatable( var_names, { __index = function( _, key ) return key end } );
|
|
|
|
---@param t table
|
|
local function decode( t )
|
|
local l = {}
|
|
for key, value in pairs( t ) do
|
|
if type( value ) == "table" then
|
|
value = decode( value )
|
|
end
|
|
|
|
l[ var_names[ key ] ] = value
|
|
end
|
|
return l
|
|
end
|
|
|
|
---@param command MessageCommand
|
|
---@param data table?
|
|
local function broadcast( command, data )
|
|
m.debug( string.format( "Broadcasting %s", command ) )
|
|
|
|
ace_comm:SendCommMessage( m.prefix, command .. "::" .. ace_serializer.Serialize( M, data ), "GUILD", nil, "NORMAL" )
|
|
end
|
|
|
|
local function send_tradeskill( tradeskill )
|
|
m.debug( string.format( "Sending %s", tradeskill ) )
|
|
|
|
if not m.db.tradeskills[ tradeskill ] then
|
|
m.debug( string.format( "No data for tradeskill: %s", tradeskill ) )
|
|
return
|
|
end
|
|
|
|
local data = {
|
|
tradeskill = tradeskill,
|
|
recipes = {}
|
|
}
|
|
|
|
for id, item in pairs( m.db.tradeskills[ tradeskill ] ) do
|
|
local players = {}
|
|
for _, p in pairs( m.comma_separated_to_table( item.p ) ) do
|
|
table.insert( players, m.db.players[ tonumber( p ) ] )
|
|
end
|
|
|
|
table.insert( data.recipes, {
|
|
id = id,
|
|
p = players
|
|
} )
|
|
end
|
|
|
|
broadcast( MessageCommand.Tradeskill, data )
|
|
end
|
|
|
|
local function send_tradeskills()
|
|
for tradeskill in pairs( m.db.tradeskills ) do
|
|
send_tradeskill( tradeskill )
|
|
end
|
|
end
|
|
|
|
local function request_tradeskill( tradeskill )
|
|
pinging = true
|
|
best_ping = {}
|
|
|
|
broadcast( MessageCommand.Ping, {
|
|
[string.sub( tradeskill, 1, 3 )] = m.tradeskill_hash( tradeskill )
|
|
} )
|
|
end
|
|
|
|
local function request_tradeskills()
|
|
pinging = true
|
|
best_ping = {}
|
|
local hashes = {}
|
|
|
|
for tradeskill in pairs(m.TRADE_SKILL_LOCALIZATION) do
|
|
hashes[ string.sub( tradeskill, 1, 3 ) ] = m.tradeskill_hash( tradeskill )
|
|
end
|
|
|
|
broadcast( MessageCommand.Ping, hashes )
|
|
end
|
|
|
|
local function version_check()
|
|
broadcast( MessageCommand.VersionCheck )
|
|
end
|
|
|
|
---@param command string
|
|
---@param data table
|
|
---@param sender string
|
|
local function on_command( command, data, sender )
|
|
if command == MessageCommand.Tradeskill then
|
|
--
|
|
-- Receive tradeskill
|
|
--
|
|
m.debug( string.format( "Receiving %s from %s.", data.tradeskill, sender ) )
|
|
local tradeskill = data.tradeskill
|
|
m.db.tradeskills[ tradeskill ] = m.db.tradeskills[ tradeskill ] or {}
|
|
|
|
for _, v in pairs( data.recipes ) do
|
|
if v.id then
|
|
---@type Item
|
|
local item = nil
|
|
if m.db.tradeskills[ tradeskill ][ v.id ] then
|
|
item = {
|
|
id = v.id,
|
|
name = m.db.tradeskills[ tradeskill ][ v.id ].n,
|
|
quality = m.db.tradeskills[ tradeskill ][ v.id ].q
|
|
}
|
|
else
|
|
if tradeskill == "Enchanting" then
|
|
if v and v.id then
|
|
local name = m.Enchants[ v.id ] and m.Enchants[ v.id ].name
|
|
if not name then
|
|
m.error( string.format( "Unknown enchantment received (%d)", v.id ) )
|
|
else
|
|
item = {
|
|
id = v.id,
|
|
name = name,
|
|
}
|
|
end
|
|
else
|
|
m.debug( "empty enchant data??" )
|
|
end
|
|
else
|
|
m.debug( "Fetching item info for " .. tostring( v.id ) )
|
|
m.get_item_info( v.id, function( item_info, players )
|
|
if item_info then
|
|
local i = {
|
|
id = item_info.id,
|
|
name = item_info.name,
|
|
quality = item_info.quality
|
|
}
|
|
|
|
m.update_tradeskill_item( tradeskill, i, players )
|
|
else
|
|
m.debug( "No item_info for " .. tostring( v.id ) )
|
|
end
|
|
end, v.players )
|
|
end
|
|
end
|
|
|
|
if item then
|
|
--m.debug( "got item" )
|
|
m.update_tradeskill_item( tradeskill, item, v.players )
|
|
end
|
|
end
|
|
end
|
|
|
|
m.db.tradeskills_last_update[ tradeskill ] = m.get_server_timestamp()
|
|
elseif command == MessageCommand.RequestTradeskill and data.player == m.player then
|
|
--
|
|
-- Request for tradeskill
|
|
--
|
|
m.debug(m.dump(data))
|
|
send_tradeskill( data.tradeskill )
|
|
elseif command == MessageCommand.Ping and sender ~= m.player then
|
|
--
|
|
-- Recive ping
|
|
--
|
|
for tradeskill, hash in pairs( data or {} ) do
|
|
local local_hash = m.tradeskill_hash( tradeskill )
|
|
if local_hash == hash then
|
|
data[ tradeskill ] = nil
|
|
else
|
|
data[ tradeskill ] = m.db.tradeskills_last_update[ tradeskill ] or 0
|
|
end
|
|
end
|
|
|
|
m.debug( m.dump( data ) )
|
|
broadcast( MessageCommand.Pong, data )
|
|
elseif command == MessageCommand.Pong and pinging then
|
|
--
|
|
-- Receive pong
|
|
--
|
|
m.debug( m.dump( data ) )
|
|
for tradeskill, last_update in pairs( data or {} ) do
|
|
if not best_ping[ tradeskill ] or (last_update > best_ping[ tradeskill ].last_update) then
|
|
best_ping[ tradeskill ] = {
|
|
player = sender,
|
|
last_update = last_update
|
|
}
|
|
end
|
|
end
|
|
|
|
if ace_timer:TimeLeft( M[ "ping_timer" ] ) == 0 then
|
|
M[ "ping_timer" ] = ace_timer.ScheduleTimer( M, function()
|
|
if pinging then
|
|
m.debug( "Ping timeout, requesting tradeskills from best pings." )
|
|
pinging = false
|
|
for tradeskill, ping_info in pairs( best_ping ) do
|
|
m.debug( string.format( "Requesting %s from %s (last update: %d)", tradeskill, ping_info.player, ping_info.last_update ) )
|
|
broadcast( MessageCommand.RequestTradeskill, {
|
|
player = ping_info.player,
|
|
ts = tradeskill
|
|
} )
|
|
end
|
|
end
|
|
end, 2 )
|
|
end
|
|
elseif command == MessageCommand.VersionCheck then
|
|
--
|
|
-- Receive version request
|
|
--
|
|
broadcast( MessageCommand.Version, { requester = sender, version = m.version, class = m.player_class } )
|
|
elseif command == MessageCommand.Version then
|
|
--
|
|
-- Receive version
|
|
--
|
|
if data.requester == m.player then
|
|
m.info( string.format( "%s [v%s]", m.colorize_player_by_class( sender, data.class ), data.version ), true )
|
|
end
|
|
end
|
|
end
|
|
|
|
local function on_comm_received( prefix, data_str, _, sender )
|
|
if prefix ~= m.prefix or sender == m.player then return end
|
|
|
|
local command = string.match( data_str, "^(.-)::" )
|
|
data_str = string.gsub( data_str, "^.-::", "" )
|
|
|
|
m.debug( "Received " .. command )
|
|
|
|
local success, data = ace_serializer.Deserialize( M, data_str )
|
|
if success then
|
|
if data then
|
|
data = decode( data )
|
|
end
|
|
|
|
on_command( command, data, sender )
|
|
else
|
|
m.error( "Corrupt data in addon message!" )
|
|
end
|
|
end
|
|
|
|
ace_comm.RegisterComm( M, m.prefix, on_comm_received )
|
|
|
|
-- Also listen on the original GuildRecipes prefix. If we hear another
|
|
-- player broadcasting on it, they're running the outdated addon -- send
|
|
-- them a one-time whisper per session letting them know it's been replaced.
|
|
local warned_players = {}
|
|
local function on_legacy_comm_received( prefix, data_str, _, sender )
|
|
if sender == m.player then return end
|
|
if not m.legacy_warning_enabled then return end
|
|
if warned_players[ sender ] then return end
|
|
warned_players[ sender ] = true
|
|
SendChatMessage(
|
|
"GuildRecipes is out of date and will not work correctly with OctoWoW, please check the Discord for replacement version.",
|
|
"WHISPER", nil, sender
|
|
)
|
|
end
|
|
ace_comm.RegisterComm( M, "GRECIPES", on_legacy_comm_received )
|
|
|
|
---@type MessageHandler
|
|
return {
|
|
send_tradeskill = send_tradeskill,
|
|
request_tradeskill = request_tradeskill,
|
|
request_tradeskills = request_tradeskills,
|
|
version_check = version_check
|
|
}
|
|
end
|
|
|
|
m.MessageHandler = M
|
|
return M
|