commit 947fcde9ca72e0d08fa8d4815943186ba96c7d03 Author: zznty <94796179+zznty@users.noreply.github.com> Date: Sun May 11 02:37:57 2025 +0700 1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..add57be --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ \ No newline at end of file diff --git a/.idea/.idea.Plugin.ClientModLoader/.idea/.gitignore b/.idea/.idea.Plugin.ClientModLoader/.idea/.gitignore new file mode 100644 index 0000000..bf3cc9e --- /dev/null +++ b/.idea/.idea.Plugin.ClientModLoader/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/projectSettingsUpdater.xml +/modules.xml +/contentModel.xml +/.idea.Plugin.ClientModLoader.iml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.Plugin.ClientModLoader/.idea/encodings.xml b/.idea/.idea.Plugin.ClientModLoader/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.Plugin.ClientModLoader/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.Plugin.ClientModLoader/.idea/git_toolbox_blame.xml b/.idea/.idea.Plugin.ClientModLoader/.idea/git_toolbox_blame.xml new file mode 100644 index 0000000..7dc1249 --- /dev/null +++ b/.idea/.idea.Plugin.ClientModLoader/.idea/git_toolbox_blame.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/.idea.Plugin.ClientModLoader/.idea/indexLayout.xml b/.idea/.idea.Plugin.ClientModLoader/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.Plugin.ClientModLoader/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.Plugin.ClientModLoader/.idea/vcs.xml b/.idea/.idea.Plugin.ClientModLoader/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/.idea.Plugin.ClientModLoader/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Plugin.ClientModLoader.sln.DotSettings.user b/Plugin.ClientModLoader.sln.DotSettings.user new file mode 100644 index 0000000..688a97f --- /dev/null +++ b/Plugin.ClientModLoader.sln.DotSettings.user @@ -0,0 +1,13 @@ + + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded \ No newline at end of file diff --git a/Plugin.ClientModLoader.slnx b/Plugin.ClientModLoader.slnx new file mode 100644 index 0000000..c34b7c4 --- /dev/null +++ b/Plugin.ClientModLoader.slnx @@ -0,0 +1,3 @@ + + + diff --git a/Plugin.ClientModLoader/ModInjector.cs b/Plugin.ClientModLoader/ModInjector.cs new file mode 100644 index 0000000..7a12da6 --- /dev/null +++ b/Plugin.ClientModLoader/ModInjector.cs @@ -0,0 +1,87 @@ +using System.Reflection.Emit; +using System.Runtime.CompilerServices; +using HarmonyLib; +using Sandbox.Definitions; +using Sandbox.Engine.Networking; +using Sandbox.Game.World; +using VRage.Game; + +namespace Plugin.ClientModLoader; + +[HarmonyPatch] +internal static class ModInjector +{ + public static HashSet Mods = []; + private static readonly List AdditionalFilledModItems = []; + + [HarmonyPatch(typeof(MyWorkshop), nameof(MyWorkshop.DownloadWorldModsBlockingInternal))] + [HarmonyPrefix] + private static void DownloadModsBlockingPrefix(ref List mods, ref List __state) + { + AdditionalFilledModItems.Clear(); + __state = mods; + AppendToList(ref mods); + } + + [HarmonyPatch(typeof(MyWorkshop), nameof(MyWorkshop.DownloadWorldModsBlockingInternal))] + [HarmonyPostfix] + private static void DownloadModsBlockingPostfix(List mods, List __state) + { + foreach (var mod in mods) + { + var index = __state.FindIndex(b => + b.PublishedFileId == mod.PublishedFileId && b.PublishedServiceName == mod.PublishedServiceName); + + if (index != -1) + { + var stateMod = __state[index]; + stateMod.SetModData(mod.GetModData()); + __state[index] = stateMod; + } + else if (Mods.Contains(mod.PublishedFileId)) + AdditionalFilledModItems.Add(mod); + else + __state.Add(mod); + } + } + + [HarmonyPatch(typeof(MyDefinitionManager), nameof(MyDefinitionManager.LoadData))] + [HarmonyPrefix] + private static void LoadDefinitionsPrefix(ref List mods) => AppendToList(ref mods); + + [HarmonyPatch(typeof(MyScriptManager), nameof(MyScriptManager.LoadData))] + [HarmonyTranspiler] + private static IEnumerable LoadScriptsTranspiler(IEnumerable instructions, ILGenerator generator) + { + var staticGetter = AccessTools.PropertyGetter(typeof(MySession), nameof(MySession.Static)); + var modsGetter = AccessTools.PropertyGetter(typeof(MySession), nameof(MySession.Mods)); + return new CodeMatcher(instructions, generator) + .Start() + .DeclareLocal(typeof(List), out var modsLocal) + .CreateLabel(out var start) + .InsertAndAdvance( + new(OpCodes.Call, staticGetter), + new(OpCodes.Call, modsGetter), + new(OpCodes.Stloc, modsLocal), + new(OpCodes.Ldloc, modsLocal), + new(OpCodes.Brfalse, start), + new(OpCodes.Ldloca, modsLocal), + CodeInstruction.Call(typeof(ModInjector), nameof(AppendToList)) + ) + .MatchStartForward(CodeMatch.Calls(staticGetter), CodeMatch.Calls(modsGetter)) + .Repeat(a => a + .SetAndAdvance(OpCodes.Ldloc, modsLocal) + .SetAndAdvance(OpCodes.Nop, null)) + .Instructions(); + } + + private static void AppendToList(ref List mods) + { + // copy + mods = mods.ToList(); + + mods.AddRange(AdditionalFilledModItems.Count > 0 + ? AdditionalFilledModItems + : Mods.Select(mod => new MyObjectBuilder_Checkpoint.ModItem(mod, "Steam"))); + } +} \ No newline at end of file diff --git a/Plugin.ClientModLoader/ModListComponent.cs b/Plugin.ClientModLoader/ModListComponent.cs new file mode 100644 index 0000000..25dc673 --- /dev/null +++ b/Plugin.ClientModLoader/ModListComponent.cs @@ -0,0 +1,321 @@ +using System.Collections.Immutable; +using System.Net.Http.Json; +using System.Runtime.InteropServices; +using System.Text.Json; +using CringePlugins.Abstractions; +using ImGuiNET; +using Plugin.ClientModLoader.Utils; +using Steamworks; +using VRage; +using static ImGuiNET.ImGui; + +namespace Plugin.ClientModLoader; + +public class ModListComponent : IRenderComponent +{ + private readonly string _configPath; + private readonly JsonSerializerOptions _options = new(JsonSerializerDefaults.Web); + + private bool _visible; + private string _searchQuery = string.Empty; + private Task? _searchTask; + + private PublishedFileId_t[] _mods = []; + private ImmutableDictionary _whitelist = ImmutableDictionary.Empty; + + private List _modList = []; + private ModItem? _selected; + public HashSet Installed { get; } + + public bool Visible + { + get => _visible; + set => _visible = value; + } + + public ModListComponent(string configPath) + { + _configPath = configPath; + if (File.Exists(configPath)) + { + using var stream = File.OpenRead(configPath); + Installed = JsonSerializer.Deserialize>(stream, _options)!; + } + else Installed = []; + + _searchTask = DownloadWhitelist(); + } + + private async Task DownloadWhitelist() + { + using var client = new HttpClient(); + var response = + await client.GetFromJsonAsync( + "https://github.com/sepluginloader/sepluginloader.github.io/raw/refs/heads/main/plugins.json"); + + if (response is null) return; + + var mods = new List(); + var builder = ImmutableDictionary.CreateBuilder(); + + foreach (var item in response.Mods) + { + if (!ulong.TryParse(item.Id, out var id)) continue; + + mods.Add(new PublishedFileId_t(id)); + builder.Add(id, item); + } + + _mods = mods.ToArray(); + _whitelist = builder.ToImmutable(); + await RefreshAsync(); + } + + public void OnFrame() + { + if (!Visible) return; + SetNextWindowSize(new(700, 500), ImGuiCond.FirstUseEver); + if (!Begin("Mod List", ref _visible)) return; + + try + { + InputText("##searchbox", ref _searchQuery, 256); + + SameLine(); + + if (Button("Search")) + { + _searchTask = RefreshAsync(); + return; + } + + Spacing(); + + switch (_searchTask) + { + case { IsCompleted: false }: + TextDisabled("Loading..."); + return; + case { IsCompletedSuccessfully: false }: + { + TextDisabled("Failed to load plugins list"); + if (_searchTask.Exception is null) return; + + foreach (var exception in _searchTask.Exception.InnerExceptions) + { + TextWrapped($"{exception.GetType()}: {exception.Message}"); + } + + return; + } + } + + if (_modList.Count == 0) + { + TextDisabled("Nothing found"); + return; + } + + BeginChild("List", new(400, 0), ImGuiChildFlags.Border | ImGuiChildFlags.ResizeX); + { + if (BeginTable("AvailableModsTable", 3, + ImGuiTableFlags.ScrollY | ImGuiTableFlags.Resizable | ImGuiTableFlags.SizingStretchProp)) + { + TableSetupColumn("Name", ImGuiTableColumnFlags.None, .75f); + TableSetupColumn("Installed", ImGuiTableColumnFlags.None, .25f); + TableHeadersRow(); + + foreach (var mod in _modList) + { + TableNextRow(); + + TableNextColumn(); + + var selected = _selected == mod; + + if (Selectable(mod.Name, ref selected, ImGuiSelectableFlags.SpanAllColumns)) + { + _selected = selected ? mod : null; + } + + if (!string.IsNullOrEmpty(mod.Summary) && IsItemHovered(ImGuiHoveredFlags.ForTooltip)) + { + SetTooltip(mod.Summary); + } + + TableNextColumn(); + + var installed = Installed.Contains(mod.Id); + TextColored(installed ? new(0f, 1f, 0f, 1f) : new(1f, 0f, 0f, 1f), + installed ? "Installed" : "Not Installed"); + } + + EndTable(); + } + + EndChild(); + } + + SameLine(); + + BeginGroup(); + + BeginChild("Mod View", new(0, -GetFrameHeightWithSpacing())); // Leave room for 1 line below us + + if (_selected is not null) + { + Text(_selected.Name); + Separator(); + if (BeginTabBar("##ModViewTabs")) + { + if (!string.IsNullOrEmpty(_selected.Description) && BeginTabItem("Description")) + { + TextWrapped(_selected.Description); + EndTabItem(); + } + + if (BeginTabItem("Mod Description")) + { + TextWrapped(string.IsNullOrEmpty(_selected.ModDescription) ? "Nothing." : _selected.ModDescription); + EndTabItem(); + } + + if (BeginTabItem("Details")) + { + TextLinkOpenURL("Mod URL", _selected.Url); + + Text("Author:"); + SameLine(); + TextWrapped(_selected.Author); + + Text("Created:"); + SameLine(); + TextWrapped(DateTimeOffset.FromUnixTimeSeconds(_selected.Created).ToString("g")); + + Text("Updated:"); + SameLine(); + TextWrapped(DateTimeOffset.FromUnixTimeSeconds(_selected.Updated).ToString("g")); + + EndTabItem(); + } + + EndTabBar(); + } + } + + EndChild(); + + if (_selected is not null) + { + var installed = Installed.Contains(_selected.Id); + if (Button(installed ? "Uninstall" : "Install")) + { + if (installed) + Installed.Remove(_selected.Id); + else + Installed.Add(_selected.Id); + + Save(); + } + } + + EndGroup(); + } + finally + { + End(); + } + } + + + private void Save() + { + using var stream = File.Create(_configPath); + + JsonSerializer.Serialize(stream, Installed, _options); + } + + private async Task RefreshAsync() + { + var handle = SteamUGC.CreateQueryUGCDetailsRequest(_mods, (uint)_mods.Length); + + if (handle.m_UGCQueryHandle == ulong.MaxValue) + throw new Exception("Failed to create UGC request"); + + try + { + SteamUGC.SetSearchText(handle, _searchQuery); + SteamUGC.SetReturnLongDescription(handle, true); + // TODO font support for other languages + // SteamUGC.SetLanguage(handle, MapLanguage(MySandboxGame.Config.Language)); + + var call = SteamUGC.SendQueryUGCRequest(handle); + + var result = await CallResultAsync.Create(call); + + var list = new List((int)result.m_unNumResultsReturned); + + for (uint i = 0; i < result.m_unNumResultsReturned; i++) + { + if (!SteamUGC.GetQueryUGCResult(handle, i, out var details)) + break; + if (details.m_eResult != EResult.k_EResultOK) + continue; + + var title = details.m_rgchTitle; + + if (!string.IsNullOrEmpty(_searchQuery) && !title.Contains(_searchQuery, StringComparison.OrdinalIgnoreCase)) + continue; + + var item = _whitelist[details.m_nPublishedFileId.m_PublishedFileId]; + + var description = details.m_rgchDescription; + list.Add(new(details.m_nPublishedFileId.m_PublishedFileId, title, + string.IsNullOrEmpty(item.Tooltip) + ? description[..Math.Min(description.Length - 1, 255)] + : item.Tooltip, + item.Description, + description, $"https://steamcommunity.com/sharedfiles/filedetails/?id={details.m_nPublishedFileId.m_PublishedFileId}", + details.m_rtimeCreated, details.m_rtimeUpdated, item.Author)); + } + + _modList = list; + } + finally + { + SteamUGC.ReleaseQueryUGCRequest(handle); + } + } + + private static string MapLanguage(MyLanguagesEnum lang) => + lang switch + { + MyLanguagesEnum.Czech => "czech", + MyLanguagesEnum.German => "german", + MyLanguagesEnum.Russian => "russian", + MyLanguagesEnum.Spanish_Spain => "spanish", + MyLanguagesEnum.French => "french", + MyLanguagesEnum.Italian => "italian", + MyLanguagesEnum.Danish => "danish", + MyLanguagesEnum.Dutch => "dutch", + MyLanguagesEnum.Polish => "polish", + MyLanguagesEnum.Finnish => "finnish", + MyLanguagesEnum.Hungarian => "hungarian", + MyLanguagesEnum.Portuguese_Brazil => "brazilian", + MyLanguagesEnum.Norwegian => "norwegian", + MyLanguagesEnum.Spanish_HispanicAmerica => "latam", + MyLanguagesEnum.Swedish => "swedish", + MyLanguagesEnum.Romanian => "romanian", + MyLanguagesEnum.Ukrainian => "ukrainian", + MyLanguagesEnum.Turkish => "turkish", + MyLanguagesEnum.ChineseChina => "schinese", + MyLanguagesEnum.Japanese => "japanese", + _ => "english", + }; + + private record ModItem(ulong Id, string Name, string Summary, string? Description, string ModDescription, string Url, long Created, long Updated, string Author); + + private record WhitelistItem(string Id, string? Tooltip, string Author, string? Description); + + private record Whitelist(ImmutableArray Mods); +} \ No newline at end of file diff --git a/Plugin.ClientModLoader/Plugin.ClientModLoader.csproj b/Plugin.ClientModLoader/Plugin.ClientModLoader.csproj new file mode 100644 index 0000000..95bbe6f --- /dev/null +++ b/Plugin.ClientModLoader/Plugin.ClientModLoader.csproj @@ -0,0 +1,21 @@ + + + + net9.0-windows + enable + enable + win-x64 + True + true + true + true + https://ng.zznty.ru/v3/index.json + true + + + + + + + + diff --git a/Plugin.ClientModLoader/Plugin.cs b/Plugin.ClientModLoader/Plugin.cs new file mode 100644 index 0000000..04d5746 --- /dev/null +++ b/Plugin.ClientModLoader/Plugin.cs @@ -0,0 +1,34 @@ +using CringePlugins.Render; +using HarmonyLib; +using VRage.Plugins; + +namespace Plugin.ClientModLoader; + +public class Plugin : IPlugin +{ + private ModListComponent? _component; + + private readonly DirectoryInfo _dir = + new(Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "CringeLauncher")); + + public void Dispose() + { + } + + public void Init(object gameInstance) + { + new Harmony("Plugin.ClientModLoader").PatchAll(typeof(Plugin).Assembly); + RenderHandler.Current.RegisterComponent(_component = new ModListComponent(Path.Join(_dir.FullName, "mods.json"))); + ModInjector.Mods = _component.Installed; + } + + public void Update() + { + } + + public void OpenConfigDialog() + { + if (_component != null) _component.Visible = true; + } +} \ No newline at end of file diff --git a/Plugin.ClientModLoader/Utils/CallResultAsync.cs b/Plugin.ClientModLoader/Utils/CallResultAsync.cs new file mode 100644 index 0000000..a9e20bd --- /dev/null +++ b/Plugin.ClientModLoader/Utils/CallResultAsync.cs @@ -0,0 +1,32 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Steamworks; + +namespace Plugin.ClientModLoader.Utils; + +public static class CallResultAsync where T : struct +{ + public static async Task Create(SteamAPICall_t call) + { + var tcs = new TaskCompletionSource(); + using var callResult = CallResult.Create((args, failed) => + { + if (failed) + { + ref var result = ref Unsafe.As(ref args); + tcs.TrySetException(new Exception($"CallResult failed: {result.m_eResult}")); + } + else tcs.TrySetResult(args); + }); + callResult.Set(call); + + return await tcs.Task; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + private struct GenericCallResult + { + public UGCQueryHandle_t m_handle; + public EResult m_eResult; + } +} \ No newline at end of file diff --git a/Plugin.ClientModLoader/packages.lock.json b/Plugin.ClientModLoader/packages.lock.json new file mode 100644 index 0000000..a993fb3 --- /dev/null +++ b/Plugin.ClientModLoader/packages.lock.json @@ -0,0 +1,201 @@ +{ + "version": 1, + "dependencies": { + "net9.0-windows7.0": { + "CringePlugins": { + "type": "Direct", + "requested": "[*, )", + "resolved": "0.1.51", + "contentHash": "6v6FfWlrLge3E67R75P/svFtvbAodzffwMyISUYFrZK6XTYsLPLExegnHswPNMC1PFbwD5ukhXYF9eUgIluubQ==", + "dependencies": { + "ImGui.NET.DirectX": "1.91.0.1", + "Lib.Harmony.Thin": "2.3.4-torch", + "NLog": "5.4.0", + "NuGet": "0.1.51", + "SharedCringe": "0.1.51", + "SpaceEngineersDedicated.ReferenceAssemblies": "1.206.30", + "dnlib": "4.4.0" + } + }, + "Steamworks.NET": { + "type": "Direct", + "requested": "[20.1.0, )", + "resolved": "20.1.0", + "contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ==" + }, + "CringeBootstrap.Abstractions": { + "type": "Transitive", + "resolved": "0.1.51", + "contentHash": "dpA0Tr7Ir+6WzlVq98on0kxcEwpUr/arl0+8EX3QPsO2tXYTuRJRDMqy4SlMjN5t+xDfT/iILzkcUldIfogE8A==" + }, + "dnlib": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "cKHI720q+zfEEvzklWVGt6B0TH3AibAyJbpUJl4U6KvTP13tycfnqJpkGHRZ/oQ45BTIoIxIwltHIJVDN+iCqQ==" + }, + "ImGui.NET.DirectX": { + "type": "Transitive", + "resolved": "1.91.0.1", + "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "Lib.Harmony.Thin": { + "type": "Transitive", + "resolved": "2.3.4-torch", + "contentHash": "UnLUnLLiXfHZdKa1zhi6w8cl8tJTrpVixLtvjFEVtlDA6Rkf06OcZ2gSidcbcgKjTcR+fk5Qsdos3mU5oohzfg==", + "dependencies": { + "MonoMod.Core": "1.2.2", + "System.Text.Json": "9.0.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, + "Mono.Cecil": { + "type": "Transitive", + "resolved": "0.11.5", + "contentHash": "fxfX+0JGTZ8YQeu1MYjbBiK2CYTSzDyEeIixt+yqKKTn7FW8rv7JMY70qevup4ZJfD7Kk/VG/jDzQQTpfch87g==" + }, + "MonoMod.Backports": { + "type": "Transitive", + "resolved": "1.1.2", + "contentHash": "baYlNy8n8kmaNhNvqmZ/dIPOeO1r9//dG1i2WbunMWtWZ2EKtIgmXaS+ZzphzTsikkGnoD4Jwr5g0TVdpDjgpw==", + "dependencies": { + "MonoMod.ILHelpers": "1.1.0" + } + }, + "MonoMod.Core": { + "type": "Transitive", + "resolved": "1.2.2", + "contentHash": "3R9mQ7TxeQQBFLtGTR2VIDSBGx/I7d8RYpxvW1Mot0/PB6+UOnHr+lkw7dj8cus8YSnLdCFT+CG4JW89daEvjg==", + "dependencies": { + "Mono.Cecil": "0.11.5", + "MonoMod.Backports": "1.1.2", + "MonoMod.ILHelpers": "1.1.0", + "MonoMod.Utils": "25.0.8" + } + }, + "MonoMod.ILHelpers": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "L2FWjhTrv7tcIxshfZ+M3OcaNr4cNw0IwiVZEgwqRnZ5QAN3+RrNJ8ZwCzwXUWyPDqooJxMcjjg8PsSYUiNBjQ==" + }, + "MonoMod.Utils": { + "type": "Transitive", + "resolved": "25.0.8", + "contentHash": "8wfyawgvGqUvfchAj7/gPazAjXO8CWNyXH+C0az+hgJH/80zVL5LxDhQMz0NQTyoCEJWU6gNBGc7CL+G7vCbaQ==", + "dependencies": { + "Mono.Cecil": "0.11.5", + "MonoMod.Backports": "1.1.2", + "MonoMod.ILHelpers": "1.1.0" + } + }, + "NLog": { + "type": "Transitive", + "resolved": "5.4.0", + "contentHash": "LwMcGSW3soF3/SL68rlJN3Eh3ktrAPycC3zZR/07OYBPraZUu0bygEC7kIN10lUQgMXT4s84Fi1chglGdGrQEg==" + }, + "NuGet": { + "type": "Transitive", + "resolved": "0.1.51", + "contentHash": "fwUsNKy/EQB26JocU3suqYqFqbQ8mb63Ri5NGf7OPy7zLooxHNUYaN+MuBhbshveP+8IKdlPfc8UkrFyzKK8PA==", + "dependencies": { + "NuGet.Frameworks": "6.13.2", + "NuGet.Versioning": "6.13.2", + "System.Linq.Async": "6.0.1" + } + }, + "NuGet.Frameworks": { + "type": "Transitive", + "resolved": "6.13.2", + "contentHash": "SQKUf56j7IdJL//fU7fcmn234awjRA2qLvgbfs/TxmY7oJrNOxaaDxASyCbS4eJW3LCOd6ONHMZ/cPlbQh4xVg==" + }, + "NuGet.Versioning": { + "type": "Transitive", + "resolved": "6.13.2", + "contentHash": "pGYNyvCVM+Z9jITTiJiuxFC8oJXFdh2k25ZDV4tSAOSuKyAWvh1VcfJy0WZGWdI6J7Avkbl0qra7XENYFSy4Ng==" + }, + "protobuf-net": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "kTGOK0E87473sOImOjgZOnz3kTC2aMLffoRWQLYNuBLJnwNNmjanF9IkevZ9Q7yYLeABQfcF3BpeepuMntMVNw==" + }, + "SharedCringe": { + "type": "Transitive", + "resolved": "0.1.51", + "contentHash": "9QargvU/hAVUXt1QZaeCHExmoYfrtHP9Vq9X5oMbIX8lOCmjulZx0rSuwoDR46/I1eu4+xVvM78/u+F4UiP6uw==", + "dependencies": { + "CringeBootstrap.Abstractions": "0.1.51", + "NLog": "5.4.0", + "SpaceEngineersDedicated.ReferenceAssemblies": "1.206.30" + } + }, + "SharpDX": { + "type": "Transitive", + "resolved": "4.2.0-keen-cringe", + "contentHash": "LaJN3h1Gi1FWVdef2I5WtOH9gwzKCBniH0CragarbkN2QheYY6Lqm+91PcOfp1w/4wdVb+k8Kjv3sO393Tphtw==" + }, + "SpaceEngineersDedicated.ReferenceAssemblies": { + "type": "Transitive", + "resolved": "1.206.30", + "contentHash": "xk/EgMhbG7oT4fPzW1DcFT8tYkxJFPK3+j+t4vms9a/wz8cCmszbilA2Y+JWIpmauUDcfovX8eqAOKlgz3dpcg==", + "dependencies": { + "SharpDX": "4.2.0-keen-cringe", + "protobuf-net": "1.0.0" + } + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Linq.Async": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "js7+qAu/9mQvnhA4EfGMZNEzXtJCDxgkgj8ohuxq/Qxv+R56G+ljefhiJHOxTNiw54q8vmABCWUwkMulNdlZ4A==" + } + }, + "net9.0-windows7.0/win-x64": { + "Steamworks.NET": { + "type": "Direct", + "requested": "[20.1.0, )", + "resolved": "20.1.0", + "contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ==" + }, + "ImGui.NET.DirectX": { + "type": "Transitive", + "resolved": "1.91.0.1", + "contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + } + } + } +} \ No newline at end of file