diff --git a/resources/[inventory]/nordi_vending/client.lua b/resources/[inventory]/nordi_vending/client.lua index ee0d582e2..e3aafdc14 100644 --- a/resources/[inventory]/nordi_vending/client.lua +++ b/resources/[inventory]/nordi_vending/client.lua @@ -26,52 +26,52 @@ function DrawText3D(x, y, z, text) ClearDrawOrigin() end --- Get machine data with proper callback handling +-- Get machine data with optimized callback handling function GetMachineData(entity) local coords = GetEntityCoords(entity) local entityId = tostring(coords.x) .. tostring(coords.y) .. tostring(coords.z) - -- Check if we need to refresh the data + -- Return cached data if available and not expired local currentTime = GetGameTimer() - if not machineData[entityId] or (currentTime - machineData[entityId].lastCheck > 10000) then - -- Initialize with default values + if machineData[entityId] and (currentTime - machineData[entityId].lastCheck < 10000) then + return machineData[entityId] + end + + -- Initialize with default values + if not machineData[entityId] then machineData[entityId] = { isRegistered = false, canManage = false, lastCheck = currentTime, checking = true } - - -- Check if machine is registered - QBCore.Functions.TriggerCallback('vending:server:machineExists', function(exists) - if exists then - machineData[entityId].isRegistered = true - - -- Only check management if registered - QBCore.Functions.TriggerCallback('vending:server:canManage', function(result) - machineData[entityId].canManage = result - machineData[entityId].checking = false - end, coords) - else - machineData[entityId].isRegistered = false - machineData[entityId].canManage = false - machineData[entityId].checking = false - end - end, coords) + else + machineData[entityId].checking = true + machineData[entityId].lastCheck = currentTime end - -- Wait for callbacks to complete if currently checking - if machineData[entityId].checking then - local timeout = 0 - while machineData[entityId].checking and timeout < 50 do - Wait(10) - timeout = timeout + 1 - end - - -- If timeout reached, set checking to false to avoid deadlock - if timeout >= 50 then - machineData[entityId].checking = false + -- Single callback to get all machine data at once (more efficient) + QBCore.Functions.TriggerCallback('vending:server:getMachineStatus', function(status) + if status then + machineData[entityId].isRegistered = status.exists + machineData[entityId].canManage = status.canManage + else + machineData[entityId].isRegistered = false + machineData[entityId].canManage = false end + machineData[entityId].checking = false + end, coords) + + -- Short wait for callback to complete + local timeout = 0 + while machineData[entityId].checking and timeout < 20 do -- Reduced timeout + Wait(5) -- Shorter wait + timeout = timeout + 1 + end + + -- If timeout reached, set checking to false to avoid deadlock + if timeout >= 20 then + machineData[entityId].checking = false end return machineData[entityId] @@ -229,49 +229,48 @@ RegisterNetEvent('vending:client:openBuyMenu', function(data) local entity = data.entity local coords = GetEntityCoords(entity) - -- Double-check if machine is registered before proceeding - QBCore.Functions.TriggerCallback('vending:server:machineExists', function(exists) - if not exists then - QBCore.Functions.Notify('Dieser Automat ist nicht registriert!', 'error') + -- Fast check using cached data + local entityId = tostring(coords.x) .. tostring(coords.y) .. tostring(coords.z) + if machineData[entityId] and not machineData[entityId].isRegistered then + QBCore.Functions.Notify('Dieser Automat ist nicht registriert!', 'error') + return + end + + QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items) + if #items == 0 then + QBCore.Functions.Notify('Dieser Automat ist leer!', 'error') return end - QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items) - if #items == 0 then - QBCore.Functions.Notify('Dieser Automat ist leer!', 'error') - return + local options = {} + + for i = 1, #items do + local item = items[i] + if item.amount > 0 then + local itemLabel = QBCore.Shared.Items[item.name] and QBCore.Shared.Items[item.name].label or item.name + table.insert(options, { + title = itemLabel, + description = 'Preis: $' .. item.price .. ' | Verfügbar: ' .. item.amount, + icon = 'fas fa-shopping-cart', + onSelect = function() + openQuantityDialog(coords, item.name, item.price, item.amount, itemLabel) + end + }) end - - local options = {} - - for i = 1, #items do - local item = items[i] - if item.amount > 0 then - local itemLabel = QBCore.Shared.Items[item.name] and QBCore.Shared.Items[item.name].label or item.name - table.insert(options, { - title = itemLabel, - description = 'Preis: $' .. item.price .. ' | Verfügbar: ' .. item.amount, - icon = 'fas fa-shopping-cart', - onSelect = function() - openQuantityDialog(coords, item.name, item.price, item.amount, itemLabel) - end - }) - end - end - - if #options == 0 then - QBCore.Functions.Notify('Keine Artikel verfügbar!', 'error') - return - end - - lib.registerContext({ - id = 'vending_buy_menu', - title = 'Verkaufsautomat', - options = options - }) - - lib.showContext('vending_buy_menu') - end, coords) + end + + if #options == 0 then + QBCore.Functions.Notify('Keine Artikel verfügbar!', 'error') + return + end + + lib.registerContext({ + id = 'vending_buy_menu', + title = 'Verkaufsautomat', + options = options + }) + + lib.showContext('vending_buy_menu') end, coords) end) @@ -304,84 +303,83 @@ RegisterNetEvent('vending:client:openOwnerMenu', function(data) local entity = data.entity local coords = GetEntityCoords(entity) - -- Double-check if player can manage this machine before proceeding - QBCore.Functions.TriggerCallback('vending:server:canManage', function(canManage) - if not canManage then - QBCore.Functions.Notify('Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') + -- Fast check using cached data + local entityId = tostring(coords.x) .. tostring(coords.y) .. tostring(coords.z) + if machineData[entityId] and not machineData[entityId].canManage then + QBCore.Functions.Notify('Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') + return + end + + QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine) + if not machine then + QBCore.Functions.Notify('Automat nicht gefunden!', 'error') return end - QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine) - if not machine then - QBCore.Functions.Notify('Automat nicht gefunden!', 'error') - return - end - - local options = { - { - title = 'Inventar verwalten', - description = 'Items hinzufügen/entfernen', - icon = 'fas fa-box', - onSelect = function() - TriggerServerEvent('vending:server:openStash', coords) - end - }, - { - title = 'Preise festlegen', - description = 'Verkaufspreise für Items setzen', - icon = 'fas fa-tags', - onSelect = function() - openPriceMenu(coords) - end - }, - { - title = 'Geld abheben', - description = 'Verfügbar: $' .. machine.money, - icon = 'fas fa-money-bill', - onSelect = function() - openWithdrawMenu(coords, machine.money) - end - }, - { - title = 'Statistiken', - description = 'Verkaufsstatistiken anzeigen', - icon = 'fas fa-chart-bar', - onSelect = function() - openStatsMenu(machine) - end - } + local options = { + { + title = 'Inventar verwalten', + description = 'Items hinzufügen/entfernen', + icon = 'fas fa-box', + onSelect = function() + TriggerServerEvent('vending:server:openStash', coords) + end + }, + { + title = 'Preise festlegen', + description = 'Verkaufspreise für Items setzen', + icon = 'fas fa-tags', + onSelect = function() + openPriceMenu(coords) + end + }, + { + title = 'Geld abheben', + description = 'Verfügbar: $' .. machine.money, + icon = 'fas fa-money-bill', + onSelect = function() + openWithdrawMenu(coords, machine.money) + end + }, + { + title = 'Statistiken', + description = 'Verkaufsstatistiken anzeigen', + icon = 'fas fa-chart-bar', + onSelect = function() + openStatsMenu(machine) + end } - - -- Add manager options only for owner - if machine.isOwner then - table.insert(options, { - title = 'Verwalter', - description = 'Verwalter hinzufügen/entfernen', - icon = 'fas fa-users-cog', - onSelect = function() - openManagersMenu(coords) - end - }) - - -- Add sell option only for owner - table.insert(options, { - title = 'Automaten verkaufen', - description = 'Verkaufe den Automaten für ' .. math.floor(Config.VendingMachinePrice * Config.SellBackPercentage / 100) .. '$', - icon = 'fas fa-dollar-sign', - onSelect = function() - sellVendingMachine(coords, machine.id) - end - }) - end - - lib.registerContext({ - id = 'vending_owner_menu', - title = 'Verkaufsautomat Verwaltung', - options = options + } + + -- Add manager options only for owner + if machine.isOwner then + table.insert(options, { + title = 'Verwalter', + description = 'Verwalter hinzufügen/entfernen', + icon = 'fas fa-users-cog', + onSelect = function() + openManagersMenu(coords) + end }) - lib.showContext('vending_owner_menu') - end, coords) + -- Add sell option only for owner + table.insert(options, { + title = 'Automaten verkaufen', + description = 'Verkaufe den Automaten für ' .. math.floor(Config.VendingMachinePrice * Config.SellBackPercentage / 100) .. '$', + icon = 'fas fa-dollar-sign', + onSelect = function() + sellVendingMachine(coords, machine.id) + end + }) + end + + lib.registerContext({ + id = 'vending_owner_menu', + title = 'Verkaufsautomat Verwaltung', + options = options + }) + + lib.showContext('vending_owner_menu') end, coords) end) @@ -406,43 +404,42 @@ end -- Open price menu function openPriceMenu(coords) - -- Double-check if player can manage this machine before proceeding - QBCore.Functions.TriggerCallback('vending:server:canManage', function(canManage) - if not canManage then - QBCore.Functions.Notify('Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') + -- Fast check using cached data + local entityId = tostring(coords.x) .. tostring(coords.y) .. tostring(coords.z) + if machineData[entityId] and not machineData[entityId].canManage then + QBCore.Functions.Notify('Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') + return + end + + QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items) + if #items == 0 then + QBCore.Functions.Notify('Keine Items im Automaten!', 'error') return end - QBCore.Functions.TriggerCallback('vending:server:getStashItems', function(items) - if #items == 0 then - QBCore.Functions.Notify('Keine Items im Automaten!', 'error') - return - end - - local options = {} - - for i = 1, #items do - local item = items[i] - local itemLabel = QBCore.Shared.Items[item.name] and QBCore.Shared.Items[item.name].label or item.name - table.insert(options, { - title = itemLabel, - description = 'Aktueller Preis: $' .. item.price, - icon = 'fas fa-tag', - onSelect = function() - setPriceForItem(coords, item.name, itemLabel) - end - }) - end - - lib.registerContext({ - id = 'vending_price_menu', - title = 'Preise festlegen', - menu = 'vending_owner_menu', - options = options + local options = {} + + for i = 1, #items do + local item = items[i] + local itemLabel = QBCore.Shared.Items[item.name] and QBCore.Shared.Items[item.name].label or item.name + table.insert(options, { + title = itemLabel, + description = 'Aktueller Preis: $' .. item.price, + icon = 'fas fa-tag', + onSelect = function() + setPriceForItem(coords, item.name, itemLabel) + end }) - - lib.showContext('vending_price_menu') - end, coords) + end + + lib.registerContext({ + id = 'vending_price_menu', + title = 'Preise festlegen', + menu = 'vending_owner_menu', + options = options + }) + + lib.showContext('vending_price_menu') end, coords) end @@ -466,33 +463,32 @@ end -- Open withdraw menu function openWithdrawMenu(coords, availableMoney) - -- Double-check if player can manage this machine before proceeding - QBCore.Functions.TriggerCallback('vending:server:canManage', function(canManage) - if not canManage then - QBCore.Functions.Notify('Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') - return - end - - if availableMoney <= 0 then - QBCore.Functions.Notify('Kein Geld im Automaten!', 'error') - return - end - - local input = lib.inputDialog('Geld abheben', { - { - type = 'number', - label = 'Betrag (Verfügbar: $' .. availableMoney .. ')', - description = 'Wie viel möchtest du abheben?', - required = true, - min = 1, - max = availableMoney - } - }) - - if input and input[1] then - TriggerServerEvent('vending:server:withdrawMoney', coords, tonumber(input[1])) - end - end, coords) + -- Fast check using cached data + local entityId = tostring(coords.x) .. tostring(coords.y) .. tostring(coords.z) + if machineData[entityId] and not machineData[entityId].canManage then + QBCore.Functions.Notify('Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') + return + end + + if availableMoney <= 0 then + QBCore.Functions.Notify('Kein Geld im Automaten!', 'error') + return + end + + local input = lib.inputDialog('Geld abheben', { + { + type = 'number', + label = 'Betrag (Verfügbar: $' .. availableMoney .. ')', + description = 'Wie viel möchtest du abheben?', + required = true, + min = 1, + max = availableMoney + } + }) + + if input and input[1] then + TriggerServerEvent('vending:server:withdrawMoney', coords, tonumber(input[1])) + end end -- Open stats menu @@ -525,7 +521,7 @@ end -- Open managers menu function openManagersMenu(coords) - -- Double-check if player is owner of this machine before proceeding + -- Fast check for owner status QBCore.Functions.TriggerCallback('vending:server:isOwner', function(isOwner) if not isOwner then QBCore.Functions.Notify('Nur der Besitzer kann Verwalter verwalten!', 'error') @@ -598,7 +594,7 @@ end -- Open add manager menu function openAddManagerMenu(coords) - -- Double-check if player is owner of this machine before proceeding + -- Fast check for owner status QBCore.Functions.TriggerCallback('vending:server:isOwner', function(isOwner) if not isOwner then QBCore.Functions.Notify('Nur der Besitzer kann Verwalter hinzufügen!', 'error') @@ -644,42 +640,39 @@ RegisterNetEvent('vending:client:startRobbery', function(data) local entity = data.entity local coords = GetEntityCoords(entity) - -- Double-check if machine is registered and player cannot manage it - QBCore.Functions.TriggerCallback('vending:server:machineExists', function(exists) - if not exists then + -- Fast check using cached data + local entityId = tostring(coords.x) .. tostring(coords.y) .. tostring(coords.z) + if machineData[entityId] then + if not machineData[entityId].isRegistered then QBCore.Functions.Notify('Dieser Automat ist nicht registriert!', 'error') return + elseif machineData[entityId].canManage then + QBCore.Functions.Notify('Du kannst deinen eigenen Automaten nicht aufbrechen!', 'error') + return end - - QBCore.Functions.TriggerCallback('vending:server:canManage', function(canManage) - if canManage then - QBCore.Functions.Notify('Du kannst deinen eigenen Automaten nicht aufbrechen!', 'error') - return - end - - lib.registerContext({ - id = 'vending_robbery_confirm', - title = 'Verkaufsautomat aufbrechen', - options = { - { - title = 'Aufbrechen', - description = 'Versuche den Automaten aufzubrechen', - icon = 'fas fa-mask', - onSelect = function() - TriggerServerEvent('vending:server:startRobbery', coords) - end - }, - { - title = 'Abbrechen', - description = 'Aufbruch abbrechen', - icon = 'fas fa-times' - } - } - }) - - lib.showContext('vending_robbery_confirm') - end, coords) - end, coords) + end + + lib.registerContext({ + id = 'vending_robbery_confirm', + title = 'Verkaufsautomat aufbrechen', + options = { + { + title = 'Aufbrechen', + description = 'Versuche den Automaten aufzubrechen', + icon = 'fas fa-mask', + onSelect = function() + TriggerServerEvent('vending:server:startRobbery', coords) + end + }, + { + title = 'Abbrechen', + description = 'Aufbruch abbrechen', + icon = 'fas fa-times' + } + } + }) + + lib.showContext('vending_robbery_confirm') end) -- Start robbery animation and progress @@ -747,7 +740,7 @@ end) -- Management menu (alternative opening method) RegisterNetEvent('vending:client:openManagement', function(machine) - -- Double-check if player can manage this machine + -- Fast check for management permissions QBCore.Functions.TriggerCallback('vending:server:canManage', function(canManage) if not canManage then QBCore.Functions.Notify('Du hast keine Berechtigung diesen Automaten zu verwalten!', 'error') @@ -871,4 +864,3 @@ AddEventHandler('onResourceStop', function(resourceName) -- Nothing to do here, but good to have for completeness end end) - diff --git a/resources/[inventory]/nordi_vending/server.lua b/resources/[inventory]/nordi_vending/server.lua index 9e877da76..f3c861eee 100644 --- a/resources/[inventory]/nordi_vending/server.lua +++ b/resources/[inventory]/nordi_vending/server.lua @@ -712,4 +712,39 @@ QBCore.Commands.Add('vendingdebug', 'Debug vending machines (Admin Only)', {}, f end end, 'admin') +-- Combined callback for faster machine status checks +QBCore.Functions.CreateCallback('vending:server:getMachineStatus', function(source, cb, coords) + local src = source + local Player = QBCore.Functions.GetPlayer(src) + if not Player then + cb(nil) + return + end + + local machineId = getMachineIdByCoords(coords) + if not machineId then + cb({exists = false, canManage = false}) + return + end + + local machine = vendingMachines[machineId] + local canManage = false + + -- Check if player is owner + if machine.owner == Player.PlayerData.citizenid then + canManage = true + else + -- Check if player is manager + if machine.managers then + for _, manager in pairs(machine.managers) do + if manager == Player.PlayerData.citizenid then + canManage = true + break + end + end + end + end + + cb({exists = true, canManage = canManage}) +end)