ERR_NO_PATH & hard reset : stuck moving to another room



  • I have made a 'scout' creep that explores the whole map over time. It works fine for a long time. But eventually the creep gets 'stuck' on the edge between two rooms. All pathfinding, including moveTo, returns ERR_NO_PATH even though the creep is literally in the target room with clear space ahead of it. I notice that visually the creep bounces between the target room and previous room, but creep.pos.roomName always gives the previous room name - it doesn't seem to recognise when it makes it across the edge.

    My code executes completely, but then I get a cpu hard reset every single tick. Commenting out the scout code gets rid of the hard reset. NB I normally have a full bucket - the code is nowhere near to exhausting the cpu.

    I have re-written my code in different ways and I always eventually get this problem. I can't rule out that the fault is mine, but I been over this carefully for a long time and not found a fault. Moreover, as above, things work fine for many many rooms and then suddenly don't work.

    Using steam client private server 2.10.2 with setTickRate mod only. db.json emailed.


  • Dev Team

    Hello ignarl,

    Could you please check your entire scout code and ensure that you compare creep.pos.roomName and creep.pos correctly (I mean, with '==' or '===', but not '=')? This mistake could give a result similar to what you described.



  • I checked again but can't see a bad compare.

    I've posted my code below. Obviously it depends on code that depends on code... and I haven't posted the whole code base.

     

    Some observations.

    This works fine for a long time. There is only one scout creep at a time. When it dies, a new one is made and picks up where the old one left off. The scout(s) explores all 121 rooms and manages to re-check previously scouted rooms after this.

     

    I have a maxOps 50000 as some of the paths get long. I fall back to map.findRoute because routes can get longer than 16 rooms which causes other pathfinders to fail. (The first iteration used findRoute as a first resort, but I completely re-wrote the code more than once with different approaches to try to solve this bug - each time I get the same thing. This is why it might seem over-engineered - I tried more and more convoluted approaches).

     

    The code seems to execute fine even with a hard reset. I get the final "Scout code executed" logged, and in fact I have a final console.log as the last thing in main() which also gets executed. The pattern seems to be that everything gets executed but then there is a pause and a cpu reset each tick. Everything seems to work OK, except that the scout gets jammed on an edge.

     

    There are two main branches: one where the scout arrives in its target room and one where it it doesn't. Note that the bug occurs when I can see that the scout has arrived (bouncing on the edge) - but it doesn't recognise this and stays in the branch for not being in the target room every tick.

     

    Line 49 contains a work around that just kills the creep when things go wrong:

    if (moveResult == ERR_NO_PATH)

                        creep.suicide(); // work around cpu reset bug

     

    Scouting.closestTargetRoom and oldestScoutedRoom return either a room name or null. The debugging console logs do not appear to indicate anything wrong with the values returned by these functions.

     

    I emailed my db to you in connection with another bug. I can email the whole codebase if you want - although I think the code is in the db. I apologise if the fault is mine, which is certainly possible since I'm new to screeps and javascript. I wouldn't dream of asking someone to fix my code. But in this case, having spent a lot of time, I think it's at least possible it's a bug in Screeps.

     

    After the listing I include sample output from the console.logs (this is after commenting out the suicide() above to re-introduce the error).

    You can see that it is stuck at position y:0 in room W2N9 and never gets to the target room W2N10 from a console.log(JSON.stringify(creep.pos)).

    In fact I see it enter W2N10 (screenshot) and bounce back-and-forth.

     

    The last line of my script, in the main function is:

     

    console.log("Total cpu use " + Game.cpu.getUsed() + " limit "+Game.cpu.limit+" tickLimit "+Game.cpu.tickLimit+" bucket "+Game.cpu.bucket);

     

    This executes fine and we don't get close to the tickLimit on the private server.

     

     

    var Scouting = require('Scouting');

    var Pather = require('Pathing');

     

    const DEBUG = false;

     

    var roleScout = {

        run: function (creep) {

            if (Game.cpu.bucket < 1000) return;

            if (creep.spawning) return;

            if (DEBUG) console.log("Scout: on entry target is "+creep.memory.target);

            if (creep.memory.target === undefined || creep.memory.target === null) {

                if (DEBUG) console.log("Calling closestTargetRoom");

                creep.memory.target = Scouting.closestTargetRoom(creep.room);

                if (creep.memory.target === null) {

                    if (DEBUG) console.log("Calling oldest scouted room");

                    creep.memory.target = Scouting.oldestScoutedRoom(creep.room);

                }

            }

            if (DEBUG) console.log("Target room: " + creep.memory.target + " and current room: " + creep.room.name + " and pos " + JSON.stringify(creep.pos));

            if (creep.memory.target === creep.room.name) {

                if (DEBUG) console.log("Scout in target room " + creep.room.name)

                Scouting.generateReport(creep.room);

                creep.memory.target = Scouting.closestTargetRoom(creep.room);

                if (creep.memory.target === null) {

                    if (DEBUG) console.log("Calling oldest scouted room");

                    creep.memory.target = Scouting.oldestScoutedRoom(creep.room);

                }

                let destination = new RoomPosition(25, 25, creep.memory.target);

                let moveResult = creep.moveTo(destination, { visualizePathStyle: {}, reusePath: 10, costCallback: Pather.costMatrixAvoidKeepers, maxOps: 50000 });

                if (moveResult == ERR_NO_PATH) {

                    let path = Game.map.findRoute(creep.room.name, creep.memory.target, { routeCallbakc: Pather.findRouteAvoidKeepers });

                    if (DEBUG) console.log("Path: " + JSON.stringify(path));

                    creep.memory.target = path[0].room;

                    let destination = new RoomPosition(25, 25, creep.memory.target);

                    let moveResult = creep.moveTo(destination, { visualizePathStyle: {}, reusePath: 10, costCallback: Pather.costMatrixAvoidKeepers, maxOps: 50000 });

                }

                if (DEBUG) console.log("In room Scout move from " + JSON.stringify(creep.pos) + " to " + JSON.stringify(destination) + " returned " + moveResult);

            }

            else {

                let destination = new RoomPosition(25, 25, creep.memory.target);

                let moveResult = creep.moveTo(destination, { visualizePathStyle: {}, reusePath: 10, costCallback: Pather.costMatrixAvoidKeepers, maxOps: 50000 });

                if (moveResult == ERR_NO_PATH) {

                    let path = Game.map.findRoute(creep.room.name, creep.memory.target, { routeCallbakc: Pather.findRouteAvoidKeepers });

                    if (DEBUG) console.log("Path: " + JSON.stringify(path));

                    creep.memory.target = path[0].room;

                    let destination = new RoomPosition(25, 25, creep.memory.target);

                    let moveResult = creep.moveTo(destination, { visualizePathStyle: {}, reusePath: 10, costCallback: Pather.costMatrixAvoidKeepers, maxOps: 50000 });

                    if (DEBUG) console.log("Scout (failed) move from " + JSON.stringify(creep.pos) + " to " + JSON.stringify(destination) + " returned " + moveResult);

                    if (moveResult == ERR_NO_PATH)

                        creep.suicide(); // work around cpu reset bug

                }

                //let path = creep.room.findPath(creep.pos, destination, { costCallback: Pather.costMatrixAvoidKeepers });

                if (DEBUG) console.log("Scout move from " + JSON.stringify(creep.pos) + " to " + JSON.stringify(destination) + " returned " + moveResult);

            }

            if (DEBUG) console.log("Scout code executed");

        }

    }

     

    module.exports = roleScout;

     

    [7:15:29 PM]Scout: on entry target is W2N10

    [7:15:29 PM]Target room: W2N10 and current room: W2N9 and pos {"x":8,"y":0,"roomName":"W2N9"}

    [7:15:29 PM]Path: [{"exit":1,"room":"W2N10"}]

    [7:15:29 PM]Scout (failed) move from {"x":8,"y":0,"roomName":"W2N9"} to {"x":25,"y":25,"roomName":"W2N10"} returned -2

    [7:15:29 PM]Scout move from {"x":8,"y":0,"roomName":"W2N9"} to {"x":25,"y":25,"roomName":"W2N10"} returned -2

    [7:15:29 PM]Scout code executed

    [7:15:29 PM]Total cpu use 68.93355 limit 100 tickLimit 10100 bucket 10000

    [7:15:31 PM]Script execution has been interrupted with a hard reset: CPU limit reached

    [7:15:31 PM]Scout: on entry target is W2N10

    [7:15:31 PM]Target room: W2N10 and current room: W2N9 and pos {"x":8,"y":0,"roomName":"W2N9"}

    [7:15:31 PM]Path: [{"exit":1,"room":"W2N10"}]

    [7:15:31 PM]Scout (failed) move from {"x":8,"y":0,"roomName":"W2N9"} to {"x":25,"y":25,"roomName":"W2N10"} returned -2

    [7:15:31 PM]Scout move from {"x":8,"y":0,"roomName":"W2N9"} to {"x":25,"y":25,"roomName":"W2N10"} returned -2

    [7:15:31 PM]Scout code executed

    [7:15:31 PM]Total cpu use 48.874552 limit 100 tickLimit 10100 bucket 10000

    [7:15:34 PM]Script execution has been interrupted with a hard reset: CPU limit reached

    [7:15:34 PM]Scout: on entry target is W2N10

    [7:15:34 PM]Target room: W2N10 and current room: W2N9 and pos {"x":8,"y":0,"roomName":"W2N9"}

    [7:15:34 PM]Path: [{"exit":1,"room":"W2N10"}]

    [7:15:34 PM]Scout (failed) move from {"x":8,"y":0,"roomName":"W2N9"} to {"x":25,"y":25,"roomName":"W2N10"} returned -2

    [7:15:34 PM]Scout move from {"x":8,"y":0,"roomName":"W2N9"} to {"x":25,"y":25,"roomName":"W2N10"} returned -2

    [7:15:34 PM]Scout code executed

    [7:15:34 PM]Total cpu use 55.214741000000004 limit 100 tickLimit 10100 bucket 10000

    [7:15:36 PM]Script execution has been interrupted with a hard reset: CPU limit reached

    [7:15:37 PM]Scout: on entry target is W2N10

    [7:15:37 PM]Target room: W2N10 and current room: W2N9 and pos {"x":8,"y":0,"roomName":"W2N9"}

    [7:15:37 PM]Path: [{"exit":1,"room":"W2N10"}]

    [7:15:37 PM]Scout (failed) move from {"x":8,"y":0,"roomName":"W2N9"} to {"x":25,"y":25,"roomName":"W2N10"} returned -2

    [7:15:37 PM]Scout move from {"x":8,"y":0,"roomName":"W2N9"} to {"x":25,"y":25,"roomName":"W2N10"} returned -2

    [7:15:37 PM]Scout code executed

    [7:15:37 PM]Total cpu use 54.214553 limit 100 tickLimit 10100 bucket 10000

    [7:15:39 PM]Script execution has been interrupted with a hard reset: CPU limit reached

    [7:15:39 PM]Scout: on entry target is W2N10

    [7:15:39 PM]Target room: W2N10 and current room: W2N9 and pos {"x":8,"y":0,"roomName":"W2N9"}

    [7:15:39 PM]Path: [{"exit":1,"room":"W2N10"}]

    [7:15:39 PM]Scout (failed) move from {"x":8,"y":0,"roomName":"W2N9"} to {"x":25,"y":25,"roomName":"W2N10"} returned -2

    [7:15:39 PM]Scout move from {"x":8,"y":0,"roomName":"W2N9"} to {"x":25,"y":25,"roomName":"W2N10"} returned -2

    [7:15:39 PM]Scout code executed

    [7:15:39 PM]Total cpu use 57.702722 limit 100 tickLimit 10100 bucket 10000

     



  • I think I had similar problem some time ago. Since then I am using a code posted below as a workaround for all creeps that move between the rooms and might be the first to enter the room:

            if (creep.pos.x == 0) {
                creep.move(RIGHT);
                creep.heal(creep);
            } else if (creep.pos.x == 49) {
                creep.move(LEFT);
                creep.heal(creep);
            } else if (creep.pos.y == 0) {
                creep.move(BOTTOM);
                creep.heal(creep);
            } else if (creep.pos.y == 49) {
                creep.move(TOP);
                creep.heal(creep);
            } else {
    //regular move code here
            }
    

    My creeps never stuck after I started doing this, so either this works or the bug is gone.



  • Thanks. This didn't directly fix the issue but trying your approach lead me to a bug in my code: under certain conditions closestTargetRoom could be very inefficient and exhaust cpu. It seems no console.logs work when the cpu runs out.

    This issue is resolved, and the fault was mine, not in Screeps.