local QBCore = exports['qb-core']:GetCoreObject() local bowls = {} -- Initialize Citizen.CreateThread(function() -- Load all bowls from database LoadBowls() end) -- Load bowls from database function LoadBowls() MySQL.query('SELECT * FROM pet_bowls', {}, function(results) if results and #results > 0 then for _, bowl in pairs(results) do bowls[bowl.bowl_id] = { id = bowl.bowl_id, model = bowl.model, type = bowl.type, fill_level = bowl.fill_level, coords = bowl.coords } end print('^2[Pet-Bowls]^7 Loaded ' .. #results .. ' bowls from database') else print('^2[Pet-Bowls]^7 No bowls found in database') end end) end -- Client requests all bowls RegisterNetEvent('pet-bowls:server:requestBowls', function() local src = source TriggerClientEvent('pet-bowls:client:loadBowls', src, bowls) end) -- 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) if not Player then return end -- Save to database local coordsJson = json.encode(coords) MySQL.insert('INSERT INTO pet_bowls (bowl_id, model, type, fill_level, coords) VALUES (?, ?, ?, ?, ?)', {bowlId, model, bowlType, 0, coordsJson}, function(id) if id then -- Save to memory bowls[bowlId] = { id = bowlId, model = model, type = bowlType, fill_level = 0, coords = coordsJson } -- Notify all clients about the new bowl TriggerClientEvent('pet-bowls:client:updateBowlLevel', -1, bowlId, 0) print('^2[Pet-Bowls]^7 New bowl registered: ' .. bowlId) end end ) end) -- Fill a bowl RegisterNetEvent('pet-bowls:server:fillBowl', function(bowlId, itemName, fillAmount) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end -- Check if player has the item using standard QBCore function local item = Player.Functions.GetItemByName(itemName) if not item or item.amount < 1 then TriggerClientEvent('ox_lib:notify', src, Config.Notifications.noItem) return end -- 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] if bowl then local newLevel = math.min(100, bowl.fill_level + fillAmount) -- Update in memory bowl.fill_level = newLevel -- Update in database MySQL.update('UPDATE pet_bowls SET fill_level = ?, last_refill = CURRENT_TIMESTAMP WHERE bowl_id = ?', {newLevel, bowlId} ) -- Update all clients TriggerClientEvent('pet-bowls:client:updateBowlLevel', -1, bowlId, newLevel) TriggerClientEvent('ox_lib:notify', src, Config.Notifications.bowlFilled) print('^2[Pet-Bowls]^7 Bowl ' .. bowlId .. ' filled to ' .. newLevel .. '%') end end) -- Consume from a bowl RegisterNetEvent('pet-bowls:server:consumeBowl', function(bowlId) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end -- Get bowl data local bowl = bowls[bowlId] if not bowl then return end -- Find the bowl config local bowlConfig = nil for _, config in pairs(Config.BowlProps) do if config.model == bowl.model then bowlConfig = config break end end if not bowlConfig then return end -- Check if bowl has content if bowl.fill_level <= 0 then TriggerClientEvent('ox_lib:notify', src, Config.Notifications.bowlEmpty) return end -- Consume from bowl local consumeAmount = bowlConfig.consumeAmount local newLevel = math.max(0, bowl.fill_level - consumeAmount) -- Update in memory bowl.fill_level = newLevel -- Update in database MySQL.update('UPDATE pet_bowls SET fill_level = ? WHERE bowl_id = ?', {newLevel, bowlId} ) -- Apply effects to player - FIXED VERSION FOR DIFFERENT QBCORE VERSIONS local effects = Config.Effects[bowl.type] if effects then -- Get player metadata local metadata = Player.PlayerData.metadata -- Apply hunger effect for food bowls if effects.hunger and bowl.type == 'food' then -- Direct HUD update for hunger TriggerClientEvent('hud:client:UpdateHunger', src, effects.hunger, true) print('^2[Pet-Bowls]^7 Updated player hunger by +' .. effects.hunger) end -- Apply thirst effect for water bowls if effects.thirst and bowl.type == 'water' then -- Direct HUD update for thirst TriggerClientEvent('hud:client:UpdateThirst', src, effects.thirst, true) print('^2[Pet-Bowls]^7 Updated player thirst by +' .. effects.thirst) end -- Apply stress effect (if your server uses this) if effects.stress then -- Try to update stress using common event TriggerClientEvent('hud:client:UpdateStress', src, effects.stress) end end -- Update all clients TriggerClientEvent('pet-bowls:client:updateBowlLevel', -1, bowlId, newLevel) TriggerClientEvent('ox_lib:notify', src, Config.Notifications.consumed) print('^2[Pet-Bowls]^7 Bowl ' .. bowlId .. ' consumed, new level: ' .. newLevel .. '%') end) -- Remove a bowl from database (if needed) RegisterNetEvent('pet-bowls:server:removeBowl', function(bowlId) local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player then return end -- Remove from database MySQL.query('DELETE FROM pet_bowls WHERE bowl_id = ?', {bowlId}) -- Remove from memory bowls[bowlId] = nil -- Notify all clients TriggerClientEvent('pet-bowls:client:bowlRemoved', -1, bowlId) print('^2[Pet-Bowls]^7 Bowl removed: ' .. bowlId) end) -- Register command to register bowls QBCore.Commands.Add('registerbowl', 'Register a nearby bowl prop', {}, false, function(source, args) TriggerClientEvent('pet-bowls:client:openRegisterBowlMenu', source) end)