PrismarineJS / mineflayer-collectblock

A simple utility plugin for Mineflayer that add a higher level API for collecting blocks.
MIT License
39 stars 25 forks source link

Bot stays looking at the chests. #65

Closed barbarbar338 closed 3 years ago

barbarbar338 commented 3 years ago

When i say "collect dirt", bot stays looking at the chests like this: https://i.imgur.com/UkAyi4t.png this is bot's inventory: https://i.imgur.com/hWk1IJt.png and this is my console: https://i.imgur.com/sND3VwT.png

i changed plugin's code to see what's going on and this is the code

// mineflayer-collectblock Inventory.js, line 67
function gotoChest(bot, location, cb) {
    console.log(location); // added this
    const pathfinder = bot.pathfinder;
    pathfinder.setGoal(new mineflayer_pathfinder_1.goals.GoalBlock(location.x, location.y, location.z));
    const events = new mineflayer_utils_1.TemporarySubscriber(bot);
    events.subscribeTo('goal_reached', () => {
        console.log("goal_reached"); // added this
        events.cleanup();
        cb();
    });
    events.subscribeTo('path_update', (results) => {
        console.log("path_update"); // added this -- spams this line to console
        if (results.status === 'noPath') {
            events.cleanup();
            cb(Util_1.error('NoPath', 'No path to target block!'));
        }
    });
    events.subscribeTo('goal_updated', () => {
        console.log("goal_updated"); // added this
        events.cleanup();
        cb(Util_1.error('PathfindingInterrupted', 'Pathfinding interrupted before item could be reached.'));
    });
}

my fetch chest code:

public fetchChests(bot: Bot, minecraft_data: IndexedData) {
        bot.collectBlock.chestLocations = bot.findBlocks({
            matching: minecraft_data.blocksByName.chest.id,
            maxDistance: 32,
            count: 999999,
        });
        if (bot.collectBlock.chestLocations.length === 0) {
            bot.chat(
                `I don't see any chests nearby. You may need to assist me when my inventory is full. (or place some chests and use the "${CONFIG.PREFIX}chest" command.)`,
            );
        } else
            bot.chat(
                `I see ${bot.collectBlock.chestLocations.length} chest(s) nearby. I'll use them when my inventory is full.`,
            );
}

and my collect code:

    public collectBlock(bot: Bot, blockID: number, count?: number) {
        const limit = count || 1;
        return new Promise((resolve, reject) => {
            const blocks = bot.findBlocks({
                matching: blockID,
                maxDistance: 64,
                count: limit,
            });
            if (blocks.length < 1) {
                bot.chat("I don't see that block nearby.");
                resolve(false);
            } else {
                const targets = [];
                for (let i = 0; i < Math.min(blocks.length, limit); i++) {
                    targets.push(bot.blockAt(blocks[i]));
                }
                bot.chat(
                    `Found ${targets.length} block(s), starting to collect them.`,
                );
                bot.collectBlock.collect(targets, (err) => {
                    if (err) {
                        console.log(err);
                        reject(err);
                    } else resolve(true);
                });
            }
        });
    }
SeanMcCord commented 3 years ago

I had the same issue a few days ago. Right now there are a few issues with the chest interactions in collectblock. One is the goal type GoalBlock should be GoalGetToBlock as right now the bot is attempting to move to the position the chest occupies. I've mentioned this in pr 53 and I just made a focused pr for this issue #66 . Additionally there are issues with the way collectblock attempts to place items into the chest. In my opinion the steps forward are

p.s. I appreciate you adding logging. Would you mind showing an example output. I'm assuming that the bot doesn't reach its goal and therefore does not log 'goal_reached'.

barbarbar338 commented 3 years ago

it just spams "path_update" and does nothing (does not logs "goal_reached" or anything). When I tell bot to come to me with another "pathfinding" command when it is stuck where it is, im getting "PathfindingInterrupted: Pathfinding interrupted before item could be reached." error as it should be: https://i.imgur.com/dJmiC9b.png

SeanMcCord commented 3 years ago

Thanks. If you change the goal in function gotoChest in mineflayer-collectblock/lib/Inventory.js from

pathfinder.setGoal(new mineflayer_pathfinder_1.goals.GoalBlock(location.x, location.y, location.z));

to

pathfinder.setGoal(new mineflayer_pathfinder_1.goals.GoalGetToBlock(location.x, location.y, location.z));

You should find that the bot does emit 'goal_reached' now; however, it fails to empty its inventory.

barbarbar338 commented 3 years ago

as you said, it opens chest but says "TypeError: chest.once is not a function" open chest: https://i.imgur.com/Xur7ioW.png error and code: https://i.imgur.com/xndj7YR.png

API says "Returns a promise on a Container instance which represents the container you are opening.". Lemme see whats going on when use async await

barbarbar338 commented 3 years ago

i changed this line with (chest.items.length >= chest.inventoryStart) and it stored one stack of items. but then gave "TypeError: Cannot read property 'type' of null": https://i.imgur.com/HuT5o9y.png - mineflayer/lib/plugins/inventory.js, line 223 (window.selectedItem comes "null")

barbarbar338 commented 3 years ago

also changed openChest as openContainer and used promises, here is the result:

// Inventory.js, line 87
function placeItems(bot, chestPos, itemFilter, cb) {
    const chestBlock = bot.blockAt(chestPos);
    if (chestBlock == null) {
        cb(Util_1.error('UnloadedChunk', 'Chest is in an unloaded chunk!'), true);
        return;
    }
    try {
        let itemsRemain = false;
        bot.openContainer(chestBlock).then(chest => {
            const tryDepositItem = (item, cb) => {
                // @ts-expect-error ; A workaround for checking if the chest is already full
                console.log(chest);
                if (chest.items().length >= chest.inventoryStart) {
                    // Mark that we have items that didn't fit.
                    itemsRemain = true;
                    cb();
                    return;
                }
                chest.deposit(item.type, item.metadata, item.count, cb);
            };
            const taskQueue = new mineflayer_utils_1.TaskQueue();
            for (const item of bot.inventory.items()) {
                if (itemFilter(item)) {
                    taskQueue.add(cb => tryDepositItem(item, cb));
                }
            }
            taskQueue.addSync(() => chest.close());
            taskQueue.runAll((err) => {
                if (err != null) {
                    cb(err, true);
                    return;
                }
                cb(undefined, itemsRemain);
            });
        })
    }
    catch (err) {
        // Sometimes open chest will throw a few asserts if block is not a chest
        cb(err, true);
    }
}
barbarbar338 commented 3 years ago

well, I tried putting items into the chest with the command and realized that the error was caused by the Mineflayer. sometimes it puts the items and sometimes gives this error: https://i.imgur.com/9LXOPvk.png

i'll create an issue on mineflayer

barbarbar338 commented 3 years ago

Once again I was wrong :D error was caused by the mineflayer-web-inventory plugin. I found this issue and removed mineflayer-web-inventory from my code and it worked :^)

i changed pathfinder.setGoal(new mineflayer_pathfinder_1.goals.GoalBlock(location.x, location.y, location.z)); to pathfinder.setGoal(new mineflayer_pathfinder_1.goals.GoalGetToBlock(location.x, location.y, location.z)); and placeItems to:

function placeItems(bot, chestPos, itemFilter, cb) {
    const chestBlock = bot.blockAt(chestPos);
    if (chestBlock == null) {
        cb(Util_1.error('UnloadedChunk', 'Chest is in an unloaded chunk!'), true);
        return;
    }
    try {
        let itemsRemain = false;
        bot.openChest(chestBlock).then(chest => { // used promise
            const tryDepositItem = (item, cb) => {
                // @ts-expect-error ; A workaround for checking if the chest is already full
                if (chest.items().length >= chest.inventoryStart) { // removed window
                    // Mark that we have items that didn't fit.
                    itemsRemain = true;
                    cb();
                    return;
                }
                chest.deposit(item.type, item.metadata, item.count, cb);
            };
            const taskQueue = new mineflayer_utils_1.TaskQueue();
            for (const item of bot.inventory.items()) {
                if (itemFilter(item)) {
                    taskQueue.add(cb => tryDepositItem(item, cb));
                }
            }
            taskQueue.addSync(() => chest.close());
            taskQueue.runAll((err) => {
                if (err != null) {
                    cb(err, true);
                    return;
                }
                cb(undefined, itemsRemain);
            });
        });
    }
    catch (err) {
        // Sometimes open chest will throw a few asserts if block is not a chest
        cb(err, true);
    }
}

in mineflayer-collectblock/lib/Inventory.js and it works