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) -- Create the bowl object local hash = GetHashKey(bowl.model) RequestModel(hash) while not HasModelLoaded(hash) do Wait(10) 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) -- 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, }, { type = "client", icon = "fas fa-trash", label = "Pick Up Bowl", action = function() PickUpBowl(bowlId) 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 -- 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 placedBowls[bowlId].fillLevel = newLevel end end) -- Initialize Citizen.CreateThread(function() -- Request all placed bowls from server TriggerServerEvent('pet-bowls:server:requestBowls') end)