304 lines
12 KiB
Lua
304 lines
12 KiB
Lua
|
-- ------------------------------------------------------------------------------ --
|
||
|
-- TradeSkillMaster --
|
||
|
-- https://tradeskillmaster.com --
|
||
|
-- All Rights Reserved - Detailed license information included with addon. --
|
||
|
-- ------------------------------------------------------------------------------ --
|
||
|
|
||
|
local _, TSM = ...
|
||
|
local PlayerProfessions = TSM.Crafting:NewPackage("PlayerProfessions")
|
||
|
local ProfessionInfo = TSM.Include("Data.ProfessionInfo")
|
||
|
local Database = TSM.Include("Util.Database")
|
||
|
local Event = TSM.Include("Util.Event")
|
||
|
local Delay = TSM.Include("Util.Delay")
|
||
|
local TempTable = TSM.Include("Util.TempTable")
|
||
|
local Vararg = TSM.Include("Util.Vararg")
|
||
|
local Threading = TSM.Include("Service.Threading")
|
||
|
local private = {
|
||
|
playerProfessionsThread = nil,
|
||
|
playerProfessionsThreadRunning = false,
|
||
|
db = nil,
|
||
|
query = nil,
|
||
|
}
|
||
|
local TAILORING_ES = "Sastrería"
|
||
|
local TAILORING_SKILL_ES = "Costura"
|
||
|
local LEATHERWORKING_ES = "Peletería"
|
||
|
local LEATHERWORKING_SKILL_ES = "Marroquinería"
|
||
|
local ENGINEERING_FR = "Ingénieur"
|
||
|
local ENGINEERING_SKILL_FR = "Ingénierie"
|
||
|
local FIRST_AID_FR = "Premiers soins"
|
||
|
local FIRST_AID_SKILL_FR = "Secourisme"
|
||
|
|
||
|
|
||
|
|
||
|
-- ============================================================================
|
||
|
-- Module Functions
|
||
|
-- ============================================================================
|
||
|
|
||
|
function PlayerProfessions.OnInitialize()
|
||
|
private.db = Database.NewSchema("PLAYER_PROFESSIONS")
|
||
|
:AddStringField("player")
|
||
|
:AddStringField("profession")
|
||
|
:AddNumberField("skillId")
|
||
|
:AddNumberField("level")
|
||
|
:AddNumberField("maxLevel")
|
||
|
:AddBooleanField("isSecondary")
|
||
|
:AddIndex("player")
|
||
|
:Commit()
|
||
|
private.query = private.db:NewQuery()
|
||
|
:Select("player", "profession", "skillId", "level", "maxLevel")
|
||
|
:OrderBy("isSecondary", true)
|
||
|
:OrderBy("level", false)
|
||
|
:OrderBy("profession", true)
|
||
|
private.playerProfessionsThread = Threading.New("PLAYER_PROFESSIONS", private.PlayerProfessionsThread)
|
||
|
private.StartPlayerProfessionsThread()
|
||
|
Event.Register("SKILL_LINES_CHANGED", private.PlayerProfessionsSkillUpdate)
|
||
|
Event.Register("LEARNED_SPELL_IN_TAB", private.StartPlayerProfessionsThread)
|
||
|
end
|
||
|
|
||
|
function PlayerProfessions.CreateQuery()
|
||
|
return private.db:NewQuery()
|
||
|
end
|
||
|
|
||
|
function PlayerProfessions.Iterator()
|
||
|
return private.query:Iterator()
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
-- ============================================================================
|
||
|
-- Player Professions Thread
|
||
|
-- ============================================================================
|
||
|
|
||
|
function private.StartPlayerProfessionsThread()
|
||
|
if private.playerProfessionsThreadRunning then
|
||
|
Threading.Kill(private.playerProfessionsThread)
|
||
|
end
|
||
|
private.playerProfessionsThreadRunning = true
|
||
|
Threading.Start(private.playerProfessionsThread)
|
||
|
end
|
||
|
|
||
|
function private.UpdatePlayerProfessionInfo(name, skillId, level, maxLevel, isSecondary)
|
||
|
local professionInfo = TSM.db.sync.internalData.playerProfessions[name] or {}
|
||
|
TSM.db.sync.internalData.playerProfessions[name] = professionInfo
|
||
|
-- preserve whether or not we've prompted to create groups and the profession link if possible
|
||
|
local oldPrompted = professionInfo.prompted or nil
|
||
|
local oldLink = professionInfo.link or nil
|
||
|
wipe(professionInfo)
|
||
|
professionInfo.skillId = skillId
|
||
|
professionInfo.level = level
|
||
|
professionInfo.maxLevel = maxLevel
|
||
|
professionInfo.isSecondary = isSecondary
|
||
|
professionInfo.prompted = oldPrompted
|
||
|
professionInfo.link = oldLink
|
||
|
end
|
||
|
|
||
|
function private.PlayerProfessionsSkillUpdate()
|
||
|
if TSM.IsWowClassic() then
|
||
|
local _, _, offset, numSpells = GetSpellTabInfo(1)
|
||
|
for i = offset + 1, offset + numSpells do
|
||
|
local name, subName = GetSpellBookItemName(i, BOOKTYPE_SPELL)
|
||
|
if not subName then
|
||
|
Delay.AfterTime(0.05, private.PlayerProfessionsSkillUpdate)
|
||
|
return
|
||
|
end
|
||
|
if name and subName and (ProfessionInfo.IsSubNameClassic(strtrim(subName, " ")) or name == ProfessionInfo.GetName("Smelting") or name == ProfessionInfo.GetName("Poisons") or name == LEATHERWORKING_ES or name == TAILORING_ES or name == ENGINEERING_FR or name == FIRST_AID_FR) and not TSM.UI.CraftingUI.IsProfessionIgnored(name) then
|
||
|
local level, maxLevel = nil, nil
|
||
|
for j = 1, GetNumSkillLines() do
|
||
|
local skillName, _, _, skillRank, _, _, skillMaxRank = GetSkillLineInfo(j)
|
||
|
if skillName == name then
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
elseif name == ProfessionInfo.GetName("Smelting") and skillName == ProfessionInfo.GetName("Mining") then
|
||
|
name = ProfessionInfo.GetName("Mining")
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
elseif name == LEATHERWORKING_ES and skillName == LEATHERWORKING_SKILL_ES then
|
||
|
name = LEATHERWORKING_SKILL_ES
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
elseif name == TAILORING_ES and skillName == TAILORING_SKILL_ES then
|
||
|
name = TAILORING_SKILL_ES
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
elseif name == ENGINEERING_FR and skillName == ENGINEERING_SKILL_FR then
|
||
|
name = ENGINEERING_SKILL_FR
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
elseif name == FIRST_AID_FR and skillName == FIRST_AID_SKILL_FR then
|
||
|
name = FIRST_AID_SKILL_FR
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
if level and maxLevel and not TSM.UI.CraftingUI.IsProfessionIgnored(name) then -- exclude ignored professions
|
||
|
private.UpdatePlayerProfessionInfo(name, -1, level, maxLevel, name == GetSpellInfo(129))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
local professionIds = TempTable.Acquire(GetProfessions())
|
||
|
for i, id in pairs(professionIds) do -- needs to be pairs since there might be holes
|
||
|
if id ~= 8 and id ~= 9 then -- ignore fishing and arheology
|
||
|
local name, _, level, maxLevel, _, _, skillId = GetProfessionInfo(id)
|
||
|
if not TSM.UI.CraftingUI.IsProfessionIgnored(name) then -- exclude ignored professions
|
||
|
private.UpdatePlayerProfessionInfo(name, skillId, level, maxLevel, i > 2)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
TempTable.Release(professionIds)
|
||
|
end
|
||
|
|
||
|
-- update our DB
|
||
|
private.db:TruncateAndBulkInsertStart()
|
||
|
for _, character in TSM.db:FactionrealmCharacterIterator() do
|
||
|
local playerProfessions = TSM.db:Get("sync", TSM.db:GetSyncScopeKeyByCharacter(character), "internalData", "playerProfessions")
|
||
|
if playerProfessions then
|
||
|
for name, info in pairs(playerProfessions) do
|
||
|
private.db:BulkInsertNewRow(character, name, info.skillId or -1, info.level, info.maxLevel, info.isSecondary)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
private.db:BulkInsertEnd()
|
||
|
end
|
||
|
|
||
|
function private.PlayerProfessionsThread()
|
||
|
-- get the player's tradeskills
|
||
|
if TSM.IsWowClassic() then
|
||
|
SpellBookFrame_UpdateSkillLineTabs()
|
||
|
else
|
||
|
SpellBook_UpdateProfTab()
|
||
|
end
|
||
|
local forgetProfession = Threading.AcquireSafeTempTable()
|
||
|
for name in pairs(TSM.db.sync.internalData.playerProfessions) do
|
||
|
forgetProfession[name] = true
|
||
|
end
|
||
|
if TSM.IsWowClassic() then
|
||
|
local _, _, offset, numSpells = GetSpellTabInfo(1)
|
||
|
for i = offset + 1, offset + numSpells do
|
||
|
local name, subName = GetSpellBookItemName(i, BOOKTYPE_SPELL)
|
||
|
if name and subName and (ProfessionInfo.IsSubNameClassic(strtrim(subName, " ")) or name == ProfessionInfo.GetName("Smelting") or name == ProfessionInfo.GetName("Poisons") or name == LEATHERWORKING_ES or name == TAILORING_ES or name == ENGINEERING_FR or name == FIRST_AID_FR) and not TSM.UI.CraftingUI.IsProfessionIgnored(name) then
|
||
|
local level, maxLevel = nil, nil
|
||
|
for j = 1, GetNumSkillLines() do
|
||
|
local skillName, _, _, skillRank, _, _, skillMaxRank = GetSkillLineInfo(j)
|
||
|
if skillName == name then
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
elseif name == ProfessionInfo.GetName("Smelting") and skillName == ProfessionInfo.GetName("Mining") then
|
||
|
name = ProfessionInfo.GetName("Mining")
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
elseif name == LEATHERWORKING_ES and skillName == LEATHERWORKING_SKILL_ES then
|
||
|
name = LEATHERWORKING_SKILL_ES
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
elseif name == TAILORING_ES and skillName == TAILORING_SKILL_ES then
|
||
|
name = TAILORING_SKILL_ES
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
elseif name == ENGINEERING_FR and skillName == ENGINEERING_SKILL_FR then
|
||
|
name = ENGINEERING_SKILL_FR
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
elseif name == FIRST_AID_FR and skillName == FIRST_AID_SKILL_FR then
|
||
|
name = FIRST_AID_SKILL_FR
|
||
|
level = skillRank
|
||
|
maxLevel = skillMaxRank
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
if level and maxLevel and not TSM.UI.CraftingUI.IsProfessionIgnored(name) then -- exclude ignored professions
|
||
|
forgetProfession[name] = nil
|
||
|
private.UpdatePlayerProfessionInfo(name, -1, level, maxLevel, name == GetSpellInfo(129))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
Threading.WaitForFunction(GetProfessions)
|
||
|
local professionIds = Threading.AcquireSafeTempTable(GetProfessions())
|
||
|
-- ignore archeology and fishing which are in the 3rd and 4th slots respectively
|
||
|
professionIds[3] = nil
|
||
|
professionIds[4] = nil
|
||
|
for i, id in pairs(professionIds) do -- needs to be pairs since there might be holes
|
||
|
local name, _, level, maxLevel, _, _, skillId = Threading.WaitForFunction(GetProfessionInfo, id)
|
||
|
if not TSM.UI.CraftingUI.IsProfessionIgnored(name) then -- exclude ignored professions
|
||
|
forgetProfession[name] = nil
|
||
|
private.UpdatePlayerProfessionInfo(name, skillId, level, maxLevel, i > 2)
|
||
|
end
|
||
|
end
|
||
|
Threading.ReleaseSafeTempTable(professionIds)
|
||
|
end
|
||
|
for name in pairs(forgetProfession) do
|
||
|
TSM.db.sync.internalData.playerProfessions[name] = nil
|
||
|
end
|
||
|
Threading.ReleaseSafeTempTable(forgetProfession)
|
||
|
|
||
|
-- clean up crafts which are no longer known
|
||
|
local matUsed = Threading.AcquireSafeTempTable()
|
||
|
local spellIds = Threading.AcquireSafeTempTable()
|
||
|
for _, spellId in TSM.Crafting.SpellIterator() do
|
||
|
tinsert(spellIds, spellId)
|
||
|
end
|
||
|
for _, spellId in ipairs(spellIds) do
|
||
|
local playersToRemove = TempTable.Acquire()
|
||
|
for _, player in Vararg.Iterator(TSM.Crafting.GetPlayers(spellId)) do
|
||
|
-- check if the player still exists and still has this profession
|
||
|
local playerProfessions = TSM.db:Get("sync", TSM.db:GetSyncScopeKeyByCharacter(player), "internalData", "playerProfessions")
|
||
|
if not playerProfessions or not playerProfessions[TSM.Crafting.GetProfession(spellId)] then
|
||
|
tinsert(playersToRemove, player)
|
||
|
end
|
||
|
end
|
||
|
local stillExists = true
|
||
|
if #playersToRemove > 0 then
|
||
|
stillExists = TSM.Crafting.RemovePlayers(spellId, playersToRemove)
|
||
|
end
|
||
|
TempTable.Release(playersToRemove)
|
||
|
if stillExists then
|
||
|
for _, itemString in TSM.Crafting.MatIterator(spellId) do
|
||
|
matUsed[itemString] = true
|
||
|
end
|
||
|
end
|
||
|
Threading.Yield()
|
||
|
end
|
||
|
Threading.ReleaseSafeTempTable(spellIds)
|
||
|
|
||
|
-- clean up mats which aren't used anymore
|
||
|
local toRemove = TempTable.Acquire()
|
||
|
for itemString, matInfo in pairs(TSM.db.factionrealm.internalData.mats) do
|
||
|
-- clear out old names
|
||
|
matInfo.name = nil
|
||
|
if not matUsed[itemString] then
|
||
|
tinsert(toRemove, itemString)
|
||
|
end
|
||
|
end
|
||
|
Threading.ReleaseSafeTempTable(matUsed)
|
||
|
for _, itemString in ipairs(toRemove) do
|
||
|
TSM.db.factionrealm.internalData.mats[itemString] = nil
|
||
|
end
|
||
|
TempTable.Release(toRemove)
|
||
|
|
||
|
-- update our DB
|
||
|
private.db:TruncateAndBulkInsertStart()
|
||
|
for _, character in TSM.db:FactionrealmCharacterIterator() do
|
||
|
local playerProfessions = TSM.db:Get("sync", TSM.db:GetSyncScopeKeyByCharacter(character), "internalData", "playerProfessions")
|
||
|
if playerProfessions then
|
||
|
for name, info in pairs(playerProfessions) do
|
||
|
private.db:BulkInsertNewRow(character, name, info.skillId or -1, info.level, info.maxLevel, info.isSecondary)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
private.db:BulkInsertEnd()
|
||
|
|
||
|
private.playerProfessionsThreadRunning = false
|
||
|
end
|