Format code
This commit is contained in:
@@ -53,6 +53,7 @@ namespace Flax.Build.Plugins
|
||||
internal const string NetworkRpc = "NetworkRpc";
|
||||
private const string Thunk1 = "INetworkSerializable_Serialize";
|
||||
private const string Thunk2 = "INetworkSerializable_Deserialize";
|
||||
|
||||
private static readonly Dictionary<string, InBuildSerializer> _inBuildSerializers = new Dictionary<string, InBuildSerializer>()
|
||||
{
|
||||
{ "System.Boolean", new InBuildSerializer("WriteBoolean", "ReadBoolean") },
|
||||
@@ -127,6 +128,7 @@ namespace Flax.Build.Plugins
|
||||
{
|
||||
fields = structInfo.Fields;
|
||||
}
|
||||
|
||||
bool useReplication = false, useRpc = false;
|
||||
if (fields != null)
|
||||
{
|
||||
@@ -139,6 +141,7 @@ namespace Flax.Build.Plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (properties != null)
|
||||
{
|
||||
foreach (var propertyInfo in properties)
|
||||
@@ -150,6 +153,7 @@ namespace Flax.Build.Plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (functions != null)
|
||||
{
|
||||
foreach (var functionInfo in functions)
|
||||
@@ -161,20 +165,22 @@ namespace Flax.Build.Plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useReplication)
|
||||
{
|
||||
typeInfo.SetTag(NetworkReplicated, string.Empty);
|
||||
|
||||
|
||||
// Generate C++ wrapper functions to serialize/deserialize type
|
||||
BindingsGenerator.CppIncludeFiles.Add("Engine/Networking/NetworkReplicator.h");
|
||||
BindingsGenerator.CppIncludeFiles.Add("Engine/Networking/NetworkStream.h");
|
||||
OnGenerateCppTypeSerialize(buildData, typeInfo, contents, fields, properties, true);
|
||||
OnGenerateCppTypeSerialize(buildData, typeInfo, contents, fields, properties, false);
|
||||
}
|
||||
|
||||
if (useRpc)
|
||||
{
|
||||
typeInfo.SetTag(NetworkRpc, string.Empty);
|
||||
|
||||
|
||||
// Generate C++ wrapper functions to invoke/execute RPC
|
||||
BindingsGenerator.CppIncludeFiles.Add("Engine/Networking/NetworkStream.h");
|
||||
BindingsGenerator.CppIncludeFiles.Add("Engine/Networking/NetworkReplicator.h");
|
||||
@@ -282,7 +288,7 @@ namespace Flax.Build.Plugins
|
||||
// Replicate base type
|
||||
OnGenerateCppWriteSerializer(contents, classStructInfo.BaseType.NativeName, "obj", serialize);
|
||||
}
|
||||
|
||||
|
||||
// Replicate all marked fields and properties
|
||||
if (fields != null)
|
||||
{
|
||||
@@ -293,6 +299,7 @@ namespace Flax.Build.Plugins
|
||||
OnGenerateCppTypeSerializeData(buildData, typeInfo, contents, fieldInfo.Type, $"obj.{fieldInfo.Name}", serialize);
|
||||
}
|
||||
}
|
||||
|
||||
if (properties != null)
|
||||
{
|
||||
foreach (var propertyInfo in properties)
|
||||
@@ -308,6 +315,7 @@ namespace Flax.Build.Plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contents.AppendLine(" }");
|
||||
contents.AppendLine();
|
||||
}
|
||||
@@ -326,9 +334,10 @@ namespace Flax.Build.Plugins
|
||||
if (apiType != null)
|
||||
return IsRawPOD(buildData, apiType);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void OnGenerateCppTypeSerializeData(Builder.BuildData buildData, ApiTypeInfo caller, StringBuilder contents, TypeInfo type, string name, bool serialize)
|
||||
{
|
||||
var apiType = BindingsGenerator.FindApiTypeInfo(buildData, type, caller);
|
||||
@@ -365,7 +374,7 @@ namespace Flax.Build.Plugins
|
||||
throw new Exception($"Invalid pointer type '{type}' that cannot be serialized for replication of {caller.Name}.");
|
||||
if (type.IsRef)
|
||||
throw new Exception($"Invalid reference type '{type}' that cannot be serialized for replication of {caller.Name}.");
|
||||
|
||||
|
||||
// Structure serializer
|
||||
OnGenerateCppWriteSerializer(contents, apiType.NativeName, name, serialize);
|
||||
}
|
||||
@@ -375,13 +384,13 @@ namespace Flax.Build.Plugins
|
||||
OnGenerateCppWriteRaw(contents, name, serialize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnGenerateCppWriteRaw(StringBuilder contents, string data, bool serialize)
|
||||
{
|
||||
var method = serialize ? "Write" : "Read";
|
||||
contents.AppendLine($" stream->{method}({data});");
|
||||
}
|
||||
|
||||
|
||||
private void OnGenerateCppWriteSerializer(StringBuilder contents, string type, string data, bool serialize)
|
||||
{
|
||||
if (type == "ScriptingObject" || type == "Script" || type == "Actor")
|
||||
@@ -405,6 +414,7 @@ namespace Flax.Build.Plugins
|
||||
// Register generated serializer functions
|
||||
contents.AppendLine($" NetworkReplicator::AddSerializer(ScriptingTypeHandle({typeNameNative}::TypeInitializer), {typeNameInternal}Internal::INetworkSerializable_Serialize, {typeNameInternal}Internal::INetworkSerializable_Deserialize);");
|
||||
}
|
||||
|
||||
if (rpcTag != null)
|
||||
{
|
||||
// Register generated RPCs
|
||||
@@ -413,6 +423,7 @@ namespace Flax.Build.Plugins
|
||||
{
|
||||
functions = classInfo.Functions;
|
||||
}
|
||||
|
||||
if (functions != null)
|
||||
{
|
||||
foreach (var functionInfo in functions)
|
||||
@@ -430,16 +441,15 @@ namespace Flax.Build.Plugins
|
||||
// Skip types that don't use networking
|
||||
if (typeInfo.GetTag(NetworkReplicated) == null)
|
||||
return;
|
||||
|
||||
|
||||
if (typeInfo is ClassInfo)
|
||||
return;
|
||||
|
||||
// Generate C# wrapper functions to serialize/deserialize type directly from managed code
|
||||
OnGenerateCSharpTypeSerialize(buildData, typeInfo, contents, indent, true);
|
||||
OnGenerateCSharpTypeSerialize(buildData, typeInfo, contents, indent, false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void OnGenerateCSharpTypeSerialize(Builder.BuildData buildData, ApiTypeInfo typeInfo, StringBuilder contents, string indent, bool serialize)
|
||||
{
|
||||
var mode = serialize ? "true" : "false";
|
||||
@@ -463,6 +473,7 @@ namespace Flax.Build.Plugins
|
||||
contents.Append(indent).AppendLine($" throw new NotImplementedException(\"Not supported native structure with references used in managed code for replication.\");");
|
||||
}
|
||||
}
|
||||
|
||||
contents.Append(indent).AppendLine("}");
|
||||
}
|
||||
|
||||
@@ -493,7 +504,7 @@ namespace Flax.Build.Plugins
|
||||
private void OnPatchDotNetAssembly(Builder.BuildData buildData, NativeCpp.BuildOptions buildOptions, Task buildTask, string assemblyPath)
|
||||
{
|
||||
using (DefaultAssemblyResolver assemblyResolver = new DefaultAssemblyResolver())
|
||||
using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters{ ReadWrite = true, ReadSymbols = true, AssemblyResolver = assemblyResolver }))
|
||||
using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters { ReadWrite = true, ReadSymbols = true, AssemblyResolver = assemblyResolver }))
|
||||
{
|
||||
// Setup module search locations
|
||||
var searchDirectories = new HashSet<string>();
|
||||
@@ -503,6 +514,7 @@ namespace Flax.Build.Plugins
|
||||
if (file.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
|
||||
searchDirectories.Add(Path.GetDirectoryName(file));
|
||||
}
|
||||
|
||||
foreach (var e in searchDirectories)
|
||||
assemblyResolver.AddSearchDirectory(e);
|
||||
|
||||
@@ -554,6 +566,7 @@ namespace Flax.Build.Plugins
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var isNetworkReplicated = false;
|
||||
foreach (FieldDefinition f in type.Fields)
|
||||
{
|
||||
@@ -562,6 +575,7 @@ namespace Flax.Build.Plugins
|
||||
isNetworkReplicated = true;
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (PropertyDefinition p in type.Properties)
|
||||
{
|
||||
if (!p.HasAttribute(NetworkReplicatedAttribute))
|
||||
@@ -569,6 +583,7 @@ namespace Flax.Build.Plugins
|
||||
isNetworkReplicated = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (type.IsValueType)
|
||||
{
|
||||
if (isINetworkSerializable)
|
||||
@@ -597,6 +612,7 @@ namespace Flax.Build.Plugins
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed)
|
||||
throw new Exception($"Failed to generate network replication for assembly {assemblyPath}");
|
||||
if (!modified)
|
||||
@@ -650,6 +666,7 @@ namespace Flax.Build.Plugins
|
||||
il.Emit(OpCodes.Newobj, module.ImportReference(serializeFuncCtor));
|
||||
il.Emit(OpCodes.Call, module.ImportReference(addSerializer));
|
||||
}
|
||||
|
||||
foreach (var e in methodRPCs)
|
||||
{
|
||||
// NetworkReplicator.AddRPC(typeof(<type>), "<name>", <name>_Execute, <isServer>, <isClient>, <channel>);
|
||||
@@ -664,13 +681,14 @@ namespace Flax.Build.Plugins
|
||||
il.Emit(OpCodes.Ldc_I4, e.Channel);
|
||||
il.Emit(OpCodes.Call, module.ImportReference(addRPC));
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Nop);
|
||||
il.Emit(OpCodes.Ret);
|
||||
c.Methods.Add(m);
|
||||
}
|
||||
|
||||
// Serialize assembly back to the file
|
||||
assembly.Write(new WriterParameters { WriteSymbols = true } );
|
||||
assembly.Write(new WriterParameters { WriteSymbols = true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -696,7 +714,7 @@ namespace Flax.Build.Plugins
|
||||
TypeDefinition networkStream = networkStreamType.Resolve();
|
||||
ILProcessor il = m.Body.GetILProcessor();
|
||||
il.Emit(OpCodes.Nop);
|
||||
|
||||
|
||||
// Serialize base type
|
||||
if (type.BaseType != null && type.BaseType.FullName != "System.ValueType" && type.BaseType.FullName != "FlaxEngine.Object" && type.BaseType.CanBeResolved())
|
||||
{
|
||||
@@ -747,14 +765,14 @@ namespace Flax.Build.Plugins
|
||||
il.Emit(OpCodes.Call, module.ImportReference(fromUnmanagedPtr));
|
||||
il.Emit(OpCodes.Castclass, type);
|
||||
il.Emit(OpCodes.Stloc_0);
|
||||
|
||||
|
||||
// NetworkStream stream = (NetworkStream)FlaxEngine.Object.FromUnmanagedPtr(streamPtr)
|
||||
il.Body.Variables.Add(new VariableDefinition(networkStream));
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
il.Emit(OpCodes.Call, module.ImportReference(fromUnmanagedPtr));
|
||||
il.Emit(OpCodes.Castclass, module.ImportReference(networkStream));
|
||||
il.Emit(OpCodes.Stloc_1);
|
||||
|
||||
|
||||
// Generate normal serializer
|
||||
var serializer = GenerateSerializer(type, serialize, ref failed, name, voidType, networkStreamType);
|
||||
|
||||
@@ -810,17 +828,20 @@ namespace Flax.Build.Plugins
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (property.SetMethod == null)
|
||||
{
|
||||
MonoCecil.CompilationError($"Missing setter method for property '{property.Name}' of type {valueType.FullName} in {type.FullName} for automatic replication.", property);
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (property.GetMethod.IsVirtual)
|
||||
propertyGetOpCode = OpCodes.Callvirt;
|
||||
if (property.SetMethod.IsVirtual)
|
||||
propertySetOpCode = OpCodes.Callvirt;
|
||||
}
|
||||
|
||||
ModuleDefinition module = type.Module;
|
||||
TypeDefinition valueTypeDef = valueType.Resolve();
|
||||
if (_inBuildSerializers.TryGetValue(valueType.FullName, out var serializer))
|
||||
@@ -843,6 +864,7 @@ namespace Flax.Build.Plugins
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
m = networkStreamType.GetMethod(serializer.ReadMethod);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Callvirt, module.ImportReference(m));
|
||||
if (!serialize)
|
||||
{
|
||||
@@ -966,7 +988,7 @@ namespace Flax.Build.Plugins
|
||||
else
|
||||
il.Emit(propertyGetOpCode, property.GetMethod);
|
||||
|
||||
// int num2 = ((array2 != null) ? array2.Length : 0);
|
||||
// int num2 = ((array2 != null) ? array2.Length : 0);
|
||||
il.Emit(OpCodes.Dup);
|
||||
Instruction jmp1 = il.Create(OpCodes.Nop);
|
||||
il.Emit(OpCodes.Brtrue_S, jmp1);
|
||||
@@ -979,8 +1001,8 @@ namespace Flax.Build.Plugins
|
||||
il.Emit(OpCodes.Conv_I4);
|
||||
il.Append(jmp2);
|
||||
il.Emit(OpCodes.Stloc, varStart + 0);
|
||||
|
||||
// stream.WriteInt32(num2);
|
||||
|
||||
// stream.WriteInt32(num2);
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
il.Emit(OpCodes.Ldloc, varStart + 0);
|
||||
var m = networkStreamType.GetMethod("WriteInt32");
|
||||
@@ -1039,16 +1061,16 @@ namespace Flax.Build.Plugins
|
||||
var m = networkStreamType.GetMethod("ReadInt32");
|
||||
il.Emit(OpCodes.Callvirt, module.ImportReference(m));
|
||||
il.Emit(OpCodes.Stloc, varStart + 0);
|
||||
|
||||
// System.Array.Resize(ref Array1, num);
|
||||
|
||||
// System.Array.Resize(ref Array1, num);
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Ldflda, field);
|
||||
il.Emit(OpCodes.Ldloc, varStart + 0);
|
||||
module.TryGetTypeReference("System.Array", out var arrayType);
|
||||
m = arrayType.Resolve().GetMethod("Resize", 2);
|
||||
il.Emit(OpCodes.Call, module.ImportReference(m.InflateGeneric(elementType)));
|
||||
|
||||
// fixed (int* buffer = Array1)
|
||||
|
||||
// fixed (int* buffer = Array1)
|
||||
il.Emit(OpCodes.Nop);
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Ldfld, field);
|
||||
@@ -1067,8 +1089,8 @@ namespace Flax.Build.Plugins
|
||||
il.Emit(OpCodes.Stloc, varStart + 1);
|
||||
Instruction jmp3 = il.Create(OpCodes.Nop);
|
||||
il.Emit(OpCodes.Br_S, jmp3);
|
||||
|
||||
// stream.ReadBytes((byte*)buffer, num * sizeof(<elementType>));
|
||||
|
||||
// stream.ReadBytes((byte*)buffer, num * sizeof(<elementType>));
|
||||
il.Append(jmp2);
|
||||
il.Emit(OpCodes.Ldloc, varStart + 2);
|
||||
il.Emit(OpCodes.Ldc_I4_0);
|
||||
@@ -1127,7 +1149,7 @@ namespace Flax.Build.Plugins
|
||||
module.GetType("System.Guid", out var guidType);
|
||||
module.GetType("FlaxEngine.Object", out var scriptingObjectType);
|
||||
if (serialize)
|
||||
{
|
||||
{
|
||||
il.InsertBefore(ilStart, il.Create(OpCodes.Nop));
|
||||
il.InsertBefore(ilStart, il.Create(OpCodes.Ldloc, streamLocalIndex));
|
||||
il.InsertBefore(ilStart, il.Create(OpCodes.Ldarg, localIndex));
|
||||
@@ -1222,12 +1244,14 @@ namespace Flax.Build.Plugins
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (method.IsVirtual)
|
||||
{
|
||||
MonoCecil.CompilationError($"Not supported virtual RPC method '{method.FullName}'.", method);
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ModuleDefinition module = type.Module;
|
||||
var voidType = module.TypeSystem.Void;
|
||||
if (method.ReturnType != voidType)
|
||||
@@ -1236,12 +1260,14 @@ namespace Flax.Build.Plugins
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (method.IsStatic)
|
||||
{
|
||||
MonoCecil.CompilationError($"Not supported static RPC method '{method.FullName}'.", method);
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var methodRPC = new MethodRPC();
|
||||
methodRPC.Type = type;
|
||||
methodRPC.Method = method;
|
||||
@@ -1252,6 +1278,7 @@ namespace Flax.Build.Plugins
|
||||
methodRPC.IsClient = (bool)attribute.ConstructorArguments[1].Value;
|
||||
methodRPC.Channel = (int)attribute.ConstructorArguments[2].Value;
|
||||
}
|
||||
|
||||
methodRPC.IsServer = (bool)attribute.GetFieldValue("Server", methodRPC.IsServer);
|
||||
methodRPC.IsClient = (bool)attribute.GetFieldValue("Client", methodRPC.IsClient);
|
||||
methodRPC.Channel = (int)attribute.GetFieldValue("Channel", methodRPC.Channel);
|
||||
@@ -1261,12 +1288,14 @@ namespace Flax.Build.Plugins
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!methodRPC.IsServer && !methodRPC.IsClient)
|
||||
{
|
||||
MonoCecil.CompilationError($"Network RPC {method.Name} in {type.FullName} needs to have Server or Client specifier.", method);
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
module.GetType("System.IntPtr", out var intPtrType);
|
||||
module.GetType("FlaxEngine.Object", out var scriptingObjectType);
|
||||
var fromUnmanagedPtr = scriptingObjectType.Resolve().GetMethod("FromUnmanagedPtr");
|
||||
@@ -1294,7 +1323,7 @@ namespace Flax.Build.Plugins
|
||||
il.Emit(OpCodes.Call, module.ImportReference(fromUnmanagedPtr));
|
||||
il.Emit(OpCodes.Castclass, networkStream);
|
||||
il.Emit(OpCodes.Stloc_1);
|
||||
|
||||
|
||||
// Add locals for each RPC parameter
|
||||
var argsStart = il.Body.Variables.Count;
|
||||
for (int i = 0; i < method.Parameters.Count; i++)
|
||||
@@ -1306,6 +1335,7 @@ namespace Flax.Build.Plugins
|
||||
failed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var parameterType = parameter.ParameterType;
|
||||
il.Body.Variables.Add(new VariableDefinition(parameterType));
|
||||
}
|
||||
@@ -1324,8 +1354,9 @@ namespace Flax.Build.Plugins
|
||||
{
|
||||
il.Emit(OpCodes.Ldloc, argsStart + i);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Callvirt, method);
|
||||
|
||||
|
||||
il.Emit(OpCodes.Nop);
|
||||
il.Emit(OpCodes.Ret);
|
||||
type.Methods.Add(m);
|
||||
@@ -1418,7 +1449,6 @@ namespace Flax.Build.Plugins
|
||||
il.InsertBefore(ilStart, tmp);
|
||||
//il.InsertBefore(ilStart, il.Create(OpCodes.Ret));
|
||||
il.InsertBefore(ilStart, il.Create(OpCodes.Br, jumpBodyEnd));
|
||||
|
||||
}
|
||||
|
||||
// if (client && networkMode == NetworkManagerMode.Server) return;
|
||||
|
||||
Reference in New Issue
Block a user