def position_look(self, container): oldx, chaff, oldz, chaff = split_coords(self.player.location.x, self.player.location.z) oldpos = (self.player.location.x, self.player.location.y, self.player.location.z) self.player.location.load_from_packet(container) pos = (self.player.location.x, self.player.location.y, self.player.location.z) if oldpos == pos: # We haven't actually moved... return x, chaff, z, chaff = split_coords(pos[0], pos[2]) if oldx != x or oldz != z: self.update_chunks() for entity in self.factory.entities_near(pos[0] * 32, pos[1] * 32, pos[2] * 32, 2 * 32): if entity.name != "Pickup": continue if self.player.inventory.add(entity.block, entity.quantity): packet = self.player.inventory.save_to_packet() self.transport.write(packet) packet = make_packet("collect", eid=entity.eid, destination=self.player.eid) self.transport.write(packet) packet = make_packet("destroy", eid=entity.eid) self.transport.write(packet) self.factory.destroy_entity(entity) for entity in self.factory.entities_near(pos[0] * 32, pos[1] * 32, pos[2] * 32, 160 * 32): if (entity is self.player or entity.name != "Player" or entity.eid in self.entities): continue self.entities.add(entity.eid) packet = entity.save_to_packet() self.transport.write(packet) packet = make_packet("create", eid=entity.eid) self.transport.write(packet)
def position_changed(self): x, chaff, z, chaff = split_coords(self.location.x, self.location.z) # Inform everybody of our new location. packet = make_packet( "teleport", eid=self.player.eid, x=self.location.x * 32, y=self.location.y * 32, z=self.location.z * 32, yaw=int(self.location.theta * 255 / (2 * pi)) % 256, pitch=int(self.location.phi * 255 / (2 * pi)) % 256, ) self.factory.broadcast_for_others(packet, self) self.update_chunks() for entity in self.entities_near(2): if entity.name != "Item": continue if self.player.inventory.add(entity.item, entity.quantity): packet = make_packet("collect", eid=entity.eid, destination=self.player.eid) self.factory.broadcast(packet) packet = make_packet("destroy", eid=entity.eid) self.factory.broadcast(packet) packet = self.player.inventory.save_to_packet() self.transport.write(packet) self.factory.destroy_entity(entity)
def sign(self, container): bigx, smallx, bigz, smallz = split_coords(container.x, container.z) try: chunk = self.chunks[bigx, bigz] except KeyError: self.error("Couldn't handle sign in chunk (%d, %d)!" % (bigx, bigz)) return if (smallx, container.y, smallz) in chunk.tiles: new = False s = chunk.tiles[smallx, container.y, smallz] else: new = True s = Sign(smallx, container.y, smallz) chunk.tiles[smallx, container.y, smallz] = s s.text1 = container.line1 s.text2 = container.line2 s.text3 = container.line3 s.text4 = container.line4 chunk.dirty = True # The best part of a sign isn't making one, it's showing everybody # else on the server that you did. packet = make_packet("sign", container) self.factory.broadcast_for_chunk(packet, bigx, bigz) # Run sign hooks. for hook in self.sign_hooks: hook.sign_hook(self.factory, chunk, container.x, container.y, container.z, [s.text1, s.text2, s.text3, s.text4], new)
def send_initial_chunk_and_location(self): bigx, smallx, bigz, smallz = split_coords(self.location.x, self.location.z) # Spawn the 25 chunks in a square around the spawn, *before* spawning # the player. Otherwise, there's a funky Beta 1.2 bug which causes the # player to not be able to move. d = cooperate( self.enable_chunk(i, j) for i, j in product(xrange(bigx - 3, bigx + 3), xrange(bigz - 3, bigz + 3))).whenDone() # Don't dare send more chunks beyond the initial one until we've # spawned. d.addCallback(lambda none: self.update_location()) d.addCallback(lambda none: self.position_changed()) # Send the MOTD. if self.motd: packet = make_packet("chat", message=self.motd.replace( "<tagline>", get_motd())) d.addCallback(lambda none: self.transport.write(packet)) # Finally, start the secondary chunk loop. d.addCallback(lambda none: self.update_chunks())
def send_initial_chunk_and_location(self): bigx, smallx, bigz, smallz = split_coords(self.location.x, self.location.z) # Spawn the 25 chunks in a square around the spawn, *before* spawning # the player. Otherwise, there's a funky Beta 1.2 bug which causes the # player to not be able to move. d = cooperate( self.enable_chunk(i, j) for i, j in product( xrange(bigx - 3, bigx + 3), xrange(bigz - 3, bigz + 3) ) ).whenDone() # Don't dare send more chunks beyond the initial one until we've # spawned. d.addCallback(lambda none: self.update_location()) d.addCallback(lambda none: self.position_changed()) # Send the MOTD. if self.motd: packet = make_packet("chat", message=self.motd.replace("<tagline>", get_motd())) d.addCallback(lambda none: self.transport.write(packet)) # Finally, start the secondary chunk loop. d.addCallback(lambda none: self.update_chunks())
def digging(self, container): # XXX several improvements should happen here # ~ We should time started and stopped pairs to force clients to # slow-break their blocks # ~ we should handle "dropped" state packets for item drops if container.x == -1 and container.z == -1 and container.y == 255: # Lala-land dig packet. Discard it for now. return if container.state != "stopped": # We only care about digs which break blocks. return if time() - self.last_dig_build_timer < 0.1: self.error("You are digging too fast.") self.last_dig_build_timer = time() bigx, smallx, bigz, smallz = split_coords(container.x, container.z) try: chunk = self.chunks[bigx, bigz] except KeyError: self.error("Couldn't dig in chunk (%d, %d)!" % (bigx, bigz)) return oldblock = blocks[chunk.get_block((smallx, container.y, smallz))] for hook in self.dig_hooks: hook.dig_hook(self.factory, chunk, smallx, container.y, smallz, oldblock) self.factory.flush_chunk(chunk)
def decorated(self, coords, *args, **kwargs): x, y, z = coords bigx, smallx, bigz, smallz = split_coords(x, z) chunk = self.load_chunk(bigx, bigz) return f(self, chunk, (smallx, y, smallz), *args, **kwargs)
def build(self, container): # Is the target being selected? 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 if (chunk.get_block((smallx, container.y, smallz)) == blocks["workbench"].slot): i = Workbench() sync_inventories(self.player.inventory, i) self.windows[self.wid] = i packet = make_packet("window-open", wid=self.wid, type="workbench", title="Hurp", slots=2) self.wid += 1 self.transport.write(packet) 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 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 if time() - self.last_dig_build_timer < 0.2: self.error("You are building too fast.") self.last_dig_build_timer = time() builddata = BuildData(block, 0x0, container.x, container.y, container.z, container.face) for hook in self.build_hooks: cont, builddata = hook.build_hook(self.factory, self.player, builddata) if not cont: break # Re-send inventory. # XXX this could be optimized if/when inventories track damage. packet = self.player.inventory.save_to_packet() self.transport.write(packet) # Flush damaged chunks. for chunk in self.chunks.itervalues(): self.factory.flush_chunk(chunk)
def sign(self, container): bigx, smallx, bigz, smallz = split_coords(container.x, container.z) try: chunk = self.chunks[bigx, bigz] except KeyError: self.error("Couldn't handle sign in chunk (%d, %d)!" % (bigx, bigz)) return if (smallx, container.y, smallz) in chunk.tiles: s = chunk.tiles[smallx, container.y, smallz] else: s = Sign() s.x = smallx s.y = container.y s.z = smallz s.text1 = container.line1 s.text2 = container.line2 s.text3 = container.line3 s.text4 = container.line4 chunk.tiles[smallx, container.y, smallz] = s chunk.dirty = True # The best part of a sign isn't making one, it's showing everybody # else on the server that you did. packet = make_packet("sign", container) self.factory.broadcast_for_chunk(packet, bigx, bigz)
def build_hook(self, factory, player, builddata): block, metadata, x, y, z, face = builddata # Don't place items as blocks. if block.slot not in blocks: return True, builddata # Make sure we can remove it from the inventory first. if not player.inventory.consume((block.slot, 0)): return True, builddata # Offset coords according to face. if face == "-x": x -= 1 elif face == "+x": x += 1 elif face == "-y": y -= 1 elif face == "+y": y += 1 elif face == "-z": z -= 1 elif face == "+z": z += 1 bigx, smallx, bigz, smallz = split_coords(x, z) chunk = factory.world.load_chunk(bigx, bigz) chunk.set_block((smallx, y, smallz), block.slot) if metadata: chunk.set_metadata((smallx, y, smallz), metadata) return True, builddata
def update_chunks(self): x, chaff, z, chaff = split_coords(self.player.location.x, self.player.location.z) new = set((i + x, j + z) for i, j in circle) old = set(self.chunks.iterkeys()) added = new - old discarded = old - new # Perhaps some explanation is in order. # The cooperate() function iterates over the iterable it is fed, # without tying up the reactor, by yielding after each iteration. The # inner part of the generator expression generates all of the chunks # around the currently needed chunk, and it sorts them by distance to # the current chunk. The end result is that we load chunks one-by-one, # nearest to furthest, without stalling other clients. if self.chunk_tasks: for task in self.chunk_tasks: try: task.stop() except (TaskDone, TaskFailed): pass self.chunk_tasks = [cooperate(task) for task in ( self.enable_chunk(i, j) for i, j in sorted(added, key=lambda t: (t[0] - x)**2 + (t[1] - z)**2) ), (self.disable_chunk(i, j) for i, j in discarded) ]
def update_chunks(self): x, chaff, z, chaff = split_coords(self.location.x, self.location.z) new = set((i + x, j + z) for i, j in circle) old = set(self.chunks.iterkeys()) added = new - old discarded = old - new # Perhaps some explanation is in order. # The cooperate() function iterates over the iterable it is fed, # without tying up the reactor, by yielding after each iteration. The # inner part of the generator expression generates all of the chunks # around the currently needed chunk, and it sorts them by distance to # the current chunk. The end result is that we load chunks one-by-one, # nearest to furthest, without stalling other clients. if self.chunk_tasks: for task in self.chunk_tasks: try: task.stop() except (TaskDone, TaskFailed): pass self.chunk_tasks = [ cooperate(task) for task in (self.enable_chunk(i, j) for i, j in sorted( added, key=lambda t: (t[0] - x)**2 + (t[1] - z)**2) ), (self.disable_chunk(i, j) for i, j in discarded) ]
def position_changed(self): x, chaff, z, chaff = split_coords(self.location.x, self.location.z) # Inform everybody of our new location. packet = make_packet("teleport", eid=self.player.eid, x=self.location.x * 32, y=self.location.y * 32, z=self.location.z * 32, yaw=int(self.location.theta * 255 / (2 * pi)) % 256, pitch=int(self.location.phi * 255 / (2 * pi)) % 256, ) self.factory.broadcast_for_others(packet, self) self.update_chunks() for entity in self.entities_near(2): if entity.name != "Item": continue if self.player.inventory.add(entity.item, entity.quantity): packet = make_packet("collect", eid=entity.eid, destination=self.player.eid) self.factory.broadcast(packet) packet = make_packet("destroy", eid=entity.eid) self.factory.broadcast(packet) packet = self.player.inventory.save_to_packet() self.transport.write(packet) self.factory.destroy_entity(entity)
def build_hook(self, factory, player, builddata): bigx, smallx, bigz, smallz = split_coords(builddata.x, builddata.z) chunk = factory.world.load_chunk(bigx, bigz) block = chunk.get_block((smallx, builddata.y, smallz)) if block == blocks["snow"].slot: # Building any block on snow causes snow to get replaced. builddata = builddata._replace(face="+y", y=builddata.y - 1) return True, builddata
def set_metadata(self, coords, value): """ Set a block's metadata in an unknown chunk. """ x, y, z = coords bigx, smallx, bigz, smallz = split_coords(x, z) chunk = self.load_chunk(bigx, bigz) chunk.set_metadata((smallx, y, smallz), value)
def get_metadata(self, coords): """ Get a block's metadata from an unknown chunk. """ x, y, z = coords bigx, smallx, bigz, smallz = split_coords(x, z) chunk = self.load_chunk(bigx, bigz) return chunk.get_metadata((smallx, y, smallz))
def decorated(self, coords, *args, **kwargs): x, y, z = coords bigx, smallx, bigz, smallz = split_coords(x, z) d = self.request_chunk(bigx, bigz) def cb(chunk): return f(self, chunk, (smallx, y, smallz), *args, **kwargs) d.addCallback(cb) return d
def update_location(self): bigx, smallx, bigz, smallz = split_coords(self.player.location.x, self.player.location.z) chunk = self.chunks[bigx, bigz] height = chunk.height_at(smallx, smallz) + 2 self.player.location.y = height packet = self.player.location.save_to_packet() self.transport.write(packet)
def update_location(self): bigx, smallx, bigz, smallz = split_coords(self.location.x, self.location.z) chunk = self.chunks[bigx, bigz] height = chunk.height_at(smallx, smallz) + 2 self.location.y = height packet = self.location.save_to_packet() self.transport.write(packet)
def send_initial_chunk_and_location(self): bigx, smallx, bigz, smallz = split_coords(self.location.x, self.location.z) # Spawn the 25 chunks in a square around the spawn, *before* spawning # the player. Otherwise, there's a funky Beta 1.2 bug which causes the # player to not be able to move. d = cooperate( self.enable_chunk(i, j) for i, j in product(xrange(bigx - 3, bigx + 3), xrange(bigz - 3, bigz + 3))).whenDone() # Don't dare send more chunks beyond the initial one until we've # spawned. d.addCallback(lambda none: self.update_location()) d.addCallback(lambda none: self.position_changed()) d.addCallback(lambda none: self.update_chunks())
def build_hook(self, factory, player, builddata): item, metadata, x, y, z, face = builddata if item.slot == items["sign"].slot: # Buildin' a sign, puttin' it on a wall... builddata = builddata._replace(block=blocks["wall-sign"]) # Offset coords according to face. if face == "-x": builddata = builddata._replace(metadata=0x4) x -= 1 elif face == "+x": builddata = builddata._replace(metadata=0x5) x += 1 elif face == "-y": # Ceiling Sign is watching you read. return False, builddata elif face == "+y": # Put +Y signs on signposts. We're fancy that way. builddata = builddata._replace(block=blocks["signpost"]) y += 1 elif face == "-z": builddata = builddata._replace(metadata=0x2) z -= 1 elif face == "+z": builddata = builddata._replace(metadata=0x3) z += 1 bigx, smallx, bigz, smallz = split_coords(x, z) chunk = factory.world.load_chunk(bigx, bigz) # Let's build a sign! s = tile_entities["Sign"]() s.x = x s.y = y s.z = z chunk.tiles[x, y, z] = s # We handled this build correctly, but the signpost still needs to # get placed. return True, builddata return True, builddata
def send_initial_chunk_and_location(self): bigx, smallx, bigz, smallz = split_coords(self.player.location.x, self.player.location.z) # Spawn the 25 chunks in a square around the spawn, *before* spawning # the player. Otherwise, there's a funky Beta 1.2 bug which causes the # player to not be able to move. d = cooperate( self.enable_chunk(i, j) for i, j in product( xrange(bigx - 3, bigx + 3), xrange(bigz - 3, bigz + 3) ) ).whenDone() # Don't dare send more chunks beyond the initial one until we've # spawned. d.addCallback(lambda none: self.update_location()) d.addCallback(lambda none: self.update_chunks())
def entities_near(self, radius): """ Obtain the entities within a radius of this player. Radius is measured in blocks. """ chunk_radius = int(radius // 16 + 1) chunkx, chaff, chunkz, chaff = split_coords(self.location.x, self.location.z) minx = chunkx - chunk_radius maxx = chunkx + chunk_radius + 1 minz = chunkz - chunk_radius maxz = chunkz + chunk_radius + 1 for x, z in product(xrange(minx, maxx), xrange(minz, maxz)): chunk = self.chunks[x, z] yieldables = [entity for entity in chunk.entities if self.location.distance(entity.location) <= radius] for i in yieldables: yield i
def digging(self, container): if container.state != 3: return if time() - self.last_dig_build_timer < 0.2: self.error("You are digging too fast.") self.last_dig_build_timer = time() bigx, smallx, bigz, smallz = split_coords(container.x, container.z) try: chunk = self.chunks[bigx, bigz] except KeyError: self.error("Couldn't dig in chunk (%d, %d)!" % (bigx, bigz)) return oldblock = blocks[chunk.get_block((smallx, container.y, smallz))] for hook in self.dig_hooks: hook.dig_hook(self.factory, chunk, smallx, container.y, smallz, oldblock) self.factory.flush_chunk(chunk)
def build_hook(self, factory, player, builddata): item, metadata, x, y, z, face = builddata if item.slot == items["sign"].slot: # Buildin' a sign, puttin' it on a wall... builddata = builddata._replace(block=blocks["wall-sign"]) # Offset coords according to face. if face == "-x": builddata = builddata._replace(metadata=0x4) x -= 1 elif face == "+x": builddata = builddata._replace(metadata=0x5) x += 1 elif face == "-y": # Ceiling Sign is watching you read. return False, builddata elif face == "+y": # Put +Y signs on signposts. We're fancy that way. Also, # calculate the proper orientation based on player # orientation. # 180 degrees around to orient the signs correctly, and then # 23 degrees to get the sign to midpoint correctly. metadata = ((player.location.yaw + 180) * 16 // 360) % 0xF builddata = builddata._replace(block=blocks["signpost"], metadata=metadata) y += 1 elif face == "-z": builddata = builddata._replace(metadata=0x2) z -= 1 elif face == "+z": builddata = builddata._replace(metadata=0x3) z += 1 bigx, smallx, bigz, smallz = split_coords(x, z) chunk = factory.world.load_chunk(bigx, bigz) # Let's build a sign! s = Sign(smallx, y, smallz) chunk.tiles[smallx, y, smallz] = s elif item.slot == blocks["chest"].slot: if face == "-x": x -= 1 elif face == "+x": x += 1 elif face == "-y": y -= 1 elif face == "+y": y += 1 elif face == "-z": z -= 1 elif face == "+z": z += 1 bigx, smallx, bigz, smallz = split_coords(x, z) chunk = factory.world.load_chunk(bigx, bigz) # Not much to do, just tell the chunk about this chest. c = Chest(smallx, y, smallz) chunk.tiles[smallx, y, smallz] = c return True, builddata
def build_hook(self, factory, player, builddata): bigx, smallx, bigz, smallz = split_coords(builddata.x, builddata.z) chunk = yield factory.world.request_chunk(bigx, bigz) self.dig_hook(factory, chunk, smallx, builddata.y, smallz, builddata.block) returnValue((True, builddata))
def build_hook(self, factory, player, builddata): item, metadata, x, y, z, face = builddata if item.slot == items["sign"].slot: # Buildin' a sign, puttin' it on a wall... builddata = builddata._replace(block=blocks["wall-sign"]) # Offset coords according to face. if face == "-x": builddata = builddata._replace(metadata=0x4) x -= 1 elif face == "+x": builddata = builddata._replace(metadata=0x5) x += 1 elif face == "-y": # Ceiling Sign is watching you read. return False, builddata elif face == "+y": # Put +Y signs on signposts. We're fancy that way. Also, # calculate the proper orientation based on player # orientation. # 180 degrees around to orient the signs correctly, and then # 23 degrees to get the sign to midpoint correctly. metadata = ((player.location.yaw + 180) * 16 // 360) % 0xf builddata = builddata._replace(block=blocks["signpost"], metadata=metadata) y += 1 elif face == "-z": builddata = builddata._replace(metadata=0x2) z -= 1 elif face == "+z": builddata = builddata._replace(metadata=0x3) z += 1 bigx, smallx, bigz, smallz = split_coords(x, z) chunk = factory.world.load_chunk(bigx, bigz) # Let's build a sign! s = Sign(smallx, y, smallz) chunk.tiles[smallx, y, smallz] = s elif item.slot == blocks["chest"].slot: if face == "-x": x -= 1 elif face == "+x": x += 1 elif face == "-y": y -= 1 elif face == "+y": y += 1 elif face == "-z": z -= 1 elif face == "+z": z += 1 bigx, smallx, bigz, smallz = split_coords(x, z) chunk = factory.world.load_chunk(bigx, bigz) # Not much to do, just tell the chunk about this chest. c = Chest(smallx, y, smallz) chunk.tiles[smallx, y, smallz] = c return True, builddata
def build_hook(self, factory, player, builddata): bigx, smallx, bigz, smallz = split_coords(builddata.x, builddata.z) chunk = factory.world.load_chunk(bigx, bigz) self.dig_hook(factory, chunk, smallx, builddata.y, smallz, builddata.block) return True, builddata
def build(self, container): if container.x == -1 and container.z == -1 and container.y == 255: # Lala-land build packet. Discard it for now. return # Is the target being selected? 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 if (chunk.get_block( (smallx, container.y, smallz)) == blocks["workbench"].slot): i = Workbench() sync_inventories(self.player.inventory, i) self.windows[self.wid] = i packet = make_packet("window-open", wid=self.wid, type="workbench", title="Hurp", slots=2) self.wid += 1 self.transport.write(packet) 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 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 if time() - self.last_dig_build_timer < 0.05: self.error("You are building too fast.") self.last_dig_build_timer = time() # it's the top of the world, you can't build here if container.y == 127 and container.face == '+y': return builddata = BuildData(block, 0x0, container.x, container.y, container.z, container.face) for hook in self.build_hooks: cont, builddata = yield maybeDeferred(hook.build_hook, self.factory, self.player, builddata) if not cont: break newblock = builddata.block.slot # Feed automatons. for automaton in self.factory.automatons: if newblock in automaton.blocks: automaton.feed(self.factory, (builddata.x, builddata.y, builddata.z)) # Re-send inventory. # XXX this could be optimized if/when inventories track damage. packet = self.player.inventory.save_to_packet() self.transport.write(packet) # Flush damaged chunks. for chunk in self.chunks.itervalues(): self.factory.flush_chunk(chunk)
def digging(self, container): # XXX several improvements should happen here # ~ We should time started and stopped pairs to force clients to # slow-break their blocks if container.x == -1 and container.z == -1 and container.y == 255: # Lala-land dig packet. Discard it for now. return # Player drops currently holding item/block. if (container.state == "dropped" and container.face == "-y" and container.x == 0 and container.y == 0 and container.z == 0): i = self.player.inventory holding = i.holdables[self.player.equipped] if holding: primary, secondary, count = holding if i.consume((primary, secondary), self.player.equipped): dest = self.location.in_front_of(2) dest.y += 1 coords = (int(dest.x * 32) + 16, int(dest.y * 32) + 16, int(dest.z * 32) + 16) self.factory.give(coords, (primary, secondary), 1) # Re-send inventory. packet = self.player.inventory.save_to_packet() self.transport.write(packet) # If no items in this slot are left, this player isn't # holding an item anymore. if i.holdables[self.player.equipped] is None: packet = make_packet("entity-equipment", eid=self.player.eid, slot=0, primary=65535, secondary=0) self.factory.broadcast_for_others(packet, self) return if container.state != "stopped": # We only care about digs which break blocks. return if time() - self.last_dig_build_timer < 0.1: self.error("You are digging too fast.") self.last_dig_build_timer = time() bigx, smallx, bigz, smallz = split_coords(container.x, container.z) try: chunk = self.chunks[bigx, bigz] except KeyError: self.error("Couldn't dig in chunk (%d, %d)!" % (bigx, bigz)) return oldblock = blocks[chunk.get_block((smallx, container.y, smallz))] l = [] for hook in self.dig_hooks: l.append( maybeDeferred(hook.dig_hook, self.factory, chunk, smallx, container.y, smallz, oldblock)) dl = DeferredList(l) dl.addCallback(lambda none: self.factory.flush_chunk(chunk))
def digging(self, container): # XXX several improvements should happen here # ~ We should time started and stopped pairs to force clients to # slow-break their blocks if container.x == -1 and container.z == -1 and container.y == 255: # Lala-land dig packet. Discard it for now. return # Player drops currently holding item/block. if (container.state == "dropped" and container.face == "-y" and container.x == 0 and container.y == 0 and container.z == 0): i = self.player.inventory holding = i.holdables[self.player.equipped] if holding: primary, secondary, count = holding if i.consume((primary, secondary), self.player.equipped): dest = self.location.in_front_of(2) dest.y += 1 coords = (int(dest.x * 32) + 16, int(dest.y * 32) + 16, int(dest.z * 32) + 16) self.factory.give(coords, (primary, secondary), 1) # Re-send inventory. packet = self.player.inventory.save_to_packet() self.transport.write(packet) # If no items in this slot are left, this player isn't # holding an item anymore. if i.holdables[self.player.equipped] is None: packet = make_packet("entity-equipment", eid=self.player.eid, slot=0, primary=65535, secondary=0 ) self.factory.broadcast_for_others(packet, self) return if container.state != "stopped": # We only care about digs which break blocks. return if time() - self.last_dig_build_timer < 0.1: self.error("You are digging too fast.") self.last_dig_build_timer = time() bigx, smallx, bigz, smallz = split_coords(container.x, container.z) try: chunk = self.chunks[bigx, bigz] except KeyError: self.error("Couldn't dig in chunk (%d, %d)!" % (bigx, bigz)) return oldblock = blocks[chunk.get_block((smallx, container.y, smallz))] l = [] for hook in self.dig_hooks: l.append(maybeDeferred(hook.dig_hook, self.factory, chunk, smallx, container.y, smallz, oldblock)) dl = DeferredList(l) dl.addCallback(lambda none: self.factory.flush_chunk(chunk))