Original Post
My senior project is coming along right on schedual but im running into some issues with the networking. The game will be a capture the flag type spinoff so getting the players to move smoothly is extreamly important. My team implimented alpha build over the weekend and the network layer was set in place. This is probably a good point to stop and explain the engine design as being i am very new to networking some of you may be able to forewarn me of issues.
Archetecture: Server-Client
Server
-------
The server runs two threads. The first thread is the listen thread. The listen thread waits for new connections and when one is made it creates a new client in a static array and sets it up for sending and recieving data. After the client structure is created it immediatly sends all connected clients a notification through tcp of a new player. It also sends the new client notifications of all existing clients. The final step to the connection process is the sending of a port confirmation to the new client.
Each client structure on the server has a stream socket and a datagram socket dedicated entirely to the client. The second thread uses these connections to recieve messages. It first queries all active client structures on the server to recieve any data from each clients stream or datagram sockets. Chat data is put into a queue and later relayed to all connected clients. All other messages get put into a seperate queue if and only if they pass the timestamp (UDP) and they are complete packets (no partial packets, the server throws them out). This thread continues to loop through the clients recieving, sending chat, and queueing data without interaction of the game.
When i mention no interaction with the game thats not entirely true. Since multiple threads are running I create a lockinstance and release instance function that are wrapped in critical sections. The gameloop locks the server instance once per frame freezing all activity on the queue. It does this so that the queue may be safely accessed and all messages can be handled.
Client
-------
The client is setup in a similar mannner to the server. It runs one thread that recieves messages from the server and puts them in a queue to be dealt with by the game loop. All outgoing and incoming UDP packets are timestamped and verified. The client has an ID that the server assigns it when connected (the id is just the index in the servers array of client structures).
Game
-----
The game loop is the final piece to the puzzle. This is where all messages get processed in the queue. It is also responsible for sending data to update the server. Every 100ms (subject to change) it sends a position packet that contains a vector that represents world position and a vector that represents velocity. This packet is confirmed and updates the server gamestate.
The server game loop sends position data every 100ms as well, the difference is that it sends to each connected client, positions of all other clients.
*** So now the problem ***
I hope that wasnt too boring, but I think it was needed before I describe the issue at hand. Each client is "predicting" the other clients by them having a position and a velocity. Between packets they continue to move from the last known position with the velocity given. Packets from the server are used to update the position and velocitys. The only exception to this is when a position packet is recieved from the server pertaining to the actual player that belongs to that client it is ignored. Im going to have a seperate packet that fixes the position only if the server detected a problem with one of the requested movements. That may have been confusing but here is a break down of how it goes....
Client 0: Server here is my latest position.
Server: Client 0 position updated.
Server: Client 0. Here is position data for everyone connected.
Client 0: Updating positions and velocities of all other players and ignoring my own.
Client 1: Server, you do not know i have a hacked game copy but im going to move through this wall. Position data sent.
Server: Client 1 position update failed. Sending a notification to him.
Client 1: Recieved notification. Damn.
I know that the client should probably just be updating its position and velocity from the servers updates as well but when i tried that i found that the client was not able to move. The server had his initial velocity as 0 and by the time the client tried to updated the server he had already recieved a packet setting it back to zero.
The real problem that im having is the client side prediction. It correctly predicts the positions but when a server sends a packet to sync the clients the time it takes to get from the server to the client and processed is lost. This means the server sends a packets and by the time it gets to the client it is "old" or a tad behind. Since prediction is always running during this lost time the client ends up where he should be but the packet whips him back ever so slightly.
example...
Client 0: Predicting client 1...hes on the move
Client 0: Predicting client 1...hes on the move
Server: Sending update....
**here there is a small time slice while the packet is in travel**.
Client 0: Predicting client 1...hes still on the move
Client 0: Recieved update..adjusting position and velocity.
**the player is whiped back a small amount (due to time loss)
I have a few ideas of how i might solve this but they all have a downside. I was thinking about only adjusting position if the velocity has changed. I think that this would still get a whipping effect when velocity is changed though and it also means that if a player moved in one direction for a long time he could get way off sync. I was also thinking of scaling the velocity somehow using the difference in the distances of the recieved packet and current position.
Any ideas or advice would be HIGHLY appreciated. You can check out the project at www.fatesforgiven.com to see its status.
Thanks,
Daniel Doptis