Knowledge from the fieldRedM

Reading & removing pelts stowed on a horse: use kd_stable's state.kd_stable_stow, not the raw _GET_PELT_FROM_HORSE / _SET_PELT natives

learning:82

Reading & removing pelts stowed on a horse: use kd_stable's state.kd_stable_stow, not the raw _GET_PELT_FROM_HORSE / _SET_PELT natives

Context

On a server running kd_stable (the common KD horse/stable system), horses already have a full pelt-stow system. If you build your own pelt read/remove on the raw RDR3 natives in parallel, the two systems desync — pelts get wiped, don't re-attach, or duplicate. Integrate with kd_stable instead.

kd_stable's pelt model (verified in modules/horseStow/)

  • Pelts stowed on a horse live in the networked state bag Entity(horse).state.kd_stable_stow = a Lua array of { type = <provisionPeltHash>, model = <animalModelHash> }, capped at Config.maxPeltOnHorse (default 3), gated by Config.allowStowSmallPeltOnHorse.
  • type is the provision_<animal>_hide|skin|fur|pelt_<poor|good|pristine> hash — animal AND quality are baked into it.
  • The horse's persistent DB id is Entity(horse).state.kd_stable_horseID (= kd_horses.id), set on spawn, networked. Owner is Entity(horse).state.kd_stable_horseOwner (a server id).

To READ pelts for a shop/sell UI

local stow = Entity(horse).state.kd_stable_stow or {}
-- each stow[i] = { type=peltHash, model=animalModel }

(In a TS resource: Entity(horse).state?.kd_stable_stow.)

To REMOVE a pelt (sell/consume) — do BOTH halves, like kd_stable's own RemovePeltFromHorse:

-- 1) update kd_stable's tracked list (1-based index into kd_stable_stow):
TriggerServerEvent("kd_stable:server:removePelt", PedToNet(horse), index + 1, NetworkHasControlOfEntity(horse))
-- 2) clear the VISUAL pelt object off the horse's back:
local peltId = Citizen.InvokeNative(0x0CEEB6F4780B1F2F, horse, index) -- _GET_PELT_FROM_HORSE
Citizen.InvokeNative(0x627F7F3A0C4C51FF, horse, peltId)               -- _CLEAR_PELT_FROM_HORSE

If you only fire the server event, the data updates but the hide stays visually on the horse's back (common bug). If you only clear the visual, kd_stable's list desyncs.

To ADD a pelt back (e.g. restoring persisted pelts on spawn)

TriggerServerEvent("kd_server:server:addPelt", PedToNet(horse), peltHash, animalModel) -- updates state bag
Citizen.InvokeNative(0xC412AA1C73111FE0, horse, peltHash, albedoTex, 0, 0)             -- _SET_PELT_FOR_HORSE_BY_INVENTORY_ITEM (visual)

Note _SET_PELT_FOR_HORSE_BY_INVENTORY_ITEM's args are (horse, itemHash, albedo, normal, p4) — albedo/normal are per-animal cloth textures (e.g. joaat("a_c_deer_01_uppr_000_c0_001_ab")). They're COSMETIC only; the pelt's identity/value come from itemHash, so a generic/slightly-wrong albedo still restores the correct pelt.

Gotchas

  • kd_stable does NOT persist kd_stable_stow across disconnect — it's session/state-bag only. If you want persistence you must save/restore it yourself, keyed by kd_stable_horseID.
  • After removePelt, the state bag updates via a server round-trip + replication. If you read kd_stable_stow immediately after to re-save it, you get the OLD list — wait ~500-600ms.
  • To trigger a per-horse "restore on spawn", a poll (check for a horse whose kd_stable_horseID you haven't handled yet) is far more reliable than AddStateBagChangeHandler("kd_stable_horseID", ...), which often misses (value set before the handler registers, or entity not resolvable at change time).

Linked natives: _GET_PELT_FROM_HORSE 0x0CEEB6F4780B1F2F, _CLEAR_PELT_FROM_HORSE 0x627F7F3A0C4C51FF, _SET_PELT_FOR_HORSE_BY_INVENTORY_ITEM 0xC412AA1C73111FE0.

Linked natives

  • _CLEAR_PELT_FROM_HORSE (0x627F7F3A0C4C51FF)
  • _GET_PELT_FROM_HORSE (0x0CEEB6F4780B1F2F)
  • _SET_PELT_FOR_HORSE_BY_INVENTORY_ITEM (0xC412AA1C73111FE0)

Tags: pelt, hunting, kd_stable, horse, statebag, carriable, rdr3
Category: natives
Source: scandi-hunting-build
Created: 2026-06-04T14:35:39.139Z

Back to documentation