163 lines
6.8 KiB
Lua
163 lines
6.8 KiB
Lua
-- Weapon constant names (as shown on FiveM docs)
|
|
WEAPON_HASHES = {
|
|
[`WEAPON_SNOWLAUNCHER`] = "WEAPON_SNOWLAUNCHER",
|
|
[`WEAPON_COMPACTLAUNCHER`] = "WEAPON_COMPACTLAUNCHER",
|
|
[`WEAPON_MINIGUN`] = "WEAPON_MINIGUN",
|
|
[`WEAPON_GRENADELAUNCHER_SMOKE`] = "WEAPON_GRENADELAUNCHER_SMOKE",
|
|
[`WEAPON_HOMINGLAUNCHER`] = "WEAPON_HOMINGLAUNCHER",
|
|
[`WEAPON_RAILGUN`] = "WEAPON_RAILGUN",
|
|
[`WEAPON_FIREWORK`] = "WEAPON_FIREWORK",
|
|
[`WEAPON_GRENADELAUNCHER`] = "WEAPON_GRENADELAUNCHER",
|
|
[`WEAPON_RPG`] = "WEAPON_RPG",
|
|
[`WEAPON_RAYMINIGUN`] = "WEAPON_RAYMINIGUN",
|
|
[`WEAPON_EMPLAUNCHER`] = "WEAPON_EMPLAUNCHER",
|
|
[`WEAPON_RAILGUNXM3`] = "WEAPON_RAILGUNXM3",
|
|
|
|
-- explosives / throwable
|
|
[`WEAPON_GRENADE`] = "WEAPON_GRENADE",
|
|
[`WEAPON_BZGAS`] = "WEAPON_BZGAS",
|
|
[`WEAPON_PROXMINE`] = "WEAPON_PROXMINE",
|
|
[`WEAPON_PIPEBOMB`] = "WEAPON_PIPEBOMB",
|
|
[`WEAPON_ACIDPACKAGE`] = "WEAPON_ACIDPACKAGE",
|
|
[`WEAPON_SMOKEGRENADE`] = "WEAPON_SMOKEGRENADE",
|
|
|
|
-- pistols (examples from page)
|
|
[`WEAPON_VINTAGEPISTOL`] = "WEAPON_VINTAGEPISTOL",
|
|
[`WEAPON_PISTOL`] = "WEAPON_PISTOL",
|
|
[`WEAPON_PISTOLXM3`] = "WEAPON_PISTOLXM3",
|
|
|
|
-- shotguns (examples)
|
|
[`WEAPON_COMBATSHOTGUN`] = "WEAPON_COMBATSHOTGUN",
|
|
[`WEAPON_AUTOSHOTGUN`] = "WEAPON_AUTOSHOTGUN",
|
|
|
|
-- melee / blunt
|
|
[`WEAPON_STONE_HATCHET`] = "WEAPON_STONE_HATCHET",
|
|
[`WEAPON_GOLFCLUB`] = "WEAPON_GOLFCLUB",
|
|
[`WEAPON_HAMMER`] = "WEAPON_HAMMER",
|
|
[`WEAPON_CANDYCANE`] = "WEAPON_CANDYCANE",
|
|
[`WEAPON_NIGHTSTICK`] = "WEAPON_NIGHTSTICK",
|
|
[`WEAPON_CROWBAR`] = "WEAPON_CROWBAR",
|
|
[`WEAPON_FLASHLIGHT`] = "WEAPON_FLASHLIGHT",
|
|
[`WEAPON_DAGGER`] = "WEAPON_DAGGER",
|
|
[`WEAPON_POOLCUE`] = "WEAPON_POOLCUE",
|
|
[`WEAPON_BAT`] = "WEAPON_BAT",
|
|
[`WEAPON_BATTLEAXE`] = "WEAPON_BATTLEAXE",
|
|
[`WEAPON_STUNROD`] = "WEAPON_STUNROD",
|
|
[`WEAPON_MACHETE`] = "WEAPON_MACHETE",
|
|
[`WEAPON_SWITCHBLADE`] = "WEAPON_SWITCHBLADE",
|
|
[`WEAPON_HATCHET`] = "WEAPON_HATCHET",
|
|
[`WEAPON_BOTTLE`] = "WEAPON_BOTTLE",
|
|
|
|
-- other devices
|
|
[`WEAPON_HACKINGDEVICE`] = "WEAPON_HACKINGDEVICE",
|
|
[`WEAPON_STUNGUN`] = "WEAPON_STUNGUN",
|
|
[`WEAPON_STUNGUN_MP`] = "WEAPON_STUNGUN_MP",
|
|
}
|
|
|
|
--- Add missing weapon hashes from ox_inventory
|
|
if GetResourceState('ox_inventory') == 'started' then
|
|
local list = require "@ox_inventory.data.weapons"
|
|
|
|
for k in pairs(list.Weapons) do
|
|
WEAPON_HASHES[joaat(k)] = k
|
|
end
|
|
end
|
|
|
|
-- headshot ratio
|
|
local totalKills = 0
|
|
local totalKillsByHeadshot = 0
|
|
|
|
--- Batch the logs to send them in a single request and prevent spam
|
|
---@class BatchLogs
|
|
---@field deaths string[]
|
|
---@field actions string[]
|
|
local batchLogs = {
|
|
deaths = {},
|
|
actions = {},
|
|
}
|
|
|
|
---TODO: Check other causes of death, like vehicle collisions, falls, etc.
|
|
AddEventHandler('gameEventTriggered', function(event, args)
|
|
if event == "CEventNetworkEntityDamage" then
|
|
local playerPed = PlayerPedId()
|
|
local attacker = args[2]
|
|
-- Check if the attacker is the client
|
|
local isAttacker = attacker ~= playerPed
|
|
local victim = args[1]
|
|
local wasFatal = args[6] == 1
|
|
local isMelee = args[12] == 1
|
|
local _found, bone = GetPedLastDamageBone(victim)
|
|
|
|
|
|
local hasWeapon, clientWeaponHash = GetCurrentPedWeapon(playerPed, true)
|
|
local clientWeaponModel = hasWeapon and (WEAPON_HASHES[clientWeaponHash] or clientWeaponHash) or "unarmed"
|
|
|
|
if isAttacker and wasFatal and not isMelee then
|
|
totalKills = totalKills + 1
|
|
if bone == 31086 then
|
|
totalKillsByHeadshot = totalKillsByHeadshot + 1
|
|
end
|
|
Luxu.triggerServerEvent("hs:update", totalKillsByHeadshot / totalKills)
|
|
end
|
|
--- If the victim is the client, log the death
|
|
if victim == playerPed then
|
|
local isAttackerAPlayer = NetworkGetPlayerIndexFromPed(attacker)
|
|
|
|
|
|
local selfHarm = attacker == -1 -- Fell or Drowning
|
|
|
|
--- Check if the player died from falling or drowning
|
|
if selfHarm and wasFatal then
|
|
local playerName = GetPlayerName(Luxu.cache.playerId)
|
|
local logMessage = ("%s died from falling or drowning"):format(playerName)
|
|
batchLogs.deaths[#batchLogs.deaths + 1] = logMessage
|
|
return
|
|
end
|
|
|
|
--- Killed by another player
|
|
if wasFatal and isAttackerAPlayer ~= -1 then
|
|
local attackerServerId = GetPlayerServerId(isAttackerAPlayer)
|
|
local attackerName = GetPlayerName(isAttackerAPlayer)
|
|
local attackerHasWeapon, attackerWeaponHash = GetCurrentPedWeapon(attacker, true)
|
|
local attackerWeaponModel = attackerHasWeapon and GetWeapontypeModel(attackerWeaponHash) or "unarmed"
|
|
local victimName = GetPlayerName(Luxu.cache.playerId)
|
|
local logMessage = ("%s was killed by [%d]%s | Weapon %s:%s"):format(
|
|
victimName,
|
|
attackerServerId,
|
|
attackerName,
|
|
attackerWeaponModel,
|
|
attackerWeaponHash)
|
|
batchLogs.deaths[#batchLogs.deaths + 1] = logMessage
|
|
end
|
|
end
|
|
|
|
|
|
--- Check if any action was done by this client as the attacker
|
|
if attacker ~= PlayerPedId() then return end
|
|
|
|
local victimEntityType = IsEntityAPed(victim) and "ped" or IsEntityAVehicle(victim) and "vehicle" or
|
|
IsEntityAnObject(victim) and "object" or "unknown"
|
|
|
|
--- Log vehicle destruction
|
|
if victimEntityType == "vehicle" and wasFatal then
|
|
local playerName = GetPlayerName(Luxu.cache.playerId)
|
|
local plate = GetVehicleNumberPlateText(victim)
|
|
local logMessage = ("%s destroyed a vehicle with plate: [%s] using %s:%s"):format(playerName, plate,
|
|
clientWeaponModel, clientWeaponHash)
|
|
batchLogs.actions[#batchLogs.actions + 1] = logMessage
|
|
return
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- Periodically send batched logs to the server using a latent trigger
|
|
Citizen.CreateThread(function()
|
|
while true do
|
|
if #batchLogs.deaths > 0 then
|
|
Luxu.triggerServerEventLatent("log:playerDeathBatch", 10000, batchLogs.deaths)
|
|
batchLogs.deaths = {} -- Clear the batch after sending
|
|
end
|
|
Citizen.Wait(10e3) -- Wait for 10 seconds before checking again
|
|
end
|
|
end)
|