Multiplayer¶
Set it up single-player, ship multiplayer. The IC is server-authoritative and replicates its running state: there is no separate multiplayer mode to opt into, only settings to leave alone or tune.
Save the real screenshot as: shot-multiplayer-two-clients.png
Turning it on¶
bReplicateActions (default true) on the IC, plus the owning actor
having Replicates set. That's the whole opt-in, no per-Group or
per-Cycle flag to remember.
Late join: ReplicatedActionStates¶
Running groups (a spinning fan, a half-open door) live in
ReplicatedActionStates on the IC. A client that joins mid-game
reconstructs each of them at the correct timeline phase via
OnRep_ActionStates: a late joiner sees the fan already spinning, not
restarting from zero.
Route client requests via the Interactor¶
Important
Client requests must go via the player-owned Interactor, never call
Server_* on a world-placed actor directly. A Server RPC called straight
on a server-owned interactable is dropped with no error: Unreal only routes
a Server RPC from the actor's owning connection, and a world-placed door
is owned by the server, not by any client.
MovaInteract routes every client request (interaction, typed command,
proximity) via the player-owned UMovaIxInteractorComponent
instead:
Server_TargetInteraction(IC, ChoiceIndex, AnchorName)Server_TargetAction(IC, GroupName, TargetName)Server_TargetTags(IC, Tags)
Each takes the target IC as a parameter, so the RPC itself travels over
the pawn's connection (which the client owns) while still
naming an arbitrary world actor to act on. A collapsed multi-choice pick is
addressed by its source point (ResolveServerAddress(Point, ChoiceIndex, OutAnchor, OutServerIndex)) so the server re-resolves the
raw point by anchor and rebuilds it identically from tags, instead of
trusting a client-computed collapsed index.
sequenceDiagram
participant C as Client (pawn)
participant I as Interactor (owned by client)
participant S as Server (IC authority)
participant O as Other clients
C->>I: TargetInteraction(ChoiceIndex)
I->>S: Server_TargetInteraction(IC, ChoiceIndex, Anchor)
Note over S: WithValidation + range check
S->>S: Execute group, update ReplicatedActionStates
S-->>C: Multicast group start/stop
S-->>O: Multicast group start/stop
Note over C,O: Every client renders the same phase
Validated + range-verified¶
All the Server_* RPCs above are WithValidation. Beyond that,
every networked interaction is distance-verified server-side so a
modified client cannot trigger an object across the map by sending a raw
RPC with a fabricated IC reference:
bServerVerifyRange(Project Settings → Plugins → Mova Interact → Network, default on) enables the check.ServerRangeSlackwidens the allowed distance to absorb normal network lag: a client's aim can have moved a little by the time the RPC lands.The reject is soft: out-of-range requests are dropped and logged, never a kick or a hard disconnect. A laggy but honest player never gets punished for it. Only a request that's implausible even with slack gets ignored.
Replicated grab¶
Grab / carry / throw (see Grab, carry & throw) follows the identical
pattern: the client aims and requests locally, the server re-validates
(IsGrabbable + IsGrabInServerRange + a clamped throw strength) and owns
the physics handle, and HeldComponent's replication drives OnGrabbed /
OnReleased / OnThrown on every machine via OnRep_Held. The carried
object itself still needs to be a replicated actor with replicated movement
to visibly move on remote clients.
Verifying it¶
To eyeball it in PIE with 2+ clients, turn on the debug
overlay's net-role banner, it always shows while mova.ix.Debug is on, so
it doubles as your multiplayer diagnostic view (see Debug overlay & troubleshooting):
Save the real screenshot as: shot-debug-overlay-net-banner.png
See also¶
Grab, carry & throw: the grab system's own multiplayer section, in more depth.
Tag Grammar Reference:
%Actor^delegation, relevant when a networked tag hands off execution to another actor's IC.Debug overlay & troubleshooting: the
mova.ix.Debugnet-role banner (SERVER / CLIENT) is invaluable when diagnosing "works in single-player, not in PIE with 2 clients."