From 7a0ad7e96861a6c308bcaca6685a296f422941f2 Mon Sep 17 00:00:00 2001 From: Samuele Lorefice Date: Thu, 27 Feb 2025 20:57:12 +0100 Subject: [PATCH] Added IsClass and FilterFields methods to streamline types creation, added more documentation --- CodeGenerator/Program.cs | 105 ++++++++++++++++++++++++++++++++------- 1 file changed, 86 insertions(+), 19 deletions(-) diff --git a/CodeGenerator/Program.cs b/CodeGenerator/Program.cs index 55fc565..8009b9c 100644 --- a/CodeGenerator/Program.cs +++ b/CodeGenerator/Program.cs @@ -69,10 +69,6 @@ namespace CodeGenerator { _customTypes = new(); foreach (var type in _blendfile.SdnaStructs) { - Log($"Generating struct {type.Type}"); - bool referenceSelf = false; - bool referencePointer = false; - //Add the type to the custom types list _customTypes.Add(type.Type); @@ -82,27 +78,27 @@ namespace CodeGenerator { new CodeAttributeArgument(new CodePrimitiveExpression(type.IdxType)), new CodeAttributeArgument(new CodePrimitiveExpression(type.Type)) )); - //TODO: when encountering a list, run trough the fields to find a count/lenght or similar data. - foreach (var field in type.Fields) { - if (field.Name.Contains("*")) { - referencePointer = true; - } - if (field.Type.Contains(type.Type)) { - referenceSelf = true; - } - } - - if (referenceSelf || referencePointer) { - Log("Struct contains references"); + + Log($"Generating type from struct {type.Type}"); + + if(IsClass(type)) { + Log($"Marking {type.Type} as class"); ctd.IsClass = true; } else { - ctd.IsStruct = true; + Log($"Marking {type.Type} as struct"); + ctd.IsStruct = !ctd.IsClass; } - //Add the class to the namespace ns.Types.Add(ctd); + //TODO: when encountering a list, run trough the fields to find a count/lenght or similar data. + List normalFields; //Fields that are not lists nor lenghts of lists + List<(BlendFile.DnaField, BlendFile.DnaField)> listFields; //Fields that are lists, and their corresponding length fields + + //filter the fields we want to include in the class minus the lists + FilterFields(type.Fields, out normalFields, out listFields); + var totalSize = 0; //Add the fields to the class @@ -142,6 +138,76 @@ namespace CodeGenerator { return ns; } + /// + /// Determines if the type has to be serialized as a class or a struct + /// + /// istance to analyze + /// if there is any pointer or self reference, otherwise + private static bool IsClass(BlendFile.DnaStruct type) { + foreach (var field in type.Fields) { + if (field.Name.Contains("*")) { + Log($"Pointer detected. {field.Type} {field.Name}"); + return true; + } + if (field.Type.Contains(type.Type)) { + Log($"Self reference detected. {field.Type} {field.Name}"); + return true; + } + } + Log($"No pointer or self reference detected in {type.Type}"); + return false; + } + + + /// + /// Filters the fields into normal fields and list fields pairs + /// + /// of s from all parameters + /// of containing all fields not part of a List + /// of (, ) collection where Item1 is the ListPointer and Item2 is the list lenght + private static void FilterFields(IEnumerable fields, + out List normalFields, + out List<(BlendFile.DnaField, BlendFile.DnaField)> listFields) { + normalFields = new(); //Fields that are not lists nor lengths of lists + listFields = new(); //Fields that are lists, and their corresponding length fields + //Cast to array the fields to avoid multiple enumerations + var dnaFields = fields as BlendFile.DnaField[] ?? fields.ToArray(); + foreach (var field in dnaFields) { + if (ListMarkerStr.Any(s => field.Name.Contains(s))) { + Log($"Found list field {field.Name}"); + Log($"Searching for list length field"); + var listLengthField = dnaFields.FirstOrDefault(f => + f.Name.Contains(field.Name) && ListLenghtStr.Any(s => f.Name.Contains(s))); + + if (listLengthField == null) + Log($"No list length field found for {field.Name}"); + else { + Log($"Found list length field {listLengthField.Name}"); + listFields.Add((field, listLengthField)); + + //Remove the list length field from the normal fields (if present) + if(normalFields.Remove(listLengthField)) + Log($"Removed list length field {listLengthField.Name}"); + } + continue; + } + + //Skip fields that are recognized as listLengths + if (listFields.Select(f => f.Item2).Contains(field)) { + Log($"Skipping known list length field {field.Name}"); + continue; + } + + Log($"Adding normal field {field.Name}"); + normalFields.Add(field); + } + } + + /// + /// Generates the following attribute types DNAAttribute, DNAFieldAttribute, DNAClassAttribute, DNAListAttribute + /// + /// array containing the generated attribute types + /// This internally uses a single instance of and sequentially generates the various attributes. private static CodeTypeDeclaration[] GenerateTypeDeclarations() { var attributeBuilder = new AttributeBuilder(); @@ -190,6 +256,7 @@ namespace CodeGenerator { return typeDeclarations; } + //TODO: use AttributeBuilder inside here private static CodeAttributeDeclaration GenerateDnaFieldAttribute(int index, BlendFile.DnaField field, BlendFile.Dna1Body body, int offset, out int size) { string t; @@ -236,7 +303,7 @@ namespace CodeGenerator { }); return cad; } - + private static CodeMemberField CreateMemberField(BlendFile.DnaField field) { Type t = Type.GetType(field.Type.ParseFType()); CodeMemberField cmf;