예제 #1
0
파일: mobmanager.py 프로젝트: squiddy/bravo
    def check_block_collision(self, location, minvec, maxvec):
        min_point = [minvec[0] + location.x, minvec[1] + location.y, minvec[2] + location.z]

        max_point = [maxvec[0] + location.x, maxvec[1] + location.y, maxvec[2] + location.z]

        min_point[0] = int(floor(min_point[0]))
        min_point[1] = int(floor(min_point[1]))
        min_point[2] = int(floor(min_point[2]))

        max_point[0] = int(floor(max_point[0]))
        max_point[1] = int(floor(max_point[1]))
        max_point[2] = int(floor(max_point[2]))

        for x in xrange(min_point[0], max_point[0]):
            for y in xrange(min_point[1], max_point[1]):
                for z in xrange(min_point[2], max_point[2]):
                    if self.world.sync_get_block((x, y, z)) != 0:
                        normal = (
                            clamp(location.x - x, -1, 1),
                            clamp(location.y - y, -1, 1),
                            clamp(location.z - z, -1, 1),
                        )
                        return False, normal

        return True
예제 #2
0
파일: entity.py 프로젝트: mmcgill/bravo
    def update(self):
        """
        Update this mob's location with respect to a factory.
        """

        # XXX  Discuss appropriate style with MAD
        player = self.manager.closest_player((self.location.x,
                                 self.location.y,
                                 self.location.z),
                                 16)

        if player == None:
            vector = (uniform(-.4,.4),
                      uniform(-.4,.4),
                      uniform(-.4,.4))

            target = (self.location.x + vector[0],
                self.location.y + vector[1],
                self.location.z + vector[2])
        else:
            target = (player.location.x,
                player.location.y,
                player.location.z)

            self_pos = (self.location.x, self.location.y, self.location.z)
            vector = gen_close_point(self_pos, target)

            vector = (
                clamp(vector[0], -0.4, 0.4),
                clamp(vector[1], -0.4, 0.4),
                clamp(vector[2], -0.4, 0.4),
            )

        new_position = (vector[0] + self.location.x,
            vector[1] + self.location.y,
            vector[2] + self.location.z,)

        new_theta = int(atan2(
            (self.location.z - new_position[2]),
            (self.location.x - new_position[0] ))
            + pi/2)

        if new_theta < 0 :
            new_theta = 0

        can_go = self.manager.check_block_collision(self.location, (-.3, 0, -.3,), (.5, 1, .5))
        self.location.theta = new_theta

        if can_go:
            self.slide = False
            self.location.x = new_position[0]
            self.location.y = new_position[1]
            self.location.z = new_position[2]

            self.manager.correct_origin_chunk(self)
            self.manager.broadcast(self.save_location_to_packet())
        else:
            self.slide = self.manager.slide_vector(vector, )
            self.manager.broadcast(self.save_location_to_packet())
예제 #3
0
파일: location.py 프로젝트: JDShu/bravo
    def clamp(self):
        """
        Force this location to be sane.

        Forces the position and orientation to be sane, then fixes up
        location-specific things, like stance.

        :returns: bool indicating whether this location had to be altered
        """

        clamped = False

        y = self.pos.y

        # Clamp Y. We take precautions here and forbid things to go up past
        # the top of the world; this tend to strand entities up in the sky
        # where they cannot get down.
        if not (32 * 1) < y < (32 * 126):
            y = clamp(y, 32 * 1, 32 * 126)
            self.pos = self.pos._replace(y=y)
            clamped = True

        # Stance is the current jumping position, plus a small offset of
        # around 0.1. In the Alpha server, it must between 0.1 and 1.65, or
        # the anti-grounded code kicks the client. In the Beta server, though,
        # the clamp is different. Experimentally, the stance can be as short
        # as 1.5 (crouching) to 2.4 (jumping). At this point, we enforce some
        # sanity on our client, and force the stance to a reasonable value.
        fy = y / 32
        if not 1.5 < (self.stance - fy) < 2.4:
            # Standard standing stance is 1.62.
            self.stance = fy + 1.62
            clamped = True

        return clamped
예제 #4
0
파일: test_maths.py 프로젝트: JDShu/bravo
    def test_middle_polymorphic(self):
        """
        ``clamp()`` doesn't care too much about its arguments, and won't
        modify types unnecessarily.
        """

        self.assertEqual(clamp(1.5, 0, 3), 1.5)
예제 #5
0
파일: location.py 프로젝트: JDShu/bravo
    def clamp(self):
        """
        Force this location to be sane.

        Forces the position and orientation to be sane, then fixes up
        location-specific things, like stance.

        :returns: bool indicating whether this location had to be altered
        """

        clamped = False

        y = self.pos.y

        # Clamp Y. We take precautions here and forbid things to go up past
        # the top of the world; this tend to strand entities up in the sky
        # where they cannot get down.
        if not (32 * 1) < y < (32 * 126):
            y = clamp(y, 32 * 1, 32 * 126)
            self.pos = self.pos._replace(y=y)
            clamped = True

        # Stance is the current jumping position, plus a small offset of
        # around 0.1. In the Alpha server, it must between 0.1 and 1.65, or
        # the anti-grounded code kicks the client. In the Beta server, though,
        # the clamp is different. Experimentally, the stance can be as short
        # as 1.5 (crouching) to 2.4 (jumping). At this point, we enforce some
        # sanity on our client, and force the stance to a reasonable value.
        fy = y / 32
        if not 1.5 < (self.stance - fy) < 2.4:
            # Standard standing stance is 1.62.
            self.stance = fy + 1.62
            clamped = True

        return clamped
예제 #6
0
    def test_middle_polymorphic(self):
        """
        ``clamp()`` doesn't care too much about its arguments, and won't
        modify types unnecessarily.
        """

        self.assertEqual(clamp(1.5, 0, 3), 1.5)
예제 #7
0
파일: entity.py 프로젝트: JDShu/bravo
    def update(self):
        """
        Update this mob's location with respect to a factory.
        """

        # XXX  Discuss appropriate style with MAD
        # XXX remarkably untested
        player = self.manager.closest_player(self.location.pos, 16)

        if player is None:
            vector = (uniform(-.4,.4),
                      uniform(-.4,.4),
                      uniform(-.4,.4))

            target = self.location.pos + vector
        else:
            target = player.location.pos

            self_pos = self.location.pos
            vector = gen_close_point(self_pos, target)

            vector = (
                clamp(vector[0], -0.4, 0.4),
                clamp(vector[1], -0.4, 0.4),
                clamp(vector[2], -0.4, 0.4),
            )

        new_position = self.location.pos + vector

        new_theta = self.location.pos.heading(new_position)
        self.location.ori = self.location.ori._replace(theta=new_theta)

        # XXX explain these magic numbers please
        can_go = self.manager.check_block_collision(self.location.pos,
                (-10, 0, -10), (16, 32, 16))

        if can_go:
            self.slide = False
            self.location.pos = new_position

            self.manager.correct_origin_chunk(self)
            self.manager.broadcast(self.save_location_to_packet())
        else:
            self.slide = self.manager.slide_vector(vector)
            self.manager.broadcast(self.save_location_to_packet())
예제 #8
0
파일: chunk.py 프로젝트: Zebetus/bravo
    def regenerate_blocklight(self):
        lightmap = array("L", [0] * (16 * 16 * CHUNK_HEIGHT))

        for x, z, y in iterchunk():
            block = self.get_block((x, y, z))
            if block in glowing_blocks:
                composite_glow(lightmap, glowing_blocks[block], x, y, z)

        self.blocklight = array("B", [clamp(x, 0, 15) for x in lightmap])
예제 #9
0
파일: chunk.py 프로젝트: miea/bravo
    def regenerate_blocklight(self):
        lightmap = array("L", [0] * (16 * 16 * 128))

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

        self.blocklight = array("B", [clamp(x, 0, 15) for x in lightmap])
예제 #10
0
    def regenerate_blocklight(self):
        lightmap = array("L", [0] * (16 * 16 * CHUNK_HEIGHT))

        for x, z, y in iterchunk():
            block = self.get_block((x, y, z))
            if block in glowing_blocks:
                composite_glow(lightmap, glowing_blocks[block], x, y, z)

        self.blocklight = array("B", [clamp(x, 0, 15) for x in lightmap])
예제 #11
0
파일: entity.py 프로젝트: JDShu/bravo
    def update(self):
        """
        Update this mob's location with respect to a factory.
        """

        # XXX  Discuss appropriate style with MAD
        # XXX remarkably untested
        player = self.manager.closest_player(self.location.pos, 16)

        if player is None:
            vector = (uniform(-.4, .4), uniform(-.4, .4), uniform(-.4, .4))

            target = self.location.pos + vector
        else:
            target = player.location.pos

            self_pos = self.location.pos
            vector = gen_close_point(self_pos, target)

            vector = (
                clamp(vector[0], -0.4, 0.4),
                clamp(vector[1], -0.4, 0.4),
                clamp(vector[2], -0.4, 0.4),
            )

        new_position = self.location.pos + vector

        new_theta = self.location.pos.heading(new_position)
        self.location.ori = self.location.ori._replace(theta=new_theta)

        # XXX explain these magic numbers please
        can_go = self.manager.check_block_collision(self.location.pos,
                                                    (-10, 0, -10),
                                                    (16, 32, 16))

        if can_go:
            self.slide = False
            self.location.pos = new_position

            self.manager.correct_origin_chunk(self)
            self.manager.broadcast(self.save_location_to_packet())
        else:
            self.slide = self.manager.slide_vector(vector)
            self.manager.broadcast(self.save_location_to_packet())
예제 #12
0
def neighboring_light(glow, block):
    """
    Calculate the amount of light that should be shone on a block.

    ``glow`` is the brighest neighboring light. ``block`` is the slot of the
    block being illuminated.

    The return value is always a valid light value.
    """

    return clamp(glow - blocks[block].dim, 0, 15)
예제 #13
0
    def latency(self, value):
        # Clamp the value to not exceed the boundaries of the packet. This is
        # necessary even though, in theory, a ping this high is bad news.
        value = clamp(value, 0, 65535)

        # Check to see if this is a new value, and if so, alert everybody.
        if self._latency != value:
            packet = make_packet("players", name=self.username, online=True,
                ping=value)
            self.factory.broadcast(packet)
            self._latency = value
예제 #14
0
def neighboring_light(glow, block):
    """
    Calculate the amount of light that should be shone on a block.

    ``glow`` is the brighest neighboring light. ``block`` is the slot of the
    block being illuminated.

    The return value is always a valid light value.
    """

    return clamp(glow - blocks[block].dim, 0, 15)
예제 #15
0
파일: protocol.py 프로젝트: squiddy/bravo
    def latency(self, value):
        # Clamp the value to not exceed the boundaries of the packet. This is
        # necessary even though, in theory, a ping this high is bad news.
        value = clamp(value, 0, 65535)

        # Check to see if this is a new value, and if so, alert everybody.
        if self._latency != value:
            packet = make_packet("players", name=self.username, online=True,
                ping=value)
            self.factory.broadcast(packet)
            self._latency = value
예제 #16
0
def make_glows():
    """
    Set up glow tables.

    These tables provide glow maps for illuminated points.
    """

    glow = [None] * 16
    for i in range(16):
        dim = 2 * i + 1
        glow[i] = array("b", [0] * (dim**3))
        for x, y, z in product(xrange(dim), repeat=3):
            distance = abs(x - i) + abs(y - i) + abs(z - i)
            glow[i][(x * dim + y) * dim + z] = i + 1 - distance
        glow[i] = array("B", [clamp(x, 0, 15) for x in glow[i]])
    return glow
예제 #17
0
파일: chunk.py 프로젝트: Zebetus/bravo
def make_glows():
    """
    Set up glow tables.

    These tables provide glow maps for illuminated points.
    """

    glow = [None] * 16
    for i in range(16):
        dim = 2 * i + 1
        glow[i] = array("b", [0] * (dim**3))
        for x, y, z in product(xrange(dim), repeat=3):
            distance = abs(x - i) + abs(y - i) + abs(z - i)
            glow[i][(x * dim + y) * dim + z] = i + 1 - distance
        glow[i] = array("B", [clamp(x, 0, 15) for x in glow[i]])
    return glow
예제 #18
0
    def set_block(self, coords, block):
        """
        Update a block value.

        :param tuple coords: coordinate triplet
        :param int block: block type
        """

        x, y, z = coords
        index, section_y = divmod(y, 16)

        column = x * 16 + z

        if self.get_block(coords) != block:
            self.sections[index].set_block((x, section_y, z), block)

            if not self.populated:
                return

            # Regenerate heightmap at this coordinate.
            if block:
                self.heightmap[column] = max(self.heightmap[column], y)
            else:
                # If we replace the highest block with air, we need to go
                # through all blocks below it to find the new top block.
                height = self.heightmap[column]
                if y == height:
                    for y in range(height, -1, -1):
                        if self.get_block((x, y, z)):
                            break
                    self.heightmap[column] = y

            # Do the blocklight at this coordinate, if appropriate.
            if block in glowing_blocks:
                composite_glow(self.blocklight, glowing_blocks[block],
                    x, y, z)
                bl = [clamp(light, 0, 15) for light in self.blocklight]
                self.blocklight = array("B", bl)

            # And the skylight.
            glow = max(self.get_skylight((nx, ny, nz))
                       for nx, nz, ny in iter_neighbors((x, z, y)))
            self.set_skylight((x, y, z), neighboring_light(glow, block))

            self.dirty = True
            self.damage(coords)
예제 #19
0
파일: chunk.py 프로젝트: miea/bravo
    def set_block(self, coords, block):
        """
        Update a block value.

        :param tuple coords: coordinate triplet
        :param int block: block type
        """

        x, y, z = coords

        column = x * 16 + z
        offset = column * 128 + y

        if self.blocks[offset] != block:
            self.blocks[offset] = block

            if not self.populated:
                return

            # Regenerate heightmap at this coordinate.
            if block:
                self.heightmap[column] = max(self.heightmap[column], y)
            else:
                # If we replace the highest block with air, we need to go
                # through all blocks below it to find the new top block.
                height = self.heightmap[column]
                if y == height:
                    for y in range(height, -1, -1):
                        if self.blocks[column * 128 + y]:
                            break
                    self.heightmap[column] = y

            # Do the blocklight at this coordinate, if appropriate.
            if block in glowing_blocks:
                composite_glow(self.blocklight, glowing_blocks[block],
                    x, y, z)
                self.blocklight = array("B", [clamp(x, 0, 15) for x in
                                              self.blocklight])

            # And the skylight.
            glow = max(self.skylight[(nx * 16 + nz) * 128 + ny]
                for nx, nz, ny in iter_neighbors((x, z, y)))
            self.skylight[offset] = neighboring_light(glow, block)

            self.dirty = True
            self.damage(coords)
예제 #20
0
파일: chunk.py 프로젝트: Zebetus/bravo
    def set_block(self, coords, block):
        """
        Update a block value.

        :param tuple coords: coordinate triplet
        :param int block: block type
        """

        x, y, z = coords
        index, section_y = divmod(y, 16)

        column = x * 16 + z

        if self.get_block(coords) != block:
            self.sections[index].set_block((x, section_y, z), block)

            if not self.populated:
                return

            # Regenerate heightmap at this coordinate.
            if block:
                self.heightmap[column] = max(self.heightmap[column], y)
            else:
                # If we replace the highest block with air, we need to go
                # through all blocks below it to find the new top block.
                height = self.heightmap[column]
                if y == height:
                    for y in range(height, -1, -1):
                        if self.get_block((x, y, z)):
                            break
                    self.heightmap[column] = y

            # Do the blocklight at this coordinate, if appropriate.
            if block in glowing_blocks:
                composite_glow(self.blocklight, glowing_blocks[block], x, y, z)
                bl = [clamp(light, 0, 15) for light in self.blocklight]
                self.blocklight = array("B", bl)

            # And the skylight.
            glow = max(
                self.get_skylight((nx, ny, nz))
                for nx, nz, ny in iter_neighbors((x, z, y)))
            self.set_skylight((x, y, z), neighboring_light(glow, block))

            self.dirty = True
            self.damage(coords)
예제 #21
0
파일: chunk.py 프로젝트: miea/bravo
            return 0

        return f(chunk, coords, *args, **kwargs)

    return deco

# Set up glow tables.
# These tables provide glow maps for illuminated points.
glow = [None] * 16
for i in range(16):
    dim = 2 * i + 1
    glow[i] = array("b", [0] * (dim**3))
    for x, y, z in product(xrange(dim), repeat=3):
        distance = abs(x - i) + abs(y - i) + abs(z - i)
        glow[i][(x * dim + y) * dim + z] = i + 1 - distance
    glow[i] = array("B", [clamp(x, 0, 15) for x in glow[i]])

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
    sy = y - strength
    sz = z - strength
예제 #22
0
 def test_middle(self):
     self.assertEqual(clamp(2, 0, 3), 2)
예제 #23
0
 def test_maximum(self):
     self.assertEqual(clamp(4, 0, 3), 3)
예제 #24
0
 def test_minimum(self):
     self.assertEqual(clamp(-1, 0, 3), 0)
예제 #25
0
파일: test_maths.py 프로젝트: JDShu/bravo
 def test_minimum(self):
     self.assertEqual(clamp(-1, 0, 3), 0)
예제 #26
0
파일: test_maths.py 프로젝트: JDShu/bravo
 def test_maximum(self):
     self.assertEqual(clamp(4, 0, 3), 3)
예제 #27
0
파일: chunk.py 프로젝트: miea/bravo
    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 = array("B", [0] * (16 * 16 * 128))

        for x, z in product(xrange(16), repeat=2):
            offset = x * 16 + z

            # 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[offset] + 1

            # The topmost block, regardless of type, is set to maximum
            # lighting, as are all the blocks above it.
            for i in xrange(height, 128):
                lightmap[offset + i] = 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[offset * 128 + y]].dim
                light -= dim
                if light <= 0:
                    break

                lightmap[offset * 128 + y] = light

        # Now it's time to spread the light around. This flavor uses extra
        # memory to speed things up; the basic idea is to spread *all* light,
        # one glow level at a time, rather than spread each block
        # individually.
        max_height = max(self.heightmap)

        lightable = [blocks[block].dim < 15 for block in self.blocks]
        unlit = [x and not y for (x, y) in zip(lightable, lightmap)]

        # Create a mask to find all blocks that have an unlit block as a
        # neighbour in the xz-plane, then apply the mask to the lightmap to
        # find all lighted blocks with one or more unlit blocks as neighbours.
        spread = set()
        for x, z, y in product(xrange(16), xrange(16), xrange(max_height)):
            if not lightmap[(x * 16 + z) * 128 + y]:
                continue

            if ((x > 0  and unlit[((x - 1) * 16 + z) * 128 + y]) or
                (x < 15 and unlit[((x + 1) * 16 + z) * 128 + y]) or
                (z > 0  and unlit[(x * 16 + (z - 1)) * 128 + y]) or
                (z < 15 and unlit[(x * 16 + (z + 1)) * 128 + y])):
                spread.add((x, z, y))

        visited = set()

        # Run the actual glow loop. For each glow level, go over unvisited air
        # blocks and illuminate them.
        for glow in xrange(14, 0, -1):
            for coords in spread:
                if lightmap[(coords[0] * 16 + coords[1]) * 16 + coords[2]] <= glow:
                    visited.add(coords)
                    continue

                for target in iter_neighbors(coords):
                    # Skip targets that already have valid lighting.
                    if target in visited:
                        continue

                    x, z, y = target

                    if not (0 <= x < 16 and 0 <= z < 16 and 0 <= y < 128):
                        continue

                    offset = (x * 16 + z) * 128 + y

                    # If the block's lightable and the lightmap isn't fully
                    # lit up, then light the block appropriately and mark it
                    # as visited.
                    if (lightable[offset]
                        and lightmap[offset] < glow):
                        light = neighboring_light(glow, self.blocks[offset])
                        lightmap[offset] = clamp(light, 0, 15)
                        visited.add(target)
            spread = visited
            visited = set()

        self.skylight = lightmap
예제 #28
0
파일: test_maths.py 프로젝트: JDShu/bravo
 def test_middle(self):
     self.assertEqual(clamp(2, 0, 3), 2)