Tutorial: Updating controller (Inefficient code in module?)



  • Hi.

    When you are through with the tutorial Updating controller part it seems the creep.upgrader every time is just loading 2 energy, then going to push the room controller. With this it seem to be very unefficient because you will loose  activity on moving and have lesser resource gaining/room controller pushing.

    Would it not be better when the creep.upgrader loads itself to the max energy capacity and then going to push the room controller.

    Original Tutorial Module: role.upgrader

    var roleUpgrader = {

        /** @param {Creep} creep **/
        run: function(creep) {
            if(creep.carry.energy == 0) {
                var sources = creep.room.find(FIND_SOURCES);
                if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
                    creep.moveTo(sources[0]);
                }
            }
            else {
                if(creep.upgradeController(creep.room.controller) == ERR_NOT_IN_RANGE) {
                    creep.moveTo(creep.room.controller);
                }
            }
        }
    };

    module.exports = roleUpgrader;

     

    Modified Module: role.upgrader

    var roleUpgrader = {

        /** @param {Creep} creep **/
        run: function(creep) {
            if(creep.carry.energy < creep.carryCapacity && creep.carry.energy == 0) {
                var sources = creep.room.find(FIND_SOURCES);
                if(creep.harvest(sources[0]) == ERR_NOT_IN_RANGE) {
                    creep.moveTo(sources[0]);
                }
            }
            else {
                    if(creep.upgradeController(creep.room.controller) == ERR_NOT_IN_RANGE) {
                        creep.moveTo(creep.room.controller);
                    }
            }
        }
    };

    module.exports = roleUpgrader;

     

    1) If i am wrong, can someone tell me why ?

    2) If i am right, maybe they should propably update the tutorial code.



  • if(creep.carry.energy < creep.carryCapacity && creep.carry.energy == 0)

    As soon as you harvest any energy this is no longer true, so it will pick up one energy and take it to the controller. It needs a switch like they teach you about in the building tutorial


  • Dev Team

    This is basic simple code for educational purposes. It becomes better in Section 4, see here: https://github.com/screeps/tutorial-scripts/blob/master/section4/role.upgrader.js



  • Try this. I had to adapt it to harvest, as I don't let my upgraders harvest anything.

    If the creep is at full energy, or is in range of the controller AND has some energy left, it'll upgrade. Otherwise, it'll go get energy. Comes full, leaves empty. Plus it searches for the nearest source node it can reach that has energy left or is about to respawn, so you never stop upgrading even if you deplete a node.

    var roleUpgrader = {
        run: function(creep) {
            if(creep.carry.energy == creep.carryCapacity || (creep.upgradeController(creep.room.controller) != ERR_NOT_IN_RANGE && creep.carry.energy > 0))
                if (creep.upgradeController(creep.room.controller) == ERR_NOT_IN_RANGE
    {
    creep.moveTo(creep.room.controller);
    creep.upgradeController(creep.room.controller);
    }
    }
    else
    {
    let source = creep.pos.findClosestByPath(FIND_SOURCES, {
    filter: (node) =>
    {
    return (node.energy > 0 || node.ticksToRegeneration < 20)
    }
    });
    if (source)
    {
    if (creep.harvest(source) == ERR_NOT_IN_RANGE)
    {
    creep.moveTo(source);
    creep.harvest(source);
    }
    }
            }
        }
    };

    module.exports = roleUpgrader;

     



  • if (creep.upgradeController(creep.room.controller) == ERR_NOT_IN_RANGE
                {
                    creep.moveTo(creep.room.controller);
                    creep.upgradeController(creep.room.controller);
                }

    The second upgradeController there is rather pointless and can be safely removed. moveTo, like all other actions, is not executed immedately, but between ticks, thus that second upgradeController call will never return anything else than ERR_NOT_IN_RANGE, because the creep hasn't moved yet. however, in the next iteration, after the creep has moved, the first upgradeController might return something else and thus this condition won't be entered anymore.

    if (creep.harvest(source) == ERR_NOT_IN_RANGE)
                    {
                        creep.moveTo(source);
                        creep.harvest(source);
                    }

    same thing here, the second creep.harvest is entirely pointless, you can safely remove it and the script would still do exactly the same it did before.

    I'm surprised to even see code managing this task without the use of memory though, but it looks like it might actually work. Will have to play around with that some time.. 



  • Actually, the whole point of the second upgradeController is because you can combine actions for a creep to execute in the same tick.

    I.e a creep can move and upgrade in the same tick, so the purpose of the second call is so that as soon as it enters range it upgrades. Otherwise, you're losing one tick of upgrading. Same applies for things like withdrawing, transfering, building, repairing, harvesting, etc.



  • @redeven Yes you can do that but it doesnt work the way you implemented it.

    build,harvest and such are only shedules if the current gamestate allows ist. (when you are in range).

    Your second command will always return ERR_NOT_IN_RANGE. Meaning it wont be shedules to be executed after your script is finished. I Testet it with one of my harvesters. While approaching the source it never Returned 0 (OK) and it wasnt executed when the harvester was at the source.

    it only works the other way around.

    For example:

    youre in range of your transfertarget. you sucessfully shedule a transfer (retVal == OK). Then you can issue a move to somewhere.

    The only thing that you can change while your script is running is memory. Everything else stays the same until next tick. And all commands must have the prerequisites fulfilled when they are issued and dont consider the next tick.



  • Think of it this way: Your actions (.move, .upgradeController) do not execute said action right away. They check if they could be executed, and if possible, schedule them to happen after the tick.

    so what this code...

    creep.moveTo(creep.room.controller);
    creep.upgradeController(creep.room.controller);

    ...is doing is, it checks: can I move? Yes I can, so schedule that. then it checks: can I upgrade? No, I'm not in range -> ERR_NOT_IN_RANGE.

    and then, when all is done and the tick ends, the creep actually moves.

     

    another scenario: imagine the creep is just in range of the controller, and you execute these two statements (except moving away from the controller instead of towards it). what happens? it checks: can I move? Yes I can, so schedule that. then it checks: Can i upgrade? yes, because I am in range, so schedule that. And then as the tick ends, it moves, and even though it then is no longer in range of the controller, still upgrades because it was when it was scheduled. that's what it means when the docs say these actions can be combined.

     

    Nothing you do actually happens right when you do it, except as Fou_Lou says, memory changes. It is all just scheduled to happen after the tick.



  • As Artem said, this was just a simple code for educational purposes in the tutorial. - I found some beginner help within the slack channel.

    Anyway, thank you for all your answers 🙂