Skip to content

Commit

Permalink
Merge pull request #1 from mafia-rust/rolelist-sharing
Browse files Browse the repository at this point in the history
Approved by sam
  • Loading branch information
TB516 authored Apr 4, 2024
2 parents a6b3aea + 47d2534 commit 30838b5
Show file tree
Hide file tree
Showing 6 changed files with 352 additions and 8 deletions.
9 changes: 5 additions & 4 deletions Mafia-Bot.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="DSharpPlus" Version="5.0.0-nightly-02132" />
<PackageReference Include="DSharpPlus.CommandsNext" Version="5.0.0-nightly-02132" />
<PackageReference Include="DSharpPlus.Interactivity" Version="5.0.0-nightly-02132" />
<PackageReference Include="DSharpPlus.SlashCommands" Version="5.0.0-nightly-02132" />
<PackageReference Include="DSharpPlus" Version="5.0.0-nightly-02188" />
<PackageReference Include="DSharpPlus.CommandsNext" Version="5.0.0-nightly-02188" />
<PackageReference Include="DSharpPlus.Interactivity" Version="5.0.0-nightly-02188" />
<PackageReference Include="DSharpPlus.SlashCommands" Version="5.0.0-nightly-02188" />
<PackageReference Include="HtmlSanitizer" Version="8.1.860-beta" />
</ItemGroup>

</Project>
9 changes: 5 additions & 4 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using DSharpPlus.SlashCommands;
using DSharpPlus;
using Mafia_Bot.RoleDeckComponents;

namespace Mafia_Bot
{
internal class Program
{
public static DiscordClient discord = new DiscordClient(new DiscordConfiguration()
public static DiscordClient Discord = new DiscordClient(new DiscordConfiguration()
{
Token = File.ReadAllLines("BotKey.txt")[0],
TokenType = TokenType.Bot,
Expand All @@ -18,11 +19,11 @@ static void Main(string[] args)
}
static async Task MainAsync()
{
SlashCommandsExtension slash = discord.UseSlashCommands();
SlashCommandsExtension slash = Discord.UseSlashCommands();

slash.RegisterCommands<RolelistSlashCommands>(724358800517365851);
slash.RegisterCommands<RoledeckSlashCommands>();

await discord.ConnectAsync();
await Discord.ConnectAsync();
Console.WriteLine("Connected");
while (Console.ReadLine() != "stop") ;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using DSharpPlus.SlashCommands;

namespace Mafia_Bot.RoleDeckComponents.InteractionPrechecks
{
internal class MessageResponseFromAttribute(string commandName) : ContextMenuCheckBaseAttribute
{
public override Task<bool> ExecuteChecksAsync(ContextMenuContext ctx)
{
if (ctx.TargetMessage.Interaction != null && ctx.TargetMessage.ApplicationId == ctx.Client.CurrentApplication.Id && ctx.TargetMessage.Interaction.Name == commandName)
{
return Task.FromResult(true);
}
else
{
ctx.CreateResponseAsync("That is not a valid command response for this action to be performed on!", true);
return Task.FromResult(false);
}
}
}
}
108 changes: 108 additions & 0 deletions RoleDeckComponents/Roledeck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using Newtonsoft.Json.Linq;

namespace Mafia_Bot.RoleDeckComponents
{
/// <summary>
/// Wrapper for rolelist data
/// </summary>
internal struct Roledeck
{
/// <summary>
/// Phases of day/night
/// </summary>
public enum Phases
{
briefing,
obituary,
discussion,
nomination,
testimony,
judgement,
finalWords,
dusk,
night,
}

private readonly JObject _roleDeck;
private readonly string _name;
private readonly string[][] _rolelist;
private readonly int[] _phaseTimes;
private readonly string[] _roleBans;

/// <summary>
/// JSON data of rolelist
/// </summary>
public readonly string JsonString => _roleDeck.ToString();
/// <summary>
/// Name of rolelist
/// </summary>
public readonly string Name => _name;
/// <summary>
/// String representation of the rolelist
/// </summary>
public readonly string[][] Rolelist => _rolelist;
/// <summary>
/// Array of phasetimes
/// </summary>
public readonly int[] PhaseTimes => _phaseTimes;
/// <summary>
/// String representation of banned roles
/// </summary>
public readonly string[] BannedRoles => _roleBans;

/// <summary>
/// Wrapper for rolelist data
/// </summary>
/// <param name="json">JSON node to parse</param>
/// <exception cref="KeyNotFoundException">Thrown if JSON property is not found</exception>
public Roledeck(JObject json)
{
_roleDeck = json;

if (_roleDeck["name"] == null)
{
_roleDeck.Add("name", "Unnamed Game Mode");
}
else if (_roleDeck["name"]!.ToString().Trim() == "")
{
_roleDeck["name"] = "Unnamed Game Mode";
}
_name = _roleDeck["name"]!.ToString();

_rolelist = new string[_roleDeck["roleList"]!.Count()][];
_phaseTimes = new int[_roleDeck["phaseTimes"]!.Count()];
_roleBans = new string[_roleDeck["disabledRoles"]!.Count()];

PopulateRolelist();
PopulatePhaseTimes();
PopulateRoleBans();
}
private readonly void PopulateRolelist()
{
for (int i = 0; i < _rolelist.Length; i++)
{
_rolelist[i] = new string[_roleDeck["roleList"]![i]!["options"]!.Count()];

for (int j = 0; j < _rolelist[i].Length; j++)
{
string type = _roleDeck["roleList"]![i]!["options"]![j]!["type"]!.ToString();
_rolelist[i][j] = _roleDeck["roleList"]![i]!["options"]![j]![type]!.ToString();
}
}
}
private readonly void PopulatePhaseTimes()
{
for (int i = 0; i < _phaseTimes.Length; i++)
{
_phaseTimes[i] = (int)_roleDeck["phaseTimes"]![((Phases)i).ToString()]!;
}
}
private readonly void PopulateRoleBans()
{
for (int i = 0; i < _roleBans.Length; i++)
{
_roleBans[i] = _roleDeck["disabledRoles"]![i]!.ToString();
}
}
}
}
94 changes: 94 additions & 0 deletions RoleDeckComponents/RoledeckMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using DSharpPlus.Entities;
using DSharpPlus.SlashCommands;
using Newtonsoft.Json.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Mafia_Bot.RoleDeckComponents
{
/// <summary>
/// Discord message containing rolelist
/// </summary>
public class RoledeckMessage
{
private readonly Roledeck _deck;
private readonly DiscordMessageBuilder _messageBuilder;

/// <summary>
/// Creates discord message based on entered json
/// </summary>
/// <param name="author"></param>
/// <param name="json"></param>
public RoledeckMessage(string author, JObject json)
{
try
{
_deck = new(json);
}
catch
{
throw new KeyNotFoundException("A JSON property was not found!");
}

_messageBuilder = new();

_messageBuilder.WithContent($"# \"{FormatString(_deck.Name)}\" By {author}\n\n{GetRolelist()}{GetPhaseTimes()}{GetBannedRoles()}");

_messageBuilder.AddFile($"{_deck.Name}.json", new MemoryStream(Encoding.UTF8.GetBytes(_deck.JsonString)));
}
/// <summary>
/// Sends rolelist as discord message
/// </summary>
/// <param name="ctx"></param>
public async void SendRoledeck(InteractionContext ctx)
{
await ctx.CreateResponseAsync(new(_messageBuilder));
}
private string GetRolelist()
{
string rolelist = "## Roles\n";

for (int i = 0; i < _deck.Rolelist.Length; i++)
{
rolelist += "- ";
for (int j = 0; j < _deck.Rolelist[i].Length; j++)
{
rolelist += FormatString(_deck.Rolelist[i][j].ToString()) + ((_deck.Rolelist[i].Length > 1 && j < _deck.Rolelist[i].Length - 1) ? " OR " : "");
}
rolelist += "\n";
}

return rolelist;
}
private string GetPhaseTimes()
{
string phaseTimes = "## Phase Times\n";

for (int i = 0; i < _deck.PhaseTimes.Length; i++)
{
phaseTimes += $"- {FormatString(((Roledeck.Phases)i).ToString())} : {_deck.PhaseTimes[i]} seconds\n";
}

return phaseTimes;
}
private string GetBannedRoles()
{
string bannedRoles = "## Disabled Roles\n";

for (int i = 0; i < _deck.BannedRoles.Length; i++)
{
bannedRoles += $"- {FormatString(_deck.BannedRoles[i])}\n";
}

bannedRoles += (_deck.BannedRoles.Length == 0) ? "- None" : "";

return bannedRoles;
}
/// <summary>
/// Splits string at capitals and capitalizes the first letter
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private static string FormatString(string data) => char.ToUpper(data[0]) + string.Join(" ", Regex.Split(data, @"(?<!^)(?=[A-Z](?![A-Z]|$))")).Trim()[1..];
}
}
120 changes: 120 additions & 0 deletions RoleDeckComponents/RoledeckSlashCommands.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using DSharpPlus.CommandsNext.Attributes;
using DSharpPlus.Entities;
using DSharpPlus.Exceptions;
using DSharpPlus.SlashCommands;
using Mafia_Bot.RoleDeckComponents.InteractionPrechecks;
using Newtonsoft.Json.Linq;
using System.Text.RegularExpressions;

namespace Mafia_Bot.RoleDeckComponents
{
internal class RoledeckSlashCommands : ApplicationCommandModule
{
[SlashCommand("help", "Lists all commands and their use.")]
public async Task Help(InteractionContext ctx)
{
ctx.CreateResponseAsync("```" +
"/help (posts this message)\n" +
"/post <json> (formats and posts a gamemode using exported json)\n" +
"/delete <link> (deletes a posted gamemode using a link to that message, you can also use an app context menu to delete it)\n" +
"```", true);
}

[SlashCommand("post", "Posts a formatted gamemode to the current channel.")]
public async Task PostList(InteractionContext ctx, [Option("JSON", "JSON data of the gamemode.")] string json)
{
json = Regex.Replace(json, @"\\t|\t|\\n|\n|\\r|\r", string.Empty);

JObject jsonNode;
RoledeckMessage message;
try
{
jsonNode = JObject.Parse(json)!;
message = new(ctx.Member.Nickname, jsonNode);
}
catch
{
ctx.CreateResponseAsync("Invalid gamemode data entered!", true);
return;
}
message.SendRoledeck(ctx);
}

[ContextMenu(DSharpPlus.ApplicationCommandType.MessageContextMenu, "Delete Gamemode")]
[MessageResponseFrom("post")]
public async Task DeleteList(ContextMenuContext ctx)
{
if (ctx.TargetMessage.Interaction.User != ctx.User)
{
ctx.CreateResponseAsync("That message wasn't made by you!", true);
return;
}

await ctx.Channel.DeleteMessageAsync(ctx.TargetMessage);
ctx.CreateResponseAsync("Deleted gamemode!", true);
}

[SlashCommand("delete", "Deletes a gamemode posting if created by you.")]
public async Task DeleteList(InteractionContext ctx, [Option("Gamemode", "Link to gamemode to delete.")] string link)
{
if (!ulong.TryParse(link.Split('/')[^1], out ulong id))
{
ctx.CreateResponseAsync("Thats not a valid message link!", true);
return;
}

DiscordMessage message;
try
{
message = await ctx.Channel.GetMessageAsync(id);
}
catch (UnauthorizedException)
{
ctx.CreateResponseAsync("The bot doesnt have permissions to access that message!", true);
return;
}
catch (NotFoundException)
{
ctx.CreateResponseAsync("The requested message was not found!", true);
return;
}
catch (Exception e)
{
ctx.CreateResponseAsync($"There was an error accessing the message: {e.Message}", true);
return;
}

if (!(message.Interaction != null && message.Author.IsCurrent && message.Interaction.Name == "post"))
{
ctx.CreateResponseAsync("That is not a valid gamemode posting!", true);
return;
}
else if (ctx.Interaction.User.Id != ctx.User.Id)
{
ctx.CreateResponseAsync("You cannot delete someone else's gamemode posting!");
return;
}

try
{
ctx.Channel.DeleteMessageAsync(message);
ctx.CreateResponseAsync("Deleted gamemode post!", true);
}
catch (UnauthorizedException)
{
ctx.CreateResponseAsync("The bot doesnt have permissions to access that message!", true);
return;
}
catch (NotFoundException)
{
ctx.CreateResponseAsync("The requested message was not found!", true);
return;
}
catch (Exception e)
{
ctx.CreateResponseAsync($"There was an error accessing the message: {e.Message}", true);
return;
}
}
}
}

0 comments on commit 30838b5

Please sign in to comment.