Important change: game objects prototypes

On May 12 an update will be deployed that will introduce some changes to the API which can require adjustments in your script. The changes affect two fields:

  1. The underlying data structure in which flags data is stored on the server was revised for optimization purposes, and now the Flag prototype does not have the id property. If you have worked only with properties name, color/secondaryColor, and memory, you have nothing to worry about. Otherwise please change your logic in order not to use the id property. Besides, the constants COLOR_* now represent integer values rather than strings, so if you used their values directly, please make sure to use names of variables from now on.

  2. We are considerably expanding the list of prototypes of game objects. Now all the prototypes will be arranged into a hierarchy and inherited in a chain. Here is the tree of prototypes:

       
Room
RoomPosition
RoomObject  (room, pos)
ConstructionSite
Creep
Flag
Mineral
Resource
Source
Structure (structureType, hits, hitsMax, destroy, notifyWhenAttacked, isActive)
  OwnedStructure (my, owner)
  StructureController
  StructureExtension
  StructureExtractor
  StructureKeeperLair
  StructureLab
  StructureLink
  StructureNuker
  StructureObserver
  StructurePowerBank
  StructurePowerSpawn
  StructureRampart
  StructureSpawn (aliased as Spawn for backward compatibility)
  StructureStorage
  StructureTerminal
  StructureTower
  StructureContainer
  StructureRoad
  StructureWall

You are free to use these prototypes in your scripts:

Game.rooms.W0N0.storage instanceof StructureStorage // true
Game.rooms.W0N0.storage instanceof OwnedStructure // true
Game.rooms.W0N0.storage instanceof Structure // true
Game.rooms.W0N0.storage instanceof RoomObject // true

So, because of this, if you have overrided some properties or methods, you have to check that you are doing this in the right place of the tree.

These changes have already been deployed on the Public Test Realm, so we recommend to go there and check if your script works correctly before the update goes live on the main server.

Have more questions? Submit a request

Comments

  • Avatar
    Dissi

    Can we get a new copy from PROD to PTR?

  • Avatar
    Dissi

    What is the reason to remove the ID behind flags? It was the one thing that was uniform between all objects, which now means my complete path/route caching mechanism is broken and has to be re-written.

    To say the least, I'm not happy about this.

  • Avatar
    Artem from Screeps

    Can we get a new copy from PROD to PTR?

    It has been copied by the time this article had been published.

    What is the reason to remove the ID behind flags? It was the one thing that was uniform between all objects, which now means my complete path/route caching mechanism is broken and has to be re-written.
    To say the least, I’m not happy about this.

    The allowed flags count is unlimited for every player, and some players have thousands of them, while owning only few “real” game objects. However, they were stored as real database objects which affects its performance significantly. Now, they all are serialized into string form and stored in a few database entries. id property cannot be assigned by database to them in this case.

    Another option to solve this perf issue would be introducing a hard limit for flags, but we really don’t want to go this way.

    For a quick and dirty fix I’d recommend using some abstract layer on top of Flag.name property like that:

    function getObjectOrFlagById(id) {
        return Game.getObjectById(id) || Game.flags[id];
    }
    
    function getIdOfObjectOrFlag(objectOrFlag) {
        if(objectOrFlag instanceof Flag) {
            return objectOrFlag.name;
        }
        return objectOrFlag.id;
    }

     

  • Avatar
    Dissi

    Thanks for the quick reply Artem.

     

    My rooms are RCL 7 inside the PTR, thats why I asked for a copy of prod.

     

    I'm all for the unlimited amount of flags, as it doesn't limit people's creations.

     

    I'll try to get the "dirty fix" working, sadly regexes aren't exactly quick, but buys some time.

    Sadly the only place where I used this ID is inside the path-cache because the Game.getObjectById() method was so performant, the rest used flag names.

  • Avatar
    Dissi

    It seems like transferEnergy is completely removed now, can you confirm this?

  • Avatar
    Artem from Screeps

    My rooms are RCL 7 inside the PTR, thats why I asked for a copy of prod.

    Right, something went wrong. Copied again.

    It seems like transferEnergy is completely removed now, can you confirm this?

    On which prototype? It has been deprecated for ages on storages, so it has not been added to StructureStorage. However, it’s still there inStructureExtension, StructureSpawn, etc.

  • Avatar
    Dissi

    It was on StructureStorage, Apparently I still used it to abstract away the Spawn and Storage difference.

    Can we get an StructureSpawn.transfer(target, resource) to make it more uniform? I suggest that StructureSpawn.transfer(someCreep, RESOURCE_*) will return ERR_INVALID_ARGS if it's not energy.

  • Amadox

    Cause it might help some people, this here should register the id property again, using the flags name. Ofc won't help with issues where you've cached current Flag IDs, but the code at least won't completely break because of a missing property:

    Object.defineProperty(Flag.prototype, "id", {
        configurable: true,
        get: function() {
            return this.id || this.name;
        }
    });

    In combination with this:

    https://gist.github.com/Amadox/4099f4f87bd7d3ff188fb21510cd6662

    as a wrapper for Game.getObjectById

    Edited by Amadox
  • Avatar
    Artem from Screeps

    Can we get an StructureSpawn.transfer(target, resource) to make it more uniform? I suggest that StructureSpawn.transfer(someCreep, RESOURCE_*) will return ERR_INVALID_ARGS if it’s not energy.

    Feel free to extend StructureSpawn prototype this way, if you’d like to.

  • Amadox

    ...will so do that. Also, quite excited about Spawn finally inheriting from Structure.. :D

  • chris

    Great change! I was desperately waiting for a proper prototype chain. Appreciate it!

  • chris

    One addition: I would appreciate having a prototype "NeutralStructures" to group containers, walls and roads (and future neutral ones). I think this would be consistent to the rest of the hierarchy.

  • Avatar
    Artem from Screeps

    One addition: I would appreciate having a prototype “NeutralStructures” to group containers, walls and roads (and future neutral ones). I think this would be consistent to the rest of the hierarchy.

    It would not have any own properties though. What are you going to use it for, any usage examples that don’t fit into Structure prototype?

  • chris

    You could write filters based on this prototype, instead of having to enumerate all of those structures separately. Perhaps one could extend the FIND constants to FIND_NEUTRAL_STRUCTURES as well. I realize, that it's a rather limited use case, but it might come in handy. And since you are revamping the structure anyways...? At the moment I already have 100+ prototype extensions - I guess once I advance deeper into currently untouched aspects of the game, there might be some use for me. I wouldn't be surprised, if other players already have some more concrete examples.

     

  • Avatar
    Dissi

    Artem, can we remove the depricate creep.transferEnergy as well? This way we remove everything depricated in 1 go.

    Edited by Dissi
  • chris

    This change would be a perfect match for Node 6, e.g. with having "super" and function "name" properties. But ofc I understand if you won't be able to do this soon.

  • wicked

    I would reconsider removing Flag ids. It's not too hard to get around, like you have shown, but it's an unnecessary complication of the class hierarchy and hence the documentation. For example, in all the find path and moveTo methods you might need to specify that you can move to a RoomObject or a Flag, or "anything that has a pos", but that's needlessly complicating things.

     

    I suggest giving the Flags a standard code generated UUID

  • Avatar
    Artem from Screeps

    UUID doesn't seem to be a good solution when there could be hundreds of items generated across different machines within a few milliseconds. There is a considerable collision chance in this case.

  • wicked

    I sincerely doubt it. From the article: "In other words, only after generating 1 billion UUIDs every second for the next 100 years, the probability of creating just one duplicate would be about 50%"

    *(edit to note: this is referring to UUIDv4)*

    If you're still unsure, you might want to prefix the id with a player id.

    Edited by wicked
  • Avatar
    Artem from Screeps

    You are talking about fully RFC-compliant UUID. However, most JavaScript implementations are plagued with either broken (at least in V8) Math.random, or extremely costly crypto.randomBytes calls. Both are unreliable in our use case.

    However, we might end up with simply aliasing flag ids to something like"f_"+name, which seems to be enough since they are unique to their owner, and are not accessible to others anyway.

    On the other hand, it is not about the ID generation algorithm. Flags don’t represent any real “physical” objects, they are invisible to other players, cannot be obtained via getObjectById by anyone except their owner. So the id property (which identifies the object globally in the game world) doesn’t make any sense in their case, they just don’t exist in the game world basically, they are sort of visualization of some player’s array on his own screen. So it seems to be very consistent that they are not derived from the RoomObject prototype.

  • wicked

    There is a node-uuid package promising RFC-compliant UUIDs, but I agree that your method solves the problem in an extremely quick and simple way. No matter the method, then the hierarchy can be streamlined.

  • Avatar
    Artem from Screeps

    node-uuid uses crypto.randomBytes. You will not be happy with the performance of Room.createFlag if we go this way :)

    On the other hand (again), RoomObject could contain only room andpos and no id, then flags could be derived as well. We’ll have to think about that.

  • wicked

    To reply to your point about "real, physical objects": I see your point. However, as a player I don't see any difference, because I see and use flags like any other game object that I am able to select and interact with (unlike e.g. terrain). From my "player point of view", they're not a special case and I would prefer they worked like all other game objects, even with id.

    Like you have shown before, there's also not a huge problem to implement getObjectById to also consider flag ids (though possibly with a small performance hit every time you ask for an object by ID and it's not found and have to check flags too, unless they are in the same list as other objects with ID).

  • Avatar
    Artem from Screeps

    I admit that from the “player point of view” they are like RoomObject in the way that they have the same Room and RoomPosition linked by the game engine to them, so they might inherit those properties from the appropriate prototype. However, as they won’t have any real database IDs anyway, aliasing their IDs to their names is likely a task for user code than for the game engine.

    Removing id from RoomObject and making Flag derived from it, seems to be the most sensible move.

Powered by Zendesk