using FishNet.CodeGenerating.Helping.Extension; using FishNet.CodeGenerating.Processing; using FishNet.Object.Synchronizing; using FishNet.Object.Synchronizing.Internal; using MonoFN.Cecil; using MonoFN.Cecil.Rocks; using System; using System.Collections.Generic; namespace FishNet.CodeGenerating.Helping { internal class CreatedSyncVarGenerator : CodegenBase { private readonly Dictionary _createdSyncVars = new Dictionary(); #region Relfection references. private TypeReference _syncBase_TypeRef; internal TypeReference SyncVar_TypeRef; private MethodReference _syncVar_Constructor_MethodRef; #endregion #region Const. private const string GETVALUE_NAME = "GetValue"; private const string SETVALUE_NAME = "SetValue"; #endregion /* //feature add and test the dirty boolean changes * eg... instead of base.Dirty() * do if (!base.Dirty()) return false; * See synclist for more info. */ /// /// Imports references needed by this helper. /// /// /// public override bool ImportReferences() { SyncVar_TypeRef = base.ImportReference(typeof(SyncVar<>)); MethodDefinition svConstructor = SyncVar_TypeRef.GetFirstConstructor(base.Session, true); _syncVar_Constructor_MethodRef = base.ImportReference(svConstructor); Type syncBaseType = typeof(SyncBase); _syncBase_TypeRef = base.ImportReference(syncBaseType); return true; } /// /// Gets and optionally creates data for SyncVar /// /// /// internal CreatedSyncVar GetCreatedSyncVar(FieldDefinition originalFd, bool createMissing) { TypeReference dataTr = originalFd.FieldType; TypeDefinition dataTd = dataTr.CachedResolve(base.Session); string typeHash = dataTr.FullName + dataTr.IsArray.ToString(); if (_createdSyncVars.TryGetValue(typeHash, out CreatedSyncVar createdSyncVar)) { return createdSyncVar; } else { if (!createMissing) return null; base.ImportReference(dataTd); GenericInstanceType syncVarGit = SyncVar_TypeRef.MakeGenericInstanceType(new TypeReference[] { dataTr }); TypeReference genericDataTr = syncVarGit.GenericArguments[0]; //Make sure can serialize. bool canSerialize = base.GetClass().HasSerializerAndDeserializer(genericDataTr, true); if (!canSerialize) { base.LogError($"SyncVar {originalFd.Name} data type {genericDataTr.FullName} does not support serialization. Use a supported type or create a custom serializer."); return null; } //Set needed methods from syncbase. MethodReference setSyncIndexMr; MethodReference genericSyncVarCtor = _syncVar_Constructor_MethodRef.MakeHostInstanceGeneric(base.Session, syncVarGit); if (!base.GetClass().SetSyncBaseMethods(_syncBase_TypeRef.CachedResolve(base.Session), out setSyncIndexMr, out _)) return null; MethodReference setValueMr = null; MethodReference getValueMr = null; foreach (MethodDefinition md in SyncVar_TypeRef.CachedResolve(base.Session).Methods) { //GetValue. if (md.Name == GETVALUE_NAME) { MethodReference mr = base.ImportReference(md); getValueMr = mr.MakeHostInstanceGeneric(base.Session, syncVarGit); } //SetValue. else if (md.Name == SETVALUE_NAME) { MethodReference mr = base.ImportReference(md); setValueMr = mr.MakeHostInstanceGeneric(base.Session, syncVarGit); } } if (setValueMr == null || getValueMr == null) return null; CreatedSyncVar csv = new CreatedSyncVar(syncVarGit, dataTd, getValueMr, setValueMr, setSyncIndexMr, null, genericSyncVarCtor); _createdSyncVars.Add(typeHash, csv); return csv; } } } }