initial
This commit is contained in:
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
|
Reference in New Issue
Block a user