initial
This commit is contained in:
8
LightPerms/Config.cs
Normal file
8
LightPerms/Config.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Torch;
|
||||
|
||||
namespace LightPerms;
|
||||
|
||||
public class Config : ViewModel
|
||||
{
|
||||
|
||||
}
|
3
LightPerms/FodyWeavers.xml
Normal file
3
LightPerms/FodyWeavers.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<PropertyChanged />
|
||||
</Weavers>
|
47
LightPerms/Group.cs
Normal file
47
LightPerms/Group.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using PetaPoco;
|
||||
namespace LightPerms;
|
||||
|
||||
[TableName("groups")]
|
||||
[PrimaryKey(nameof(Uid), AutoIncrement = true)]
|
||||
public class Group
|
||||
{
|
||||
[Column]
|
||||
public long Uid { get; set; }
|
||||
[Column]
|
||||
public string Name { get; set; } = "group";
|
||||
|
||||
internal const string CreateTableSql = "create table if not exists groups (uid INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL);";
|
||||
}
|
||||
|
||||
[TableName("permissions")]
|
||||
[PrimaryKey(nameof(Uid), AutoIncrement = true)]
|
||||
public class Permission
|
||||
{
|
||||
[Column]
|
||||
public long Uid { get; set; }
|
||||
[Column]
|
||||
public string Value { get; set; } = "*";
|
||||
[Column]
|
||||
public long GroupUid { get; set; }
|
||||
|
||||
internal const string CreateTableSql = "create table if not exists permissions (uid INTEGER PRIMARY KEY AUTOINCREMENT, value TEXT NOT NULL, group_uid INTEGER, FOREIGN KEY(group_uid) REFERENCES groups(uid));";
|
||||
}
|
||||
|
||||
[TableName("group_members")]
|
||||
[PrimaryKey(nameof(Uid), AutoIncrement = true)]
|
||||
public class GroupMember
|
||||
{
|
||||
[Column]
|
||||
public long Uid { get; set; }
|
||||
|
||||
[Column]
|
||||
public string Name { get; set; } = "no name";
|
||||
|
||||
[Column]
|
||||
public string ClientId { get; set; } = "0";
|
||||
|
||||
[Column]
|
||||
public long GroupUid { get; set; }
|
||||
|
||||
internal const string CreateTableSql = "create table if not exists group_members (uid INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, client_id INTEGER, group_uid INTEGER, FOREIGN KEY(group_uid) REFERENCES groups(uid));";
|
||||
}
|
88
LightPerms/LightPerms.csproj
Normal file
88
LightPerms/LightPerms.csproj
Normal file
@@ -0,0 +1,88 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>10</LangVersion>
|
||||
<UseWpf>true</UseWpf>
|
||||
<TorchDir>$(SolutionDir)TorchBinaries\</TorchDir>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DebugType>none</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c">
|
||||
<HintPath>$(TorchDir)NLog.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Sandbox.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>$(TorchDir)DedicatedServer64\Sandbox.Common.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Sandbox.Game, Version=0.1.1.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>$(TorchDir)DedicatedServer64\Sandbox.Game.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Sandbox.Graphics, Version=0.1.1.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>$(TorchDir)DedicatedServer64\Sandbox.Graphics.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="Torch">
|
||||
<HintPath>$(TorchDir)Torch.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Torch.API">
|
||||
<HintPath>$(TorchDir)Torch.API.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Torch.Server">
|
||||
<HintPath>$(TorchDir)Torch.Server.exe</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>$(TorchDir)DedicatedServer64\VRage.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Game, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>$(TorchDir)DedicatedServer64\VRage.Game.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Input, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>$(TorchDir)DedicatedServer64\VRage.Input.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Library, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>$(TorchDir)DedicatedServer64\VRage.Library.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Math, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>$(TorchDir)DedicatedServer64\VRage.Math.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="VRage.Network, Version=1.0.53.0, Culture=neutral, PublicKeyToken=null">
|
||||
<HintPath>$(TorchDir)DedicatedServer64\VRage.Network.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="heh" Version="1.0.4" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="4.0.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="manifest.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyToTorch" AfterTargets="Build">
|
||||
<ZipDirectory DestinationFile="$(TorchDir)Plugins\$(AssemblyName).zip" SourceDirectory="$(TargetDir)" Overwrite="true" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
163
LightPerms/LpCommands.cs
Normal file
163
LightPerms/LpCommands.cs
Normal file
@@ -0,0 +1,163 @@
|
||||
using PetaPoco;
|
||||
using Torch.API.Managers;
|
||||
using Torch.Commands;
|
||||
using Torch.Commands.Permissions;
|
||||
using VRage.Game.ModAPI;
|
||||
namespace LightPerms;
|
||||
|
||||
[Category("lp")]
|
||||
public class LpCommands : CommandModule
|
||||
{
|
||||
private IPermissionsManager Pm => Context.Torch.Managers.GetManager<IPermissionsManager>();
|
||||
|
||||
#if DEBUG
|
||||
[Command("gen")]
|
||||
public void GenTest()
|
||||
{
|
||||
var db = Pm.Db;
|
||||
|
||||
db.Execute("delete from groups");
|
||||
db.Execute("delete from group_members");
|
||||
db.Execute("delete from permissions");
|
||||
|
||||
var playerGroup = (long)db.Insert(new Group {Name = "player"});
|
||||
db.Insert(new Permission {Value = "test.permission.player", GroupUid = playerGroup});
|
||||
|
||||
var adminGroup = (long)db.Insert(new Group {Name = "admin"});
|
||||
db.Insert(new Permission {Value = "test.permission.admin", GroupUid = adminGroup});
|
||||
|
||||
db.Insert(new GroupMember {Name = Context.Player.DisplayName, ClientId = Context.Player.SteamUserId.ToString(), GroupUid = playerGroup});
|
||||
}
|
||||
#endif
|
||||
|
||||
[Command("has perm")]
|
||||
[Permission(MyPromoteLevel.Admin)]
|
||||
public void HasPermission(string perm, ulong clientId = 0)
|
||||
{
|
||||
clientId = Context.Player?.SteamUserId ?? clientId;
|
||||
|
||||
if (clientId == 0)
|
||||
{
|
||||
Context.Respond("Specify valid client id.");
|
||||
return;
|
||||
}
|
||||
|
||||
Context.Respond(Pm.HasPermission(clientId, perm) ? "Yes" : "No");
|
||||
}
|
||||
|
||||
[Command("get groups")]
|
||||
[Permission(MyPromoteLevel.Admin)]
|
||||
public void GetGroups()
|
||||
{
|
||||
Context.Respond($"Available groups:\n {string.Join("\n ", Pm.Db.Query<Group>().Select(b => $"{b.Name} - id {b.Uid}"))}");
|
||||
}
|
||||
|
||||
[Command("get perms")]
|
||||
[Permission(MyPromoteLevel.Admin)]
|
||||
public void GetPerms(string groupName)
|
||||
{
|
||||
if (Pm.Db.SingleOrDefault<Group>(Sql.Builder.Where("name = @0", groupName)) is not { } group)
|
||||
{
|
||||
Context.Respond("No group found with given name");
|
||||
return;
|
||||
}
|
||||
|
||||
Context.Respond($"Available perms:\n {string.Join("\n ", Pm.Db.Query<Permission>(Sql.Builder.Where("group_uid = @0", group.Uid)).Select(b => b.Value).OrderBy(b => b))}");
|
||||
}
|
||||
|
||||
[Command("add group")]
|
||||
[Permission(MyPromoteLevel.Admin)]
|
||||
public void AddGroup(string groupName)
|
||||
{
|
||||
if (Pm.Db.Exists<Group>("name = @0", groupName))
|
||||
{
|
||||
Context.Respond("Group already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
Pm.Db.Insert(new Group
|
||||
{
|
||||
Name = groupName
|
||||
});
|
||||
Context.Respond("Added");
|
||||
}
|
||||
|
||||
[Command("add perm")]
|
||||
[Permission(MyPromoteLevel.Admin)]
|
||||
public void AddPerm(string groupName, string permission)
|
||||
{
|
||||
if (Pm.Db.SingleOrDefault<Group>(Sql.Builder.Where("name = @0", groupName)) is not { } group)
|
||||
{
|
||||
Context.Respond("No group found with given name");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Pm.Db.Exists<Permission>("group_uid = @0 and value like @1", group.Uid, permission.Replace('*', '%')))
|
||||
{
|
||||
Context.Respond("Permission already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
Pm.Db.Insert(new Permission
|
||||
{
|
||||
Value = permission,
|
||||
GroupUid = group.Uid
|
||||
});
|
||||
Context.Respond("Added");
|
||||
}
|
||||
|
||||
[Command("del group")]
|
||||
[Permission(MyPromoteLevel.Admin)]
|
||||
public void DelGroup(string groupName)
|
||||
{
|
||||
if (Pm.Db.Delete<Group>(Sql.Builder.Where("name = @0", groupName)) != 1)
|
||||
{
|
||||
Context.Respond("Group not exists");
|
||||
return;
|
||||
}
|
||||
Context.Respond("Deleted");
|
||||
}
|
||||
|
||||
[Command("del perm")]
|
||||
[Permission(MyPromoteLevel.Admin)]
|
||||
public void DelPerm(string groupName, string permission)
|
||||
{
|
||||
if (Pm.Db.SingleOrDefault<Group>(Sql.Builder.Where("name = @0", groupName)) is not { } group)
|
||||
{
|
||||
Context.Respond("No group found with given name");
|
||||
return;
|
||||
}
|
||||
|
||||
var count = Pm.Db.Delete<Permission>(Sql.Builder.Where("group_uid = @0 and value like @1", group.Uid, permission.Replace('*', '%')));
|
||||
if (count > 0)
|
||||
{
|
||||
Context.Respond($"Deleted {count} permissions");
|
||||
return;
|
||||
}
|
||||
|
||||
Context.Respond("No permissions found");
|
||||
}
|
||||
|
||||
[Command("assign group")]
|
||||
[Permission(MyPromoteLevel.Admin)]
|
||||
public void AssignGroup(string groupName, ulong clientId = 0)
|
||||
{
|
||||
if (clientId == 0)
|
||||
clientId = Context.Player.SteamUserId;
|
||||
|
||||
if (Pm.Db.SingleOrDefault<Group>(Sql.Builder.Where("name = @0", groupName)) is not { } group)
|
||||
{
|
||||
Context.Respond("No group found with given name");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Pm.Db.Exists<GroupMember>("group_uid = @0 and client_id = @1", group.Uid, clientId))
|
||||
{
|
||||
Context.Respond("User already assigned to this group");
|
||||
return;
|
||||
}
|
||||
|
||||
Pm.AssignGroup(clientId, groupName);
|
||||
Context.Respond("User assigned to the group");
|
||||
}
|
||||
}
|
37
LightPerms/MultiplayerMembersManager.cs
Normal file
37
LightPerms/MultiplayerMembersManager.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Torch.API;
|
||||
using Torch.API.Managers;
|
||||
using Torch.Managers;
|
||||
namespace LightPerms;
|
||||
|
||||
public class MultiplayerMembersManager : Manager
|
||||
{
|
||||
[Dependency]
|
||||
private readonly IPermissionsManager _permissionsManager = null!;
|
||||
[Dependency]
|
||||
private readonly IMultiplayerManagerServer _multiplayerManager = null!;
|
||||
|
||||
public MultiplayerMembersManager(ITorchBase torchInstance) : base(torchInstance)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Attach()
|
||||
{
|
||||
base.Attach();
|
||||
_multiplayerManager.PlayerJoined += MultiplayerManagerOnPlayerJoined;
|
||||
}
|
||||
|
||||
private void MultiplayerManagerOnPlayerJoined(IPlayer player)
|
||||
{
|
||||
if (_permissionsManager.Db.Exists<GroupMember>("client_id = @0", player.SteamId))
|
||||
return;
|
||||
|
||||
var groupMember = new GroupMember
|
||||
{
|
||||
Name = player.Name,
|
||||
ClientId = player.SteamId.ToString(),
|
||||
GroupUid = 0
|
||||
};
|
||||
|
||||
_permissionsManager.Db.Insert(groupMember);
|
||||
}
|
||||
}
|
85
LightPerms/PermissionsManager.cs
Normal file
85
LightPerms/PermissionsManager.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using heh;
|
||||
using NLog;
|
||||
using PetaPoco;
|
||||
using Sandbox.Game.Multiplayer;
|
||||
using Torch.API;
|
||||
using Torch.API.Managers;
|
||||
using Torch.Managers;
|
||||
namespace LightPerms;
|
||||
|
||||
public interface IPermissionsManager : IManager
|
||||
{
|
||||
bool HasPermission(ulong clientId, string permission);
|
||||
|
||||
void AssignGroup(ulong clientId, string groupName);
|
||||
|
||||
Group? GetGroup(string groupName);
|
||||
|
||||
IDatabase Db { get; }
|
||||
}
|
||||
|
||||
public class PermissionsManager : Manager, IPermissionsManager
|
||||
{
|
||||
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
|
||||
private static readonly char[] InvalidPermissionChars = {'*', '?'};
|
||||
|
||||
[Dependency]
|
||||
private readonly IDbManager _dbManager = null!;
|
||||
|
||||
public PermissionsManager(ITorchBase torchInstance) : base(torchInstance)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Attach()
|
||||
{
|
||||
base.Attach();
|
||||
Db = _dbManager.Create("light_perms");
|
||||
Db.Execute(Group.CreateTableSql);
|
||||
Db.Execute(Permission.CreateTableSql);
|
||||
Db.Execute(GroupMember.CreateTableSql);
|
||||
|
||||
if (GetGroup("player") is null)
|
||||
Db.Insert(new Group
|
||||
{
|
||||
Name = "player"
|
||||
});
|
||||
}
|
||||
|
||||
public bool HasPermission(ulong clientId, string permission)
|
||||
{
|
||||
if (permission.IndexOfAny(InvalidPermissionChars) > -1)
|
||||
throw new InvalidOperationException("Permission should not contain any invalid characters");
|
||||
|
||||
var member = Db.SingleOrDefault<GroupMember>(Sql.Builder.Where("client_id = @0", clientId));
|
||||
var result = member is not null && Db.Exists<Permission>("group_uid = @0 and @1 like replace(replace(value,'*','%'),'?','_')", member.GroupUid, permission);
|
||||
|
||||
if (!result)
|
||||
Log.Info("User ({0}) has no permission '{1}'", clientId, permission);
|
||||
|
||||
return result;
|
||||
}
|
||||
public void AssignGroup(ulong clientId, string groupName)
|
||||
{
|
||||
if (Sync.Players.TryGetPlayerIdentity(new(clientId)) is not { } identity)
|
||||
throw new InvalidOperationException($"Invalid client id {clientId}");
|
||||
|
||||
if (Db.SingleOrDefault<Group>(Sql.Builder.Where("name = @0", groupName)) is not { } group)
|
||||
throw new InvalidOperationException($"Invalid group name {groupName}");
|
||||
|
||||
if (Db.SingleOrDefault<GroupMember>(Sql.Builder.Where("client_id = @0", clientId)) is { } groupMember)
|
||||
Db.Delete(groupMember);
|
||||
|
||||
Db.Insert(new GroupMember
|
||||
{
|
||||
Name = identity.DisplayName,
|
||||
ClientId = clientId.ToString(),
|
||||
GroupUid = group.Uid
|
||||
});
|
||||
}
|
||||
public Group? GetGroup(string groupName)
|
||||
{
|
||||
return Db.SingleOrDefault<Group>(Sql.Builder.Where("name = @0", groupName));
|
||||
}
|
||||
|
||||
public IDatabase Db { get; private set; } = null!;
|
||||
}
|
31
LightPerms/Plugin.cs
Normal file
31
LightPerms/Plugin.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.IO;
|
||||
using System.Windows.Controls;
|
||||
using heh;
|
||||
using Torch;
|
||||
using Torch.API;
|
||||
using Torch.API.Managers;
|
||||
using Torch.API.Plugins;
|
||||
using Torch.API.Session;
|
||||
using Torch.Views;
|
||||
|
||||
namespace LightPerms;
|
||||
|
||||
public class Plugin : TorchPluginBase, IWpfPlugin
|
||||
{
|
||||
private Persistent<Config> _config = null!;
|
||||
|
||||
public override void Init(ITorchBase torch)
|
||||
{
|
||||
base.Init(torch);
|
||||
_config = Persistent<Config>.Load(Path.Combine(StoragePath, "LightPerms.cfg"));
|
||||
Torch.Managers.AddManager(DbManager.Static);
|
||||
Torch.Managers.AddManager(new PermissionsManager(Torch));
|
||||
Torch.Managers.GetManager<ITorchSessionManager>().AddFactory(s => new MultiplayerMembersManager(s.Torch));
|
||||
}
|
||||
|
||||
public UserControl GetControl() => new PropertyGrid
|
||||
{
|
||||
Margin = new(3),
|
||||
DataContext = _config.Data
|
||||
};
|
||||
}
|
25
LightPerms/README.md
Normal file
25
LightPerms/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
Light plugin to add permission system (like minecraft's PermissionEx or LuckPerms) to your server.
|
||||
|
||||
|
||||
In this plugins all permissions can be wildcards and belongs to groups
|
||||
|
||||
By default plugin creates and assigns `player` group to all players automatically (currently unchangeable)
|
||||
|
||||
### Commands
|
||||
|
||||
+ `!lp get groups` - Returns list of all groups
|
||||
+ `!lp add group <group name>` - Creates a new group
|
||||
+ `!lp del groups <group name>` - Deletes the group
|
||||
+ `!lp get perms <group name>` - Returns list of permissions in the group
|
||||
+ `!lp add perm <group name> <permission>` - Adds a new permission to the group
|
||||
+ `!lp del perm <group name> <permission>` - Deletes a permission from the group
|
||||
+ `!lp has perm <permission> <client id>` - Returns if player has a permission (client id can be removed to use the sender id)
|
||||
+ `!lp assign group <group name> <client id>` - Assigns a group to the player (client id can be removed to use the sender id)
|
||||
|
||||
### Groups based on discord roles
|
||||
|
||||
To automatically assign a group to players if they have a specific role in discord server use [LightPerms.Discord](https://torchapi.com/plugins/view/?guid=d53cf5e6-27ea-491b-9579-8506d93f184b) plugin
|
||||
|
||||
### Support in plugins
|
||||
|
||||
+ [Kits](https://torchapi.com/plugins/view/?guid=d095391d-b5ec-43a9-8ba4-6c4909227e6e)
|
6
LightPerms/manifest.xml
Normal file
6
LightPerms/manifest.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<PluginManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Name>LightPerms</Name>
|
||||
<Guid>5c3f35b3-ac9d-486f-8559-f931536c6700</Guid>
|
||||
<Version>v1.0.1</Version>
|
||||
</PluginManifest>
|
20
LightPerms/setup.bat
Normal file
20
LightPerms/setup.bat
Normal file
@@ -0,0 +1,20 @@
|
||||
:: This script creates a symlink to the game binaries to account for different installation directories on different systems.
|
||||
|
||||
@echo off
|
||||
|
||||
set /p path="Please enter the folder location of your Torch.Server.exe: "
|
||||
cd %~dp0
|
||||
rmdir TorchBinaries > nul 2>&1
|
||||
mklink /J ..\TorchBinaries "%path%"
|
||||
if errorlevel 1 goto Error
|
||||
echo Done!
|
||||
|
||||
echo You can now open the plugin without issue.
|
||||
goto EndFinal
|
||||
|
||||
:Error
|
||||
echo An error occured creating the symlink.
|
||||
goto EndFinal
|
||||
|
||||
:EndFinal
|
||||
pause
|
Reference in New Issue
Block a user