TeamInterestManagement.cs 7.4 KB
Newer Older
cann-alberto's avatar
cann-alberto committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
using System.Collections.Generic;
using UnityEngine;

namespace Mirror
{
    [AddComponentMenu("Network/ Interest Management/ Team/Team Interest Management")]
    public class TeamInterestManagement : InterestManagement
    {
        readonly Dictionary<string, HashSet<NetworkTeam>> teamObjects =
            new Dictionary<string, HashSet<NetworkTeam>>();

        readonly HashSet<string> dirtyTeams = new HashSet<string>();

        // LateUpdate so that all spawns/despawns/changes are done
        [ServerCallback]
        void LateUpdate()
        {
            // Rebuild all dirty teams
            // dirtyTeams will be empty if no teams changed members
            // by spawning or destroying or changing teamId in this frame.
            foreach (string dirtyTeam in dirtyTeams)
            {
                // rebuild always, even if teamObjects[dirtyTeam] is empty.
                // Players might have left the team, but they may still be spawned.
                RebuildTeamObservers(dirtyTeam);

                // clean up empty entries in the dict
                if (teamObjects[dirtyTeam].Count == 0)
                    teamObjects.Remove(dirtyTeam);
            }

            dirtyTeams.Clear();
        }

        [ServerCallback]
        void RebuildTeamObservers(string teamId)
        {
            foreach (NetworkTeam networkTeam in teamObjects[teamId])
                if (networkTeam.netIdentity != null)
                    NetworkServer.RebuildObservers(networkTeam.netIdentity, false);
        }

        // called by NetworkTeam.teamId setter
        [ServerCallback]
        internal void OnTeamChanged(NetworkTeam networkTeam, string oldTeam)
        {
            // This object is in a new team so observers in the prior team
            // and the new team need to rebuild their respective observers lists.

            // Remove this object from the hashset of the team it just left
            // Null / Empty string is never a valid teamId
            if (!string.IsNullOrWhiteSpace(oldTeam))
            {
                dirtyTeams.Add(oldTeam);
                teamObjects[oldTeam].Remove(networkTeam);
            }

            // Null / Empty string is never a valid teamId
            if (string.IsNullOrWhiteSpace(networkTeam.teamId))
                return;

            dirtyTeams.Add(networkTeam.teamId);

            // Make sure this new team is in the dictionary
            if (!teamObjects.ContainsKey(networkTeam.teamId))
                teamObjects[networkTeam.teamId] = new HashSet<NetworkTeam>();

            // Add this object to the hashset of the new team
            teamObjects[networkTeam.teamId].Add(networkTeam);
        }

        [ServerCallback]
        public override void OnSpawned(NetworkIdentity identity)
        {
            if (!identity.TryGetComponent(out NetworkTeam networkTeam))
                return;

            string networkTeamId = networkTeam.teamId;

            // Null / Empty string is never a valid teamId...do not add to teamObjects collection
            if (string.IsNullOrWhiteSpace(networkTeamId))
                return;

            // Debug.Log($"TeamInterestManagement.OnSpawned({identity.name}) currentTeam: {currentTeam}");
            if (!teamObjects.TryGetValue(networkTeamId, out HashSet<NetworkTeam> objects))
            {
                objects = new HashSet<NetworkTeam>();
                teamObjects.Add(networkTeamId, objects);
            }

            objects.Add(networkTeam);

            // Team ID could have been set in NetworkBehaviour::OnStartServer on this object.
            // Since that's after OnCheckObserver is called it would be missed, so force Rebuild here.
            // Add the current team to dirtyTeames for LateUpdate to rebuild it.
            dirtyTeams.Add(networkTeamId);
        }

        [ServerCallback]
        public override void OnDestroyed(NetworkIdentity identity)
        {
            // Don't RebuildSceneObservers here - that will happen in LateUpdate.
            // Multiple objects could be destroyed in same frame and we don't
            // want to rebuild for each one...let LateUpdate do it once.
            // We must add the current team to dirtyTeames for LateUpdate to rebuild it.
            if (identity.TryGetComponent(out NetworkTeam currentTeam))
            {
                if (!string.IsNullOrWhiteSpace(currentTeam.teamId) &&
                    teamObjects.TryGetValue(currentTeam.teamId, out HashSet<NetworkTeam> objects) &&
                    objects.Remove(currentTeam))
                    dirtyTeams.Add(currentTeam.teamId);
            }
        }

        public override bool OnCheckObserver(NetworkIdentity identity, NetworkConnectionToClient newObserver)
        {
            // Always observed if no NetworkTeam component
            if (!identity.TryGetComponent(out NetworkTeam identityNetworkTeam))
                return true;

            if (identityNetworkTeam.forceShown)
                return true;

            // Null / Empty string is never a valid teamId
            if (string.IsNullOrWhiteSpace(identityNetworkTeam.teamId))
                return false;

            // Always observed if no NetworkTeam component
            if (!newObserver.identity.TryGetComponent(out NetworkTeam newObserverNetworkTeam))
                return true;

            // Null / Empty string is never a valid teamId
            if (string.IsNullOrWhiteSpace(newObserverNetworkTeam.teamId))
                return false;

            //Debug.Log($"TeamInterestManagement.OnCheckObserver {identity.name} {identityNetworkTeam.teamId} | {newObserver.identity.name} {newObserverNetworkTeam.teamId}");

            // Observed only if teamId's team
            return identityNetworkTeam.teamId == newObserverNetworkTeam.teamId;
        }

        public override void OnRebuildObservers(NetworkIdentity identity, HashSet<NetworkConnectionToClient> newObservers)
        {
            // If this object doesn't have a NetworkTeam then it's visible to all clients
            if (!identity.TryGetComponent(out NetworkTeam networkTeam))
            {
                AddAllConnections(newObservers);
                return;
            }

            // If this object has NetworkTeam and forceShown == true then it's visible to all clients
            if (networkTeam.forceShown)
            {
                AddAllConnections(newObservers);
                return;
            }

            // Null / Empty string is never a valid teamId
            if (string.IsNullOrWhiteSpace(networkTeam.teamId))
                return;

            // Abort if this team hasn't been created yet by OnSpawned or OnTeamChanged
            if (!teamObjects.TryGetValue(networkTeam.teamId, out HashSet<NetworkTeam> objects))
                return;

            // Add everything in the hashset for this object's current team
            foreach (NetworkTeam netTeam in objects)
                if (netTeam.netIdentity != null && netTeam.netIdentity.connectionToClient != null)
                    newObservers.Add(netTeam.netIdentity.connectionToClient);
        }

        void AddAllConnections(HashSet<NetworkConnectionToClient> newObservers)
        {
            foreach (NetworkConnectionToClient conn in NetworkServer.connections.Values)
            {
                // authenticated and joined world with a player?
                if (conn != null && conn.isAuthenticated && conn.identity != null)
                    newObservers.Add(conn);
            }
        }
    }
}