rustyscreeps/screeps-game-api

Some objects have no id

drewcrawford opened this issue · 3 comments

Certain objects do not have an id, and this seems like a footgun. For example,

  1. Spawn a new creep
  2. During the same tick as 1, do screeps::game::creeps::values().iter().map(|p| p.id())
  3. Traceback
1:18:24 PM]caught exception: TypeError: Cannot read property 'length' of undefined
[1:18:24 PM]stack trace: TypeError: Cannot read property 'length' of undefined
    at object_id_to_packed (eval at exports.evalCode (blob:https://screeps.com/29a5a139-d638-4e92-a50d-359e08cec132:2:11757), :870:12)
    at eval (eval at exports.evalCode (blob:https://screeps.com/29a5a139-d638-4e92-a50d-359e08cec132:2:11757), :1101:107)
    at __cargo_web_snippet_fa761c1402d330c48e501b99c4185c8157f04119 (eval at exports.evalCode (blob:https://screeps.com/29a5a139-d638-4e92-a50d-359e08cec132:2:11757), :1101:138)
    at _ZN7screeps7objects5HasId2id17hd202e9200e20e409E (wasm-function[550]:0x2ee78)

Although this traceback is opaque, ultimately the root cause is a creep has no id during its first tick (of being spawned) and so screeps-game-api crashes trying to get it.

It's not immediately clear how to fix this. HasId has fn id(&self) -> ObjectId<Self> but when there is no id I don't think this can be implemented correctly, instead we need a signature like Option<ObjectId<Self>>.

If this is specific to Creep we could potentially introduce a new trait like MaybeHasId, although this would complicate generic interfaces. However my suspicion is that it actually happens for most types under the right circumstances, and so we maybe ought to change HasId itself. However I imagine that this is a nontrivial API breakage.

See also #246. Had to address this for power creeps with the AccountPowerCreep wrapper, but this is the only other case I'm aware of where a normally-ID'd object gets none, and it's so specific (and easy to avoid) that it's hard to justify the option wrapper on everything in HasId; probably more likely a custom wrapper like that on screeps::game::power_creeps since that's the only case outstanding where this can happen, unless you're aware of more?

I haven't actually tried it, but i have a suspicion this may be possible in the case of ConstructionSite or Nuke

Can confirm this happens with ConstructionSite (create and access on the same tick).

IMO the most sensible solution is to introduce new API for HasId like fn maybe_id() -> Option<ObjectId<Self>> or try_id() -> Result<ObjectId<Self>,..> as a safe alternative to id. Then just document id panics in some cases, and link to the issues