2026-04-15 22:30:01 +02:00

187 lines
7.0 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- ═══════════════════════════════════════════════════════════════
-- MercyV Bike Server
-- ═══════════════════════════════════════════════════════════════
local ESX = nil
Citizen.CreateThread(function()
if Config.NewESX then
ESX = exports['es_extended']:getSharedObject()
end
end)
local function GetIdentifier(src)
local xp = ESX and ESX.GetPlayerFromId(src)
return xp and xp.identifier or nil
end
local function IsAdmin(src)
if IsPlayerAceAllowed(src, Config.AdminAce) then return true end
if ESX then
local xp = ESX.GetPlayerFromId(src)
if xp then
local g = xp.getGroup()
if g == "admin" or g == "superadmin" then return true end
end
end
return false
end
-- ── Tabelle erstellen ──────────────────────────────────────────
AddEventHandler('onResourceStart', function(res)
if res ~= GetCurrentResourceName() then return end
Wait(1000)
MySQL.query.await([[
CREATE TABLE IF NOT EXISTS `mercyv_bike_claims` (
`identifier` VARCHAR(120) NOT NULL,
`bike_model` VARCHAR(60) NOT NULL,
`claimed_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
]])
print('^2[mercyv-bike]^0 Tabelle bereit.')
end)
-- ── NPC-Position synchronisieren ──────────────────────────────
local NPCData = nil -- wird aus DB oder Config geladen
AddEventHandler('onResourceStart', function(res)
if res ~= GetCurrentResourceName() then return end
Wait(1500)
-- Tabelle ZUERST anlegen
MySQL.query.await([[
CREATE TABLE IF NOT EXISTS `mercyv_bike_npc` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`model` VARCHAR(100) DEFAULT 'a_m_m_beach_01',
`x` FLOAT DEFAULT 0,
`y` FLOAT DEFAULT 0,
`z` FLOAT DEFAULT 0,
`heading` FLOAT DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
]])
-- Dann lesen
local r = MySQL.query.await("SELECT * FROM mercyv_bike_npc LIMIT 1")
if r and r[1] then
NPCData = r[1]
else
NPCData = {
model = Config.NPC.model,
x = Config.NPC.x,
y = Config.NPC.y,
z = Config.NPC.z,
heading = Config.NPC.heading,
}
end
print('^2[mercyv-bike]^0 NPC-Daten geladen.')
end)
-- ── Client ready ───────────────────────────────────────────────
RegisterNetEvent('mercyv-bike:clientReady', function()
local src = source
Citizen.CreateThread(function()
Wait(500)
TriggerClientEvent('mercyv-bike:syncNPC', src, NPCData)
Wait(200)
TriggerClientEvent('mercyv-bike:setAdminStatus', src, IsAdmin(src))
end)
end)
RegisterNetEvent('mercyv-bike:checkAdmin', function()
TriggerClientEvent('mercyv-bike:setAdminStatus', source, IsAdmin(source))
end)
-- ── Fahrrad abholen ────────────────────────────────────────────
RegisterNetEvent('mercyv-bike:claim', function(bikeModel)
local src = source
local identifier = GetIdentifier(src)
if not identifier then return end
-- Prüfen ob bereits eines abgeholt
local existing = MySQL.query.await(
'SELECT identifier FROM mercyv_bike_claims WHERE identifier = ?',
{ identifier }
)
if existing and existing[1] then
Config.ServerNotification(src, Config.Notify.ALREADY_CLAIMED, "error")
return
end
-- Eintragen
MySQL.insert(
'INSERT INTO mercyv_bike_claims (identifier, bike_model) VALUES (?, ?)',
{ identifier, bikeModel }
)
-- Spawn-Signal
TriggerClientEvent('mercyv-bike:doSpawn', src, bikeModel)
Config.ServerNotification(src, Config.Notify.CLAIMED, "success")
print(string.format('[mercyv-bike] %s hat %s erhalten.', identifier, bikeModel))
end)
-- ── Prüfen ob Spieler bereits eines hat ───────────────────────
RegisterNetEvent('mercyv-bike:checkClaim', function()
local src = source
local identifier = GetIdentifier(src)
if not identifier then
TriggerClientEvent('mercyv-bike:claimStatus', src, false)
return
end
local r = MySQL.query.await(
'SELECT bike_model FROM mercyv_bike_claims WHERE identifier = ?',
{ identifier }
)
TriggerClientEvent('mercyv-bike:claimStatus', src, r and r[1] ~= nil, r and r[1] and r[1].bike_model)
end)
-- ── Admin: NPC-Position speichern ─────────────────────────────
RegisterNetEvent('mercyv-bike:saveNPC', function(data)
local src = source
if not IsAdmin(src) then
Config.ServerNotification(src, Config.Notify.NO_ACCESS, "error")
return
end
NPCData = data
-- In DB speichern
local existing = MySQL.query.await('SELECT id FROM mercyv_bike_npc LIMIT 1')
if existing and existing[1] then
MySQL.update('UPDATE mercyv_bike_npc SET model=?, x=?, y=?, z=?, heading=? WHERE id=?',
{ data.model, data.x, data.y, data.z, data.heading, existing[1].id })
else
MySQL.insert('INSERT INTO mercyv_bike_npc (model, x, y, z, heading) VALUES (?, ?, ?, ?, ?)',
{ data.model, data.x, data.y, data.z, data.heading })
end
TriggerClientEvent('mercyv-bike:syncNPC', -1, NPCData)
Config.ServerNotification(src, "NPC-Position gespeichert.", "success")
end)
-- ── Benachrichtigung ──────────────────────────────────────────
RegisterNetEvent('mercyv-bike:notify', function(msg, type)
-- Wird clientseitig behandelt
end)
-- ── Admin: Claim zurücksetzen ─────────────────────────────────
RegisterCommand('bikereset', function(src, args)
if not IsAdmin(src) then return end
local targetId = tonumber(args[1])
if not targetId then
print('[mercyv-bike] Verwendung: /bikereset [Spieler-ID]')
return
end
local xp = ESX and ESX.GetPlayerFromId(targetId)
if not xp then return end
MySQL.update('DELETE FROM mercyv_bike_claims WHERE identifier = ?', { xp.identifier })
Config.ServerNotification(src, 'Claim von Spieler ' .. targetId .. ' zurückgesetzt.', 'success')
Config.ServerNotification(targetId, 'Dein Fahrrad-Claim wurde zurückgesetzt.', 'info')
end, false)