diff --git a/resources/[inventory]/nordi_petbowl/client.lua b/resources/[inventory]/nordi_petbowl/client.lua index 8952448c3..f8fd9f2a6 100644 --- a/resources/[inventory]/nordi_petbowl/client.lua +++ b/resources/[inventory]/nordi_petbowl/client.lua @@ -8,29 +8,27 @@ RegisterNetEvent('pet-bowls:client:loadBowls', function(bowls) local coords = json.decode(bowl.coords) local bowlCoords = vector3(coords.x, coords.y, coords.z) - -- Create the bowl object - local hash = GetHashKey(bowl.model) - RequestModel(hash) - while not HasModelLoaded(hash) do - Wait(10) + -- Add target to existing bowl objects + local bowlObjects = GetGamePool('CObject') + for _, object in pairs(bowlObjects) do + local objectCoords = GetEntityCoords(object) + local distance = #(objectCoords - bowlCoords) + + if distance < 0.5 and GetEntityModel(object) == GetHashKey(bowl.model) then + -- Found the bowl object + placedBowls[bowl.bowl_id] = { + object = object, + id = bowl.bowl_id, + model = bowl.model, + type = bowl.type, + fillLevel = bowl.fill_level + } + + -- Add target + AddTargetToBowl(object, bowl.bowl_id, bowl.type) + break + end end - - local bowlObject = CreateObject(hash, bowlCoords.x, bowlCoords.y, bowlCoords.z, false, false, false) - SetEntityHeading(bowlObject, coords.w) - FreezeEntityPosition(bowlObject, true) - SetEntityAsMissionEntity(bowlObject, true, true) - - -- Store in local table - placedBowls[bowl.bowl_id] = { - object = bowlObject, - id = bowl.bowl_id, - model = bowl.model, - type = bowl.type, - fillLevel = bowl.fill_level - } - - -- Add target - AddTargetToBowl(bowlObject, bowl.bowl_id, bowl.type) end end) @@ -59,17 +57,6 @@ function AddTargetToBowl(bowlObject, bowlId, bowlType) canInteract = function() return true end, - }, - { - type = "client", - icon = "fas fa-trash", - label = "Pick Up Bowl", - action = function() - PickUpBowl(bowlId) - end, - canInteract = function() - return true - end, } }, distance = 2.0 @@ -134,101 +121,6 @@ function FillBowl(bowlId, itemName, fillAmount) end end --- Function to pick up a bowl -function PickUpBowl(bowlId) - local bowl = placedBowls[bowlId] - if not bowl then return end - - -- Delete the object and remove from server - if DoesEntityExist(bowl.object) then - DeleteEntity(bowl.object) - end - - TriggerServerEvent('pet-bowls:server:removeBowl', bowlId) - placedBowls[bowlId] = nil -end - --- Command to place a bowl -RegisterCommand('placebowl', function() - OpenPlaceBowlMenu() -end) - --- Function to open place bowl menu -function OpenPlaceBowlMenu() - local options = {} - - for _, bowl in pairs(Config.BowlProps) do - table.insert(options, { - title = bowl.label, - description = 'Type: ' .. (bowl.type == 'food' and 'Food Bowl' or 'Water Bowl'), - onSelect = function() - PlaceBowl(bowl) - end - }) - end - - lib.registerContext({ - id = 'place_bowl_menu', - title = 'Place Bowl', - options = options - }) - - lib.showContext('place_bowl_menu') -end - --- Function to place a bowl -function PlaceBowl(bowlConfig) - local playerPed = PlayerPedId() - local coords = GetEntityCoords(playerPed) - local heading = GetEntityHeading(playerPed) - - -- Create the bowl object - local hash = GetHashKey(bowlConfig.model) - RequestModel(hash) - while not HasModelLoaded(hash) do - Wait(10) - end - - local forward = GetEntityForwardVector(playerPed) - local placementCoords = vector3( - coords.x + forward.x * 0.5, - coords.y + forward.y * 0.5, - coords.z - 0.5 - ) - - local bowlObject = CreateObject(hash, placementCoords.x, placementCoords.y, placementCoords.z, true, false, false) - SetEntityHeading(bowlObject, heading) - PlaceObjectOnGroundProperly(bowlObject) - FreezeEntityPosition(bowlObject, true) - SetEntityAsMissionEntity(bowlObject, true, true) - - -- Generate a unique ID for this bowl - local bowlId = 'bowl_' .. math.random(100000, 999999) .. '_' .. GetGameTimer() - - -- Save to server - local finalCoords = GetEntityCoords(bowlObject) - TriggerServerEvent('pet-bowls:server:placeBowl', bowlId, bowlConfig.model, bowlConfig.type, { - x = finalCoords.x, - y = finalCoords.y, - z = finalCoords.z, - w = heading - }) - - -- Store locally - placedBowls[bowlId] = { - object = bowlObject, - id = bowlId, - model = bowlConfig.model, - type = bowlConfig.type, - fillLevel = 0 - } - - -- Add target - AddTargetToBowl(bowlObject, bowlId, bowlConfig.type) - - lib.notify(Config.Notifications.bowlPlaced) -end - -- Update bowl fill level RegisterNetEvent('pet-bowls:client:updateBowlLevel', function(bowlId, newLevel) if placedBowls[bowlId] then @@ -236,8 +128,99 @@ RegisterNetEvent('pet-bowls:client:updateBowlLevel', function(bowlId, newLevel) end end) +-- Register a new bowl (called from ProPlacer) +RegisterNetEvent('pet-bowls:client:registerBowl', function(objectNetId, bowlType) + local bowlObject = NetworkGetEntityFromNetworkId(objectNetId) + if not DoesEntityExist(bowlObject) then return end + + local model = GetEntityModel(bowlObject) + local modelName = nil + + -- Find the model name from the hash + for _, bowlConfig in pairs(Config.BowlProps) do + if GetHashKey(bowlConfig.model) == model then + modelName = bowlConfig.model + break + end + end + + if not modelName then return end + + -- Generate a unique ID for this bowl + local bowlId = 'bowl_' .. math.random(100000, 999999) .. '_' .. GetGameTimer() + + -- Save to server + local coords = GetEntityCoords(bowlObject) + local heading = GetEntityHeading(bowlObject) + + TriggerServerEvent('pet-bowls:server:placeBowl', bowlId, modelName, bowlType, { + x = coords.x, + y = coords.y, + z = coords.z, + w = heading + }) + + -- Store locally + placedBowls[bowlId] = { + object = bowlObject, + id = bowlId, + model = modelName, + type = bowlType, + fillLevel = 0 + } + + -- Add target + AddTargetToBowl(bowlObject, bowlId, bowlType) + + lib.notify(Config.Notifications.bowlPlaced) +end) + -- Initialize Citizen.CreateThread(function() -- Request all placed bowls from server TriggerServerEvent('pet-bowls:server:requestBowls') + + -- Add target to all valid bowl props in the world + Citizen.Wait(2000) -- Wait for world to load + + local validModels = {} + for _, bowlConfig in pairs(Config.BowlProps) do + validModels[GetHashKey(bowlConfig.model)] = bowlConfig.type + end + + local objects = GetGamePool('CObject') + for _, object in pairs(objects) do + local model = GetEntityModel(object) + if validModels[model] then + -- This is a valid bowl model, check if it's already registered + local isRegistered = false + for id, bowl in pairs(placedBowls) do + if bowl.object == object then + isRegistered = true + break + end + end + + if not isRegistered then + -- This bowl isn't registered yet, add interaction without database entry + exports['qb-target']:AddTargetEntity(object, { + options = { + { + type = "client", + icon = "fas fa-plus", + label = "Register as Bowl", + action = function() + local bowlType = validModels[model] + TriggerEvent('pet-bowls:client:registerBowl', NetworkGetNetworkIdFromEntity(object), bowlType) + end, + canInteract = function() + return true + end, + } + }, + distance = 2.0 + }) + end + end + end end) diff --git a/resources/[inventory]/nordi_petbowl/config.lua b/resources/[inventory]/nordi_petbowl/config.lua index 30183d167..b537abc4c 100644 --- a/resources/[inventory]/nordi_petbowl/config.lua +++ b/resources/[inventory]/nordi_petbowl/config.lua @@ -87,7 +87,7 @@ Config.ProgressBar = { }, filling = { duration = 2000, - label = 'Filling Bowl...', + label = 'Napf füllen...', position = 'bottom', useWhileDead = false, canCancel = true, @@ -108,7 +108,7 @@ Config.ProgressBar = { Config.Notifications = { bowlPlaced = { title = 'Bowl System', - description = 'You placed a bowl!', + description = 'Bowl registered successfully!', type = 'success' }, bowlFilled = { diff --git a/resources/[inventory]/nordi_petbowl/server.lua b/resources/[inventory]/nordi_petbowl/server.lua index adf5c0c45..cb3d17537 100644 --- a/resources/[inventory]/nordi_petbowl/server.lua +++ b/resources/[inventory]/nordi_petbowl/server.lua @@ -33,7 +33,7 @@ RegisterNetEvent('pet-bowls:server:requestBowls', function() TriggerClientEvent('pet-bowls:client:loadBowls', src, bowls) end) --- Place a new bowl +-- Place a new bowl (register an existing prop as a bowl) RegisterNetEvent('pet-bowls:server:placeBowl', function(bowlId, model, bowlType, coords) local src = source local Player = QBCore.Functions.GetPlayer(src) @@ -69,16 +69,17 @@ RegisterNetEvent('pet-bowls:server:fillBowl', function(bowlId, itemName, fillAmo if not Player then return end - -- Check if player has the item - local hasItem = exports["tgiann-inventory"]:GetItemByName(src, itemName) + -- Check if player has the item using standard QBCore function + local item = Player.Functions.GetItemByName(itemName) - if not hasItem or hasItem.amount < 1 then + if not item or item.amount < 1 then TriggerClientEvent('ox_lib:notify', src, Config.Notifications.noItem) return end - -- Remove the item - exports["tgiann-inventory"]:RemoveItem(src, itemName, 1) + -- Remove the item using standard QBCore function + Player.Functions.RemoveItem(itemName, 1) + TriggerClientEvent('inventory:client:ItemBox', src, QBCore.Shared.Items[itemName], "remove") -- Update bowl fill level local bowl = bowls[bowlId] @@ -163,7 +164,7 @@ RegisterNetEvent('pet-bowls:server:consumeBowl', function(bowlId) TriggerClientEvent('ox_lib:notify', src, Config.Notifications.consumed) end) --- Remove a bowl +-- Remove a bowl from database (if needed) RegisterNetEvent('pet-bowls:server:removeBowl', function(bowlId) local src = source local Player = QBCore.Functions.GetPlayer(src) @@ -175,9 +176,7 @@ RegisterNetEvent('pet-bowls:server:removeBowl', function(bowlId) -- Remove from memory bowls[bowlId] = nil -end) - --- Register command to place bowls -QBCore.Commands.Add('placebowl', 'Place a pet bowl', {}, false, function(source, args) - TriggerClientEvent('pet-bowls:client:openPlaceBowlMenu', source) + + -- Notify all clients + TriggerClientEvent('pet-bowls:client:bowlRemoved', -1, bowlId) end)