Ejemplo n.º 1
0
        public override async Task LoadWrapup(ObjectGeneration obj)
        {
            try
            {
                await Task.WhenAll(
                    obj.IterateFields(expandSets : SetMarkerType.ExpandSets.TrueAndInclude, nonIntegrated : true)
                    .Select(async(field) =>
                {
                    await SetContainerSubTriggers(obj, field);
                }));

                foreach (var field in obj.IterateFields(expandSets: SetMarkerType.ExpandSets.TrueAndInclude, nonIntegrated: true))
                {
                    await SetRecordTrigger(obj, field, field.GetFieldData());
                }
                await SetObjectTrigger(obj);

                obj.GetObjectData().WiringComplete.Complete();
                await base.LoadWrapup(obj);
            }
            catch (Exception ex)
            {
                obj.GetObjectData().WiringComplete.SetException(ex);
                throw;
            }
        }
Ejemplo n.º 2
0
 public override async Task PostLoad(ObjectGeneration obj)
 {
     obj.GetObjectData().MajorRecordFlags = obj.Node.GetAttribute("majorFlag", false);
     if (obj.GetObjectData().MajorRecordFlags &&
         obj.GetObjectType() != ObjectType.Record)
     {
         throw new ArgumentException();
     }
 }
        public override async Task PreLoad(ObjectGeneration obj)
        {
            var objData = obj.GetObjectData();

            objData.BaseRecordTypeConverter = GetConverter(obj.Node.Element(XName.Get("BaseRecordTypeOverrides", LoquiGenerator.Namespace)));

            var gameModeOverrides = obj.Node.Element(XName.Get("GameModeOverride", LoquiGenerator.Namespace));

            if (gameModeOverrides != null)
            {
                var mode = gameModeOverrides.GetAttribute <GameRelease>("release", throwException: true);
                if (objData.GameReleaseConverters == null)
                {
                    objData.GameReleaseConverters = new Dictionary <GameRelease, RecordTypeConverter>();
                }
                objData.GameReleaseConverters[mode] = GetConverter(gameModeOverrides);
            }

            var versionModeOverrides = obj.Node.Element(XName.Get("VersionOverride", LoquiGenerator.Namespace));

            if (versionModeOverrides != null)
            {
                var version = versionModeOverrides.GetAttribute <byte>("version", throwException: true);
                if (objData.VersionConverters == null)
                {
                    objData.VersionConverters = new Dictionary <byte, RecordTypeConverter>();
                }
                objData.VersionConverters[version] = GetConverter(versionModeOverrides);
            }
            await base.PreLoad(obj);
        }
Ejemplo n.º 4
0
        public override Task GenerateInRegistration(ObjectGeneration obj, FileGeneration fg)
        {
            var objData = obj.GetObjectData();

            GenerateConverterMember(fg, obj.BaseClass, objData.BaseRecordTypeConverter, "Base");
            foreach (var field in obj.IterateFields(expandSets: SetMarkerType.ExpandSets.FalseAndInclude, nonIntegrated: true))
            {
                LoquiType loquiType = field as LoquiType;
                if (loquiType == null)
                {
                    switch (field)
                    {
                    case WrapperType wrapper:
                        loquiType = wrapper.SubTypeGeneration as LoquiType;
                        if (loquiType != null)
                        {
                            break;
                        }
                        continue;

                    default:
                        continue;
                    }
                }
                var fieldData = loquiType.GetFieldData();
                GenerateConverterMember(fg, loquiType.TargetObjectGeneration, fieldData.RecordTypeConverter, field.Name);
            }
            return(base.GenerateInRegistration(obj, fg));
        }
Ejemplo n.º 5
0
        private void GenerateCustomBinaryEndCreatePartial(ObjectGeneration obj, FileGeneration fg)
        {
            var data = obj.GetObjectData();

            if (data.CustomBinaryEnd == CustomEnd.Off)
            {
                return;
            }
            if (data.CustomBinaryEnd == CustomEnd.Normal)
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"public static partial void CustomBinaryEndImport"))
                {
                    args.Add($"{ReaderClass} {ReaderMemberName}");
                    args.Add($"{obj.Interface(getter: false, internalInterface: true)} obj");
                }
                using (var args = new FunctionWrapper(fg,
                                                      $"public static void CustomBinaryEndImportPublic"))
                {
                    args.Add($"{ReaderClass} {ReaderMemberName}");
                    args.Add($"{obj.Interface(getter: false, internalInterface: true)} obj");
                }
                using (new BraceWrapper(fg))
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"CustomBinaryEndImport"))
                    {
                        args.AddPassArg(ReaderMemberName);
                        args.AddPassArg($"obj");
                    }
                }
            }
        }
Ejemplo n.º 6
0
        public override async Task PreLoad(ObjectGeneration obj)
        {
            var recTypeOverrides = obj.Node.Element(XName.Get("BaseRecordTypeOverrides", LoquiGenerator.Namespace));

            if (recTypeOverrides == null)
            {
                return;
            }
            var recConversions = recTypeOverrides.Elements(XName.Get("Mapping", LoquiGenerator.Namespace));

            if (recConversions == null || !recConversions.Any())
            {
                return;
            }
            var objData = obj.GetObjectData();

            objData.BaseRecordTypeConverter = new RecordTypeConverter(
                recConversions.Select((n) =>
            {
                return(new KeyValuePair <RecordType, RecordType>(
                           new RecordType(n.GetAttribute("From")),
                           new RecordType(n.GetAttribute("To"))));
            }).ToArray());
            await base.PreLoad(obj);
        }
Ejemplo n.º 7
0
        public override async Task GenerateInCommon(ObjectGeneration obj, FileGeneration fg, MaskTypeSet maskTypes)
        {
            if (!await obj.IsMajorRecord())
            {
                return;
            }
            if (!maskTypes.Applicable(LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal))
            {
                return;
            }
            //ToDo
            // Modify to getter interface after copy is refactored
            fg.AppendLine($"partial void PostDuplicate({obj.Name} obj, {obj.ObjectName} rhs, Func<FormKey> getNextFormKey, IList<({nameof(IMajorRecordCommon)} Record, FormKey OriginalFormKey)>? duplicatedRecords);");
            fg.AppendLine();

            fg.AppendLine($"public{obj.FunctionOverride()}{nameof(IMajorRecordCommon)} Duplicate({nameof(IMajorRecordCommonGetter)} item, Func<FormKey> getNextFormKey, IList<({nameof(IMajorRecordCommon)} Record, FormKey OriginalFormKey)>? duplicatedRecords)");
            using (new BraceWrapper(fg))
            {
                if (obj.Abstract)
                {
                    fg.AppendLine($"throw new {nameof(NotImplementedException)}();");
                }
                else
                {
                    fg.AppendLine($"var ret = new {obj.Name}(getNextFormKey(){((obj.GetObjectData().GameCategory?.HasFormVersion() ?? false) ? $", (({obj.Interface(getter: true)})item).FormVersion" : string.Empty)});");
                    //ToDo
                    // Modify to getter interface after copy is refactored
                    fg.AppendLine($"ret.DeepCopyIn(({obj.ObjectName})item);");
                    fg.AppendLine("duplicatedRecords?.Add((ret, item.FormKey));");
                    fg.AppendLine($"PostDuplicate(ret, ({obj.ObjectName})item, getNextFormKey, duplicatedRecords);");
                    fg.AppendLine("return ret;");
                }
            }
            fg.AppendLine();
        }
Ejemplo n.º 8
0
        public override async Task PostLoad(ObjectGeneration obj)
        {
            try
            {
                foreach (var field in obj.IterateFields(expandSets: SetMarkerType.ExpandSets.TrueAndInclude, nonIntegrated: true))
                {
                    MutagenFieldData subData;
                    switch (field)
                    {
                    case WrapperType wrapper:
                        subData = wrapper.SubTypeGeneration.GetFieldData();
                        break;

                    case DictType_KeyedValue dict:
                        subData = dict.ValueTypeGen.GetFieldData();
                        break;

                    default:
                        continue;
                    }
                    subData.Parent = field;
                }
            }
            catch (Exception ex)
            {
                obj.GetObjectData().WiringComplete.SetException(ex);
                throw;
            }
        }
Ejemplo n.º 9
0
 protected override async Task GenerateNewSnippet(ObjectGeneration obj, FileGeneration fg)
 {
     if (await obj.IsMajorRecord())
     {
         fg.AppendLine($"var ret = new {obj.Name}();");
     }
     else
     {
         if (obj.TryGetCustomRecordTypeTriggers(out var customLogicTriggers))
         {
             using (var args = new ArgsWrapper(fg,
                                               $"var nextRecord = HeaderTranslation.GetNext{(obj.GetObjectType() == ObjectType.Subrecord ? "Subrecord" : "Record")}Type"))
             {
                 args.Add($"reader: {ReaderMemberName}.Reader");
                 args.Add("contentLength: out var customLen");
             }
             fg.AppendLine("nextRecord = recordTypeConverter.ConvertToCustom(nextRecord);");
             fg.AppendLine("switch (nextRecord.TypeInt)");
             using (new BraceWrapper(fg))
             {
                 foreach (var item in customLogicTriggers)
                 {
                     fg.AppendLine($"case {item.TypeInt}: // {item.Type}");
                 }
                 using (new DepthWrapper(fg))
                 {
                     using (var args = new ArgsWrapper(fg,
                                                       "return CustomRecordTypeTrigger"))
                     {
                         args.Add($"{ReaderMemberName}: {ReaderMemberName}.SpawnWithLength(customLen + {ReaderMemberName}.{nameof(MutagenFrame.MetaData)}.{nameof(ParsingBundle.Constants)}.{nameof(GameConstants.SubConstants)}.{nameof(GameConstants.SubConstants.HeaderLength)})");
                         args.Add("recordType: nextRecord");
                         args.AddPassArg("recordTypeConverter");
                     }
                 }
                 fg.AppendLine("default:");
                 using (new DepthWrapper(fg))
                 {
                     fg.AppendLine("break;");
                 }
             }
         }
         using (var args = new ArgsWrapper(fg,
                                           $"var ret = new {obj.Name}{obj.GetGenericTypes(MaskType.Normal)}"))
         {
             if (obj.GetObjectType() == ObjectType.Mod)
             {
                 args.AddPassArg("modKey");
             }
             if (obj.GetObjectData().GameReleaseOptions != null)
             {
                 args.AddPassArg("release");
             }
         }
         if (obj.GetObjectType() == ObjectType.Mod)
         {
             fg.AppendLine($"{ReaderMemberName}.MetaData.ModKey = modKey;");
         }
     }
 }
Ejemplo n.º 10
0
        public static bool IsVariableLengthStruct(this ObjectGeneration objGen)
        {
            var objData = objGen.GetObjectData();

            return(objGen.GetObjectType() == ObjectType.Subrecord &&
                   objData.TriggeringSource == null &&
                   objData.HasVersioning());
        }
Ejemplo n.º 11
0
 public override async Task <bool> AsyncImport(ObjectGeneration obj)
 {
     if (obj.GetObjectData().CustomBinaryEnd == CustomEnd.Async)
     {
         return(true);
     }
     return(await base.AsyncImport(obj));
 }
Ejemplo n.º 12
0
        public override Task PreLoad(ObjectGeneration obj)
        {
            var data   = obj.GetObjectData();
            var record = obj.Node.GetAttribute("recordType");

            data.FailOnUnknown   = obj.Node.GetAttribute <bool>("failOnUnknownType", defaultVal: false);
            data.CustomBinary    = obj.Node.GetAttribute <bool>("customBinary", defaultVal: false);
            data.UsesStringFiles = obj.Node.GetAttribute <bool>("usesStringFiles", defaultVal: true);
            data.CustomBinaryEnd = obj.Node.GetAttribute <CustomEnd>("customBinaryEnd", defaultVal: CustomEnd.Off);
            data.BinaryOverlay   = obj.Node.GetAttribute <BinaryGenerationType>("binaryOverlay", defaultVal: BinaryGenerationType.Normal);

            var objType = obj.Node.GetAttribute(Mutagen.Bethesda.Generation.Constants.ObjectType);

            if (!Enum.TryParse <ObjectType>(objType, out var objTypeEnum))
            {
                throw new ArgumentException("Must specify object type.");
            }
            data.ObjectType = objTypeEnum;

            if (record != null)
            {
                data.RecordType = new RecordType(record);
            }
            else if (objTypeEnum == ObjectType.Group)
            {
                data.RecordType = Mutagen.Bethesda.Internals.Constants.Group;
            }

            foreach (var elem in obj.Node.Elements(XName.Get("CustomRecordTypeTrigger", LoquiGenerator.Namespace)))
            {
                obj.GetObjectData().CustomRecordTypeTriggers.Add(new RecordType(elem.Value));
            }

            if (obj.Node.TryGetAttribute("markerType", out var markerType))
            {
                var markerTypeRec = new RecordType(markerType.Value);
                data.MarkerType = markerTypeRec;
            }
            if (obj.Node.TryGetAttribute("endMarkerType", out var endMarker))
            {
                var markerTypeRec = new RecordType(endMarker.Value);
                data.EndMarkerType = markerTypeRec;
            }
            return(base.PreLoad(obj));
        }
Ejemplo n.º 13
0
        public static async Task <TryGet <IEnumerable <RecordType> > > TryGetTriggeringRecordTypes(this ObjectGeneration objGen)
        {
            await objGen.LoadingCompleteTask.Task;
            var data = objGen.GetObjectData();

            return(TryGet <IEnumerable <RecordType> > .Create(
                       successful : data.TriggeringRecordTypes.Any(),
                       val : data.TriggeringRecordTypes));
        }
Ejemplo n.º 14
0
        public static ObjectType GetObjectType(this ObjectGeneration objGen)
        {
            var objType = objGen.GetObjectData().ObjectType;

            if (objType.HasValue)
            {
                return(objType.Value);
            }
            return(ObjectType.Subrecord);
        }
Ejemplo n.º 15
0
        public static async Task <bool> IsSingleTriggerSource(this ObjectGeneration objGen)
        {
            var enumer = await objGen.GetObjectData().GenerationTypes;

            if (!enumer.SelectMany((e) => e.Key).Distinct().Any())
            {
                return(false);
            }
            return(!enumer.SelectMany((e) => e.Key).Distinct().CountGreaterThan(1));
        }
Ejemplo n.º 16
0
        public static ObjectType GetObjectType(this ObjectGeneration objGen)
        {
            var objType = objGen.GetObjectData().ObjectType;

            if (objType.HasValue)
            {
                return(objType.Value);
            }
            throw new ArgumentException($"Object {objGen.Name} did not have object type defined.");
        }
Ejemplo n.º 17
0
        public override async IAsyncEnumerable <string> RequiredUsingStatements(ObjectGeneration obj)
        {
            if (obj.GetObjectData().ObjectType == ObjectType.Mod)
            {
                yield return("System.Collections.Concurrent");

                yield return("System.Threading.Tasks");

                yield return("System.IO");
            }
        }
Ejemplo n.º 18
0
        public static bool TryGetMarkerType(this ObjectGeneration objGen, out RecordType recType)
        {
            var data = objGen.GetObjectData();

            if (data.MarkerType == null)
            {
                recType = default;
                return(false);
            }
            recType = data.MarkerType.Value;
            return(true);
        }
Ejemplo n.º 19
0
        public override async Task GenerateInRegistration(ObjectGeneration obj, FileGeneration fg)
        {
            HashSet <RecordType> trigRecordTypes = new HashSet <RecordType>();
            var data = obj.GetObjectData();

            trigRecordTypes.Add((await data.GenerationTypes).SelectMany((kv) => kv.Key));
            var count = trigRecordTypes.Count();

            if (obj.Name.EndsWith("MajorRecord"))
            {
                return;
            }
            if (count == 1)
            {
                fg.AppendLine($"public static readonly {nameof(RecordType)} {Mutagen.Bethesda.Internals.Constants.TriggeringRecordTypeMember} = {obj.RecordTypeHeaderName(trigRecordTypes.First())};");
            }
            else if (count > 1)
            {
                fg.AppendLine($"public static ICollectionGetter<RecordType> TriggeringRecordTypes => _TriggeringRecordTypes.Value;");
                fg.AppendLine($"private static readonly Lazy<ICollectionGetter<RecordType>> _TriggeringRecordTypes = new Lazy<ICollectionGetter<RecordType>>(() =>");
                using (new BraceWrapper(fg)
                {
                    AppendSemicolon = true, AppendParenthesis = true
                })
                {
                    fg.AppendLine($"return new CollectionGetterWrapper<RecordType>(");
                    using (new DepthWrapper(fg))
                    {
                        fg.AppendLine("new HashSet<RecordType>(");
                        using (new DepthWrapper(fg))
                        {
                            fg.AppendLine($"new RecordType[]");
                            using (new BraceWrapper(fg)
                            {
                                AppendParenthesis = true
                            })
                            {
                                using (var comma = new CommaWrapper(fg))
                                {
                                    foreach (var trigger in trigRecordTypes)
                                    {
                                        comma.Add($"{obj.RecordTypeHeaderName(trigger)}");
                                    }
                                }
                            }
                        }
                    }
                    fg.AppendLine(");");
                }
            }
            await base.GenerateInRegistration(obj, fg);
        }
Ejemplo n.º 20
0
 public override async Task GenerateInClass(ObjectGeneration obj, FileGeneration fg)
 {
     if (!obj.GetObjectData().MajorRecordFlags)
     {
         return;
     }
     fg.AppendLine("public MajorFlag MajorFlags");
     using (new BraceWrapper(fg))
     {
         fg.AppendLine("get => (MajorFlag)this.MajorRecordFlagsRaw;");
         fg.AppendLine("set => this.MajorRecordFlagsRaw = (int)value;");
     }
 }
Ejemplo n.º 21
0
        public static bool TryGetCustomRecordTypeTriggers(this ObjectGeneration objGen, out IEnumerable <RecordType> recTypes)
        {
            var data = objGen.GetObjectData();

            if (data.CustomRecordTypeTriggers == null ||
                data.CustomRecordTypeTriggers.Count == 0)
            {
                recTypes = default;
                return(false);
            }
            recTypes = data.CustomRecordTypeTriggers;
            return(true);
        }
Ejemplo n.º 22
0
        protected string GetRecordTypeString(ObjectGeneration obj, Accessor gameReleaseAccessor, Accessor versionAccessor)
        {
            var data = obj.GetObjectData();

            if (data.GameReleaseConverters != null)
            {
                return($"recordTypeConverter.Combine({obj.RegistrationName}.Get({gameReleaseAccessor})).ConvertToCustom({obj.RecordTypeHeaderName(obj.GetRecordType())})");
            }
            if (data.VersionConverters != null)
            {
                return($"recordTypeConverter.Combine({obj.RegistrationName}.Get({versionAccessor})).ConvertToCustom({obj.RecordTypeHeaderName(obj.GetRecordType())})");
            }
            return($"recordTypeConverter.ConvertToCustom({obj.RecordTypeHeaderName(obj.GetRecordType())})");
        }
Ejemplo n.º 23
0
 public override async Task GenerateInInterface(ObjectGeneration obj, FileGeneration fg, bool internalInterface, bool getter)
 {
     if (!obj.GetObjectData().MajorRecordFlags || internalInterface)
     {
         return;
     }
     if (getter)
     {
         fg.AppendLine($"{obj.ObjectName}.MajorFlag MajorFlags {{ get; }}");
     }
     else
     {
         fg.AppendLine($"new {obj.ObjectName}.MajorFlag MajorFlags {{ get; set; }}");
     }
 }
Ejemplo n.º 24
0
        public void GenerateModGameCategoryRegistration(ObjectGeneration obj, FileGeneration fg)
        {
            using (var ns = new NamespaceWrapper(fg, $"Mutagen.Bethesda.{obj.GetObjectData().GameCategory}.Internals", fileScoped: false))
            {
                using (var c = new ClassWrapper(fg, $"{obj.Name}_Registration"))
                {
                    c.Partial = true;
                    c.Interfaces.Add(nameof(IModRegistration));
                }

                using (new BraceWrapper(fg))
                {
                    fg.AppendLine($"public {nameof(GameCategory)} GameCategory => {nameof(GameCategory)}.{obj.GetObjectData().GameCategory};");
                }
                fg.AppendLine();
            }
        }
Ejemplo n.º 25
0
        public override async IAsyncEnumerable <string> RequiredUsingStatements(ObjectGeneration obj)
        {
            if (obj.GetObjectData().ObjectType == ObjectType.Mod)
            {
                yield return("System.Collections.Concurrent");

                yield return("System.Threading.Tasks");

                yield return("System.IO");

                yield return("System.IO.Abstractions");

                yield return("Mutagen.Bethesda.Plugins.Masters");

                yield return("Mutagen.Bethesda.Strings.DI");
            }
        }
Ejemplo n.º 26
0
        public override async Task PreLoad(ObjectGeneration obj)
        {
            if (obj.GetObjectType() != ObjectType.Mod)
            {
                return;
            }
            var elems = obj.Node.Elements(XName.Get(GameReleaseOptions, LoquiGenerator.Namespace));

            if (!elems.Any())
            {
                return;
            }
            var objData = obj.GetObjectData();

            objData.GameReleaseOptions = elems.Select(el => Enum.Parse <GameRelease>(el.Value)).ToHashSet();
            obj.Interfaces.Add(LoquiInterfaceDefinitionType.IGetter, $"IMajorRecordContextEnumerable<{obj.Interface(getter: false, internalInterface: true)}>");
        }
Ejemplo n.º 27
0
        public override async Task GenerateInInterface(ObjectGeneration obj, FileGeneration fg, bool internalInterface, bool getter)
        {
            await base.GenerateInInterface(obj, fg, internalInterface, getter);

            if (obj.GetObjectType() != ObjectType.Mod)
            {
                return;
            }
            if (!getter)
            {
                return;
            }
            if (obj.GetObjectData().GameReleaseOptions == null)
            {
                return;
            }
            fg.AppendLine($"{ReleaseEnumName(obj)} {ReleaseEnumName(obj)} {{ get; }}");
        }
Ejemplo n.º 28
0
        public override async Task LoadWrapup(ObjectGeneration obj)
        {
            await base.LoadWrapup(obj);

            foreach (var field in obj.IterateFields(expandSets: SetMarkerType.ExpandSets.FalseAndInclude))
            {
                if (!(field is DataType dataType))
                {
                    continue;
                }
                XElement elem = new XElement("Enum");
                elem.Add(new XAttribute(Loqui.Generation.Constants.NAME, dataType.StateName));
                elem.Add(new XAttribute(Loqui.Generation.Constants.ENUM_NAME, $"{obj.ObjectName}.{dataType.EnumName}"));
                elem.Add(new XAttribute("binary", nameof(BinaryGenerationType.NoGeneration)));
                elem.Add(new XAttribute(Loqui.Generation.Constants.NULLABLE, "false"));
                await obj.LoadField(elem, requireName : true, add : true);
            }
            obj.GetObjectData().DataTypeModuleComplete.SetResult();
        }
Ejemplo n.º 29
0
        public override async Task LoadWrapup(ObjectGeneration obj)
        {
            var objData = obj.GetObjectData();
            await Task.WhenAll(
                objData.WiringComplete.Task,
                objData.DataTypeModuleComplete.Task);

            bool triggerEncountered = false;

            foreach (var field in obj.IterateFields(
                         nonIntegrated: true,
                         expandSets: SetMarkerType.ExpandSets.False))
            {
                if (field is SetMarkerType)
                {
                    continue;
                }
                if (field.Derivative || !field.IntegrateField)
                {
                    continue;
                }
                var data = field.GetFieldData();
                if (data.Binary == BinaryGenerationType.NoGeneration)
                {
                    continue;
                }
                if (data.HasTrigger)
                {
                    triggerEncountered = true;
                }
                else if (triggerEncountered)
                {
                    throw new ArgumentException($"{obj.Name} cannot have an embedded field without a record type after ones with record types have been defined: {field.Name}");
                }
            }

            await base.LoadWrapup(obj);
        }
Ejemplo n.º 30
0
        private void GenerateWriteParallel(ObjectGeneration obj, FileGeneration fg)
        {
            LoquiType groupInstance     = null;
            LoquiType listGroupInstance = null;
            var       objData           = obj.GetObjectData();

            fg.AppendLine("const int CutCount = 100;");
            using (var args = new FunctionWrapper(fg,
                                                  "public static void WriteParallel"))
            {
                args.Add($"{obj.Interface(getter: true, internalInterface: false)} item");
                args.Add($"Stream stream");
                args.Add($"{nameof(BinaryWriteParameters)} param");
                args.Add($"ModKey modKey");
            }
            using (new BraceWrapper(fg))
            {
                string gameConstantsStr;
                if (objData.GameReleaseOptions == null)
                {
                    gameConstantsStr = $"{nameof(GameConstants)}.{obj.GetObjectData().GameCategory}";
                }
                else
                {
                    fg.AppendLine($"var gameConstants = {nameof(GameConstants)}.Get(item.{ReleaseEnumName(obj)}.ToGameRelease());");
                    gameConstantsStr = $"gameConstants";
                }
                fg.AppendLine($"var bundle = new {nameof(WritingBundle)}({gameConstantsStr});");
                fg.AppendLine($"var writer = new MutagenWriter(stream, bundle);");
                using (var args = new ArgsWrapper(fg,
                                                  $"{nameof(ModHeaderWriteLogic)}.{nameof(ModHeaderWriteLogic.WriteHeader)}"))
                {
                    args.AddPassArg("param");
                    args.AddPassArg("writer");
                    args.Add("mod: item");
                    args.Add("modHeader: item.ModHeader.DeepCopy()");
                    args.AddPassArg("modKey");
                }

                int groupCount = obj.IterateFields()
                                 .Select(f => f as LoquiType)
                                 .Where(l => l != null)
                                 .Where(l => l.TargetObjectGeneration?.GetObjectData().ObjectType == ObjectType.Group)
                                 .Count();

                fg.AppendLine($"Stream[] outputStreams = new Stream[{groupCount}];");
                fg.AppendLine($"List<Action> toDo = new List<Action>();");
                int i = 0;
                foreach (var field in obj.IterateFields())
                {
                    if (!(field is LoquiType loqui))
                    {
                        continue;
                    }
                    if (loqui.TargetObjectGeneration?.GetObjectData().ObjectType != ObjectType.Group)
                    {
                        continue;
                    }
                    if (loqui.TargetObjectGeneration.Name == "ListGroup")
                    {
                        listGroupInstance = loqui;
                    }
                    else
                    {
                        groupInstance = loqui;
                    }
                    if (loqui.GetGroupTarget().GetObjectData().CustomBinaryEnd == CustomEnd.Off &&
                        loqui.TargetObjectGeneration.Name != "ListGroup")
                    {
                        fg.AppendLine($"toDo.Add(() => WriteGroupParallel(item.{field.Name}, writer.MetaData.MasterReferences!, {i}{(objData.GameReleaseOptions == null ? null : ", gameConstants")}, outputStreams{(objData.UsesStringFiles ? ", param.StringsWriter" : null)}));");
                    }
                    else
                    {
                        fg.AppendLine($"toDo.Add(() => Write{field.Name}Parallel(item.{field.Name}, writer.MetaData.MasterReferences!, {i}{(objData.GameReleaseOptions == null ? null : ", gameConstants")}, outputStreams));");
                    }
                    i++;
                }
                fg.AppendLine("Parallel.Invoke(toDo.ToArray());");
                using (var args = new ArgsWrapper(fg,
                                                  $"{nameof(UtilityTranslation)}.{nameof(UtilityTranslation.CompileStreamsInto)}"))
                {
                    args.Add("outputStreams.NotNull()");
                    args.Add("stream");
                }
            }
            fg.AppendLine();

            if (groupInstance != null)
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"public static void WriteGroupParallel<T>"))
                {
                    args.Add("IGroupGetter<T> group");
                    args.Add($"{nameof(MasterReferenceReader)} masters");
                    args.Add("int targetIndex");
                    if (objData.GameReleaseOptions != null)
                    {
                        args.Add($"{nameof(GameConstants)} gameConstants");
                    }
                    args.Add("Stream[] streamDepositArray");
                    if (objData.UsesStringFiles)
                    {
                        args.Add($"{nameof(StringsWriter)}? stringsWriter");
                    }
                    args.Wheres.AddRange(groupInstance.TargetObjectGeneration.GenerateWhereClauses(LoquiInterfaceType.IGetter, groupInstance.TargetObjectGeneration.Generics));
                }
                using (new BraceWrapper(fg))
                {
                    string gameConstantsStr;
                    if (objData.GameReleaseOptions == null)
                    {
                        gameConstantsStr = $"{nameof(GameConstants)}.{obj.GetObjectData().GameCategory}";
                    }
                    else
                    {
                        gameConstantsStr = "gameConstants";
                    }
                    fg.AppendLine("if (group.RecordCache.Count == 0) return;");
                    fg.AppendLine($"var cuts = group.Cut(CutCount).ToArray();");
                    fg.AppendLine($"Stream[] subStreams = new Stream[cuts.Length + 1];");
                    fg.AppendLine($"byte[] groupBytes = new byte[{gameConstantsStr}.GroupConstants.HeaderLength];");
                    fg.AppendLine($"BinaryPrimitives.WriteInt32LittleEndian(groupBytes.AsSpan(), RecordTypes.GRUP.TypeInt);");
                    fg.AppendLine($"var groupByteStream = new MemoryStream(groupBytes);");
                    fg.AppendLine($"using (var stream = new MutagenWriter(groupByteStream, {gameConstantsStr}, dispose: false))");
                    using (new BraceWrapper(fg))
                    {
                        fg.AppendLine($"stream.Position += 8;");
                        fg.AppendLine($"GroupBinaryWriteTranslation.WriteEmbedded<T>(group, stream);");
                    }
                    fg.AppendLine($"subStreams[0] = groupByteStream;");
                    fg.AppendLine($"Parallel.ForEach(cuts, (cutItems, state, counter) =>");
                    using (new BraceWrapper(fg)
                    {
                        AppendSemicolon = true, AppendParenthesis = true
                    })
                    {
                        fg.AppendLine($"{nameof(MemoryTributary)} trib = new {nameof(MemoryTributary)}();");
                        fg.AppendLine($"var bundle = new {nameof(WritingBundle)}({gameConstantsStr})");
                        using (var prop = new PropertyCtorWrapper(fg))
                        {
                            prop.Add($"{nameof(WritingBundle.MasterReferences)} = masters");
                            if (objData.UsesStringFiles)
                            {
                                prop.Add($"{nameof(WritingBundle.StringsWriter)} = stringsWriter");
                            }
                        }
                        fg.AppendLine($"using (var stream = new MutagenWriter(trib, bundle, dispose: false))");
                        using (new BraceWrapper(fg))
                        {
                            fg.AppendLine($"foreach (var item in cutItems)");
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine($"item.WriteToBinary(stream);");
                            }
                        }
                        fg.AppendLine($"subStreams[(int)counter + 1] = trib;");
                    }
                    fg.AppendLine($"UtilityTranslation.CompileSetGroupLength(subStreams, groupBytes);");
                    fg.AppendLine($"streamDepositArray[targetIndex] = new CompositeReadStream(subStreams, resetPositions: true);");
                }
                fg.AppendLine();
            }
        }