local QBCore = exports['qb-core']:GetCoreObject() local placedBowls = {} local currentBowl = nil -- Load placed bowls from server RegisterNetEvent('pet-bowls:client:loadBowls', function(bowls) for _, bowl in pairs(bowls) do local coords = json.decode(bowl.coords) local bowlCoords = vector3(coords.x, coords.y, coords.z) -- 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 end end) -- Function to add qb-target to a bowl function AddTargetToBowl(bowlObject, bowlId, bowlType) exports['qb-target']:AddTargetEntity(bowlObject, { options = { { type = "client", icon = "fas fa-hand", label = "Use Bowl", action = function() UseBowl(bowlId, bowlType) end, canInteract = function() return true end, }, { type = "client", icon = "fas fa-fill", label = "Fill Bowl", action = function() OpenFillMenu(bowlId, bowlType) end, canInteract = function() return true end, } }, distance = 2.0 }) end -- Function to use a bowl function UseBowl(bowlId, bowlType) local bowl = placedBowls[bowlId] if not bowl then return end -- Check if bowl has content if bowl.fillLevel <= 0 then lib.notify(Config.Notifications.bowlEmpty) return end -- Set animation and progress bar based on bowl type local progressConfig = bowlType == 'food' and Config.ProgressBar.eating or Config.ProgressBar.drinking -- Start progress bar if lib.progressBar(progressConfig) then -- Consume from bowl TriggerServerEvent('pet-bowls:server:consumeBowl', bowlId) end end -- Function to open fill menu function OpenFillMenu(bowlId, bowlType) local bowl = placedBowls[bowlId] if not bowl then return end -- Get fill items for this bowl type local fillItems = Config.FillItems[bowlType] local options = {} for _, item in pairs(fillItems) do table.insert(options, { title = item.label, description = 'Fill Amount: ' .. item.fillAmount .. '%', onSelect = function() FillBowl(bowlId, item.item, item.fillAmount) end }) end lib.registerContext({ id = 'bowl_fill_menu', title = 'Fill ' .. (bowlType == 'food' and 'Food' or 'Water') .. ' Bowl (' .. bowl.fillLevel .. '%)', options = options }) lib.showContext('bowl_fill_menu') end -- Function to fill a bowl function FillBowl(bowlId, itemName, fillAmount) -- Start progress bar if lib.progressBar(Config.ProgressBar.filling) then -- Fill the bowl TriggerServerEvent('pet-bowls:server:fillBowl', bowlId, itemName, fillAmount) end end -- Update bowl fill level RegisterNetEvent('pet-bowls:client:updateBowlLevel', function(bowlId, newLevel) if placedBowls[bowlId] then placedBowls[bowlId].fillLevel = 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)