TradeSkillMaster/Core/Service/Crafting/PlayerProfessions.lua

304 lines
12 KiB
Lua
Raw Normal View History

2020-11-13 14:13:12 -05:00
-- ------------------------------------------------------------------------------ --
-- 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