Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bade2ad95 |
34
README.md
34
README.md
@@ -1,8 +1,32 @@
|
|||||||
# txAdminLogs
|
# 🛠️ txAdminLogs
|
||||||
Simple Standalone txAdmin Logs made for FiveM
|
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