config handler
Some checks failed
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (NuGet) (push) Successful in 3m38s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 4m2s
Build / Build Nuget package (SharedCringe) (push) Successful in 4m1s
Build / Build Nuget package (CringePlugins) (push) Successful in 4m18s
Build / Build Launcher (push) Failing after 4m31s
Some checks failed
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (NuGet) (push) Successful in 3m38s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 4m2s
Build / Build Nuget package (SharedCringe) (push) Successful in 4m1s
Build / Build Nuget package (CringePlugins) (push) Successful in 4m18s
Build / Build Launcher (push) Failing after 4m31s
global service provider with our stuff so we stop using statics everywhere polly retry policy for httpclient
This commit is contained in:
151
CringePlugins/Config/ConfigHandler.cs
Normal file
151
CringePlugins/Config/ConfigHandler.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using CringePlugins.Config.Spec;
|
||||
using Json.Schema;
|
||||
using Json.Schema.Generation;
|
||||
using NLog;
|
||||
using NuGet;
|
||||
|
||||
namespace CringePlugins.Config;
|
||||
|
||||
public sealed class ConfigHandler
|
||||
{
|
||||
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly DirectoryInfo _configDirectory;
|
||||
private readonly JsonSerializerOptions _serializerOptions = new(NuGetClient.SerializerOptions)
|
||||
{
|
||||
WriteIndented = true,
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
};
|
||||
|
||||
private readonly EvaluationOptions _evaluationOptions = new()
|
||||
{
|
||||
OutputFormat = OutputFormat.List,
|
||||
RequireFormatValidation = true
|
||||
};
|
||||
|
||||
public event EventHandler<ConfigValue>? ConfigReloaded;
|
||||
|
||||
internal ConfigHandler(DirectoryInfo configDirectory)
|
||||
{
|
||||
_configDirectory = configDirectory;
|
||||
}
|
||||
|
||||
public ConfigReference<T> RegisterConfig<T>(string name, T? defaultInstance = null) where T : class
|
||||
{
|
||||
var spec = IConfigurationSpecProvider.FromType(typeof(T));
|
||||
|
||||
var path = Path.Join(_configDirectory.FullName, $"{name}.json");
|
||||
var backupPath = path + $".bak.{DateTimeOffset.Now.ToUnixTimeSeconds()}";
|
||||
|
||||
JsonNode? jsonNode = null;
|
||||
if (File.Exists(path))
|
||||
{
|
||||
using var stream = File.OpenRead(path);
|
||||
try
|
||||
{
|
||||
jsonNode = JsonNode.Parse(stream, new JsonNodeOptions { PropertyNameCaseInsensitive = true },
|
||||
new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true });
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
Log.Warn(e, "Failed to load config {Name}", name);
|
||||
}
|
||||
}
|
||||
|
||||
var reference = new ConfigReference<T>(name, this);
|
||||
if (jsonNode == null || (spec != null && !TryValidate(name, spec, jsonNode)))
|
||||
{
|
||||
if (File.Exists(path))
|
||||
File.Move(path, backupPath);
|
||||
defaultInstance ??= Activator.CreateInstance<T>();
|
||||
RegisterChange(name, defaultInstance);
|
||||
return reference;
|
||||
}
|
||||
|
||||
var instance = jsonNode.Deserialize<T>(_serializerOptions)!;
|
||||
ConfigReloaded?.Invoke(this, new ConfigValue<T>(name, instance));
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
internal void RegisterChange<T>(string name, T newValue)
|
||||
{
|
||||
var spec = IConfigurationSpecProvider.FromType(typeof(T));
|
||||
|
||||
var jsonNode = JsonSerializer.SerializeToNode(newValue, _serializerOptions)!;
|
||||
|
||||
if (spec != null && !TryValidate(name, spec, jsonNode))
|
||||
throw new JsonException($"Supplied config value for {name} is invalid");
|
||||
|
||||
var path = Path.Join(_configDirectory.FullName, $"{name}.json");
|
||||
|
||||
using var stream = File.Create(path);
|
||||
using var writer = new Utf8JsonWriter(stream, new()
|
||||
{
|
||||
Indented = true
|
||||
});
|
||||
jsonNode.WriteTo(writer, _serializerOptions);
|
||||
|
||||
ConfigReloaded?.Invoke(this, new ConfigValue<T>(name, newValue));
|
||||
}
|
||||
|
||||
private bool TryValidate(string name, JsonSchema schema, JsonNode jsonNode)
|
||||
{
|
||||
var results = schema.Evaluate(jsonNode, _evaluationOptions);
|
||||
|
||||
if (results.IsValid)
|
||||
return true;
|
||||
|
||||
Log.Error("Config {Name} is invalid:", name);
|
||||
foreach (var detail in results.Details)
|
||||
{
|
||||
Log.Error("Property {PropertyPath} is invalid:", detail.EvaluationPath);
|
||||
foreach (var error in detail.Errors?.Values ?? [])
|
||||
{
|
||||
Log.Error("\t- {Error}", error);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract record ConfigValue(string Name);
|
||||
public sealed record ConfigValue<T>(string Name, T Value) : ConfigValue(Name);
|
||||
}
|
||||
|
||||
public sealed class ConfigReference<T> : IDisposable
|
||||
{
|
||||
private readonly string _name;
|
||||
private readonly ConfigHandler _instance;
|
||||
private T? _value;
|
||||
|
||||
public T Value
|
||||
{
|
||||
get => _value ?? throw new InvalidOperationException("Config has not been loaded yet");
|
||||
set => _instance.RegisterChange(_name, value);
|
||||
}
|
||||
|
||||
internal ConfigReference(string name, ConfigHandler instance)
|
||||
{
|
||||
_name = name;
|
||||
_instance = instance;
|
||||
instance.ConfigReloaded += InstanceOnConfigReloaded;
|
||||
}
|
||||
|
||||
private void InstanceOnConfigReloaded(object? sender, ConfigHandler.ConfigValue e)
|
||||
{
|
||||
if (e.Name != _name) return;
|
||||
if (e is ConfigHandler.ConfigValue<T> configValue)
|
||||
_value = configValue.Value;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_instance.ConfigReloaded -= InstanceOnConfigReloaded;
|
||||
}
|
||||
|
||||
public static implicit operator T(ConfigReference<T> reference) => reference.Value;
|
||||
}
|
21
CringePlugins/Config/Spec/IConfigurationSpecProvider.cs
Normal file
21
CringePlugins/Config/Spec/IConfigurationSpecProvider.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Reflection;
|
||||
using Json.Schema;
|
||||
using Json.Schema.Generation;
|
||||
|
||||
namespace CringePlugins.Config.Spec;
|
||||
|
||||
public interface IConfigurationSpecProvider
|
||||
{
|
||||
static abstract JsonSchema Spec { get; }
|
||||
|
||||
static JsonSchema? FromType(Type type)
|
||||
{
|
||||
if (type.IsAssignableTo(typeof(IConfigurationSpecProvider)))
|
||||
{
|
||||
return (JsonSchema)type.GetProperty(nameof(Spec), BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)!
|
||||
.GetValue(null)!;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -8,6 +8,7 @@
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -23,6 +24,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Basic.Reference.Assemblies.Net90" Version="1.8.0" PrivateAssets="all" />
|
||||
<PackageReference Include="JsonSchema.Net.Generation" Version="5.0.2" />
|
||||
<PackageReference Include="NLog" Version="5.4.0" />
|
||||
<PackageReference Include="Lib.Harmony.Thin" Version="2.3.4-torch" />
|
||||
<PackageReference Include="ImGui.NET.DirectX" Version="1.91.0.1" />
|
||||
|
@@ -13,10 +13,11 @@ using NuGet.Frameworks;
|
||||
using NuGet.Models;
|
||||
using NuGet.Versioning;
|
||||
using SharedCringe.Loader;
|
||||
using VRage.FileSystem;
|
||||
|
||||
namespace CringePlugins.Loader;
|
||||
|
||||
public class PluginsLifetime(string gameFolder) : ILoadingStage
|
||||
public class PluginsLifetime(ConfigHandler configHandler, HttpClient client) : ILoadingStage
|
||||
{
|
||||
public static ImmutableArray<DerivedAssemblyLoadContext> Contexts { get; private set; } = [];
|
||||
|
||||
@@ -28,53 +29,43 @@ public class PluginsLifetime(string gameFolder) : ILoadingStage
|
||||
// TODO move this as api for other plugins
|
||||
private readonly DirectoryInfo _dir = Directory.CreateDirectory(Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "CringeLauncher"));
|
||||
private readonly NuGetRuntimeFramework _runtimeFramework = new(NuGetFramework.ParseFolder("net9.0-windows10.0.19041.0"), RuntimeInformation.RuntimeIdentifier);
|
||||
|
||||
private ConfigReference<PackagesConfig>? _configReference;
|
||||
|
||||
public async ValueTask Load(ISplashProgress progress)
|
||||
{
|
||||
progress.DefineStepsCount(6);
|
||||
|
||||
|
||||
progress.Report("Discovering local plugins");
|
||||
|
||||
|
||||
DiscoverLocalPlugins(_dir.CreateSubdirectory("plugins"));
|
||||
|
||||
|
||||
progress.Report("Loading config");
|
||||
|
||||
PackagesConfig? packagesConfig = null;
|
||||
_configReference = configHandler.RegisterConfig("packages", PackagesConfig.Default);
|
||||
var packagesConfig = _configReference.Value;
|
||||
|
||||
var configDir = _dir.CreateSubdirectory("config");
|
||||
var configPath = Path.Join(configDir.FullName, "packages.json");
|
||||
if (File.Exists(configPath))
|
||||
await using (var stream = File.OpenRead(configPath))
|
||||
packagesConfig = await JsonSerializer.DeserializeAsync<PackagesConfig>(stream, NuGetClient.SerializerOptions)!;
|
||||
|
||||
if (packagesConfig == null)
|
||||
{
|
||||
packagesConfig = PackagesConfig.Default;
|
||||
await using var stream = File.Create(configPath);
|
||||
await JsonSerializer.SerializeAsync(stream, packagesConfig, NuGetClient.SerializerOptions);
|
||||
}
|
||||
|
||||
progress.Report("Resolving packages");
|
||||
|
||||
var sourceMapping = new PackageSourceMapping(packagesConfig.Sources);
|
||||
var sourceMapping = new PackageSourceMapping(packagesConfig.Sources, client);
|
||||
// TODO take into account the target framework runtime identifier
|
||||
var resolver = new PackageResolver(_runtimeFramework.Framework, packagesConfig.Packages, sourceMapping);
|
||||
|
||||
var packages = await resolver.ResolveAsync();
|
||||
|
||||
|
||||
progress.Report("Downloading packages");
|
||||
|
||||
var builtInPackages = await BuiltInPackages.GetPackagesAsync(_runtimeFramework);
|
||||
var cachedPackages = await resolver.DownloadPackagesAsync(_dir.CreateSubdirectory("cache"), packages, builtInPackages.Keys.ToHashSet(), progress);
|
||||
|
||||
|
||||
progress.Report("Loading plugins");
|
||||
|
||||
//we can move this, but it should be before plugin init
|
||||
RenderHandler.Current.RegisterComponent(new NotificationsComponent());
|
||||
|
||||
await LoadPlugins(cachedPackages, sourceMapping, packagesConfig, builtInPackages);
|
||||
|
||||
RenderHandler.Current.RegisterComponent(new PluginListComponent(packagesConfig, sourceMapping, configPath, gameFolder, _plugins));
|
||||
|
||||
RenderHandler.Current.RegisterComponent(new PluginListComponent(_configReference, sourceMapping, MyFileSystem.ExePath, _plugins));
|
||||
}
|
||||
|
||||
public void RegisterLifetime()
|
||||
|
13
CringePlugins/Services/GameServicesExtension.cs
Normal file
13
CringePlugins/Services/GameServicesExtension.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Sandbox;
|
||||
|
||||
namespace CringePlugins.Services;
|
||||
|
||||
public static class GameServicesExtension
|
||||
{
|
||||
internal static IServiceProvider GameServices { get; set; } = null!;
|
||||
|
||||
extension(MySandboxGame)
|
||||
{
|
||||
public static IServiceProvider Services => GameServices;
|
||||
}
|
||||
}
|
@@ -32,25 +32,23 @@ internal class PluginListComponent : IRenderComponent
|
||||
|
||||
private bool _changed;
|
||||
private bool _open = true;
|
||||
private PackagesConfig _packagesConfig;
|
||||
private readonly ConfigReference<PackagesConfig> _packagesConfig;
|
||||
private readonly PackageSourceMapping _sourceMapping;
|
||||
private readonly JsonSerializerOptions _serializerOptions = new(JsonSerializerDefaults.Web);
|
||||
private ImmutableHashSet<PackageSource>? _selectedSources;
|
||||
private readonly string _configPath;
|
||||
private readonly string _gameFolder;
|
||||
private ImmutableArray<PluginInstance> _plugins;
|
||||
private (SearchResultEntry entry, NuGetClient client)? _selected;
|
||||
private (PackageSource source, int index)? _selectedSource;
|
||||
|
||||
public PluginListComponent(PackagesConfig packagesConfig, PackageSourceMapping sourceMapping, string configPath, string gameFolder,
|
||||
public PluginListComponent(ConfigReference<PackagesConfig> packagesConfig, PackageSourceMapping sourceMapping, string gameFolder,
|
||||
ImmutableArray<PluginInstance> plugins)
|
||||
{
|
||||
_packagesConfig = packagesConfig;
|
||||
_sourceMapping = sourceMapping;
|
||||
_configPath = configPath;
|
||||
_gameFolder = gameFolder;
|
||||
_plugins = plugins;
|
||||
_packages = packagesConfig.Packages.ToImmutableDictionary(b => b.Id, b => b.Range,
|
||||
_packages = packagesConfig.Value.Packages.ToImmutableDictionary(b => b.Id, b => b.Range,
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
MyScreenManager.ScreenAdded += ScreenChanged;
|
||||
@@ -153,9 +151,9 @@ internal class PluginListComponent : IRenderComponent
|
||||
TableSetupColumn("Url", ImGuiTableColumnFlags.None, .8f);
|
||||
TableHeadersRow();
|
||||
|
||||
for (var index = 0; index < _packagesConfig.Sources.Length; index++)
|
||||
for (var index = 0; index < _packagesConfig.Value.Sources.Length; index++)
|
||||
{
|
||||
var source = _packagesConfig.Sources[index];
|
||||
var source = _packagesConfig.Value.Sources[index];
|
||||
TableNextRow();
|
||||
|
||||
TableNextColumn();
|
||||
@@ -211,15 +209,15 @@ internal class PluginListComponent : IRenderComponent
|
||||
|
||||
if (Button("Save"))
|
||||
{
|
||||
var array = _packagesConfig.Sources.RemoveAt(index).Insert(index, selectedSource);
|
||||
var array = _packagesConfig.Value.Sources.RemoveAt(index).Insert(index, selectedSource);
|
||||
|
||||
_packagesConfig = _packagesConfig with
|
||||
_packagesConfig.Value = _packagesConfig.Value with
|
||||
{
|
||||
Sources = array
|
||||
};
|
||||
|
||||
_selectedSource = null;
|
||||
|
||||
|
||||
Save();
|
||||
}
|
||||
|
||||
@@ -227,15 +225,15 @@ internal class PluginListComponent : IRenderComponent
|
||||
|
||||
if (Button("Delete"))
|
||||
{
|
||||
var array = _packagesConfig.Sources.RemoveAt(index);
|
||||
var array = _packagesConfig.Value.Sources.RemoveAt(index);
|
||||
|
||||
_packagesConfig = _packagesConfig with
|
||||
_packagesConfig.Value = _packagesConfig.Value with
|
||||
{
|
||||
Sources = array
|
||||
};
|
||||
|
||||
_selectedSource = null;
|
||||
|
||||
|
||||
Save();
|
||||
}
|
||||
}
|
||||
@@ -246,10 +244,10 @@ internal class PluginListComponent : IRenderComponent
|
||||
if (Button("Add New"))
|
||||
{
|
||||
var source = new PackageSource("source name", "", "https://url.to/index.json");
|
||||
|
||||
var array = _packagesConfig.Sources.Add(source);
|
||||
|
||||
_packagesConfig = _packagesConfig with
|
||||
var array = _packagesConfig.Value.Sources.Add(source);
|
||||
|
||||
_packagesConfig.Value = _packagesConfig.Value with
|
||||
{
|
||||
Sources = array
|
||||
};
|
||||
@@ -274,11 +272,11 @@ internal class PluginListComponent : IRenderComponent
|
||||
|
||||
if (configSerializer.Deserialize(fs) is PluginLoaderConfig oldConfig)
|
||||
{
|
||||
_packagesConfig = oldConfig.MigratePlugins(_packagesConfig);
|
||||
_packagesConfig.Value = oldConfig.MigratePlugins(_packagesConfig);
|
||||
|
||||
Save(false);
|
||||
|
||||
_packages = _packagesConfig.Packages.ToImmutableDictionary(b => b.Id, b => b.Range, StringComparer.OrdinalIgnoreCase);
|
||||
_packages = _packagesConfig.Value.Packages.ToImmutableDictionary(b => b.Id, b => b.Range, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,15 +344,15 @@ internal class PluginListComponent : IRenderComponent
|
||||
_selectedSources.Count > 2 ? $"{_selectedSources.First().Name} +{_selectedSources.Count - 1}" :
|
||||
string.Join(",", _selectedSources.Select(b => b.Name)), ImGuiComboFlags.WidthFitPreview))
|
||||
{
|
||||
foreach (var source in _packagesConfig.Sources)
|
||||
foreach (var source in _packagesConfig.Value.Sources)
|
||||
{
|
||||
var selected = _selectedSources?.Contains(source) ?? true;
|
||||
if (Selectable(source.Name, ref selected))
|
||||
{
|
||||
_selectedSources = selected
|
||||
? (_selectedSources?.Count ?? 0) + 1 == _packagesConfig.Sources.Length ? null : _selectedSources?.Add(source)
|
||||
: (_selectedSources ?? _packagesConfig.Sources.ToImmutableHashSet()).Remove(source);
|
||||
|
||||
? (_selectedSources?.Count ?? 0) + 1 == _packagesConfig.Value.Sources.Length ? null : _selectedSources?.Add(source)
|
||||
: (_selectedSources ?? _packagesConfig.Value.Sources.ToImmutableHashSet()).Remove(source);
|
||||
|
||||
_searchTask = RefreshAsync();
|
||||
return;
|
||||
}
|
||||
@@ -488,7 +486,7 @@ internal class PluginListComponent : IRenderComponent
|
||||
Text("Pulled from");
|
||||
SameLine();
|
||||
var url = _selected.Value.client.ToString();
|
||||
TextLinkOpenURL(_packagesConfig.Sources.FirstOrDefault(b => b.Url == url)?.Name ?? url, url);
|
||||
TextLinkOpenURL(_packagesConfig.Value.Sources.FirstOrDefault(b => b.Url == url)?.Name ?? url, url);
|
||||
|
||||
if (selected.Authors is not null)
|
||||
{
|
||||
@@ -563,14 +561,12 @@ internal class PluginListComponent : IRenderComponent
|
||||
|
||||
private void Save(bool keepPackages = true)
|
||||
{
|
||||
_changed = true;
|
||||
|
||||
using var stream = File.Create(_configPath);
|
||||
|
||||
JsonSerializer.Serialize(stream, keepPackages ? _packagesConfig with
|
||||
_packagesConfig.Value = keepPackages ? _packagesConfig.Value with
|
||||
{
|
||||
Packages = [.._packages.Select(b => new PackageReference(b.Key, b.Value))]
|
||||
} : _packagesConfig, NuGetClient.SerializerOptions);
|
||||
Packages = [.. _packages.Select(b => new PackageReference(b.Key, b.Value))]
|
||||
} : _packagesConfig;
|
||||
|
||||
_changed = true;
|
||||
}
|
||||
|
||||
private static unsafe int ComparePlugins(PluginInstance x, PluginInstance y, ImGuiTableSortSpecsPtr specs)
|
||||
|
@@ -21,11 +21,16 @@
|
||||
"type": "Direct",
|
||||
"requested": "[1.91.0.1, )",
|
||||
"resolved": "1.91.0.1",
|
||||
"contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g==",
|
||||
"contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g=="
|
||||
},
|
||||
"JsonSchema.Net.Generation": {
|
||||
"type": "Direct",
|
||||
"requested": "[5.0.2, )",
|
||||
"resolved": "5.0.2",
|
||||
"contentHash": "+khIPgLqOyFOWjgHSzXMjJijwbQb85/cFRf4NwTaV6QBoGM9IT8LeLCnmwazruwKsx16HB1UFX3mslUujfjVpg==",
|
||||
"dependencies": {
|
||||
"System.Buffers": "4.5.1",
|
||||
"System.Numerics.Vectors": "4.5.0",
|
||||
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||
"Humanizer.Core": "2.14.1",
|
||||
"JsonSchema.Net": "7.3.4"
|
||||
}
|
||||
},
|
||||
"Krafs.Publicizer": {
|
||||
@@ -40,8 +45,7 @@
|
||||
"resolved": "2.3.4-torch",
|
||||
"contentHash": "UnLUnLLiXfHZdKa1zhi6w8cl8tJTrpVixLtvjFEVtlDA6Rkf06OcZ2gSidcbcgKjTcR+fk5Qsdos3mU5oohzfg==",
|
||||
"dependencies": {
|
||||
"MonoMod.Core": "1.2.2",
|
||||
"System.Text.Json": "9.0.0"
|
||||
"MonoMod.Core": "1.2.2"
|
||||
}
|
||||
},
|
||||
"NLog": {
|
||||
@@ -53,8 +57,8 @@
|
||||
"SpaceEngineersDedicated.ReferenceAssemblies": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.*, )",
|
||||
"resolved": "1.206.30",
|
||||
"contentHash": "xk/EgMhbG7oT4fPzW1DcFT8tYkxJFPK3+j+t4vms9a/wz8cCmszbilA2Y+JWIpmauUDcfovX8eqAOKlgz3dpcg==",
|
||||
"resolved": "1.206.32",
|
||||
"contentHash": "uFhkUUxmumct/turcfMeM2f+jJHxuiB6jAE4JMGa/AOFKCsWIr+ZWTX9hW2muEoJpUNKrzCbGrxH8ssaJUZpig==",
|
||||
"dependencies": {
|
||||
"SharpDX": "4.2.0-keen-cringe",
|
||||
"protobuf-net": "1.0.0"
|
||||
@@ -66,6 +70,33 @@
|
||||
"resolved": "20.1.0",
|
||||
"contentHash": "+GntwnyJ5tCNvUIaQxv2+ehDvZJzGUqlSB5xRBk1hTj1qqBJ6s4vK/OfGD/jae7aTmXiGSm8wpJORosNtQevJQ=="
|
||||
},
|
||||
"Humanizer.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.14.1",
|
||||
"contentHash": "lQKvtaTDOXnoVJ20ibTuSIOf2i0uO0MPbDhd1jm238I+U/2ZnRENj0cktKZhtchBMtCUSRQ5v4xBCUbKNmyVMw=="
|
||||
},
|
||||
"Json.More.Net": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.1",
|
||||
"contentHash": "ZXAKl2VsdnIZeUo1PFII3Oi1m1L4YQjEyDjygHfHln5vgsjgIo749X6xWkv7qFYp8RROES+vOEfDcvvoVgs8kA=="
|
||||
},
|
||||
"JsonPointer.Net": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.3.1",
|
||||
"contentHash": "3e2OJjU0OaE26XC/klgxbJuXvteFWTDJIJv0ITYWcJEoskq7jzUwPSC1s0iz4wPPQnfN7vwwFmg2gJfwRAPwgw==",
|
||||
"dependencies": {
|
||||
"Humanizer.Core": "2.14.1",
|
||||
"Json.More.Net": "2.1.1"
|
||||
}
|
||||
},
|
||||
"JsonSchema.Net": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.3.4",
|
||||
"contentHash": "7GggWrdzKrtGWETRn3dcMnmuLSyWaDkBK94TK80LEHQEVz4bmsQc7FYO7qL40RDdZU2YPz5d98aT9lW5OYExuA==",
|
||||
"dependencies": {
|
||||
"JsonPointer.Net": "5.3.1"
|
||||
}
|
||||
},
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
@@ -81,9 +112,7 @@
|
||||
"resolved": "4.11.0",
|
||||
"contentHash": "djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==",
|
||||
"dependencies": {
|
||||
"Microsoft.CodeAnalysis.Analyzers": "3.3.4",
|
||||
"System.Collections.Immutable": "8.0.0",
|
||||
"System.Reflection.Metadata": "8.0.0"
|
||||
"Microsoft.CodeAnalysis.Analyzers": "3.3.4"
|
||||
}
|
||||
},
|
||||
"Mono.Cecil": {
|
||||
@@ -145,16 +174,6 @@
|
||||
"resolved": "4.2.0-keen-cringe",
|
||||
"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": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.1",
|
||||
@@ -163,29 +182,6 @@
|
||||
"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": {
|
||||
"type": "Project"
|
||||
},
|
||||
@@ -211,12 +207,7 @@
|
||||
"type": "Direct",
|
||||
"requested": "[1.91.0.1, )",
|
||||
"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"
|
||||
}
|
||||
"contentHash": "PpW1gQ9g97h6Hm/h/tkSBOmsBYgGwN8wKNmlJomcQFD/zRY1HPkJZz18XRSfRLHPmH2eeh4hhhZv1KHug7dF9g=="
|
||||
},
|
||||
"Steamworks.NET": {
|
||||
"type": "Direct",
|
||||
|
Reference in New Issue
Block a user