Skip to content

Commit

Permalink
Merge branch 'draftbot-v5' into top-command
Browse files Browse the repository at this point in the history
# Conflicts:
#	Discord/src/packetHandlers/handlers/CommandHandlers.ts
  • Loading branch information
Feiryn committed Jan 14, 2025
2 parents 24e31b7 + 55b9ce0 commit b972734
Show file tree
Hide file tree
Showing 11 changed files with 418 additions and 4 deletions.
136 changes: 136 additions & 0 deletions Core/src/commands/guild/GuildElderCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import Player, {Players} from "../../core/database/game/models/Player";
import {DraftBotPacket, makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket";
import {Guilds} from "../../core/database/game/models/Guild";
import {
CommandGuildElderAcceptPacketRes,
CommandGuildElderAlreadyElderPacketRes,
CommandGuildElderFoundPlayerPacketRes,
CommandGuildElderHimselfPacketRes,
CommandGuildElderPacketReq,
CommandGuildElderRefusePacketRes,
CommandGuildElderSameGuildPacketRes
} from "../../../../Lib/src/packets/commands/CommandGuildElderPacket";
import {draftBotInstance} from "../../index";
import {commandRequires, CommandUtils} from "../../core/utils/CommandUtils";
import {GuildConstants} from "../../../../Lib/src/constants/GuildConstants";
import {GuildRole} from "../../../../Lib/src/enums/GuildRole";
import {EndCallback, ReactionCollectorInstance} from "../../core/utils/ReactionsCollector";
import {ReactionCollectorAcceptReaction} from "../../../../Lib/src/packets/interaction/ReactionCollectorPacket";
import {BlockingUtils} from "../../core/utils/BlockingUtils";
import {BlockingConstants} from "../../../../Lib/src/constants/BlockingConstants";
import {ReactionCollectorGuildElder} from "../../../../Lib/src/packets/interaction/ReactionCollectorGuildElder";

/**
* Return true if promotedPlayer can be promoted
* @param player
* @param promotedPlayer
* @param response
*/
async function isEligible(player: Player, promotedPlayer: Player, response: DraftBotPacket[]): Promise<boolean> {
if (promotedPlayer === null) {
response.push(makePacket(CommandGuildElderFoundPlayerPacketRes, {}));
return false;
}
let promotedGuild;
try {
promotedGuild = await Guilds.getById(promotedPlayer.guildId);
}
catch (error) {
promotedGuild = null;
}

const guild = await Guilds.getById(player.guildId);
if (promotedGuild === null || promotedGuild.id !== player.guildId) {
response.push(makePacket(CommandGuildElderSameGuildPacketRes, {}));
return false;
}

if (promotedPlayer.id === player.id) {
response.push(makePacket(CommandGuildElderHimselfPacketRes, {}));
return false;
}

if (promotedPlayer.id === guild.elderId) {
response.push(makePacket(CommandGuildElderAlreadyElderPacketRes, {}));
return false;
}
return true;
}

/**
* Promote promotedPlayer as elder of the guild
* @param player
* @param promotedPlayer
* @param response
*/
async function acceptGuildElder(player: Player, promotedPlayer: Player, response: DraftBotPacket[]): Promise<void> {
await player.reload();
await promotedPlayer.reload();
// Do all necessary checks again just in case something changed during the menu
if (!await isEligible(player, promotedPlayer, response)) {
return;
}
const guild = await Guilds.getById(player.guildId);
guild.elderId = promotedPlayer.id;

await Promise.all([
promotedPlayer.save(),
guild.save()
]);
draftBotInstance.logsDatabase.logGuildElderAdd(guild, promotedPlayer.keycloakId).then();

response.push(makePacket(CommandGuildElderAcceptPacketRes, {
promotedKeycloakId: promotedPlayer.keycloakId,
guildName: guild.name
}));
}

export default class GuildElderCommand {
@commandRequires(CommandGuildElderPacketReq, {
notBlocked: true,
disallowedEffects: CommandUtils.DISALLOWED_EFFECTS.NOT_STARTED_OR_DEAD,
level: GuildConstants.REQUIRED_LEVEL,
guildNeeded: true,
guildRoleNeeded: GuildRole.CHIEF
})
async execute(response: DraftBotPacket[], player: Player, packet: CommandGuildElderPacketReq, context: PacketContext): Promise<void> {
const promotedPlayer = await Players.getAskedPlayer({keycloakId: packet.askedPlayerKeycloakId}, player);

if (!await isEligible(player, promotedPlayer, response)) {
return;
}
const guildName = (await Guilds.getById(player.guildId)).name;

const collector = new ReactionCollectorGuildElder(
guildName,
promotedPlayer.keycloakId
);

const endCallback: EndCallback = async (collector: ReactionCollectorInstance, response: DraftBotPacket[]): Promise<void> => {
const reaction = collector.getFirstReaction();
if (reaction && reaction.reaction.type === ReactionCollectorAcceptReaction.name) {
await acceptGuildElder(player, promotedPlayer, response);
}
else {
response.push(makePacket(CommandGuildElderRefusePacketRes, {
promotedKeycloakId: promotedPlayer.keycloakId
}));
}
BlockingUtils.unblockPlayer(player.id, BlockingConstants.REASONS.GUILD_ELDER);
};

const collectorPacket = new ReactionCollectorInstance(
collector,
context,
{
allowedPlayerKeycloakIds: [player.keycloakId],
reactionLimit: 1
},
endCallback
)
.block(player.id, BlockingConstants.REASONS.GUILD_ELDER)
.build();

response.push(collectorPacket);
}
}
2 changes: 1 addition & 1 deletion Core/src/commands/guild/GuildKickCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ async function isNotEligible(player: Player, kickedPlayer: Player, response: Dra
}

if (kickedPlayer.id === player.id) {
// Different guild
// Same player
response.push(makePacket(CommandGuildKickPacketRes, {
foundPlayer: true,
sameGuild: true,
Expand Down
121 changes: 121 additions & 0 deletions Discord/src/commands/guild/GuildElderCommand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import {ReactionCollectorCreationPacket} from "../../../../Lib/src/packets/interaction/ReactionCollectorPacket";
import {makePacket, PacketContext} from "../../../../Lib/src/packets/DraftBotPacket";
import {DiscordCache} from "../../bot/DiscordCache";
import {KeycloakUtils} from "../../../../Lib/src/keycloak/KeycloakUtils";
import {keycloakConfig} from "../../bot/DraftBotShard";
import {DraftBotEmbed} from "../../messages/DraftBotEmbed";
import i18n from "../../translations/i18n";
import {DiscordCollectorUtils} from "../../utils/DiscordCollectorUtils";
import {ReactionCollectorGuildElderData} from "../../../../Lib/src/packets/interaction/ReactionCollectorGuildElder";
import {
CommandGuildElderAcceptPacketRes,
CommandGuildElderPacketReq,
CommandGuildElderRefusePacketRes
} from "../../../../Lib/src/packets/commands/CommandGuildElderPacket";
import {ICommand} from "../ICommand";
import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator";
import {DraftbotInteraction} from "../../messages/DraftbotInteraction";
import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser";
import {PacketUtils} from "../../utils/PacketUtils";
import {SlashCommandBuilder} from "@discordjs/builders";

/**
* Create a collector to confirm the promotion
* @param packet
* @param context
*/
export async function createGuildElderCollector(packet: ReactionCollectorCreationPacket, context: PacketContext): Promise<void> {
const interaction = DiscordCache.getInteraction(context.discord!.interaction)!;
await interaction.deferReply();
const data = packet.data.data as ReactionCollectorGuildElderData;
const elderPlayer = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, data.promotedKeycloakId))!;
const embed = new DraftBotEmbed().formatAuthor(i18n.t("commands:guildElder.title", {
lng: interaction.userLanguage,
pseudo: interaction.user.displayName
}), interaction.user)
.setDescription(
i18n.t("commands:guildElder.confirmDesc", {
lng: interaction.userLanguage,
elderPseudo: elderPlayer.attributes.gameUsername,
guildName: data.guildName
})
);

await DiscordCollectorUtils.createAcceptRefuseCollector(interaction, embed, packet, context);
}

/**
* Handle the response of the server after a guild elder,
* this packet is only sent if the promotion is refused
* @param packet
* @param context
*/
export async function handleCommandGuildElderRefusePacketRes(packet: CommandGuildElderRefusePacketRes, context: PacketContext): Promise<void> {
const originalInteraction = DiscordCache.getInteraction(context.discord!.interaction!);
if (!originalInteraction) {
return;
}
const buttonInteraction = DiscordCache.getButtonInteraction(context.discord!.buttonInteraction!);
const promotedPlayer = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, packet.promotedKeycloakId))!;
await buttonInteraction?.editReply({
embeds: [
new DraftBotEmbed().formatAuthor(i18n.t("commands:guildElder.canceledTitle", {
lng: originalInteraction.userLanguage,
pseudo: originalInteraction.user.displayName
}), originalInteraction.user)
.setDescription(
i18n.t("commands:guildElder.canceledDesc", {
lng: originalInteraction.userLanguage,
elderPseudo: promotedPlayer.attributes.gameUsername
})
)
.setErrorColor()
]
});
}

/**
* Handle the response of the server after a guild elder,
* this packet is only sent if the promotion is accepted
* @param packet
* @param context
*/
export async function handleCommandGuildElderAcceptPacketRes(packet: CommandGuildElderAcceptPacketRes, context: PacketContext): Promise<void> {
const originalInteraction = DiscordCache.getInteraction(context.discord!.interaction!);
const buttonInteraction = DiscordCache.getButtonInteraction(context.discord!.buttonInteraction!);
const promotedPlayer = (await KeycloakUtils.getUserByKeycloakId(keycloakConfig, packet.promotedKeycloakId!))!;
if (buttonInteraction && originalInteraction) {
await buttonInteraction.editReply({
embeds: [
new DraftBotEmbed().formatAuthor(i18n.t("commands:guildElder.successElderAddTitle", {
lng: originalInteraction.userLanguage,
elderPseudo: promotedPlayer.attributes.gameUsername,
guildName: packet.guildName
}), originalInteraction.user)
.setDescription(
i18n.t("commands:guildElder.acceptedDesc", {lng: originalInteraction.userLanguage})
)
]
});
}
}

/**
* Promote a player from a guild
*/
async function getPacket(interaction: DraftbotInteraction, user: KeycloakUser): Promise<CommandGuildElderPacketReq | null> {
const askedPlayer = await PacketUtils.prepareAskedPlayer(interaction, user);
if (!askedPlayer || !askedPlayer.keycloakId) {
return null;
}
return makePacket(CommandGuildElderPacketReq, {askedPlayerKeycloakId: askedPlayer.keycloakId});
}

export const commandInfo: ICommand = {
slashCommandBuilder: SlashCommandBuilderGenerator.generateBaseCommand("guildElder")
.addUserOption(option =>
SlashCommandBuilderGenerator.generateOption("guildElder", "user", option)
.setRequired(true)) as SlashCommandBuilder,
getPacket,
mainGuildCommand: false
};
10 changes: 7 additions & 3 deletions Discord/src/commands/guild/GuildKickCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@ import {SlashCommandBuilderGenerator} from "../SlashCommandBuilderGenerator";
import {SlashCommandBuilder} from "@discordjs/builders";
import {DiscordCache} from "../../bot/DiscordCache";
import {KeycloakUser} from "../../../../Lib/src/keycloak/KeycloakUser";
import {CommandGuildKickAcceptPacketRes, CommandGuildKickPacketReq, CommandGuildKickPacketRes, CommandGuildKickRefusePacketRes} from "../../../../Lib/src/packets/commands/CommandGuildKickPacket";
import {
CommandGuildKickAcceptPacketRes,
CommandGuildKickPacketReq,
CommandGuildKickPacketRes,
CommandGuildKickRefusePacketRes
} from "../../../../Lib/src/packets/commands/CommandGuildKickPacket";
import {ReactionCollectorCreationPacket} from "../../../../Lib/src/packets/interaction/ReactionCollectorPacket";
import {DraftBotEmbed} from "../../messages/DraftBotEmbed";
import {DiscordCollectorUtils} from "../../utils/DiscordCollectorUtils";
import {ReactionCollectorGuildKickData} from "../../../../Lib/src/packets/interaction/ReactionCollectorGuildKick";
import {PacketUtils} from "../../utils/PacketUtils";
import {CommandProfilePacketReq} from "../../../../Lib/src/packets/commands/CommandProfilePacket";
import {sendErrorMessage, SendManner} from "../../utils/ErrorUtils";
import {KeycloakUtils} from "../../../../Lib/src/keycloak/KeycloakUtils";
import {keycloakConfig} from "../../bot/DraftBotShard";

/**
* Kick a player from a guild
*/
async function getPacket(interaction: DraftbotInteraction, user: KeycloakUser): Promise<CommandProfilePacketReq | null> {
async function getPacket(interaction: DraftbotInteraction, user: KeycloakUser): Promise<CommandGuildKickPacketReq | null> {
const askedPlayer = await PacketUtils.prepareAskedPlayer(interaction, user);
if (!askedPlayer) {
return null;
Expand Down
42 changes: 42 additions & 0 deletions Discord/src/packetHandlers/handlers/CommandHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,18 @@ import {
handleCommandTopPacketResGuild,
handleCommandTopPacketResScore, handleCommandTopPlayersEmptyPacket
} from "../../commands/player/TopCommand";
import {
CommandGuildElderAcceptPacketRes,
CommandGuildElderAlreadyElderPacketRes,
CommandGuildElderFoundPlayerPacketRes,
CommandGuildElderHimselfPacketRes,
CommandGuildElderRefusePacketRes,
CommandGuildElderSameGuildPacketRes
} from "../../../../Lib/src/packets/commands/CommandGuildElderPacket";
import {
handleCommandGuildElderAcceptPacketRes,
handleCommandGuildElderRefusePacketRes
} from "../../commands/guild/GuildElderCommand";

export default class CommandHandlers {
@packetHandler(CommandPingPacketRes)
Expand Down Expand Up @@ -301,6 +313,36 @@ export default class CommandHandlers {
await handleCommandGuildKickAcceptPacketRes(packet, context);
}

@packetHandler(CommandGuildElderSameGuildPacketRes)
async guildElderSameGuildRes(packet: CommandGuildElderSameGuildPacketRes, context: PacketContext): Promise<void> {
await handleClassicError(context, "commands:guildElder.notSameGuild");
}

@packetHandler(CommandGuildElderHimselfPacketRes)
async guildElderHimselfRes(packet: CommandGuildElderHimselfPacketRes, context: PacketContext): Promise<void> {
await handleClassicError(context, "commands:guildElder.chiefError");
}

@packetHandler(CommandGuildElderAlreadyElderPacketRes)
async guildElderAlreadyElderRes(packet: CommandGuildElderAlreadyElderPacketRes, context: PacketContext): Promise<void> {
await handleClassicError(context, "commands:guildElder.alreadyElder");
}

@packetHandler(CommandGuildElderFoundPlayerPacketRes)
async guildElderFoundPlayerRes(packet: CommandGuildElderFoundPlayerPacketRes, context: PacketContext): Promise<void> {
await handleClassicError(context, "commands:guildElder.playerNotFound");
}

@packetHandler(CommandGuildElderRefusePacketRes)
async guildElderRefuseRes(packet: CommandGuildElderRefusePacketRes, context: PacketContext): Promise<void> {
await handleCommandGuildElderRefusePacketRes(packet, context);
}

@packetHandler(CommandGuildElderAcceptPacketRes)
async guildElderAcceptRes(packet: CommandGuildElderAcceptPacketRes, context: PacketContext): Promise<void> {
await handleCommandGuildElderAcceptPacketRes(packet, context);
}


@packetHandler(CommandInventoryPacketRes)
async inventoryRes(packet: CommandInventoryPacketRes, context: PacketContext): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import {smallShopCollector} from "../../smallEvents/shop";
import {epicItemShopCollector} from "../../smallEvents/epicItemShop";
import {ReactionCollectorEpicShopSmallEventData} from "../../../../Lib/src/packets/interaction/ReactionCollectorEpicShopSmallEvent";
import {ReactionCollectorShopSmallEventData} from "../../../../Lib/src/packets/interaction/ReactionCollectorShopSmallEvent";
import {createGuildElderCollector} from "../../commands/guild/GuildElderCommand";
import {ReactionCollectorGuildElderData} from "../../../../Lib/src/packets/interaction/ReactionCollectorGuildElder";

export default class ReactionCollectorHandler {

Expand All @@ -52,6 +54,7 @@ export default class ReactionCollectorHandler {
ReactionCollectorHandler.collectorMap.set(ReactionCollectorPetFreeData.name, createPetFreeCollector);
ReactionCollectorHandler.collectorMap.set(ReactionCollectorGuildCreateData.name, createGuildCreateCollector);
ReactionCollectorHandler.collectorMap.set(ReactionCollectorGuildKickData.name, createGuildKickCollector);
ReactionCollectorHandler.collectorMap.set(ReactionCollectorGuildElderData.name, createGuildElderCollector);
ReactionCollectorHandler.collectorMap.set(ReactionCollectorLotteryData.name, lotteryCollector);
ReactionCollectorHandler.collectorMap.set(ReactionCollectorInteractOtherPlayersPoorData.name, interactOtherPlayersCollector);
ReactionCollectorHandler.collectorMap.set(ReactionCollectorWitchData.name, witchCollector);
Expand Down
10 changes: 10 additions & 0 deletions Lang/en/discordBuilder.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@
}
}
},
"guildElder": {
"description": "Promote a guild member to elder.",
"name": "guildelder",
"options": {
"user": {
"description": "The user who will be promoted as an elder.",
"name": "user"
}
}
},
"profile": {
"description": "Displays the profile of a player.",
"name": "profile",
Expand Down
Loading

0 comments on commit b972734

Please sign in to comment.