[Raid] Move format code to another class

This commit is contained in:
2022-11-23 22:36:56 +01:00
parent a6df178dff
commit 4f0ccb9464
6 changed files with 95 additions and 62 deletions

View File

@@ -0,0 +1,8 @@
namespace Cocotte.Modules.Raids;
public enum PlayerRole
{
Dps,
Healer,
Tank
}

View File

@@ -0,0 +1,59 @@
using Cocotte.Options;
using Cocotte.Utils;
using Discord;
namespace Cocotte.Modules.Raids;
public class RaidFormatter
{
private readonly RolesOptions _rolesOptions;
public RaidFormatter(RolesOptions rolesOptions)
{
_rolesOptions = rolesOptions;
}
private string RoleToEmote(PlayerRole role) => role switch
{
PlayerRole.Dps => _rolesOptions.DpsEmote,
PlayerRole.Tank => _rolesOptions.TankEmote,
PlayerRole.Healer => _rolesOptions.HealerEmote,
_ => ":question:"
};
public static string FcFormat(int fc) => fc switch
{
< 1_000 => $"{fc}",
_ => $"{fc/1000}k"
};
public string FormatRosterPlayer(RosterPlayer player) => player.Substitue switch
{
false => $"{RoleToEmote(player.Role)} {player.Name} ({FcFormat(player.Fc)} FC)",
true => $"*{RoleToEmote(player.Role)} {player.Name} ({FcFormat(player.Fc)} FC)*"
};
public EmbedBuilder RaidEmbed(Raid raid)
{
EmbedFieldBuilder RosterEmbed(int rosterNumber, IEnumerable<RosterPlayer> players)
{
var rosterPlayers = players.ToList();
var nonSubstitute = rosterPlayers.Where(p => !p.Substitue);
var substitute = rosterPlayers.Where(p => p.Substitue);
var separatorLength = Math.Max(nonSubstitute.Select(p => p.Name.Length).Max(), substitute.Select(p => p.Name.Length).Max());
separatorLength = (int) ((separatorLength + 13) * 0.49); // Don't ask why, it just works
return new EmbedFieldBuilder()
.WithName($"Roster {rosterNumber}")
.WithValue($"{string.Join("\n", nonSubstitute.Select(FormatRosterPlayer))}\n{new string('━', separatorLength)}\n{string.Join("\n", substitute.Select(FormatRosterPlayer))}")
.WithIsInline(true);
}
return new EmbedBuilder()
.WithColor(Colors.CocotteBlue)
.WithTitle(":crossed_swords: Raid")
.WithDescription($"**Date:** {TimestampTag.FromDateTime(raid.DateTime, TimestampTagStyles.LongDateTime)}")
.WithFields(raid.Rosters.Select(r => RosterEmbed(r.Key, r)));
}
}

View File

@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using Cocotte.Options;
using Cocotte.Utils;
using Discord;
using Discord.Interactions;
@@ -14,11 +15,13 @@ public class RaidModule : InteractionModuleBase<SocketInteractionContext>
{
private readonly ILogger<RaidModule> _logger;
private readonly IRaidsRepository _raidsRepository;
private readonly RaidFormatter _raidFormatter;
public RaidModule(ILogger<RaidModule> logger, IRaidsRepository raidsRepository)
public RaidModule(ILogger<RaidModule> logger, IRaidsRepository raidsRepository, RaidFormatter raidFormatter)
{
_logger = logger;
_raidsRepository = raidsRepository;
_raidFormatter = raidFormatter;
}
[EnabledInDm(false)]
@@ -48,14 +51,14 @@ public class RaidModule : InteractionModuleBase<SocketInteractionContext>
// Build the raid message
var raid = _raidsRepository[raidId];
var embed = RaidEmbed(raid);
var components = RaidComponents(raidId);
var embed = _raidFormatter.RaidEmbed(raid);
await ModifyOriginalResponseAsync(m =>
{
m.Content = "";
m.Embed = embed.Build();
m.Components = components.Build();
m.Embed = embed.Build();
});
}
@@ -65,7 +68,7 @@ public class RaidModule : InteractionModuleBase<SocketInteractionContext>
if (!_raidsRepository.TryGetRaid(raidId, out var raid))
{
await RespondAsync(ephemeral: true, embed: EmbedUtils.ErrorEmbed("This raid does not exist").Build());
return;
}
@@ -74,10 +77,10 @@ public class RaidModule : InteractionModuleBase<SocketInteractionContext>
if (!raid.AddPlayer(user.Id, user.DisplayName, PlayerRole.Dps, 10000))
{
await RespondAsync(ephemeral: true, embed: EmbedUtils.InfoEmbed("You're already registered for this raid").Build());
return;
}
_logger.LogInformation("User {User} joined raid {Raid}", Context.User.Username, raid);
await UpdateRaidRosterEmbed(raid);
@@ -90,7 +93,7 @@ public class RaidModule : InteractionModuleBase<SocketInteractionContext>
if (!_raidsRepository.TryGetRaid(raidId, out var raid))
{
await RespondAsync(ephemeral: true, embed: EmbedUtils.ErrorEmbed("This raid does not exist").Build());
return;
}
@@ -98,10 +101,10 @@ public class RaidModule : InteractionModuleBase<SocketInteractionContext>
if (!raid.RemovePlayer(user.Id))
{
await RespondAsync(ephemeral: true, embed: EmbedUtils.WarningEmbed("You're not registered for this raid").Build());
return;
}
await UpdateRaidRosterEmbed(raid);
await RespondAsync(ephemeral: true, embed: EmbedUtils.SuccessEmbed("Successfully left the raid").Build());
}
@@ -112,34 +115,10 @@ public class RaidModule : InteractionModuleBase<SocketInteractionContext>
if (message is SocketUserMessage userMessage)
{
await userMessage.ModifyAsync(m => m.Embed = RaidEmbed(raid).Build());
await userMessage.ModifyAsync(m => m.Embed = _raidFormatter.RaidEmbed(raid).Build());
}
}
private EmbedBuilder RaidEmbed(Raid raid)
{
EmbedFieldBuilder RosterEmbed(int rosterNumber, IEnumerable<RosterPlayer> players)
{
var rosterPlayers = players.ToList();
var nonSubstitute = rosterPlayers.Where(p => !p.Substitue);
var substitute = rosterPlayers.Where(p => p.Substitue);
var separatorLength = Math.Max(nonSubstitute.Select(p => p.Name.Length).Max(), substitute.Select(p => p.Name.Length).Max());
separatorLength = (int) ((separatorLength + 13) * 0.49); // Don't ask why, it just works
return new EmbedFieldBuilder()
.WithName($"Roster {rosterNumber}")
.WithValue($"{string.Join("\n", nonSubstitute)}\n{new string('━', separatorLength)}\n{string.Join("\n", substitute)}")
.WithIsInline(true);
}
return new EmbedBuilder()
.WithColor(Colors.CocotteBlue)
.WithTitle(":crossed_swords: Raid")
.WithDescription($"**Date:** {TimestampTag.FromDateTime(raid.DateTime, TimestampTagStyles.LongDateTime)}")
.WithFields(raid.Rosters.Select(r => RosterEmbed(r.Key, r)));
}
private ComponentBuilder RaidComponents(ulong raidId)
{
return new ComponentBuilder()

View File

@@ -1,23 +1,11 @@
namespace Cocotte.Modules.Raids;
using Cocotte.Options;
namespace Cocotte.Modules.Raids;
public record RosterPlayer(ulong Id, string Name, PlayerRole Role, int Fc, bool Substitue = false)
{
public int RosterNumber { get; set; }
private static string RoleToEmote(PlayerRole role) => role switch
{
PlayerRole.Dps => ":red_circle:",
PlayerRole.Tank => ":yellow_circle:",
PlayerRole.Healer => ":green_circle:",
_ => ":question:"
};
public static string FcFormat(int fc) => fc switch
{
< 1_000 => $"{fc}",
_ => $"{fc/1000}k"
};
public override int GetHashCode()
{
return (int) (Id % int.MaxValue);
@@ -27,17 +15,4 @@ public record RosterPlayer(ulong Id, string Name, PlayerRole Role, int Fc, bool
{
return other is not null && other.Id == Id;
}
public override string ToString() => Substitue switch
{
false => $"{RoleToEmote(Role)} {Name} ({FcFormat(Fc)} FC)",
true => $"*{RoleToEmote(Role)} {Name} ({FcFormat(Fc)} FC)*"
};
}
public enum PlayerRole
{
Dps,
Healer,
Tank
}

View File

@@ -0,0 +1,8 @@
namespace Cocotte.Options;
public class RolesOptions
{
public string DpsEmote { get; set; } = ":red_circle:";
public string TankEmote { get; set; } = ":yellow_circle:";
public string HealerEmote { get; set; } = ":green_circle:";
}

View File

@@ -34,6 +34,10 @@ IHost host = Host.CreateDefaultBuilder(args)
// Data
services.AddSingleton<IRaidsRepository, MemoryRaidRepository>();
services.AddSingleton<RolesOptions>();
// Raids
services.AddSingleton<RaidFormatter>();
// Custom
services.AddSingleton<SharedCounter>();