def build(self, container): """ Handle a build packet. Several things must happen. First, the packet's contents need to be examined to ensure that the packet is valid. A check is done to see if the packet is opening a windowed object. If not, then a build is run. """ # Is the target within our purview? We don't do a very strict # containment check, but we *do* require that the chunk be loaded. bigx, smallx, bigz, smallz = split_coords(container.x, container.z) try: chunk = self.chunks[bigx, bigz] except KeyError: self.error("Couldn't select in chunk (%d, %d)!" % (bigx, bigz)) return target = blocks[chunk.get_block((smallx, container.y, smallz))] # If it's a chest, hax. if target.name == "chest": from bravo.policy.windows import Chest w = Chest() self.windows[self.wid] = w w.open() self.write_packet("window-open", wid=self.wid, type=w.identifier, title=w.title, slots=w.slots) self.wid += 1 return elif target.name == "workbench": from bravo.policy.windows import Workbench w = Workbench() self.windows[self.wid] = w w.open() self.write_packet("window-open", wid=self.wid, type=w.identifier, title=w.title, slots=w.slots) self.wid += 1 return # Try to open it first for hook in self.open_hooks: window = yield maybeDeferred(hook.open_hook, self, container, chunk.get_block((smallx, container.y, smallz))) if window: self.write_packet("window-open", wid=window.wid, type=window.identifier, title=window.title, slots=window.slots_num) packet = window.save_to_packet() self.transport.write(packet) # window opened return # Ignore clients that think -1 is placeable. if container.primary == -1: return # Special case when face is "noop": Update the status of the currently # held block rather than placing a new block. if container.face == "noop": return # If the target block is vanishable, then adjust our aim accordingly. if target.vanishes: container.face = "+y" container.y -= 1 if container.primary in blocks: block = blocks[container.primary] elif container.primary in items: block = items[container.primary] else: log.err("Ignoring request to place unknown block %d" % container.primary) return # Run pre-build hooks. These hooks are able to interrupt the build # process. builddata = BuildData(block, 0x0, container.x, container.y, container.z, container.face) for hook in self.pre_build_hooks: cont, builddata, cancel = yield maybeDeferred(hook.pre_build_hook, self.player, builddata) if cancel: # Flush damaged chunks. for chunk in self.chunks.itervalues(): self.factory.flush_chunk(chunk) return if not cont: break # Run the build. try: yield maybeDeferred(self.run_build, builddata) except BuildError: return newblock = builddata.block.slot coords = adjust_coords_for_face( (builddata.x, builddata.y, builddata.z), builddata.face) # Run post-build hooks. These are merely callbacks which cannot # interfere with the build process, largely because the build process # already happened. for hook in self.post_build_hooks: yield maybeDeferred(hook.post_build_hook, self.player, coords, builddata.block) # Feed automatons. for automaton in self.factory.automatons: if newblock in automaton.blocks: automaton.feed(coords) # Re-send inventory. # XXX this could be optimized if/when inventories track damage. packet = self.inventory.save_to_packet() self.transport.write(packet) # Flush damaged chunks. for chunk in self.chunks.itervalues(): self.factory.flush_chunk(chunk)
def test_verify_object(self): c = Chest() verifyObject(IWindow, c)
def test_damage_single(self): c = Chest() c.altered(17, None, None) self.assertTrue(17 in c.damaged())