public void LoadOrderNoMatch(LinkCacheTestTypes cacheType) { var prototype = new SkyrimMod(TestConstants.PluginModKey, SkyrimRelease.SkyrimLE); prototype.Npcs.AddNew(); using var disp = ConvertMod(prototype, out var mod); var loadOrder = new LoadOrder <ISkyrimModGetter>(); loadOrder.Add(mod); var(style, package) = GetLinkCache(loadOrder, cacheType); // Test FormKey fails Assert.False(package.TryResolve(UnusedFormKey, out var _)); Assert.False(package.TryResolve(FormKey.Null, out var _)); Assert.False(package.TryResolve <IMajorRecordGetter>(UnusedFormKey, out var _)); Assert.False(package.TryResolve <IMajorRecordGetter>(FormKey.Null, out var _)); Assert.False(package.TryResolve <ISkyrimMajorRecordGetter>(UnusedFormKey, out var _)); Assert.False(package.TryResolve <ISkyrimMajorRecordGetter>(FormKey.Null, out var _)); // Test EditorID fails Assert.False(package.TryResolve(UnusedEditorID, out var _)); Assert.False(package.TryResolve(string.Empty, out var _)); Assert.False(package.TryResolve <IMajorRecordGetter>(UnusedEditorID, out var _)); Assert.False(package.TryResolve <IMajorRecordGetter>(string.Empty, out var _)); Assert.False(package.TryResolve <ISkyrimMajorRecordGetter>(UnusedEditorID, out var _)); Assert.False(package.TryResolve <ISkyrimMajorRecordGetter>(string.Empty, out var _)); }
public void LoadOrderOriginatingTarget(LinkCacheTestTypes cacheType) { var prototype1 = new SkyrimMod(TestConstants.PluginModKey, SkyrimRelease.SkyrimLE); var prototype2 = new SkyrimMod(new ModKey("Dummy2", ModType.Master), SkyrimRelease.SkyrimLE); var overriddenRec = prototype1.ObjectEffects.AddNew("EditorID1"); var overrideRec = overriddenRec.DeepCopy(); overrideRec.EditorID = "EditorID1"; prototype2.ObjectEffects.RecordCache.Set(overrideRec); using var disp1 = ConvertMod(prototype1, out var mod1); using var disp2 = ConvertMod(prototype2, out var mod2); var loadOrder = new LoadOrder <ISkyrimModGetter> { mod1, mod2 }; var(style, package) = GetLinkCache(loadOrder, cacheType); // Test query successes // Do linked interfaces first, as this tests a specific edge case WrapPotentialThrow(cacheType, style, () => { Assert.True(package.TryResolve <IEffectRecordGetter>(overriddenRec.FormKey, out var rec, ResolveTarget.Origin)); rec.EditorID.Should().Be(overriddenRec.EditorID); });
public static LoadOrder <OblivionMod> ImportUsualLoadOrder( DirectoryPath dataFolder, GroupMask?importMask = null, ModKey?modKeyExclusionHint = null, bool allowMissingMods = false) { var loadOrderListing = LoadOrder.GetUsualLoadOrder(GameMode.Oblivion, dataFolder, allowMissingMods: allowMissingMods); if (modKeyExclusionHint != null) { loadOrderListing.Remove(modKeyExclusionHint.Value); } var loadOrder = new LoadOrder <OblivionMod>(); loadOrder.Import( dataFolder, loadOrderListing, importer: (FilePath path, ModKey modKey, out OblivionMod mod) => { mod = OblivionMod.CreateFromBinary( path.Path, modKey, importMask: importMask); return(true); }); return(loadOrder); }
private void FindValue(LoadOrder loadOrder) { switch (loadOrder) { case LoadOrder.FLAT_SPHERE: { float y2 = y * 2f; val = x * x + y2 * y2 + z * z; break; } case LoadOrder.SPHERE: { val = x * x + y * y + z * z; break; } case LoadOrder.CYLINDER: { val = x * x + z * z + y * 0.0001f; break; } case LoadOrder.CUBE_FILL: { val = y * 1000 * 1000 + z * 1000 + x; break; } } }
public void AddAnExistingThing() { SkyrimMod masterMod = new(masterModKey, SkyrimRelease.SkyrimSE); var origFlst = masterMod.FormLists.AddNew("origFlst"); var newThing = masterMod.MiscItems.AddNew("newItem"); origFlst.Items.Add(newThing.AsLink()); SkyrimMod patchMod = new(patchModKey, SkyrimRelease.SkyrimSE); var linkCache = masterMod.ToImmutableLinkCache(); var loadOrder = new LoadOrder <IModListing <ISkyrimModGetter> > { new ModListing <ISkyrimModGetter>(masterMod, true), new ModListing <ISkyrimModGetter>(patchMod, true) }; Program program = new(loadOrder, linkCache, patchMod, GameRelease.SkyrimSE); HashSet <IFormLinkGetter <IItemGetter> > set = new(); set.Add(newThing.AsLink()); program.ApplySetToFLST(origFlst.AsLinkGetter(), set); Assert.Empty(patchMod.FormLists); }
public void GetListings_NoCreationClub() { using var tmp = Utility.GetTempFolder(nameof(LoadOrder_Tests)); var pluginsPath = Path.Combine(tmp.Dir.Path, "Plugins.txt"); var dataPath = Path.Combine(tmp.Dir.Path, "Data"); File.WriteAllLines(pluginsPath, new string[] { $"{Utility.MasterModKey.FileName}", $"{Utility.PluginModKey.FileName}", }); Directory.CreateDirectory(dataPath); File.WriteAllText(Path.Combine(dataPath, Utility.MasterModKey.FileName), string.Empty); File.WriteAllText(Path.Combine(dataPath, Utility.PluginModKey.FileName), string.Empty); var results = LoadOrder.GetListings( game: GameRelease.Oblivion, dataPath: dataPath, pluginsFilePath: pluginsPath, creationClubFilePath: null) .ToList(); results.Should().HaveCount(2); results.Should().Equal(new LoadOrderListing[] { new LoadOrderListing(Utility.MasterModKey, enabled: true), new LoadOrderListing(Utility.PluginModKey, enabled: true), }); }
public static TempFolder SetupDataFolder(TempFolder tempFolder, GameRelease release, string?loadOrderPath = null) { var dataFolder = new TempFolder(Path.Combine(tempFolder.Dir.Path, "Data")); loadOrderPath ??= PathToLoadOrderFile; string testPath, overridePath; switch (release) { case GameRelease.Oblivion: testPath = OblivionPathToTestFile; overridePath = OblivionPathToOverrideFile; break; case GameRelease.SkyrimLE: case GameRelease.SkyrimSE: testPath = LePathToTestFile; overridePath = LePathToOverrideFile; break; default: throw new NotImplementedException(); } File.Copy(testPath, Path.Combine(dataFolder.Dir.Path, TestFileName)); File.Copy(overridePath, Path.Combine(dataFolder.Dir.Path, OverrideFileName)); var loadOrderListing = LoadOrder.FromPath(loadOrderPath, release, dataFolder.Dir); LoadOrder.AlignTimestamps(loadOrderListing.OnlyEnabled().Select(m => m.ModKey), dataFolder.Dir.Path); return(dataFolder); }
public ResourceLoadTable(LoadOrderItem[] tbl, int size, int locn, LoadOrder type) { table = tbl; tableSize = size; bfrLocation = locn; orderType = type; }
public void FormLink_LoadOrder_ResolveAll_DoubleQuery(LinkCacheTestTypes cacheType) { var mod = new SkyrimMod(TestConstants.PluginModKey, SkyrimRelease.SkyrimLE); var npc = mod.Npcs.AddNew(); var mod2 = new SkyrimMod(TestConstants.PluginModKey3, SkyrimRelease.SkyrimLE); var npcOverride = mod2.Npcs.GetOrAddAsOverride(npc); npcOverride.FaceParts = new NpcFaceParts(); var loadOrder = new LoadOrder <ISkyrimModGetter>() { mod, new SkyrimMod(TestConstants.PluginModKey2, SkyrimRelease.SkyrimLE), mod2 }; var(style, package) = GetLinkCache(loadOrder, cacheType); var formLink = new FormLink <INpcGetter>(npc.FormKey); WrapPotentialThrow(cacheType, style, () => { var resolved = formLink.ResolveAll(package).ToArray(); resolved.Should().HaveCount(2); resolved.First().Should().BeSameAs(npcOverride); resolved.Last().Should().BeSameAs(npc); }); }
public Finder(string dataFolder) { _dataFolder = dataFolder; _fileSet = new HashSet <string>(StringComparer.OrdinalIgnoreCase); MissingAssets = new List <MissingAsset>(); _loadOrder = new LoadOrder <ISkyrimModDisposableGetter>(); }
public void FormLink_LoadOrder_ResolveAllContexts_DoubleQuery(LinkCacheTestTypes cacheType, AContextRetriever contextRetriever) { var mod = new SkyrimMod(TestConstants.PluginModKey, SkyrimRelease.SkyrimLE); var npc = mod.Npcs.AddNew(); var mod2 = new SkyrimMod(TestConstants.PluginModKey3, SkyrimRelease.SkyrimLE); var npcOverride = mod2.Npcs.GetOrAddAsOverride(npc); npcOverride.FaceParts = new NpcFaceParts(); var loadOrder = new LoadOrder <ISkyrimModGetter>() { mod, new SkyrimMod(TestConstants.PluginModKey2, SkyrimRelease.SkyrimLE), mod2 }; var(style, package) = GetLinkCache(loadOrder, cacheType); var formLink = new FormLink <INpcGetter>(npc.FormKey); var resolved = contextRetriever.ResolveAllContexts <INpc, INpcGetter>(formLink, package).ToArray(); resolved = contextRetriever.ResolveAllContexts <INpc, INpcGetter>(formLink, package).ToArray(); resolved.Should().HaveCount(2); resolved.First().Record.Should().BeSameAs(npcOverride); resolved.First().ModKey.Should().Be(TestConstants.PluginModKey3); resolved.First().Parent.Should().BeNull(); resolved.Last().Record.Should().BeSameAs(npc); resolved.Last().ModKey.Should().Be(TestConstants.PluginModKey); resolved.Last().Parent.Should().BeNull(); }
public void UpdateBufferRadius(int radius, int height) { iteratorPos = 0; bufferRadius = radius; bufferHeight = height; lastLoadOrder = loadOrder; int diameter = radius * 2 + 1; int diameterUp = height * 2 + 1; chunkOffsets = new ChunkOffset[diameter * diameterUp * diameter]; int x, y, z; int i = 0; for (x = -radius; x <= radius; x++) { for (y = -height; y <= height; y++) { for (z = -radius; z <= radius; z++) { chunkOffsets[i++] = new ChunkOffset(loadOrder, x, y, z); } } } Array.Sort(chunkOffsets); }
public ResolvedFormID Resolve(LoadOrder order, SSEPlugin parent) { var master = parent.GetMasterName((int)MasterIndex); var masterIndex = (UInt32)order.plugins.FindIndex(plugin => string.Equals(master, plugin, StringComparison.OrdinalIgnoreCase)); return(new ResolvedFormID(RecordID, masterIndex)); }
//public static TMajor? GetWinningOverride<TMajor> (this TMajor record , SynthesisState<ISkyrimMod, ISkyrimModGetter> state) where TMajor : class, IMajorRecordCommonGetter //{ // if (record == null || state == null) return null; // var result = state.LoadOrder.PriorityOrder.WinningOverrides<TMajor>().Where(x => x.FormKey.ID == record.FormKey.ID).ToList(); // return (result.Count > 0) ? result.First() : null; //} //public static TMajor? GetWinningOverrideAtOrder<TMajor>(this TMajor record, int Order, SynthesisState<ISkyrimMod, ISkyrimModGetter> state) where TMajor : class, IMajorRecordCommonGetter //{ // if (record == null || state == null) return null; // var result = state.LoadOrder.PriorityOrder.Take(Order + 1).Select(x => x.Mod).Select(x=>x?.GetTopLevelGroupGetter<TMajor>()).SelectMany(x=>x?.Items).Where(x => (long) x.FormKey.ID == (long) record.FormKey.ID).ToList(); // return (result.Count > 0) ? result.Last() : null; //} public static int GetFileOrder(this LoadOrder <IModListing <ISkyrimModGetter> >?LoadOrder, string Filename) { if (Filename == null || LoadOrder == null) { return(-1); } return(LoadOrder.Keys.ToList().FindIndex(0, LoadOrder.Keys.Count(), x => x.FileName.ToLower() == Filename.ToLower())); }
public void Dispose() { LoadOrder.Dispose(); if (_formKeyAllocator is IDisposable disp) { disp.Dispose(); } }
public IMetaData(Arch arch, Atlas atlas, SlotGroup slotGroup, LayerEnum layer, LoadOrder loadOrder) { this.Archetype = arch; this.LoadOrder = loadOrder; this.Atlas = atlas; this.SlotGroup = slotGroup; this.Layer = layer; }
public ChunkOffset(LoadOrder loadOrder, int x, int y, int z) { this.x = x; this.y = y; this.z = z; FindValue(loadOrder); }
public void AddAHearthFiresThing(SkyrimRelease release) { var xHFSxConstructionFLSTFormLink = release switch { SkyrimRelease.SkyrimLE => HearthFireStores_GS.FormList.xHFSxConstructionFLST, SkyrimRelease.SkyrimSE or SkyrimRelease.SkyrimVR => GeneralStores.FormList.xHFSxConstructionFLST, _ => throw new ArgumentException(null, nameof(release)), }; var gameRelease = release switch { SkyrimRelease.SkyrimLE => GameRelease.SkyrimLE, SkyrimRelease.SkyrimSE => GameRelease.SkyrimSE, SkyrimRelease.SkyrimVR => GameRelease.SkyrimVR, _ => throw new ArgumentException(null, nameof(release)), }; var generalStores = new SkyrimMod(xHFSxConstructionFLSTFormLink.FormKey.ModKey, release); var xHFSxConstructionFLST = new FormList(xHFSxConstructionFLSTFormLink.FormKey, release); generalStores.FormLists.Add(xHFSxConstructionFLST); SkyrimMod masterMod = new(masterModKey, release); var newThing = masterMod.MiscItems.AddNew("newItem"); SkyrimMod patchMod = new(patchModKey, release); var loadOrder = new LoadOrder <IModListing <ISkyrimModGetter> > { new ModListing <ISkyrimModGetter>(generalStores, true), new ModListing <ISkyrimModGetter>(masterMod, true), new ModListing <ISkyrimModGetter>(patchMod, true) }; var linkCache = loadOrder.ToImmutableLinkCache(); Program program = new(loadOrder, linkCache, patchMod, gameRelease); program.hearthFiresConstructionSet.Add(newThing.AsLink()); program.RecordClassifiedItems(); Assert.Single(patchMod.FormLists); var updatedFlst = patchMod.FormLists.Single(); Assert.Equal(xHFSxConstructionFLSTFormLink, updatedFlst.AsLink()); Assert.Single(updatedFlst.Items); var newThingLink = updatedFlst.Items.Single(); Assert.False(newThingLink.IsNull); Assert.Equal(newThing.AsLink(), newThingLink); }
/// <summary> /// Initializes the Plugin System. /// </summary> /// <param name="internalConfigPath">The Path that is used by internal config files by the Plugin System</param> /// <param name="pluginDirectory">The Path used as "Install Directory" for Plugins/Packages</param> public static void Initialize( string internalConfigPath, string pluginDirectory, Func <string, string, bool> updateDialog, Action <string, int, int> setStatus, string staticDataConfig = null, bool checkUpdates = true) { if (IsInitialized) { throw new Exception("Can not Initialize the Plugin System Twice"); } SendLog("Initializing Plugin System"); //TODO: Process Things like updates before the plugin system loads the libraries. PluginPaths.InternalSystemConfigPath = Path.GetFullPath(internalConfigPath); PluginPaths.PluginDirectory = Path.GetFullPath(pluginDirectory); PluginPaths.EnsureInternalDirectoriesExist(); PluginPaths.CreateInternalFilesIfMissing(); ErrorHandler.Initialize(); LoadOrder.Initialize(); if (staticDataConfig != null && File.Exists(staticDataConfig)) { StaticData.SetState(File.ReadAllText(staticDataConfig)); } IsInitialized = true; SendLog("Updating.."); PluginHost = new PluginSystemHost(); HelperClass.ReloadDefaultPlugins(); OnInitialized?.Invoke(); if (File.Exists(PluginPaths.InternalStartupInstructionPath)) { SendLog("Running Start Actions.."); ActionRunner.RunActions(); } if (checkUpdates) { ListHelper.LoadList(PluginPaths.PluginListFile).Select(x => new BasePluginPointer(x)).ToList() .ForEach(x => UpdateManager.CheckAndUpdate(x, updateDialog, setStatus)); } SendLog("Registering System Host.."); LoadPlugins(PluginHost); SendLog("Registered System Host.."); SendLogDivider(); //Everything Finished SendLog("Initialization Complete."); SendLogDivider(); }
public static TMod GetIfEnabledAndExists <TMod>(this LoadOrder <IModListing <TMod> > loadOrder, ModKey modKey) where TMod : class, IModGetter { if (TryGetIfEnabledAndExists(loadOrder, modKey, out var mod)) { return(mod); } throw new MissingModException(modKey); }
ReforgedArmor(this LoadOrder <IModListing <ISkyrimModGetter> > mods, IArmorGetter vanillaArmor) { return(from cobj in mods.PriorityOrder.ConstructibleObject().WinningOverrides() where cobj.Items !.Any(rf => rf.Item.Item.FormKey == vanillaArmor.FormKey) from produces in mods.PriorityOrder.Armor().WinningOverrides() where cobj.CreatedObject.FormKey == produces.FormKey where produces.EditorID !.Contains($"[{SReplica}]") select(VanillaArmor: vanillaArmor, Recipe: cobj, Reforged: produces)); }
public void OrderListings() { ModKey baseEsm = new ModKey("Base", ModType.Master); ModKey baseEsm2 = new ModKey("Base2", ModType.Master); ModKey ccEsm = new ModKey("CC", ModType.Master); ModKey ccEsm2 = new ModKey("CC2", ModType.Master); ModKey ccEsl = new ModKey("CC", ModType.LightMaster); ModKey ccEsl2 = new ModKey("CC2", ModType.LightMaster); ModKey esm = new ModKey("Normal", ModType.Master); ModKey esm2 = new ModKey("Normal2", ModType.Master); ModKey esl = new ModKey("Normal", ModType.LightMaster); ModKey esl2 = new ModKey("Normal2", ModType.LightMaster); ModKey esp = new ModKey("Normal", ModType.Plugin); ModKey esp2 = new ModKey("Normal2", ModType.Plugin); var ordered = LoadOrder.OrderListings( implicitListings: new ModKey[] { baseEsm, baseEsm2, }, creationClubListings: new ModKey[] { ccEsl, ccEsl2, ccEsm, ccEsm2, }, pluginsListings: new ModKey[] { esm, esm2, esl, esl2, esp, esp2, }, selector: m => m) .ToList(); ordered.Should().Equal(new ModKey[] { baseEsm, baseEsm2, ccEsm, ccEsm2, ccEsl, ccEsl2, esm, esm2, esl, esl2, esp, esp2, }); }
public static ISkyrimModGetter?GetModByFileName(this LoadOrder <IModListing <ISkyrimModGetter> >?LoadOrder, string Name) { if (LoadOrder == null) { return(null); } var Mods = LoadOrder.Keys.Where(x => x.FileName.ToLower() == Name.ToLower()).ToList(); return((Mods.Count > 0) ?LoadOrder[Mods.First()].Mod : null); }
public Merger(string dataFolderPath, List <ModKey> plugins, ModKey outputKey) { _loadOrder = LoadOrder.Import( dataFolderPath, plugins, path => ModInstantiator <ISkyrimModGetter> .Importer(path, GameRelease.SkyrimSE)); _outputMod = new SkyrimMod(outputKey, SkyrimRelease.SkyrimSE); _outputPath = Path.Combine(dataFolderPath, outputKey.FileName); }
public void GetListings_VortexCreationClub() { using var tmp = Utility.GetTempFolder(nameof(LoadOrder_Tests)); var cccPath = Path.Combine(tmp.Dir.Path, "Skyrim.ccc"); var pluginsPath = Path.Combine(tmp.Dir.Path, "Plugins.txt"); var dataPath = Path.Combine(tmp.Dir.Path, "Data"); File.WriteAllLines(cccPath, new string[] { Utility.LightMasterModKey.FileName, Utility.LightMasterModKey2.FileName, }); File.WriteAllLines(pluginsPath, new string[] { Utility.LightMasterModKey2.FileName, Utility.LightMasterModKey.FileName, $"*{Utility.MasterModKey.FileName}", $"{Utility.MasterModKey2.FileName}", $"*{Utility.LightMasterModKey3.FileName}", $"{Utility.LightMasterModKey4.FileName}", $"*{Utility.PluginModKey.FileName}", $"{Utility.PluginModKey2.FileName}", }); Directory.CreateDirectory(dataPath); File.WriteAllText(Path.Combine(dataPath, Utility.LightMasterModKey.FileName), string.Empty); File.WriteAllText(Path.Combine(dataPath, Utility.LightMasterModKey2.FileName), string.Empty); File.WriteAllText(Path.Combine(dataPath, Utility.MasterModKey.FileName), string.Empty); File.WriteAllText(Path.Combine(dataPath, Utility.MasterModKey2.FileName), string.Empty); File.WriteAllText(Path.Combine(dataPath, Utility.LightMasterModKey3.FileName), string.Empty); File.WriteAllText(Path.Combine(dataPath, Utility.LightMasterModKey4.FileName), string.Empty); File.WriteAllText(Path.Combine(dataPath, Utility.PluginModKey.FileName), string.Empty); File.WriteAllText(Path.Combine(dataPath, Utility.PluginModKey2.FileName), string.Empty); var results = LoadOrder.GetListings( game: GameRelease.SkyrimSE, dataPath: dataPath, pluginsFilePath: pluginsPath, creationClubFilePath: cccPath) .ToList(); results.Should().HaveCount(8); results.Should().Equal(new LoadOrderListing[] { new LoadOrderListing(Utility.LightMasterModKey2, enabled: true), new LoadOrderListing(Utility.LightMasterModKey, enabled: true), new LoadOrderListing(Utility.MasterModKey, enabled: true), new LoadOrderListing(Utility.MasterModKey2, enabled: false), new LoadOrderListing(Utility.LightMasterModKey3, enabled: true), new LoadOrderListing(Utility.LightMasterModKey4, enabled: false), new LoadOrderListing(Utility.PluginModKey, enabled: true), new LoadOrderListing(Utility.PluginModKey2, enabled: false), }); }
public Program_Tests() { masterMod = new SkyrimMod(masterModKey, SkyrimRelease.SkyrimSE); patchMod = new SkyrimMod(patchModKey, SkyrimRelease.SkyrimSE); loadOrder = new LoadOrder <IModListing <ISkyrimModGetter> > { new ModListing <ISkyrimModGetter>(masterMod, true), new ModListing <ISkyrimModGetter>(patchMod, true) }; }
public static bool TryGetIfEnabledAndExists <TMod>(this LoadOrder <IModListing <TMod> > loadOrder, ModKey modKey, [MaybeNullWhen(false)] out TMod item) where TMod : class, IModGetter { if (!TryGetIfEnabled(loadOrder, modKey, out var listing)) { item = default; return(false); } item = listing.Mod; return(item != null); }
public override void OnLoad(PluginAssemblyPointer ptr) { //Call the Base OnLoad to Automatically do the registration. base.OnLoad(ptr); if (!isEmbedded) //Make sure that the Folder Packer is listed in the Init List and its one of the first things that get loaded. { LoadOrder.MoveToTop(LoadOrderQueue.Default, ptr.PluginName, true); } }
public void Comparer_LoadOrder_FallbackGreater() { var loadOrder = new LoadOrder <OblivionMod>() { new OblivionMod(ModKey.FromNameAndExtension("Oblivion.esm")), new OblivionMod(ModKey.FromNameAndExtension("Knights.esm")), }; FormKey k1 = FormKey.Factory("00C51A:Oblivion.esm"); FormKey k2 = FormKey.Factory("00C51B:Oblivion.esm"); var compare = FormKey.LoadOrderComparer(loadOrder); Assert.True(compare.Compare(k2, k1) > 0); }
public void Comparer_LoadOrder_Unknown() { var loadOrder = new LoadOrder <OblivionMod>() { new OblivionMod(ModKey.FromNameAndExtension("Oblivion.esm")), new OblivionMod(ModKey.FromNameAndExtension("Knights.esm")), }; FormKey k1 = FormKey.Factory("00C51A:MyMod.esm"); FormKey k2 = FormKey.Factory("00C51B:Oblivion.esm"); var compare = FormKey.LoadOrderComparer(loadOrder); Assert.Throws <ArgumentOutOfRangeException>(() => compare.Compare(k1, k2)); }