/// <summary> /// Generates serialization methods for synclists /// </summary> /// <param name="td">The synclist class</param> public static void Process(TypeDefinition td) { var resolver = new GenericArgumentResolver(2); TypeReference syncDictionaryType = WeaverTypes.Import(typeof(SyncDictionary <,>)); TypeReference keyType = resolver.GetGenericFromBaseClass(td, 0, syncDictionaryType); if (keyType != null) { SyncObjectProcessor.GenerateSerialization(td, keyType, syncDictionaryType, "SerializeKey", "DeserializeKey"); } else { Weaver.Error($"Could not find generic arguments for SyncDictionary in {td.Name}", td); return; } TypeReference itemType = resolver.GetGenericFromBaseClass(td, 1, syncDictionaryType); if (itemType != null) { SyncObjectProcessor.GenerateSerialization(td, itemType, syncDictionaryType, "SerializeItem", "DeserializeItem"); } else { Weaver.Error($"Could not find generic arguments for SyncDictionary in {td.Name}", td); } }
public NetworkBehaviourProcessor(TypeDefinition td, Readers readers, Writers writers, PropertySiteProcessor propertySiteProcessor, IWeaverLogger logger) { Weaver.DLog(td, "NetworkBehaviourProcessor"); netBehaviourSubclass = td; this.logger = logger; serverRpcProcessor = new ServerRpcProcessor(netBehaviourSubclass.Module, readers, writers, logger); clientRpcProcessor = new ClientRpcProcessor(netBehaviourSubclass.Module, readers, writers, logger); syncVarProcessor = new SyncVarProcessor(netBehaviourSubclass.Module, readers, writers, propertySiteProcessor, logger); syncObjectProcessor = new SyncObjectProcessor(readers, writers, logger); }
/// <summary> /// Generates serialization methods for synclists /// </summary> /// <param name="td">The synclist class</param> /// <param name="mirrorBaseType">the base SyncObject td inherits from</param> public static void Process(TypeDefinition td, TypeReference mirrorBaseType) { GenericArgumentResolver resolver = new GenericArgumentResolver(1); if (resolver.GetGenericFromBaseClass(td, 0, mirrorBaseType, out TypeReference itemType)) { SyncObjectProcessor.GenerateSerialization(td, itemType, mirrorBaseType, "SerializeItem", "DeserializeItem"); } else { Weaver.Error($"Could not find generic arguments for {mirrorBaseType.Name} in {td}", td); } }
static void ProcessSyncVars(TypeDefinition td) { // find syncvars foreach (FieldDefinition fd in td.Fields) { if (fd.HasCustomAttribute <SyncVarAttribute>()) { Weaver.Error($"SyncVar {fd.Name} must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd); } if (SyncObjectProcessor.ImplementsSyncObject(fd.FieldType)) { Weaver.Error($"{fd.Name} is a SyncObject and must be inside a NetworkBehaviour. {td.Name} is not a NetworkBehaviour", fd); } } }
// return true if modified public bool Process() { // only process once if (WasProcessed(netBehaviourSubclass)) { return(false); } Weaver.DLog(netBehaviourSubclass, "Found NetworkBehaviour " + netBehaviourSubclass.FullName); if (netBehaviourSubclass.HasGenericParameters) { Weaver.Error($"{netBehaviourSubclass.Name} cannot have generic parameters", netBehaviourSubclass); // originally Process returned true in every case, except if already processed. // maybe return false here in the future. return(true); } Weaver.DLog(netBehaviourSubclass, "Process Start"); MarkAsProcessed(netBehaviourSubclass); // deconstruct tuple and set fields (syncVars, syncVarNetIds) = SyncVarProcessor.ProcessSyncVars(netBehaviourSubclass); syncObjects = SyncObjectProcessor.FindSyncObjectsFields(netBehaviourSubclass); ProcessMethods(); SyncEventProcessor.ProcessEvents(netBehaviourSubclass, eventRpcs, eventRpcInvocationFuncs); if (Weaver.WeavingFailed) { // originally Process returned true in every case, except if already processed. // maybe return false here in the future. return(true); } GenerateConstants(); GenerateSerialization(); if (Weaver.WeavingFailed) { // originally Process returned true in every case, except if already processed. // maybe return false here in the future. return(true); } GenerateDeSerialization(); Weaver.DLog(netBehaviourSubclass, "Process Done"); return(true); }
static void ProcessSyncVars(TypeDefinition td) { // find syncvars foreach (FieldDefinition fd in td.Fields) { foreach (CustomAttribute ca in fd.CustomAttributes) { if (ca.AttributeType.FullName == Weaver.SyncVarType.FullName) { Weaver.Error("Script " + td.FullName + " uses [SyncVar] " + fd.Name + " but is not a NetworkBehaviour."); } } if (SyncObjectProcessor.ImplementsSyncObject(fd.FieldType)) { Weaver.Error(string.Format("Script {0} defines field {1} with type {2}, but it's not a NetworkBehaviour", td.FullName, fd.Name, Helpers.PrettyPrintType(fd.FieldType))); } } }
// return true if modified public bool Process(ref bool WeavingFailed) { // only process once if (WasProcessed(netBehaviourSubclass)) { return(false); } MarkAsProcessed(netBehaviourSubclass); // deconstruct tuple and set fields (syncVars, syncVarNetIds) = syncVarAttributeProcessor.ProcessSyncVars(netBehaviourSubclass, ref WeavingFailed); syncObjects = SyncObjectProcessor.FindSyncObjectsFields(writers, readers, Log, netBehaviourSubclass, ref WeavingFailed); ProcessMethods(ref WeavingFailed); if (WeavingFailed) { // originally Process returned true in every case, except if already processed. // maybe return false here in the future. return(true); } // inject initializations into static & instance constructor InjectIntoStaticConstructor(ref WeavingFailed); InjectIntoInstanceConstructor(ref WeavingFailed); GenerateSerialization(ref WeavingFailed); if (WeavingFailed) { // originally Process returned true in every case, except if already processed. // maybe return false here in the future. return(true); } GenerateDeSerialization(ref WeavingFailed); return(true); }
/// <summary> /// Generates serialization methods for synclists /// </summary> /// <param name="td">The synclist class</param> public static void Process(TypeDefinition td) { GenericArgumentResolver resolver = new GenericArgumentResolver(2); if (resolver.GetGenericFromBaseClass(td, 0, WeaverTypes.SyncDictionaryType, out TypeReference keyType)) { SyncObjectProcessor.GenerateSerialization(td, keyType, WeaverTypes.SyncDictionaryType, "SerializeKey", "DeserializeKey"); } else { Weaver.Error($"Could not find generic arguments for SyncDictionary in {td.Name}", td); return; } if (resolver.GetGenericFromBaseClass(td, 1, WeaverTypes.SyncDictionaryType, out TypeReference itemType)) { SyncObjectProcessor.GenerateSerialization(td, itemType, WeaverTypes.SyncDictionaryType, "SerializeItem", "DeserializeItem"); } else { Weaver.Error($"Could not find generic arguments for SyncDictionary in {td.Name}", td); } }
public static void ProcessSyncVars(TypeDefinition td, List <FieldDefinition> syncVars, List <FieldDefinition> syncObjects, Dictionary <FieldDefinition, FieldDefinition> syncVarNetIds) { int numSyncVars = 0; // the mapping of dirtybits to sync-vars is implicit in the order of the fields here. this order is recorded in m_replacementProperties. // start assigning syncvars at the place the base class stopped, if any int dirtyBitCounter = Weaver.GetSyncVarStart(td.BaseType.FullName); syncVarNetIds.Clear(); // find syncvars foreach (FieldDefinition fd in td.Fields) { foreach (var ca in fd.CustomAttributes) { if (ca.AttributeType.FullName == Weaver.SyncVarType.FullName) { var resolvedField = fd.FieldType.Resolve(); if (resolvedField.IsDerivedFrom(Weaver.NetworkBehaviourType)) { Log.Error("SyncVar [" + fd.FullName + "] cannot be derived from NetworkBehaviour."); Weaver.fail = true; return; } if (resolvedField.IsDerivedFrom(Weaver.ScriptableObjectType)) { Log.Error("SyncVar [" + fd.FullName + "] cannot be derived from ScriptableObject."); Weaver.fail = true; return; } if ((fd.Attributes & FieldAttributes.Static) != 0) { Log.Error("SyncVar [" + fd.FullName + "] cannot be static."); Weaver.fail = true; return; } if (resolvedField.HasGenericParameters) { Log.Error("SyncVar [" + fd.FullName + "] cannot have generic parameters."); Weaver.fail = true; return; } if (resolvedField.IsInterface) { Log.Error("SyncVar [" + fd.FullName + "] cannot be an interface."); Weaver.fail = true; return; } var fieldModuleName = resolvedField.Module.Name; if (fieldModuleName != Weaver.scriptDef.MainModule.Name && fieldModuleName != Weaver.m_UnityAssemblyDefinition.MainModule.Name && fieldModuleName != Weaver.m_UNetAssemblyDefinition.MainModule.Name && fieldModuleName != Weaver.corLib.Name && fieldModuleName != "System.Runtime.dll" && // this is only for Metro, built-in types are not in corlib on metro fieldModuleName != "netstandard.dll" // handle built-in types when weaving new C#7 compiler assemblies ) { Log.Error("SyncVar [" + fd.FullName + "] from " + resolvedField.Module.ToString() + " cannot be a different module."); Weaver.fail = true; return; } if (fd.FieldType.IsArray) { Log.Error("SyncVar [" + fd.FullName + "] cannot be an array. Use a SyncList instead."); Weaver.fail = true; return; } if (SyncObjectProcessor.ImplementsSyncObject(fd.FieldType)) { Log.Warning(string.Format("Script class [{0}] has [SyncVar] attribute on SyncList field {1}, SyncLists should not be marked with SyncVar.", td.FullName, fd.Name)); break; } syncVars.Add(fd); ProcessSyncVar(td, fd, syncVarNetIds, 1L << dirtyBitCounter); dirtyBitCounter += 1; numSyncVars += 1; if (dirtyBitCounter == k_SyncVarLimit) { Log.Error("Script class [" + td.FullName + "] has too many SyncVars (" + k_SyncVarLimit + "). (This could include base classes)"); Weaver.fail = true; return; } break; } } if (fd.FieldType.FullName.Contains("Mirror.SyncListStruct")) { Log.Error("SyncListStruct member variable [" + fd.FullName + "] must use a dervied class, like \"class MySyncList : SyncListStruct<MyStruct> {}\"."); Weaver.fail = true; return; } if (fd.FieldType.Resolve().ImplementsInterface(Weaver.SyncObjectType)) { if (fd.IsStatic) { Log.Error("SyncList [" + td.FullName + ":" + fd.FullName + "] cannot be a static"); Weaver.fail = true; return; } syncObjects.Add(fd); } } // add all the new SyncVar __netId fields foreach (FieldDefinition fd in syncVarNetIds.Values) { td.Fields.Add(fd); } Weaver.SetNumSyncVars(td.FullName, numSyncVars); }
/// <summary> /// Generates serialization methods for synclists /// </summary> /// <param name="td">The synclist class</param> public static void Process(TypeDefinition td) { SyncObjectProcessor.GenerateSerialization(td, 0, "SerializeItem", "DeserializeItem"); }
//////////////////////////////////////////////////////////////////////// void GenerateConstants() { if (m_Cmds.Count == 0 && m_Rpcs.Count == 0 && m_TargetRpcs.Count == 0 && m_Events.Count == 0 && m_SyncObjects.Count == 0) { return; } Weaver.DLog(m_td, " GenerateConstants "); // find static constructor MethodDefinition cctor = null; bool cctorFound = false; foreach (MethodDefinition md in m_td.Methods) { if (md.Name == ".cctor") { cctor = md; cctorFound = true; } } if (cctor != null) { // remove the return opcode from end of function. will add our own later. if (cctor.Body.Instructions.Count != 0) { Instruction ret = cctor.Body.Instructions[cctor.Body.Instructions.Count - 1]; if (ret.OpCode == OpCodes.Ret) { cctor.Body.Instructions.RemoveAt(cctor.Body.Instructions.Count - 1); } else { Log.Error("No cctor for " + m_td.Name); Weaver.fail = true; return; } } } else { // make one! cctor = new MethodDefinition(".cctor", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | MethodAttributes.Static, Weaver.voidType); } // find instance constructor MethodDefinition ctor = null; foreach (MethodDefinition md in m_td.Methods) { if (md.Name == ".ctor") { ctor = md; var ret = ctor.Body.Instructions[ctor.Body.Instructions.Count - 1]; if (ret.OpCode == OpCodes.Ret) { ctor.Body.Instructions.RemoveAt(ctor.Body.Instructions.Count - 1); } else { Weaver.fail = true; Log.Error("No ctor for " + m_td.Name); return; } break; } } if (ctor == null) { Weaver.fail = true; Log.Error("No ctor for " + m_td.Name); return; } ILProcessor ctorWorker = ctor.Body.GetILProcessor(); ILProcessor cctorWorker = cctor.Body.GetILProcessor(); for (int i = 0; i < m_Cmds.Count; ++i) { GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerCommandDelegateReference, m_CmdInvocationFuncs[i], m_Cmds[i].Name); } for (int i = 0; i < m_Rpcs.Count; ++i) { GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerRpcDelegateReference, m_RpcInvocationFuncs[i], m_Rpcs[i].Name); } for (int i = 0; i < m_TargetRpcs.Count; ++i) { GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerRpcDelegateReference, m_TargetRpcInvocationFuncs[i], m_TargetRpcs[i].Name); } for (int i = 0; i < m_Events.Count; ++i) { GenerateRegisterCommandDelegate(cctorWorker, Weaver.registerEventDelegateReference, m_EventInvocationFuncs[i], m_Events[i].Name); } foreach (FieldDefinition fd in m_SyncObjects) { SyncListProcessor.GenerateSyncListInstanceInitializer(ctorWorker, fd); SyncObjectProcessor.GenerateSyncObjectInitializer(ctorWorker, fd); } cctorWorker.Append(cctorWorker.Create(OpCodes.Ret)); if (!cctorFound) { m_td.Methods.Add(cctor); } // finish ctor ctorWorker.Append(ctorWorker.Create(OpCodes.Ret)); // in case class had no cctor, it might have BeforeFieldInit, so injected cctor would be called too late m_td.Attributes = m_td.Attributes & ~TypeAttributes.BeforeFieldInit; }