metaloph1l / pacman

2 stars 1 forks source link

Implement server logic #7

Open metaloph1l opened 12 years ago

metaloph1l commented 12 years ago

Implement the basic game logic of the server. The included methods are executed after the server received actions by the clients. The logic needs to update the game state in the way that is necessary by the action.

Possible actions are at least (not necessarily complete):

After updating the game state and saving it within the logic, updates need to be sent to clients by the server. Sending the updates is not included within this issue. However, the logic needs to have methods that return both the complete current game state, as well as methods that return the changes of the last performed action, so that small incremental updates can be sent to the clients.

Therefore it is advisable, that the all the possible actions, that can be performed in the logic, return a small update delta, that can be sent to the clients, e.g.: public List <GameUpdate> moveUp(Pacman pacman, ...) throws ...; public Game getCurrentGame() throws ...;

Note though, that not all the actions need to provide small updates. This is only really necessary for the movement of the pacmans. Resets or switching of the labyrinth can still send the whole Game Object: public Game resetGame() throws ...; or (with need to call .getGame() later): public void resetGame() throws ...;

Package: at.ac.foop.pacman.gameserver.logic

lanoxx commented 12 years ago

I would suggest that each Client implements a Game interface that has the following methods:

void notifyMapChange();

This would notify the client that a map change is imminent (we could possibly pass a timer value to notify the client ahead of the change) and then the client can pull the new map from the server with a separate call

void notifyPieceMovement(int clock, Piece piece, Direction a);

This notifies a client that another player has changed the direction of his piece. Passing the clock number makes it unambiguous when this event occoured and since a pieces keep moving into the same direction until the player sets a different direction, each client is able to calculate the state of the game by himself. The client must additionally have a way of "fixing" the game state in case such a call arrives late.

Additionally we need some kind of method to synchronize the game clock. That is some method such as for example:

void clock(int x);

which tells the client the current clock value of the server (the servers clock would be authoritative) that way if the network is slow for some reason we can still show a fluent movement of the game. The server could call this every Nth clock interval to make sure the clients stay in sync. If the client clock differes more than a value x, we show a lag screen and pause the game until the client has had time receive all messages.

metaloph1l commented 12 years ago

Your approach seems pretty good. However, I'm not sure if the usage of a clock is really necessary. Maybe we should ask if that is the case.

Since the client only displays the game and changes the representation based on the updates it gets by the server, I'm not sure if we would ever need to resynchronize the client. However, we can still implement a fall back solution for the case of lost packets:

spookyTU commented 12 years ago

I like the synchronization idea. However, since all the calculations are done on the server I don't think it is necessary for the clients to be able to calculate the game state themselves (the synchronization might get complicated). What if we just rely on the latest game status and if the client doesn't receive an update for a longer (defined) period of time it initializes a game state pull from the server?

In this case the game would just "freeze" as long as there are no status updates.

metaloph1l commented 12 years ago

We (Sebastian and I) had a discussion today and came to some conclusions. We agreed that we need a synchronization mechanism. This would be a clock that is updated and propagated to the clients. Additionally we need to send movements of the other and own pacman to the client for the update of the presentation.

There is still an open issue about synchronization. RMI calls usually are synchronized calls so we need to make sure a dropped client does not block the server. This should be achievable by sending asynchronous calls or sending a synchronous call in a new thread with timeout.

As for lag:

lanoxx commented 12 years ago

I discussed this with Philipp today. We will design a Game interface which has the following methods:

interface Game

This is basically a simplification of my suggested game interface. When the server calls notify the clients have to download the map from the server (will still need to write a separate GameServer interface for this). The server keeps an internal clock counter which is incremented by some timer. Before each incrementation of the clock the server calls the clock method on each client and sends them a list of Directions for each Pacman (Id and direction).

At the beginning of a round each client downloads the map and the pacman positions from the game server. After that the labyrinth state can only change when a clock message arrives. This way we ensure that the game state is always consistent (RMI).

Also the server should maintain a separate thread for each client so that a call to clock(...) does not block the server when one of the clients looses the network connection.


The GameServer interface could look something like this:

interface GameServer

ready notifies the server that a given client is ready after a map change and the download map function would download the map to the client. XXX is a data structure we still have to design which needs to contain the Labyrinth and the Pacman positions.

Phillip let me know if I have forgotten something.

metaloph1l commented 12 years ago

Just some notes:

``` GameClient: I think we should use: clock(int turn, List<Pacman, Direction> directions);

Because then the client automatically gets send the (new/old) colors of the pacmans along with the directions and can automatically update the presentation.

As of the GameServer we need some sort of the following for signaling the server (dont know if the clock is necessary): void directionChange(int clock, Player player, Direction direction) or void directionChange(int clock, Pacman pacman, Direction direction)

Other than that it looks good.

lanoxx commented 12 years ago

Ah yes, I forgot the directionChange methods in the game server interface.

About the Game interface: Im not sure how RMI handles this. If we send Pacman objects instead of the id as long or int then does the client get a Object which actually lives on the server or does he get a copy of the pacman object that the server has?

lanoxx commented 12 years ago

And also since the Pacman and Player objects are also connected to each other as well as to square and board objects it might be just easier to pass the id or color of the Pacman and then let the clients do the initialization by them selves. We just make sure that both clients and server use the same id field for the same pacman/player.

spookyTU commented 12 years ago

As long as we have serializable objects we should be able to transfer them. But since we don't transfer an actual Labyrinth-Object in downloadMap(); and the client initializes the game itself we could just transfer IDs and let the client organize them themselves. Or we just have a stub and marshal all requests directly through the object?

As for synchronization: If we use separate threads for each player we can just send all movements and let the server pick them at discrete points in time (from all involved players). This way we could keep a consistent game state (I think this is what Philipp mentioned). Does the clock value from the client refer to the last valid clock state received from the server?

lanoxx commented 12 years ago

I definitely prefer using ids then having to create stubs and marshal everything from the server to the client.

About synchronization: Does the clock value from the client refer to the last valid clock state received from the server? Yes thats the idea

spookyTU commented 12 years ago

I was just thinking about the fast forward part (if movements get lost): For such a case it would be necessary to keep the last n game states in memory and transfer them again (for example a Client sends an update with clock x = 15 and game state on server is on 20). Asynchronous calls from Server to Client are probably not a good idea because then we can't tell if we got all the game state updates (I think an acknowledgment is necessary). If the client misses some updates (for whatever reason) it is probably easier to get the current state of the game from the server and ignore prior movement updates (maybe you meant it this way, I wasn't sure).

Beside from that I think the concept is very well thought out.