How can i store all my extensions/spawns in order?

  • Hello!

    Each time my "refillers" load energy, they start doing a findClosesByPath() call after unloading energy on a extension or spawn. I wonder how i could store all of them in some kind of array so they always unload energy in the same order (but a logical order, not just storing them and then going to unload at ext[0],ext[1],ext[2]...). This way i would avoid a ton of calls to this function and the only drawback could just be that the initial extension/spawn would not be the nearest.

    Thank you in advance!

  • Dev Team

    You can store it in an array if ids using .map() to convert it here and there.

    const extensions = room.find(...);
    room.memory.extensions =>;
    const extensions =>Game.getObjectById(i));

  • @o4kapuk Thanks for your reply, Sir.

    However, unless i'm wrong (what is very possible) storing them just by ids wouldn't allow my creep to refill them in an optimal order, right?

  • Dev Team

    @calfa That method will keep your order. So if you're able to form the aforementioned optimal order, these map()s will preserve it.

    You may wish to observe my rooms, I use static routing for chargers, together with a good layout it's very efficient by time and cpu both.

  • TMB

    What you're having trouble with is actually sorting them by path, right ? All I see to achieve this is along these lines :

    var sortedExt = [];
        let ext = creep.findClosestByPath(FIND_EXTENSION, {filter: (e)=>!sortedExt.includes(e)});
        if (ext != null)

    That's going to be a very consumming operation though. And I tend to distrust while(true)...

    I've already been thinking about a "plural" findClosestsByPath, if the devs can think of something more optimized than repeated calls to findClosestsByPath...

  • Dev Team

    @estecka said in How can i store all my extensions/spawns in order?:

    I've already been thinking about a "plural" findClosestsByPath, if the devs can think of something more optimized than repeated calls to findClosestsByPath...

    Optimizations and other code improvements are parts of the gameplay. Again, I suggest you observe my fillers. Fun fact: when it comes to spawns and extensions filling, they never call findClosestsByPath, they never call findPath, they never call If you think that that findClosestsByPath is too expensive to be called multiple times, find a way to avoid that. Or store temporary results and distribute the load over several ticks. Play with cost matrixes. Play with flood filling. Play with layouts maybe...It's not devs who supposed to think about optimizations of game tasks, you are 🙂


  • @estecka Yes, that's exactly what i'm having troubles with. Well' it's not that i'm having troubles to be honest since i haven't started doing it, but just thinking on how to.

    My "best" idea is to let the creep follow his route once using findClosestByPath() and store spawns and extensions until the array reaches a length equal to the number of these structures, and then use this same route forever, but other creeps might make my creep change the route.

    I also thought about hardcoding each id in order, but it's not as funny as solving the problem and not efficient too, despite the fact that i should have to do this for every current and future room.

    Maybe i go for my first option, just making sure that there are no obstacles in the way, and repeting the process if there are.

  • Dev Team

    @calfa I'd mention one of the golden rules of programming: never, never pre-optimize. Implement it with findClosestByPath(), then run profiler and examine how bad is it and where it's slow, then decide how to optimize it.

  • @o4kapuk I have it implemented with findClosestByPath already and i suspect it's bad to the point of being terrible. However, profiling it is not easy for me, since i can do a "general" profile, but when it comes to profile a single module...i just can't. It might be due to language issues, or maybe due to brain issues...who knows, but i can't get it to work and i've given up. After all, i've never studied anything related to programming, and i've learned everything by myself (with the priceless help of people in forums like this, of course).

    The funny thing is that i have sooooo many things to do that as i find something i can't deal with i can always try to improve something else.

  • You can always do something like:

    let start = Game.cpu.getUsed();
    let end = Game.cpu.getUsed();
    console.log("code took", end-start, "cpu");

  • @wtfrank That's osom!!!! 😂

    These are my refillers deciding where will they unload their energy....

    [1:23:37] [shard3]unloadEnergy Refiller834304 1.5348690000000005 cpu
    [1:23:39] [shard3]unloadEnergy Refiller834304 0.2223639999999989 cpu
    [1:23:42] [shard3]unloadEnergy Refiller834304 0.21644699999999872 cpu
    [1:23:44] [shard3]unloadEnergy Refiller834055 4.476258999999999 cpu
    [1:23:44] [shard3]unloadEnergy Refiller834304 0.26218800000000186 cpu
    [1:23:46] [shard3]unloadEnergy Refiller834055 0.7212580000000006 cpu
    [1:23:46] [shard3]unloadEnergy Refiller834304 0.5383530000000007 cpu
    [1:23:48] [shard3]unloadEnergy Refiller834055 1.2878429999999987 cpu
    [1:23:50] [shard3]unloadEnergy Refiller834055 0.2621580000000012 cpu
    [1:23:53] [shard3]unloadEnergy Refiller834055 1.195928000000002 cpu

    Never had such a detailed info of the cpu i use, and now i'm crying. Crying because of that super powerful tool you gave me and crying because there's a damn creep using 4.5 cpu in a single tick for a single decission.

    Thank you so so much!!!

  • Dev Team

    You may also wish to use profiler.

  • @o4kapuk Thanks a lot for the tip. I already use profiler, but only for getting general info about my code because as i said above i don't know how to profile only a single module to get deeper knowledge of what's going on. And that's also the reason i was so happy when i read @wtfrank reply 🙂

  • Dev Team

    @calfa said in How can i store all my extensions/spawns in order?:

    i don't know how to profile only a single module

    You register the module with a name, then specify the name as second parameter to a profiler call.


  • @Calfa just to give some more context on why this is so expensive:

    Using findClosestByPath() this way determines paths to all extensions, gives you the closest one and tosses out all information it calculated. Because of your loop, it then calculates all those same paths again but just for 1 less extension. So it's doing a lot of duplicate work.

    For example, if you have 5 extensions it first calculates 5 paths, saves the closest, then 4 paths, saves the closest, then 3 paths, saves the closest, then 2 paths, saves the closest, and then paths to and saves the last one. That's 5+4+3+2+1=15 paths, or three times the work necessary!

    In addition to that unnecessary work, there can be cases where the sort is no longer valid. If the closest extension is a few steps to the left, and the next closest is to the right, that information is outdated after your creep has moved:


    In this case, the left most extension is furthest, the second is closest and the rightmost extension is middle distance. Using your sorting, this creep will go middle-right-left which is longer than right-middle-left or middle-left-right.


    One possible improvement you could make is finding the nearest empty extension, saving that somehow, and then finding empty extension that's closest to the first one, then closest to the second one, and so on. That way your 'sorted' order will be better and you cut the duplicate calculations.

    There's still a lot of room for improvement, but hopefully it can inspire you to think of new ways to calculate this 🙂

  • @calfa Just FYI you sometimes see big CPU usage just because some javascript garbage collection kicked in. So seeing several CPU occasionally doesn't guarantee that there's a problem in your code. But if you see big CPU consistently, then it's unlikely to be garbage collection and there probably is something inefficient in the code.

  • @keenathar That's awesome information!! I spend time, sometimes, watching my creeps doing their stuff and i know they use to lose time because of what you explain (didn't think of it in a deeper way like you did, but indeed i realized it was not very efficient). However, i never thought in that approach and it seems great and achievable to me!

    I appreciate sooo much!!

    @wtfrank That's very good to know. I was afraid it was my code (and still might be), but it's not really usual, just sometimes. And this takes me to another question...Yesterday i was receiving messages in the console, telling me that i reached my cpu limit and my bucket was empty. I started looking for ways to stop it and i finally got to an average of about 23.5cpu. (since then, i have profiled 3 or 4 times for 1000ticks). However my limit on Shard3 is 20cpu but that message hasn't appeared again for the last 20~22 hours.

    How is this possible? Maybe profiler and Screeps don't measure the cpu consumption the same way?

    @o4kapuk I'm ashamed, but i tried and didn't get it to work 😞

  • I got something! Tomorrow i'll try my refiller to follow this route to see what happens, but in the meantime i'd like to show you what i came up with

    let roleRouter = {
        run: function(creep){
            //Initialize Route
                creep.memory.route = [];
            //Number of structures added to the route
                creep.memory.currentStructures = 0;
            //Get number of extensions + spawns
                creep.memory.totalStructures =, {
                    filter: function(s){ return (s.structureType == STRUCTURE_SPAWN || s.structureType == STRUCTURE_EXTENSION); }
            //If i haven't added to the route as many elements as spawns + extensions
            if(creep.memory.currentStructures < creep.memory.totalStructures) {   
                //Look for a structure not added to the route yet
                let nextStructure = creep.pos.findClosestByPath(FIND_MY_STRUCTURES, {
                    filter: function(s){
                        return ((s.structureType == STRUCTURE_SPAWN || s.structureType == STRUCTURE_EXTENSION) && !_.includes(creep.memory.route,;
                    //add structure to the route
                    creep.memory.currentStructures ++;
                    //Now if i'm not near to the structure above, move towards it
                    //And now that i'm next to it...
                        //Look for nearby structures that are not included yet
                        let nearbyStructures = creep.pos.findInRange(FIND_MY_STRUCTURES, 1, {
                            filter: function(s){
                                return (s.structureType == STRUCTURE_SPAWN || s.structureType == STRUCTURE_EXTENSION) && !_.includes(creep.memory.route,;
                        //And now add these structures to the route
                        if(nearbyStructures && nearbyStructures.length > 0){
                            for(let i in nearbyStructures){
                                creep.memory.currentStructures ++;
                    console.log('You are fucked!');
            //If the route is complete, store it in the room's memory
       = creep.memory.route;
    module.exports = roleRouter;

    So far, there's no errors and the number of elements in the route is 41 (40 extensions and 1 spawn) so it looks like a pretty good start.