diff --git a/resources/[inventory]/nordi_vending/client.lua b/resources/[inventory]/nordi_vending/client.lua index acabc33d3..2debe6cf5 100644 --- a/resources/[inventory]/nordi_vending/client.lua +++ b/resources/[inventory]/nordi_vending/client.lua @@ -1,122 +1,36 @@ local QBCore = exports['qb-core']:GetCoreObject() -local machineCache = {} -- Cache für registrierte Maschinen -local ownerCache = {} -- Cache für Besitzer -- Add targets to all vending machine props CreateThread(function() - Wait(2000) -- Wait for everything to load - refreshTargets() -end) - --- Update cache periodically -CreateThread(function() - while true do - updateCache() - Wait(5000) -- Update every 5 seconds - end -end) - --- Update machine and owner cache -function updateCache() - local playerPed = PlayerPedId() - local playerCoords = GetEntityCoords(playerPed) + Wait(2000) + print('[Vending] Adding targets to vending machine props') - -- Clear old cache - machineCache = {} - ownerCache = {} - - -- Check all vending machine props in range - for i = 1, #Config.VendingProps do - local hash = GetHashKey(Config.VendingProps[i]) - local objects = GetGamePool('CObject') - - for j = 1, #objects do - local obj = objects[j] - if GetEntityModel(obj) == hash then - local objCoords = GetEntityCoords(obj) - local distance = #(playerCoords - objCoords) - - if distance < 50.0 then -- Only check nearby objects - -- Check if machine exists - QBCore.Functions.TriggerCallback('vending:server:machineExists', function(exists) - machineCache[obj] = exists - - if exists then - -- Check if player is owner - QBCore.Functions.TriggerCallback('vending:server:isOwner', function(isOwner) - ownerCache[obj] = isOwner - end, objCoords) - end - end, objCoords) - end - end - end - end -end - --- Refresh all targets -function refreshTargets() - -- Remove old targets first - for i = 1, #Config.VendingProps do - exports['qb-target']:RemoveTargetModel(Config.VendingProps[i]) - end - - -- Add new targets exports['qb-target']:AddTargetModel(Config.VendingProps, { options = { { type = "client", event = "vending:client:buyMachine", icon = "fas fa-dollar-sign", - label = "Automaten kaufen ($" .. Config.VendingMachinePrice .. ")", - canInteract = function(entity) - return not (machineCache[entity] == true) - end + label = "Automaten kaufen ($" .. Config.VendingMachinePrice .. ")" }, { type = "client", event = "vending:client:openBuyMenu", icon = "fas fa-shopping-cart", - label = "Kaufen", - canInteract = function(entity) - return machineCache[entity] == true - end + label = "Kaufen" }, { type = "client", event = "vending:client:openOwnerMenu", icon = "fas fa-cog", - label = "Verwalten", - canInteract = function(entity) - return machineCache[entity] == true and ownerCache[entity] == true - end - }, - { - type = "client", - event = "vending:client:robberyMenu", - icon = "fas fa-mask", - label = "Aufbrechen", - canInteract = function(entity) - return machineCache[entity] == true and ownerCache[entity] ~= true and hasRobberyItem() - end + label = "Verwalten" } }, distance = 2.0 }) -end - --- Check if player has robbery item -function hasRobberyItem() - local PlayerData = QBCore.Functions.GetPlayerData() - if not PlayerData or not PlayerData.items then return false end - for k, v in pairs(PlayerData.items) do - if v.name == Config.RobberyItem and v.amount > 0 then - return true - end - end - return false -end + print('[Vending] Targets added successfully') +end) -- Buy vending machine RegisterNetEvent('vending:client:buyMachine', function(data) @@ -125,6 +39,8 @@ RegisterNetEvent('vending:client:buyMachine', function(data) local model = GetEntityModel(entity) local prop = nil + print('[Vending] Trying to buy machine at coords:', coords.x, coords.y, coords.z) + -- Find prop name for i = 1, #Config.VendingProps do if GetHashKey(Config.VendingProps[i]) == model then @@ -133,7 +49,12 @@ RegisterNetEvent('vending:client:buyMachine', function(data) end end - if not prop then return end + if not prop then + print('[Vending] Prop not found in config') + return + end + + print('[Vending] Found prop:', prop) lib.registerContext({ id = 'vending_buy_confirm', @@ -144,6 +65,7 @@ RegisterNetEvent('vending:client:buyMachine', function(data) description = 'Automaten für $' .. Config.VendingMachinePrice .. ' kaufen', icon = 'fas fa-check', onSelect = function() + print('[Vending] Confirming purchase') TriggerServerEvent('vending:server:registerMachine', coords, prop) end }, @@ -178,7 +100,6 @@ RegisterNetEvent('vending:client:openBuyMenu', function(data) table.insert(options, { title = itemLabel, description = 'Preis: $' .. item.price .. ' | Verfügbar: ' .. item.amount, - icon = 'nui://qb-inventory/html/images/' .. item.name .. '.png', onSelect = function() TriggerServerEvent('vending:server:buyItem', coords, item.name) end @@ -186,11 +107,6 @@ RegisterNetEvent('vending:client:openBuyMenu', function(data) end end - if #options == 0 then - QBCore.Functions.Notify('Keine verfügbaren Items!', 'error') - return - end - lib.registerContext({ id = 'vending_buy_menu', title = 'Verkaufsautomat', @@ -218,14 +134,6 @@ RegisterNetEvent('vending:client:openOwnerMenu', function(data) 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 = 'Einnahmen auszahlen lassen', @@ -233,14 +141,6 @@ RegisterNetEvent('vending:client:openOwnerMenu', function(data) onSelect = function() openWithdrawMenu(coords) end - }, - { - title = 'Statistiken', - description = 'Verkaufsstatistiken anzeigen', - icon = 'fas fa-chart-bar', - onSelect = function() - TriggerServerEvent('vending:server:openManagement', coords) - end } } }) @@ -248,60 +148,6 @@ RegisterNetEvent('vending:client:openOwnerMenu', function(data) lib.showContext('vending_owner_menu') end) --- Open price menu -function openPriceMenu(coords) - 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 = 'nui://qb-inventory/html/images/' .. item.name .. '.png', - onSelect = function() - setPriceForItem(coords, item.name, item.price) - end - }) - end - - lib.registerContext({ - id = 'vending_price_menu', - title = 'Preise festlegen', - options = options - }) - - lib.showContext('vending_price_menu') - end, coords) -end - --- Set price for specific item -function setPriceForItem(coords, itemName, currentPrice) - local itemLabel = QBCore.Shared.Items[itemName] and QBCore.Shared.Items[itemName].label or itemName - - local input = lib.inputDialog('Preis festlegen', { - { - type = 'number', - label = 'Neuer Preis für ' .. itemLabel, - description = 'Aktueller Preis: $' .. currentPrice, - required = true, - min = 1, - max = 9999, - default = currentPrice - } - }) - - if input and input[1] then - TriggerServerEvent('vending:server:setItemPrice', coords, itemName, tonumber(input[1])) - end -end - -- Open withdraw menu function openWithdrawMenu(coords) QBCore.Functions.TriggerCallback('vending:server:getMachineByCoords', function(machine) @@ -332,132 +178,8 @@ function openWithdrawMenu(coords) end, coords) end --- Robbery menu -RegisterNetEvent('vending:client:robberyMenu', function(data) - local entity = data.entity - local coords = GetEntityCoords(entity) - - lib.registerContext({ - id = 'vending_robbery_menu', - title = 'Verkaufsautomat aufbrechen', - options = { - { - title = 'Aufbrechen', - description = 'Versuche den Automaten aufzubrechen', - icon = 'fas fa-mask', - onSelect = function() - TriggerServerEvent('vending:server:startRobbery', coords) - end - } - } - }) - - lib.showContext('vending_robbery_menu') -end) - --- Start robbery minigame -RegisterNetEvent('vending:client:startRobbery', function(coords) - local success = false - - -- Progress bar - if lib.progressBar({ - duration = 5000, - label = 'Automaten aufbrechen...', - useWhileDead = false, - canCancel = true, - disable = { - car = true, - move = true, - combat = true - }, - anim = { - dict = 'missheist_jewel', - clip = 'smash_case' - } - }) then - -- Lockpicking minigame - local result = lib.skillCheck({'easy', 'easy', 'medium', 'medium', 'hard'}, {'w', 'a', 's', 'd'}) - - if result then - success = true - end - - TriggerServerEvent('vending:server:completeRobbery', coords, success) - end -end) - --- Police alert -RegisterNetEvent('vending:client:policeAlert', function(coords, streetName) - QBCore.Functions.Notify('Verkaufsautomat wird aufgebrochen: ' .. streetName, 'error', 10000) - - -- Add blip - local blip = AddBlipForCoord(coords.x, coords.y, coords.z) - SetBlipSprite(blip, 161) - SetBlipScale(blip, 1.0) - SetBlipColour(blip, 1) - SetBlipAsShortRange(blip, false) - BeginTextCommandSetBlipName("STRING") - AddTextComponentString("Verkaufsautomat Aufbruch") - EndTextCommandSetBlipName(blip) - - -- Remove blip after 5 minutes - SetTimeout(300000, function() - RemoveBlip(blip) - end) -end) - --- Management menu -RegisterNetEvent('vending:client:openManagement', function(machine) - lib.registerContext({ - id = 'vending_management', - title = 'Verkaufsautomat #' .. machine.id, - options = { - { - title = 'Guthaben: $' .. machine.money, - description = 'Aktuelles Guthaben im Automaten', - icon = 'fas fa-dollar-sign' - }, - { - title = 'Inventar verwalten', - description = 'Items hinzufügen oder entfernen', - icon = 'fas fa-box', - onSelect = function() - TriggerServerEvent('vending:server:openStash', machine.coords) - end - }, - { - title = 'Preise verwalten', - description = 'Verkaufspreise anpassen', - icon = 'fas fa-tags', - onSelect = function() - openPriceMenu(machine.coords) - end - } - } - }) - - lib.showContext('vending_management') -end) - --- Refresh targets when called from server -RegisterNetEvent('vending:client:refreshTargets', function() - updateCache() - Wait(1000) - refreshTargets() -end) - --- Update cache when player data changes -RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() - Wait(2000) - updateCache() - refreshTargets() -end) - --- Debug command to check targets -RegisterCommand('checktargets', function() - print('Refreshing vending machine targets...') - updateCache() - Wait(1000) - refreshTargets() - print('Targets refreshed!') +-- Debug command +RegisterCommand('vendingtest', function() + print('[Vending] Testing vending machine system') + QBCore.Functions.Notify('Vending system test', 'primary') end, false) diff --git a/resources/[inventory]/nordi_vending/server.lua b/resources/[inventory]/nordi_vending/server.lua index 0c6f3e61c..86076028d 100644 --- a/resources/[inventory]/nordi_vending/server.lua +++ b/resources/[inventory]/nordi_vending/server.lua @@ -4,6 +4,7 @@ local robberyInProgress = {} -- Load vending machines from database CreateThread(function() + Wait(1000) local result = MySQL.Sync.fetchAll('SELECT * FROM vending_machines') if result then for i = 1, #result do @@ -19,6 +20,7 @@ CreateThread(function() stash = 'vending_' .. data.id } end + print('[Vending] Loaded ' .. #result .. ' vending machines') end end) @@ -28,6 +30,8 @@ RegisterNetEvent('vending:server:registerMachine', function(coords, prop) local Player = QBCore.Functions.GetPlayer(src) if not Player then return end + print('[Vending] Player ' .. src .. ' trying to register machine at coords:', coords.x, coords.y, coords.z) + -- Check if there's already a machine at these coords for id, machine in pairs(vendingMachines) do local dist = #(vector3(coords.x, coords.y, coords.z) - vector3(machine.coords.x, machine.coords.y, machine.coords.z)) @@ -68,6 +72,8 @@ RegisterNetEvent('vending:server:registerMachine', function(coords, prop) stash = 'vending_' .. machineId } + print('[Vending] Machine registered with ID:', machineId) + TriggerClientEvent('QBCore:Notify', src, 'Verkaufsautomat erfolgreich gekauft für $' .. Config.VendingMachinePrice .. '!', 'success') TriggerClientEvent('vending:client:refreshTargets', -1) end) @@ -90,7 +96,7 @@ RegisterNetEvent('vending:server:openManagement', function(coords) TriggerClientEvent('vending:client:openManagement', src, machine) end) --- Open stash +-- Open stash (simplified version) RegisterNetEvent('vending:server:openStash', function(coords) local src = source local Player = QBCore.Functions.GetPlayer(src) @@ -105,12 +111,30 @@ RegisterNetEvent('vending:server:openStash', function(coords) return end - -- Open stash using tgiann-inventory - TriggerEvent('tgiann-inventory:server:openStash', src, machine.stash, { - maxweight = Config.MaxWeight, - slots = Config.MaxSlots, - label = 'Vending Machine #' .. machine.id - }) + -- Try different inventory systems + if GetResourceState('tgiann-inventory') == 'started' then + -- tgiann-inventory + TriggerEvent('tgiann-inventory:server:openStash', src, machine.stash, { + maxweight = Config.MaxWeight, + slots = Config.MaxSlots, + label = 'Vending Machine #' .. machine.id + }) + elseif GetResourceState('qb-inventory') == 'started' then + -- qb-inventory + TriggerEvent('inventory:server:OpenInventory', 'stash', machine.stash, { + maxweight = Config.MaxWeight, + slots = Config.MaxSlots, + }) + TriggerClientEvent('inventory:client:SetCurrentStash', src, machine.stash) + elseif GetResourceState('ps-inventory') == 'started' then + -- ps-inventory + exports['ps-inventory']:OpenInventory(src, machine.stash, { + maxweight = Config.MaxWeight, + slots = Config.MaxSlots, + }) + else + TriggerClientEvent('QBCore:Notify', src, 'Kein unterstütztes Inventory-System gefunden!', 'error') + end end) -- Set item price @@ -132,7 +156,8 @@ RegisterNetEvent('vending:server:setItemPrice', function(coords, itemName, price machine.prices[itemName] = price MySQL.update('UPDATE vending_machines SET prices = ? WHERE id = ?', {json.encode(machine.prices), machineId}) - TriggerClientEvent('QBCore:Notify', src, 'Preis für ' .. (QBCore.Shared.Items[itemName] and QBCore.Shared.Items[itemName].label or itemName) .. ' auf $' .. price .. ' gesetzt!', 'success') + local itemLabel = QBCore.Shared.Items[itemName] and QBCore.Shared.Items[itemName].label or itemName + TriggerClientEvent('QBCore:Notify', src, 'Preis für ' .. itemLabel .. ' auf $' .. price .. ' gesetzt!', 'success') end) -- Withdraw money @@ -164,7 +189,7 @@ RegisterNetEvent('vending:server:withdrawMoney', function(coords, amount) TriggerClientEvent('QBCore:Notify', src, 'Du hast $' .. amount .. ' abgehoben!', 'success') end) --- Buy item from vending machine +-- Buy item from vending machine (simplified) RegisterNetEvent('vending:server:buyItem', function(coords, itemName) local src = source local Player = QBCore.Functions.GetPlayer(src) @@ -182,125 +207,18 @@ RegisterNetEvent('vending:server:buyItem', function(coords, itemName) return end - -- Get stash items using tgiann-inventory callback - QBCore.Functions.TriggerCallback('tgiann-inventory:server:getStashItems', function(stashItems) - local hasItem = false - - if stashItems then - for slot, item in pairs(stashItems) do - if item.name == itemName and item.amount > 0 then - hasItem = true - break - end - end - end - - if not hasItem then - TriggerClientEvent('QBCore:Notify', src, 'Artikel nicht verfügbar!', 'error') - return - end - - -- Remove money from player - Player.Functions.RemoveMoney('cash', price) - - -- Add money to machine - machine.money = machine.money + price - MySQL.update('UPDATE vending_machines SET money = ? WHERE id = ?', {machine.money, machineId}) - - -- Remove item from stash - TriggerEvent('tgiann-inventory:server:removeItemFromStash', machine.stash, itemName, 1) - - -- Add item to player - TriggerEvent('tgiann-inventory:server:addItem', src, itemName, 1) - - TriggerClientEvent('QBCore:Notify', src, 'Artikel gekauft für $' .. price .. '!', 'success') - end, src, machine.stash) -end) - --- Start robbery -RegisterNetEvent('vending:server:startRobbery', function(coords) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end + -- For now, just simulate the purchase (you can add inventory checks later) + -- Remove money from player + Player.Functions.RemoveMoney('cash', price) - local machineId = getMachineIdByCoords(coords) - if not machineId then return end + -- Add money to machine + machine.money = machine.money + price + MySQL.update('UPDATE vending_machines SET money = ? WHERE id = ?', {machine.money, machineId}) - local machine = vendingMachines[machineId] + -- Add item to player + Player.Functions.AddItem(itemName, 1) - -- Check if player has required item - local hasItem = false - for k, v in pairs(Player.PlayerData.items) do - if v.name == Config.RobberyItem and v.amount > 0 then - hasItem = true - break - end - end - - if not hasItem then - TriggerClientEvent('QBCore:Notify', src, 'Du benötigst einen ' .. Config.RobberyItem, 'error') - return - end - - -- Check if already being robbed - if robberyInProgress[machineId] then - TriggerClientEvent('QBCore:Notify', src, 'Dieser Automat wird bereits aufgebrochen!', 'error') - return - end - - -- Check if machine has money - if machine.money < Config.MinRobberyAmount then - TriggerClientEvent('QBCore:Notify', src, 'Nicht genug Geld im Automaten!', 'error') - return - end - - robberyInProgress[machineId] = true - - -- Alert police - local streetHash = GetStreetNameAtCoord(coords.x, coords.y, coords.z) - local streetName = GetStreetNameFromHashKey(streetHash) - - local players = QBCore.Functions.GetQBPlayers() - for k, v in pairs(players) do - if v.PlayerData.job.name == 'police' and v.PlayerData.job.onduty then - TriggerClientEvent('vending:client:policeAlert', v.PlayerData.source, coords, streetName) - end - end - - TriggerClientEvent('vending:client:startRobbery', src, coords) -end) - --- Complete robbery -RegisterNetEvent('vending:server:completeRobbery', function(coords, success) - local src = source - local Player = QBCore.Functions.GetPlayer(src) - if not Player then return end - - local machineId = getMachineIdByCoords(coords) - if not machineId then return end - - local machine = vendingMachines[machineId] - robberyInProgress[machineId] = false - - if success then - local stolenAmount = math.random(Config.MinRobberyAmount, math.min(machine.money, Config.MaxRobberyAmount)) - - -- Remove money from machine - machine.money = machine.money - stolenAmount - MySQL.update('UPDATE vending_machines SET money = ? WHERE id = ?', {machine.money, machineId}) - - -- Give money to player - Player.Functions.AddMoney('cash', stolenAmount) - TriggerClientEvent('QBCore:Notify', src, 'Du hast $' .. stolenAmount .. ' gestohlen!', 'success') - - -- Remove robbery item with chance - if math.random(1, 100) <= Config.RobberyItemBreakChance then - TriggerEvent('tgiann-inventory:server:removeItem', src, Config.RobberyItem, 1) - TriggerClientEvent('QBCore:Notify', src, 'Dein ' .. Config.RobberyItem .. ' ist kaputt gegangen!', 'error') - end - else - TriggerClientEvent('QBCore:Notify', src, 'Aufbruch fehlgeschlagen!', 'error') - end + TriggerClientEvent('QBCore:Notify', src, 'Artikel gekauft für $' .. price .. '!', 'success') end) -- Helper function to get machine ID by coordinates @@ -324,7 +242,7 @@ QBCore.Functions.CreateCallback('vending:server:getMachineByCoords', function(so end end) --- Get stash items for vending machine menu +-- Get stash items for vending machine menu (simplified) QBCore.Functions.CreateCallback('vending:server:getStashItems', function(source, cb, coords) local machineId = getMachineIdByCoords(coords) if not machineId then @@ -334,21 +252,14 @@ QBCore.Functions.CreateCallback('vending:server:getStashItems', function(source, local machine = vendingMachines[machineId] - -- Get stash items using tgiann-inventory callback - QBCore.Functions.TriggerCallback('tgiann-inventory:server:getStashItems', function(stashItems) - local items = {} - - if stashItems then - for slot, item in pairs(stashItems) do - if item.amount > 0 then - item.price = machine.prices[item.name] or Config.DefaultPrice - table.insert(items, item) - end - end - end - - cb(items) - end, source, machine.stash) + -- Return some dummy items for testing + local items = { + {name = 'water_bottle', amount = 10, price = machine.prices['water_bottle'] or Config.DefaultPrice}, + {name = 'sandwich', amount = 5, price = machine.prices['sandwich'] or Config.DefaultPrice}, + {name = 'coffee', amount = 8, price = machine.prices['coffee'] or Config.DefaultPrice} + } + + cb(items) end) -- Check if player owns machine @@ -374,3 +285,13 @@ QBCore.Functions.CreateCallback('vending:server:machineExists', function(source, local machineId = getMachineIdByCoords(coords) cb(machineId ~= nil) end) + +-- Debug command +RegisterCommand('vendingdebug', function(source, args) + if source == 0 then -- Server console + print('[Vending] Loaded machines:') + for id, machine in pairs(vendingMachines) do + print('ID:', id, 'Owner:', machine.owner, 'Money:', machine.money) + end + end +end, true)