Пример #1
0
    def enable_cache(self, size):
        """
        Set the permanent cache size.

        Changing the size of the cache sets off a series of events which will
        empty or fill the cache to make it the proper size.

        For reference, 3 is a large-enough size to completely satisfy the
        Notchian client's login demands. 10 is enough to completely fill the
        Notchian client's chunk buffer.

        :param int size: The taxicab radius of the cache, in chunks
        """

        log.msg("Setting cache size to %d..." % size)

        self.permanent_cache = set()

        def assign(chunk):
            self.permanent_cache.add(chunk)

        x = self.spawn[0] // 16
        z = self.spawn[2] // 16

        rx = xrange(x - size, x + size)
        rz = xrange(z - size, z + size)
        d = coiterate(
            self.request_chunk(x, z).addCallback(assign)
            for x, z in product(rx, rz))
        d.addCallback(lambda chaff: log.msg("Cache size is now %d" % size))
Пример #2
0
    def dig_hook(self, factory, chunk, x, y, z, block):
        """
        Check for neighboring water that might want to spread.

        Also check to see whether we are, for example, dug ice that has turned
        back into water.
        """

        x += chunk.x * 16
        z += chunk.z * 16

        # Check for sponges first, since they will mark the entirety of the
        # area.
        if block == self.sponge:
            for coords in product(
                xrange(x - 3, x + 4),
                xrange(max(y - 3, 0), min(y + 4, 128)),
                xrange(z - 3, z + 4),
                ):
                self.pending[factory].add(coords)

        else:
            for (dx, dy, dz) in (
                ( 0, 0,  0),
                ( 0, 0,  1),
                ( 0, 0, -1),
                ( 0, 1,  0),
                ( 1, 0,  0),
                (-1, 0,  0)):
                coords = x + dx, y + dy, z + dz
                if factory.world.get_block(coords) in (self.spring, self.fluid):
                    self.pending[factory].add(coords)

        if any(self.pending.itervalues()) and not self.loop.running:
            self.loop.start(self.step)
Пример #3
0
    def keys_near(self, key, radius):
        """
        Get all bucket keys "near" this key.

        This method may return a generator.
        """

        minx, innerx = divmod(key[0], 16)
        minz, innerz = divmod(key[1], 16)
        minx = int(minx)
        minz = int(minz)

        # Adjust for range() purposes.
        maxx = minx + 1
        maxz = minz + 1

        # Adjust for leakiness.
        if innerx <= radius:
            minx -= 1
        if innerz <= radius:
            minz -= 1
        if innerx + radius >= 16:
            maxx += 1
        if innerz + radius >= 16:
            maxz += 1

        # Expand as needed.
        expand = int(radius // 16)
        minx -= expand
        minz -= expand
        maxx += expand
        maxz += expand

        return product(xrange(minx, maxx), xrange(minz, maxz))
Пример #4
0
    def build_hook(self, factory, player, builddata):
        """
        Remove water around a placed sponge.

        Remember that we are post-build here, so coordinates have already been
        adjusted.
        """

        if builddata.block.slot != blocks["sponge"].slot:
            return True, builddata

        fluids = set([blocks["spring"].slot, blocks["water"].slot,
            blocks["ice"].slot])

        # Minimum offsets.
        minx = builddata.x - 2
        miny = max(builddata.y - 2, 0)
        minz = builddata.z - 2

        # Maximum offsets. Remember to +1 for range().
        maxx = builddata.x + 3
        maxy = min(builddata.y + 3, 128)
        maxz = builddata.z + 3

        for coords in product(xrange(minx, maxx), xrange(miny, maxy),
            xrange(minz, maxz)):
            if coords == (builddata.x, builddata.y, builddata.z):
                continue
            if factory.world.get_block(coords) in fluids:
                factory.world.set_block(coords, blocks["air"].slot)
                factory.world.set_metadata(coords, 0x0)

        return True, builddata
Пример #5
0
    def populate(self, chunk, seed):
        """
        Make smooth waves of stone.
        """

        reseed(seed)

        # And into one end he plugged the whole of reality as extrapolated
        # from a piece of fairy cake, and into the other end he plugged his
        # wife: so that when he turned it on she saw in one instant the whole
        # infinity of creation and herself in relation to it.

        factor = 1 / 256

        for x, z in product(xrange(16), repeat=2):
            magx = (chunk.x * 16 + x) * factor
            magz = (chunk.z * 16 + z) * factor

            height = octaves2(magx, magz, 6)
            # Normalize around 70. Normalization is scaled according to a
            # rotated cosine.
            #scale = rotated_cosine(magx, magz, seed, 16 * 10)
            height *= 15
            height = int(height + 70)

            column = chunk.get_column(x, z)
            column[:height + 1].fill([blocks["stone"].slot])
Пример #6
0
    def build_hook(self, factory, player, builddata):
        """
        Remove water around a placed sponge.

        Remember that we are post-build here, so coordinates have already been
        adjusted.
        """

        if builddata.block.slot != blocks["sponge"].slot:
            return True, builddata

        fluids = set(
            [blocks["spring"].slot, blocks["water"].slot, blocks["ice"].slot])

        # Minimum offsets.
        minx = builddata.x - 2
        miny = max(builddata.y - 2, 0)
        minz = builddata.z - 2

        # Maximum offsets. Remember to +1 for range().
        maxx = builddata.x + 3
        maxy = min(builddata.y + 3, 128)
        maxz = builddata.z + 3

        for coords in product(xrange(minx, maxx), xrange(miny, maxy),
                              xrange(minz, maxz)):
            if coords == (builddata.x, builddata.y, builddata.z):
                continue
            if factory.world.get_block(coords) in fluids:
                factory.world.set_block(coords, blocks["air"].slot)
                factory.world.set_metadata(coords, 0x0)

        return True, builddata
Пример #7
0
    def keys_near(self, key, radius):
        """
        Get all bucket keys "near" this key.

        This method may return a generator.
        """

        minx, innerx = divmod(key[0], 16)
        minz, innerz = divmod(key[1], 16)
        minx = int(minx)
        minz = int(minz)

        # Adjust for range() purposes.
        maxx = minx + 1
        maxz = minz + 1

        # Adjust for leakiness.
        if innerx <= radius:
            minx -= 1
        if innerz <= radius:
            minz -= 1
        if innerx + radius >= 16:
            maxx += 1
        if innerz + radius >= 16:
            maxz += 1

        # Expand as needed.
        expand = int(radius // 16)
        minx -= expand
        minz -= expand
        maxx += expand
        maxz += expand

        return product(xrange(minx, maxx), xrange(minz, maxz))
Пример #8
0
    def enable_cache(self, size):
        """
        Set the permanent cache size.

        Changing the size of the cache sets off a series of events which will
        empty or fill the cache to make it the proper size.

        For reference, 3 is a large-enough size to completely satisfy the
        Notchian client's login demands. 10 is enough to completely fill the
        Notchian client's chunk buffer.

        :param int size: The taxicab radius of the cache, in chunks
        """

        log.msg("Setting cache size to %d..." % size)

        self.permanent_cache = set()
        def assign(chunk):
            self.permanent_cache.add(chunk)

        rx = xrange(self.spawn[0] - size, self.spawn[0] + size)
        rz = xrange(self.spawn[2] - size, self.spawn[2] + size)
        d = coiterate(self.request_chunk(x, z).addCallback(assign)
            for x, z in product(rx, rz))
        d.addCallback(lambda chaff: log.msg("Cache size is now %d" % size))
Пример #9
0
    def populate(self, chunk, seed):
        """
        Make smooth waves of stone.
        """

        reseed(seed)

        # And into one end he plugged the whole of reality as extrapolated
        # from a piece of fairy cake, and into the other end he plugged his
        # wife: so that when he turned it on she saw in one instant the whole
        # infinity of creation and herself in relation to it.

        factor = 1 / 256

        for x, z in product(xrange(16), repeat=2):
            magx = (chunk.x * 16 + x) * factor
            magz = (chunk.z * 16 + z) * factor

            height = octaves2(magx, magz, 6)
            # Normalize around 70. Normalization is scaled according to a
            # rotated cosine.
            #scale = rotated_cosine(magx, magz, seed, 16 * 10)
            height *= 15
            height = int(height + 70)

            column = chunk.get_column(x, z)
            column[:height + 1].fill([blocks["stone"].slot])
Пример #10
0
    def reduce_recipe(self):
        """
        Reduce a crafting table according to a recipe.

        This function returns None; the crafting table is modified in-place.

        This function assumes that the recipe already fits the crafting table and
        will not do additional checks to verify this assumption.
        """

        crafting = self.crafting_table
        offset = self.recipe_offset
        dims = self.recipe.dimensions
        indices = product(xrange(offset[0], offset[0] + dims[1]),
            xrange(offset[1], offset[1] + dims[0]))

        for index, slot in zip(indices, self.recipe.recipe):
            if slot is not None:
                scount = slot[1]
                tblock, tdamage, tcount = crafting[index]
                tcount -= scount
                if tcount:
                    crafting[index] = tblock, tdamage, tcount
                else:
                    crafting[index] = None
Пример #11
0
    def regenerate_blocklight(self):
        lightmap = zeros((16, 16, 128), dtype=uint32)

        for x, y, z in product(xrange(16), xrange(128), xrange(16)):
            block = self.blocks[x, z, y]
            if block in glowing_blocks:
                composite_glow(lightmap, glowing_blocks[block], x, y, z)

        self.blocklight = cast[uint8](lightmap.clip(0, 15))
Пример #12
0
    def regenerate_blocklight(self):
        lightmap = zeros((16, 16, 128), dtype=uint32)

        for x, y, z in product(xrange(16), xrange(128), xrange(16)):
            block = self.blocks[x, z, y]
            if block in glowing_blocks:
                composite_glow(lightmap, glowing_blocks[block], x, y, z)

        self.blocklight = cast[uint8](lightmap.clip(0, 15))
Пример #13
0
    def enable_cache(self):
        """
        Start up a rudimentary permanent cache.
        """

        self.permanent_cache = set()
        def assign(chunk):
            self.permanent_cache.add(chunk)

        rx = xrange(self.spawn[0] - 3, self.spawn[0] + 3)
        rz = xrange(self.spawn[2] - 3, self.spawn[2] + 3)
        d = coiterate(assign(self.load_chunk(x, z)) for x, z in product(rx, rz))
        d.addCallback(lambda chaff: log.msg("Cache is warmed up!"))
Пример #14
0
    def populate(self, chunk, seed):
        """
        Turn the top few layers of stone into dirt.
        """

        chunk.regenerate_heightmap()

        for x, z in product(xrange(16), repeat=2):
            y = chunk.heightmap[x, z]

            if chunk.get_block((x, y, z)) == blocks["stone"].slot:
                column = chunk.get_column(x, z)
                bottom = max(y - 3, 0)
                column[bottom:y + 1].fill(blocks["dirt"].slot)
Пример #15
0
    def regenerate_heightmap(self):
        """
        Regenerate the height map.

        The height map is merely the position of the tallest block in any
        xz-column.
        """

        for x, z in product(xrange(16), repeat=2):
            for y in range(127, -1, -1):
                if self.blocks[x, z, y]:
                    break

            self.heightmap[x, z] = y
Пример #16
0
    def populate(self, chunk, seed):
        """
        Find the top dirt block in each y-level and turn it into grass.
        """

        chunk.regenerate_heightmap()

        for x, z in product(xrange(16), repeat=2):
            y = chunk.heightmap[x, z]

            if (chunk.get_block((x, y, z)) == blocks["dirt"].slot and
                (y == 127 or
                    chunk.get_block((x, y + 1, z)) == blocks["air"].slot)):
                        chunk.set_block((x, y, z), blocks["grass"].slot)
Пример #17
0
    def populate(self, chunk, seed):
        """
        Turn the top few layers of stone into dirt.
        """

        chunk.regenerate_heightmap()

        for x, z in product(xrange(16), repeat=2):
            y = chunk.heightmap[x, z]

            if chunk.get_block((x, y, z)) == blocks["stone"].slot:
                column = chunk.get_column(x, z)
                bottom = max(y - 3, 0)
                column[bottom:y + 1].fill(blocks["dirt"].slot)
Пример #18
0
    def populate(self, chunk, seed):
        """
        Find the top dirt block in each y-level and turn it into grass.
        """

        chunk.regenerate_heightmap()

        for x, z in product(xrange(16), repeat=2):
            y = chunk.heightmap[x, z]

            if (chunk.get_block((x, y, z)) == blocks["dirt"].slot
                    and (y == 127 or chunk.get_block(
                        (x, y + 1, z)) == blocks["air"].slot)):
                chunk.blocks[x, z, y] = blocks["grass"].slot
Пример #19
0
    def regenerate_heightmap(self):
        """
        Regenerate the height map.

        The height map is merely the position of the tallest block in any
        xz-column.
        """

        for x, z in product(xrange(16), repeat=2):
            for y in range(127, -1, -1):
                if self.blocks[x, z, y]:
                    break

            self.heightmap[x, z] = y
Пример #20
0
    def transform(self, chunk):
        chunk.sed(blocks["spring"].slot, blocks["ice"].slot)

        # Make sure that the heightmap is valid so that we don't spawn
        # floating snow.
        chunk.regenerate_heightmap()

        # Lay snow over anything not already snowed and not snow-resistant.
        for x, z in product(xrange(16), xrange(16)):
            height = chunk.height_at(x, z)
            top_block = chunk.get_block((x, height, z))

            if top_block != blocks["snow"].slot:
                if top_block not in snow_resistant:
                    chunk.set_block((x, height + 1, z), blocks["snow"].slot)
Пример #21
0
 def populate(self, chunk, seed):
     """
     Make smooth waves of stone, then compare to current landscape
     """
     factor = 1 / 256
     for x, z in product(xrange(16), repeat=2):
         magx = ((chunk.x + 32) * 16 + x) * factor
         magz = ((chunk.z + 32) * 16 + z) * factor
         height = octaves2(magx, magz, 6)
         height *= 15
         height = int(height + 70)
         if -6 < chunk.heightmap[x,z] - height < 3 and chunk.heightmap[x,z] > 63 and height > 63:
             column = chunk.get_column(x, z)
             column[:].fill(blocks["air"].slot)
             column[:height-3].fill(blocks["stone"].slot)
Пример #22
0
    def transform(self, chunk):
        chunk.sed(blocks["spring"].slot, blocks["ice"].slot)

        # Make sure that the heightmap is valid so that we don't spawn
        # floating snow.
        chunk.regenerate_heightmap()

        # Lay snow over anything not already snowed and not snow-resistant.
        for x, z in product(xrange(16), xrange(16)):
            height = chunk.height_at(x, z)
            top_block = chunk.get_block((x, height, z))

            if top_block != blocks["snow"].slot:
                if top_block not in snow_resistant:
                    chunk.set_block((x, height + 1, z), blocks["snow"].slot)
Пример #23
0
    def populate(self, chunk, seed):
        """
        Find water level and if the chunk at water level or water level minus
        1 should be dirt, make it sand.
        """

        chunk.regenerate_heightmap()

        for x, z in product(xrange(16), repeat=2):
            y = chunk.heightmap[x, z]

            if (60 <= y <= 64 and
                (chunk.get_block((x, y + 1, z)) in self.above) and
                (chunk.get_block((x, y, z)) in self.replace)):
                chunk.set_block((x, y, z), blocks["sand"].slot)
Пример #24
0
    def transform(self, chunk):
        chunk.sed(blocks["spring"].slot, blocks["ice"].slot)

        # Lay snow over anything not already snowed and not snow-resistant.
        for x, z in product(xrange(16), xrange(16)):
            column = chunk.get_column(x, z)

            # First is above second.
            for first, second in pairwise(enumerate(reversed(column))):
                if second[1] not in (blocks["snow"].slot, blocks["air"].slot):
                    # Solid ground! Is it snowable?
                    if second[1] not in snow_resistant:
                        # Yay!
                        y = len(column) - 1 - first[0]
                        chunk.set_block((x, y, z), blocks["snow"].slot)
                    break
Пример #25
0
 def populate(self, chunk, seed):
     """
     Make smooth waves of stone, then compare to current landscape
     """
     factor = 1 / 256
     for x, z in product(xrange(16), repeat=2):
         magx = ((chunk.x + 32) * 16 + x) * factor
         magz = ((chunk.z + 32) * 16 + z) * factor
         height = octaves2(magx, magz, 6)
         height *= 15
         height = int(height + 70)
         if -6 < chunk.heightmap[x, z] - height < 3 and chunk.heightmap[
                 x, z] > 63 and height > 63:
             column = chunk.get_column(x, z)
             column[:].fill(blocks["air"].slot)
             column[:height - 3].fill(blocks["stone"].slot)
Пример #26
0
    def populate(self, chunk, seed):
        """
        Eat moar stone
        """

        factor = 1 / 256
        for x, z in product(xrange(16), repeat=2):
            magx = ((chunk.x+16) * 16 + x) * factor
            magz = ((chunk.z+16) * 16 + z) * factor

            height = octaves2(magx, magz, 6)
            height *= 15
            height = int(height + 70)
            column = chunk.get_column(x, z)
            if abs(chunk.heightmap[x,z] - height) < 10:
                column[:].fill(blocks["air"].slot)
            else:
                column[:height-30+randint(-15,10)].fill(blocks["air"].slot)
Пример #27
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())
        d.addCallback(lambda none: self.update_chunks())
Пример #28
0
    def regenerate_skylight(self):
        """
        Regenerate the ambient light map.

        Each block's individual light comes from two sources. The ambient
        light comes from the sky.

        The height map must be valid for this method to produce valid results.
        """

        lightmap = zeros((16, 16, 128), dtype=uint32)

        for x, z in product(xrange(16), repeat=2):
            y = self.heightmap[x, z]

            composite_glow(lightmap, 14, x, y, z)

        self.skylight = cast[uint8](lightmap.clip(0, 15))
Пример #29
0
    def populate(self, chunk, seed):
        """
        Eat moar stone
        """

        factor = 1 / 256
        for x, z in product(xrange(16), repeat=2):
            magx = ((chunk.x + 16) * 16 + x) * factor
            magz = ((chunk.z + 16) * 16 + z) * factor

            height = octaves2(magx, magz, 6)
            height *= 15
            height = int(height + 70)
            column = chunk.get_column(x, z)
            if abs(chunk.heightmap[x, z] - height) < 10:
                column[:].fill(blocks["air"].slot)
            else:
                column[:height - 30 + randint(-15, 10)].fill(
                    blocks["air"].slot)
Пример #30
0
    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())
Пример #31
0
    def populate(self, chunk, seed):
        """
        Find blocks within a height range and turn them into sand if they are
        dirt and underwater or exposed to air. If the height range is near the
        water table level, this creates fairly good beaches.
        """

        chunk.regenerate_heightmap()

        for x, z in product(xrange(16), repeat=2):
            y = chunk.heightmap[x, z]

            while y > 60 and chunk.get_block((x, y, z)) in self.above:
                y -= 1

            if not 60 < y < 66:
                continue

            if chunk.get_block((x, y, z)) in self.replace:
                chunk.blocks[x, z, y] = blocks["sand"].slot
Пример #32
0
    def populate(self, chunk, seed):
        """
        Find blocks within a height range and turn them into sand if they are
        dirt and underwater or exposed to air. If the height range is near the
        water table level, this creates fairly good beaches.
        """

        chunk.regenerate_heightmap()

        for x, z in product(xrange(16), repeat=2):
            y = chunk.heightmap[x, z]

            while y > 60 and chunk.get_block((x, y, z)) in self.above:
                y -= 1

            if not 60 < y < 66:
                continue

            if chunk.get_block((x, y, z)) in self.replace:
                chunk.blocks[x, z, y] = blocks["sand"].slot
Пример #33
0
    def check_recipes(self):
        """
        See if the crafting table matches any recipes.

        :returns: the recipe and offset, or None if no matches could be made
        """

        # This isn't perfect, unfortunately, but correctness trumps algorithmic
        # perfection. (For now.)
        crafting = self.crafting_table
        for recipe in retrieve_plugins(IRecipe).itervalues():
            dims = recipe.dimensions

            for x, y in crafting.iterkeys():
                if (x + dims[1] > self.crafting_stride or
                    y + dims[0] > self.crafting_stride):
                    continue

                indices = product(xrange(x, x + dims[1]),
                    xrange(y, y + dims[0]))

                matches_needed = dims[0] * dims[1]

                for index, slot in zip(indices, recipe.recipe):

                    if crafting[index] is None and slot is None:
                        matches_needed -= 1
                    elif crafting[index] is not None and slot is not None:
                        cprimary, csecondary, ccount = crafting[index]
                        skey, scount = slot
                        if ((cprimary, csecondary) == skey
                            and ccount >= scount):
                            matches_needed -= 1

                    if matches_needed == 0:
                        # Jackpot!
                        self.recipe = recipe
                        self.recipe_offset = (x, y)
                        return

        self.recipe = None
Пример #34
0
    def populate(self, chunk, seed):
        """
        Make smooth islands of stone.
        """

        reseed(seed)

        factor = 1 / 256

        for x, z in product(xrange(16), repeat=2):
            column = chunk.get_column(x, z)
            magx = (chunk.x * 16 + x) * factor
            magz = (chunk.z * 16 + z) * factor

            samples = array([octaves3(magx, magz, y * factor, 6)
                    for y in xrange(column.size)])

            column = where(samples > 0, blocks["dirt"].slot, column)
            column = where(samples > 0.1, blocks["stone"].slot, column)

            chunk.set_column(x, z, column)
Пример #35
0
    def populate(self, chunk, seed):
        reseed(seed)

        xzfactor = 1 / 16
        yfactor = 1 / 32

        for x, z in product(xrange(16), repeat=2):
            for y in range(chunk.heightmap[x, z] + 1):
                magx = (chunk.x * 16 + x) * xzfactor
                magz = (chunk.z * 16 + z) * xzfactor
                magy = y * yfactor

                sample = octaves3(magx, magz, magy, 3)

                if sample > 0.9999:
                    # Figure out what to place here.
                    old = chunk.get_block((x, y, z))
                    if old == blocks["sand"].slot:
                        # Sand becomes clay.
                        chunk.set_block((x, y, z), blocks["clay"].slot)
                    elif old == blocks["dirt"].slot:
                        # Dirt becomes gravel.
                        chunk.set_block((x, y, z), blocks["gravel"].slot)
                    elif old == blocks["stone"].slot:
                        # Stone becomes one of the ores.
                        if y < 12:
                            chunk.set_block((x, y, z),
                                blocks["diamond-ore"].slot)
                        elif y < 24:
                            chunk.set_block((x, y, z),
                                blocks["gold-ore"].slot)
                        elif y < 36:
                            chunk.set_block((x, y, z),
                                blocks["redstone-ore"].slot)
                        elif y < 48:
                            chunk.set_block((x, y, z),
                                blocks["iron-ore"].slot)
                        else:
                            chunk.set_block((x, y, z),
                                blocks["coal-ore"].slot)
Пример #36
0
    def populate(self, chunk, seed):
        reseed(seed)

        xzfactor = 1 / 16
        yfactor = 1 / 32

        for x, z in product(xrange(16), repeat=2):
            for y in range(chunk.heightmap[x, z] + 1):
                magx = (chunk.x * 16 + x) * xzfactor
                magz = (chunk.z * 16 + z) * xzfactor
                magy = y * yfactor

                sample = octaves3(magx, magz, magy, 3)

                if sample > 0.9999:
                    # Figure out what to place here.
                    old = chunk.blocks[x, z, y]
                    new = None
                    if old == blocks["sand"].slot:
                        # Sand becomes clay.
                        new = blocks["clay"].slot
                    elif old == blocks["dirt"].slot:
                        # Dirt becomes gravel.
                        new = blocks["gravel"].slot
                    elif old == blocks["stone"].slot:
                        # Stone becomes one of the ores.
                        if y < 12:
                            new = blocks["diamond-ore"].slot
                        elif y < 24:
                            new = blocks["gold-ore"].slot
                        elif y < 36:
                            new = blocks["redstone-ore"].slot
                        elif y < 48:
                            new = blocks["iron-ore"].slot
                        else:
                            new = blocks["coal-ore"].slot

                    if new:
                        chunk.blocks[x, z, y] = new
Пример #37
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)):
            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
Пример #38
0
    def populate(self, chunk, seed):
        """
        Make smooth islands of stone.
        """

        reseed(seed)

        factor = 1 / 256

        for x, z in product(xrange(16), repeat=2):
            column = chunk.get_column(x, z)
            magx = (chunk.x * 16 + x) * factor
            magz = (chunk.z * 16 + z) * factor

            samples = array([
                octaves3(magx, magz, y * factor, 6)
                for y in xrange(column.size)
            ])

            column = where(samples > 0, blocks["dirt"].slot, column)
            column = where(samples > 0.1, blocks["stone"].slot, column)

            chunk.set_column(x, z, column)
Пример #39
0
    def regenerate_skylight(self):
        """
        Regenerate the ambient light map.

        Each block's individual light comes from two sources. The ambient
        light comes from the sky.

        The height map must be valid for this method to produce valid results.
        """

        lightmap = zeros((16, 16, 128), dtype=uint8)

        for x, z in product(xrange(16), repeat=2):
            light = 15
            for y in range(127, -1, -1):
                dim = blocks[self.blocks[x, z, y]].dim
                light -= dim
                if light <= 0:
                    break
                
                lightmap[x, z, y] = light

        self.skylight = lightmap.clip(0, 15)
Пример #40
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)):
            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
Пример #41
0
    def apply_recipe(self):
        """
        Return the crafted output of an applied recipe.

        This function assumes that the recipe already fits the crafting table and
        will not do additional checks to verify this assumption.
        """

        crafting = self.crafting_table
        offset = self.recipe_offset
        dims = self.recipe.dimensions
        indices = product(xrange(offset[0], offset[0] + dims[1]),
            xrange(offset[1], offset[1] + dims[0]))
        count = []

        for index, slot in zip(indices, self.recipe.recipe):
            if slot is not None and crafting[index] is not None:
                scount = slot[1]
                tcount = crafting[index][2]
                count.append(tcount // scount)

        counted = min(count)
        if counted > 0:
            return self.recipe.provides[0], self.recipe.provides[1] * counted
Пример #42
0
    def regenerate_skylight(self):
        """
        Regenerate the ambient light map.

        Each block's individual light comes from two sources. The ambient
        light comes from the sky.

        The height map must be valid for this method to produce valid results.
        """

        lightmap = zeros((16, 16, 128), dtype=uint8)

        for x, z in product(xrange(16), repeat=2):
            # The maximum lighting value, unsurprisingly, is 0xf, which is the
            # biggest possible value for a nibble.
            light = 0xf

            # Apparently, skylights start at the block *above* the block on
            # which the light is incident?
            height = self.heightmap[x, z] + 1

            # The topmost block, regardless of type, is set to maximum
            # lighting, as are all the blocks above it.
            lightmap[x, z, height:] = light

            # Dim the light going throught the remaining blocks, until there
            # is no more light left.
            for y in range(height, -1, -1):
                dim = blocks[self.blocks[x, z, y]].dim
                light -= dim
                if light <= 0:
                    break

                lightmap[x, z, y] = light

        self.skylight = lightmap.clip(0, 15)
Пример #43
0
    os.makedirs(target)

print "Making map of %dx%d chunks in %s" % (size, size, target)
print "Using pipeline: %s" % ", ".join(plugin.name for plugin in pipeline)

world = World(target)
world.pipeline = pipeline
world.season = None

counts = [1, 2, 4, 5, 8]
count = 0
total = size ** 2

cpu = 0
before = time.time()
for i, j in product(xrange(size), repeat=2):
    start = time.time()
    chunk = world.load_chunk(i, j)
    cpu += (time.time() - start)
    world.save_chunk(chunk)
    count += 1
    if count >= counts[0]:
        print "Status: %d/%d (%.2f%%)" % (count, total, count * 100 / total)
        counts.append(counts.pop(0) * 10)

taken = time.time() - before
print "Finished!"
print "Took %.2f seconds to generate (%dms/chunk)" % (taken,
    taken * 1000 / size)
print "Spent %.2f seconds on CPU (%dms/chunk)" % (cpu, cpu * 1000 / size)
Пример #44
0
x, y, w, h = (float(i) for i in arguments)

image = Image.new("L", (WIDTH, HEIGHT))
pbo = image.load()

counts = [1, 2, 4, 5, 8]
count = 0
total = WIDTH * HEIGHT

print "Seed: %d" % options.seed
print "Coords: %f, %f" % (x, y)
print "Window: %fx%f" % (w, h)
print "Octaves: %d" % options.octaves
print "Offsets: %f, %f" % (xoffset, yoffset)

for i, j in product(xrange(WIDTH), xrange(HEIGHT)):
    count += 1
    if count >= counts[0]:
        print "Status: %d/%d (%.2f%%)" % (count, total, count * 100 / total)
        counts.append(counts.pop(0) * 10)

    # Get our scaled coords
    xcoord = x + w * i / WIDTH
    ycoord = y + h * j / HEIGHT

    # Get noise and scale from [-1, 1] to [0, 255]
    if xoffset or yoffset:
        noise = offset2(xcoord, ycoord, xoffset, yoffset, options.octaves)
    if options.octaves > 1:
        noise = octaves2(xcoord, ycoord, options.octaves)
    else:
Пример #45
0
from numpy import int8, uint8, uint32
from numpy import cast, empty, where, zeros

from bravo.blocks import blocks, glowing_blocks
from bravo.compat import product
from bravo.packets import make_packet
from bravo.utilities import pack_nibbles

# Set up glow tables.
# These tables provide glow maps for illuminated points.
glow = [None] * 15
for i in range(15):
    dim = 2 * i + 1
    glow[i] = zeros((dim, dim, dim), dtype=int8)
    for x, y, z in product(xrange(dim), repeat=3):
        distance = abs(x - i) + abs(y - i) + abs(z - i)
        glow[i][ x,  y,  z] = i + 1 - distance
    glow[i] = cast[uint8](glow[i].clip(0, 15))

def composite_glow(target, strength, x, y, z):
    """
    Composite a light source onto a lightmap.

    The exact operation is not quite unlike an add.
    """

    ambient = glow[strength]

    xbound, zbound, ybound = target.shape

    sx = x - strength
Пример #46
0
    def process(self):
        for factory in self.pending:
            w = factory.world
            new = set()

            for x, y, z in self.pending[factory]:
                # Neighbors on the xz-level.
                neighbors = ((x - 1, y, z), (x + 1, y, z), (x, y, z - 1),
                        (x, y, z + 1))
                # Our downstairs pal.
                below = (x, y - 1, z)

                block = w.get_block((x, y, z))
                if block == self.sponge:
                    # Track this sponge.
                    self.sponges[factory][x, y, z] = True

                    # Destroy the water! Destroy!
                    for coords in product(
                        xrange(x - 2, x + 3),
                        xrange(max(y - 2, 0), min(y + 3, 128)),
                        xrange(z - 2, z + 3),
                        ):
                        target = w.get_block(coords)
                        if target == self.spring:
                            if (coords[0], coords[2]) in self.springs[factory]:
                                del self.springs[factory][coords[0],
                                    coords[2]]
                            w.destroy(coords)
                        elif target == self.fluid:
                            w.destroy(coords)

                    # And now mark our surroundings so that they can be
                    # updated appropriately.
                    for coords in product(
                        xrange(x - 3, x + 4),
                        xrange(max(y - 3, 0), min(y + 4, 128)),
                        xrange(z - 3, z + 4),
                        ):
                        if coords != (x, y, z):
                            new.add(coords)

                if block == self.spring:
                    # Double-check that we weren't placed inside a sponge.
                    # That's just wrong.
                    if any(self.sponges[factory].iteritemsnear((x, y, z), 2)):
                        w.destroy((x, y, z))
                        continue

                    # Track this spring.
                    self.springs[factory][x, z] = y

                    # Spawn water from springs.
                    for coords in neighbors:
                        if (w.get_block(coords) in self.whitespace and
                            not any(self.sponges[factory].iteritemsnear(coords, 2))):
                            w.set_block(coords, self.fluid)
                            w.set_metadata(coords, 0x0)
                            new.add(coords)

                    # Is this water falling down to the next y-level?
                    if (y > 0 and w.get_block(below) in self.whitespace and
                        not any(self.sponges[factory].iteritemsnear(below, 2))):
                        w.set_block(below, self.fluid)
                        w.set_metadata(below, FALLING)
                        new.add(below)

                elif block == self.fluid:
                    # Double-check that we weren't placed inside a sponge.
                    if any(self.sponges[factory].iteritemsnear((x, y, z), 2)):
                        w.destroy((x, y, z))
                        continue

                    # First, figure out whether or not we should be spreading.
                    # Let's see if there are any springs nearby which are
                    # above us and thus able to fuel us.
                    if not any(springy >= y
                        for springy in self.springs[factory].iterkeysnear(
                            (x, z), self.levels + 1
                        )
                    ):
                        # Oh noes, we're drying up! We should mark our
                        # neighbors and dry ourselves up.
                        new.update(neighbors)
                        new.add(below)
                        w.destroy((x, y, z))
                        continue

                    metadata = w.get_metadata((x, y, z))
                    newmd = self.levels + 1

                    for coords in neighbors:
                        jones = w.get_block(coords)
                        if jones == self.spring:
                            newmd = 0
                            new.update(neighbors)
                            break
                        elif jones == self.fluid:
                            jonesmd = w.get_metadata(coords) & ~FALLING
                            if jonesmd + 1 < newmd:
                                newmd = jonesmd + 1

                    if newmd > self.levels:
                        # We should dry up.
                        new.update(neighbors)
                        new.add(below)
                        w.destroy((x, y, z))
                        continue

                    # Mark any neighbors which should adjust themselves. This
                    # will only mark lower water levels than ourselves, and
                    # only if they are definitely too low.
                    for coords in neighbors:
                        if w.get_metadata(coords) & ~FALLING > newmd + 1:
                            new.add(coords)

                    # Now, it's time to extend water. Remember, either the
                    # water flows downward to the next y-level, or it
                    # flows out across the xz-level, but *not* both.

                    # Fall down to the next y-level, if possible.
                    if (y > 0 and w.get_block(below) in self.whitespace and
                        not any(self.sponges[factory].iteritemsnear(below, 2))):
                        w.set_block(below, self.fluid)
                        w.set_metadata(below, newmd | FALLING)
                        new.add(below)
                        continue

                    # Clamp our newmd and assign. Also, set ourselves again;
                    # we changed this time and we might change again.
                    w.set_metadata((x, y, z), newmd)

                    # Otherwise, just fill our neighbors with water, where
                    # applicable, and mark them.
                    if newmd < self.levels:
                        newmd += 1
                        for coords in neighbors:
                            if (w.get_block(coords) in self.whitespace and
                                not any(self.sponges[factory].iteritemsnear(coords, 2))):
                                w.set_block(coords, self.fluid)
                                w.set_metadata(coords, newmd)
                                new.add(coords)


                else:
                    # Hm, why would a pending block not be any of the things
                    # we care about? Maybe it used to be a spring or
                    # something?
                    if (x, z) in self.springs[factory]:
                        # Destroyed spring. Add neighbors and below to blocks
                        # to update.
                        del self.springs[factory][x, z]

                        new.update(neighbors)
                        new.add(below)

                    elif (x, y, z) in self.sponges[factory]:
                        # The evil sponge tyrant is gone. Flow, minions, flow!
                        for coords in product(
                            xrange(x - 3, x + 4),
                            xrange(max(y - 3, 0), min(y + 4, 128)),
                            xrange(z - 3, z + 4),
                            ):
                            if coords != (x, y, z):
                                new.add(coords)

            # Flush affected chunks.
            to_flush = defaultdict(set)
            for x, y, z in chain(self.pending[factory], new):
                to_flush[factory].add(factory.world.load_chunk(x // 16, z // 16))
            for factory, chunks in to_flush.iteritems():
                for chunk in chunks:
                    factory.flush_chunk(chunk)

            self.pending[factory] = new

        # Prune and turn off the loop if appropriate.
        for dd in (self.pending, self.springs, self.sponges):
            for factory in dd.keys():
                if not dd[factory]:
                    del dd[factory]
        if not self.pending and self.loop.running:
            self.loop.stop()
Пример #47
0
from bravo.blocks import blocks, items
from bravo.compat import namedtuple, product
from bravo.config import configuration
from bravo.entity import Sign
from bravo.factories.infini import InfiniClientFactory
from bravo.ibravo import IChatCommand, IBuildHook, IDigHook
from bravo.inventory import Workbench, sync_inventories
from bravo.packets import parse_packets, make_packet, make_error_packet
from bravo.plugin import retrieve_plugins, retrieve_named_plugins
from bravo.utilities import split_coords

(STATE_UNAUTHENTICATED, STATE_CHALLENGED, STATE_AUTHENTICATED) = range(3)

circle = [(i, j)
    for i, j in sorted(
        product(xrange(-10, 10), xrange(-10, 10)),
        key=lambda t: t[0]**2 + t[1]**2)
    if i**2 + j**2 <= 100
]
"""
A list of points in a filled circle of radius 10, sorted according to distance
from the center.
"""

BuildData = namedtuple("BuildData", "block, metadata, x, y, z, face")

class BetaServerProtocol(Protocol):
    """
    The Minecraft Alpha/Beta server protocol.

    This class is mostly designed to be a skeleton for featureful clients. It
Пример #48
0
from numpy import cast, empty, where, zeros

from bravo.blocks import glowing_blocks
from bravo.compat import product
from bravo.entity import tile_entities
from bravo.packets import make_packet
from bravo.serialize import ChunkSerializer
from bravo.utilities import pack_nibbles

# Set up glow tables.
# These tables provide glow maps for illuminated points.
glow = [None] * 15
for i in range(15):
    dim = 2 * i + 1
    glow[i] = zeros((dim, dim, dim), dtype=int8)
    for x, y, z in product(xrange(dim), repeat=3):
        distance = abs(x - i) + abs(y - i) + abs(z - i)
        glow[i][x, y, z] = i + 1 - distance
    glow[i] = cast[uint8](glow[i].clip(0, 15))


def composite_glow(target, strength, x, y, z):
    """
    Composite a light source onto a lightmap.

    The exact operation is not quite unlike an add.
    """

    ambient = glow[strength]

    xbound, zbound, ybound = target.shape
Пример #49
0
    os.makedirs(target)

print "Making map of %dx%d chunks in %s" % (size, size, target)
print "Using pipeline: %s" % ", ".join(plugin.name for plugin in pipeline)

world = World(target)
world.pipeline = pipeline
world.season = None

counts = [1, 2, 4, 5, 8]
count = 0
total = size**2

cpu = 0
before = time.time()
for i, j in product(xrange(size), repeat=2):
    start = time.time()
    chunk = world.load_chunk(i, j)
    cpu += (time.time() - start)
    world.save_chunk(chunk)
    count += 1
    if count >= counts[0]:
        print "Status: %d/%d (%.2f%%)" % (count, total, count * 100 / total)
        counts.append(counts.pop(0) * 10)

taken = time.time() - before
print "Finished!"
print "Took %.2f seconds to generate (%dms/chunk)" % (taken,
                                                      taken * 1000 / size)
print "Spent %.2f seconds on CPU (%dms/chunk)" % (cpu, cpu * 1000 / size)
Пример #50
0
from bravo.blocks import blocks, items
from bravo.compat import namedtuple, product
from bravo.config import configuration
from bravo.entity import Sign
from bravo.factories.infini import InfiniClientFactory
from bravo.ibravo import IChatCommand, IBuildHook, IDigHook, ISignHook
from bravo.inventory import Workbench, sync_inventories
from bravo.location import Location
from bravo.packets import parse_packets, make_packet, make_error_packet
from bravo.plugin import retrieve_plugins, retrieve_sorted_plugins
from bravo.utilities import split_coords

(STATE_UNAUTHENTICATED, STATE_CHALLENGED, STATE_AUTHENTICATED) = range(3)

circle = [(i, j) for i, j in product(xrange(-10, 10), xrange(-10, 10))
          if i**2 + j**2 <= 100]
"""
A list of points in a filled circle of radius 10.
"""

BuildData = namedtuple("BuildData", "block, metadata, x, y, z, face")


class BetaServerProtocol(Protocol):
    """
    The Minecraft Alpha/Beta server protocol.

    This class is mostly designed to be a skeleton for featureful clients. It
    tries hard to not step on the toes of potential subclasses.
    """