image loader for imgui and optional nuget icons for plugins in browse tab
All checks were successful
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 4m13s
Build / Build Nuget package (NuGet) (push) Successful in 4m12s
Build / Build Nuget package (CringePlugins) (push) Successful in 4m16s
Build / Build Nuget package (SharedCringe) (push) Successful in 4m11s
Build / Build Launcher (push) Successful in 5m13s
All checks were successful
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 4m13s
Build / Build Nuget package (NuGet) (push) Successful in 4m12s
Build / Build Nuget package (CringePlugins) (push) Successful in 4m16s
Build / Build Nuget package (SharedCringe) (push) Successful in 4m11s
Build / Build Launcher (push) Successful in 5m13s
This commit is contained in:
@@ -434,6 +434,7 @@
|
|||||||
"ImGui.NET.DirectX": "[1.91.0.1, )",
|
"ImGui.NET.DirectX": "[1.91.0.1, )",
|
||||||
"JsonSchema.Net.Generation": "[5.0.2, )",
|
"JsonSchema.Net.Generation": "[5.0.2, )",
|
||||||
"Lib.Harmony.Thin": "[2.3.4-torch, )",
|
"Lib.Harmony.Thin": "[2.3.4-torch, )",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.5, )",
|
||||||
"NLog": "[5.4.0, )",
|
"NLog": "[5.4.0, )",
|
||||||
"NuGet": "[1.0.0, )",
|
"NuGet": "[1.0.0, )",
|
||||||
"SharedCringe": "[1.0.0, )",
|
"SharedCringe": "[1.0.0, )",
|
||||||
|
@@ -7,7 +7,9 @@ using Windows.Win32.Foundation;
|
|||||||
using Windows.Win32.UI.WindowsAndMessaging;
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
using CringePlugins.Abstractions;
|
using CringePlugins.Abstractions;
|
||||||
using CringePlugins.Render;
|
using CringePlugins.Render;
|
||||||
|
using CringePlugins.Services;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using SharpDX.Direct3D11;
|
using SharpDX.Direct3D11;
|
||||||
using static ImGuiNET.ImGui;
|
using static ImGuiNET.ImGui;
|
||||||
using VRage;
|
using VRage;
|
||||||
@@ -36,12 +38,14 @@ internal sealed class ImGuiHandler : IGuiHandler, IDisposable
|
|||||||
public static RenderTargetView? Rtv;
|
public static RenderTargetView? Rtv;
|
||||||
|
|
||||||
private readonly IRootRenderComponent _renderHandler;
|
private readonly IRootRenderComponent _renderHandler;
|
||||||
|
private readonly ImGuiImageService _imageService;
|
||||||
private static bool _init;
|
private static bool _init;
|
||||||
|
|
||||||
public ImGuiHandler(DirectoryInfo configDir)
|
public ImGuiHandler(DirectoryInfo configDir)
|
||||||
{
|
{
|
||||||
_configDir = configDir;
|
_configDir = configDir;
|
||||||
_renderHandler = new RenderHandler(this);
|
_renderHandler = new RenderHandler(this);
|
||||||
|
_imageService = (ImGuiImageService)GameServicesExtension.GameServices.GetRequiredService<IImGuiImageService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void Init(nint windowHandle, Device1 device, DeviceContext deviceContext)
|
public unsafe void Init(nint windowHandle, Device1 device, DeviceContext deviceContext)
|
||||||
@@ -62,6 +66,8 @@ internal sealed class ImGuiHandler : IGuiHandler, IDisposable
|
|||||||
ImGui_ImplWin32_Init(windowHandle);
|
ImGui_ImplWin32_Init(windowHandle);
|
||||||
ImGui_ImplDX11_Init(device.NativePointer, deviceContext.NativePointer);
|
ImGui_ImplDX11_Init(device.NativePointer, deviceContext.NativePointer);
|
||||||
_init = true;
|
_init = true;
|
||||||
|
|
||||||
|
_imageService.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void HookWindow(HWND windowHandle)
|
public static void HookWindow(HWND windowHandle)
|
||||||
@@ -117,6 +123,8 @@ internal sealed class ImGuiHandler : IGuiHandler, IDisposable
|
|||||||
|
|
||||||
UpdatePlatformWindows();
|
UpdatePlatformWindows();
|
||||||
RenderPlatformWindowsDefault();
|
RenderPlatformWindowsDefault();
|
||||||
|
|
||||||
|
_imageService.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
|
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Reflection;
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
@@ -161,15 +162,26 @@ public class Launcher : ICorePlugin
|
|||||||
{
|
{
|
||||||
var services = new ServiceCollection();
|
var services = new ServiceCollection();
|
||||||
|
|
||||||
|
var retryPolicy = HttpPolicyExtensions.HandleTransientHttpError()
|
||||||
|
.WaitAndRetryAsync(5, _ => TimeSpan.FromSeconds(1));
|
||||||
|
|
||||||
services.AddHttpClient<PluginsLifetime>()
|
services.AddHttpClient<PluginsLifetime>()
|
||||||
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
|
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
|
||||||
{
|
{
|
||||||
AutomaticDecompression = System.Net.DecompressionMethods.All
|
AutomaticDecompression = DecompressionMethods.All
|
||||||
})
|
})
|
||||||
.AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(5, _ => TimeSpan.FromSeconds(1)));
|
.AddPolicyHandler(retryPolicy);
|
||||||
|
|
||||||
|
services.AddHttpClient<ImGuiImageService>()
|
||||||
|
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
|
||||||
|
{
|
||||||
|
AutomaticDecompression = DecompressionMethods.All
|
||||||
|
})
|
||||||
|
.AddPolicyHandler(retryPolicy);
|
||||||
|
|
||||||
services.AddSingleton(_ => RenderHandler.Current)
|
services.AddSingleton(_ => RenderHandler.Current)
|
||||||
.AddSingleton<IPluginsLifetime>(s => s.GetRequiredService<PluginsLifetime>())
|
.AddSingleton<IPluginsLifetime>(s => s.GetRequiredService<PluginsLifetime>())
|
||||||
|
.AddSingleton<IImGuiImageService>(s => s.GetRequiredService<ImGuiImageService>())
|
||||||
.AddSingleton(_ => new ConfigHandler(_configDir));
|
.AddSingleton(_ => new ConfigHandler(_configDir));
|
||||||
|
|
||||||
return GameServicesExtension.GameServices = services.BuildServiceProvider();
|
return GameServicesExtension.GameServices = services.BuildServiceProvider();
|
||||||
|
@@ -455,6 +455,7 @@
|
|||||||
"ImGui.NET.DirectX": "[1.91.0.1, )",
|
"ImGui.NET.DirectX": "[1.91.0.1, )",
|
||||||
"JsonSchema.Net.Generation": "[5.0.2, )",
|
"JsonSchema.Net.Generation": "[5.0.2, )",
|
||||||
"Lib.Harmony.Thin": "[2.3.4-torch, )",
|
"Lib.Harmony.Thin": "[2.3.4-torch, )",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.5, )",
|
||||||
"NLog": "[5.4.0, )",
|
"NLog": "[5.4.0, )",
|
||||||
"NuGet": "[1.0.0, )",
|
"NuGet": "[1.0.0, )",
|
||||||
"SharedCringe": "[1.0.0, )",
|
"SharedCringe": "[1.0.0, )",
|
||||||
|
@@ -20,11 +20,13 @@
|
|||||||
<Publicize Include="VRage:VRage.Plugins.MyPlugins.m_plugins" />
|
<Publicize Include="VRage:VRage.Plugins.MyPlugins.m_plugins" />
|
||||||
<Publicize Include="VRage:VRage.Plugins.MyPlugins.m_handleInputPlugins" />
|
<Publicize Include="VRage:VRage.Plugins.MyPlugins.m_handleInputPlugins" />
|
||||||
<Publicize Include="VRage.Render11:VRageRender.MyCommon" />
|
<Publicize Include="VRage.Render11:VRageRender.MyCommon" />
|
||||||
|
<Publicize Include="VRage.Render11:VRageRender.MyRender11.DeviceInstance" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Basic.Reference.Assemblies.Net90" Version="1.8.0" PrivateAssets="all" />
|
<PackageReference Include="Basic.Reference.Assemblies.Net90" Version="1.8.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="JsonSchema.Net.Generation" Version="5.0.2" />
|
<PackageReference Include="JsonSchema.Net.Generation" Version="5.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.5" />
|
||||||
<PackageReference Include="NLog" Version="5.4.0" />
|
<PackageReference Include="NLog" Version="5.4.0" />
|
||||||
<PackageReference Include="Lib.Harmony.Thin" Version="2.3.4-torch" />
|
<PackageReference Include="Lib.Harmony.Thin" Version="2.3.4-torch" />
|
||||||
<PackageReference Include="ImGui.NET.DirectX" Version="1.91.0.1" />
|
<PackageReference Include="ImGui.NET.DirectX" Version="1.91.0.1" />
|
||||||
|
243
CringePlugins/Services/ImGuiImageService.cs
Normal file
243
CringePlugins/Services/ImGuiImageService.cs
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using NLog;
|
||||||
|
using SharpDX.Direct3D11;
|
||||||
|
using SharpDX.DXGI;
|
||||||
|
using VRage.Collections;
|
||||||
|
using VRageRender;
|
||||||
|
|
||||||
|
namespace CringePlugins.Services;
|
||||||
|
|
||||||
|
public interface IImGuiImageService
|
||||||
|
{
|
||||||
|
ImGuiImage GetFromUrl(Uri url);
|
||||||
|
ImGuiImage GetFromPath(string path);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class ImGuiImageService(HttpClient client) : IImGuiImageService
|
||||||
|
{
|
||||||
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
private readonly string _dir = Directory.CreateDirectory(
|
||||||
|
Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "CringeLauncher", "cache", "images")).FullName;
|
||||||
|
private readonly CachingDictionary<ImageIdentifier, Image> _images = [];
|
||||||
|
private readonly Dictionary<ImageIdentifier, ImageReference> _imageReferences = [];
|
||||||
|
private readonly Dictionary<WebImageIdentifier, EntityTagHeaderValue> _webCacheEtag = [];
|
||||||
|
private Image? _placeholderImage;
|
||||||
|
|
||||||
|
internal void Initialize()
|
||||||
|
{
|
||||||
|
using var tex = new Texture2D(MyRender11.DeviceInstance, new()
|
||||||
|
{
|
||||||
|
Width = 1,
|
||||||
|
Height = 1,
|
||||||
|
Format = Format.R8G8B8A8_UNorm,
|
||||||
|
MipLevels = 1,
|
||||||
|
ArraySize = 1,
|
||||||
|
SampleDescription = new()
|
||||||
|
{
|
||||||
|
Count = 1
|
||||||
|
},
|
||||||
|
Usage = ResourceUsage.Default,
|
||||||
|
BindFlags = BindFlags.ShaderResource,
|
||||||
|
CpuAccessFlags = CpuAccessFlags.None,
|
||||||
|
OptionFlags = ResourceOptionFlags.None,
|
||||||
|
});
|
||||||
|
|
||||||
|
var srv = new ShaderResourceView(MyRender11.DeviceInstance, tex);
|
||||||
|
|
||||||
|
_placeholderImage = new Image(null!, srv, new(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Update()
|
||||||
|
{
|
||||||
|
foreach (var (identifier, image) in _images)
|
||||||
|
{
|
||||||
|
if (!image.IsUnused)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_images.Remove(identifier);
|
||||||
|
_imageReferences.Remove(identifier);
|
||||||
|
image.Dispose();
|
||||||
|
}
|
||||||
|
_images.ApplyRemovals();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImGuiImage GetFromUrl(Uri url)
|
||||||
|
{
|
||||||
|
var identifier = new WebImageIdentifier(url);
|
||||||
|
if (_images.TryGetValue(identifier, out var image))
|
||||||
|
return image;
|
||||||
|
if (_imageReferences.TryGetValue(identifier, out var imageReference))
|
||||||
|
return imageReference;
|
||||||
|
|
||||||
|
var cachePath = Path.Join(_dir,
|
||||||
|
Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(url.ToString()))));
|
||||||
|
|
||||||
|
var reference = new ImageReference(_placeholderImage!);
|
||||||
|
LoadAsync(url, cachePath, reference);
|
||||||
|
_imageReferences.Add(identifier, reference);
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void LoadAsync(Uri url, string cachePath, ImageReference reference)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||||
|
if (_webCacheEtag.TryGetValue(new(url), out var existingEtag))
|
||||||
|
request.Headers.IfNoneMatch.Add(existingEtag);
|
||||||
|
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
||||||
|
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
if (response.Headers.ETag is { } etag)
|
||||||
|
_webCacheEtag[new(url)] = etag;
|
||||||
|
|
||||||
|
if (!File.Exists(cachePath) || (response.StatusCode != HttpStatusCode.NotModified &&
|
||||||
|
!CompareCache(cachePath, response.Headers)))
|
||||||
|
{
|
||||||
|
await using var stream = await response.Content.ReadAsStreamAsync();
|
||||||
|
await using var file = File.Create(cachePath);
|
||||||
|
await stream.CopyToAsync(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
reference.Image = GetFromPath(cachePath);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error(e, "Failed to load image {Url}", url);
|
||||||
|
reference.ErrorImage = null; // todo make an error image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CompareCache(string path, HttpResponseHeaders headers)
|
||||||
|
{
|
||||||
|
if (headers.CacheControl is not { } cacheControl)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (cacheControl.NoCache)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (cacheControl.MaxAge.HasValue)
|
||||||
|
{
|
||||||
|
var responseAge = DateTimeOffset.UtcNow - cacheControl.MaxAge.Value;
|
||||||
|
return File.GetLastWriteTimeUtc(path) > responseAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImGuiImage GetFromPath(string path)
|
||||||
|
{
|
||||||
|
path = Path.GetFullPath(path);
|
||||||
|
var identifier = new FileImageIdentifier(path);
|
||||||
|
if (_images.TryGetValue(identifier, out var image))
|
||||||
|
return image;
|
||||||
|
|
||||||
|
if (!File.Exists(path))
|
||||||
|
throw new FileNotFoundException(null, path);
|
||||||
|
|
||||||
|
using var img = SharpDX.Toolkit.Graphics.Image.Load(path);
|
||||||
|
|
||||||
|
var desc = img.Description;
|
||||||
|
using var tex = new Texture2D(MyRender11.DeviceInstance, new()
|
||||||
|
{
|
||||||
|
Width = desc.Width,
|
||||||
|
Height = desc.Height,
|
||||||
|
Format = desc.Format,
|
||||||
|
MipLevels = desc.MipLevels,
|
||||||
|
ArraySize = desc.ArraySize,
|
||||||
|
SampleDescription = new()
|
||||||
|
{
|
||||||
|
Count = 1
|
||||||
|
},
|
||||||
|
Usage = ResourceUsage.Default,
|
||||||
|
BindFlags = BindFlags.ShaderResource,
|
||||||
|
CpuAccessFlags = CpuAccessFlags.None,
|
||||||
|
OptionFlags = ResourceOptionFlags.None,
|
||||||
|
}, img.ToDataBox());
|
||||||
|
|
||||||
|
var srv = new ShaderResourceView(MyRender11.DeviceInstance, tex);
|
||||||
|
|
||||||
|
image = new Image(identifier, srv, new(desc.Width, desc.Height));
|
||||||
|
_images.Add(identifier, image, true);
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ImageReference(ImGuiImage placeholderImage) : ImGuiImage
|
||||||
|
{
|
||||||
|
public ImGuiImage? Image;
|
||||||
|
public ImGuiImage? ErrorImage;
|
||||||
|
|
||||||
|
public override nint TextureId => Image ?? ErrorImage ?? placeholderImage;
|
||||||
|
public override Vector2 Size => Image ?? ErrorImage ?? placeholderImage;
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
Image?.Dispose();
|
||||||
|
ErrorImage?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Image(ImageIdentifier identifier, ShaderResourceView srv, Vector2 size) : ImGuiImage
|
||||||
|
{
|
||||||
|
private bool _disposed;
|
||||||
|
private long _lastUse = Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
|
public override nint TextureId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
OnUse();
|
||||||
|
return srv.NativePointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Vector2 Size
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
OnUse();
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsUnused => _disposed || Stopwatch.GetElapsedTime(_lastUse) > TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
|
private void OnUse()
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
_lastUse = Stopwatch.GetTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
if (_disposed) return;
|
||||||
|
_disposed = true;
|
||||||
|
srv.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Image {{ {identifier} {size} }}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private abstract record ImageIdentifier;
|
||||||
|
private record WebImageIdentifier(Uri Url) : ImageIdentifier;
|
||||||
|
private record FileImageIdentifier(string Path) : ImageIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class ImGuiImage : IDisposable
|
||||||
|
{
|
||||||
|
public abstract nint TextureId { get; }
|
||||||
|
public abstract Vector2 Size { get; }
|
||||||
|
|
||||||
|
public static implicit operator nint(ImGuiImage image) => image.TextureId;
|
||||||
|
public static implicit operator Vector2(ImGuiImage image) => image.Size;
|
||||||
|
public abstract void Dispose();
|
||||||
|
}
|
@@ -7,8 +7,10 @@ using CringePlugins.Compatability;
|
|||||||
using CringePlugins.Config;
|
using CringePlugins.Config;
|
||||||
using CringePlugins.Loader;
|
using CringePlugins.Loader;
|
||||||
using CringePlugins.Resolver;
|
using CringePlugins.Resolver;
|
||||||
|
using CringePlugins.Services;
|
||||||
using CringePlugins.Utils;
|
using CringePlugins.Utils;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NuGet;
|
using NuGet;
|
||||||
using NuGet.Models;
|
using NuGet.Models;
|
||||||
@@ -40,6 +42,7 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
private ImmutableArray<PluginInstance> _plugins;
|
private ImmutableArray<PluginInstance> _plugins;
|
||||||
private (SearchResultEntry entry, NuGetClient client)? _selected;
|
private (SearchResultEntry entry, NuGetClient client)? _selected;
|
||||||
private (PackageSource source, int index)? _selectedSource;
|
private (PackageSource source, int index)? _selectedSource;
|
||||||
|
private readonly IImGuiImageService _imageService = GameServicesExtension.GameServices.GetRequiredService<IImGuiImageService>();
|
||||||
|
|
||||||
public PluginListComponent(ConfigReference<PackagesConfig> packagesConfig, PackageSourceMapping sourceMapping, string gameFolder,
|
public PluginListComponent(ConfigReference<PackagesConfig> packagesConfig, PackageSourceMapping sourceMapping, string gameFolder,
|
||||||
ImmutableArray<PluginInstance> plugins)
|
ImmutableArray<PluginInstance> plugins)
|
||||||
@@ -469,6 +472,13 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
{
|
{
|
||||||
var selected = _selected.Value.entry;
|
var selected = _selected.Value.entry;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(selected.IconUrl))
|
||||||
|
{
|
||||||
|
var image = _imageService.GetFromUrl(new Uri(selected.IconUrl));
|
||||||
|
Image(image, new(64, 64));
|
||||||
|
SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
Text(selected.Title ?? selected.Id);
|
Text(selected.Title ?? selected.Id);
|
||||||
SameLine();
|
SameLine();
|
||||||
TextColored(*GetStyleColorVec4(ImGuiCol.TextLink), selected.Version.ToString());
|
TextColored(*GetStyleColorVec4(ImGuiCol.TextLink), selected.Version.ToString());
|
||||||
|
@@ -21,7 +21,12 @@
|
|||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.91.0.1, )",
|
"requested": "[1.91.0.1, )",
|
||||||
"resolved": "1.91.0.1",
|
"resolved": "1.91.0.1",
|
||||||
"contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g=="
|
"contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Buffers": "4.5.1",
|
||||||
|
"System.Numerics.Vectors": "4.5.0",
|
||||||
|
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"JsonSchema.Net.Generation": {
|
"JsonSchema.Net.Generation": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
@@ -45,9 +50,16 @@
|
|||||||
"resolved": "2.3.4-torch",
|
"resolved": "2.3.4-torch",
|
||||||
"contentHash": "UnLUnLLiXfHZdKa1zhi6w8cl8tJTrpVixLtvjFEVtlDA6Rkf06OcZ2gSidcbcgKjTcR+fk5Qsdos3mU5oohzfg==",
|
"contentHash": "UnLUnLLiXfHZdKa1zhi6w8cl8tJTrpVixLtvjFEVtlDA6Rkf06OcZ2gSidcbcgKjTcR+fk5Qsdos3mU5oohzfg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"MonoMod.Core": "1.2.2"
|
"MonoMod.Core": "1.2.2",
|
||||||
|
"System.Text.Json": "9.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[9.0.5, )",
|
||||||
|
"resolved": "9.0.5",
|
||||||
|
"contentHash": "cjnRtsEAzU73aN6W7vkWy8Phj5t3Xm78HSqgrbh/O4Q9SK/yN73wZVa21QQY6amSLQRQ/M8N+koGnY6PuvKQsw=="
|
||||||
|
},
|
||||||
"NLog": {
|
"NLog": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[5.4.0, )",
|
"requested": "[5.4.0, )",
|
||||||
@@ -112,7 +124,9 @@
|
|||||||
"resolved": "4.11.0",
|
"resolved": "4.11.0",
|
||||||
"contentHash": "djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==",
|
"contentHash": "djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.CodeAnalysis.Analyzers": "3.3.4"
|
"Microsoft.CodeAnalysis.Analyzers": "3.3.4",
|
||||||
|
"System.Collections.Immutable": "8.0.0",
|
||||||
|
"System.Reflection.Metadata": "8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Mono.Cecil": {
|
"Mono.Cecil": {
|
||||||
@@ -174,6 +188,16 @@
|
|||||||
"resolved": "4.2.0-keen-cringe",
|
"resolved": "4.2.0-keen-cringe",
|
||||||
"contentHash": "LaJN3h1Gi1FWVdef2I5WtOH9gwzKCBniH0CragarbkN2QheYY6Lqm+91PcOfp1w/4wdVb+k8Kjv3sO393Tphtw=="
|
"contentHash": "LaJN3h1Gi1FWVdef2I5WtOH9gwzKCBniH0CragarbkN2QheYY6Lqm+91PcOfp1w/4wdVb+k8Kjv3sO393Tphtw=="
|
||||||
},
|
},
|
||||||
|
"System.Buffers": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.5.1",
|
||||||
|
"contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
|
||||||
|
},
|
||||||
|
"System.Collections.Immutable": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg=="
|
||||||
|
},
|
||||||
"System.Linq.Async": {
|
"System.Linq.Async": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "6.0.1",
|
"resolved": "6.0.1",
|
||||||
@@ -182,6 +206,29 @@
|
|||||||
"Microsoft.Bcl.AsyncInterfaces": "6.0.0"
|
"Microsoft.Bcl.AsyncInterfaces": "6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Numerics.Vectors": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.5.0",
|
||||||
|
"contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
|
||||||
|
},
|
||||||
|
"System.Reflection.Metadata": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Collections.Immutable": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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=="
|
||||||
|
},
|
||||||
"cringebootstrap.abstractions": {
|
"cringebootstrap.abstractions": {
|
||||||
"type": "Project"
|
"type": "Project"
|
||||||
},
|
},
|
||||||
@@ -207,7 +254,12 @@
|
|||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.91.0.1, )",
|
"requested": "[1.91.0.1, )",
|
||||||
"resolved": "1.91.0.1",
|
"resolved": "1.91.0.1",
|
||||||
"contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g=="
|
"contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Buffers": "4.5.1",
|
||||||
|
"System.Numerics.Vectors": "4.5.0",
|
||||||
|
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Steamworks.NET": {
|
"Steamworks.NET": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
|
@@ -23,11 +23,11 @@ public record SearchResultEntry(
|
|||||||
[property: JsonConverter(typeof(StringOrStringArrayConverter))]
|
[property: JsonConverter(typeof(StringOrStringArrayConverter))]
|
||||||
ImmutableArray<string>? Tags,
|
ImmutableArray<string>? Tags,
|
||||||
string? Title,
|
string? Title,
|
||||||
int? TotalDownloads,
|
ulong? TotalDownloads,
|
||||||
ImmutableArray<PackageType> PackageTypes,
|
ImmutableArray<PackageType> PackageTypes,
|
||||||
bool Verified = false);
|
bool Verified = false);
|
||||||
|
|
||||||
public record SearchResultPackageVersion(
|
public record SearchResultPackageVersion(
|
||||||
NuGetVersion Version,
|
NuGetVersion Version,
|
||||||
int Downloads,
|
ulong Downloads,
|
||||||
[property: JsonPropertyName("@id")] Uri Registration);
|
[property: JsonPropertyName("@id")] Uri Registration);
|
||||||
|
Reference in New Issue
Block a user