meh
This commit is contained in:
@@ -17,7 +17,7 @@
|
|||||||
<PackageReference Include="LuckPerms.Torch.Api" Version="5.4.0" />
|
<PackageReference Include="LuckPerms.Torch.Api" Version="5.4.0" />
|
||||||
<PackageReference Include="PetaPoco.Compiled" Version="6.0.480" />
|
<PackageReference Include="PetaPoco.Compiled" Version="6.0.480" />
|
||||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
|
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.207-master" PrivateAssets="all" IncludeAssets="compile" />
|
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.260-master" PrivateAssets="all" IncludeAssets="compile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
<PackageReference Include="Discord.Net.Commands" Version="3.6.1" />
|
<PackageReference Include="Discord.Net.Commands" Version="3.6.1" />
|
||||||
<PackageReference Include="Discord.Net.WebSocket" Version="3.6.1" />
|
<PackageReference Include="Discord.Net.WebSocket" Version="3.6.1" />
|
||||||
<PackageReference Include="PropertyChanged.Fody" Version="4.0.0" PrivateAssets="all" />
|
<PackageReference Include="PropertyChanged.Fody" Version="4.0.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.207-master" PrivateAssets="all" IncludeAssets="compile" />
|
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.260-master" PrivateAssets="all" IncludeAssets="compile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
|
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.207-master" PrivateAssets="all" IncludeAssets="compile" />
|
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.260-master" PrivateAssets="all" IncludeAssets="compile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.207-master" PrivateAssets="all" IncludeAssets="compile" />
|
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.260-master" PrivateAssets="all" IncludeAssets="compile" />
|
||||||
<PackageReference Include="PropertyChanged.Fody" Version="4.0.0" PrivateAssets="all" />
|
<PackageReference Include="PropertyChanged.Fody" Version="4.0.0" PrivateAssets="all" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
<dependencies>
|
<dependencies>
|
||||||
<group targetFramework=".NETFramework4.8">
|
<group targetFramework=".NETFramework4.8">
|
||||||
<dependency id="Torch.Loader" version="1.0.0" />
|
<dependency id="Torch.Loader" version="1.0.0" />
|
||||||
|
<dependency id="LuckPerms.Torch.Utils" version="1.0.0" />
|
||||||
<dependency id="IKVM.Maven.Sdk" version="1.6.1" />
|
<dependency id="IKVM.Maven.Sdk" version="1.6.1" />
|
||||||
</group>
|
</group>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
78
LuckPerms.Torch.Utils/Extensions/DelegateExtensions.cs
Normal file
78
LuckPerms.Torch.Utils/Extensions/DelegateExtensions.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using java.lang;
|
||||||
|
using java.util.concurrent;
|
||||||
|
using java.util.function;
|
||||||
|
using net.luckperms.api.@event;
|
||||||
|
|
||||||
|
namespace LuckPerms.Torch.Utils.Extensions;
|
||||||
|
|
||||||
|
public static class DelegateExtensions
|
||||||
|
{
|
||||||
|
private static readonly Func<Consumer, Consumer, Consumer> AndThenDefault =
|
||||||
|
(Func<Consumer, Consumer, Consumer>)typeof(Consumer).GetMethod("<default>andThen",
|
||||||
|
BindingFlags.Static | BindingFlags.NonPublic)!.CreateDelegate(typeof(Func<Consumer, Consumer, Consumer>));
|
||||||
|
|
||||||
|
private static readonly Func<Predicate, Predicate, Predicate> AndDefault =
|
||||||
|
(Func<Predicate, Predicate, Predicate>)typeof(Predicate).GetMethod("<default>and",
|
||||||
|
BindingFlags.Static | BindingFlags.NonPublic)!.CreateDelegate(typeof(Func<Predicate, Predicate, Predicate>));
|
||||||
|
|
||||||
|
private static readonly Func<Predicate, Predicate> NegateDefault =
|
||||||
|
(Func<Predicate, Predicate>)typeof(Predicate).GetMethod("<default>negate",
|
||||||
|
BindingFlags.Static | BindingFlags.NonPublic)!.CreateDelegate(typeof(Func<Predicate, Predicate>));
|
||||||
|
|
||||||
|
private static readonly Func<Predicate, Predicate, Predicate> OrDefault =
|
||||||
|
(Func<Predicate, Predicate, Predicate>)typeof(Predicate).GetMethod("<default>or",
|
||||||
|
BindingFlags.Static | BindingFlags.NonPublic)!.CreateDelegate(typeof(Func<Predicate, Predicate, Predicate>));
|
||||||
|
|
||||||
|
public static Runnable ToRunnable(this Action action) => new DelegateRunnable(action);
|
||||||
|
|
||||||
|
public static Consumer ToConsumer<T>(this Action<T> action) => new DelegateConsumer<T>(action);
|
||||||
|
|
||||||
|
public static Supplier ToSupplier<T>(this Func<T> func) where T : notnull => new DelegateSupplier<T>(func);
|
||||||
|
|
||||||
|
public static Predicate ToPredicate<T>(this Predicate<T> predicate) => new DelegatePredicate<T>(predicate);
|
||||||
|
|
||||||
|
public static Callable ToCallable<T>(this Func<T> func) => new DelegateSupplier<T>(func);
|
||||||
|
|
||||||
|
private sealed class DelegatePredicate<T>(Predicate<T> predicate) : Predicate
|
||||||
|
{
|
||||||
|
public bool test(object t) => predicate((T)t);
|
||||||
|
|
||||||
|
public Predicate and(Predicate other) => AndDefault(this, other);
|
||||||
|
|
||||||
|
public Predicate negate() => NegateDefault(this);
|
||||||
|
|
||||||
|
public Predicate or(Predicate other) => OrDefault(this, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class DelegateSupplier<T>(Func<T> func) : Supplier, Callable where T : notnull
|
||||||
|
{
|
||||||
|
public object get() => func();
|
||||||
|
public object call() => func();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class DelegateConsumer<T>(Action<T> action) : Consumer
|
||||||
|
{
|
||||||
|
public void accept(object t)
|
||||||
|
{
|
||||||
|
action((T)t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer andThen(Consumer after) => AndThenDefault(this, after);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
// lets make it an overload for convenience
|
||||||
|
public static void execute(this Executor executor, Action action) => executor.execute(action.ToRunnable());
|
||||||
|
|
||||||
|
public static EventSubscription subscribe<TEvent>(this EventBus bus, object plugin, Action<TEvent> action)
|
||||||
|
where TEvent : class, LuckPermsEvent => bus.subscribe(plugin, typeof(TEvent), action.ToConsumer());
|
||||||
|
|
||||||
|
public static EventSubscription subscribe<TEvent>(this EventBus bus, Action<TEvent> action)
|
||||||
|
where TEvent : class, LuckPermsEvent => bus.subscribe(typeof(TEvent), action.ToConsumer());
|
||||||
|
|
||||||
|
private sealed class DelegateRunnable(Action action) : Runnable
|
||||||
|
{
|
||||||
|
public void run() => action();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,8 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using java.util;
|
||||||
using System.Linq;
|
|
||||||
using java.util;
|
|
||||||
|
|
||||||
namespace LuckPerms.Torch.Extensions;
|
namespace LuckPerms.Torch.Utils.Extensions;
|
||||||
|
|
||||||
public static class EnumerableExtensions
|
public static class EnumerableExtensions
|
||||||
{
|
{
|
@@ -1,12 +1,23 @@
|
|||||||
using System;
|
using System.Collections;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using java.util;
|
using java.util;
|
||||||
|
using java.util.stream;
|
||||||
|
|
||||||
namespace LuckPerms.Torch.Extensions;
|
namespace LuckPerms.Torch.Utils.Extensions;
|
||||||
|
|
||||||
public static class IteratorExtensions
|
public static class IteratorExtensions
|
||||||
{
|
{
|
||||||
|
public static StreamEnumerable<T> AsEnumerable<T>(this BaseStream stream) => new(stream);
|
||||||
|
|
||||||
|
public static IteratorEnumerator<object> GetEnumerator(this BaseStream stream) => new(stream.iterator());
|
||||||
|
|
||||||
|
public struct StreamEnumerable<T>(BaseStream stream) : IEnumerable<T>
|
||||||
|
{
|
||||||
|
public IteratorEnumerator<T> GetEnumerator() => new(stream.iterator());
|
||||||
|
|
||||||
|
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
public static IteratorEnumerator<object> GetEnumerator(this Iterator iterator) => new(iterator);
|
public static IteratorEnumerator<object> GetEnumerator(this Iterator iterator) => new(iterator);
|
||||||
|
|
||||||
public static IteratorEnumerable<T> AsEnumerable<T>(this Iterator iterator) => new(iterator);
|
public static IteratorEnumerable<T> AsEnumerable<T>(this Iterator iterator) => new(iterator);
|
||||||
@@ -39,11 +50,8 @@ public static class IteratorExtensions
|
|||||||
{
|
{
|
||||||
public IteratorEnumerator<T> GetEnumerator() => new(iterator);
|
public IteratorEnumerator<T> GetEnumerator() => new(iterator);
|
||||||
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => null!;
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
}
|
}
|
||||||
}
|
}
|
92
LuckPerms.Torch.Utils/Extensions/StreamExtensions.cs
Normal file
92
LuckPerms.Torch.Utils/Extensions/StreamExtensions.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
using java.io;
|
||||||
|
using JavaIOException = java.io.IOException;
|
||||||
|
using SystemIOException = System.IO.IOException;
|
||||||
|
|
||||||
|
namespace LuckPerms.Torch.Utils.Extensions;
|
||||||
|
|
||||||
|
public static class StreamExtensions
|
||||||
|
{
|
||||||
|
public static InputStream GetInputStream(this Stream stream)
|
||||||
|
{
|
||||||
|
if (!stream.CanRead)
|
||||||
|
throw new ArgumentException("Stream should be readable", nameof(stream));
|
||||||
|
|
||||||
|
return new WrapperInputStream(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class WrapperInputStream(Stream stream) : InputStream
|
||||||
|
{
|
||||||
|
public override int read()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return stream.ReadByte();
|
||||||
|
}
|
||||||
|
catch (SystemIOException e)
|
||||||
|
{
|
||||||
|
throw new JavaIOException(e.Message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int read(byte[] b, int off, int len)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return stream.Read(b, off, len);
|
||||||
|
}
|
||||||
|
catch (SystemIOException e)
|
||||||
|
{
|
||||||
|
throw new JavaIOException(e.Message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long skip(long n)
|
||||||
|
{
|
||||||
|
if (!stream.CanSeek) return base.skip(n);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return stream.Seek(n, SeekOrigin.Current);
|
||||||
|
}
|
||||||
|
catch (SystemIOException e)
|
||||||
|
{
|
||||||
|
throw new JavaIOException(e.Message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int available()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (int)(stream.Length - stream.Position);
|
||||||
|
}
|
||||||
|
catch (SystemIOException e)
|
||||||
|
{
|
||||||
|
throw new JavaIOException(e.Message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void reset()
|
||||||
|
{
|
||||||
|
if (!stream.CanSeek)
|
||||||
|
{
|
||||||
|
base.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
}
|
||||||
|
catch (SystemIOException e)
|
||||||
|
{
|
||||||
|
throw new JavaIOException(e.Message, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void close()
|
||||||
|
{
|
||||||
|
stream.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
using java.util;
|
using java.util;
|
||||||
|
|
||||||
namespace LuckPerms.Torch.Extensions;
|
namespace LuckPerms.Torch.Utils.Extensions;
|
||||||
|
|
||||||
public static class UuidExtensions
|
public static class UuidExtensions
|
||||||
{
|
{
|
27
LuckPerms.Torch.Utils/LuckPerms.Torch.Utils.csproj
Normal file
27
LuckPerms.Torch.Utils/LuckPerms.Torch.Utils.csproj
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<LangVersion>12</LangVersion>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<Version>1.0.0</Version>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<LibsPath>$(ProjectDir)libs\</LibsPath>
|
||||||
|
<ApiJarPath>$(LibsPath)api-5.4.jar</ApiJarPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<IkvmReference Include="$(ApiJarPath)">
|
||||||
|
<AssemblyName>api</AssemblyName>
|
||||||
|
<DisableAutoAssemblyName>true</DisableAutoAssemblyName>
|
||||||
|
</IkvmReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="IKVM" Version="8.7.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
using java.lang;
|
|
||||||
using java.util.concurrent;
|
|
||||||
|
|
||||||
namespace LuckPerms.Torch.Extensions;
|
|
||||||
|
|
||||||
public static class DelegateExtensions
|
|
||||||
{
|
|
||||||
public static Runnable ToRunnable(this Action action) => new DelegateRunnable(action);
|
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
|
||||||
// lets make it an overload for convenience
|
|
||||||
public static void execute(this Executor executor, Action action) => executor.execute(action.ToRunnable());
|
|
||||||
|
|
||||||
private sealed class DelegateRunnable(Action action) : Runnable
|
|
||||||
{
|
|
||||||
public void run() => action();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,4 +1,5 @@
|
|||||||
using java.util;
|
using java.util;
|
||||||
|
using LuckPerms.Torch.Utils.Extensions;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.Server.Managers;
|
using Torch.Server.Managers;
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using java.io;
|
|
||||||
using Torch.Utils;
|
|
||||||
|
|
||||||
namespace LuckPerms.Torch.Extensions;
|
|
||||||
|
|
||||||
internal static class StreamExtensions
|
|
||||||
{
|
|
||||||
public static InputStream GetInputStream(this Stream stream)
|
|
||||||
{
|
|
||||||
if (!stream.CanRead)
|
|
||||||
throw new ArgumentException("Stream should be readable", nameof(stream));
|
|
||||||
|
|
||||||
var array = stream.ReadToEnd(); // TODO make it not allocate array for an entire stream content
|
|
||||||
|
|
||||||
return new ByteArrayInputStream(array);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,5 +1,6 @@
|
|||||||
using LuckPerms.Torch.Extensions;
|
using LuckPerms.Torch.Extensions;
|
||||||
using LuckPerms.Torch.PlatformApi;
|
using LuckPerms.Torch.PlatformApi;
|
||||||
|
using LuckPerms.Torch.Utils.Extensions;
|
||||||
using me.lucko.luckperms.common.plugin;
|
using me.lucko.luckperms.common.plugin;
|
||||||
using me.lucko.luckperms.common.plugin.util;
|
using me.lucko.luckperms.common.plugin.util;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
using java.util;
|
using java.util;
|
||||||
using LuckPerms.Torch.Extensions;
|
using LuckPerms.Torch.Extensions;
|
||||||
using LuckPerms.Torch.PlatformApi;
|
using LuckPerms.Torch.PlatformApi;
|
||||||
|
using LuckPerms.Torch.Utils.Extensions;
|
||||||
using me.lucko.luckperms.common.config;
|
using me.lucko.luckperms.common.config;
|
||||||
using me.lucko.luckperms.common.context.manager;
|
using me.lucko.luckperms.common.context.manager;
|
||||||
using me.lucko.luckperms.common.plugin;
|
using me.lucko.luckperms.common.plugin;
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using java.util;
|
using java.util;
|
||||||
using LuckPerms.Torch.Extensions;
|
using LuckPerms.Torch.Extensions;
|
||||||
|
using LuckPerms.Torch.Utils.Extensions;
|
||||||
using me.lucko.luckperms.common.locale;
|
using me.lucko.luckperms.common.locale;
|
||||||
using me.lucko.luckperms.common.plugin;
|
using me.lucko.luckperms.common.plugin;
|
||||||
using me.lucko.luckperms.common.sender;
|
using me.lucko.luckperms.common.sender;
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using java.io;
|
using java.io;
|
||||||
using java.lang;
|
using java.lang;
|
||||||
@@ -7,6 +8,7 @@ using java.time;
|
|||||||
using java.util;
|
using java.util;
|
||||||
using java.util.concurrent;
|
using java.util.concurrent;
|
||||||
using LuckPerms.Torch.Extensions;
|
using LuckPerms.Torch.Extensions;
|
||||||
|
using LuckPerms.Torch.Utils.Extensions;
|
||||||
using me.lucko.luckperms.common.plugin.bootstrap;
|
using me.lucko.luckperms.common.plugin.bootstrap;
|
||||||
using me.lucko.luckperms.common.plugin.classpath;
|
using me.lucko.luckperms.common.plugin.classpath;
|
||||||
using me.lucko.luckperms.common.plugin.logging;
|
using me.lucko.luckperms.common.plugin.logging;
|
||||||
@@ -18,6 +20,7 @@ using Torch.API;
|
|||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.API.Plugins;
|
using Torch.API.Plugins;
|
||||||
using Torch.Server.Managers;
|
using Torch.Server.Managers;
|
||||||
|
using Path = java.nio.file.Path;
|
||||||
|
|
||||||
namespace LuckPerms.Torch.Impl;
|
namespace LuckPerms.Torch.Impl;
|
||||||
|
|
||||||
@@ -30,7 +33,8 @@ public class LpTorchBootstrap : LuckPermsBootstrap
|
|||||||
public CountDownLatch EnableLatch { get; } = new(1);
|
public CountDownLatch EnableLatch { get; } = new(1);
|
||||||
private readonly ITorchServer _torch;
|
private readonly ITorchServer _torch;
|
||||||
private readonly ITorchPlugin _torchPlugin;
|
private readonly ITorchPlugin _torchPlugin;
|
||||||
private readonly string _configDir;
|
private readonly Path _configDir;
|
||||||
|
private readonly Path _dataDir;
|
||||||
|
|
||||||
public LpTorchPlugin Plugin { get; }
|
public LpTorchPlugin Plugin { get; }
|
||||||
|
|
||||||
@@ -39,13 +43,15 @@ public class LpTorchBootstrap : LuckPermsBootstrap
|
|||||||
_pluginLogger = new NLogPluginLogger(logger);
|
_pluginLogger = new NLogPluginLogger(logger);
|
||||||
_torch = torch;
|
_torch = torch;
|
||||||
_torchPlugin = torchPlugin;
|
_torchPlugin = torchPlugin;
|
||||||
_configDir = configDir;
|
var configDirInfo = Directory.CreateDirectory(configDir);
|
||||||
|
_configDir = Paths.get(configDirInfo.FullName);
|
||||||
|
_dataDir = Paths.get(configDirInfo.CreateSubdirectory("data").FullName);
|
||||||
Plugin = new(this, torch);
|
Plugin = new(this, torch);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITorchPlugin GetTorchPlugin() => _torchPlugin;
|
public ITorchPlugin GetTorchPlugin() => _torchPlugin;
|
||||||
|
|
||||||
public Path getDataDirectory() => Paths.get(_configDir, "data");
|
public Path getDataDirectory() => _dataDir;
|
||||||
|
|
||||||
public string identifyClassLoader(ClassLoader classLoader) => classLoader.toString();
|
public string identifyClassLoader(ClassLoader classLoader) => classLoader.toString();
|
||||||
|
|
||||||
@@ -56,7 +62,7 @@ public class LpTorchBootstrap : LuckPermsBootstrap
|
|||||||
|
|
||||||
public SchedulerAdapter getScheduler() => _schedulerAdapter ??= new LpSchedulerAdapter(this, _torch);
|
public SchedulerAdapter getScheduler() => _schedulerAdapter ??= new LpSchedulerAdapter(this, _torch);
|
||||||
|
|
||||||
public Path getConfigDirectory() => Paths.get(_configDir);
|
public Path getConfigDirectory() => _configDir;
|
||||||
|
|
||||||
public bool isPlayerOnline(UUID uuid) =>
|
public bool isPlayerOnline(UUID uuid) =>
|
||||||
_torch.CurrentSession?.Managers.GetManager<MultiplayerManagerDedicated>().Players
|
_torch.CurrentSession?.Managers.GetManager<MultiplayerManagerDedicated>().Players
|
||||||
|
@@ -8,6 +8,7 @@ using LuckPerms.Torch.Impl.Listeners;
|
|||||||
using LuckPerms.Torch.Impl.Messaging;
|
using LuckPerms.Torch.Impl.Messaging;
|
||||||
using LuckPerms.Torch.ModApi;
|
using LuckPerms.Torch.ModApi;
|
||||||
using LuckPerms.Torch.PlatformHooks;
|
using LuckPerms.Torch.PlatformHooks;
|
||||||
|
using LuckPerms.Torch.Utils.Extensions;
|
||||||
using me.lucko.luckperms.common.api;
|
using me.lucko.luckperms.common.api;
|
||||||
using me.lucko.luckperms.common.calculator;
|
using me.lucko.luckperms.common.calculator;
|
||||||
using me.lucko.luckperms.common.command;
|
using me.lucko.luckperms.common.command;
|
||||||
|
@@ -259,4 +259,8 @@
|
|||||||
<EmbeddedResource Include="Resources\config.yml" LogicalName="config.yml" />
|
<EmbeddedResource Include="Resources\config.yml" LogicalName="config.yml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LuckPerms.Torch.Utils\LuckPerms.Torch.Utils.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@@ -5,6 +5,7 @@ using ikvm.extensions;
|
|||||||
using ikvm.runtime;
|
using ikvm.runtime;
|
||||||
using java.lang;
|
using java.lang;
|
||||||
using LuckPerms.Torch.Extensions;
|
using LuckPerms.Torch.Extensions;
|
||||||
|
using LuckPerms.Torch.Utils.Extensions;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using VRage.Scripting;
|
using VRage.Scripting;
|
||||||
|
@@ -2,5 +2,5 @@
|
|||||||
<PluginManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
<PluginManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
<Name>LuckPerms.Torch</Name>
|
<Name>LuckPerms.Torch</Name>
|
||||||
<Guid>7E4B3CC8-64FA-416E-8910-AACDF2DA5E2C</Guid>
|
<Guid>7E4B3CC8-64FA-416E-8910-AACDF2DA5E2C</Guid>
|
||||||
<Version>v5.4.106.4</Version>
|
<Version>v5.4.106.5</Version>
|
||||||
</PluginManifest>
|
</PluginManifest>
|
@@ -49,7 +49,7 @@
|
|||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.0.0, )",
|
"requested": "[1.0.0, )",
|
||||||
"resolved": "1.0.0",
|
"resolved": "1.0.0",
|
||||||
"contentHash": "GAf9Mv1t1/qTGHSgDqkiKAc7Xbh36+U8Ce1PuSoJZNKxHVmzbKHc3nSVz0dIBHhLE7Op8k60NfmclDRAQAppbQ=="
|
"contentHash": "HkuAujKa9IqPPqoA1205teUPBxuNOC9z0xZJkrMlFT0htH02X0ieZ5qh4onwyV10qVKiRBCSLkc5tA8lp1l5ig=="
|
||||||
},
|
},
|
||||||
"Torch.Server.ReferenceAssemblies": {
|
"Torch.Server.ReferenceAssemblies": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
@@ -357,6 +357,12 @@
|
|||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.5.0",
|
"resolved": "4.5.0",
|
||||||
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
|
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
|
||||||
|
},
|
||||||
|
"luckperms.torch.utils": {
|
||||||
|
"type": "Project",
|
||||||
|
"dependencies": {
|
||||||
|
"IKVM": "[8.7.1, )"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
".NETFramework,Version=v4.8/win-x64": {
|
".NETFramework,Version=v4.8/win-x64": {
|
||||||
|
144
Maintenance/Commands.cs
Normal file
144
Maintenance/Commands.cs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
using Maintenance.Managers;
|
||||||
|
using Torch.API.Managers;
|
||||||
|
using Torch.Commands;
|
||||||
|
|
||||||
|
namespace Maintenance;
|
||||||
|
|
||||||
|
[Category("maintenance")]
|
||||||
|
public class Commands : CommandModule
|
||||||
|
{
|
||||||
|
private static readonly TimeSpan MaxTime = TimeSpan.FromDays(28);
|
||||||
|
|
||||||
|
private MaintenanceManager MaintenanceManager =>
|
||||||
|
Context.Torch.CurrentSession.Managers.GetManager<MaintenanceManager>();
|
||||||
|
|
||||||
|
private MaintenanceScheduleManager MaintenanceScheduler =>
|
||||||
|
Context.Torch.CurrentSession.Managers.GetManager<MaintenanceScheduleManager>();
|
||||||
|
|
||||||
|
private LanguageManager LanguageManager =>
|
||||||
|
Context.Torch.Managers.GetManager<LanguageManager>();
|
||||||
|
|
||||||
|
[Command("on", "Set the status of the maintenance mode to enabled.")]
|
||||||
|
public void On()
|
||||||
|
{
|
||||||
|
if (MaintenanceManager.MaintenanceEnabled)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.AlreadyEnabled]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaintenanceManager.MaintenanceEnabled = true;
|
||||||
|
|
||||||
|
Context.Respond(LanguageManager[LangKeys.MaintenanceActivated]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("off", "Set the status of the maintenance mode to disabled.")]
|
||||||
|
public void Off()
|
||||||
|
{
|
||||||
|
if (!MaintenanceManager.MaintenanceEnabled)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.AlreadyDisabled]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaintenanceManager.MaintenanceEnabled = false;
|
||||||
|
MaintenanceScheduler.CancelTimer(null);
|
||||||
|
|
||||||
|
Context.Respond(LanguageManager[LangKeys.MaintenanceDeactivated]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("starttimer", "Will enable maintenance mode after the time is up.")]
|
||||||
|
public void StartTimer(string time)
|
||||||
|
{
|
||||||
|
var startTime = double.TryParse(time, out var seconds) ? TimeSpan.FromSeconds(seconds) : TimeSpan.Parse(time);
|
||||||
|
|
||||||
|
if (startTime > MaxTime)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.TimerTooLong]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaintenanceManager.MaintenanceEnabled)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.AlreadyEnabled]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaintenanceScheduler.CurrentSchedule.StartTime.HasValue)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.TimerAlreadyRunning]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaintenanceScheduler.ScheduleTimer(TimerType.Start, startTime);
|
||||||
|
|
||||||
|
Context.Respond(LanguageManager.Format(LangKeys.StartTimerStarted, MaintenanceScheduler.CurrentSchedule));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("endtimer",
|
||||||
|
"Will enable maintenance mode for the given time in minutes. After the time is up, it'll be disabled again.")]
|
||||||
|
public void EndTimer(string duration)
|
||||||
|
{
|
||||||
|
var endTime = double.TryParse(duration, out var seconds) ? TimeSpan.FromSeconds(seconds) : TimeSpan.Parse(duration);
|
||||||
|
|
||||||
|
if (endTime > MaxTime)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.TimerTooLong]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaintenanceScheduler.CurrentSchedule.EndTime.HasValue)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.TimerAlreadyRunning]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaintenanceManager.MaintenanceEnabled = true;
|
||||||
|
MaintenanceScheduler.ScheduleTimer(TimerType.End, endTime);
|
||||||
|
|
||||||
|
Context.Respond(LanguageManager.Format(LangKeys.EndTimerStarted, MaintenanceScheduler.CurrentSchedule));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("schedule", "Will enable maintenance mode after the given time, then disable it according to the second parameter.")]
|
||||||
|
public void Schedule(string time, string duration)
|
||||||
|
{
|
||||||
|
var startTime = double.TryParse(time, out var startSeconds) ? TimeSpan.FromSeconds(startSeconds) : TimeSpan.Parse(time);
|
||||||
|
var endTime = double.TryParse(duration, out var endSeconds) ? TimeSpan.FromSeconds(endSeconds) : TimeSpan.Parse(duration);
|
||||||
|
|
||||||
|
if (startTime > MaxTime || endTime > MaxTime)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.TimerTooLong]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaintenanceScheduler.CurrentSchedule != MaintenanceSchedule.Default)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.TimerAlreadyRunning]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MaintenanceManager.MaintenanceEnabled)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.AlreadyEnabled]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaintenanceScheduler.ScheduleMaintenance(startTime, endTime);
|
||||||
|
|
||||||
|
Context.Respond(LanguageManager.Format(LangKeys.ScheduleTimerBroadcast, MaintenanceScheduler.CurrentSchedule));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("aborttimer", "Cancels a running start-/endtimer")]
|
||||||
|
public void AbortTimer()
|
||||||
|
{
|
||||||
|
if (MaintenanceScheduler.CurrentSchedule == MaintenanceSchedule.Default)
|
||||||
|
{
|
||||||
|
Context.Respond(LanguageManager[LangKeys.TimerNotRunning]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaintenanceScheduler.CancelTimer(null);
|
||||||
|
|
||||||
|
Context.Respond(LanguageManager[LangKeys.TimerCancelled]);
|
||||||
|
}
|
||||||
|
}
|
20
Maintenance/ConfigKeys.cs
Normal file
20
Maintenance/ConfigKeys.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
namespace Maintenance;
|
||||||
|
|
||||||
|
public static class ConfigKeys
|
||||||
|
{
|
||||||
|
public const string MaintenanceEnabled = "maintenance-enabled";
|
||||||
|
|
||||||
|
public const string CommandsOnMaintenanceEnable = "commands-on-maintenance-enable";
|
||||||
|
public const string CommandsOnMaintenanceDisable = "commands-on-maintenance-disable";
|
||||||
|
|
||||||
|
public const string EnableWorldMessage = "enable-world-message";
|
||||||
|
public const string WorldMessage = "world-message";
|
||||||
|
|
||||||
|
public const string KickOnlinePlayers = "kick-online-players";
|
||||||
|
|
||||||
|
public const string Language = "language";
|
||||||
|
|
||||||
|
public const string ContinueEndTimerAfterRestart = "continue-endtimer-after-restart";
|
||||||
|
|
||||||
|
public const string TimerBroadcastForSeconds = "timer-broadcast-for-seconds";
|
||||||
|
}
|
31
Maintenance/Extensions/CompletableFutureExtensions.cs
Normal file
31
Maintenance/Extensions/CompletableFutureExtensions.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using java.util.concurrent;
|
||||||
|
using java.util.function;
|
||||||
|
using Torch.Utils;
|
||||||
|
|
||||||
|
namespace Maintenance.Extensions;
|
||||||
|
|
||||||
|
public static class CompletableFutureExtensions
|
||||||
|
{
|
||||||
|
[ReflectedStaticMethod(Type = typeof(Consumer), Name = "<default>andThen")]
|
||||||
|
private static readonly Func<Consumer, Consumer, Consumer> AndThenDefault = null!;
|
||||||
|
|
||||||
|
public static Task<T> ToTask<T>(this CompletableFuture completableFuture)
|
||||||
|
{
|
||||||
|
var taskCompletionSource = new TaskCompletionSource<T>();
|
||||||
|
|
||||||
|
completableFuture.thenAccept(new TaskConsumer<T>(taskCompletionSource));
|
||||||
|
|
||||||
|
return taskCompletionSource.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class TaskConsumer<T>(TaskCompletionSource<T> completionSource) : Consumer
|
||||||
|
{
|
||||||
|
|
||||||
|
public void accept(object t)
|
||||||
|
{
|
||||||
|
completionSource.SetResult((T)t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer andThen(Consumer after) => AndThenDefault(this, after);
|
||||||
|
}
|
||||||
|
}
|
18
Maintenance/LangKeys.cs
Normal file
18
Maintenance/LangKeys.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
namespace Maintenance;
|
||||||
|
|
||||||
|
public static class LangKeys
|
||||||
|
{
|
||||||
|
public const string MaintenanceActivated = "maintenanceActivated";
|
||||||
|
public const string MaintenanceDeactivated = "maintenanceDeactivated";
|
||||||
|
public const string AlreadyEnabled = "alreadyEnabled";
|
||||||
|
public const string AlreadyDisabled = "alreadyDisabled";
|
||||||
|
public const string EndTimerBroadcast = "endtimerBroadcast";
|
||||||
|
public const string EndTimerStarted = "endtimerStarted";
|
||||||
|
public const string StartTimerBroadcast = "starttimerBroadcast";
|
||||||
|
public const string StartTimerStarted = "starttimerStarted";
|
||||||
|
public const string ScheduleTimerBroadcast = "scheduletimerBroadcast";
|
||||||
|
public const string TimerAlreadyRunning = "timerAlreadyRunning";
|
||||||
|
public const string TimerNotRunning = "timerNotRunning";
|
||||||
|
public const string TimerCancelled = "timerCancelled";
|
||||||
|
public const string TimerTooLong = "timerTooLong";
|
||||||
|
}
|
53
Maintenance/Maintenance.csproj
Normal file
53
Maintenance/Maintenance.csproj
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<LangVersion>12</LangVersion>
|
||||||
|
<UseWpf>true</UseWpf>
|
||||||
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<DebugType>none</DebugType>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="LuckPerms.Torch.Api" Version="5.4.0" />
|
||||||
|
<PackageReference Include="Alexinea.Extensions.Configuration.Yaml" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="8.0.0" />
|
||||||
|
<PackageReference Include="SmartFormat" Version="3.3.0" />
|
||||||
|
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.260-master" PrivateAssets="all" IncludeAssets="compile"/>
|
||||||
|
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="PolySharp" Version="1.8.1">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="manifest.xml">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Resources\config.yml" LogicalName="config.yml" />
|
||||||
|
<EmbeddedResource Include="Resources\translations\en.yml" LogicalName="translations.en.yml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Steamworks.NET">
|
||||||
|
<HintPath>libs\Steamworks.NET.dll</HintPath>
|
||||||
|
<Private>False</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
38
Maintenance/Managers/ConfigManager.cs
Normal file
38
Maintenance/Managers/ConfigManager.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System.IO;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Torch.API.Managers;
|
||||||
|
|
||||||
|
namespace Maintenance.Managers;
|
||||||
|
|
||||||
|
public class ConfigManager(string storagePath) : IManager
|
||||||
|
{
|
||||||
|
private IConfigurationRoot? _configurationRoot;
|
||||||
|
|
||||||
|
public IConfiguration Configuration => _configurationRoot ?? throw new InvalidOperationException("Manager is not attached");
|
||||||
|
|
||||||
|
public void Attach()
|
||||||
|
{
|
||||||
|
var configPath = Path.Combine(storagePath, "config.yml");
|
||||||
|
|
||||||
|
if (!File.Exists(configPath))
|
||||||
|
ExtractDefault(configPath);
|
||||||
|
|
||||||
|
_configurationRoot = new ConfigurationBuilder()
|
||||||
|
.AddYamlFile(configPath, false, true)
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExtractDefault(string path)
|
||||||
|
{
|
||||||
|
var name = path[storagePath.Length..].TrimStart(Path.GetInvalidFileNameChars()).Replace('\\', '.');
|
||||||
|
|
||||||
|
using var stream = typeof(ConfigManager).Assembly.GetManifestResourceStream(name)!;
|
||||||
|
using var file = File.Create(path);
|
||||||
|
|
||||||
|
stream.CopyTo(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Detach()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
62
Maintenance/Managers/LanguageManager.cs
Normal file
62
Maintenance/Managers/LanguageManager.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System.IO;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using SmartFormat;
|
||||||
|
using SmartFormat.Core.Settings;
|
||||||
|
using Torch.API.Managers;
|
||||||
|
using Torch.Managers;
|
||||||
|
|
||||||
|
namespace Maintenance.Managers;
|
||||||
|
|
||||||
|
public class LanguageManager(string storagePath) : IManager
|
||||||
|
{
|
||||||
|
private readonly string[] _langs = { "en" };
|
||||||
|
|
||||||
|
public IConfiguration Language => _configurationRoot ?? throw new InvalidOperationException("Manager is not attached");
|
||||||
|
|
||||||
|
private IConfigurationRoot? _configurationRoot;
|
||||||
|
|
||||||
|
[Manager.Dependency]
|
||||||
|
private readonly ConfigManager _configManager = null!;
|
||||||
|
|
||||||
|
public SmartFormatter Formatter { get; } = Smart.CreateDefaultSmartFormat(new()
|
||||||
|
{
|
||||||
|
CaseSensitivity = CaseSensitivityType.CaseInsensitive
|
||||||
|
});
|
||||||
|
|
||||||
|
public string this[string key] => Language[key] ?? throw new KeyNotFoundException(key);
|
||||||
|
|
||||||
|
public void Attach()
|
||||||
|
{
|
||||||
|
var langDirectory = Path.Combine(storagePath, "translations");
|
||||||
|
|
||||||
|
if (!Directory.Exists(langDirectory))
|
||||||
|
Directory.CreateDirectory(langDirectory);
|
||||||
|
|
||||||
|
foreach (var lang in _langs)
|
||||||
|
{
|
||||||
|
var path = Path.Combine(langDirectory, $"{lang}.yml");
|
||||||
|
if (!File.Exists(path))
|
||||||
|
ExtractTranslation(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
_configurationRoot = new ConfigurationBuilder()
|
||||||
|
.AddYamlFile(Path.Combine(langDirectory, $"{_configManager.Configuration.GetValue<string>(ConfigKeys.Language)!}.yml"), false, true)
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Format(string key, object obj) => Formatter.Format(this[key], obj);
|
||||||
|
|
||||||
|
private void ExtractTranslation(string path)
|
||||||
|
{
|
||||||
|
var lang = path[storagePath.Length..].TrimStart(Path.GetInvalidFileNameChars()).Replace('\\', '.');
|
||||||
|
|
||||||
|
using var stream = typeof(LanguageManager).Assembly.GetManifestResourceStream(lang)!;
|
||||||
|
using var file = File.Create(path);
|
||||||
|
|
||||||
|
stream.CopyTo(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Detach()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
179
Maintenance/Managers/MaintenanceManager.cs
Normal file
179
Maintenance/Managers/MaintenanceManager.cs
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
using java.lang;
|
||||||
|
using LuckPerms.Torch.Utils.Extensions;
|
||||||
|
using Maintenance.Extensions;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using net.luckperms.api;
|
||||||
|
using net.luckperms.api.model.user;
|
||||||
|
using NLog;
|
||||||
|
using Sandbox;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Torch.API;
|
||||||
|
using Torch.API.Event;
|
||||||
|
using Torch.Commands;
|
||||||
|
using Torch.Managers;
|
||||||
|
using Torch.Server.Managers;
|
||||||
|
using Torch.Utils;
|
||||||
|
using VRage.Game.ModAPI;
|
||||||
|
using VRage.Network;
|
||||||
|
|
||||||
|
namespace Maintenance.Managers;
|
||||||
|
|
||||||
|
public class MaintenanceManager(ITorchBase torch) : Manager(torch), IEventHandler
|
||||||
|
{
|
||||||
|
public const string BypassPermission = "maintenance.bypass";
|
||||||
|
|
||||||
|
[ReflectedStaticMethod(Type = typeof(MyDedicatedServerBase))]
|
||||||
|
private static readonly Func<ulong, string> ConvertSteamIDFrom64 = null!;
|
||||||
|
|
||||||
|
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
[Dependency]
|
||||||
|
private readonly IEventManager _eventManager = null!;
|
||||||
|
|
||||||
|
[Dependency]
|
||||||
|
private readonly ConfigManager _configManager = null!;
|
||||||
|
|
||||||
|
[Dependency]
|
||||||
|
private readonly MultiplayerManagerDedicated _multiplayerManager = null!;
|
||||||
|
|
||||||
|
[Dependency]
|
||||||
|
private readonly CommandManager _commandManager = null!;
|
||||||
|
|
||||||
|
private bool _maintenanceEnabled;
|
||||||
|
private IDisposable? _disposable;
|
||||||
|
|
||||||
|
public bool MaintenanceEnabled
|
||||||
|
{
|
||||||
|
get => _maintenanceEnabled;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == _maintenanceEnabled) return;
|
||||||
|
_maintenanceEnabled = value;
|
||||||
|
|
||||||
|
Log.Info(_maintenanceEnabled ? "Maintenance Enabled" : "Maintenance Disabled");
|
||||||
|
|
||||||
|
ExecuteCommandsOnModeChange();
|
||||||
|
|
||||||
|
if (!_maintenanceEnabled ||
|
||||||
|
!_configManager.Configuration.GetValue<bool>(ConfigKeys.KickOnlinePlayers)) return;
|
||||||
|
|
||||||
|
Torch.Invoke(() =>
|
||||||
|
{
|
||||||
|
Log.Info("Kicking online players");
|
||||||
|
foreach (var steamId in _multiplayerManager.Players.Keys)
|
||||||
|
{
|
||||||
|
if (!GetIsAllowedToJoin(steamId))
|
||||||
|
MyMultiplayer.Static.DisconnectClient(steamId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteCommandsOnModeChange()
|
||||||
|
{
|
||||||
|
var commandsOnEnable =
|
||||||
|
_configManager.Configuration.GetSection(ConfigKeys.CommandsOnMaintenanceEnable).GetChildren()
|
||||||
|
.Select(b => b.Value!).ToArray();
|
||||||
|
var commandsOnDisable =
|
||||||
|
_configManager.Configuration.GetSection(ConfigKeys.CommandsOnMaintenanceDisable).GetChildren()
|
||||||
|
.Select(b => b.Value!).ToArray();
|
||||||
|
|
||||||
|
if (commandsOnEnable.Length <= 0 && commandsOnDisable.Length <= 0) return;
|
||||||
|
|
||||||
|
Torch.Invoke(() =>
|
||||||
|
{
|
||||||
|
switch (_maintenanceEnabled)
|
||||||
|
{
|
||||||
|
case true when commandsOnEnable.Length > 0:
|
||||||
|
{
|
||||||
|
foreach (var command in commandsOnEnable)
|
||||||
|
{
|
||||||
|
_commandManager.HandleCommandFromServer(command,
|
||||||
|
msg => Log.Info("Feedback from `{0}`: `{1}`", command, msg.Message));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case false when commandsOnDisable.Length > 0:
|
||||||
|
{
|
||||||
|
foreach (var command in commandsOnDisable)
|
||||||
|
{
|
||||||
|
_commandManager.HandleCommandFromServer(command,
|
||||||
|
msg => Log.Info("Feedback from `{0}`: `{1}`", command, msg.Message));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Attach()
|
||||||
|
{
|
||||||
|
_eventManager.RegisterHandler(this);
|
||||||
|
_disposable = _configManager.Configuration.GetRequiredSection(ConfigKeys.MaintenanceEnabled).GetReloadToken()
|
||||||
|
.RegisterChangeCallback(
|
||||||
|
_ => MaintenanceEnabled = _configManager.Configuration.GetValue<bool>(ConfigKeys.MaintenanceEnabled),
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Detach()
|
||||||
|
{
|
||||||
|
_disposable?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[EventHandler]
|
||||||
|
private void OnValidateAuthTicket(ref ValidateAuthTicketEvent info)
|
||||||
|
{
|
||||||
|
if (!MaintenanceEnabled) return;
|
||||||
|
|
||||||
|
var steamId = info.SteamID;
|
||||||
|
var response = info.SteamResponse;
|
||||||
|
|
||||||
|
info.FutureVerdict = FutureVerdict();
|
||||||
|
|
||||||
|
async Task<JoinResult> FutureVerdict()
|
||||||
|
{
|
||||||
|
if (await GetIsAllowedToJoinAsync(steamId)) return response;
|
||||||
|
|
||||||
|
Log.Info("Rejecting {0}", steamId);
|
||||||
|
return JoinResult.TicketCanceled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async ValueTask<bool> GetIsAllowedToJoinAsync(ulong steamId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var api = LuckPermsProvider.get();
|
||||||
|
var user = await api.getUserManager().loadUser(steamId.GetUuid()).ToTask<User>();
|
||||||
|
|
||||||
|
return user.getCachedData().getPermissionData().checkPermission(BypassPermission).asBoolean();
|
||||||
|
}
|
||||||
|
catch (IllegalStateException)
|
||||||
|
{
|
||||||
|
// we dont have api initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
var stringId = steamId.ToString();
|
||||||
|
|
||||||
|
return MySandboxGame.ConfigDedicated.Administrators.Any(
|
||||||
|
b => b == stringId || b == ConvertSteamIDFrom64(steamId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool GetIsAllowedToJoin(ulong steamId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var api = LuckPermsProvider.get();
|
||||||
|
return api.getPlayerAdapter(typeof(IPlayer)).getPermissionData(_multiplayerManager.Players[steamId])
|
||||||
|
.checkPermission(BypassPermission).asBoolean();
|
||||||
|
}
|
||||||
|
catch (IllegalStateException)
|
||||||
|
{
|
||||||
|
// we dont have api initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
return _multiplayerManager.GetUserPromoteLevel(steamId) == MyPromoteLevel.Owner;
|
||||||
|
}
|
||||||
|
}
|
181
Maintenance/Managers/MaintenanceScheduleManager.cs
Normal file
181
Maintenance/Managers/MaintenanceScheduleManager.cs
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Torch.API.Managers;
|
||||||
|
using Torch.Managers;
|
||||||
|
|
||||||
|
namespace Maintenance.Managers;
|
||||||
|
|
||||||
|
public class MaintenanceScheduleManager(string storagePath) : IManager
|
||||||
|
{
|
||||||
|
[Manager.Dependency]
|
||||||
|
private readonly MaintenanceManager _maintenanceManager = null!;
|
||||||
|
|
||||||
|
[Manager.Dependency]
|
||||||
|
private readonly ConfigManager _configManager = null!;
|
||||||
|
|
||||||
|
[Manager.Dependency]
|
||||||
|
private readonly LanguageManager _languageManager = null!;
|
||||||
|
|
||||||
|
[Manager.Dependency]
|
||||||
|
private readonly IChatManagerServer _chatManager = null!;
|
||||||
|
|
||||||
|
private MaintenanceSchedule _currentSchedule = MaintenanceSchedule.Default;
|
||||||
|
|
||||||
|
private readonly FileInfo _scheduleFile = new(Path.Combine(storagePath, ".schedule"));
|
||||||
|
|
||||||
|
public MaintenanceSchedule CurrentSchedule
|
||||||
|
{
|
||||||
|
get => _currentSchedule;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (value != _currentSchedule)
|
||||||
|
{
|
||||||
|
using var file = _scheduleFile.Create();
|
||||||
|
JsonSerializer.Serialize(file, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentSchedule = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
||||||
|
|
||||||
|
public void Attach()
|
||||||
|
{
|
||||||
|
Scheduler();
|
||||||
|
|
||||||
|
if (!_scheduleFile.Exists) return;
|
||||||
|
|
||||||
|
using (var file = _scheduleFile.OpenRead())
|
||||||
|
_currentSchedule = JsonSerializer.Deserialize<MaintenanceSchedule>(file)!;
|
||||||
|
|
||||||
|
_scheduleFile.Delete();
|
||||||
|
|
||||||
|
if (_currentSchedule is not { StartTime: null, EndTime: not null }) return;
|
||||||
|
|
||||||
|
if (!_configManager.Configuration.GetValue<bool>(ConfigKeys.ContinueEndTimerAfterRestart))
|
||||||
|
CurrentSchedule = MaintenanceSchedule.Default;
|
||||||
|
|
||||||
|
_maintenanceManager.MaintenanceEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Scheduler()
|
||||||
|
{
|
||||||
|
var token = _cancellationTokenSource.Token;
|
||||||
|
|
||||||
|
var timerSecondsSection = _configManager.Configuration.GetSection(ConfigKeys.TimerBroadcastForSeconds);
|
||||||
|
var timerSeconds = timerSecondsSection.GetChildren().Select(b => b.Get<int>()).ToArray();
|
||||||
|
|
||||||
|
using var disposable = timerSecondsSection.GetReloadToken()
|
||||||
|
.RegisterChangeCallback(_ => timerSeconds = timerSecondsSection.GetChildren().Select(b => b.Get<int>()).ToArray(), null);
|
||||||
|
|
||||||
|
while (!token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
await Task.Delay(2000, token);
|
||||||
|
|
||||||
|
switch (_maintenanceManager.MaintenanceEnabled)
|
||||||
|
{
|
||||||
|
case false when _currentSchedule.StartTime.HasValue:
|
||||||
|
{
|
||||||
|
if (timerSeconds.Any(b => Math.Abs(_currentSchedule.Time.TotalSeconds - b) <= 1))
|
||||||
|
{
|
||||||
|
_chatManager.SendMessageAsOther("Maintenance",
|
||||||
|
Format(_currentSchedule.EndTime.HasValue
|
||||||
|
? LangKeys.ScheduleTimerBroadcast
|
||||||
|
: LangKeys.StartTimerBroadcast));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentSchedule.Time.TotalSeconds <= 1)
|
||||||
|
{
|
||||||
|
_chatManager.SendMessageAsOther("Maintenance", Format(LangKeys.MaintenanceActivated));
|
||||||
|
_maintenanceManager.MaintenanceEnabled = true;
|
||||||
|
CurrentSchedule = CurrentSchedule with { StartTime = null };
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case true when _currentSchedule.EndTime.HasValue:
|
||||||
|
{
|
||||||
|
if (timerSeconds.Any(b => Math.Abs(_currentSchedule.Duration.TotalSeconds - b) <= 1))
|
||||||
|
{
|
||||||
|
_chatManager.SendMessageAsOther("Maintenance", Format(LangKeys.EndTimerBroadcast));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentSchedule.Duration.TotalSeconds <= 1)
|
||||||
|
{
|
||||||
|
_chatManager.SendMessageAsOther("Maintenance", Format(LangKeys.MaintenanceDeactivated));
|
||||||
|
_maintenanceManager.MaintenanceEnabled = false;
|
||||||
|
CurrentSchedule = CurrentSchedule with { EndTime = null };
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string Format(string key) => _languageManager.Format(key, _currentSchedule);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Detach()
|
||||||
|
{
|
||||||
|
_cancellationTokenSource.Cancel();
|
||||||
|
_cancellationTokenSource.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ScheduleTimer(TimerType type, TimeSpan duration)
|
||||||
|
{
|
||||||
|
if (_maintenanceManager.MaintenanceEnabled && type == TimerType.Start)
|
||||||
|
throw new InvalidOperationException("Maintenance is already enabled");
|
||||||
|
|
||||||
|
if (type == TimerType.Start)
|
||||||
|
CurrentSchedule = CurrentSchedule with { StartTime = DateTimeOffset.Now + duration };
|
||||||
|
else
|
||||||
|
CurrentSchedule = CurrentSchedule with { EndTime = DateTimeOffset.Now + duration };
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ScheduleMaintenance(TimeSpan startTime, TimeSpan endTime)
|
||||||
|
{
|
||||||
|
if (_maintenanceManager.MaintenanceEnabled)
|
||||||
|
throw new InvalidOperationException("Maintenance is already enabled");
|
||||||
|
|
||||||
|
var startDateTime = DateTimeOffset.Now + startTime;
|
||||||
|
|
||||||
|
CurrentSchedule = new(startDateTime, startDateTime + endTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelTimer(TimerType? type)
|
||||||
|
{
|
||||||
|
CurrentSchedule = type switch
|
||||||
|
{
|
||||||
|
TimerType.Start when !_currentSchedule.StartTime.HasValue => throw new InvalidOperationException(
|
||||||
|
"No start timer running"),
|
||||||
|
TimerType.Start => MaintenanceSchedule.Default,
|
||||||
|
TimerType.End when !_currentSchedule.EndTime.HasValue => throw new InvalidOperationException(
|
||||||
|
"No end timer running"),
|
||||||
|
TimerType.End => CurrentSchedule with { EndTime = null },
|
||||||
|
_ => MaintenanceSchedule.Default
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record MaintenanceSchedule(DateTimeOffset? StartTime, DateTimeOffset? EndTime)
|
||||||
|
{
|
||||||
|
public static MaintenanceSchedule Default => new(null, null);
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public TimeSpan Time => Round((StartTime ?? throw new InvalidOperationException("No start timer running"))
|
||||||
|
- DateTimeOffset.Now);
|
||||||
|
[JsonIgnore]
|
||||||
|
public TimeSpan Duration => Round((EndTime ?? throw new InvalidOperationException("No end timer running"))
|
||||||
|
- (StartTime ?? DateTimeOffset.Now));
|
||||||
|
|
||||||
|
private static TimeSpan Round(TimeSpan timeSpan) => TimeSpan.FromSeconds(Math.Round(timeSpan.TotalSeconds, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TimerType : byte
|
||||||
|
{
|
||||||
|
Start,
|
||||||
|
End
|
||||||
|
}
|
361
Maintenance/Patches/SteamQueryPatch.cs
Normal file
361
Maintenance/Patches/SteamQueryPatch.cs
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using Maintenance.Managers;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using NLog;
|
||||||
|
using Sandbox;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Sandbox.Game.Multiplayer;
|
||||||
|
using Sandbox.Game.World;
|
||||||
|
using Steamworks;
|
||||||
|
using Torch;
|
||||||
|
using Torch.API;
|
||||||
|
using Torch.API.Managers;
|
||||||
|
using Torch.Managers.PatchManager;
|
||||||
|
using Torch.Utils;
|
||||||
|
using VRage.Game;
|
||||||
|
using VRage.GameServices;
|
||||||
|
using VRage.Library.Utils;
|
||||||
|
using VRage.Utils;
|
||||||
|
|
||||||
|
namespace Maintenance.Patches;
|
||||||
|
|
||||||
|
[PatchShim]
|
||||||
|
public static class SteamQueryPatch
|
||||||
|
{
|
||||||
|
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
[ReflectedMethodInfo(null, "SteamServerEntryPoint", TypeName = "VRage.Steam.MySteamGameServer, VRage.Steam")]
|
||||||
|
private static readonly MethodInfo EntryPointMethod = null!;
|
||||||
|
|
||||||
|
[ReflectedMethodInfo(typeof(SteamQueryPatch), nameof(Prefix))]
|
||||||
|
private static readonly MethodInfo PrefixMethod = null!;
|
||||||
|
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
private static ITorchBase Torch => TorchBase.Instance;
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
|
||||||
|
private static bool MaintenanceEnabled =>
|
||||||
|
Torch.CurrentSession?.Managers.GetManager<MaintenanceManager>().MaintenanceEnabled is true;
|
||||||
|
|
||||||
|
public static void Patch(PatchContext context)
|
||||||
|
{
|
||||||
|
context.GetPattern(EntryPointMethod).Prefixes.Add(PrefixMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool Prefix(IMyGameServer __instance, object argument)
|
||||||
|
{
|
||||||
|
var socket = (Socket)argument;
|
||||||
|
RunServerAsync(__instance, socket);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async void RunServerAsync(IMyGameServer server, Socket socket)
|
||||||
|
{
|
||||||
|
var localEndPoint = socket.LocalEndPoint;
|
||||||
|
var zeroEndPoint = new IPEndPoint(0L, 0);
|
||||||
|
// better to calc based on mtu but i dont care
|
||||||
|
var buffer = new byte[1500];
|
||||||
|
|
||||||
|
while (server.Running)
|
||||||
|
{
|
||||||
|
SocketReceiveFromResult result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = await socket.ReceiveFromAsync(new(buffer), SocketFlags.None, zeroEndPoint);
|
||||||
|
}
|
||||||
|
catch (SocketException ex)
|
||||||
|
{
|
||||||
|
if (!server.Running)
|
||||||
|
break;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket.Close();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Warn($"Received socket exception with error code: {ex.ErrorCode}, {ex.SocketErrorCode}", ex);
|
||||||
|
Log.Info("Attempting to create new socket.");
|
||||||
|
socket = new(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket.Bind(localEndPoint);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
catch (SocketException e)
|
||||||
|
{
|
||||||
|
Log.Fatal(e, "Error binding server endpoint");
|
||||||
|
|
||||||
|
socket.Close();
|
||||||
|
server.GetType().GetProperty("Running")?.SetValue(server, false);
|
||||||
|
GameServer.Shutdown();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CheckHeader(buffer.AsSpan(0, 4)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (result.ReceivedBytes > 4 && MySession.Static is not null)
|
||||||
|
{
|
||||||
|
Debug.Write("byte is ");
|
||||||
|
Debug.WriteLine(buffer[4].ToString("X"));
|
||||||
|
switch (buffer[4])
|
||||||
|
{
|
||||||
|
case 0x54:
|
||||||
|
await HandleInfoRequestAsync(socket, result.RemoteEndPoint);
|
||||||
|
continue;
|
||||||
|
// players request without challenge
|
||||||
|
case 0x55 when result.ReceivedBytes > 8 && !CheckHeader(buffer.AsSpan(5, 4)):
|
||||||
|
await HandlePlayersRequestAsync(socket, result.RemoteEndPoint);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var remoteEndPoint = (IPEndPoint)result.RemoteEndPoint;
|
||||||
|
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
SteamGameServer.HandleIncomingPacket(buffer, result.ReceivedBytes, (uint)remoteEndPoint.Address.Address,
|
||||||
|
(ushort)remoteEndPoint.Port);
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
|
||||||
|
int length;
|
||||||
|
while ((length = SteamGameServer.GetNextOutgoingPacket(buffer, buffer.Length, out var addr, out var port)) >
|
||||||
|
0)
|
||||||
|
{
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
remoteEndPoint.Address.Address = addr;
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
remoteEndPoint.Port = port;
|
||||||
|
|
||||||
|
await socket.SendToAsync(new(buffer, 0, length), SocketFlags.None, remoteEndPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static bool CheckHeader(Span<byte> header) =>
|
||||||
|
Unsafe.ReadUnaligned<uint>(ref header.GetPinnableReference()) == 0xFFFFFFFF;
|
||||||
|
|
||||||
|
private static Task HandlePlayersRequestAsync(Socket socket, EndPoint sender)
|
||||||
|
{
|
||||||
|
if (Sync.Players is null)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
Debug.WriteLine($"players request from {sender}");
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
|
||||||
|
// header
|
||||||
|
ms.WriteNoAlloc(0xFFFFFFFF);
|
||||||
|
ms.WriteByte(0x44);
|
||||||
|
|
||||||
|
if (MaintenanceEnabled)
|
||||||
|
{
|
||||||
|
ms.WriteByte(0); // count
|
||||||
|
return SendAsync(ms, socket, sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
var players = Sync.Clients.GetClients().Where(b => !b.IsLocal).Select(b => (b.DisplayName,
|
||||||
|
(float?)(DateTime.Now - Sync.Players.TryGetIdentity((long)b.SteamUserId)?.LastLoginTime)?.TotalSeconds ??
|
||||||
|
0f)).ToArray();
|
||||||
|
|
||||||
|
var count = (byte)players.Length;
|
||||||
|
|
||||||
|
// total
|
||||||
|
ms.WriteByte(count);
|
||||||
|
|
||||||
|
for (byte i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
// i
|
||||||
|
ms.WriteByte(i);
|
||||||
|
|
||||||
|
var (name, duration) = players[i];
|
||||||
|
|
||||||
|
// name
|
||||||
|
WriteUtf8String(ms, name);
|
||||||
|
|
||||||
|
// score
|
||||||
|
ms.WriteNoAlloc(0U);
|
||||||
|
|
||||||
|
// duration
|
||||||
|
ms.WriteNoAlloc(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SendAsync(ms, socket, sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Task HandleInfoRequestAsync(Socket socket, EndPoint sender)
|
||||||
|
{
|
||||||
|
if (Sync.Players is null)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
Debug.WriteLine($"info request from {sender}");
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
|
||||||
|
var mp = MyMultiplayer.Static;
|
||||||
|
|
||||||
|
// header
|
||||||
|
ms.WriteNoAlloc(0xFFFFFFFF);
|
||||||
|
ms.WriteByte(0x49);
|
||||||
|
|
||||||
|
// protocol
|
||||||
|
ms.WriteByte(0x11);
|
||||||
|
|
||||||
|
var maintenanceEnabled = MaintenanceEnabled;
|
||||||
|
|
||||||
|
// name
|
||||||
|
WriteUtf8String(ms, mp.HostName);
|
||||||
|
|
||||||
|
if (maintenanceEnabled)
|
||||||
|
{
|
||||||
|
var config = Torch.Managers.GetManager<ConfigManager>().Configuration;
|
||||||
|
var formatter = Torch.Managers.GetManager<LanguageManager>().Formatter;
|
||||||
|
|
||||||
|
if (config.GetValue<bool>(ConfigKeys.EnableWorldMessage))
|
||||||
|
{
|
||||||
|
var randomItem = config.GetSection(ConfigKeys.WorldMessage).GetChildren().Select(b => b.Value!).ToArray()
|
||||||
|
.GetRandomItem();
|
||||||
|
var schedule = Torch.CurrentSession.Managers.GetManager<MaintenanceScheduleManager>().CurrentSchedule;
|
||||||
|
|
||||||
|
// map
|
||||||
|
WriteUtf8String(ms, schedule.EndTime.HasValue ? formatter.Format(randomItem, schedule) : randomItem);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// map
|
||||||
|
WriteUtf8String(ms, mp.WorldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// map
|
||||||
|
WriteUtf8String(ms, mp.WorldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// folder
|
||||||
|
WriteUtf8String(ms, "Space Engineers");
|
||||||
|
|
||||||
|
// game full name
|
||||||
|
WriteUtf8String(ms, "Space Engineers");
|
||||||
|
|
||||||
|
// app id
|
||||||
|
ms.WriteNoAlloc((short)0);
|
||||||
|
|
||||||
|
// players
|
||||||
|
ms.WriteByte(maintenanceEnabled ? default : (byte)(Sync.Clients.Count - 1));
|
||||||
|
|
||||||
|
// max players
|
||||||
|
ms.WriteByte((byte)(maintenanceEnabled ? 0x00 : mp.MaxPlayers));
|
||||||
|
|
||||||
|
// bots
|
||||||
|
ms.WriteByte(0x00);
|
||||||
|
|
||||||
|
// server type
|
||||||
|
ms.WriteByte((byte)'d');
|
||||||
|
|
||||||
|
// env
|
||||||
|
ms.WriteByte((byte)'w');
|
||||||
|
|
||||||
|
// visibility
|
||||||
|
ms.WriteByte(0x00);
|
||||||
|
|
||||||
|
// vac
|
||||||
|
ms.WriteByte(0x01);
|
||||||
|
|
||||||
|
// version
|
||||||
|
WriteUtf8String(ms, MyFinalBuildConstants.APP_VERSION.Version.ToString());
|
||||||
|
|
||||||
|
// edf (GameID SteamID Keywords Port)
|
||||||
|
ms.WriteByte(177);
|
||||||
|
|
||||||
|
// edf port
|
||||||
|
ms.WriteNoAlloc((short)((IPEndPoint)socket.LocalEndPoint).Port);
|
||||||
|
|
||||||
|
// edf steam id
|
||||||
|
ms.WriteNoAlloc(Sync.MyId);
|
||||||
|
|
||||||
|
// edf keywords
|
||||||
|
var gameMode = mp.GameMode is MyGameModeEnum.Survival
|
||||||
|
? $"S{mp.InventoryMultiplier}-{mp.BlocksInventoryMultiplier}-{mp.AssemblerMultiplier}-{mp.RefineryMultiplier}"
|
||||||
|
: "C";
|
||||||
|
WriteUtf8String(
|
||||||
|
ms,
|
||||||
|
$"groupId{MySandboxGame.ConfigDedicated.GroupID} version{MyFinalBuildConstants.APP_VERSION} datahasheRRN1/jJ7J2ZlR7GB1D5PDzn0sQ= mods{mp.ModCount} gamemode{gameMode} view{mp.SyncDistance}");
|
||||||
|
|
||||||
|
// edf game id
|
||||||
|
ms.WriteNoAlloc((ulong)244850);
|
||||||
|
|
||||||
|
return SendAsync(ms, socket, sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task SendAsync(MemoryStream ms, Socket socket, EndPoint sender)
|
||||||
|
{
|
||||||
|
Debug.WriteLine(string.Join(" ", ms.GetBuffer().Take((int)ms.Length).Select(b => b.ToString("X"))));
|
||||||
|
|
||||||
|
const int packetSize = 1200;
|
||||||
|
|
||||||
|
if (ms.Length < packetSize)
|
||||||
|
{
|
||||||
|
await socket.SendToAsync(new(ms.GetBuffer(), 0, (int)ms.Length), SocketFlags.None, sender);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = (uint)MyRandom.Instance.Next();
|
||||||
|
id &= ~(1 << 31);
|
||||||
|
|
||||||
|
var msLength = ms.Length - 4;
|
||||||
|
for (var i = 0; i < msLength; i += packetSize)
|
||||||
|
{
|
||||||
|
var length = Math.Min(packetSize, (int)msLength - i);
|
||||||
|
|
||||||
|
var buffer = new byte[length + 10];
|
||||||
|
|
||||||
|
// header
|
||||||
|
Unsafe.WriteUnaligned(ref buffer.AsSpan(0, 4).GetPinnableReference(), 0xFFFFFFFE);
|
||||||
|
|
||||||
|
// id
|
||||||
|
Unsafe.WriteUnaligned(ref buffer.AsSpan(4, 4).GetPinnableReference(), id);
|
||||||
|
|
||||||
|
// total
|
||||||
|
buffer[8] = (byte)Math.Ceiling((float)msLength / packetSize);
|
||||||
|
|
||||||
|
// number
|
||||||
|
buffer[9] = (byte)(i / packetSize);
|
||||||
|
|
||||||
|
ms.GetBuffer().AsSpan(i + 4, length).CopyTo(buffer.AsSpan(10));
|
||||||
|
|
||||||
|
await socket.SendToAsync(new(buffer), SocketFlags.None, sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe void WriteUtf8String(Stream stream, string str)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(str))
|
||||||
|
{
|
||||||
|
stream.WriteByte(0x00);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var chars = str.AsSpan();
|
||||||
|
Span<byte> bytes = stackalloc byte[Encoding.UTF8.GetByteCount(str)];
|
||||||
|
|
||||||
|
var length = Encoding.UTF8.GetBytes((char*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(chars)),
|
||||||
|
chars.Length,
|
||||||
|
(byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(bytes)),
|
||||||
|
bytes.Length);
|
||||||
|
|
||||||
|
stream.WriteNoAlloc((byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(bytes)), 0, length);
|
||||||
|
stream.WriteByte(0x00);
|
||||||
|
}
|
||||||
|
}
|
21
Maintenance/Plugin.cs
Normal file
21
Maintenance/Plugin.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System.IO;
|
||||||
|
using Maintenance.Managers;
|
||||||
|
using Torch;
|
||||||
|
using Torch.API;
|
||||||
|
using Torch.API.Managers;
|
||||||
|
using Torch.API.Session;
|
||||||
|
|
||||||
|
namespace Maintenance;
|
||||||
|
|
||||||
|
public class Plugin : TorchPluginBase
|
||||||
|
{
|
||||||
|
public override void Init(ITorchBase torch)
|
||||||
|
{
|
||||||
|
var storagePath = Directory.CreateDirectory(Path.Combine(StoragePath, "maintenance")).FullName;
|
||||||
|
|
||||||
|
torch.Managers.AddManager(new ConfigManager(storagePath));
|
||||||
|
torch.Managers.AddManager(new LanguageManager(storagePath));
|
||||||
|
torch.Managers.GetManager<ITorchSessionManager>().AddFactory(s => new MaintenanceManager(s.Torch));
|
||||||
|
torch.Managers.GetManager<ITorchSessionManager>().AddFactory(_ => new MaintenanceScheduleManager(storagePath));
|
||||||
|
}
|
||||||
|
}
|
32
Maintenance/Resources/config.yml
Normal file
32
Maintenance/Resources/config.yml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Enables maintenance mode.
|
||||||
|
maintenance-enabled: false
|
||||||
|
|
||||||
|
# Any extra commands inside the arrays will be executed when maintenance is enabled/disabled.
|
||||||
|
# Example: commands-on-maintenance-enable: ["say hello!", "stop"]
|
||||||
|
commands-on-maintenance-enable: []
|
||||||
|
commands-on-maintenance-disable: []
|
||||||
|
|
||||||
|
# If set to true, the world name for the servers list from this pool will be chosen.
|
||||||
|
# If you put in multiple entries, one of them will be chosen randomly on every ping.
|
||||||
|
# If running an endtimer, the time left can be displayed by including {duration} in the message.
|
||||||
|
# Additionally you can set custom timestamp format with {duration:hh\\:mm\\:\\ss}. See all available formats at https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-timespan-format-strings
|
||||||
|
enable-world-message: true
|
||||||
|
world-message:
|
||||||
|
# - "[MAINTENANCE]"
|
||||||
|
# - "Back in {duration:hh\\:mm}"
|
||||||
|
|
||||||
|
# Set this to false if you do not want players to be kicked when you enable maintenance (new connections will still be blocked).
|
||||||
|
# ... I don't know why you would want that, but you can disable it. :p
|
||||||
|
kick-online-players: true
|
||||||
|
|
||||||
|
# Changes the language of command feedback/messages.
|
||||||
|
# If you find missing translations or want to contribute a new language file, you are very welcome to message me on my Discord server! :)
|
||||||
|
# Currently available are: en (English)
|
||||||
|
language: en
|
||||||
|
|
||||||
|
# If enabled and the server is restarted while running an endtimer, the timer will be continued after the restart.
|
||||||
|
# If the timer ends while the server is offline, maintenance will be disabled as soon as the server starts again.
|
||||||
|
continue-endtimer-after-restart: true
|
||||||
|
|
||||||
|
# If using the timer command: In what intervals before enabling/disabling maintenance there will be a broadcast.
|
||||||
|
timer-broadcast-for-seconds: [1200, 900, 600, 300, 120, 60, 30, 20, 10, 5, 4, 3, 2, 1]
|
13
Maintenance/Resources/translations/en.yml
Normal file
13
Maintenance/Resources/translations/en.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
maintenanceActivated: "Maintenance mode is now activated."
|
||||||
|
maintenanceDeactivated: "Maintenance mode is now deactivated."
|
||||||
|
alreadyEnabled: "Maintenance is already enabled!"
|
||||||
|
alreadyDisabled: "Maintenance is already disabled!"
|
||||||
|
endtimerBroadcast: "Maintenance mode will be disabled in {duration}."
|
||||||
|
endtimerStarted: "Started timer: Maintenance mode will be deactivated in {duration}."
|
||||||
|
starttimerBroadcast: "Maintenance mode will be enabled in {time}."
|
||||||
|
starttimerStarted: "Started timer: Maintenance mode will be activated in {time}."
|
||||||
|
scheduletimerBroadcast: "Maintenance mode will be enabled in {time} and will last for {duration}."
|
||||||
|
timerAlreadyRunning: "There is already a timer scheduled!"
|
||||||
|
timerNotRunning: "There is currently no running timer."
|
||||||
|
timerCancelled: "The current timer has been disabled."
|
||||||
|
timerTooLong: "The number has to be less than 40320 (28 days)!"
|
6
Maintenance/manifest.xml
Normal file
6
Maintenance/manifest.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<PluginManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<Name>Maintenance</Name>
|
||||||
|
<Guid>42AF9955-AAA7-442F-9BF4-AAC4FA4A923F</Guid>
|
||||||
|
<Version>v1.0.0</Version>
|
||||||
|
</PluginManifest>
|
438
Maintenance/packages.lock.json
Normal file
438
Maintenance/packages.lock.json
Normal file
@@ -0,0 +1,438 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"dependencies": {
|
||||||
|
".NETFramework,Version=v4.8": {
|
||||||
|
"Alexinea.Extensions.Configuration.Yaml": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[7.0.0, )",
|
||||||
|
"resolved": "7.0.0",
|
||||||
|
"contentHash": "gIeecqFF2YeDrGxRulJvyYCRbQcvmowNnQt5qDg2FUS3bzjtwgahHFioD+yWFGxBYR/vWGbP3h6PGoCUxOzTqA==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration": "7.0.0",
|
||||||
|
"Microsoft.Extensions.Configuration.FileExtensions": "7.0.0",
|
||||||
|
"YamlDotNet": "12.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"LuckPerms.Torch.Api": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[5.4.0, )",
|
||||||
|
"resolved": "5.4.0",
|
||||||
|
"contentHash": "jwmRs6dJupqqj2V5bf1vMleQIFqKxhsaLxiNvTFFrzsgFjPJf3TDMEe68Qf62/J1Z2gQKvVbSw/LCGCn+ZOWmw==",
|
||||||
|
"dependencies": {
|
||||||
|
"IKVM.Maven.Sdk": "1.6.1",
|
||||||
|
"LuckPerms.Torch.Utils": "1.0.0",
|
||||||
|
"Torch.Loader": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.Configuration.Binder": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[8.0.0, )",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "mBMoXLsr5s1y2zOHWmKsE9veDcx8h1x/c3rz4baEdQKTeDcmQAPNbB54Pi/lhFO3K431eEq6PFbMgLaa6PHFfA==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.Configuration.FileExtensions": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[8.0.0, )",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.FileProviders.Physical": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.NETFramework.ReferenceAssemblies": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.0.3, )",
|
||||||
|
"resolved": "1.0.3",
|
||||||
|
"contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.NETFramework.ReferenceAssemblies.net48": "1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PolySharp": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.8.1, )",
|
||||||
|
"resolved": "1.8.1",
|
||||||
|
"contentHash": "T60CnqUsOC8JT2O9ixmBVBoA+0n4FIkRGwK4IuuPgncsJYd5m44s/IaNMQsCzZ7nxmPHa6A9DEaXSi1/ENx8iA=="
|
||||||
|
},
|
||||||
|
"SmartFormat": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[3.3.0, )",
|
||||||
|
"resolved": "3.3.0",
|
||||||
|
"contentHash": "JN19FJuWZwW3G3euSQNTDLAr5wI8ok/VDcBfEN88cZPvzCQMPdyS9s4/fQlEuupXH+IV0wBEbodHVS51t2RIDQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Memory": "4.5.5",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Torch.Server.ReferenceAssemblies": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.3.1.260-master, )",
|
||||||
|
"resolved": "1.3.1.260-master",
|
||||||
|
"contentHash": "p9fHBwPI2BZDLO2PiSPvJxHQ7lksYf/20BZ0uUxMlSnJk/AvFUpjT6CMxJWow4UuAFG+NcPEI4VhxZ5x9jhGGA==",
|
||||||
|
"dependencies": {
|
||||||
|
"NLog": "4.4.12",
|
||||||
|
"Newtonsoft.Json": "12.0.2",
|
||||||
|
"SpaceEngineersDedicated.ReferenceAssemblies": "1.203.505"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IKVM": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "CEgKzDhnBq5XoCt0ABREfIn6k0TqF2go7zFAiaI9cjXesPezfquVJRPPn9fl+hO90fOo7eCDnkgDn5B8DoZe1w==",
|
||||||
|
"dependencies": {
|
||||||
|
"IKVM.Image": "8.7.1",
|
||||||
|
"IKVM.MSBuild": "8.7.1",
|
||||||
|
"Mono.Posix": "7.1.0-final.1.21458.1",
|
||||||
|
"Mono.Unix": "7.1.0-final.1.21458.1",
|
||||||
|
"System.Buffers": "4.5.1",
|
||||||
|
"System.IO.Pipelines": "6.0.3",
|
||||||
|
"System.Memory": "4.5.5",
|
||||||
|
"System.Runtime.CompilerServices.Unsafe": "6.0.0",
|
||||||
|
"System.Runtime.InteropServices.RuntimeInformation": "4.3.0",
|
||||||
|
"System.Text.Json": "6.0.6",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IKVM.Image": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "RqwuWeb9cwqmcTKREb71odXvv5NO5+Zvo3SSG2CW1XumqCwCkm7sFdzulTYHEQcVs8GjDUlvLIEnrb6QLsqb7w==",
|
||||||
|
"dependencies": {
|
||||||
|
"IKVM.Image.runtime.linux-arm": "8.7.1",
|
||||||
|
"IKVM.Image.runtime.linux-arm64": "8.7.1",
|
||||||
|
"IKVM.Image.runtime.linux-musl-arm": "8.7.1",
|
||||||
|
"IKVM.Image.runtime.linux-musl-arm64": "8.7.1",
|
||||||
|
"IKVM.Image.runtime.linux-musl-x64": "8.7.1",
|
||||||
|
"IKVM.Image.runtime.linux-x64": "8.7.1",
|
||||||
|
"IKVM.Image.runtime.osx-arm64": "8.7.1",
|
||||||
|
"IKVM.Image.runtime.osx-x64": "8.7.1",
|
||||||
|
"IKVM.Image.runtime.win-arm64": "8.7.1",
|
||||||
|
"IKVM.Image.runtime.win-x64": "8.7.1",
|
||||||
|
"IKVM.Image.runtime.win-x86": "8.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.linux-arm": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "f12l6AKUfM8Q1Dv9ZbkW39Ok2URq8ar9buhvXFtCeDbXxi5euYyYfR/eehM3nSb0wTo3cyvGxqM/G5M/jI9WUg=="
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.linux-arm64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "o1URwAXZjfgdkS6R12ZA/l2oKhk5j9f98YjUiQfhzgt63ksVHjz3f5sRELDrsHUCAWNT2GR3ahlPHABuD3WT4A=="
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.linux-musl-arm": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "+3ijUii2jwsl0KeZZ3nkiwKkie0qpskLerARjrKdKQ3ylDxVaSwxtQWGJT7Eiu1YpKbyKYXOMptHE1IQqO4Zkg=="
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.linux-musl-arm64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "9cXMSPAa8ODf99vuce0wnFV9urYy4iVjAp+pE4ieejqp/Jk2NCtKr7NJs+Q6shs3nsOl6A2aJnxZV5FGnd/wCg=="
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.linux-musl-x64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "K3DO1q2kGYnnyFNZ3K27K3Q19yl5U+at4le9aA9O/Or3zpXi2c1GOFaA+hrVB7DzIrvxXGCR6qKGzM9K8goYmg=="
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.linux-x64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "bG9Sara5Ft7JTf8iMS9RUea4Foi05Vdr7t7VA37SeloTTxlFmNUYSafo+X1U9eOYuv8XUueveid07E+KzMTSGQ=="
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.osx-arm64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "vShR5pUZJIsTsc1lUzsNdBINGjPZ20RrUIunQe9W/rCW63El3uKZq2Rboa2E50YXNG3BgmMaCEUmel3nqS8DQw=="
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.osx-x64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "E/IFd3Eqj/6vxk1EqRBD5lpZGwI3qx/Uocqnt98UGr01HPO2ZvNs3Y2kmSmz3hA/xwDrjObCVrdYWKsfzoIwTw=="
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.win-arm64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "oSvRLYy3iWgdJyFkbmNr0pl4x9/1zbXvavybpOzTFa7xSg3dfAcysUi8nHgjNpd94z8udrOcKEbm8GQ5DKAdRg=="
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.win-x64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "Od5ynm5wVyzV85CQ5VfUmQAvbrEKjRxEIR1Id2tHugVGPnL3cviEezbokg+tkByIubIx1mAjJ4HGqtcNqTDpmA=="
|
||||||
|
},
|
||||||
|
"IKVM.Image.runtime.win-x86": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "yBXBH2Ad8UjJ6ZhH6eqJyya8a22Et5lAUNQ0S8Vtexmay+oby3880bzvUkQ0rRKF1OceJxm6u3bLC58hnh16eQ=="
|
||||||
|
},
|
||||||
|
"IKVM.Maven.Sdk": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.6.1",
|
||||||
|
"contentHash": "Gb8bB12uYQGxiFggrT540Sy/71xYQr+8JSrauG5OlKiIcQhh6k3vI7I7hLQAWdd+bzdFYO7rs/BxdPzzV+j3Fg==",
|
||||||
|
"dependencies": {
|
||||||
|
"IKVM": "8.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IKVM.MSBuild": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "gkSV0y7mZ25PgXw9cnTnVFhE/oa9XSxcPkXnYS2I4XQ+moKkPeuZokUJaFy/qN1hcJIL8s9UKo6kUNwjjEFLBQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"IKVM.MSBuild.Tools": "8.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IKVM.MSBuild.Tools": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "MJzc2ymPe27pY3Cz+s6yvr67RuVnAsFKuD0hSdN2wnERpz/K2wl9ZSaJ/egRJRrfs/0R2qqYo4Eer6H9Mcc4ag==",
|
||||||
|
"dependencies": {
|
||||||
|
"IKVM.MSBuild.Tools.runtime.linux-arm": "8.7.1",
|
||||||
|
"IKVM.MSBuild.Tools.runtime.linux-arm64": "8.7.1",
|
||||||
|
"IKVM.MSBuild.Tools.runtime.linux-x64": "8.7.1",
|
||||||
|
"IKVM.MSBuild.Tools.runtime.osx-arm64": "8.7.1",
|
||||||
|
"IKVM.MSBuild.Tools.runtime.osx-x64": "8.7.1",
|
||||||
|
"IKVM.MSBuild.Tools.runtime.win-arm64": "8.7.1",
|
||||||
|
"IKVM.MSBuild.Tools.runtime.win-x64": "8.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IKVM.MSBuild.Tools.runtime.linux-arm": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "2X2meYtplgzEJpZEHpEdrnhbyzKlJmfkOfKMenMM1W707JQ2SsWTDHlWw7PwY3KzPKoDbqNWb69rHS9a99TnUQ=="
|
||||||
|
},
|
||||||
|
"IKVM.MSBuild.Tools.runtime.linux-arm64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "BmhJBqbjn693fLo5G+YyXB7uDF11Ia5k1K7INk1zMYiBcfYZHJUEE29KZ5fvXgspjn6OEazgmOF/PxoxWTBmkQ=="
|
||||||
|
},
|
||||||
|
"IKVM.MSBuild.Tools.runtime.linux-x64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "zBaGJoJ4pvf3uPNfxreHPGGhQFWUqiLyGcDurTuPGix29T8c3TeCU4z5JAJkhGf7hat/s98pSzqt9T5uAahSDg=="
|
||||||
|
},
|
||||||
|
"IKVM.MSBuild.Tools.runtime.osx-arm64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "XCG8udNMf7WjfUth7K1x63vP/Kra+4p/WByzMHNvLoM47x2XVX8OMyw1N6SGah+cHtsKL8VKkLdlct/b2Cpxbw=="
|
||||||
|
},
|
||||||
|
"IKVM.MSBuild.Tools.runtime.osx-x64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "boMF3LCpTrkbi2emU263gVHz/TYCgtCVhDMLXTojIaJ8guA5q/nuFufhYljpjECzxzVg3IUIX6jNBu4PEjC+HQ=="
|
||||||
|
},
|
||||||
|
"IKVM.MSBuild.Tools.runtime.win-arm64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "TRssQQBZbeXBKDtF8yo5bLk9mXmnvN1MUucLgP+t+6araaYUohsVJieMoDiJhcVqWgStv88+BHKLCexII/NUFw=="
|
||||||
|
},
|
||||||
|
"IKVM.MSBuild.Tools.runtime.win-x64": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.7.1",
|
||||||
|
"contentHash": "tS4FAjGeZ0Gvaabb6Jy74Haw20kZu9w8AP9P+h27aYJm9udKqc+XFHRlifPOnXazVbbPOW1PkUtrk4TEsLYeRw=="
|
||||||
|
},
|
||||||
|
"LuckPerms.Torch.Utils": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.0.0",
|
||||||
|
"contentHash": "lEapa9SvIZDOaD4/vJ05Ire5Ixl3lSLhg6LlEvArVoC1rBGGriNV/9h5rFwS+fVpJOvkUWvwuX6HPO7rfspDgA==",
|
||||||
|
"dependencies": {
|
||||||
|
"IKVM": "8.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Bcl.AsyncInterfaces": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "6.0.0",
|
||||||
|
"contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.Configuration": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Primitives": "8.0.0",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.FileProviders.Abstractions": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.FileProviders.Physical": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.FileSystemGlobbing": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.FileSystemGlobbing": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ=="
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.Primitives": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Memory": "4.5.5",
|
||||||
|
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.NETFramework.ReferenceAssemblies.net48": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.0.3",
|
||||||
|
"contentHash": "zMk4D+9zyiEWByyQ7oPImPN/Jhpj166Ky0Nlla4eXlNL8hI/BtSJsgR8Inldd4NNpIAH3oh8yym0W2DrhXdSLQ=="
|
||||||
|
},
|
||||||
|
"Mono.Posix": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "7.1.0-final.1.21458.1",
|
||||||
|
"contentHash": "xhil/0zRkA2MrkyMZXC3dPSDWOhq6YD0vYGl1VnBbjsEZfLQCu7+mJZ/ftnOd0r4qmeHVeNuW6Pt33NoxO671A==",
|
||||||
|
"dependencies": {
|
||||||
|
"Mono.Unix": "7.1.0-final.1.21458.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Mono.Unix": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "7.1.0-final.1.21458.1",
|
||||||
|
"contentHash": "Rhxz4A7By8Q0wEgDqR+mioDsYXGrcYMYPiWE9bSaUKMpG8yAGArhetEQV5Ms6KhKCLdQTlPYLBKPZYoKbAvT/g=="
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "12.0.2",
|
||||||
|
"contentHash": "rTK0s2EKlfHsQsH6Yx2smvcTCeyoDNgCW7FEYyV01drPlh2T243PR2DiDXqtC5N4GDm4Ma/lkxfW5a/4793vbA=="
|
||||||
|
},
|
||||||
|
"NLog": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.4.12",
|
||||||
|
"contentHash": "fODew3BFT2XhAuqhGo2ZYT9OJE0ciGEBfvKXOmAAvaDsP/3ROIf083p8QUnmwKKw4jCkVW06ObX6gn/eFi2Skg=="
|
||||||
|
},
|
||||||
|
"protobuf-net": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.0.0",
|
||||||
|
"contentHash": "kTGOK0E87473sOImOjgZOnz3kTC2aMLffoRWQLYNuBLJnwNNmjanF9IkevZ9Q7yYLeABQfcF3BpeepuMntMVNw=="
|
||||||
|
},
|
||||||
|
"SpaceEngineersDedicated.ReferenceAssemblies": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.203.505",
|
||||||
|
"contentHash": "Wq4GIn2ilHyFdLdVKdVhC7iGQ+1FdVsChKY6hyQluFYSSV7oe8bDc9aTZC8XgxNMKCZoQBSVyaYHxQD+74BySQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"protobuf-net": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Buffers": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.5.1",
|
||||||
|
"contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
|
||||||
|
},
|
||||||
|
"System.IO.Pipelines": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "6.0.3",
|
||||||
|
"contentHash": "ryTgF+iFkpGZY1vRQhfCzX0xTdlV3pyaTTqRu2ETbEv+HlV7O6y7hyQURnghNIXvctl5DuZ//Dpks6HdL/Txgw==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Buffers": "4.5.1",
|
||||||
|
"System.Memory": "4.5.4",
|
||||||
|
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Memory": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.5.5",
|
||||||
|
"contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Buffers": "4.5.1",
|
||||||
|
"System.Numerics.Vectors": "4.5.0",
|
||||||
|
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"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.Runtime.InteropServices.RuntimeInformation": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.3.0",
|
||||||
|
"contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw=="
|
||||||
|
},
|
||||||
|
"System.Text.Encodings.Web": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "6.0.0",
|
||||||
|
"contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Buffers": "4.5.1",
|
||||||
|
"System.Memory": "4.5.4",
|
||||||
|
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Text.Json": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "6.0.6",
|
||||||
|
"contentHash": "GZ+62pLOr544jwSvyXv5ezSfzlFBTjLuPhgOS2dnKuknAA8dPNUGXLKTHf9XdsudU9JpbtweXnE4oEiKEB2T1Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Bcl.AsyncInterfaces": "6.0.0",
|
||||||
|
"System.Buffers": "4.5.1",
|
||||||
|
"System.Memory": "4.5.4",
|
||||||
|
"System.Numerics.Vectors": "4.5.0",
|
||||||
|
"System.Runtime.CompilerServices.Unsafe": "6.0.0",
|
||||||
|
"System.Text.Encodings.Web": "6.0.0",
|
||||||
|
"System.Threading.Tasks.Extensions": "4.5.4",
|
||||||
|
"System.ValueTuple": "4.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.Threading.Tasks.Extensions": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.5.4",
|
||||||
|
"contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"System.ValueTuple": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.5.0",
|
||||||
|
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
|
||||||
|
},
|
||||||
|
"Torch.Loader": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.0.0",
|
||||||
|
"contentHash": "HkuAujKa9IqPPqoA1205teUPBxuNOC9z0xZJkrMlFT0htH02X0ieZ5qh4onwyV10qVKiRBCSLkc5tA8lp1l5ig=="
|
||||||
|
},
|
||||||
|
"YamlDotNet": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "12.1.0",
|
||||||
|
"contentHash": "iP6tzi3DJ16wyTtEClbG8W6epvc+MvKSBdNcpllzhal40C94WzjWxF2aszcoOSjbESsWXsLY+NoRewgfo8ah6Q=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -27,6 +27,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libs", "libs", "{862C7244-2
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "heh", "heh\heh.csproj", "{927CB303-E699-4716-A62E-232AE1125159}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "heh", "heh\heh.csproj", "{927CB303-E699-4716-A62E-232AE1125159}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Maintenance", "Maintenance\Maintenance.csproj", "{66F3BF72-D663-44E0-B54C-5193E39839B9}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuckPerms.Torch.Utils", "LuckPerms.Torch.Utils\LuckPerms.Torch.Utils.csproj", "{615FD610-A3E6-457F-B8B9-C9D1235A4B2C}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -65,6 +69,14 @@ Global
|
|||||||
{927CB303-E699-4716-A62E-232AE1125159}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{927CB303-E699-4716-A62E-232AE1125159}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{927CB303-E699-4716-A62E-232AE1125159}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{927CB303-E699-4716-A62E-232AE1125159}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{927CB303-E699-4716-A62E-232AE1125159}.Release|Any CPU.Build.0 = Release|Any CPU
|
{927CB303-E699-4716-A62E-232AE1125159}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{66F3BF72-D663-44E0-B54C-5193E39839B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{66F3BF72-D663-44E0-B54C-5193E39839B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{66F3BF72-D663-44E0-B54C-5193E39839B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{66F3BF72-D663-44E0-B54C-5193E39839B9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{615FD610-A3E6-457F-B8B9-C9D1235A4B2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{615FD610-A3E6-457F-B8B9-C9D1235A4B2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{615FD610-A3E6-457F-B8B9-C9D1235A4B2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{615FD610-A3E6-457F-B8B9-C9D1235A4B2C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{AD9B7D1E-386A-4EF2-B475-BCB770537035} = {06CD2354-307D-4A1C-B46B-1D9EB3AAE742}
|
{AD9B7D1E-386A-4EF2-B475-BCB770537035} = {06CD2354-307D-4A1C-B46B-1D9EB3AAE742}
|
||||||
@@ -75,5 +87,7 @@ Global
|
|||||||
{B1A35416-6CFB-4AE7-A2F2-818E8F7A8C13} = {557A4A51-B8ED-4CA0-866D-D18D219129F3}
|
{B1A35416-6CFB-4AE7-A2F2-818E8F7A8C13} = {557A4A51-B8ED-4CA0-866D-D18D219129F3}
|
||||||
{8F9D910F-FFE6-4010-921F-5872ACF638BB} = {557A4A51-B8ED-4CA0-866D-D18D219129F3}
|
{8F9D910F-FFE6-4010-921F-5872ACF638BB} = {557A4A51-B8ED-4CA0-866D-D18D219129F3}
|
||||||
{927CB303-E699-4716-A62E-232AE1125159} = {862C7244-258E-4BFD-B271-9AA2D3FBE916}
|
{927CB303-E699-4716-A62E-232AE1125159} = {862C7244-258E-4BFD-B271-9AA2D3FBE916}
|
||||||
|
{66F3BF72-D663-44E0-B54C-5193E39839B9} = {2C911BD8-8B11-460E-AB7E-16552949A6FC}
|
||||||
|
{615FD610-A3E6-457F-B8B9-C9D1235A4B2C} = {862C7244-258E-4BFD-B271-9AA2D3FBE916}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@@ -16,6 +16,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="PetaPoco.Compiled" Version="6.0.480" />
|
<PackageReference Include="PetaPoco.Compiled" Version="6.0.480" />
|
||||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
|
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.207-master" PrivateAssets="all" IncludeAssets="compile" />
|
<PackageReference Include="Torch.Server.ReferenceAssemblies" Version="1.3.1.260-master" PrivateAssets="all" IncludeAssets="compile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
Reference in New Issue
Block a user