Refactor Heimdall modules to use class-based structure for improved organization and clarity

This commit is contained in:
2025-05-18 12:28:25 +02:00
parent b16cf762ac
commit 017cbf01f8
5 changed files with 340 additions and 329 deletions

View File

@@ -1,12 +1,12 @@
local _, shared = ...
---@cast shared HeimdallShared
local ModuleName = "Configurator"
---@class HeimdallConfiguratorConfig
---@field enabled boolean
---@field debug boolean
local ModuleName = "Configurator"
---@diagnostic disable-next-line: missing-fields
shared.Configurator = {}
function shared.Configurator.Init() print(string.format("[Heimdall] %s module loaded", ModuleName)) end
---@class Configurator
shared.Configurator = {
Init = function() print(string.format("[Heimdall] %s module loaded", ModuleName)) end,
}

View File

@@ -1,5 +1,6 @@
local _, shared = ...
---@cast shared HeimdallShared
local ModuleName = "DeathReporter"
---@class HeimdallDeathReporterConfig
---@field enabled boolean
@@ -10,95 +11,56 @@ local _, shared = ...
---@field zoneOverride string?
---@field duelThrottle number
local ModuleName = "DeathReporter"
---@class DeathReporter
shared.DeathReporter = {
Init = function()
---@type table<string, number>
local recentDeaths = {}
---@type table<string, number>
local recentDuels = {}
---@diagnostic disable-next-line: missing-fields
shared.DeathReporter = {}
function shared.DeathReporter.Init()
---@type table<string, number>
local recentDeaths = {}
---@type table<string, number>
local recentDuels = {}
---@param source string
---@param destination string
---@param spellName string
local function RegisterDeath(source, destination, spellName)
if Heimdall_Data.config.deathReporter.debug then
print(
string.format(
"[%s] Processing death event - Source: %s, Target: %s, Spell: %s",
ModuleName,
source,
destination,
spellName
)
)
end
if not Heimdall_Data.config.deathReporter.enabled then
---@param source string
---@param destination string
---@param spellName string
local function RegisterDeath(source, destination, spellName)
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Module disabled, ignoring death event", ModuleName))
end
return
end
if
recentDeaths[destination]
and GetTime() - recentDeaths[destination] < Heimdall_Data.config.deathReporter.throttle
then
if Heimdall_Data.config.deathReporter.debug then
local timeLeft = Heimdall_Data.config.deathReporter.throttle - (GetTime() - recentDeaths[destination])
print(
string.format(
"[%s] Death report throttled for %s (%.1f seconds remaining)",
"[%s] Processing death event - Source: %s, Target: %s, Spell: %s",
ModuleName,
source,
destination,
timeLeft
spellName
)
)
end
return
end
if
recentDuels[destination]
and GetTime() - recentDuels[destination] < Heimdall_Data.config.deathReporter.duelThrottle
then
if Heimdall_Data.config.deathReporter.debug then
print(
string.format(
"[%s] Ignoring death report - Recent duel detected for target: %s",
ModuleName,
destination
)
)
if not Heimdall_Data.config.deathReporter.enabled then
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Module disabled, ignoring death event", ModuleName))
end
return
end
return
end
if
recentDuels[source]
and GetTime() - recentDuels[source] < Heimdall_Data.config.deathReporter.duelThrottle
then
if Heimdall_Data.config.deathReporter.debug then
print(
string.format(
"[%s] Ignoring death report - Recent duel detected for source: %s",
ModuleName,
source
if
recentDeaths[destination]
and GetTime() - recentDeaths[destination] < Heimdall_Data.config.deathReporter.throttle
then
if Heimdall_Data.config.deathReporter.debug then
local timeLeft = Heimdall_Data.config.deathReporter.throttle
- (GetTime() - recentDeaths[destination])
print(
string.format(
"[%s] Death report throttled for %s (%.1f seconds remaining)",
ModuleName,
destination,
timeLeft
)
)
)
end
return
end
return
end
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Recording death for %s", ModuleName, destination))
end
recentDeaths[destination] = GetTime()
C_Timer.NewTimer(3, function()
if
recentDuels[destination]
and GetTime() - recentDuels[destination] < Heimdall_Data.config.deathReporter.duelThrottle
@@ -106,7 +68,7 @@ function shared.DeathReporter.Init()
if Heimdall_Data.config.deathReporter.debug then
print(
string.format(
"[%s] Cancelling delayed death report - Recent duel detected for: %s",
"[%s] Ignoring death report - Recent duel detected for target: %s",
ModuleName,
destination
)
@@ -122,7 +84,7 @@ function shared.DeathReporter.Init()
if Heimdall_Data.config.deathReporter.debug then
print(
string.format(
"[%s] Cancelling delayed death report - Recent duel detected for: %s",
"[%s] Ignoring death report - Recent duel detected for source: %s",
ModuleName,
source
)
@@ -132,131 +94,175 @@ function shared.DeathReporter.Init()
end
if Heimdall_Data.config.deathReporter.debug then
print(
string.format(
"[%s] Sending death report - %s killed %s with %s",
ModuleName,
print(string.format("[%s] Recording death for %s", ModuleName, destination))
end
recentDeaths[destination] = GetTime()
C_Timer.NewTimer(3, function()
if
recentDuels[destination]
and GetTime() - recentDuels[destination] < Heimdall_Data.config.deathReporter.duelThrottle
then
if Heimdall_Data.config.deathReporter.debug then
print(
string.format(
"[%s] Cancelling delayed death report - Recent duel detected for: %s",
ModuleName,
destination
)
)
end
return
end
if
recentDuels[source]
and GetTime() - recentDuels[source] < Heimdall_Data.config.deathReporter.duelThrottle
then
if Heimdall_Data.config.deathReporter.debug then
print(
string.format(
"[%s] Cancelling delayed death report - Recent duel detected for: %s",
ModuleName,
source
)
)
end
return
end
if Heimdall_Data.config.deathReporter.debug then
print(
string.format(
"[%s] Sending death report - %s killed %s with %s",
ModuleName,
source,
destination,
spellName
)
)
end
local zone, subzone = GetZoneText() or "Unknown", GetSubZoneText() or "Unknown"
if Heimdall_Data.config.spotter.zoneOverride then
zone = Heimdall_Data.config.spotter.zoneOverride or ""
subzone = ""
end
local x, y = GetPlayerMapPosition("player")
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Player coordinates: %.2f, %.2f", ModuleName, x * 100, y * 100))
end
SetMapToCurrentZone()
SetMapByID(GetCurrentMapAreaID())
local zoneId = GetCurrentMapAreaID()
for _, channel in pairs(Heimdall_Data.config.deathReporter.channels) do
local locale = shared.GetLocaleForChannel(channel)
local text = string.format(
shared._L("killed", locale),
source,
destination,
spellName
shared._L(spellName, locale),
shared._L(zone, locale),
shared._L(subzone, locale),
zoneId,
x * 100,
y * 100
)
---@type Message
local msg = {
channel = "C",
data = channel,
message = text,
}
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Queuing death report message", ModuleName))
shared.dumpTable(msg)
end
table.insert(shared.messenger.queue, msg)
end
end)
end
local cleuFrame = CreateFrame("Frame")
cleuFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
cleuFrame:SetScript("OnEvent", function(self, event, ...)
-- if Heimdall_Data.config.deathReporter.debug then
-- print(string.format("[%s] Received combat log event", ModuleName))
-- end
if not Heimdall_Data.config.deathReporter.enabled then return end
local overkill, source, destination, spellName, sourceGUID, destinationGUID, err
overkill, err = CLEUParser.GetOverkill(...)
if not err and overkill > 0 then
source, err = CLEUParser.GetSourceName(...)
if err then
source = "unknown"
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Error getting source name", ModuleName))
end
end
destination, err = CLEUParser.GetDestName(...)
if err then
destination = "unknown"
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Error getting destination name", ModuleName))
end
end
spellName, err = CLEUParser.GetSpellName(...)
if err then
spellName = "unknown"
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Error getting spell name", ModuleName))
end
end
sourceGUID, err = CLEUParser.GetSourceGUID(...)
if err or not string.match(sourceGUID, "Player") then return end
destinationGUID, err = CLEUParser.GetDestGUID(...)
if err or not string.match(destinationGUID, "Player") then return end
RegisterDeath(source, destination, spellName)
end
end)
local systemMessageFrame = CreateFrame("Frame")
systemMessageFrame:RegisterEvent("CHAT_MSG_SYSTEM")
systemMessageFrame:SetScript("OnEvent", function(self, event, msg)
if not Heimdall_Data.config.deathReporter.enabled then return end
local source, destination = string.match(msg, "([^ ]+) has defeated ([^ ]+) in a duel")
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Received system message: %s", ModuleName, msg))
print(
string.format(
"[%s] Source: %s, Destination: %s",
ModuleName,
tostring(source),
tostring(destination)
)
)
end
local zone, subzone = GetZoneText() or "Unknown", GetSubZoneText() or "Unknown"
if Heimdall_Data.config.spotter.zoneOverride then
zone = Heimdall_Data.config.spotter.zoneOverride or ""
subzone = ""
end
local x, y = GetPlayerMapPosition("player")
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Player coordinates: %.2f, %.2f", ModuleName, x * 100, y * 100))
end
SetMapToCurrentZone()
SetMapByID(GetCurrentMapAreaID())
local zoneId = GetCurrentMapAreaID()
for _, channel in pairs(Heimdall_Data.config.deathReporter.channels) do
local locale = shared.GetLocaleForChannel(channel)
local text = string.format(
shared._L("killed", locale),
source,
destination,
shared._L(spellName, locale),
shared._L(zone, locale),
shared._L(subzone, locale),
zoneId,
x * 100,
y * 100
)
---@type Message
local msg = {
channel = "C",
data = channel,
message = text,
}
if not source or not destination then return end
source = string.match(source, "([^-]+)")
destination = string.match(destination, "([^-]+)")
if source and destination then
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Queuing death report message", ModuleName))
shared.dumpTable(msg)
print(string.format("[%s] Detected duel between %s and %s", ModuleName, source, destination))
end
table.insert(shared.messenger.queue, msg)
local now = GetTime()
recentDuels[source] = now
recentDuels[destination] = now
end
end)
end
local cleuFrame = CreateFrame("Frame")
cleuFrame:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
cleuFrame:SetScript("OnEvent", function(self, event, ...)
-- if Heimdall_Data.config.deathReporter.debug then
-- print(string.format("[%s] Received combat log event", ModuleName))
-- end
if not Heimdall_Data.config.deathReporter.enabled then return end
local overkill, source, destination, spellName, sourceGUID, destinationGUID, err
overkill, err = CLEUParser.GetOverkill(...)
if not err and overkill > 0 then
source, err = CLEUParser.GetSourceName(...)
if err then
source = "unknown"
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Error getting source name", ModuleName))
end
end
destination, err = CLEUParser.GetDestName(...)
if err then
destination = "unknown"
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Error getting destination name", ModuleName))
end
end
spellName, err = CLEUParser.GetSpellName(...)
if err then
spellName = "unknown"
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Error getting spell name", ModuleName))
end
end
sourceGUID, err = CLEUParser.GetSourceGUID(...)
if err or not string.match(sourceGUID, "Player") then return end
destinationGUID, err = CLEUParser.GetDestGUID(...)
if err or not string.match(destinationGUID, "Player") then return end
RegisterDeath(source, destination, spellName)
end
end)
local systemMessageFrame = CreateFrame("Frame")
systemMessageFrame:RegisterEvent("CHAT_MSG_SYSTEM")
systemMessageFrame:SetScript("OnEvent", function(self, event, msg)
if not Heimdall_Data.config.deathReporter.enabled then return end
local source, destination = string.match(msg, "([^ ]+) has defeated ([^ ]+) in a duel")
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Received system message: %s", ModuleName, msg))
print(
string.format("[%s] Source: %s, Destination: %s", ModuleName, tostring(source), tostring(destination))
string.format(
"[%s] Module initialized with throttle: %.1fs, duel throttle: %.1fs",
ModuleName,
Heimdall_Data.config.deathReporter.throttle,
Heimdall_Data.config.deathReporter.duelThrottle
)
)
end
if not source or not destination then return end
source = string.match(source, "([^-]+)")
destination = string.match(destination, "([^-]+)")
if source and destination then
if Heimdall_Data.config.deathReporter.debug then
print(string.format("[%s] Detected duel between %s and %s", ModuleName, source, destination))
end
local now = GetTime()
recentDuels[source] = now
recentDuels[destination] = now
end
end)
if Heimdall_Data.config.deathReporter.debug then
print(
string.format(
"[%s] Module initialized with throttle: %.1fs, duel throttle: %.1fs",
ModuleName,
Heimdall_Data.config.deathReporter.throttle,
Heimdall_Data.config.deathReporter.duelThrottle
)
)
end
print("[Heimdall] DeathReporter loaded")
end
print("[Heimdall] DeathReporter loaded")
end,
}

View File

@@ -2,54 +2,57 @@ local _, shared = ...
---@cast shared HeimdallShared
local ModuleName = "Dueler"
---@diagnostic disable-next-line: missing-fields
shared.Dueler = {}
function shared.Dueler.Init()
local frame = CreateFrame("Frame")
frame:RegisterEvent("DUEL_REQUESTED")
frame:SetScript("OnEvent", function(self, event, sender)
if Heimdall_Data.config.dueler.debug then
print(string.format("[%s] Duel request received from: %s", ModuleName, sender))
end
if not Heimdall_Data.config.dueler.enabled then
---@class Dueler
shared.Dueler = {
Init = function()
local frame = CreateFrame("Frame")
frame:RegisterEvent("DUEL_REQUESTED")
frame:SetScript("OnEvent", function(self, event, sender)
if Heimdall_Data.config.dueler.debug then
print(string.format("[%s] Module disabled, ignoring duel request", ModuleName))
print(string.format("[%s] Duel request received from: %s", ModuleName, sender))
end
return
end
if Heimdall_Data.config.dueler.debug then
print(string.format("[%s] Checking if sender '%s' is in agents list", ModuleName, sender))
end
local allow = shared.AgentTracker.IsAgent(sender)
if allow then
if Heimdall_Data.config.dueler.debug then
print(string.format("[%s] Accepting duel from trusted agent: %s", ModuleName, sender))
end
AcceptDuel()
else
if Heimdall_Data.config.dueler.declineOther then
if not Heimdall_Data.config.dueler.enabled then
if Heimdall_Data.config.dueler.debug then
print(string.format("[%s] Auto-declining duel from untrusted sender: %s", ModuleName, sender))
print(string.format("[%s] Module disabled, ignoring duel request", ModuleName))
end
CancelDuel()
return
end
if Heimdall_Data.config.dueler.debug then
print(string.format("[%s] Checking if sender '%s' is in agents list", ModuleName, sender))
end
local allow = shared.AgentTracker.IsAgent(sender)
if allow then
if Heimdall_Data.config.dueler.debug then
print(string.format("[%s] Accepting duel from trusted agent: %s", ModuleName, sender))
end
AcceptDuel()
else
if Heimdall_Data.config.dueler.debug then
print(string.format("[%s] Leaving duel request from %s for manual response", ModuleName, sender))
if Heimdall_Data.config.dueler.declineOther then
if Heimdall_Data.config.dueler.debug then
print(string.format("[%s] Auto-declining duel from untrusted sender: %s", ModuleName, sender))
end
CancelDuel()
else
if Heimdall_Data.config.dueler.debug then
print(
string.format("[%s] Leaving duel request from %s for manual response", ModuleName, sender)
)
end
end
end
end
end)
end)
if Heimdall_Data.config.dueler.debug then
print(
string.format(
"[%s] Module initialized with auto-decline: %s",
ModuleName,
tostring(Heimdall_Data.config.dueler.declineOther)
if Heimdall_Data.config.dueler.debug then
print(
string.format(
"[%s] Module initialized with auto-decline: %s",
ModuleName,
tostring(Heimdall_Data.config.dueler.declineOther)
)
)
)
end
print("[Heimdall] Dueler loaded")
end
end
print("[Heimdall] Dueler loaded")
end,
}

View File

@@ -2,57 +2,58 @@ local _, shared = ...
---@cast shared HeimdallShared
local ModuleName = "Echoer"
---@diagnostic disable-next-line: missing-fields
shared.Echoer = {}
function shared.Echoer.Init()
local frame = CreateFrame("Frame")
frame:RegisterEvent("CHAT_MSG_CHANNEL")
frame:SetScript("OnEvent", function(self, event, msg, sender, ...)
--if Heimdall_Data.config.echoer.debug then
-- print(string.format("[%s] Channel message received from: %s", ModuleName, sender))
--end
if not Heimdall_Data.config.echoer.enabled then
---@class Echoer
shared.Echoer = {
Init = function()
local frame = CreateFrame("Frame")
frame:RegisterEvent("CHAT_MSG_CHANNEL")
frame:SetScript("OnEvent", function(self, event, msg, sender, ...)
--if Heimdall_Data.config.echoer.debug then
-- print(string.format("[%s] Module disabled, ignoring message", ModuleName))
-- print(string.format("[%s] Channel message received from: %s", ModuleName, sender))
--end
return
end
local channelId = select(6, ...)
local _, channelname = GetChannelName(channelId)
local ok = false
for _, channel in pairs(Heimdall_Data.config.echoer.channels) do
if channel == channelname then
ok = true
break
if not Heimdall_Data.config.echoer.enabled then
--if Heimdall_Data.config.echoer.debug then
-- print(string.format("[%s] Module disabled, ignoring message", ModuleName))
--end
return
end
end
if not ok then
if Heimdall_Data.config.echoer.debug then
print(string.format("[%s] Channel name does not match any of the channels", ModuleName))
end
return
end
if Heimdall_Data.config.echoer.debug then
print(string.format("[%s] Processing message from master channel: %s", ModuleName, sender))
shared.dumpTable(Heimdall_Data.config.echoer)
end
if string.find(msg, "^" .. Heimdall_Data.config.echoer.prefix) then
if Heimdall_Data.config.echoer.debug then
print(string.format("[%s] Found echo command in message: %s", ModuleName, msg))
local channelId = select(6, ...)
local _, channelname = GetChannelName(channelId)
local ok = false
for _, channel in pairs(Heimdall_Data.config.echoer.channels) do
if channel == channelname then
ok = true
break
end
end
local echomsg = string.sub(msg, string.len(Heimdall_Data.config.echoer.prefix) + 1)
if Heimdall_Data.config.echoer.debug then
print(string.format("[%s] Echoing message: %s", ModuleName, echomsg))
if not ok then
if Heimdall_Data.config.echoer.debug then
print(string.format("[%s] Channel name does not match any of the channels", ModuleName))
end
return
end
if Heimdall_Data.config.echoer.debug then
print(string.format("[%s] Processing message from master channel: %s", ModuleName, sender))
shared.dumpTable(Heimdall_Data.config.echoer)
end
SendChatMessage(echomsg, "SAY")
elseif Heimdall_Data.config.echoer.debug then
print(string.format("[%s] Message does not start with echo prefix", ModuleName))
end
end)
if Heimdall_Data.config.echoer.debug then print(string.format("[%s] Module initialized", ModuleName)) end
print("[Heimdall] Echoer loaded")
end
if string.find(msg, "^" .. Heimdall_Data.config.echoer.prefix) then
if Heimdall_Data.config.echoer.debug then
print(string.format("[%s] Found echo command in message: %s", ModuleName, msg))
end
local echomsg = string.sub(msg, string.len(Heimdall_Data.config.echoer.prefix) + 1)
if Heimdall_Data.config.echoer.debug then
print(string.format("[%s] Echoing message: %s", ModuleName, echomsg))
end
SendChatMessage(echomsg, "SAY")
elseif Heimdall_Data.config.echoer.debug then
print(string.format("[%s] Message does not start with echo prefix", ModuleName))
end
end)
if Heimdall_Data.config.echoer.debug then print(string.format("[%s] Module initialized", ModuleName)) end
print("[Heimdall] Echoer loaded")
end,
}

View File

@@ -2,58 +2,59 @@ local _, shared = ...
---@cast shared HeimdallShared
local ModuleName = "Emoter"
---@diagnostic disable-next-line: missing-fields
shared.Emoter = {}
function shared.Emoter.Init()
local frame = CreateFrame("Frame")
frame:RegisterEvent("CHAT_MSG_CHANNEL")
frame:SetScript("OnEvent", function(self, event, msg, sender, ...)
--if Heimdall_Data.config.emoter.debug then
-- print(string.format("[%s] Channel message received from: %s", ModuleName, sender))
--end
if not Heimdall_Data.config.emoter.enabled then
---@class Emoter
shared.Emoter = {
Init = function()
local frame = CreateFrame("Frame")
frame:RegisterEvent("CHAT_MSG_CHANNEL")
frame:SetScript("OnEvent", function(self, event, msg, sender, ...)
--if Heimdall_Data.config.emoter.debug then
-- print(string.format("[%s] Module disabled, ignoring message", ModuleName))
-- print(string.format("[%s] Channel message received from: %s", ModuleName, sender))
--end
return
end
local channelId = select(6, ...)
local _, channelname = GetChannelName(channelId)
local ok = false
for _, channel in pairs(Heimdall_Data.config.emoter.channels) do
if channel == channelname then
ok = true
break
if not Heimdall_Data.config.emoter.enabled then
--if Heimdall_Data.config.emoter.debug then
-- print(string.format("[%s] Module disabled, ignoring message", ModuleName))
--end
return
end
end
if not ok then
local channelId = select(6, ...)
local _, channelname = GetChannelName(channelId)
local ok = false
for _, channel in pairs(Heimdall_Data.config.emoter.channels) do
if channel == channelname then
ok = true
break
end
end
if not ok then
if Heimdall_Data.config.emoter.debug then
print(string.format("[%s] Channel name does not match any of the channels", ModuleName))
end
return
end
if Heimdall_Data.config.emoter.debug then
print(string.format("[%s] Channel name does not match any of the channels", ModuleName))
print(string.format("[%s] Processing message from master channel: %s", ModuleName, sender))
shared.dumpTable(Heimdall_Data.config.emoter)
end
return
end
if Heimdall_Data.config.emoter.debug then
print(string.format("[%s] Processing message from master channel: %s", ModuleName, sender))
shared.dumpTable(Heimdall_Data.config.emoter)
end
if string.find(msg, "^" .. Heimdall_Data.config.emoter.prefix) then
if Heimdall_Data.config.emoter.debug then
print(string.format("[%s] Found emote command in message: %s", ModuleName, msg))
if string.find(msg, "^" .. Heimdall_Data.config.emoter.prefix) then
if Heimdall_Data.config.emoter.debug then
print(string.format("[%s] Found emote command in message: %s", ModuleName, msg))
end
local emote = string.sub(msg, string.len(Heimdall_Data.config.emoter.prefix) + 1)
if Heimdall_Data.config.emoter.debug then
print(string.format("[%s] Performing emote: %s", ModuleName, emote))
end
DoEmote(emote)
elseif Heimdall_Data.config.emoter.debug then
print(string.format("[%s] Message does not start with emote prefix", ModuleName))
end
local emote = string.sub(msg, string.len(Heimdall_Data.config.emoter.prefix) + 1)
if Heimdall_Data.config.emoter.debug then
print(string.format("[%s] Performing emote: %s", ModuleName, emote))
end
DoEmote(emote)
elseif Heimdall_Data.config.emoter.debug then
print(string.format("[%s] Message does not start with emote prefix", ModuleName))
end
end)
end)
if Heimdall_Data.config.emoter.debug then print(string.format("[%s] Module initialized", ModuleName)) end
print("[Heimdall] Emoter loaded")
end
if Heimdall_Data.config.emoter.debug then print(string.format("[%s] Module initialized", ModuleName)) end
print("[Heimdall] Emoter loaded")
end,
}