public static void Main() { var referencedByDict = new Dictionary <Type, List <Type> >(); var referencesDict = new Dictionary <Type, List <Type> >(); var structureRefTypes = new Dictionary <Type, StructureReferenceType>(); var unsortedTypes = Assembly.GetExecutingAssembly().GetTypes() .Where(type => type.Namespace == "UpdateFieldCodeGenerator.Structures"); foreach (var type in unsortedTypes) { structureRefTypes[type] = StructureReferenceType.Root; } foreach (var type in unsortedTypes) { var allFields = type.GetFields(BindingFlags.Static | BindingFlags.Public) .Where(field => typeof(UpdateField).IsAssignableFrom(field.FieldType)) .Select(field => ResolveField(field).Field) .OrderBy(field => field.Order) .Select(field => GetFieldElementType(field.Type, StructureReferenceType.Embedded)) .Where(fieldType => fieldType.Item1.Namespace == "UpdateFieldCodeGenerator.Structures"); foreach (var(fieldType, refType) in allFields) { var reference = referencesDict.ComputeIfAbsent(type, k => new List <Type>()); if (!reference.Contains(fieldType)) { reference.Add(fieldType); } referencedByDict.ComputeIfAbsent(fieldType, k => new List <Type>()).Add(type); structureRefTypes[fieldType] = refType; } } foreach (var referencedBy in referencedByDict) { referencedBy.Value.Sort((a, b) => GetObjectType(a).CompareTo(GetObjectType(b))); } var typeList = structureRefTypes.Where(kvp => kvp.Value == StructureReferenceType.Root) .Select(kvp => kvp.Key) .OrderBy(type => GetObjectType(type)) .SelectMany(type => (referencesDict.ContainsKey(type) ? referencesDict[type] : Enumerable.Empty <Type>()).Concat(Enumerable.Repeat(type, 1))) .Distinct(); using (var handlers = new UpdateFieldHandlers()) { handlers.BeforeStructures(); foreach (var dataType in typeList) { var objectType = GetObjectType(referencedByDict.ContainsKey(dataType) ? referencedByDict[dataType].First() : dataType); WriteCreate(dataType, objectType, handlers); WriteUpdate(dataType, objectType, handlers); } handlers.AfterStructures(); } }
private static void WriteUpdate(Type dataType, ObjectType objectType, UpdateFieldHandlers fieldHandler) { // Update - if the value is a complex structure, it gets its own bits for each field // -- dynamic only if sizeof(struct) > 32 // -- arrays always // if next array field is same size, merge it into previous loop // Order // * bools (as bits, not part of masks) // * blz::vectors (CGItemData::m_modifiers) // * JamDynamicField.Count // * JamDynamicField[].Count (CGActivePlayerData::m_research is a blz::array<JamDynamicField, 1>) // * JamDynamicField[].Values (separate loop from count) // * JamDynamicField.Values // * Values // * Arrays var allFields = dataType.GetFields(BindingFlags.Static | BindingFlags.Public) .Where(field => typeof(UpdateField).IsAssignableFrom(field.FieldType)) .Select(field => ResolveField(field)) .GroupBy(field => GetUpdateTypeOrder(field.Field)) .Select(group => (group.Key, group.OrderBy(field => field.Field.Order))) .ToDictionary(thing => thing.Key, thing => thing.Item2); var hasChangesMask = dataType.GetCustomAttribute <HasChangesMaskAttribute>(); fieldHandler.OnStructureBegin(dataType, objectType, false, hasChangesMask != null); IOrderedEnumerable <(UpdateField Field, string Name)> fieldGroup; if (allFields.TryGetValue(UpdateTypeOrder.Bits, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } if (allFields.TryGetValue(UpdateTypeOrder.BlzVector, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } fieldHandler.FinishControlBlocks(); fieldHandler.FinishBitPack(); } if (allFields.TryGetValue(UpdateTypeOrder.JamDynamicField, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnDynamicFieldSizeUpdate(Name, Field); } fieldHandler.FinishControlBlocks(); } if (allFields.TryGetValue(UpdateTypeOrder.JamDynamicFieldArray, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnDynamicFieldSizeUpdate(Name, Field); } fieldHandler.FinishControlBlocks(); } if (allFields.TryGetValue(UpdateTypeOrder.JamDynamicFieldArray, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } if (hasChangesMask != null || allFields.ContainsKey(UpdateTypeOrder.Bits) || allFields.ContainsKey(UpdateTypeOrder.JamDynamicField) || allFields.ContainsKey(UpdateTypeOrder.JamDynamicFieldArray)) { fieldHandler.FinishControlBlocks(); fieldHandler.FinishBitPack(); } if (allFields.TryGetValue(UpdateTypeOrder.JamDynamicField, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup.Where(field => !StructureHasBitFields(field.Field.Type.GenericTypeArguments[0]))) { fieldHandler.OnField(Name, Field); } foreach (var(Field, Name) in fieldGroup.Where(field => StructureHasBitFields(field.Field.Type.GenericTypeArguments[0]))) { fieldHandler.OnField(Name, Field); } } if (allFields.TryGetValue(UpdateTypeOrder.Default, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } if (allFields.TryGetValue(UpdateTypeOrder.Optional, out fieldGroup)) { fieldHandler.FinishControlBlocks(); fieldHandler.FinishBitPack(); foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnOptionalFieldInitUpdate(Name, Field); } } if (allFields.TryGetValue(UpdateTypeOrder.Optional, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } if (allFields.TryGetValue(UpdateTypeOrder.Array, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } fieldHandler.OnStructureEnd(StructureHasBitFields(dataType), hasChangesMask != null && hasChangesMask.ForceMaskMask); }
public static void Main() { var referencedByDict = new Dictionary <Type, List <Type> >(); var referencesDict = new Dictionary <Type, List <Type> >(); var structureRefTypes = new Dictionary <Type, StructureReferenceType>(); var unsortedTypes = Assembly.GetExecutingAssembly().GetTypes() .Where(type => type.Namespace == "UpdateFieldCodeGenerator.Structures") .ToList(); foreach (var type in unsortedTypes) { structureRefTypes[type] = StructureReferenceType.Root; } foreach (var type in unsortedTypes) { var allFields = type.GetFields(BindingFlags.Static | BindingFlags.Public) .Where(field => typeof(UpdateField).IsAssignableFrom(field.FieldType)) .Select(field => ResolveField(field).Field) .OrderBy(field => field.Order) .Select(field => GetFieldElementType(field.Type, StructureReferenceType.Embedded)) .Where(fieldType => fieldType.Item1.Namespace == "UpdateFieldCodeGenerator.Structures"); foreach (var(fieldType, refType) in allFields) { var reference = referencesDict.ComputeIfAbsent(type, k => new List <Type>()); if (!reference.Contains(fieldType)) { reference.Add(fieldType); } referencedByDict.ComputeIfAbsent(fieldType, k => new List <Type>()).Add(type); structureRefTypes[fieldType] = refType; } } var typeList = structureRefTypes.Where(kvp => kvp.Value == StructureReferenceType.Root) .Select(kvp => kvp.Key) .OrderBy(type => GetObjectType(type)) .ToList(); foreach (var type in typeList) { unsortedTypes.Remove(type); } // add all missed types while (unsortedTypes.Count > 0) { for (var i = 0; i < typeList.Count; ++i) { if (referencesDict.TryGetValue(typeList[i], out var referencedTypes)) { var insertIndex = i; foreach (var referencedType in referencedTypes) { var unsortedTypeIndex = unsortedTypes.IndexOf(referencedType); if (unsortedTypeIndex == -1) { continue; } typeList.Insert(insertIndex, referencedType); unsortedTypes.RemoveAt(unsortedTypeIndex); i = 0; break; } } } } if (unsortedTypes.Count > 0) { typeList.AddRange(unsortedTypes); } using (var handlers = new UpdateFieldHandlers()) { handlers.BeforeStructures(); foreach (var dataType in typeList) { var objectType = structureRefTypes[dataType] == StructureReferenceType.Root ? GetObjectType(dataType) : GetCommonObjectType(GetObjectTypeReferenceRoots(dataType, referencedByDict).Select(t => GetObjectType(t)).ToList()); WriteCreate(dataType, objectType, handlers); WriteUpdate(dataType, objectType, handlers); } handlers.AfterStructures(); } }
private static void WriteCreate(Type dataType, ObjectType objectType, UpdateFieldHandlers fieldHandler) { // Create // * In declaration order // * JamDynamicField[].Count (CGActivePlayerData::m_research is a blz::array<JamDynamicField, 1>) // * JamDynamicField[].Values (separate loop from count) // * JamDynamicField.Values // * Bits // * JamDynamicField.Values that have bits in them var allFields = dataType.GetFields(BindingFlags.Static | BindingFlags.Public) .Where(field => typeof(UpdateField).IsAssignableFrom(field.FieldType)) .Select(field => ResolveField(field)) .GroupBy(field => GetCreateTypeOrder(field.Field)) .Select(group => (group.Key, group.OrderBy(field => field.Field.Order))) .ToDictionary(thing => thing.Key, thing => thing.Item2); fieldHandler.OnStructureBegin(dataType, objectType, true, dataType.GetCustomAttribute <HasChangesMaskAttribute>() != null); IOrderedEnumerable <(UpdateField Field, string Name)> fieldGroup; var firstBunchOfFields = Enumerable.Empty <(UpdateField Field, string Name)>(); if (allFields.TryGetValue(CreateTypeOrder.Default, out fieldGroup)) { firstBunchOfFields = firstBunchOfFields.Concat(fieldGroup); } if (allFields.TryGetValue(CreateTypeOrder.JamDynamicField, out fieldGroup)) { firstBunchOfFields = firstBunchOfFields.Concat(fieldGroup); } if (allFields.TryGetValue(CreateTypeOrder.JamDynamicFieldArray, out fieldGroup)) { firstBunchOfFields = firstBunchOfFields.Concat(fieldGroup); } if (allFields.TryGetValue(CreateTypeOrder.JamDynamicFieldWithBits, out fieldGroup)) { firstBunchOfFields = firstBunchOfFields.Concat(fieldGroup); } foreach (var(Field, Name) in firstBunchOfFields.OrderBy(field => field.Field.Order)) { if (typeof(DynamicUpdateField).IsAssignableFrom(Field.Type) || (Field.Type.IsArray && typeof(DynamicUpdateField).IsAssignableFrom(Field.Type.GetElementType()))) { fieldHandler.OnDynamicFieldSizeCreate(Name, Field); } else { fieldHandler.OnField(Name, Field); } } if (allFields.TryGetValue(CreateTypeOrder.JamDynamicFieldArray, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } if (allFields.TryGetValue(CreateTypeOrder.JamDynamicField, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } if (allFields.TryGetValue(CreateTypeOrder.DefaultWithBits, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } if (allFields.TryGetValue(CreateTypeOrder.ArrayWithBits, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } if ((allFields.ContainsKey(CreateTypeOrder.DefaultWithBits) || allFields.ContainsKey(CreateTypeOrder.ArrayWithBits)) && (allFields.ContainsKey(CreateTypeOrder.Bits) || allFields.ContainsKey(CreateTypeOrder.Optional))) { fieldHandler.FinishControlBlocks(); fieldHandler.FinishBitPack(); } if (allFields.TryGetValue(CreateTypeOrder.Bits, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } if (allFields.TryGetValue(CreateTypeOrder.Optional, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnOptionalFieldInitCreate(Name, Field); } } if (allFields.TryGetValue(CreateTypeOrder.Optional, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } if (allFields.TryGetValue(CreateTypeOrder.JamDynamicFieldWithBits, out fieldGroup)) { foreach (var(Field, Name) in fieldGroup) { fieldHandler.OnField(Name, Field); } } fieldHandler.OnStructureEnd(StructureHasBitFields(dataType), false); }