2026-04-14 15:54:53 +02:00

316 lines
10 KiB
Lua

ESX = exports['es_extended']:getSharedObject()
local isNuiOpen = false
local currentProp = nil
local currentCardData = nil
local currentCardType = nil
-- =====================
-- ANIMATION
-- =====================
function PlayIdAnimation()
local playerPed = PlayerPedId()
local anim = Config.Animation
RequestAnimDict(anim.dict)
while not HasAnimDictLoaded(anim.dict) do Citizen.Wait(10) end
TaskPlayAnim(playerPed, anim.dict, anim.name, 8.0, -8.0, anim.duration, anim.flag, 0, false, false, false)
-- Prop attachen
if anim.prop and anim.prop.enabled and anim.prop.model then
local propHash = GetHashKey(anim.prop.model)
RequestModel(propHash)
while not HasModelLoaded(propHash) do Citizen.Wait(10) end
local prop = CreateObject(propHash, 0.0, 0.0, 0.0, true, true, false)
AttachEntityToEntity(prop, playerPed, GetPedBoneIndex(playerPed, anim.prop.bone),
anim.prop.offset.x, anim.prop.offset.y, anim.prop.offset.z,
anim.prop.rotation.x, anim.prop.rotation.y, anim.prop.rotation.z,
true, true, false, true, 1, true)
SetModelAsNoLongerNeeded(propHash)
currentProp = prop
end
end
function StopIdAnimation()
local playerPed = PlayerPedId()
ClearPedTasks(playerPed)
if currentProp and DoesEntityExist(currentProp) then
DeleteEntity(currentProp)
currentProp = nil
end
end
-- =====================
-- MUGSHOT (wird einmal beim Spawnen generiert)
-- =====================
local cachedMugShot = nil
local mugShotReady = false
-- Mugshot im Hintergrund generieren (beim Spawn)
local function GenerateMugShotAsync()
if not Config.MugShot or not Config.MugShot.enabled then return end
Citizen.CreateThread(function()
-- Kurz warten bis Ped vollstaendig geladen
Citizen.Wait(5000)
local ok, mugshot = pcall(function()
return exports["MugShotBase64"]:GetMugShotBase64(PlayerPedId(), Config.MugShot.transparent)
end)
if ok and mugshot and mugshot ~= '' then
cachedMugShot = mugshot
mugShotReady = true
print('[mercyv-id] Mugshot erfolgreich generiert und gecacht')
else
print('[mercyv-id] Mugshot konnte nicht generiert werden')
end
end)
end
-- Beim Spieler-Spawn Mugshot generieren
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function()
GenerateMugShotAsync()
end)
-- Falls Spieler schon geladen ist (z.B. Resource-Restart)
Citizen.CreateThread(function()
while not ESX.IsPlayerLoaded() do Citizen.Wait(500) end
if not mugShotReady then
GenerateMugShotAsync()
end
end)
-- =====================
-- NUI MANAGEMENT
-- =====================
function OpenIdCard(cardType, data, isViewing)
if isNuiOpen then return end
isNuiOpen = true
currentCardData = data
currentCardType = cardType
SetNuiFocus(true, true)
SendNUIMessage({
type = 'open',
cardType = cardType,
playerData = data,
licenseDisplay = Config.LicenseDisplay,
theme = Config.Theme,
cardTitle = Config.CardTitle,
isViewing = isViewing or false,
})
end
function CloseMenu()
if not isNuiOpen then return end
isNuiOpen = false
currentCardData = nil
currentCardType = nil
SetNuiFocus(false, false)
SendNUIMessage({ type = 'close' })
StopIdAnimation()
end
-- =====================
-- ITEM USE (vom Server getriggert)
-- =====================
RegisterNetEvent('mercyv-id:useItem')
AddEventHandler('mercyv-id:useItem', function(itemName, cardType)
if isNuiOpen then return end
-- Animation starten
PlayIdAnimation()
-- Daten vom Server holen
ESX.TriggerServerCallback('mercyv-id:getPlayerData', function(data)
if not data then
StopIdAnimation()
TriggerEvent(Config.Notification.event, Config.Notification.title, 'Daten konnten nicht geladen werden', 'error', Config.Notification.duration)
return
end
-- Gecachtes Mugshot anwenden
if (not data.photo or data.photo == '') and cachedMugShot then
data.photo = cachedMugShot
end
OpenIdCard(cardType, data, false)
end)
end)
-- =====================
-- AUSWEIS VON ANDEREM SPIELER EMPFANGEN
-- =====================
RegisterNetEvent('mercyv-id:receiveCard')
AddEventHandler('mercyv-id:receiveCard', function(cardData, cardType, senderName)
if isNuiOpen then return end
TriggerEvent(Config.Notification.event, Config.Notification.title, senderName .. ' zeigt dir einen Ausweis', 'info', Config.Notification.duration)
OpenIdCard(cardType, cardData, true)
end)
-- =====================
-- NUI CALLBACKS
-- =====================
RegisterNUICallback('close', function(_, cb)
CloseMenu()
cb('ok')
end)
RegisterNUICallback('showToNearby', function(_, cb)
if not currentCardData or not currentCardType then
cb('ok')
return
end
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local nearbyIds = {}
-- Alle Spieler in der Naehe finden
local players = GetActivePlayers()
for _, playerId in ipairs(players) do
if playerId ~= PlayerId() then
local targetPed = GetPlayerPed(playerId)
if DoesEntityExist(targetPed) then
local targetCoords = GetEntityCoords(targetPed)
local dist = #(playerCoords - targetCoords)
if dist <= Config.ShowDistance then
nearbyIds[#nearbyIds + 1] = GetPlayerServerId(playerId)
end
end
end
end
if #nearbyIds == 0 then
TriggerEvent(Config.Notification.event, Config.Notification.title, 'Keine Spieler in der Naehe', 'info', Config.Notification.duration)
else
TriggerServerEvent('mercyv-id:showToNearby', currentCardData, currentCardType, nearbyIds)
TriggerEvent(Config.Notification.event, Config.Notification.title, 'Ausweis wird ' .. #nearbyIds .. ' Spieler(n) gezeigt', 'success', Config.Notification.duration)
end
cb('ok')
end)
-- =====================
-- RADIAL MENU EVENTS (rlo_radialmenu)
-- =====================
-- Hilfsfunktion: Nahe Spieler finden und Karte senden
local function ShowCardToNearby(playerData, cardType, cardLabel)
local playerPed = PlayerPedId()
local playerCoords = GetEntityCoords(playerPed)
local nearbyIds = {}
local players = GetActivePlayers()
for _, playerId in ipairs(players) do
if playerId ~= PlayerId() then
local targetPed = GetPlayerPed(playerId)
if DoesEntityExist(targetPed) then
local targetCoords = GetEntityCoords(targetPed)
local dist = #(playerCoords - targetCoords)
if dist <= Config.ShowDistance then
nearbyIds[#nearbyIds + 1] = GetPlayerServerId(playerId)
end
end
end
end
if #nearbyIds > 0 then
TriggerServerEvent('mercyv-id:showToNearby', playerData, cardType, nearbyIds)
TriggerEvent(Config.Notification.event, Config.Notification.title, cardLabel .. ' wird ' .. #nearbyIds .. ' Spieler(n) gezeigt', 'success', Config.Notification.duration)
else
TriggerEvent(Config.Notification.event, Config.Notification.title, 'Keine Spieler in der Nähe', 'info', Config.Notification.duration)
end
end
-- Hilfsfunktion: Karte oeffnen mit Lizenz-Check
local function OpenCardWithCheck(cardType, showToOthers)
if isNuiOpen then return end
ESX.TriggerServerCallback('mercyv-id:hasLicense', function(hasLicense)
if not hasLicense then
local names = {
license = 'Führerschein',
weapon = 'Waffenschein',
}
TriggerEvent(Config.Notification.event, Config.Notification.title, 'Du besitzt keinen ' .. (names[cardType] or 'Ausweis'), 'error', Config.Notification.duration)
return
end
PlayIdAnimation()
ESX.TriggerServerCallback('mercyv-id:getPlayerData', function(playerData)
if not playerData then
StopIdAnimation()
TriggerEvent(Config.Notification.event, Config.Notification.title, 'Daten konnten nicht geladen werden', 'error', Config.Notification.duration)
return
end
-- Gecachtes Mugshot anwenden
if (not playerData.photo or playerData.photo == '') and cachedMugShot then
playerData.photo = cachedMugShot
end
OpenIdCard(cardType, playerData, false)
if showToOthers then
local labels = { id = 'Ausweis', license = 'Führerschein', weapon = 'Waffenschein' }
ShowCardToNearby(playerData, cardType, labels[cardType] or 'Ausweis')
end
end)
end, cardType)
end
-- Ausweis ansehen
RegisterNetEvent('mercyv-id:radial:viewId')
AddEventHandler('mercyv-id:radial:viewId', function(data)
OpenCardWithCheck('id', false)
end)
-- Ausweis zeigen
RegisterNetEvent('mercyv-id:radial:showId')
AddEventHandler('mercyv-id:radial:showId', function(data)
OpenCardWithCheck('id', true)
end)
-- Führerschein ansehen
RegisterNetEvent('mercyv-id:radial:viewLicense')
AddEventHandler('mercyv-id:radial:viewLicense', function(data)
OpenCardWithCheck('license', false)
end)
-- Führerschein zeigen
RegisterNetEvent('mercyv-id:radial:showLicense')
AddEventHandler('mercyv-id:radial:showLicense', function(data)
OpenCardWithCheck('license', true)
end)
-- Waffenschein ansehen
RegisterNetEvent('mercyv-id:radial:viewWeapon')
AddEventHandler('mercyv-id:radial:viewWeapon', function(data)
OpenCardWithCheck('weapon', false)
end)
-- Waffenschein zeigen
RegisterNetEvent('mercyv-id:radial:showWeapon')
AddEventHandler('mercyv-id:radial:showWeapon', function(data)
OpenCardWithCheck('weapon', true)
end)
-- =====================
-- CLEANUP
-- =====================
AddEventHandler('onResourceStop', function(resourceName)
if resourceName ~= GetCurrentResourceName() then return end
if isNuiOpen then
SetNuiFocus(false, false)
end
if currentProp and DoesEntityExist(currentProp) then
DeleteEntity(currentProp)
end
ClearPedTasks(PlayerPedId())
end)