Concept: Multiplayer
Equipment is server-authoritative with no client prediction. The server mutates; clients receive. Everything below follows from that, and most equipment bugs are one of these facts being assumed away.
Where things run
| Operation | Runs on | Notes |
|---|---|---|
Equip Item, Unequip Item, Unequip Item In Slot | Server | BlueprintAuthorityOnly. On a client the node does nothing and an error is logged. |
Swap Equipped Items, Move Equipped Item To Slot | Server | Same. They only rewrite slot fields. |
Gather Save Data, Restore From Save Data | Server | Without authority they warn and no-op. |
ICrimsonEquipmentHost::Equip | Server | Fails with "Equip requires authority." otherwise. |
| Every query node | Any machine | The equipment list replicates to all connections, so clients get the same answers. |
OnEquipped / OnUnequipped | Server and every client | On the server from the mutation; on clients from the list's replication callbacks. Gate authoritative work. |
On Equipment Changed delegate | Server only | Never broadcast from the replication callbacks. |
| The equipment messages | Server and every client | The client-side path fires from the replication callbacks. |
All Machines visual actors | Every machine, locally, non-replicated | Late joiners spawn theirs when the instance replicates in. |
Server Only visual actors | Server | The actor class must replicate itself, or clients see nothing. |
| Ability grants | Wherever the ASC has authority | Handles are NotReplicated. |
This plugin ships no RPCs
There are no Server_, Client_ or Multicast_ functions anywhere in CrimsonEquipment, and therefore no _Validate functions. That is deliberate: routing player intent is the game's job, not a gear system's, and where the RPC lives - PlayerController, pawn, an interaction component - varies per project.
The practical consequence is that a client UI wired straight to Equip Item does nothing at all. Every player-driven equip needs a server RPC your project owns, and that RPC is where you validate that the player may do it. Can Equip Item gates rules about the character; ownership and legality are yours. How-To: Get the Building Blocks, step 4, has the shape.
What replicates, and how
| State | Mechanism | Condition |
|---|---|---|
EquipmentList on the manager | FFastArraySerializer delta serialization | COND_None - every connection, not just the owner. Other players see your gear, which is the point. |
SourceObject on the instance | ReplicatedUsing = OnRep_SourceObject | COND_None. Resolves only once the object itself has replicated to that client. |
Definition on the instance | ReplicatedUsing = OnRep_Definition | COND_None. Its arrival is what makes a client spawn its cosmetic actors. |
| Granted ability handles | Not replicated | Authority-only by design. |
SpawnedActors on the instance | Not replicated | Per machine. Each machine spawns and owns its own. |
| The slot layout | Not replicated | Duplicated from Blueprint defaults on both sides. |
The instance is registered as a replicated subobject of the manager - through AddReplicatedSubObject on the registered-subobject list, through the legacy ReplicateSubobjects override, and through Iris fragments. Adding a Replicated property to your own instance subclass needs nothing but the property and its DOREPLIFETIME line.
The ordering a client sees
A client learns about an equip through the fast array, in this order: the entry is added, OnEquipped runs on the instance, then the changed and source-changed messages are broadcast, then look-changed. On removal it is the mirror: OnUnequipped, the actors are destroyed, then the messages.
Fast-array callbacks never run on the authority, so a listen-server host does not double-broadcast: the host gets the messages once, from the server-side mutation path.
Ordering hazards to design around
- The manager arrives late on clients. It is added on the server and replicates down, so a client's pawn exists before its manager does. Look it up when you need it; do not cache it from a possession callback.
- Components added by a Game Feature arrive later still. Wait on the
Crimson.SystemReady.Equipmentfeature state (RegisterAndCallForActorInitState) rather than binding fromBeginPlay. - `SourceObject` can be null on a client even when the equip has arrived, because the object replicates on its own schedule. Treat null as not-yet-resolved.
- Swaps and moves notify clients only through look-changed, because
PostReplicatedChangeis empty by design. UI that tracks positions must re-read. - Teardown still broadcasts unequip messages. When the component is uninitialized the server force-unequips everything and deliberately still fires the unequip messages, so listeners can clean up; the
On Equipment Changeddelegate is skipped in that path.
A test that catches the common failures
- Play As Client, 2 players. Equip from the server: the gear appears in both windows.
- Call
Equip Itemdirectly from the client: nothing happens, and the client log carries an authority error. That is the missing-RPC failure. - Join late, or re-possess: the gear is still there, spawned locally by the joining client from the replicated instance.
- Swap two equipped items: the client's look-changed listener fires and a re-read returns the new positions.
- Unequip: actors disappear in both windows and the ability grants are gone from the server's
showdebug abilitysystem.