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

OperationRuns onNotes
Equip Item, Unequip Item, Unequip Item In SlotServerBlueprintAuthorityOnly. On a client the node does nothing and an error is logged.
Swap Equipped Items, Move Equipped Item To SlotServerSame. They only rewrite slot fields.
Gather Save Data, Restore From Save DataServerWithout authority they warn and no-op.
ICrimsonEquipmentHost::EquipServerFails with "Equip requires authority." otherwise.
Every query nodeAny machineThe equipment list replicates to all connections, so clients get the same answers.
OnEquipped / OnUnequippedServer and every clientOn the server from the mutation; on clients from the list's replication callbacks. Gate authoritative work.
On Equipment Changed delegateServer onlyNever broadcast from the replication callbacks.
The equipment messagesServer and every clientThe client-side path fires from the replication callbacks.
All Machines visual actorsEvery machine, locally, non-replicatedLate joiners spawn theirs when the instance replicates in.
Server Only visual actorsServerThe actor class must replicate itself, or clients see nothing.
Ability grantsWherever the ASC has authorityHandles 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

StateMechanismCondition
EquipmentList on the managerFFastArraySerializer delta serializationCOND_None - every connection, not just the owner. Other players see your gear, which is the point.
SourceObject on the instanceReplicatedUsing = OnRep_SourceObjectCOND_None. Resolves only once the object itself has replicated to that client.
Definition on the instanceReplicatedUsing = OnRep_DefinitionCOND_None. Its arrival is what makes a client spawn its cosmetic actors.
Granted ability handlesNot replicatedAuthority-only by design.
SpawnedActors on the instanceNot replicatedPer machine. Each machine spawns and owns its own.
The slot layoutNot replicatedDuplicated 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.

A listen-server host is the server
Equipment that appears to work when you test in a single PIE window is being exercised entirely on the authority. Test with Net Mode = Play As Client and at least 2 players, and read the client window - that is the only place a missing RPC, an unreplicated property, or a client-side null source object shows up.

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.Equipment feature state (RegisterAndCallForActorInitState) rather than binding from BeginPlay.
  • `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 PostReplicatedChange is 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 Changed delegate is skipped in that path.

A test that catches the common failures

  1. Play As Client, 2 players. Equip from the server: the gear appears in both windows.
  2. Call Equip Item directly from the client: nothing happens, and the client log carries an authority error. That is the missing-RPC failure.
  3. Join late, or re-possess: the gear is still there, spawned locally by the joining client from the replicated instance.
  4. Swap two equipped items: the client's look-changed listener fires and a re-read returns the new positions.
  5. Unequip: actors disappear in both windows and the ability grants are gone from the server's showdebug abilitysystem.