// A tool to manage land claims (i.e. a certain Space is delegated to only call a specific `call()` if a tileUpdate occurs differing from that Space) const ms = require('../utils/measurespace'); const ri = require('../utils/rectintersect'); const vec = require('../utils/vec'); const comb = require('../utils/comb'); module.exports = function(){ // catchall is called if tileUpdate occurs w/ no relevant claim on a part. let claims = {}; let claimId = 0; this.claim = function(space, call, excl=true){ // `space` is Space obj; `call` is callback function // `exclusive` sets whether this callback will prevent other (incl. catchall) functions from seeing the space. Cannot be used with an exclusive callback, and does not guarantee order. // If exclusive claim intersects another claim, behavior undefined. claimId++; claims[claimId] = {'space':space, 'call':call, 'excl':excl, 'area':ms(space)} return claimId; } this.unclaim = function(id){ delete claims[id]; } this.handle = function(send, tilespaces, locs){ // Because usually tilespaces is small, the inefficiency of an O(nk) rect match is acceptable for (let id in claims){ claim = claims[id]; diffspace = {}; rellocs = []; for (let loc of locs){ let tile = tilespaces[loc]; if (ri(claim.area, [vec.tileToChar(loc), vec.tileToChar(vec.add(loc, [1,1]))])){ let diff = claim.space.copy(); diff.comb(tile, comb.unmask); rellocs.push(loc); diffspace[loc] = diff; if (claim.excl){ let newtile = claim.space.copy(); newtile.comb(tile, comb.mask); tilespaces[loc] = newtile; } } } claim.call(send, diffspace, rellocs, id, claim.space, claim.area); // claim.space should not be modified by the function. it is only present to make functions easier to write } this.emit('fallback', send, tilespaces, locs); } }