Esempio n. 1
0
    def pre_build_hook(self, player, builddata):
        item, metadata, x, y, z, face = builddata

        if item.slot != blocks["chest"].slot:
            returnValue((True, builddata, False))

        x, y, z = adjust_coords_for_face((x, y, z), face)
        bigx, smallx, bigz, smallz = split_coords(x, z)

        # chest orientation according to players position
        if face == "-y" or face == "+y":
            orientation = ('+x', '+z', '-x', '-z')[((int(player.location.yaw) \
                                                - 45 + 360) % 360) / 90]
        else:
            orientation = face

        # Chests have some restrictions on building:
        # you cannot connect more than two chests. (notchian)
        ccs = chestsAround(self.factory, (x, y, z))
        ccn = len(ccs)
        if ccn > 1:
            # cannot build three or more connected chests
            returnValue((False, builddata, True))

        chunk = yield self.factory.world.request_chunk(bigx, bigz)

        if ccn == 0:
            metadata = blocks["chest"].orientation(orientation)
        elif ccn == 1:
            # check gonna-be-connected chest is not connected already
            n = len(chestsAround(self.factory, ccs[0]))
            if n != 0:
                returnValue((False, builddata, True))

            # align both blocks correctly (since 1.8)
            # get second block
            x2, y2, z2 = ccs[0]
            bigx2, smallx2, bigz2, smallz2 = split_coords(x2, z2)
            # new chests orientation axis according to blocks position
            pair = x - x2, z - z2
            ornt = {(0, 1): "x", (0, -1): "x", (1, 0): "z", (-1, 0): "z"}[pair]
            # if player is faced another direction, fix it
            if orientation[1] != ornt:
                # same sign with proper orientation
                # XXX Probably notchian logic is different here
                #     but this one works well enough
                orientation = orientation[0] + ornt
            metadata = blocks["chest"].orientation(orientation)
            # update second block's metadata
            if bigx == bigx2 and bigz == bigz2:
                # both blocks are in same chunk
                chunk2 = chunk
            else:
                chunk2 = yield self.factory.world.request_chunk(bigx2, bigz2)
            chunk2.set_metadata((smallx2, y2, smallz2), metadata)

        # Not much to do, just tell the chunk about this tile.
        chunk.tiles[smallx, y, smallz] = ChestTile(smallx, y, smallz)
        builddata = builddata._replace(metadata=metadata)
        returnValue((True, builddata, False))
Esempio n. 2
0
    def open_hook(self, player, container, block):
        """
        The ``player`` is a Player's protocol
        The ``container`` is a 0x64 message
        The ``block`` is a block we trying to open
        :returns: None or window object
        """
        if block != blocks["chest"].slot:
            returnValue(None)

        bigx, smallx, bigz, smallz = split_coords(container.x, container.z)
        chunk = yield self.factory.world.request_chunk(bigx, bigz)

        chests_around = chestsAround(self.factory,
                                     (container.x, container.y, container.z))
        chests_around_num = len(chests_around)

        if chests_around_num == 0:  # small chest
            chest = self.get_chest_tile(chunk, (smallx, container.y, smallz))
            if chest is None:
                returnValue(None)
            coords = bigx, smallx, bigz, smallz, container.y
            window = ChestWindow(player.wid, player.player.inventory,
                                 chest.inventory, coords)
        elif chests_around_num == 1:  # large chest
            # process second chest coordinates
            x2, y2, z2 = chests_around[0]
            bigx2, smallx2, bigz2, smallz2 = split_coords(x2, z2)
            if bigx == bigx2 and bigz == bigz2:
                # both chest blocks are in same chunk
                chunk2 = chunk
            else:
                chunk2 = yield self.factory.world.request_chunk(bigx2, bigz2)

            chest1 = self.get_chest_tile(chunk, (smallx, container.y, smallz))
            chest2 = self.get_chest_tile(chunk2,
                                         (smallx2, container.y, smallz2))
            if chest1 is None or chest2 is None:
                returnValue(None)
            c1 = bigx, smallx, bigz, smallz, container.y
            c2 = bigx2, smallx2, bigz2, smallz2, container.y
            # We shall properly order chest inventories
            if c1 < c2:
                window = LargeChestWindow(player.wid, player.player.inventory,
                                          chest1.inventory, chest2.inventory,
                                          c1)
            else:
                window = LargeChestWindow(player.wid, player.player.inventory,
                                          chest2.inventory, chest1.inventory,
                                          c2)
        else:
            log.msg("Chest at (%d, %d, %d) have three chests connected" %
                    (container.x, container.y, container.z))
            returnValue(None)

        player.windows.append(window)
        returnValue(window)
Esempio n. 3
0
    def open_hook(self, player, container, block):
        """
        The ``player`` is a Player's protocol
        The ``container`` is a 0x64 message
        The ``block`` is a block we trying to open
        :returns: None or window object
        """
        if block != blocks["chest"].slot:
            returnValue(None)

        bigx, smallx, bigz, smallz = split_coords(container.x, container.z)
        chunk = yield self.factory.world.request_chunk(bigx, bigz)

        chests_around = chestsAround(self.factory,
                (container.x, container.y, container.z))
        chests_around_num = len(chests_around)

        if chests_around_num == 0: # small chest
            chest = self.get_chest_tile(chunk, (smallx, container.y, smallz))
            if chest is None:
                returnValue(None)
            coords = bigx, smallx, bigz, smallz, container.y
            window = ChestWindow(player.wid, player.player.inventory,
                                 chest.inventory, coords)
        elif chests_around_num == 1: # large chest
            # process second chest coordinates
            x2, y2, z2 = chests_around[0]
            bigx2, smallx2, bigz2, smallz2 = split_coords(x2, z2)
            if bigx == bigx2 and bigz == bigz2:
                # both chest blocks are in same chunk
                chunk2 = chunk
            else:
                chunk2 = yield self.factory.world.request_chunk(bigx2, bigz2)

            chest1 = self.get_chest_tile(chunk, (smallx, container.y, smallz))
            chest2 = self.get_chest_tile(chunk2, (smallx2, container.y, smallz2))
            if chest1 is None or chest2 is None:
                returnValue(None)
            c1 = bigx, smallx, bigz, smallz, container.y
            c2 = bigx2, smallx2, bigz2, smallz2, container.y
            # We shall properly order chest inventories
            if c1 < c2:
                window = LargeChestWindow(player.wid, player.player.inventory,
                        chest1.inventory, chest2.inventory, c1)
            else:
                window = LargeChestWindow(player.wid, player.player.inventory,
                        chest2.inventory, chest1.inventory, c2)
        else:
            log.msg("Chest at (%d, %d, %d) have three chests connected" %
                    (container.x, container.y, container.z))
            returnValue(None)

        player.windows.append(window)
        returnValue(window)
Esempio n. 4
0
    def pre_build_hook(self, 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.
                returnValue((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)

            # Let's build a sign!
            chunk = yield factory.world.request_chunk(bigx, bigz)
            s = Sign(smallx, y, smallz)
            chunk.tiles[smallx, y, smallz] = s

        elif item.slot == blocks["chest"].slot:
            x, y, z = adjust_coords_for_face((x, y, z), face)

            bigx, smallx, bigz, smallz = split_coords(x, z)

           # Not much to do, just tell the chunk about this chest.
            chunk = yield factory.world.request_chunk(bigx, bigz)
            c = Chest(smallx, y, smallz)
            chunk.tiles[smallx, y, smallz] = c

        returnValue((True, builddata))
Esempio n. 5
0
    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)
        ]
Esempio n. 6
0
    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)
Esempio n. 7
0
    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)):
            if (x, z) not in self.chunks:
                continue
            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
Esempio n. 8
0
    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)
Esempio n. 9
0
    def open_or_close(self, world, point):
        """
        Toggle the state of the door : open it if it was closed, close it if it was open.
        """
        x, y, z = point[0], point[1], point[2]

        bigx, x, bigz, z = split_coords(x, z)
        d = world.request_chunk(bigx, bigz)

        @d.addCallback
        def cb(chunk):
            block = chunk.get_block((x, y, z))
            if block not in Door.doors: # already removed
                return
            metadata = chunk.get_metadata((x, y, z))
            chunk.set_metadata((x, y, z), metadata ^ DOOR_IS_SWUNG)

            # Finding out which block is the door's top block.
            if (metadata & DOOR_TOP_BLOCK) != 0:
                other_y = y - 1
            else:
                other_y = y + 1

            other_block = chunk.get_block((x, other_y, z))
            if other_block in Door.doors:
                metadata = chunk.get_metadata((x, other_y, z))
                chunk.set_metadata((x, other_y, z), metadata ^ DOOR_IS_SWUNG)

            # Flush changed chunk
            self.factory.flush_chunk(chunk)
Esempio n. 10
0
    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.pos.x,
                                                    self.location.pos.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)):
            if (x, z) not in self.chunks:
                continue
            chunk = self.chunks[x, z]

            yieldables = [
                entity for entity in chunk.entities
                if self.location.distance(entity.location) <= (radius * 32)
            ]
            for i in yieldables:
                yield i
Esempio n. 11
0
    def open_or_close(self, world, point):
        """
        Toggle the state of the door : open it if it was closed, close it if it was open.
        """
        x, y, z = point[0], point[1], point[2]

        bigx, x, bigz, z = split_coords(x, z)
        d = world.request_chunk(bigx, bigz)

        @d.addCallback
        def cb(chunk):
            block = chunk.get_block((x, y, z))
            if block not in Door.doors:  # already removed
                return
            metadata = chunk.get_metadata((x, y, z))
            chunk.set_metadata((x, y, z), metadata ^ DOOR_IS_SWUNG)

            # Finding out which block is the door's top block.
            if (metadata & DOOR_TOP_BLOCK) != 0:
                other_y = y - 1
            else:
                other_y = y + 1

            other_block = chunk.get_block((x, other_y, z))
            if other_block in Door.doors:
                metadata = chunk.get_metadata((x, other_y, z))
                chunk.set_metadata((x, other_y, z), metadata ^ DOOR_IS_SWUNG)

            # Flush changed chunk
            self.factory.flush_chunk(chunk)
Esempio n. 12
0
    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())
Esempio n. 13
0
    def update_chunks(self):
        x, y, z = self.location.pos.to_block()
        x, chaff, z, chaff = split_coords(x, 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(
                self.enable_chunk(i, j) for i, j in sorted(
                    added, key=lambda t: (t[0] - x)**2 + (t[1] - z)**2)),
            cooperate(self.disable_chunk(i, j) for i, j in discarded)
        ]
Esempio n. 14
0
    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)
Esempio n. 15
0
File: beta.py Progetto: mkaay/bravo
    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

        # it's the top of the world, you can't build here
        if container.y == 127 and container.face == "+y":
            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 = yield maybeDeferred(hook.pre_build_hook, self.player, builddata)
            if not cont:
                break

        # Run the build.
        try:
            builddata = self.prepare_build(builddata)
            yield maybeDeferred(self.run_build, builddata)
        except BuildError, e:
            print e
            return
Esempio n. 16
0
 def run(self):
     """
     Starts a mob's loop process
     """
     xcoord, chaff, zcoord, chaff = split_coords(self.location.x,
         self.location.z)
     self.chunk_coords = (xcoord,1, zcoord) # XXX The one is redundant, fix it
     self.loop = LoopingCall(self.update)
     self.loop.start(.2)
Esempio n. 17
0
File: beta.py Progetto: mkaay/bravo
    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)
Esempio n. 18
0
File: world.py Progetto: driax/bravo
    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
Esempio n. 19
0
 def test_split_coords(self):
     cases = {
         (0, 0): (0, 0, 0, 0),
         (1, 1): (0, 1, 0, 1),
         (16, 16): (1, 0, 1, 0),
         (-1, -1): (-1, 15, -1, 15),
         (-16, -16): (-1, 0, -1, 0),
     }
     for case in cases:
         self.assertEqual(split_coords(*case), cases[case])
Esempio n. 20
0
    def decorated(self, coords, *args, **kwargs):
        x, y, z = coords

        bigx, smallx, bigz, smallz = split_coords(x, z)
        d = self.request_chunk(bigx, bigz)

        @d.addCallback
        def cb(chunk):
            return f(self, chunk, (smallx, y, smallz), *args, **kwargs)

        return d
Esempio n. 21
0
    def decorated(self, coords, *args, **kwargs):
        x, y, z = coords

        bigx, smallx, bigz, smallz = split_coords(x, z)
        if (bigx, bigz) in self.chunk_cache:
            chunk = self.chunk_cache[bigx, bigz]
        elif (bigx, bigz) in self.dirty_chunk_cache:
            chunk = self.dirty_chunk_cache[bigx, bigz]
        else:
            raise ChunkNotLoaded("Chunk (%d, %d) isn't loaded")

        return f(self, chunk, (smallx, y, smallz), *args, **kwargs)
Esempio n. 22
0
    def open_or_close(self, coords):
        x, y, z = coords
        bigx, x, bigz, z = split_coords(x, z)
        d = self.factory.world.request_chunk(bigx, bigz)

        @d.addCallback
        def cb(chunk):
            block = chunk.get_block((x, y, z))
            if block != blocks["trapdoor"].slot:  # already removed
                return
            metadata = chunk.get_metadata((x, y, z))
            chunk.set_metadata((x, y, z), metadata ^ DOOR_IS_SWUNG)
            self.factory.flush_chunk(chunk)
Esempio n. 23
0
    def open_or_close(self, coords):
        x, y, z = coords
        bigx, x, bigz, z = split_coords(x, z)
        d = self.factory.world.request_chunk(bigx, bigz)

        @d.addCallback
        def cb(chunk):
            block = chunk.get_block((x, y, z))
            if block != blocks["trapdoor"].slot: # already removed
                return
            metadata = chunk.get_metadata((x, y, z))
            chunk.set_metadata((x, y, z), metadata ^ DOOR_IS_SWUNG)
            self.factory.flush_chunk(chunk)
Esempio n. 24
0
    def decorated(self, coords, *args, **kwargs):
        x, y, z = coords

        bigx, smallx, bigz, smallz = split_coords(x, z)
        bigcoords = bigx, bigz
        if bigcoords in self.chunk_cache:
            chunk = self.chunk_cache[bigcoords]
        elif bigcoords in self.dirty_chunk_cache:
            chunk = self.dirty_chunk_cache[bigcoords]
        else:
            raise ChunkNotLoaded("Chunk (%d, %d) isn't loaded" % bigcoords)

        return f(self, chunk, (smallx, y, smallz), *args, **kwargs)
Esempio n. 25
0
    def send_initial_chunk_and_location(self):
        """
        Send the initial chunks and location.

        This method sends more than one chunk; since Beta 1.2, it must send
        nearly fifty chunks before the location can be safely sent.
        """

        # Disable located hooks. We'll re-enable them at the end.
        self.state = STATE_AUTHENTICATED

        log.msg("Initial, position %d, %d, %d" % self.location.pos)
        x, y, z = self.location.pos.to_block()
        bigx, smallx, bigz, smallz = split_coords(x, z)

        # Spawn the 49 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 = gatherResults([
            self.enable_chunk(i, j)
            for i, j in product(xrange(bigx - 3, bigx +
                                       3), xrange(bigz - 3, bigz + 3))
        ])

        # What to do if we can't load a given chunk? Just kick 'em.
        d.addErrback(lambda fail: self.error("Couldn't load a chunk... :c"))

        # Don't dare send more chunks beyond the initial one until we've
        # spawned. Once we've spawned, set our status to LOCATED and then
        # update_location() will work.
        @d.addCallback
        def located(none):
            self.state = STATE_LOCATED
            # Ensure that we're above-ground.
            self.ascend(0)

        d.addCallback(lambda none: self.update_location())
        d.addCallback(lambda none: self.position_changed())

        # Send the MOTD.
        if self.motd:

            @d.addCallback
            def motd(none):
                self.write_packet("chat",
                                  message=self.motd.replace(
                                      "<tagline>", get_motd()))

        # Finally, start the secondary chunk loop.
        d.addCallback(lambda none: self.update_chunks())
Esempio n. 26
0
    def decorated(self, coords, *args, **kwargs):
        x, y, z = coords

        # Fail early if Y is OOB.
        if not 0 <= y < CHUNK_HEIGHT:
            raise ImpossibleCoordinates("Y value %d is impossible" % y)

        bigx, smallx, bigz, smallz = split_coords(x, z)
        d = self.request_chunk(bigx, bigz)

        @d.addCallback
        def cb(chunk):
            return f(self, chunk, (smallx, y, smallz), *args, **kwargs)

        return d
Esempio n. 27
0
    def send_initial_chunk_and_location(self):
        """
        Send the initial chunks and location.

        This method sends more than one chunk; since Beta 1.2, it must send
        nearly fifty chunks before the location can be safely sent.
        """

        # Disable located hooks. We'll re-enable them at the end.
        self.state = STATE_AUTHENTICATED

        log.msg("Initial, position %d, %d, %d" % self.location.pos)
        x, y, z = self.location.pos.to_block()
        bigx, smallx, bigz, smallz = split_coords(x, z)

        # Spawn the 49 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 = gatherResults([self.enable_chunk(i, j)
            for i, j in product(
                xrange(bigx - 3, bigx + 3),
                xrange(bigz - 3, bigz + 3)
            )
        ])

        # What to do if we can't load a given chunk? Just kick 'em.
        d.addErrback(lambda fail: self.error("Couldn't load a chunk... :c"))

        # Don't dare send more chunks beyond the initial one until we've
        # spawned. Once we've spawned, set our status to LOCATED and then
        # update_location() will work.
        @d.addCallback
        def located(none):
            self.state = STATE_LOCATED
            # Ensure that we're above-ground.
            self.ascend(0)
        d.addCallback(lambda none: self.update_location())
        d.addCallback(lambda none: self.position_changed())

        # Send the MOTD.
        if self.motd:
            @d.addCallback
            def motd(none):
                self.write_packet("chat",
                    message=self.motd.replace("<tagline>", get_motd()))

        # Finally, start the secondary chunk loop.
        d.addCallback(lambda none: self.update_chunks())
Esempio n. 28
0
    def send_initial_chunk_and_location(self):
        """
        Send the initial chunks and location.

        This method sends more than one chunk; since Beta 1.2, it must send
        nearly fifty chunks before the location can be safely sent.
        """

        # Disable located hooks. We'll re-enable them at the end.
        self.state = STATE_AUTHENTICATED

        log.msg("Initial, position %d, %d, %d" % self.location.pos)
        x, y, z = self.location.pos.to_block()
        bigx, smallx, bigz, smallz = split_coords(x, z)

        # Send the chunk that the player will stand on. The other chunks are
        # not so important. There *used* to be a bug, circa Beta 1.2, that
        # required lots of surrounding geometry to be present, but that's been
        # fixed.
        d = self.enable_chunk(bigx, bigz)

        # What to do if we can't load a given chunk? Just kick 'em.
        d.addErrback(lambda fail: self.error("Couldn't load a chunk... :c"))

        # Don't dare send more chunks beyond the initial one until we've
        # spawned. Once we've spawned, set our status to LOCATED and then
        # update_location() will work.
        @d.addCallback
        def located(none):
            self.state = STATE_LOCATED
            # Ensure that we're above-ground.
            self.ascend(0)
            # XXX for now, drop down from way up high down onto the ground.
            # ascend() is busted, I think, and there's no good way to get up
            # this high.
            self.location.pos = self.location.pos._replace(y=250 * 32)
        d.addCallback(lambda none: self.update_location())
        d.addCallback(lambda none: self.position_changed())

        # Send the MOTD.
        if self.motd:
            @d.addCallback
            def motd(none):
                self.write_packet("chat",
                    message=self.motd.replace("<tagline>", get_motd()))

        # Finally, start the secondary chunk loop.
        d.addCallback(lambda none: self.update_chunks())
Esempio n. 29
0
    def decorated(self, coords, *args, **kwargs):
        x, y, z = coords

        # Fail early if Y is OOB.
        if not 0 <= y < CHUNK_HEIGHT:
            raise ImpossibleCoordinates("Y value %d is impossible" % y)

        bigx, smallx, bigz, smallz = split_coords(x, z)
        bigcoords = bigx, bigz

        chunk = self._cache.get(bigcoords)

        if chunk is None:
            raise ChunkNotLoaded("Chunk (%d, %d) isn't loaded" % bigcoords)

        return f(self, chunk, (smallx, y, smallz), *args, **kwargs)
Esempio n. 30
0
    def play_notes(self, notes):
        """
        Play some music.

        Send a sequence of notes to the player. ``notes`` is a finite iterable
        of pairs of instruments and pitches.

        There is no way to time notes; if staggered playback is desired (and
        it usually is!), then ``play_notes()`` should be called repeatedly at
        the appropriate times.

        This method turns the block beneath the player into a note block,
        plays the requested notes through it, then turns it back into the
        original block, all without actually modifying the chunk.
        """

        x, y, z = self.location.pos.to_block()

        if y:
            y -= 1

        bigx, smallx, bigz, smallz = split_coords(x, z)

        if (bigx, bigz) not in self.chunks:
            return

        block = self.chunks[bigx, bigz].get_block((smallx, y, smallz))
        meta = self.chunks[bigx, bigz].get_metadata((smallx, y, smallz))

        self.write_packet("block",
                          x=x,
                          y=y,
                          z=z,
                          type=blocks["note-block"].slot,
                          meta=0)

        for instrument, pitch in notes:
            self.write_packet("note",
                              x=x,
                              y=y,
                              z=z,
                              pitch=pitch,
                              instrument=instrument)

        self.write_packet("block", x=x, y=y, z=z, type=block, meta=meta)
Esempio n. 31
0
    def pre_build_hook(self, player, builddata):
        item, metadata, x, y, z, face = builddata

        if item.slot != items["sign"].slot:
            returnValue((True, builddata, False))

        # 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.
            returnValue((False, builddata, False))
        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.
            yaw = player.location.ori.to_degs()[0]
            metadata = ((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)

        # Let's build a sign!
        chunk = yield self.factory.world.request_chunk(bigx, bigz)
        s = SignTile(smallx, y, smallz)
        chunk.tiles[smallx, y, smallz] = s

        returnValue((True, builddata, False))
Esempio n. 32
0
    def ascend(self, count):
        """
        Ascend to the next XZ-plane.

        ``count`` is the number of ascensions to perform, and may be zero in
        order to force this player to not be standing inside a block.

        :returns: bool of whether the ascension was successful

        This client must be located for this method to have any effect.
        """

        if self.state != STATE_LOCATED:
            return False

        x, y, z = self.location.pos.to_block()

        bigx, smallx, bigz, smallz = split_coords(x, z)

        chunk = self.chunks[bigx, bigz]
        column = [chunk.get_block((smallx, i, smallz))
                  for i in range(CHUNK_HEIGHT)]

        # Special case: Ascend at most once, if the current spot isn't good.
        if count == 0:
            if (not column[y]) or column[y + 1] or column[y + 2]:
                # Yeah, we're gonna need to move.
                count += 1
            else:
                # Nope, we're fine where we are.
                return True

        for i in xrange(y, 255):
            # Find the next spot above us which has a platform and two empty
            # blocks of air.
            if column[i] and (not column[i + 1]) and not column[i + 2]:
                count -= 1
                if not count:
                    break
        else:
            return False

        self.location.pos = self.location.pos._replace(y=i * 32)
        return True
Esempio n. 33
0
    def update_chunks(self):
        # Don't send chunks unless we're located.
        if self.state != STATE_LOCATED:
            return

        x, y, z = self.location.pos.to_block()
        x, chaff, z, chaff = split_coords(x, z)

        # These numbers come from a couple spots, including minecraftwiki, but
        # I verified them experimentally using torches and pillars to mark
        # distances on each setting. ~ C.
        distances = {
            "tiny": 2,
            "short": 4,
            "far": 16,
        }

        radius = distances.get(self.settings.distance, 8)

        new = set(circling(x, z, radius))
        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

        to_enable = sorted_by_distance(added, x, z)

        self.chunk_tasks = [
            cooperate(self.enable_chunk(i, j) for i, j in to_enable),
            cooperate(self.disable_chunk(i, j) for i, j in discarded),
        ]
Esempio n. 34
0
    def ascend(self, count):
        """
        Ascend to the next XZ-plane.

        ``count`` is the number of ascensions to perform, and may be zero in
        order to force this player to not be standing inside a block.

        :returns: bool of whether the ascension was successful

        This client must be located for this method to have any effect.
        """

        if self.state != STATE_LOCATED:
            return False

        x, y, z = self.location.pos.to_block()

        bigx, smallx, bigz, smallz = split_coords(x, z)

        chunk = self.chunks[bigx, bigz]
        column = [chunk.get_block((smallx, i, smallz))
                  for i in range(CHUNK_HEIGHT)]

        # Special case: Ascend at most once, if the current spot isn't good.
        if count == 0:
            if (not column[y]) or column[y + 1] or column[y + 2]:
                # Yeah, we're gonna need to move.
                count += 1
            else:
                # Nope, we're fine where we are.
                return True

        for i in xrange(y, 255):
            # Find the next spot above us which has a platform and two empty
            # blocks of air.
            if column[i] and (not column[i + 1]) and not column[i + 2]:
                count -= 1
                if not count:
                    break
        else:
            return False

        self.location.pos = self.location.pos._replace(y=i * 32)
        return True
Esempio n. 35
0
    def send_initial_chunk_and_location(self):
        """
        Send the initial chunks and location.

        This method sends more than one chunk; since Beta 1.2, it must send
        nearly fifty chunks before the location can be safely sent.
        """

        # Disable located hooks. We'll re-enable them at the end.
        self.state = STATE_AUTHENTICATED

        log.msg("Initial, position %d, %d, %d" % self.location.pos)
        x, y, z = self.location.pos.to_block()
        bigx, smallx, bigz, smallz = split_coords(x, z)

        # Send the chunk that the player will stand on. The other chunks are
        # not so important. There *used* to be a bug, circa Beta 1.2, that
        # required lots of surrounding geometry to be present, but that's been
        # fixed.
        d = self.enable_chunk(bigx, bigz)

        # What to do if we can't load a given chunk? Just kick 'em.
        d.addErrback(lambda fail: self.error("Couldn't load a chunk... :c"))

        # Don't dare send more chunks beyond the initial one until we've
        # spawned. Once we've spawned, set our status to LOCATED and then
        # update_location() will work.
        @d.addCallback
        def located(none):
            self.state = STATE_LOCATED
            # Ensure that we're above-ground.
            self.ascend(0)
        d.addCallback(lambda none: self.update_location())
        d.addCallback(lambda none: self.position_changed())

        # Send the MOTD.
        if self.motd:
            @d.addCallback
            def motd(none):
                self.send_chat(self.motd.replace("<tagline>", get_motd()))

        # Finally, start the secondary chunk loop.
        d.addCallback(lambda none: self.update_chunks())
Esempio n. 36
0
File: beta.py Progetto: gwylim/bravo
    def update_entities(self):
        """
        Update all entities covered by this factory.
        """

        # XXX this method could cause chunks to be generated :c

        points = set()

        for player in self.protocols.itervalues():
            x = player.location.x
            z = player.location.z
            bigx, chaff, bigz, chaff = split_coords(x, z)
            new = set((i + bigx, j + bigz) for i, j in circle)
            points.update(new)

        for x, y in points:
            d = self.world.request_chunk(x, y)
            d.addCallback(lambda chunk: chunk.update_entities(self))
Esempio n. 37
0
    def pre_build_hook(self, player, builddata):
        item, metadata, x, y, z, face = builddata

        if item.slot != blocks["furnace"].slot:
            returnValue((True, builddata, False))

        x, y, z = adjust_coords_for_face((x, y, z), face)
        bigx, smallx, bigz, smallz = split_coords(x, z)

        # the furnace cannot be oriented up or down
        if face == "-y" or face == "+y":
            orientation = ('+x', '+z', '-x', '-z')[((int(player.location.yaw) \
                                                - 45 + 360) % 360) / 90]
            metadata = blocks["furnace"].orientation(orientation)
            builddata = builddata._replace(metadata=metadata)

        # Not much to do, just tell the chunk about this tile.
        chunk = yield self.factory.world.request_chunk(bigx, bigz)
        chunk.tiles[smallx, y, smallz] = FurnaceTile(smallx, y, smallz)
        returnValue((True, builddata, False))
Esempio n. 38
0
    def pre_build_hook(self, player, builddata):
        item, metadata, x, y, z, face = builddata

        if item.slot != blocks["furnace"].slot:
            returnValue((True, builddata, False))

        x, y, z = adjust_coords_for_face((x, y, z), face)
        bigx, smallx, bigz, smallz = split_coords(x, z)

        # the furnace cannot be oriented up or down
        if face == "-y" or face == "+y":
            orientation = ('+x', '+z', '-x', '-z')[((int(player.location.yaw) \
                                                - 45 + 360) % 360) / 90]
            metadata = blocks["furnace"].orientation(orientation)
            builddata = builddata._replace(metadata=metadata)

        # Not much to do, just tell the chunk about this tile.
        chunk = yield self.factory.world.request_chunk(bigx, bigz)
        chunk.tiles[smallx, y, smallz] = FurnaceTile(smallx, y, smallz)
        returnValue((True, builddata, False))
Esempio n. 39
0
    def open_hook(self, player, container, block):
        """
        The ``player`` is a Player's protocol
        The ``container`` is a 0x64 message
        The ``block`` is a block we trying to open
        :returns: None or window object
        """
        if block not in (blocks["furnace"].slot, blocks["burning-furnace"].slot):
            returnValue(None)

        bigx, smallx, bigz, smallz = split_coords(container.x, container.z)
        chunk = yield factory.world.request_chunk(bigx, bigz)

        furnace = self.get_furnace_tile(chunk, (smallx, container.y, smallz))
        if furnace is None:
            returnValue(None)

        coords = bigx, smallx, bigz, smallz, container.y
        window = FurnaceWindow(player.wid, player.player.inventory,
                               furnace.inventory, coords)
        player.windows.append(window)
        returnValue(window)
Esempio n. 40
0
    def chat_command(self, username, parameters):
        protocol = self.factory.protocols[username]
        l = protocol.player.location

        x, y, z = l.pos.to_block()
        bigx, smallx, bigz, smallz = split_coords(x, z)

        chunk = self.factory.world.sync_request_chunk((x, y, z))
        column = [chunk.get_block((smallx, i, smallz)) for i in range(256)]

        # Find the next spot below us which has a platform and two empty
        # blocks of air.
        while y > 0:
            y -= 1
            if column[y] and not column[y + 1] and not column[y + 2]:
                break
        else:
            return ("Couldn't find anywhere to descend!",)

        l.pos = l.pos._replace(y=y)
        protocol.send_initial_chunk_and_location()
        return ("Descended!",)
Esempio n. 41
0
    def open_hook(self, player, container, block):
        """
        The ``player`` is a Player's protocol
        The ``container`` is a 0x64 message
        The ``block`` is a block we trying to open
        :returns: None or window object
        """
        if block not in (blocks["furnace"].slot, blocks["burning-furnace"].slot):
            returnValue(None)

        bigx, smallx, bigz, smallz = split_coords(container.x, container.z)
        chunk = yield self.factory.world.request_chunk(bigx, bigz)

        furnace = self.get_furnace_tile(chunk, (smallx, container.y, smallz))
        if furnace is None:
            returnValue(None)

        coords = bigx, smallx, bigz, smallz, container.y
        window = FurnaceWindow(player.wid, player.player.inventory,
                               furnace.inventory, coords)
        player.windows.append(window)
        returnValue(window)
Esempio n. 42
0
    def chat_command(self, username, parameters):
        protocol = factory.protocols[username]
        l = protocol.player.location

        x, y, z = l.pos.to_block()
        bigx, smallx, bigz, smallz = split_coords(x, z)

        chunk = factory.world.sync_request_chunk((x, y, z))
        column = chunk.get_column(smallx, smallz)

        # Find the next spot below us which has a platform and two empty
        # blocks of air.
        while y > 0:
            y -= 1
            if column[y] and not column[y + 1] and not column[y + 2]:
                break
        else:
            return ("Couldn't find anywhere to descend!", )

        l.pos = l.pos._replace(y=y)
        protocol.send_initial_chunk_and_location()
        return ("Descended!", )
Esempio n. 43
0
File: warp.py Progetto: RyanED/bravo
    def chat_command(self, username, parameters):
        protocol = factory.protocols[username]
        x = protocol.player.location.x
        z = protocol.player.location.z
        bigx, smallx, bigz, smallz = split_coords(x, z)

        chunk = yield factory.world.request_chunk(bigx, bigz)
        column = chunk.get_column(smallx, smallz)

        y = protocol.player.location.y

        # Find the next spot below us which has a platform and two empty
        # blocks of air.
        while y > 0:
            y -= 1
            if column[y] and not column[y + 1] and not column[y + 2]:
                break
        else:
            returnValue(("Couldn't find anywhere to descend!",))

        protocol.player.location.y = y
        protocol.send_initial_chunk_and_location()
        returnValue(("Descended!",))
Esempio n. 44
0
    def play_notes(self, notes):
        """
        Play some music.

        Send a sequence of notes to the player. ``notes`` is a finite iterable
        of pairs of instruments and pitches.

        There is no way to time notes; if staggered playback is desired (and
        it usually is!), then ``play_notes()`` should be called repeatedly at
        the appropriate times.

        This method turns the block beneath the player into a note block,
        plays the requested notes through it, then turns it back into the
        original block, all without actually modifying the chunk.
        """

        x, y, z = self.location.x, self.location.y, self.location.z

        if y:
            y -= 1

        bigx, smallx, bigz, smallz = split_coords(x, z)

        if (bigx, bigz) not in self.chunks:
            return

        block = self.chunks[bigx, bigz].get_block((smallx, y, smallz))
        meta = self.chunks[bigx, bigz].get_metadata((smallx, y, smallz))

        self.write_packet("block", x=x, y=y, z=z,
                          type=blocks["note-block"].slot, meta=0)

        for (instrument, pitch) in notes:
            self.write_packet("note", x=x, y=y, z=z, pitch=pitch,
                    instrument=instrument)

        self.write_packet("block", x=x, y=y, z=z, type=block, meta=meta)
Esempio n. 45
0
    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

        # it's the top of the world, you can't build here
        if container.y == 127 and container.face == '+y':
            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 = yield maybeDeferred(hook.pre_build_hook,
                self.player, builddata)
            if not cont:
                break

        # Run the build.
        try:
            yield maybeDeferred(self.run_build, builddata)
        except BuildError:
            return

        newblock = builddata.block.slot
        coords = builddata.x, builddata.y, builddata.z

        # 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((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)
Esempio n. 46
0
    def digging(self, container):
        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

        bigx, smallx, bigz, smallz = split_coords(container.x, container.z)
        coords = smallx, container.y, smallz

        try:
            chunk = self.chunks[bigx, bigz]
        except KeyError:
            self.error("Couldn't dig in chunk (%d, %d)!" % (bigx, bigz))
            return

        block = chunk.get_block((smallx, container.y, smallz))

        if container.state == "started":
            tool = self.player.inventory.holdables[self.player.equipped]
            # Check to see whether we should break this block.
            if self.dig_policy.is_1ko(block, tool):
                self.run_dig_hooks(chunk, coords, blocks[block])
            else:
                # Set up a timer for breaking the block later.
                dtime = time() + self.dig_policy.dig_time(block, tool)
                self.last_dig = coords, block, dtime
        elif container.state == "stopped":
            # The client thinks it has broken a block. We shall see.
            if not self.last_dig:
                return

            oldcoords, oldblock, dtime = self.last_dig
            if oldcoords != coords or oldblock != block:
                # Nope!
                self.last_dig = None
                return

            dtime -= time()

            # When enough time has elapsed, run the dig hooks.
            d = deferLater(reactor, max(dtime, 0), self.run_dig_hooks, chunk,
                           coords, blocks[block])
            d.addCallback(lambda none: setattr(self, "last_dig", None))
Esempio n. 47
0
 def setMetadata(self, coords, meta):
     factory.world.set_metadata(coords, meta)
     
     bigx, smallx, bigz, smallz = split_coords(coords[0], coords[2])
     self.touchedChunks.add( (bigx, bigz) )
Esempio n. 48
0
 def post_build_hook(self, player, coords, block):
     bigx, smallx, bigz, smallz = split_coords(coords[0], coords[2])
     chunk = yield factory.world.request_chunk(bigx, bigz)
     self.dig_hook(chunk, smallx, coords[1], smallz, block)
Esempio n. 49
0
    def pre_build_hook(self, player, builddata):
        item, metadata, x, y, z, face = builddata

        if item.slot != blocks["chest"].slot:
            returnValue((True, builddata, False))

        x, y, z = adjust_coords_for_face((x, y, z), face)
        bigx, smallx, bigz, smallz = split_coords(x, z)

        # chest orientation according to players position
        if face == "-y" or face == "+y":
            orientation = ('+x', '+z', '-x', '-z')[((int(player.location.yaw) \
                                                - 45 + 360) % 360) / 90]
        else:
            orientation = face

        # Chests have some restrictions on building:
        # you cannot connect more than two chests. (notchian)
        ccs = chestsAround(self.factory, (x, y, z))
        ccn = len(ccs)
        if ccn > 1:
            # cannot build three or more connected chests
            returnValue((False, builddata, True))

        chunk = yield self.factory.world.request_chunk(bigx, bigz)

        if ccn == 0:
            metadata = blocks["chest"].orientation(orientation)
        elif ccn == 1:
            # check gonna-be-connected chest is not connected already
            n = len(chestsAround(self.factory, ccs[0]))
            if n != 0:
                returnValue((False, builddata, True))

            # align both blocks correctly (since 1.8)
            # get second block
            x2, y2, z2 = ccs[0]
            bigx2, smallx2, bigz2, smallz2 = split_coords(x2, z2)
            # new chests orientation axis according to blocks position
            pair = x - x2, z - z2
            ornt = {(0, 1): "x", (0, -1): "x",
                    (1, 0): "z", (-1, 0): "z"}[pair]
            # if player is faced another direction, fix it
            if orientation[1] != ornt:
                # same sign with proper orientation
                # XXX Probably notchian logic is different here
                #     but this one works well enough
                orientation = orientation[0] + ornt
            metadata = blocks["chest"].orientation(orientation)
            # update second block's metadata
            if bigx == bigx2 and bigz == bigz2:
                # both blocks are in same chunk
                chunk2 = chunk
            else:
                chunk2 = yield self.factory.world.request_chunk(bigx2, bigz2)
            chunk2.set_metadata((smallx2, y2, smallz2), metadata)

        # Not much to do, just tell the chunk about this tile.
        chunk.tiles[smallx, y, smallz] = ChestTile(smallx, y, smallz)
        builddata = builddata._replace(metadata=metadata)
        returnValue((True, builddata, False))
Esempio n. 50
0
    def digging(self, container):
        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)
                    coords = dest.pos._replace(y=dest.pos.y + 1)
                    self.factory.give(coords, (primary, secondary), 1)

                    # Re-send inventory.
                    packet = self.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 == "shooting":
            self.shoot_arrow()
            return

        bigx, smallx, bigz, smallz = split_coords(container.x, container.z)
        coords = smallx, container.y, smallz

        try:
            chunk = self.chunks[bigx, bigz]
        except KeyError:
            self.error("Couldn't dig in chunk (%d, %d)!" % (bigx, bigz))
            return

        block = chunk.get_block((smallx, container.y, smallz))

        if container.state == "started":
            # Run pre dig hooks
            for hook in self.pre_dig_hooks:
                cancel = yield maybeDeferred(
                    hook.pre_dig_hook, self.player,
                    (container.x, container.y, container.z), block)
                if cancel:
                    return

            tool = self.player.inventory.holdables[self.player.equipped]
            # Check to see whether we should break this block.
            if self.dig_policy.is_1ko(block, tool):
                self.run_dig_hooks(chunk, coords, blocks[block])
            else:
                # Set up a timer for breaking the block later.
                dtime = time() + self.dig_policy.dig_time(block, tool)
                self.last_dig = coords, block, dtime
        elif container.state == "stopped":
            # The client thinks it has broken a block. We shall see.
            if not self.last_dig:
                return

            oldcoords, oldblock, dtime = self.last_dig
            if oldcoords != coords or oldblock != block:
                # Nope!
                self.last_dig = None
                return

            dtime -= time()

            # When enough time has elapsed, run the dig hooks.
            d = deferLater(reactor, max(dtime, 0), self.run_dig_hooks, chunk,
                           coords, blocks[block])
            d.addCallback(lambda none: setattr(self, "last_dig", None))
Esempio n. 51
0
    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

        # 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 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

        # it's the top of the world, you can't build here
        if container.y == 127 and container.face == '+y':
            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)
Esempio n. 52
0
    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))]

        # Attempt to open a window.
        from bravo.policy.windows import window_for_block
        window = window_for_block(target)
        if window is not None:
            # We have a window!
            self.windows[self.wid] = window
            identifier, title, slots = window.open()
            self.write_packet("window-open", wid=self.wid, type=identifier,
                              title=title, slots=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 0x%x" %
                    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)
Esempio n. 53
0
 def post_build_hook(self, player, coords, block):
     bigx, smallx, bigz, smallz = split_coords(coords[0], coords[2])
     chunk = yield factory.world.request_chunk(bigx, bigz)
     self.dig_hook(chunk, smallx, coords[1], smallz, block)