예제 #1
0
파일: world.py 프로젝트: alucas/bravo
    def request_chunk(self, x, z):
        """
        Request a ``Chunk`` to be delivered later.

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

        # First, try the cache.
        cached = self._cache.get((x, z))
        if cached is not None:
            returnValue(cached)

        # Is it pending?
        if (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)

        # Create a new chunk object, since the cache turned up empty.
        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)

        # Add in our magic dirtiness hook so that the cache can be aware of
        # chunks who have been...naughty.
        chunk.dirtied = self._cache.dirtied
        if chunk.dirty:
            # The chunk was already dirty!? Oh, naughty indeed!
            self._cache.dirtied(chunk)

        if chunk.populated:
            self._cache.put(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._cache.dirtied(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)