diff --git a/LuckPerms.Loader/LuckPerms.Loader.csproj b/LuckPerms.Loader/LuckPerms.Loader.csproj new file mode 100644 index 0000000..ce9e370 --- /dev/null +++ b/LuckPerms.Loader/LuckPerms.Loader.csproj @@ -0,0 +1,63 @@ + + + + net48 + 12 + enable + enable + true + true + true + + + + false + none + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + PreserveNewest + Always + + + + + + + + + + + + + + ..\LuckPerms.Torch\bin\$(Configuration)\$(TargetFramework)\win-x64\ + $(BaseIntermediateOutputPath)$(Configuration)\$(TargetFramework)\plugin.zip + + + + + + + + \ No newline at end of file diff --git a/LuckPerms.Loader/Plugin.cs b/LuckPerms.Loader/Plugin.cs new file mode 100644 index 0000000..051062e --- /dev/null +++ b/LuckPerms.Loader/Plugin.cs @@ -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._plugins.Remove(Manifest.Guid); + pluginManager._plugins.Add(Manifest.Guid, MainPluginInstance); + + MainPluginInstance.Init(torch); + + Log.Info("Injected successfully"); + } +} \ No newline at end of file diff --git a/LuckPerms.Loader/manifest.xml b/LuckPerms.Loader/manifest.xml new file mode 100644 index 0000000..dc273fa --- /dev/null +++ b/LuckPerms.Loader/manifest.xml @@ -0,0 +1,6 @@ + + + LuckPerms.Loader + 7E4B3CC8-64FA-416E-8910-AACDF2DA5E2C + v5.4.106 + \ No newline at end of file diff --git a/LuckPerms.Loader/packages.lock.json b/LuckPerms.Loader/packages.lock.json new file mode 100644 index 0000000..467e46a --- /dev/null +++ b/LuckPerms.Loader/packages.lock.json @@ -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" + } + } + } + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Extensions/CommandExtensions.cs b/LuckPerms.Torch/Extensions/CommandExtensions.cs new file mode 100644 index 0000000..d4644ef --- /dev/null +++ b/LuckPerms.Torch/Extensions/CommandExtensions.cs @@ -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()))}"; + } +} diff --git a/LuckPerms.Torch/Extensions/DelegateExtensions.cs b/LuckPerms.Torch/Extensions/DelegateExtensions.cs new file mode 100644 index 0000000..3142a38 --- /dev/null +++ b/LuckPerms.Torch/Extensions/DelegateExtensions.cs @@ -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(); + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Extensions/EnumerableExtensions.cs b/LuckPerms.Torch/Extensions/EnumerableExtensions.cs new file mode 100644 index 0000000..40857b4 --- /dev/null +++ b/LuckPerms.Torch/Extensions/EnumerableExtensions.cs @@ -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(this IEnumerable enumerable) + { + var collection = enumerable is IReadOnlyCollection readOnlyCollection ? new ArrayList(readOnlyCollection.Count) : new ArrayList(((IReadOnlyCollection)(enumerable = enumerable.ToArray())).Count); + + foreach (var t in enumerable) + { + collection.add(t); + } + + return collection; + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Extensions/IteratorExtensions.cs b/LuckPerms.Torch/Extensions/IteratorExtensions.cs new file mode 100644 index 0000000..6eac4cd --- /dev/null +++ b/LuckPerms.Torch/Extensions/IteratorExtensions.cs @@ -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 GetEnumerator(this Iterator iterator) => new(iterator); + + public static IteratorEnumerable AsEnumerable(this Iterator iterator) => new(iterator); + + public struct IteratorEnumerator(Iterator iterator) : IEnumerator + { + 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(Iterator iterator) : IEnumerable + { + public IteratorEnumerator GetEnumerator() => new(iterator); + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() => null!; + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Extensions/KeyedConfigurationExtensions.cs b/LuckPerms.Torch/Extensions/KeyedConfigurationExtensions.cs new file mode 100644 index 0000000..d305e86 --- /dev/null +++ b/LuckPerms.Torch/Extensions/KeyedConfigurationExtensions.cs @@ -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 + }; + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Extensions/StreamExtensions.cs b/LuckPerms.Torch/Extensions/StreamExtensions.cs new file mode 100644 index 0000000..a9f4cf3 --- /dev/null +++ b/LuckPerms.Torch/Extensions/StreamExtensions.cs @@ -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); + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Extensions/UUIDExtensions.cs b/LuckPerms.Torch/Extensions/UUIDExtensions.cs new file mode 100644 index 0000000..a92e8d5 --- /dev/null +++ b/LuckPerms.Torch/Extensions/UUIDExtensions.cs @@ -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); +} \ No newline at end of file diff --git a/LuckPerms.Torch/FodyWeavers.xml b/LuckPerms.Torch/FodyWeavers.xml new file mode 100644 index 0000000..d5abfed --- /dev/null +++ b/LuckPerms.Torch/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/Calculator/ConsoleProcessor.cs b/LuckPerms.Torch/Impl/Calculator/ConsoleProcessor.cs new file mode 100644 index 0000000..e15cb70 --- /dev/null +++ b/LuckPerms.Torch/Impl/Calculator/ConsoleProcessor.cs @@ -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; +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/Calculator/LpCalculatorFactory.cs b/LuckPerms.Torch/Impl/Calculator/LpCalculatorFactory.cs new file mode 100644 index 0000000..1dd001a --- /dev/null +++ b/LuckPerms.Torch/Impl/Calculator/LpCalculatorFactory.cs @@ -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); + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/CompatPatches/GeneratedEventClassPatch.cs b/LuckPerms.Torch/Impl/CompatPatches/GeneratedEventClassPatch.cs new file mode 100644 index 0000000..a5802f6 --- /dev/null +++ b/LuckPerms.Torch/Impl/CompatPatches/GeneratedEventClassPatch.cs @@ -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())!; + + private static readonly ConstructorInfo AbstractEventCtor = + typeof(AbstractEvent).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly, null, + new[] { typeof(net.luckperms.api.LuckPerms) }, Array.Empty())!; + + // [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())!; + // + // 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()) + .OrderBy(b => ((Param)b.GetCustomAttribute()!).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; + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/CompatPatches/LoaderCheckPatch.cs b/LuckPerms.Torch/Impl/CompatPatches/LoaderCheckPatch.cs new file mode 100644 index 0000000..bd05434 --- /dev/null +++ b/LuckPerms.Torch/Impl/CompatPatches/LoaderCheckPatch.cs @@ -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; +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/Listeners/LpConnectionListener.cs b/LuckPerms.Torch/Impl/Listeners/LpConnectionListener.cs new file mode 100644 index 0000000..f5e3311 --- /dev/null +++ b/LuckPerms.Torch/Impl/Listeners/LpConnectionListener.cs @@ -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() + { + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/LpClassPathAppender.cs b/LuckPerms.Torch/Impl/LpClassPathAppender.cs new file mode 100644 index 0000000..8bf546d --- /dev/null +++ b/LuckPerms.Torch/Impl/LpClassPathAppender.cs @@ -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() + { + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/LpCommandManager.cs b/LuckPerms.Torch/Impl/LpCommandManager.cs new file mode 100644 index 0000000..483a188 --- /dev/null +++ b/LuckPerms.Torch/Impl/LpCommandManager.cs @@ -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() + { + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/LpConfigurationAdapter.cs b/LuckPerms.Torch/Impl/LpConfigurationAdapter.cs new file mode 100644 index 0000000..e7254e2 --- /dev/null +++ b/LuckPerms.Torch/Impl/LpConfigurationAdapter.cs @@ -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(); + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/LpContextManager.cs b/LuckPerms.Torch/Impl/LpContextManager.cs new file mode 100644 index 0000000..f10da3b --- /dev/null +++ b/LuckPerms.Torch/Impl/LpContextManager.cs @@ -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() + { + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/LpDependencyManager.cs b/LuckPerms.Torch/Impl/LpDependencyManager.cs new file mode 100644 index 0000000..287ea0c --- /dev/null +++ b/LuckPerms.Torch/Impl/LpDependencyManager.cs @@ -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() + { + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/LpEventBus.cs b/LuckPerms.Torch/Impl/LpEventBus.cs new file mode 100644 index 0000000..ff9d303 --- /dev/null +++ b/LuckPerms.Torch/Impl/LpEventBus.cs @@ -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() + .FirstOrDefault(b => b.GetType().Assembly == obj.GetType().Assembly) ?? + throw new InvalidOperationException("plugin not found"); + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/LpSchedulerAdapter.cs b/LuckPerms.Torch/Impl/LpSchedulerAdapter.cs new file mode 100644 index 0000000..8468a53 --- /dev/null +++ b/LuckPerms.Torch/Impl/LpSchedulerAdapter.cs @@ -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); + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/LpSenderFactory.cs b/LuckPerms.Torch/Impl/LpSenderFactory.cs new file mode 100644 index 0000000..fc7ac26 --- /dev/null +++ b/LuckPerms.Torch/Impl/LpSenderFactory.cs @@ -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; + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/LpTorchBootstrap.cs b/LuckPerms.Torch/Impl/LpTorchBootstrap.cs new file mode 100644 index 0000000..3f22f8b --- /dev/null +++ b/LuckPerms.Torch/Impl/LpTorchBootstrap.cs @@ -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().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().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().Players.Select(b => b.Key.GetUuid()) + .ToCollection() ?? Collections.EMPTY_LIST; + } + + public CountDownLatch getLoadLatch() => LoadLatch; + + public CountDownLatch getEnableLatch() => EnableLatch; + + public string getServerName() => _torch.Managers.GetManager().DedicatedConfig.ServerName; + + public Optional getPlayer(UUID uuid) => _torch.CurrentSession?.Managers.GetManager().Players.TryGetValue(uuid.GetSteamId(), out var player) ?? false + ? Optional.of(player) + : Optional.empty(); +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/LpTorchPlugin.cs b/LuckPerms.Torch/Impl/LpTorchPlugin.cs new file mode 100644 index 0000000..9b6b78e --- /dev/null +++ b/LuckPerms.Torch/Impl/LpTorchPlugin.cs @@ -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().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().AddFactory(_ => _commandManager); + } + + protected override void setupManagers() + { + _userManager = new(this); + _groupManager = new(this); + _trackManager = new(this); + _connectionListener = new(this); + torch.Managers.GetManager().AddFactory(_ => _connectionListener); + } + + protected override CalculatorFactory provideCalculatorFactory() => new LpCalculatorFactory(this); + + protected override void setupContextManager() + { + _contextManager = new LpContextManager(this); + torch.Managers.GetManager().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().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(); + 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(); +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/Messaging/LpMessagingFactory.cs b/LuckPerms.Torch/Impl/Messaging/LpMessagingFactory.cs new file mode 100644 index 0000000..6f02a64 --- /dev/null +++ b/LuckPerms.Torch/Impl/Messaging/LpMessagingFactory.cs @@ -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 + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Impl/NLogPluginLogger.cs b/LuckPerms.Torch/Impl/NLogPluginLogger.cs new file mode 100644 index 0000000..f59f699 --- /dev/null +++ b/LuckPerms.Torch/Impl/NLogPluginLogger.cs @@ -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); +} \ No newline at end of file diff --git a/LuckPerms.Torch/LuckPerms.Torch.csproj b/LuckPerms.Torch/LuckPerms.Torch.csproj new file mode 100644 index 0000000..ba5778f --- /dev/null +++ b/LuckPerms.Torch/LuckPerms.Torch.csproj @@ -0,0 +1,258 @@ + + + + net48 + 12 + enable + true + true + true + win-x64 + + + + false + none + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + $(ProjectDir)libs\ + $(LibsPath)api-5.4.jar + $(LibsPath)common-5.4-SNAPSHOT.jar + + $(LibsPath)config-1.4.0.jar + $(LibsPath)toml4j-0.7.2.jar + $(LibsPath)configurate-toml-3.7.jar + $(LibsPath)configurate-gson-3.7.2.jar + $(LibsPath)configurate-hocon-3.7.2.jar + $(LibsPath)configurate-core-3.7.2.jar + $(LibsPath)configurate-yaml-3.7.2.jar + $(LibsPath)snakeyaml-1.26.jar + $(LibsPath)checker-qual-3.12.0.jar + + $(LibsPath)adventure-text-serializer-plain-4.11.0.jar + $(LibsPath)adventure-text-serializer-legacy-4.11.0.jar + $(LibsPath)adventure-text-minimessage-4.11.0.jar + $(LibsPath)adventure-api-4.11.0.jar + $(LibsPath)adventure-key-4.11.0.jar + $(LibsPath)examination-api-1.3.0.jar + $(LibsPath)examination-string-1.3.0.jar + + $(LibsPath)annotations-23.0.0.jar + $(LibsPath)guava-19.0.jar + $(LibsPath)error_prone_annotations-2.0.2.jar + $(LibsPath)animal-sniffer-annotations-1.14.jar + $(LibsPath)j2objc-annotations-0.1.jar + $(LibsPath)jsr305-1.3.9.jar + $(LibsPath)gson-2.7.jar + + $(LibsPath)brigadier-1.0.18.jar + + $(LibsPath)event-api-3.0.0.jar + + $(LibsPath)slf4j-api-1.7.30.jar + $(LibsPath)log4j-api-2.14.0.jar + + $(LibsPath)caffeine-2.9.0.jar + + $(LibsPath)okio-1.17.5.jar + $(LibsPath)okhttp-3.14.9.jar + $(LibsPath)conscrypt-openjdk-uber-2.0.0.jar + + $(LibsPath)byte-buddy-1.10.22.jar + + $(LibsPath)eddsa-0.3.0.jar + $(LibsPath)jnats-2.16.4.jar + + $(LibsPath)HikariCP-4.0.3.jar + + $(LibsPath)json-20230227.jar + $(LibsPath)pool2-2.11.1.jar + $(LibsPath)jedis-4.4.3.jar + + $(LibsPath)amqp-client-5.12.0.jar + + $(LibsPath)bson-4.5.0.jar + $(LibsPath)mongodb-driver-core-4.5.0.jar + $(LibsPath)mongodb-driver-sync-4.5.0.jar + $(LibsPath)mongodb-driver-legacy-4.5.0.jar + + $(LibsPath)postgresql-42.6.0.jar + + $(LibsPath)h2-2.1.214.jar + + $(LibsPath)mariadb-java-client-3.3.0.jar + $(LibsPath)waffle-jna-3.3.0.jar + $(LibsPath)jcl-over-slf4j-2.0.7.jar + $(LibsPath)jna-platform-5.13.0.jar + $(LibsPath)jna-5.13.0.jar + + $(LibsPath)mysql-connector-j-8.0.33.jar + $(LibsPath)protobuf-java-3.21.9.jar + + + + + $(ProtobufPath) + + + + + $(WaffleJnaPath);$(Slf4jApiPath) + + + $(Slf4jApiPath);$(JclOverSlf4jPath);$(CheckerQualPath);$(JnaPlatformPath);$(JnaPath);$(CaffeinePath) + + + $(Slf4jApiPath) + + + $(JnaPath) + + + + + + + + $(Slf4jApiPath);$(BsonPath);$(MongoDriverCorePath);$(MongoDriverSyncPath) + + + $(Slf4jApiPath);$(BsonPath);$(MongoDriverCorePath) + + + $(Slf4jApiPath);$(BsonPath) + + + $(Slf4jApiPath) + + + + $(Slf4jApiPath) + + + + $(Slf4jApiPath);$(CommonsPoolPath);$(JsonPath);$(GsonPath) + + + 2023.02.27.0 + + + + + $(Slf4jApiPath) + + + + $(EddsaPath) + + + + + + + $(OkioPath);$(ConscryptPath) + + + $(AnimalSnifferAnnotationsPath) + + + + + $(ErrorProneAnnotationsPath);$(CheckerQualPath) + + + + + + + $(GuavaPath);$(CheckerQualPath) + + + + + + + + + + + $(ErrorProneAnnotationsPath);$(AnimalSnifferAnnotationsPath);$(J2objcAnnotationsPath);$(Jsr305Path) + + + + + $(AnnotationsPath) + + + + $(ExaminationApiPath);$(ExaminationStringPath);$(AnnotationsPath) + + + $(ExaminationApiPath);$(ExaminationStringPath);$(AdventureKeyPath);$(AnnotationsPath) + + + $(AdventureApiPath);$(AnnotationsPath);$(ExaminationApiPath) + + + $(AdventureApiPath);$(ExaminationApiPath) + + + $(AdventureApiPath);$(ExaminationApiPath) + + + + $(GsonPath) + + + + $(ConfigurateCorePath);$(Toml4jPath);$(GuavaPath) + + + $(ConfigurateCorePath);$(GsonPath) + + + $(ConfigurateCorePath);$(TypesafeConfigPath) + + + $(CheckerQualPath);$(GuavaPath) + + + $(ConfigurateCorePath);$(SnakeYamlPath) + + + + + + + $(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) + + + + + + PreserveNewest + Always + + + + + + + + + + + + + \ No newline at end of file diff --git a/LuckPerms.Torch/PlatformApi/LpPlayerModel.cs b/LuckPerms.Torch/PlatformApi/LpPlayerModel.cs new file mode 100644 index 0000000..59b1db3 --- /dev/null +++ b/LuckPerms.Torch/PlatformApi/LpPlayerModel.cs @@ -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} }}"; +} \ No newline at end of file diff --git a/LuckPerms.Torch/PlatformHooks/CommandPermissionsPatch.cs b/LuckPerms.Torch/PlatformHooks/CommandPermissionsPatch.cs new file mode 100644 index 0000000..645373f --- /dev/null +++ b/LuckPerms.Torch/PlatformHooks/CommandPermissionsPatch.cs @@ -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 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.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.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() + .Players[steamId]; + + var result = player.HasPermission(command.GetPermissionString()); + + __result = result.asBoolean(); + return false; + } + + private static IEnumerable Transpiler(IEnumerable 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; + } + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/PlatformHooks/CommandPrefixPatch.cs b/LuckPerms.Torch/PlatformHooks/CommandPrefixPatch.cs new file mode 100644 index 0000000..259b81a --- /dev/null +++ b/LuckPerms.Torch/PlatformHooks/CommandPrefixPatch.cs @@ -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 HandleCommandTranspiler(IEnumerable instructions) + { + var list = instructions.ToList(); + + var index = list.FindIndex(b => + b.OpCode == OpCodes.Call && b.Operand is MsilOperandInline.MsilOperandReflected { 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; +} \ No newline at end of file diff --git a/LuckPerms.Torch/PlatformHooks/PlayerPatch.cs b/LuckPerms.Torch/PlatformHooks/PlayerPatch.cs new file mode 100644 index 0000000..ada47c0 --- /dev/null +++ b/LuckPerms.Torch/PlatformHooks/PlayerPatch.cs @@ -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 Transpiler(IEnumerable 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; + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Plugin.cs b/LuckPerms.Torch/Plugin.cs new file mode 100644 index 0000000..ccb85da --- /dev/null +++ b/LuckPerms.Torch/Plugin.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/LuckPerms.Torch/Resources/config.yml b/LuckPerms.Torch/Resources/config.yml new file mode 100644 index 0000000..ef492df --- /dev/null +++ b/LuckPerms.Torch/Resources/config.yml @@ -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 ' +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_ Selects the value with the highest weight, but only if the +# value was inherited from a group on the given track. +# +# => lowest_on_track_ Same as above, except takes the value with the lowest weight. +# +# => highest_not_on_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_ Same as above, except takes the value with the lowest weight. +# +# => highest_from_group_ Selects the value with the highest weight, but only if the +# value was inherited from the given group. +# +# => lowest_from_group_ Same as above, except takes the value with the lowest weight. +# +# => highest_not_from_group_ Selects the value with the highest weight, but only if the +# value was not inherited from the given group. +# +# => lowest_not_from_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 diff --git a/LuckPerms.Torch/Resources/schema/h2.sql b/LuckPerms.Torch/Resources/schema/h2.sql new file mode 100644 index 0000000..e3d6b62 --- /dev/null +++ b/LuckPerms.Torch/Resources/schema/h2.sql @@ -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`) +); diff --git a/LuckPerms.Torch/Resources/schema/mariadb.sql b/LuckPerms.Torch/Resources/schema/mariadb.sql new file mode 100644 index 0000000..47eb753 --- /dev/null +++ b/LuckPerms.Torch/Resources/schema/mariadb.sql @@ -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; diff --git a/LuckPerms.Torch/Resources/schema/mysql.sql b/LuckPerms.Torch/Resources/schema/mysql.sql new file mode 100644 index 0000000..5166675 --- /dev/null +++ b/LuckPerms.Torch/Resources/schema/mysql.sql @@ -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; diff --git a/LuckPerms.Torch/Resources/schema/postgresql.sql b/LuckPerms.Torch/Resources/schema/postgresql.sql new file mode 100644 index 0000000..b0e9395 --- /dev/null +++ b/LuckPerms.Torch/Resources/schema/postgresql.sql @@ -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 +); diff --git a/LuckPerms.Torch/Resources/schema/sqlite.sql b/LuckPerms.Torch/Resources/schema/sqlite.sql new file mode 100644 index 0000000..d6d49d2 --- /dev/null +++ b/LuckPerms.Torch/Resources/schema/sqlite.sql @@ -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`) +); diff --git a/LuckPerms.Torch/libs/HikariCP-4.0.3.jar b/LuckPerms.Torch/libs/HikariCP-4.0.3.jar new file mode 100644 index 0000000..f328920 Binary files /dev/null and b/LuckPerms.Torch/libs/HikariCP-4.0.3.jar differ diff --git a/LuckPerms.Torch/libs/adventure-api-4.11.0.jar b/LuckPerms.Torch/libs/adventure-api-4.11.0.jar new file mode 100644 index 0000000..e400b9d Binary files /dev/null and b/LuckPerms.Torch/libs/adventure-api-4.11.0.jar differ diff --git a/LuckPerms.Torch/libs/adventure-key-4.11.0.jar b/LuckPerms.Torch/libs/adventure-key-4.11.0.jar new file mode 100644 index 0000000..4c8493b Binary files /dev/null and b/LuckPerms.Torch/libs/adventure-key-4.11.0.jar differ diff --git a/LuckPerms.Torch/libs/adventure-text-minimessage-4.11.0.jar b/LuckPerms.Torch/libs/adventure-text-minimessage-4.11.0.jar new file mode 100644 index 0000000..da20229 Binary files /dev/null and b/LuckPerms.Torch/libs/adventure-text-minimessage-4.11.0.jar differ diff --git a/LuckPerms.Torch/libs/adventure-text-serializer-legacy-4.11.0.jar b/LuckPerms.Torch/libs/adventure-text-serializer-legacy-4.11.0.jar new file mode 100644 index 0000000..23e88a5 Binary files /dev/null and b/LuckPerms.Torch/libs/adventure-text-serializer-legacy-4.11.0.jar differ diff --git a/LuckPerms.Torch/libs/adventure-text-serializer-plain-4.11.0.jar b/LuckPerms.Torch/libs/adventure-text-serializer-plain-4.11.0.jar new file mode 100644 index 0000000..82ffc4b Binary files /dev/null and b/LuckPerms.Torch/libs/adventure-text-serializer-plain-4.11.0.jar differ diff --git a/LuckPerms.Torch/libs/amqp-client-5.12.0.jar b/LuckPerms.Torch/libs/amqp-client-5.12.0.jar new file mode 100644 index 0000000..9874b5f Binary files /dev/null and b/LuckPerms.Torch/libs/amqp-client-5.12.0.jar differ diff --git a/LuckPerms.Torch/libs/animal-sniffer-annotations-1.14.jar b/LuckPerms.Torch/libs/animal-sniffer-annotations-1.14.jar new file mode 100644 index 0000000..fb76acf Binary files /dev/null and b/LuckPerms.Torch/libs/animal-sniffer-annotations-1.14.jar differ diff --git a/LuckPerms.Torch/libs/annotations-23.0.0.jar b/LuckPerms.Torch/libs/annotations-23.0.0.jar new file mode 100644 index 0000000..5119f5e Binary files /dev/null and b/LuckPerms.Torch/libs/annotations-23.0.0.jar differ diff --git a/LuckPerms.Torch/libs/api-5.4.jar b/LuckPerms.Torch/libs/api-5.4.jar new file mode 100644 index 0000000..a69acaf Binary files /dev/null and b/LuckPerms.Torch/libs/api-5.4.jar differ diff --git a/LuckPerms.Torch/libs/brigadier-1.0.18.jar b/LuckPerms.Torch/libs/brigadier-1.0.18.jar new file mode 100644 index 0000000..e55d405 Binary files /dev/null and b/LuckPerms.Torch/libs/brigadier-1.0.18.jar differ diff --git a/LuckPerms.Torch/libs/bson-4.5.0.jar b/LuckPerms.Torch/libs/bson-4.5.0.jar new file mode 100644 index 0000000..782f0a8 Binary files /dev/null and b/LuckPerms.Torch/libs/bson-4.5.0.jar differ diff --git a/LuckPerms.Torch/libs/byte-buddy-1.10.22.jar b/LuckPerms.Torch/libs/byte-buddy-1.10.22.jar new file mode 100644 index 0000000..688da7e Binary files /dev/null and b/LuckPerms.Torch/libs/byte-buddy-1.10.22.jar differ diff --git a/LuckPerms.Torch/libs/caffeine-2.9.0.jar b/LuckPerms.Torch/libs/caffeine-2.9.0.jar new file mode 100644 index 0000000..9d9f795 Binary files /dev/null and b/LuckPerms.Torch/libs/caffeine-2.9.0.jar differ diff --git a/LuckPerms.Torch/libs/checker-qual-3.12.0.jar b/LuckPerms.Torch/libs/checker-qual-3.12.0.jar new file mode 100644 index 0000000..e9eed80 Binary files /dev/null and b/LuckPerms.Torch/libs/checker-qual-3.12.0.jar differ diff --git a/LuckPerms.Torch/libs/common-5.4-SNAPSHOT.jar b/LuckPerms.Torch/libs/common-5.4-SNAPSHOT.jar new file mode 100644 index 0000000..d5d8121 Binary files /dev/null and b/LuckPerms.Torch/libs/common-5.4-SNAPSHOT.jar differ diff --git a/LuckPerms.Torch/libs/config-1.4.0.jar b/LuckPerms.Torch/libs/config-1.4.0.jar new file mode 100644 index 0000000..5030c9f Binary files /dev/null and b/LuckPerms.Torch/libs/config-1.4.0.jar differ diff --git a/LuckPerms.Torch/libs/configurate-core-3.7.2.jar b/LuckPerms.Torch/libs/configurate-core-3.7.2.jar new file mode 100644 index 0000000..1ed08cd Binary files /dev/null and b/LuckPerms.Torch/libs/configurate-core-3.7.2.jar differ diff --git a/LuckPerms.Torch/libs/configurate-gson-3.7.2.jar b/LuckPerms.Torch/libs/configurate-gson-3.7.2.jar new file mode 100644 index 0000000..6ec5ad9 Binary files /dev/null and b/LuckPerms.Torch/libs/configurate-gson-3.7.2.jar differ diff --git a/LuckPerms.Torch/libs/configurate-hocon-3.7.2.jar b/LuckPerms.Torch/libs/configurate-hocon-3.7.2.jar new file mode 100644 index 0000000..4da53c7 Binary files /dev/null and b/LuckPerms.Torch/libs/configurate-hocon-3.7.2.jar differ diff --git a/LuckPerms.Torch/libs/configurate-toml-3.7.jar b/LuckPerms.Torch/libs/configurate-toml-3.7.jar new file mode 100644 index 0000000..f7ca51b Binary files /dev/null and b/LuckPerms.Torch/libs/configurate-toml-3.7.jar differ diff --git a/LuckPerms.Torch/libs/configurate-yaml-3.7.2.jar b/LuckPerms.Torch/libs/configurate-yaml-3.7.2.jar new file mode 100644 index 0000000..f2543f2 Binary files /dev/null and b/LuckPerms.Torch/libs/configurate-yaml-3.7.2.jar differ diff --git a/LuckPerms.Torch/libs/conscrypt-openjdk-uber-2.0.0.jar b/LuckPerms.Torch/libs/conscrypt-openjdk-uber-2.0.0.jar new file mode 100644 index 0000000..0339297 Binary files /dev/null and b/LuckPerms.Torch/libs/conscrypt-openjdk-uber-2.0.0.jar differ diff --git a/LuckPerms.Torch/libs/eddsa-0.3.0.jar b/LuckPerms.Torch/libs/eddsa-0.3.0.jar new file mode 100644 index 0000000..31a271d Binary files /dev/null and b/LuckPerms.Torch/libs/eddsa-0.3.0.jar differ diff --git a/LuckPerms.Torch/libs/error_prone_annotations-2.0.2.jar b/LuckPerms.Torch/libs/error_prone_annotations-2.0.2.jar new file mode 100644 index 0000000..bee8eff Binary files /dev/null and b/LuckPerms.Torch/libs/error_prone_annotations-2.0.2.jar differ diff --git a/LuckPerms.Torch/libs/event-api-3.0.0.jar b/LuckPerms.Torch/libs/event-api-3.0.0.jar new file mode 100644 index 0000000..b768b86 Binary files /dev/null and b/LuckPerms.Torch/libs/event-api-3.0.0.jar differ diff --git a/LuckPerms.Torch/libs/examination-api-1.3.0.jar b/LuckPerms.Torch/libs/examination-api-1.3.0.jar new file mode 100644 index 0000000..8021db0 Binary files /dev/null and b/LuckPerms.Torch/libs/examination-api-1.3.0.jar differ diff --git a/LuckPerms.Torch/libs/examination-string-1.3.0.jar b/LuckPerms.Torch/libs/examination-string-1.3.0.jar new file mode 100644 index 0000000..0d3587e Binary files /dev/null and b/LuckPerms.Torch/libs/examination-string-1.3.0.jar differ diff --git a/LuckPerms.Torch/libs/gson-2.7.jar b/LuckPerms.Torch/libs/gson-2.7.jar new file mode 100644 index 0000000..be5b59b Binary files /dev/null and b/LuckPerms.Torch/libs/gson-2.7.jar differ diff --git a/LuckPerms.Torch/libs/guava-19.0.jar b/LuckPerms.Torch/libs/guava-19.0.jar new file mode 100644 index 0000000..b175ca8 Binary files /dev/null and b/LuckPerms.Torch/libs/guava-19.0.jar differ diff --git a/LuckPerms.Torch/libs/h2-2.1.214.jar b/LuckPerms.Torch/libs/h2-2.1.214.jar new file mode 100644 index 0000000..e8e3efc Binary files /dev/null and b/LuckPerms.Torch/libs/h2-2.1.214.jar differ diff --git a/LuckPerms.Torch/libs/j2objc-annotations-0.1.jar b/LuckPerms.Torch/libs/j2objc-annotations-0.1.jar new file mode 100644 index 0000000..1403a52 Binary files /dev/null and b/LuckPerms.Torch/libs/j2objc-annotations-0.1.jar differ diff --git a/LuckPerms.Torch/libs/jcl-over-slf4j-2.0.7.jar b/LuckPerms.Torch/libs/jcl-over-slf4j-2.0.7.jar new file mode 100644 index 0000000..1552378 Binary files /dev/null and b/LuckPerms.Torch/libs/jcl-over-slf4j-2.0.7.jar differ diff --git a/LuckPerms.Torch/libs/jedis-4.4.3.jar b/LuckPerms.Torch/libs/jedis-4.4.3.jar new file mode 100644 index 0000000..45d4a86 Binary files /dev/null and b/LuckPerms.Torch/libs/jedis-4.4.3.jar differ diff --git a/LuckPerms.Torch/libs/jna-5.13.0.jar b/LuckPerms.Torch/libs/jna-5.13.0.jar new file mode 100644 index 0000000..3d49c81 Binary files /dev/null and b/LuckPerms.Torch/libs/jna-5.13.0.jar differ diff --git a/LuckPerms.Torch/libs/jna-platform-5.13.0.jar b/LuckPerms.Torch/libs/jna-platform-5.13.0.jar new file mode 100644 index 0000000..816a567 Binary files /dev/null and b/LuckPerms.Torch/libs/jna-platform-5.13.0.jar differ diff --git a/LuckPerms.Torch/libs/jnats-2.16.4.jar b/LuckPerms.Torch/libs/jnats-2.16.4.jar new file mode 100644 index 0000000..31cb559 Binary files /dev/null and b/LuckPerms.Torch/libs/jnats-2.16.4.jar differ diff --git a/LuckPerms.Torch/libs/json-20230227.jar b/LuckPerms.Torch/libs/json-20230227.jar new file mode 100644 index 0000000..abdb16b Binary files /dev/null and b/LuckPerms.Torch/libs/json-20230227.jar differ diff --git a/LuckPerms.Torch/libs/jsr305-1.3.9.jar b/LuckPerms.Torch/libs/jsr305-1.3.9.jar new file mode 100644 index 0000000..a9afc66 Binary files /dev/null and b/LuckPerms.Torch/libs/jsr305-1.3.9.jar differ diff --git a/LuckPerms.Torch/libs/log4j-api-2.14.0.jar b/LuckPerms.Torch/libs/log4j-api-2.14.0.jar new file mode 100644 index 0000000..35956e7 Binary files /dev/null and b/LuckPerms.Torch/libs/log4j-api-2.14.0.jar differ diff --git a/LuckPerms.Torch/libs/mariadb-java-client-3.3.0.jar b/LuckPerms.Torch/libs/mariadb-java-client-3.3.0.jar new file mode 100644 index 0000000..bcb8758 Binary files /dev/null and b/LuckPerms.Torch/libs/mariadb-java-client-3.3.0.jar differ diff --git a/LuckPerms.Torch/libs/mongodb-driver-core-4.5.0.jar b/LuckPerms.Torch/libs/mongodb-driver-core-4.5.0.jar new file mode 100644 index 0000000..9d31684 Binary files /dev/null and b/LuckPerms.Torch/libs/mongodb-driver-core-4.5.0.jar differ diff --git a/LuckPerms.Torch/libs/mongodb-driver-legacy-4.5.0.jar b/LuckPerms.Torch/libs/mongodb-driver-legacy-4.5.0.jar new file mode 100644 index 0000000..429e348 Binary files /dev/null and b/LuckPerms.Torch/libs/mongodb-driver-legacy-4.5.0.jar differ diff --git a/LuckPerms.Torch/libs/mongodb-driver-sync-4.5.0.jar b/LuckPerms.Torch/libs/mongodb-driver-sync-4.5.0.jar new file mode 100644 index 0000000..3dccada Binary files /dev/null and b/LuckPerms.Torch/libs/mongodb-driver-sync-4.5.0.jar differ diff --git a/LuckPerms.Torch/libs/mysql-connector-j-8.0.33.jar b/LuckPerms.Torch/libs/mysql-connector-j-8.0.33.jar new file mode 100644 index 0000000..3f741f5 Binary files /dev/null and b/LuckPerms.Torch/libs/mysql-connector-j-8.0.33.jar differ diff --git a/LuckPerms.Torch/libs/okhttp-3.14.9.jar b/LuckPerms.Torch/libs/okhttp-3.14.9.jar new file mode 100644 index 0000000..52c046c Binary files /dev/null and b/LuckPerms.Torch/libs/okhttp-3.14.9.jar differ diff --git a/LuckPerms.Torch/libs/okio-1.17.5.jar b/LuckPerms.Torch/libs/okio-1.17.5.jar new file mode 100644 index 0000000..fb3ddd9 Binary files /dev/null and b/LuckPerms.Torch/libs/okio-1.17.5.jar differ diff --git a/LuckPerms.Torch/libs/pool2-2.11.1.jar b/LuckPerms.Torch/libs/pool2-2.11.1.jar new file mode 100644 index 0000000..8da8a82 Binary files /dev/null and b/LuckPerms.Torch/libs/pool2-2.11.1.jar differ diff --git a/LuckPerms.Torch/libs/postgresql-42.6.0.jar b/LuckPerms.Torch/libs/postgresql-42.6.0.jar new file mode 100644 index 0000000..02f902a Binary files /dev/null and b/LuckPerms.Torch/libs/postgresql-42.6.0.jar differ diff --git a/LuckPerms.Torch/libs/protobuf-java-3.21.9.jar b/LuckPerms.Torch/libs/protobuf-java-3.21.9.jar new file mode 100644 index 0000000..c4fd860 Binary files /dev/null and b/LuckPerms.Torch/libs/protobuf-java-3.21.9.jar differ diff --git a/LuckPerms.Torch/libs/slf4j-api-1.7.30.jar b/LuckPerms.Torch/libs/slf4j-api-1.7.30.jar new file mode 100644 index 0000000..29ac26f Binary files /dev/null and b/LuckPerms.Torch/libs/slf4j-api-1.7.30.jar differ diff --git a/LuckPerms.Torch/libs/snakeyaml-1.26.jar b/LuckPerms.Torch/libs/snakeyaml-1.26.jar new file mode 100644 index 0000000..8f301fd Binary files /dev/null and b/LuckPerms.Torch/libs/snakeyaml-1.26.jar differ diff --git a/LuckPerms.Torch/libs/toml4j-0.7.2.jar b/LuckPerms.Torch/libs/toml4j-0.7.2.jar new file mode 100644 index 0000000..71444ec Binary files /dev/null and b/LuckPerms.Torch/libs/toml4j-0.7.2.jar differ diff --git a/LuckPerms.Torch/libs/waffle-jna-3.3.0.jar b/LuckPerms.Torch/libs/waffle-jna-3.3.0.jar new file mode 100644 index 0000000..f09b874 Binary files /dev/null and b/LuckPerms.Torch/libs/waffle-jna-3.3.0.jar differ diff --git a/LuckPerms.Torch/manifest.xml b/LuckPerms.Torch/manifest.xml new file mode 100644 index 0000000..fbdecf1 --- /dev/null +++ b/LuckPerms.Torch/manifest.xml @@ -0,0 +1,6 @@ + + + LuckPerms.Torch + 7E4B3CC8-64FA-416E-8910-AACDF2DA5E2C + v5.4.106 + \ No newline at end of file diff --git a/LuckPerms.Torch/packages.lock.json b/LuckPerms.Torch/packages.lock.json new file mode 100644 index 0000000..f7a9f3f --- /dev/null +++ b/LuckPerms.Torch/packages.lock.json @@ -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==" + } + } + } +} \ No newline at end of file diff --git a/LightPerms.sln b/TorchPlugins.sln similarity index 64% rename from LightPerms.sln rename to TorchPlugins.sln index c6b75ee..1646ca6 100644 --- a/LightPerms.sln +++ b/TorchPlugins.sln @@ -6,6 +6,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightPerms.Discord", "Light EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightPerms.TorchCommands", "LightPerms.TorchCommands\LightPerms.TorchCommands.csproj", "{8F9D910F-FFE6-4010-921F-5872ACF638BB}" 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 GlobalSection(SolutionConfigurationPlatforms) = preSolution 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}.Release|Any CPU.ActiveCfg = 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 EndGlobal