com.unity.netcode.gameobjects is installed — without that package it is entirely absent: no errors, no stubs, and the core stays exactly the network-free asset it is without it.The Architecture in One Paragraph
Every networked feature is a pure component paired with a replicator. The pure component — Transform Controller, Prop Stat Sheet, Round System, Prop Whistle — never knows the network exists. The replicator sits next to it on the same prefab, subscribes to its events on the way out, calls its entry points on the way in, and is dormant offline: without a listening NetworkManager, OnNetworkSpawn never fires and the prefab behaves exactly as it does in a singleplayer scene. One prefab, every mode.
Pure component Replicator (next to it, same prefab)
-------------- ------------------------------------
PropTransformController --events--> PropTransformReplicator --> the wire
<--calls--- <-- the wire
PropStatSheet ---------> PropStatReplicator
RoundSystem ---------> RoundReplicator (server-authoritative)
PropWhistle ---------> PropWhistleReplicator
Presentation - highlights, transform FX, own-view hiding, camera
framing - is never replicated. Each peer decides what its player sees.Who Owns What
| State | Authority | What travels |
|---|---|---|
| Disguise — Prop Transform Replicator | Owner | The PropDefinition ID, 32 characters. Every machine rebuilds the clone, hitbox and FX locally from its own scene. |
| Stats — Prop Stat Replicator | Owner | Current and max per stat, index-aligned with the sheet. A damage instruction run on any other machine is routed to the owner instead of applied. |
| Round — Round Replicator | Server | Phase, round number, the phase deadline as server time, the outcome, and eliminations as events. Props Alive is never sent — each peer derives it. |
| Whistle — Prop Whistle Replicator | Owner | The action only. Each machine's cooldown timer starts itself. |
| Transform / animation | Owner | Client Network Transform and Owner Network Animator — owner-authoritative, because the Game Creator character motor runs where the input is. |
Is Alive and to the eliminated mark.Setup
Three steps, and two of them are what you would do for any Game Creator module.
- Install the Netcode package
Package Manager → Install by name →
com.unity.netcode.gameobjects. Do this before installing the samples: their prefabs carry multiplayer components, and a prefab opened and saved while its scripts are missing can lose them. - Install the samples
Everything arrives wired — the player and hunter prefabs, the Network Manager and the Host/Join menu, the round object, and a networked sample scene. If you skipped step 1, a dialog offers to install the package once the samples are in; take it before opening any of those prefabs.
- Open the Setup window and clear any red row
In a fresh project exactly one is red: the sample scenes are not in Build Settings. That is project settings rather than assets, so no package can deliver it. One click fixes it.
Then press Play in the menu scene. Host puts you in the arena as the hunter; Join, from a second instance, arrives as a prop player.
127.0.0.1 from the other.Spawn Points and the Hunt-Phase Release
Add a Player Spawn Point to one GameObject in the arena with role Prop Player, and one in the hunters' staging area with role Hunter. Spawned players are placed at their role's point automatically — on spawn and on every scene load — with a small scatter radius so simultaneous joiners do not stack.
To release hunters into the arena when the hunt begins, put this trigger on the hunter prefab:
Trigger: On Round State Changed
Condition: Is Round Phase = Hunt
Instruction: Move To Spawn Point Target = Self Spawn Point = Prop PlayerPlacement is network-correct end to end: the character moves through the Game Creator driver (a motor-driven character silently undoes plain transform writes), and on a networked character the owner performs a proper network teleport, so other machines see a jump instead of an interpolated slide through the level. On machines that do not own the character the instruction deliberately does nothing — the replicated result is the mover.
Bringing Your Own Character
The sample prefabs ship wired; yours will not be. Right-click your prefab → Transformation System → Wire For Multiplayer → Prop Player — or Hunter, or Round System for a round object. It adds exactly the components listed on the Components page, is idempotent, and logs what it changed.
Also move the camera rig and the HUD canvas under the prefab and list them in Owner Only Objects; list input-reading components that cannot move to a child under Owner Only Behaviours. Leave Auto Register As Prop on for hiders and turn it off on a hunter prefab.
Authoring Rules for Networked Scenes
One Prop Definition per distinct look
The wire carries the definition ID, and a remote machine rebuilds the disguise from the first active world prop with that definition. Two different-looking props sharing one definition means a player disguised as one can appear as the other on remote screens. A chair, a table and a crate are three definitions, all in the registry.
Do not mark cloneable props Static
A static-batched mesh can render wrongly when its object is cloned at runtime — the disguise looks fine in the editor and breaks in a build.
Role-specific scene UI needs a visibility component
A canvas exists on every machine, so a hunter panel authored in the scene shows on prop players' screens too. Put a Network Role Visibility component on the canvas — next to the panel, never on it, since a deactivated object cannot run its own components — point it at the panel and choose who sees it. Offline it does nothing, so singleplayer scenes stay as authored.
Remote copies are inert by construction
On machines that do not own a player, the bootstrap disables that copy's Prop Highlight, Hunter Interaction and Prop Whistle, and the disabled components refuse input calls — so your clicks cannot fire someone else's hunter, and your whistle key cannot whistle through someone else's character.
Aiming needs no wiring
Hunter Interaction and Prop Highlight resolve their Ray Origin at use time: an explicit assignment wins, otherwise the main camera — so the ray leaves the camera along its forward, exactly the centre of the screen, and a crosshair is honest in every mode, including for characters spawned at runtime from a prefab that cannot reference a scene camera.
Only the host starts rounds
Keep the Start Round instruction in a host-driven trigger. On a client the call is simply ignored, with a console note. By default, joins are refused once a round is past Waiting — "The round has already started." — so a hunter cannot materialise mid-hunt.
How Damage Flows in a Networked Match
Author damage prop-side, which is the pattern the samples already use:
On Was Found -> Deal Damage Target = Self Amount = <your number> (prop player prefab)
On Wrong Guess -> Deal Damage Target = Self Amount = <your number> (hunter prefab)The hunter inspects on their own machine; the disguise they strike is the replicated clone, so correct and wrong guesses evaluate locally with no round-trip. The resulting Deal Damage lands on whatever machine ran the trigger — and the stat replicator delivers it to the owner, whose write then mirrors back to everyone. Vital depletion fires on every machine; each one's Report Prop Eliminated either counts (host) or is forwarded (clients), and duplicates are idempotent by design.
On Was Found fires on the machine whose hunter guessed — it is not forwarded to the found player's machine. For "you were found" feedback on the victim's own screen, react to On Vital Depleted or On Stat Changed, which replicate through the stats.Scope & Limits
Included
- Host / join by address
- Replicated disguise, stats, round and whistle
- Owner-authoritative transform and animation
- Role-keyed spawn points and role visibility
- A lobby-style menu flow with a status label
- Right-click Wire For Multiplayer on your own prefab
- A networked sample scene, ready to play
Deliberately not included
- Relay, NAT traversal and matchmaking — these need per-project accounts and keys no asset can ship for you
- Session discovery
- Server-side anti-cheat
Out of the box the module is direct-connect: the host opens a UDP port and clients enter an address — which covers LAN, VPN tools and port-forwarded hosts. The seam for adding a backend is small: authenticate, exchange the address (or relay allocation) through your service, then call NetworkSession.StartClient / StartHost exactly as the launcher does.
The topology is owner-authoritative, the standard trust model for co-op and party games — the same one the round lock, capacity gate and server-decided eliminations already enforce at the edges. A fully server-authoritative competitive topology would need the character motor to run host-side, which Game Creator's motor does not do.
Using Another Stack
The core contains no networking code, so Photon, Fusion or your own transport goes around it without editing anything in the package. The events are your outbound hooks; the entry points are your inbound ones. The shipped module is the reference implementation of exactly these seams.
Owner Everyone else
----- -------------
player picks a prop
TransformInto(worldProp) -> TransformIntoById(id)
OnTransformComplete fires OnTransformComplete fires
server starts the round
StartRound(prep, hunt) -> StartRound(prep, hunt)
OnRoundStateChanged fires OnRoundStateChanged fires
server applies damage
SetStat(health, value) -> SetStat(health, value)
OnVitalDepleted fires (if empty) OnVitalDepleted fires (if empty)
ReportPropEliminated -> ReportPropEliminatedTwo details worth knowing before you write that layer:
- Prefer SetStat to ModifyStat when replicating. A dropped or duplicated ModifyStat leaves two peers permanently apart; a repeated SetStat is harmless.
- Unsubscribe from the static
OnAny…events on teardown. With domain reload disabled, a handler from the previous session survives, throws from inside the invocation list, and silently skips every subscriber after it. The package clears its own statics on subsystem registration; do not rely on the scene going away.
TransformInto(PropDefinition) sets Is Disguised without creating a disguise — that is the state-only overload for a peer that will build the visuals itself. It is also why HasVisibleDisguise exists: a hunter scores a correct guess only against a disguise that is actually in the scene, so a state-only peer cannot be "found" for standing around looking like themselves.