Skip to content

Commit 027f807

Browse files
authored
refactor: Part 2 of INetworkMessage ILPP refactor (#1282)
Moves all aspects of message registration go ILPP and replaces attribute inspection with an IMessageProvider class that allows tests to change the discovery from the automatic ILPP discovery to returning a defined set of messages for the test.
1 parent dbd2fcb commit 027f807

12 files changed

+204
-149
lines changed

com.unity.netcode.gameobjects/Editor/CodeGen/CodeGenHelpers.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ internal static class CodeGenHelpers
2323
public static readonly string ServerRpcParams_FullName = typeof(ServerRpcParams).FullName;
2424
public static readonly string ClientRpcParams_FullName = typeof(ClientRpcParams).FullName;
2525
public static readonly string INetworkSerializable_FullName = typeof(INetworkSerializable).FullName;
26-
public static readonly string INetworkSerializable_NetworkSerialize_Name = nameof(INetworkSerializable.NetworkSerialize);
27-
public static readonly string IgnoreMessageIfSystemOwnerIsNotOfTypeAttribute_FullName = typeof(IgnoreMessageIfSystemOwnerIsNotOfTypeAttribute).FullName;
2826
public static readonly string UnityColor_FullName = typeof(Color).FullName;
2927
public static readonly string UnityColor32_FullName = typeof(Color32).FullName;
3028
public static readonly string UnityVector2_FullName = typeof(Vector2).FullName;

com.unity.netcode.gameobjects/Editor/CodeGen/INetworkMessageILPP.cs

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
5959

6060
try
6161
{
62-
types.ForEach(b => ProcessINetworkMessage(b));
6362
CreateModuleInitializer(assemblyDefinition, types);
6463
}
6564
catch (Exception e)
@@ -98,7 +97,11 @@ public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly)
9897

9998
private TypeReference m_FastBufferReader_TypeRef;
10099
private TypeReference m_NetworkContext_TypeRef;
101-
private FieldReference m_MessagingSystem___network_message_types_FieldRef;
100+
private TypeReference m_MessagingSystem_MessageWithHandler_TypeRef;
101+
private MethodReference m_MessagingSystem_MessageHandler_Constructor_TypeRef;
102+
private FieldReference m_ILPPMessageProvider___network_message_types_FieldRef;
103+
private FieldReference m_MessagingSystem_MessageWithHandler_MessageType_FieldRef;
104+
private FieldReference m_MessagingSystem_MessageWithHandler_Handler_FieldRef;
102105
private MethodReference m_Type_GetTypeFromHandle_MethodRef;
103106

104107
private MethodReference m_List_Add_MethodRef;
@@ -107,6 +110,24 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
107110
{
108111
m_FastBufferReader_TypeRef = moduleDefinition.ImportReference(typeof(FastBufferReader));
109112
m_NetworkContext_TypeRef = moduleDefinition.ImportReference(typeof(NetworkContext));
113+
m_MessagingSystem_MessageHandler_Constructor_TypeRef =
114+
moduleDefinition.ImportReference(typeof(MessagingSystem.MessageHandler).GetConstructors()[0]);
115+
116+
var messageWithHandlerType = typeof(MessagingSystem.MessageWithHandler);
117+
m_MessagingSystem_MessageWithHandler_TypeRef =
118+
moduleDefinition.ImportReference(messageWithHandlerType);
119+
foreach (var fieldInfo in messageWithHandlerType.GetFields())
120+
{
121+
switch (fieldInfo.Name)
122+
{
123+
case nameof(MessagingSystem.MessageWithHandler.MessageType):
124+
m_MessagingSystem_MessageWithHandler_MessageType_FieldRef = moduleDefinition.ImportReference(fieldInfo);
125+
break;
126+
case nameof(MessagingSystem.MessageWithHandler.Handler):
127+
m_MessagingSystem_MessageWithHandler_Handler_FieldRef = moduleDefinition.ImportReference(fieldInfo);
128+
break;
129+
}
130+
}
110131

111132
var typeType = typeof(Type);
112133
foreach (var methodInfo in typeType.GetMethods())
@@ -119,23 +140,23 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
119140
}
120141
}
121142

122-
var messagingSystemType = typeof(MessagingSystem);
123-
foreach (var fieldInfo in messagingSystemType.GetFields(BindingFlags.Static | BindingFlags.NonPublic))
143+
var ilppMessageProviderType = typeof(ILPPMessageProvider);
144+
foreach (var fieldInfo in ilppMessageProviderType.GetFields(BindingFlags.Static | BindingFlags.NonPublic))
124145
{
125146
switch (fieldInfo.Name)
126147
{
127-
case nameof(MessagingSystem.__network_message_types):
128-
m_MessagingSystem___network_message_types_FieldRef = moduleDefinition.ImportReference(fieldInfo);
148+
case nameof(ILPPMessageProvider.__network_message_types):
149+
m_ILPPMessageProvider___network_message_types_FieldRef = moduleDefinition.ImportReference(fieldInfo);
129150
break;
130151
}
131152
}
132153

133-
var listType = typeof(List<Type>);
154+
var listType = typeof(List<MessagingSystem.MessageWithHandler>);
134155
foreach (var methodInfo in listType.GetMethods())
135156
{
136157
switch (methodInfo.Name)
137158
{
138-
case nameof(List<Type>.Add):
159+
case nameof(List<MessagingSystem.MessageWithHandler>.Add):
139160
m_List_Add_MethodRef = moduleDefinition.ImportReference(methodInfo);
140161
break;
141162
}
@@ -145,9 +166,8 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
145166
return true;
146167
}
147168

148-
private void ProcessINetworkMessage(TypeDefinition typeDefinition)
169+
private MethodReference GetNetworkMessageRecieveHandler(TypeDefinition typeDefinition)
149170
{
150-
var foundAValidMethod = false;
151171
SequencePoint typeSequence = null;
152172
foreach (var method in typeDefinition.Methods)
153173
{
@@ -168,15 +188,12 @@ private void ProcessINetworkMessage(TypeDefinition typeDefinition)
168188
&& resolved.Parameters[1].ParameterType.GetElementType().Resolve() == m_NetworkContext_TypeRef.Resolve()
169189
&& resolved.ReturnType == resolved.Module.TypeSystem.Void)
170190
{
171-
foundAValidMethod = true;
172-
break;
191+
return method;
173192
}
174193
}
175194

176-
if (!foundAValidMethod)
177-
{
178-
m_Diagnostics.AddError(typeSequence, $"Class {typeDefinition.FullName} does not implement required function: `public static void Receive(FastBufferReader, in NetworkContext)`");
179-
}
195+
m_Diagnostics.AddError(typeSequence, $"Class {typeDefinition.FullName} does not implement required method: `public static void Receive(FastBufferReader, in NetworkContext)`");
196+
return null;
180197
}
181198

182199
private MethodDefinition GetOrCreateStaticConstructor(TypeDefinition typeDefinition)
@@ -198,12 +215,32 @@ private MethodDefinition GetOrCreateStaticConstructor(TypeDefinition typeDefinit
198215
return staticCtorMethodDef;
199216
}
200217

201-
private void CreateInstructionsToRegisterType(ILProcessor processor, List<Instruction> instructions, TypeReference type)
218+
private void CreateInstructionsToRegisterType(ILProcessor processor, List<Instruction> instructions, TypeReference type, MethodReference receiveMethod)
202219
{
203-
// MessagingSystem.__network_message_types.Add(typeof(type));
204-
instructions.Add(processor.Create(OpCodes.Ldsfld, m_MessagingSystem___network_message_types_FieldRef));
220+
// MessagingSystem.__network_message_types.Add(new MessagingSystem.MessageWithHandler{MessageType=typeof(type), Handler=type.Receive});
221+
processor.Body.Variables.Add(new VariableDefinition(m_MessagingSystem_MessageWithHandler_TypeRef));
222+
int messageWithHandlerLocIdx = processor.Body.Variables.Count - 1;
223+
224+
instructions.Add(processor.Create(OpCodes.Ldsfld, m_ILPPMessageProvider___network_message_types_FieldRef));
225+
instructions.Add(processor.Create(OpCodes.Ldloca, messageWithHandlerLocIdx));
226+
instructions.Add(processor.Create(OpCodes.Initobj, m_MessagingSystem_MessageWithHandler_TypeRef));
227+
228+
// tmp.MessageType = typeof(type);
229+
instructions.Add(processor.Create(OpCodes.Ldloca, messageWithHandlerLocIdx));
205230
instructions.Add(processor.Create(OpCodes.Ldtoken, type));
206231
instructions.Add(processor.Create(OpCodes.Call, m_Type_GetTypeFromHandle_MethodRef));
232+
instructions.Add(processor.Create(OpCodes.Stfld, m_MessagingSystem_MessageWithHandler_MessageType_FieldRef));
233+
234+
// tmp.Handler = type.Receive
235+
instructions.Add(processor.Create(OpCodes.Ldloca, messageWithHandlerLocIdx));
236+
instructions.Add(processor.Create(OpCodes.Ldnull));
237+
238+
instructions.Add(processor.Create(OpCodes.Ldftn, receiveMethod));
239+
instructions.Add(processor.Create(OpCodes.Newobj, m_MessagingSystem_MessageHandler_Constructor_TypeRef));
240+
instructions.Add(processor.Create(OpCodes.Stfld, m_MessagingSystem_MessageWithHandler_Handler_FieldRef));
241+
242+
// ILPPMessageProvider.__network_message_types.Add(tmp);
243+
instructions.Add(processor.Create(OpCodes.Ldloc, messageWithHandlerLocIdx));
207244
instructions.Add(processor.Create(OpCodes.Callvirt, m_List_Add_MethodRef));
208245
}
209246

@@ -227,7 +264,12 @@ private void CreateModuleInitializer(AssemblyDefinition assembly, List<TypeDefin
227264

228265
foreach (var type in networkMessageTypes)
229266
{
230-
CreateInstructionsToRegisterType(processor, instructions, type);
267+
var receiveMethod = GetNetworkMessageRecieveHandler(type);
268+
if (receiveMethod == null)
269+
{
270+
continue;
271+
}
272+
CreateInstructionsToRegisterType(processor, instructions, type, receiveMethod);
231273
}
232274

233275
instructions.ForEach(instruction => processor.Body.Instructions.Insert(processor.Body.Instructions.Count - 1, instruction));

com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,7 @@ public GameObject GetNetworkPrefabOverride(GameObject gameObject)
241241
public ulong LocalClientId
242242
{
243243
get => IsServer ? NetworkConfig.NetworkTransport.ServerClientId : m_LocalClientId;
244-
internal set
245-
{
246-
m_LocalClientId = value;
247-
MessagingSystem.SetLocalClientId(value);
248-
}
244+
internal set => m_LocalClientId = value;
249245
}
250246

251247
private ulong m_LocalClientId;
@@ -497,7 +493,7 @@ private void Initialize(bool server)
497493
this.RegisterNetworkUpdate(NetworkUpdateStage.EarlyUpdate);
498494
this.RegisterNetworkUpdate(NetworkUpdateStage.PostLateUpdate);
499495

500-
MessagingSystem = new MessagingSystem(new NetworkManagerMessageSender(this), this, ulong.MaxValue);
496+
MessagingSystem = new MessagingSystem(new NetworkManagerMessageSender(this), this);
501497

502498
MessagingSystem.Hook(new NetworkManagerHooks(this));
503499
#if DEVELOPMENT_BUILD || UNITY_EDITOR
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Collections.Generic;
2+
3+
namespace Unity.Netcode
4+
{
5+
internal struct ILPPMessageProvider : IMessageProvider
6+
{
7+
#pragma warning disable IDE1006 // disable naming rule violation check
8+
// This is NOT modified by RuntimeAccessModifiersILPP right now, but is populated by ILPP.
9+
internal static readonly List<MessagingSystem.MessageWithHandler> __network_message_types = new List<MessagingSystem.MessageWithHandler>();
10+
#pragma warning restore IDE1006 // restore naming rule violation check
11+
12+
public List<MessagingSystem.MessageWithHandler> GetMessages()
13+
{
14+
return __network_message_types;
15+
}
16+
}
17+
}
Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Collections.Generic;
2+
3+
namespace Unity.Netcode
4+
{
5+
internal interface IMessageProvider
6+
{
7+
List<MessagingSystem.MessageWithHandler> GetMessages();
8+
}
9+
}

com.unity.netcode.gameobjects/Runtime/Messaging/IMessageProvider.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

com.unity.netcode.gameobjects/Runtime/Messaging/IgnoreMessageIfSystemOwnerIsNotOfTypeAttribute.cs

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

com.unity.netcode.gameobjects/Runtime/Messaging/MessagingSystem.cs

Lines changed: 15 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,6 @@ public InvalidMessageStructureException(string issue) : base(issue) { }
1717

1818
internal class MessagingSystem : IDisposable
1919
{
20-
21-
22-
#pragma warning disable IDE1006 // disable naming rule violation check
23-
// This is NOT modified by RuntimeAccessModifiersILPP right now, but is populated by ILPP.
24-
internal static readonly List<Type> __network_message_types = new List<Type>();
25-
#pragma warning restore IDE1006 // restore naming rule violation check
26-
2720
private struct ReceiveQueueItem
2821
{
2922
public FastBufferReader Reader;
@@ -61,7 +54,6 @@ public SendQueueItem(NetworkDelivery delivery, int writerSize, Allocator writerA
6154
private byte m_HighMessageType;
6255
private object m_Owner;
6356
private IMessageSender m_MessageSender;
64-
private ulong m_LocalClientId;
6557
private bool m_Disposed;
6658

6759
internal Type[] MessageTypes => m_ReverseTypeMap;
@@ -76,50 +68,26 @@ internal byte GetMessageType(Type t)
7668
public const int NON_FRAGMENTED_MESSAGE_MAX_SIZE = 1300;
7769
public const int FRAGMENTED_MESSAGE_MAX_SIZE = 64000;
7870

79-
public MessagingSystem(IMessageSender messageSender, object owner, ulong localClientId = long.MaxValue)
71+
internal struct MessageWithHandler
72+
{
73+
public Type MessageType;
74+
public MessageHandler Handler;
75+
}
76+
77+
public MessagingSystem(IMessageSender messageSender, object owner, IMessageProvider provider = null)
8078
{
8179
try
8280
{
83-
m_LocalClientId = localClientId;
8481
m_MessageSender = messageSender;
8582
m_Owner = owner;
8683

87-
var allowedTypes = new List<Type>();
88-
foreach (var type in __network_message_types)
84+
if (provider == null)
8985
{
90-
var attributes = type.GetCustomAttributes(typeof(IgnoreMessageIfSystemOwnerIsNotOfTypeAttribute), false);
91-
// If [IgnoreMessageIfSystemOwnerIsNotOfTypeAttribute(ownerType)] isn't provided, it defaults
92-
// to being bound to NetworkManager. This is technically a breach of domain by having
93-
// MessagingSystem know about the existence of NetworkManager... but ultimately,
94-
// IgnoreMessageIfSystemOwnerIsNotOfTypeAttribute is provided to support testing, not to support
95-
// general use of MessagingSystem outside of Netcode for GameObjects, so having MessagingSystem
96-
// know about NetworkManager isn't so bad. Especially since it's just a default value.
97-
// This is just a convenience to keep us and our users from having to use
98-
// [Bind(typeof(NetworkManager))] on every message - only tests that don't want to use
99-
// the full NetworkManager need to worry about it.
100-
var shouldSkip = attributes.Length != 0 || !(m_Owner is NetworkManager);
101-
for (var i = 0; i < attributes.Length; ++i)
102-
{
103-
var bindAttribute = (IgnoreMessageIfSystemOwnerIsNotOfTypeAttribute)attributes[i];
104-
if (
105-
(bindAttribute.BoundType != null &&
106-
bindAttribute.BoundType.IsInstanceOfType(m_Owner)) ||
107-
(m_Owner == null && bindAttribute.BoundType == null))
108-
{
109-
shouldSkip = false;
110-
break;
111-
}
112-
}
113-
114-
if (shouldSkip)
115-
{
116-
continue;
117-
}
118-
119-
allowedTypes.Add(type);
86+
provider = new ILPPMessageProvider();
12087
}
88+
var allowedTypes = provider.GetMessages();
12189

122-
allowedTypes.Sort((a, b) => string.CompareOrdinal(a.FullName, b.FullName));
90+
allowedTypes.Sort((a, b) => string.CompareOrdinal(a.MessageType.FullName, b.MessageType.FullName));
12391
foreach (var type in allowedTypes)
12492
{
12593
RegisterMessageType(type);
@@ -154,40 +122,16 @@ public void Dispose()
154122
Dispose();
155123
}
156124

157-
public void SetLocalClientId(ulong localClientId)
158-
{
159-
m_LocalClientId = localClientId;
160-
}
161-
162125
public void Hook(INetworkHooks hooks)
163126
{
164127
m_Hooks.Add(hooks);
165128
}
166129

167-
private void RegisterMessageType(Type messageType)
130+
private void RegisterMessageType(MessageWithHandler messageWithHandler)
168131
{
169-
if (!typeof(INetworkMessage).IsAssignableFrom(messageType))
170-
{
171-
throw new ArgumentException("RegisterMessageType types must be INetworkMessage types.");
172-
}
173-
174-
var method = messageType.GetMethod("Receive");
175-
if (method == null)
176-
{
177-
throw new InvalidMessageStructureException(
178-
$"{messageType.FullName}: All INetworkMessage types must implement public static void Receive(FastBufferReader reader, in NetworkContext context)");
179-
}
180-
181-
var asDelegate = Delegate.CreateDelegate(typeof(MessageHandler), method, false);
182-
if (asDelegate == null)
183-
{
184-
throw new InvalidMessageStructureException(
185-
$"{messageType.FullName}: All INetworkMessage types must implement public static void Receive(FastBufferReader reader, in NetworkContext context)");
186-
}
187-
188-
m_MessageHandlers[m_HighMessageType] = (MessageHandler)asDelegate;
189-
m_ReverseTypeMap[m_HighMessageType] = messageType;
190-
m_MessageTypes[messageType] = m_HighMessageType++;
132+
m_MessageHandlers[m_HighMessageType] = messageWithHandler.Handler;
133+
m_ReverseTypeMap[m_HighMessageType] = messageWithHandler.MessageType;
134+
m_MessageTypes[messageWithHandler.MessageType] = m_HighMessageType++;
191135
}
192136

193137
internal void HandleIncomingData(ulong clientId, ArraySegment<byte> data, float receiveTime)

0 commit comments

Comments
 (0)