1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-08-06 15:36:50 +02:00
parent 6d22d5f77c
commit 63fbc60a00
86 changed files with 8352 additions and 3428 deletions

View file

@ -0,0 +1,954 @@
-- error when both menus are enabled
if (Config.useContextMenu and Config.useNativeUI) then
print("^1[ERROR] You can use only one menu or no menu at all. You cannot use both menus."
.. "\nMake sure to set at least one to false in the config and to edit the fxmanifest accordingly!")
end
local keymakers = {}
local lockNotif = nil
local createNewKeyNotif = nil
local LockStatus = {
Unlocked = 1,
Locked = 2
}
local CB = exports["kimi_callbacks"]
local menuPoolNativeUI
local keymakerMenuNativeUI
local keyInvMenuNativeUI
if (Config.useNativeUI) then
if (NativeUI == nil) then
print("^1[ERROR] NativeUI was not properly initialized! Make sure to install NativeUI and start it before this resource!")
end
menuPoolNativeUI = NativeUI.CreatePool()
keymakerMenuNativeUI = NativeUI.CreateMenu(Config.Strings.keymakerTitle, Config.Strings.keymakerSub)
keyInvMenuNativeUI = NativeUI.CreateMenu(Config.Strings.keyInvTitle, Config.Strings.keyInvSub)
end
local isAtKeymaker = false
local menuOpen = false
-- create client side peds
Citizen.CreateThread(function()
for i, keymaker in ipairs(Config.Keymakers) do
RequestModel(keymaker.model)
while not HasModelLoaded(keymaker.model) do
Citizen.Wait(0)
end
local ped = CreatePed(0, keymaker.model, keymaker.pos.x, keymaker.pos.y, keymaker.pos.z, keymaker.pos.w, false, true)
SetBlockingOfNonTemporaryEvents(ped, true)
FreezeEntityPosition(ped, true)
SetEntityInvincible(ped, true)
table.insert(keymakers, ped)
-- add blip
local blip = AddBlipForCoord(keymaker.pos.x, keymaker.pos.y, keymaker.pos.z)
SetBlipSprite(blip, 134)
SetBlipColour(blip, 0)
SetBlipScale(blip, 1.0)
SetBlipDisplay(blip, 2)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName(Config.Strings.keymaker)
EndTextCommandSetBlipName(blip)
end
end)
-- main loop
Citizen.CreateThread(function()
while (true) do
Citizen.Wait(0)
if (Config.useNativeUI) then
if (menuOpen) then
menuPoolNativeUI:ProcessMenus()
end
if (isAtKeymaker) then
if (not menuOpen) then
ShowHelpText(Config.Strings.helpText)
end
if (IsControlJustPressed(0, 51)) then
if (menuPoolNativeUI:IsAnyMenuOpen()) then
menuPoolNativeUI:CloseAllMenus()
menuOpen = false
else
GenerateKeymakerMenuNativeUI()
keymakerMenuNativeUI:Visible(true)
menuOpen = true
end
end
end
if (IsControlJustPressed(0, Config.keyMenuKey)) then
if (menuPoolNativeUI:IsAnyMenuOpen()) then
menuPoolNativeUI:CloseAllMenus()
menuOpen = false
else
GenerateKeyInventoryNativeUI()
keyInvMenuNativeUI:Visible(true)
menuOpen = true
end
end
end
-- lock vehicle with key
--[[ if (Config.lockKey and IsControlJustPressed(0, Config.lockKey)) then
local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0)
if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then
ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked)
end
end ]]
end
end)
-- ContextMenu
if (Config.useContextMenu) then
local menuPool = MenuPool()
menuPool.OnOpenMenu = function(screenPosition, hitSomething, worldPosition, hitEntity, normalDirection)
local playerPos = GetEntityCoords(PlayerPedId())
if (Vdist(worldPosition.x, worldPosition.y, worldPosition.z, playerPos.x, playerPos.y, playerPos.z) < Config.maxDistance) then
CreateMenu(screenPosition, hitEntity)
end
end
function CreateMenu(screenPosition, hitEntity)
menuPool:Reset()
if (hitEntity) then
if (hitEntity == PlayerPedId()) then
local vehicleData = CB:Trigger("VKC:getPlayerVehicleData")
local ownedKeys = GetPlayerKeys()
menuPool:Reset()
local playerMenu = menuPool:AddMenu()
local ownVehMenu, ownVehMenuItem = menuPool:AddSubmenu(playerMenu, Config.Strings.CM.masterKeysTitle)
for i, vehicle in ipairs(vehicleData) do
local plate = vehicle[1]
local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(vehicle[2])
end
local item = ownVehMenu:AddItem(model .. " " .. plate)
end
local ownKeyMenu, ownKeyMenuItem = menuPool:AddSubmenu(playerMenu, Config.Strings.CM.keysTitle)
for i, key in ipairs(ownedKeys) do
local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(key.model)
end
local item = ownKeyMenu:AddItem(model .. " " .. key.plate)
item.rightText = Text("x" .. key.count)
end
-- Fahrzeugübergabe-Menü hinzufügen
local transferVehMenu, transferVehMenuItem = menuPool:AddSubmenu(playerMenu, "Fahrzeug übergeben")
for i, vehicle in ipairs(vehicleData) do
local plate = vehicle[1]
local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(vehicle[2])
end
local item = transferVehMenu:AddItem(model .. " " .. plate)
item.closeMenuOnClick = true
item.OnClick = function()
-- Finde den nächsten Spieler
local player = GetClosestPlayer(5.0)
if player then
local targetPlayerId = GetPlayerServerId(player)
local playerName = GetPlayerName(player)
local success = CB:Trigger("VKC:transferVehicleOwnership", plate, targetPlayerId)
if success then
Notification(string.format("Du hast dein %s an %s übergeben", model, playerName))
else
Notification("Übergabe fehlgeschlagen")
end
else
Notification("Kein Spieler in der Nähe gefunden")
end
end
end
playerMenu:SetPosition(screenPosition)
playerMenu:Visible(true)
elseif (IsEntityAKeymaker(hitEntity)) then
local vehicleData = GetPlayerVehicleData()
local ownedKeys = GetPlayerKeys()
menuPool:Reset()
local keymakerMenu = menuPool:AddMenu()
local createKeyMenu, createKeyMenuItem = menuPool:AddSubmenu(keymakerMenu, Config.Strings.CM.createKeyTitle)
for i, vehicle in ipairs(vehicleData) do
local plate = vehicle[1]
local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(vehicle[2])
end
local keyCount = GetKeyCount(plate, ownedKeys)
local keyItem = createKeyMenu:AddItem(model .. " " .. plate)
keyItem.rightText = Text("x" .. tostring(keyCount))
keyItem.OnClick = function()
local result = CB:Trigger("VKC:createNewKey", plate, 1)
if (type(result) == "boolean" and result == true) then
Notification(string.format(Config.Strings.createSuccess, model))
local oldCount = keyItem.rightText.title:gsub("x", "")
keyItem.rightText.title = "x" .. tostring(tonumber(oldCount) + 1)
elseif (type(result) == "string" and result == "noMoney") then
Notification(string.format(Config.Strings.createNoMoney, model))
else
Notification(string.format(Config.Strings.createFailed, model))
end
end
end
local invalidateKeyMenu, invalidateKeyMenuItem = menuPool:AddSubmenu(keymakerMenu, Config.Strings.CM.invalKeyTitle)
for i, vehicle in ipairs(vehicleData) do
local plate = vehicle[1]
local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(vehicle[2])
end
local item = invalidateKeyMenu:AddItem(model .. " " .. plate)
item.closeMenuOnClick = true
item.OnClick = function()
local result = CB:Trigger("VKC:removeAllKeys", plate)
if (type(result) == "boolean" and result == true) then
Notification(string.format(Config.Strings.deleteKeys, model))
elseif (type(result) == "string" and result == "noMoney") then
Notification(string.format(Config.Strings.removeNoMoney, vehName))
else
Notification(string.format(Config.Strings.removeFailed, vehName))
end
end
end
keymakerMenu:SetPosition(screenPosition)
keymakerMenu:Visible(true)
elseif (IsEntityAPed(hitEntity) and IsPedAPlayer(hitEntity)) then
local ownedKeys = GetPlayerKeys()
menuPool:Reset()
local interactMenu = menuPool:AddMenu()
local giveKeyMenu, giveKeyMenuItem = menuPool:AddSubmenu(interactMenu, Config.Strings.CM.giveKey)
for i, key in ipairs(ownedKeys) do
local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(key.model)
end
local keyItem = giveKeyMenu:AddItem(model .. " " .. key.plate)
keyItem.rightText = Text("x" .. key.count)
keyItem.closeMenuOnClick = true
keyItem.OnClick = function()
local players = GetActivePlayers()
for i, player in ipairs(players) do
if (GetPlayerPed(player) == hitEntity) then
local success = CB:Trigger("VKC:giveKeyToPlayer", key.plate, GetPlayerServerId(player))
if (success) then
Notification(string.format(Config.Strings.giveSuccess, model))
else
Notification(string.format(Config.Strings.giveFailed, model))
end
break
end
end
end
end
interactMenu:SetPosition(screenPosition)
interactMenu:Visible(true)
end
end
end
function IsEntityAKeymaker(entity)
for i, keymaker in ipairs(keymakers) do
if (entity == keymaker) then
return true
end
end
return false
end
end
-- NativeUI
function GenerateKeymakerMenuNativeUI()
keymakerMenuNativeUI:Clear()
local vehicleData = GetPlayerVehicleData()
local ownedKeys = GetPlayerKeys()
keymakerMenuNativeUI = NativeUI.CreateMenu(Config.Strings.NUI.keymakerMenuTitle, Config.Strings.NUI.keymakerMenuSub)
menuPoolNativeUI:Add(keymakerMenuNativeUI)
local submenuCreateKey = menuPoolNativeUI:AddSubMenu(keymakerMenuNativeUI, Config.Strings.NUI.createKeyTitle, Config.Strings.NUI.createKeyDesc)
submenuCreateKey.ParentItem:RightLabel(">")
submenuCreateKey.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.createKeyTitle
for i, vehicle in ipairs(vehicleData) do
local plate = vehicle[1]
local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(vehicle[2])
end
local keyCount = GetKeyCount(plate, ownedKeys)
local vehItem = NativeUI.CreateItem(model .. " " .. plate, string.format(Config.Strings.NUI.createVehicleKey, model, plate))
vehItem:RightLabel("x" .. tostring(keyCount))
submenuCreateKey:AddItem(vehItem)
end
submenuCreateKey.OnItemSelect = function(menu, item, index)
Citizen.CreateThread(function()
local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicleData[index][2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(vehicleData[index][2])
end
local result = CB:Trigger("VKC:createNewKey", vehicleData[index][1], 1)
if (type(result) == "boolean" and result == true) then
Notification(string.format(Config.Strings.createSuccess, model))
if (submenuCreateKey:Visible()) then
local oldCount = item.Label.Text._Text:gsub("x", "")
item:RightLabel("x" .. tostring(tonumber(oldCount) + 1))
end
elseif (type(result) == "string" and result == "noMoney") then
Notification(string.format(Config.Strings.createNoMoney, model))
else
Notification(string.format(Config.Strings.createFailed, model))
end
end)
end
local submenuInvalidateKey = menuPoolNativeUI:AddSubMenu(keymakerMenuNativeUI, Config.Strings.NUI.invalKeyTitle, Config.Strings.NUI.invalKeyDesc)
submenuInvalidateKey.ParentItem:RightLabel(">")
submenuInvalidateKey.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.invalKeyTitle
for i, vehicle in ipairs(vehicleData) do
local plate = vehicle[1]
local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(vehicle[2])
end
local keyItem = NativeUI.CreateItem(model .. " " .. plate, string.format(Config.Strings.NUI.invalVehicleKey, model, plate))
submenuInvalidateKey:AddItem(keyItem)
end
submenuInvalidateKey.OnItemSelect = function(menu, item, index)
Citizen.CreateThread(function()
local result = CB:Trigger("VKC:removeAllKeys", vehicleData[index][1])
if (type(result) == "boolean" and result == true) then
local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicleData[index][2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(vehicleData[index][2])
end
Notification(string.format(Config.Strings.deleteKeys, model))
elseif (type(result) == "string" and result == "noMoney") then
Notification(string.format(Config.Strings.removeNoMoney, vehName))
else
Notification(string.format(Config.Strings.removeFailed, vehName))
end
end)
end
keymakerMenuNativeUI.OnMenuClosed = function(menu)
menuOpen = false
end
menuPoolNativeUI:ControlDisablingEnabled(false)
menuPoolNativeUI:MouseControlsEnabled(false)
menuPoolNativeUI:RefreshIndex()
end
function GenerateKeyInventoryNativeUI()
keyInvMenuNativeUI:Clear()
local vehicleData = GetPlayerVehicleData()
local ownedKeys = GetPlayerKeys()
keyInvMenuNativeUI = NativeUI.CreateMenu(Config.Strings.NUI.keyInventoryTitle, Config.Strings.NUI.keyInventorySub)
menuPoolNativeUI:Add(keyInvMenuNativeUI)
local submenuShowMasterKeys = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, Config.Strings.NUI.masterKeysTitle, Config.Strings.NUI.masterKeysDesc)
submenuShowMasterKeys.ParentItem:RightLabel(">")
submenuShowMasterKeys.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.masterKeysTitle
for i, vehicle in ipairs(vehicleData) do
local plate = vehicle[1]
local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(vehicle[2])
end
--local keyCount = GetKeyCount(plate, ownedKeys)
local vehItem = NativeUI.CreateItem(model .. " " .. plate, "")
--vehItem:RightLabel("x" .. tostring(keyCount))
submenuShowMasterKeys:AddItem(vehItem)
end
-- Fahrzeugübergabe-Untermenü hinzufügen
local submenuTransferVehicle = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, "Fahrzeug übergeben", "Übertrage ein Fahrzeug an einen Spieler in der Nähe")
submenuTransferVehicle.ParentItem:RightLabel(">")
submenuTransferVehicle.Subtitle.Text._Text = "~b~Fahrzeug übergeben"
for i, vehicle in ipairs(vehicleData) do
local plate = vehicle[1]
local model = GetLabelText(GetDisplayNameFromVehicleModel(vehicle[2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(vehicle[2])
end
local vehItem = NativeUI.CreateItem(model .. " " .. plate, "Wähle dieses Fahrzeug zum Übergeben")
submenuTransferVehicle:AddItem(vehItem)
end
submenuTransferVehicle.OnItemSelect = function(menu, item, index)
local selectedVehicle = vehicleData[index]
local plate = selectedVehicle[1]
local model = GetLabelText(GetDisplayNameFromVehicleModel(selectedVehicle[2]))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(selectedVehicle[2])
end
-- Finde den nächsten Spieler
local player = GetClosestPlayer(5.0)
if player then
local targetPlayerId = GetPlayerServerId(player)
local playerName = GetPlayerName(player)
local success = CB:Trigger("VKC:transferVehicleOwnership", plate, targetPlayerId)
if success then
lib.notify({
title = "Fahrzeug übergeben",
description = "Du hast dein " .. model .. " an " .. playerName .. " übergeben",
position = "top",
type = "success",
icon = "car"
})
else
lib.notify({
title = "Fahrzeug übergeben",
description = "Übergabe fehlgeschlagen",
position = "top",
type = "error",
icon = "car"
})
end
else
lib.notify({
title = "Fahrzeug übergeben",
description = "Kein Spieler in der Nähe gefunden",
position = "top",
type = "error",
icon = "car"
})
end
menuPoolNativeUI:CloseAllMenus()
menuOpen = false
end
local submenuShowKeys = menuPoolNativeUI:AddSubMenu(keyInvMenuNativeUI, Config.Strings.NUI.keysTitle, Config.Strings.NUI.keysDesc)
submenuShowKeys.ParentItem:RightLabel(">")
submenuShowKeys.Subtitle.Text._Text = "~b~" .. Config.Strings.NUI.keysTitle
for i, key in ipairs(ownedKeys) do
local model = GetLabelText(GetDisplayNameFromVehicleModel(key.model))
if (model == "NULL") then
model = GetDisplayNameFromVehicleModel(key.model)
end
local submenuKey = menuPoolNativeUI:AddSubMenu(submenuShowKeys, model .. " " .. key.plate, "")
submenuKey.ParentItem:RightLabel("x" .. tostring(key.count) .. " >")
submenuKey.Subtitle.Text._Text = "~b~" .. model .. " " .. key.plate
local giveItem = NativeUI.CreateItem(Config.Strings.NUI.giveKeyTitle, Config.Strings.NUI.giveKeyDesc)
submenuKey:AddItem(giveItem)
local removeItem = NativeUI.CreateItem(Config.Strings.NUI.removeKeyTitle, Config.Strings.NUI.removeKeyDesc)
submenuKey:AddItem(removeItem)
submenuKey.OnItemSelect = function(menu, item, index)
if (item == giveItem) then
Citizen.CreateThread(function()
local player = GetClosestPlayer(2.0)
if (player) then
local success = CB:Trigger("VKC:giveKeyToPlayer", key.plate, GetPlayerServerId(player))
if (success) then
Notification(string.format(Config.Strings.giveSuccess, key.plate))
else
Notification(string.format(Config.Strings.giveFailed, key.plate))
end
else
Notification(string.format(Config.Strings.giveFailed, key.plate))
end
end)
elseif (item == removeItem) then
Citizen.CreateThread(function()
local success = CB:Trigger("VKC:removeKey", key.plate, 1)
if (success) then
Notification(string.format(Config.Strings.removeSuccess, key.plate))
if (submenuShowKeys:Visible() or submenuKey:Visible()) then
local oldCount = submenuKey.ParentItem.Label.Text._Text:gsub("x", "")
oldCount = oldCount:gsub(" >", "")
submenuKey.ParentItem:RightLabel("x" .. tostring(tonumber(oldCount) - 1) .. " >")
end
else
Notification(string.format(Config.Strings.removeFailed, key.plate))
end
end)
end
end
end
keyInvMenuNativeUI.OnMenuClosed = function(menu)
menuOpen = false
end
menuPoolNativeUI:ControlDisablingEnabled(false)
menuPoolNativeUI:MouseControlsEnabled(false)
menuPoolNativeUI:RefreshIndex()
end
if (Config.useNativeUI) then
Citizen.CreateThread(function()
while (true) do
Citizen.Wait(250)
isAtKeymaker = false
local pos = GetEntityCoords(PlayerPedId())
for i, keymaker in ipairs(Config.Keymakers) do
if (Vdist(pos.x, pos.y, pos.z, keymaker.pos.x, keymaker.pos.y, keymaker.pos.z) < 2.0) then
isAtKeymaker = true
break
end
end
end
end)
if (Config.keyMenuCommand) then
RegisterCommand(Config.keyMenuCommand, function(source, args, raw)
if (menuPoolNativeUI:IsAnyMenuOpen()) then
menuPoolNativeUI:CloseAllMenus()
end
GenerateKeyInventoryNativeUI()
keyInvMenuNativeUI:Visible(true)
menuOpen = true
end, false)
end
end
-- lock vehicle
if (Config.lockCommand) then
RegisterCommand(Config.lockCommand, function(source, args, raw)
local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0)
if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then
ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked)
end
end, false)
end
function ToggleLock(vehicle, lock)
local lockStatus = GetVehicleDoorLockStatus(vehicle)
if (NetworkHasControlOfEntity(vehicle)) then
ToggleLockOnVehicle(vehicle, lock)
else
TriggerServerEvent("VKC:toggleLockNet", NetworkGetNetworkIdFromEntity(vehicle), lock)
end
-- play sound
TriggerServerEvent("VKC:playDoorLockSoundNet", NetworkGetNetworkIdFromEntity(vehicle), lock)
-- play remote animation
if (not IsPedInAnyVehicle(PlayerPedId(), false)) then
PlayRemoteAnimation()
end
-- show notification
--[[
if (lockNotif) then
RemoveNotification(lockNotif)
end
lockNotif = Notification(lockStatus == LockStatus.Locked and Config.Strings.unlockNotif or Config.Strings.lockNotif)
]]
end
function ToggleLockOnVehicle(vehicle, lock)
if (lock) then
SetVehicleDoorsShut(vehicle, false)
SetVehicleDoorsLocked(vehicle, LockStatus.Locked)
--exports['okokNotify']:Alert("Fahrzeug", "Du hast dein Fahrzeug Abgeschlossen", 3000, 'error')
lib.notify({
title = "Fahrzeug",
description = "Du hast dein Fahrzeug Abgeschlossen",
position = "top",
type = "error",
icon = "car"
})
SetVehicleLights(vehicle, 2)
Citizen.Wait(150)
SetVehicleLights(vehicle, 0)
Citizen.Wait(150)
SetVehicleLights(vehicle, 2)
Citizen.Wait(150)
SetVehicleLights(vehicle, 0)
else
SetVehicleDoorsLocked(vehicle, LockStatus.Unlocked)
--exports['okokNotify']:Alert("Fahrzeug", "Du hast dein Fahrzeug Aufgeschlossen", 3000, 'success')
lib.notify({
title = "Fahrzeug",
description = "Du hast dein Fahrzeug Aufgeschlossen",
position = "top",
type = "success",
icon = "car"
})
SetVehicleLights(vehicle, 2)
Citizen.Wait(150)
SetVehicleLights(vehicle, 0)
Citizen.Wait(150)
SetVehicleLights(vehicle, 2)
Citizen.Wait(150)
SetVehicleLights(vehicle, 0)
Citizen.Wait(150)
SetVehicleLights(vehicle, 2)
Citizen.Wait(150)
SetVehicleLights(vehicle, 0)
Citizen.Wait(150)
SetVehicleLights(vehicle, 2)
Citizen.Wait(150)
SetVehicleLights(vehicle, 0)
Citizen.Wait(150)
SetVehicleLights(vehicle, 2)
Citizen.Wait(150)
SetVehicleLights(vehicle, 0)
end
end
function PlayDoorLockSound(vehicle, lock)
if (lock) then
PlayVehicleDoorCloseSound(vehicle, 0)
else
PlayVehicleDoorOpenSound(vehicle, 0)
end
end
if (Config.lockCommand or Config.lockKey) then
RegisterNetEvent("VKC:toggleLockOnPlayer")
AddEventHandler("VKC:toggleLockOnPlayer", function(vehicleNetId, unlocked)
local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId)
if (DoesEntityExist(vehicle) and NetworkHasControlOfEntity(vehicle)) then
local lockStatus = GetVehicleDoorLockStatus(vehicle)
ToggleLockOnVehicle(vehicle, unlocked)
end
end)
RegisterNetEvent("VKC:playDoorLockSound")
AddEventHandler("VKC:playDoorLockSound", function(vehicleNetId, lock)
local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId)
if (DoesEntityExist(vehicle)) then
PlayDoorLockSound(vehicle, lock)
end
end)
end
RegisterNetEvent("VKC:giveKeyNotif")
AddEventHandler("VKC:giveKeyNotif", function(plate)
Notification(string.format(Config.Strings.giveSuccessPly, plate))
end)
-- Ereignis für Fahrzeugübergabe-Benachrichtigung
RegisterNetEvent("VKC:vehicleTransferNotif")
AddEventHandler("VKC:vehicleTransferNotif", function(plate, model)
lib.notify({
title = "Fahrzeug erhalten",
description = "Du hast ein " .. model .. " mit dem Kennzeichen " .. plate .. " erhalten",
position = "top",
type = "success",
icon = "car"
})
end)
function IsVehicleOwner(vehicle)
if (not DoesEntityExist(vehicle)) then
print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsVehicleOwner\"!")
return
end
return CB:Trigger("VKC:isVehicleOwner", GetVehicleNumberPlateText(vehicle))
end
function IsKeyOwner(vehicle)
if (not DoesEntityExist(vehicle)) then
print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsKeyOwner\"!")
return
end
return CB:Trigger("VKC:isKeyOwner", GetVehicleNumberPlateText(vehicle), GetEntityModel(vehicle))
end
function IsVehicleOrKeyOwner(vehicle)
if (not DoesEntityExist(vehicle)) then
print("^1[ERROR] Parameter \"vehicle\" was nil or vehicle did not exist while triggering export \"IsVehicleOrKeyOwner\"!")
return
end
return CB:Trigger("VKC:isVehicleOrKeyOwner", GetVehicleNumberPlateText(vehicle), GetEntityModel(vehicle))
end
function GetPlayerKeys()
return CB:Trigger("VKC:getPlayerKeys")
end
function GetPlayerVehicleData()
return CB:Trigger("VKC:getPlayerVehicleData")
end
-- play lock animation
function PlayRemoteAnimation()
Citizen.CreateThread(function()
RequestModel(keyPropHash)
RequestAnimDict("anim@mp_player_intmenu@key_fob@")
while (not HasModelLoaded(keyPropHash) and not HasAnimDictLoaded("anim@mp_player_intmenu@key_fob@")) do
Citizen.Wait(0)
end
local playerPed = PlayerPedId()
local playerPos = GetEntityCoords(playerPed)
local keyObj = CreateObjectNoOffset(keyPropHash, playerPos.x, playerPos.y, playerPos.z, true, true, false)
SetModelAsNoLongerNeeded(keyPropHash)
local boneIndex = GetEntityBoneIndexByName(playerPed, "IK_R_Hand")
local offset = vector3(0.08, 0.025, -0.01)
local rotOffset = vector3(0, 70, 140)
AttachEntityToEntity(keyObj, playerPed, boneIndex, offset.x, offset.y, offset.z, rotOffset.x, rotOffset.y, rotOffset.z, false, false, true, false, 2, true)
TaskPlayAnim(playerPed, "anim@mp_player_intmenu@key_fob@", "fob_click_fp", 8.0, 8.0, -1, 48, 1, false, false, false)
RemoveAnimDict("anim@mp_player_intmenu@key_fob@")
Citizen.Wait(1500)
DeleteEntity(keyObj)
end)
end
-- show text in upper left corner
function ShowHelpText(text)
BeginTextCommandDisplayHelp('STRING')
AddTextComponentSubstringPlayerName(text)
EndTextCommandDisplayHelp(0, false, true, -1)
end
-- displays a notification and returns its handle
function Notification(text)
SetNotificationTextEntry('STRING')
AddTextComponentSubstringPlayerName(text)
return DrawNotification(false, true)
end
-- get key count
function GetKeyCount(plate, keyArray)
for i, key in ipairs(keyArray) do
if (plate == key.plate) then
return key.count
end
end
return 0
end
-- get all players
function GetAllPlayers()
local players = {}
for k, v in ipairs(GetActivePlayers()) do
table.insert(players, v)
end
return players
end
-- get the closest player
function GetClosestPlayer(maxRange)
local playerPed = PlayerPedId()
local players = GetAllPlayers()
local playerCoords = GetEntityCoords(playerPed)
local closestDistance = maxRange
local closestPlayer = nil
for i=1, #players, 1 do
local coords = GetEntityCoords(GetPlayerPed(players[i]))
local dist = Vdist(playerCoords.x, playerCoords.y, playerCoords.z, coords.x, coords.y, coords.z)
if (dist < closestDistance and players[i] ~= PlayerId()) then
closestDistance = dist
closestPlayer = players[i]
end
end
if (closestPlayer ~= nil and DoesEntityExist(GetPlayerPed(closestPlayer))) then
return closestPlayer
else
return nil
end
end
-- Return closest loaded vehicle entity or nil if no vehicle is found
function GetClosestVehicle(position, maxRadius)
local vehicles = GetAllVehicles()
local dist = maxRadius
local closestVehicle = nil
for i=1, #vehicles, 1 do
local vehicleCoords = GetEntityCoords(vehicles[i])
local tempDist = Vdist(vehicleCoords.x, vehicleCoords.y, vehicleCoords.z, position.x, position.y, position.z)
if (tempDist < dist) then
dist = tempDist
closestVehicle = vehicles[i]
end
end
if (closestVehicle ~= nil and DoesEntityExist(closestVehicle)) then
return closestVehicle
else
return nil
end
end
-- Returns all loaded vehicles on client side
function GetAllVehicles()
local vehicles = {}
for vehicle in EnumerateVehicles() do
table.insert(vehicles, vehicle)
end
return vehicles
end
-- getting all vehicles
function EnumerateVehicles()
return EnumerateEntities(FindFirstVehicle, FindNextVehicle, EndFindVehicle)
end
function EnumerateEntities(initFunc, moveFunc, disposeFunc)
return coroutine.wrap(function()
local iter, id = initFunc()
if not id or id == 0 then
disposeFunc(iter)
return
end
local enum = {handle = iter, destructor = disposeFunc}
setmetatable(enum, entityEnumerator)
local next = true
repeat
coroutine.yield(id)
next, id = moveFunc(iter)
until not next
enum.destructor, enum.handle = nil, nil
disposeFunc(iter)
end)
end
local entityEnumerator = {
__gc = function(enum)
if enum.destructor and enum.handle then
enum.destructor(enum.handle)
end
enum.destructor = nil
enum.handle = nil
end
}
--[[
RegisterCommand("plate", function(source, args, raw)
local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0)
if (DoesEntityExist(vehicle)) then
SetVehicleNumberPlateText(vehicle, args[1])
end
end, false)
]]
RegisterKeyMapping("vehicleLock", "Vehicle Lock", "keyboard", "PAGEUP")
RegisterCommand("vehicleLock", function()
local vehicle = GetClosestVehicle(GetEntityCoords(PlayerPedId()), 10.0)
if (DoesEntityExist(vehicle) and IsVehicleOrKeyOwner(vehicle)) then
ToggleLock(vehicle, GetVehicleDoorLockStatus(vehicle) ~= LockStatus.Locked)
end
end, false)
-- Integration mit dem Mietfahrzeug-System
RegisterNetEvent('vehiclerental:client:checkRentalKeys')
AddEventHandler('vehiclerental:client:checkRentalKeys', function()
TriggerServerEvent('vehiclerental:server:checkRentalKeys')
end)
-- Überprüfe Mietfahrzeug-Schlüssel beim Öffnen des Schlüssel-Menüs
if Config.useNativeUI then
-- Speichere die ursprüngliche Funktion
local originalGenerateKeyInventoryNativeUI = GenerateKeyInventoryNativeUI
-- Überschreibe die Funktion
GenerateKeyInventoryNativeUI = function()
-- Überprüfe Mietfahrzeug-Schlüssel
TriggerServerEvent('vehiclerental:server:checkRentalKeys')
-- Warte kurz, damit die Schlüssel aktualisiert werden können
Citizen.Wait(100)
-- Rufe die ursprüngliche Funktion auf
originalGenerateKeyInventoryNativeUI()
end
end

View file

@ -0,0 +1,149 @@
Config = {}
-- set at least one to false, otherwise both menus will clash
-- and don't forget to comment the menu in the fxmanifest.lua if you don't use it!
-- Setting both to true does not work!
-- setting both to false results in no menu being usable at all
-- you can then just include the exports in your own menu if you have one
Config.useContextMenu = false
Config.useNativeUI = true
-- set to nil if you don't want to use the command
Config.lockCommand = "lock"
-- set to nil if you don't want to use the button (303, U)
Config.lockKey = 10 -- PageUp
-- set to nil if you don't want to use the command
Config.keyMenuCommand = "keys"
-- set to nil if you don't want to use the button (311, K)
Config.keyMenuKey = 56 -- F9
-- maximum distance (in meters) between the player and ContextMenu interaction point
Config.maxDistance = 5.0
-- you can define more keymakers by just adding additional entries
Config.Keymakers = {
{
-- ped model (yes, the ` symbols are correct)
model = `s_m_m_autoshop_01`,
-- position and heading vector4(x, y, z, heading)
pos = vector4(170.33, -1799.13, 28.32, 313.0)
},
}
-- define costs for creating a new key and exchanging locks
Config.Costs = {
GetMoney = "cash", -- cash or bank
newKey = 150,
exchangeLocks = 650
}
-- define job vehicles like this (this acts as a key for those vehicles)
-- models in ``
-- either exact plates or just a string that should be in the vehicles plate
-- e.g. "LSPD" will let a police officer lock/unlock any vehicle with the plate "LSPD1337" or "13LSPD37"
Config.JobVehicles = {
-- examples:
--["police"] = {
--models = {
--`police`,
--`policeb`,
--`pbus`
--},
--plates = {
--""
--}
--},
--["mechanic"] = {
-- models = {
-- `flatbed`
-- },
-- plates = {
-- "MECH"
-- }
--},
}
Config.Strings = {
keymaker = "Schlüsseldienst",
helpText = "~w~Drück ~g~E ~w~um mit den Schlüsseldienst zu reden",
lockNotif = "~r~Fahrzeug Abgeschlossen",
unlockNotif = "~g~Fahrzeug Aufgeschlossen",
createSuccess = "~g~Ersatzschlüssel Nachgemacht %s.",
createNoMoney = "~r~Schlüssel kann nicht nachgemacht werden, du hast zu wenig Geld dabei",
createFailed = "~r~Ersatzschlüssel machen Fehlgeschlagen %s!",
giveSuccess = "~g~Schlüssel an %s Weitergegeben.",
giveSuccessPly = "~g~Schlüssel von %s erhalten ",
giveFailed = "~r~Schlüssel geben von %s Fehlgeschlagen",
removeSuccess = "~r~Schlüssel für ~g~%s ~r~aus deiner Tasche Entfernt",
removeNoMoney = "~r~Schloss kann nicht bezahlt werden, du hast kein Geld dabei",
removeFailed = "~r~Entfernen von Schlüssel für ~g~%s ~r~Fehgeschlagen!",
deleteKeys = "~r~Du hast für dein ~g~%s ~r~Das Schloss ausgetasucht, und somit sind jetzt alle Schlüssel nicht mehr Gültig.",
-- NativeUI
NUI = {
-- keymaker menu
keymakerMenuTitle = "Schlüssel-System",
keymakerMenuSub = "~g~Erstelle Schlüssel und Tausche deine Fahrzeug Schlösser aus",
-- create key
createKeyTitle = "~g~Ersatzschlüssel erstellen",
createKeyDesc = "Erstelle einen neuen Schlüssel für eines Ihrer Fahrzeuge ",
createVehicleKey = "Erstelle einen Schlüssel für Ihr %s mit den Kennzeichen %s. ~g~Preis "..Config.Costs.newKey.."$",
-- invalidate Key
invalKeyTitle = "~r~Fahrzeug Schlöss Tauschen",
invalKeyDesc = "Tausche die Schlösser von Ihren Auto aus, alle schlüssel sind damit nicht mehr Gültig!",
invalVehicleKey = "Schloss Tauschen von %s mit den Kennzeichen %s. ~g~Preis "..Config.Costs.exchangeLocks.."$",
-- key Inventory
keyInventoryTitle = "Schlüssel",
keyInventorySub = "~g~Da sind alle deine Schlüssel",
-- master keys
masterKeysTitle = "Hauptschlüssel",
masterKeysDesc = "~g~Zeigt alle deine Hauptschlüssel an",
-- additional keys
keysTitle = "Ersatzschlüssel",
keysDesc = "~g~Zeigt alle deine Ersatzschlüssel an",
giveKeyTitle = "~g~Ersatzschlüssel Geben",
giveKeyDesc = "~g~Ersatzschlüssel Geben",
removeKeyTitle = "~r~Schlüssel Entfernen",
removeKeyDesc = "~r~Schlüssel Entfernen",
transferVehicleTitle = "~g~Fahrzeug übergeben",
transferVehicleDesc = "~g~Übertrage ein Fahrzeug an einen Spieler in der Nähe",
transferVehicleSuccess = "~g~Fahrzeug erfolgreich übergeben an %s",
transferVehicleFailed = "~r~Fahrzeugübergabe fehlgeschlagen",
transferVehicleReceived = "~g~Du hast ein Fahrzeug erhalten",
noPlayersNearby = "~r~Keine Spieler in der Nähe",
},
-- ContextMenu
CM = {
-- keymaker menu
createKeyTitle = "Ersatzschlüssel",
invalKeyTitle = "Schlossaustauschen",
-- key inventory
masterKeysTitle = "~g~Hauptschlüssel",
keysTitle = "~b~Ersatzschlüssel",
-- other player
giveKey = "~r~Gebe ein Schlüssel, an der Person",
transferVehicleTitle = "Fahrzeug übergeben",
}
}

View file

@ -0,0 +1,57 @@
fx_version 'cerulean'
games { 'gta5' }
author 'Mîhó'
description 'Manage vehicle keys!'
version '1.1.1'
dependency 'kimi_callbacks'
dependency 'NativeUI'
server_scripts {
--'@mysql-async/lib/MySQL.lua',
'@oxmysql/lib/MySQL.lua',
'config.lua',
'server.lua'
}
client_scripts {
-- comment these lines if not using the ContextMenu
--'@ContextMenu/screenToWorld.lua',
--'@ContextMenu/Drawables/Color.lua',
--'@ContextMenu/Drawables/Rect.lua',
--'@ContextMenu/Drawables/Text.lua',
--'@ContextMenu/Drawables/Sprite.lua',
--'@ContextMenu/Menu/Item.lua',
--'@ContextMenu/Menu/TextItem.lua',
--'@ContextMenu/Menu/CheckboxItem.lua',
--'@ContextMenu/Menu/SubmenuItem.lua',
--'@ContextMenu/Menu/Separator.lua',
--'@ContextMenu/Menu/Border.lua',
--'@ContextMenu/Menu/Menu.lua',
--'@ContextMenu/Menu/MenuPool.lua',
-- comment this line if not using NativeUILua
'@NativeUI/NativeUI.lua',
'@ox_lib/init.lua',
'config.lua',
'client.lua'
}
server_exports {
'IsVehicleOwner',
'IsKeyOwner',
'IsVehicleOrKeyOwner',
'GetPlayerKeys',
'GetPlayerVehicles'
}
exports {
'IsVehicleOwner',
'IsKeyOwner',
'IsVehicleOrKeyOwner',
'GetAllKeys',
'GetAllVehicles'
}

View file

@ -0,0 +1,503 @@
local CB = exports["kimi_callbacks"]
local QBCore = exports['qb-core']:GetCoreObject()
-- create a new key
CB:Register("VKC:createNewKey", function(source, plate, count)
local src = source
if (plate == nil or count == nil) then
print("^1[ERROR] \"plate\" or \"count\" was nil while creating new key for id " .. tostring(src))
return false
end
local Player = QBCore.Functions.GetPlayer(src)
if (Player) then
local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper()
if (Player.Functions.GetMoney('cash') >= Config.Costs.newKey) then
local results = MySQL.Sync.fetchAll("SELECT count FROM vehicle_keys WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", {
["@owner"] = Player.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate
})
local rows = 0
if (#results > 0) then
rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count + @count WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", {
["@owner"] = Player.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate,
["@count"] = count
})
else
rows = MySQL.Sync.execute("INSERT INTO vehicle_keys (owner, plate, count) VALUES (@owner, @trimmedPlate, @count)", {
["@owner"] = Player.PlayerData.citizenid,
["@trimmedPlate"] = trimmedPlate,
["@count"] = count
})
end
if (rows == 0) then
return false
end
Player.Functions.RemoveMoney('cash', Config.Costs.newKey)
else
return "noMoney"
end
else
print("^1[ERROR] \"playerData\" was nil while creating new key for id " .. tostring(src))
return false
end
return true
end)
-- remove a key from a plate
CB:Register("VKC:removeKey", function(source, plate, num)
local src = source
if (plate == nil or num == nil) then
print("^1[ERROR] \"plate\" or \"num\" was nil while removing a key for id " .. tostring(src))
return false
end
local Player = QBCore.Functions.GetPlayer(src)
if (Player) then
local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper()
local rows = MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate) and count = @num", {
["@owner"] = Player.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate,
["@num"] = num
})
if (rows == 0) then
rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count - @num WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", {
["@owner"] = Player.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate,
["@num"] = num
})
end
if (rows == 0) then
return false
end
else
print("^1[ERROR] \"playerData\" was nil while removing a key for id " .. tostring(src))
return false
end
return true
end)
-- remove a key from a plate
CB:Register("VKC:giveKeyToPlayer", function(source, plate, playerId)
local src = source
if (plate == nil or playerId == nil) then
print("^1[ERROR] \"plate\" or \"playerId\" was nil while giving a key for id " .. tostring(src))
return false
end
local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper()
local Playera = QBCore.Functions.GetPlayer(src) --MARK
local Playerb = QBCore.Functions.GetPlayer(playerId)
if (Playera and Playerb) then
local rows = MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate) and count = 1", {
["@owner"] = Playera.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate
})
if (rows == 0) then
rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count - 1 WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", {
["@owner"] = Playera.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate
})
end
if (rows == 0) then
return false
else
local results = MySQL.Sync.fetchAll("SELECT count FROM vehicle_keys WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", {
["@owner"] = Playerb.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate
})
rows = 0
if (#results > 0) then
rows = MySQL.Sync.execute("UPDATE vehicle_keys SET count = count + 1 WHERE owner = @owner AND (plate = @plate OR plate = @trimmedPlate)", {
["@owner"] = Playerb.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate
})
else
rows = MySQL.Sync.execute("INSERT INTO vehicle_keys (owner, plate, count) VALUES (@owner, @trimmedPlate, 1)", {
["@owner"] = Playerb.PlayerData.citizenid,
["@trimmedPlate"] = trimmedPlate
})
end
if (rows == 0) then
return false
end
end
else
print("^1[ERROR] \"playerData\" or \"playerData2\" was nil while giving a key for id " .. tostring(src))
return false
end
TriggerClientEvent("VKC:giveKeyNotif", playerId, trimmedPlate)
return true
end)
-- remove all keys from a plate
CB:Register("VKC:removeAllKeys", function(source, plate)
local src = source
if (plate == nil) then
print("^1[ERROR] \"plate\" was nil while removing all keys for " .. tostring(src))
return false
end
local Player = QBCore.Functions.GetPlayer(src)
if (Player) then
local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper()
if (Player.Functions.GetMoney(Config.Costs.GetMoney) >= Config.Costs.exchangeLocks) then
MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE plate = @trimmedPlate", {
["@trimmedPlate"] = trimmedPlate
})
Player.Functions.RemoveMoney(Config.Costs.GetMoney, Config.Costs.exchangeLocks)
return true
else
return "noMoney"
end
end
return false
end)
-- get all owned vehicles from player
function GetPlayerVehicleData(playerId)
if (playerId == nil) then
print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"GetOwnedVehicles\"!")
return
end
local Player = QBCore.Functions.GetPlayer(playerId)
local vehicles = {}
if (Player) then
local results = MySQL.Sync.fetchAll("SELECT plate, vehicle FROM player_vehicles WHERE citizenid = @owner", {
["@owner"] = Player.PlayerData.citizenid
})
for i = 1, #results, 1 do
print(json.encode(results[i]))
table.insert(vehicles, {
results[i].plate,
results[i].vehicle})
--json.decode(results[i].vehicles).model})
end
else
print("^1[ERROR] \"playerData\" was nil while getting owned vehicles for id " .. tostring(playerId))
end
print(json.encode(vehicles))
return vehicles
end
CB:Register("VKC:getPlayerVehicleData", GetPlayerVehicleData)
-- get all owned keys from player
function GetPlayerKeys(playerId)
if (playerId == nil) then
print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"GetOwnedKeys\"!")
return
end
local keys = {}
local Player = QBCore.Functions.GetPlayer(playerId)
if (Player) then
local results = MySQL.Sync.fetchAll("SELECT vehicle_keys.plate, vehicle_keys.count, player_vehicles.vehicle FROM vehicle_keys INNER JOIN player_vehicles ON vehicle_keys.plate = player_vehicles.plate WHERE vehicle_keys.owner = @owner", {
["@owner"] = Player.PlayerData.citizenid
})
for i = 1, #results, 1 do
table.insert(keys, {
plate = results[i].plate,
count = results[i].count,
model = results[i].vehicle --json.decode(results[i].vehicle).model
})
end
else
print("^1[ERROR] \"playerData\" was nil while getting owned keys for id " .. tostring(playerId))
end
return keys
end
CB:Register("VKC:getPlayerKeys", GetPlayerKeys)
-- return if playerId is owner of vehicle
function IsVehicleOwner(playerId, plate)
if (playerId == nil) then
print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"IsVehicleOwner\"!")
return
end
if (plate == nil) then
print("^1[ERROR] Parameter \"plate\" was nil while triggering server export \"IsVehicleOwner\"!")
return
end
local Player = QBCore.Functions.GetPlayer(playerId)
if (Player) then
local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper()
local results = MySQL.Sync.fetchAll("SELECT plate FROM player_vehicles WHERE citizenid = @owner and (plate = @plate OR plate = @trimmedPlate)", {
["@owner"] = Player.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate
})
if (#results > 0) then
return true
end
else
print("^1[ERROR] \"playerData\" was nil while getting vehicle ownership for id " .. tostring(playerId))
end
return false
end
CB:Register("VKC:isVehicleOwner", IsVehicleOwner)
-- return if playerId is owner of key
function IsKeyOwner(playerId, plate, model)
if (playerId == nil) then
print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"IsKeyOwner\"!")
return
end
if (plate == nil) then
print("^1[ERROR] Parameter \"plate\" was nil while triggering server export \"IsKeyOwner\"!")
return
end
if (model == nil) then
print("^1[ERROR] Parameter \"model\" was nil while triggering server export \"IsKeyOwner\"!")
return
end
local Player = QBCore.Functions.GetPlayer(playerId)
if (Player) then
local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper()
if (IsJobVehicle(Player.PlayerData.job.name, trimmedPlate, model)) then
return true
end
local results = MySQL.Sync.fetchAll("SELECT plate FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", {
["@owner"] = Player.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate
})
if (#results > 0) then
return true
end
else
print("^1[ERROR] \"playerData\" was nil while getting key ownership for id " .. tostring(playerId))
end
return false
end
exports["kimi_callbacks"]:Register("VKC:isKeyOwner", IsKeyOwner)
-- return if playerId is owner of vehicle or key
function IsVehicleOrKeyOwner(playerId, plate, model)
if (playerId == nil) then
print("^1[ERROR] Parameter \"playerId\" was nil while triggering server export \"IsVehicleOrKeyOwner\"!")
return
end
if (plate == nil) then
print("^1[ERROR] Parameter \"plate\" was nil while triggering server export \"IsVehicleOrKeyOwner\"!")
return
end
if (model == nil) then
print("^1[ERROR] Parameter \"model\" was nil while triggering server export \"IsVehicleOrKeyOwner\"!")
return
end
local Player = QBCore.Functions.GetPlayer(playerId)
if (Player) then
local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper()
if (IsJobVehicle(Player.PlayerData.job.name, trimmedPlate, model)) then
return true
end
local results = MySQL.Sync.fetchAll("SELECT plate FROM player_vehicles WHERE citizenid = @owner and (plate = @plate OR plate = @trimmedPlate)", {
["@owner"] = Player.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate
})
if (#results > 0) then
return true
end
results = MySQL.Sync.fetchAll("SELECT plate FROM vehicle_keys WHERE owner = @owner and (plate = @plate OR plate = @trimmedPlate)", {
["@owner"] = Player.PlayerData.citizenid,
["@plate"] = plate,
["@trimmedPlate"] = trimmedPlate
})
if (#results > 0) then
return true
end
else
print("^1[ERROR] \"playerData\" was nil while getting vehicle or key ownership for id " .. tostring(playerId))
end
return false
end
CB:Register("VKC:isVehicleOrKeyOwner", IsVehicleOrKeyOwner)
-- if the given vehicle is a job vehicle
function IsJobVehicle(job, plate, model)
local jobData = Config.JobVehicles[job]
if (jobData == nil) then
return false
end
for i, m in ipairs(jobData.models) do
if (m == model) then
return true
end
end
for i, p in ipairs(jobData.plates) do
if (plate:find(p:upper())) then
return true
end
end
return false
end
-- toggle door lock over network to ensure it always works
RegisterServerEvent("VKC:toggleLockNet")
AddEventHandler("VKC:toggleLockNet", function(vehicleNetId, unlocked)
local vehicle = NetworkGetEntityFromNetworkId(vehicleNetId)
if (DoesEntityExist(vehicle)) then
local entityOwner = NetworkGetEntityOwner(vehicle)
TriggerClientEvent("VKC:toggleLockOnPlayer", entityOwner, vehicleNetId, unlocked)
end
end)
RegisterServerEvent("VKC:playDoorLockSoundNet")
AddEventHandler("VKC:playDoorLockSoundNet", function(vehicleNetId, lock)
TriggerClientEvent("VKC:playDoorLockSound", -1, vehicleNetId, lock)
end)
RegisterServerEvent('VKC:setvehkey')
AddEventHandler('VKC:setvehkey', function(plate)
local _source = source
local xPlayer = QBCore.Functions.GetPlayer(_source)
MySQL.query("INSERT INTO vehicle_keys(owner, plate, count) VALUES (?, ?, ?)", {xPlayer.PlayerData.citizenid, plate, 1})
end)
RegisterServerEvent('VKC:delvehkey')
AddEventHandler('VKC:delvehkey', function(plate, owner)
local _source = source
if owner then
local xPlayer = QBCore.Functions.GetPlayer(_source)
MySQL.query("DELETE FROM vehicle_keys WHERE plate = ? and owner = ?", {plate, xPlayer.PlayerData.citizenid})
else
MySQL.query("DELETE FROM vehicle_keys WHERE plate = ?", {plate})
end
end)
-- Fahrzeugbesitz an einen anderen Spieler übertragen
CB:Register("VKC:transferVehicleOwnership", function(source, plate, targetPlayerId)
local src = source
if (plate == nil or targetPlayerId == nil) then
print("^1[ERROR] \"plate\" or \"targetPlayerId\" was nil while transferring vehicle ownership for id " .. tostring(src))
return false
end
local Player = QBCore.Functions.GetPlayer(src)
local TargetPlayer = QBCore.Functions.GetPlayer(targetPlayerId)
if (not Player or not TargetPlayer) then
print("^1[ERROR] Player or target player not found while transferring vehicle ownership")
return false
end
local trimmedPlate = plate:gsub("^%s*(.-)%s*$", "%1"):upper()
-- Überprüfen, ob der Spieler das Fahrzeug besitzt
local isOwner = IsVehicleOwner(src, trimmedPlate)
if not isOwner then
return false
end
-- Fahrzeugmodell für die Benachrichtigung abrufen
local vehicleModel = nil
local results = MySQL.Sync.fetchAll("SELECT vehicle FROM player_vehicles WHERE plate = @plate AND citizenid = @owner", {
["@plate"] = trimmedPlate,
["@owner"] = Player.PlayerData.citizenid
})
if #results > 0 then
vehicleModel = results[1].vehicle
end
-- Besitz in der Datenbank übertragen
local success = MySQL.Sync.execute("UPDATE player_vehicles SET citizenid = @newOwner WHERE plate = @plate AND citizenid = @oldOwner", {
["@newOwner"] = TargetPlayer.PlayerData.citizenid,
["@plate"] = trimmedPlate,
["@oldOwner"] = Player.PlayerData.citizenid
})
if success > 0 then
-- Alle Schlüssel auf den neuen Besitzer übertragen
MySQL.Sync.execute("DELETE FROM vehicle_keys WHERE plate = @plate", {
["@plate"] = trimmedPlate
})
-- Einen Schlüssel dem neuen Besitzer geben
MySQL.Sync.execute("INSERT INTO vehicle_keys (owner, plate, count) VALUES (@owner, @plate, 1)", {
["@owner"] = TargetPlayer.PlayerData.citizenid,
["@plate"] = trimmedPlate
})
-- Den Zielspieler benachrichtigen
TriggerClientEvent("VKC:vehicleTransferNotif", targetPlayerId, trimmedPlate, vehicleModel)
return true
end
return false
end)

View file

@ -0,0 +1,27 @@
-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Server version: 10.1.28-MariaDB - mariadb.org binary distribution
-- Server OS: Win32
-- HeidiSQL Version: 11.0.0.5919
-- --------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-- Dumping structure for table essentialmode.vehicle_keys
CREATE TABLE IF NOT EXISTS `vehicle_keys` (
`owner` varchar(60) NOT NULL,
`plate` varchar(8) NOT NULL,
`count` smallint(6) NOT NULL,
KEY `plate` (`plate`),
KEY `owner` (`owner`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Data exporting was unselected.
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;