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;");
         }
     }
 }
Exemple #2
0
        public static void GenerateCreatePartialMethods(
            FileGeneration fg,
            ObjectGeneration obj,
            TypeGeneration field,
            bool isAsync,
            bool useReturnValue)
        {
            var fieldData            = field.GetFieldData();
            var returningParseResult = useReturnValue && fieldData.HasTrigger;

            if (!isAsync)
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"public static partial {(returningParseResult ? nameof(ParseResult) : "void")} FillBinary{field.Name}Custom")
                {
                    SemiColon = true
                })
                {
                    args.Add($"{nameof(MutagenFrame)} frame");
                    args.Add($"{obj.Interface(getter: false, internalInterface: true)} item");
                    if (returningParseResult && obj.GetObjectType() == ObjectType.Subrecord)
                    {
                        args.Add($"{nameof(PreviousParse)} lastParsed");
                    }
                }
                fg.AppendLine();
            }
        }
Exemple #3
0
 public override async Task PreLoad(ObjectGeneration obj)
 {
     if (obj.GetObjectType() == ObjectType.Mod)
     {
         mods.Add(obj);
     }
 }
Exemple #4
0
 public static bool HasVersionedFields(this ObjectGeneration objGen)
 {
     if (objGen.GetObjectType() != ObjectType.Record)
     {
         return(false);
     }
     return(objGen.Fields.Any(f => f.GetFieldData().CustomVersion != null));
 }
Exemple #5
0
        public static bool IsVariableLengthStruct(this ObjectGeneration objGen)
        {
            var objData = objGen.GetObjectData();

            return(objGen.GetObjectType() == ObjectType.Subrecord &&
                   objData.TriggeringSource == null &&
                   objData.HasVersioning());
        }
Exemple #6
0
 public override async Task GenerateInClass(ObjectGeneration obj, FileGeneration fg)
 {
     if (obj.GetObjectType() != ObjectType.Mod)
     {
         return;
     }
     GenerateClassImplementation(obj, fg);
 }
Exemple #7
0
 public override async Task GenerateInCtor(ObjectGeneration obj, FileGeneration fg)
 {
     if (obj.GetObjectType() != ObjectType.Mod)
     {
         return;
     }
     await base.GenerateInCtor(obj, fg);
 }
Exemple #8
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();
     }
 }
Exemple #9
0
 public static void GenerateClassImplementation(ObjectGeneration obj, FileGeneration fg, bool onlyGetter = false)
 {
     if (obj.GetObjectType() == ObjectType.Mod)
     {
         fg.AppendLine("[DebuggerStepThrough]");
         fg.AppendLine($"IEnumerable<IModContext<{obj.Interface(getter: false)}, TSetter, TGetter>> IMajorRecordContextEnumerable<{obj.Interface(getter: false)}>.EnumerateMajorRecordContexts<TSetter, TGetter>({nameof(ILinkCache)} linkCache, bool throwIfUnknown) => this.EnumerateMajorRecordContexts{obj.GetGenericTypes(MaskType.Normal, "TSetter".AsEnumerable().And("TGetter").ToArray())}(linkCache, throwIfUnknown: throwIfUnknown);");
         fg.AppendLine("[DebuggerStepThrough]");
         fg.AppendLine($"IEnumerable<IModContext<{obj.Interface(getter: false)}, IMajorRecordCommon, IMajorRecordCommonGetter>> IMajorRecordContextEnumerable<{obj.Interface(getter: false)}>.EnumerateMajorRecordContexts({nameof(ILinkCache)} linkCache, Type type, bool throwIfUnknown) => this.EnumerateMajorRecordContexts(linkCache, type: type, throwIfUnknown: throwIfUnknown);");
     }
 }
Exemple #10
0
        public override async IAsyncEnumerable <(LoquiInterfaceType Location, string Interface)> Interfaces(ObjectGeneration obj)
        {
            if (obj.GetObjectType() != ObjectType.Mod)
            {
                yield break;
            }
            yield return(LoquiInterfaceType.IGetter, nameof(IModGetter));

            yield return(LoquiInterfaceType.ISetter, nameof(IMod));
        }
Exemple #11
0
 public override async Task PostLoad(ObjectGeneration obj)
 {
     if (obj.GetObjectType() == ObjectType.Mod)
     {
         obj.Interfaces.Add(LoquiInterfaceDefinitionType.IGetter, $"IMajorRecordContextEnumerable<{obj.Interface(getter: false)}>");
     }
     if (await MajorRecordModule.HasMajorRecordsInTree(obj, false) == Case.No)
     {
         return;
     }
 }
Exemple #12
0
 public static bool IsTopLevelGroup(this ObjectGeneration objGen)
 {
     if (objGen.GetObjectType() != ObjectType.Group)
     {
         return(false);
     }
     if (objGen.Name == "Group")
     {
         return(true);
     }
     return(false);
 }
Exemple #13
0
        public static async Task <bool> IsMajorRecord(this ObjectGeneration objGen)
        {
            if (objGen.GetObjectType() != ObjectType.Record)
            {
                return(false);
            }
            if (objGen.Name == "MajorRecord")
            {
                return(true);
            }
            await Task.WhenAll(objGen.BaseClassTrail().Select(bo => bo.LoadingCompleteTask.Task));

            return(objGen.BaseClassTrail().Any(bo => bo.Name == "MajorRecord"));
        }
Exemple #14
0
        public override async IAsyncEnumerable <(LoquiInterfaceType Location, string Interface)> Interfaces(ObjectGeneration obj)
        {
            if (obj.GetObjectType() != ObjectType.Mod)
            {
                yield break;
            }
            yield return(LoquiInterfaceType.IGetter, nameof(IModGetter));

            yield return(LoquiInterfaceType.ISetter, nameof(IMod));

            yield return(LoquiInterfaceType.IGetter, $"IContextGetterMod<{obj.Interface(getter: false)}, {obj.Interface(getter: true)}>");

            yield return(LoquiInterfaceType.ISetter, $"IContextMod<{obj.Interface(getter: false)}, {obj.Interface(getter: true)}>");
        }
Exemple #15
0
        public override async Task GenerateInCommon(ObjectGeneration obj, FileGeneration fg, MaskTypeSet maskTypes)
        {
            await base.GenerateInCommon(obj, fg, maskTypes);

            if (obj.GetObjectType() != ObjectType.Mod)
            {
                return;
            }
            if (!maskTypes.Applicable(LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal))
            {
                return;
            }

            GenerateGetGroup(obj, fg);
            GenerateWriteParallel(obj, fg);
        }
Exemple #16
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)}>");
        }
Exemple #17
0
        public static async Task <LoquiType> GetGroupLoquiTypeLowest(this ObjectGeneration objGen)
        {
            await objGen.LoadingCompleteTask.Task;

            if (objGen.GetObjectType() != ObjectType.Group)
            {
                throw new ArgumentException();
            }

            var loquiType = await GetGroupLoquiType(objGen);

            while (loquiType.TargetObjectGeneration.GetObjectType() == ObjectType.Group)
            {
                loquiType = await GetGroupLoquiType(loquiType.TargetObjectGeneration);
            }
            return(loquiType);
        }
        public override async IAsyncEnumerable <string> RequiredUsingStatements(ObjectGeneration obj)
        {
            await foreach (var item in base.RequiredUsingStatements(obj))
            {
                yield return(item);
            }
            yield return("Mutagen.Bethesda.Binary");

            yield return("System.Buffers.Binary");

            yield return("Mutagen.Bethesda.Translations.Binary");

            if (obj.GetObjectType() == ObjectType.Mod)
            {
                yield return("Mutagen.Bethesda.Plugins.Binary.Parameters");
            }
        }
Exemple #19
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; }}");
        }
Exemple #20
0
 public static async Task <bool> GetNeedsMasters(this ObjectGeneration objGen)
 {
     if (objGen.GetObjectType() == ObjectType.Group)
     {
         return(true);
     }
     foreach (var field in objGen.IterateFields())
     {
         if (field is FormKeyType)
         {
             return(true);
         }
         if (field is FormIDType)
         {
             return(true);
         }
         if (field is ContainerType cont)
         {
             if (cont.SubTypeGeneration is LoquiType loqui &&
                 (loqui.TargetObjectGeneration == null || await loqui.TargetObjectGeneration.GetNeedsMasters()))
             {
                 return(true);
             }
         }
         if (field is DictType dict)
         {
             if (dict.ValueTypeGen is LoquiType loqui &&
                 (loqui.TargetObjectGeneration == null || await loqui.TargetObjectGeneration.GetNeedsMasters()))
             {
                 return(true);
             }
         }
     }
     foreach (var baseObj in objGen.BaseClassTrail())
     {
         if (await baseObj.GetNeedsMasters())
         {
             return(true);
         }
     }
     return(false);
 }
Exemple #21
0
        public static async Task <LoquiType> GetGroupLoquiType(this ObjectGeneration objGen)
        {
            await objGen.LoadingCompleteTask.Task;

            if (objGen.GetObjectType() != ObjectType.Group)
            {
                throw new ArgumentException();
            }
            foreach (var field in objGen.IterateFields())
            {
                if (field is ContainerType cont)
                {
                    return(cont.SubTypeGeneration as LoquiType);
                }
                else if (field is DictType dictType)
                {
                    return(dictType.ValueTypeGen as LoquiType);
                }
            }
            throw new ArgumentException();
        }
Exemple #22
0
        public void GenerateFill(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration field,
            Accessor frameAccessor,
            bool isAsync,
            bool useReturnValue)
        {
            var data = field.GetFieldData();
            var returningParseValue = useReturnValue && data.HasTrigger;

            using (var args = new ArgsWrapper(fg,
                                              $"{(returningParseValue ? "return " : null)}{Loqui.Generation.Utility.Await(isAsync)}{this.Module.TranslationCreateClass(field.ObjectGen)}.FillBinary{field.Name}Custom"))
            {
                args.Add($"frame: {(data.HasTrigger ? $"{frameAccessor}.SpawnWithLength(frame.{nameof(MutagenFrame.MetaData)}.{nameof(ParsingBundle.Constants)}.{nameof(GameConstants.SubConstants)}.{nameof(GameConstants.SubConstants.HeaderLength)} + contentLength)" : frameAccessor)}");
                args.AddPassArg("item");
                if (returningParseValue && objGen.GetObjectType() == ObjectType.Subrecord)
                {
                    args.AddPassArg("lastParsed");
                }
            }
        }
        public override async Task GenerateInClass(ObjectGeneration obj, FileGeneration fg)
        {
            await base.GenerateInClass(obj, fg);

            switch (obj.GetObjectType())
            {
            case ObjectType.Record:
                await GenerateForRecord(obj, fg);

                break;

            case ObjectType.Mod:
                await GenerateForMod(obj, fg);

                break;

            case ObjectType.Subrecord:
            case ObjectType.Group:
            default:
                break;
            }
        }
Exemple #24
0
        public override async Task GenerateWrapperRecordTypeParse(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor locationAccessor,
            Accessor packageAccessor,
            Accessor converterAccessor)
        {
            var fieldData           = typeGen.GetFieldData();
            var returningParseValue = fieldData.HasTrigger;

            using (var args = new ArgsWrapper(fg,
                                              $"{(returningParseValue ? "return " : null)}{(typeGen.Name == null ? typeGen.GetFieldData().RecordType?.ToString() : typeGen.Name)}CustomParse"))
            {
                args.Add("stream");
                args.Add("offset");
                if (returningParseValue && objGen.GetObjectType() == ObjectType.Subrecord)
                {
                    args.AddPassArg("lastParsed");
                }
            }
        }
Exemple #25
0
        public override async Task GenerateWrapperFields(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor dataAccessor,
            int?passedLength,
            string passedLengthAccessor,
            DataType data = null)
        {
            var fieldData           = typeGen.GetFieldData();
            var returningParseValue = fieldData.HasTrigger;

            using (var args = new ArgsWrapper(fg,
                                              $"{(returningParseValue ? "public" : null)} partial {(returningParseValue ? nameof(ParseResult) : "void")} {(typeGen.Name == null ? typeGen.GetFieldData().RecordType?.ToString() : typeGen.Name)}CustomParse"))
            {
                args.Add($"{nameof(OverlayStream)} stream");
                args.Add($"int offset");
                if (returningParseValue && objGen.GetObjectType() == ObjectType.Subrecord)
                {
                    args.Add($"{nameof(PreviousParse)} lastParsed");
                }
            }
        }
Exemple #26
0
        public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg)
        {
            await base.GenerateInCommonMixin(obj, fg);

            if (obj.GetObjectType() != ObjectType.Mod)
            {
                return;
            }
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IReadOnlyCache<T, FormKey> {nameof(IModGetter.GetTopLevelGroupGetter)}<T>"))
            {
                args.Wheres.Add($"where T : {nameof(IMajorRecordCommonGetter)}");
                args.Add($"this {obj.Interface(getter: true)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return (IReadOnlyCache<T, FormKey>){obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.GetGroup<T>"))
                {
                    args.AddPassArg("obj");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  "public static ICache<T, FormKey> GetGroup<T>"))
            {
                args.Wheres.Add($"where T : {nameof(IMajorRecordCommon)}");
                args.Add($"this {obj.Interface(getter: false)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return (ICache<T, FormKey>){obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.GetGroup<T>"))
                {
                    args.AddPassArg("obj");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  $"public static void WriteToBinaryParallel"))
            {
                args.Add($"this {obj.Interface(getter: true, internalInterface: false)} item");
                args.Add($"Stream stream");
                args.Add($"{nameof(BinaryWriteParameters)}? param = null");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"{obj.CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.WriteParallel"))
                {
                    args.AddPassArg("item");
                    args.AddPassArg("stream");
                    args.Add($"param: param ?? {nameof(BinaryWriteParameters)}.{nameof(BinaryWriteParameters.Default)}");
                    args.Add("modKey: item.ModKey");
                }
            }
            fg.AppendLine();

            using (var args = new FunctionWrapper(fg,
                                                  $"public static void WriteToBinaryParallel"))
            {
                args.Add($"this {obj.Interface(getter: true, internalInterface: false)} item");
                args.Add($"string path");
                args.Add($"{nameof(BinaryWriteParameters)}? param = null");
            }
            using (new BraceWrapper(fg))
            {
                fg.AppendLine($"param ??= {nameof(BinaryWriteParameters)}.{nameof(BinaryWriteParameters.Default)};");
                using (var args = new ArgsWrapper(fg,
                                                  $"var modKey = param.{nameof(BinaryWriteParameters.RunMasterMatch)}"))
                {
                    args.Add("mod: item");
                    args.AddPassArg("path");
                }
                if (obj.GetObjectData().UsesStringFiles)
                {
                    fg.AppendLine("bool disposeStrings = param.StringsWriter == null;");
                    fg.AppendLine("param.StringsWriter ??= EnumExt.HasFlag((int)item.ModHeader.Flags, (int)ModHeaderCommonFlag.Localized) ? new StringsWriter(modKey, Path.Combine(Path.GetDirectoryName(path)!, \"Strings\")) : null;");
                }
                fg.AppendLine("using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write))");
                using (new BraceWrapper(fg))
                {
                    using (var args = new ArgsWrapper(fg,
                                                      $"{obj.CommonClass(LoquiInterfaceType.IGetter, CommonGenerics.Class, MaskType.Normal)}.WriteParallel"))
                    {
                        args.AddPassArg("item");
                        args.AddPassArg("stream");
                        args.Add($"param: param");
                        args.AddPassArg("modKey");
                    }
                }
                if (obj.GetObjectData().UsesStringFiles)
                {
                    fg.AppendLine("if (disposeStrings)");
                    using (new BraceWrapper(fg))
                    {
                        fg.AppendLine("param.StringsWriter?.Dispose();");
                    }
                }
            }
            fg.AppendLine();
        }
Exemple #27
0
        public override async Task GenerateInVoid(ObjectGeneration obj, FileGeneration fg)
        {
            if (obj.GetObjectType() != ObjectType.Mod)
            {
                return;
            }
            using (new NamespaceWrapper(fg, obj.Namespace))
            {
                var objData = obj.GetObjectData();
                fg.AppendLine("public class GroupMask");
                using (new BraceWrapper(fg))
                {
                    foreach (var field in obj.IterateFields())
                    {
                        if (!(field is LoquiType loqui))
                        {
                            continue;
                        }
                        if (loqui.TargetObjectGeneration == null)
                        {
                            continue;
                        }
                        if (loqui.TargetObjectGeneration.GetObjectType() != ObjectType.Group)
                        {
                            continue;
                        }
                        fg.AppendLine($"public bool {loqui.Name};");
                    }

                    fg.AppendLine("public GroupMask()");
                    using (new BraceWrapper(fg))
                    {
                    }

                    fg.AppendLine("public GroupMask(bool defaultValue)");
                    using (new BraceWrapper(fg))
                    {
                        foreach (var field in obj.IterateFields())
                        {
                            if (!(field is LoquiType loqui))
                            {
                                continue;
                            }
                            if (loqui.TargetObjectGeneration == null)
                            {
                                continue;
                            }
                            if (loqui.TargetObjectGeneration.GetObjectType() != ObjectType.Group)
                            {
                                continue;
                            }
                            fg.AppendLine($"{loqui.Name} = defaultValue;");
                        }
                    }
                }
                fg.AppendLine();

                fg.AppendLine($"public interface I{obj.Name}DisposableGetter : {obj.Interface(getter: true, internalInterface: true)}, IModDisposeGetter");
                using (new BraceWrapper(fg))
                {
                }
                fg.AppendLine();

                if (objData.GameReleaseOptions != null)
                {
                    using (var comment = new CommentWrapper(fg))
                    {
                        comment.Summary.AppendLine($"Different game release versions a {ModName(obj)} mod can have");
                    }
                    fg.AppendLine($"public enum {ReleaseEnumName(obj)}");
                    using (new BraceWrapper(fg))
                    {
                        using (var comma = new CommaWrapper(fg))
                        {
                            foreach (var opt in objData.GameReleaseOptions)
                            {
                                comma.Add($"{opt} = {(int)opt}");
                            }
                        }
                    }
                    fg.AppendLine();

                    using (var c = new ClassWrapper(fg, $"{ReleaseEnumName(obj)}Ext"))
                    {
                        c.Static = true;
                    }
                    using (new BraceWrapper(fg))
                    {
                        using (var args = new FunctionWrapper(fg,
                                                              $"public static {nameof(GameRelease)} ToGameRelease"))
                        {
                            args.Add($"this {ReleaseEnumName(obj)} release");
                        }
                        using (new BraceWrapper(fg))
                        {
                            fg.AppendLine("return release switch");
                            using (new BraceWrapper(fg)
                            {
                                AppendSemicolon = true
                            })
                            {
                                using (var comma = new CommaWrapper(fg))
                                {
                                    foreach (var item in objData.GameReleaseOptions)
                                    {
                                        comma.Add($"{ReleaseEnumName(obj)}.{item} => {nameof(GameRelease)}.{item}");
                                    }
                                    comma.Add("_ => throw new ArgumentException()");
                                }
                            }
                        }
                        fg.AppendLine();

                        using (var args = new FunctionWrapper(fg,
                                                              $"public static {ReleaseEnumName(obj)} To{ReleaseEnumName(obj)}"))
                        {
                            args.Add($"this {nameof(GameRelease)} release");
                        }
                        using (new BraceWrapper(fg))
                        {
                            fg.AppendLine("return release switch");
                            using (new BraceWrapper(fg)
                            {
                                AppendSemicolon = true
                            })
                            {
                                using (var comma = new CommaWrapper(fg))
                                {
                                    foreach (var item in objData.GameReleaseOptions)
                                    {
                                        comma.Add($"{nameof(GameRelease)}.{item} => {ReleaseEnumName(obj)}.{item}");
                                    }
                                    comma.Add("_ => throw new ArgumentException()");
                                }
                            }
                        }
                    }
                }
            }
        }
        public override async Task GenerateInCommonMixin(ObjectGeneration obj, FileGeneration fg)
        {
            if (await MajorRecordModule.HasMajorRecordsInTree(obj, includeBaseClass: false) == Case.No)
            {
                return;
            }
            var    needsCatch = obj.GetObjectType() == ObjectType.Mod;
            string catchLine  = needsCatch ? ".Catch(e => throw RecordException.Enrich(e, obj.ModKey))" : string.Empty;
            string enderSemi  = needsCatch ? string.Empty : ";";

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<{nameof(IMajorRecordCommonGetter)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecords",
                                                  suffixLine: catchLine))
                {
                    args.AddPassArg("obj");
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<TMajor> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal, "TMajor")}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics));
                args.Wheres.Add($"where TMajor : class, IMajorRecordCommonGetter");
                args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj");
                args.Add($"bool throwIfUnknown = true");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecords"))
                {
                    args.AddPassArg("obj");
                    args.Add("type: typeof(TMajor)");
                    args.AddPassArg("throwIfUnknown");
                }
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($".Select(m => (TMajor)m){enderSemi}");
                    if (needsCatch)
                    {
                        fg.AppendLine($"{catchLine};");
                    }
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<{nameof(IMajorRecordCommonGetter)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Add($"this {obj.Interface(getter: true, internalInterface: true)} obj");
                args.Add($"Type type");
                args.Add($"bool throwIfUnknown = true");
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.IGetter, obj.Generics));
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.IGetter, CommonGenerics.Class)}.EnumerateMajorRecords"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("type");
                    args.AddPassArg("throwIfUnknown");
                }
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($".Select(m => ({nameof(IMajorRecordCommonGetter)})m){enderSemi}");
                    if (needsCatch)
                    {
                        fg.AppendLine($"{catchLine};");
                    }
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<{nameof(IMajorRecordCommon)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.EnumerateMajorRecords",
                                                  suffixLine: catchLine))
                {
                    args.AddPassArg("obj");
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<TMajor> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal, "TMajor")}"))
            {
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
                args.Wheres.Add($"where TMajor : class, IMajorRecordCommon");
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.EnumerateMajorRecords"))
                {
                    args.AddPassArg("obj");
                    args.Add("type: typeof(TMajor)");
                    args.Add("throwIfUnknown: true");
                }
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($".Select(m => (TMajor)m){enderSemi}");
                    if (needsCatch)
                    {
                        fg.AppendLine($"{catchLine};");
                    }
                }
            }
            fg.AppendLine();

            fg.AppendLine("[DebuggerStepThrough]");
            using (var args = new FunctionWrapper(fg,
                                                  $"public static IEnumerable<{nameof(IMajorRecordCommon)}> EnumerateMajorRecords{obj.GetGenericTypes(MaskType.Normal)}"))
            {
                args.Add($"this {obj.Interface(getter: false, internalInterface: true)} obj");
                args.Add($"Type? type");
                args.Add($"bool throwIfUnknown = true");
                args.Wheres.AddRange(obj.GenerateWhereClauses(LoquiInterfaceType.ISetter, obj.Generics));
            }
            using (new BraceWrapper(fg))
            {
                using (var args = new FunctionWrapper(fg,
                                                      $"return {obj.CommonClassInstance("obj", LoquiInterfaceType.ISetter, CommonGenerics.Class)}.EnumeratePotentiallyTypedMajorRecords"))
                {
                    args.AddPassArg("obj");
                    args.AddPassArg("type");
                    args.AddPassArg("throwIfUnknown");
                }
                using (new DepthWrapper(fg))
                {
                    fg.AppendLine($".Select(m => ({nameof(IMajorRecordCommon)})m){enderSemi}");
                    if (needsCatch)
                    {
                        fg.AppendLine($"{catchLine};");
                    }
                }
            }
            fg.AppendLine();
        }
        public override async Task GenerateWrite(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor writerAccessor,
            Accessor itemAccessor,
            Accessor errorMaskAccessor,
            Accessor translationMaskAccessor,
            Accessor converterAccessor)
        {
            var  loquiGen = typeGen as LoquiType;
            bool isGroup  = objGen.GetObjectType() == ObjectType.Mod &&
                            loquiGen.TargetObjectGeneration.GetObjectData().ObjectType == ObjectType.Group;

            if (typeGen.Nullable)
            {
                fg.AppendLine($"if ({itemAccessor}.TryGet(out var {typeGen.Name}Item))");
                itemAccessor = $"{typeGen.Name}Item";
            }
            else
            {
                // We want to cache retrievals, in case it's a wrapper being written
                fg.AppendLine($"var {typeGen.Name}Item = {itemAccessor};");
                itemAccessor = $"{typeGen.Name}Item";
            }
            using (new BraceWrapper(fg, doIt: typeGen.Nullable))
            {
                if (isGroup)
                {
                    var dictGroup = loquiGen.TargetObjectGeneration.Name == "Group";
                    fg.AppendLine($"if ({itemAccessor}.{(dictGroup ? "RecordCache" : "Records")}.Count > 0)");
                }
                using (new BraceWrapper(fg, doIt: isGroup))
                {
                    var data = loquiGen.GetFieldData();
                    if (data.MarkerType.HasValue)
                    {
                        fg.AppendLine($"using ({nameof(HeaderExport)}.{nameof(HeaderExport.Subrecord)}(writer, {objGen.RecordTypeHeaderName(data.MarkerType.Value)})) {{ }}");
                    }
                    var needsHeaderWrite = false;
                    if (NeedsHeaderProcessing(loquiGen))
                    {
                        needsHeaderWrite = true;
                        fg.AppendLine($"using ({nameof(HeaderExport)}.{nameof(HeaderExport.Subrecord)}(writer, {loquiGen.GetFieldData().TriggeringRecordSetAccessor}))");
                    }
                    using (new BraceWrapper(fg, doIt: needsHeaderWrite))
                    {
                        string line;
                        if (loquiGen.TargetObjectGeneration != null)
                        {
                            line = $"(({this.Module.TranslationWriteClassName(loquiGen.TargetObjectGeneration)})(({nameof(IBinaryItem)}){itemAccessor}).{this.Module.TranslationWriteItemMember})";
                        }
                        else
                        {
                            line = $"(({this.Module.TranslationWriteInterface})(({nameof(IBinaryItem)}){itemAccessor}).{this.Module.TranslationWriteItemMember})";
                        }
                        using (var args = new ArgsWrapper(fg, $"{line}.Write{loquiGen.GetGenericTypes(true, MaskType.Normal)}"))
                        {
                            args.Add($"item: {itemAccessor}");
                            args.Add($"writer: {writerAccessor}");
                            if (data?.RecordTypeConverter != null &&
                                data.RecordTypeConverter.FromConversions.Count > 0)
                            {
                                args.Add($"recordTypeConverter: {objGen.RegistrationName}.{(typeGen.Name ?? typeGen.Parent?.Name)}Converter");
                            }
                            else if (converterAccessor != null)
                            {
                                args.Add($"recordTypeConverter: {converterAccessor}");
                            }
                        }
                    }
                }
            }
        }
 private string GetLocationObjectString(ObjectGeneration obj) => obj.GetObjectType() == ObjectType.Mod ? nameof(RangeInt64) : nameof(RangeInt32);