As I said in the previous post I was thinking about the best way to automate the gameplay in the game and I decided to go with the artificial intelligence and implemented some logic in order for the ships to move around and shoot and make some sense doing so. Basically, they just wonder around the arena up to a maximum distance from the center (for them not to get stuck in corners) until they get close enough to an enemy ship in which case they initiate the pursuit and try to shoot them. A small trick for them not to just get stuck to each other was to define a minimum distance that they try to maintain from the enemy.
Since the number of options was growing I’ve added an options menu where it’s possible to configure desired resolution, to run or not in full screen, enable/disable bots and others.
Following is a video of the 2 bots as seen by the client (host is the green one) using VFC to reduce the network load. It’s possible to see in the video the varying quantity of data received (in Bytes per Second - shown on the bottom to the left) by the client depending on the distance of the enemy and asteroids. It’s also clear that there the enemy makes some “jumps” when he’s coming from outside the larger circle (which indicate the different consistency zones) due to inconsistency between the opponents’ known position and “real” position.
Net Rumble Gameplay with VFC
I discovered a couple more bugs in the game, related to features added by me. After introducing the player IDs I run a couple tests and the IDs seemed to be correct on all the machines but, as it turns out, they weren't. Fixed this by initializing every time a player joins the game. The host is the responsible for sending out the correct data. Another bug that happened when the host exited the game in the Lobby screen was also fixed (just another verification of the network session. The feature of joining the game in progress was also broken because of a couple initializations that were missing - fixed.
Simulate latency and packet loss
I've also been working in ways of collecting interesting data with this VFC implementation. I was thinking about using a XNA feature that enables the simulation of a typical Internet conditions on a LAN. By using the SimulatedLatency and SimulatedPacketLoss properties of the NetworkSession I thought would be able to simulate the desired conditions. As it turns out there are a couple of issues with these simulated properties. First, they also affect local data and the server would lose data that it sent to itself. Tried to work around it by setting this up in a per-send basis but didn't work. Seems like it isn't able to identify which packets are to be delayed or not. I also think that these simulation properties don't work well with XNA's reliable communication, I believe that even packets sent with the Reliable option get caught in the packet loss simulation (which shouldn't since the framework itself guarantees it's delivery).
Simulating actual conditions found in the Internet for the gameplay is a major concern. For this reason I've been trying to find and test different tools that simulate a WAN on a LAN. There are a couple commercial solutions that work but I'm still unable to find an open source or at least free tool that would work as expected on a windows machine. For now, I'm using a trial version of Shunra VE Desktop Standard and it looks pretty good for the purpose intended. Already tested a couple variables and the network starts to get annoying at about 200ms of latency with 10% packet loss. Still I'm yet to try other parameters for the VFC requirements so it's possible to tolerate bigger limits on the latency and packet loss.
There are other very useful properties in the XNA framework NetworkSession: BytesPerSecondSent and BytesPerSecondReceived. Using these it's possible to see the actual bandwidth used in each scenario of the game. Even with only two players it's possible to see the difference when they are close or far from each other, varying from around 1.5kBps to 250B of data sent by the server. The data received by the server is constant and shouldn't be a problem since it's about only 1kBps for each player.
Artificial Intelligence vs Repeated Input
I've been trying to think about the best solution in order to test the behavior of the game with more terminals and concurrent real players. I have two approaches in mind:
Making some basic artificial intelligence that would only chose the input and send it to the host (the same way a player would do), nothing very smart is needed, just that it keeps moving and shooting around;
Or recording the input from a game and replaying it on several machines.
I believe the first alternative is the best one since it should be quite easy, given the position on the arena to choose where I want to move and shoot. It's irrelevant whether the bots are really aiming at a target or if they are just shooting and moving around. The most important thing is that they keep moving around getting closer and further away from each other so that it is possible to observe a correct flow of the game.
Finally I got to the main implementation and use of the VFC model for the NetRumble game.
In order to keep the class as simple and separated from the specific game (Net Rumble) as possible, I used interfaces which must be implemented by the game objects that are intended to be pivots. I'm already using it on the asteroids and the player's ships.
It's working just as expected for the asteroids and the ships movement. From the first tests I did it's clearly observable the difference in the movement of asteroids and, specially, ships. Using the scale parameter to choose the area shown in each player it's possible to see the enemy ships further away and analyze their behavior depending on the consistency zone in which they are. The jumps in the positions of the ships are very frequent in the outer areas and their movement is smooth in the inner areas, where consistency requirements are tighter. The tightest area of the game should include all or most of the player's original view of the game.
There's still one issue I have to deal with in order for the game to run correctly. At this moment I'm using the ship pivot for the input and for the position. The player input includes the movement and the firing of projectiles. I need to change the way the firing is handled and create a new message type for projectiles. Then, the projectile would become a pivot and would be sent to all players accordingly.
Soon I'll try to post a video feed of the gameplay for you to observe the given behavior. I'll also now start making some tests to check how much bandwidth is used with and without the use of VFC and collect other useful information about the communication.
Well, as I said in my last post I made a new custom PacketWriter class. It's working fine and compatible with the PacketReader on the other side, by instinct since the order in which each member is written/read from the packets is not specified. It only requires one more step before beginning each packet to Reset the packet, but becomes much more flexible in terms of reuse of the same packet to send to a group of peers.
I've also done some refactoring of the code more specific to the VFC implementation: drawing of the consistency areas identification, custom packet writer, and so on. It is now packed in a different namespace.
Since I allowed the players to join the game in progress there were a couple bugs in the state of the current game when a player joined, in particular:
- he wouldn't see a power up had already been spawned - the host now checks for a power up when the player join and sends it's spawn message;
- wouldn't know about the current weapon of each of the other players (if they had caught a power up earlier) - the periodic status packet for each player now includes the current weapon he has.
Some other bug related to the change to the client-server architecture was the acceleration of the other players comparing to the host. The other players would be slower. To pass this around it is only needed to use the same direction input while another packet with new input is not received by the host. It works like a charm.
The XNA framework includes a helper class called PacketWriter. PacketWriter provides common functionality for efficiently formatting outgoing network packets. Using this class is useful when the messages are sent only to one or all the peers. Since most of the packets my host will be sending are for a group of peers, just a few of the participating players, I'll need to make my own helper class so I can choose when I want the packet to be reset, after sending it out to the desired clients.
I've done the custom packet writer class and will now make the migration and test of this new class.
Everything seems to be working fine with the new architecture in the Net Rumble game. Now all messages are sent to the Host and sent to all members through him. Although some more verifications should be done by the Host for now, most of the elements of the game are ready for the implementation of the VFC model with the Host of the game responsible to calculate all the distances between players so it's possible to know the different requirements of consistency for each players zones.
Besides that, I've added the possibility for players to join the session during the game so players can now dynamically enter and leave the game as they wish, like most of the online FPS. For that, the Host automatically sends the current state of the game to the new player joining the session. In order for players to be able to find the session the flag AllowJoinInProgress of the network session must be set to true (XNA framework).
In the last days I've been changing the game architecture in order for all requests to pass through the server. For a matter of simplicity I haven't added any security related checks in the messages sent by the players (for now...), but all update messages coming from a source other than the server are ignored.
This change hasn't been very easy because there were a lot of mixed messaging types and the identification of the player to which the data received belonged to relied only on the sender of the message. So, I had to add a way to identify the player to which an update message corresponds since all data received now comes from the server.
There is still some polishing to do in order for the game to run smoothly for all players. For now the host of the game is the only player able have a good gameplay experience.
Hope to post here some more news, hopefully of the completion, about this task during this week.
After giving it a lot of thought about the way the communication is done in NetRumble I've decided to make a big change to it's architecture. The way the different objects are handled in Net Rumble is kind of an hybrid architecture between Client-Server and Peer-to-Peer in the way that each player is responsible for analyzing and sending the message about each other ships. From the beginning, before fully analyzing Net Rumble code, I had planned to first implement VFC using Client-Server architecture and then if I had time experiment using some peer-to-peer modules.
So, for now I'll be changing the architecture to a fully centralized server one.
In VFC there is the concept of pivot, which is an element that has a virtual relative location to other elements of the game. The main elements that I will need to map with VFC in NetRumble are
For the player's ships, currently, each player is responsible for it's own ship: local player is the authority on the death of their own ship and for sending the updates to all other players.
Since ships can move along through different consistency zones I'm thinking about having the host be a central authority and notify when players change relative zones. This is probably only needed when the players are moving closer to each other since that's when we have to tighten the consistency requirements. So, in practice, the Host player will always be in the tightest zone of all other players so it can judge effectively where other players are.
The asteroids are controlled at the Host player who updates it's state and sends the information to all clients.
This should be the easiest pivot I'll have to implement since it's already centralized and all the calculus will be done at the host. I believe this is a good starting point to implement VFC in this game.
Projectiles and other input
The way the input is handled is this game might be a bit of an obstacle to the implementation of the VFC model. The input is interpreted by every participant in the game the same way, and expected to result in the same output. However, this might not be true due to latency fluctuation, lost packets, and so on. This is usually a nice approach when we are applying it to an RTS (Real-time Strategy) game because these have a tolerance for higher latency. Since NetRumble has more affinity with FPS-style (First-person shooter) I believe this problem should be solved differently.
My idea, in order to improve this too optimistic behavior, is to tag the projectiles with a game time (elapsed time), position, direction and speed (these two can be combined in speed_x and speed_y) and send it out to other players (according to VFC consistency requirements defined). Then, each player will calculate the actual position of the projectile when he receives that kind of packet depending on the speed of the projectile and direction.
Here are some screen shots of the game with the original view port and the current one (scaled to half the size).
<p>Original game play view </p> <p><a href="//lh5.ggpht.com/_6Gs1Q7vPPW0/SblymBz_Q3I/AAAAAAAAA1U/v5ZNV8GDBBw/s1600-h/NetRumble-original%5B4%5D.jpg"><img title="NetRumble-original" alt="NetRumble-original" src="//lh5.ggpht.com/_6Gs1Q7vPPW0/SblymvUJV2I/AAAAAAAAA1Y/II60gBoTqYM/NetRumble-original_thumb%5B2%5D.jpg?imgmax=800" border="0" width="244" height="196"></a> </p> <p>Zoomed out and circles added (draft)
<div>Technorati Tags: <a href="//technorati.com/tags/Screenshots" rel="tag">Screenshots</a>,<a href="//technorati.com/tags/Game+play" rel="tag">Game play</a>,<a href="//technorati.com/tags/sprite+batch" rel="tag">sprite batch</a></div> </span>