So, it just took a bit of re-thinking to discover the issue. I had all along thought it was with the collission code, since the velocity was increasing where we collided alot… however, what I didn’t think about earlier was that there was some turning going on too!

In the code related to turning I had added a parameter to retain momentum to a certain extent in the new direction. The idea itself is harmless, but the execution I had done earlier had some (problably) floating point precision errors, resulting in velocity gains of 0.1~0.2% at times! No wonder the ships would go crazy after a while. Currently trying to solve it, I’m going to use some simple damping (which I by the way also added to the collission handling code, too, that can probably be removed now).

Something along the following seems to do the trick:

                 /// And apply some damping or it will increase.
                float dampingDueToRotation = pow(0.99854f, angularVelocity);
                dynamicEntity->physics->velocity *= dampingDueToRotation;

Might have to tweak it a bit more, but yeah, happy to solve a bug quickly after taking a break is always nice :)
Also considering adding several physics options since I guess this kind of error could potentially vary from machine to machine..? Or just fun to test out various combinations.. ^^

I don’t really feel like I’ve had much meaningful progress since the last update, but things have been done nonetheless that are worth mentioning!

Firstly, I optimized several calls to Sleep the threads, resulting in a much higher network update frequency, but also a higher CPU consumption. Secondly, I added support for selecting both player ships and level to race in, since I managed to complete a second simple test level. Thirdly, I held another testing session with the help of my friend Karl Wängberg (who lives in Skövde) again, since the distance (nearly 1000 km) makes the test feel a bit more “real” when thinking about lag than testing locally or with peers in Skellefteå.

The test went well, and playability has apparently increased to ~90% (compared to ~80% earlier), probably mostly due to the network update frequency, which increased from ca. 20~40 to 60~120 updates per second. One thing that I noticed, however, was that UDP seemingly did not activate, meaning that the test that is performed at the beginning must have failed, which in turn must have meant that all those updates were handled with TCP. How or why it failed was also not printed. This leads me to a new short-term goal: improve visualization (for the host at least) as to all network-related testing, and also enable viewing of a list of what transmission protocol is active to which peer (including average packet delay, if possible). Currently both TCP and UDP can be selected from the peer- or client-side, although UDP will only be made active if the previous tests succeeded. The second short-term goal is that  I will have to make the UDP test more robust, and also properly link its results to the visualization.

On another note, not related to networking, I added support for playing Ogg Theora (tested with Open movie project Big Buck Bunny), which I intend to try and use to visualize levels before the players get to play them, if I find the time to do it beside the networking. This also meant some restructuring for the main Ogg stream and how I’d handled Ogg Vorbis earlier, meaning that audio is currently not working until I fix that.

I still intend to add client-based prediction, but as I want to focus on the underlying structure for now, that will maybe have to wait until next week or whenever I get the UDP tools to work correctly.

Below we have a screen of the new level (which is a standard elongated Torus pretty much) and the Theora test.

Screenshot 2014-02-14 05.45.27 Screenshot 2014-02-17 09.04.43

Oh, yes, bugs… There is currently a bug in which players, when accelerating against a wall at a certain angle, gain absurd amounts of velocity boost. This bug, although funny at times, is disrupting and distracting the tests. I have sought a bit, but haven’t found the reason nor a solution yet, and hope to do so soon.

Spent half the day adding UDP, which is now working decently on localhost, and the second half dealing with a memory leak, which was due to not releasing a gl vertex array(important!) in the UI system. I also spent some time removing unneccessary sleep time in order to try and improve network latency further.

An issue I had a little while with UDP was that I had a strange 5 ~ 20 second delay on all packets. Apparently when I tried to use the regular recv function with it it only wants to read 1 datagram at a time, while my TCP-sockets that I’ve been working with so far usually have dumped all their current contents into the buffer. Easy fix by placing it a in while loop after realizing the error.

As a note on design and ports, I decided to lock host UDP port to 33002 and client UDP port to 33003. This way no communication is needed beforehand, but on the other hand it limits the amount of usable ports and also testing to a maximum of 1 client per device. This makes my total number of used ports at 4 now, in the following order:

  • 33000: TCP SIP primary communication
  • 33001: TCP Space Race communication
  • 33002: UDP Space Race host rapid communication
  • 33003: UDP Space Race client rapid communication

Screenshot as usual, added another input for the clients, so that they may request themselves if they want the host to deliver new in-game data via TCP or UDP (for testing purposes, as usual). The little I’ve tested myself hasn’t given too much (from what I can tell), and I’ll have to poke a few people for testing it again soon, maybe tomorrow.

Screenshot 2014-02-13 15.18.38

Thought I’d actually try the techniques I talked about earlier with testers, which ended up being a wise choice! Things did not work out as intended and both techniques created more or less chaos! The interpolation was slow and reacted with a 20ish second delay, while the extrapolation was jerking and kicking around in far too many ways to be comprehended sanely.

The clients were still rendered correctly at the host, and the effect on the interpolation gave a clue as to the issue. After discussing a bit with my tester he synchronized his system clock to within a few seconds of my own. Voila! He could nearly play the game! This made it perfectly clear that it was my usage of time that was the culprit, and I realized I had to create a form of game time. However, since the current time function is in use pretty much everywhere and I do not want to create more time-classes (since I think it just adds to the confusion), I added a time adjustment variable, so that it is possible to change the perception of current time. Not wanting to completely remove the availability of system time, though, it is still possible to fetch it simply by passing a ‘true’ argument to the same function.

I haven’t really posted any code in this blog yet, so I guess I can show you the declaration of said function at least:

	// Returns the current time. If true, returns unmodified machine time, if false will return synchronized time as set with SetAdjustment.
	static time_t GetCurrentTimeMs(bool machineTime = false);

MS2

Milestone 2 is here, and in addition to the above I tried tidying up a few other issues (audio, thread deadlocks, etc.) before preparing the new build. A zipped archive of the prototype is now available in the MS2 repository. Unfortunately I have not prioritized documentation nor usability, which means that it might crash or behave strangely.

To try the game, simply click on Network, then either Host Game or Join Game. By default the target IP is my computer, which I will try and run throughout the day for anyone that wants to test connecting (assuming it doesn’t crash). I’ve tested it a bit, so hopefully it’ll survive! If you want to play the game you or your friends might have to host it, since my server will probably only facilitate test-connections throughout the day.

I’ll also mention some command-line arguments that I’ve added:

  • ‘mute’, will disable all audio-playback. I opted to include some of my music which I intend to include with the game later on, but this is useful for sparing ears no matter what reason.
  • ‘networkTest’ or ‘testNetwork’, which tries to either host a new game, or if that fails tries to join a game. This is similar to running the below two command-line arguments.
  • ‘host_game’, which automatically hosts a game.
  • ‘join_game’, which automatically tries to connect to a predefined host. By default this host will be my computer since I’ve got everything set up.

Running it on Windows via Git Bash for example could look something like the following:

$ SpaceRace.exe mute join_game

If there are any uncertainties or you need help testing it, go ahead and contact me!
Below some new screenshots just to try and make it a tradition.

Screenshot 2014-02-10 09.48.19 Screenshot 2014-02-10 09.48.14

… talking about discovering issues, I just tested and realized that the chat does not work between clients. Will have to enable chat-packet re-transmission so that everyone gets them and not just the host.

Since the last post a bunch of things have been done. Some issues from the previous playtests have been fixed (like the white-sphere shield bug, it was just there for appearances’ sake anyway), a new font has been designed (yes, it actually helps if testers can read it), and UI components have been adjusted to not be interactable if they haven’t been tested fully by me.

Some pictures below.

Screenshot 2014-02-07 06.32.43_cropScreenshot 2014-02-07 07.40.46

Screenshot 2014-02-07 07.49.36Screenshot 2014-02-07 12.18.22

Interpolation works, but it’s not really enjoyable, so I haven’t gotten around to asking testers to try it yet. Think I might try and add extrapolation and investigate why it jerks around sometimes first.

Beside that I’ll probably try and polish it a bit further before monday’s MS2 deadline.

I cannot really remember much hardship these past 3-4 days, with the exception of writing my own GIMP script to be able to work with the font in a manner that doesn’t infuriate me, but that is kind of unrelated to the networking parts. Will try to throw up a new post right away the next time I solve a network-related problem.. :P

Glad to say I managed to connect my two computers over a LAN and test the game now!
It’s all still not working quite as intended (for example the connection time was far too long), but it’s a step in the right direction! :D

There have been several issues that I’ve had to deal with, and some design changes have been in order, but more of those details will come toward the end of the week, maybe as an update to this post.

Screenshot 2014-02-04 21.53.50

Post-night update:

Managed to fix some connection issues with some testing support from Aksel (cheers!), which ended up in some test sessions with up to 4 players~!

The overall response was suprisingly positive, even with a very rudimentary position-update system! The criticism was mostly due to appearance and choice of font, which is a given, but I might take a look at that once I’ve iterated a bit more, since a few more bugs appeared that might require fixing first…

Too busy enjoying the fruits of labour, I forgot to take decent screenshots of the gameplay, but I’ll try and make a copy of the prototype available for MS2 on monday. Hopefully the lobby screenshots proves my point to some extent. Synchronization delay or flow will require a video to display anyway…

Screenshot 2014-02-05 02.27.48Screenshot 2014-02-05 02.45.50

For those interested in development issues and solutions:

– The long connection delay was due to protocol suggesting to connect using IPv6 before IPv4. As I have yet to see a decent IPv6 solution (and have barely grasped IPv4) I chose to disable IPv6 connection attempts until further notice. Optionally one might just want to sort the various solutions and try IPv4 first and IPv6 later, but using IPv6 at all requires the ability to host games with the same uh… addressing scheme, which I don’t think (although I’m not sure) is available automatically? Might actually have to test that too now…

– Addresses. Earlier I thought that it might be clever for the host to inform the players (via SIP) of the addresses where the games are available. This did not work as well as I thought, since it would probably require a different approach, using static IP addresses for a public server etc.. which is not really what I had in mind.

– I had previously thought that I should place all related variables in a game state, and then use packets to manually synchronize them. Also, players should be managed in the lobby state! Now after thinking and trying some other things for a bit, it seems much wiser to use an independant entity to store and handle these, in this case the SRSession (Space Race Session). Storing and managing players in this object helps clarify which bits have to be synchronized, and also allows for switching of game states without tearing everything apart. It also allows for some packets to be handled right after they’ve been received, instead of having to post them to the active game states for reading at the next iteration. This may be a more complex solution, allowing players to be in different game states, but it allows more freedom, which is one of my main goals with the engine and my games in general, so I will try to stick to it if possible.

Sup! Glad to say that the first week has gone pretty well so far. I’ve successfully managed to implement a few basic classes for Sockets, Sessions and Packets. As I’ve mentioned earlier I want a basic SIP structure for basic communication for gathering data of available games and other types of sessions, while having specific sessions for games later on. This means that more flexibility is added, but also an added responsibility since it requires games wanting to include network functionality to have to define their own network-protocols or handling. This could of course also be done via SIP by embedding all messages in for example SIP INFO messages, but from experience that doesn’t end up working too well, and also disallows any kind of optimization later, which might/will be necessary for games.

I hadn’t really thought of this all when I started this week and threw myself into the work with Sockets, meaning I stumbled upon a “bit” of more work than I’d thought, but as I already have a decent prototype with chat working in a lobby, I’m entirely OK with it. :)

Below I’d added a few inheritance diagrams for the network classes related to the Space Race game, all or most preceded by SpaceRace or SR to know they are associated with this specific game. The diagrams for SIP look similar and have been omitted.

First we’ve got the Session class that will manage the whole gaming session, like accepting or declining new peers, as well as re-routing those messages that should be delivered to other clients. The diagram demonstrates a middle-class called GameSession which I thought might be good for storing general functionality like managing amount of players, spectators, etc.
class_space_race_session
Next we’ve got the packet-classes. Not much to say here, except that the structure is somewhat similar to SIP in the sense that it should be easy to handle the various packets. For now all packets are text-based, but that might also be subject to change later on. For optimization I might add a SendBinary() function to the SRPacket class, allowing for sending of the data by binary means instead of text-based. As it would require more work I am thinking of doing it after most main features are done, since it requires modifying or adding another packet parser that can handle identifying what packets are receiving properly.

class_s_r_packet

One issue I considered was session-specific user data. Where should it be stored? For example SIP requires knowledge of which registrations and subscriptions are active, while SpaceRace might want to know what ship the player has chosen or how long it was since the peer sent a packet/message in the Space Race-Session. I figured that the best approach would be to have each session that requires additional data will have to define their own “SessionData” structures, and that these then will be attachable to the Peer-classes.

For example consider a complex game later on that enables File-transfers, VoIP, gaming and of course SIP for base communication. In this case all peers would probably have sessionData for each of these sessions that they are involved with, and those peers that have disabled some service would just not have that attached. One advantage to having these session data stored in the Peer-class is that the sessionData can remain more-or-less untouched in the event of dis- and reconnections. Of course it would be up to the specific to the Session to reset their appropriate sessionData variables as they deem fit should any such event occur. Below we can see the two used SessionData-subclasses in use so far.

class_session_data

So, yeah. My project will pretty much consist of developing a networking solution to the game engine I’ve been working on, using the Space Race game as a test-bed.

Proposal: TCNS_Proposal_emihed-8
Initial release of the game (semi-buggy): http://aeonicgames.com/jm/space-race/releases
Facebook: https://www.facebook.com/AEonicGames

I’ve also published most of the project plan for the project already, which can be found in the MS1 link on the top right!