Creeps can't detect when they enter a new room



  • Re: ERR_NO_PATH when creep moveTo flag in another room

    Hello!

    I am trying to expand into another room but I'm running into the issue where creeps are stuck on the exit, going back and forth between rooms. I tried a lot of solutions, read a ton of posts and docs, but nothing helped. So, I'll try to explain in as much detail possible everything I tried and what were the results in order if someone can help me figure out what I am getting wrong (most likely) or if there's an actual problem with the game.

    First, I played the game maybe a year ago locally on my machine and managed to get working harvesting and building in two adjacent rooms. I remember that I had this issue back then, but have been able to solve it after all.

    Code that I used is the following:

    harvester code:

    module.exports = {
        run: function(creep) {
            if (creep.memory.working && creep.carry.energy === creep.carryCapacity) {
                creep.memory.working = false;
                creep.say('delivering');
            } else if (!creep.memory.working && creep.carry.energy === 0) {
                creep.memory.working = true;
                creep.say('harvesting');
            }
            
            // bring the dude home if he's stuck
            // const storageStructure = Game.rooms[creep.memory.storageRoom].storage;
            // creep.moveTo(storageStructure, {visualizePathStyle: {stroke: '#00ff00'}});
    
            if (creep.memory.working) {
                // console.log('working');
                // console.log('room', creep.room.name);
                // console.log('target room', creep.memory.targetRoom);
                if (creep.room.name === creep.memory.targetRoom) {
                    console.log('here'); // this never runs, even when the creep is in the targetRoom
                    const energySource = creep.pos.findClosestByPath(FIND_SOURCES, {
                        filter: source => source.energy > 0
                    });
                    if (creep.harvest(energySource) === ERR_NOT_IN_RANGE) {
                        creep.moveTo(energySource, {visualizePathStyle: {stroke: '#007700'}});
                    }
                } else {
                    // console.log('move to exit'); // this runs only in the home room
                    const exitDirection =  creep.room.findExitTo(creep.memory.targetRoom);
                    const exitRoom = creep.pos.findClosestByPath(exitDirection);
                    creep.moveTo(exitRoom);
                }
            } else {
                console.log('not working'); // it never gets to this of course
                if (creep.room.name !== creep.memory.targetRoom) {
                    const storageStructure = Game.rooms[creep.memory.storageRoom].storage;
                    if (creep.transfer(storageStructure, RESOURCE_ENERGY) === ERR_NOT_IN_RANGE) {
                        creep.moveTo(storageStructure, {visualizePathStyle: {stroke: '#00ff00'}});
                    }
                } else {
                    const exitDirection =  creep.room.findExitTo(creep.memory.storageRoom);
                    const exitRoom = creep.pos.findClosestByPath(exitDirection);
                    creep.moveTo(exitRoom);
                }
            }
        }
    };
    

    I removed the code that I used to create and run them, but I wrote a new one to test it locally again:

    I was creating them with:

            const targetRoom = 'W8N2';
            const storageRoom = 'W8N3';
            firstSpawnInRoom.spawnCreep(body, `H-${targetRoom}-${getCreepName()}`, {
                memory: {
                    role: 'harvesterExternal',
                    working: false,
                    targetRoom: targetRoom,
                    storageRoom: storageRoom
                }
            });
    

    and runing them with:

        const creepNamesInGame = Object.keys(Game.creeps);
        creepNamesInGame && creepNamesInGame.forEach(name => {
            const creep = Game.creeps[name];
            const role = creep.memory.role;
            creepRoles[role].run(creep);
        });
    

    They get created fine and go to the correct exit, and then they get stuck going back and forth. So, the creep code above was the code that worked a year ago, but now it doesn't work, and I don't think other two pieces of code are creating problems.

    Now, here's everything I tried in a game in the World.

    The idea was to have a flag in the other room, find a flag, create a creep, make it move to the flag and once it is in the room where the flag is, find the controller and move to it/claim or whatever.

    The creep code with details explained and with some alternative ways I tried to solve this:

    const logObject = require('util.logObject');
    const { visualizePath } = require('util.functions');
    
    const getNextRoomName = (currentRoomName, pathThroughRooms) => {
        // return the name of the next room in the path
        // when in the target room, other condition will prevent calling this function
        const roomIndex = pathThroughRooms.indexOf(currentRoomName);
        return pathThroughRooms[roomIndex + 1];
    };
    
    module.exports = {
        run: function(creep) {
            // there is the issue of moving through another room;
            // looks like the swapm terrain is preventing creeps from properly moving
            // I have to make sure that the creep enters new room at the position with no swamp // THIS IS DONE - DOESN'T HELP
    
            // all of the following properties/objects are passed correctly:
            const flagName = creep.memory.flagName;
            const flag = Game.flags[flagName];
            const targetRoomName = flag.pos.roomName;
            const currentRoomName = creep.room.name;
    
            // try findPathTo; from the docs example
            // the path array only contains the points in the current room;
            // I guess that's fine, the problem is when the creeps exits the room, the path is empty array
    
            // const path = creep.pos.findPathTo(flag);
            // logObject(path);
            // if (path.length > 0) {
            //     const moveOutput = creep.move(path[0].direction);
            //     console.log(moveOutput); // for debugging
            // }
    
            console.log('target', targetRoomName);
            console.log('current', currentRoomName); // it never reads the name of the other room, only for the home room
    
            if (currentRoomName !== targetRoomName) {
                // in the home room, everything is read properly
                // once out of the home room, it's like the creep is in limbo
    
                // move room by room
                 // look for the exit towards the next room in the `pathThroughRooms` array (array of room names)
                // const pathThroughRooms = creep.memory.pathThroughRooms;
                // logObject(pathThroughRooms); // reads fine
                // const nextRoomName = getNextRoomName(currentRoomName, pathThroughRooms);
                // const exitDirection =  creep.room.findExitTo(nextRoomName);
                // const exitRoom = creep.pos.findClosestByPath(exitDirection);
                // const moveOutput = creep.moveTo(exitRoom, visualizePath('#ff0000'));
    
                // console.log('next', nextRoomName);
                
                // move to flag; docs suggest this
                const moveOutput = creep.moveTo(flag, visualizePath('#ff0000'));
    
                // this returns 0 while moving toward the home room exit
                // when creep exits the home room, it returns nothing since this whole `if` block does not execute, in fact, the whole script does not execute
                // when the creeps goes back to the home room, it starts outputing -2, can't find path, but again, only when it is in the home room
                console.log(moveOutput);
    
                console.log('target', targetRoomName);
                console.log('current', currentRoomName);
            } else {
                // this part is, of course, never reached
                console.log('where I am?');
                if(creep.room.controller && !creep.room.controller.my) {
                    // if(creep.attackController(creep.room.controller) == ERR_NOT_IN_RANGE) {
                        creep.moveTo(creep.room.controller);
                    // }
                }
            }
        }
    };
    

    In the main module, I have this code to check if the creep should be created:

    const creatingClaimer = false;
    
    Object.keys(Game.flags).forEach(flagName => {
        if (flagName.indexOf('ControllerToClaim') === -1) return;
    
        creatingClaimer = Object.keys(Game.creeps).every(creepName => Game.creeps[creepName].memory.role !== 'claimer');
    
        if (!creatingClaimer) return;
    
        flagNameToClaim = flagName;
    });
    

    Then, among other checks, I have this:

    if (creatingClaimer) {
        // firstSpawnInRoom.spawnCreep([CLAIM, CLAIM, MOVE, MOVE, MOVE, MOVE, MOVE, MOVE], `C-${name}-${getCreepName()}`, setCreepMemory('claimer', { flagName: flagNameToClaim }));
        firstSpawnInRoom.spawnCreep([MOVE,MOVE], `SCOUT-${name}-${getCreepName()}`, setCreepMemory('claimer', {
            flagName: flagNameToClaim,
            homeRoom: name,
            pathThroughRooms: [ 'W32N45' ]
        }));
    }
    

    And at the end I run all creeps same as I showed for the local game I have:

    const creepNamesInGame = Object.keys(Game.creeps);
    creepNamesInGame && creepNamesInGame.forEach(name => {
        const creep = Game.creeps[name];
        const role = creep.memory.role;
        creepRoles[role].run(creep);
    });
    

    So, I want to go into the room that is two tiles away, there's one room between my home room and the target room. the path is clear, no obstacles. I also made sure that the creep does not enter the new room at the place where the terrain is swamp. I also tried to move the flag into the room between the target room and my home room, but the result was the same. I also tried to give it hardcoded position in the adjacent room, still nothing. I tried using flag object and flag.pos property of the flag object, no good.

    I also tried adding maxOps setting as suggested in the referenced thread, but still didn't help. I liked the idea suggested in the last post there, but I don't think it will help since, after all of this, I figured out that the creep simply does not detect when it is in the other room and that is the root of the issue.

    If anyone could help me and point me in the right direction how to determine if the creep knows that it is in the another room I believe that will solve this issue.

    Any help greatly appreciated! Thanks for reading through all of this!


  • Dev Team

    @gruximillian I'd try to create a minimal reproduce code which could work with empty main. This would either help to find an issue in code (if it's there) or properly report a bug (if it's on the engine side)



  • @o4kapuk Thank you very much!



  • @o4kapuk

    I have managed to find the problem. It was a mistake on my end, as I suspected and your suggestion to try with empty Main module helped to quickly identify the problem spot. Funny thing is that, just one keyword change did it.

    The reason was that I my Main module I had this for loop and condition:

        for (const name in Game.rooms) {
            const room = Game.rooms[name];
            if (!settings[name]) return;
            // .... rest of the room specific code
        }
    

    I wasn't aware that when my creep enters a new room, it is listed in Game.rooms object even though it is not my room. In settings[name] I am keeping room settings. When the creep gets into a room that is not in my list, then settings[name] is undefined and return makes an early exit from the Main module and skips all other code execution. That was the reason for another side effect where my other creeps stopped all actions while the scout creep is in the other room. I somehow made myself think that this return only returns from the for loop (god knows why! maybe I was thinking about forEach callback) and not from the entire module. So, a quick change from return to continue did the trick:

        for (const name in Game.rooms) {
            const room = Game.rooms[name];
            if (!settings[name]) continue;
            // .... rest of the room specific code
        }
    

    After that I tested all of the approaches for getting into the target room, and they all worked, where the one that used the pathThroughRooms array only needed to include the target room name in the array as well.

    So, I'd say that this is solved and I hope that the details I provided will help someone else in the future if they encounter a similar issue.

    Thanks for pointing me in the right direction!!


  • Dev Team

    @gruximillian

    Thanks for pointing me in the right direction!!

    You're welcome!