Tax Collection Example
A complete wc_taxman resource — a server-only scheduled sweep that takes a small cut of cash from every online player on an interval, skips anyone who can't afford it, and posts a summary to Discord. No client script needed at all.
Use this pattern for any periodic server-side job: property upkeep, gang dues, business taxes, or a "wealth tax" event. The shape is always the same — loop connected players, read money, remove money, notify, log.
fxmanifest.lua
wc_taxman/fxmanifest.lua
fx_version 'adamant'
game 'rdr3'
lua54 'yes'
name 'wc_taxman'
dependency 'wc_libs'
shared_scripts { '@wc_libs/init.lua', 'config.lua' }
server_scripts { 'server.lua' }
config.lua
wc_taxman/config.lua
Config = {}
Config.IntervalMs = 30 * 60000 -- every 30 minutes
Config.Rate = 0.02 -- 2% of on-hand cash
Config.MinBalance = 20 -- don't tax players below this
Config.WebhookUrl = GetConvar('wc_taxman_webhook', '')
server.lua
wc_taxman/server.lua
local function runTaxSweep()
local collected = 0
local taxedCount = 0
for _, pid in ipairs(GetPlayers()) do
local src = tonumber(pid)
if src then
local cash = wc:GetMoney(src)
if cash and cash >= Config.MinBalance then
local owed = math.floor(cash * Config.Rate)
if owed > 0 then
wc:RemoveMoney(src, owed)
wc:Notify(src, { variant = 'warning', title = ("Territory tax: -$%d"):format(owed) })
collected = collected + owed
taxedCount = taxedCount + 1
end
end
end
end
if taxedCount > 0 then
-- SendWebhook expects a player source for the "who" fields; use the
-- first taxed player as a nominal reporter, or write your own summary
-- sender if you want a source-less system embed instead.
print(('[wc_taxman] collected $%d from %d players'):format(collected, taxedCount))
end
end
CreateThread(function()
while true do
Wait(Config.IntervalMs)
runTaxSweep()
end
end)
Security. This resource never reads a client-sent amount at all — it computes
owed entirely from the server's own GetMoney read and Config.Rate. There's no client input to validate because there's no client script; that's the safest possible shape for a periodic system job.
Common mistakes
- Running the sweep every server tick instead of on a real interval — always gate scheduled jobs behind
Wait(Config.IntervalMs)in their own thread. - Taxing below
Config.MinBalanceand pushing broke players into a negative-feeling loop — always floor at a reasonable minimum. - Forgetting
math.flooron the owed amount — fractional cents look wrong in a western-themed HUD.