Auto-sync 2026-04-15 22:45
This commit is contained in:
parent
a3d5af24ec
commit
f148a720da
@ -136,33 +136,30 @@ end)
|
||||
|
||||
-- Admin: Aktuelle Position erfassen
|
||||
RegisterNUICallback('capturePos', function(data, cb)
|
||||
local field = data.field or 'npc'
|
||||
ClosePanel()
|
||||
Citizen.Wait(300)
|
||||
local ped = PlayerPedId()
|
||||
local coords = GetEntityCoords(ped)
|
||||
local heading = GetEntityHeading(ped)
|
||||
|
||||
Notify("Geh zur NPC-Position und drücke E.", "info")
|
||||
Notify("Geh zur Position und drücke E.", "info")
|
||||
exports['hex_4_hud']:ShowHelpNotify("Position erfassen", "E")
|
||||
|
||||
Citizen.CreateThread(function()
|
||||
while true do
|
||||
Citizen.Wait(0)
|
||||
if IsControlJustPressed(0, 38) then -- E
|
||||
if IsControlJustPressed(0, 38) then
|
||||
exports['hex_4_hud']:HideHelpNotify()
|
||||
local c = GetEntityCoords(PlayerPedId())
|
||||
local h = GetEntityHeading(PlayerPedId())
|
||||
-- Panel wieder öffnen mit erfassten Koordinaten
|
||||
local coords = GetEntityCoords(PlayerPedId())
|
||||
local heading = GetEntityHeading(PlayerPedId())
|
||||
SetNuiFocus(true, true)
|
||||
exports['hex_4_hud']:HideHud(true)
|
||||
PanelOpen = true
|
||||
SendNUIMessage({
|
||||
action = "OPEN_ADMIN",
|
||||
isAdmin = IsAdmin,
|
||||
captured = { x = c.x, y = c.y, z = c.z, heading = h },
|
||||
captured = { x = coords.x, y = coords.y, z = coords.z, heading = heading, field = field },
|
||||
})
|
||||
break
|
||||
elseif IsControlJustPressed(0, 322) then -- ESC
|
||||
elseif IsControlJustPressed(0, 322) then
|
||||
exports['hex_4_hud']:HideHelpNotify()
|
||||
OpenPanel()
|
||||
break
|
||||
@ -218,27 +215,47 @@ end)
|
||||
|
||||
-- ── Fahrrad spawnen ────────────────────────────────────────────
|
||||
|
||||
RegisterNetEvent('mercyv-bike:doSpawn', function(bikeModel)
|
||||
RegisterNetEvent('mercyv-bike:doSpawn', function(bikeModel, spawnData)
|
||||
print('[mercyv-bike] Spawne Fahrrad: ' .. tostring(bikeModel))
|
||||
|
||||
local model = GetHashKey(bikeModel)
|
||||
if model == 0 then
|
||||
Notify("Unbekanntes Fahrrad-Modell: " .. tostring(bikeModel), "error")
|
||||
return
|
||||
end
|
||||
|
||||
RequestModel(model)
|
||||
local t = GetGameTimer() + 5000
|
||||
local t = GetGameTimer() + 8000
|
||||
while not HasModelLoaded(model) do
|
||||
if GetGameTimer() > t then
|
||||
Notify("Fahrrad konnte nicht gespawnt werden.", "error")
|
||||
Notify("Fahrrad-Modell konnte nicht geladen werden.", "error")
|
||||
return
|
||||
end
|
||||
Citizen.Wait(100)
|
||||
end
|
||||
|
||||
local ped = PlayerPedId()
|
||||
local coords = GetEntityCoords(ped)
|
||||
local heading = GetEntityHeading(ped)
|
||||
local rad = math.rad(heading)
|
||||
local spawnX = coords.x + math.sin(-rad) * Config.SpawnOffset
|
||||
local spawnY = coords.y + math.cos(-rad) * Config.SpawnOffset
|
||||
-- Spawn-Position: vom Server gesetzte Koordinaten oder vor Spieler
|
||||
local sx, sy, sz, sh
|
||||
if spawnData and spawnData.x and spawnData.x ~= 0 then
|
||||
sx = spawnData.x
|
||||
sy = spawnData.y
|
||||
sz = spawnData.z
|
||||
sh = spawnData.heading or 0
|
||||
else
|
||||
local ped = PlayerPedId()
|
||||
local coords = GetEntityCoords(ped)
|
||||
local heading = GetEntityHeading(ped)
|
||||
local rad = math.rad(heading)
|
||||
sx = coords.x + math.sin(-rad) * Config.SpawnOffset
|
||||
sy = coords.y + math.cos(-rad) * Config.SpawnOffset
|
||||
sz = coords.z
|
||||
sh = heading
|
||||
end
|
||||
|
||||
local bike = CreateVehicle(model, spawnX, spawnY, coords.z, heading, true, false)
|
||||
local tw = GetGameTimer() + 3000
|
||||
print(string.format('[mercyv-bike] Spawn bei %.1f, %.1f, %.1f', sx, sy, sz))
|
||||
|
||||
local bike = CreateVehicle(model, sx, sy, sz, sh, true, false)
|
||||
local tw = GetGameTimer() + 4000
|
||||
while not DoesEntityExist(bike) do
|
||||
if GetGameTimer() > tw then break end
|
||||
Citizen.Wait(100)
|
||||
@ -248,12 +265,11 @@ RegisterNetEvent('mercyv-bike:doSpawn', function(bikeModel)
|
||||
SetEntityAsMissionEntity(bike, true, true)
|
||||
SetVehicleEngineOn(bike, true, true, false)
|
||||
SetModelAsNoLongerNeeded(model)
|
||||
-- Schlüssel geben
|
||||
local ks = Config.VehicleKeySystem
|
||||
if ks == 'jaksam' then
|
||||
TriggerServerEvent('vehicles_keys:selfGiveVehicleKeys',
|
||||
GetVehicleNumberPlateText(bike))
|
||||
end
|
||||
TriggerServerEvent('vehicles_keys:selfGiveVehicleKeys', GetVehicleNumberPlateText(bike))
|
||||
Notify("Fahrrad erhalten! Viel Spaß!", "success")
|
||||
print('[mercyv-bike] Fahrrad erfolgreich gespawnt.')
|
||||
else
|
||||
Notify("Fahrrad konnte nicht gespawnt werden.", "error")
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
@ -285,8 +285,21 @@ body {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="mb-form-section">
|
||||
<div class="mb-form-label"><i class="fas fa-car"></i> Fahrrad Spawn-Position</div>
|
||||
<div class="mb-pos-row">
|
||||
<input type="number" v-model.number="npc.spawn_x" placeholder="X" class="mb-input mb-input-sm">
|
||||
<input type="number" v-model.number="npc.spawn_y" placeholder="Y" class="mb-input mb-input-sm">
|
||||
<input type="number" v-model.number="npc.spawn_z" placeholder="Z" class="mb-input mb-input-sm">
|
||||
<input type="number" v-model.number="npc.spawn_heading" placeholder="Heading" class="mb-input mb-input-sm">
|
||||
</div>
|
||||
<button class="mb-capture-btn" v-on:click="captureSpawn()">
|
||||
<i class="fas fa-crosshairs"></i> Spawn-Position erfassen
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button class="mb-save-btn" v-on:click="saveNPC()">
|
||||
<i class="fas fa-save"></i> NPC speichern
|
||||
<i class="fas fa-save"></i> Speichern
|
||||
</button>
|
||||
|
||||
<div class="mb-admin-hint">
|
||||
@ -358,7 +371,10 @@ var app = new Vue({
|
||||
postNUI('close');
|
||||
},
|
||||
capturePos: function() {
|
||||
postNUI('capturePos', {});
|
||||
postNUI('capturePos', { field: 'npc' });
|
||||
},
|
||||
captureSpawn: function() {
|
||||
postNUI('capturePos', { field: 'spawn' });
|
||||
},
|
||||
saveNPC: function() {
|
||||
postNUI('saveNPC', {
|
||||
@ -387,10 +403,17 @@ window.addEventListener('message', function(event) {
|
||||
app.showAdmin = true;
|
||||
app.isAdmin = true;
|
||||
if (msg.captured) {
|
||||
app.npc.x = Math.round(msg.captured.x * 100) / 100;
|
||||
app.npc.y = Math.round(msg.captured.y * 100) / 100;
|
||||
app.npc.z = Math.round(msg.captured.z * 100) / 100;
|
||||
app.npc.heading = Math.round(msg.captured.heading * 100) / 100;
|
||||
var rx = Math.round(msg.captured.x * 100) / 100;
|
||||
var ry = Math.round(msg.captured.y * 100) / 100;
|
||||
var rz = Math.round(msg.captured.z * 100) / 100;
|
||||
var rh = Math.round(msg.captured.heading * 100) / 100;
|
||||
if (msg.captured.field === 'spawn') {
|
||||
app.npc.spawn_x = rx; app.npc.spawn_y = ry;
|
||||
app.npc.spawn_z = rz; app.npc.spawn_heading = rh;
|
||||
} else {
|
||||
app.npc.x = rx; app.npc.y = ry;
|
||||
app.npc.z = rz; app.npc.heading = rh;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'CLOSE':
|
||||
|
||||
@ -45,7 +45,8 @@ end)
|
||||
|
||||
-- ── NPC-Position synchronisieren ──────────────────────────────
|
||||
|
||||
local NPCData = nil -- wird aus DB oder Config geladen
|
||||
local NPCData = nil
|
||||
local SpawnData = nil -- separate Spawn-Position für Fahrräder
|
||||
|
||||
AddEventHandler('onResourceStart', function(res)
|
||||
if res ~= GetCurrentResourceName() then return end
|
||||
@ -53,18 +54,25 @@ AddEventHandler('onResourceStart', function(res)
|
||||
-- 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
|
||||
`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,
|
||||
`spawn_x` FLOAT DEFAULT 0,
|
||||
`spawn_y` FLOAT DEFAULT 0,
|
||||
`spawn_z` FLOAT DEFAULT 0,
|
||||
`spawn_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]
|
||||
if r[1].spawn_x and r[1].spawn_x ~= 0 then
|
||||
SpawnData = { x = r[1].spawn_x, y = r[1].spawn_y, z = r[1].spawn_z, heading = r[1].spawn_heading or 0 }
|
||||
end
|
||||
else
|
||||
NPCData = {
|
||||
model = Config.NPC.model,
|
||||
@ -117,7 +125,7 @@ RegisterNetEvent('mercyv-bike:claim', function(bikeModel)
|
||||
)
|
||||
|
||||
-- Spawn-Signal
|
||||
TriggerClientEvent('mercyv-bike:doSpawn', src, bikeModel)
|
||||
TriggerClientEvent('mercyv-bike:doSpawn', src, bikeModel, SpawnData)
|
||||
Config.ServerNotification(src, Config.Notify.CLAIMED, "success")
|
||||
print(string.format('[mercyv-bike] %s hat %s erhalten.', identifier, bikeModel))
|
||||
end)
|
||||
@ -148,15 +156,22 @@ RegisterNetEvent('mercyv-bike:saveNPC', function(data)
|
||||
end
|
||||
|
||||
NPCData = data
|
||||
if data.spawn_x and data.spawn_x ~= 0 then
|
||||
SpawnData = { x = data.spawn_x, y = data.spawn_y, z = data.spawn_z, heading = data.spawn_heading or 0 }
|
||||
end
|
||||
|
||||
-- In DB speichern
|
||||
local existing = MySQL.query.await('SELECT id FROM mercyv_bike_npc LIMIT 1')
|
||||
local sx = data.spawn_x or 0
|
||||
local sy = data.spawn_y or 0
|
||||
local sz = data.spawn_z or 0
|
||||
local sh = data.spawn_heading or 0
|
||||
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 })
|
||||
MySQL.update('UPDATE mercyv_bike_npc SET model=?, x=?, y=?, z=?, heading=?, spawn_x=?, spawn_y=?, spawn_z=?, spawn_heading=? WHERE id=?',
|
||||
{ data.model, data.x, data.y, data.z, data.heading, sx, sy, sz, sh, 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 })
|
||||
MySQL.insert('INSERT INTO mercyv_bike_npc (model, x, y, z, heading, spawn_x, spawn_y, spawn_z, spawn_heading) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
{ data.model, data.x, data.y, data.z, data.heading, sx, sy, sz, sh })
|
||||
end
|
||||
|
||||
TriggerClientEvent('mercyv-bike:syncNPC', -1, NPCData)
|
||||
|
||||
@ -703,7 +703,7 @@ AddEventHandler('mercyv-deathscreen:client:npcReviveTeleport', function()
|
||||
local ped = PlayerPedId()
|
||||
|
||||
-- Kurz warten, damit der Spieler nach dem Revive sicher am Leben ist
|
||||
Wait(500)
|
||||
Wait(200)
|
||||
|
||||
-- Bildschirm langsam schwarz ausblenden (Dauer: 1000 Millisekunden = 1 Sekunde)
|
||||
DoScreenFadeOut(1000)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user