How-To: React to Equipment Changes
Goal: update a HUD, play a sound, or refresh a paper doll when gear changes - on the machine that has to show it, which is almost never the server.
1. Know which signal to use
There are three, and picking the wrong one is why equipment UI usually fails to update on clients.
| Signal | Where it fires | Use it for |
|---|---|---|
On Equipment Changed delegate | Server only. Broadcast from Equip Item, Unequip Item, Swap Equipped Items and Move Equipped Item To Slot, and never from the replication callbacks. | Server-side game logic. Not for UI - a client widget bound to it is never called. |
On Equipment Changed Message (native OnEquipmentChangedMessageNative) | Server and every client. On the server from the mutation itself; on clients when the equipment list replicates. | UI and cosmetics. Carries the typed UCrimsonEquipmentInstance (channel Crimson.Equipment.Message.Changed). |
On Equipment Source Changed (native OnEquipmentSourceChangedNative) | Same machines and the same moment - the two always fire together. | Item systems and paper dolls that track their own object: carries the source object and the host, not the instance (channel Message.Equipment.SourceChanged). |
On Equipment Changed is a BlueprintAssignable delegate on the manager, which makes it look like the obvious thing for a widget to bind. It is broadcast only from the authority paths, so on a client it never fires. Use On Equipment Changed Message for anything a player sees.On Equipment Changed on a client and equip from the server: nothing prints in the client window. A handler bound to On Equipment Changed Message in the same widget prints.2. Bind the typed event
FCrimsonEquipmentChangedMessage carries Instance, Slot Tag and b Equipped; the delegate also passes the channel tag Crimson.Equipment.Message.Changed.
In your widget: Event Construct -> Get Equipment Manager (from the pawn) -> Bind Event to On Equipment Changed Message. In the event, break the message and branch on b Equipped, then refresh the cell for Slot Tag. Bind once in Event Construct; unbind in Event Destruct.
b Equipped true and the correct slot tag.3. Track your own item
FCrimsonEquipmentSourceChangedMessage (Equipment/CrimsonEquipmentBridgeTypes.h) is keyed by the object you passed as the source, so an item widget can match it against its own item. It carries Host, Source Object, Definition Class, Slot Tag, Slot Index and b Equipped.
Bind Event to On Equipment Source Changed on the manager. Break the message and compare Source Object against the item your widget is showing.
Source Object is whatever the instance returns on that machine. A client whose copy of your item has not replicated yet reads null, even though the server's message carried it. Treat null as 'not resolved yet' rather than 'nothing', and re-check on your item's own replication.4. Refresh anything that draws the character
Every equip, unequip, swap and move also fires On Character Look Changed (OnCharacterLookChangedNative, payload FCrimsonCharacterLookChangedMessage with just the pawn, channel Message.Character.LookChanged). That is the cheap signal for anything that has to re-read the whole look rather than one slot.
Bind Event to On Character Look Changed on the manager, compare the message's Pawn to yours, and rebuild.
Swap Equipped Items and Move Equipped Item To Slot fire only the look-changed event - no changed event, no source-changed event, and no client-side callback at all, because the equipment list's PostReplicatedChange is deliberately empty (nothing was equipped or unequipped, so the lifecycle hooks must not run again). A UI that only binds the changed event will show stale slot positions after a swap. Listen to look-changed as well and re-read the slots.See also
- How-To: Add Per-Item Logic
- Concept: Multiplayer
- API Reference