Пример #1
0
class EnvironmentTests(TestCase, ArrayMixin):
    """
    Tests for L{game.environment.Environment}.
    """

    def setUp(self):
        """
        Create an L{Environment} attached to a L{Clock} so that its behavior is
        deterministic.
        """
        self.clock = Clock()
        self.environment = Environment(1, self.clock)
        self.environment.start()


    def test_terrain(self):
        """
        An L{Environment} should start with an empty terrain array.
        """
        self.assertEquals(self.environment.terrain.dict(), {})


    def test_createPlayer(self):
        """
        L{Environment.createPlayer} should instantiate a L{Player} and
        broadcast it to all registered observers.
        """
        position = Vector(1, 2, 3)
        speed = 20
        observer = PlayerVisibilityObserver()
        self.environment.addObserver(observer)
        player = self.environment.createPlayer(position, speed)
        self.assertEqual(observer.createdPlayers, [player])
        self.assertEqual(player.getPosition(), position)
        self.assertEqual(player.speed, speed)
        self.assertEqual(player.seconds, self.environment.seconds)


    def test_removePlayer(self):
        """
        L{Environment.removePlayer} should broadcast C{playerRemoved}
        to all registered observers.
        """
        position = Vector(1, 2, 3)
        speed = 20
        observer = PlayerVisibilityObserver()
        self.environment.addObserver(observer)
        player = self.environment.createPlayer(position, speed)
        self.environment.removePlayer(player)
        self.assertEqual(observer.createdPlayers, observer.removedPlayers)


    def test_setInitialPlayer(self):
        """
        L{Environment.setInitialPlayer} should change the environment's
        C{initialPlayer} attribute from C{None} to its argument.
        """
        self.assertIdentical(self.environment.initialPlayer, None)
        player = object()
        self.environment.setInitialPlayer(player)
        self.assertIdentical(self.environment.initialPlayer, player)


    def test_setNetwork(self):
        """
        L{Environment.setNetwork} changes the environment's C{network} attribute
        from C{None} to its argument.
        """
        self.assertIdentical(self.environment.network, None)
        network = object()
        self.environment.setNetwork(network)
        self.assertIdentical(self.environment.network, network)
Пример #2
0
class NetworkController(AMP):
    """
    A controller which responds to AMP commands to make state changes to local
    model objects.

    @ivar modelObjects: A C{dict} mapping identifiers to model objects.

    @ivar clock: A provider of L{IReactorTime} which will be used to
        update the model time.
    """

    environment = None

    def __init__(self, clock):
        self.modelObjects = {}
        self.clock = clock


    def addModelObject(self, identifier, modelObject):
        """
        Associate a network identifier with a model object.
        """
        self.modelObjects[identifier] = modelObject
        modelObject.addObserver(self)


    def directionChanged(self, modelObject):
        """
        Notify the network that a local model object changed direction.

        @param modelObject: The L{Player} whose direction has changed.
        """
        d = self.callRemote(
            SetMyDirection,
            direction=modelObject.direction, y=modelObject.orientation.y)
        d.addCallback(self._gotNewPosition, modelObject)
        # XXX Add an errback


    def _gotNewPosition(self, position, player):
        """
        Update a L{Player}'s position based on new data from the server.

        @param player: The L{Player} whose position to change.
        @param position: Dict with C{x} and C{y} keys, whose values should be
        integers specifying position.
        """
        player.setPosition(Vector(position['x'], position['y'], position['z']))


    def createInitialPlayer(self, environment, identifier, position,
                            speed):
        """
        Create this client's player as the initial player in the given
        environment and add it to the model object mapping.
        """
        player = environment.createPlayer(position, speed)
        environment.setInitialPlayer(player)
        self.addModelObject(identifier, player)


    def introduce(self):
        """
        Greet the server and register the player model object which belongs to
        this client and remember the identifier with which it responds.
        """
        d = self.callRemote(Introduce)
        def cbIntroduce(box):
            granularity = box['granularity']
            position = Vector(box['x'], box['y'], box['z'])
            speed = box['speed']
            self.environment = Environment(granularity, self.clock)
            self.environment.setNetwork(self)
            self.createInitialPlayer(
                self.environment, box['identifier'], position,
                speed)
            return self.environment
        d.addCallback(cbIntroduce)
        return d


    def objectByIdentifier(self, identifier):
        """
        Look up a pre-existing model object by its network identifier.

        @type identifier: C{int}

        @raise KeyError: If no existing model object has the given identifier.
        """
        return self.modelObjects[identifier]


    def identifierByObject(self, modelObject):
        """
        Look up the network identifier for a given model object.

        @raise ValueError: If no network identifier is associated with the
            given model object.

        @rtype: L{int}
        """
        for identifier, object in self.modelObjects.iteritems():
            if object is modelObject:
                return identifier
        raise ValueError("identifierByObject passed unknown model objects")


    def setDirectionOf(self, identifier, direction, x, y, z, orientation):
        """
        Set the direction of a local model object.

        @type identifier: L{int}
        @type direction: One of the L{game.direction} direction constants

        @see: L{SetDirectionOf}
        """
        player = self.objectByIdentifier(identifier)
        player.setDirection(direction)
        player.setPosition(Vector(x, y, z))
        player.orientation.y = orientation
        return {}
    SetDirectionOf.responder(setDirectionOf)


    def newPlayer(self, identifier, x, y, z, speed):
        """
        Add a new L{Player} object to the L{Environment} and start
        tracking its identifier on the network.

        @param identifier: The network-level identifier of the player.
        @param x: The x position of the new L{Player}.
        @param y: The y position of the new L{Player}.
        @param z: The z position of the new L{Player}.
        """
        player = self.environment.createPlayer(Vector(x, y, z), speed)
        self.modelObjects[identifier] = player
        return {}
    NewPlayer.responder(newPlayer)


    def removePlayer(self, identifier):
        """
        Remove an existing L{Player} object from the L{Environment}
        and stop tracking its identifier on the network.

        @param identifier: The network-level identifier of the player.
        """
        self.environment.removePlayer(self.objectByIdentifier(identifier))
        del self.modelObjects[identifier]
        return {}
    RemovePlayer.responder(removePlayer)


    def setTerrain(self, x, y, z, voxels):
        """
        Add new terrain information to the environment.

        @param x: The x coordinate where the given voxels begin.
        @param y: The y coordinate where the given voxels begin.
        @param z: The z coordinate where the given voxels begin.

        @param voxels: An L{numpy.array} specifying terrain information starting
            at the specified location and proceeding in the positive direction
            along all axes
        """
        self.environment.terrain.set(x, y, z, voxels)
        return {}
    SetTerrain.responder(setTerrain)