Skip to content

Commit 2fdbeba

Browse files
Merge branch 'develop-2.0.0' into standards-check-fix
2 parents e885729 + 19fdff8 commit 2fdbeba

12 files changed

Lines changed: 319 additions & 7 deletions

File tree

.github/pull_request_template.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ _Does the change require QA team to:_
5656

5757
If any boxes above are checked the QA team will be automatically added as a PR reviewer.
5858

59+
## Up-port
60+
[//]: # (
61+
This section is REQUIRED and should link to the PR that targets develop-3.0.0 branch. Assuming that the PR lands agains default develop-2.0.0 branch
62+
If this is not needed, for example feature specific to NGOv2.X, then just mention this fact.
63+
)
64+
5965
## Backports
6066
[//]: # (
6167
This section is REQUIRED and should link to the PR that targets other NGO version which is either develop or develop-2.0.0 branch

.github/workflows/pr-description-validation.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ jobs:
5151
header: '## Backports',
5252
description: 'PR description must include a "## Backports" section. Please add this section and provide information about this PR backport to develop or develop-2.0.0 branch respectively or explain why backport is not needed.'
5353
},
54+
{
55+
header: '## Up-port',
56+
description: 'PR description must include a "## Up-port" section. Please add this section and provide information about this PR up-port to develop-3.0.0 branch or explain why up-port is not needed.'
57+
},
5458
{
5559
header: '## Testing & QA',
5660
description: 'PR description must include a "## Testing & QA" section. Please add this section and provide information about the testing performed for this PR. It can range from adding unit tests to full samples and is needed from QA side to analyze PRs while Playtesting for the release.'

com.unity.netcode.gameobjects/CHANGELOG.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@ Additional documentation and release notes are available at [Multiplayer Documen
2222

2323
### Fixed
2424

25+
26+
### Security
27+
28+
29+
### Obsolete
30+
31+
32+
## [2.13.1] - 2026-07-19
33+
34+
### Added
35+
36+
- 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)
37+
38+
### Fixed
39+
40+
- Issue where `NetworkAnimator` did no bounds check on the parameter index read prior to obtaining a pointer to the location within the array. (#4090)
2541
- Issue where scene migration in a distributed authority session would throw an exception on clients migrating their owned `NetworkObject` instances to a different scene.(#4086)
2642
- Issue where migrating a dynamically spawned or in-scene placed `NetworkObject` into a different scene during awake could result in that spawned instance to not be synchronized. (#4086)
2743
- Issue where a NullReferenceException was thrown when a non-authority failed to spawn a NetworkObject. (#4067)
@@ -31,12 +47,6 @@ Additional documentation and release notes are available at [Multiplayer Documen
3147
- Issue where NetworkRigidbodyBase was always checking the 3D rigid body's interpolation mode when determining if it is kinematic and needs to put the rigid body to sleep and then switch to interpolation. (#4012)
3248
- Fixed AnticipatedNetworkTransform not respecting the InLocalSpace flag. (#3995)
3349

34-
### Security
35-
36-
37-
### Obsolete
38-
39-
4050
## [2.13.0] - 2026-06-21
4151

4252
### Added

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/Runtime/Components/NetworkAnimator.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,13 @@ private unsafe void ReadParameters(FastBufferReader reader)
13771377
while (totalParametersRead < totalParametersToRead)
13781378
{
13791379
ByteUnpacker.ReadValuePacked(reader, out uint parameterIndex);
1380+
1381+
// Do bounds check prior to getting the element as a reference at that index.
1382+
if (parameterIndex >= m_CachedAnimatorParameters.Length)
1383+
{
1384+
NetworkManager.Log.ErrorServer(new Logging.Context(LogLevel.Error, $"[{nameof(NetworkAnimator)}][{name}] Invalid index of {parameterIndex} was received when there are only {m_CachedAnimatorParameters.Length} parameters. Ignoring the remainger of this {nameof(ParametersUpdateMessage)}!"));
1385+
return;
1386+
}
13801387
ref var cacheValue = ref UnsafeUtility.ArrayElementAsRef<AnimatorParamCache>(m_CachedAnimatorParameters.GetUnsafePtr(), (int)parameterIndex);
13811388
var hash = cacheValue.Hash;
13821389
if (cacheValue.Type == AnimationParamEnumWrapper.AnimatorControllerParameterInt)

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.

com.unity.netcode.gameobjects/Tests/Runtime/Prefabs/NetworkPrefabHandlerSynchronizationTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ protected override void OnServerAndClientsCreated()
2828
}
2929

3030
[UnityTest]
31+
[UnityPlatform(exclude = new[] { RuntimePlatform.IPhonePlayer, RuntimePlatform.OSXPlayer, RuntimePlatform.OSXEditor })] // Ignored test tracked in MTT-15473
3132
public IEnumerator NetworkPrefabHandlerSpawnAndSynchronizeTests()
3233
{
3334
var nonAuthority = GetNonAuthorityNetworkManager();

0 commit comments

Comments
 (0)