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