-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathNetworkWorld.cs
More file actions
140 lines (118 loc) · 5.42 KB
/
Copy pathNetworkWorld.cs
File metadata and controls
140 lines (118 loc) · 5.42 KB
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
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Mirage.Logging;
using UnityEngine;
namespace Mirage
{
/// <summary>
/// Event that can be used to check authority
/// </summary>
/// <param name="hasAuthority">if the owner now has authority or if it was removed</param>
/// <param name="owner">the new or old owner. Owner value might be null on client side. But will be set on server</param>
public delegate void AuthorityChanged(NetworkIdentity identity, bool hasAuthority, INetworkPlayer owner);
/// <summary>
/// Holds collection of spawned network objects
/// <para>This class works on both server and client</para>
/// </summary>
public class NetworkWorld : IObjectLocator
{
private static readonly ILogger logger = LogFactory.GetLogger<NetworkWorld>();
/// <summary>
/// Raised when object is spawned
/// </summary>
public event Action<NetworkIdentity> onSpawn;
/// <summary>
/// Raised when object is unspawned or destroyed
/// </summary>
public event Action<NetworkIdentity> onUnspawn;
/// <summary>
/// Raised when authority is given or removed from an identity. It is invoked on both server and client
/// <para>
/// Can be used when you need to check for authority on all objects, rather than adding an event to each object.
/// </para>
/// </summary>
public event AuthorityChanged OnAuthorityChanged;
/// <summary>
/// Time kept in this world
/// </summary>
public NetworkTime Time { get; } = new NetworkTime();
private readonly Dictionary<uint, NetworkIdentity> _spawnedObjects = new Dictionary<uint, NetworkIdentity>();
public IReadOnlyCollection<NetworkIdentity> SpawnedIdentities => _spawnedObjects.Values;
public bool TryGetIdentity(uint netId, out NetworkIdentity identity)
{
return _spawnedObjects.TryGetValue(netId, out identity) && identity != null;
}
/// <summary>
/// Adds Identity to world and invokes spawned event
/// </summary>
/// <param name="netId"></param>
/// <param name="identity"></param>
internal void AddIdentity(uint netId, NetworkIdentity identity)
{
if (netId == 0) throw new ArgumentException("id can not be zero", nameof(netId));
if (identity == null) throw new ArgumentNullException(nameof(identity));
if (netId != identity.NetId) throw new ArgumentException("NetworkIdentity did not have matching netId", nameof(identity));
if (_spawnedObjects.TryGetValue(netId, out var existing) && existing != null) throw new ArgumentException("An Identity with same id already exists in network world", nameof(netId));
if (logger.LogEnabled()) logger.Log($"Adding [netId={netId}, name={identity.name}] to World");
// dont use add, netId might already exist but have been destroyed
// this can happen client side. we check for this case in TryGetValue above
_spawnedObjects[netId] = identity;
onSpawn?.Invoke(identity);
// owner might be set before World is
// so we need to invoke authChange now if the object has an owner
if (identity.Owner != null)
InvokeOnAuthorityChanged(identity, true, identity.Owner);
}
internal void RemoveIdentity(NetworkIdentity identity)
{
var netId = identity.NetId;
RemoveInternal(netId, identity);
}
internal void RemoveIdentity(uint netId)
{
if (netId == 0) throw new ArgumentException("id can not be zero", nameof(netId));
_spawnedObjects.TryGetValue(netId, out var identity);
RemoveInternal(netId, identity);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void RemoveInternal(uint netId, NetworkIdentity identity)
{
var removed = _spawnedObjects.Remove(netId);
// only invoke event if values was successfully removed
if (removed)
{
if (logger.LogEnabled()) logger.Log($"Removing [netId={netId}, name={identity?.name}] from World");
onUnspawn?.Invoke(identity);
}
else
{
if (logger.LogEnabled()) logger.Log($"Did not remove [netId={netId}, name={identity?.name}] from World. Maybe it was previously removed?");
}
}
internal void RemoveDestroyedObjects()
{
if (logger.LogEnabled()) logger.Log($"Removing destroyed objects");
var removalCollection = new List<NetworkIdentity>(SpawnedIdentities);
foreach (var identity in removalCollection)
{
if (identity == null)
{
if (logger.LogEnabled()) logger.Log($"Removing destroyed object:[netId={identity.NetId}]");
_spawnedObjects.Remove(identity.NetId);
}
}
}
internal void ClearSpawnedObjects()
{
_spawnedObjects.Clear();
}
internal void InvokeOnAuthorityChanged(NetworkIdentity identity, bool hasAuthority, INetworkPlayer owner)
{
OnAuthorityChanged?.Invoke(identity, hasAuthority, owner);
}
public NetworkWorld()
{
}
}
}