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.

multiplayer two clients (placeholder mockup)

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.

Server-authoritative execution + multicast

The server runs interactions and multicasts group start/stop to every client. Visible motion on a client is driven by replicated data, not a local guess re-simulating the same tween, so a slow or lagging client still sees the door open at the same rate and phase as everyone else.

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.

  • ServerRangeSlack widens 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):

debug overlay net banner (placeholder mockup)

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.Debug net-role banner (SERVER / CLIENT) is invaluable when diagnosing "works in single-player, not in PIE with 2 clients."