-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from mafia-rust/rolelist-sharing
Approved by sam
- Loading branch information
Showing
6 changed files
with
352 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
RoleDeckComponents/InteractionPrechecks/MessageResponseFromAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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..]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
} | ||
} |