using Mono.Cecil;
using Mono.Cecil.Cil;
using System;
using System.Collections.Generic;
using System.Linq;

namespace QNetWeaver
{
	internal class NetworkBehaviourProcessor
	{
		public NetworkBehaviourProcessor(TypeDefinition td)
		{
			Weaver.DLog(td, "NetworkBehaviourProcessor", new object[0]);
			m_td = td;
		}

		public void Process()
		{
			if (m_td.HasGenericParameters)
			{
				Weaver.fail = true;
				Log.Error("NetworkBehaviour " + m_td.Name + " cannot have generic parameters");
			}
			else
			{
				Weaver.DLog(m_td, "Process Start", new object[0]);
				ProcessVersion();
				ProcessSyncVars();
				Weaver.ResetRecursionCount();
				ProcessMethods();
				ProcessEvents();
				if (!Weaver.fail)
				{
					GenerateNetworkSettings();
					GenerateConstants();
					Weaver.ResetRecursionCount();
					GenerateSerialization();
					if (!Weaver.fail)
					{
						GenerateDeSerialization();
						GeneratePreStartClient();
						Weaver.DLog(m_td, "Process Done", new object[0]);
					}
				}
			}
		}

		private static void WriteClientActiveCheck(ILProcessor worker, string mdName, Instruction label, string errString)
		{
			worker.Append(worker.Create(OpCodes.Call, Weaver.NetworkClientGetActive));
			worker.Append(worker.Create(OpCodes.Brtrue, label));
			worker.Append(worker.Create(OpCodes.Ldstr, errString + " " + mdName + " called on server."));
			worker.Append(worker.Create(OpCodes.Call, Weaver.logErrorReference));
			worker.Append(worker.Create(OpCodes.Ret));
			worker.Append(label);
		}

		private static void WriteServerActiveCheck(ILProcessor worker, string mdName, Instruction label, string errString)
		{
			worker.Append(worker.Create(OpCodes.Call, Weaver.NetworkServerGetActive));
			worker.Append(worker.Create(OpCodes.Brtrue, label));
			worker.Append(worker.Create(OpCodes.Ldstr, errString + " " + mdName + " called on client."));
			worker.Append(worker.Create(OpCodes.Call, Weaver.logErrorReference));
			worker.Append(worker.Create(OpCodes.Ret));
			worker.Append(label);
		}

		private static void WriteSetupLocals(ILProcessor worker)
		{
			worker.Body.InitLocals = true;
			worker.Body.Variables.Add(new VariableDefinition(Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkWriterType)));
		}

		private static void WriteCreateWriter(ILProcessor worker)
		{
			worker.Append(worker.Create(OpCodes.Newobj, Weaver.NetworkWriterCtor));
			worker.Append(worker.Create(OpCodes.Stloc_0));
			worker.Append(worker.Create(OpCodes.Ldloc_0));
		}

		private static void WriteMessageSize(ILProcessor worker)
		{
			worker.Append(worker.Create(OpCodes.Ldc_I4_0));
			worker.Append(worker.Create(OpCodes.Callvirt, Weaver.NetworkWriterWriteInt16));
		}

		private static void WriteMessageId(ILProcessor worker, int msgId)
		{
			worker.Append(worker.Create(OpCodes.Ldloc_0));
			worker.Append(worker.Create(OpCodes.Ldc_I4, msgId));
			worker.Append(worker.Create(OpCodes.Conv_U2));
			worker.Append(worker.Create(OpCodes.Callvirt, Weaver.NetworkWriterWriteInt16));
		}

		private static bool WriteArguments(ILProcessor worker, MethodDefinition md, string errString, bool skipFirst)
		{
			short num = 1;
			foreach (var parameterDefinition in md.Parameters)
			{
				if (num == 1 && skipFirst)
				{
					num += 1;
				}
				else
				{
					var writeFunc = Weaver.GetWriteFunc(parameterDefinition.ParameterType);
					if (writeFunc == null)
					{
						Log.Error(string.Concat(new object[]
						{
							"WriteArguments for ",
							md.Name,
							" type ",
							parameterDefinition.ParameterType,
							" not supported"
						}));
						Weaver.fail = true;
						return false;
					}

					worker.Append(worker.Create(OpCodes.Ldloc_0));
					worker.Append(worker.Create(OpCodes.Ldarg, num));
					worker.Append(worker.Create(OpCodes.Call, writeFunc));
					num += 1;
				}
			}

			return true;
		}

		private void ProcessVersion()
		{
			foreach (var methodDefinition in m_td.Methods)
			{
				if (methodDefinition.Name == "UNetVersion")
				{
					return;
				}
			}

			var methodDefinition2 = new MethodDefinition("UNetVersion", MethodAttributes.Private, Weaver.voidType);
			var ilprocessor = methodDefinition2.Body.GetILProcessor();
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
			m_td.Methods.Add(methodDefinition2);
		}

		private void GenerateConstants()
		{
			if (m_Cmds.Count != 0 || m_Rpcs.Count != 0 || m_TargetRpcs.Count != 0 || m_Events.Count != 0 || m_SyncLists.Count != 0)
			{
				Weaver.DLog(m_td, "  GenerateConstants ", new object[0]);
				MethodDefinition cctorMethodDef = null;

				var flag = false;
				foreach (var methodDef in m_td.Methods)
				{
					if (methodDef.Name == ".cctor")
					{
						cctorMethodDef = methodDef;
						flag = true;
					}
				}

				if (cctorMethodDef != null)
				{
					if (cctorMethodDef.Body.Instructions.Count != 0)
					{
						var returnInstruction = cctorMethodDef.Body.Instructions[cctorMethodDef.Body.Instructions.Count - 1];
						if (!(returnInstruction.OpCode == OpCodes.Ret))
						{
							Log.Error("No .cctor for " + m_td.Name);
							Weaver.fail = true;
							return;
						}

						cctorMethodDef.Body.Instructions.RemoveAt(cctorMethodDef.Body.Instructions.Count - 1);
					}
				}
				else
				{
					Weaver.DLog(m_td, "  No. cctor found, making... ", new object[0]);
					cctorMethodDef = new MethodDefinition(".cctor", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, Weaver.voidType);
				}

				MethodDefinition ctorMethodDef = null;
				foreach (var methodDef in m_td.Methods)
				{
					if (methodDef.Name == ".ctor")
					{
						ctorMethodDef = methodDef;
						var returnInstruction = ctorMethodDef.Body.Instructions[ctorMethodDef.Body.Instructions.Count - 1];
						if (returnInstruction.OpCode == OpCodes.Ret)
						{
							Weaver.DLog(m_td, "  Found .ctor ", new object[0]);
							ctorMethodDef.Body.Instructions.RemoveAt(ctorMethodDef.Body.Instructions.Count - 1);
							break;
						}

						Weaver.fail = true;
						Log.Error("No .ctor for " + m_td.Name);
						return;
					}
				}

				if (ctorMethodDef == null)
				{
					Weaver.fail = true;
					Log.Error("No .ctor for " + m_td.Name);
				}
				else
				{
					var ilprocessor = ctorMethodDef.Body.GetILProcessor();
					var ilprocessor2 = cctorMethodDef.Body.GetILProcessor();

					var commandIndex = 0;
					foreach (var commandDef in m_Cmds)
					{
						Weaver.DLog(m_td, $"  Found command {commandDef.Name}", new object[0]);
						var field = Weaver.ResolveField(m_td, "kCmd" + commandDef.Name);
						Weaver.DLog(m_td, $"    got field", new object[0]);
						var hashCode = GetHashCode(m_td.Name + ":Cmd:" + commandDef.Name);
						Weaver.DLog(m_td, $"    got hashcode", new object[0]);
						ilprocessor2.Append(ilprocessor2.Create(OpCodes.Ldc_I4, hashCode));
						ilprocessor2.Append(ilprocessor2.Create(OpCodes.Stsfld, field));

						GenerateCommandDelegate(ilprocessor2, Weaver.registerCommandDelegateReference, m_CmdInvocationFuncs[commandIndex], field);
						commandIndex++;
					}

					var rpcIndex = 0;
					foreach (var rpcDef in m_Rpcs)
					{
						var field2 = Weaver.ResolveField(m_td, "kRpc" + rpcDef.Name);
						var hashCode2 = GetHashCode(m_td.Name + ":Rpc:" + rpcDef.Name);
						ilprocessor2.Append(ilprocessor2.Create(OpCodes.Ldc_I4, hashCode2));
						ilprocessor2.Append(ilprocessor2.Create(OpCodes.Stsfld, field2));
						GenerateCommandDelegate(ilprocessor2, Weaver.registerRpcDelegateReference, m_RpcInvocationFuncs[rpcIndex], field2);
						rpcIndex++;
					}

					var targetRpcIndex = 0;
					foreach (var targetRpcDef in m_TargetRpcs)
					{
						var field3 = Weaver.ResolveField(m_td, "kTargetRpc" + targetRpcDef.Name);
						var hashCode3 = GetHashCode(m_td.Name + ":TargetRpc:" + targetRpcDef.Name);
						ilprocessor2.Append(ilprocessor2.Create(OpCodes.Ldc_I4, hashCode3));
						ilprocessor2.Append(ilprocessor2.Create(OpCodes.Stsfld, field3));
						GenerateCommandDelegate(ilprocessor2, Weaver.registerRpcDelegateReference, m_TargetRpcInvocationFuncs[targetRpcIndex], field3);
						targetRpcIndex++;
					}

					var eventIndex = 0;
					foreach (var eventDef in m_Events)
					{
						var field4 = Weaver.ResolveField(m_td, "kEvent" + eventDef.Name);
						var hashCode4 = GetHashCode(m_td.Name + ":Event:" + eventDef.Name);
						ilprocessor2.Append(ilprocessor2.Create(OpCodes.Ldc_I4, hashCode4));
						ilprocessor2.Append(ilprocessor2.Create(OpCodes.Stsfld, field4));
						GenerateCommandDelegate(ilprocessor2, Weaver.registerEventDelegateReference, m_EventInvocationFuncs[eventIndex], field4);
						eventIndex++;
					}

					var syncListIndex = 0;
					foreach (var syncListDef in m_SyncLists)
					{
						var field5 = Weaver.ResolveField(m_td, "kList" + syncListDef.Name);
						var hashCode5 = GetHashCode(m_td.Name + ":List:" + syncListDef.Name);
						ilprocessor2.Append(ilprocessor2.Create(OpCodes.Ldc_I4, hashCode5));
						ilprocessor2.Append(ilprocessor2.Create(OpCodes.Stsfld, field5));
						GenerateSyncListInstanceInitializer(ilprocessor, syncListDef);
						GenerateCommandDelegate(ilprocessor2, Weaver.registerSyncListDelegateReference, m_SyncListInvocationFuncs[syncListIndex], field5);
						syncListIndex++;
					}

					ilprocessor2.Append(ilprocessor2.Create(OpCodes.Ldstr, m_td.Name));
					ilprocessor2.Append(ilprocessor2.Create(OpCodes.Ldc_I4, m_QosChannel));
					ilprocessor2.Append(ilprocessor2.Create(OpCodes.Call, Weaver.RegisterBehaviourReference));
					ilprocessor2.Append(ilprocessor2.Create(OpCodes.Ret));
					if (!flag)
					{
						m_td.Methods.Add(cctorMethodDef);
					}

					ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
					m_td.Attributes = (m_td.Attributes & ~TypeAttributes.BeforeFieldInit);
					if (m_SyncLists.Count != 0)
					{
						MethodDefinition methodDefinition8 = null;
						var flag2 = false;
						foreach (var methodDefinition9 in m_td.Methods)
						{
							if (methodDefinition9.Name == "Awake")
							{
								methodDefinition8 = methodDefinition9;
								flag2 = true;
							}
						}

						if (methodDefinition8 != null)
						{
							if (methodDefinition8.Body.Instructions.Count != 0)
							{
								var instruction3 = methodDefinition8.Body.Instructions[methodDefinition8.Body.Instructions.Count - 1];
								if (!(instruction3.OpCode == OpCodes.Ret))
								{
									Log.Error("No awake for " + m_td.Name);
									Weaver.fail = true;
									return;
								}

								methodDefinition8.Body.Instructions.RemoveAt(methodDefinition8.Body.Instructions.Count - 1);
							}
						}
						else
						{
							methodDefinition8 = new MethodDefinition("Awake", MethodAttributes.Private, Weaver.voidType);
						}

						var ilprocessor3 = methodDefinition8.Body.GetILProcessor();
						if (!flag2)
						{
							CheckForCustomBaseClassAwakeMethod(ilprocessor3);
						}

						var num6 = 0;
						foreach (var fd in m_SyncLists)
						{
							GenerateSyncListInitializer(ilprocessor3, fd, num6);
							num6++;
						}

						ilprocessor3.Append(ilprocessor3.Create(OpCodes.Ret));
						if (!flag2)
						{
							m_td.Methods.Add(methodDefinition8);
						}
					}
				}
			}
		}

		private void CheckForCustomBaseClassAwakeMethod(ILProcessor awakeWorker)
		{
			var baseType = m_td.BaseType;
			while (baseType.FullName != Weaver.NetworkBehaviourType.FullName)
			{
				var methodDefinition = Enumerable.FirstOrDefault<MethodDefinition>(baseType.Resolve().Methods, (MethodDefinition x) => x.Name == "Awake" && !x.HasParameters);
				if (methodDefinition != null)
				{
					awakeWorker.Append(awakeWorker.Create(OpCodes.Ldarg_0));
					awakeWorker.Append(awakeWorker.Create(OpCodes.Call, methodDefinition));
					break;
				}

				baseType = baseType.Resolve().BaseType;
			}
		}

		private void GenerateSyncListInstanceInitializer(ILProcessor ctorWorker, FieldDefinition fd)
		{
			foreach (var instruction in ctorWorker.Body.Instructions)
			{
				if (instruction.OpCode.Code == Code.Stfld)
				{
					var fieldDefinition = (FieldDefinition)instruction.Operand;
					if (fieldDefinition.DeclaringType == fd.DeclaringType && fieldDefinition.Name == fd.Name)
					{
						return;
					}
				}
			}

			var method = Weaver.scriptDef.MainModule.ImportReference(Enumerable.First<MethodDefinition>(fd.FieldType.Resolve().Methods, (MethodDefinition x) => x.Name == ".ctor" && !x.HasParameters));
			ctorWorker.Append(ctorWorker.Create(OpCodes.Ldarg_0));
			ctorWorker.Append(ctorWorker.Create(OpCodes.Newobj, method));
			ctorWorker.Append(ctorWorker.Create(OpCodes.Stfld, fd));
		}

		private void GenerateCommandDelegate(ILProcessor awakeWorker, MethodReference registerMethod, MethodDefinition func, FieldReference field)
		{
			Weaver.DLog(m_td, "  GenerateCommandDelegate ", new object[0]);
			awakeWorker.Append(awakeWorker.Create(OpCodes.Ldtoken, m_td));
			awakeWorker.Append(awakeWorker.Create(OpCodes.Call, Weaver.getTypeFromHandleReference));
			awakeWorker.Append(awakeWorker.Create(OpCodes.Ldsfld, field));
			awakeWorker.Append(awakeWorker.Create(OpCodes.Ldnull));
			awakeWorker.Append(awakeWorker.Create(OpCodes.Ldftn, func));
			awakeWorker.Append(awakeWorker.Create(OpCodes.Newobj, Weaver.CmdDelegateConstructor));
			awakeWorker.Append(awakeWorker.Create(OpCodes.Call, registerMethod));
		}

		private void GenerateSyncListInitializer(ILProcessor awakeWorker, FieldReference fd, int index)
		{
			awakeWorker.Append(awakeWorker.Create(OpCodes.Ldarg_0));
			awakeWorker.Append(awakeWorker.Create(OpCodes.Ldfld, fd));
			awakeWorker.Append(awakeWorker.Create(OpCodes.Ldarg_0));
			awakeWorker.Append(awakeWorker.Create(OpCodes.Ldsfld, m_SyncListStaticFields[index]));
			var genericInstanceType = (GenericInstanceType)fd.FieldType.Resolve().BaseType;
			genericInstanceType = (GenericInstanceType)Weaver.scriptDef.MainModule.ImportReference(genericInstanceType);
			var typeReference = genericInstanceType.GenericArguments[0];
			var method = Helpers.MakeHostInstanceGeneric(Weaver.SyncListInitBehaviourReference, new TypeReference[]
			{
				typeReference
			});
			awakeWorker.Append(awakeWorker.Create(OpCodes.Callvirt, method));
			Weaver.scriptDef.MainModule.ImportReference(method);
		}

		private void GenerateSerialization()
		{
			Weaver.DLog(m_td, "  NetworkBehaviour GenerateSerialization", new object[0]);
			foreach (var methodDefinition in m_td.Methods)
			{
				if (methodDefinition.Name == "OnSerialize")
				{
					Weaver.DLog(m_td, "    Abort - is OnSerialize", new object[0]);
					return;
				}
			}

			var methodDefinition2 = new MethodDefinition("OnSerialize", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, Weaver.boolType);
			methodDefinition2.Parameters.Add(new ParameterDefinition("writer", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkWriterType)));
			methodDefinition2.Parameters.Add(new ParameterDefinition("forceAll", ParameterAttributes.None, Weaver.boolType));
			var ilprocessor = methodDefinition2.Body.GetILProcessor();
			methodDefinition2.Body.InitLocals = true;
			var item = new VariableDefinition(Weaver.boolType);
			methodDefinition2.Body.Variables.Add(item);
			var flag = false;

			if (m_td.BaseType.FullName != Weaver.NetworkBehaviourType.FullName)
			{
				var methodReference = Weaver.ResolveMethod(m_td.BaseType, "OnSerialize");
				if (methodReference != null)
				{
					var item2 = new VariableDefinition(Weaver.boolType);
					methodDefinition2.Body.Variables.Add(item2);
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_2));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Call, methodReference));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Stloc_1));
					flag = true;
				}
			}

			if (m_SyncVars.Count == 0)
			{
				Weaver.DLog(m_td, "    No syncvars", new object[0]);
				if (flag)
				{
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_1));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Or));
				}
				else
				{
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
				}

				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				m_td.Methods.Add(methodDefinition2);
			}
			else
			{
				Weaver.DLog(m_td, "    Syncvars exist", new object[0]);
				var instruction = ilprocessor.Create(OpCodes.Nop);
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_2));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Brfalse, instruction));
				foreach (var fieldDefinition in m_SyncVars)
				{
					Weaver.DLog(m_td, $"    For {fieldDefinition.Name}", new object[0]);
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldfld, fieldDefinition));
					var writeFunc = Weaver.GetWriteFunc(fieldDefinition.FieldType);
					if (writeFunc == null)
					{
						Weaver.fail = true;
						Log.Error(string.Concat(new object[]
						{
							"GenerateSerialization for ",
							m_td.Name,
							" unknown type [",
							fieldDefinition.FieldType,
							"]. UNet [SyncVar] member variables must be basic types."
						}));
						return;
					}

					ilprocessor.Append(ilprocessor.Create(OpCodes.Call, writeFunc));
				}

				Weaver.DLog(m_td, $"    Finish foreach 1", new object[0]);
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4_1));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				ilprocessor.Append(instruction);
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Stloc_0));
				var num = Weaver.GetSyncVarStart(m_td.BaseType.FullName);
				foreach (var fieldDefinition2 in m_SyncVars)
				{
					Weaver.DLog(m_td, $"    For {fieldDefinition2.Name}", new object[0]);
					var instruction2 = ilprocessor.Create(OpCodes.Nop);
					Weaver.DLog(m_td, $"    Got instruction2", new object[0]);
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
					Weaver.DLog(m_td, $"    call dirtbits reference", new object[0]);
					ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference));
					Weaver.DLog(m_td, $"    finish call dirtbits reference", new object[0]);
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4, 1 << num));
					ilprocessor.Append(ilprocessor.Create(OpCodes.And));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Brfalse, instruction2));
					Weaver.DLog(m_td, $"    writing dirtycheck", new object[0]);
					WriteDirtyCheck(ilprocessor, true);
					Weaver.DLog(m_td, $"    done writing dirtycheck", new object[0]);
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldfld, fieldDefinition2));
					Weaver.DLog(m_td, $"    Getting writeFunc2", new object[0]);
					var writeFunc2 = Weaver.GetWriteFunc(fieldDefinition2.FieldType);
					Weaver.DLog(m_td, $"    Got writeFunc2", new object[0]);
					if (writeFunc2 == null)
					{
						Log.Error(string.Concat(new object[]
						{
							"GenerateSerialization for ",
							m_td.Name,
							" unknown type [",
							fieldDefinition2.FieldType,
							"]. UNet [SyncVar] member variables must be basic types."
						}));
						Weaver.fail = true;
						return;
					}

					ilprocessor.Append(ilprocessor.Create(OpCodes.Call, writeFunc2));
					ilprocessor.Append(instruction2);
					num++;
				}

				Weaver.DLog(m_td, $"    Finish foreach 2", new object[0]);
				WriteDirtyCheck(ilprocessor, false);
				if (Weaver.generateLogErrors)
				{
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldstr, "Injected Serialize " + m_td.Name));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.logErrorReference));
				}

				if (flag)
				{
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_1));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Or));
				}
				else
				{
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
				}

				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				m_td.Methods.Add(methodDefinition2);
				Weaver.DLog(m_td, $"    Finish", new object[0]);
			}

			Weaver.DLog(m_td, $"  Finish", new object[0]);
		}

		private static void WriteDirtyCheck(ILProcessor serWorker, bool reset)
		{
			var instruction = serWorker.Create(OpCodes.Nop);
			serWorker.Append(serWorker.Create(OpCodes.Ldloc_0));
			serWorker.Append(serWorker.Create(OpCodes.Brtrue, instruction));
			serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
			serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
			serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.NetworkBehaviourDirtyBitsReference));
			serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkWriterWritePacked32));
			if (reset)
			{
				serWorker.Append(serWorker.Create(OpCodes.Ldc_I4_1));
				serWorker.Append(serWorker.Create(OpCodes.Stloc_0));
			}

			serWorker.Append(instruction);
		}

		private static int GetChannelId(FieldDefinition field)
		{
			var result = 0;
			foreach (var customAttribute in field.CustomAttributes)
			{
				if (customAttribute.AttributeType.FullName == Weaver.SyncVarType.FullName)
				{
					foreach (var customAttributeNamedArgument in customAttribute.Fields)
					{
						if (customAttributeNamedArgument.Name == "channel")
						{
							result = (int)customAttributeNamedArgument.Argument.Value;
							break;
						}
					}
				}
			}

			return result;
		}

		private bool CheckForHookFunction(FieldDefinition syncVar, out MethodDefinition foundMethod)
		{
			foundMethod = null;
			foreach (var customAttribute in syncVar.CustomAttributes)
			{
				if (customAttribute.AttributeType.FullName == Weaver.SyncVarType.FullName)
				{
					foreach (var customAttributeNamedArgument in customAttribute.Fields)
					{
						if (customAttributeNamedArgument.Name == "hook")
						{
							var text = customAttributeNamedArgument.Argument.Value as string;
							foreach (var methodDefinition in m_td.Methods)
							{
								if (methodDefinition.Name == text)
								{
									if (methodDefinition.Parameters.Count != 1)
									{
										Log.Error("SyncVar Hook function " + text + " must have one argument " + m_td.Name);
										Weaver.fail = true;
										return false;
									}

									if (methodDefinition.Parameters[0].ParameterType != syncVar.FieldType)
									{
										Log.Error("SyncVar Hook function " + text + " has wrong type signature for " + m_td.Name);
										Weaver.fail = true;
										return false;
									}

									foundMethod = methodDefinition;
									return true;
								}
							}

							Log.Error("SyncVar Hook function " + text + " not found for " + m_td.Name);
							Weaver.fail = true;
							return false;
						}
					}
				}
			}

			return true;
		}

		private void GenerateNetworkChannelSetting(int channel)
		{
			var methodDefinition = new MethodDefinition("GetNetworkChannel", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, Weaver.int32Type);
			var ilprocessor = methodDefinition.Body.GetILProcessor();
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4, channel));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
			m_td.Methods.Add(methodDefinition);
		}

		private void GenerateNetworkIntervalSetting(float interval)
		{
			var methodDefinition = new MethodDefinition("GetNetworkSendInterval", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, Weaver.singleType);
			var ilprocessor = methodDefinition.Body.GetILProcessor();
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_R4, interval));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
			m_td.Methods.Add(methodDefinition);
		}

		private void GenerateNetworkSettings()
		{
			foreach (var customAttribute in m_td.CustomAttributes)
			{
				if (customAttribute.AttributeType.FullName == Weaver.NetworkSettingsType.FullName)
				{
					foreach (var customAttributeNamedArgument in customAttribute.Fields)
					{
						if (customAttributeNamedArgument.Name == "channel")
						{
							if ((int)customAttributeNamedArgument.Argument.Value == 0)
							{
								continue;
							}

							if (HasMethod("GetNetworkChannel"))
							{
								Log.Error("GetNetworkChannel, is already implemented, please make sure you either use NetworkSettings or GetNetworkChannel");
								Weaver.fail = true;
								return;
							}

							m_QosChannel = (int)customAttributeNamedArgument.Argument.Value;
							GenerateNetworkChannelSetting(m_QosChannel);
						}

						if (customAttributeNamedArgument.Name == "sendInterval")
						{
							if (Math.Abs((float)customAttributeNamedArgument.Argument.Value - 0.1f) > 1E-05f)
							{
								if (HasMethod("GetNetworkSendInterval"))
								{
									Log.Error("GetNetworkSendInterval, is already implemented, please make sure you either use NetworkSettings or GetNetworkSendInterval");
									Weaver.fail = true;
									return;
								}

								GenerateNetworkIntervalSetting((float)customAttributeNamedArgument.Argument.Value);
							}
						}
					}
				}
			}
		}

		private void GeneratePreStartClient()
		{
			m_NetIdFieldCounter = 0;
			MethodDefinition methodDefinition = null;
			ILProcessor ilprocessor = null;
			foreach (var methodDefinition2 in m_td.Methods)
			{
				if (methodDefinition2.Name == "PreStartClient")
				{
					return;
				}
			}

			foreach (var fieldDefinition in m_SyncVars)
			{
				if (fieldDefinition.FieldType.FullName == Weaver.gameObjectType.FullName)
				{
					if (methodDefinition == null)
					{
						methodDefinition = new MethodDefinition("PreStartClient", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, Weaver.voidType);
						ilprocessor = methodDefinition.Body.GetILProcessor();
					}

					var field = m_SyncVarNetIds[m_NetIdFieldCounter];
					m_NetIdFieldCounter++;
					var instruction = ilprocessor.Create(OpCodes.Nop);
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldflda, field));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.NetworkInstanceIsEmpty));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Brtrue, instruction));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldfld, field));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.FindLocalObjectReference));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Stfld, fieldDefinition));
					ilprocessor.Append(instruction);
				}
			}

			if (methodDefinition != null)
			{
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				m_td.Methods.Add(methodDefinition);
			}
		}

		private void GenerateDeSerialization()
		{
			Weaver.DLog(m_td, "  GenerateDeSerialization", new object[0]);
			m_NetIdFieldCounter = 0;
			foreach (var methodDefinition in m_td.Methods)
			{
				if (methodDefinition.Name == "OnDeserialize")
				{
					return;
				}
			}

			var methodDefinition2 = new MethodDefinition("OnDeserialize", MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, Weaver.voidType);
			methodDefinition2.Parameters.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkReaderType)));
			methodDefinition2.Parameters.Add(new ParameterDefinition("initialState", ParameterAttributes.None, Weaver.boolType));
			var ilprocessor = methodDefinition2.Body.GetILProcessor();
			if (m_td.BaseType.FullName != Weaver.NetworkBehaviourType.FullName)
			{
				var methodReference = Weaver.ResolveMethod(m_td.BaseType, "OnDeserialize");
				if (methodReference != null)
				{
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_2));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Call, methodReference));
				}
			}

			if (m_SyncVars.Count == 0)
			{
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				m_td.Methods.Add(methodDefinition2);
			}
			else
			{
				var instruction = ilprocessor.Create(OpCodes.Nop);
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_2));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Brfalse, instruction));
				foreach (var fieldDefinition in m_SyncVars)
				{
					var readByReferenceFunc = Weaver.GetReadByReferenceFunc(fieldDefinition.FieldType);
					if (readByReferenceFunc != null)
					{
						ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
						ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
						ilprocessor.Append(ilprocessor.Create(OpCodes.Ldfld, fieldDefinition));
						ilprocessor.Append(ilprocessor.Create(OpCodes.Call, readByReferenceFunc));
					}
					else
					{
						ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
						ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
						if (fieldDefinition.FieldType.FullName == Weaver.gameObjectType.FullName)
						{
							var field = m_SyncVarNetIds[m_NetIdFieldCounter];
							m_NetIdFieldCounter++;
							ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.NetworkReaderReadNetworkInstanceId));
							ilprocessor.Append(ilprocessor.Create(OpCodes.Stfld, field));
						}
						else
						{
							var readFunc = Weaver.GetReadFunc(fieldDefinition.FieldType);
							if (readFunc == null)
							{
								Log.Error(string.Concat(new object[]
								{
									"GenerateDeSerialization for ",
									m_td.Name,
									" unknown type [",
									fieldDefinition.FieldType,
									"]. UNet [SyncVar] member variables must be basic types."
								}));
								Weaver.fail = true;
								return;
							}

							ilprocessor.Append(ilprocessor.Create(OpCodes.Call, readFunc));
							ilprocessor.Append(ilprocessor.Create(OpCodes.Stfld, fieldDefinition));
						}
					}
				}

				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				ilprocessor.Append(instruction);
				methodDefinition2.Body.InitLocals = true;
				var item = new VariableDefinition(Weaver.int32Type);
				methodDefinition2.Body.Variables.Add(item);
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.NetworkReaderReadPacked32));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Stloc_0));
				var num = Weaver.GetSyncVarStart(m_td.BaseType.FullName);
				foreach (var fieldDefinition2 in m_SyncVars)
				{
					var instruction2 = ilprocessor.Create(OpCodes.Nop);
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4, 1 << num));
					ilprocessor.Append(ilprocessor.Create(OpCodes.And));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Brfalse, instruction2));
					var readByReferenceFunc2 = Weaver.GetReadByReferenceFunc(fieldDefinition2.FieldType);
					if (readByReferenceFunc2 != null)
					{
						ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
						ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
						ilprocessor.Append(ilprocessor.Create(OpCodes.Ldfld, fieldDefinition2));
						ilprocessor.Append(ilprocessor.Create(OpCodes.Call, readByReferenceFunc2));
					}
					else
					{
						var readFunc2 = Weaver.GetReadFunc(fieldDefinition2.FieldType);
						if (readFunc2 == null)
						{
							Log.Error(string.Concat(new object[]
							{
								"GenerateDeSerialization for ",
								m_td.Name,
								" unknown type [",
								fieldDefinition2.FieldType,
								"]. UNet [SyncVar] member variables must be basic types."
							}));
							Weaver.fail = true;
							return;
						}

						if (!CheckForHookFunction(fieldDefinition2, out var methodDefinition3))
						{
							return;
						}

						if (methodDefinition3 == null)
						{
							ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
							ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
							ilprocessor.Append(ilprocessor.Create(OpCodes.Call, readFunc2));
							ilprocessor.Append(ilprocessor.Create(OpCodes.Stfld, fieldDefinition2));
						}
						else
						{
							ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
							ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
							ilprocessor.Append(ilprocessor.Create(OpCodes.Call, readFunc2));
							ilprocessor.Append(ilprocessor.Create(OpCodes.Call, methodDefinition3));
						}
					}

					ilprocessor.Append(instruction2);
					num++;
				}

				if (Weaver.generateLogErrors)
				{
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ldstr, "Injected Deserialize " + m_td.Name));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.logErrorReference));
				}

				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				m_td.Methods.Add(methodDefinition2);
			}
		}

		private bool ProcessNetworkReaderParameters(MethodDefinition md, ILProcessor worker, bool skipFirst)
		{
			var num = 0;
			foreach (var parameterDefinition in md.Parameters)
			{
				if (num++ != 0 || !skipFirst)
				{
					var readFunc = Weaver.GetReadFunc(parameterDefinition.ParameterType);
					if (readFunc == null)
					{
						Log.Error(string.Concat(new object[]
						{
							"ProcessNetworkReaderParameters for ",
							m_td.Name,
							":",
							md.Name,
							" type ",
							parameterDefinition.ParameterType,
							" not supported"
						}));
						Weaver.fail = true;
						return false;
					}

					worker.Append(worker.Create(OpCodes.Ldarg_1));
					worker.Append(worker.Create(OpCodes.Call, readFunc));
					if (parameterDefinition.ParameterType.FullName == Weaver.singleType.FullName)
					{
						worker.Append(worker.Create(OpCodes.Conv_R4));
					}
					else if (parameterDefinition.ParameterType.FullName == Weaver.doubleType.FullName)
					{
						worker.Append(worker.Create(OpCodes.Conv_R8));
					}
				}
			}

			return true;
		}

		private MethodDefinition ProcessCommandInvoke(MethodDefinition md)
		{
			var methodDefinition = new MethodDefinition("InvokeCmd" + md.Name, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, Weaver.voidType);
			var ilprocessor = methodDefinition.Body.GetILProcessor();
			var label = ilprocessor.Create(OpCodes.Nop);
			WriteServerActiveCheck(ilprocessor, md.Name, label, "Command");
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Castclass, m_td));
			MethodDefinition result;
			if (!ProcessNetworkReaderParameters(md, ilprocessor, false))
			{
				result = null;
			}
			else
			{
				ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, md));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				AddInvokeParameters(methodDefinition.Parameters);
				result = methodDefinition;
			}

			return result;
		}

		private static void AddInvokeParameters(ICollection<ParameterDefinition> collection)
		{
			collection.Add(new ParameterDefinition("obj", ParameterAttributes.None, Weaver.NetworkBehaviourType2));
			collection.Add(new ParameterDefinition("reader", ParameterAttributes.None, Weaver.scriptDef.MainModule.ImportReference(Weaver.NetworkReaderType)));
		}

		private MethodDefinition ProcessCommandCall(MethodDefinition md, CustomAttribute ca)
		{
			var methodDefinition = new MethodDefinition("Call" + md.Name, MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.HideBySig, Weaver.voidType);
			foreach (var parameterDefinition in md.Parameters)
			{
				methodDefinition.Parameters.Add(new ParameterDefinition(parameterDefinition.Name, ParameterAttributes.None, parameterDefinition.ParameterType));
			}

			var ilprocessor = methodDefinition.Body.GetILProcessor();
			var label = ilprocessor.Create(OpCodes.Nop);
			WriteSetupLocals(ilprocessor);
			if (Weaver.generateLogErrors)
			{
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldstr, "Call Command function " + md.Name));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.logErrorReference));
			}

			WriteClientActiveCheck(ilprocessor, md.Name, label, "Command function");
			var instruction = ilprocessor.Create(OpCodes.Nop);
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.UBehaviourIsServer));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Brfalse, instruction));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			for (var i = 0; i < md.Parameters.Count; i++)
			{
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg, i + 1));
			}

			ilprocessor.Append(ilprocessor.Create(OpCodes.Call, md));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
			ilprocessor.Append(instruction);
			WriteCreateWriter(ilprocessor);
			WriteMessageSize(ilprocessor);
			WriteMessageId(ilprocessor, 5);
			var fieldDefinition = new FieldDefinition("kCmd" + md.Name, FieldAttributes.Private | FieldAttributes.Static, Weaver.int32Type);
			m_td.Fields.Add(fieldDefinition);
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldsfld, fieldDefinition));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.NetworkWriterWritePacked32));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.getComponentReference));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.getUNetIdReference));
			var writeFunc = Weaver.GetWriteFunc(Weaver.NetworkInstanceIdType);
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, writeFunc));
			MethodDefinition result;
			if (!WriteArguments(ilprocessor, md, "Command", false))
			{
				result = null;
			}
			else
			{
				var value = 0;
				foreach (var customAttributeNamedArgument in ca.Fields)
				{
					if (customAttributeNamedArgument.Name == "channel")
					{
						value = (int)customAttributeNamedArgument.Argument.Value;
					}
				}

				var text = md.Name;
				var num = text.IndexOf("InvokeCmd");
				if (num > -1)
				{
					text = text.Substring("InvokeCmd".Length);
				}

				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4, value));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldstr, text));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.sendCommandInternal));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				result = methodDefinition;
			}

			return result;
		}

		private MethodDefinition ProcessTargetRpcInvoke(MethodDefinition md)
		{
			var methodDefinition = new MethodDefinition("InvokeRpc" + md.Name, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, Weaver.voidType);
			var ilprocessor = methodDefinition.Body.GetILProcessor();
			var label = ilprocessor.Create(OpCodes.Nop);
			WriteClientActiveCheck(ilprocessor, md.Name, label, "TargetRPC");
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Castclass, m_td));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.ReadyConnectionReference));
			MethodDefinition result;
			if (!ProcessNetworkReaderParameters(md, ilprocessor, true))
			{
				result = null;
			}
			else
			{
				ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, md));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				AddInvokeParameters(methodDefinition.Parameters);
				result = methodDefinition;
			}

			return result;
		}

		private MethodDefinition ProcessRpcInvoke(MethodDefinition md)
		{
			var methodDefinition = new MethodDefinition("InvokeRpc" + md.Name, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, Weaver.voidType);
			var ilprocessor = methodDefinition.Body.GetILProcessor();
			var label = ilprocessor.Create(OpCodes.Nop);
			WriteClientActiveCheck(ilprocessor, md.Name, label, "RPC");
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Castclass, m_td));
			MethodDefinition result;
			if (!ProcessNetworkReaderParameters(md, ilprocessor, false))
			{
				result = null;
			}
			else
			{
				ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, md));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				AddInvokeParameters(methodDefinition.Parameters);
				result = methodDefinition;
			}

			return result;
		}

		private MethodDefinition ProcessTargetRpcCall(MethodDefinition md, CustomAttribute ca)
		{
			var methodDefinition = new MethodDefinition("Call" + md.Name, MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.HideBySig, Weaver.voidType);
			foreach (var parameterDefinition in md.Parameters)
			{
				methodDefinition.Parameters.Add(new ParameterDefinition(parameterDefinition.Name, ParameterAttributes.None, parameterDefinition.ParameterType));
			}

			var ilprocessor = methodDefinition.Body.GetILProcessor();
			var label = ilprocessor.Create(OpCodes.Nop);
			WriteSetupLocals(ilprocessor);
			WriteServerActiveCheck(ilprocessor, md.Name, label, "TargetRPC Function");
			var instruction = ilprocessor.Create(OpCodes.Nop);
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Isinst, Weaver.ULocalConnectionToServerType));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Brfalse, instruction));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldstr, string.Format("TargetRPC Function {0} called on connection to server", md.Name)));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.logErrorReference));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
			ilprocessor.Append(instruction);
			WriteCreateWriter(ilprocessor);
			WriteMessageSize(ilprocessor);
			WriteMessageId(ilprocessor, 2);
			var fieldDefinition = new FieldDefinition("kTargetRpc" + md.Name, FieldAttributes.Private | FieldAttributes.Static, Weaver.int32Type);
			m_td.Fields.Add(fieldDefinition);
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldsfld, fieldDefinition));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.NetworkWriterWritePacked32));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.getComponentReference));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.getUNetIdReference));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.NetworkWriterWriteNetworkInstanceId));
			MethodDefinition result;
			if (!WriteArguments(ilprocessor, md, "TargetRPC", true))
			{
				result = null;
			}
			else
			{
				var value = 0;
				foreach (var customAttributeNamedArgument in ca.Fields)
				{
					if (customAttributeNamedArgument.Name == "channel")
					{
						value = (int)customAttributeNamedArgument.Argument.Value;
					}
				}

				var text = md.Name;
				var num = text.IndexOf("InvokeTargetRpc");
				if (num > -1)
				{
					text = text.Substring("InvokeTargetRpc".Length);
				}

				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4, value));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldstr, text));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.sendTargetRpcInternal));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				result = methodDefinition;
			}

			return result;
		}

		private MethodDefinition ProcessRpcCall(MethodDefinition md, CustomAttribute ca)
		{
			var methodDefinition = new MethodDefinition("Call" + md.Name, MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.HideBySig, Weaver.voidType);
			foreach (var parameterDefinition in md.Parameters)
			{
				methodDefinition.Parameters.Add(new ParameterDefinition(parameterDefinition.Name, ParameterAttributes.None, parameterDefinition.ParameterType));
			}

			var ilprocessor = methodDefinition.Body.GetILProcessor();
			var label = ilprocessor.Create(OpCodes.Nop);
			WriteSetupLocals(ilprocessor);
			WriteServerActiveCheck(ilprocessor, md.Name, label, "RPC Function");
			WriteCreateWriter(ilprocessor);
			WriteMessageSize(ilprocessor);
			WriteMessageId(ilprocessor, 2);
			var fieldDefinition = new FieldDefinition("kRpc" + md.Name, FieldAttributes.Private | FieldAttributes.Static, Weaver.int32Type);
			m_td.Fields.Add(fieldDefinition);
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldsfld, fieldDefinition));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.NetworkWriterWritePacked32));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.getComponentReference));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.getUNetIdReference));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.NetworkWriterWriteNetworkInstanceId));
			MethodDefinition result;
			if (!WriteArguments(ilprocessor, md, "RPC", false))
			{
				result = null;
			}
			else
			{
				var value = 0;
				foreach (var customAttributeNamedArgument in ca.Fields)
				{
					if (customAttributeNamedArgument.Name == "channel")
					{
						value = (int)customAttributeNamedArgument.Argument.Value;
					}
				}

				var text = md.Name;
				var num = text.IndexOf("InvokeRpc");
				if (num > -1)
				{
					text = text.Substring("InvokeRpc".Length);
				}

				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4, value));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldstr, text));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.sendRpcInternal));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				result = methodDefinition;
			}

			return result;
		}

		private bool ProcessMethodsValidateFunction(MethodReference md, CustomAttribute ca, string actionType)
		{
			bool result;
			if (md.ReturnType.FullName == Weaver.IEnumeratorType.FullName)
			{
				Log.Error(string.Concat(new string[]
				{
					actionType,
					" function [",
					m_td.FullName,
					":",
					md.Name,
					"] cannot be a coroutine"
				}));
				Weaver.fail = true;
				result = false;
			}
			else if (md.ReturnType.FullName != Weaver.voidType.FullName)
			{
				Log.Error(string.Concat(new string[]
				{
					actionType,
					" function [",
					m_td.FullName,
					":",
					md.Name,
					"] must have a void return type."
				}));
				Weaver.fail = true;
				result = false;
			}
			else if (md.HasGenericParameters)
			{
				Log.Error(string.Concat(new string[]
				{
					actionType,
					" [",
					m_td.FullName,
					":",
					md.Name,
					"] cannot have generic parameters"
				}));
				Weaver.fail = true;
				result = false;
			}
			else
			{
				result = true;
			}

			return result;
		}

		private bool ProcessMethodsValidateParameters(MethodReference md, CustomAttribute ca, string actionType)
		{
			var i = 0;
			while (i < md.Parameters.Count)
			{
				var parameterDefinition = md.Parameters[i];
				bool result;
				if (parameterDefinition.IsOut)
				{
					Log.Error(string.Concat(new string[]
					{
						actionType,
						" function [",
						m_td.FullName,
						":",
						md.Name,
						"] cannot have out parameters"
					}));
					Weaver.fail = true;
					result = false;
				}
				else if (parameterDefinition.IsOptional)
				{
					Log.Error(string.Concat(new string[]
					{
						actionType,
						"function [",
						m_td.FullName,
						":",
						md.Name,
						"] cannot have optional parameters"
					}));
					Weaver.fail = true;
					result = false;
				}
				else if (parameterDefinition.ParameterType.Resolve().IsAbstract)
				{
					Log.Error(string.Concat(new string[]
					{
						actionType,
						" function [",
						m_td.FullName,
						":",
						md.Name,
						"] cannot have abstract parameters"
					}));
					Weaver.fail = true;
					result = false;
				}
				else if (parameterDefinition.ParameterType.IsByReference)
				{
					Log.Error(string.Concat(new string[]
					{
						actionType,
						" function [",
						m_td.FullName,
						":",
						md.Name,
						"] cannot have ref parameters"
					}));
					Weaver.fail = true;
					result = false;
				}
				else
				{
					if (!(parameterDefinition.ParameterType.FullName == Weaver.NetworkConnectionType.FullName) || (ca.AttributeType.FullName == Weaver.TargetRpcType.FullName && i == 0))
					{
						if (Weaver.IsDerivedFrom(parameterDefinition.ParameterType.Resolve(), Weaver.ComponentType))
						{
							if (parameterDefinition.ParameterType.FullName != Weaver.NetworkIdentityType.FullName)
							{
								Log.Error(string.Concat(new string[]
								{
									actionType,
									" function [",
									m_td.FullName,
									":",
									md.Name,
									"] parameter [",
									parameterDefinition.Name,
									"] is of the type [",
									parameterDefinition.ParameterType.Name,
									"] which is a Component. You cannot pass a Component to a remote call. Try passing data from within the component."
								}));
								Weaver.fail = true;
								return false;
							}
						}

						i++;
						continue;
					}

					Log.Error(string.Concat(new string[]
					{
						actionType,
						" [",
						m_td.FullName,
						":",
						md.Name,
						"] cannot use a NetworkConnection as a parameter. To access a player object's connection on the server use connectionToClient"
					}));
					Log.Error("Name: " + ca.AttributeType.FullName + " parameter: " + md.Parameters[0].ParameterType.FullName);
					Weaver.fail = true;
					result = false;
				}

				return result;
			}

			return true;
		}

		private bool ProcessMethodsValidateCommand(MethodDefinition md, CustomAttribute ca)
		{
			bool result;
			if (md.Name.Length > 2 && md.Name.Substring(0, 3) != "Cmd")
			{
				Log.Error(string.Concat(new string[]
				{
					"Command function [",
					m_td.FullName,
					":",
					md.Name,
					"] doesnt have 'Cmd' prefix"
				}));
				Weaver.fail = true;
				result = false;
			}
			else if (md.IsStatic)
			{
				Log.Error(string.Concat(new string[]
				{
					"Command function [",
					m_td.FullName,
					":",
					md.Name,
					"] cant be a static method"
				}));
				Weaver.fail = true;
				result = false;
			}
			else
			{
				result = (ProcessMethodsValidateFunction(md, ca, "Command") && ProcessMethodsValidateParameters(md, ca, "Command"));
			}

			return result;
		}

		private bool ProcessMethodsValidateTargetRpc(MethodDefinition md, CustomAttribute ca)
		{
			var length = "Target".Length;
			bool result;
			if (md.Name.Length > length && md.Name.Substring(0, length) != "Target")
			{
				Log.Error(string.Concat(new string[]
				{
					"Target Rpc function [",
					m_td.FullName,
					":",
					md.Name,
					"] doesnt have 'Target' prefix"
				}));
				Weaver.fail = true;
				result = false;
			}
			else if (md.IsStatic)
			{
				Log.Error(string.Concat(new string[]
				{
					"TargetRpc function [",
					m_td.FullName,
					":",
					md.Name,
					"] cant be a static method"
				}));
				Weaver.fail = true;
				result = false;
			}
			else if (!ProcessMethodsValidateFunction(md, ca, "Target Rpc"))
			{
				result = false;
			}
			else if (md.Parameters.Count < 1)
			{
				Log.Error(string.Concat(new string[]
				{
					"Target Rpc function [",
					m_td.FullName,
					":",
					md.Name,
					"] must have a NetworkConnection as the first parameter"
				}));
				Weaver.fail = true;
				result = false;
			}
			else if (md.Parameters[0].ParameterType.FullName != Weaver.NetworkConnectionType.FullName)
			{
				Log.Error(string.Concat(new string[]
				{
					"Target Rpc function [",
					m_td.FullName,
					":",
					md.Name,
					"] first parameter must be a NetworkConnection"
				}));
				Weaver.fail = true;
				result = false;
			}
			else
			{
				result = ProcessMethodsValidateParameters(md, ca, "Target Rpc");
			}

			return result;
		}

		private bool ProcessMethodsValidateRpc(MethodDefinition md, CustomAttribute ca)
		{
			bool result;
			if (md.Name.Length > 2 && md.Name.Substring(0, 3) != "Rpc")
			{
				Log.Error(string.Concat(new string[]
				{
					"Rpc function [",
					m_td.FullName,
					":",
					md.Name,
					"] doesnt have 'Rpc' prefix"
				}));
				Weaver.fail = true;
				result = false;
			}
			else if (md.IsStatic)
			{
				Log.Error(string.Concat(new string[]
				{
					"ClientRpc function [",
					m_td.FullName,
					":",
					md.Name,
					"] cant be a static method"
				}));
				Weaver.fail = true;
				result = false;
			}
			else
			{
				result = (ProcessMethodsValidateFunction(md, ca, "Rpc") && ProcessMethodsValidateParameters(md, ca, "Rpc"));
			}

			return result;
		}

		private void ProcessMethods()
		{
			var hashSet = new HashSet<string>();
			foreach (var methodDefinition in m_td.Methods)
			{
				Weaver.ResetRecursionCount();
				foreach (var customAttribute in methodDefinition.CustomAttributes)
				{
					if (customAttribute.AttributeType.FullName == Weaver.CommandType.FullName)
					{
						if (!ProcessMethodsValidateCommand(methodDefinition, customAttribute))
						{
							return;
						}

						if (hashSet.Contains(methodDefinition.Name))
						{
							Log.Error(string.Concat(new string[]
							{
								"Duplicate Command name [",
								m_td.FullName,
								":",
								methodDefinition.Name,
								"]"
							}));
							Weaver.fail = true;
							return;
						}

						hashSet.Add(methodDefinition.Name);
						m_Cmds.Add(methodDefinition);
						var methodDefinition2 = ProcessCommandInvoke(methodDefinition);
						if (methodDefinition2 != null)
						{
							m_CmdInvocationFuncs.Add(methodDefinition2);
						}

						var methodDefinition3 = ProcessCommandCall(methodDefinition, customAttribute);
						if (methodDefinition3 != null)
						{
							m_CmdCallFuncs.Add(methodDefinition3);
							Weaver.lists.replacedMethods.Add(methodDefinition);
							Weaver.lists.replacementMethods.Add(methodDefinition3);
						}

						break;
					}
					else if (customAttribute.AttributeType.FullName == Weaver.TargetRpcType.FullName)
					{
						if (!ProcessMethodsValidateTargetRpc(methodDefinition, customAttribute))
						{
							return;
						}

						if (hashSet.Contains(methodDefinition.Name))
						{
							Log.Error(string.Concat(new string[]
							{
								"Duplicate Target Rpc name [",
								m_td.FullName,
								":",
								methodDefinition.Name,
								"]"
							}));
							Weaver.fail = true;
							return;
						}

						hashSet.Add(methodDefinition.Name);
						m_TargetRpcs.Add(methodDefinition);
						var methodDefinition4 = ProcessTargetRpcInvoke(methodDefinition);
						if (methodDefinition4 != null)
						{
							m_TargetRpcInvocationFuncs.Add(methodDefinition4);
						}

						var methodDefinition5 = ProcessTargetRpcCall(methodDefinition, customAttribute);
						if (methodDefinition5 != null)
						{
							m_TargetRpcCallFuncs.Add(methodDefinition5);
							Weaver.lists.replacedMethods.Add(methodDefinition);
							Weaver.lists.replacementMethods.Add(methodDefinition5);
						}

						break;
					}
					else if (customAttribute.AttributeType.FullName == Weaver.ClientRpcType.FullName)
					{
						if (!ProcessMethodsValidateRpc(methodDefinition, customAttribute))
						{
							return;
						}

						if (hashSet.Contains(methodDefinition.Name))
						{
							Log.Error(string.Concat(new string[]
							{
								"Duplicate ClientRpc name [",
								m_td.FullName,
								":",
								methodDefinition.Name,
								"]"
							}));
							Weaver.fail = true;
							return;
						}

						hashSet.Add(methodDefinition.Name);
						m_Rpcs.Add(methodDefinition);
						var methodDefinition6 = ProcessRpcInvoke(methodDefinition);
						if (methodDefinition6 != null)
						{
							m_RpcInvocationFuncs.Add(methodDefinition6);
						}

						var methodDefinition7 = ProcessRpcCall(methodDefinition, customAttribute);
						if (methodDefinition7 != null)
						{
							m_RpcCallFuncs.Add(methodDefinition7);
							Weaver.lists.replacedMethods.Add(methodDefinition);
							Weaver.lists.replacementMethods.Add(methodDefinition7);
						}

						break;
					}
				}
			}

			foreach (var item in m_CmdInvocationFuncs)
			{
				m_td.Methods.Add(item);
			}

			foreach (var item2 in m_CmdCallFuncs)
			{
				m_td.Methods.Add(item2);
			}

			foreach (var item3 in m_RpcInvocationFuncs)
			{
				m_td.Methods.Add(item3);
			}

			foreach (var item4 in m_TargetRpcInvocationFuncs)
			{
				m_td.Methods.Add(item4);
			}

			foreach (var item5 in m_RpcCallFuncs)
			{
				m_td.Methods.Add(item5);
			}

			foreach (var item6 in m_TargetRpcCallFuncs)
			{
				m_td.Methods.Add(item6);
			}
		}

		private MethodDefinition ProcessEventInvoke(EventDefinition ed)
		{
			FieldDefinition fieldDefinition = null;
			foreach (var fieldDefinition2 in m_td.Fields)
			{
				if (fieldDefinition2.FullName == ed.FullName)
				{
					fieldDefinition = fieldDefinition2;
					break;
				}
			}

			MethodDefinition result;
			if (fieldDefinition == null)
			{
				Weaver.DLog(m_td, "ERROR: no event field?!", new object[0]);
				Weaver.fail = true;
				result = null;
			}
			else
			{
				var methodDefinition = new MethodDefinition("InvokeSyncEvent" + ed.Name, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, Weaver.voidType);
				var ilprocessor = methodDefinition.Body.GetILProcessor();
				var label = ilprocessor.Create(OpCodes.Nop);
				var instruction = ilprocessor.Create(OpCodes.Nop);
				WriteClientActiveCheck(ilprocessor, ed.Name, label, "Event");
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Castclass, m_td));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldfld, fieldDefinition));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Brtrue, instruction));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				ilprocessor.Append(instruction);
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Castclass, m_td));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldfld, fieldDefinition));
				var methodReference = Weaver.ResolveMethod(fieldDefinition.FieldType, "Invoke");
				if (!ProcessNetworkReaderParameters(methodReference.Resolve(), ilprocessor, false))
				{
					result = null;
				}
				else
				{
					ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, methodReference));
					ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
					AddInvokeParameters(methodDefinition.Parameters);
					result = methodDefinition;
				}
			}

			return result;
		}

		private MethodDefinition ProcessEventCall(EventDefinition ed, CustomAttribute ca)
		{
			var methodReference = Weaver.ResolveMethod(ed.EventType, "Invoke");
			var methodDefinition = new MethodDefinition("Call" + ed.Name, MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.HideBySig, Weaver.voidType);
			foreach (var parameterDefinition in methodReference.Parameters)
			{
				methodDefinition.Parameters.Add(new ParameterDefinition(parameterDefinition.Name, ParameterAttributes.None, parameterDefinition.ParameterType));
			}

			var ilprocessor = methodDefinition.Body.GetILProcessor();
			var label = ilprocessor.Create(OpCodes.Nop);
			WriteSetupLocals(ilprocessor);
			WriteServerActiveCheck(ilprocessor, ed.Name, label, "Event");
			WriteCreateWriter(ilprocessor);
			WriteMessageSize(ilprocessor);
			WriteMessageId(ilprocessor, 7);
			var fieldDefinition = new FieldDefinition("kEvent" + ed.Name, FieldAttributes.Private | FieldAttributes.Static, Weaver.int32Type);
			m_td.Fields.Add(fieldDefinition);
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldsfld, fieldDefinition));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.NetworkWriterWritePacked32));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.getComponentReference));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.getUNetIdReference));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, Weaver.NetworkWriterWriteNetworkInstanceId));
			MethodDefinition result;
			if (!WriteArguments(ilprocessor, methodReference.Resolve(), "SyncEvent", false))
			{
				result = null;
			}
			else
			{
				var value = 0;
				foreach (var customAttributeNamedArgument in ca.Fields)
				{
					if (customAttributeNamedArgument.Name == "channel")
					{
						value = (int)customAttributeNamedArgument.Argument.Value;
					}
				}

				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldloc_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4, value));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldstr, ed.Name));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.sendEventInternal));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				result = methodDefinition;
			}

			return result;
		}

		private void ProcessEvents()
		{
			foreach (var eventDefinition in m_td.Events)
			{
				foreach (var customAttribute in eventDefinition.CustomAttributes)
				{
					if (customAttribute.AttributeType.FullName == Weaver.SyncEventType.FullName)
					{
						if (eventDefinition.Name.Length > 4 && eventDefinition.Name.Substring(0, 5) != "Event")
						{
							Log.Error(string.Concat(new string[]
							{
								"Event  [",
								m_td.FullName,
								":",
								eventDefinition.FullName,
								"] doesnt have 'Event' prefix"
							}));
							Weaver.fail = true;
							return;
						}

						if (eventDefinition.EventType.Resolve().HasGenericParameters)
						{
							Log.Error(string.Concat(new string[]
							{
								"Event  [",
								m_td.FullName,
								":",
								eventDefinition.FullName,
								"] cannot have generic parameters"
							}));
							Weaver.fail = true;
							return;
						}

						m_Events.Add(eventDefinition);
						var methodDefinition = ProcessEventInvoke(eventDefinition);
						if (methodDefinition == null)
						{
							return;
						}

						m_td.Methods.Add(methodDefinition);
						m_EventInvocationFuncs.Add(methodDefinition);
						Weaver.DLog(m_td, "ProcessEvent " + eventDefinition, new object[0]);
						var methodDefinition2 = ProcessEventCall(eventDefinition, customAttribute);
						m_td.Methods.Add(methodDefinition2);
						Weaver.lists.replacedEvents.Add(eventDefinition);
						Weaver.lists.replacementEvents.Add(methodDefinition2);
						Weaver.DLog(m_td, "  Event: " + eventDefinition.Name, new object[0]);
						break;
					}
				}
			}
		}

		private static MethodDefinition ProcessSyncVarGet(FieldDefinition fd, string originalName)
		{
			var methodDefinition = new MethodDefinition("get_Network" + originalName, MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.SpecialName, fd.FieldType);
			var ilprocessor = methodDefinition.Body.GetILProcessor();
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldfld, fd));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
			methodDefinition.Body.Variables.Add(new VariableDefinition(fd.FieldType));
			methodDefinition.Body.InitLocals = true;
			methodDefinition.SemanticsAttributes = MethodSemanticsAttributes.Getter;
			return methodDefinition;
		}

		private MethodDefinition ProcessSyncVarSet(FieldDefinition fd, string originalName, int dirtyBit, FieldDefinition netFieldId)
		{
			var methodDefinition = new MethodDefinition("set_Network" + originalName, MethodAttributes.FamANDAssem | MethodAttributes.Family | MethodAttributes.HideBySig | MethodAttributes.SpecialName, Weaver.voidType);
			var ilprocessor = methodDefinition.Body.GetILProcessor();

			var noOperatorInstruction = ilprocessor.Create(OpCodes.Nop);
			var returnInstruction = ilprocessor.Create(OpCodes.Ret);

			CheckForHookFunction(fd, out var methodDefinition2);
			if (methodDefinition2 != null)
			{

				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.NetworkServerGetLocalClientActive));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Brfalse, noOperatorInstruction));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.getSyncVarHookGuard));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Brtrue, noOperatorInstruction));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4_1));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.setSyncVarHookGuard));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, methodDefinition2));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.setSyncVarHookGuard));
				ilprocessor.Append(noOperatorInstruction);
			}

			if (fd.FieldType.FullName == Weaver.gameObjectType.FullName)
			{
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldflda, netFieldId));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.setSyncVarGameObjectReference));
			}
			else
			{
				var genericInstanceMethod = new GenericInstanceMethod(Weaver.setSyncVarReference);
				genericInstanceMethod.GenericArguments.Add(fd.FieldType);

				var index11 = ilprocessor.Create(OpCodes.Ldarg_0);

				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.UBehaviourIsServer));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Brfalse_S, index11));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldflda, fd));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4, dirtyBit));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, genericInstanceMethod));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Pop));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
				ilprocessor.Append(index11);
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldflda, fd));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldc_I4, dirtyBit));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, genericInstanceMethod));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Brfalse_S, returnInstruction));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
				ilprocessor.Append(ilprocessor.Create(OpCodes.Call, Weaver.NetworkBehaviourClientSendUpdateVars));
			}

			ilprocessor.Append(returnInstruction);
			methodDefinition.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType));
			methodDefinition.SemanticsAttributes = MethodSemanticsAttributes.Setter;
			return methodDefinition;
		}

		private void ProcessSyncVar(FieldDefinition fd, int dirtyBit)
		{
			var name = fd.Name;
			Weaver.lists.replacedFields.Add(fd);
			Weaver.DLog(m_td, $"Found SyncVar {fd.Name} of type {fd.FieldType}", new object[0]);
			FieldDefinition fieldDefinition = null;
			if (fd.FieldType.FullName == Weaver.gameObjectType.FullName)
			{
				fieldDefinition = new FieldDefinition("___" + fd.Name + "NetId", FieldAttributes.Private, Weaver.NetworkInstanceIdType);
				m_SyncVarNetIds.Add(fieldDefinition);
				Weaver.lists.netIdFields.Add(fieldDefinition);
			}

			var methodDefinition = ProcessSyncVarGet(fd, name);
			var methodDefinition2 = ProcessSyncVarSet(fd, name, dirtyBit, fieldDefinition);
			var item = new PropertyDefinition("Network" + name, PropertyAttributes.None, fd.FieldType)
			{
				GetMethod = methodDefinition,
				SetMethod = methodDefinition2
			};
			m_td.Methods.Add(methodDefinition);
			m_td.Methods.Add(methodDefinition2);
			m_td.Properties.Add(item);
			Weaver.lists.replacementProperties.Add(methodDefinition2);
		}

		private static MethodDefinition ProcessSyncListInvoke(FieldDefinition fd)
		{
			var methodDefinition = new MethodDefinition("InvokeSyncList" + fd.Name, MethodAttributes.Family | MethodAttributes.Static | MethodAttributes.HideBySig, Weaver.voidType);
			var ilprocessor = methodDefinition.Body.GetILProcessor();
			var label = ilprocessor.Create(OpCodes.Nop);
			WriteClientActiveCheck(ilprocessor, fd.Name, label, "SyncList");
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_0));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Castclass, fd.DeclaringType));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldfld, fd));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ldarg_1));
			var genericInstanceType = (GenericInstanceType)fd.FieldType.Resolve().BaseType;
			genericInstanceType = (GenericInstanceType)Weaver.scriptDef.MainModule.ImportReference(genericInstanceType);
			var typeReference = genericInstanceType.GenericArguments[0];
			var method = Helpers.MakeHostInstanceGeneric(Weaver.SyncListInitHandleMsg, new TypeReference[]
			{
				typeReference
			});
			ilprocessor.Append(ilprocessor.Create(OpCodes.Callvirt, method));
			ilprocessor.Append(ilprocessor.Create(OpCodes.Ret));
			AddInvokeParameters(methodDefinition.Parameters);
			return methodDefinition;
		}

		private FieldDefinition ProcessSyncList(FieldDefinition fd, int dirtyBit)
		{
			var methodDefinition = ProcessSyncListInvoke(fd);
			m_SyncListInvocationFuncs.Add(methodDefinition);
			return new FieldDefinition("kList" + fd.Name, FieldAttributes.Private | FieldAttributes.Static, Weaver.int32Type);
		}

		private void ProcessSyncVars()
		{
			var num = 0;
			var num2 = Weaver.GetSyncVarStart(m_td.BaseType.FullName);
			m_SyncVarNetIds.Clear();
			var list = new List<FieldDefinition>();
			foreach (var fieldDefinition in m_td.Fields)
			{
				foreach (var customAttribute in fieldDefinition.CustomAttributes)
				{
					if (customAttribute.AttributeType.FullName == Weaver.SyncVarType.FullName)
					{
						var typeDefinition = fieldDefinition.FieldType.Resolve();
						if (Weaver.IsDerivedFrom(typeDefinition, Weaver.NetworkBehaviourType))
						{
							Log.Error("SyncVar [" + fieldDefinition.FullName + "] cannot be derived from NetworkBehaviour.");
							Weaver.fail = true;
							return;
						}

						if (Weaver.IsDerivedFrom(typeDefinition, Weaver.ScriptableObjectType))
						{
							Log.Error("SyncVar [" + fieldDefinition.FullName + "] cannot be derived from ScriptableObject.");
							Weaver.fail = true;
							return;
						}

						if ((ushort)(fieldDefinition.Attributes & FieldAttributes.Static) != 0)
						{
							Log.Error("SyncVar [" + fieldDefinition.FullName + "] cannot be static.");
							Weaver.fail = true;
							return;
						}

						if (typeDefinition.HasGenericParameters)
						{
							Log.Error("SyncVar [" + fieldDefinition.FullName + "] cannot have generic parameters.");
							Weaver.fail = true;
							return;
						}

						if (typeDefinition.IsInterface)
						{
							Log.Error("SyncVar [" + fieldDefinition.FullName + "] cannot be an interface.");
							Weaver.fail = true;
							return;
						}

						var name = typeDefinition.Module.Name;
						if (name != Weaver.scriptDef.MainModule.Name && name != Weaver.UnityAssemblyDefinition.MainModule.Name && name != Weaver.QNetAssemblyDefinition.MainModule.Name && name != Weaver.corLib.Name && name != "System.Runtime.dll")
						{
							Log.Error($"SyncVar [{fieldDefinition.FullName}] is from an inaccessible module! : [{name}]");
							Weaver.fail = true;
							return;
						}

						if (fieldDefinition.FieldType.IsArray)
						{
							Log.Error("SyncVar [" + fieldDefinition.FullName + "] cannot be an array. Use a SyncList instead.");
							Weaver.fail = true;
							return;
						}

						if (Helpers.InheritsFromSyncList(fieldDefinition.FieldType))
						{
							Log.Warning(string.Format("Script class [{0}] has [SyncVar] attribute on SyncList field {1}, SyncLists should not be marked with SyncVar.", m_td.FullName, fieldDefinition.Name));
							break;
						}

						m_SyncVars.Add(fieldDefinition);
						ProcessSyncVar(fieldDefinition, 1 << num2);
						num2++;
						num++;
						if (num2 == 32)
						{
							Log.Error(string.Concat(new object[]
							{
								"Script class [",
								m_td.FullName,
								"] has too many SyncVars (",
								32,
								"). (This could include base classes)"
							}));
							Weaver.fail = true;
							return;
						}

						break;
					}
				}

				if (fieldDefinition.FieldType.FullName.Contains("UnityEngine.Networking.SyncListStruct"))
				{
					Log.Error("SyncListStruct member variable [" + fieldDefinition.FullName + "] must use a dervied class, like \"class MySyncList : SyncListStruct<MyStruct> {}\".");
					Weaver.fail = true;
					return;
				}

				if (Weaver.IsDerivedFrom(fieldDefinition.FieldType.Resolve(), Weaver.SyncListType))
				{
					if (fieldDefinition.IsStatic)
					{
						Log.Error(string.Concat(new string[]
						{
							"SyncList [",
							m_td.FullName,
							":",
							fieldDefinition.FullName,
							"] cannot be a static"
						}));
						Weaver.fail = true;
						return;
					}

					m_SyncVars.Add(fieldDefinition);
					m_SyncLists.Add(fieldDefinition);
					list.Add(ProcessSyncList(fieldDefinition, 1 << num2));
					num2++;
					num++;
					if (num2 == 32)
					{
						Log.Error(string.Concat(new object[]
						{
							"Script class [",
							m_td.FullName,
							"] has too many SyncVars (",
							32,
							"). (This could include base classes)"
						}));
						Weaver.fail = true;
						return;
					}
				}
			}

			foreach (var fieldDefinition2 in list)
			{
				m_td.Fields.Add(fieldDefinition2);
				m_SyncListStaticFields.Add(fieldDefinition2);
			}

			foreach (var item in m_SyncVarNetIds)
			{
				m_td.Fields.Add(item);
			}

			foreach (var item2 in m_SyncListInvocationFuncs)
			{
				m_td.Methods.Add(item2);
			}

			Weaver.SetNumSyncVars(m_td.FullName, num);
		}

		private static int GetHashCode(string s)
		{
			var assembly = typeof(Unity.UNetWeaver.Program).Assembly;
			var networkProcessorType = assembly.GetType("Unity.UNetWeaver.NetworkBehaviourProcessor");
			var methodInfo = networkProcessorType.GetMethod("GetHashCode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
			return (int)methodInfo.Invoke(null, new object[] { s });
		}

		private bool HasMethod(string name)
		{
			foreach (var methodDefinition in m_td.Methods)
			{
				if (methodDefinition.Name == name)
				{
					return true;
				}
			}

			return false;
		}

		private List<FieldDefinition> m_SyncVars = new List<FieldDefinition>();

		private List<FieldDefinition> m_SyncLists = new List<FieldDefinition>();

		private List<FieldDefinition> m_SyncVarNetIds = new List<FieldDefinition>();

		private List<MethodDefinition> m_Cmds = new List<MethodDefinition>();

		private List<MethodDefinition> m_Rpcs = new List<MethodDefinition>();

		private List<MethodDefinition> m_TargetRpcs = new List<MethodDefinition>();

		private List<EventDefinition> m_Events = new List<EventDefinition>();

		private List<FieldDefinition> m_SyncListStaticFields = new List<FieldDefinition>();

		private List<MethodDefinition> m_CmdInvocationFuncs = new List<MethodDefinition>();

		private List<MethodDefinition> m_SyncListInvocationFuncs = new List<MethodDefinition>();

		private List<MethodDefinition> m_RpcInvocationFuncs = new List<MethodDefinition>();

		private List<MethodDefinition> m_TargetRpcInvocationFuncs = new List<MethodDefinition>();

		private List<MethodDefinition> m_EventInvocationFuncs = new List<MethodDefinition>();

		private List<MethodDefinition> m_CmdCallFuncs = new List<MethodDefinition>();

		private List<MethodDefinition> m_RpcCallFuncs = new List<MethodDefinition>();

		private List<MethodDefinition> m_TargetRpcCallFuncs = new List<MethodDefinition>();

		private const int k_SyncVarLimit = 32;

		private int m_QosChannel;

		private TypeDefinition m_td;

		private int m_NetIdFieldCounter;

		private const string k_CmdPrefix = "InvokeCmd";

		private const string k_RpcPrefix = "InvokeRpc";

		private const string k_TargetRpcPrefix = "InvokeTargetRpc";
	}
}
