add luckperms plugin

This commit is contained in:
zznty
2023-11-09 16:53:02 +07:00
parent b05113f971
commit ec5e20b922
98 changed files with 3230 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<LangVersion>12</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>false</DebugSymbols>
<DebugType>none</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Krafs.Publicizer" Version="2.2.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="PolySharp" Version="1.13.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="torch.server.referenceassemblies" Version="1.3.1.260-master" PrivateAssets="all" IncludeAssets="compile" />
</ItemGroup>
<ItemGroup>
<Publicize Include="Torch:Torch.TorchBase.RegisterAuxAssembly" />
<Publicize Include="Torch:Torch.Managers.PluginManager._plugins" />
<Publicize Include="Torch:Torch.TorchPluginBase.Manifest" />
<Publicize Include="Torch:Torch.TorchPluginBase.StoragePath" />
</ItemGroup>
<ItemGroup>
<Content Include="manifest.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LuckPerms.Torch\LuckPerms.Torch.csproj" ReferenceOutputAssembly="false" Private="false" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.IO.Compression" />
</ItemGroup>
<Target Name="BuildArchive" BeforeTargets="PreBuildEvent">
<PropertyGroup>
<PluginDir>..\LuckPerms.Torch\bin\$(Configuration)\$(TargetFramework)\win-x64\</PluginDir>
<PluginZipPath>$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework)\plugin.zip</PluginZipPath>
</PropertyGroup>
<ZipDirectory DestinationFile="$(PluginZipPath)" SourceDirectory="$(PluginDir)" Overwrite="true" />
<ItemGroup>
<EmbeddedResource Include="$(PluginZipPath)" LogicalName="plugin.zip" />
</ItemGroup>
</Target>
</Project>

View File

@@ -0,0 +1,72 @@
using System.IO.Compression;
using System.Reflection;
using System.Runtime.CompilerServices;
using NLog;
using Torch;
using Torch.API;
using Torch.API.Managers;
using Torch.API.Plugins;
using Torch.Managers;
namespace LuckPerms.Loader;
public class Plugin : TorchPluginBase
{
private static readonly ITorchPlugin MainPluginInstance;
private static readonly ILogger Log = LogManager.GetLogger("LuckPerms.Loader");
static Plugin()
{
#pragma warning disable CS0618 // Type or member is obsolete
var torch = (ITorchServer)TorchBase.Instance;
#pragma warning restore CS0618 // Type or member is obsolete
var dir = new DirectoryInfo(Path.Combine(torch.InstancePath, "cache", "luckperms.loader"));
if (dir.Exists)
dir.Delete(true);
Log.Info($"Extracting cache to {dir}");
using (var pluginStream = typeof(Plugin).Assembly.GetManifestResourceStream("plugin.zip")!)
using (var archive = new ZipArchive(pluginStream, ZipArchiveMode.Read))
archive.ExtractToDirectory(dir.FullName);
Log.Info("Injecting LuckPerms");
AppDomain.CurrentDomain.AssemblyResolve += (_, args) =>
{
var fileName = args.Name[..args.Name.IndexOf(',')];
var path = Path.Combine(dir.FullName, fileName + ".dll");
return File.Exists(path) ? Assembly.LoadFile(path) : null;
};
var mainAssembly = Assembly.LoadFile(Path.Combine(dir.FullName, "LuckPerms.Torch.dll"));
var pluginType = mainAssembly.GetType("LuckPerms.Torch.Plugin", true)!;
// a hacky way to configure JVM
RuntimeHelpers.RunClassConstructor(pluginType.TypeHandle);
TorchBase.RegisterAuxAssembly(mainAssembly);
MainPluginInstance = (ITorchPlugin)Activator.CreateInstance(pluginType)!;
if (MainPluginInstance is not TorchPluginBase pluginBase) return;
pluginBase.Manifest = PluginManifest.Load(Path.Combine(dir.FullName, "manifest.xml"));
pluginBase.StoragePath = torch.InstancePath;
}
public override void Init(ITorchBase torch)
{
var pluginManager = torch.Managers.GetManager<PluginManager>();
pluginManager._plugins.Remove(Manifest.Guid);
pluginManager._plugins.Add(Manifest.Guid, MainPluginInstance);
MainPluginInstance.Init(torch);
Log.Info("Injected successfully");
}
}

View 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>LuckPerms.Loader</Name>
<Guid>7E4B3CC8-64FA-416E-8910-AACDF2DA5E2C</Guid>
<Version>v5.4.106</Version>
</PluginManifest>

View File

@@ -0,0 +1,67 @@
{
"version": 1,
"dependencies": {
".NETFramework,Version=v4.8": {
"Krafs.Publicizer": {
"type": "Direct",
"requested": "[2.2.1, )",
"resolved": "2.2.1",
"contentHash": "QGI4nMGQbKsuFUUboixVHu4mv3lHB5RejIa7toIlzTmwLkuCYYEpUBJjmy3OpXYyj5dVSZAXVbr4oeMSloE67Q=="
},
"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.13.2, )",
"resolved": "1.13.2",
"contentHash": "XwNhfkr7IeUiH8AE4pzob8YioxfL6nxgAx+fHEeWCObY/NZuBMfWLh39FznXbneKvagiqeeI7quIvZ6P1eVaEA=="
},
"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"
}
},
"Microsoft.NETFramework.ReferenceAssemblies.net48": {
"type": "Transitive",
"resolved": "1.0.3",
"contentHash": "zMk4D+9zyiEWByyQ7oPImPN/Jhpj166Ky0Nlla4eXlNL8hI/BtSJsgR8Inldd4NNpIAH3oh8yym0W2DrhXdSLQ=="
},
"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"
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
using System.Linq;
using Torch.Commands;
namespace LuckPerms.Torch.Extensions;
public static class CommandExtensions
{
public static string GetPermissionString(this Command command)
{
return $"minecraft.command.{string.Join(".", command.Path.Select(b => b.ToLowerInvariant()))}";
}
}

View File

@@ -0,0 +1,19 @@
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();
}
}

View File

@@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Linq;
using java.util;
namespace LuckPerms.Torch.Extensions;
public static class EnumerableExtensions
{
public static Collection ToCollection<T>(this IEnumerable<T> enumerable)
{
var collection = enumerable is IReadOnlyCollection<T> readOnlyCollection ? new ArrayList(readOnlyCollection.Count) : new ArrayList(((IReadOnlyCollection<T>)(enumerable = enumerable.ToArray())).Count);
foreach (var t in enumerable)
{
collection.add(t);
}
return collection;
}
}

View File

@@ -0,0 +1,53 @@
using System;
using System.Collections;
using System.Collections.Generic;
using java.util;
namespace LuckPerms.Torch.Extensions;
public static class IteratorExtensions
{
public static IteratorEnumerator<object> GetEnumerator(this Iterator iterator) => new(iterator);
public static IteratorEnumerable<T> AsEnumerable<T>(this Iterator iterator) => new(iterator);
public struct IteratorEnumerator<T>(Iterator iterator) : IEnumerator<T>
{
public bool MoveNext()
{
if (iterator.hasNext())
{
Current = iterator.next() is T ? (T)iterator.next() : default;
return true;
}
Current = default;
return false;
}
public void Reset()
{
throw new NotSupportedException();
}
object? IEnumerator.Current => Current;
public T? Current { get; private set; }
public void Dispose()
{
}
}
public struct IteratorEnumerable<T>(Iterator iterator) : IEnumerable<T>
{
public IteratorEnumerator<T> GetEnumerator() => new(iterator);
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => null!;
}
}

View File

@@ -0,0 +1,20 @@
using java.lang;
using me.lucko.luckperms.common.config.generic;
using me.lucko.luckperms.common.config.generic.key;
namespace LuckPerms.Torch.Extensions;
public static class KeyedConfigurationExtensions
{
public static bool GetBoolean(this KeyedConfiguration config, ConfigKey key, bool defaultValue = default)
{
var value = config.get(key);
return value switch
{
bool boolValue => boolValue,
Boolean booleanValue => booleanValue.booleanValue(),
_ => defaultValue
};
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.IO;
using java.io;
using Torch.Utils;
namespace LuckPerms.Torch.Extensions;
public 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);
}
}

View File

@@ -0,0 +1,10 @@
using java.util;
namespace LuckPerms.Torch.Extensions;
public static class UuidExtensions
{
public static ulong GetSteamId(this UUID uuid) => (ulong)uuid.getLeastSignificantBits();
public static UUID GetUuid(this ulong steamId) => new(0, (long)steamId);
}

View File

@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<PropertyChanged />
</Weavers>

View File

@@ -0,0 +1,15 @@
using me.lucko.luckperms.common.cacheddata.result;
using me.lucko.luckperms.common.calculator.processor;
using net.luckperms.api.util;
namespace LuckPerms.Torch.Impl.Calculator;
public class ConsoleProcessor : AbstractPermissionProcessor
{
private static readonly TristateResult TrueResult =
new TristateResult.Factory(typeof(ConsoleProcessor)).result(Tristate.TRUE);
public static readonly ConsoleProcessor Instance = new();
protected override TristateResult hasPermission(string str) => TrueResult;
}

View File

@@ -0,0 +1,34 @@
using java.lang;
using java.util;
using LuckPerms.Torch.Extensions;
using me.lucko.luckperms.common.cacheddata;
using me.lucko.luckperms.common.calculator;
using me.lucko.luckperms.common.calculator.processor;
using me.lucko.luckperms.common.config;
using net.luckperms.api.query;
namespace LuckPerms.Torch.Impl.Calculator;
public class LpCalculatorFactory(LpTorchPlugin plugin) : CalculatorFactory
{
public PermissionCalculator build(QueryOptions qo, CacheMetadata cm)
{
List processors = new ArrayList(5);
processors.add(new DirectProcessor());
if (plugin.getConfiguration().GetBoolean(ConfigKeys.APPLYING_REGEX))
processors.add(new RegexProcessor());
if (plugin.getConfiguration().GetBoolean(ConfigKeys.APPLYING_WILDCARDS))
processors.add(new WildcardProcessor());
if (plugin.getConfiguration().GetBoolean(ConfigKeys.APPLYING_WILDCARDS_SPONGE))
processors.add(new SpongeWildcardProcessor());
if (((Boolean)qo.option(LpContextManager.ConsoleOption).orElse(Boolean.FALSE)).booleanValue())
processors.add(ConsoleProcessor.Instance); // TODO add config option to disable bypassing checks for console
return new(plugin, cm, processors);
}
}

View File

@@ -0,0 +1,194 @@
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using ikvm.runtime;
using java.lang;
using java.lang.invoke;
using java.util.concurrent.atomic;
using me.lucko.luckperms.common.@event.gen;
using net.luckperms.api.@event;
using net.luckperms.api.@event.type;
using net.luckperms.api.@event.util;
using Torch.Managers.PatchManager;
using MethodType = java.lang.invoke.MethodType;
using Object = java.lang.Object;
using Void = java.lang.Void;
namespace LuckPerms.Torch.Impl.CompatPatches;
[PatchShim]
[HarmonyPatch(typeof(GeneratedEventClass), HarmonyLib.MethodType.Constructor, typeof(Class))]
public static class GeneratedEventClassPatch
{
private static readonly MethodInfo GetClassFromHandle =
typeof(Util).GetMethod(nameof(Util.getClassFromTypeHandle), new[] { typeof(RuntimeTypeHandle) })!;
private static readonly MethodInfo LookupMethod =
typeof(MethodHandles).GetMethod(nameof(MethodHandles.lookup), Array.Empty<Type>())!;
private static readonly ConstructorInfo AbstractEventCtor =
typeof(AbstractEvent).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly, null,
new[] { typeof(net.luckperms.api.LuckPerms) }, Array.Empty<ParameterModifier>())!;
// [ReflectedMethodInfo(typeof(GeneratedEventClassPatch), nameof(Prefix))]
// private static MethodInfo _prefixMethod = null!;
private static ModuleBuilder? _builder;
public static void Patch(PatchContext context)
{
// var target = typeof(GeneratedEventClass).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly,
// null,
// new[] { typeof(Class) }, Array.Empty<ParameterModifier>())!;
//
// context.GetPattern(target).Prefixes.Add(_prefixMethod);
new Harmony("GeneratedEventClassPatch").CreateClassProcessor(typeof(GeneratedEventClassPatch)).Patch();
}
public static bool Prefix(Class __0, ref MethodHandle ___constructor, ref MethodHandle[] ___setters)
{
var eventClassSuffix = __0.getName()[((Class)typeof(LuckPermsEvent)).getPackage().getName().Length..];
var packageWithName = ((Class)typeof(GeneratedEventClass)).getName();
var generatedClassName = packageWithName[..packageWithName.LastIndexOf('.')] + eventClassSuffix;
const string name = "LuckPerms.GeneratedEventClasses";
_builder ??= AssemblyBuilder.DefineDynamicAssembly(new(name), AssemblyBuilderAccess.Run).DefineDynamicModule(name);
// create a subclass of AbstractEvent
// using the predetermined generated class name
var typeBuilder = _builder.DefineType(generatedClassName, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, typeof(AbstractEvent));
var eventInterfaceType = Util.getRuntimeTypeFromClass(__0);
// implement the event interface
typeBuilder.AddInterfaceImplementation(eventInterfaceType);
var methods = eventInterfaceType
.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
.Where(b => b.HasAttribute<ParamAttribute>())
.OrderBy(b => ((Param)b.GetCustomAttribute<ParamAttribute>()!).value())
.ToArray();
// implement all methods annotated with Param by simply returning the value from the corresponding field with the same name
foreach (var methodInfo in methods)
{
var valueField = typeBuilder.DefineField(methodInfo.Name, methodInfo.ReturnType, FieldAttributes.Private);
var methodBuilder = typeBuilder.DefineMethod(methodInfo.Name,
MethodAttributes.Public | MethodAttributes.Virtual, methodInfo.ReturnType,
methodInfo.GetParameters().Select(p => p.ParameterType).ToArray());
var ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, valueField);
ilGenerator.Emit(OpCodes.Ret);
}
// implement non param methods to their default impl
FieldBuilder? cancellationStateField = null;
foreach (var methodInfo in eventInterfaceType.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Concat(eventInterfaceType.GetInterfaces()
.SelectMany(b => b.GetMethods(BindingFlags.Public | BindingFlags.Instance))).Except(methods))
{
var methodBuilder = typeBuilder.DefineMethod(methodInfo.Name,
MethodAttributes.Public | MethodAttributes.Virtual, methodInfo.ReturnType,
methodInfo.GetParameters().Select(p => p.ParameterType).ToArray());
var ilGenerator = methodBuilder.GetILGenerator();
if (methodInfo.DeclaringType == typeof(Cancellable) && methodInfo.Name == "cancellationState")
{
cancellationStateField = typeBuilder.DefineField("cancellationState", typeof(AtomicBoolean), FieldAttributes.Private);
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldfld, cancellationStateField);
ilGenerator.Emit(OpCodes.Ret);
continue;
}
var defaultMethodsType = methodInfo.DeclaringType!.GetNestedType("__DefaultMethods", BindingFlags.NonPublic | BindingFlags.Static);
var defaultMethod = defaultMethodsType?.GetMethod(methodInfo.Name,
methodInfo.GetParameters().Select(p => p.ParameterType).ToArray());
if (defaultMethodsType is null || defaultMethod is null)
{
if (methodInfo.ReturnType != typeof(void))
ilGenerator.Emit(OpCodes.Ldnull);
ilGenerator.Emit(OpCodes.Ret);
continue;
}
for (var i = 0; i < methodInfo.GetParameters().Length; i++)
{
ilGenerator.Emit(OpCodes.Ldarg, i + 1);
}
ilGenerator.Emit(OpCodes.Call, defaultMethod);
ilGenerator.Emit(OpCodes.Ret);
}
// implement LuckPermsEvent#getEventType by returning the event class type
var getEventTypeBuilder = typeBuilder.DefineMethod("getEventType", MethodAttributes.Public | MethodAttributes.Virtual, typeof(Class), null);
var getEventTypeIlGenerator = getEventTypeBuilder.GetILGenerator();
getEventTypeIlGenerator.Emit(OpCodes.Ldtoken, eventInterfaceType);
getEventTypeIlGenerator.Emit(OpCodes.Call, GetClassFromHandle);
getEventTypeIlGenerator.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(getEventTypeBuilder, typeof(AbstractEvent).GetMethod(nameof(AbstractEvent.getEventType))!);
// implement AbstractEvent#mh by calling & returning the value of MethodHandles.lookup()
var mhlBuilder = typeBuilder.DefineMethod("mhl", MethodAttributes.Public | MethodAttributes.Virtual,
typeof(MethodHandles.Lookup), null);
mhlBuilder.SetImplementationFlags(MethodImplAttributes.NoInlining);
var mhlIlGenerator = mhlBuilder.GetILGenerator();
mhlIlGenerator.Emit(OpCodes.Call, LookupMethod);
mhlIlGenerator.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(mhlBuilder, typeof(AbstractEvent).GetMethod(nameof(AbstractEvent.mhl))!);
// define constructor
var constructorBuilder = typeBuilder.DefineConstructor(
MethodAttributes.Public, CallingConventions.HasThis,
new[] { typeof(net.luckperms.api.LuckPerms) });
var constructorIlGenerator = constructorBuilder.GetILGenerator();
constructorIlGenerator.Emit(OpCodes.Ldarg_0);
constructorIlGenerator.Emit(OpCodes.Ldarg_1);
constructorIlGenerator.Emit(OpCodes.Call, AbstractEventCtor);
if (cancellationStateField is not null)
{
constructorIlGenerator.Emit(OpCodes.Ldarg_0);
constructorIlGenerator.Emit(OpCodes.Ldc_I4_0);
constructorIlGenerator.Emit(OpCodes.Newobj, typeof(AtomicBoolean).GetConstructors()[0]);
constructorIlGenerator.Emit(OpCodes.Stfld, cancellationStateField);
}
constructorIlGenerator.Emit(OpCodes.Ret);
var type = typeBuilder.CreateType();
var lookup = ((AbstractEvent)type.GetConstructor(new[] { typeof(net.luckperms.api.LuckPerms) })!
.Invoke(new object?[] { null })).mhl();
___constructor =
lookup.findConstructor(type, MethodType.methodType(Void.TYPE, typeof(net.luckperms.api.LuckPerms)))
.asType(MethodType.methodType(typeof(AbstractEvent), typeof(net.luckperms.api.LuckPerms)));
___setters = methods.Select(b =>
lookup.findSetter(type, b.Name, b.ReturnType)
.asType(MethodType.methodType(Void.TYPE,
new Class[] { typeof(AbstractEvent), typeof(Object) })))
.ToArray();
return false;
}
}

View File

@@ -0,0 +1,25 @@
using System.Reflection;
using me.lucko.luckperms.common.api;
using Torch.Managers.PatchManager;
using Torch.Utils;
namespace LuckPerms.Torch.Impl.CompatPatches;
[PatchShim]
public static class LoaderCheckPatch
{
// TODO sort this out when i get to plugin api stuff
[ReflectedMethodInfo(typeof(LuckPermsApiProvider), nameof(LuckPermsApiProvider.ensureApiWasLoadedByPlugin))]
private static MethodInfo TargetMethod = null!;
[ReflectedMethodInfo(typeof(LoaderCheckPatch), nameof(Prefix))]
private static MethodInfo PrefixMethod = null!;
public static void Patch(PatchContext context)
{
context.GetPattern(TargetMethod).Prefixes.Add(PrefixMethod);
}
private static bool Prefix() => false;
}

View File

@@ -0,0 +1,48 @@
using LuckPerms.Torch.Extensions;
using LuckPerms.Torch.PlatformApi;
using me.lucko.luckperms.common.plugin;
using me.lucko.luckperms.common.plugin.util;
using Torch.API;
using Torch.API.Managers;
using Torch.Managers;
using Torch.Server.Managers;
namespace LuckPerms.Torch.Impl.Listeners;
public class LpConnectionListener(LuckPermsPlugin plugin) : AbstractConnectionListener(plugin), IManager
{
[Manager.Dependency]
private MultiplayerManagerDedicated _multiplayerManager = null!;
public void Attach()
{
_multiplayerManager.PlayerJoined += MultiplayerManagerOnPlayerJoined;
_multiplayerManager.PlayerLeft += MultiplayerManagerOnPlayerLeft;
}
private void MultiplayerManagerOnPlayerLeft(IPlayer player)
{
handleDisconnect(player.SteamId.GetUuid());
}
private void MultiplayerManagerOnPlayerJoined(IPlayer player)
{
plugin.getBootstrap().getScheduler().async().execute(() => OnPlayerJoined(player));
}
private void OnPlayerJoined(IPlayer player)
{
var uuid = player.SteamId.GetUuid();
var user = loadUser(uuid, player.Name);
recordConnection(uuid);
plugin.getEventDispatcher().dispatchPlayerLoginProcess(uuid, player.Name, user); // TODO move that to validate phase? but need to get username from steam somehow
((LpPlayerModel)player).InitializePermissions(user);
plugin.getContextManager().signalContextUpdate(player);
}
public void Detach()
{
}
}

View File

@@ -0,0 +1,22 @@
using System.Reflection;
using java.nio.file;
using me.lucko.luckperms.common.plugin.classpath;
namespace LuckPerms.Torch.Impl;
public class LpClassPathAppender : ClassPathAppender
{
public void Dispose()
{
}
public void addJarToClasspath(Path p)
{
if (p.endsWith(".dll"))
Assembly.Load(p.toString());
}
public void close()
{
}
}

View File

@@ -0,0 +1,43 @@
using me.lucko.luckperms.common.command.utils;
using me.lucko.luckperms.common.plugin;
using me.lucko.luckperms.common.sender;
using Torch.API.Managers;
using Torch.Commands;
using Torch.Managers;
using Torch.Server.Managers;
using VRage.Game.ModAPI;
namespace LuckPerms.Torch.Impl;
public class LpCommandManager(LuckPermsPlugin plugin, LpSenderFactory senderFactory) : me.lucko.luckperms.common.command.CommandManager(plugin), IManager
{
private static readonly string[] Aliases = { "luckperms", "lp", "perm", "perms", "permission", "permissions" };
[Manager.Dependency]
private CommandManager _commandManager = null!;
[Manager.Dependency]
private MultiplayerManagerDedicated _multiplayerManager = null!;
public void Attach()
{
foreach (var alias in Aliases)
{
_commandManager.Commands.AddCommand(new(alias, "LuckPerms commands", (ctx, _) => Execute(alias, ctx),
((LpTorchBootstrap)plugin.getBootstrap()).GetTorchPlugin(), MyPromoteLevel.None));
}
}
private void Execute(string prefix, CommandContext context)
{
executeCommand(
senderFactory.Wrap(context.SentBySelf
? context.Torch
: _multiplayerManager.Players[context.Player.SteamUserId], context), prefix,
ArgumentTokenizer.EXECUTE.tokenizeInput(context.RawArgs));
}
public void Detach()
{
}
}

View File

@@ -0,0 +1,15 @@
using java.nio.file;
using me.lucko.luckperms.common.config.generic.adapter;
using me.lucko.luckperms.common.plugin;
using ninja.leaping.configurate.loader;
using ninja.leaping.configurate.yaml;
namespace LuckPerms.Torch.Impl;
public class LpConfigurationAdapter(LuckPermsPlugin plugin, Path path) : ConfigurateConfigAdapter(plugin, path)
{
protected override ConfigurationLoader createLoader(Path p)
{
return YAMLConfigurationLoader.builder().setPath(p).build();
}
}

View File

@@ -0,0 +1,72 @@
using System;
using java.util;
using LuckPerms.Torch.Extensions;
using LuckPerms.Torch.PlatformApi;
using me.lucko.luckperms.common.config;
using me.lucko.luckperms.common.context.manager;
using me.lucko.luckperms.common.plugin;
using net.luckperms.api.context;
using net.luckperms.api.query;
using Torch.API;
using Torch.API.Managers;
using Torch.Managers;
using Torch.Server.Managers;
using VRage.Game.ModAPI;
using Boolean = java.lang.Boolean;
using ContextManager = me.lucko.luckperms.common.context.manager.ContextManager;
using String = java.lang.String;
namespace LuckPerms.Torch.Impl;
public class LpContextManager(LuckPermsPlugin plugin) : ContextManager(plugin, typeof(IPlayer), typeof(IPlayer)), IManager
{
public static readonly OptionKey PromotionOption = OptionKey.of("keen.promotion", typeof(String));
public static readonly OptionKey ConsoleOption = OptionKey.of("console", typeof(Boolean));
[Manager.Dependency]
private MultiplayerManagerDedicated _multiplayerManager = null!;
public QueryOptionsCache CreateQueryOptionsCache(LpPlayerModel player) => new(player, this);
public override QueryOptionsSupplier getCacheFor(object obj)
{
return ((LpPlayerModel)obj).QueryOptionsCache ??
throw new ArgumentException($"Trying to get query options for non registered player {obj}");
}
protected override void invalidateCache(object obj)
{
((QueryOptionsCache)getCacheFor(obj)).invalidate();
}
public override QueryOptions formQueryOptions(object obj, ImmutableContextSet mmutableContextSet)
{
var queryOptions = ((QueryOptions)plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS)).toBuilder();
var player = (IPlayer)obj;
queryOptions.option(PromotionOption,
_multiplayerManager.GetUserPromoteLevel(player.SteamId).ToString().ToLowerInvariant());
return queryOptions.context(mmutableContextSet).build();
}
public override UUID getUniqueId(object obj)
{
return ((IPlayer)obj).SteamId.GetUuid();
}
public void Attach()
{
_multiplayerManager.PlayerPromoted += MultiplayerManagerOnPlayerPromoted;
}
private void MultiplayerManagerOnPlayerPromoted(ulong steamId, MyPromoteLevel arg2)
{
signalContextUpdate(_multiplayerManager.Players[steamId]);
}
public void Detach()
{
}
}

View File

@@ -0,0 +1,29 @@
using ikvm.runtime;
using java.lang;
using java.util;
using me.lucko.luckperms.common.dependencies;
namespace LuckPerms.Torch.Impl;
public class LpDependencyManager : DependencyManager
{
public static readonly ClassLoader CurrentClassLoader = new AppDomainAssemblyClassLoader(typeof(LpDependencyManager).Assembly);
public void Dispose()
{
}
public void loadDependencies(Set s)
{
}
public ClassLoader obtainClassLoaderWith(Set s) => CurrentClassLoader;
public void loadStorageDependencies(Set s, bool b1, bool b2, bool b3)
{
}
public void close()
{
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Linq;
using me.lucko.luckperms.common.api;
using me.lucko.luckperms.common.@event;
using me.lucko.luckperms.common.plugin;
using Torch.API;
using Torch.API.Managers;
namespace LuckPerms.Torch.Impl;
public class LpEventBus(LuckPermsPlugin plugin, LuckPermsApiProvider apiProvider, ITorchBase torch)
: AbstractEventBus(plugin, apiProvider)
{
protected override object checkPlugin(object obj)
{
return torch.Managers.GetManager<IPluginManager>()
.FirstOrDefault(b => b.GetType().Assembly == obj.GetType().Assembly) ??
throw new InvalidOperationException("plugin not found");
}
}

View File

@@ -0,0 +1,19 @@
using java.lang;
using java.util.concurrent;
using me.lucko.luckperms.common.plugin.bootstrap;
using me.lucko.luckperms.common.plugin.scheduler;
using Torch.API;
namespace LuckPerms.Torch.Impl;
public class LpSchedulerAdapter(LuckPermsBootstrap bootstrap, ITorchBase torch) : AbstractJavaScheduler(bootstrap)
{
private readonly Executor _torchExecutor = new TorchExecutor(torch);
public override Executor sync() => _torchExecutor;
private class TorchExecutor(ITorchBase torch) : Executor
{
public void execute(Runnable command) => torch.Invoke(command.run);
}
}

View File

@@ -0,0 +1,113 @@
using java.util;
using LuckPerms.Torch.Extensions;
using me.lucko.luckperms.common.locale;
using me.lucko.luckperms.common.plugin;
using me.lucko.luckperms.common.sender;
using net.kyori.adventure.text;
using net.kyori.adventure.text.serializer.plain;
using net.luckperms.api.util;
using Torch.API;
using Torch.API.Managers;
using Torch.Commands;
using Torch.Managers;
using Torch.Managers.ChatManager;
using VRage.Game;
namespace LuckPerms.Torch.Impl;
public class LpSenderFactory(LuckPermsPlugin plugin) : SenderFactory(plugin), IManager
{
[Manager.Dependency]
private ChatManagerServer? _chatManager = null;
[Manager.Dependency]
private CommandManager? _commandManager = null;
public Sender Wrap(object obj, CommandContext context) => wrap(new SenderWrapper(obj, context));
protected override UUID getUniqueId(object obj)
{
if (obj is IPlayer player)
return player.SteamId.GetUuid();
return Sender.CONSOLE_UUID;
}
protected override string getName(object obj)
{
if (obj is IPlayer player)
return player.Name;
return Sender.CONSOLE_NAME;
}
protected override void sendMessage(object obj, Component c)
{
if (_chatManager is null)
return;
c = TranslationManager.render(c, Locale.ENGLISH); // TODO make use of client side lang
var plainText = PlainTextComponentSerializer.plainText().serialize(c);
switch (obj)
{
case IPlayer player:
_chatManager.SendMessageAsOther("LuckPerms", plainText, targetSteamId: player.SteamId);
break;
case SenderWrapper wrapper:
wrapper.Context.Respond(plainText, "LuckPerms");
break;
default:
_chatManager.DisplayMessageOnSelf("LuckPerms", plainText, MyFontEnum.White);
break;
}
}
protected override Tristate getPermissionValue(object obj, string str)
{
if (obj is not IPlayer)
return Tristate.UNDEFINED;
return Tristate.UNDEFINED; // idk what to do here cuz torch/se doesnt have any decent permissions at all
}
protected override bool hasPermission(object obj, string str) => getPermissionValue(obj, str).asBoolean();
protected override void performCommand(object obj, string str)
{
if (_commandManager is null)
return;
if (obj is IPlayer player)
{
var consumed = false;
_commandManager.HandleCommand(str, player.SteamId, ref consumed);
}
else _commandManager.HandleCommandFromServer(str, _ => { });
}
protected override bool isConsole(object obj)
{
return obj switch
{
SenderWrapper wrapper => wrapper.IsConsole,
IPlayer => false,
ITorchBase => true,
_ => false
};
}
public void Attach()
{
}
public void Detach()
{
}
private sealed record SenderWrapper(object Obj, CommandContext Context)
{
public bool IsConsole => Obj is not IPlayer;
}
}

View File

@@ -0,0 +1,120 @@
using System;
using System.Linq;
using java.io;
using java.lang;
using java.nio.file;
using java.time;
using java.util;
using java.util.concurrent;
using LuckPerms.Torch.Extensions;
using me.lucko.luckperms.common.plugin.bootstrap;
using me.lucko.luckperms.common.plugin.classpath;
using me.lucko.luckperms.common.plugin.logging;
using me.lucko.luckperms.common.plugin.scheduler;
using net.luckperms.api.platform;
using NLog;
using Sandbox.Game.Multiplayer;
using Torch.API;
using Torch.API.Managers;
using Torch.API.Plugins;
using Torch.Server.Managers;
namespace LuckPerms.Torch.Impl;
public class LpTorchBootstrap : LuckPermsBootstrap
{
private SchedulerAdapter? _schedulerAdapter;
private ClassPathAppender? _classPathAppender;
private readonly PluginLogger _pluginLogger;
public CountDownLatch LoadLatch { get; } = new(1);
public CountDownLatch EnableLatch { get; } = new(1);
private readonly ITorchServer _torch;
private readonly ITorchPlugin _torchPlugin;
private readonly string _configDir;
public LpTorchPlugin Plugin { get; }
public LpTorchBootstrap(ITorchServer torch, ITorchPlugin torchPlugin, ILogger logger, string configDir)
{
_pluginLogger = new NLogPluginLogger(logger);
_torch = torch;
_torchPlugin = torchPlugin;
_configDir = configDir;
Plugin = new(this, torch);
}
public ITorchPlugin GetTorchPlugin() => _torchPlugin;
public Path getDataDirectory() => Paths.get(_configDir, "data");
public string identifyClassLoader(ClassLoader classLoader) => classLoader.toString();
public Collection getPlayerList() => Sync.Players?.GetAllPlayers()
.Select(b => Sync.Players.TryGetPlayerIdentity(b)?.DisplayName).Where(b => b is not null).ToCollection() ?? Collections.EMPTY_LIST;
public Platform.Type getType() => Platform.Type.STANDALONE; // meh
public SchedulerAdapter getScheduler() => _schedulerAdapter ??= new LpSchedulerAdapter(this, _torch);
public Path getConfigDirectory() => Paths.get(_configDir);
public bool isPlayerOnline(UUID uuid) =>
_torch.CurrentSession?.Managers.GetManager<MultiplayerManagerDedicated>().Players
.ContainsKey(uuid.GetSteamId()) ?? false;
public string getVersion() => _torchPlugin.Version.TrimStart('v');
public string getServerBrand() => "Torch";
public string getServerVersion() => _torch.TorchVersion.ToString();
public int getPlayerCount() =>
_torch.CurrentSession?.Managers.GetManager<MultiplayerManagerDedicated>().Players.Count ?? 0;
public Instant getStartupTime() => Instant.ofEpochMilli((DateTimeOffset.Now - _torch.ElapsedPlayTime).ToUnixTimeMilliseconds());
public ClassPathAppender getClassPathAppender() => _classPathAppender ??= new LpClassPathAppender();
public InputStream? getResourceStream(string path)
{
var normalizedPath = path.Replace('/', '.');
using var dotnetStream = typeof(LpTorchBootstrap).Assembly.GetManifestResourceStream(normalizedPath);
return dotnetStream?.GetInputStream();
}
public PluginLogger getPluginLogger() => _pluginLogger;
public Optional lookupUniqueId(string str)
{
if (Sync.Players?.GetAllIdentities().FirstOrDefault(b => b.DisplayName == str)?.IdentityId is
{ } identityId && Sync.Players.TryGetSteamId(identityId) is { } steamId and > 0)
return Optional.of(steamId.GetUuid());
return Optional.empty();
}
public Optional lookupUsername(UUID uuid)
{
if (Sync.Players?.TryGetPlayerIdentity(uuid.GetSteamId())?.DisplayName is { } displayName)
return Optional.of(displayName);
return Optional.empty();
}
public Collection getOnlinePlayers()
{
return _torch.CurrentSession?.Managers.GetManager<MultiplayerManagerDedicated>().Players.Select(b => b.Key.GetUuid())
.ToCollection() ?? Collections.EMPTY_LIST;
}
public CountDownLatch getLoadLatch() => LoadLatch;
public CountDownLatch getEnableLatch() => EnableLatch;
public string getServerName() => _torch.Managers.GetManager<InstanceManager>().DedicatedConfig.ServerName;
public Optional getPlayer(UUID uuid) => _torch.CurrentSession?.Managers.GetManager<MultiplayerManagerDedicated>().Players.TryGetValue(uuid.GetSteamId(), out var player) ?? false
? Optional.of(player)
: Optional.empty();
}

View File

@@ -0,0 +1,137 @@
using System;
using System.Linq;
using java.util;
using java.util.stream;
using LuckPerms.Torch.Extensions;
using LuckPerms.Torch.Impl.Calculator;
using LuckPerms.Torch.Impl.Listeners;
using LuckPerms.Torch.Impl.Messaging;
using LuckPerms.Torch.PlatformHooks;
using me.lucko.luckperms.common.api;
using me.lucko.luckperms.common.calculator;
using me.lucko.luckperms.common.command;
using me.lucko.luckperms.common.config.generic.adapter;
using me.lucko.luckperms.common.context.manager;
using me.lucko.luckperms.common.dependencies;
using me.lucko.luckperms.common.@event;
using me.lucko.luckperms.common.messaging;
using me.lucko.luckperms.common.model;
using me.lucko.luckperms.common.model.manager.group;
using me.lucko.luckperms.common.model.manager.track;
using me.lucko.luckperms.common.model.manager.user;
using me.lucko.luckperms.common.plugin;
using me.lucko.luckperms.common.plugin.bootstrap;
using me.lucko.luckperms.common.plugin.util;
using me.lucko.luckperms.common.sender;
using Torch.API;
using Torch.API.Managers;
using Torch.API.Session;
using Torch.Managers.PatchManager;
using Torch.Server.Managers;
namespace LuckPerms.Torch.Impl;
public class LpTorchPlugin(LuckPermsBootstrap bootstrap, ITorchBase torch) : AbstractLuckPermsPlugin
{
private StandardUserManager? _userManager;
private StandardGroupManager? _groupManager;
private StandardTrackManager? _trackManager;
private LpCommandManager? _commandManager;
private LpContextManager? _contextManager;
private LpSenderFactory? _senderFactory;
private LpConnectionListener? _connectionListener;
public override LuckPermsBootstrap getBootstrap() => bootstrap;
protected override void setupSenderFactory()
{
_senderFactory = new LpSenderFactory(this);
torch.Managers.GetManager<ITorchSessionManager>().AddFactory(_ => _senderFactory);
}
public override Sender getConsoleSender() => _senderFactory?.wrap(torch) ?? throw new InvalidOperationException("call setupSenderFactory first");
protected override ConfigurationAdapter provideConfigurationAdapter() => new LpConfigurationAdapter(this, resolveConfig("config.yml"));
protected override void registerPlatformListeners()
{
}
protected override MessagingFactory provideMessagingFactory() => new LpMessagingFactory(this);
protected override void registerCommands()
{
_commandManager = new LpCommandManager(this, _senderFactory!);
torch.Managers.GetManager<ITorchSessionManager>().AddFactory(_ => _commandManager);
}
protected override void setupManagers()
{
_userManager = new(this);
_groupManager = new(this);
_trackManager = new(this);
_connectionListener = new(this);
torch.Managers.GetManager<ITorchSessionManager>().AddFactory(_ => _connectionListener);
}
protected override CalculatorFactory provideCalculatorFactory() => new LpCalculatorFactory(this);
protected override void setupContextManager()
{
_contextManager = new LpContextManager(this);
torch.Managers.GetManager<ITorchSessionManager>().AddFactory(_ => _contextManager);
}
public override GroupManager getGroupManager() => _groupManager ?? throw new InvalidOperationException("call setupManagers first");
public override TrackManager getTrackManager() => _trackManager ?? throw new InvalidOperationException("call setupManagers first");
public override CommandManager getCommandManager() => _commandManager ?? throw new InvalidOperationException("call registerCommands first");
public override AbstractConnectionListener getConnectionListener() => _connectionListener ?? throw new InvalidOperationException("call setupManagers first");
public override Optional getQueryOptionsForUser(User value)
{
var player = bootstrap.getPlayer(value.getUniqueId());
if (!player.isPresent())
return Optional.empty();
var options = _contextManager?.getQueryOptions(player.get());
return options is null ? Optional.empty() : Optional.of(options);
}
public override Stream getOnlineSenders() =>
Stream.concat(
Stream.of(getConsoleSender()),
torch.CurrentSession?.Managers.GetManager<MultiplayerManagerDedicated>().Players.Values
.Select(_senderFactory!.wrap).ToCollection().stream() ?? Stream.empty()
);
public override ContextManager getContextManager() => _contextManager ?? throw new InvalidOperationException("call setupContextManager first");
public override UserManager getUserManager() => _userManager ?? throw new InvalidOperationException("call setupManagers first");
protected override void setupPlatformHooks()
{
var patchManager = torch.Managers.GetManager<PatchManager>();
var context = patchManager.AcquireContext();
PlayerPatch.Patch(context);
CommandPermissionsPatch.Patch(context);
CommandPrefixPatch.Patch(context);
patchManager.Commit();
}
protected override AbstractEventBus provideEventBus(LuckPermsApiProvider luckPermsApiProvider) => new LpEventBus(this, luckPermsApiProvider, torch);
protected override void registerApiOnPlatform(net.luckperms.api.LuckPerms luckPerms)
{
}
protected override void performFinalSetup()
{
}
protected override DependencyManager createDependencyManager() => new LpDependencyManager();
}

View File

@@ -0,0 +1,12 @@
using me.lucko.luckperms.common.messaging;
using me.lucko.luckperms.common.plugin;
namespace LuckPerms.Torch.Impl.Messaging;
public class LpMessagingFactory(LuckPermsPlugin plugin) : MessagingFactory(plugin)
{
protected override InternalMessagingService getServiceFor(string messagingType)
{
return base.getServiceFor(messagingType); // TODO add nexus messaging
}
}

View File

@@ -0,0 +1,18 @@
using System;
using me.lucko.luckperms.common.plugin.logging;
using NLog;
namespace LuckPerms.Torch.Impl;
public class NLogPluginLogger(ILogger logger) : PluginLogger
{
public void warn(string str) => logger.Warn(str);
public void warn(string str, Exception t) => logger.Warn(t, str);
public void info(string str) => logger.Info(str);
public void severe(string str) => logger.Error(str);
public void severe(string str, Exception t) => logger.Error(t, str);
}

View File

@@ -0,0 +1,258 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net48</TargetFramework>
<LangVersion>12</LangVersion>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>false</DebugSymbols>
<DebugType>none</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IKVM" Version="8.7.1" />
<PackageReference Include="Lib.Harmony" Version="2.3.0-prerelease.2" />
<PackageReference Include="PolySharp" Version="1.13.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="torch.server.referenceassemblies" Version="1.3.1.260-master" PrivateAssets="all" IncludeAssets="compile" />
</ItemGroup>
<PropertyGroup>
<LibsPath>$(ProjectDir)libs\</LibsPath>
<ApiJarPath>$(LibsPath)api-5.4.jar</ApiJarPath>
<CommonJarPath>$(LibsPath)common-5.4-SNAPSHOT.jar</CommonJarPath>
<TypesafeConfigPath>$(LibsPath)config-1.4.0.jar</TypesafeConfigPath>
<Toml4jPath>$(LibsPath)toml4j-0.7.2.jar</Toml4jPath>
<ConfigurateTomlPath>$(LibsPath)configurate-toml-3.7.jar</ConfigurateTomlPath>
<ConfigurateGsonPath>$(LibsPath)configurate-gson-3.7.2.jar</ConfigurateGsonPath>
<ConfigurateHoconPath>$(LibsPath)configurate-hocon-3.7.2.jar</ConfigurateHoconPath>
<ConfigurateCorePath>$(LibsPath)configurate-core-3.7.2.jar</ConfigurateCorePath>
<ConfigurateYamlPath>$(LibsPath)configurate-yaml-3.7.2.jar</ConfigurateYamlPath>
<SnakeYamlPath>$(LibsPath)snakeyaml-1.26.jar</SnakeYamlPath>
<CheckerQualPath>$(LibsPath)checker-qual-3.12.0.jar</CheckerQualPath>
<AdventureTextPlainPath>$(LibsPath)adventure-text-serializer-plain-4.11.0.jar</AdventureTextPlainPath>
<AdventureTextLegacyPath>$(LibsPath)adventure-text-serializer-legacy-4.11.0.jar</AdventureTextLegacyPath>
<AdventureTextMinimessagePath>$(LibsPath)adventure-text-minimessage-4.11.0.jar</AdventureTextMinimessagePath>
<AdventureApiPath>$(LibsPath)adventure-api-4.11.0.jar</AdventureApiPath>
<AdventureKeyPath>$(LibsPath)adventure-key-4.11.0.jar</AdventureKeyPath>
<ExaminationApiPath>$(LibsPath)examination-api-1.3.0.jar</ExaminationApiPath>
<ExaminationStringPath>$(LibsPath)examination-string-1.3.0.jar</ExaminationStringPath>
<AnnotationsPath>$(LibsPath)annotations-23.0.0.jar</AnnotationsPath>
<GuavaPath>$(LibsPath)guava-19.0.jar</GuavaPath>
<ErrorProneAnnotationsPath>$(LibsPath)error_prone_annotations-2.0.2.jar</ErrorProneAnnotationsPath>
<AnimalSnifferAnnotationsPath>$(LibsPath)animal-sniffer-annotations-1.14.jar</AnimalSnifferAnnotationsPath>
<J2objcAnnotationsPath>$(LibsPath)j2objc-annotations-0.1.jar</J2objcAnnotationsPath>
<Jsr305Path>$(LibsPath)jsr305-1.3.9.jar</Jsr305Path>
<GsonPath>$(LibsPath)gson-2.7.jar</GsonPath>
<BrigadierPath>$(LibsPath)brigadier-1.0.18.jar</BrigadierPath>
<EventApiPath>$(LibsPath)event-api-3.0.0.jar</EventApiPath>
<Slf4jApiPath>$(LibsPath)slf4j-api-1.7.30.jar</Slf4jApiPath>
<Log4jApiPath>$(LibsPath)log4j-api-2.14.0.jar</Log4jApiPath>
<CaffeinePath>$(LibsPath)caffeine-2.9.0.jar</CaffeinePath>
<OkioPath>$(LibsPath)okio-1.17.5.jar</OkioPath>
<OkHttpPath>$(LibsPath)okhttp-3.14.9.jar</OkHttpPath>
<ConscryptPath>$(LibsPath)conscrypt-openjdk-uber-2.0.0.jar</ConscryptPath>
<ByteBuddyPath>$(LibsPath)byte-buddy-1.10.22.jar</ByteBuddyPath>
<EddsaPath>$(LibsPath)eddsa-0.3.0.jar</EddsaPath>
<JnatsPath>$(LibsPath)jnats-2.16.4.jar</JnatsPath>
<HikariCPPath>$(LibsPath)HikariCP-4.0.3.jar</HikariCPPath>
<JsonPath>$(LibsPath)json-20230227.jar</JsonPath>
<CommonsPoolPath>$(LibsPath)pool2-2.11.1.jar</CommonsPoolPath>
<JedisPath>$(LibsPath)jedis-4.4.3.jar</JedisPath>
<AmqpClientPath>$(LibsPath)amqp-client-5.12.0.jar</AmqpClientPath>
<BsonPath>$(LibsPath)bson-4.5.0.jar</BsonPath>
<MongoDriverCorePath>$(LibsPath)mongodb-driver-core-4.5.0.jar</MongoDriverCorePath>
<MongoDriverSyncPath>$(LibsPath)mongodb-driver-sync-4.5.0.jar</MongoDriverSyncPath>
<MongoDriverLegacyPath>$(LibsPath)mongodb-driver-legacy-4.5.0.jar</MongoDriverLegacyPath>
<PostgreSqlPath>$(LibsPath)postgresql-42.6.0.jar</PostgreSqlPath>
<H2Path>$(LibsPath)h2-2.1.214.jar</H2Path>
<MariaDbPath>$(LibsPath)mariadb-java-client-3.3.0.jar</MariaDbPath>
<WaffleJnaPath>$(LibsPath)waffle-jna-3.3.0.jar</WaffleJnaPath>
<JclOverSlf4jPath>$(LibsPath)jcl-over-slf4j-2.0.7.jar</JclOverSlf4jPath>
<JnaPlatformPath>$(LibsPath)jna-platform-5.13.0.jar</JnaPlatformPath>
<JnaPath>$(LibsPath)jna-5.13.0.jar</JnaPath>
<MySqlPath>$(LibsPath)mysql-connector-j-8.0.33.jar</MySqlPath>
<ProtobufPath>$(LibsPath)protobuf-java-3.21.9.jar</ProtobufPath>
</PropertyGroup>
<ItemGroup>
<IkvmReference Include="$(MySqlPath)">
<References>$(ProtobufPath)</References>
</IkvmReference>
<IkvmReference Include="$(ProtobufPath)" />
<IkvmReference Include="$(MariaDbPath)">
<References>$(WaffleJnaPath);$(Slf4jApiPath)</References>
</IkvmReference>
<IkvmReference Include="$(WaffleJnaPath)">
<References>$(Slf4jApiPath);$(JclOverSlf4jPath);$(CheckerQualPath);$(JnaPlatformPath);$(JnaPath);$(CaffeinePath)</References>
</IkvmReference>
<IkvmReference Include="$(JclOverSlf4jPath)">
<References>$(Slf4jApiPath)</References>
</IkvmReference>
<IkvmReference Include="$(JnaPlatformPath)">
<References>$(JnaPath)</References>
</IkvmReference>
<IkvmReference Include="$(JnaPath)" />
<IkvmReference Include="$(H2Path)" />
<IkvmReference Include="$(PostgreSqlPath)" />
<IkvmReference Include="$(MongoDriverLegacyPath)">
<References>$(Slf4jApiPath);$(BsonPath);$(MongoDriverCorePath);$(MongoDriverSyncPath)</References>
</IkvmReference>
<IkvmReference Include="$(MongoDriverSyncPath)">
<References>$(Slf4jApiPath);$(BsonPath);$(MongoDriverCorePath)</References>
</IkvmReference>
<IkvmReference Include="$(MongoDriverCorePath)">
<References>$(Slf4jApiPath);$(BsonPath)</References>
</IkvmReference>
<IkvmReference Include="$(BsonPath)">
<References>$(Slf4jApiPath)</References>
</IkvmReference>
<IkvmReference Include="$(AmqpClientPath)">
<References>$(Slf4jApiPath)</References>
</IkvmReference>
<IkvmReference Include="$(JedisPath)">
<References>$(Slf4jApiPath);$(CommonsPoolPath);$(JsonPath);$(GsonPath)</References>
</IkvmReference>
<IkvmReference Include="$(JsonPath)">
<AssemblyVersion>2023.02.27.0</AssemblyVersion>
</IkvmReference>
<IkvmReference Include="$(CommonsPoolPath)" />
<IkvmReference Include="$(HikariCPPath)">
<References>$(Slf4jApiPath)</References>
</IkvmReference>
<IkvmReference Include="$(JnatsPath)">
<References>$(EddsaPath)</References>
</IkvmReference>
<IkvmReference Include="$(EddsaPath)" />
<IkvmReference Include="$(ByteBuddyPath)" />
<IkvmReference Include="$(OkHttpPath)">
<References>$(OkioPath);$(ConscryptPath)</References>
</IkvmReference>
<IkvmReference Include="$(OkioPath)">
<References>$(AnimalSnifferAnnotationsPath)</References>
</IkvmReference>
<IkvmReference Include="$(ConscryptPath)" />
<IkvmReference Include="$(CaffeinePath)">
<References>$(ErrorProneAnnotationsPath);$(CheckerQualPath)</References>
</IkvmReference>
<IkvmReference Include="$(Slf4jApiPath)" />
<IkvmReference Include="$(Log4jApiPath)" />
<IkvmReference Include="$(EventApiPath)">
<References>$(GuavaPath);$(CheckerQualPath)</References>
</IkvmReference>
<IkvmReference Include="$(BrigadierPath)" />
<IkvmReference Include="$(GsonPath)" />
<IkvmReference Include="$(ErrorProneAnnotationsPath)" />
<IkvmReference Include="$(AnimalSnifferAnnotationsPath)" />
<IkvmReference Include="$(J2objcAnnotationsPath)" />
<IkvmReference Include="$(Jsr305Path)" />
<IkvmReference Include="$(GuavaPath)">
<References>$(ErrorProneAnnotationsPath);$(AnimalSnifferAnnotationsPath);$(J2objcAnnotationsPath);$(Jsr305Path)</References>
</IkvmReference>
<IkvmReference Include="$(AnnotationsPath)" />
<IkvmReference Include="$(ExaminationApiPath)">
<Reference>$(AnnotationsPath)</Reference>
</IkvmReference>
<IkvmReference Include="$(ExaminationStringPath)" />
<IkvmReference Include="$(AdventureKeyPath)">
<References>$(ExaminationApiPath);$(ExaminationStringPath);$(AnnotationsPath)</References>
</IkvmReference>
<IkvmReference Include="$(AdventureApiPath)">
<References>$(ExaminationApiPath);$(ExaminationStringPath);$(AdventureKeyPath);$(AnnotationsPath)</References>
</IkvmReference>
<IkvmReference Include="$(AdventureTextPlainPath)">
<References>$(AdventureApiPath);$(AnnotationsPath);$(ExaminationApiPath)</References>
</IkvmReference>
<IkvmReference Include="$(AdventureTextLegacyPath)">
<References>$(AdventureApiPath);$(ExaminationApiPath)</References>
</IkvmReference>
<IkvmReference Include="$(AdventureTextMinimessagePath)">
<References>$(AdventureApiPath);$(ExaminationApiPath)</References>
</IkvmReference>
<IkvmReference Include="$(Toml4jPath)">
<References>$(GsonPath)</References>
</IkvmReference>
<IkvmReference Include="$(TypesafeConfigPath)" />
<IkvmReference Include="$(ConfigurateTomlPath)">
<References>$(ConfigurateCorePath);$(Toml4jPath);$(GuavaPath)</References>
</IkvmReference>
<IkvmReference Include="$(ConfigurateGsonPath)">
<References>$(ConfigurateCorePath);$(GsonPath)</References>
</IkvmReference>
<IkvmReference Include="$(ConfigurateHoconPath)">
<References>$(ConfigurateCorePath);$(TypesafeConfigPath)</References>
</IkvmReference>
<IkvmReference Include="$(ConfigurateCorePath)">
<References>$(CheckerQualPath);$(GuavaPath)</References>
</IkvmReference>
<IkvmReference Include="$(ConfigurateYamlPath)">
<References>$(ConfigurateCorePath);$(SnakeYamlPath)</References>
</IkvmReference>
<IkvmReference Include="$(SnakeYamlPath)" />
<IkvmReference Include="$(CheckerQualPath)" />
<IkvmReference Include="$(ApiJarPath)" />
<IkvmReference Include="$(CommonJarPath)">
<References>$(ApiJarPath);$(ConfigurateCorePath);$(ConfigurateGsonPath);$(ConfigurateHoconPath);$(ConfigurateYamlPath);$(SnakeYamlPath);$(CheckerQualPath);$(AdventureApiPath);$(AdventureKeyPath);$(AdventureTextPlainPath);$(AdventureTextLegacyPath);$(AdventureTextMinimessagePath);$(ExaminationApiPath);$(GuavaPath);$(GsonPath);$(ConfigurateTomlPath);$(BrigadierPath);$(EventApiPath);$(Slf4jApiPath);$(Log4jApiPath);$(CaffeinePath);$(OkHttpPath);$(OkioPath);$(ByteBuddyPath);$(JnatsPath);$(HikariCPPath);$(JedisPath);$(CommonsPoolPath);$(AmqpClientPath);$(BsonPath);$(MongoDriverCorePath);$(MongoDriverLegacyPath);$(MongoDriverSyncPath);$(PostgreSqlPath);$(H2Path);$(MariaDbPath);$(MySqlPath)</References>
</IkvmReference>
</ItemGroup>
<ItemGroup>
<Content Include="manifest.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\schema\h2.sql" LogicalName="me.lucko.luckperms.schema.h2.sql" />
<EmbeddedResource Include="Resources\schema\mariadb.sql" LogicalName="me.lucko.luckperms.schema.mariadb.sql" />
<EmbeddedResource Include="Resources\schema\mysql.sql" LogicalName="me.lucko.luckperms.schema.mysql.sql" />
<EmbeddedResource Include="Resources\schema\postgresql.sql" LogicalName="me.lucko.luckperms.schema.postgresql.sql" />
<EmbeddedResource Include="Resources\schema\sqlite.sql" LogicalName="me.lucko.luckperms.schema.sqlite.sql" />
<EmbeddedResource Include="Resources\config.yml" LogicalName="config.yml" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,60 @@
using LuckPerms.Torch.Impl;
using me.lucko.luckperms.common.context.manager;
using me.lucko.luckperms.common.model;
using me.lucko.luckperms.common.verbose.@event;
using net.luckperms.api.query;
using net.luckperms.api.util;
using Torch.ViewModels;
namespace LuckPerms.Torch.PlatformApi;
public class LpPlayerModel(ulong steamId, string? name = null) : PlayerViewModel(steamId, name)
{
public QueryOptionsCache? QueryOptionsCache { get; private set; }
public User? LpUser { get; private set; }
internal void InitializePermissions(User user)
{
LpUser = user;
QueryOptionsCache ??= ((LpContextManager)user.getPlugin().getContextManager()).CreateQueryOptionsCache(this);
}
public Tristate HasPermission(string permission)
{
if (LpUser is null || QueryOptionsCache is null)
return Tristate.UNDEFINED;
return HasPermission(permission, QueryOptionsCache.getQueryOptions());
}
public Tristate HasPermission(string permission, QueryOptions queryOptions)
{
if (LpUser is null || QueryOptionsCache is null)
return Tristate.UNDEFINED;
var data = LpUser.getCachedData().getPermissionData(queryOptions);
return data.checkPermission(permission, CheckOrigin.PLATFORM_API_HAS_PERMISSION).result();
}
public string? GetOption(string key)
{
if (LpUser is null || QueryOptionsCache is null)
return null;
return GetOption(key, QueryOptionsCache.getQueryOptions());
}
public string? GetOption(string key, QueryOptions queryOptions)
{
if (LpUser is null || QueryOptionsCache is null)
return null;
var cache = LpUser.getCachedData().getMetaData(queryOptions);
return cache.getMetaOrChatMetaValue(key, CheckOrigin.PLATFORM_API);
}
public override string ToString() => $"Player {{ SteamId = {SteamId}, Name = {Name} }}";
}

View File

@@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using LuckPerms.Torch.Extensions;
using LuckPerms.Torch.PlatformApi;
using Sandbox.Game.Multiplayer;
using Sandbox.Game.World;
using Torch.API;
using Torch.API.Managers;
using Torch.Commands;
using Torch.Managers;
using Torch.Managers.PatchManager;
using Torch.Managers.PatchManager.MSIL;
using Torch.Mod;
using Torch.Mod.Messages;
using Torch.Server.Managers;
using Torch.Utils;
namespace LuckPerms.Torch.PlatformHooks;
internal static class CommandPermissionsPatch
{
[ReflectedMethodInfo(typeof(CommandManager), nameof(CommandManager.HasPermission))]
private static MethodInfo HasPermissionMethod = null!;
[ReflectedMethodInfo(typeof(TorchCommands), nameof(TorchCommands.Help))]
private static MethodInfo HelpMethod = null!;
[ReflectedMethodInfo(typeof(TorchCommands), nameof(TorchCommands.LongHelp))]
private static MethodInfo LongHelpMethod = null!;
[ReflectedMethodInfo(typeof(CommandPermissionsPatch), nameof(Prefix))]
private static MethodInfo PrefixMethod = null!;
[ReflectedMethodInfo(typeof(CommandPermissionsPatch), nameof(PrefixHelp))]
private static MethodInfo PrefixHelpMethod = null!;
[ReflectedMethodInfo(typeof(CommandPermissionsPatch), nameof(PrefixLongHelp))]
private static MethodInfo PrefixLongHelpMethod = null!;
[ReflectedMethodInfo(typeof(CommandPermissionsPatch), nameof(Transpiler))]
private static MethodInfo TranspilerMethod = null!;
[ReflectedGetter(Name = "Torch")]
private static Func<Manager, ITorchBase> TorchGetter = null!;
public static void Patch(PatchContext context)
{
context.GetPattern(HasPermissionMethod).Prefixes.Add(PrefixMethod);
context.GetPattern(typeof(CommandManager).GetMethod(nameof(CommandManager.HandleCommand),
new []{typeof(string), typeof(ulong), typeof(bool).MakeByRefType(), typeof(bool)})).Transpilers.Add(TranspilerMethod);
context.GetPattern(HelpMethod).Prefixes.Add(PrefixHelpMethod);
context.GetPattern(LongHelpMethod).Prefixes.Add(PrefixLongHelpMethod);
}
private static bool PrefixHelp(CommandModule __instance)
{
var commandManager = __instance.Context.Torch.CurrentSession.Managers.GetManager<CommandManager>();
commandManager.Commands.GetNode(__instance.Context.Args, out var node);
if (node is null)
{
__instance.Context.Respond(
$"Command not found. Use the {commandManager.Prefix}longhelp command for a full list of commands.");
return false;
}
var command = node.Command;
var children = node.Subcommands.Where(e => __instance.Context.Player == null ||
!e.Value.IsCommand ||
!commandManager.HasPermission(__instance.Context.Player.SteamUserId, e.Value.Command))
.Select(x => x.Key);
var sb = new StringBuilder();
if (command is not null)
{
if (__instance.Context.Player is not null && !commandManager.HasPermission(__instance.Context.Player.SteamUserId, command))
{
__instance.Context.Respond("You are not allowed to use this command.");
return false;
}
sb.AppendLine($"Syntax: {command.SyntaxHelp}");
sb.Append(command.HelpText);
}
if (node.Subcommands.Count > 0)
sb.Append($"\nSubcommands: {string.Join(", ", children)}");
__instance.Context.Respond(sb.ToString());
return false;
}
private static bool PrefixLongHelp(CommandModule __instance)
{
var commandManager = __instance.Context.Torch.CurrentSession.Managers.GetManager<CommandManager>();
commandManager.Commands.GetNode(__instance.Context.Args, out var node);
if (node != null)
{
var command = node.Command;
var children = node.Subcommands.Where(e => __instance.Context.Player == null ||
!e.Value.IsCommand ||
!commandManager.HasPermission(__instance.Context.Player.SteamUserId, e.Value.Command));
var sb = new StringBuilder();
if (command != null && (__instance.Context.Player is null || commandManager.HasPermission(__instance.Context.Player.SteamUserId, command)))
{
sb.AppendLine($"Syntax: {command.SyntaxHelp}");
sb.Append(command.HelpText);
}
if (node.Subcommands.Count > 0)
sb.Append($"\nSubcommands: {string.Join(", ", children)}");
__instance.Context.Respond(sb.ToString());
}
else
{
var sb = new StringBuilder();
foreach (var command in commandManager.Commands.WalkTree())
{
if (command.IsCommand && (__instance.Context.Player is null || commandManager.HasPermission(__instance.Context.Player.SteamUserId, command.Command)))
sb.AppendLine($"{command.Command.SyntaxHelp}\n {command.Command.HelpText}");
}
if (!__instance.Context.SentBySelf)
{
var m = new DialogMessage("Torch Help", "Available commands:", sb.ToString());
ModCommunication.SendMessageTo(m, __instance.Context.Player!.SteamUserId);
}
else
__instance.Context.Respond($"Available commands: {sb}");
}
return false;
}
private static bool Prefix(Manager __instance, ulong steamId, Command command, ref bool __result)
{
if (steamId == Sync.MyId)
{
__result = true;
return false;
}
var player = (LpPlayerModel)TorchGetter(__instance).CurrentSession.Managers.GetManager<MultiplayerManagerDedicated>()
.Players[steamId];
var result = player.HasPermission(command.GetPermissionString());
__result = result.asBoolean();
return false;
}
private static IEnumerable<MsilInstruction> Transpiler(IEnumerable<MsilInstruction> ins)
{
foreach (var instruction in ins)
{
if (instruction.OpCode == OpCodes.Ldstr &&
instruction.Operand is MsilOperandInline.MsilOperandString {Value: "You need to be a {0} or higher to use that command."})
yield return instruction.InlineValue("You don't have permission to use that command.");
else
yield return instruction;
}
}
}

View File

@@ -0,0 +1,59 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using Torch.Commands;
using Torch.Managers.PatchManager;
using Torch.Managers.PatchManager.MSIL;
using Torch.Utils;
namespace LuckPerms.Torch.PlatformHooks;
internal static class CommandPrefixPatch
{
private const char DefaultPrefix = '!';
private const char SlashPrefix = '/';
[ReflectedMethodInfo(typeof(CommandPrefixPatch), nameof(CheckPrefix))]
private static MethodInfo CheckPrefixMethod = null!;
[ReflectedMethodInfo(typeof(CommandPrefixPatch), nameof(IsCommandPrefix))]
private static MethodInfo IsCommandPrefixMethod = null!;
[ReflectedMethodInfo(typeof(CommandPrefixPatch), nameof(HandleCommandTranspiler))]
private static MethodInfo HandleCommandTranspilerMethod = null!;
[ReflectedMethodInfo(typeof(CommandManager), nameof(CommandManager.IsCommand))]
private static MethodInfo IsCommandMethod = null!;
public static void Patch(PatchContext context)
{
context.GetPattern(IsCommandMethod).Prefixes.Add(IsCommandPrefixMethod);
var handleCommandMethod = typeof(CommandManager).GetMethods().Single(b =>
b.Name == nameof(CommandManager.HandleCommand) && b.GetParameters().Length == 4);
context.GetPattern(handleCommandMethod).Transpilers.Add(HandleCommandTranspilerMethod);
}
private static bool IsCommandPrefix(string command, out bool __result)
{
__result = !string.IsNullOrEmpty(command) && command[0] is DefaultPrefix or SlashPrefix;
return false;
}
private static IEnumerable<MsilInstruction> HandleCommandTranspiler(IEnumerable<MsilInstruction> instructions)
{
var list = instructions.ToList();
var index = list.FindIndex(b =>
b.OpCode == OpCodes.Call && b.Operand is MsilOperandInline.MsilOperandReflected<MethodBase> { Value.Name: "get_Prefix" });
list[index - 1] = new(OpCodes.Nop);
list[index] = list[index].InlineValue(CheckPrefixMethod);
list[index + 1] = new MsilInstruction(OpCodes.Brtrue_S).InlineTarget(list[index + 3].Labels.First());
return list;
}
private static bool CheckPrefix(char prefix) => prefix is DefaultPrefix or SlashPrefix;
}

View File

@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using LuckPerms.Torch.PlatformApi;
using Torch.Managers;
using Torch.Managers.PatchManager;
using Torch.Managers.PatchManager.MSIL;
using Torch.Utils;
namespace LuckPerms.Torch.PlatformHooks;
internal static class PlayerPatch
{
[ReflectedMethodInfo(typeof(MultiplayerManagerBase), "RaiseClientJoined")]
private static MethodInfo Target = null!;
[ReflectedMethodInfo(typeof(PlayerPatch), nameof(Transpiler))]
private static MethodInfo TranspilerMethod = null!;
public static void Patch(PatchContext context)
{
context.GetPattern(Target).Transpilers.Add(TranspilerMethod);
}
private static IEnumerable<MsilInstruction> Transpiler(IEnumerable<MsilInstruction> instructions)
{
var list = instructions.ToList();
var newIndex = list.FindIndex(b => b.OpCode == OpCodes.Newobj);
list[newIndex] = list[newIndex].InlineValue(typeof(LpPlayerModel).GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)[0]);
return list;
}
}

80
LuckPerms.Torch/Plugin.cs Normal file
View File

@@ -0,0 +1,80 @@
using System;
using System.IO;
using java.lang;
using java.util;
using LuckPerms.Torch.Impl;
using NLog;
using Sandbox;
using Torch;
using Torch.API;
using Exception = System.Exception;
using Object = java.lang.Object;
namespace LuckPerms.Torch;
public class Plugin : TorchPluginBase
{
static Plugin()
{
// for some fucking reason if jvm is getting initialized in some other place - it throws
// happens only on framework and most likely related to its retarded types initialization rules
_ = new Object();
Locale.setDefault(Locale.ENGLISH);
}
public static readonly ILogger Log = LogManager.GetLogger("LuckPerms");
private LpTorchBootstrap? _bootstrap;
public override void Init(ITorchBase torch)
{
base.Init(torch);
Torch.GameStateChanged += TorchOnGameStateChanged;
_bootstrap = new((ITorchServer)Torch, this, Log, Path.Combine(StoragePath, "luckperms"));
try
{
Log.Info("Initializing LuckPerms");
_bootstrap.Plugin.load();
}
catch (Exception e)
{
Log.Fatal(e);
throw;
}
finally
{
_bootstrap.LoadLatch.countDown();
}
}
private void TorchOnGameStateChanged(MySandboxGame game, TorchGameState newState)
{
if (_bootstrap is null)
throw new InvalidOperationException("Plugin is not initialized");
switch (newState)
{
case TorchGameState.Loading:
try
{
Log.Info("Loading LuckPerms");
Thread.currentThread().setContextClassLoader(LpDependencyManager.CurrentClassLoader);
_bootstrap.Plugin.enable();
}
catch (Exception e)
{
Log.Fatal(e);
throw;
}
finally
{
_bootstrap.EnableLatch.countDown();
}
break;
case TorchGameState.Unloading:
Log.Info("Unloading LuckPerms");
_bootstrap.Plugin.disable();
break;
}
}
}

View File

@@ -0,0 +1,578 @@
####################################################################################################
# +----------------------------------------------------------------------------------------------+ #
# | __ __ ___ __ __ | #
# | | | | / ` |__/ |__) |__ |__) |\/| /__` | #
# | |___ \__/ \__, | \ | |___ | \ | | .__/ | #
# | | #
# | https://luckperms.net | #
# | | #
# | WIKI: https://luckperms.net/wiki | #
# | DISCORD: https://discord.gg/VAb2zgXHA | #
# | BUG REPORTS: https://github.com/PveTeam/TorchPlugins/issues | #
# | | #
# | Each option in this file is documented and explained here: | #
# | ==> https://luckperms.net/wiki/Configuration | #
# | | #
# | New options are not added to this file automatically. Default values are used if an | #
# | option cannot be found. The latest config versions can be obtained at the link above. | #
# +----------------------------------------------------------------------------------------------+ #
####################################################################################################
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | ESSENTIAL SETTINGS | #
# | | #
# | Important settings that control how LuckPerms functions. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# The name of the server, used for server specific permissions.
#
# - When set to "global" this setting is effectively ignored.
# - In all other cases, the value here is added to all players in a "server" context.
# - See: https://luckperms.net/wiki/Context
server: global
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | STORAGE SETTINGS | #
# | | #
# | Controls which storage method LuckPerms will use to store data. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# How the plugin should store data
#
# - The various options are explained in more detail on the wiki:
# https://luckperms.net/wiki/Storage-types
#
# - Possible options:
#
# | Remote databases - require connection information to be configured below
# |=> MySQL
# |=> MariaDB (preferred over MySQL)
# |=> PostgreSQL
# |=> MongoDB
#
# | Flatfile/local database - don't require any extra configuration
# |=> H2 (preferred over SQLite)
# |=> SQLite
#
# | Readable & editable text files - don't require any extra configuration
# |=> YAML (.yml files)
# |=> JSON (.json files)
# |=> HOCON (.conf files)
# |=> TOML (.toml files)
# |
# | By default, user, group and track data is separated into different files. Data can be combined
# | and all stored in the same file by switching to a combined storage variant.
# | Just add '-combined' to the end of the storage-method, e.g. 'yaml-combined'
#
# - A H2 database is the default option.
# - If you want to edit data manually in "traditional" storage files, we suggest using YAML.
storage-method: h2
# The following block defines the settings for remote database storage methods.
#
# - You don't need to touch any of the settings here if you're using a local storage method!
# - The connection detail options are shared between all remote storage types.
data:
# Define the address and port for the database.
# - The standard DB engine port is used by default
# (MySQL: 3306, PostgreSQL: 5432, MongoDB: 27017)
# - Specify as "host:port" if differs
address: localhost
# The name of the database to store LuckPerms data in.
# - This must be created already. Don't worry about this setting if you're using MongoDB.
database: space-engineers
# Credentials for the database.
username: root
password: ''
# These settings apply to the MySQL connection pool.
# - The default values will be suitable for the majority of users.
# - Do not change these settings unless you know what you're doing!
pool-settings:
# Sets the maximum size of the MySQL connection pool.
# - Basically this value will determine the maximum number of actual
# connections to the database backend.
# - More information about determining the size of connection pools can be found here:
# https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
maximum-pool-size: 10
# Sets the minimum number of idle connections that the pool will try to maintain.
# - For maximum performance and responsiveness to spike demands, it is recommended to not set
# this value and instead allow the pool to act as a fixed size connection pool.
# (set this value to the same as 'maximum-pool-size')
minimum-idle: 10
# This setting controls the maximum lifetime of a connection in the pool in milliseconds.
# - The value should be at least 30 seconds less than any database or infrastructure imposed
# connection time limit.
maximum-lifetime: 1800000 # 30 minutes
# This setting controls how frequently the pool will 'ping' a connection in order to prevent it
# from being timed out by the database or network infrastructure, measured in milliseconds.
# - The value should be less than maximum-lifetime and greater than 30000 (30 seconds).
# - Setting the value to zero will disable the keepalive functionality.
keepalive-time: 0
# This setting controls the maximum number of milliseconds that the plugin will wait for a
# connection from the pool, before timing out.
connection-timeout: 5000 # 5 seconds
# This setting allows you to define extra properties for connections.
#
# By default, the following options are set to enable utf8 encoding. (you may need to remove
# these if you are using PostgreSQL)
# useUnicode: true
# characterEncoding: utf8
#
# You can also use this section to disable SSL connections, by uncommenting the 'useSSL' and
# 'verifyServerCertificate' options below.
properties:
useUnicode: true
characterEncoding: utf8
#useSSL: false
#verifyServerCertificate: false
# The prefix for all LuckPerms SQL tables.
#
# - This only applies for remote SQL storage types (MySQL, MariaDB, etc).
# - Change this if you want to use different tables for different servers.
table-prefix: 'luckperms_'
# The prefix to use for all LuckPerms MongoDB collections.
#
# - This only applies for the MongoDB storage type.
# - Change this if you want to use different collections for different servers. The default is no
# prefix.
mongodb-collection-prefix: ''
# The connection string URI to use to connect to the MongoDB instance.
#
# - When configured, this setting will override anything defined in the address, database,
# username or password fields above.
# - If you have a connection string that starts with 'mongodb://' or 'mongodb+srv://', enter it
# below.
# - For more information, please see https://docs.mongodb.com/manual/reference/connection-string/
mongodb-connection-uri: ''
# Define settings for a "split" storage setup.
#
# - This allows you to define a storage method for each type of data.
# - The connection options above still have to be correct for each type here.
split-storage:
# Don't touch this if you don't want to use split storage!
enabled: false
methods:
# These options don't need to be modified if split storage isn't enabled.
user: h2
group: h2
track: h2
uuid: h2
log: h2
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | UPDATE PROPAGATION & MESSAGING SERVICE | #
# | | #
# | Controls the ways in which LuckPerms will sync data & notify other servers of changes. | #
# | These options are documented on greater detail on the wiki under "Instant Updates". | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# This option controls how frequently LuckPerms will perform a sync task.
#
# - A sync task will refresh all data from the storage, and ensure that the most up-to-date data is
# being used by the plugin.
# - This is disabled by default, as most users will not need it. However, if you're using a remote
# storage type without a messaging service setup, you may wish to set this to something like 3.
# - Set to -1 to disable the task completely.
sync-minutes: -1
# If the file watcher should be enabled.
#
# - When using a file-based storage type, LuckPerms can monitor the data files for changes, and
# automatically update when changes are detected.
# - If you don't want this feature to be active, set this option to false.
watch-files: true
# Define which messaging service should be used by the plugin.
#
# - If enabled and configured, LuckPerms will use the messaging service to inform other connected
# servers of changes.
# - Use the command "/lp networksync" to manually push changes.
# - Data is NOT stored using this service. It is only used as a messaging platform.
#
# - If you decide to enable this feature, you should set "sync-minutes" to -1, as there is no need
# for LuckPerms to poll the database for changes.
#
# - Possible options:
# => sql Uses the SQL database to form a queue system for communication. Will only work when
# 'storage-method' is set to MySQL or MariaDB. This is chosen by default if the
# option is set to 'auto' and SQL storage is in use. Set to 'notsql' to disable this.
# => redis Uses Redis pub-sub to push changes. Your server connection info must be configured
# below.
# => rabbitmq Uses RabbitMQ pub-sub to push changes. Your server connection info must be
# configured below.
# => nats Uses Nats pub-sub to push changes. Your server connection info must be
# configured below.
# => custom Uses a messaging service provided using the LuckPerms API.
# => auto Attempts to automatically setup a messaging service using redis or sql.
messaging-service: auto
# If LuckPerms should automatically push updates after a change has been made with a command.
auto-push-updates: true
# If LuckPerms should push logging entries to connected servers via the messaging service.
push-log-entries: true
# If LuckPerms should broadcast received logging entries to players on this platform.
#
# - If you have LuckPerms installed on your backend servers as well as a BungeeCord proxy, you
# should set this option to false on either your backends or your proxies, to avoid players being
# messaged twice about log entries.
broadcast-received-log-entries: true
# Settings for Redis.
# Port 6379 is used by default; set address to "host:port" if differs
# Multiple Redis nodes can be specified in the same format as a string list under the name "addresses".
redis:
enabled: false
address: localhost
username: ''
password: ''
# Settings for Nats.
# Port 4222 is used by default; set address to "host:port" if differs
nats:
enabled: false
address: localhost
username: ''
password: ''
# Settings for RabbitMQ.
# Port 5672 is used by default; set address to "host:port" if differs
rabbitmq:
enabled: false
address: localhost
vhost: '/'
username: 'guest'
password: 'guest'
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | CUSTOMIZATION SETTINGS | #
# | | #
# | Settings that allow admins to customize the way LuckPerms operates. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# Controls how temporary permissions/parents/meta should be accumulated.
#
# - The default behaviour is "deny".
# - This behaviour can also be specified when the command is executed. See the command usage
# documentation for more info.
#
# - Possible options:
# => accumulate durations will be added to the existing expiry time
# => replace durations will be replaced if the new duration is later than the current
# expiration
# => deny the command will just fail if you try to add another node with the same expiry
temporary-add-behaviour: deny
# Controls how LuckPerms will determine a users "primary" group.
#
# - The meaning and influence of "primary groups" are explained in detail on the wiki.
# - The preferred approach is to let LuckPerms automatically determine a users primary group
# based on the relative weight of their parent groups.
#
# - Possible options:
# => stored use the value stored against the users record in the file/database
# => parents-by-weight just use the users most highly weighted parent
# => all-parents-by-weight same as above, but calculates based upon all parents inherited from
# both directly and indirectly
primary-group-calculation: parents-by-weight
# If the plugin should check for "extra" permissions with users run LP commands.
#
# - These extra permissions allow finer control over what users can do with each command, and who
# they have access to edit.
# - The nature of the checks are documented on the wiki under "Argument based command permissions".
# - Argument based permissions are *not* static, unlike the 'base' permissions, and will depend upon
# the arguments given within the command.
argument-based-command-permissions: false
# If the plugin should check whether senders are a member of a given group before they're able to
# edit the groups data or add/remove other users to/from it.
# Note: these limitations do not apply to the web editor!
require-sender-group-membership-to-modify: false
# If the plugin should send log notifications to users whenever permissions are modified.
#
# - Notifications are only sent to those with the appropriate permission to receive them
# - They can also be temporarily enabled/disabled on a per-user basis using
# '/lp log notify <on|off>'
log-notify: true
# Defines a list of log entries which should not be sent as notifications to users.
#
# - Each entry in the list is a RegEx expression which is matched against the log entry description.
log-notify-filtered-descriptions:
# - "parent add example"
# If LuckPerms should automatically install translation bundles and periodically update them.
auto-install-translations: true
# Defines the options for prefix and suffix stacking.
#
# - The feature allows you to display multiple prefixes or suffixes alongside a players username in
# chat.
# - It is explained and documented in more detail on the wiki under "Prefix & Suffix Stacking".
#
# - The options are divided into separate sections for prefixes and suffixes.
# - The 'duplicates' setting refers to how duplicate elements are handled. Can be 'retain-all',
# 'first-only' or 'last-only'.
# - The value of 'start-spacer' is included at the start of the resultant prefix/suffix.
# - The value of 'end-spacer' is included at the end of the resultant prefix/suffix.
# - The value of 'middle-spacer' is included between each element in the resultant prefix/suffix.
#
# - Possible format options:
# => highest Selects the value with the highest weight, from all values
# held by or inherited by the player.
#
# => lowest Same as above, except takes the one with the lowest weight.
#
# => highest_own Selects the value with the highest weight, but will not
# accept any inherited values.
#
# => lowest_own Same as above, except takes the value with the lowest weight.
#
# => highest_inherited Selects the value with the highest weight, but will only
# accept inherited values.
#
# => lowest_inherited Same as above, except takes the value with the lowest weight.
#
# => highest_on_track_<track> Selects the value with the highest weight, but only if the
# value was inherited from a group on the given track.
#
# => lowest_on_track_<track> Same as above, except takes the value with the lowest weight.
#
# => highest_not_on_track_<track> Selects the value with the highest weight, but only if the
# value was inherited from a group not on the given track.
#
# => lowest_not_on_track_<track> Same as above, except takes the value with the lowest weight.
#
# => highest_from_group_<group> Selects the value with the highest weight, but only if the
# value was inherited from the given group.
#
# => lowest_from_group_<group> Same as above, except takes the value with the lowest weight.
#
# => highest_not_from_group_<group> Selects the value with the highest weight, but only if the
# value was not inherited from the given group.
#
# => lowest_not_from_group_<group> Same as above, except takes the value with the lowest weight.
meta-formatting:
prefix:
format:
- "highest"
duplicates: first-only
start-spacer: ""
middle-spacer: " "
end-spacer: ""
suffix:
format:
- "highest"
duplicates: first-only
start-spacer: ""
middle-spacer: " "
end-spacer: ""
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | PERMISSION CALCULATION AND INHERITANCE | #
# | | #
# | Modify the way permission checks, meta lookups and inheritance resolutions are handled. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# The algorithm LuckPerms should use when traversing the "inheritance tree".
#
# - Possible options:
# => breadth-first See: https://en.wikipedia.org/wiki/Breadth-first_search
# => depth-first-pre-order See: https://en.wikipedia.org/wiki/Depth-first_search
# => depth-first-post-order See: https://en.wikipedia.org/wiki/Depth-first_search
inheritance-traversal-algorithm: depth-first-pre-order
# If a final sort according to "inheritance rules" should be performed after the traversal algorithm
# has resolved the inheritance tree.
#
# "Inheritance rules" refers to things such as group weightings, primary group status, and the
# natural contextual ordering of the group nodes.
#
# Setting this to 'true' will allow for the inheritance rules to take priority over the structure of
# the inheritance tree.
#
# Effectively when this setting is 'true': the tree is flattened, and rules applied afterwards,
# and when this setting is 'false':, the rules are just applied during each step of the traversal.
post-traversal-inheritance-sort: false
# Defines the mode used to determine whether a set of contexts are satisfied.
#
# - Possible options:
# => at-least-one-value-per-key Set A will be satisfied by another set B, if at least one of the
# key-value entries per key in A are also in B.
# => all-values-per-key Set A will be satisfied by another set B, if all key-value
# entries in A are also in B.
context-satisfy-mode: at-least-one-value-per-key
# +----------------------------------------------------------------------------------------------+ #
# | Permission resolution settings | #
# +----------------------------------------------------------------------------------------------+ #
# If users on this server should have their global permissions applied.
# When set to false, only server specific permissions will apply for users on this server
include-global: true
# If users on this server should have their global world permissions applied.
# When set to false, only world specific permissions will apply for users on this server
include-global-world: true
# If users on this server should have global (non-server specific) groups applied
apply-global-groups: true
# If users on this server should have global (non-world specific) groups applied
apply-global-world-groups: true
# +----------------------------------------------------------------------------------------------+ #
# | Meta lookup settings | #
# +----------------------------------------------------------------------------------------------+ #
# Defines how meta values should be selected.
#
# - Possible options:
# => inheritance Selects the meta value that was inherited first
# => highest-number Selects the highest numerical meta value
# => lowest-number Selects the lowest numerical meta value
meta-value-selection-default: inheritance
# Defines how meta values should be selected per key.
meta-value-selection:
# max-homes: highest-number
# +----------------------------------------------------------------------------------------------+ #
# | Inheritance settings | #
# +----------------------------------------------------------------------------------------------+ #
# If the plugin should apply wildcard permissions.
#
# - If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered
# permissions matching the wildcard.
apply-wildcards: true
# If LuckPerms should resolve and apply permissions according to the Sponge style implicit wildcard
# inheritance system.
#
# - That being: If a user has been granted "example", then the player should have also be
# automatically granted "example.function", "example.another", "example.deeper.nesting",
# and so on.
apply-sponge-implicit-wildcards: false
# If the plugin should apply negated Bukkit default permissions before it considers wildcard
# assignments.
#
# - Plugin authors can define permissions which explicitly should not be given automatically to OPs.
# This is usually used for so called "anti-permissions" - permissions which, when granted, apply
# something negative.
# - If this option is set to true, LuckPerms will consider any negated declarations made by
# plugins before it considers wildcards. (similar to the way the OP system works)
# - If this option is set to false, LuckPerms will consider any wildcard assignments first.
apply-default-negated-permissions-before-wildcards: false
# If the plugin should parse regex permissions.
#
# - If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the
# node, and resolve & apply all registered permissions matching the regex.
apply-regex: true
# If the plugin should complete and apply shorthand permissions.
#
# - If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# +----------------------------------------------------------------------------------------------+ #
# | Extra settings | #
# +----------------------------------------------------------------------------------------------+ #
# A list of context calculators which will be skipped when calculating contexts.
#
# - You can disable context calculators by either:
# => specifying the Java class name used by the calculator (e.g. com.example.ExampleCalculator)
# => specifying a sub-section of the Java package used by the calculator (e.g. com.example)
disabled-context-calculators: []
# Define special group weights for this server.
#
# - Group weights can also be applied directly to group data, using the setweight command.
# - This section allows weights to be set on a per-server basis.
group-weight:
# admin: 10
# +----------------------------------------------------------------------------------------------+ #
# | | #
# | FINE TUNING OPTIONS | #
# | | #
# | A number of more niche settings for tweaking and changing behaviour. The section also | #
# | contains toggles for some more specialised features. It is only necessary to make changes to | #
# | these options if you want to fine-tune LuckPerms behaviour. | #
# | | #
# +----------------------------------------------------------------------------------------------+ #
# +----------------------------------------------------------------------------------------------+ #
# | Miscellaneous (and rarely used) settings | #
# +----------------------------------------------------------------------------------------------+ #
# If LuckPerms should allow usernames with non alphanumeric characters.
#
# - Note that due to the design of the storage implementation, usernames must still be 16 characters
# or less.
allow-invalid-usernames: false
# If LuckPerms should not require users to confirm bulkupdate operations.
#
# - When set to true, operations will be executed immediately.
# - This is not recommended, as bulkupdate has the potential to irreversibly delete large amounts of
# data, and is not designed to be executed automatically.
# - If automation is needed, users should prefer using the LuckPerms API.
skip-bulkupdate-confirmation: false
# If LuckPerms should prevent bulkupdate operations.
#
# - When set to true, bulkupdate operations (the /lp bulkupdate command) will not work.
# - When set to false, bulkupdate operations will be allowed via the console.
disable-bulkupdate: false
# If LuckPerms should allow a users primary group to be removed with the 'parent remove' command.
#
# - When this happens, the plugin will set their primary group back to default.
prevent-primary-group-removal: false

View File

@@ -0,0 +1,58 @@
-- LuckPerms H2 Schema.
CREATE TABLE `{prefix}user_permissions` (
`id` INT AUTO_INCREMENT NOT NULL,
`uuid` VARCHAR(36) NOT NULL,
`permission` VARCHAR(200) NOT NULL,
`value` BOOL NOT NULL,
`server` VARCHAR(36) NOT NULL,
`world` VARCHAR(64) NOT NULL,
`expiry` BIGINT NOT NULL,
`contexts` VARCHAR(200) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE INDEX ON `{prefix}user_permissions` (`uuid`);
CREATE TABLE `{prefix}group_permissions` (
`id` INT AUTO_INCREMENT NOT NULL,
`name` VARCHAR(36) NOT NULL,
`permission` VARCHAR(200) NOT NULL,
`value` BOOL NOT NULL,
`server` VARCHAR(36) NOT NULL,
`world` VARCHAR(64) NOT NULL,
`expiry` BIGINT NOT NULL,
`contexts` VARCHAR(200) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE INDEX ON `{prefix}group_permissions` (`name`);
CREATE TABLE `{prefix}players` (
`uuid` VARCHAR(36) NOT NULL,
`username` VARCHAR(16) NOT NULL,
`primary_group` VARCHAR(36) NOT NULL,
PRIMARY KEY (`uuid`)
);
CREATE INDEX ON `{prefix}players` (`username`);
CREATE TABLE `{prefix}groups` (
`name` VARCHAR(36) NOT NULL,
PRIMARY KEY (`name`)
);
CREATE TABLE `{prefix}actions` (
`id` INT AUTO_INCREMENT NOT NULL,
`time` BIGINT NOT NULL,
`actor_uuid` VARCHAR(36) NOT NULL,
`actor_name` VARCHAR(100) NOT NULL,
`type` CHAR(1) NOT NULL,
`acted_uuid` VARCHAR(36) NOT NULL,
`acted_name` VARCHAR(36) NOT NULL,
`action` VARCHAR(300) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `{prefix}tracks` (
`name` VARCHAR(36) NOT NULL,
`groups` TEXT NOT NULL,
PRIMARY KEY (`name`)
);

View File

@@ -0,0 +1,58 @@
-- LuckPerms MariaDB Schema
CREATE TABLE `{prefix}user_permissions` (
`id` INT AUTO_INCREMENT NOT NULL,
`uuid` VARCHAR(36) NOT NULL,
`permission` VARCHAR(200) NOT NULL,
`value` BOOL NOT NULL,
`server` VARCHAR(36) NOT NULL,
`world` VARCHAR(64) NOT NULL,
`expiry` BIGINT NOT NULL,
`contexts` VARCHAR(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET = utf8mb4;
CREATE INDEX `{prefix}user_permissions_uuid` ON `{prefix}user_permissions` (`uuid`);
CREATE TABLE `{prefix}group_permissions` (
`id` INT AUTO_INCREMENT NOT NULL,
`name` VARCHAR(36) NOT NULL,
`permission` VARCHAR(200) NOT NULL,
`value` BOOL NOT NULL,
`server` VARCHAR(36) NOT NULL,
`world` VARCHAR(64) NOT NULL,
`expiry` BIGINT NOT NULL,
`contexts` VARCHAR(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET = utf8mb4;
CREATE INDEX `{prefix}group_permissions_name` ON `{prefix}group_permissions` (`name`);
CREATE TABLE `{prefix}players` (
`uuid` VARCHAR(36) NOT NULL,
`username` VARCHAR(16) NOT NULL,
`primary_group` VARCHAR(36) NOT NULL,
PRIMARY KEY (`uuid`)
) DEFAULT CHARSET = utf8mb4;
CREATE INDEX `{prefix}players_username` ON `{prefix}players` (`username`);
CREATE TABLE `{prefix}groups` (
`name` VARCHAR(36) NOT NULL,
PRIMARY KEY (`name`)
) DEFAULT CHARSET = utf8mb4;
CREATE TABLE `{prefix}actions` (
`id` INT AUTO_INCREMENT NOT NULL,
`time` BIGINT NOT NULL,
`actor_uuid` VARCHAR(36) NOT NULL,
`actor_name` VARCHAR(100) NOT NULL,
`type` CHAR(1) NOT NULL,
`acted_uuid` VARCHAR(36) NOT NULL,
`acted_name` VARCHAR(36) NOT NULL,
`action` VARCHAR(300) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET = utf8mb4;
CREATE TABLE `{prefix}tracks` (
`name` VARCHAR(36) NOT NULL,
`groups` TEXT NOT NULL,
PRIMARY KEY (`name`)
) DEFAULT CHARSET = utf8mb4;

View File

@@ -0,0 +1,58 @@
-- LuckPerms MySQL Schema
CREATE TABLE `{prefix}user_permissions` (
`id` INT AUTO_INCREMENT NOT NULL,
`uuid` VARCHAR(36) NOT NULL,
`permission` VARCHAR(200) NOT NULL,
`value` BOOL NOT NULL,
`server` VARCHAR(36) NOT NULL,
`world` VARCHAR(64) NOT NULL,
`expiry` BIGINT NOT NULL,
`contexts` VARCHAR(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET = utf8mb4;
CREATE INDEX `{prefix}user_permissions_uuid` ON `{prefix}user_permissions` (`uuid`);
CREATE TABLE `{prefix}group_permissions` (
`id` INT AUTO_INCREMENT NOT NULL,
`name` VARCHAR(36) NOT NULL,
`permission` VARCHAR(200) NOT NULL,
`value` BOOL NOT NULL,
`server` VARCHAR(36) NOT NULL,
`world` VARCHAR(64) NOT NULL,
`expiry` BIGINT NOT NULL,
`contexts` VARCHAR(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET = utf8mb4;
CREATE INDEX `{prefix}group_permissions_name` ON `{prefix}group_permissions` (`name`);
CREATE TABLE `{prefix}players` (
`uuid` VARCHAR(36) NOT NULL,
`username` VARCHAR(16) NOT NULL,
`primary_group` VARCHAR(36) NOT NULL,
PRIMARY KEY (`uuid`)
) DEFAULT CHARSET = utf8mb4;
CREATE INDEX `{prefix}players_username` ON `{prefix}players` (`username`);
CREATE TABLE `{prefix}groups` (
`name` VARCHAR(36) NOT NULL,
PRIMARY KEY (`name`)
) DEFAULT CHARSET = utf8mb4;
CREATE TABLE `{prefix}actions` (
`id` INT AUTO_INCREMENT NOT NULL,
`time` BIGINT NOT NULL,
`actor_uuid` VARCHAR(36) NOT NULL,
`actor_name` VARCHAR(100) NOT NULL,
`type` CHAR(1) NOT NULL,
`acted_uuid` VARCHAR(36) NOT NULL,
`acted_name` VARCHAR(36) NOT NULL,
`action` VARCHAR(300) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET = utf8mb4;
CREATE TABLE `{prefix}tracks` (
`name` VARCHAR(36) NOT NULL,
`groups` TEXT NOT NULL,
PRIMARY KEY (`name`)
) DEFAULT CHARSET = utf8mb4;

View File

@@ -0,0 +1,52 @@
-- LuckPerms PostgreSQL Schema
CREATE TABLE "{prefix}user_permissions" (
"id" SERIAL PRIMARY KEY NOT NULL,
"uuid" VARCHAR(36) NOT NULL,
"permission" VARCHAR(200) NOT NULL,
"value" BOOL NOT NULL,
"server" VARCHAR(36) NOT NULL,
"world" VARCHAR(64) NOT NULL,
"expiry" BIGINT NOT NULL,
"contexts" VARCHAR(200) NOT NULL
);
CREATE INDEX "{prefix}user_permissions_uuid" ON "{prefix}user_permissions" ("uuid");
CREATE TABLE "{prefix}group_permissions" (
"id" SERIAL PRIMARY KEY NOT NULL,
"name" VARCHAR(36) NOT NULL,
"permission" VARCHAR(200) NOT NULL,
"value" BOOL NOT NULL,
"server" VARCHAR(36) NOT NULL,
"world" VARCHAR(64) NOT NULL,
"expiry" BIGINT NOT NULL,
"contexts" VARCHAR(200) NOT NULL
);
CREATE INDEX "{prefix}group_permissions_name" ON "{prefix}group_permissions" ("name");
CREATE TABLE "{prefix}players" (
"uuid" VARCHAR(36) PRIMARY KEY NOT NULL,
"username" VARCHAR(16) NOT NULL,
"primary_group" VARCHAR(36) NOT NULL
);
CREATE INDEX "{prefix}players_username" ON "{prefix}players" ("username");
CREATE TABLE "{prefix}groups" (
"name" VARCHAR(36) PRIMARY KEY NOT NULL
);
CREATE TABLE "{prefix}actions" (
"id" SERIAL PRIMARY KEY NOT NULL,
"time" BIGINT NOT NULL,
"actor_uuid" VARCHAR(36) NOT NULL,
"actor_name" VARCHAR(100) NOT NULL,
"type" CHAR(1) NOT NULL,
"acted_uuid" VARCHAR(36) NOT NULL,
"acted_name" VARCHAR(36) NOT NULL,
"action" VARCHAR(300) NOT NULL
);
CREATE TABLE "{prefix}tracks" (
"name" VARCHAR(36) PRIMARY KEY NOT NULL,
"groups" TEXT NOT NULL
);

View File

@@ -0,0 +1,55 @@
-- LuckPerms SQLite Schema
CREATE TABLE `{prefix}user_permissions` (
`id` INTEGER PRIMARY KEY NOT NULL,
`uuid` VARCHAR(36) NOT NULL,
`permission` VARCHAR(200) NOT NULL,
`value` BOOL NOT NULL,
`server` VARCHAR(36) NOT NULL,
`world` VARCHAR(64) NOT NULL,
`expiry` BIGINT NOT NULL,
`contexts` VARCHAR(200) NOT NULL
);
CREATE INDEX `{prefix}user_permissions_uuid` ON `{prefix}user_permissions` (`uuid`);
CREATE TABLE `{prefix}group_permissions` (
`id` INTEGER PRIMARY KEY NOT NULL,
`name` VARCHAR(36) NOT NULL,
`permission` VARCHAR(200) NOT NULL,
`value` BOOL NOT NULL,
`server` VARCHAR(36) NOT NULL,
`world` VARCHAR(64) NOT NULL,
`expiry` BIGINT NOT NULL,
`contexts` VARCHAR(200) NOT NULL
);
CREATE INDEX `{prefix}group_permissions_name` ON `{prefix}group_permissions` (`name`);
CREATE TABLE `{prefix}players` (
`uuid` VARCHAR(36) NOT NULL,
`username` VARCHAR(16) NOT NULL,
`primary_group` VARCHAR(36) NOT NULL,
PRIMARY KEY (`uuid`)
);
CREATE INDEX `{prefix}players_username` ON `{prefix}players` (`username`);
CREATE TABLE `{prefix}groups` (
`name` VARCHAR(36) NOT NULL,
PRIMARY KEY (`name`)
);
CREATE TABLE `{prefix}actions` (
`id` INTEGER PRIMARY KEY NOT NULL,
`time` BIGINT NOT NULL,
`actor_uuid` VARCHAR(36) NOT NULL,
`actor_name` VARCHAR(100) NOT NULL,
`type` CHAR(1) NOT NULL,
`acted_uuid` VARCHAR(36) NOT NULL,
`acted_name` VARCHAR(36) NOT NULL,
`action` VARCHAR(300) NOT NULL
);
CREATE TABLE `{prefix}tracks` (
`name` VARCHAR(36) NOT NULL,
`groups` TEXT NOT NULL,
PRIMARY KEY (`name`)
);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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>LuckPerms.Torch</Name>
<Guid>7E4B3CC8-64FA-416E-8910-AACDF2DA5E2C</Guid>
<Version>v5.4.106</Version>
</PluginManifest>

View File

@@ -0,0 +1,388 @@
{
"version": 1,
"dependencies": {
".NETFramework,Version=v4.8": {
"IKVM": {
"type": "Direct",
"requested": "[8.7.1, )",
"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"
}
},
"Lib.Harmony": {
"type": "Direct",
"requested": "[2.3.0-prerelease.2, )",
"resolved": "2.3.0-prerelease.2",
"contentHash": "96ijLrds6W9otxxKIopzQS68tAm6sFbfWBSxfnxkWb9QmE84NJJH/6mutr8sqQ+Dv5Oqg6fAZBdcM6WfB6khVA==",
"dependencies": {
"MonoMod.Core": "1.0.0-prerelease.2"
}
},
"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.13.2, )",
"resolved": "1.13.2",
"contentHash": "XwNhfkr7IeUiH8AE4pzob8YioxfL6nxgAx+fHEeWCObY/NZuBMfWLh39FznXbneKvagiqeeI7quIvZ6P1eVaEA=="
},
"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.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.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=="
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==",
"dependencies": {
"System.Threading.Tasks.Extensions": "4.5.4"
}
},
"Microsoft.NETFramework.ReferenceAssemblies.net48": {
"type": "Transitive",
"resolved": "1.0.3",
"contentHash": "zMk4D+9zyiEWByyQ7oPImPN/Jhpj166Ky0Nlla4eXlNL8hI/BtSJsgR8Inldd4NNpIAH3oh8yym0W2DrhXdSLQ=="
},
"Mono.Cecil": {
"type": "Transitive",
"resolved": "0.11.4",
"contentHash": "IC1h5g0NeJGHIUgzM1P82ld57knhP0IcQfrYITDPXlNpMYGUrsG5TxuaWTjaeqDNQMBDNZkB8L0rBnwsY6JHuQ=="
},
"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=="
},
"MonoMod.Backports": {
"type": "Transitive",
"resolved": "1.0.0-prerelease.2",
"contentHash": "x7ap9fLFhLllTNorvWt8IuVP4NwH3+qfpO/AmoTM/Fcq11DgTyo0up+udsMFdw2nCpxh1//xmVydpac96ulqlg==",
"dependencies": {
"MonoMod.ILHelpers": "1.0.0-prerelease.2"
}
},
"MonoMod.Core": {
"type": "Transitive",
"resolved": "1.0.0-prerelease.2",
"contentHash": "nQYYvooFTMfH7KljHXg1eHCm5CpCmYgJTTdEMVgkhKOdfco/Gw9h/KYC1EXOMNjQdmi/hwcFP5PgF7W6XWVMRg==",
"dependencies": {
"Mono.Cecil": "0.11.4",
"MonoMod.Backports": "1.0.0-prerelease.2",
"MonoMod.ILHelpers": "1.0.0-prerelease.2",
"MonoMod.Utils": "25.0.0-prerelease.2"
}
},
"MonoMod.ILHelpers": {
"type": "Transitive",
"resolved": "1.0.0-prerelease.2",
"contentHash": "jB1JpcLGtKsWFIPItn/eQgmKwzPBKoDJnnBRDxWV3Ma4am6wPx8ynXXTwoTZOFi5gfHvkqK0RIu9MwJbwRCmow=="
},
"MonoMod.Utils": {
"type": "Transitive",
"resolved": "25.0.0-prerelease.2",
"contentHash": "8NWKe2Kc/CIt8BpK+DcZnc+23XP5+LG+nuUP8ELQ32qxad1JOBjLMRmCXLfxpk74z37XuBpTJUABa9pwPY2MXg==",
"dependencies": {
"Mono.Cecil": "0.11.4",
"MonoMod.Backports": "1.0.0-prerelease.2",
"MonoMod.ILHelpers": "1.0.0-prerelease.2"
}
},
"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=="
}
},
".NETFramework,Version=v4.8/win-x64": {
"IKVM": {
"type": "Direct",
"requested": "[8.7.1, )",
"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"
}
},
"Mono.Unix": {
"type": "Transitive",
"resolved": "7.1.0-final.1.21458.1",
"contentHash": "Rhxz4A7By8Q0wEgDqR+mioDsYXGrcYMYPiWE9bSaUKMpG8yAGArhetEQV5Ms6KhKCLdQTlPYLBKPZYoKbAvT/g=="
},
"System.Runtime.InteropServices.RuntimeInformation": {
"type": "Transitive",
"resolved": "4.3.0",
"contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw=="
}
}
}
}

View File

@@ -6,6 +6,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightPerms.Discord", "Light
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightPerms.TorchCommands", "LightPerms.TorchCommands\LightPerms.TorchCommands.csproj", "{8F9D910F-FFE6-4010-921F-5872ACF638BB}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightPerms.TorchCommands", "LightPerms.TorchCommands\LightPerms.TorchCommands.csproj", "{8F9D910F-FFE6-4010-921F-5872ACF638BB}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuckPerms.Torch", "LuckPerms.Torch\LuckPerms.Torch.csproj", "{2C069BB5-B110-4024-93B7-28C6965AD21F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuckPerms.Loader", "LuckPerms.Loader\LuckPerms.Loader.csproj", "{D1D4E971-39CE-482C-A56D-9448A77883BB}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -24,5 +28,13 @@ Global
{8F9D910F-FFE6-4010-921F-5872ACF638BB}.Debug|Any CPU.Build.0 = Debug|Any CPU {8F9D910F-FFE6-4010-921F-5872ACF638BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F9D910F-FFE6-4010-921F-5872ACF638BB}.Release|Any CPU.ActiveCfg = Release|Any CPU {8F9D910F-FFE6-4010-921F-5872ACF638BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F9D910F-FFE6-4010-921F-5872ACF638BB}.Release|Any CPU.Build.0 = Release|Any CPU {8F9D910F-FFE6-4010-921F-5872ACF638BB}.Release|Any CPU.Build.0 = Release|Any CPU
{2C069BB5-B110-4024-93B7-28C6965AD21F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C069BB5-B110-4024-93B7-28C6965AD21F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C069BB5-B110-4024-93B7-28C6965AD21F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C069BB5-B110-4024-93B7-28C6965AD21F}.Release|Any CPU.Build.0 = Release|Any CPU
{D1D4E971-39CE-482C-A56D-9448A77883BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1D4E971-39CE-482C-A56D-9448A77883BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1D4E971-39CE-482C-A56D-9448A77883BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1D4E971-39CE-482C-A56D-9448A77883BB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal