Skip to content

Commit 9a5929d

Browse files
committed
Bunch of new Mirror events (RemovingObserver, RemovedObserver, SendingRpc, SentRpc, UpdatingSyncVar, UpdatedSyncVar) and modified events (AddingObserver, AddedObserver, Spawning)
1 parent 72e89a0 commit 9a5929d

11 files changed

Lines changed: 676 additions & 107 deletions

LabExtended/API/MirrorMethods.cs

Lines changed: 87 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public static class MirrorMethods
2727
private static Dictionary<string, int> rpcHashes = new();
2828
private static Dictionary<string, ulong> dirtyBits = new();
2929
private static Dictionary<Type, MethodInfo> writers = new();
30+
private static Dictionary<Type, Dictionary<ulong, PropertyInfo>> propertiesByBit = new();
3031

3132
private static Action<NetworkIdentity, NetworkConnection> sendSpawnMessage;
3233

@@ -40,7 +41,7 @@ public static class MirrorMethods
4041
/// <remarks>Keys are formatted as the declaring type of the property and then the name of the property
4142
/// (MyType.MyProperty)</remarks>
4243
/// </summary>
43-
public static Dictionary<string, string> RpcNames
44+
public static IReadOnlyDictionary<string, string> RpcNames
4445
{
4546
get
4647
{
@@ -56,7 +57,7 @@ public static Dictionary<string, string> RpcNames
5657
/// <remarks>Keys are formatted as the declaring type of the property and then the name of the property
5758
/// (MyType.MyProperty)</remarks>
5859
/// </summary>
59-
public static Dictionary<string, int> RpcHashes
60+
public static IReadOnlyDictionary<string, int> RpcHashes
6061
{
6162
get
6263
{
@@ -72,7 +73,7 @@ public static Dictionary<string, int> RpcHashes
7273
/// <remarks>Keys are formatted as the declaring type of the property and then the name of the property
7374
/// (MyType.MyProperty)</remarks>
7475
/// </summary>
75-
public static Dictionary<string, ulong> DirtyBits
76+
public static IReadOnlyDictionary<string, ulong> DirtyBits
7677
{
7778
get
7879
{
@@ -83,10 +84,28 @@ public static Dictionary<string, ulong> DirtyBits
8384
}
8485
}
8586

87+
/// <summary>
88+
/// Gets a mapping of types to dictionaries that associate bit values with their corresponding property names.
89+
/// </summary>
90+
/// <remarks>This property provides access to a dictionary where each key is a type, and each value is
91+
/// another dictionary mapping bitwise flag values to property names for that type. This can be used to look up the
92+
/// name of a property based on its bit representation for supported types. The property is initialized on first
93+
/// access and is thread-safe for reading.</remarks>
94+
public static IReadOnlyDictionary<Type, Dictionary<ulong, PropertyInfo>> PropertiesByBit
95+
{
96+
get
97+
{
98+
if (!hasInitialized)
99+
Init();
100+
101+
return propertiesByBit;
102+
}
103+
}
104+
86105
/// <summary>
87106
/// Gets Mirror-generated network writer extensions.
88107
/// </summary>
89-
public static Dictionary<Type, MethodInfo> Writers
108+
public static IReadOnlyDictionary<Type, MethodInfo> Writers
90109
{
91110
get
92111
{
@@ -146,12 +165,12 @@ public static bool TryGetBehaviour<T>(uint identityId, out T behaviour) where T
146165
/// <param name="writer">The found delegate</param>
147166
/// <returns>true if the delegate was found</returns>
148167
/// <exception cref="ArgumentNullException"></exception>
149-
public static bool TryGetWriter(this Type type, out Func<object, object[], object> writer)
168+
public static bool TryGetWriter(this Type type, out MethodInfo writer)
150169
{
151170
if (type is null)
152171
throw new ArgumentNullException(nameof(type));
153172

154-
return Writers.TryGetValue(type, out writer);
173+
return writers.TryGetValue(type, out writer);
155174
}
156175

157176
/// <summary>
@@ -312,6 +331,52 @@ public static bool TryGetDirtyBit(this Type behaviourType, string propertyName,
312331

313332
return DirtyBits.TryGetValue(string.Concat(behaviourType.Name, propertyName), out dirtyBit);
314333
}
334+
335+
/// <summary>
336+
/// Attempts to retrieve the property name associated with the specified dirty bit for a given behavior type.
337+
/// </summary>
338+
/// <param name="behaviourType">The type of the behavior whose property name mapping is to be queried. Cannot be null.</param>
339+
/// <param name="dirtyBit">The dirty bit value for which to look up the corresponding property name.</param>
340+
/// <param name="property">When this method returns, contains the property associated with the specified dirty bit, if found;
341+
/// otherwise, an empty string. This parameter is passed uninitialized.</param>
342+
/// <returns>true if a property name corresponding to the specified dirty bit is found for the given behavior type;
343+
/// otherwise, false.</returns>
344+
/// <exception cref="ArgumentNullException">Thrown if behaviourType is null.</exception>
345+
public static bool TryGetPropertyName(Type behaviourType, ulong dirtyBit, out PropertyInfo property)
346+
{
347+
if (behaviourType is null)
348+
throw new ArgumentNullException(nameof(behaviourType));
349+
350+
if (!propertiesByBit.TryGetValue(behaviourType, out var dict))
351+
{
352+
property = null!;
353+
return false;
354+
}
355+
356+
return dict.TryGetValue(dirtyBit, out property);
357+
}
358+
359+
/// <summary>
360+
/// Attempts to retrieve the property name associated with the specified dirty bit for the given network behaviour
361+
/// type.
362+
/// </summary>
363+
/// <remarks>Use this method to map a dirty bit to its corresponding property name for a specific
364+
/// NetworkBehaviour type, typically when handling network synchronization or debugging.</remarks>
365+
/// <typeparam name="T">The type of NetworkBehaviour for which to look up the property name.</typeparam>
366+
/// <param name="dirtyBit">The dirty bit value representing a property to look up.</param>
367+
/// <param name="property">When this method returns, contains the property associated with the specified dirty bit, if found;
368+
/// otherwise, an empty string. This parameter is passed uninitialized.</param>
369+
/// <returns>true if a property name was found for the specified dirty bit and type; otherwise, false.</returns>
370+
public static bool TryGetPropertyName<T>(ulong dirtyBit, out PropertyInfo property) where T : NetworkBehaviour
371+
{
372+
if (!propertiesByBit.TryGetValue(typeof(T), out var dict))
373+
{
374+
property = null!;
375+
return false;
376+
}
377+
378+
return dict.TryGetValue(dirtyBit, out property);
379+
}
315380

316381
/// <summary>
317382
/// Sets a network property as dirty.
@@ -1129,8 +1194,6 @@ private static void InitIdentityServerSide(NetworkIdentity identity, NetworkConn
11291194
}
11301195
}
11311196

1132-
// TODO: There's a weird bug that causes the Mono runtime to randomly crash at random points in this method.
1133-
// Seems to be caused by the Mono runtimn as no exceptions are thrown (and it doesn't happen on Windows).
11341197
private static void Init()
11351198
{
11361199
try
@@ -1172,16 +1235,16 @@ private static void Init()
11721235
if (serializedType is null)
11731236
continue;
11741237

1175-
if (Writers.ContainsKey(serializedType))
1238+
if (writers.ContainsKey(serializedType))
11761239
continue;
11771240

1178-
Writers.Add(serializedType, method);
1241+
writers.Add(serializedType, method);
11791242
}
11801243
else if (method.HasAttribute<ClientRpcAttribute>() || method.HasAttribute<TargetRpcAttribute>())
11811244
{
11821245
var name = $"{method.ReflectedType.Name}.{method.Name}";
11831246

1184-
if (RpcNames.ContainsKey(name))
1247+
if (rpcNames.ContainsKey(name))
11851248
continue;
11861249

11871250
var body = method.GetMethodBody();
@@ -1194,14 +1257,14 @@ private static void Init()
11941257
if (codes?.Length < 1)
11951258
continue;
11961259

1197-
var full = method.Module.ResolveString(BitConverter.ToInt32(codes,
1198-
codes.IndexOf((byte)OpCodes.Ldstr.Value) + 1));
1260+
var full = method.Module.ResolveString(BitConverter.ToInt32(codes, codes.IndexOf((byte)OpCodes.Ldstr.Value) + 1));
1261+
11991262
var hashIndex = codes.IndexOf((byte)OpCodes.Ldc_I4.Value) + 1;
12001263
var hash = codes[hashIndex] | (codes[hashIndex + 1] << 8) | (codes[hashIndex + 2] << 16) |
12011264
(codes[hashIndex + 3] << 24);
12021265

1203-
RpcNames.Add(name, full);
1204-
RpcHashes.Add(name, hash);
1266+
rpcNames.Add(name, full);
1267+
rpcHashes.Add(name, hash);
12051268
}
12061269
}
12071270

@@ -1214,9 +1277,12 @@ private static void Init()
12141277

12151278
var name = $"{prop.ReflectedType.Name}.{prop.Name}";
12161279

1217-
if (DirtyBits.ContainsKey(name))
1280+
if (dirtyBits.ContainsKey(name))
12181281
continue;
12191282

1283+
if (!propertiesByBit.TryGetValue(type, out var typeDict))
1284+
propertiesByBit[type] = typeDict = new();
1285+
12201286
var setter = prop.GetSetMethod(true);
12211287

12221288
if (setter is null)
@@ -1234,7 +1300,8 @@ private static void Init()
12341300

12351301
var bit = il[il.LastIndexOf((byte)OpCodes.Ldc_I8.Value) + 1];
12361302

1237-
DirtyBits.Add(name, bit);
1303+
dirtyBits.Add(name, bit);
1304+
typeDict.Add(bit, prop);
12381305
}
12391306
}
12401307
catch (Exception ex)
@@ -1267,7 +1334,7 @@ private static void Init()
12671334
if (type is null)
12681335
continue;
12691336

1270-
Writers.Add(type, method);
1337+
writers.Add(type, method);
12711338
}
12721339
catch (Exception ex)
12731340
{
@@ -1300,10 +1367,10 @@ private static void Init()
13001367
if (type is null)
13011368
continue;
13021369

1303-
if (Writers.ContainsKey(type))
1370+
if (writers.ContainsKey(type))
13041371
continue;
13051372

1306-
Writers.Add(type, method);
1373+
writers.Add(type, method);
13071374
}
13081375
catch (Exception ex)
13091376
{

LabExtended/Core/ApiLoader.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
using LabExtended.API.Custom.Effects;
5151

5252
using Version = System.Version;
53+
using LabExtended.Patches.Events.Mirror;
5354

5455
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
5556
#pragma warning disable CS8764 // Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
@@ -370,6 +371,7 @@ private static void InvokeApi(bool isPreload)
370371
InternalEvents.Internal_Init();
371372

372373
Scp049CancellingResurrectionPatch.Internal_Init();
374+
MirrorSetSyncVarPatch.Internal_Init();
373375

374376
FirearmModuleCache.Internal_Init();
375377

LabExtended/Events/Mirror/MirrorAddedObserverEventArgs.cs

Lines changed: 0 additions & 33 deletions
This file was deleted.

LabExtended/Events/Mirror/MirrorAddingObserverEventArgs.cs

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)