comparison Main.lua @ 485:5e5ddb69f845 7.0.3-3

Added full world quest data recording support.
author MMOSimca <mmosimca@gmail.com>
date Tue, 06 Sep 2016 09:37:07 -0400
parents 679e2846ff88
children b661f10e04d9
comparison
equal deleted inserted replaced
484:679e2846ff88 485:5e5ddb69f845
10 local math = _G.math 10 local math = _G.math
11 local table = _G.table 11 local table = _G.table
12 12
13 local next = _G.next 13 local next = _G.next
14 local select = _G.select 14 local select = _G.select
15 local type = _G.type
15 local unpack = _G.unpack 16 local unpack = _G.unpack
16 17
17 local C_Timer = _G.C_Timer 18 local C_Timer = _G.C_Timer
18 19
19 20
38 local CLIENT_LOCALE = _G.GetLocale() 39 local CLIENT_LOCALE = _G.GetLocale()
39 local DB_VERSION = 18 40 local DB_VERSION = 18
40 local DEBUGGING = false 41 local DEBUGGING = false
41 local EVENT_DEBUG = false 42 local EVENT_DEBUG = false
42 43
44 -- Timer durations in seconds
45 local DELAY_PROCESS_ITEMS = 30
46 local DELAY_PROCESS_WORLD_QUESTS = 60
47 local DELAY_UPDATE_TARGET_LOCATION = 0.5
48
43 local ITEM_ID_TIMBER = 114781 49 local ITEM_ID_TIMBER = 114781
44 50
45 local LOOT_SOURCE_ID_REDUNDANT = 3 51 local LOOT_SOURCE_ID_REDUNDANT = 3
46 local LOOT_SOURCE_ID_GARRISON_CACHE = 10 52 local LOOT_SOURCE_ID_GARRISON_CACHE = 10
47 53
50 local OBJECT_ID_FORGE = 1685 56 local OBJECT_ID_FORGE = 1685
51 57
52 local PLAYER_CLASS, PLAYER_CLASS_ID = _G.select(2, _G.UnitClass("player")) 58 local PLAYER_CLASS, PLAYER_CLASS_ID = _G.select(2, _G.UnitClass("player"))
53 local PLAYER_FACTION = _G.UnitFactionGroup("player") 59 local PLAYER_FACTION = _G.UnitFactionGroup("player")
54 local PLAYER_GUID 60 local PLAYER_GUID
61 local PLAYER_LEVEL = _G.UnitLevel("player")
55 local PLAYER_NAME = _G.UnitName("player") 62 local PLAYER_NAME = _G.UnitName("player")
56 local PLAYER_RACE = _G.select(2, _G.UnitRace("player")) 63 local PLAYER_RACE = _G.select(2, _G.UnitRace("player"))
57 64
58 local LOOT_SLOT_CURRENCY = _G.LOOT_SLOT_CURRENCY 65 local LOOT_SLOT_CURRENCY = _G.LOOT_SLOT_CURRENCY
59 local LOOT_SLOT_ITEM = _G.LOOT_SLOT_ITEM 66 local LOOT_SLOT_ITEM = _G.LOOT_SLOT_ITEM
60 local LOOT_SLOT_MONEY = _G.LOOT_SLOT_MONEY 67 local LOOT_SLOT_MONEY = _G.LOOT_SLOT_MONEY
68
69 local WORLD_MAP_ID_BROKEN_ISLES = 1007
61 70
62 -- Removed in Legion but still needed 71 -- Removed in Legion but still needed
63 local ERR_QUEST_REWARD_ITEM_MULT_IS = _G.ERR_QUEST_REWARD_ITEM_MULT_IS or "Received %d of item: %s." 72 local ERR_QUEST_REWARD_ITEM_MULT_IS = _G.ERR_QUEST_REWARD_ITEM_MULT_IS or "Received %d of item: %s."
64 local ERR_QUEST_REWARD_ITEM_S = _G.ERR_QUEST_REWARD_ITEM_S or "Received item: %s." 73 local ERR_QUEST_REWARD_ITEM_S = _G.ERR_QUEST_REWARD_ITEM_S or "Received item: %s."
65 74
181 local last_timber_spell_id 190 local last_timber_spell_id
182 local last_garrison_cache_object_id 191 local last_garrison_cache_object_id
183 local block_chat_loot_data 192 local block_chat_loot_data
184 local chat_loot_data = {} 193 local chat_loot_data = {}
185 local chat_loot_timer_handle 194 local chat_loot_timer_handle
195 local world_quest_timer_handle
196 local world_quest_event_timestamp = 0
186 local current_target_id 197 local current_target_id
187 local current_loot 198 local current_loot
188 199
189 200
190 -- Data for our current action. Including possible values as a reference. 201 -- Data for our current action. Including possible values as a reference.
325 336
326 -- Put coordinates into expected format (as integers, they don't get a billion decimals output in the SavedVariables) 337 -- Put coordinates into expected format (as integers, they don't get a billion decimals output in the SavedVariables)
327 local x_int = nil 338 local x_int = nil
328 if (x and type(x) == "number") then 339 if (x and type(x) == "number") then
329 x_int = _G.floor(x * 1000) 340 x_int = _G.floor(x * 1000)
330 341
331 -- Limit precision to 0.2 342 -- Limit precision to 0.2
332 if x_int % 2 ~= 0 then 343 if x_int % 2 ~= 0 then
333 x_int = x_int + 1 344 x_int = x_int + 1
334 end 345 end
335 346
336 -- Prevent out of bounds coordinates 347 -- Prevent out of bounds coordinates
337 if (x_int < 0 or x_int > 1000) then 348 if (x_int < 0 or x_int > 1000) then
338 x_int = nil 349 x_int = nil
339 end 350 end
340 end 351 end
341 local y_int = nil 352 local y_int = nil
342 if (y and type(y) == "number") then 353 if (y and type(y) == "number") then
343 y_int = _G.floor(y * 1000) 354 y_int = _G.floor(y * 1000)
344 355
345 -- Limit precision to 0.2 356 -- Limit precision to 0.2
346 if y_int % 2 ~= 0 then 357 if y_int % 2 ~= 0 then
347 y_int = y_int + 1 358 y_int = y_int + 1
348 end 359 end
349 360
350 -- Prevent out of bounds coordinates 361 -- Prevent out of bounds coordinates
351 if (y_int < 0 or y_int > 1000) then 362 if (y_int < 0 or y_int > 1000) then
352 y_int = nil 363 y_int = nil
353 end 364 end
354 end 365 end
839 global_db = db.global 850 global_db = db.global
840 char_db = db.char 851 char_db = db.char
841 852
842 local raw_db = _G.WoWDBProfilerData 853 local raw_db = _G.WoWDBProfilerData
843 local build_num = tonumber(private.build_num) 854 local build_num = tonumber(private.build_num)
844 855
845 -- Get current region from LibRealmInfo (and account for the fact that PTR and Beta return nil) 856 -- Get current region from LibRealmInfo (and account for the fact that PTR and Beta return nil)
846 local current_region = LibRealmInfo:GetCurrentRegion() or "XX" 857 local current_region = LibRealmInfo:GetCurrentRegion() or "XX"
847 858
848 -- Wipe all data if DB version or build number changed 859 -- Wipe all data if DB version or build number changed
849 if (raw_db.version and raw_db.version < DB_VERSION) or (raw_db.build_num and raw_db.build_num < build_num) then 860 if (raw_db.version and raw_db.version < DB_VERSION) or (raw_db.build_num and raw_db.build_num < build_num) then
850 for entry in pairs(DATABASE_DEFAULTS.global) do 861 for entry in pairs(DATABASE_DEFAULTS.global) do
851 global_db[entry] = {} 862 global_db[entry] = {}
852 end 863 end
853 end 864 end
865 -- Wipe World Quest data if region changed
866 if raw_db.region and raw_db.region ~= current_region and global_db["world_quests"] then
867 global_db["world_quests"] = {}
868 end
869
854 raw_db.build_num = build_num 870 raw_db.build_num = build_num
855 raw_db.region = current_region 871 raw_db.region = current_region
856 raw_db.version = DB_VERSION 872 raw_db.version = DB_VERSION
857 873
858 private.InitializeCommentSystem() 874 private.InitializeCommentSystem()
893 909
894 for index = 1, _G.GetNumLanguages() do 910 for index = 1, _G.GetNumLanguages() do
895 languages_known[_G.GetLanguageByIndex(index)] = true 911 languages_known[_G.GetLanguageByIndex(index)] = true
896 end 912 end
897 913
898 -- These two timers loop indefinitely using Lua's infinity constant 914 -- These timers loop indefinitely using Lua's infinity constant
899 item_process_timer_handle = C_Timer.NewTicker(30, WDP.ProcessItems, math.huge) 915 item_process_timer_handle = C_Timer.NewTicker(DELAY_PROCESS_ITEMS, WDP.ProcessItems, math.huge)
900 target_location_timer_handle = C_Timer.NewTicker(0.5, WDP.UpdateTargetLocation, math.huge) 916 target_location_timer_handle = C_Timer.NewTicker(DELAY_UPDATE_TARGET_LOCATION, WDP.UpdateTargetLocation, math.huge)
917 world_quest_timer_handle = C_Timer.NewTicker(DELAY_PROCESS_WORLD_QUESTS, WDP.ProcessWorldQuests, math.huge)
901 918
902 _G.hooksecurefunc("UseContainerItem", function(bag_index, slot_index, target_unit) 919 _G.hooksecurefunc("UseContainerItem", function(bag_index, slot_index, target_unit)
903 if target_unit then 920 if target_unit then
904 return 921 return
905 end 922 end
913 local _, item_link = _G.GetItemInfo(identifier) 930 local _, item_link = _G.GetItemInfo(identifier)
914 HandleItemUse(item_link) 931 HandleItemUse(item_link)
915 end) 932 end)
916 933
917 self:GROUP_ROSTER_UPDATE() 934 self:GROUP_ROSTER_UPDATE()
935 end
936
937
938 -- Record data for a specific quest ID; reward data must be available or nothing will be recorded
939 -- When we reach this point, we've already checked for a valid mapID, questID, quest data, and worldQuestType
940 local function RecordWorldQuestData(world_map_id, quest_id, api_data_table)
941
942 -- Ensure we have location data and rewards (barely readable so putting it on multiple lines)
943 if not api_data_table.x or not api_data_table.y or not api_data_table.floor or not
944 (_G.GetQuestLogRewardXP(quest_id) > 0 or _G.GetNumQuestLogRewardCurrencies(quest_id) > 0
945 or _G.GetNumQuestLogRewards(quest_id) > 0 or _G.GetQuestLogRewardMoney(quest_id) > 0
946 or _G.GetQuestLogRewardArtifactXP(quest_id) > 0 or _G.GetQuestLogRewardHonor(quest_id) > 0) then
947 return
948 end
949
950 local entry = DBEntry("world_quests", quest_id)
951
952 if entry then
953
954 -- Record location
955 entry["location"] = {}
956 entry["location"]["world_map_id"] = world_map_id
957 entry["location"]["x"] = (tonumber(api_data_table.x) or 0) * 100
958 entry["location"]["y"] = (tonumber(api_data_table.y) or 0) * 100
959 entry["location"]["floor"] = tonumber(api_data_table.floor) or 0
960
961 -- Record simple rewards (XP, money, artifact XP, honor)
962 entry["rewards"] = {}
963 entry["rewards"]["xp"] = tonumber(_G.GetQuestLogRewardXP(quest_id)) or 0
964 entry["rewards"]["money"] = tonumber(_G.GetQuestLogRewardMoney(quest_id)) or 0
965 local actualXP, scaling = _G.GetQuestLogRewardArtifactXP(quest_id)
966 entry["rewards"]["artifact_xp"] = ("%d:%d"):format(tonumber(actualXP) or 0, tonumber(scaling) or 0)
967 entry["rewards"]["honor"] = tonumber(_G.GetQuestLogRewardHonor(quest_id)) or 0
968
969 -- Record currencies
970 entry["rewards"]["currency_count"] = tonumber(_G.GetNumQuestLogRewardCurrencies(quest_id)) or 0
971
972 if entry["rewards"]["currency_count"] > 0 then
973
974 -- Create currency rewards sub-table and fill
975 entry["rewards"]["currencies"] = {}
976 for i = 1, entry["rewards"]["currency_count"] do
977 local name, texture_path, quantity = _G.GetQuestLogRewardCurrencyInfo(i, quest_id)
978 local currency_texture = texture_path:match("[^\\]+$"):lower()
979 table.insert(entry["rewards"]["currencies"], ("%d:%s"):format(quantity, currency_texture))
980 end
981 end
982
983 -- Record items
984 entry["rewards"]["item_count"] = tonumber(_G.GetNumQuestLogRewards(quest_id)) or 0
985
986 if entry["rewards"]["item_count"] > 0 then
987
988 -- Create item rewards sub-table and fill
989 entry["rewards"]["items"] = {}
990 for i = 1, entry["rewards"]["item_count"] do
991 local item_name, item_texture, quantity, quality, is_usable, item_id = _G.GetQuestLogRewardInfo(i, quest_id)
992 table.insert(entry["rewards"]["items"], ("%d:%d"):format(item_id, quantity))
993 end
994 end
995
996 -- Record time remaining
997 entry["estimated_end_time"] = _G.GetServerTime() + ((_G.C_TaskQuest.GetQuestTimeLeftMinutes(quest_id) or 0) * 60)
998 end
999 end
1000
1001
1002 function WDP:ProcessWorldQuests()
1003 -- Ignore if player is low level
1004 if _G.UnitLevel("player") ~= 110 then return end
1005
1006 local current_world_map_id = _G.GetCurrentMapAreaID()
1007
1008 -- Iterate over known World Quest maps
1009 for i = 1, #private.WORLD_QUEST_MAP_IDS do
1010 local world_map_id = private.WORLD_QUEST_MAP_IDS[i]
1011
1012 -- Only bother checking the API if the world map in question is currently displayed OR its continent is currently displayed
1013 if current_world_map_id == WORLD_MAP_ID_BROKEN_ISLES or current_world_map_id == world_map_id then
1014
1015 -- Get data for World Quests on map
1016 local api_data = _G.C_TaskQuest.GetQuestsForPlayerByMapID(world_map_id)
1017
1018 -- Iterate over the questIDs for each map, doing preload reward requests and creating SavedVariables entries
1019 if api_data and type(api_data) == "table" and #api_data > 0 then
1020 for j = 1, #api_data do
1021 local current_data = api_data[j]
1022
1023 -- Check if we had a valid API table returned to us
1024 if current_data and type(current_data) == "table" and current_data["questId"] then
1025 local quest_id = tonumber(current_data["questId"]) or 0
1026
1027 -- Check if we have quest data
1028 if _G.HaveQuestData(quest_id) then
1029 local tag_id, tag_name, world_quest_type, rarity, is_elite, tradeskill_line_index = _G.GetQuestTagInfo(quest_id)
1030
1031 -- Check for valid questID and whether or not it is a World Quest
1032 if quest_id > 0 and world_quest_type ~= nil then
1033 _G.C_TaskQuest.RequestPreloadRewardData(quest_id)
1034 RecordWorldQuestData(world_map_id, quest_id, current_data)
1035 end
1036 end
1037 end
1038 end
1039 end
1040 end
1041 end
918 end 1042 end
919 1043
920 1044
921 local function RecordItemData(item_id, item_link, process_bonus_ids, durability) 1045 local function RecordItemData(item_id, item_link, process_bonus_ids, durability)
922 local _, _, item_string = item_link:find("^|%x+|H(.+)|h%[.+%]") 1046 local _, _, item_string = item_link:find("^|%x+|H(.+)|h%[.+%]")
1161 1285
1162 function WDP:ResumeChatLootRecording(event_name) 1286 function WDP:ResumeChatLootRecording(event_name)
1163 if block_chat_loot_data then 1287 if block_chat_loot_data then
1164 Debug("%s: Resuming chat-based loot recording.", event_name) 1288 Debug("%s: Resuming chat-based loot recording.", event_name)
1165 block_chat_loot_data = false 1289 block_chat_loot_data = false
1290 end
1291 end
1292
1293
1294 -- Process world quests if the map is moved to the Broken Isles continent world map (this provides us an opportunity to get data for all zones on the continent without moving the map)
1295 function WDP:WORLD_MAP_UPATE(event_name)
1296 if _G.GetCurrentMapAreaID() == WORLD_MAP_ID_BROKEN_ISLES and _G.GetServerTime() > (world_quest_event_timestamp + DELAY_PROCESS_WORLD_QUESTS) then
1297 world_quest_event_timestamp = _G.GetServerTime()
1298 WDP:ProcessWorldQuests()
1166 end 1299 end
1167 end 1300 end
1168 1301
1169 1302
1170 -- For now, bonus roll data only pollutes the true drop percentages. We still want to capture the data from SPELL_CONFIRMATION_PROMPT because of legendary quest items though. 1303 -- For now, bonus roll data only pollutes the true drop percentages. We still want to capture the data from SPELL_CONFIRMATION_PROMPT because of legendary quest items though.