From 4c9a54ff7bd980aaeb705dbcc3869ca76ee79dde Mon Sep 17 00:00:00 2001 From: Nordi98 Date: Tue, 5 Aug 2025 08:45:18 +0200 Subject: [PATCH] ed --- .../[Mark]/mh_garage/client/debug.lua | 5 + .../[Mark]/mh_garage/client/main.lua | 180 ++++++++++++++++++ .../[Mark]/mh_garage/client/retrieve.lua | 152 +++++++++++++++ .../[Mark]/mh_garage/client/stored.lua | 131 +++++++++++++ .../[Mark]/mh_garage/client/verwaltung.lua | 76 ++++++++ .../[Mark]/mh_garage/config/config.lua | 162 ++++++++++++++++ .../[Mark]/mh_garage/config/price.lua | 3 + .../[Mark]/mh_garage/fxmanifest.lua | 17 ++ .../[Mark]/mh_garage/server/log.lua | 59 ++++++ .../[Mark]/mh_garage/server/server.lua | 159 ++++++++++++++++ 10 files changed, 944 insertions(+) create mode 100644 resources/[Developer]/[Mark]/mh_garage/client/debug.lua create mode 100644 resources/[Developer]/[Mark]/mh_garage/client/main.lua create mode 100644 resources/[Developer]/[Mark]/mh_garage/client/retrieve.lua create mode 100644 resources/[Developer]/[Mark]/mh_garage/client/stored.lua create mode 100644 resources/[Developer]/[Mark]/mh_garage/client/verwaltung.lua create mode 100644 resources/[Developer]/[Mark]/mh_garage/config/config.lua create mode 100644 resources/[Developer]/[Mark]/mh_garage/config/price.lua create mode 100644 resources/[Developer]/[Mark]/mh_garage/fxmanifest.lua create mode 100644 resources/[Developer]/[Mark]/mh_garage/server/log.lua create mode 100644 resources/[Developer]/[Mark]/mh_garage/server/server.lua diff --git a/resources/[Developer]/[Mark]/mh_garage/client/debug.lua b/resources/[Developer]/[Mark]/mh_garage/client/debug.lua new file mode 100644 index 000000000..b64d9f7e9 --- /dev/null +++ b/resources/[Developer]/[Mark]/mh_garage/client/debug.lua @@ -0,0 +1,5 @@ +function Debug(text) + if Config.Debug then + print(text) + end +end \ No newline at end of file diff --git a/resources/[Developer]/[Mark]/mh_garage/client/main.lua b/resources/[Developer]/[Mark]/mh_garage/client/main.lua new file mode 100644 index 000000000..8f9bda9a4 --- /dev/null +++ b/resources/[Developer]/[Mark]/mh_garage/client/main.lua @@ -0,0 +1,180 @@ +QBCore = exports['qb-core']:GetCoreObject() + +Player = nil +npcHandle = nil +isNPCSpawned = false +CurrentZone = nil + +CurrentActionData = {} +hasAlreadyEnteredMarker = false + +Citizen.CreateThread(function() + while Player == nil do + Player = exports['qb-core']:GetPlayerData() + Wait(0) + end +end) + +Citizen.CreateThread(function() + while true do + Wait(15000) + local ped = PlayerPedId() + + if IsPedInAnyVehicle(ped, false) then + local veh = GetVehiclePedIsIn(ped, false) + local mods = QBCore.Functions.GetVehicleProperties(veh) + print("Triggert setMods: "..json.encode(mods)) + TriggerServerEvent('mh_garage:setMods', mods) + end + end +end) + +-- Funktion zum Spawnen des NPCs +function SpawnGuardNPC(npc) + -- Ped Model laden + RequestModel(npc.model) + local timeout = 0 + while not HasModelLoaded(npc.model) and timeout < 100 do + timeout = timeout + 1 + Wait(100) + end + + if not HasModelLoaded(npc.model) then + return + end + + -- NPC erstellen + npcHandle = CreatePed(4, npc.model, npc.spawn.x, npc.spawn.y, npc.spawn.z, npc.spawn.w, false, true) + if not DoesEntityExist(npcHandle) then + return + end + + -- NPC Eigenschaften setzen + SetEntityAsMissionEntity(npcHandle, true, true) + SetBlockingOfNonTemporaryEvents(npcHandle, true) + SetPedDiesWhenInjured(npcHandle, false) + SetPedCanPlayAmbientAnims(npcHandle, true) + SetPedCanRagdollFromPlayerImpact(npcHandle, false) + SetEntityInvincible(npcHandle, true) + FreezeEntityPosition(npcHandle, true) + + -- Optional: Animation für den NPC + TaskStartScenarioInPlace(npcHandle, "WORLD_HUMAN_GUARD_STAND", 0, true) + + isNPCSpawned = true +end + +-- Funktion zum Entfernen des NPCs +function RemoveGuardNPC() + if DoesEntityExist(npcHandle) then + DeleteEntity(npcHandle) + isNPCSpawned = false + end +end + +-- Hauptthread zum Überprüfen der Spieler-Position +CreateThread(function() + while true do + Wait(0) + local ped = PlayerPedId() + local coords = GetEntityCoords(ped) + + local isInMarker = false + + for k, v in pairs(Config.Zonen) do + local dist = #(coords - vector3(v.NPC.spawn.x, v.NPC.spawn.y, v.NPC.spawn.z)) + local spawnDistance = v.NPC.distance + + if dist <= spawnDistance then + isInMarker = true + CurrentZone = v + end + end + + if isInMarker and not hasAlreadyEnteredMarker then + hasAlreadyEnteredMarker = true + SpawnGuardNPC(CurrentZone.NPC) + AddTargetOptions() + end + + if not isInMarker and hasAlreadyEnteredMarker then + hasAlreadyEnteredMarker = false + CurrentZone = nil + exports['qb-target']:RemoveTargetEntity(npcHandle) + RemoveGuardNPC() + end + end +end) + +function AddTargetOptions() + + local opt = { + { + type = "client", + event = "mh_garage:storeVehicle", + icon = "fas fa-parking", + label = "Fahrzeug einparken", + }, + { + type = "client", + event = "mh_garage:retrieveOwnerVehicle", + icon = "fas fa-car", + label = "Eigene Fahrzeug ausparken", + }, + { + type = "client", + event = "mh_garage:retrieveVehicle", + icon = "key", + label = "Schlüssel Fahrzeug ausparken", + } + } + + if Config.Verwaltung.garage then + table.insert(opt, { + type = "client", + event = "mh_garage:verwaltungVeh", + icon = "hand", + label = "Fahrzeuge Verwalten", + }) + end + + exports['qb-target']:AddTargetEntity(npcHandle, { + options = opt, + distance = 2.5 + }) +end + +function Notification(text, type) + lib.notify({ + title = "Garage - "..CurrentZone.name, + description = text, + type = type, + position = 'top', + }) +end + +---------------------------- NetEvents +RegisterNetEvent('mh_jobgarage:notify') +AddEventHandler('mh_jobgarage:notify', function(title, text, type) + Notification(text, type) +end) + +function GetVehicleDamagePercentage(vehicle) + if not vehicle then return 0 end + + -- Hole die verschiedenen Gesundheitswerte + local engineHealth = GetVehicleEngineHealth(vehicle) + local bodyHealth = GetVehicleBodyHealth(vehicle) + local tankHealth = GetVehiclePetrolTankHealth(vehicle) + + -- Normalisiere die Werte (Standard-Maximalwerte: 1000.0) + local enginePercent = (engineHealth / 1000.0) * 100 + local bodyPercent = (bodyHealth / 1000.0) * 100 + local tankPercent = (tankHealth / 1000.0) * 100 + + -- Berechne Durchschnitt als Gesamtzustand + local totalHealth = (enginePercent + bodyPercent + tankPercent) / 3 + + -- Runde auf ganze Zahlen + return math.floor(totalHealth) +end \ No newline at end of file diff --git a/resources/[Developer]/[Mark]/mh_garage/client/retrieve.lua b/resources/[Developer]/[Mark]/mh_garage/client/retrieve.lua new file mode 100644 index 000000000..595294e6d --- /dev/null +++ b/resources/[Developer]/[Mark]/mh_garage/client/retrieve.lua @@ -0,0 +1,152 @@ +RegisterNetEvent('mh_garage:retrieveOwnerVehicle') +AddEventHandler('mh_garage:retrieveOwnerVehicle', function() + local ped = PlayerPedId() + local coords = GetEntityCoords(ped) + local random = SelectName() + + local opt = {} + + QBCore.Functions.TriggerCallback('mh_garage:retrieveOwnerVehicle', function(cb) + if cb == false then + Notification("Es ist kein Fahrzeug hier!", "inform") + return + end + + for i = 1, #cb, 1 do + local mods = json.decode(cb[i].mods) + table.insert(opt, { + title = cb[i].name, + description = "Kennzeichen: "..cb[i].plate, --[[ \nTankinhalt: "..math.round(mods.fuelLevel, 2).."%" ]] + icon = "car", + onSelect = function() + cb[i].mods = mods + SpawnThisVehicle(cb[i]) + end + }) + end + lib.registerContext({ + id = "retrieveVehicle", + title = random.name, + options = opt + }) + + lib.showContext("retrieveVehicle") + end, CurrentZone.name) +end) + +RegisterNetEvent('mh_garage:retrieveVehicle') +AddEventHandler('mh_garage:retrieveVehicle', function() + local ped = PlayerPedId() + local coords = GetEntityCoords(ped) + local random = SelectName() + + local opt = {} + + QBCore.Functions.TriggerCallback('mh_garage:retrieveKeyVehicle', function(cb) + if cb == false then + Notification("Es ist kein Fahrzeug hier!", "inform") + return + end + + for i = 1, #cb, 1 do + if cb[i].garage ~= "OUT" then + local mods = json.decode(cb[i].mods) + table.insert(opt, { + title = cb[i].name, + description = "Kennzeichen: "..cb[i].plate, --[[ \nTankinhalt: "..math.round(mods.fuelLevel, 2).."%" ]] + icon = "car", + onSelect = function() + cb[i].mods = mods + SpawnThisVehicle(cb[i]) + end + }) + end + end + + lib.registerContext({ + id = "retrieveVehicle", + title = random.name, + options = opt + }) + + lib.showContext("retrieveVehicle") + end, CurrentZone.name) +end) + +function SpawnThisVehicle(vehicle) + local spawnPoint = nil + + -- Freien Spawnpunkt suchen + for _, spot in pairs(CurrentZone.vehicle_spawn) do + if not IsAnyVehicleNearPoint(spot.x, spot.y, spot.z, 3.0) then + spawnPoint = spot + break + end + end + + if spawnPoint then + QBCore.Functions.SpawnVehicle(vehicle.vehicle, function(veh) + -- Fahrzeug ID für Server + local netId = NetworkGetNetworkIdFromEntity(veh) + + -- Grundeinstellungen + SetVehicleNumberPlateText(veh, vehicle.plate) + SetVehicleDoorsLocked(veh, 0) + SetEntityHeading(veh, spawnPoint.w) + + -- Motor aus + SetVehicleEngineOn(veh, false, true, true) + + -- Fahrzeug Eigenschaften + local mods = type(vehicle.mods) == 'string' and json.decode(vehicle.mods) or vehicle.mods + + -- Grundwerte setzen + SetVehicleFuelLevel(veh, mods.fuelLevel) + exports["lc_fuel"]:SetFuel(veh, mods.fuelLevel) + SetVehicleEngineHealth(veh, mods.engineHealth) + SetVehicleBodyHealth(veh, mods.bodyHealth) + SetVehicleDirtLevel(veh, mods.dirtLevel) + + -- Türen Status + if mods.doorStatus then + for doorIndex = 0, 5 do + if mods.doorStatus[tostring(doorIndex)] then + SetVehicleDoorBroken(veh, doorIndex, true) + end + end + end + + -- Fenster Status + if mods.windowStatus then + for windowIndex = 0, 7 do + if not mods.windowStatus[tostring(windowIndex)] then + SmashVehicleWindow(veh, windowIndex) + end + end + end + + -- Alle Mods anwenden + QBCore.Functions.SetVehicleProperties(veh, mods) + + -- Fahrzeug auf den Boden setzen + SetVehicleOnGroundProperly(veh) + + -- Server über gespawntes Fahrzeug informieren + TriggerServerEvent('mh_garage:spawnedVehicle', netId, vehicle.plate) + + -- Optional: Erfolgsmeldung + lib.notify({ + title = "Fahrzeug geparkt...", + description = "Dein Fahrzeug steht auf Parkplatz "..math.random(1, 15), + type = "success" + }) + end, vector3(spawnPoint.x, spawnPoint.y, spawnPoint.z), true) + else + QBCore.Functions.Notify('Alle Parkplätze sind belegt!', 'error') + lib.notify({ + title = "Fahrzeug nicht gefunden", + description = "Alle Parkplätze sind belegt!", + type = "success" + }) + end +end \ No newline at end of file diff --git a/resources/[Developer]/[Mark]/mh_garage/client/stored.lua b/resources/[Developer]/[Mark]/mh_garage/client/stored.lua new file mode 100644 index 000000000..d52641efe --- /dev/null +++ b/resources/[Developer]/[Mark]/mh_garage/client/stored.lua @@ -0,0 +1,131 @@ +RegisterNetEvent('mh_garage:storeVehicle') +AddEventHandler('mh_garage:storeVehicle', function() + local ped = PlayerPedId() + local coords = GetEntityCoords(ped) + local vehicles = GetGamePool('CVehicle') + local random = SelectName() + + local opt = {} + for i = 1, #vehicles, 1 do + local veh_coords = GetEntityCoords(vehicles[i]) + local distance = #(veh_coords - coords) + if distance < 15.0 then + local mods = QBCore.Functions.GetVehicleProperties(vehicles[i]) + local lc_fuelLevel = exports["lc_fuel"]:GetFuel(vehicles[i]) -- Get the fuel level + + mods.fuelLevel = lc_fuelLevel + table.insert(opt, { + title = "Kennzeichen: "..mods.plate, + description = GetRandomCarDescription(), + icon = "car", + onSelect = function() + print(CurrentZone.price) + if CurrentZone.price ~= nil then + lib.hideContext("StoredVehicles") + + lib.registerContext({ + id = "thisVehicle", + title = random.name, + options = { + {title = "Kosten: "..CurrentZone.price.."$"}, + {title = "", disabled = true}, + { + title = "Akzeptieren", + description = "Geld wird vom Bankkonto abgebucht!", + icon = "check", + onSelect = function() + lib.hideContext("thisVehicle") + QBCore.Functions.TriggerCallback('mh_garage:storedVehicle', function(cb) + if cb.status then + TriggerServerEvent('mh_Parking:deleteVehicle', mods.plate, NetworkGetNetworkIdFromEntity(vehicles[i])) + --DeleteVehicle(vehicles[i]) + Notification(cb.text, cb.type, CurrentZone.name) + else + if cb.police and Config.EnabledPolice then + exports["roadphone"]:sendDispatch("Hier hat grade jemand versucht, ein Fahrzeug einzuparken.\nDas Zündschloss sah Beschädigt aus.\nKennzeichen: "..veh.plate, 'police', nil) + end + Notification(cb.text, cb.type) + end + end, mods, CurrentZone) + end + }, + { + title = "Abbrechen", + description = "Das ist sehr Schade,", + icon = "close", + onSelect = function() + lib.hideContext("thisVehicle") + end + } + } + }) + + lib.showContext("thisVehicle") + else + QBCore.Functions.TriggerCallback('mh_garage:storedVehicle', function(cb) + if cb.status then + TriggerServerEvent('mh_Parking:deleteVehicle', mods.plate, NetworkGetNetworkIdFromEntity(vehicles[i])) + --DeleteVehicle(vehicles[i]) + Notification(cb.text, cb.type, CurrentZone.name) + else + if cb.police and Config.EnabledPolice then + exports["roadphone"]:sendDispatch("Hier hat grade jemand versucht, ein Fahrzeug einzuparken.\nDas Zündschloss sah Beschädigt aus.\nKennzeichen: "..veh.plate, 'police', nil) + end + Notification(cb.text, cb.type) + end + end, mods, CurrentZone) + end + end + }) + lib.registerContext({ + id = "StoredVehicles", + title = random.name.."\n\n"..random.description, + options = opt + }) + lib.showContext("StoredVehicles") + end + end +end) + +function SelectName() + local names = { + {name = "Garagen-Guru", + description = "passt auf, dass keiner falsch parkt, Schranken nicht durchdrehen und Autos nicht fliegen!"}, + {name = "Torflüsterer", + description = "Redet Schranken gut zu wenn diese wieder nicht funktionieren."}, + {name = "Parkplatz-Papst", + description = "segnet jedes Auto, das diese heilige Halle betritt. Kein Ölverlust ohne dein Amen!"}, + {name = "Schranken-Schamane", + description = "Elektronik und Technik? Kein Problem! Ich kontrolliere den Strom der Schranken mit reiner Willenskraft und Kabelbinder!"}, + {name = "Chef vom Schuppen", + description = "Wer falsch parkt, kriegt nicht den Abschleppdienst, sondern eine Ansprache. Kurz. Hart. Legendär!"} + } + + return names[math.random(1, #names)] +end + +function GetRandomCarDescription() + local descriptions = { + "Das Auto für alle, die beim Beschleunigen mehr Spaß haben als beim Ankommen.", + "Wenn du ein Auto suchst, das schneller fährt als dein WiFi, bist du hier richtig.", + "Nicht das schnellste Auto, aber hey, es hat vier Räder und eine Hupe!", + "Das einzig wahre Fahren – keine GPS-Fehler, nur pure Straßenmagie.", + "Mit diesem Auto wirst du die Straße genauso lieben wie das Benzin in deinem Tank.", + "Fahr‘ einfach, und schau, wie viele Leute sich fragen, ob du gerade von der Rennstrecke kommst.", + "Dieses Auto bringt mehr Nervenkitzel als ein Achterbahn-Abenteuer!", + "Dieses Fahrzeug hat mehr Charakter als deine letzte Beziehung.", + "Es ist nicht das teuerste Auto, aber es fährt immer noch besser als deine Laune nach dem Montagmorgen!", + "Mit diesem Wagen wirst du zur Legende – oder zumindest zum König des Parkhauses.", + "Schneller als dein Chef’s Auto, langsamer als dein Instagram-Feed.", + "Wenn der Sound des Motors dich mehr motiviert als dein Wecker am Morgen!", + "Sicheres Fahren ist wichtig. Aber Spaß haben – das ist die wahre Kunst!", + "Nicht der neueste Sportwagen, aber dafür ein echter Klassiker auf der Straße.", + "Weniger PS als dein Laptop, aber hey, er fährt!" + } + + -- Zufällige Beschreibung auswählen + local randomIndex = math.random(1, #descriptions) + + -- Beschreibung zurückgeben + return descriptions[randomIndex] +end \ No newline at end of file diff --git a/resources/[Developer]/[Mark]/mh_garage/client/verwaltung.lua b/resources/[Developer]/[Mark]/mh_garage/client/verwaltung.lua new file mode 100644 index 000000000..844485fd5 --- /dev/null +++ b/resources/[Developer]/[Mark]/mh_garage/client/verwaltung.lua @@ -0,0 +1,76 @@ +RegisterNetEvent('mh_garage:verwaltungVeh') +AddEventHandler('mh_garage:verwaltungVeh', function() + QBCore.TriggerCallback('mh_garage:verwaltung', function(cb) + Debug("Verwaltung CB: "..json.encode(cb)) + if cb[1] ~= nil then + local opt = {} + + for i = 1, #cb, 1 do + + local isingarage = cb[i].current_in_garage + local des = "" + + if isingarage then + des = "Bearbeite das Fahrzeug\nKennzeichen: "..cb[i].current_plate.."\nGarage: "..cb[i].current_garage + else + des = "Bearbeite das Fahrzeug\nKennzeichen: "..cb[i].current_plate.."\nLetzte bekannte Garage: "..cb[i].current_garage + end + + table.insert(opt, { + title = cb[i].current_name, + description = des, + icon = "car", + onSelect = function() + OpenVerwaltung(cb[i]) + end + }) + end + else + lib.notify({ + title = "Fahrzeug Verwaltung", + description = "Du bist nicht im Besitz eines Fahrzeuges!", + type = "inform" + }) + end + end) +end) + +function OpenVerwaltung(vehicleInfos) + Debug("OpenVerwaltung: "..json.encode(vehicleInfos)) + local garages = {} + for k, v in pairs(Config.Zonen) do + table.insert(garages, v.name) + end + lib.registerMenu({ + id = 'some_menu_id', + title = 'Menu title', + position = 'top-right', + onSideScroll = function(selected, scrollIndex, args) + print("Scroll: ", selected, scrollIndex, args) + end, + onSelected = function(selected, secondary, args) + if not secondary then + print("Normal button") + else + if args.isCheck then + print("Check button") + end + + if args.isScroll then + print("Scroll button") + end + end + print(selected, secondary, json.encode(args, {indent=true})) + end, + options = { + {label = "Name ändern", icon = "paper"}, + {label = 'Transport to:', icon = 'arrows-up-down-left-right', values=garages}, + } + }, function(selected, scrollIndex, args) + print(selected, scrollIndex, args) + end) + + RegisterCommand('testmenu', function() + lib.showMenu('some_menu_id') + end) +end \ No newline at end of file diff --git a/resources/[Developer]/[Mark]/mh_garage/config/config.lua b/resources/[Developer]/[Mark]/mh_garage/config/config.lua new file mode 100644 index 000000000..44733be36 --- /dev/null +++ b/resources/[Developer]/[Mark]/mh_garage/config/config.lua @@ -0,0 +1,162 @@ +Config = {} + +Config.Debug = true + +Config.PriceModel = false + +Config.CallKeyVehicles = true + +Config.Verwaltung = { + garage = false, + garage_change = 1000, -- Kosten um das Fahrzeug in einer anderen Garage zu versetzen. + garage_time = 10, -- Zeit in Minuten bis das Fahrzeug in der neuen Garage ist! + + repair = false, + repair_car = 600, -- Kosten wenn das Fahrzeug Repariert werden soll + repair_time = 10, --Zeit in Minuten bis das Fahrzeug Repariert ist! + + tank = false, + tank_car = 300, -- Kosten wenn das Fahrzeug getankt werden soll + tank_time = 3, -- Zeit in Minuten bis das Fahrzeug voll getankt ist +} + +Config.Zonen = { + { + name = "pillboxgarage", + price = nil, --pro FZ + NPC = { + spawn = vector4(213.9830, -808.7876, 30.0149, 166.4462), + model = "s_m_m_security_01", + distance = 30.0 + }, + vehicle_spawn = { + vector4(216.0978, -804.5941, 29.7967, 61.7316), + vector4(216.4074, -801.9208, 29.7928, 63.4452), + vector4(217.3208, -799.2861, 29.7802, 67.0612), + vector4(218.2428, -796.9962, 29.7684, 86.0924) + } + }, + { + name = "grovegarage", + price = nil, --pro FZ + NPC = { + spawn = vector4(-74.8718, -1824.8325, 25.9420, 249.5276), + model = "G_F_Y_Families_01", + distance = 30.0 + }, + vehicle_spawn = { + vector4(-62.5727, -1840.5316, 25.6792, 321.5169), + vector4(-60.1089, -1842.8113, 25.5816, 323.8478), + vector4(-60.1089, -1842.8113, 25.5816, 323.8478), + vector4(-54.8264, -1847.2078, 25.3799, 317.6915) + } + }, + { + name = "vespuccigarage", + price = nil, --pro FZ + NPC = { + spawn = vector4(-1184.6665, -1509.8247, 3.6493, 312.6639), + model = "s_m_m_security_01", + distance = 30.0 + }, + vehicle_spawn = { + vector4(-1191.6841, -1504.4095, 3.3688, 303.5921), + vector4(-1194.9706, -1500.1947, 3.3634, 310.3644), + vector4(-1196.7946, -1496.9948, 3.3652, 303.5580), + vector4(-1198.0444, -1493.9160, 3.3705, 311.4306) + } + }, + { + name = "vinewoodgarage", + price = nil, --pro FZ + NPC = { + spawn = vector4(-340.6176, 266.3422, 84.6795, 22.1944), + model = "s_m_m_security_01", + distance = 30.0 + }, + vehicle_spawn = { + vector4(-349.4257, 272.3725, 83.1077, 277.4619), + vector4(-349.8885, 276.0246, 83.9945, 276.0025), + vector4(-349.4035, 279.3595, 83.9495, 275.8749), + vector4(-349.3278, 282.7364, 83.9431, 278.1651) + } + }, + { + name = "sandygarage", + price = nil, --pro FZ + NPC = { + spawn = vector4(1974.4922, 3766.7776, 31.4449, 207.1671), + model = "s_m_m_security_01", + distance = 30.0 + }, + vehicle_spawn = { + vector4(1976.9423, 3776.3718, 31.1820, 202.0667), + vector4(1978.5798, 3779.2981, 31.1810, 207.7097), + vector4(1981.8478, 3783.0405, 31.1808, 213.8446), + + } + }, + { + name = "paletogarage", + price = nil, --pro FZ + NPC = { + spawn = vector4(67.5230, 6412.9517, 30.4838, 230.1375), + model = "s_m_m_security_01", + distance = 30.0 + }, + vehicle_spawn = { + vector4(64.5739, 6406.8584, 30.2258, 208.3274), + vector4(61.9570, 6404.0493, 30.2258, 202.9158), + vector4(59.0419, 6401.0122, 30.2258, 211.3612), + vector4(73.0162, 6404.4741, 30.2258, 131.4993) + } + }, + + { + name = "eastsidegarage", + price = nil, --pro FZ + NPC = { + spawn = vector4(1010.1598, -2289.5979, 29.5095, 186.2906), + model = "s_m_m_security_01", + distance = 30.0 + }, + vehicle_spawn = { + vector4(1003.6630, -2299.5208, 29.5095, 266.1712), + vector4(1005.3187, -2304.5198, 29.5095, 261.7787), + vector4(1005.2725, -2308.4385, 29.5095, 277.7379), + vector4(1004.2752, -2313.1870, 29.5095, 268.2005) + } + }, + + { + name = "cayogarage", + price = nil, --pro FZ + NPC = { + spawn = vector4(4505.5659, -4549.3335, 3.0960, 69.6222), + model = "IG_JuanStrickler", + distance = 30.0 + }, + vehicle_spawn = { + vector4(4501.0264, -4546.2852, 3.0278, 24.5729), + vector4(4497.0498, -4536.6616, 3.1636, 276.0185), + } + }, + + +} + +Config.Log = { + Webhook = "https://discord.com/api/webhooks/1366812966049288192/9ZjJC9_gLX6Fk-acf0YSW_haGWpCqG9zRGWaj0wCKLZefp8FX-GwNZBP77H6K93KfIw3", + Color = { + green = 56108, + grey = 8421504, + red = 16711680, + orange = 16744192, + blue = 2061822, + purple = 11750815, + }, + + SystemName = "Evolution_State_life Log [Garage]", + UserAvatar = '', + SystemAvatar = '', +} \ No newline at end of file diff --git a/resources/[Developer]/[Mark]/mh_garage/config/price.lua b/resources/[Developer]/[Mark]/mh_garage/config/price.lua new file mode 100644 index 000000000..1ad11e0dc --- /dev/null +++ b/resources/[Developer]/[Mark]/mh_garage/config/price.lua @@ -0,0 +1,3 @@ +cprice = { + ["asea"] = 3, +} \ No newline at end of file diff --git a/resources/[Developer]/[Mark]/mh_garage/fxmanifest.lua b/resources/[Developer]/[Mark]/mh_garage/fxmanifest.lua new file mode 100644 index 000000000..704c4f1ef --- /dev/null +++ b/resources/[Developer]/[Mark]/mh_garage/fxmanifest.lua @@ -0,0 +1,17 @@ +author 'Mîhó' + +fx_version 'adamant' +game 'gta5' +lua54 'yes' + +client_scripts { + '@ox_lib/init.lua', + 'config/*.lua', + 'client/*.lua' +} + +server_scripts { + '@oxmysql/lib/MySQL.lua', + 'config/*.lua', + 'server/*.lua' +} \ No newline at end of file diff --git a/resources/[Developer]/[Mark]/mh_garage/server/log.lua b/resources/[Developer]/[Mark]/mh_garage/server/log.lua new file mode 100644 index 000000000..177bbd5d2 --- /dev/null +++ b/resources/[Developer]/[Mark]/mh_garage/server/log.lua @@ -0,0 +1,59 @@ +function sendToDiscord(Titel, Text, Color) ------ Sende Nachricht an Channel: Join/Left + local embeds = { + { + ["title"]=Text, + ["type"]="rich", + ["color"] =Config.Log.Color[Color], + ["footer"]= { + ["text"]= Config.Log.SystemName, + }, + } + } + + PerformHttpRequest(Config.Log.Webhook, function(err, text, headers) + if err and err ~= 204 and err ~= 200 then + print("Fehler beim Discord Webhook [" .. tostring(err) .. "]: " .. tostring(text)) + end + end, 'POST', json.encode({ username = Titel.." - Mîhó",avatar_url = Config.SystemAvatar, embeds = embeds, tts = TTS}), { ['Content-Type'] = 'application/json' }) +end + +AddEventHandler('mh_garage:log') +RegisterServerEvent('mh_garage:log', function(type) + local Player = QBCore.Functions.GetPlayer(source) + local PlyData = Player.PlayerData + local Color = "purple" + + Playerinfo = { + name = PlyData.charinfo.firstname .. " ".. PlyData.charinfo.lastname, + citizenid = PlyData.citizenid, + } + local user = Playerinfo.name.."[".. Playerinfo.citizenid .."]" + + if type == "call" then + Text = "Dr. Teddy wurde von " .. user .." gerufen." + Color = "grey" + elseif type == "cash" then + Text = user.." hat Bar Bezahlt." + Color = "green" + elseif type == "bank" then + Text = user .. "hat via Überweisung Bezahlt." + Color = "green" + elseif type == "noMoney" then + Text = user .." Hatte nicht genug Geld." + Color = "orange" + elseif type == "noPlayer" then + Text = user .. " Wurde nicht gefunden und abgebrochen!" + Color = "red" + elseif type == "storno" then + Text = user .. " Hat die Behandlung doch Abgelehnt." + Color = "red" + elseif type == "heal" then + Text = user.. " Wurde Geheilt." + Color = "green" + elseif type == "end" then + Text = "NPC wurde wieder Entfernt..." + Color = "blue" + end + + sendToDiscord("Garage", Text, Color) +end) \ No newline at end of file diff --git a/resources/[Developer]/[Mark]/mh_garage/server/server.lua b/resources/[Developer]/[Mark]/mh_garage/server/server.lua new file mode 100644 index 000000000..5b0fe9bf2 --- /dev/null +++ b/resources/[Developer]/[Mark]/mh_garage/server/server.lua @@ -0,0 +1,159 @@ +QBCore = exports['qb-core']:GetCoreObject() +local test_vari = {} + +RegisterServerEvent('mh_garage:setMods') +AddEventHandler('mh_garage:setMods', function(mods) + if test_vari[mods.plate] == true then + return + else + MySQL.query("SELECT mods FROM player_vehicles WHERE plate = ?", {mods.plate}, function(rs) + -- Prüfen ob rs überhaupt Daten enthält + if rs and rs[1] then + -- Wenn mods ein String ist, konvertieren wir es zu einem Table + local modsData = type(rs[1].mods) == "string" and json.decode(rs[1].mods) or rs[1].mods + + if not modsData or next(modsData) == nil then + -- Hier sollten Sie wahrscheinlich auch die mods-Daten übergeben, nicht nur plate + MySQL.query("UPDATE player_vehicles SET mods = ? WHERE plate = ?", {json.encode(mods), mods.plate}) + test_vari[mods.plate] = true + else + test_vari[mods.plate] = true + end + end + end) + end +end) + +QBCore.Functions.CreateCallback('mh_garage:storedVehicle', function(source, cb, veh, zone) + local Player = QBCore.Functions.GetPlayer(source) + + if Player ~= nil then + if Player.Functions.GetMoney('bank', zone.price) then + MySQL.query("SELECT * FROM player_vehicles WHERE citizenid = ? AND plate = ?", {Player.PlayerData.citizenid, veh.plate}, function(rs) + if rs[1] ~= nil then + MySQL.query("UPDATE player_vehicles SET garage = ?, mods = ? WHERE plate = ?", {zone.name, json.encode(veh), veh.plate}) + DelVehParking(veh.plate) + cb({ + status = true, + text = "Fahrzeug erfolgreich eingeparkt!", + type = "success", + other = false, + police = false + }) + else + MySQL.query("SELECT * FROM vehicle_keys WHERE owner = ? AND plate = ?", {Player.PlayerData.citizenid, veh.plate}, function(rs) + if rs[1] ~= nil then + MySQL.query("UPDATE player_vehicles SET garage = ?, mods = ? WHERE plate = ?", {zone.name, json.encode(veh), veh.plate}) + --TriggerEvent('mh_Parking:removeVehicle', source, veh.plate) + --DelVehParking(veh.plate) + cb({ + status = true, + text = "Fahrzeug erfolgreich eingeparkt!", + type = "success", + other = true, + police = false + }) + else + cb({ + status = false, + text = "Du besitzt kein Schlüssel für dieses Fahrzeug.", + type = "warning", + other = false, + police = true + }) + end + end) + end + end) + end + end +end) + +function DelVehParking(plate) + MySQL.query("SELECT * FROM vehicle_parking WHERE plate = ?", {plate}, function(rs) + if rs[1] ~= nil then + MySQL.query("DELETE FROM vehicle_parking WHERE plate = ?", {plate}) + end + end) +end + +QBCore.Functions.CreateCallback('mh_garage:retrieveOwnerVehicle', function(source, cb, zone) + local _source = source + local Player = QBCore.Functions.GetPlayer(_source) + local pedid = Player.PlayerData.citizenid + local veh = {} + + MySQL.query("SELECT * FROM player_vehicles WHERE citizenid = ? and garage = ?", {pedid, zone}, function(rs) + if rs ~= nil and rs[1] ~= nil then + for k, v in pairs (rs) do + table.insert(veh, { + vehicle = v.vehicle, + mods = v.mods, + plate = v.plate, + name = v.name + }) + end + Wait(100) + cb(veh) + else + cb(false) + end + end) +end) + +QBCore.Functions.CreateCallback('mh_garage:retrieveKeyVehicle', function(source, cb, zone) + local _source = source + local Player = QBCore.Functions.GetPlayer(_source) + local pedid = Player.PlayerData.citizenid + local veh = {} + + MySQL.query("SELECT pv.* FROM player_vehicles pv JOIN vehicle_keys vk ON pv.plate = vk.plate WHERE vk.owner = ? AND vk.count > 0 AND pv.garage = ?", {pedid, zone}, function(vehicles) + if vehicles and #vehicles > 0 then + for _, vehicle in pairs(vehicles) do + table.insert(veh, { + vehicle = vehicle.vehicle, + mods = vehicle.mods, + plate = vehicle.plate, + name = vehicle.name + }) + end + Wait(100) + cb(veh) + else + cb(false) + end +end) +end) + +QBCore.Functions.CreateCallback('mh_garage:verwaltung', function(source, cb) + local Player = QBCore.Functions.GetPlayer(source) + local vehicles = {} + MySQL.query("SELECT * FROM player_vehicles WHERE citizenid = ?", {Player.PlayerData.citizenid}, function(rs) + if rs and rs[1] then + for k, v in pairs(rs) do + table.insert(vehicles, { + current_garage = v.garage, + current_in_garage = v.parking, + current_name = v.name, + current_plate = v.plate, + }) + end + end + end) + return vehicles +end) + +RegisterServerEvent('mh_garage:spawnedVehicle') +AddEventHandler('mh_garage:spawnedVehicle', function(netID, plate) + MySQL.query("UPDATE player_vehicles SET garage = ? WHERE plate = ?", {"OUT", plate}) +end) + +QBCore.Functions.CreateCallback('mh_garage:CheckownerVehicles', function(source, cb, plate) + MySQL.query("SELECT * FROM player_vehicles WHERE plate = ?", {plate}, function(rs) + if rs ~= nil and rs[1] ~= nil then + cb(true) + else + cb(false) + end + end) +end) \ No newline at end of file