Skip to content

Commit 4ee539d

Browse files
test
Added validation test for RigidbodyContactEventManager
1 parent 6d4b9d7 commit 4ee539d

File tree

1 file changed

+383
-0
lines changed

1 file changed

+383
-0
lines changed

com.unity.netcode.gameobjects/Tests/Runtime/Physics/NetworkRigidbodyTest.cs

Lines changed: 383 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#if COM_UNITY_MODULES_PHYSICS
22
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Text;
35
using NUnit.Framework;
46
using Unity.Netcode.Components;
57
using Unity.Netcode.TestHelpers.Runtime;
@@ -108,5 +110,386 @@ public IEnumerator TestRigidbodyKinematicEnableDisable()
108110
Assert.IsTrue(clientPlayerInstance == null, $"[Client-Side] Player {nameof(NetworkObject)} is not null!");
109111
}
110112
}
113+
114+
internal class ContactEventTransformHelperWithInfo : ContactEventTransformHelper, IContactEventHandlerWithInfo
115+
{
116+
public ContactEventHandlerInfo GetContactEventHandlerInfo()
117+
{
118+
var contactEventHandlerInfo = new ContactEventHandlerInfo()
119+
{
120+
HasContactEventPriority = IsOwner,
121+
ProvideNonRigidBodyContactEvents = m_EnableNonRigidbodyContacts.Value,
122+
};
123+
return contactEventHandlerInfo;
124+
}
125+
126+
protected override void OnRegisterForContactEvents(bool isRegistering)
127+
{
128+
RigidbodyContactEventManager.Instance.RegisterHandler(this, isRegistering);
129+
}
130+
}
131+
132+
133+
internal class ContactEventTransformHelper : NetworkTransform, IContactEventHandler
134+
{
135+
public static Vector3 SessionOwnerSpawnPoint;
136+
public static Vector3 ClientSpawnPoint;
137+
public static bool VerboseDebug;
138+
public enum HelperStates
139+
{
140+
None,
141+
MoveForward,
142+
}
143+
144+
private HelperStates m_HelperState;
145+
146+
public void SetHelperState(HelperStates state)
147+
{
148+
m_HelperState = state;
149+
if (!m_NetworkRigidbody.IsKinematic())
150+
{
151+
m_NetworkRigidbody.Rigidbody.angularVelocity = Vector3.zero;
152+
m_NetworkRigidbody.Rigidbody.linearVelocity = Vector3.zero;
153+
}
154+
m_NetworkRigidbody.Rigidbody.isKinematic = m_HelperState == HelperStates.None;
155+
if (!m_NetworkRigidbody.IsKinematic())
156+
{
157+
m_NetworkRigidbody.Rigidbody.angularVelocity = Vector3.zero;
158+
m_NetworkRigidbody.Rigidbody.linearVelocity = Vector3.zero;
159+
}
160+
161+
}
162+
163+
protected struct ContactEventInfo
164+
{
165+
public ulong EventId;
166+
public Vector3 AveragedCollisionNormal;
167+
public Rigidbody CollidingBody;
168+
public Vector3 ContactPoint;
169+
}
170+
171+
protected List<ContactEventInfo> m_ContactEvents = new List<ContactEventInfo>();
172+
173+
protected NetworkVariable<bool> m_EnableNonRigidbodyContacts = new NetworkVariable<bool>(false, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
174+
175+
protected NetworkRigidbody m_NetworkRigidbody;
176+
public ContactEventTransformHelper Target;
177+
178+
public bool HasContactEvents()
179+
{
180+
return m_ContactEvents.Count > 0;
181+
}
182+
183+
public Rigidbody GetRigidbody()
184+
{
185+
return m_NetworkRigidbody.Rigidbody;
186+
}
187+
188+
public bool HadContactWith(ContactEventTransformHelper otherObject)
189+
{
190+
if (otherObject == null)
191+
{
192+
return false;
193+
}
194+
foreach (var contactEvent in m_ContactEvents)
195+
{
196+
if (contactEvent.CollidingBody == otherObject.m_NetworkRigidbody.Rigidbody)
197+
{
198+
return true;
199+
}
200+
}
201+
return false;
202+
}
203+
204+
protected virtual void CheckToStopMoving()
205+
{
206+
SetHelperState(HadContactWith(Target) ? HelperStates.None : HelperStates.MoveForward);
207+
}
208+
209+
public void ContactEvent(ulong eventId, Vector3 averagedCollisionNormal, Rigidbody collidingBody, Vector3 contactPoint, bool hasCollisionStay = false, Vector3 averagedCollisionStayNormal = default)
210+
{
211+
if (Target == null)
212+
{
213+
return;
214+
}
215+
216+
if (collidingBody != null)
217+
{
218+
Log($">>>>>>> contact event with {collidingBody.name}!");
219+
}
220+
else
221+
{
222+
Log($">>>>>>> contact event with non-rigidbody!");
223+
}
224+
225+
m_ContactEvents.Add(new ContactEventInfo()
226+
{
227+
EventId = eventId,
228+
AveragedCollisionNormal = averagedCollisionNormal,
229+
CollidingBody = collidingBody,
230+
ContactPoint = contactPoint,
231+
});
232+
CheckToStopMoving();
233+
}
234+
235+
private void SetInitialPositionClientServer()
236+
{
237+
if (IsServer)
238+
{
239+
if (!NetworkManager.DistributedAuthorityMode && !IsLocalPlayer)
240+
{
241+
transform.position = ClientSpawnPoint;
242+
m_NetworkRigidbody.Rigidbody.position = ClientSpawnPoint;
243+
}
244+
else
245+
{
246+
transform.position = SessionOwnerSpawnPoint;
247+
m_NetworkRigidbody.Rigidbody.position = SessionOwnerSpawnPoint;
248+
}
249+
}
250+
else
251+
{
252+
transform.position = ClientSpawnPoint;
253+
m_NetworkRigidbody.Rigidbody.position = ClientSpawnPoint;
254+
}
255+
}
256+
257+
private void SetInitialPositionDistributedAuthority()
258+
{
259+
if (HasAuthority)
260+
{
261+
if (IsSessionOwner)
262+
{
263+
transform.position = SessionOwnerSpawnPoint;
264+
m_NetworkRigidbody.Rigidbody.position = SessionOwnerSpawnPoint;
265+
}
266+
else
267+
{
268+
transform.position = ClientSpawnPoint;
269+
m_NetworkRigidbody.Rigidbody.position = ClientSpawnPoint;
270+
}
271+
}
272+
}
273+
274+
public override void OnNetworkSpawn()
275+
{
276+
m_NetworkRigidbody = GetComponent<NetworkRigidbody>();
277+
278+
m_NetworkRigidbody.Rigidbody.maxLinearVelocity = 15;
279+
m_NetworkRigidbody.Rigidbody.maxAngularVelocity = 10;
280+
281+
if (NetworkManager.DistributedAuthorityMode)
282+
{
283+
SetInitialPositionDistributedAuthority();
284+
}
285+
else
286+
{
287+
SetInitialPositionClientServer();
288+
}
289+
if (IsLocalPlayer)
290+
{
291+
RegisterForContactEvents(true);
292+
}
293+
else
294+
{
295+
m_NetworkRigidbody.Rigidbody.detectCollisions = false;
296+
}
297+
base.OnNetworkSpawn();
298+
}
299+
300+
protected virtual void OnRegisterForContactEvents(bool isRegistering)
301+
{
302+
RigidbodyContactEventManager.Instance.RegisterHandler(this, isRegistering);
303+
}
304+
305+
public void RegisterForContactEvents(bool isRegistering)
306+
{
307+
OnRegisterForContactEvents(isRegistering);
308+
}
309+
310+
private void FixedUpdate()
311+
{
312+
if (!IsSpawned || !IsOwner || m_HelperState != HelperStates.MoveForward)
313+
{
314+
return;
315+
}
316+
var distance = Vector3.Distance(Target.transform.position, transform.position);
317+
var moveAmount = Mathf.Max(1.2f, distance);
318+
// Head towards our target
319+
var dir = (Target.transform.position - transform.position).normalized;
320+
var deltaMove = dir * moveAmount * Time.fixedDeltaTime;
321+
m_NetworkRigidbody.Rigidbody.MovePosition(m_NetworkRigidbody.Rigidbody.position + deltaMove);
322+
323+
324+
Log($" Loc: {transform.position} | Dest: {Target.transform.position} | Dist: {distance} | MoveDelta: {deltaMove}");
325+
}
326+
327+
protected void Log(string msg)
328+
{
329+
if (VerboseDebug)
330+
{
331+
Debug.Log($"Client-{OwnerClientId} {msg}");
332+
}
333+
}
334+
}
335+
336+
[TestFixture(HostOrServer.Host, ContactEventTypes.Default)]
337+
[TestFixture(HostOrServer.DAHost, ContactEventTypes.Default)]
338+
[TestFixture(HostOrServer.Host, ContactEventTypes.WithInfo)]
339+
[TestFixture(HostOrServer.DAHost, ContactEventTypes.WithInfo)]
340+
internal class RigidbodyContactEventManagerTests : IntegrationTestWithApproximation
341+
{
342+
protected override int NumberOfClients => 1;
343+
344+
345+
private GameObject m_RigidbodyContactEventManager;
346+
347+
public enum ContactEventTypes
348+
{
349+
Default,
350+
WithInfo
351+
}
352+
353+
private ContactEventTypes m_ContactEventType;
354+
private StringBuilder m_ErrorLogger = new StringBuilder();
355+
356+
public RigidbodyContactEventManagerTests(HostOrServer hostOrServer, ContactEventTypes contactEventType) : base(hostOrServer)
357+
{
358+
m_ContactEventType = contactEventType;
359+
}
360+
361+
protected override void OnCreatePlayerPrefab()
362+
{
363+
ContactEventTransformHelper.SessionOwnerSpawnPoint = GetRandomVector3(-4, -3);
364+
ContactEventTransformHelper.ClientSpawnPoint = GetRandomVector3(3, 4);
365+
if (m_ContactEventType == ContactEventTypes.Default)
366+
{
367+
var helper = m_PlayerPrefab.AddComponent<ContactEventTransformHelper>();
368+
helper.AuthorityMode = NetworkTransform.AuthorityModes.Owner;
369+
}
370+
else
371+
{
372+
var helperWithInfo = m_PlayerPrefab.AddComponent<ContactEventTransformHelperWithInfo>();
373+
helperWithInfo.AuthorityMode = NetworkTransform.AuthorityModes.Owner;
374+
}
375+
376+
var rigidbody = m_PlayerPrefab.AddComponent<Rigidbody>();
377+
rigidbody.useGravity = false;
378+
rigidbody.isKinematic = true;
379+
rigidbody.mass = 5.0f;
380+
rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;
381+
var sphereCollider = m_PlayerPrefab.AddComponent<SphereCollider>();
382+
sphereCollider.radius = 0.5f;
383+
sphereCollider.providesContacts = true;
384+
385+
var networkRigidbody = m_PlayerPrefab.AddComponent<NetworkRigidbody>();
386+
networkRigidbody.UseRigidBodyForMotion = true;
387+
networkRigidbody.AutoUpdateKinematicState = false;
388+
389+
m_RigidbodyContactEventManager = new GameObject();
390+
m_RigidbodyContactEventManager.AddComponent<RigidbodyContactEventManager>();
391+
}
392+
393+
394+
395+
private bool PlayersSpawnedInRightLocation()
396+
{
397+
var position = m_ServerNetworkManager.LocalClient.PlayerObject.transform.position;
398+
if (!Approximately(ContactEventTransformHelper.SessionOwnerSpawnPoint, position))
399+
{
400+
m_ErrorLogger.AppendLine($"Client-{m_ServerNetworkManager.LocalClientId} player position {position} does not match the assigned player position {ContactEventTransformHelper.SessionOwnerSpawnPoint}!");
401+
return false;
402+
}
403+
404+
position = m_ClientNetworkManagers[0].LocalClient.PlayerObject.transform.position;
405+
if (!Approximately(ContactEventTransformHelper.ClientSpawnPoint, position))
406+
{
407+
m_ErrorLogger.AppendLine($"Client-{m_ClientNetworkManagers[0].LocalClientId} player position {position} does not match the assigned player position {ContactEventTransformHelper.ClientSpawnPoint}!");
408+
return false;
409+
}
410+
var playerObject = (NetworkObject)null;
411+
if (!m_ServerNetworkManager.SpawnManager.SpawnedObjects.ContainsKey(m_ClientNetworkManagers[0].LocalClient.PlayerObject.NetworkObjectId))
412+
{
413+
m_ErrorLogger.AppendLine($"Client-{m_ServerNetworkManager.LocalClientId} cannot find a local spawned instance of Client-{m_ClientNetworkManagers[0].LocalClientId}'s player object!");
414+
return false;
415+
}
416+
playerObject = m_ServerNetworkManager.SpawnManager.SpawnedObjects[m_ClientNetworkManagers[0].LocalClient.PlayerObject.NetworkObjectId];
417+
position = playerObject.transform.position;
418+
419+
if (!Approximately(ContactEventTransformHelper.ClientSpawnPoint, position))
420+
{
421+
m_ErrorLogger.AppendLine($"Client-{m_ServerNetworkManager.LocalClientId} player position {position} for Client-{playerObject.OwnerClientId} does not match the assigned player position {ContactEventTransformHelper.ClientSpawnPoint}!");
422+
return false;
423+
}
424+
425+
if (!m_ClientNetworkManagers[0].SpawnManager.SpawnedObjects.ContainsKey(m_ServerNetworkManager.LocalClient.PlayerObject.NetworkObjectId))
426+
{
427+
m_ErrorLogger.AppendLine($"Client-{m_ClientNetworkManagers[0].LocalClientId} cannot find a local spawned instance of Client-{m_ServerNetworkManager.LocalClientId}'s player object!");
428+
return false;
429+
}
430+
playerObject = m_ClientNetworkManagers[0].SpawnManager.SpawnedObjects[m_ServerNetworkManager.LocalClient.PlayerObject.NetworkObjectId];
431+
position = playerObject.transform.position;
432+
if (!Approximately(ContactEventTransformHelper.SessionOwnerSpawnPoint, playerObject.transform.position))
433+
{
434+
m_ErrorLogger.AppendLine($"Client-{m_ClientNetworkManagers[0].LocalClientId} player position {position} for Client-{playerObject.OwnerClientId} does not match the assigned player position {ContactEventTransformHelper.SessionOwnerSpawnPoint}!");
435+
return false;
436+
}
437+
return true;
438+
}
439+
440+
441+
[UnityTest]
442+
public IEnumerator TestContactEvents()
443+
{
444+
ContactEventTransformHelper.VerboseDebug = m_EnableVerboseDebug;
445+
446+
m_PlayerPrefab.SetActive(false);
447+
m_ErrorLogger.Clear();
448+
// Validate all instances are spawned in the right location
449+
yield return WaitForConditionOrTimeOut(PlayersSpawnedInRightLocation);
450+
AssertOnTimeout($"Timed out waiting for all player instances to spawn in the corect location:\n {m_ErrorLogger}");
451+
m_ErrorLogger.Clear();
452+
453+
var sessionOwnerPlayer = m_ContactEventType == ContactEventTypes.Default ? m_ServerNetworkManager.LocalClient.PlayerObject.GetComponent<ContactEventTransformHelper>() :
454+
m_ServerNetworkManager.LocalClient.PlayerObject.GetComponent<ContactEventTransformHelperWithInfo>();
455+
var clientPlayer = m_ContactEventType == ContactEventTypes.Default ? m_ClientNetworkManagers[0].LocalClient.PlayerObject.GetComponent<ContactEventTransformHelper>() :
456+
m_ClientNetworkManagers[0].LocalClient.PlayerObject.GetComponent<ContactEventTransformHelperWithInfo>();
457+
458+
// Get both players to point towards each other
459+
sessionOwnerPlayer.Target = clientPlayer;
460+
clientPlayer.Target = sessionOwnerPlayer;
461+
462+
sessionOwnerPlayer.SetHelperState(ContactEventTransformHelper.HelperStates.MoveForward);
463+
clientPlayer.SetHelperState(ContactEventTransformHelper.HelperStates.MoveForward);
464+
465+
466+
yield return WaitForConditionOrTimeOut(() => sessionOwnerPlayer.HadContactWith(clientPlayer) || clientPlayer.HadContactWith(sessionOwnerPlayer));
467+
AssertOnTimeout("Timed out waiting for a player to collide with another player!");
468+
469+
clientPlayer.RegisterForContactEvents(false);
470+
sessionOwnerPlayer.RegisterForContactEvents(false);
471+
var otherPlayer = m_ContactEventType == ContactEventTypes.Default ? m_ServerNetworkManager.SpawnManager.SpawnedObjects[clientPlayer.NetworkObjectId].GetComponent<ContactEventTransformHelper>() :
472+
m_ServerNetworkManager.SpawnManager.SpawnedObjects[clientPlayer.NetworkObjectId].GetComponent<ContactEventTransformHelperWithInfo>();
473+
otherPlayer.RegisterForContactEvents(false);
474+
otherPlayer = m_ContactEventType == ContactEventTypes.Default ? m_ClientNetworkManagers[0].SpawnManager.SpawnedObjects[sessionOwnerPlayer.NetworkObjectId].GetComponent<ContactEventTransformHelper>() :
475+
m_ClientNetworkManagers[0].SpawnManager.SpawnedObjects[sessionOwnerPlayer.NetworkObjectId].GetComponent<ContactEventTransformHelperWithInfo>();
476+
otherPlayer.RegisterForContactEvents(false);
477+
478+
Object.Destroy(m_RigidbodyContactEventManager);
479+
m_RigidbodyContactEventManager = null;
480+
}
481+
482+
protected override IEnumerator OnTearDown()
483+
{
484+
// In case of a test failure
485+
if (m_RigidbodyContactEventManager)
486+
{
487+
Object.Destroy(m_RigidbodyContactEventManager);
488+
m_RigidbodyContactEventManager = null;
489+
}
490+
491+
return base.OnTearDown();
492+
}
493+
}
111494
}
112495
#endif // COM_UNITY_MODULES_PHYSICS

0 commit comments

Comments
 (0)