This commit is contained in:
2026-07-07 21:08:52 +02:00
commit 4c20cfc716
2613 changed files with 318021 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
---@diagnostic disable: duplicate-set-field
-- =============================================
-- MARK: Variables
-- =============================================
Callbacks = {}
Callbacks.requests = {}
Callbacks.storage = {}
Callbacks.id = 0
-- =============================================
-- MARK: Internal Functions
-- =============================================
function Callbacks:Register(name, resource, cb)
self.storage[name] = {
resource = resource,
cb = cb
}
end
function Callbacks:Execute(cb, ...)
local success, errorString = pcall(cb, ...)
if not success then
print(("[^1ERROR^7] Failed to execute Callback with RequestId: ^5%s^7"):format(self.currentId))
print("^3Callback Error:^7 " .. tostring(errorString)) -- just log, don't throw
self.currentId = nil
return
end
self.currentId = nil
end
function Callbacks:Trigger(player, event, cb, invoker, ...)
self.requests[self.id] = {
await = type(cb) == "boolean",
cb = cb or promise:new()
}
local table = self.requests[self.id]
TriggerClientEvent("esx:triggerClientCallback", player, event, self.id, invoker, ...)
self.id += 1
return table.cb
end
function Callbacks:ServerRecieve(player, event, requestId, invoker, ...)
self.currentId = requestId
if not self.storage[event] then
return error(("Server Callback with requestId ^5%s^1 Was Called by ^5%s^1 but does not exist."):format(event, invoker))
end
local returnCb = function(...)
TriggerClientEvent("esx:serverCallback", player, requestId, invoker, ...)
end
local callback = self.storage[event].cb
self:Execute(callback, player, returnCb, ...)
end
function Callbacks:RecieveClient(requestId, invoker, ...)
self.currentId = requestId
if not self.requests[self.currentId] then
return error(("Client Callback with requestId ^5%s^1 Was Called by ^5%s^1 but does not exist."):format(self.currentId, invoker))
end
local callback = self.requests[self.currentId]
self.requests[requestId] = nil
if callback.await then
callback.cb:resolve({ ... })
else
self:Execute(callback.cb, ...)
end
end
-- =============================================
-- MARK: ESX Functions
-- =============================================
---@param player number playerId
---@param eventName string
---@param callback function
---@param ... any
function ESX.TriggerClientCallback(player, eventName, callback, ...)
local invokingResource = GetInvokingResource()
local invoker = (invokingResource and invokingResource ~= "Unknown") and invokingResource or "es_extended"
Callbacks:Trigger(player, eventName, callback, invoker, ...)
end
---@param player number playerId
---@param eventName string
---@param ... any
---@return ...
function ESX.AwaitClientCallback(player, eventName, ...)
local invokingResource = GetInvokingResource()
local invoker = (invokingResource and invokingResource ~= "Unknown") and invokingResource or "es_extended"
local p = Callbacks:Trigger(player, eventName, false, invoker, ...)
if not p then return end
SetTimeout(15000, function()
if p.state == "pending" then
p:reject("Server Callback Timed Out")
end
end)
Citizen.Await(p)
return table.unpack(p.value)
end
---@param eventName string
---@param callback function
---@return nil
function ESX.RegisterServerCallback(eventName, callback)
local invokingResource = GetInvokingResource()
local invoker = (invokingResource and invokingResource ~= "Unknown") and invokingResource or "es_extended"
Callbacks:Register(eventName, invoker, callback)
end
---@param eventName string
---@return boolean
function ESX.DoesServerCallbackExist(eventName)
return Callbacks.storage[eventName] ~= nil
end
-- =============================================
-- MARK: Events
-- =============================================
RegisterNetEvent("esx:clientCallback", function(requestId, invoker, ...)
Callbacks:RecieveClient(requestId, invoker, ...)
end)
RegisterNetEvent("esx:triggerServerCallback", function(eventName, requestId, invoker, ...)
local source = source
Callbacks:ServerRecieve(source, eventName, requestId, invoker, ...)
end)
AddEventHandler("onResourceStop", function(resource)
for k, v in pairs(Callbacks.storage) do
if v.resource == resource then
Callbacks.storage[k] = nil
end
end
end)

View File

@@ -0,0 +1,774 @@
ESX.RegisterCommand(
{ "setcoords", "tp" },
"admin",
function(xPlayer, args)
xPlayer.setCoords({ x = args.x, y = args.y, z = args.z })
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Set Coordinates /setcoords Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "X Coord", value = args.x, inline = true },
{ name = "Y Coord", value = args.y, inline = true },
{ name = "Z Coord", value = args.z, inline = true },
})
end
end,
false,
{
help = TranslateCap("command_setcoords"),
validate = true,
arguments = {
{ name = "x", help = TranslateCap("command_setcoords_x"), type = "coordinate" },
{ name = "y", help = TranslateCap("command_setcoords_y"), type = "coordinate" },
{ name = "z", help = TranslateCap("command_setcoords_z"), type = "coordinate" },
},
}
)
ESX.RegisterCommand(
"setjob",
"admin",
function(xPlayer, args, showError)
if not ESX.DoesJobExist(args.job, args.grade) then
return showError(TranslateCap("command_setjob_invalid"))
end
args.playerId.setJob(args.job, args.grade)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Set Job /setjob Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Job", value = args.job, inline = true },
{ name = "Grade", value = args.grade, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_setjob"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
{ name = "job", help = TranslateCap("command_setjob_job"), type = "string" },
{ name = "grade", help = TranslateCap("command_setjob_grade"), type = "number" },
},
}
)
local upgrades = Config.SpawnVehMaxUpgrades and {
plate = "ADMINCAR",
modEngine = 3,
modBrakes = 2,
modTransmission = 2,
modSuspension = 3,
modArmor = true,
windowTint = 1,
} or {}
ESX.RegisterCommand(
"car",
"admin",
function(xPlayer, args, showError)
if not xPlayer then
return showError("[^1ERROR^7] The xPlayer value is nil")
end
local playerPed = GetPlayerPed(xPlayer.source)
local playerCoords = GetEntityCoords(playerPed)
local playerHeading = GetEntityHeading(playerPed)
local playerVehicle = GetVehiclePedIsIn(playerPed, false)
if not args.car or type(args.car) ~= "string" then
args.car = "adder"
end
if playerVehicle then
DeleteEntity(playerVehicle)
end
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Spawn Car /car Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Vehicle", value = args.car, inline = true },
})
end
local xRoutingBucket = GetPlayerRoutingBucket(xPlayer.source)
ESX.OneSync.SpawnVehicle(args.car, playerCoords, playerHeading, upgrades, function(networkId)
if networkId then
local vehicle = NetworkGetEntityFromNetworkId(networkId)
if xRoutingBucket ~= 0 then
SetEntityRoutingBucket(vehicle, xRoutingBucket)
end
for _ = 1, 100 do
Wait(0)
SetPedIntoVehicle(playerPed, vehicle, -1)
if GetVehiclePedIsIn(playerPed, false) == vehicle then
break
end
end
if GetVehiclePedIsIn(playerPed, false) ~= vehicle then
showError("[^1ERROR^7] The player could not be seated in the vehicle")
end
end
end)
end,
false,
{
help = TranslateCap("command_car"),
validate = false,
arguments = {
{ name = "car", validate = false, help = TranslateCap("command_car_car"), type = "string" },
},
}
)
ESX.RegisterCommand(
{ "cardel", "dv" },
"admin",
function(xPlayer, args)
local ped = GetPlayerPed(xPlayer.source)
local pedVehicle = GetVehiclePedIsIn(ped, false)
if DoesEntityExist(pedVehicle) then
DeleteEntity(pedVehicle)
end
local coords = GetEntityCoords(ped)
local Vehicles = ESX.OneSync.GetVehiclesInArea(coords, tonumber(args.radius) or 5.0)
for i = 1, #Vehicles do
local Vehicle = NetworkGetEntityFromNetworkId(Vehicles[i])
if DoesEntityExist(Vehicle) then
DeleteEntity(Vehicle)
end
end
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Delete Vehicle /dv Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
})
end
end,
false,
{
help = TranslateCap("command_cardel"),
validate = false,
arguments = {
{ name = "radius", validate = false, help = TranslateCap("command_cardel_radius"), type = "number" },
},
}
)
ESX.RegisterCommand(
{ "fix", "repair" },
"admin",
function(xPlayer, args, showError)
local xTarget = args.playerId
local ped = GetPlayerPed(xTarget.source)
local pedVehicle = GetVehiclePedIsIn(ped, false)
if not pedVehicle or GetPedInVehicleSeat(pedVehicle, -1) ~= ped then
showError(TranslateCap("not_in_vehicle"))
return
end
xTarget.triggerEvent("esx:repairPedVehicle")
xPlayer.showNotification(TranslateCap("command_repair_success"), true, false, 140)
if xPlayer.source ~= xTarget.source then
xTarget.showNotification(TranslateCap("command_repair_success_target"), true, false, 140)
end
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Fix Vehicle /fix Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = xTarget.name, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_repair"),
validate = false,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
},
}
)
ESX.RegisterCommand(
"setaccountmoney",
"admin",
function(xPlayer, args, showError)
if not args.playerId.getAccount(args.account) then
return showError(TranslateCap("command_giveaccountmoney_invalid"))
end
args.playerId.setAccountMoney(args.account, args.amount, "Government Grant")
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Set Account Money /setaccountmoney Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Account", value = args.account, inline = true },
{ name = "Amount", value = args.amount, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_setaccountmoney"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
{ name = "account", help = TranslateCap("command_giveaccountmoney_account"), type = "string" },
{ name = "amount", help = TranslateCap("command_setaccountmoney_amount"), type = "number" },
},
}
)
ESX.RegisterCommand(
"giveaccountmoney",
"admin",
function(xPlayer, args, showError)
if not args.playerId.getAccount(args.account) then
return showError(TranslateCap("command_giveaccountmoney_invalid"))
end
args.playerId.addAccountMoney(args.account, args.amount, "Government Grant")
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Give Account Money /giveaccountmoney Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Account", value = args.account, inline = true },
{ name = "Amount", value = args.amount, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_giveaccountmoney"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
{ name = "account", help = TranslateCap("command_giveaccountmoney_account"), type = "string" },
{ name = "amount", help = TranslateCap("command_giveaccountmoney_amount"), type = "number" },
},
}
)
ESX.RegisterCommand(
"removeaccountmoney",
"admin",
function(xPlayer, args, showError)
if not args.playerId.getAccount(args.account) then
return showError(TranslateCap("command_removeaccountmoney_invalid"))
end
args.playerId.removeAccountMoney(args.account, args.amount, "Government Tax")
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Remove Account Money /removeaccountmoney Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Account", value = args.account, inline = true },
{ name = "Amount", value = args.amount, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_removeaccountmoney"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
{ name = "account", help = TranslateCap("command_removeaccountmoney_account"), type = "string" },
{ name = "amount", help = TranslateCap("command_removeaccountmoney_amount"), type = "number" },
},
}
)
if not Config.CustomInventory then
ESX.RegisterCommand(
"giveitem",
"admin",
function(xPlayer, args)
args.playerId.addInventoryItem(args.item, args.count)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Give Item /giveitem Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Item", value = args.item, inline = true },
{ name = "Quantity", value = args.count, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_giveitem"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
{ name = "item", help = TranslateCap("command_giveitem_item"), type = "item" },
{ name = "count", help = TranslateCap("command_giveitem_count"), type = "number", Validator = {
validate = function(x) return x > 0 end,
err = TranslateCap("commanderror_argumentmismatch_positive_number", "count")
}},
},
}
)
ESX.RegisterCommand(
"giveweapon",
"admin",
function(xPlayer, args, showError)
if args.playerId.hasWeapon(args.weapon) then
return showError(TranslateCap("command_giveweapon_hasalready"))
end
args.playerId.addWeapon(args.weapon, args.ammo)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Give Weapon /giveweapon Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Weapon", value = args.weapon, inline = true },
{ name = "Ammo", value = args.ammo, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_giveweapon"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
{ name = "weapon", help = TranslateCap("command_giveweapon_weapon"), type = "weapon" },
{ name = "ammo", help = TranslateCap("command_giveweapon_ammo"), type = "number" },
},
}
)
ESX.RegisterCommand(
"giveammo",
"admin",
function(xPlayer, args, showError)
if not args.playerId.hasWeapon(args.weapon) then
return showError(TranslateCap("command_giveammo_noweapon_found"))
end
args.playerId.addWeaponAmmo(args.weapon, args.ammo)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Give Ammunition /giveammo Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Weapon", value = args.weapon, inline = true },
{ name = "Ammo", value = args.ammo, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_giveweapon"),
validate = false,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
{ name = "weapon", help = TranslateCap("command_giveammo_weapon"), type = "weapon" },
{ name = "ammo", help = TranslateCap("command_giveammo_ammo"), type = "number" },
},
}
)
ESX.RegisterCommand(
"giveweaponcomponent",
"admin",
function(xPlayer, args, showError)
if args.playerId.hasWeapon(args.weaponName) then
local component = ESX.GetWeaponComponent(args.weaponName, args.componentName)
if component then
if args.playerId.hasWeaponComponent(args.weaponName, args.componentName) then
showError(TranslateCap("command_giveweaponcomponent_hasalready"))
else
args.playerId.addWeaponComponent(args.weaponName, args.componentName)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Give Weapon Component /giveweaponcomponent Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Weapon", value = args.weaponName, inline = true },
{ name = "Component", value = args.componentName, inline = true },
})
end
end
else
showError(TranslateCap("command_giveweaponcomponent_invalid"))
end
else
showError(TranslateCap("command_giveweaponcomponent_missingweapon"))
end
end,
true,
{
help = TranslateCap("command_giveweaponcomponent"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
{ name = "weaponName", help = TranslateCap("command_giveweapon_weapon"), type = "weapon" },
{ name = "componentName", help = TranslateCap("command_giveweaponcomponent_component"), type = "string" },
},
}
)
end
ESX.RegisterCommand({ "clear", "cls" }, "user", function(xPlayer)
xPlayer.triggerEvent("chat:clear")
end, false, { help = TranslateCap("command_clear") })
ESX.RegisterCommand({ "clearall", "clsall" }, "admin", function(xPlayer)
TriggerClientEvent("chat:clear", -1)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Clear Chat /clearall Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
})
end
end, true, { help = TranslateCap("command_clearall") })
ESX.RegisterCommand("refreshjobs", "admin", function()
ESX.RefreshJobs()
end, true, { help = TranslateCap("command_clearall") })
if not Config.CustomInventory then
ESX.RegisterCommand("refreshitems", "admin", function(xPlayer)
local itemCount = ESX.RefreshItems()
xPlayer.showNotification(Translate("command_refreshitems_success", itemCount), true, false, 140)
end, true, { help = TranslateCap("command_refreshitems") })
ESX.RegisterCommand(
"clearinventory",
"admin",
function(xPlayer, args)
for _, v in ipairs(args.playerId.inventory) do
if v.count > 0 then
args.playerId.setInventoryItem(v.name, 0)
end
end
TriggerEvent("esx:playerInventoryCleared", args.playerId)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Clear Inventory /clearinventory Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_clearinventory"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
},
}
)
ESX.RegisterCommand(
"clearloadout",
"admin",
function(xPlayer, args)
for i = #args.playerId.loadout, 1, -1 do
args.playerId.removeWeapon(args.playerId.loadout[i].name)
end
TriggerEvent("esx:playerLoadoutCleared", args.playerId)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "/clearloadout Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_clearloadout"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
},
}
)
end
ESX.RegisterCommand(
"setgroup",
"admin",
function(xPlayer, args)
if not args.playerId then
args.playerId = xPlayer.source
end
if args.group == "superadmin" then
args.group = "admin"
print("[^3WARNING^7] ^5Superadmin^7 detected, setting group to ^5admin^7")
end
args.playerId.setGroup(args.group)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "/setgroup Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Group", value = args.group, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_setgroup"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
{ name = "group", help = TranslateCap("command_setgroup_group"), type = "string" },
},
}
)
ESX.RegisterCommand(
"save",
"admin",
function(_, args)
Core.SavePlayer(args.playerId)
print(("[^2Info^0] Saved Player - ^5%s^0"):format(args.playerId.source))
end,
true,
{
help = TranslateCap("command_save"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
},
}
)
ESX.RegisterCommand("saveall", "admin", function()
Core.SavePlayers()
end, true, { help = TranslateCap("command_saveall") })
ESX.RegisterCommand("group", { "user", "admin" }, function(xPlayer, _, _)
print(("%s, you are currently: ^5%s^0"):format(xPlayer.getName(), xPlayer.getGroup()))
end, true)
ESX.RegisterCommand("job", { "user", "admin" }, function(xPlayer, _, _)
local job = xPlayer.getJob()
print(("%s, your job is: ^5%s^0 - ^5%s^0 - ^5%s^0"):format(xPlayer.getName(), job.name, job.grade_label, job.onDuty and "On Duty" or "Off Duty"))
end, false)
ESX.RegisterCommand("info", { "user", "admin" }, function(xPlayer)
local job = xPlayer.getJob().name
print(("^2ID: ^5%s^0 | ^2Name: ^5%s^0 | ^2Group: ^5%s^0 | ^2Job: ^5%s^0"):format(xPlayer.source, xPlayer.getName(), xPlayer.getGroup(), job))
end, false)
ESX.RegisterCommand("playtime", { "user", "admin" }, function(xPlayer)
local playtime = xPlayer.getPlayTime()
local days = math.floor(playtime / 86400)
local hours = math.floor((playtime % 86400) / 3600)
local minutes = math.floor((playtime % 3600) / 60)
print(("Playtime: ^5%s^0 Days | ^5%s^0 Hours | ^5%s^0 Minutes"):format(days, hours, minutes))
end, false)
ESX.RegisterCommand("coords", "admin", function(xPlayer)
local ped = GetPlayerPed(xPlayer.source)
local coords = GetEntityCoords(ped, false)
local heading = GetEntityHeading(ped)
print(("Coords - Vector3: ^5%s^0"):format(vector3(coords.x, coords.y, coords.z)))
print(("Coords - Vector4: ^5%s^0"):format(vector4(coords.x, coords.y, coords.z, heading)))
end, false)
ESX.RegisterCommand("tpm", "admin", function(xPlayer)
xPlayer.triggerEvent("esx:tpm")
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Admin Teleport /tpm Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
})
end
end, false)
ESX.RegisterCommand(
"goto",
"admin",
function(xPlayer, args)
local targetCoords = args.playerId.getCoords()
local srcDim = GetPlayerRoutingBucket(xPlayer.source)
local targetDim = GetPlayerRoutingBucket(args.playerId.source)
if srcDim ~= targetDim then
SetPlayerRoutingBucket(xPlayer.source, targetDim)
end
xPlayer.setCoords(targetCoords)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Admin Teleport /goto Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Target Coords", value = targetCoords, inline = true },
})
end
end,
false,
{
help = TranslateCap("command_goto"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
},
}
)
ESX.RegisterCommand(
"bring",
"admin",
function(xPlayer, args)
local targetCoords = args.playerId.getCoords()
local playerCoords = xPlayer.getCoords()
local targetDim = GetPlayerRoutingBucket(args.playerId.source)
local srcDim = GetPlayerRoutingBucket(xPlayer.source)
if targetDim ~= srcDim then
SetPlayerRoutingBucket(args.playerId.source, srcDim)
end
args.playerId.setCoords(playerCoords)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Admin Teleport /bring Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Target Coords", value = targetCoords, inline = true },
})
end
end,
false,
{
help = TranslateCap("command_bring"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
},
}
)
ESX.RegisterCommand(
"kill",
"admin",
function(xPlayer, args)
args.playerId.triggerEvent("esx:killPlayer")
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Kill Command /kill Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_kill"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
},
}
)
ESX.RegisterCommand(
"freeze",
"admin",
function(xPlayer, args)
args.playerId.triggerEvent("esx:freezePlayer", "freeze")
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Admin Freeze /freeze Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_freeze"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
},
}
)
ESX.RegisterCommand(
"unfreeze",
"admin",
function(xPlayer, args)
args.playerId.triggerEvent("esx:freezePlayer", "unfreeze")
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Admin UnFreeze /unfreeze Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_unfreeze"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
},
}
)
ESX.RegisterCommand("noclip", "admin", function(xPlayer)
xPlayer.triggerEvent("esx:noclip")
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Admin NoClip /noclip Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
})
end
end, false)
ESX.RegisterCommand("players", "admin", function()
local xPlayers = ESX.GetExtendedPlayers() -- Returns all xPlayers
print(("^5%s^2 online player(s)^0"):format(#xPlayers))
for i = 1, #xPlayers do
local xPlayer = xPlayers[i]
print(("^1[^2ID: ^5%s^0 | ^2Name : ^5%s^0 | ^2Group : ^5%s^0 | ^2Identifier : ^5%s^1]^0\n"):format(xPlayer.source, xPlayer.getName(), xPlayer.getGroup(), xPlayer.identifier))
end
end, true)
ESX.RegisterCommand(
{"setdim", "setbucket"},
"admin",
function(xPlayer, args)
SetPlayerRoutingBucket(args.playerId.source, args.dimension)
if Config.AdminLogging then
ESX.DiscordLogFields("UserActions", "Admin Set Dim /setdim Triggered!", "pink", {
{ name = "Player", value = xPlayer and xPlayer.name or "Server Console", inline = true },
{ name = "ID", value = xPlayer and xPlayer.source or "Unknown ID", inline = true },
{ name = "Target", value = args.playerId.name, inline = true },
{ name = "Dimension", value = args.dimension, inline = true },
})
end
end,
true,
{
help = TranslateCap("command_setdim"),
validate = true,
arguments = {
{ name = "playerId", help = TranslateCap("commandgeneric_playerid"), type = "player" },
{ name = "dimension", help = TranslateCap("commandgeneric_dimension"), type = "number" },
},
}
)

View File

@@ -0,0 +1,101 @@
local NOTIFY_TYPES = {
INFO = "^5[%s]^7-^6[INFO]^7 %s",
SUCCESS = "^5[%s]^7-^2[SUCCESS]^7 %s",
ERROR = "^5[%s]^7-^1[ERROR]^7 %s"
}
local function doesJobAndGradesExist(name, grades)
if not ESX.Jobs[name] then
return false
end
for _, grade in ipairs(grades) do
if not ESX.DoesJobExist(name, grade.grade) then
return false
end
end
return true
end
local function generateNewJobTable(name, label, grades, jobType)
local job = { name = name, label = label, type = jobType, grades = {} }
for _, v in pairs(grades) do
job.grades[tostring(v.grade)] = { job_name = name, grade = v.grade, name = v.name, label = v.label, salary = v.salary, skin_male = v.skin_male or '{}', skin_female = v.skin_female or '{}' }
end
return job
end
local function notify(notifyType,resourceName,message,...)
local formattedMessage = string.format(message, ...)
if not NOTIFY_TYPES[notifyType] then
return print(NOTIFY_TYPES.INFO:format(resourceName,formattedMessage))
end
return print(NOTIFY_TYPES[notifyType]:format(resourceName,formattedMessage))
end
--- Create Job at Runtime
--- @param name string
--- @param label string
--- @param grades table
--- @param jobType string
function ESX.CreateJob(name, label, grades, jobType)
local currentResourceName = GetInvokingResource()
local success = false
if not name or name == '' then
notify("ERROR",currentResourceName, 'Missing argument `name`')
return success
end
if not label or label == '' then
notify("ERROR",currentResourceName, 'Missing argument `label`')
return success
end
if not grades or not next(grades) then
notify("ERROR",currentResourceName, 'Missing argument `grades`')
return success
end
if type(jobType) ~= "string" then
jobType = "civ"
end
local currentJobExist = doesJobAndGradesExist(name, grades)
if currentJobExist then
notify("ERROR",currentResourceName, 'Job or grades already exists: `%s`', name)
return success
end
local queries = {
{ query = 'INSERT INTO `jobs` (`name`, `label`, `type`) VALUES (?, ?, ?)', values = { name, label, jobType } }
}
for _, grade in pairs(grades) do
queries[#queries + 1] = {
query = 'INSERT INTO job_grades (job_name, grade, name, label, salary, skin_male, skin_female) VALUES (?, ?, ?, ?, ?, ?, ?)',
values = { name, grade.grade, grade.name, grade.label, grade.salary, grade.skin_male and json.encode(grade.skin_male) or '{}', grade.skin_female and json.encode(grade.skin_female) or '{}' }
}
end
success = exports.oxmysql:transaction_async(queries)
if not success then
notify("ERROR", currentResourceName, 'Failed to insert one or more grades for job: `%s`', name)
return success
end
ESX.Jobs[name] = generateNewJobTable(name, label, grades, jobType)
notify("SUCCESS", currentResourceName, 'Job created successfully: `%s`', name)
TriggerEvent('esx:jobCreated', name, ESX.Jobs[name])
return success
end

View File

@@ -0,0 +1,52 @@
local npwd = GetResourceState("npwd"):find("start") and exports.npwd or nil
AddEventHandler("onServerResourceStart", function(resource)
if resource ~= "npwd" then
return
end
npwd = GetResourceState("npwd"):find("start") and exports.npwd or nil
if not npwd then
return
end
for _, xPlayer in pairs(ESX.Players) do
npwd:newPlayer({
source = xPlayer.source,
identifier = xPlayer.identifier,
firstname = xPlayer.get("firstName"),
lastname = xPlayer.get("lastName"),
})
end
end)
AddEventHandler("onServerResourceStop", function(resource)
if resource == "npwd" then
npwd = nil
end
end)
AddEventHandler("esx:playerLoaded", function(playerId, xPlayer)
if not npwd then
return
end
if not xPlayer then
xPlayer = ESX.GetPlayerFromId(playerId)
end
npwd:newPlayer({
source = playerId,
identifier = xPlayer.identifier,
firstname = xPlayer.get("firstName"),
lastname = xPlayer.get("lastName"),
})
end)
AddEventHandler("esx:playerLogout", function(playerId)
if not npwd then
return
end
npwd:unloadPlayer(playerId)
end)

View File

@@ -0,0 +1,387 @@
ESX.OneSync = {}
---@param source number|vector3
---@param closest boolean
---@param distance? number
---@param ignore? table
---@param routingBucket? number
local function getNearbyPlayers(source, closest, distance, ignore, routingBucket)
local result = {}
local count = 0
local playerPed
local playerCoords
ignore = ignore or {}
if not distance then
distance = 100
end
if type(source) == "number" then
playerPed = GetPlayerPed(source)
if not source then
error("Received invalid first argument (source); should be playerId")
end
playerCoords = GetEntityCoords(playerPed)
if not playerCoords then
error("Received nil value (playerCoords); perhaps source is nil at first place?")
end
end
if type(source) == "vector3" then
playerCoords = source
if not playerCoords then
error("Received nil value (playerCoords); perhaps source is nil at first place?")
end
end
for _, xPlayer in pairs(ESX.Players) do
if not ignore[xPlayer.source] and (not routingBucket or GetPlayerRoutingBucket(xPlayer.source) == routingBucket) then
local entity = GetPlayerPed(xPlayer.source)
local coords = GetEntityCoords(entity)
if not closest then
local dist = #(playerCoords - coords)
if dist <= distance then
count = count + 1
result[count] = { id = xPlayer.source, ped = NetworkGetNetworkIdFromEntity(entity), coords = coords, dist = dist }
end
else
if xPlayer.source ~= source then
local dist = #(playerCoords - coords)
if dist <= (result.dist or distance) then
result = { id = xPlayer.source, ped = NetworkGetNetworkIdFromEntity(entity), coords = coords, dist = dist }
end
end
end
end
end
return result
end
---@param source vector3|number playerId or vector3 coordinates
---@param maxDistance number
---@param ignore? table playerIds to ignore, where the key is playerId and value is true
---@param routingBucket? number
function ESX.OneSync.GetPlayersInArea(source, maxDistance, ignore, routingBucket)
return getNearbyPlayers(source, false, maxDistance, ignore, routingBucket)
end
---@param source vector3|number playerId or vector3 coordinates
---@param maxDistance number
---@param ignore? table playerIds to ignore, where the key is playerId and value is true
---@param routingBucket? number
function ESX.OneSync.GetClosestPlayer(source, maxDistance, ignore, routingBucket)
return getNearbyPlayers(source, true, maxDistance, ignore, routingBucket)
end
---@param vehicleModel number|string
---@param coords vector3|table
---@param heading number
---@param vehicleProperties table
---@param cb? fun(netId: number)
---@param vehicleType string?
---@return number? netId
function ESX.OneSync.SpawnVehicle(vehicleModel, coords, heading, vehicleProperties, cb, vehicleType)
if cb and not ESX.IsFunctionReference(cb) then
error("Invalid callback function")
end
vehicleModel = joaat(vehicleModel)
local promise = not cb and promise.new()
local function resolve(result)
if promise then
promise:resolve(result)
elseif cb then
cb(result)
end
return result
end
local function reject(err)
if promise then
promise:reject(err)
end
error(err)
end
CreateThread(function()
if not vehicleType then
local xPlayer = ESX.GetExtendedPlayers()[1]
if xPlayer then
vehicleType = ESX.GetVehicleType(vehicleModel, xPlayer.source)
end
end
if not vehicleType then
return reject("No players found nearby to check vehicle type! Alternatively, you can specify the vehicle type manually.")
end
local createdVehicle = CreateVehicleServerSetter(vehicleModel, vehicleType, coords.x, coords.y, coords.z, heading)
local tries = 0
local hasNetOwner = next(ESX.OneSync.GetClosestPlayer(coords, 300, nil, 0) or {}) ~= nil
while not createdVehicle or createdVehicle == 0
or (hasNetOwner and NetworkGetEntityOwner(createdVehicle) == -1)
or (not hasNetOwner and not DoesEntityExist(createdVehicle)) do
Wait(200)
tries = tries + 1
if tries > 40 then
return reject(("Could not spawn vehicle - ^5%s^7!"):format(vehicleModel))
end
end
-- luacheck: ignore
SetEntityOrphanMode(createdVehicle, 2)
local networkId = NetworkGetNetworkIdFromEntity(createdVehicle)
Entity(createdVehicle).state:set("VehicleProperties", vehicleProperties, true)
resolve(networkId)
end)
if promise then
return Citizen.Await(promise)
end
end
---@param model number|string
---@param coords vector3|table
---@param heading number
---@param cb? fun(netId: number)
---@return number? netId
function ESX.OneSync.SpawnObject(model, coords, heading, cb)
if type(model) == "string" then
model = joaat(model)
end
local promise = not cb and promise.new()
local objectCoords = type(coords) == "vector3" and coords or vector3(coords.x, coords.y, coords.z)
local function resolve(result)
if promise then
promise:resolve(result)
elseif cb then
cb(result)
end
end
local function reject(err)
if promise then
promise:reject(err)
end
error(err)
end
CreateThread(function()
local entity = CreateObject(model, objectCoords.x, objectCoords.y, objectCoords.z, true, true, false)
local tries = 0
while not DoesEntityExist(entity) do
Wait(200)
tries = tries + 1
if tries > 40 then
return reject(("Could not spawn object - ^5%s^7!"):format(entity))
end
end
local networkId = NetworkGetNetworkIdFromEntity(entity)
SetEntityHeading(entity, heading)
resolve(networkId)
end)
if promise then
return Citizen.Await(promise)
end
end
---@param model number|string
---@param coords vector3|table
---@param heading number
---@param cb? fun(netId: number)
---@return number? netId
function ESX.OneSync.SpawnPed(model, coords, heading, cb)
if type(model) == "string" then
model = joaat(model)
end
local promise = not cb and promise.new()
local function resolve(result)
if promise then
promise:resolve(result)
elseif cb then
cb(result)
end
end
local function reject(err)
if promise then
promise:reject(err)
end
error(err)
end
CreateThread(function()
local entity = CreatePed(0, model, coords.x, coords.y, coords.z, heading, true, true)
local tries = 0
while not DoesEntityExist(entity) do
Wait(200)
tries = tries + 1
if tries > 40 then
return reject(("Could not spawn ped - ^5%s^7!"):format(model))
end
end
local networkId = NetworkGetNetworkIdFromEntity(entity)
resolve(networkId)
end)
if promise then
return Citizen.Await(promise)
end
end
---@param model number|string
---@param vehicle number entityId
---@param seat number
---@param cb? fun(netId: number)
---@return number? netId
function ESX.OneSync.SpawnPedInVehicle(model, vehicle, seat, cb)
if type(model) == "string" then
model = joaat(model)
end
local promise = not cb and promise.new()
local function resolve(result)
if promise then
promise:resolve(result)
elseif cb then
cb(result)
end
end
local function reject(err)
if promise then
promise:reject(err)
end
error(err)
end
CreateThread(function()
local entity = CreatePedInsideVehicle(vehicle, 1, model, seat, true, true)
local tries = 0
while not DoesEntityExist(entity) do
Wait(200)
tries = tries + 1
if tries > 40 then
reject(("Could not spawn ped - ^5%s^7!"):format(model))
end
end
local networkId = NetworkGetNetworkIdFromEntity(entity)
resolve(networkId)
end)
if promise then
return Citizen.Await(promise)
end
end
local function getNearbyEntities(entities, coords, modelFilter, maxDistance, isPed)
local nearbyEntities = {}
coords = type(coords) == "number" and GetEntityCoords(GetPlayerPed(coords)) or vector3(coords.x, coords.y, coords.z)
for _, entity in pairs(entities) do
if not isPed or (isPed and not IsPedAPlayer(entity)) then
if not modelFilter or modelFilter[GetEntityModel(entity)] then
local entityCoords = GetEntityCoords(entity)
if not maxDistance or #(coords - entityCoords) <= maxDistance then
nearbyEntities[#nearbyEntities + 1] = NetworkGetNetworkIdFromEntity(entity)
end
end
end
end
return nearbyEntities
end
---@param coords vector3
---@param maxDistance number
---@param modelFilter table models to ignore, where the key is the model hash and the value is true
---@return table
function ESX.OneSync.GetPedsInArea(coords, maxDistance, modelFilter)
return getNearbyEntities(GetAllPeds(), coords, modelFilter, maxDistance, true)
end
---@param coords vector3
---@param maxDistance number
---@param modelFilter table models to ignore, where the key is the model hash and the value is true
---@return table
function ESX.OneSync.GetObjectsInArea(coords, maxDistance, modelFilter)
return getNearbyEntities(GetAllObjects(), coords, modelFilter, maxDistance)
end
---@param coords vector3
---@param maxDistance number
---@param modelFilter table | nil models to ignore, where the key is the model hash and the value is true
---@return table
function ESX.OneSync.GetVehiclesInArea(coords, maxDistance, modelFilter)
return getNearbyEntities(GetAllVehicles(), coords, modelFilter, maxDistance)
end
local function getClosestEntity(entities, coords, modelFilter, isPed)
local distance, closestEntity, closestCoords = 100, 0, vector3(0, 0, 0)
coords = type(coords) == "number" and GetEntityCoords(GetPlayerPed(coords)) or vector3(coords.x, coords.y, coords.z)
for _, entity in pairs(entities) do
if not isPed or (isPed and not IsPedAPlayer(entity)) then
if not modelFilter or modelFilter[GetEntityModel(entity)] then
local entityCoords = GetEntityCoords(entity)
local dist = #(coords - entityCoords)
if dist < distance then
closestEntity, distance, closestCoords = entity, dist, entityCoords
end
end
end
end
return NetworkGetNetworkIdFromEntity(closestEntity), distance, closestCoords
end
---@param coords vector3
---@param modelFilter table models to ignore, where the key is the model hash and the value is true
---@return number entityId, number distance, vector3 coords
function ESX.OneSync.GetClosestPed(coords, modelFilter)
return getClosestEntity(GetAllPeds(), coords, modelFilter, true)
end
---@param coords vector3
---@param modelFilter table models to ignore, where the key is the model hash and the value is true
---@return number entityId, number distance, vector3 coords
function ESX.OneSync.GetClosestObject(coords, modelFilter)
return getClosestEntity(GetAllObjects(), coords, modelFilter)
end
---@param coords vector3
---@param modelFilter table models to ignore, where the key is the model hash and the value is true
---@return number entityId, number distance, vector3 coords
function ESX.OneSync.GetClosestVehicle(coords, modelFilter)
return getClosestEntity(GetAllVehicles(), coords, modelFilter)
end

View File

@@ -0,0 +1,71 @@
function StartPayCheck()
CreateThread(function()
while true do
Wait(Config.PaycheckInterval)
for player, xPlayer in pairs(ESX.Players) do
local jobLabel = xPlayer.job.label
local job = xPlayer.job.grade_name
local onDuty = xPlayer.job.onDuty
local salary = (job == "unemployed" or onDuty) and xPlayer.job.grade_salary or ESX.Math.Round(xPlayer.job.grade_salary * Config.OffDutyPaycheckMultiplier)
if xPlayer.paycheckEnabled then
if salary > 0 then
if job == "unemployed" then -- unemployed
xPlayer.addAccountMoney("bank", salary, "Welfare Check")
TriggerClientEvent("esx:showAdvancedNotification", player, TranslateCap("bank"), TranslateCap("received_paycheck"), TranslateCap("received_help", salary), "CHAR_BANK_MAZE", 9)
if Config.LogPaycheck then
ESX.DiscordLogFields("Paycheck", "Paycheck - Unemployment Benefits", "green", {
{ name = "Player", value = xPlayer.name, inline = true },
{ name = "ID", value = xPlayer.source, inline = true },
{ name = "Amount", value = salary, inline = true },
})
end
elseif Config.EnableSocietyPayouts then -- possibly a society
TriggerEvent("esx_society:getSociety", xPlayer.job.name, function(society)
if society ~= nil then -- verified society
TriggerEvent("esx_addonaccount:getSharedAccount", society.account, function(account)
if account.money >= salary then -- does the society money to pay its employees?
xPlayer.addAccountMoney("bank", salary, "Paycheck")
account.removeMoney(salary)
if Config.LogPaycheck then
ESX.DiscordLogFields("Paycheck", "Paycheck - " .. jobLabel, "green", {
{ name = "Player", value = xPlayer.name, inline = true },
{ name = "ID", value = xPlayer.source, inline = true },
{ name = "Amount", value = salary, inline = true },
})
end
TriggerClientEvent("esx:showAdvancedNotification", player, TranslateCap("bank"), TranslateCap("received_paycheck"), TranslateCap("received_salary", salary), "CHAR_BANK_MAZE", 9)
else
TriggerClientEvent("esx:showAdvancedNotification", player, TranslateCap("bank"), "", TranslateCap("company_nomoney"), "CHAR_BANK_MAZE", 1)
end
end)
else -- not a society
xPlayer.addAccountMoney("bank", salary, "Paycheck")
if Config.LogPaycheck then
ESX.DiscordLogFields("Paycheck", "Paycheck - " .. jobLabel, "green", {
{ name = "Player", value = xPlayer.name, inline = true },
{ name = "ID", value = xPlayer.source, inline = true },
{ name = "Amount", value = salary, inline = true },
})
end
TriggerClientEvent("esx:showAdvancedNotification", player, TranslateCap("bank"), TranslateCap("received_paycheck"), TranslateCap("received_salary", salary), "CHAR_BANK_MAZE", 9)
end
end)
else -- generic job
xPlayer.addAccountMoney("bank", salary, "Paycheck")
if Config.LogPaycheck then
ESX.DiscordLogFields("Paycheck", "Paycheck - Generic", "green", {
{ name = "Player", value = xPlayer.name, inline = true },
{ name = "ID", value = xPlayer.source, inline = true },
{ name = "Amount", value = salary, inline = true },
})
end
TriggerClientEvent("esx:showAdvancedNotification", player, TranslateCap("bank"), TranslateCap("received_paycheck"), TranslateCap("received_salary", salary), "CHAR_BANK_MAZE", 9)
end
end
end
end
end
end)
end