initial
This commit is contained in:
391
.gitignore
vendored
Normal file
391
.gitignore
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Nuget personal access tokens and Credentials
|
||||
nuget.config
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
GameBinaries
|
||||
TorchBinaries
|
25
LightPerms.Discord/Config.cs
Normal file
25
LightPerms.Discord/Config.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Torch;
|
||||
using Torch.Views;
|
||||
|
||||
namespace LightPerms.Discord;
|
||||
|
||||
public class Config : ViewModel
|
||||
{
|
||||
[Display(Name = "Token", Description = "Discord bot token")]
|
||||
public string Token { get; set; } = "bot-token";
|
||||
[Display(Name = "Guild Id", Description = "Id of the guild to work with")]
|
||||
public ulong GuildId { get; set; }
|
||||
[Display(Name = "Role Configs")]
|
||||
public ObservableCollection<DiscordRoleConfig> RoleConfigs { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DiscordRoleConfig : ViewModel
|
||||
{
|
||||
[Display(Name = "Role Id", Description = "Id of the discord role to work with")]
|
||||
public ulong RoleId { get; set; }
|
||||
[Display(Name = "Group Name", Description = "Name of the group to work with (read guide on LightPerms plugin page to create a new group)")]
|
||||
public string GroupName { get; set; } = "role-group";
|
||||
|
||||
public override string ToString() => GroupName;
|
||||
}
|
143
LightPerms.Discord/DiscordManager.cs
Normal file
143
LightPerms.Discord/DiscordManager.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NLog;
|
||||
using NLog.Fluent;
|
||||
using PetaPoco;
|
||||
using Torch.API;
|
||||
using Torch.Managers;
|
||||
namespace LightPerms.Discord;
|
||||
|
||||
public class DiscordManager : Manager
|
||||
{
|
||||
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly Config _config;
|
||||
[Dependency]
|
||||
private readonly IPermissionsManager _permissionsManager = null!;
|
||||
private readonly DiscordSocketClient _client = new(new()
|
||||
{
|
||||
GatewayIntents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | GatewayIntents.GuildMembers
|
||||
});
|
||||
|
||||
private IDatabase _db = null!;
|
||||
|
||||
public Dictionary<string, ulong> WaitingUsers { get; } = new();
|
||||
|
||||
public DiscordManager(ITorchBase torchInstance, Config config) : base(torchInstance)
|
||||
{
|
||||
_config = config;
|
||||
_client.SlashCommandExecuted += ClientOnSlashCommandExecutedAsync;
|
||||
_client.GuildMemberUpdated += ClientOnGuildMemberUpdatedAsync;
|
||||
_client.Ready += ClientOnReady;
|
||||
_client.Log += message =>
|
||||
{
|
||||
NLog.Fluent.Log.Level(message.Severity switch
|
||||
{
|
||||
LogSeverity.Critical => LogLevel.Fatal,
|
||||
LogSeverity.Error => LogLevel.Error,
|
||||
LogSeverity.Warning => LogLevel.Warn,
|
||||
LogSeverity.Info => LogLevel.Info,
|
||||
LogSeverity.Debug => LogLevel.Debug,
|
||||
LogSeverity.Verbose => LogLevel.Trace,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
}).LoggerName(message.Source).Exception(message.Exception).Message(message.Message).Write();
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
}
|
||||
private async Task ClientOnReady()
|
||||
{
|
||||
var guild = _client.GetGuild(_config.GuildId);
|
||||
|
||||
if (_config.RoleConfigs.Any(b => guild.Roles.All(c => c.Id != b.RoleId)))
|
||||
throw new InvalidOperationException("Some roles are not exists in the guild");
|
||||
|
||||
await AddSlashCommandsAsync(guild);
|
||||
|
||||
await guild.DownloadUsersAsync();
|
||||
await Task.WhenAll(guild.Users.Select(b => ClientOnGuildMemberUpdatedAsync(default, b)));
|
||||
}
|
||||
|
||||
public override void Attach()
|
||||
{
|
||||
base.Attach();
|
||||
_db = _permissionsManager.Db;
|
||||
_db.Execute(LinkedUser.CreateTableSql);
|
||||
|
||||
Task.Run(AttachAsync);
|
||||
}
|
||||
|
||||
private async Task AttachAsync()
|
||||
{
|
||||
await _client.LoginAsync(TokenType.Bot, _config.Token);
|
||||
await _client.StartAsync();
|
||||
}
|
||||
|
||||
private async Task ClientOnGuildMemberUpdatedAsync(Cacheable<SocketGuildUser, ulong> cacheable, SocketGuildUser user)
|
||||
{
|
||||
if (await _db.SingleOrDefaultAsync<LinkedUser>(Sql.Builder.Where("discord_id = @0", user.Id.ToString())) is not { } linkedUser ||
|
||||
await _db.SingleOrDefaultAsync<GroupMember>(Sql.Builder.Where("client_id = @0", linkedUser.ClientId)) is not { } groupMember)
|
||||
return;
|
||||
|
||||
bool HasRole(ulong id) => user.Roles.Any(b => b.Id == id);
|
||||
|
||||
foreach (var (role, group) in _config.RoleConfigs.Select(b => (b, _permissionsManager.GetGroup(b.GroupName)!)))
|
||||
{
|
||||
if (!HasRole(role.RoleId) && groupMember.GroupUid == group.Uid)
|
||||
{
|
||||
_permissionsManager.AssignGroup(linkedUser.ClientIdNumber, "player");
|
||||
Log.Info($"Removed group {role.GroupName} from {linkedUser.ClientId}");
|
||||
}
|
||||
else if (HasRole(role.RoleId) && groupMember.GroupUid != group.Uid)
|
||||
{
|
||||
_permissionsManager.AssignGroup(linkedUser.ClientIdNumber, group.Name);
|
||||
groupMember.GroupUid = group.Uid;
|
||||
Log.Info($"Assigned group {role.GroupName} to {linkedUser.ClientId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ClientOnSlashCommandExecutedAsync(SocketSlashCommand arg)
|
||||
{
|
||||
if (arg.CommandName != "lp-link")
|
||||
return;
|
||||
|
||||
if (GetClientIdByDiscordId(arg.User.Id) is { })
|
||||
{
|
||||
await arg.RespondAsync("You are already linked with lp.");
|
||||
return;
|
||||
}
|
||||
|
||||
var username = Format.UsernameAndDiscriminator(arg.User, false);
|
||||
|
||||
if (!WaitingUsers.ContainsKey(username))
|
||||
{
|
||||
await arg.RespondAsync("Type `!lp link` in-game first.");
|
||||
return;
|
||||
}
|
||||
|
||||
var clientId = WaitingUsers[username];
|
||||
WaitingUsers.Remove(username);
|
||||
|
||||
await _db.InsertAsync(new LinkedUser
|
||||
{
|
||||
DiscordId = arg.User.Id.ToString(),
|
||||
ClientId = clientId.ToString()
|
||||
});
|
||||
await arg.RespondAsync("Linked successfully.");
|
||||
}
|
||||
|
||||
private Task AddSlashCommandsAsync(SocketGuild guild)
|
||||
{
|
||||
return guild.CreateApplicationCommandAsync(new SlashCommandBuilder()
|
||||
.WithName("lp-link")
|
||||
.WithDescription("Light perms link with game")
|
||||
.Build());
|
||||
}
|
||||
|
||||
public ulong? GetClientIdByDiscordId(ulong discordId)
|
||||
{
|
||||
if (_db.SingleOrDefault<LinkedUser>(Sql.Builder.Where("discord_id = @0", discordId.ToString())) is not { } user)
|
||||
return null;
|
||||
return ulong.Parse(user.ClientId);
|
||||
}
|
||||
}
|
3
LightPerms.Discord/FodyWeavers.xml
Normal file
3
LightPerms.Discord/FodyWeavers.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<PropertyChanged />
|
||||
</Weavers>
|
93
LightPerms.Discord/LightPerms.Discord.csproj
Normal file
93
LightPerms.Discord/LightPerms.Discord.csproj
Normal file
@@ -0,0 +1,93 @@
|
||||
<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="Discord.Net.Commands" Version="3.6.1" />
|
||||
<PackageReference Include="Discord.Net.WebSocket" Version="3.6.1" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="4.0.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="manifest.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LightPerms\LightPerms.csproj" Private="false" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyToTorch" AfterTargets="Build">
|
||||
<ZipDirectory DestinationFile="$(TorchDir)Plugins\$(AssemblyName).zip" SourceDirectory="$(TargetDir)" Overwrite="true" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
20
LightPerms.Discord/LinkedUser.cs
Normal file
20
LightPerms.Discord/LinkedUser.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using PetaPoco;
|
||||
namespace LightPerms.Discord;
|
||||
|
||||
[TableName("linked_users")]
|
||||
[PrimaryKey(nameof(Uid), AutoIncrement = true)]
|
||||
public class LinkedUser
|
||||
{
|
||||
[Column]
|
||||
public long Uid { get; set;}
|
||||
|
||||
[Column]
|
||||
public string DiscordId { get; set; } = "0";
|
||||
[Column]
|
||||
public string ClientId { get; set; } = "0";
|
||||
|
||||
internal const string CreateTableSql = "create table if not exists linked_users (uid INTEGER PRIMARY KEY AUTOINCREMENT, discord_id TEXT NOT NULL, client_id TEXT NOT NULL);";
|
||||
|
||||
[Ignore]
|
||||
public ulong ClientIdNumber => ulong.Parse(ClientId);
|
||||
}
|
26
LightPerms.Discord/LpCommands.cs
Normal file
26
LightPerms.Discord/LpCommands.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Torch.API.Managers;
|
||||
using Torch.Commands;
|
||||
using Torch.Commands.Permissions;
|
||||
using VRage.Game.ModAPI;
|
||||
namespace LightPerms.Discord;
|
||||
|
||||
[Category("lp")]
|
||||
public class LpCommands : CommandModule
|
||||
{
|
||||
private static readonly Regex DiscordTagRegex = new(@"^.{3,32}#[0-9]{4}$");
|
||||
|
||||
[Command("link", "Link you with your discord account. (type `/lp-link` on server discord after)")]
|
||||
[Permission(MyPromoteLevel.None)]
|
||||
public void Link(string discordUsername)
|
||||
{
|
||||
if (!DiscordTagRegex.IsMatch(discordUsername))
|
||||
{
|
||||
Context.Respond("Please enter a valid discord username! (like abcde#1234)");
|
||||
return;
|
||||
}
|
||||
|
||||
Context.Torch.CurrentSession.Managers.GetManager<DiscordManager>().WaitingUsers[discordUsername] = Context.Player.SteamUserId;
|
||||
Context.Respond("Type `/lp-link` on server discord");
|
||||
}
|
||||
}
|
29
LightPerms.Discord/Plugin.cs
Normal file
29
LightPerms.Discord/Plugin.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.IO;
|
||||
using System.Windows.Controls;
|
||||
using Torch;
|
||||
using Torch.API;
|
||||
using Torch.API.Managers;
|
||||
using Torch.API.Plugins;
|
||||
using Torch.API.Session;
|
||||
using Torch.Views;
|
||||
|
||||
namespace LightPerms.Discord;
|
||||
|
||||
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.Discord.cfg"));
|
||||
|
||||
Torch.Managers.GetManager<ITorchSessionManager>().AddFactory(s => new DiscordManager(s.Torch, _config.Data));
|
||||
}
|
||||
|
||||
public UserControl GetControl() => new PropertyGrid
|
||||
{
|
||||
Margin = new(3),
|
||||
DataContext = _config.Data
|
||||
};
|
||||
}
|
5
LightPerms.Discord/README.md
Normal file
5
LightPerms.Discord/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Add-on for [LightPerms](https://torchapi.com/plugins/view/?guid=5c3f35b3-ac9d-486f-8559-f931536c6700) plugin to automatically assign groups based on discord role
|
||||
|
||||
# Setup a bot
|
||||
|
||||
if you already have a bot installed with **SEDB** or **Torch Alert** you use token from it else you have to follow the [guide](https://goo.gl/5Do8LJ)
|
12
LightPerms.Discord/manifest.xml
Normal file
12
LightPerms.Discord/manifest.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
<PluginManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Name>LightPerms.Discord</Name>
|
||||
<Guid>d53cf5e6-27ea-491b-9579-8506d93f184b</Guid>
|
||||
<Version>v1.0.1</Version>
|
||||
<Dependencies>
|
||||
<PluginDependency>
|
||||
<Plugin>5c3f35b3-ac9d-486f-8559-f931536c6700</Plugin>
|
||||
<MinVersion>v1.0.1</MinVersion>
|
||||
</PluginDependency>
|
||||
</Dependencies>
|
||||
</PluginManifest>
|
20
LightPerms.Discord/setup.bat
Normal file
20
LightPerms.Discord/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
|
30
LightPerms.TorchCommands/Commands.cs
Normal file
30
LightPerms.TorchCommands/Commands.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Text;
|
||||
using Torch.API.Managers;
|
||||
using Torch.Commands;
|
||||
using Torch.Mod;
|
||||
using Torch.Mod.Messages;
|
||||
namespace LightPerms.TorchCommands;
|
||||
|
||||
[Category("lp")]
|
||||
public class Commands : CommandModule
|
||||
{
|
||||
[Command("get commands", "Get all command permissions")]
|
||||
public void GetCommands()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if (Context.Player is null)
|
||||
sb.AppendLine("Available commands:");
|
||||
|
||||
foreach (var commandNode in Context.Torch.CurrentSession.Managers.GetManager<CommandManager>().Commands.WalkTree()
|
||||
.Where(b => b.IsCommand))
|
||||
{
|
||||
sb.Append(" ".PadRight(4)).AppendLine(commandNode.Command.GetPermissionString());
|
||||
}
|
||||
|
||||
if (Context.Player is null)
|
||||
Context.Respond(sb.ToString());
|
||||
else
|
||||
ModCommunication.SendMessageTo(new DialogMessage("Light Perms", "Available commands:", sb.ToString()), Context.Player.SteamUserId);
|
||||
}
|
||||
}
|
10
LightPerms.TorchCommands/Extensions.cs
Normal file
10
LightPerms.TorchCommands/Extensions.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Torch.Commands;
|
||||
namespace LightPerms.TorchCommands;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static string GetPermissionString(this Command command)
|
||||
{
|
||||
return $"command.{string.Join(".", command.Path.Select(b => b.ToLowerInvariant()))}";
|
||||
}
|
||||
}
|
3
LightPerms.TorchCommands/FodyWeavers.xml
Normal file
3
LightPerms.TorchCommands/FodyWeavers.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<PropertyChanged />
|
||||
</Weavers>
|
91
LightPerms.TorchCommands/LightPerms.TorchCommands.csproj
Normal file
91
LightPerms.TorchCommands/LightPerms.TorchCommands.csproj
Normal file
@@ -0,0 +1,91 @@
|
||||
<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="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LightPerms\LightPerms.csproj" Private="false" 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>
|
157
LightPerms.TorchCommands/PermissionPatch.cs
Normal file
157
LightPerms.TorchCommands/PermissionPatch.cs
Normal file
@@ -0,0 +1,157 @@
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text;
|
||||
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.Utils;
|
||||
namespace LightPerms.TorchCommands;
|
||||
|
||||
[PatchShim]
|
||||
public static class PermissionPatch
|
||||
{
|
||||
[ReflectedMethodInfo(typeof(CommandManager), nameof(CommandManager.HasPermission))]
|
||||
private static readonly MethodInfo HasPermissionMethod = null!;
|
||||
|
||||
[ReflectedMethodInfo(typeof(Torch.Commands.TorchCommands), nameof(Torch.Commands.TorchCommands.Help))]
|
||||
private static readonly MethodInfo HelpMethod = null!;
|
||||
|
||||
[ReflectedMethodInfo(typeof(Torch.Commands.TorchCommands), nameof(Torch.Commands.TorchCommands.LongHelp))]
|
||||
private static readonly MethodInfo LongHelpMethod = null!;
|
||||
|
||||
[ReflectedMethodInfo(typeof(PermissionPatch), nameof(Prefix))]
|
||||
private static readonly MethodInfo PrefixMethod = null!;
|
||||
|
||||
[ReflectedMethodInfo(typeof(PermissionPatch), nameof(PrefixHelp))]
|
||||
private static readonly MethodInfo PrefixHelpMethod = null!;
|
||||
|
||||
[ReflectedMethodInfo(typeof(PermissionPatch), nameof(PrefixLongHelp))]
|
||||
private static readonly MethodInfo PrefixLongHelpMethod = null!;
|
||||
|
||||
[ReflectedMethodInfo(typeof(PermissionPatch), nameof(Transpiler))]
|
||||
private static readonly MethodInfo TranspilerMethod = null!;
|
||||
|
||||
[ReflectedGetter(Name = "Torch")]
|
||||
private static readonly Func<Manager, ITorchBase> TorchGetter = null!;
|
||||
|
||||
public static void Patch(PatchContext context)
|
||||
{
|
||||
context.GetPattern(HasPermissionMethod).Prefixes.Add(PrefixMethod);
|
||||
context.GetPattern(typeof(CommandManager).GetMethod(nameof(CommandManager.HandleCommand),
|
||||
new []{typeof(string), typeof(ulong), typeof(bool).MakeByRefType(), typeof(bool)})).Transpilers.Add(TranspilerMethod);
|
||||
|
||||
context.GetPattern(HelpMethod).Prefixes.Add(PrefixHelpMethod);
|
||||
context.GetPattern(LongHelpMethod).Prefixes.Add(PrefixLongHelpMethod);
|
||||
}
|
||||
|
||||
private static bool PrefixHelp(CommandModule __instance)
|
||||
{
|
||||
var commandManager = __instance.Context.Torch.CurrentSession.Managers.GetManager<CommandManager>();
|
||||
commandManager.Commands.GetNode(__instance.Context.Args, out var node);
|
||||
|
||||
if (node is null)
|
||||
{
|
||||
__instance.Context.Respond(
|
||||
$"Command not found. Use the {commandManager.Prefix}longhelp command for a full list of commands.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var command = node.Command;
|
||||
var children = node.Subcommands.Where(e => __instance.Context.Player == null ||
|
||||
!e.Value.IsCommand ||
|
||||
!commandManager.HasPermission(__instance.Context.Player.SteamUserId, e.Value.Command))
|
||||
.Select(x => x.Key);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if (command is not null)
|
||||
{
|
||||
if (__instance.Context.Player is not null && !commandManager.HasPermission(__instance.Context.Player.SteamUserId, command))
|
||||
{
|
||||
__instance.Context.Respond("You are not authorized to use this command.");
|
||||
return false;
|
||||
}
|
||||
|
||||
sb.AppendLine($"Syntax: {command.SyntaxHelp}");
|
||||
sb.Append(command.HelpText);
|
||||
}
|
||||
|
||||
if (node.Subcommands.Count > 0)
|
||||
sb.Append($"\nSubcommands: {string.Join(", ", children)}");
|
||||
|
||||
__instance.Context.Respond(sb.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool PrefixLongHelp(CommandModule __instance)
|
||||
{
|
||||
var commandManager = __instance.Context.Torch.CurrentSession.Managers.GetManager<CommandManager>();
|
||||
commandManager.Commands.GetNode(__instance.Context.Args, out var node);
|
||||
|
||||
if (node != null)
|
||||
{
|
||||
var command = node.Command;
|
||||
var children = node.Subcommands.Where(e => __instance.Context.Player == null ||
|
||||
!e.Value.IsCommand ||
|
||||
!commandManager.HasPermission(__instance.Context.Player.SteamUserId, e.Value.Command));
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if (command != null && (__instance.Context.Player is null || commandManager.HasPermission(__instance.Context.Player.SteamUserId, command)))
|
||||
{
|
||||
sb.AppendLine($"Syntax: {command.SyntaxHelp}");
|
||||
sb.Append(command.HelpText);
|
||||
}
|
||||
|
||||
if (node.Subcommands.Count > 0)
|
||||
sb.Append($"\nSubcommands: {string.Join(", ", children)}");
|
||||
|
||||
__instance.Context.Respond(sb.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var command in commandManager.Commands.WalkTree())
|
||||
{
|
||||
if (command.IsCommand && (__instance.Context.Player is null || commandManager.HasPermission(__instance.Context.Player.SteamUserId, command.Command)))
|
||||
sb.AppendLine($"{command.Command.SyntaxHelp}\n {command.Command.HelpText}");
|
||||
}
|
||||
|
||||
if (!__instance.Context.SentBySelf)
|
||||
{
|
||||
var m = new DialogMessage("Torch Help", "Available commands:", sb.ToString());
|
||||
ModCommunication.SendMessageTo(m, __instance.Context.Player!.SteamUserId);
|
||||
}
|
||||
else
|
||||
__instance.Context.Respond($"Available commands: {sb}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool Prefix(Manager __instance, ulong steamId, Command command, ref bool __result)
|
||||
{
|
||||
__result = steamId == Sync.MyId ||
|
||||
MySession.Static.IsUserAdmin(steamId) ||
|
||||
TorchGetter(__instance).Managers.GetManager<IPermissionsManager>().HasPermission(steamId, command.GetPermissionString());
|
||||
return false;
|
||||
}
|
||||
|
||||
private static IEnumerable<MsilInstruction> Transpiler(IEnumerable<MsilInstruction> ins)
|
||||
{
|
||||
foreach (var instruction in ins)
|
||||
{
|
||||
if (instruction.OpCode == OpCodes.Ldstr &&
|
||||
instruction.Operand is MsilOperandInline.MsilOperandString {Value: "You need to be a {0} or higher to use that command."})
|
||||
yield return instruction.InlineValue("You don't have permission to use that command.");
|
||||
else
|
||||
yield return instruction;
|
||||
}
|
||||
}
|
||||
}
|
12
LightPerms.TorchCommands/Plugin.cs
Normal file
12
LightPerms.TorchCommands/Plugin.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.IO;
|
||||
using System.Windows.Controls;
|
||||
using Torch;
|
||||
using Torch.API;
|
||||
using Torch.API.Plugins;
|
||||
using Torch.Views;
|
||||
|
||||
namespace LightPerms.TorchCommands;
|
||||
|
||||
public class Plugin : TorchPluginBase
|
||||
{
|
||||
}
|
11
LightPerms.TorchCommands/README.md
Normal file
11
LightPerms.TorchCommands/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
Add-on for [LightPerms](https://torchapi.com/plugins/view/?guid=5c3f35b3-ac9d-486f-8559-f931536c6700) plugin to have better control over commands permissions.
|
||||
|
||||
### Usage
|
||||
|
||||
All existing torch commands are indexed as `command.something`, spaces are replaced by `.`
|
||||
|
||||
`!help` and `!longhelp` commands are modified to reflect permission requirements.
|
||||
|
||||
For example if you want give to players ability to use `!fixship` command, you need to invoke this command `!lp add perm player command.fixship`
|
||||
|
||||
Wildcards are also supported, for example command to give to admins ability to use all lp commands (you need to create group before using that command) `!lp add perm admin command.lp.*`
|
12
LightPerms.TorchCommands/manifest.xml
Normal file
12
LightPerms.TorchCommands/manifest.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
<PluginManifest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Name>LightPerms.TorchCommands</Name>
|
||||
<Guid>0cf57780-f235-4240-99cd-ebd7463e673a</Guid>
|
||||
<Version>v1.0.0</Version>
|
||||
<Dependencies>
|
||||
<PluginDependency>
|
||||
<Plugin>5c3f35b3-ac9d-486f-8559-f931536c6700</Plugin>
|
||||
<MinVersion>v1.0.1</MinVersion>
|
||||
</PluginDependency>
|
||||
</Dependencies>
|
||||
</PluginManifest>
|
20
LightPerms.TorchCommands/setup.bat
Normal file
20
LightPerms.TorchCommands/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
|
28
LightPerms.sln
Normal file
28
LightPerms.sln
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightPerms", "LightPerms\LightPerms.csproj", "{3963D8F4-CCB6-4305-8FEC-A19597404A19}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightPerms.Discord", "LightPerms.Discord\LightPerms.Discord.csproj", "{B1A35416-6CFB-4AE7-A2F2-818E8F7A8C13}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightPerms.TorchCommands", "LightPerms.TorchCommands\LightPerms.TorchCommands.csproj", "{8F9D910F-FFE6-4010-921F-5872ACF638BB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3963D8F4-CCB6-4305-8FEC-A19597404A19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3963D8F4-CCB6-4305-8FEC-A19597404A19}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3963D8F4-CCB6-4305-8FEC-A19597404A19}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3963D8F4-CCB6-4305-8FEC-A19597404A19}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B1A35416-6CFB-4AE7-A2F2-818E8F7A8C13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B1A35416-6CFB-4AE7-A2F2-818E8F7A8C13}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B1A35416-6CFB-4AE7-A2F2-818E8F7A8C13}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B1A35416-6CFB-4AE7-A2F2-818E8F7A8C13}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8F9D910F-FFE6-4010-921F-5872ACF638BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8F9D910F-FFE6-4010-921F-5872ACF638BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8F9D910F-FFE6-4010-921F-5872ACF638BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8F9D910F-FFE6-4010-921F-5872ACF638BB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
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