public override async Task FinalizeGeneration(ProtocolGeneration proto) { await base.FinalizeGeneration(proto); if (proto.Protocol.Namespace == "Bethesda") { return; } bool all = proto.Protocol.Namespace == "All"; FileGeneration fg = new FileGeneration(); ObjectGeneration.AddAutogenerationComment(fg); fg.AppendLine("using Loqui;"); fg.AppendLine("using Mutagen.Bethesda.Plugins.Records.Internals;"); fg.AppendLine(); using (new NamespaceWrapper(fg, proto.DefaultNamespace, fileScoped: false)) { using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine("A static class to house initialization warmup logic"); } using (var c = new ClassWrapper(fg, $"Warmup{proto.Protocol.Namespace}")) { c.Static = true; c.Partial = true; } using (new BraceWrapper(fg)) { using (var comment = new CommentWrapper(fg)) { comment.Summary.AppendLine("Will initialize internals in a more efficient way that avoids reflection."); comment.Summary.AppendLine("Not required to call, but can be used to warm up ahead of time."); if (!all) { comment.Summary.AppendLine("<br/><br/>NOTE: Calling this warmup which is for a single game, will require you warm up"); comment.Summary.AppendLine("other games in the same fashion. Use WarmupAll if you want all games to be warmed."); } } using (var args = new FunctionWrapper(fg, "public static void Init")) { } using (new BraceWrapper(fg)) { if (all) { using (var args = new ArgsWrapper(fg, $"Loqui.Initialization.SpinUp")) { args.Add($"new ProtocolDefinition_Bethesda()"); } foreach (var otherProto in proto.Gen.Protocols.Values .Where(p => p.DefaultNamespace.Contains("Mutagen.Bethesda")) .Where(p => !p.DefaultNamespace.Contains("Mutagen.Bethesda.Plugins.Records")) .Where(p => !object.ReferenceEquals(p, proto))) { fg.AppendLine($"{otherProto.DefaultNamespace}.Warmup{otherProto.Protocol.Namespace}.Init();"); } } else { using (var args = new ArgsWrapper(fg, $"Loqui.Initialization.SpinUp")) { args.Add($"new ProtocolDefinition_Bethesda()"); args.Add($"new ProtocolDefinition_{proto.Protocol.Namespace}()"); } fg.AppendLine($"LinkInterfaceMapping.AutomaticRegistration = false;"); using (var args = new ArgsWrapper(fg, $"LinkInterfaceMapping.Register")) { args.Add($"new {proto.DefaultNamespace}.Internals.LinkInterfaceMapping()"); } fg.AppendLine("InitCustom();"); } } fg.AppendLine("static partial void InitCustom();"); } } var path = Path.Combine(proto.DefFileLocation.FullName, $"../Warmup{proto.Protocol.Namespace}{Loqui.Generation.Constants.AutogeneratedMarkerString}.cs"); fg.Generate(path); proto.GeneratedFiles.Add(path, ProjItemType.Compile); }
public override async Task PrepareGeneration(ProtocolGeneration proto) { await base.PrepareGeneration(proto); // Compile interfaces implementing interfaces mapping data var interfaceInheritenceMappings = new Dictionary <string, HashSet <string> >(); foreach (var obj in proto.ObjectGenerationsByID.Values) { foreach (var item in obj.Node.Elements(XName.Get("LinkInterface", LoquiGenerator.Namespace))) { ObjectMappings.GetOrAdd(proto.Protocol).GetOrAdd(item.Value).Add(obj); } } // Generate interface files themselves if (!ObjectMappings.TryGetValue(proto.Protocol, out var mappings)) { return; } foreach (var interf in mappings) { FileGeneration fg = new FileGeneration(); ObjectGeneration.AddAutogenerationComment(fg); fg.AppendLine("using Mutagen.Bethesda;"); fg.AppendLine(); var implementedObjs = new HashSet <ObjectGeneration>(); void AddObjs(string interfKey) { implementedObjs.Add(ObjectMappings[proto.Protocol][interfKey]); if (interfaceInheritenceMappings.TryGetValue(interfKey, out var parents)) { foreach (var parent in parents) { AddObjs(parent); } } } AddObjs(interf.Key); using (new NamespaceWrapper(fg, proto.DefaultNamespace, fileScoped: false)) { fg.AppendLine("/// <summary>"); fg.AppendLine($"/// Implemented by: [{string.Join(", ", implementedObjs.Select(o => o.ObjectName))}]"); fg.AppendLine("/// </summary>"); using (var c = new ClassWrapper(fg, interf.Key)) { c.Type = ClassWrapper.ObjectType.@interface; c.Interfaces.Add($"I{proto.Protocol.Namespace}MajorRecordInternal"); c.Interfaces.Add($"{interf.Key}Getter"); if (interfaceInheritenceMappings.TryGetValue(interf.Key, out var impls)) { c.Interfaces.Add(impls); } c.Partial = true; } using (new BraceWrapper(fg)) { } fg.AppendLine(); fg.AppendLine("/// <summary>"); fg.AppendLine($"/// Implemented by: [{string.Join(", ", implementedObjs.Select(o => o.ObjectName))}]"); fg.AppendLine("/// </summary>"); using (var c = new ClassWrapper(fg, $"{interf.Key}Getter")) { c.Type = ClassWrapper.ObjectType.@interface; c.Interfaces.Add($"I{proto.Protocol.Namespace}MajorRecordGetter"); if (interfaceInheritenceMappings.TryGetValue(interf.Key, out var impls)) { c.Interfaces.Add(impls.Select(i => $"{i}Getter")); } c.Partial = true; } using (new BraceWrapper(fg)) { } } var path = Path.Combine(proto.DefFileLocation.FullName, $"../Interfaces/{interf.Key}{Loqui.Generation.Constants.AutogeneratedMarkerString}.cs"); fg.Generate(path); proto.GeneratedFiles.Add(path, ProjItemType.Compile); } // Generate interface to major record mapping registry FileGeneration mappingGen = new FileGeneration(); ObjectGeneration.AddAutogenerationComment(mappingGen); mappingGen.AppendLine($"using System;"); mappingGen.AppendLine($"using System.Collections.Generic;"); mappingGen.AppendLine($"using Mutagen.Bethesda.Plugins.Records.Internals;"); mappingGen.AppendLine(); using (new NamespaceWrapper(mappingGen, $"{proto.DefaultNamespace}.Internals", fileScoped: false)) { using (var c = new ClassWrapper(mappingGen, "LinkInterfaceMapping")) { c.Interfaces.Add(nameof(ILinkInterfaceMapping)); } using (new BraceWrapper(mappingGen)) { mappingGen.AppendLine($"public IReadOnlyDictionary<Type, Type[]> InterfaceToObjectTypes {{ get; }}"); mappingGen.AppendLine(); mappingGen.AppendLine($"public {nameof(GameCategory)} GameCategory => {nameof(GameCategory)}.{proto.Protocol.Namespace};"); mappingGen.AppendLine(); mappingGen.AppendLine("public LinkInterfaceMapping()"); using (new BraceWrapper(mappingGen)) { mappingGen.AppendLine($"var dict = new Dictionary<Type, Type[]>();"); foreach (var interf in mappings) { mappingGen.AppendLine($"dict[typeof({interf.Key})] = new Type[]"); using (new BraceWrapper(mappingGen) { AppendSemicolon = true }) { foreach (var obj in interf.Value) { mappingGen.AppendLine($"typeof({obj.ObjectName}),"); } } mappingGen.AppendLine($"dict[typeof({interf.Key}Getter)] = dict[typeof({interf.Key})];"); } mappingGen.AppendLine($"InterfaceToObjectTypes = dict;"); } } } mappingGen.AppendLine(); var mappingPath = Path.Combine(proto.DefFileLocation.FullName, $"../Interfaces/LinkInterfaceMapping{Loqui.Generation.Constants.AutogeneratedMarkerString}.cs"); mappingGen.Generate(mappingPath); proto.GeneratedFiles.Add(mappingPath, ProjItemType.Compile); }