Guide2026-05-19

FiveM Pet & Companion System Development

OntelMonke

OntelMonke

Developer at Agency Scripts

Pets as Living Roleplay Companions

Pets bring a unique emotional dimension to roleplay servers that no other system can replicate. A player walking through the city with their dog trotting beside them creates a visual personality that enriches every interaction. Pet companions transform mundane activities like walking to the store into immersive moments. They create organic conversation starters when other players notice your German Shepherd or ask about your cat. Beyond the social element, pets can serve functional roles as guard dogs that alert owners to intruders, police K-9 units that assist in searches, emotional support animals in hospital roleplay, or hunting companions that help track prey. Building a pet system requires handling ped spawning and despawning, AI follow behavior, animation integration, needs simulation like hunger and happiness, persistence across sessions, and interaction commands that let the owner control their companion through natural gestures and voice commands.

Available Animal Models and Configuration

GTA V includes several animal ped models that work well as companions. Dogs are the most versatile with models like a_c_shepherd for German Shepherds, a_c_husky for Huskies, a_c_poodle for Poodles, a_c_rottweiler for Rottweilers, a_c_retriever for Retrievers, and a_c_chop for the iconic Chop model. Cats use a_c_cat_01. For exotic options, there are rabbits with a_c_rabbit_01 and even birds with a_c_crow. Each pet type should have different behavior parameters configured in a shared file. Dogs follow closely and can run alongside vehicles at moderate speeds. Cats are more independent, occasionally wandering short distances before returning. Birds could perch on the player's shoulder using entity attachment. Define each pet type's follow distance, movement speed multiplier, idle animations, interaction animations, and special abilities to create distinct personalities for each species.

-- shared/config.lua
Config = {}

Config.PetTypes = {
    shepherd = {
        model       = 'a_c_shepherd',
        label       = 'German Shepherd',
        price       = 5000,
        followDist  = 2.5,
        runDist     = 8.0,
        maxSpeed    = 7.0,
        category    = 'dog',
        abilities   = {'guard', 'fetch', 'search'},
        idleAnims   = {'sit', 'lie_down', 'sniff'},
    },
    husky = {
        model       = 'a_c_husky',
        label       = 'Husky',
        price       = 6000,
        followDist  = 3.0,
        runDist     = 10.0,
        maxSpeed    = 8.0,
        category    = 'dog',
        abilities   = {'fetch', 'howl'},
        idleAnims   = {'sit', 'lie_down', 'play'},
    },
    cat = {
        model       = 'a_c_cat_01',
        label       = 'Cat',
        price       = 2000,
        followDist  = 4.0,
        runDist     = 6.0,
        maxSpeed    = 5.0,
        category    = 'cat',
        abilities   = {'purr', 'hunt_rodent'},
        idleAnims   = {'sit', 'groom', 'sleep'},
    },
    poodle = {
        model       = 'a_c_poodle',
        label       = 'Poodle',
        price       = 4000,
        followDist  = 2.0,
        runDist     = 6.0,
        maxSpeed    = 5.5,
        category    = 'dog',
        abilities   = {'fetch', 'trick'},
        idleAnims   = {'sit', 'beg', 'spin'},
    },
    rottweiler = {
        model       = 'a_c_rottweiler',
        label       = 'Rottweiler',
        price       = 7000,
        followDist  = 2.0,
        runDist     = 8.0,
        maxSpeed    = 7.5,
        category    = 'dog',
        abilities   = {'guard', 'attack', 'intimidate'},
        idleAnims   = {'sit', 'lie_down', 'bark'},
    },
}

Spawning and Follow Behavior

The core of any pet system is the follow AI that makes the animal naturally trail behind its owner. When a player spawns their pet, create the ped at their position using CreatePed with the appropriate model. Set the ped as non-persistent using SetEntityAsMissionEntity and configure it to be friendly to the owner using relationship groups. The follow behavior uses a client-side loop that constantly calculates the distance between the pet and owner. When the distance exceeds the follow threshold, task the pet to run toward a position slightly behind and to the side of the owner using TaskFollowToOffsetOfEntity. This native handles pathfinding automatically, making the pet navigate around obstacles, walk on sidewalks, and avoid traffic. When the owner stops moving and the pet reaches its follow distance, play an idle animation like sitting or lying down. If the owner gets into a vehicle and drives away, teleport the pet into the vehicle if it is a suitable type, or despawn the pet and respawn it when the owner exits the vehicle to prevent the pet from getting lost across the map.

-- client/pet_behavior.lua
local activePet = nil
local petData   = nil

function SpawnPet(petType, name)
    if activePet then DespawnPet() end

    local config = Config.PetTypes[petType]
    if not config then return end

    local ped = PlayerPedId()
    local coords = GetOffsetFromEntityInWorldCoords(ped, 1.5, 1.5, 0.0)

    RequestModel(config.model)
    while not HasModelLoaded(config.model) do Wait(10) end

    activePet = CreatePed(28, config.model,
        coords.x, coords.y, coords.z, 0.0, true, false)

    SetEntityAsMissionEntity(activePet, true, true)
    SetBlockingOfNonTemporaryEvents(activePet, true)
    SetPedCanBeTargetted(activePet, false)
    SetPedCanRagdoll(activePet, false)

    -- Set relationship so pet doesn't attack owner
    local playerGroup = GetHashKey('PLAYER')
    local petGroup = GetHashKey('PET_COMPANION')
    AddRelationshipGroup('PET_COMPANION')
    SetPedRelationshipGroupHash(activePet, petGroup)
    SetRelationshipBetweenGroups(0, petGroup, playerGroup)
    SetRelationshipBetweenGroups(0, playerGroup, petGroup)

    petData = {type = petType, name = name, config = config}

    -- Start follow loop
    CreateThread(PetFollowLoop)
end

function PetFollowLoop()
    while activePet and DoesEntityExist(activePet) do
        local ped = PlayerPedId()
        local petCoords = GetEntityCoords(activePet)
        local ownerCoords = GetEntityCoords(ped)
        local dist = #(petCoords - ownerCoords)

        if dist > 50.0 then
            -- Teleport if too far
            SetEntityCoords(activePet,
                ownerCoords.x, ownerCoords.y, ownerCoords.z)
        elseif dist > petData.config.runDist then
            -- Run to owner
            TaskFollowToOffsetOfEntity(activePet, ped,
                0.0, -1.5, 0.0, petData.config.maxSpeed,
                -1, 1.0, true)
        elseif dist > petData.config.followDist then
            -- Walk to owner
            TaskFollowToOffsetOfEntity(activePet, ped,
                0.0, -1.5, 0.0, 2.0, -1, 1.0, true)
        else
            -- Idle nearby
            if not IsEntityPlayingAnim(activePet, 'creatures@dog@amb@', 'sit_enter', 3) then
                if math.random() > 0.95 then
                    PlayIdleAnimation()
                end
            end
        end

        Wait(500)
    end
end

Pet Needs and Bonding System

A needs system gives pet ownership ongoing responsibility and depth. Track hunger, happiness, and health as values between 0 and 100 that decay over real time. Hunger decreases by 1 point every 5 minutes of real time that the pet is spawned. Happiness decreases more slowly at 1 point every 10 minutes but increases significantly when the owner interacts with the pet through petting, playing fetch, or giving treats. Health stays at 100 unless hunger drops below 20, at which point it starts declining. When hunger hits zero, the pet becomes lethargic with slower movement and sad animations. When health drops too low, the pet needs veterinary attention to recover. Players feed their pets by using food items from their inventory on the pet entity. Different food types restore different amounts of hunger: basic pet food restores 30 points, premium food restores 60, and treats restore 10 but boost happiness by 15. The bonding level tracks the cumulative relationship between owner and pet, increasing through positive interactions and decreasing through neglect. Higher bond levels unlock special interactions and improve the pet's responsiveness to commands.

-- server/pet_needs.lua
local petStates = {}

function InitPetState(ownerId, petId)
    petStates[ownerId] = {
        petId     = petId,
        hunger    = 100,
        happiness = 80,
        health    = 100,
        bond      = 0,
        lastFed   = os.time(),
        lastPet   = os.time(),
    }
end

-- Decay loop runs every 60 seconds
CreateThread(function()
    while true do
        Wait(60000)
        local now = os.time()
        for ownerId, state in pairs(petStates) do
            -- Hunger decay: 1 point per 5 minutes
            local minutesSinceFed = (now - state.lastFed) / 60
            state.hunger = math.max(0,
                100 - math.floor(minutesSinceFed / 5))

            -- Happiness decay
            local minutesSincePet = (now - state.lastPet) / 60
            state.happiness = math.max(0,
                math.min(100, state.happiness -
                    math.floor(minutesSincePet / 10)))

            -- Health decays when starving
            if state.hunger < 20 then
                state.health = math.max(0,
                    state.health - 1)
            end

            -- Sync to client
            local player = GetPlayerFromIdentifier(ownerId)
            if player then
                TriggerClientEvent('pet:syncState', player, state)
            end
        end
    end
end)

RegisterNetEvent('pet:feed', function(foodItem)
    local src = source
    local id = GetPlayerIdentifier(src, 0)
    local state = petStates[id]
    if not state then return end

    local foodValues = {
        petfood        = {hunger = 30, happiness = 5},
        premium_food   = {hunger = 60, happiness = 10},
        pet_treat      = {hunger = 10, happiness = 15},
    }

    local food = foodValues[foodItem]
    if not food then return end

    -- Remove item from inventory
    local removed = exports['ox_inventory']:RemoveItem(src, foodItem, 1)
    if not removed then return end

    state.hunger = math.min(100, state.hunger + food.hunger)
    state.happiness = math.min(100, state.happiness + food.happiness)
    state.lastFed = os.time()
    state.bond = state.bond + 1

    TriggerClientEvent('pet:syncState', src, state)
    TriggerClientEvent('pet:feedAnimation', src)
end)

Interaction Commands and Animations

Give players a rich set of commands to interact with their pet. A radial menu or command system should offer options like sit, stay, follow, come, lie down, shake, fetch, and speak. Each command triggers a corresponding animation on the pet ped using the creature animation dictionaries built into GTA V. The sit command uses animations from creatures@dog@amb@ with the sit_enter and sit_loop clips. Lie down uses similar ambient animations. For fetch, spawn a small ball prop, throw it using a parabolic trajectory, and task the pet to run to the ball's landing position, pick it up using an attachment, and return it to the owner. The speak command triggers a bark audio using PlayPedAmbientSpeechNative. For petting, play a kneeling animation on the player ped while simultaneously playing a happy tail-wagging animation on the pet. These interactions are not just cosmetic; each one increases the happiness and bond stats, rewarding players who actively engage with their companion rather than treating it as a passive follower.

Persistence and Pet Shop Integration

Pets need to persist across server sessions so players don't lose their companions every restart. Store pet data in the database including the owner identifier, pet type, custom name, current needs values, bond level, and any unlocked tricks or abilities. When the owner logs in, query their pet data and offer to spawn it through a command or automatically if they had it active when they last disconnected. Integrate pet acquisition through an in-game pet shop located at a logical map position. The pet shop NUI displays available pet types with their models rendered in a preview area, prices, and descriptions. After purchase, the player names their new pet and it spawns beside them. Consider adding a pet adoption center as an alternative with lower prices but randomized pet types, adding a charitable roleplay angle. For server economies, pets can also require periodic expenses like vet visits for health restoration, grooming for appearance bonuses, and training sessions that unlock new command animations, creating a realistic cost of pet ownership that integrates with your broader economic system.

-- SQL schema
CREATE TABLE IF NOT EXISTS pets (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    owner_id    VARCHAR(64) NOT NULL,
    char_slot   INT DEFAULT 1,
    pet_type    VARCHAR(32) NOT NULL,
    pet_name    VARCHAR(64) NOT NULL,
    hunger      INT DEFAULT 100,
    happiness   INT DEFAULT 80,
    health      INT DEFAULT 100,
    bond        INT DEFAULT 0,
    tricks      JSON DEFAULT '[]',
    is_active   TINYINT DEFAULT 0,
    created_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_owner (owner_id, char_slot)
);

-- server/persistence.lua
function SavePet(ownerId, charSlot, state)
    MySQL.update([[
        UPDATE pets SET
            hunger = ?, happiness = ?, health = ?,
            bond = ?, is_active = 1, updated_at = NOW()
        WHERE owner_id = ? AND char_slot = ?
    ]], {
        state.hunger, state.happiness, state.health,
        state.bond, ownerId, charSlot
    })
end

function LoadPet(ownerId, charSlot)
    return MySQL.single.await([[
        SELECT * FROM pets
        WHERE owner_id = ? AND char_slot = ?
        AND is_active = 1
    ]], {ownerId, charSlot})
end

Police K-9 Integration and Special Roles

For law enforcement roleplay, extend the pet system into a full K-9 unit integration. Police dogs gain special abilities not available to civilian pets. The search command makes the K-9 sniff nearby vehicles or buildings and alert on configurable contraband items by barking and sitting next to the source. Implement this by checking the inventories of nearby players or vehicle trunks for flagged items when the search command is issued. The track command makes the K-9 follow a scent trail, which you can implement by creating a breadcrumb trail of positions from a fleeing suspect and tasking the dog to follow them. The apprehend command makes the K-9 sprint toward a target and play an attack animation, giving officers a non-lethal option for suspect takedowns. Restrict these abilities to players with the police job and K-9 handler certification. The K-9 should wear a police vest using ped component variations or prop attachments to visually distinguish it from civilian pets. This specialization creates a unique and highly sought-after position within the police department hierarchy.

Share this article

Ready to upgrade your server?

Check out our premium FiveM scripts in the Agency Scripts store or join our Discord community for support and updates.