Skip to content

Commit 9bc24c8

Browse files
chore: adding a single player session section (#4062)
* update adding single player session section under the configuration area after transports. * Refactor ExtendedNetworkManager for single player Rearranged variable declarations and removed StartSinglePlayer method. * update Using the newer approach to adding examples where the example script lives in the same integration test file that tests the example to assure it is always a working example. * update Adding change log entry. * Change class visibility to internal for example class --------- Co-authored-by: Unity Netcode CI <74025435+netcode-ci-service@users.noreply.github.com>
1 parent 8f8b25c commit 9bc24c8

6 files changed

Lines changed: 250 additions & 0 deletions

File tree

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Additional documentation and release notes are available at [Multiplayer Documen
1010

1111
### Added
1212

13+
- Single player session section to provide users with information about `SinglePlayerTransport` and an example script of how to switch between single and multi player sessions. (#4062)
1314

1415
### Changed
1516

com.unity.netcode.gameobjects/Documentation~/TableOfContents.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* [Connection approval](basics/connection-approval.md)
1919
* [Max players](basics/maxnumberplayers.md)
2020
* [Transports](advanced-topics/transports.md)
21+
* [Single player sessions](advanced-topics/singleplayer.md)
2122
* [Unity Relay](relay/relay.md)
2223
* [Command-line arguments](command-line-arguments.md)
2324
* [Network components](network-components.md)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Single player sessions
2+
3+
Netcode for GameObjects provides a [SinglePlayerTransport](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.13/api/Unity.Netcode.Transports.SinglePlayer.SinglePlayerTransport.html) which derives from [NetworkTransport](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@2.13/api/Unity.Netcode.NetworkTransport.html).
4+
5+
This provides the ability to run a hosted session using the single player transport without having to modify your primary netcode script.
6+
7+
## Adding the single player transport
8+
9+
- Add the `SinglePlayerTransport` to your NetworkManager.
10+
- You can create a custom `MonoBehaviour` component to handle your connection flow or you can derive from `NetworkManager` and add additional methods/logic to handle starting a single player session or multiplayer session.
11+
- When starting a single player session, prior to starting the NetworkManager as a host (_required_), you will want to assign the `SinglePlayerTransport` to the `NetworkManager.NetworkConfig.NetworkTransport`.
12+
- When starting a multiplayer session, prior to starting the NetworkManager, you will want to assign the `UnityTransport` (_or any other `NetworkTransport` derived class that you might use for multiplayer sessions_) to the `NetworkManager.NetworkConfig.NetworkTransport`.
13+
14+
## Example script
15+
16+
Below is an example component script that provides a single method to start a single or multi player session:
17+
18+
[!code-cs[](../../Tests/Runtime/DocumentationCodeSamples/Configuration/SinglePlayerSessions.cs#SinglePlayerTransportExample)]

com.unity.netcode.gameobjects/Tests/Runtime/DocumentationCodeSamples/Configuration.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
using System.Collections;
2+
using System.Text;
3+
using NUnit.Framework;
4+
using Unity.Netcode;
5+
using Unity.Netcode.TestHelpers.Runtime;
6+
using Unity.Netcode.Transports.SinglePlayer;
7+
using Unity.Netcode.Transports.UTP;
8+
using UnityEngine;
9+
using UnityEngine.TestTools;
10+
11+
namespace DocumentationCodeSamples
12+
{
13+
#region SinglePlayerTransportExample
14+
/// <summary>
15+
/// Example of how to start a single player or multiplayer session.
16+
/// Place this on your NetworkManager's GameObject.
17+
/// </summary>
18+
internal class SwitchingTransportTypesExample : MonoBehaviour
19+
{
20+
public enum StartType
21+
{
22+
SinglePlayer,
23+
Client,
24+
Host,
25+
Server
26+
}
27+
28+
private UnityTransport m_UnityTransport;
29+
private SinglePlayerTransport m_SinglePlayerTransport;
30+
private NetworkManager m_NetworkManager;
31+
32+
private void Awake()
33+
{
34+
m_UnityTransport = GetComponent<UnityTransport>();
35+
m_SinglePlayerTransport = GetComponent<SinglePlayerTransport>();
36+
m_NetworkManager = GetComponent<NetworkManager>();
37+
}
38+
39+
public bool StartSession(StartType startType)
40+
{
41+
var startStatus = false;
42+
// Set the transport to use before starting
43+
m_NetworkManager.NetworkConfig.NetworkTransport = startType == StartType.SinglePlayer ? m_SinglePlayerTransport : m_UnityTransport;
44+
switch (startType)
45+
{
46+
case StartType.Host:
47+
case StartType.SinglePlayer:
48+
{
49+
// Starting a host or single player is the same
50+
startStatus = m_NetworkManager.StartHost();
51+
break;
52+
}
53+
case StartType.Server:
54+
{
55+
startStatus = m_NetworkManager.StartServer();
56+
break;
57+
}
58+
case StartType.Client:
59+
{
60+
startStatus = m_NetworkManager.StartClient();
61+
break;
62+
}
63+
}
64+
return startStatus;
65+
}
66+
}
67+
#endregion
68+
69+
internal class VerifyNetcodeSessionActive : NetworkBehaviour
70+
{
71+
public bool RpcReceived { get; private set; }
72+
73+
public bool TestNetworkVariableEvent { get; private set; }
74+
public NetworkVariable<bool> TestNetworkVariable = new NetworkVariable<bool>(false, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
75+
76+
[Rpc(SendTo.Everyone, InvokePermission = RpcInvokePermission.Owner)]
77+
private void VerifyRpc(RpcParams rpcParams = default)
78+
{
79+
RpcReceived = true;
80+
}
81+
82+
public void TestConnectivity()
83+
{
84+
if (IsOwner)
85+
{
86+
VerifyRpc();
87+
TestNetworkVariable.Value = true;
88+
}
89+
}
90+
91+
protected override void OnNetworkPostSpawn()
92+
{
93+
TestNetworkVariable.OnValueChanged += TestNetworkVariableChanged;
94+
base.OnNetworkPostSpawn();
95+
}
96+
97+
private void TestNetworkVariableChanged(bool previous, bool current)
98+
{
99+
TestNetworkVariableEvent = true;
100+
}
101+
}
102+
103+
[TestFixture(SessionType.SinglePlayer)]
104+
[TestFixture(SessionType.MultiPlayer)]
105+
internal class SwitchingTransportTypesTests : NetcodeIntegrationTest
106+
{
107+
public enum SessionType
108+
{
109+
SinglePlayer,
110+
MultiPlayer
111+
}
112+
113+
protected override int NumberOfClients => 0;
114+
115+
// We do not need to test this against CMB.
116+
protected override bool UseCMBService()
117+
{
118+
return false;
119+
}
120+
121+
private SessionType m_SessionType;
122+
public SwitchingTransportTypesTests(SessionType sessionType)
123+
{
124+
m_SessionType = sessionType;
125+
}
126+
127+
protected override IEnumerator OnSetup()
128+
{
129+
m_CanStart = false;
130+
return base.OnSetup();
131+
}
132+
133+
protected override void OnCreatePlayerPrefab()
134+
{
135+
m_PlayerPrefab.AddComponent<VerifyNetcodeSessionActive>();
136+
base.OnCreatePlayerPrefab();
137+
}
138+
139+
private bool m_CanStart = false;
140+
protected override bool CanStartServerAndClients()
141+
{
142+
return m_CanStart;
143+
}
144+
145+
private NetworkManager m_Client;
146+
protected override void OnNewClientCreated(NetworkManager networkManager)
147+
{
148+
m_Client = networkManager;
149+
networkManager.NetworkConfig.EnableSceneManagement = false;
150+
base.OnNewClientCreated(networkManager);
151+
}
152+
153+
[UnityTest]
154+
public IEnumerator SwitchTransportTest()
155+
{
156+
var authority = GetAuthorityNetworkManager();
157+
authority.NetworkConfig.EnableSceneManagement = false;
158+
var startType = SwitchingTransportTypesExample.StartType.Host;
159+
if (m_SessionType == SessionType.SinglePlayer)
160+
{
161+
startType = SwitchingTransportTypesExample.StartType.SinglePlayer;
162+
authority.gameObject.AddComponent<SinglePlayerTransport>();
163+
}
164+
m_CanStart = true;
165+
var example = authority.gameObject.AddComponent<SwitchingTransportTypesExample>();
166+
Assert.IsTrue(example.StartSession(startType), "Failed to start single player session!");
167+
168+
if (m_SessionType != SessionType.SinglePlayer)
169+
{
170+
yield return CreateAndStartNewClient();
171+
AssertOnTimeout("Timed out waiting for client to start and connect!");
172+
}
173+
174+
var verifyNetcode = authority.LocalClient.PlayerObject.GetComponent<VerifyNetcodeSessionActive>();
175+
verifyNetcode.TestConnectivity();
176+
if (m_SessionType != SessionType.SinglePlayer)
177+
{
178+
m_Client.LocalClient.PlayerObject.GetComponent<VerifyNetcodeSessionActive>().TestConnectivity();
179+
}
180+
181+
yield return WaitForConditionOrTimeOut(VerifyNetcodeSession);
182+
AssertOnTimeout($"Single player session had netcode related errors:");
183+
}
184+
185+
/// <summary>
186+
/// Verifies that all spawned players received the RPC and NetworkVariable
187+
/// changed event.
188+
/// </summary>
189+
private bool VerifyNetcodeSession(StringBuilder errorLog)
190+
{
191+
foreach (var networkManager in m_NetworkManagers)
192+
{
193+
foreach (var networkObject in networkManager.SpawnManager.SpawnedObjectsList)
194+
{
195+
if (!networkObject.IsPlayerObject)
196+
{
197+
continue;
198+
}
199+
var verify = networkObject.gameObject.GetComponent<VerifyNetcodeSessionActive>();
200+
201+
if (!verify.RpcReceived)
202+
{
203+
errorLog.AppendLine($"[Client-{networkManager.LocalClientId}][{verify.name}] Rpc was not recieved!");
204+
}
205+
206+
if (!verify.TestNetworkVariableEvent)
207+
{
208+
errorLog.AppendLine($"[Client-{networkManager.LocalClientId}][{verify.name}] NetworkVariable.OnValueChanged did not get invoked!");
209+
}
210+
211+
if (!verify.TestNetworkVariable.Value)
212+
{
213+
errorLog.AppendLine($"[Client-{networkManager.LocalClientId}][{verify.name}] {nameof(VerifyNetcodeSessionActive.TestNetworkVariable)} did not get set!");
214+
}
215+
}
216+
}
217+
return errorLog.Length == 0;
218+
}
219+
}
220+
}

com.unity.netcode.gameobjects/Tests/Runtime/DocumentationCodeSamples/Configuration/SinglePlayerSessions.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)