MatchInterestManagement.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace Mirror
  5. {
  6. [AddComponentMenu("Network/ Interest Management/ Match/Match Interest Management")]
  7. public class MatchInterestManagement : InterestManagement
  8. {
  9. readonly Dictionary<Guid, HashSet<NetworkIdentity>> matchObjects =
  10. new Dictionary<Guid, HashSet<NetworkIdentity>>();
  11. readonly Dictionary<NetworkIdentity, Guid> lastObjectMatch =
  12. new Dictionary<NetworkIdentity, Guid>();
  13. readonly HashSet<Guid> dirtyMatches = new HashSet<Guid>();
  14. [ServerCallback]
  15. public override void OnSpawned(NetworkIdentity identity)
  16. {
  17. if (!identity.TryGetComponent(out NetworkMatch networkMatch))
  18. return;
  19. Guid networkMatchId = networkMatch.matchId;
  20. lastObjectMatch[identity] = networkMatchId;
  21. // Guid.Empty is never a valid matchId...do not add to matchObjects collection
  22. if (networkMatchId == Guid.Empty)
  23. return;
  24. // Debug.Log($"MatchInterestManagement.OnSpawned({identity.name}) currentMatch: {currentMatch}");
  25. if (!matchObjects.TryGetValue(networkMatchId, out HashSet<NetworkIdentity> objects))
  26. {
  27. objects = new HashSet<NetworkIdentity>();
  28. matchObjects.Add(networkMatchId, objects);
  29. }
  30. objects.Add(identity);
  31. // Match ID could have been set in NetworkBehaviour::OnStartServer on this object.
  32. // Since that's after OnCheckObserver is called it would be missed, so force Rebuild here.
  33. // Add the current match to dirtyMatches for Update to rebuild it.
  34. dirtyMatches.Add(networkMatchId);
  35. }
  36. [ServerCallback]
  37. public override void OnDestroyed(NetworkIdentity identity)
  38. {
  39. // Don't RebuildSceneObservers here - that will happen in Update.
  40. // Multiple objects could be destroyed in same frame and we don't
  41. // want to rebuild for each one...let Update do it once.
  42. // We must add the current match to dirtyMatches for Update to rebuild it.
  43. if (lastObjectMatch.TryGetValue(identity, out Guid currentMatch))
  44. {
  45. lastObjectMatch.Remove(identity);
  46. if (currentMatch != Guid.Empty && matchObjects.TryGetValue(currentMatch, out HashSet<NetworkIdentity> objects) && objects.Remove(identity))
  47. dirtyMatches.Add(currentMatch);
  48. }
  49. }
  50. // internal so we can update from tests
  51. [ServerCallback]
  52. internal void Update()
  53. {
  54. // for each spawned:
  55. // if match changed:
  56. // add previous to dirty
  57. // add new to dirty
  58. foreach (NetworkIdentity identity in NetworkServer.spawned.Values)
  59. {
  60. // Ignore objects that don't have a NetworkMatch component
  61. if (!identity.TryGetComponent(out NetworkMatch networkMatch))
  62. continue;
  63. Guid newMatch = networkMatch.matchId;
  64. if (!lastObjectMatch.TryGetValue(identity, out Guid currentMatch))
  65. continue;
  66. // Guid.Empty is never a valid matchId
  67. // Nothing to do if matchId hasn't changed
  68. if (newMatch == Guid.Empty || newMatch == currentMatch)
  69. continue;
  70. // Mark new/old matches as dirty so they get rebuilt
  71. UpdateDirtyMatches(newMatch, currentMatch);
  72. // This object is in a new match so observers in the prior match
  73. // and the new match need to rebuild their respective observers lists.
  74. UpdateMatchObjects(identity, newMatch, currentMatch);
  75. }
  76. // rebuild all dirty matches
  77. foreach (Guid dirtyMatch in dirtyMatches)
  78. RebuildMatchObservers(dirtyMatch);
  79. dirtyMatches.Clear();
  80. }
  81. void UpdateDirtyMatches(Guid newMatch, Guid currentMatch)
  82. {
  83. // Guid.Empty is never a valid matchId
  84. if (currentMatch != Guid.Empty)
  85. dirtyMatches.Add(currentMatch);
  86. dirtyMatches.Add(newMatch);
  87. }
  88. void UpdateMatchObjects(NetworkIdentity netIdentity, Guid newMatch, Guid currentMatch)
  89. {
  90. // Remove this object from the hashset of the match it just left
  91. // Guid.Empty is never a valid matchId
  92. if (currentMatch != Guid.Empty)
  93. matchObjects[currentMatch].Remove(netIdentity);
  94. // Set this to the new match this object just entered
  95. lastObjectMatch[netIdentity] = newMatch;
  96. // Make sure this new match is in the dictionary
  97. if (!matchObjects.ContainsKey(newMatch))
  98. matchObjects.Add(newMatch, new HashSet<NetworkIdentity>());
  99. // Add this object to the hashset of the new match
  100. matchObjects[newMatch].Add(netIdentity);
  101. }
  102. void RebuildMatchObservers(Guid matchId)
  103. {
  104. foreach (NetworkIdentity netIdentity in matchObjects[matchId])
  105. if (netIdentity != null)
  106. NetworkServer.RebuildObservers(netIdentity, false);
  107. }
  108. public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver)
  109. {
  110. // Never observed if no NetworkMatch component
  111. if (!identity.TryGetComponent(out NetworkMatch identityNetworkMatch))
  112. return false;
  113. // Guid.Empty is never a valid matchId
  114. if (identityNetworkMatch.matchId == Guid.Empty)
  115. return false;
  116. // Never observed if no NetworkMatch component
  117. if (!newObserver.identity.TryGetComponent(out NetworkMatch newObserverNetworkMatch))
  118. return false;
  119. // Guid.Empty is never a valid matchId
  120. if (newObserverNetworkMatch.matchId == Guid.Empty)
  121. return false;
  122. return identityNetworkMatch.matchId == newObserverNetworkMatch.matchId;
  123. }
  124. public override void OnRebuildObservers(NetworkIdentity identity, HashSet<NetworkConnectionToClient> newObservers)
  125. {
  126. if (!identity.TryGetComponent(out NetworkMatch networkMatch))
  127. return;
  128. Guid matchId = networkMatch.matchId;
  129. // Guid.Empty is never a valid matchId
  130. if (matchId == Guid.Empty)
  131. return;
  132. if (!matchObjects.TryGetValue(matchId, out HashSet<NetworkIdentity> objects))
  133. return;
  134. // Add everything in the hashset for this object's current match
  135. foreach (NetworkIdentity networkIdentity in objects)
  136. if (networkIdentity != null && networkIdentity.connectionToClient != null)
  137. newObservers.Add(networkIdentity.connectionToClient);
  138. }
  139. }
  140. }