예제 #1
0
    def make_chunk(self, x, z, seed, generators):
        """
        Create a chunk using the given parameters.
        """

        generators = retrieve_sorted_plugins(ITerrainGenerator, generators)

        chunk = Chunk(x, z)

        for stage in generators:
            stage.populate(chunk, seed)

        chunk.regenerate()

        return {
            "blocks": chunk.blocks.tostring(),
            "metadata": chunk.metadata.tostring(),
            "skylight": chunk.skylight.tostring(),
            "blocklight": chunk.blocklight.tostring(),
            "heightmap": chunk.heightmap.tostring(),
        }
예제 #2
0
    def make_chunk(self, x, z, seed, generators):
        """
        Create a chunk using the given parameters.
        """

        generators = retrieve_sorted_plugins(ITerrainGenerator, generators)

        chunk = Chunk(x, z)

        for stage in generators:
            stage.populate(chunk, seed)

        chunk.regenerate()

        return {
            "blocks": chunk.blocks.tostring(),
            "metadata": chunk.metadata.tostring(),
            "skylight": chunk.skylight.tostring(),
            "blocklight": chunk.blocklight.tostring(),
            "heightmap": chunk.heightmap.tostring(),
        }
예제 #3
0
파일: world.py 프로젝트: RyanED/bravo
    def request_chunk(self, x, z):
        """
        Request a ``Chunk`` to be delivered later.

        :returns: ``Deferred`` that will be called with the ``Chunk``
        """

        if (x, z) in self.chunk_cache:
            returnValue(self.chunk_cache[x, z])
        elif (x, z) in self.dirty_chunk_cache:
            returnValue(self.dirty_chunk_cache[x, z])
        elif (x, z) in self._pending_chunks:
            # Rig up another Deferred and wrap it up in a to-go box.
            retval = yield self._pending_chunks[x, z].deferred()
            returnValue(retval)

        chunk = Chunk(x, z)
        yield maybeDeferred(self.serializer.load_chunk, chunk)

        if chunk.populated:
            self.chunk_cache[x, z] = chunk
            self.postprocess_chunk(chunk)
            #self.factory.scan_chunk(chunk)
            returnValue(chunk)

        if self.async:
            from ampoule import deferToAMPProcess
            from bravo.remote import MakeChunk

            d = deferToAMPProcess(MakeChunk,
                x=x,
                z=z,
                seed=self.seed,
                generators=configuration.getlist(self.config_name, "generators")
            )

            # Get chunk data into our chunk object.
            def fill_chunk(kwargs):
                chunk.blocks = fromstring(kwargs["blocks"],
                    dtype=uint8).reshape(chunk.blocks.shape)
                chunk.heightmap = fromstring(kwargs["heightmap"],
                    dtype=uint8).reshape(chunk.heightmap.shape)
                chunk.metadata = fromstring(kwargs["metadata"],
                    dtype=uint8).reshape(chunk.metadata.shape)
                chunk.skylight = fromstring(kwargs["skylight"],
                    dtype=uint8).reshape(chunk.skylight.shape)
                chunk.blocklight = fromstring(kwargs["blocklight"],
                    dtype=uint8).reshape(chunk.blocklight.shape)

                return chunk
            d.addCallback(fill_chunk)
        else:
            # Populate the chunk the slow way. :c
            for stage in self.pipeline:
                stage.populate(chunk, self.seed)

            chunk.regenerate()
            d = succeed(chunk)

        # Set up our event and generate our return-value Deferred. It has to
        # be done early becaues PendingEvents only fire exactly once and it
        # might fire immediately in certain cases.
        pe = PendingEvent()
        # This one is for our return value.
        retval = pe.deferred()
        # This one is for scanning the chunk for automatons.
        #pe.deferred().addCallback(self.factory.scan_chunk)
        self._pending_chunks[x, z] = pe

        def pp(chunk):
            chunk.populated = True
            chunk.dirty = True

            self.postprocess_chunk(chunk)

            self.dirty_chunk_cache[x, z] = chunk
            del self._pending_chunks[x, z]

            return chunk

        # Set up callbacks.
        d.addCallback(pp)
        d.chainDeferred(pe)

        # Because multiple people might be attached to this callback, we're
        # going to do something magical here. We will yield a forked version
        # of our Deferred. This means that we will wait right here, for a
        # long, long time, before actually returning with the chunk, *but*,
        # when we actually finish, we'll be ready to return the chunk
        # immediately. Our caller cannot possibly care because they only see a
        # Deferred either way.
        retval = yield retval
        returnValue(retval)
예제 #4
0
파일: test_chunk.py 프로젝트: tazjel/bravo
class TestLightmaps(unittest.TestCase):
    def setUp(self):
        self.c = Chunk(0, 0)

    def test_trivial(self):
        pass

    def test_boring_skylight_values(self):
        # Fill it as if we were the boring generator.
        for x, z in XZ:
            self.c.set_block((x, 0, z), 1)
        self.c.regenerate()

        # Make sure that all of the blocks at the bottom of the ambient
        # lightmap are set to 15 (fully illuminated).
        # Note that skylight of a solid block is 0, the important value
        # is the skylight of the transluscent (usually air) block above it.
        for x, z in XZ:
            self.assertEqual(self.c.get_skylight((x, 0, z)), 0xf)

    test_boring_skylight_values.todo = "Skylight maths is still broken"

    def test_skylight_spread(self):
        # Fill it as if we were the boring generator.
        for x, z in XZ:
            self.c.set_block((x, 0, z), 1)
        # Put a false floor up to block the light.
        for x, z in product(xrange(1, 15), repeat=2):
            self.c.set_block((x, 2, z), 1)
        self.c.regenerate()

        # Test that a gradient emerges.
        for x, z in XZ:
            flipx = x if x > 7 else 15 - x
            flipz = z if z > 7 else 15 - z
            target = max(flipx, flipz)
            self.assertEqual(self.c.get_skylight((x, 1, z)), target,
                             "%d, %d" % (x, z))

    test_skylight_spread.todo = "Skylight maths is still broken"

    def test_skylight_arch(self):
        """
        Indirect illumination should work.
        """

        # Floor.
        for x, z in XZ:
            self.c.set_block((x, 0, z), 1)

        # Arch of bedrock, with an empty spot in the middle, which will be our
        # indirect spot.
        for x, y, z in product(xrange(2), xrange(1, 3), xrange(3)):
            self.c.set_block((x, y, z), 1)
        self.c.set_block((1, 1, 1), 0)

        # Illuminate and make sure that our indirect spot has just a little
        # bit of illumination.
        self.c.regenerate()

        self.assertEqual(self.c.get_skylight((1, 1, 1)), 14)

    test_skylight_arch.todo = "Skylight maths is still broken"

    def test_skylight_arch_leaves(self):
        """
        Indirect illumination with dimming should work.
        """

        # Floor.
        for x, z in XZ:
            self.c.set_block((x, 0, z), 1)

        # Arch of bedrock, with an empty spot in the middle, which will be our
        # indirect spot.
        for x, y, z in product(xrange(2), xrange(1, 3), xrange(3)):
            self.c.set_block((x, y, z), 1)
        self.c.set_block((1, 1, 1), 0)

        # Leaves in front of the spot should cause a dimming of 1.
        self.c.set_block((2, 1, 1), 18)

        # Illuminate and make sure that our indirect spot has just a little
        # bit of illumination.
        self.c.regenerate()

        self.assertEqual(self.c.get_skylight((1, 1, 1)), 13)

    test_skylight_arch_leaves.todo = "Skylight maths is still broken"

    def test_skylight_arch_leaves_occluded(self):
        """
        Indirect illumination with dimming through occluded blocks only should
        work.
        """

        # Floor.
        for x, z in XZ:
            self.c.set_block((x, 0, z), 1)

        # Arch of bedrock, with an empty spot in the middle, which will be our
        # indirect spot.
        for x, y, z in product(xrange(3), xrange(1, 3), xrange(3)):
            self.c.set_block((x, y, z), 1)
        self.c.set_block((1, 1, 1), 0)

        # Leaves in front of the spot should cause a dimming of 1, but since
        # the leaves themselves are occluded, the total dimming should be 2.
        self.c.set_block((2, 1, 1), 18)

        # Illuminate and make sure that our indirect spot has just a little
        # bit of illumination.
        self.c.regenerate()

        self.assertEqual(self.c.get_skylight((1, 1, 1)), 12)

    test_skylight_arch_leaves_occluded.todo = "Skylight maths is still broken"

    def test_incremental_solid(self):
        """
        Regeneration isn't necessary to correctly light solid blocks.
        """

        # Initialize tables and enable set_block().
        self.c.regenerate()
        self.c.populated = True

        # Any solid block with no dimming works. I choose dirt.
        self.c.set_block((0, 0, 0), blocks["dirt"].slot)

        self.assertEqual(self.c.get_skylight((0, 0, 0)), 0)

    test_incremental_solid.todo = "Skylight maths is still broken"

    def test_incremental_air(self):
        """
        Regeneration isn't necessary to correctly light dug blocks, which
        leave behind air.
        """

        # Any solid block with no dimming works. I choose dirt.
        self.c.set_block((0, 0, 0), blocks["dirt"].slot)

        # Initialize tables and enable set_block().
        self.c.regenerate()
        self.c.populated = True

        self.c.set_block((0, 0, 0), blocks["air"].slot)

        self.assertEqual(self.c.get_skylight((0, 0, 0)), 15)
예제 #5
0
파일: test_chunk.py 프로젝트: miea/bravo
class TestLightmaps(unittest.TestCase):

    def setUp(self):
        self.c = Chunk(0, 0)

    def test_trivial(self):
        pass

    def test_boring_skylight_values(self):
        # Fill it as if we were the boring generator.
        for x, z in product(xrange(16), repeat=2):
            self.c.set_block((x, 0, z), 1)
        self.c.regenerate()

        # Make sure that all of the blocks at the bottom of the ambient
        # lightmap are set to 15 (fully illuminated).
        # Note that skylight of a solid block is 0, the important value
        # is the skylight of the transluscent (usually air) block above it.
        for i in xrange(1, 32768, 128):
            self.assertEqual(self.c.skylight[i], 0xf)

    def test_skylight_spread(self):
        # Fill it as if we were the boring generator.
        for x, z in product(xrange(16), repeat=2):
            self.c.set_block((x, 0, z), 1)
        # Put a false floor up to block the light.
        for x, z in product(xrange(1, 15), repeat=2):
            self.c.set_block((x, 2, z), 1)
        self.c.regenerate()

        # Test that a gradient emerges.
        for x, z in product(xrange(16), repeat=2):
            flipx = x if x > 7 else 15 - x
            flipz = z if z > 7 else 15 - z
            target = max(flipx, flipz)
            self.assertEqual(self.c.skylight[(x * 16 + z) * 128 + 1], target,
                            "%d, %d" % (x, z))

    def test_skylight_arch(self):
        """
        Indirect illumination should work.
        """

        # Floor.
        for x, z in product(xrange(16), repeat=2):
            self.c.set_block((x, 0, z), 1)

        # Arch of bedrock, with an empty spot in the middle, which will be our
        # indirect spot.
        for x, y, z in product(xrange(2), xrange(1, 3), xrange(3)):
            self.c.set_block((x, y, z), 1)
        self.c.set_block((1, 1, 1), 0)

        # Illuminate and make sure that our indirect spot has just a little
        # bit of illumination.
        self.c.regenerate()

        self.assertEqual(self.c.skylight[(1 * 16 + 1) * 128 + 1], 14)

    def test_skylight_arch_leaves(self):
        """
        Indirect illumination with dimming should work.
        """

        # Floor.
        for x, z in product(xrange(16), repeat=2):
            self.c.set_block((x, 0, z), 1)

        # Arch of bedrock, with an empty spot in the middle, which will be our
        # indirect spot.
        for x, y, z in product(xrange(2), xrange(1, 3), xrange(3)):
            self.c.set_block((x, y, z), 1)
        self.c.set_block((1, 1, 1), 0)

        # Leaves in front of the spot should cause a dimming of 1.
        self.c.set_block((2, 1, 1), 18)

        # Illuminate and make sure that our indirect spot has just a little
        # bit of illumination.
        self.c.regenerate()

        self.assertEqual(self.c.skylight[(1 * 16 + 1) * 128 + 1], 13)

    def test_skylight_arch_leaves_occluded(self):
        """
        Indirect illumination with dimming through occluded blocks only should
        work.
        """

        # Floor.
        for x, z in product(xrange(16), repeat=2):
            self.c.set_block((x, 0, z), 1)

        # Arch of bedrock, with an empty spot in the middle, which will be our
        # indirect spot.
        for x, y, z in product(xrange(3), xrange(1, 3), xrange(3)):
            self.c.set_block((x, y, z), 1)
        self.c.set_block((1, 1, 1), 0)

        # Leaves in front of the spot should cause a dimming of 1, but since
        # the leaves themselves are occluded, the total dimming should be 2.
        self.c.set_block((2, 1, 1), 18)

        # Illuminate and make sure that our indirect spot has just a little
        # bit of illumination.
        self.c.regenerate()

        self.assertEqual(self.c.skylight[(1 * 16 + 1) * 128 + 1], 12)

    def test_incremental_solid(self):
        """
        Regeneration isn't necessary to correctly light solid blocks.
        """

        # Initialize tables and enable set_block().
        self.c.regenerate()
        self.c.populated = True

        # Any solid block with no dimming works. I choose dirt.
        self.c.set_block((0, 0, 0), blocks["dirt"].slot)

        self.assertEqual(self.c.skylight[(0 * 16 + 0) * 128 + 0], 0)

    def test_incremental_air(self):
        """
        Regeneration isn't necessary to correctly light dug blocks, which
        leave behind air.
        """

        # Any solid block with no dimming works. I choose dirt.
        self.c.blocks[(0 * 16 + 0) * 128 + 0] = blocks["dirt"].slot

        # Initialize tables and enable set_block().
        self.c.regenerate()
        self.c.populated = True

        self.c.set_block((0, 0, 0), blocks["air"].slot)

        self.assertEqual(self.c.skylight[(0 * 16 + 0) * 128 + 0], 15)
예제 #6
0
파일: world.py 프로젝트: tazjel/bravo
    def request_chunk(self, x, z):
        """
        Request a ``Chunk`` to be delivered later.

        :returns: ``Deferred`` that will be called with the ``Chunk``
        """

        if (x, z) in self.chunk_cache:
            returnValue(self.chunk_cache[x, z])
        elif (x, z) in self.dirty_chunk_cache:
            returnValue(self.dirty_chunk_cache[x, z])
        elif (x, z) in self._pending_chunks:
            # Rig up another Deferred and wrap it up in a to-go box.
            retval = yield self._pending_chunks[x, z].deferred()
            returnValue(retval)

        try:
            chunk = yield maybeDeferred(self.serializer.load_chunk, x, z)
        except SerializerReadException:
            # Looks like the chunk wasn't already on disk. Guess we're gonna
            # need to keep going.
            chunk = Chunk(x, z)

        if chunk.populated:
            self.chunk_cache[x, z] = chunk
            self.postprocess_chunk(chunk)
            if self.factory:
                self.factory.scan_chunk(chunk)
            returnValue(chunk)

        if self. async:
            from ampoule import deferToAMPProcess
            from bravo.remote import MakeChunk

            generators = [plugin.name for plugin in self.pipeline]

            d = deferToAMPProcess(MakeChunk,
                                  x=x,
                                  z=z,
                                  seed=self.level.seed,
                                  generators=generators)

            # Get chunk data into our chunk object.
            def fill_chunk(kwargs):
                chunk.blocks = array("B")
                chunk.blocks.fromstring(kwargs["blocks"])
                chunk.heightmap = array("B")
                chunk.heightmap.fromstring(kwargs["heightmap"])
                chunk.metadata = array("B")
                chunk.metadata.fromstring(kwargs["metadata"])
                chunk.skylight = array("B")
                chunk.skylight.fromstring(kwargs["skylight"])
                chunk.blocklight = array("B")
                chunk.blocklight.fromstring(kwargs["blocklight"])
                return chunk

            d.addCallback(fill_chunk)
        else:
            # Populate the chunk the slow way. :c
            for stage in self.pipeline:
                stage.populate(chunk, self.level.seed)

            chunk.regenerate()
            d = succeed(chunk)

        # Set up our event and generate our return-value Deferred. It has to
        # be done early becaues PendingEvents only fire exactly once and it
        # might fire immediately in certain cases.
        pe = PendingEvent()
        # This one is for our return value.
        retval = pe.deferred()
        # This one is for scanning the chunk for automatons.
        if self.factory:
            pe.deferred().addCallback(self.factory.scan_chunk)
        self._pending_chunks[x, z] = pe

        def pp(chunk):
            chunk.populated = True
            chunk.dirty = True

            self.postprocess_chunk(chunk)

            self.dirty_chunk_cache[x, z] = chunk
            del self._pending_chunks[x, z]

            return chunk

        # Set up callbacks.
        d.addCallback(pp)
        d.chainDeferred(pe)

        # Because multiple people might be attached to this callback, we're
        # going to do something magical here. We will yield a forked version
        # of our Deferred. This means that we will wait right here, for a
        # long, long time, before actually returning with the chunk, *but*,
        # when we actually finish, we'll be ready to return the chunk
        # immediately. Our caller cannot possibly care because they only see a
        # Deferred either way.
        retval = yield retval
        returnValue(retval)
예제 #7
0
파일: test_chunk.py 프로젝트: JDShu/bravo
class TestLightmaps(unittest.TestCase):

    def setUp(self):
        self.c = Chunk(0, 0)

    def test_trivial(self):
        pass

    def test_boring_skylight_values(self):
        # Fill it as if we were the boring generator.
        self.c.blocks[:, :, 0].fill(1)
        self.c.regenerate()

        # Make sure that all of the blocks at the bottom of the ambient
        # lightmap are set to 15 (fully illuminated).
        # Note that skylight of a solid block is 0, the important value
        # is the skylight of the transluscent (usually air) block above it.
        reference = empty((16, 16))
        reference.fill(15)

        assert_array_equal(self.c.skylight[:, :, 1], reference)

    def test_skylight_spread(self):
        # Fill it as if we were the boring generator.
        self.c.blocks[:, :, 0].fill(1)
        # Put a false floor up to block the light.
        self.c.blocks[1:15, 1:15, 3].fill(1)
        self.c.regenerate()

        # Put a gradient on the reference lightmap.
        reference = empty((16, 16))
        reference.fill(15)
        top = 1
        bottom = 15
        glow = 14
        while top < bottom:
            reference[top:bottom, top:bottom] = glow
            top += 1
            bottom -= 1
            glow -= 1

        assert_array_equal(self.c.skylight[:, :, 1], reference)

    def test_skylight_arch(self):
        """
        Indirect illumination should work.
        """

        # Floor.
        self.c.blocks[:, :, 0].fill(1)

        # Arch of bedrock, with an empty spot in the middle, which will be our
        # indirect spot.
        self.c.blocks[0:2, 0:3, 1:3].fill(1)
        self.c.blocks[1, 1, 1] = 0

        # Illuminate and make sure that our indirect spot has just a little
        # bit of illumination.
        self.c.regenerate()

        self.assertEqual(self.c.skylight[1, 1, 1], 14)

    def test_skylight_arch_leaves(self):
        """
        Indirect illumination with dimming should work.
        """

        # Floor.
        self.c.blocks[:, :, 0].fill(1)

        # Arch of bedrock, with an empty spot in the middle, which will be our
        # indirect spot.
        self.c.blocks[0:2, 0:3, 1:3].fill(1)
        self.c.blocks[1, 1, 1] = 0

        # Leaves in front of the spot should cause a dimming of 1.
        self.c.blocks[2, 1, 1] = 18

        # Illuminate and make sure that our indirect spot has just a little
        # bit of illumination.
        self.c.regenerate()

        self.assertEqual(self.c.skylight[1, 1, 1], 13)

    def test_skylight_arch_leaves_occluded(self):
        """
        Indirect illumination with dimming through occluded blocks only should
        work.
        """

        # Floor.
        self.c.blocks[:, :, 0].fill(1)

        # Arch of bedrock, with an empty spot in the middle, which will be our
        # indirect spot.
        self.c.blocks[0:3, 0:3, 1:3].fill(1)
        self.c.blocks[1, 1, 1] = 0

        # Leaves in front of the spot should cause a dimming of 1, but since
        # the leaves themselves are occluded, the total dimming should be 2.
        self.c.blocks[2, 1, 1] = 18

        # Illuminate and make sure that our indirect spot has just a little
        # bit of illumination.
        self.c.regenerate()

        self.assertEqual(self.c.skylight[1, 1, 1], 12)

    def test_incremental_solid(self):
        """
        Regeneration isn't necessary to correctly light solid blocks.
        """

        # Initialize tables and enable set_block().
        self.c.regenerate()
        self.c.populated = True

        # Any solid block with no dimming works. I choose dirt.
        self.c.set_block((0, 0, 0), blocks["dirt"].slot)

        self.assertEqual(self.c.skylight[0, 0, 0], 0)

    def test_incremental_air(self):
        """
        Regeneration isn't necessary to correctly light dug blocks, which
        leave behind air.
        """

        # Any solid block with no dimming works. I choose dirt.
        self.c.blocks[0, 0, 0] = blocks["dirt"].slot

        # Initialize tables and enable set_block().
        self.c.regenerate()
        self.c.populated = True

        self.c.set_block((0, 0, 0), blocks["air"].slot)

        self.assertEqual(self.c.skylight[0, 0, 0], 15)