您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

153 行
7.0 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using Unity.Netcode.TestHelpers.Runtime;
namespace Unity.Netcode.RuntimeTests
{
public class RpcManyClientsObject : NetworkBehaviour
{
public int Count = 0;
public List<ulong> ReceivedFrom = new List<ulong>();
[ServerRpc(RequireOwnership = false)]
public void ResponseServerRpc(ServerRpcParams rpcParams = default)
{
ReceivedFrom.Add(rpcParams.Receive.SenderClientId);
Count++;
}
[ClientRpc]
public void NoParamsClientRpc()
{
ResponseServerRpc();
}
[ClientRpc]
public void OneParamClientRpc(int value)
{
ResponseServerRpc();
}
[ClientRpc]
public void TwoParamsClientRpc(int value1, int value2)
{
ResponseServerRpc();
}
[ClientRpc]
public void WithParamsClientRpc(ClientRpcParams param)
{
ResponseServerRpc();
}
}
public class RpcManyClientsTests : NetcodeIntegrationTest
{
protected override int NumberOfClients => 10;
private GameObject m_PrefabToSpawn;
protected override void OnServerAndClientsCreated()
{
m_PrefabToSpawn = PreparePrefab(typeof(RpcManyClientsObject));
}
public GameObject PreparePrefab(Type type)
{
var prefabToSpawn = new GameObject();
prefabToSpawn.AddComponent(type);
var networkObjectPrefab = prefabToSpawn.AddComponent<NetworkObject>();
NetcodeIntegrationTestHelpers.MakeNetworkObjectTestPrefab(networkObjectPrefab);
m_ServerNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
foreach (var clientNetworkManager in m_ClientNetworkManagers)
{
clientNetworkManager.NetworkConfig.NetworkPrefabs.Add(new NetworkPrefab() { Prefab = prefabToSpawn });
}
return prefabToSpawn;
}
[UnityTest]
public IEnumerator RpcManyClientsTest()
{
var spawnedObject = UnityEngine.Object.Instantiate(m_PrefabToSpawn);
var netSpawnedObject = spawnedObject.GetComponent<NetworkObject>();
netSpawnedObject.NetworkManagerOwner = m_ServerNetworkManager;
netSpawnedObject.Spawn();
var messageHookList = new List<MessageHookEntry>();
var serverMessageHookEntry = new MessageHookEntry(m_ServerNetworkManager);
serverMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(serverMessageHookEntry);
foreach (var client in m_ClientNetworkManagers)
{
var clientMessageHookEntry = new MessageHookEntry(client);
clientMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(clientMessageHookEntry);
}
var rpcMessageHooks = new MessageHooksConditional(messageHookList);
var rpcManyClientsObject = netSpawnedObject.GetComponent<RpcManyClientsObject>();
rpcManyClientsObject.Count = 0;
rpcManyClientsObject.NoParamsClientRpc(); // RPC with no params
// Check that all ServerRpcMessages were sent
yield return WaitForConditionOrTimeOut(rpcMessageHooks);
// Now provide a small window of time to let the server receive and process all messages
yield return WaitForConditionOrTimeOut(() => TotalClients == rpcManyClientsObject.Count);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out wait for {nameof(rpcManyClientsObject.NoParamsClientRpc)}! Only {rpcManyClientsObject.Count} of {TotalClients} was received!");
rpcManyClientsObject.Count = 0;
rpcManyClientsObject.OneParamClientRpc(0); // RPC with one param
rpcMessageHooks.Reset();
yield return WaitForConditionOrTimeOut(rpcMessageHooks);
// Now provide a small window of time to let the server receive and process all messages
yield return WaitForConditionOrTimeOut(() => TotalClients == rpcManyClientsObject.Count);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out wait for {nameof(rpcManyClientsObject.OneParamClientRpc)}! Only {rpcManyClientsObject.Count} of {TotalClients} was received!");
var param = new ClientRpcParams();
rpcManyClientsObject.Count = 0;
rpcManyClientsObject.TwoParamsClientRpc(0, 0); // RPC with two params
rpcMessageHooks.Reset();
yield return WaitForConditionOrTimeOut(rpcMessageHooks);
// Now provide a small window of time to let the server receive and process all messages
yield return WaitForConditionOrTimeOut(() => TotalClients == rpcManyClientsObject.Count);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out wait for {nameof(rpcManyClientsObject.TwoParamsClientRpc)}! Only {rpcManyClientsObject.Count} of {TotalClients} was received!");
rpcManyClientsObject.ReceivedFrom.Clear();
rpcManyClientsObject.Count = 0;
var target = new List<ulong> { m_ClientNetworkManagers[1].LocalClientId, m_ClientNetworkManagers[2].LocalClientId };
param.Send.TargetClientIds = target;
rpcManyClientsObject.WithParamsClientRpc(param);
messageHookList.Clear();
var targetedClientMessageHookEntry = new MessageHookEntry(m_ClientNetworkManagers[1]);
targetedClientMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(targetedClientMessageHookEntry);
targetedClientMessageHookEntry = new MessageHookEntry(m_ClientNetworkManagers[2]);
targetedClientMessageHookEntry.AssignMessageType<ServerRpcMessage>();
messageHookList.Add(targetedClientMessageHookEntry);
rpcMessageHooks = new MessageHooksConditional(messageHookList);
yield return WaitForConditionOrTimeOut(rpcMessageHooks);
// Now provide a small window of time to let the server receive and process all messages
yield return WaitForConditionOrTimeOut(() => 2 == rpcManyClientsObject.Count);
Assert.False(s_GlobalTimeoutHelper.TimedOut, $"Timed out wait for {nameof(rpcManyClientsObject.TwoParamsClientRpc)}! Only {rpcManyClientsObject.Count} of 2 was received!");
// either of the 2 selected clients can reply to the server first, due to network timing
var possibility1 = new List<ulong> { m_ClientNetworkManagers[1].LocalClientId, m_ClientNetworkManagers[2].LocalClientId };
var possibility2 = new List<ulong> { m_ClientNetworkManagers[2].LocalClientId, m_ClientNetworkManagers[1].LocalClientId };
Debug.Assert(Enumerable.SequenceEqual(rpcManyClientsObject.ReceivedFrom, possibility1) || Enumerable.SequenceEqual(rpcManyClientsObject.ReceivedFrom, possibility2));
}
}
}