Compare commits

..

2 Commits

Author SHA1 Message Date
ef948dba27 [Activity] Update component style
- Add icons
- Disable button when activity is full
2023-03-22 12:26:21 +01:00
8dcefeeb39 [Activity] Cleanup embed and code 2023-03-22 11:33:34 +01:00
7 changed files with 73 additions and 51 deletions

View File

@@ -22,13 +22,13 @@ public class ActivityFormatter
{ {
ActivityName.Abyss => "Abîme du Néant", ActivityName.Abyss => "Abîme du Néant",
ActivityName.Raids => "Raids", ActivityName.Raids => "Raids",
ActivityName.FrontierClash => "Conflit Frontalier", ActivityName.FrontierClash => "Conflit frontalier",
ActivityName.VoidRift => "Failles du Néant", ActivityName.VoidRift => "Failles du néant",
ActivityName.OriginsOfWar => "Origine de la Guerre", ActivityName.OriginsOfWar => "Origine de la guerre",
ActivityName.JointOperation => "Opération Conjointe", ActivityName.JointOperation => "Opération conjointe",
ActivityName.InterstellarExploration => "Exploration Interstellaire", ActivityName.InterstellarExploration => "Exploration interstellaire",
ActivityName.BreakFromDestiny => "Échapper au Destin (3v3)", ActivityName.BreakFromDestiny => "Échapper au destin (3v3)",
ActivityName.CriticalAbyss => "Abîme Critique (8v8)", ActivityName.CriticalAbyss => "Abîme critique (8v8)",
ActivityName.Event => "Event", ActivityName.Event => "Event",
ActivityName.Fishing => "Pêche", ActivityName.Fishing => "Pêche",
ActivityName.MirroriaRace => "Course Mirroria", ActivityName.MirroriaRace => "Course Mirroria",
@@ -38,10 +38,16 @@ public class ActivityFormatter
public EmbedBuilder ActivityEmbed(Activity activity, IReadOnlyCollection<ActivityPlayer> players) public EmbedBuilder ActivityEmbed(Activity activity, IReadOnlyCollection<ActivityPlayer> players)
{ {
// Activity full
bool activityFull = players.Count >= activity.MaxPlayers;
// Compute padding using player with longest name
var namePadding = players.Count > 0 ? players.Max(p => p.Name.Length) : 0;
// Players field // Players field
var playersField = new EmbedFieldBuilder() var playersField = new EmbedFieldBuilder()
.WithName("Joueurs inscrits") .WithName("Joueurs inscrits")
.WithValue($"{(!players.Any() ? "*Aucun joueur inscrit*" : string.Join("\n", players.Select(FormatActivityPlayer)))}"); .WithValue($"{(!players.Any() ? "*Aucun joueur inscrit*" : string.Join("\n", players.Select(p => FormatActivityPlayer(p, namePadding))))}");
var title = activity switch var title = activity switch
{ {
@@ -50,12 +56,18 @@ public class ActivityFormatter
_ => $"{FormatActivityName(activity.Name)} ({players.Count}/{activity.MaxPlayers})" _ => $"{FormatActivityName(activity.Name)} ({players.Count}/{activity.MaxPlayers})"
}; };
string description = string.IsNullOrWhiteSpace(activity.Description)
? $"Rejoignez l'activité de {MentionUtils.MentionUser(activity.CreatorDiscordId)}"
: activity.Description;
string bannerUrl = $"https://sage.cdn.ilysix.fr/assets/Cocotte/banner/{GetActivityCode(activity.Name)}.webp"; string bannerUrl = $"https://sage.cdn.ilysix.fr/assets/Cocotte/banner/{GetActivityCode(activity.Name)}.webp";
var color = activityFull ? Colors.CocotteOrange : Colors.CocotteBlue;
return new EmbedBuilder() return new EmbedBuilder()
.WithColor(Colors.CocotteBlue) .WithColor(color)
.WithTitle(title) .WithTitle(title)
.WithDescription($"{activity.Description}") .WithDescription(description)
.WithImageUrl(bannerUrl) .WithImageUrl(bannerUrl)
.WithFields(playersField); .WithFields(playersField);
} }
@@ -65,7 +77,7 @@ public class ActivityFormatter
ActivityName.Abyss => "VA", ActivityName.Abyss => "VA",
ActivityName.OriginsOfWar => "OOW", ActivityName.OriginsOfWar => "OOW",
ActivityName.Raids => "RD", ActivityName.Raids => "RD",
ActivityName.FrontierClash => "FC", ActivityName.FrontierClash => "FCH",
ActivityName.VoidRift => "VR", ActivityName.VoidRift => "VR",
ActivityName.JointOperation => "JO", ActivityName.JointOperation => "JO",
ActivityName.InterstellarExploration => "IE", ActivityName.InterstellarExploration => "IE",
@@ -77,9 +89,9 @@ public class ActivityFormatter
_ => "NA" _ => "NA"
}; };
public string FormatActivityPlayer(ActivityPlayer player) => player switch public string FormatActivityPlayer(ActivityPlayer player, int namePadding) => player switch
{ {
ActivityRolePlayer rolePlayer => $"{player.Name} - {RolesToEmotes(rolePlayer.Roles)}", ActivityRolePlayer rolePlayer => $"` {player.Name.PadRight(namePadding)} ` **―** {RolesToEmotes(rolePlayer.Roles)}",
_ => $"{player.Name})" _ => $"{player.Name})"
}; };

View File

@@ -45,9 +45,9 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
} }
[SlashCommand("abime", "Créer un groupe pour l'Abîme du Néant")] [SlashCommand("abime", "Créer un groupe pour l'Abîme du Néant")]
public async Task ActivityAbyss([Summary("étage", "A quel étage êtes vous")] uint stage, [Summary("description", "Message accompagnant la demande de groupe")] string description = "") public async Task ActivityAbyss([Summary("étage", "A quel étage êtes vous")] [MinValue(1), MaxValue(6)] uint stage, [Summary("description", "Message accompagnant la demande de groupe")] string description = "")
{ {
const ActivityName activityName = ActivityName.OriginsOfWar; const ActivityName activityName = ActivityName.Abyss;
var activityType = ActivityHelper.ActivityNameToType(activityName); var activityType = ActivityHelper.ActivityNameToType(activityName);
var maxPlayers = ActivityHelper.ActivityTypeToMaxPlayers(activityType); var maxPlayers = ActivityHelper.ActivityTypeToMaxPlayers(activityType);
@@ -59,6 +59,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
Description = description, Description = description,
Type = activityType, Type = activityType,
Name = activityName, Name = activityName,
RoleEnabled = true,
MaxPlayers = maxPlayers, MaxPlayers = maxPlayers,
Stage = stage Stage = stage
}; };
@@ -93,7 +94,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
await _activitiesRepository.SaveChanges(); await _activitiesRepository.SaveChanges();
// Add components // Add components
var components = ActivityRoleComponent(activity.ActivityId); var components = ActivityComponents(activity.ActivityId);
await ModifyOriginalResponseAsync(m => await ModifyOriginalResponseAsync(m =>
{ {
@@ -103,8 +104,8 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
}); });
} }
[ComponentInteraction("activity join_role:*", ignoreGroupNames: true)] [ComponentInteraction("activity join:*", ignoreGroupNames: true)]
private async Task JoinActivityRole(ulong activityId) private async Task JoinActivity(ulong activityId)
{ {
var user = (SocketGuildUser)Context.User; var user = (SocketGuildUser)Context.User;
@@ -120,7 +121,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
} }
// If player is already registered // If player is already registered
if (await _activitiesRepository.FindActivityRolePlayer(activityId, user.Id) is not null) if (await _activitiesRepository.FindActivityPlayer(activityId, user.Id) is not null)
{ {
await RespondAsync( await RespondAsync(
ephemeral: true, ephemeral: true,
@@ -143,21 +144,25 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
_logger.LogTrace("Player {Player} joined activity {Id}", user.DisplayName, activityId); _logger.LogTrace("Player {Player} joined activity {Id}", user.DisplayName, activityId);
var roles = _activityHelper.GetPlayerRoles(user.Roles); var activityPlayer = activity.RoleEnabled ? new ActivityRolePlayer
var activityRolePlayer = new ActivityRolePlayer
{ {
Activity = activity, Activity = activity,
DiscordId = user.Id, DiscordId = user.Id,
Name = user.DisplayName, Name = user.DisplayName,
Roles = roles Roles = _activityHelper.GetPlayerRoles(user.Roles)
} : new ActivityPlayer
{
Activity = activity,
DiscordId = user.Id,
Name = user.DisplayName
}; };
// Add player to activity // Add player to activity
activity.ActivityPlayers.Add(activityRolePlayer); activity.ActivityPlayers.Add(activityPlayer);
await _activitiesRepository.SaveChanges(); await _activitiesRepository.SaveChanges();
// Update activity embed // Update activity embed
await UpdateActivityEmbed(activity); await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerJoin);
await RespondAsync( await RespondAsync(
ephemeral: true, ephemeral: true,
@@ -165,8 +170,8 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
); );
} }
[ComponentInteraction("activity leave_role:*", ignoreGroupNames: true)] [ComponentInteraction("activity leave:*", ignoreGroupNames: true)]
private async Task LeaveActivityRole(ulong activityId) private async Task LeaveActivity(ulong activityId)
{ {
var user = (IGuildUser)Context.User; var user = (IGuildUser)Context.User;
@@ -198,7 +203,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
await _activitiesRepository.SaveChanges(); await _activitiesRepository.SaveChanges();
// Update activity embed // Update activity embed
await UpdateActivityEmbed(activity); await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerLeave);
await RespondAsync( await RespondAsync(
ephemeral: true, ephemeral: true,
@@ -206,15 +211,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
); );
} }
// [ComponentInteraction("activity event_join:*", ignoreGroupNames: true)] private async Task UpdateActivityEmbed(Activity activity, ActivityUpdateReason updateReason)
// private async Task JoinEventActivity(ulong activityId)
// {
// _logger.LogTrace("Player {Player} joined activity {Id}", ((IGuildUser)Context.User).DisplayName, activityId);
//
// await RespondAsync(activityId.ToString());
// }
private async Task UpdateActivityEmbed(Activity activity)
{ {
// Get channel // Get channel
var channel = await Context.Interaction.GetChannelAsync(); var channel = await Context.Interaction.GetChannelAsync();
@@ -230,22 +227,34 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
await channel.ModifyMessageAsync(activity.ActivityId, properties => await channel.ModifyMessageAsync(activity.ActivityId, properties =>
{ {
properties.Embed = _activityFormatter.ActivityEmbed(activity, players).Build(); properties.Embed = _activityFormatter.ActivityEmbed(activity, players).Build();
// Disable join button if the activity is full on join, enable it on leave if activity is not full anymore
var isActivityFull = players.Count >= activity.MaxPlayers;
properties.Components = updateReason switch
{
ActivityUpdateReason.PlayerJoin when isActivityFull => ActivityComponents(activity.ActivityId, disabled: true).Build(),
ActivityUpdateReason.PlayerLeave when !isActivityFull => ActivityComponents(activity.ActivityId, disabled: false).Build(),
_ => Optional<MessageComponent>.Unspecified
};
}); });
} }
private static ComponentBuilder ActivityRoleComponent(ulong activityId) private static ComponentBuilder ActivityComponents(ulong activityId, bool disabled = false)
{ {
return new ComponentBuilder() return new ComponentBuilder()
.AddRow(new ActionRowBuilder() .AddRow(new ActionRowBuilder()
.WithButton(new ButtonBuilder() .WithButton(new ButtonBuilder()
.WithLabel("Rejoindre l'activité") .WithLabel("Rejoindre l'activité")
.WithCustomId($"activity join_role:{activityId}") .WithCustomId($"activity join:{activityId}")
.WithEmote(":white_check_mark:".ToEmote())
.WithStyle(ButtonStyle.Primary) .WithStyle(ButtonStyle.Primary)
.WithDisabled(disabled)
) )
.WithButton(new ButtonBuilder() .WithButton(new ButtonBuilder()
.WithLabel("Se désinscrire de l'activité") .WithLabel("Se désinscrire de l'activité")
.WithCustomId($"activity leave_role:{activityId}") .WithCustomId($"activity leave:{activityId}")
.WithStyle(ButtonStyle.Danger) .WithEmote(":x:".ToEmote())
.WithStyle(ButtonStyle.Secondary)
) )
); );
} }

View File

@@ -29,7 +29,7 @@ public partial class ActivityModule
activity.ActivityPlayers.Add(player); activity.ActivityPlayers.Add(player);
await _activitiesRepository.SaveChanges(); await _activitiesRepository.SaveChanges();
await UpdateActivityEmbed(activity); await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerJoin);
} }
} }

View File

@@ -0,0 +1,8 @@
namespace Cocotte.Modules.Activities;
public enum ActivityUpdateReason
{
PlayerJoin,
PlayerLeave,
Update
}

View File

@@ -17,21 +17,11 @@ public class ActivitiesRepository
return await _cocotteDbContext.Activities.FindAsync(activityId); return await _cocotteDbContext.Activities.FindAsync(activityId);
} }
public async Task<StagedActivity?> FindStagedActivity(ulong activityId)
{
return await _cocotteDbContext.StagedActivities.FindAsync(activityId);
}
public async Task<ActivityPlayer?> FindActivityPlayer(ulong activityId, ulong playerId) public async Task<ActivityPlayer?> FindActivityPlayer(ulong activityId, ulong playerId)
{ {
return await _cocotteDbContext.ActivityPlayers.FindAsync(activityId, playerId); return await _cocotteDbContext.ActivityPlayers.FindAsync(activityId, playerId);
} }
public async Task<ActivityRolePlayer?> FindActivityRolePlayer(ulong activityId, ulong playerId)
{
return await _cocotteDbContext.ActivityRolePlayers.FindAsync(activityId, playerId);
}
public async Task<int> ActivityPlayerCount(Activity activity) => public async Task<int> ActivityPlayerCount(Activity activity) =>
await _cocotteDbContext.ActivityPlayers.Where(player => player.ActivityId == activity.ActivityId).CountAsync(); await _cocotteDbContext.ActivityPlayers.Where(player => player.ActivityId == activity.ActivityId).CountAsync();

View File

@@ -13,6 +13,7 @@ public abstract class Activity
public string? Description { get; init; } public string? Description { get; init; }
public required ActivityType Type { get; init; } public required ActivityType Type { get; init; }
public required ActivityName Name { get; init; } public required ActivityName Name { get; init; }
public required bool RoleEnabled { get; init; }
public required uint MaxPlayers { get; set; } public required uint MaxPlayers { get; set; }
public List<ActivityPlayer> ActivityPlayers { get; init; } = new(); public List<ActivityPlayer> ActivityPlayers { get; init; } = new();

View File

@@ -6,6 +6,8 @@ public static class Colors
{ {
// Main Cocotte colors // Main Cocotte colors
public static Color CocotteBlue => new(0x3196c8); public static Color CocotteBlue => new(0x3196c8);
public static Color CocotteRed => new(0xe40808);
public static Color CocotteOrange => new(0xff6d01);
// Colors used in embeds // Colors used in embeds
public static Color ErrorColor => new(0xFB6060); public static Color ErrorColor => new(0xFB6060);