Refactor txAdminLogs to modular, configurable system
Replaces the old txAdminLogs implementation with a modular, table-driven system. Adds new files (fxmanifest.lua, main.lua, settings.lua, utils.lua) and removes the previous monolithic scripts. Logging is now fully configurable via settings.lua, supports per-event webhooks, and features improved formatting and timestamp handling. Updates README with new installation and configuration instructions.
This commit is contained in:
34
README.md
34
README.md
@@ -1,8 +1,32 @@
|
||||
# txAdminLogs
|
||||
Simple Standalone txAdmin Logs made for FiveM
|
||||
# 🛠️ txAdminLogs
|
||||
A lightweight, standalone logging system for FiveM that automatically captures and routes **txAdmin** events to Discord.
|
||||
|
||||
Drag and drop installation, just add the line below to your server.cfg / resources.cfg
|
||||
---
|
||||
|
||||
`ensure txAdminLogs`
|
||||
## ✨ Features
|
||||
* **Zero Maintenance:** Automatically registers listeners for every event defined in your settings.
|
||||
* **Dual-Routing:** Sends logs to specific category channels (e.g., Bans, Whitelist) while simultaneously maintaining a "Master Log" for full history.
|
||||
* **Smart Tables:** Automatically flattens complex data (like Player Identifiers) into clean, bulleted lists.
|
||||
* **Dynamic Timestamps:** Converts expiration Unix codes into human-readable, localized Discord time (e.g., "in 2 days").
|
||||
* **Standalone:** No framework requirements. Works on any server.
|
||||
|
||||
Feel free to modify for personal usage, don't ever distribute it for any amount of money.
|
||||
---
|
||||
|
||||
## 🚀 Installation
|
||||
1. Drop the `txAdminLogs` folder into your `resources` directory.
|
||||
2. Open `settings.lua` and replace `'WEBHOOK'` with your actual Discord Webhook URLs.
|
||||
3. Add `ensure txAdminLogs` to your `server.cfg`.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Configuration
|
||||
The system uses a simple table structure in `settings.lua`.
|
||||
|
||||
* **MasterWebhook:** The catch-all channel.
|
||||
* **Webhooks Table:**
|
||||
```lua
|
||||
['playerBanned'] = {
|
||||
color = 10038562,
|
||||
title = '🔨 txAdmin: Player Banned',
|
||||
webhook = 'YOUR_SPECIFIC_URL'
|
||||
}
|
||||
14
fxmanifest.lua
Normal file
14
fxmanifest.lua
Normal file
@@ -0,0 +1,14 @@
|
||||
fx_version 'cerulean'
|
||||
game 'gta5'
|
||||
|
||||
author 'Joost'
|
||||
description 'txAdmin Logs'
|
||||
version '2.0.0'
|
||||
|
||||
server_only 'yes'
|
||||
|
||||
server_scripts {
|
||||
'settings.lua',
|
||||
'utils.lua',
|
||||
'main.lua'
|
||||
}
|
||||
5
main.lua
Normal file
5
main.lua
Normal file
@@ -0,0 +1,5 @@
|
||||
for eventName, data in pairs(Settings.Webhooks) do
|
||||
AddEventHandler('txAdmin:events:' .. eventName, function(eventData)
|
||||
sendToDiscord(eventName, eventData)
|
||||
end)
|
||||
end
|
||||
41
settings.lua
Normal file
41
settings.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
Settings = {}
|
||||
|
||||
Settings.Bot = {
|
||||
Username = 'txAdmin Logs',
|
||||
AvatarURL = '',
|
||||
FooterText = 'txAdmin Logs • ' .. os.date('%Y'),
|
||||
FooterIcon = '',
|
||||
}
|
||||
|
||||
Settings.Misc = {
|
||||
IncludeTimestamp = true,
|
||||
}
|
||||
|
||||
Settings.MasterWebhook = 'WEBHOOK'
|
||||
|
||||
Settings.Webhooks = {
|
||||
-- Server-Related Events
|
||||
['announcement'] = { color = 16776960, title = '📢 txAdmin: Announcement', webhook = 'WEBHOOK' },
|
||||
['serverShuttingDown'] = { color = 15158332, title = '🛑 txAdmin: Server Shutting Down', webhook = 'WEBHOOK' },
|
||||
['scheduledRestart'] = { color = 15105570, title = '⏲️ txAdmin: Scheduled Restart', webhook = 'WEBHOOK' },
|
||||
['scheduledRestartSkipped'] = { color = 3447003, title = '⏭️ txAdmin: Restart Skipped', webhook = 'WEBHOOK' },
|
||||
|
||||
-- Player-Related Events
|
||||
['playerBanned'] = { color = 10038562, title = '🔨 txAdmin: Player Banned', webhook = 'WEBHOOK' },
|
||||
['playerDirectMessage'] = { color = 16777215, title = '💬 txAdmin: Direct Message', webhook = 'WEBHOOK' },
|
||||
['playerHealed'] = { color = 3066993, title = '❤️ txAdmin: Player Healed', webhook = 'WEBHOOK' },
|
||||
['playerKicked'] = { color = 15158332, title = '👢 txAdmin: Player Kicked', webhook = 'WEBHOOK' },
|
||||
['playerWarned'] = { color = 15844367, title = '⚠️ txAdmin: Player Warned', webhook = 'WEBHOOK' },
|
||||
|
||||
-- Whitelist-Related Events
|
||||
['whitelistPlayer'] = { color = 3066993, title = '📝 txAdmin: Player Whitelisted', webhook = 'WEBHOOK' },
|
||||
['whitelistPreApproval'] = { color = 3447003, title = '📋 txAdmin: Whitelist Pre-Approval', webhook = 'WEBHOOK' },
|
||||
['whitelistRequest'] = { color = 1752220, title = '📩 txAdmin: Whitelist Request', webhook = 'WEBHOOK' },
|
||||
|
||||
-- Other Events
|
||||
['actionRevoked'] = { color = 9807270, title = '🔄 txAdmin: Action Revoked', webhook = 'WEBHOOK' },
|
||||
['adminAuth'] = { color = 15105570, title = '🔐 txAdmin: Admin Authenticated', webhook = 'WEBHOOK' },
|
||||
['adminsUpdated'] = { color = 3447003, title = '👥 txAdmin: Admins Updated', webhook = 'WEBHOOK' },
|
||||
['configChanged'] = { color = 15844367, title = '⚙️ txAdmin: Config Changed', webhook = 'WEBHOOK' },
|
||||
['consoleCommand'] = { color = 0, title = '💻 txAdmin: Console Command', webhook = 'WEBHOOK' },
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
Config = {}
|
||||
|
||||
Config.txAdminWebhook = 'WEBHOOK'
|
||||
|
||||
Config.Username = 'txAdmin Logs'
|
||||
|
||||
Config.FilterAnnouncements = true
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
fx_version 'cerulean'
|
||||
games { 'gta5' }
|
||||
|
||||
author 'Joost#5866'
|
||||
description 'txAdmin Logs'
|
||||
version '1.0.5'
|
||||
|
||||
server_only "yes"
|
||||
|
||||
server_scripts {
|
||||
'config.lua',
|
||||
'sv_txadmin.lua'
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
AddEventHandler('txAdmin:events:playerKicked', function(eventData)
|
||||
|
||||
local target = eventData.target
|
||||
local author = eventData.author
|
||||
local reason = eventData.reason
|
||||
|
||||
sendToDiscord('Player Kicked', "Name: **" .. GetPlayerName(target) .. "** \nAuthor: **" .. author .. "** \nReason: **" .. reason .. "**", 65280)
|
||||
|
||||
end)
|
||||
|
||||
AddEventHandler('txAdmin:events:playerWarned', function(eventData)
|
||||
|
||||
local target = eventData.target
|
||||
local author = eventData.author
|
||||
local reason = eventData.reason
|
||||
local id = eventData.actionId
|
||||
|
||||
sendToDiscord('Player Warned', "Name: **" .. GetPlayerName(target) .. "** \nAuthor: **" .. author .. "** \nReason: **" .. reason .. "**\nID: **" .. id .. "**", 65280)
|
||||
|
||||
end)
|
||||
|
||||
AddEventHandler('txAdmin:events:playerBanned', function(eventData)
|
||||
|
||||
local target = eventData.target
|
||||
local author = eventData.author
|
||||
local reason = eventData.reason
|
||||
local id = eventData.actionId
|
||||
local exp = eventData.expiration
|
||||
|
||||
if not exp then
|
||||
exp = 'Never'
|
||||
else
|
||||
exp = os.date('%c', exp)
|
||||
end
|
||||
|
||||
if (type(target) == "table") then
|
||||
playername = "`Offline Ban`"
|
||||
else
|
||||
playername = GetPlayerName(target)
|
||||
end
|
||||
|
||||
sendToDiscord('Player Banned', "Name: **" .. playername .. "** \nAuthor: **" .. author .. "** \nReason: **" .. reason .. "**\nID: **" .. id .. "**\nExpires: **" .. exp .. "**", 65280)
|
||||
|
||||
end)
|
||||
|
||||
AddEventHandler('txAdmin:events:playerWhitelisted', function(eventData)
|
||||
|
||||
local target = eventData.target
|
||||
local author = eventData.author
|
||||
local id = eventData.actionId
|
||||
|
||||
sendToDiscord('Player Whitelisted', "Identifier: **" .. target .. "** \nAuthor: **" .. author .. "**\nID: **" .. id .. "**", 65280)
|
||||
|
||||
end)
|
||||
|
||||
AddEventHandler('txAdmin:events:announcement', function(eventData)
|
||||
|
||||
local author = eventData.author
|
||||
local msg = eventData.message
|
||||
|
||||
if Config.FilterAnnouncements then
|
||||
if author ~= 'txAdmin' then
|
||||
sendToDiscord('Announcement', "Author: **" .. author .. "**\Message: **" .. msg .. "**", 65280)
|
||||
end
|
||||
else
|
||||
sendToDiscord('Announcement', "Author: **" .. author .. "**\Message: **" .. msg .. "**", 65280)
|
||||
end
|
||||
|
||||
|
||||
end)
|
||||
|
||||
AddEventHandler('txAdmin:events:configChanged', function(eventData)
|
||||
|
||||
sendToDiscord('Config Changed', "There have been made changes in the txAdmin settings, if this wasn't you then check it asap.", 65280)
|
||||
|
||||
end)
|
||||
|
||||
AddEventHandler('txAdmin:events:healedPlayer', function(eventData)
|
||||
|
||||
local target = eventData.id
|
||||
|
||||
if target == -1 then
|
||||
playername = 'Everyone'
|
||||
else
|
||||
playername = GetPlayerName(target)
|
||||
end
|
||||
|
||||
sendToDiscord('Player Healed', "Name: **" .. playername .. "**", 65280)
|
||||
|
||||
end)
|
||||
|
||||
AddEventHandler('txAdmin:events:serverShuttingDown', function(eventData)
|
||||
|
||||
local delay = eventData.delay
|
||||
local author = eventData.author
|
||||
local msg = eventData.message
|
||||
|
||||
|
||||
sendToDiscord('Server Shutdown', "Author: **" .. author .. "**\Message: **" .. msg .. "**\Delay: **" .. delay .. "ms**", 65280)
|
||||
end)
|
||||
|
||||
function sendToDiscord(header, message)
|
||||
local webhook = Config.txAdminWebhook
|
||||
local name = Config.Username
|
||||
local connect = {
|
||||
{
|
||||
["title"] = header,
|
||||
["description"] = message
|
||||
}
|
||||
}
|
||||
PerformHttpRequest(webhook, function(err, text, headers) end, 'POST', json.encode({username = name, embeds = connect, avatar_url = avatar}), { ['Content-Type'] = 'application/json' })
|
||||
end
|
||||
62
utils.lua
Normal file
62
utils.lua
Normal file
@@ -0,0 +1,62 @@
|
||||
function sendToDiscord(logType, message)
|
||||
local logData = Settings.Webhooks[logType]
|
||||
local color = logData and logData.color or 8421504
|
||||
local title = logData and logData.title or "Unknown Log Type"
|
||||
local targetWebhook = (logData and logData.webhook ~= 'WEBHOOK') and logData.webhook or Settings.MasterWebhook
|
||||
|
||||
local formattedDescription = ""
|
||||
|
||||
if type(message) == 'table' then
|
||||
for key, value in pairs(message) do
|
||||
local label = key:gsub("(%l)(%A)", "%1 %2"):gsub("^%l", string.upper)
|
||||
|
||||
if type(value) == 'table' then
|
||||
local subValues = ""
|
||||
for _, subVal in pairs(value) do
|
||||
subValues = subValues .. "• " .. tostring(subVal) .. "\n"
|
||||
end
|
||||
formattedDescription = formattedDescription .. string.format("**%s**:\n%s", label, subValues)
|
||||
elseif key:lower() == "expiration" then
|
||||
if type(value) == "number" and value > 0 then
|
||||
formattedDescription = formattedDescription .. string.format("**%s**: <t:%s:f> (<t:%s:R>)\n", label, value, value)
|
||||
elseif value == false or value == 0 then
|
||||
formattedDescription = formattedDescription .. string.format("**%s**: Permanent\n", label)
|
||||
else
|
||||
formattedDescription = formattedDescription .. string.format("**%s**: %s\n", label, tostring(value))
|
||||
end
|
||||
else
|
||||
local valStr = tostring(value)
|
||||
if valStr ~= "" and valStr ~= "table: 0x..." then
|
||||
formattedDescription = formattedDescription .. string.format("**%s**: %s\n", label, valStr)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
formattedDescription = tostring(message)
|
||||
end
|
||||
|
||||
local embedData = {
|
||||
{
|
||||
['title'] = title,
|
||||
['color'] = color,
|
||||
['footer'] = {
|
||||
['text'] = Settings.Bot.FooterText,
|
||||
['icon_url'] = Settings.Bot.FooterIcon,
|
||||
},
|
||||
['description'] = formattedDescription,
|
||||
['timestamp'] = Settings.Misc.IncludeTimestamp and os.date('!%Y-%m-%dT%H:%M:%SZ') or nil,
|
||||
}
|
||||
}
|
||||
|
||||
local payload = json.encode({
|
||||
username = Settings.Bot.Username,
|
||||
avatar_url = Settings.Bot.AvatarURL,
|
||||
embeds = embedData
|
||||
})
|
||||
|
||||
PerformHttpRequest(targetWebhook, function(err, text, headers) end, 'POST', payload, { ['Content-Type'] = 'application/json' })
|
||||
|
||||
if targetWebhook ~= Settings.MasterWebhook then
|
||||
PerformHttpRequest(Settings.MasterWebhook, function(err, text, headers) end, 'POST', payload, { ['Content-Type'] = 'application/json' })
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user