Navigation

    forum

    • Login
    • Search
    • Categories
    • Recent
    • Popular
    • Users
    • Groups
    1. Home
    2. fritzy
    • Flag Profile
    • block_user
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Groups
    • Blog

    fritzy

    @fritzy

    3
    Posts
    1454
    Profile views
    0
    Followers
    0
    Following
    Joined Last Online

    fritzy Follow

    Posts made by fritzy

    • RE: OOP Ideas for Screeps/JS

      @SystemParadox

      What's actually happening here is that the console calls .toString() on the object (e.g. Creep.prototype.toString()). [...] The toString() function tries to get this.name, but it's a getter, and it throws an error if the object doesn't have this.id.

      Nice, yeah, I figured it would be part of the toString invocation. Good find!

      The heap - that is, global variables or module scoped variables as in your example. These will last until a "global reset" [...]

      OK, makes sense. I suppose not all of the docs have been updated since the introduction of iVMs. Thanks, that's useful!

      I do things like this a lot:

      Room.prototype.getRepairTargets = function () {
          if (! this._repairTargets) {
              this._repairTargets = this.find(FIND_MY_STRUCTURES, {
                  filter: struct => struct.hits < struct.hitsMax,
              })
          }
          return this._repairTargets;
      };
      

      That way I can call this.room.getRepairTargets() on several different creeps but it will only call find once each tick.

      Right. I found that JS supports the same "decorator" syntax as Python (a language with which I am much more familiar!) and I figured out how to write a decorator to seamlessly memoize the results of a property descriptor's getter, with the goal of simplifying this common pattern. I use it like:

      class MyRoom {
        @memoize
        get repairTargets() {
          return this.find(FIND_MY_STRUCTURES, {
            filter: struct => struct.hits < struct.hitsMax
          });
        }
      }
      

      @SemperRabbit That tracks with what I'm learning - I might make a Proxy of my own. Thanks for your input! 🙂

      posted in Help
      fritzy
    • RE: OOP Ideas for Screeps/JS

      @SystemParadox Yes, that's very helpful, thank you!!

      Extending the prototypes makes sense - I guess I was thrown off because I tried entering Creep.prototype in the Screeps console, and I would see Error: This creep doesn't exist yet. I guess trying to "print" the prototype somehow tries to instantiate a Creep, but playing with it again now I can see that I can absolutely do moveTo = Creep.prototype.moveTo. I like your extendClass function, that makes a lot of sense (after reading the corresponding documentation). I agree that assigning directly to the prototype is ugly. This is pretty much exactly what I was hoping for!

      The way around this is to cache the MyCreep instances on the heap [...]

      Do you mean serializing them to Memory, or is there another "heap" that offers some persistence? I was under the impression from reading the documentation that global state is reset every tick. Is this a change with the introduction of isolated VMs? Is it as simple as using a global object/array?

      var cached_creeps = {};
      
      module.exports.loop = {
        if (!cached_creeps) { cached_creeps = [new MyCreep(Game.creeps.john_galt))]; }
        cached_creeps[0].say("I am " + cached_creeps[0].name);
      }
      
      posted in Help
      fritzy
    • OOP Ideas for Screeps/JS

      What are folks doing to integrate some OOP design into their Screeps code?

      Background: I'm an experienced systems programmer but I'm brand new to Javascript, and it's not immediately clear to me how to integrate JS classes efficiently with the existing Screeps classes. I've been playing around in the console a bit and it seems like we can't just write class MyCreep extends Creep { ... } sadly, which is exactly what I want to do.

      I've been thinking about this in the back of my mind for a few days and I think a good construct would be class MyCreep { constructor(creep_id) { ... } } where all the properties are just setters/getters to/from the creep's memory, then wherever I deal with MyCreep objects if I want to invoke a true Creep method (moveTo, etc...) I'll just have to go through a special method/property like MyCreep.creep which would return the true Creep. Kind of like this:

      class MyCreep {
        creep;
        constructor(creep_id) { this.creep = Game.getObjectById(creep_id); }
      
        get memory() { return this.creep.memory; }
        get target() { return Game.getObjectById(this.memory.target_id); }
        set target(target_object) { this.memory.target_id = target_object.id; }
      
        myMoveTo(target_object) {
          this.target = target_object;
          // other state adjustments...
      }
      

      Then I could use them like this:

      var john = new MyCreep(Game.creeps['John Galt'].id);
      john.myMoveTo(john.creep.room.controller);
      

      My biggest concern with this method is that MyCreep objects require the apparently superfluous creep member, and I have to actually allocate them with new - I would have to resort to _.forEach(Game.creeps, (creep) => {new MyCreep(creep.id)}) each tick. The systems side of me is triggered by the dynamic allocations incurred by the calls to new MyCreep(). At a high level there is no real extra state I need to capture that isn't already in the Creep object itself to which I already have a reference. I find myself inclined to find a way to run MyCreep methods directly on true Creep objects, where this can refer to the Creep itself. I'd want to use something like in the following pseudocode in-place of new:

      new_MyCreep(creep_id) {
        var creep = Game.getObjectById(creep_id);
        return (MyCreep) creep; // indicates my desire for a "conversion" from Creep to MyCreep
      }
      

      In my naiivete, I see this as avoiding the extra allocation of a dedicated MyCreep object, which now can just operate directly on the API-allocated Creep object. I would then like to use _.forEach(Game.creeps, new_MyCreep) (instead of new MyCreep()) and then use instances of MyCreep to invoke true Creep methods as well as MyCreep methods, like:

      var john = new_MyCreep(Game.creeps['John Galt'].id);
      john.myMoveTo(john.room.controller);
      

      I've seen various people mess with .prototype but I am unable refer to Creep.prototype in the Screeps console and creep_instance.prototype is undefined, so I've given up on pursuing that lead.

      I'm not well-versed enough in JS to know how dumb this all sounds, so please share your thoughts. Is my first method fine, and I'm just overestimating how expensive the extra new calls are? Is the second method even possible? What do you do?

      Cheers!

      Fritz

      posted in Help
      fritzy