Skip to content
This repository was archived by the owner on Jul 23, 2025. It is now read-only.

Commit 9051e4c

Browse files
authored
Add Multiplayer Play Mode info to local testing page (#1257)
1 parent 551a283 commit 9051e4c

File tree

2 files changed

+42
-121
lines changed

2 files changed

+42
-121
lines changed

docs/learn/rpcvnetvar.md

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,99 +5,99 @@ sidebar_label: RPC vs NetworkVariable
55
---
66
import ImageSwitcher from '@site/src/ImageSwitcher.js';
77

8-
Choosing the wrong data syncing mecanism can create bugs, generate too much bandwidth and add too much complexity to your code.
9-
Netcode for GameObjects (Netcode) has two main ways of syncing information between players. `RPC` ([Remote Procedure Call](../advanced-topics/messaging-system)) and replicated state [(NetworkVariable)](../basics/networkvariable). They both send messages over the network. The logic and your design around how they send messages is what will make you choose one over the other.
8+
Choosing the wrong data syncing mechanism can create bugs, use too much bandwidth, and add too much complexity to your code.
9+
Netcode for GameObjects (Netcode) has two main ways of syncing information between players: RPCs ([Remote Procedure Calls](../advanced-topics/messaging-system.md)) and replicated states [(`NetworkVariable`s)](../basics/networkvariable). They both send messages over the network. The logic and your design around how they send messages is what will make you choose one over the other.
1010

11-
## Choosing between NetworkVariables or RPCs
11+
## Choosing between `NetworkVariable`s or RPCs
1212

13-
- Use `RPC`s for transient events, information only useful for a moment when it's received.
13+
- Use RPCs for transient events, information only useful for a moment when it's received.
1414
- Use `NetworkVariable`s for persistent states, for information that will be around more than a moment.
1515

1616
A quick way to choose which to use is to ask yourself: "Should a player joining mid-game get that information?"
1717

1818
<figure>
19-
<ImageSwitcher
19+
<ImageSwitcher
2020
lightImageSrc="/sequence_diagrams/NetworkVariable/NetworkVariables_LateJoinClient.png?text=LightMode"
2121
darkImageSrc="/sequence_diagrams/NetworkVariable/NetworkVariables_LateJoinClient_Dark.png?text=DarkMode"/>
2222
<figcaption>Network Variables allow to seamlessly catch up late joining clients by sending the current state as soon as the tick happens.</figcaption>
2323
</figure>
2424

2525
Using the Boss Room's door as an example. A player's client needs to receive the information that the door is open to play the right animations.
2626

27-
If we sent an `RPC` to all clients, then all players connecting mid game after that `RPC` are sent will miss that information and have the wrong visual on their clients.
27+
If we sent an RPC to all clients, then all players connecting mid-game after that RPC is sent will miss that information and have the wrong visual on their clients.
2828

2929
<figure>
30-
<ImageSwitcher
30+
<ImageSwitcher
3131
lightImageSrc="/sequence_diagrams/NetworkVariableVSRPCs/RPCsLateJoin.png?text=LightMode"
3232
darkImageSrc="/sequence_diagrams/NetworkVariableVSRPCs/RPCsLateJoin_Dark.png?text=DarkMode"/>
3333
<figcaption>Sending state with RPCs won't be transmitted to late joining clients.</figcaption>
3434
</figure>
3535

3636

37-
In that case, it's preferable to use `NetworkVariable`s like shown here.
37+
In that case, it's preferable to use `NetworkVariable`s as show below:
3838

3939
```csharp reference
4040
https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop/blob/v2.2.0/Assets/Scripts/Gameplay/GameplayObjects/SwitchedDoor.cs#L10-L26
4141
```
4242

43-
It uses a `BoolNetworkVariable` to represent the "IsOpen" state. If I open the door and a player connects after this, the host will replicate all the world's information to that new player, including the door's state.
43+
It uses a `BoolNetworkVariable` to represent the `IsOpen` state. If one player opens the door and a second player connects after this, the host replicates all the world's information to that new player, including the door's state.
44+
45+
`NetworkVariable`s are eventually consistent. This means not all value changes will be synced, contrary to RPCs, where five calls to an RPC will produce five RPC sends on the network.
4446

45-
NetworkVariables are eventually consistent. This means not all value changes will be synced, contrary to RPCs, where 5 calls to an RPC will produce 5 RPC sends on the network.
4647
<figure>
47-
<ImageSwitcher
48+
<ImageSwitcher
4849
lightImageSrc="/sequence_diagrams/NetworkVariable/NetworkVariables.png?text=LightMode"
4950
darkImageSrc="/sequence_diagrams/NetworkVariable/NetworkVariables_Dark.png?text=DarkMode"/>
5051
<figcaption>Network Variables can be updated multiple times between ticks, but only the latest will be synced to other peers.</figcaption>
5152
</figure>
5253

53-
NetworkVariables will save on bandwidth for you, making sure to only send values when the data has changed. However, if you want all value changes, RPCs might be best.
54+
`NetworkVariable`s will save on bandwidth for you, making sure to only send values when the data has changed. However, if you want all value changes, RPCs might be best.
55+
56+
## Why not use `NetworkVariable`s for everything?
5457

58+
RPCs are simpler.
5559

56-
## Why not use NetworkVariables for everything?
60+
If you have a temporary event like an explosion, you don't need a replicated state for this. It would not make sense. You would have an "unexploded" state that would need to be synced every time a new player connected? From a design perspective, you might not want to represent these events as state.
5761

58-
`RPC`s are simpler.
62+
An explosion can use an RPC for the event, but the effect of the explosion should be using `NetworkVariable`s (for example player's knockback and health decrease). A newly connected player doesn't care about an explosion that happened five seconds ago. They do care about the current health of the players around that explosion though.
5963

60-
If you have a temporary event like an explosion, you don't need a replicated state for this. It would not make sense. You would have an "unexploded" state that would need to be synced everytime a new player connected? From a design perspective, you might not want to represent these events as state.
64+
Actions in Boss Room are a great example for this. The area of effect action (`AoeAction`) triggers an RPC when the action is activated (showing a VFX around the affected area). The imp's health (`NetworkVariable`s) is updated. If a new player connects, they will see the damaged imps. We would not care about the area of effect ability's VFX, which works great with a transient RPC.
6165

62-
An explosion can use an `RPC` for the event, but the effect of the explosion should be using `NetworkVariable`s ( for example player's knockback and health decrease). A newly connected player doesn't care about an explosion that happened 5 seconds ago. They do care about the current health of the players around that explosion though.
63-
64-
Actions in Boss Room are a great example for this. The area of effect action (`AoeAction`) triggers an `RPC` when the action is activated (showing a VFX around the affected area). The imp's health (`NetworkVariable`s) is updated. If a new player connects, they will see the damaged imps. We would not care about the area of effect ability's VFX, which works great with a transient `RPC`.
65-
66-
`AoeActionInput.cs` Shows the input being updated client side and not waiting for the server. It then calls an `RPC` when clicking on the area to affect.
66+
`AoeActionInput.cs` Shows the input being updated client side and not waiting for the server. It then calls an RPC when clicking on the area to affect.
6767

6868
```csharp reference
6969
https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop/blob/v2.2.0/Assets/Scripts/Gameplay/Action/Input/AoeActionInput.cs
7070
```
7171

72-
`AOEAction.cs` Server side logic detecting enemies inside the area and applying damage. It then broadcasts an `RPC` to tell all clients to play the VFX at the appropriate position. Character's state will automatically update with their respective `NetworkVariable`s update (health and alive status for example).
72+
`AOEAction.cs` has server-side logic detecting enemies inside the area and applying damage. It then broadcasts an RPC to tell all clients to play the VFX at the appropriate position. Character's state will automatically update with their respective `NetworkVariable`s update (health and alive status for example).
7373

7474

7575
```csharp reference
7676
https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop/blob/v2.2.0/Assets/Scripts/Gameplay/Action/ConcreteActions/AOEAction.cs#L8-L-40
7777
```
7878

79-
The following snippet of code is triggered by an `RPC` coming from the server
79+
The following snippet of code is triggered by an RPC coming from the server
8080

8181
```csharp reference
8282
https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop/blob/v2.2.0/Assets/Scripts/Gameplay/Action/ConcreteActions/AOEAction.cs#L77-L82
8383
```
8484

8585
:::tip
86-
If you want to make sure two variables are received at the same time, `RPC`s are great for this.
86+
If you want to make sure two variables are received at the same time, RPCs are great for this.
8787

88-
If you change `NetworkVariables` "a" and "b", there is no guarantee they will both be received client side at the same time.
88+
If you change `NetworkVariables` "a" and "b", there is no guarantee they will both be received client side at the same time.
8989

9090
<figure>
91-
<ImageSwitcher
91+
<ImageSwitcher
9292
lightImageSrc="/sequence_diagrams/NetworkVariable/NetVarDataUpdates.png?text=LightMode"
9393
darkImageSrc="/sequence_diagrams/NetworkVariable/NetVarDataUpdates_Dark.png?text=DarkMode"/>
9494
<figcaption>Different Network Variables updated within the same tick aren't guranteed to be delivered to the clients at the same time. </figcaption>
9595
</figure>
9696

97-
Sending them as two parameters in the same `RPC` allows to make sure they will be received at the same time client side.
97+
Sending them as two parameters in the same RPC ensures they will be received at the same time client side.
9898

9999
<figure>
100-
<ImageSwitcher
100+
<ImageSwitcher
101101
lightImageSrc="/sequence_diagrams/NetworkVariableVSRPCs/ManagingNetVarData_RPCs.png?text=LightMode"
102102
darkImageSrc="/sequence_diagrams/NetworkVariableVSRPCs/ManagingNetVarData_RPCs_Dark.png?text=DarkMode"/>
103103
<figcaption>To ensure that several different Network Variables are all synchronized at the same exact time we can use client RPC to join these value changes together.</figcaption>
@@ -112,5 +112,4 @@ darkImageSrc="/sequence_diagrams/NetworkVariableVSRPCs/ManagingNetVarData_RPCs_D
112112

113113
`NetworkVariable`s are great for managing state, to make sure everyone has the latest value. Use them when you want to make sure newly connected players get an up to date world state.
114114

115-
`RPC`s are great for sending transient events. Use them when transmiting short lived events.
116-
115+
RPCs are great for sending transient events. Use them when transmitting short-lived events.

docs/tutorials/testing/testing_locally.md

Lines changed: 14 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -8,111 +8,33 @@ Testing a multiplayer game presents unique challenges:
88

99
- You need to run multiple instances of the game to test multiplayer scenarios.
1010
- You also need to iterate quickly on custom code and asset changes and validate work in a multiplayer scenario.
11-
- You need to be able to debug work in a multiplayer scenario using editor tools.
11+
- You need to be able to debug work in a multiplayer scenario using Editor tools.
1212

13-
Unity doesn't offer any workflow that covers all these requirements. (Check out the [roadmap](https://unity.com/roadmap/unity-platform/multiplayer-networking))
13+
There are several different ways you can test multiplayer games locally:
1414

15-
There will always be a need to validate work in the target distribution format (on platform) and the way to do this is by creating [Player Builds](#player-builds).
15+
- Using [player builds](#player-builds) to validate work on a target distribution platform, although player builds can be slow for local iteration.
16+
- Using the [Multiplayer Play Mode package](#multiplayer-play-mode) to simulate up to four players simultaneously on the same development device.
17+
- Using third-party tools such as [ParrelSync](https://github.com/VeriorPies/ParrelSync).
1618

17-
:::important
18-
Player builds don't meet the iteration and debugging requirements for using Editor tools. As such, the current recommended workflow for local iteration is [ParrelSync](#parrelsync).
19-
:::
20-
21-
## Player Builds
22-
23-
:::tip hint
24-
This approach works well when to verify work on the target platform or with a wider group of testers.
25-
:::
19+
## Player builds
2620

27-
First step is to build an executable.
21+
Player builds are best used to verify that your game works on target platforms or with a wider group of testers. Start by building an executable to distribute.
2822

2923
1. Navigate to **File** > **Build Settings** in the menu bar.
3024
1. Click **Build**.
3125

32-
Then you can share the build can among the testers.
26+
### Local iteration using player builds
3327

34-
### Local iteration using Player Builds
28+
After the executable build completes, you can distribute it to testers and launch several instances of the built executable to both host and join a game. You can also run the build alongside the Editor that produced it, which can be useful during iterative development.
3529

36-
After the build completes, you can launch several instances of the built executable to both host and join a game.
37-
38-
It's also possible to run the builds along with an editor that produced said build, which can be useful during iterations.
30+
Though functional, this approach can be somewhat slow for the purposes of local iteration. You can use [Multiplayer Play Mode](#multiplayer-play-mode) to iterate locally at speed.
3931

4032
:::unity For Mac
41-
Mac users: to run multiple instances of the same app, you need to use the command line.
42-
Run `open -n YourAppName.app`.
43-
:::
44-
45-
:::tip hint
46-
Though functional, this approach can be somewhat slow for the purposes of local iteration. Head on to the [ParrelSync](#parrelsync) section for the suggested workflow for local iteration.
47-
:::
48-
49-
## ParrelSync
50-
51-
[**ParrelSync**](https://github.com/VeriorPies/ParrelSync) is an open-source Unity Editor extension that allows users to **test multiplayer gameplay without building the project** by having another Unity Editor window opened and mirror the changes from the original project.
52-
53-
:::caution
54-
ParallelSync is **not** supported by Unity. Refer to the repository for more information and [troubleshooting information](https://github.com/VeriorPies/ParrelSync/wiki/Troubleshooting-&-FAQs)
33+
To run multiple instances of the same app, you need to use the command line on MacOS. Run `open -n YourAppName.app`.
5534
:::
5635

57-
**ParrelSync** works by making a copy of the original project folder and creating symbolic links to the `Asset` and `Project Settings` folders back from the original project.
58-
59-
The [Boss Room sample](https://github.com/Unity-Technologies/com.unity.multiplayer.samples.coop/) team uses **ParrelSync** for local iteration.
60-
61-
![parrelsync-bossroom-demo](/img/parrelsync-bossroom-demo.gif)
62-
63-
ParrelSync is generally safe because it relies on symbolic links and partial copies of the original project folder structure.
64-
65-
:::important
66-
Although ParrelSync is generally safe, you should still consistently back up your project or use a version control system to ensure you don't lose your work.
67-
:::
68-
69-
### Installation
70-
71-
Follow the installation instructions on **ParrelSync** repository [page](https://github.com/VeriorPies/ParrelSync#installation)
72-
73-
### Usage
74-
75-
- Navigate to **ParrelSync** > **Preferences** in the menu bar to open the preferences window.
76-
- Ensure that both Options are selected as shown below
77-
78-
![parrelsync-preferences](/img/parrelsync-preferences.png)
79-
80-
:::important
81-
82-
By default, **ParrelSync** prevents asset serialization in all clone instances and changes can only be made from the original project editor. This is a **very important setting** that prevents issues with multiple editors accessing the same `Library` folder (which isn't supported and breaks basic assumptions in Unity design).
83-
84-
:::
85-
86-
- Open the **ParrelSync** > **Clones Manager** from which you can launch, create and remove clone editors.
87-
- Advanced usage is to use **ParrelSync's** capability of passing [Arguments](https://github.com/VeriorPies/ParrelSync/wiki/Argument) to clones, allowing to run custom logic on a per-clone basis.
88-
89-
### UGS Authentication
90-
91-
When you use [Unity Authentication](https://docs.unity.com/authentication/IntroUnityAuthentication.html), it caches the user's identity locally, even with [Anonymous Sign-in](https://docs.unity.com/authentication/UsingAnonSignIn.html).This means that each ParrelSync clone signs in as the same user, making testing certain scenarios difficult. You can force each clone to use a different identity using the [profile management in the Authentication SDK](https://docs.unity.com/authentication/ProfileManagement.html). You can use `ParrelSync.ClonesManager` to detect and automate this step.
92-
93-
```csharp
94-
// ParrelSync should only be used within the Unity Editor so you should use the UNITY_EDITOR define
95-
#if UNITY_EDITOR
96-
if (ParrelSync.ClonesManager.IsClone())
97-
{
98-
// When using a ParrelSync clone, switch to a different authentication profile to force the clone
99-
// to sign in as a different anonymous user account.
100-
string customArgument = ParrelSync.ClonesManager.GetArgument();
101-
AuthenticationService.Instance.SwitchProfile($"Clone_{customArgument}_Profile");
102-
}
103-
#endif
104-
```
105-
106-
### Known issues and workarounds
107-
108-
- An important nuance is that **ParrelSync** doesn't sync changes made to packages. `Packages` folder is synced on clone opening, so if you made package changes - you should close and re-open your clones.
109-
- [Relevant GitHub issue](https://github.com/VeriorPies/ParrelSync/issues/48)
110-
- If you meet a Netcode error that mentions `soft sync` - that generally means that prefabs or scenes aren't in sync between editors. Save the project in the main editor via **File** > **Save Project** and refresh the projects in the clone editors by pressing `Ctrl + R` (which is by default done automatically) or reimport networked prefabs in the main editor.
111-
- More information and general **ParrelSync** FAQ: https://github.com/VeriorPies/ParrelSync/wiki/Troubleshooting-&-FAQs
112-
- The ultimate workaround in case nothing helps - deleting and re-creating the clone instance via `ParrelSync->Clones Manager` window.
36+
## Multiplayer Play Mode
11337

114-
## General tips
38+
Multiplayer Play Mode is a Unity package you can use to simulate up to four players simultaneously on the same development device while using the same source assets on disk. It allows you to reduce project build times, run your game locally, and test the server-client relationship, all from within the Unity Editor.
11539

116-
- Bigger screens or multi-screen setups allow for more screen real estate, which is handy when one has to have multiple instances of an app opened at the same time.
117-
- **ParrelSync** has to copy and update separate `Packages` and `Library` folders for every clone, and in certain cases a fix for misbehaving clone is re-creation - a good SSD makes this process quite a bit faster.
118-
- Creating a fork of any git repository that your project relies upon in production can help avoid bad surprises if the repository gets taken down or introduces an undesirable change. You should fork **ParrelSync** before using it in your live project.
40+
For more details, refer to the [Multiplayer Play Mode documentation](https://docs-multiplayer.unity3d.com/mppm/current/about/).

0 commit comments

Comments
 (0)