2025-06-12 15:31:23 +02:00
|
|
|
local positions = {}
|
|
|
|
local presets = {}
|
|
|
|
local positionsFile = 'positions.json'
|
|
|
|
local presetsFile = 'presets.json'
|
2025-06-12 22:21:39 +02:00
|
|
|
local attachedWeapons = {}
|
2025-06-12 15:31:23 +02:00
|
|
|
|
|
|
|
-- Load saved positions from JSON file
|
|
|
|
local function LoadPositions()
|
|
|
|
local file = LoadResourceFile(GetCurrentResourceName(), 'json/' .. positionsFile)
|
|
|
|
if file then
|
|
|
|
positions = json.decode(file) or {}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Load saved presets from JSON file
|
|
|
|
local function LoadPresets()
|
|
|
|
local file = LoadResourceFile(GetCurrentResourceName(), 'json/' .. presetsFile)
|
|
|
|
if file then
|
|
|
|
presets = json.decode(file) or {}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Save positions to JSON file
|
|
|
|
local function SavePositions()
|
|
|
|
SaveResourceFile(GetCurrentResourceName(), 'json/' .. positionsFile, json.encode(positions), -1)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Save presets to JSON file
|
|
|
|
local function SavePresets()
|
|
|
|
SaveResourceFile(GetCurrentResourceName(), 'json/' .. presetsFile, json.encode(presets), -1)
|
|
|
|
end
|
|
|
|
|
2025-06-12 22:21:39 +02:00
|
|
|
-- Überprüfe ob ein Spieler eine Waffe besitzt
|
|
|
|
local function DoesPlayerHaveWeapon(source, weaponName)
|
|
|
|
if Config.Framework.name == "qbcore" then
|
|
|
|
local Player = QBCore.Functions.GetPlayer(source)
|
|
|
|
if Player then
|
|
|
|
for _, item in pairs(Player.PlayerData.items) do
|
|
|
|
if item.name == weaponName then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elseif Config.Framework.name == "esx" then
|
|
|
|
local xPlayer = ESX.GetPlayerFromId(source)
|
|
|
|
if xPlayer then
|
|
|
|
local hasWeapon = xPlayer.hasWeapon(weaponName)
|
|
|
|
return hasWeapon
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2025-06-12 15:31:23 +02:00
|
|
|
-- Load data when resource starts
|
|
|
|
CreateThread(function()
|
|
|
|
LoadPositions()
|
|
|
|
LoadPresets()
|
|
|
|
end)
|
|
|
|
|
2025-06-12 22:21:39 +02:00
|
|
|
-- Weapon sync with verification
|
2025-06-12 00:25:14 +02:00
|
|
|
RegisterNetEvent('force-sling:server:syncWeapons')
|
|
|
|
AddEventHandler('force-sling:server:syncWeapons', function(weaponData, action)
|
|
|
|
local src = source
|
2025-06-12 22:21:39 +02:00
|
|
|
|
2025-06-12 00:25:14 +02:00
|
|
|
if action == 'attach' then
|
2025-06-12 22:21:39 +02:00
|
|
|
-- Überprüfe ob der Spieler die Waffe besitzt
|
|
|
|
if not DoesPlayerHaveWeapon(src, weaponData.weaponName) then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2025-06-12 00:25:14 +02:00
|
|
|
attachedWeapons[src] = attachedWeapons[src] or {}
|
|
|
|
attachedWeapons[src][weaponData.weaponName] = weaponData
|
|
|
|
elseif action == 'detach' then
|
|
|
|
if attachedWeapons[src] then
|
|
|
|
attachedWeapons[src][weaponData.weaponName] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
TriggerClientEvent('force-sling:client:syncWeapons', -1, src, weaponData, action)
|
|
|
|
end)
|
|
|
|
|
2025-06-12 15:31:23 +02:00
|
|
|
-- Callbacks
|
|
|
|
lib.callback.register('force-sling:callback:getCachedPositions', function(source)
|
2025-06-12 22:21:39 +02:00
|
|
|
local src = source
|
|
|
|
local playerPositions = {}
|
|
|
|
|
|
|
|
-- Filtere nur die Positionen für Waffen, die der Spieler besitzt
|
|
|
|
for weaponName, posData in pairs(positions) do
|
|
|
|
if DoesPlayerHaveWeapon(src, weaponName) then
|
|
|
|
playerPositions[weaponName] = posData
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return playerPositions
|
2025-06-12 15:31:23 +02:00
|
|
|
end)
|
|
|
|
|
|
|
|
lib.callback.register('force-sling:callback:getCachedPresets', function(source)
|
|
|
|
return presets
|
|
|
|
end)
|
|
|
|
|
|
|
|
lib.callback.register('force-sling:callback:isPlayerAdmin', function(source)
|
|
|
|
local src = source
|
2025-06-12 22:21:39 +02:00
|
|
|
if Config.Framework.name == "qbcore" then
|
|
|
|
local Player = QBCore.Functions.GetPlayer(src)
|
|
|
|
return Player and Player.PlayerData.admin or false
|
|
|
|
elseif Config.Framework.name == "esx" then
|
|
|
|
local xPlayer = ESX.GetPlayerFromId(src)
|
|
|
|
return xPlayer and xPlayer.getGroup() == 'admin' or false
|
|
|
|
end
|
|
|
|
return false
|
2025-06-12 15:31:23 +02:00
|
|
|
end)
|
|
|
|
|
|
|
|
lib.callback.register('force-sling:callback:resetWeaponPositions', function(source, weapon)
|
|
|
|
local src = source
|
|
|
|
if weapon then
|
2025-06-12 22:21:39 +02:00
|
|
|
if DoesPlayerHaveWeapon(src, weapon) then
|
|
|
|
positions[weapon] = nil
|
|
|
|
SavePositions()
|
|
|
|
end
|
2025-06-12 15:31:23 +02:00
|
|
|
else
|
2025-06-12 22:21:39 +02:00
|
|
|
-- Beim kompletten Reset nur die Positionen der Waffen löschen, die der Spieler besitzt
|
|
|
|
local newPositions = {}
|
|
|
|
for weaponName, posData in pairs(positions) do
|
|
|
|
if not DoesPlayerHaveWeapon(src, weaponName) then
|
|
|
|
newPositions[weaponName] = posData
|
|
|
|
end
|
|
|
|
end
|
|
|
|
positions = newPositions
|
|
|
|
SavePositions()
|
2025-06-12 15:31:23 +02:00
|
|
|
end
|
|
|
|
return positions
|
|
|
|
end)
|
|
|
|
|
|
|
|
RegisterNetEvent('force-sling:server:saveWeaponPosition')
|
|
|
|
AddEventHandler('force-sling:server:saveWeaponPosition', function(position, rotation, weapon, weaponName, boneId, isPreset)
|
|
|
|
local src = source
|
|
|
|
local data = {
|
|
|
|
coords = position,
|
|
|
|
rot = rotation,
|
|
|
|
boneId = boneId
|
|
|
|
}
|
|
|
|
|
|
|
|
if isPreset then
|
2025-06-12 22:21:39 +02:00
|
|
|
-- Nur Admins können Presets speichern
|
|
|
|
local isAdmin = lib.callback.await('force-sling:callback:isPlayerAdmin', src)
|
|
|
|
if isAdmin then
|
|
|
|
presets[weaponName] = data
|
|
|
|
SavePresets()
|
|
|
|
end
|
2025-06-12 15:31:23 +02:00
|
|
|
else
|
2025-06-12 22:21:39 +02:00
|
|
|
-- Überprüfe ob der Spieler die Waffe besitzt
|
|
|
|
if DoesPlayerHaveWeapon(src, weaponName) then
|
|
|
|
positions[weaponName] = data
|
|
|
|
SavePositions()
|
|
|
|
end
|
2025-06-12 15:31:23 +02:00
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
|
|
|
-- Cleanup on player drop
|
2025-06-12 00:25:14 +02:00
|
|
|
AddEventHandler('playerDropped', function()
|
|
|
|
local src = source
|
|
|
|
if attachedWeapons[src] then
|
|
|
|
TriggerClientEvent('force-sling:client:cleanupPlayerWeapons', -1, src)
|
|
|
|
attachedWeapons[src] = nil
|
|
|
|
end
|
2025-06-07 08:51:21 +02:00
|
|
|
end)
|
2025-06-12 22:21:39 +02:00
|
|
|
|
|
|
|
-- Periodische Überprüfung der angehängten Waffen
|
|
|
|
CreateThread(function()
|
|
|
|
while true do
|
|
|
|
for playerId, weapons in pairs(attachedWeapons) do
|
|
|
|
for weaponName, _ in pairs(weapons) do
|
|
|
|
if not DoesPlayerHaveWeapon(playerId, weaponName) then
|
|
|
|
-- Spieler hat die Waffe nicht mehr, entferne sie
|
|
|
|
TriggerClientEvent('force-sling:client:syncWeapons', -1, playerId, {weaponName = weaponName}, 'detach')
|
|
|
|
attachedWeapons[playerId][weaponName] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
Wait(5000) -- Alle 5 Sekunden überprüfen
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|