Unify SavedVariables into two clean roots with one-time migration

Collapse all legacy/scattered SavedVariables from absorbed standalone
addons (FeedOMatic, ZHunter/zButtons, SmartAmmo, AutoQuest, AntiDaze,
AutoStrip, MinimapButton) into two persisted globals with clean per-module
nesting under .modules.<id>.

Migration engine (api/savedvariables.lua):
- MTH_SV_EnsureSchema() with schemaVersion gate, idempotent + non-destructive
- Per-module migrators map old locations -> canonical nested stores
- Driven by an ADDON_LOADED("MetaHunt") handler so it runs only AFTER WoW
  loads the real SavedVariables (fixes announce-every-session bug that ran
  the migration on empty pre-load defaults)
- One-time player-facing chat announce, gated on real legacy data present

Framework/config:
- core-framework InitSavedVariables no longer runs migration at file-load;
  unconditionally strips account-root module aliases
- config.lua stops re-creating root[module] aliases (was duplicating data
  onto disk); canonical store stays under .modules.<id>

Modules:
- feedomatic: bind FOM_* globals as runtime aliases into nested store,
  drop persisted duplicates and .legacy blob
- zhunter: ZHunterMod_Saved re-pointed at .modules.zhunter
- smartammo/autoquest/antidaze/autostrip/minimapbutton read nested store

TOC trimmed to MTH_SavedVariables + MTH_CharSavedVariables only.
Profiles unchanged (already snapshot/apply the nested .modules structure).

Also includes pet-scan refinements: canonical pet key derivation and
level-independent pet signature (schema v3).
This commit is contained in:
DuvelCorp
2026-09-09 22:52:48 +02:00
parent de6621f41f
commit 060fc555fe
22 changed files with 855 additions and 503 deletions
+25 -80
View File
@@ -56,70 +56,33 @@ local function QA_GetOptionsStore()
if type(MTH_CharSavedVariables) ~= "table" then
MTH_CharSavedVariables = {}
end
if type(MTH_CharSavedVariables.autoquest) ~= "table" then
MTH_CharSavedVariables.autoquest = {}
end
local store = MTH_CharSavedVariables.autoquest
if store._migrated ~= true then
if type(MTH_CharSavedVariables.questautomation) == "table" then
local legacyStore = MTH_CharSavedVariables.questautomation
if legacyStore.scorpokDrazial ~= nil and store.scorpokDrazial == nil then
store.scorpokDrazial = legacyStore.scorpokDrazial and true or false
end
if legacyStore.scorpokTooltip ~= nil and store.scorpokTooltip == nil then
store.scorpokTooltip = legacyStore.scorpokTooltip and true or false
end
end
local legacyChar = nil
local legacyAccount = nil
if MTH and MTH.GetModuleCharSavedVariables then
legacyChar = MTH:GetModuleCharSavedVariables("autoquest")
if type(legacyChar) ~= "table" then
legacyChar = MTH:GetModuleCharSavedVariables("questautomation")
end
end
if MTH and MTH.GetModuleSavedVariables then
legacyAccount = MTH:GetModuleSavedVariables("autoquest")
if type(legacyAccount) ~= "table" then
legacyAccount = MTH:GetModuleSavedVariables("questautomation")
end
end
if type(legacyChar) == "table" and legacyChar.scorpokDrazial ~= nil and store.scorpokDrazial == nil then
store.scorpokDrazial = legacyChar.scorpokDrazial and true or false
elseif type(legacyAccount) == "table" and legacyAccount.scorpokDrazial ~= nil and store.scorpokDrazial == nil then
store.scorpokDrazial = legacyAccount.scorpokDrazial and true or false
elseif store.scorpokDrazial == nil and MTH and MTH.GetModuleCharSavedVariables then
local autobuyStore = MTH:GetModuleCharSavedVariables("autobuy")
if type(autobuyStore) == "table"
and type(autobuyStore.questAutomation) == "table"
and autobuyStore.questAutomation.scorpokDrazial ~= nil then
store.scorpokDrazial = autobuyStore.questAutomation.scorpokDrazial and true or false
end
end
store._migrated = true
end
if store.scorpokDrazial == nil then
store.scorpokDrazial = false
end
if store.arrowsForSissies == nil then
store.arrowsForSissies = false
end
if store.scorpokTooltip == nil then
store.scorpokTooltip = false
end
local store = nil
if MTH and MTH.GetModuleCharSavedVariables then
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
if type(moduleStore) == "table" then
moduleStore.scorpokDrazial = store.scorpokDrazial and true or false
moduleStore.arrowsForSissies = store.arrowsForSissies and true or false
moduleStore.scorpokTooltip = store.scorpokTooltip and true or false
end
store = MTH:GetModuleCharSavedVariables("autoquest")
end
return store
if type(store) ~= "table" then
if type(MTH_CharSavedVariables.modules) ~= "table" then
MTH_CharSavedVariables.modules = {}
end
if type(MTH_CharSavedVariables.modules.autoquest) ~= "table" then
MTH_CharSavedVariables.modules.autoquest = {}
end
store = MTH_CharSavedVariables.modules.autoquest
end
if type(store.settings) ~= "table" then
store.settings = {}
end
local settings = store.settings
if settings.scorpokDrazial == nil then
settings.scorpokDrazial = false
end
if settings.arrowsForSissies == nil then
settings.arrowsForSissies = false
end
if settings.scorpokTooltip == nil then
settings.scorpokTooltip = false
end
return settings
end
function MTH_AutoQuest:GetStore()
@@ -129,36 +92,18 @@ end
function MTH_AutoQuest:SetScorpokDrazialEnabled(enabled)
local store = QA_GetOptionsStore()
store.scorpokDrazial = enabled and true or false
if MTH and MTH.GetModuleCharSavedVariables then
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
if type(moduleStore) == "table" then
moduleStore.scorpokDrazial = store.scorpokDrazial and true or false
end
end
QA_Debug("option write: scorpokDrazial=" .. tostring(store.scorpokDrazial and true or false))
end
function MTH_AutoQuest:SetArrowsForSissiesEnabled(enabled)
local store = QA_GetOptionsStore()
store.arrowsForSissies = enabled and true or false
if MTH and MTH.GetModuleCharSavedVariables then
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
if type(moduleStore) == "table" then
moduleStore.arrowsForSissies = store.arrowsForSissies and true or false
end
end
QA_Debug("option write: arrowsForSissies=" .. tostring(store.arrowsForSissies and true or false))
end
function MTH_AutoQuest:SetScorpokTooltipEnabled(enabled)
local store = QA_GetOptionsStore()
store.scorpokTooltip = enabled and true or false
if MTH and MTH.GetModuleCharSavedVariables then
local moduleStore = MTH:GetModuleCharSavedVariables("autoquest")
if type(moduleStore) == "table" then
moduleStore.scorpokTooltip = store.scorpokTooltip and true or false
end
end
QA_Debug("option write: scorpokTooltip=" .. tostring(store.scorpokTooltip and true or false))
end
-98
View File
@@ -650,58 +650,6 @@ function MTH_GetMerchantFoodsByDiet()
return result;
end
local function FOM_ItemQuality(itemIdOrLink)
if (type(GetItemInfo) ~= "function" or itemIdOrLink == nil) then
return nil;
end
local _, _, quality = GetItemInfo(itemIdOrLink);
return quality;
end
local function FOM_DebugLog(message)
if (not (FOM_Config and FOM_Config.Debug)) then
return;
end
local text = "[FOM] " .. tostring(message);
if (MTH and MTH.Print) then
MTH:Print(text, "debug");
elseif (DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage) then
DEFAULT_CHAT_FRAME:AddMessage(text);
end
return;
end
local function FOM_DebugLogMerchantFoods(sourceEvent)
local merchantFoods = MTH_GetMerchantFoodsByDiet();
local eventLabel = tostring(sourceEvent or "MERCHANT");
if (merchantFoods == nil) then
FOM_DebugLog(eventLabel .. ": no merchant data available.");
return;
end
local knownCount = table.getn(merchantFoods.items or {});
local unknownCount = table.getn(merchantFoods.unknown or {});
local merchantName = UnitName("npc") or UnitName("target") or "unknown";
FOM_DebugLog(eventLabel .. ": " .. tostring(merchantName) .. " | known foods=" .. tostring(knownCount) .. " | unknown items=" .. tostring(unknownCount));
if (type(merchantFoods.byDiet) == "table") then
for dietName, foodRows in merchantFoods.byDiet do
local dietCount = table.getn(foodRows or {});
FOM_DebugLog("diet " .. tostring(dietName) .. ": " .. tostring(dietCount) .. " item(s)");
for _, row in foodRows do
FOM_DebugLog(" - [" .. tostring(row.id) .. "] " .. tostring(row.name) .. " (merchantIndex=" .. tostring(row.index) .. ")");
end
end
end
if (unknownCount > 0) then
for _, row in merchantFoods.unknown do
FOM_DebugLog("unknown food map: [" .. tostring(row.id) .. "] " .. tostring(row.name) .. " (merchantIndex=" .. tostring(row.index) .. ")");
end
end
end
function MTH_FOM_FeedButton_OnClick()
if (arg1 == "RightButton") then
if (MTH_OpenOptions) then
@@ -920,10 +868,6 @@ function FOM_OnEvent(event, arg1)
end
return;
elseif ( event == "MERCHANT_SHOW" or event == "MERCHANT_UPDATE" ) then
FOM_DebugLogMerchantFoods(event);
return;
elseif ( event == "PET_ATTACK_START" ) then
-- Set Flag
@@ -950,7 +894,6 @@ function FOM_OnEvent(event, arg1)
end
if (foodID) then
FOM_LastFood = GFWUtils.ItemLink(foodID);
FOM_DebugLog("Manually fed "..FOM_LastFood);
end
end
return;
@@ -1269,31 +1212,24 @@ end
function FOM_CanFeed()
local petInfo = MTH_FOM_GetCorePetInfo();
if ( not (petInfo and petInfo.liveExists) ) then
FOM_DebugLog("Can't feed; pet doesn't exist.");
return false;
end
if ( tonumber(petInfo.health) and tonumber(petInfo.health) <= 0 ) then
FOM_DebugLog("Can't feed; pet is dead.");
return false;
end
if ( UnitHealth("player") <= 0 ) then
FOM_DebugLog("Can't feed; I'm dead.");
return false;
end
if ( CastingBarFrameStatusBar:IsVisible() ) then
FOM_DebugLog("Can't feed; casting a spell / tradeksill.");
return false;
end
if ( UnitOnTaxi("player") ) then
FOM_DebugLog("Can't feed; flying.");
return false;
end
if ( FOM_State.InCombat ) or ( PlayerFrame.inCombat ) then
FOM_DebugLog("Can't feed; in combat.");
return false;
end
if ( LootFrame:IsVisible() ) then
FOM_DebugLog("Shouldn't feed; loot window is open.");
return false;
end
@@ -1315,14 +1251,12 @@ function FOM_CanFeed()
local name = GetSpellRecField(sid, "name")
if name then
if dontFeedNames[name] then
FOM_DebugLog("Can't feed; buff detected: " .. name)
return false
end
if UnitLevel("player") >= 40 then
local lname = string.lower(name)
for _, mountSub in FOM_MOUNT_NAME_SUBSTRINGS do
if string.find(lname, mountSub) then
FOM_DebugLog("Can't feed; mounted (" .. name .. ").")
return false
end
end
@@ -1351,7 +1285,6 @@ function FOM_CanFeed()
if ( buff ~= nil) then
for _, buffTexture in dontFeedBuffTextures do
if ( buff == buffTexture ) then
FOM_DebugLog("Can't feed; currently, eating, drinking, or feigning death.");
return false;
end
end
@@ -1364,7 +1297,6 @@ function FOM_CanFeed()
msg = string.lower(msg);
for _, mountName in FOM_MOUNT_NAME_SUBSTRINGS do
if (string.find(msg, mountName)) then
FOM_DebugLog("Can't feed; mounted.");
return false;
end
end
@@ -2387,17 +2319,6 @@ function FOM_Feed(aFood, options)
foodLevel = selectedFoodLevel,
})
FOM_DebugLog("Picked "..tostring(FOM_LastFood)
.." id="..tostring(selectedId)
.." foodLevel="..tostring(selectedFoodLevel)
.." itemQuality="..tostring(FOM_ItemQuality(selectedId))
.." (bag "..tostring(foodBag)..", slot "..tostring(foodItem)..")"
.." reason="..tostring(FOM_LastChoiceReason));
if (FOM_Config.Debug) then
-- don't actually feed anything, just show what we would choose
return false;
end
-- Actually feed the item to the pet
PickupContainerItem(foodBag, foodItem);
if ( CursorHasItem() ) then
@@ -2610,19 +2531,6 @@ function FOM_FlatFoodList()
if (table.getn(foodList) == 0 and table.getn(overflowFoodList) > 0) then
foodList = overflowFoodList;
end
if (FOM_Config and FOM_Config.Debug) then
FOM_DebugLog("Candidate foods for pet level "..tostring(petLevel).." ("..tostring(table.getn(foodList)).." in diet):");
for i = 1, table.getn(foodList) do
local c = foodList[i];
FOM_DebugLog(" ["..tostring(i).."] "..tostring(c.link)
.." id="..tostring(c.itemId)
.." qty="..tostring(c.count)
.." foodLevel="..tostring(c.quality)
.." itemQuality="..tostring(FOM_ItemQuality(c.itemId))
.." known="..tostring(c.knownLevel)
.." useful="..tostring(c.useful));
end
end
return foodList;
end
@@ -2786,12 +2694,10 @@ end
function FOM_IsUsefulFood(itemID, quantity)
local foodName = GetItemInfo(itemID);
if (foodName == nil) then
FOM_DebugLog("Can't get info for item ID "..itemID..", assuming it's OK to eat.");
return false;
end
if (FOM_Cooking and FOM_Cooking[FOM_RealmPlayer] and FOM_Cooking[FOM_RealmPlayer][itemID]) then
if (FOM_Cooking[FOM_RealmPlayer][itemID] >= FOM_Config.SaveForCookingLevel) then
FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; is good for cooking.");
return true;
end
end
@@ -2803,19 +2709,15 @@ function FOM_IsUsefulFood(itemID, quantity)
FOM_Quantity[foodName] = FOM_Quantity[foodName] + quantity;
end
if (FOM_Quantity[foodName] > FOM_QuestFood[FOM_RealmPlayer][foodName]) then
FOM_DebugLog("Not skipping "..quantity.."x "..foodName.."; is needed for quest, but we have more than enough.");
return false;
else
FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; is needed for quest.");
return true;
end
end
end
if (FOM_Config.AvoidBonusFood and FOM_IsInDiet(itemID, FOM_DIET_BONUS)) then
FOM_DebugLog("Skipping "..quantity.."x "..foodName.."; has bonus effect when eaten by player.");
return true;
end
--FOM_DebugLog("Not skipping "..quantity.."x "..foodName.."; doesn't have other uses.");
return false;
end
+19 -95
View File
@@ -8,8 +8,6 @@ local MTH_FeedOMatic = {
enabled = false,
events = {
"VARIABLES_LOADED",
"MERCHANT_SHOW",
"MERCHANT_UPDATE",
"MTH_PET_LIVE_STATE_CHANGED",
"PET_ATTACK_START",
"PET_ATTACK_STOP",
@@ -31,7 +29,6 @@ local MTH_FeedOMatic = {
}
local MTH_PETL_HOOK_BOUNDARY_KEY = "pet-lifecycle-hooks"
local MTH_FOM_MerchantProbe = nil
function MTH_FeedOMatic_OnUpdate(elapsed)
if not elapsed then
@@ -128,104 +125,34 @@ local function MTH_FeedOMatic_SyncSavedVariables()
end
local moduleStore = MTH:GetModuleSavedVariables("feedomatic")
if not moduleStore.legacy then
moduleStore.legacy = {}
end
local function bindLegacyTable(globalName)
local legacyValue = moduleStore.legacy[globalName]
local globalValue = _G and _G[globalName] or nil
if type(legacyValue) ~= "table" then
-- Bind each legacy FeedOMatic global to its clean nested location under
-- modules.feedomatic. The globals are runtime aliases only (NOT persisted via
-- the TOC any more); the real data lives in these nested tables inside
-- MTH_SavedVariables. Adopt any pre-existing runtime global on first bind.
local function bindGlobal(globalName, key)
local target = moduleStore[key]
if type(target) ~= "table" then
local globalValue = _G and _G[globalName] or nil
if type(globalValue) == "table" then
legacyValue = globalValue
target = globalValue
else
legacyValue = {}
target = {}
end
moduleStore.legacy[globalName] = legacyValue
moduleStore[key] = target
end
if _G then
_G[globalName] = legacyValue
_G[globalName] = target
end
end
bindLegacyTable("FOM_Config")
bindLegacyTable("FOM_FoodQuality")
bindLegacyTable("FOM_AddedFoods")
bindLegacyTable("FOM_RemovedFoods")
bindLegacyTable("FOM_Cooking")
bindLegacyTable("FOM_QuestFood")
bindLegacyTable("FOM_LocaleInfo")
end
local function MTH_FeedOMatic_Log(message, severity)
if type(MTH_Log) == "function" then
MTH_Log("[FeedOMatic] " .. tostring(message or ""), severity)
end
end
local function MTH_FeedOMatic_DebugMerchantScan(sourceEvent)
if type(MTH_GetMerchantFoodsByDiet) ~= "function" then
MTH_FeedOMatic_Log(tostring(sourceEvent) .. ": MTH_GetMerchantFoodsByDiet is not available yet")
return
end
local merchantFoods = MTH_GetMerchantFoodsByDiet()
local knownCount = 0
local unknownCount = 0
if type(merchantFoods) == "table" then
if type(merchantFoods.items) == "table" then
knownCount = table.getn(merchantFoods.items)
end
if type(merchantFoods.unknown) == "table" then
unknownCount = table.getn(merchantFoods.unknown)
end
end
local merchantName = UnitName("npc") or UnitName("target") or "unknown"
MTH_FeedOMatic_Log(tostring(sourceEvent) .. ": wrapper scan for " .. tostring(merchantName) .. " | known=" .. tostring(knownCount) .. " | unknown=" .. tostring(unknownCount))
if type(merchantFoods.byDiet) == "table" then
for dietName, rows in merchantFoods.byDiet do
local dietCount = 0
if type(rows) == "table" then
dietCount = table.getn(rows)
end
if type(rows) == "table" then
for _, row in rows do
end
end
end
end
if unknownCount > 0 and type(merchantFoods.unknown) == "table" then
for _, row in merchantFoods.unknown do
end
end
end
local function MTH_FeedOMatic_SetMerchantProbeEnabled(enabled)
if not enabled then
if MTH_FOM_MerchantProbe then
MTH_FOM_MerchantProbe:UnregisterEvent("MERCHANT_SHOW")
MTH_FOM_MerchantProbe:UnregisterEvent("MERCHANT_UPDATE")
end
return
end
if not MTH_FOM_MerchantProbe then
MTH_FOM_MerchantProbe = CreateFrame("Frame", "MTH_FOM_MerchantProbe")
MTH_FOM_MerchantProbe:SetScript("OnEvent", function()
local evt = event
if evt == "MERCHANT_SHOW" or evt == "MERCHANT_UPDATE" then
MTH_FeedOMatic_DebugMerchantScan(evt)
end
end)
end
MTH_FOM_MerchantProbe:RegisterEvent("MERCHANT_SHOW")
MTH_FOM_MerchantProbe:RegisterEvent("MERCHANT_UPDATE")
bindGlobal("FOM_Config", "settings")
bindGlobal("FOM_FoodQuality", "foodQuality")
bindGlobal("FOM_AddedFoods", "addedFoods")
bindGlobal("FOM_RemovedFoods", "removedFoods")
bindGlobal("FOM_Cooking", "cooking")
bindGlobal("FOM_QuestFood", "questFood")
bindGlobal("FOM_LocaleInfo", "localeInfo")
end
function MTH_FeedOMatic:init()
@@ -265,7 +192,6 @@ function MTH_FeedOMatic:setEnabled(enabled)
MTH_FeedOMatic_CaptureHookBoundary()
MTH_FeedOMatic_SyncSavedVariables()
MTH_FeedOMatic_EnsureVariablesLoaded(self)
MTH_FeedOMatic_SetMerchantProbeEnabled(false)
if MTH_FOM_FeedButton then
MTH_FOM_FeedButton:Show()
end
@@ -275,7 +201,6 @@ function MTH_FeedOMatic:setEnabled(enabled)
if type(FOM_State) == "table" then
FOM_State.ShouldFeed = false
end
MTH_FeedOMatic_SetMerchantProbeEnabled(false)
if MTH_FOM_FeedButton then
MTH_FOM_FeedButton:Hide()
end
@@ -304,7 +229,6 @@ function MTH_FeedOMatic:cleanup()
if type(FOM_State) == "table" then
FOM_State.ShouldFeed = false
end
MTH_FeedOMatic_SetMerchantProbeEnabled(false)
if MTH_FOM_FeedButton then
MTH_FOM_FeedButton:Hide();
end
+35 -60
View File
@@ -1,7 +1,3 @@
local function MTHSmartAmmo_GetSaved()
return MTH_SA_GetSavedTable("MTHSmartAmmo")
end
local function MTHSmartAmmo_GetModuleStore()
if MTH and MTH.GetModuleCharSavedVariables then
return MTH:GetModuleCharSavedVariables("smartammo")
@@ -9,40 +5,43 @@ local function MTHSmartAmmo_GetModuleStore()
return nil
end
local function MTHSmartAmmo_IsSmartEnabled()
-- Single source of truth: moduleStore.settings.{smartEnabled,reloadEnabled,weaponSwapEnabled}
local function MTHSmartAmmo_GetSettings()
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" and moduleStore.smartEnabled ~= nil then
return moduleStore.smartEnabled and true or false
if type(moduleStore) ~= "table" then
return nil
end
local saved = MTHSmartAmmo_GetSaved()
if saved["enabled"] == nil then
return true
if type(moduleStore.settings) ~= "table" then
moduleStore.settings = {}
end
return saved["enabled"] and true or false
return moduleStore.settings
end
local function MTHSmartAmmo_ReadFlag(key)
local settings = MTHSmartAmmo_GetSettings()
if settings and settings[key] ~= nil then
return settings[key] and true or false
end
return true -- default enabled
end
local function MTHSmartAmmo_WriteFlag(key, enabled)
local settings = MTHSmartAmmo_GetSettings()
if settings then
settings[key] = enabled and true or false
end
end
local function MTHSmartAmmo_IsSmartEnabled()
return MTHSmartAmmo_ReadFlag("smartEnabled")
end
local function MTHSmartAmmo_IsReloadEnabled()
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" and moduleStore.reloadEnabled ~= nil then
return moduleStore.reloadEnabled and true or false
end
local saved = MTHSmartAmmo_GetSaved()
if saved["reload"] == nil then
return true
end
return saved["reload"] and true or false
return MTHSmartAmmo_ReadFlag("reloadEnabled")
end
local function MTHSmartAmmo_IsWeaponSwapEnabled()
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" and moduleStore.weaponSwapEnabled ~= nil then
return moduleStore.weaponSwapEnabled and true or false
end
local saved = MTHSmartAmmo_GetSaved()
if saved["weaponSwap"] == nil then
return true
end
return saved["weaponSwap"] and true or false
return MTHSmartAmmo_ReadFlag("weaponSwapEnabled")
end
local MTHSmartAmmo_InitializeHooks
@@ -58,9 +57,7 @@ local MTH_SA_SPELL_EVENTS = {
}
function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
saved["enabled"] = 1
local evFrame = getglobal("MTH_SA_EventFrame")
if evFrame then
for _, ev in ipairs(MTH_SA_SPELL_EVENTS) do
@@ -77,7 +74,6 @@ function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
MTH_SA_Print("Smart Ammo Enabled.")
end
else
saved["enabled"] = false
local evFrame = getglobal("MTH_SA_EventFrame")
if evFrame then
for _, ev in ipairs(MTH_SA_SPELL_EVENTS) do
@@ -89,10 +85,7 @@ function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
end
end
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" then
moduleStore.smartEnabled = enabled and true or false
end
MTHSmartAmmo_WriteFlag("smartEnabled", enabled and true or false)
end
function MTHSmartAmmo_GetSmartEnabled()
@@ -100,16 +93,7 @@ function MTHSmartAmmo_GetSmartEnabled()
end
function MTHSmartAmmo_SetReloadEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
saved["reload"] = 1
else
saved["reload"] = false
end
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" then
moduleStore.reloadEnabled = enabled and true or false
end
MTHSmartAmmo_WriteFlag("reloadEnabled", enabled and true or false)
if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo reload fallback " .. (enabled and "Enabled." or "Disabled."))
end
@@ -120,16 +104,7 @@ function MTHSmartAmmo_GetReloadEnabled()
end
function MTHSmartAmmo_SetWeaponSwapEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
saved["weaponSwap"] = 1
else
saved["weaponSwap"] = false
end
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" then
moduleStore.weaponSwapEnabled = enabled and true or false
end
MTHSmartAmmo_WriteFlag("weaponSwapEnabled", enabled and true or false)
if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo weapon-swap auto-equip " .. (enabled and "Enabled." or "Disabled."))
end
@@ -807,15 +782,15 @@ SlashCmdList["MTHSmartAmmo"] = function(msg)
return
end
local saved = MTHSmartAmmo_GetSaved()
local smartEnabled = MTHSmartAmmo_GetSmartEnabled()
if msg == "status" then
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
MTH_SA_Print("Smart Ammo status: smart=" .. tostring(saved["enabled"] and true or false) .. ", module=" .. tostring(MTH_SA_IsModuleEnabled()) .. ", hooks=" .. tostring(castHook) .. "/" .. tostring(actionHook) .. "/" .. tostring(byNameHook))
MTH_SA_Print("Smart Ammo status: smart=" .. tostring(smartEnabled) .. ", module=" .. tostring(MTH_SA_IsModuleEnabled()) .. ", hooks=" .. tostring(castHook) .. "/" .. tostring(actionHook) .. "/" .. tostring(byNameHook))
return
end
if saved["enabled"] then
if smartEnabled then
MTHSmartAmmo_SetSmartEnabled(nil)
else
MTHSmartAmmo_SetSmartEnabled(1)
+11 -66
View File
@@ -15,39 +15,6 @@ local MTH_SmartAmmo = {
local MTH_SA_BOUNDARY_KEY = "smartammo.core"
function MTH_SA_GetSavedTable(tableName)
if not MTH or not MTH.GetModuleCharSavedVariables then
if type(_G[tableName]) ~= "table" then
_G[tableName] = {}
end
return _G[tableName]
end
local moduleStore = MTH:GetModuleCharSavedVariables("smartammo")
if type(moduleStore) ~= "table" then
moduleStore = {}
end
if not moduleStore.legacy then
moduleStore.legacy = {}
end
if type(moduleStore.legacy[tableName]) ~= "table" then
moduleStore.legacy[tableName] = {}
end
if type(_G[tableName]) == "table" then
local legacyTable = moduleStore.legacy[tableName]
if not next(legacyTable) then
for key, value in pairs(_G[tableName]) do
legacyTable[key] = value
end
end
end
_G[tableName] = moduleStore.legacy[tableName]
return moduleStore.legacy[tableName]
end
function MTH_SA_IsModuleEnabled()
if MTH and MTH.IsModuleEnabled then
return MTH:IsModuleEnabled("smartammo", true) and true or false
@@ -70,43 +37,22 @@ local function MTH_SA_ApplySavedState()
return
end
local saved = MTH_SA_GetSavedTable("MTHSmartAmmo")
local moduleStore = MTH and MTH.GetModuleCharSavedVariables and MTH:GetModuleCharSavedVariables("smartammo") or nil
if type(moduleStore) == "table" then
if moduleStore.smartEnabled ~= nil then
saved["enabled"] = moduleStore.smartEnabled and 1 or false
end
if moduleStore.reloadEnabled ~= nil then
saved["reload"] = moduleStore.reloadEnabled and 1 or false
end
if moduleStore.weaponSwapEnabled ~= nil then
saved["weaponSwap"] = moduleStore.weaponSwapEnabled and 1 or false
end
end
if saved["enabled"] == nil then
saved["enabled"] = 1
if type(moduleStore) == "table" then
moduleStore.smartEnabled = true
end
end
if saved["reload"] == nil and type(moduleStore) == "table" then
moduleStore.reloadEnabled = saved["reload"] ~= false
end
if saved["weaponSwap"] == nil then
saved["weaponSwap"] = 1
if type(moduleStore) == "table" then
moduleStore.weaponSwapEnabled = true
end
elseif type(moduleStore) == "table" and moduleStore.weaponSwapEnabled == nil then
moduleStore.weaponSwapEnabled = saved["weaponSwap"] ~= false
end
local settings = (type(moduleStore) == "table" and type(moduleStore.settings) == "table") and moduleStore.settings or {}
MTHSmartAmmo_SetSmartEnabled(saved["enabled"] and 1 or nil, 1)
local smart = settings.smartEnabled
if smart == nil then smart = true end
local reload = settings.reloadEnabled
if reload == nil then reload = true end
local swap = settings.weaponSwapEnabled
if swap == nil then swap = true end
MTHSmartAmmo_SetSmartEnabled(smart and 1 or nil, 1)
if type(MTHSmartAmmo_SetReloadEnabled) == "function" then
MTHSmartAmmo_SetReloadEnabled(saved["reload"] ~= false and 1 or nil, 1)
MTHSmartAmmo_SetReloadEnabled(reload and 1 or nil, 1)
end
if type(MTHSmartAmmo_SetWeaponSwapEnabled) == "function" then
MTHSmartAmmo_SetWeaponSwapEnabled(saved["weaponSwap"] ~= false and 1 or nil, 1)
MTHSmartAmmo_SetWeaponSwapEnabled(swap and 1 or nil, 1)
end
if type(MTHSmartAmmo_EnsureHooks) == "function" then
MTHSmartAmmo_EnsureHooks("module-apply")
@@ -154,7 +100,6 @@ local function MTH_SA_RestoreHooks()
end
function MTH_SmartAmmo:init()
MTH_SA_GetSavedTable("MTHSmartAmmo")
if self.enabled then
MTH_SA_ApplySavedState()
end
+12 -11
View File
@@ -115,23 +115,24 @@ local function MTH_TT_IsOwnPetTooltipsEnabled()
end
local function MTH_TT_GetAutoQuestStore()
if type(MTH_CharSavedVariables) ~= "table" then
return nil
end
local store = MTH_CharSavedVariables.autoquest
if type(store) ~= "table" then
store = MTH_CharSavedVariables.questautomation
local store = nil
if MTH and MTH.GetModuleCharSavedVariables then
store = MTH:GetModuleCharSavedVariables("autoquest")
end
if type(store) ~= "table" then
return nil
end
if store.scorpokDrazial == nil then
store.scorpokDrazial = false
if type(store.settings) ~= "table" then
store.settings = {}
end
if store.scorpokTooltip == nil then
store.scorpokTooltip = false
local settings = store.settings
if settings.scorpokDrazial == nil then
settings.scorpokDrazial = false
end
return store
if settings.scorpokTooltip == nil then
settings.scorpokTooltip = false
end
return settings
end
local function MTH_TT_IsScorpokAutomationEnabled()
+28 -3
View File
@@ -43,10 +43,35 @@ function MTH_ZH_IsModuleEnabled()
end
function MTH_ZH_GetSavedRoot()
if type(ZHunterMod_Saved) ~= "table" then
ZHunterMod_Saved = {}
-- Canonical store is MTH_CharSavedVariables.modules.zhunter. The old global
-- ZHunterMod_Saved is kept only as a RUNTIME alias so the many zButton files
-- and options-zbuttons.lua can keep referencing it unchanged.
local store = nil
if MTH and MTH.GetModuleCharSavedVariables then
store = MTH:GetModuleCharSavedVariables("zhunter")
end
return ZHunterMod_Saved
if type(store) ~= "table" then
-- Framework not ready yet: fall back to a temporary global holder;
-- MTH_ZH_SyncSavedVariables re-binds to the nested store later.
if type(ZHunterMod_Saved) ~= "table" then
ZHunterMod_Saved = {}
end
return ZHunterMod_Saved
end
-- Adopt a pre-existing global (legacy TOC copy) once, only if the nested
-- store is still empty, so no layout is lost during the transition.
if type(ZHunterMod_Saved) == "table" and ZHunterMod_Saved ~= store then
if next(store) == nil then
for k, v in pairs(ZHunterMod_Saved) do
store[k] = v
end
end
end
ZHunterMod_Saved = store -- pure runtime alias into the canonical store
return store
end
function MTH_ZH_GetSavedTable(key)
+5 -12
View File
@@ -165,18 +165,11 @@ MTH_ZH_ApplyEnabledRuntimeState = function(source)
end
MTH_ZH_SyncSavedVariables = function()
if not MTH or not MTH.GetModuleCharSavedVariables then
return
end
local moduleStore = MTH:GetModuleCharSavedVariables("zhunter")
if type(ZHunterMod_Saved) == "table" then
if MTH_CharSavedVariables and MTH_CharSavedVariables.modules then
MTH_CharSavedVariables.modules.zhunter = ZHunterMod_Saved
end
elseif type(moduleStore) == "table" then
ZHunterMod_Saved = moduleStore
-- Bind the ZHunterMod_Saved global as a runtime alias into the canonical
-- nested store (MTH_CharSavedVariables.modules.zhunter). GetSavedRoot does the
-- adoption + aliasing; there is no second on-disk copy anymore.
if type(MTH_ZH_GetSavedRoot) == "function" then
MTH_ZH_GetSavedRoot()
end
end