v12 不会删除机器人的反应,但 v13 会删除机器人的反应 (discord.js)

v12 doesn't remove bot's react, but v13 remove bot's react (discord.js)

在命令从v12升级到v13的过程中,我发现命令删除了它自己创建的bot反应,而v12没有。

两个机器人都有管理员权限。 v12 来自 djs-games module, game connect four。我将 v12 改进为 v13

v12 :

const discord = require('discord.js')

class ConnectFour {

    constructor() {
        this.gameEmbed = null
    }

    startGame (msg) {

        const challenger = msg.author;
        const oppenent = msg.mentions.users.first();

        if(!oppenent) return msg.channel.send(`**With whom do you wanna play Connect Four?**`)
         
        const board = [
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
        ];

        const renderBoard = (board) => {
            let tempString = "";
            for (const boardSection of board) {
                tempString += `${boardSection.join("")}\n`;
            }

            tempString = tempString.concat("1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣");
            return tempString;
        }

        const initialState = renderBoard(board);

        const initial = new discord.MessageEmbed()
        .setTitle(` ${msg.author.username} its your turn!`)
        .setDescription(initialState)
        .setFooter(`${challenger.username} vs ${oppenent.username}`)
        msg.channel.send(initial).then(gameMessage => {

            gameMessage.react("1️⃣")
            gameMessage.react("2️⃣")
            gameMessage.react("3️⃣")
            gameMessage.react("4️⃣")
            gameMessage.react("5️⃣")
            gameMessage.react("6️⃣")
            gameMessage.react("7️⃣")
    
            const gameFilter = (reaction, user) => ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣"].includes(reaction.emoji.name) && (user.id === oppenent.id || user.id === challenger.id);
    
            const gameCollector = gameMessage.createReactionCollector(gameFilter);
    
            const gameData = [
                { member: challenger, playerColor: "" },
                { member: oppenent, playerColor: ""}
            ]
    
            let player = 0;
    
            const checkFour = (a, b, c, d) => (a === b) && (b === c) && (c === d) && (a !== "⚪");
    
            const horizontalCheck = () => {
    
                for (let i = 0; i < 6; i++) {
    
                    for (let j = 0; j < 4; j++) {
                        if(checkFour(board[i][j], board[i][j + 1], board[i][j + 2], board[i][j + 3])) return [
                            board[i][j], board[i][j + 1], board[i][j + 2], board[i][j + 3]
                        ];
                    }
                }
            }
    
            const verticalCheck = () => {
                for (let j = 0; j < 7; j++) {
                    for (let i = 0; i < 3; i++) {
    
                        if(checkFour(board[i][j], board[i + 1][j], board[i + 2][j], board[i + 3][j])) return [
                            board[i][j], board[i + 1][j], board[i + 2][j], board[i + 3][j]
                        ]
                    }
                }
            }
    
            const diagonal1 = () => {
                for (let col = 0; col < 4; col++) {
                    for (let row = 0; row < 3; row++) {
                        if(checkFour(board[row][col], board[row + 1][col + 1], board[row + 2][col + 2], board[row + 3][col + 3])) return [
                            board[row][col], board[row + 1][col + 1], board[row + 2][col + 2], board[row + 3][col + 3]
                        ]
                    }
                }
            }
    
            const diagonal2 = () => {
                for (let col = 0; col < 4; col++) {
                    for (let row = 5; row > 2; row--) {
                        if(checkFour(board[row][col], board[row - 1][col + 1], board[row - 2][col + 2], board[row - 3][col + 3])) return [
                            board[row][col], board[row - 1][col + 1], board[row - 2][col + 2], board[row - 3][col + 3]
                        ]
                    }
                }
            }
    
            const tieCheck = () => {
                let count = 0;
                for (const el of board) {
                    for (const string of el) {
                        if(string !== "⚪") count++;
                    }
                }
                if(count === 42) return true;
                else return false;
            }
    
            const checks = [horizontalCheck, verticalCheck, diagonal1, diagonal2];
    
            gameCollector.on("collect", (reaction, user) => {
    
                reaction.message.reactions.cache.get(reaction.emoji.name).users.remove(user.id);
    
                if(user.id === gameData[player].member.id) {
    
                    const openSpaces = [];
    
                    switch (reaction.emoji.name) {
                        case "1️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][0] === "⚪") openSpaces.push({ i, j: 0});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "2️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][1] === "⚪") openSpaces.push({ i, j: 1});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "3️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][2] === "⚪") openSpaces.push({ i, j: 2});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "4️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][3] === "⚪") openSpaces.push({ i, j: 3});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "5️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][4] === "⚪") openSpaces.push({ i, j: 4});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "6️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][5] === "⚪") openSpaces.push({ i, j: 5});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "7️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][6] === "⚪") openSpaces.push({ i, j: 6});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                    }
    
                    if(tieCheck()) {
                        gameMessage.reactions.removeAll()
                        const TieEmbed = new discord.MessageEmbed()
                        .setTitle(`The game ended, it is Tie!`)
                        .setDescription(renderBoard(board))
                        .setFooter(`${challenger.username} vs ${oppenent.username}`)
                        gameCollector.stop("Tie Game")
                        return gameMessage.edit(TieEmbed)
                    }
    
                    for (const func of checks) {
    
                        const data = func();
                        if(data) {
                            gameMessage.reactions.removeAll()
    
                            const WinEmbed = new discord.MessageEmbed()
                            .setTitle(`${gameData[player].member.username} has won the game!`)
                            .setDescription(renderBoard(board))
                            .setFooter(`${challenger.username} vs ${oppenent.username}`)
                            gameCollector.stop(`${gameData[player].member.id} won`);
                            return gameMessage.edit(WinEmbed)
                        }
                    }
    
                    player = (player + 1) % 2;
    
                    const newEmbed = new discord.MessageEmbed()
                    .setTitle(`${gameData[player].playerColor} - ${gameData[player].member.username} its your turn!`)
                    .setDescription(renderBoard(board))
                    .setFooter(`${challenger.username} vs ${oppenent.username}`)
                    gameMessage.edit("", { embed: newEmbed});
                }
            })
        })

    }


}

module.exports = ConnectFour;

v13 :

const discord = require('discord.js')

class ConnectFour {

    constructor() {
        this.gameEmbed = null
    }

    startGame (msg) {

        const challenger = msg.author;
        const oppenent = msg.mentions.users.first();

        if(!oppenent) return msg.channel.send(`**With whom do you wanna play Connect Four?**`)
         
        const board = [
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
            ["⚪", "⚪", "⚪", "⚪", "⚪", "⚪", "⚪"],
        ];

        const renderBoard = (board) => {
            let tempString = "";
            for (const boardSection of board) {
                tempString += `${boardSection.join("")}\n`;
            }

            tempString = tempString.concat("1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣");
            return tempString;
        }

        const initialState = renderBoard(board);

        const initial = new discord.MessageEmbed()
        .setTitle(` ${msg.author.username} its your turn!`)
        .setDescription(initialState)
        .setFooter(`${challenger.username} vs ${oppenent.username}`)
        msg.channel.send({embeds : [initial]}).then(gameMessage => {

            gameMessage.react("1️⃣")
            gameMessage.react("2️⃣")
            gameMessage.react("3️⃣")
            gameMessage.react("4️⃣")
            gameMessage.react("5️⃣")
            gameMessage.react("6️⃣")
            gameMessage.react("7️⃣")
    
            const gameFilter = (reaction, user) => ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣"].includes(reaction.emoji.name) && (user.id === oppenent.id || user.id === challenger.id);
    
            const gameCollector = gameMessage.createReactionCollector(gameFilter);
    
            const gameData = [
                { member: challenger, playerColor: "" },
                { member: oppenent, playerColor: ""}
            ]
    
            let player = 0;
    
            const checkFour = (a, b, c, d) => (a === b) && (b === c) && (c === d) && (a !== "⚪");
    
            const horizontalCheck = () => {
    
                for (let i = 0; i < 6; i++) {
    
                    for (let j = 0; j < 4; j++) {
                        if(checkFour(board[i][j], board[i][j + 1], board[i][j + 2], board[i][j + 3])) return [
                            board[i][j], board[i][j + 1], board[i][j + 2], board[i][j + 3]
                        ];
                    }
                }
            }
    
            const verticalCheck = () => {
                for (let j = 0; j < 7; j++) {
                    for (let i = 0; i < 3; i++) {
    
                        if(checkFour(board[i][j], board[i + 1][j], board[i + 2][j], board[i + 3][j])) return [
                            board[i][j], board[i + 1][j], board[i + 2][j], board[i + 3][j]
                        ]
                    }
                }
            }
    
            const diagonal1 = () => {
                for (let col = 0; col < 4; col++) {
                    for (let row = 0; row < 3; row++) {
                        if(checkFour(board[row][col], board[row + 1][col + 1], board[row + 2][col + 2], board[row + 3][col + 3])) return [
                            board[row][col], board[row + 1][col + 1], board[row + 2][col + 2], board[row + 3][col + 3]
                        ]
                    }
                }
            }
    
            const diagonal2 = () => {
                for (let col = 0; col < 4; col++) {
                    for (let row = 5; row > 2; row--) {
                        if(checkFour(board[row][col], board[row - 1][col + 1], board[row - 2][col + 2], board[row - 3][col + 3])) return [
                            board[row][col], board[row - 1][col + 1], board[row - 2][col + 2], board[row - 3][col + 3]
                        ]
                    }
                }
            }
    
            const tieCheck = () => {
                let count = 0;
                for (const el of board) {
                    for (const string of el) {
                        if(string !== "⚪") count++;
                    }
                }
                if(count === 42) return true;
                else return false;
            }
    
            const checks = [horizontalCheck, verticalCheck, diagonal1, diagonal2];
    
            gameCollector.on("collect", (reaction, user) => {
    
                reaction.message.reactions.cache.get(reaction.emoji.name).users.remove(user.id);
    
                if(user.id === gameData[player].member.id) {
    
                    const openSpaces = [];
    
                    switch (reaction.emoji.name) {
                        case "1️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][0] === "⚪") openSpaces.push({ i, j: 0});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "2️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][1] === "⚪") openSpaces.push({ i, j: 1});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "3️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][2] === "⚪") openSpaces.push({ i, j: 2});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "4️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][3] === "⚪") openSpaces.push({ i, j: 3});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "5️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][4] === "⚪") openSpaces.push({ i, j: 4});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "6️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][5] === "⚪") openSpaces.push({ i, j: 5});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                        case "7️⃣":
                            for (let i = 5; i > -1 ; i--) {
                                if(board[i][6] === "⚪") openSpaces.push({ i, j: 6});
                            }
                            if(openSpaces.length == 0) return msg.channel.send(`**${gameData[player].member}, that column is already full. Choose another one**`).then(msg1 => msg1.delete({timeout: 10000}))
                            else board[openSpaces[0].i][openSpaces[0].j] = gameData[player].playerColor;
                        break;
                    }
    
                    if(tieCheck()) {
                        gameMessage.reactions.removeAll()
                        const TieEmbed = new discord.MessageEmbed()
                        .setTitle(`The game ended, it is Tie!`)
                        .setDescription(renderBoard(board))
                        .setFooter(`${challenger.username} vs ${oppenent.username}`)
                        gameCollector.stop("Tie Game")
                        return gameMessage.edit({embeds : [TieEmbed]})
                    }
    
                    for (const func of checks) {
    
                        const data = func();
                        if(data) {
                            gameMessage.reactions.removeAll()
    
                            const WinEmbed = new discord.MessageEmbed()
                            .setTitle(`${gameData[player].member.username} has won the game!`)
                            .setDescription(renderBoard(board))
                            .setFooter(`${challenger.username} vs ${oppenent.username}`)
                            gameCollector.stop(`${gameData[player].member.id} won`);
                            return gameMessage.edit({embeds : [WinEmbed]})
                        }
                    }
    
                    player = (player + 1) % 2;
    
                    const newEmbed = new discord.MessageEmbed()
                    .setTitle(`${gameData[player].playerColor} - ${gameData[player].member.username} its your turn!`)
                    .setDescription(renderBoard(board))
                    .setFooter(`${challenger.username} vs ${oppenent.username}`)
                    gameMessage.edit({embed: [newEmbed]});
                }
            })
        })

    }


}

module.exports = ConnectFour;

输出:

我认为原因是:

reaction.message.reactions.cache.get(reaction.emoji.name).users.remove(user.id); //line 122

在 v13 中,机器人自动删除了它自己创建的反应。 我希望机器人不会那样自动删除,以便用户可以轻松交互。

如果有任何错误,请原谅我,因为我是这门编程语言的新手。

谢谢!

所以为了让它在 discord.js v13 上运行,我必须做一些事情。

要收集公会用户的反应,您需要 GUILD_MESSAGE_REACTIONS 意图。所以我将其添加到 client 的意图中。

const client = new Discord.Client({ intents: ["GUILDS", "GUILD_MESSAGES", "GUILD_MESSAGE_REACTIONS"] });

接下来,他们更改了您为 Message.createReactionCollector() 指定过滤器的方式。所以我相应地更新了代码。

const gameCollector = gameMessage.createReactionCollector({ filter: gameFilter });

最后,要编辑带有嵌入的消息,您需要将 newEmbed 放在 属性 的数组中 embeds 放在 MessageEditOptions 的数组中。您在 embeds 末尾遗漏了“s”,这可能是一个错误,因为在其他任何地方您都正确地使用了它。

gameMessage.edit({embeds: [newEmbed]});

结果是一个运行良好的游戏:)