static internal TypeInformation ParseTypeFields(Mono.Cecil.TypeDefinition type, bool onlyFieldWithGhostField = true)
        {
            bool isBuffer      = CecilExtensions.IsBufferElementData(type);
            bool isCommandData = CecilExtensions.IsICommandData(type);
            var  root          = new TypeInformation(type);

            if (isBuffer)
            {
                root.AttributeMask &= ~(TypeAttribute.AttributeFlags.InterpolatedAndExtrapolated);
            }

            if (!type.HasFields)
            {
                return(root);
            }
            foreach (var field in type.Fields)
            {
                if (!field.IsPublic || field.IsStatic)
                {
                    continue;
                }

                var ghostField = CecilExtensions.GetGhostFieldAttribute(type, field);
                if (!onlyFieldWithGhostField && isCommandData &&
                    field.HasAttributeOnMemberOImplementedInterfaces <DontSerializeForCommand>())
                {
                    continue;
                }
                if (!onlyFieldWithGhostField || (ghostField != null && ghostField.SendData))
                {
                    root.Add(ParseTypeField(field, field.FieldType, ghostField, TypeAttribute.Empty(), root.AttributeMask));
                }
            }
            foreach (var prop in type.Properties)
            {
                if (prop.GetMethod == null || !prop.GetMethod.IsPublic || prop.GetMethod.IsStatic)
                {
                    continue;
                }
                if (prop.SetMethod == null || !prop.SetMethod.IsPublic || prop.SetMethod.IsStatic)
                {
                    continue;
                }

                var ghostField = CecilExtensions.GetGhostFieldAttribute(type, prop);
                if (!onlyFieldWithGhostField && isCommandData &&
                    prop.HasAttributeOnMemberOImplementedInterfaces <DontSerializeForCommand>())
                {
                    continue;
                }

                if (!onlyFieldWithGhostField || (ghostField != null && ghostField.SendData))
                {
                    root.Add(ParseTypeField(prop, prop.PropertyType, ghostField, TypeAttribute.Empty(), root.AttributeMask));
                }
            }


            return(root);
        }
        TypeInformation ParseTypeFields(Mono.Cecil.TypeDefinition type, bool onlyFieldWithGhostField = true)
        {
            var root = new TypeInformation(type);

            if (!type.HasFields)
            {
                return(root);
            }

            foreach (var field in type.Fields)
            {
                if (!field.IsPublic || field.IsStatic)
                {
                    continue;
                }

                if (!onlyFieldWithGhostField || CecilExtensions.HasGhostFieldAttribute(type, field))
                {
                    if (!CecilExtensions.HasGhostFieldAttribute(type, field) || CecilExtensions.GetGhostFieldAttribute(type, field).SendData)
                    {
                        root.Add(ParseTypeField(type, field, TypeAttribute.Empty()));
                    }
                }
            }
            return(root);
        }
Exemple #3
0
        public void GenerateSerializer(CodeGenerator.Context context, Mono.Cecil.TypeDefinition type)
        {
            var replacements = new Dictionary <string, string>();

            if (context.FieldState.curChangeMask > 0)
            {
                replacements.Add("GHOST_CHANGE_MASK_BITS", context.FieldState.curChangeMask.ToString());
                m_TargetGenerator.GenerateFragment("GHOST_FLUSH_FINAL_COMPONENT_CHANGE_MASK", replacements);
            }

            if (type.Namespace != null && type.Namespace != "")
            {
                context.imports.Add(type.Namespace);
            }
            foreach (var ns in context.imports)
            {
                replacements["GHOST_USING"] = CodeGenNamespaceUtils.GetValidNamespaceForType(context.generatedNs, ns);
                m_TargetGenerator.GenerateFragment("GHOST_USING_STATEMENT", replacements);
            }

            context.collectionAssemblies.Add(type.Module.Assembly.Name.Name);

            replacements.Clear();
            replacements.Add("GHOST_NAME", type.FullName.Replace(".", "").Replace("/", "_"));
            replacements.Add("GHOST_NAMESPACE", context.generatedNs);
            replacements.Add("GHOST_COMPONENT_TYPE", type.FullName.Replace("/", "."));
            replacements.Add("GHOST_CHANGE_MASK_BITS", context.FieldState.numFields.ToString());
            replacements.Add("GHOST_FIELD_HASH", context.FieldState.ghostfieldHash.ToString());
            replacements.Add("GHOST_COMPONENT_EXCLUDE_FROM_COLLECTION_HASH", context.IsRuntimeAssembly ? "0" : "1");

            var ghostAttributes = CecilExtensions.GetGhostComponentAttribute(type);

            if (ghostAttributes != null && (ghostAttributes.OwnerPredictedSendType == GhostSendType.Interpolated || (ghostAttributes.PrefabType & GhostPrefabType.Client) == GhostPrefabType.InterpolatedClient))
            {
                replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Interpolated");
            }
            else if (ghostAttributes != null && (ghostAttributes.OwnerPredictedSendType == GhostSendType.Predicted || (ghostAttributes.PrefabType & GhostPrefabType.Client) == GhostPrefabType.PredictedClient))
            {
                replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Predicted");
            }
            else
            {
                replacements.Add("GHOST_SEND_MASK", "GhostComponentSerializer.SendMask.Interpolated | GhostComponentSerializer.SendMask.Predicted");
            }
            replacements.Add("GHOST_SEND_CHILD_ENTITY", (ghostAttributes != null && !ghostAttributes.SendDataForChildEntity)?"0":"1");

            if (m_TargetGenerator.Fragments["__GHOST_REPORT_PREDICTION_ERROR__"].Content.Length > 0)
            {
                m_TargetGenerator.GenerateFragment("GHOST_PREDICTION_ERROR_HEADER", replacements, m_TargetGenerator);
            }

            var serializerName = type.FullName.Replace("/", "+") + "Serializer.cs";

            m_TargetGenerator.GenerateFile("", context.outputFolder, serializerName, replacements, context.batch);

            context.generatedTypes.Add(replacements["GHOST_NAME"]);
        }
        static internal TypeInformation ParseVariantTypeFields(Mono.Cecil.TypeDefinition variantType, Mono.Cecil.TypeReference typeReference)
        {
            var type = typeReference.Resolve();

            var root = new TypeInformation(type);

            if (!variantType.HasFields)
            {
                return(root);
            }

            foreach (var field in variantType.Fields)
            {
                if (!field.IsPublic || field.IsStatic)
                {
                    continue;
                }

                if (type.Fields.FirstOrDefault(f => f.Name == field.Name) == null)
                {
                    UnityEngine.Debug.LogError($"Variant {variantType.Name}. field {field.Name} not present in original type {type.Name}");
                    continue;
                }

                //Avoid use ghost fields modifiers for the variant type. passing null prevent that
                var ghostField = CecilExtensions.GetGhostFieldAttribute(null, field);
                if (ghostField != null && ghostField.SendData)
                {
                    root.Add(ParseTypeField(field, field.FieldType, ghostField, TypeAttribute.Empty(), root.AttributeMask));
                }
            }
            foreach (var prop in type.Properties)
            {
                if (prop.GetMethod == null || !prop.GetMethod.IsPublic || prop.GetMethod.IsStatic)
                {
                    continue;
                }
                if (prop.SetMethod == null || !prop.SetMethod.IsPublic || prop.SetMethod.IsStatic)
                {
                    continue;
                }

                if (type.Properties.FirstOrDefault(f => f.Name == prop.Name) == null)
                {
                    UnityEngine.Debug.LogError($"Variant {variantType.Name}. field {prop.Name} not present in original type {type.Name}");
                    continue;
                }

                var ghostField = CecilExtensions.GetGhostFieldAttribute(type, prop);
                if (ghostField != null && ghostField.SendData)
                {
                    root.Add(ParseTypeField(prop, prop.PropertyType, ghostField, TypeAttribute.Empty(), root.AttributeMask));
                }
            }
            return(root);
        }
        public TypeInformation(Mono.Cecil.TypeReference parentType, Mono.Cecil.FieldDefinition fieldInfo, TypeAttribute inheritedAttribute,
                               string parent = null)
        {
            FieldInfo = fieldInfo;
            Type      = fieldInfo.FieldType;
            Fields    = new List <TypeInformation>();
            Attribute = inheritedAttribute;

            ParseAttribute(CecilExtensions.GetGhostFieldAttribute(parentType, fieldInfo));
            Parent = string.IsNullOrEmpty(parent) ? "" : parent;
        }
        void GenerateType(Context context, Mono.Cecil.TypeDefinition type)
        {
            TypeInformation typeTree;

            Mono.Cecil.TypeDefinition componentType;
            GhostComponentAttribute   ghostAttribute;
            var variantAttr = type.GetAttribute <GhostComponentVariationAttribute>();

            if (variantAttr != null)
            {
                ghostAttribute      = CecilExtensions.GetGhostComponentAttribute(type);
                context.VariantHash = CecilExtensions.ComputeVariantHash(type, variantAttr);
                var typeReference = variantAttr.ConstructorArguments.First().Value as Mono.Cecil.TypeReference;
                typeTree      = ParseVariantTypeFields(type, typeReference);
                componentType = typeReference.Resolve();
            }
            else
            {
                if (GhostAuthoringModifiers.GhostDefaultOverrides.TryGetValue(type.FullName.Replace('/', '+'), out var newComponent))
                {
                    ghostAttribute = newComponent.attribute;
                }
                else
                {
                    ghostAttribute = CecilExtensions.GetGhostComponentAttribute(type);
                }
                typeTree      = ParseTypeFields(type);
                componentType = type;
            }

            var generator = InternalGenerateType(context, typeTree, type.FullName);

            generator.GenerateMasks(context);

            var serializeGenerator = new TypeGenerator(context);

            generator.AppendTarget(serializeGenerator);
            serializeGenerator.GenerateSerializer(context, type, componentType, ghostAttribute);
        }