- switching to new C_AddOns API changes
- cascaded message hooking for Retail v12 engine - messages during encounters are sent unchanged, with a one-time notice - ignore numbered chats that do not exist - /r no longer sends to an empty whisper target if the last told target is unavailable - fixed replacements in instance chats - messages to unknown numbered channels are now discarded - right-click on the minimap button
This commit is contained in:
+3
-1
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
- handling of german umlauts (and other unicode characters)
|
||||
- updated libraries and bumped version for all incarnations of WoW (Classic Era, Forever, Classic, Retail)
|
||||
-
|
||||
- adaptations to Retail v12 new Chat handling (Send API, encounter lockdown, instance chat)
|
||||
- /r no longer sends to an empty whisper target if the last told target is unavailable
|
||||
|
||||
## Version 1.1.6 - 2023-01-18
|
||||
### Changed
|
||||
- bumped version for latest WotLK Classic patch
|
||||
|
||||
+4
-2
@@ -20,6 +20,7 @@ local _G = _G
|
||||
|
||||
-- initialize addon
|
||||
local Grichelde = LibStub("AceAddon-3.0"):NewAddon(AddonTable, AddonName, "AceConsole-3.0", "AceEvent-3.0", "AceHook-3.0")
|
||||
local GetAddOnMetadata = (_G.C_AddOns and _G.C_AddOns.GetAddOnMetadata) or _G.GetAddOnMetadata
|
||||
Grichelde.version = GetAddOnMetadata(AddonName, "Version")
|
||||
Grichelde.build = GetAddOnMetadata(AddonName, "X-Build") or "Development"
|
||||
--Grichelde.era = _G.WOW_PROJECT_ID == _G.WOW_PROJECT_CLASSIC
|
||||
@@ -40,7 +41,7 @@ end
|
||||
|
||||
function Grichelde:OnEnable()
|
||||
-- Hook in before message is sent to replace all character occurrences where replacements have been defined in the options
|
||||
self:RawHook("SendChatMessage", true)
|
||||
self:HookSendChatMessage()
|
||||
|
||||
self.options, self.dialog = self:SetupOptions()
|
||||
self.ldb, self.icon = self:MinimapButton()
|
||||
@@ -56,7 +57,8 @@ function Grichelde:OnEnable()
|
||||
end
|
||||
|
||||
function Grichelde:OnDisable()
|
||||
self:Unhook("SendChatMessage")
|
||||
self:UnhookAll()
|
||||
self.originalSend = nil
|
||||
self:CloseOptions()
|
||||
self:HideMinimapButton()
|
||||
self:UnregisterChatCommand("grichelde")
|
||||
|
||||
+87
-10
@@ -2,8 +2,8 @@
|
||||
local _G = _G or getfenv()
|
||||
local Grichelde = _G.Grichelde or {}
|
||||
|
||||
local IsAddOnLoaded, assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tFilter, tInsert, tIsEmpty, tSize, find, sub, gsub, getNextCharUtf8, isUtf8MultiByte, getUtf8Sequence, isUpper, isLower, toUpper, toLower, bytes2Char, trim, length, lengthUtf8
|
||||
= Grichelde.F.IsAddOnLoaded, Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tFilter, Grichelde.F.tInsert, Grichelde.F.tIsEmpty, Grichelde.F.tSize,
|
||||
local assert, nilOrEmpty, pairs, ipairs, spairs, tContains, tFilter, tInsert, tIsEmpty, tSize, find, sub, gsub, getNextCharUtf8, isUtf8MultiByte, getUtf8Sequence, isUpper, isLower, toUpper, toLower, bytes2Char, trim, length, lengthUtf8
|
||||
= Grichelde.F.assert, Grichelde.F.nilOrEmpty, Grichelde.F.pairs, Grichelde.F.ipairs, Grichelde.F.spairs, Grichelde.F.tContains, Grichelde.F.tFilter, Grichelde.F.tInsert, Grichelde.F.tIsEmpty, Grichelde.F.tSize,
|
||||
Grichelde.F.find, Grichelde.F.sub, Grichelde.F.gsub, Grichelde.F.getNextCharUtf8, Grichelde.F.isUtf8MultiByte, Grichelde.F.getUtf8Sequence, Grichelde.F.isUpper, Grichelde.F.isLower, Grichelde.F.toUpper, Grichelde.F.toLower, Grichelde.F.bytes2Char, Grichelde.F.trim, Grichelde.F.length, Grichelde.F.lengthUtf8
|
||||
|
||||
--- Splits a long text in longest possible chunks of <= 255 length, split at last available space
|
||||
@@ -145,10 +145,10 @@ function Grichelde:SendChunkifiedChatMessage(message, ...)
|
||||
self:DebugPrint("SendChunkifiedChatMessage : #chunks:", tSize(chunks))
|
||||
|
||||
for _, chunk in ipairs(chunks) do
|
||||
self.hooks["SendChatMessage"](chunk, ...);
|
||||
self:SendOriginal(chunk, ...)
|
||||
end
|
||||
else
|
||||
self.hooks["SendChatMessage"](message, ...);
|
||||
self:SendOriginal(message, ...)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -886,8 +886,18 @@ function Grichelde:CheckAndExtractMessageTypeTarget(message)
|
||||
-- special reply handling
|
||||
if ("/r" == chatCmd) or ("/reply" == chatCmd) then
|
||||
-- reuse last type and target if possible
|
||||
local lastTold, lastToldType = ChatEdit_GetLastToldTarget()
|
||||
-- TODO: add the Retail 12.x replacement of ChatEdit_GetLastToldTarget once confirmed in-game
|
||||
local lastTold, lastToldType
|
||||
if (_G.ChatEdit_GetLastToldTarget ~= nil) then
|
||||
lastTold, lastToldType = _G.ChatEdit_GetLastToldTarget()
|
||||
end
|
||||
self:DebugPrint("CheckAndExtractMessageTypeTarget : lastTell, lastTellType =", lastTold, lastToldType)
|
||||
|
||||
if (nilOrEmpty(lastTold)) then
|
||||
self:ErrorPrint(self.L.Error_InvalidWhisperTarget)
|
||||
-- dont send text at all
|
||||
return nil
|
||||
end
|
||||
return targetAndText, lastToldType or "WHISPER", lastTold
|
||||
elseif ("/tt" == chatCmd) then
|
||||
-- determine target from game world selection
|
||||
@@ -931,7 +941,7 @@ function Grichelde:CheckAndExtractMessageTypeTarget(message)
|
||||
local _, _, channelNumber = find(chatCmd, "^/(%d+)")
|
||||
if (channelNumber ~= nil) then
|
||||
local channelId = GetChannelName(channelNumber)
|
||||
if (channelId ~= nil) then
|
||||
if (channelId ~= nil) and (channelId > 0) then
|
||||
return targetAndText, "CHANNEL", channelId
|
||||
end
|
||||
end
|
||||
@@ -950,8 +960,50 @@ function Grichelde:CheckAndExtractMessageTypeTarget(message)
|
||||
end
|
||||
end
|
||||
|
||||
--- Hooks C_ChatInfo.SendChatMessage (Retail) and the global SendChatMessage (Classic, deprecated alias on Retail).
|
||||
--- The original C_ChatInfo function is preferred for sending.
|
||||
function Grichelde:HookSendChatMessage()
|
||||
local chatInfo = _G.C_ChatInfo
|
||||
if (chatInfo ~= nil) and (chatInfo.SendChatMessage ~= nil) then
|
||||
self:RawHook(chatInfo, "SendChatMessage", "SendChatMessage", true)
|
||||
self.originalSend = self.hooks[chatInfo]["SendChatMessage"]
|
||||
end
|
||||
|
||||
if (_G.SendChatMessage ~= nil) then
|
||||
self:RawHook("SendChatMessage", true)
|
||||
self.originalSend = self.originalSend or self.hooks["SendChatMessage"]
|
||||
end
|
||||
end
|
||||
|
||||
--- Sends a message with the original (unhooked) send function.
|
||||
function Grichelde:SendOriginal(...)
|
||||
return self.originalSend(...)
|
||||
end
|
||||
|
||||
--- Midnight blocks chat modifications by addons during instance encounters.
|
||||
--- Prints a notice once per lockdown.
|
||||
-- @return boolean
|
||||
function Grichelde:IsChatLockedDown()
|
||||
local chatInfo = _G.C_ChatInfo
|
||||
if (chatInfo == nil) or (chatInfo.InChatMessagingLockdown == nil) then
|
||||
return false
|
||||
end
|
||||
|
||||
if (chatInfo.InChatMessagingLockdown()) then
|
||||
if (not self.lockdownNoticeShown) then
|
||||
self.lockdownNoticeShown = true
|
||||
self:PrefixedPrint(self.L.Chat_Lockdown_Notice)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
self.lockdownNoticeShown = false
|
||||
return false
|
||||
end
|
||||
|
||||
function Grichelde:CleanseMessage(message)
|
||||
local text = message or ""
|
||||
local IsAddOnLoaded = (_G.C_AddOns and _G.C_AddOns.IsAddOnLoaded) or _G.IsAddOnLoaded
|
||||
if (IsAddOnLoaded("Misspelled")) then
|
||||
self:DebugPrint("Misspelled detected: cleansing message")
|
||||
text = _G.Misspelled:RemoveHighlighting(message)
|
||||
@@ -971,7 +1023,12 @@ function Grichelde:SendChatMessageOverride(message, ...)
|
||||
local msg, type, chan = self:CheckAndExtractMessageTypeTarget(cleasendText)
|
||||
|
||||
if (msg ~= nil) then
|
||||
msg = self:ReplaceText(msg)
|
||||
if (not self:IsChatLockedDown()) then
|
||||
msg = self:ReplaceText(msg)
|
||||
else
|
||||
-- do not modify message in any way during encounters
|
||||
-- msg = msg .. self.L.Chat_Lockdown_Suffix
|
||||
end
|
||||
|
||||
if (type ~= nil) then
|
||||
self:SendChunkifiedChatMessage(msg, type, fallbackLang, chan, ...)
|
||||
@@ -989,19 +1046,39 @@ end
|
||||
-- @param language string
|
||||
-- @param channel string
|
||||
function Grichelde:SendChatMessage(message, type, ...)
|
||||
if (self.isReplacing) then
|
||||
-- re-entered through the other hooked send function, text is already replaced
|
||||
self:DebugPrint("SendChatMessage : already replacing")
|
||||
self:SendOriginal(message, type, ...)
|
||||
return
|
||||
end
|
||||
|
||||
self.isReplacing = true
|
||||
-- always reset the guard, even if replacing fails
|
||||
local ok, err = pcall(self.ReplaceAndSendChatMessage, self, message, type, ...)
|
||||
self.isReplacing = false
|
||||
if (not ok) then
|
||||
error(err, 0)
|
||||
end
|
||||
end
|
||||
|
||||
function Grichelde:ReplaceAndSendChatMessage(message, type, ...)
|
||||
if (not self.db.profile.enabled) then
|
||||
self:DebugPrint("SendChatMessage : disabled")
|
||||
self.hooks["SendChatMessage"](message, type, ...);
|
||||
self:SendOriginal(message, type, ...)
|
||||
elseif (nilOrEmpty(message)) then
|
||||
self:DebugPrint("SendChatMessage : no text")
|
||||
self.hooks["SendChatMessage"](message, type, ...);
|
||||
self:SendOriginal(message, type, ...)
|
||||
elseif (self:IsChatLockedDown()) then
|
||||
self:DebugPrint("SendChatMessage : chat lockdown")
|
||||
self:SendOriginal(message, type, ...)
|
||||
else
|
||||
local cleasendText = self:CleanseMessage(message)
|
||||
if (self:CheckReplacementAllowed(cleasendText, type)) then
|
||||
cleasendText = self:ReplaceText(cleasendText)
|
||||
self:SendChunkifiedChatMessage(cleasendText, type, ...)
|
||||
else
|
||||
self.hooks["SendChatMessage"](message, type, ...);
|
||||
self:SendOriginal(message, type, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
+11
-12
@@ -106,17 +106,17 @@ Grichelde.SUPPORTED_CHAT_COMMANDS = {
|
||||
}
|
||||
|
||||
Grichelde.BLIZZ_TYPE_TO_OPTIONS = {
|
||||
["SAY"] = "say",
|
||||
["EMOTE"] = "emote",
|
||||
["YELL"] = "yell",
|
||||
["PARTY"] = "party",
|
||||
["GUILD"] = "guild",
|
||||
["OFFICER"] = "officer",
|
||||
["RAID"] = "raid",
|
||||
["RAID_WARNING"] = "raidWarning",
|
||||
["INSTANCE"] = "instance",
|
||||
["BATTLEGROUND"] = "battleground",
|
||||
["WHISPER"] = "whisper",
|
||||
["SAY"] = "say",
|
||||
["EMOTE"] = "emote",
|
||||
["YELL"] = "yell",
|
||||
["PARTY"] = "party",
|
||||
["GUILD"] = "guild",
|
||||
["OFFICER"] = "officer",
|
||||
["RAID"] = "raid",
|
||||
["RAID_WARNING"] = "raidWarning",
|
||||
["INSTANCE_CHAT"] = "instance",
|
||||
["BATTLEGROUND"] = "battleground",
|
||||
["WHISPER"] = "whisper",
|
||||
}
|
||||
|
||||
-- do not replace these patterns
|
||||
@@ -486,7 +486,6 @@ end
|
||||
|
||||
-- faster function lookups by mapping to local refs
|
||||
Grichelde.F = {
|
||||
IsAddOnLoaded = _G.IsAddOnLoaded,
|
||||
assert = _G.assert,
|
||||
type = _G.type,
|
||||
print = _G.print,
|
||||
|
||||
@@ -48,7 +48,7 @@ function Grichelde:MinimapButton()
|
||||
icon = "Interface\\Icons\\Spell_Holy_Silence",
|
||||
--icon = ([[Interface\Addons\%s\%s]]):format(self.name, self.name),
|
||||
OnClick = clickHandler,
|
||||
OnRightClick = function() self:ShowMappings() end,
|
||||
OnRightClick = function() self:ToogleMappings() end,
|
||||
OnTooltipShow = updateTooltip,
|
||||
iconR = darkened,
|
||||
iconG = darkened,
|
||||
|
||||
@@ -415,9 +415,7 @@ function Grichelde:SetupOptions()
|
||||
-- Adding options to blizzard frame
|
||||
LibStub("AceConfig-3.0"):RegisterOptionsTable(self.name, options)
|
||||
local dialog = LibStub("AceConfigDialog-3.0")
|
||||
local _, categoryID = dialog:AddToBlizOptions(self.name, self.L.AddonName)
|
||||
|
||||
self.optionsCategoryID = categoryID
|
||||
dialog:AddToBlizOptions(self.name, self.L.AddonName)
|
||||
return options, dialog
|
||||
end
|
||||
|
||||
@@ -466,8 +464,9 @@ function Grichelde:RefreshProfiles(event, _, profileName)
|
||||
end
|
||||
|
||||
function Grichelde:ToggleOptions()
|
||||
self:DebugPrint("ToggleOptions : options open: ", not not self.dialog.OpenFrames[self.name])
|
||||
if (self.dialog ~= nil) and (self.dialog.OpenFrames[self.name] ~= nil) then
|
||||
local isOpen = (self.dialog ~= nil) and (self.dialog.OpenFrames[self.name] ~= nil)
|
||||
self:DebugPrint("ToggleOptions : options open: ", isOpen)
|
||||
if (isOpen) then
|
||||
self:CloseOptions()
|
||||
else
|
||||
self:OpenOptions()
|
||||
|
||||
+3
-3
@@ -171,7 +171,7 @@ end
|
||||
--- Print UI options to chat frame
|
||||
function Grichelde:PrintOptions()
|
||||
self:PrefixedPrint(cPrefix(self.L.Debug_Options))
|
||||
self:LogPrint(-1, function(...)
|
||||
self:LogPrint(function(...)
|
||||
print(cPrefix(self.L.AddonName) .. ":", self:Format(...))
|
||||
end, self.options.args.replacements.args)
|
||||
end
|
||||
@@ -179,7 +179,7 @@ end
|
||||
--- Print current DB profile
|
||||
function Grichelde:PrintProfile()
|
||||
self:PrefixedPrint(cPrefix(self.L.Debug_Profile))
|
||||
self:LogPrint(-1, function(...)
|
||||
self:LogPrint(function(...)
|
||||
print(cPrefix(self.L.AddonName) .. ":", self:Format(...))
|
||||
end, self.db.profile)
|
||||
end
|
||||
@@ -187,7 +187,7 @@ end
|
||||
--- Print DB replacements to chat frame
|
||||
function Grichelde:PrintMappings()
|
||||
self:PrefixedPrint(cPrefix(self.L.Debug_Mappings))
|
||||
self:LogPrint(-1, function(...)
|
||||
self:LogPrint(function(...)
|
||||
print(cPrefix(self.L.AddonName) .. ":", self:Format(...))
|
||||
end, self.db.profile.replacements)
|
||||
end
|
||||
|
||||
@@ -33,6 +33,8 @@ L.Error_InvalidCommand = "Ung\195\188ltiger Befehl"
|
||||
L.Error_InvalidChannel = "Ung\195\188ltiger Kanal"
|
||||
L.Error_InvalidWhisperTarget = "Ung\195\188ltiger Fl\195\188sterziel"
|
||||
L.Error_UnsupportedChannel = "Nicht unterst\195\188tzter Kanal"
|
||||
L.Chat_Lockdown_Notice = "Der Chat ist w\195\164hrend dieses Kampfes durch das Spiel gesperrt, Grichelde hält sich zurück."
|
||||
L.Chat_Lockdown_Suffix = "(ignoriert von Grichelde)"
|
||||
|
||||
-- profiles
|
||||
L.Profiles_Available = "Verf\195\188gbare Profile:"
|
||||
|
||||
@@ -33,6 +33,8 @@ L.Error_InvalidCommand = "Invalid command"
|
||||
L.Error_InvalidChannel = "Invalid channel"
|
||||
L.Error_InvalidWhisperTarget = "Invalid whisper target"
|
||||
L.Error_UnsupportedChannel = "Unsupported channel"
|
||||
L.Chat_Lockdown_Notice = "Chat is locked by the game during this encounter. Grichelde will remain passive."
|
||||
L.Chat_Lockdown_Suffix = "(ignored by Grichelde)"
|
||||
|
||||
-- profiles
|
||||
L.Profiles_Available = "Available profiles:"
|
||||
|
||||
Reference in New Issue
Block a user