The project is approaching its deadline and MS3 with its related presentations and deliveries is to be held on Friday.
I have decided to stop working on the application and begin working on the report. The draft can be viewed in the MS3 repository, or by saving this link here. Any feedback is welcome! The draft will probably be continually updated until Friday at least.
As it seems to be customary, I’ve been sick a few days again, but it doesn’t seem to have affected too much this time around. I would have wanted to get more done, and I should probably have performed some more tests, but I feel that the project has gone on long enough now and that shifting to gathering all ideas and putting them into the report will be a good change of pace.
Might update this entry if I recall anything else later on, but if not I’ll just keep on typing ~
So, I just got some help from my pal Karl to test the game again. The tests were mostly to compare the new implementations of the interpolation/extrapolation and extrapolation with collision correction, but also to see if there were any apparent differences between TCP and UDP when using the respective techniques. Results can be seen in the form of sloppy notes here.
I’ve also made available a .ZIP archive of the game so that you may download and try it for yourself! Download it here.
As I might have mentioned earlier, I’ve moved my handling of the source onto github, and thusly also created the new page View the source in case you are interested in the code and underlying structure of how I’ve implemented it all.
EDIT: Just compiled a decent linux build (tested on 2 debian machines), and also updated the download .zip, so it should work for you linux-users too!
– I’ve added a new somewhat working extrapolation mode featuring collision-correction. It seems to be doing something, but it behaves a bit jerkily (which I had anticipated to some degree). The question is if it’s possible to improve it much more. I doubt it, but might look into it at least a day or two again.
– Added a proper new minimum update setting for the host, which sets minimum amount of milliseconds between each position-update. Using this I then tried out all modes I’ve been working on and noticed some more .. issues, or rather inherent requirements to my implementations which I was not entirely aware of before. For example both the Interpolation and Extrapolation will NOT work/look good if the synchronization delay is within a certain range. For Interpolation it should be positive or at least above the minimum update delay of the host. Similarly but inverted for Extrapolation, the sync delay has to be negative or at least below the minimum update delay of the host.
For a concrete example using Extrapolation consider the following:
– The Host has set minimum update delay to 200 ms, meaning we should get on average 5 updates per second.
– The time adjustment is set automatically on the client to -54 ms (This game-time concept has made me more confused than it probably should, not sure if it’s affecting anything really as this is just a visible indicator of a change it has done, not anything dynamic).
– Recommended sync delay (which in this case translates to the time we want to estimate in the future) should thus be around -200 or below for the extrapolation to work decently. With a sync delay of >200 ms it will detect a mismatch and only display static updates. At 150 ms the static updates will have a few extrapolation updates mixed in, giving erratic camera movment. The lower you go, the worse it gets, and at 0 ms delay the camera jumps each other frame. At -50 ms the algorithm manages to arrive at infinite numbers, requiring a hard reset in the code (which I added after discovering it now). Naturally that also means that the camera is rendered useless, trying to follow a player the estimator thinks is waaaaaaaay off from the map and all relevant entities/game content. -100 and -150 yield similarly unusable or erratic results, and only when reaching -200 does the camera and player entity return to where they should have been (after a few seconds of “correction”. Using a value of -200 causes visual artifacts and if lowering the value even more the errors will become even more obvious, but the movements also become a bit smoother.
A similar description of the above is also valid for the interpolation, except that the errors are not nearly that dramatic, but still not pleasant, and the interval is instead around 0 for static movment up to full interpolation at a sync delay of around 200.
Not sure if that made sense, but it serves its purpose of me documenting the tests anyway. Next up I will look through my plan and start evaluating what I’ve done so far vs. initial expectations, try and do some tests with simulated distance/lag and maybe try and investigate if I should try to improve the collision-correction or not (scoping issue, really). Anyway, I feel that I’m slowly starting to really understand what I’m working with. Have had a bit of a hard time keeping track of all numbers I threw in for the quick iterations, and some are maybe not used anymore (like the “Extrapolation smoothing duration” I had earlier with the erroneous previous solution).
Due to the last post, I wrote a unit test for the function and class in question, which made the errors painfully obvious, as can be seen here. I really should have gone this approach when we first noticed apparent bugs with the extrapolation, but I never thought it would be such a major design flaw.
Anyway, I figured the old code was not really usable, so I took and inspired myself from the picture I had devised for my initial presentation for how one could solve extrapolation and wrote new code, which seems to work as it should. Test results for the new code can be seen here.
The solution I use now uses a base vector for the extrapolation, which is set every time a new state is inserted into the Estimator object. Using this base and an estimated velocity (based on previous values), new estimations can be made. The trick when setting the estimated velocity is to take into consideration both the differences between the two latest inputs (the distance which would have been used for e.g. interpolation) but also the difference between our current/last estimation and the new input (which kind of symbolizes our error offset). It’s not a perfect solution, but it works, which the previous solution did NOT.
Next up is client-simulation in some form…
And because pictures are nice, a small update of the new level and ship that Andreas has made! Had to re-write the ObjLoader (last touched in 2013-07) for some reason because it failed to read the ship, but eh, yeah! :)
Decided to move my project source onto GitHub, so it is now publicly available for viewing:
After messing around with a new project, updating camera system and throwing in some improved synchronization of strings in the GUI, I realized that my little Estimator-class which handles all inter- and extrapolation was not working quite as intended.
The estimator classes are planned to have a cyclic array of states, where each state contains a vector (e.g. a position) and a timestamp. The thing with cyclic arrays is that when you reach the end, you are supposed to just restart from index 0. I had stupidly enough forgotten to mark a little boolean required for this to take effect properly (there were some other issues too, like which index to start at). Anyway, with that fixed both the static updates and Interpolation are now rid of the random off-frame issue which was one things I noted in the last playtest, but at that time attributed it to the testing software.
The extrapolator, however, requires even more work. I had been naive enough to think that just estimating a position would be enough. Or, well, I had some kind of interpolation/smoothing between the estimated values. The only issue was that the smoothing was poorly constructed and not working in the slightest bit as intended… Currently trying to add another interpolator for the estimated values, which I think should solve the problem…
Since I was unsure about if I had done UDP right, I wanted to get hold of a good testing tool. Got linked this little awesome tool by Johannes (cheers!) that seems to be exactly what I’ve been looking for!
All tests were conducted using two clients on localhost, and applying all settings on all ipv4 sockets, both inbound and outbound.
Results are a available here as a raw .txt file since I cba to format it in html for now. Further tests will probably end up in the same directory later on, so I might add a link to it on the right below the MS links.
TL;DR of the tests is that UDP is working significantly better than TCP using certain options, proving that the implementation is working to some degree.
The tests also made a point that client simulation and control is needed to overcome the greater network issues.
Is pretty much what I’ve been working on for a bit. I want to clean it up, add some more options and also focus on synchronization of all numbers. So, some things I intend to sync that aren’t working yet:
- Max players
- Player position in the race (e.g: 3/8)
- Player checkpoints passed
- Player velocity (rendered text, that is)
- Score-board throughout the race but also at the race’s end (was mismatched earlier and currently does not function at all)
Besides that I kind of want to go in and add more variables for tweaking like a proper adjuster for gravity, friction and restitution, physical damping of various sorts and maybe lighting. We’ll see how it goes. I still haven’t really thought of any good method to synchronize attributes automatically, but have also begun to wonder if you ever would want that. Usually you will always have to optimize in the end and make sure that you only send what you need to for your application’s needs.
Some other things I did earlier that I might have forgot to mention was adding/incorporating a PreferencesManager I developed in the previous lab, and enabled it to save and load some basic audio attributes like audio enabled/disabled and also volume. Network preferences could be stored in a similar fashion, but I don’t feel like adding them there just yet, what with all rapid iterations.
I redid the Ogg Vorbis streaming which I had disabled, which now supports pretty much perfect looping, and because of that also got inspired and threw together a simple music player with support for sleep fade-in/fade-out. I am considering trying to throw in support for network therein, either to be able to request playback of music or stream from/to it. If not soon I might look into that after this project has ended instead.
Now some screenshots from the latest in linux development, first one which I failed to upload to the last blogpost, second one from today’s reworkings (mostly code, but there is slight changes in the visuals too) and the third one is a screen from the music player I began to create this weekend (screenshot taken in windows).
On a side note I also took some time yesterday to work on the third (or rather, second) game project, RuneRPG. There I am also working on the UI system (since it’s still under development), but I can say that it’s starting to feel real good now that some things just work automagically (i.e, how I want them to, straight away).
Oh, and yeah. The CMakeLists file I had been using earlier actually got improved to support multiple project just a few days ago (I had been using bothersome #ifdef’s earlier in the code…), which kind of triggered or at least enabled me to start working on the other two projects. :)
Also not directly related to networking, but the audio (OpenAL) doesn’t seem to work in my usage of it on Linux (at least not on the computer I am currently testing). Not sure if I should put any effort in there, since I’ve got enough to do as it is.
Just a brief update. I took a few hours to make sure the Linux-version of the game works, but it will need some more testing. Also held a testing session for UDP, which when working didn’t seem to differ much from the TCP solution. This actually puzzles me, and means that I might have to re-think a bit, if I’m testing things right or what. Anyway, my next course of action is to improve gameplay in general, properly sync and send messages for passing checkpoints, and after that start looking at client-side physical simulation, in order to remove any apparent lag (if possible).
Apparently my UDP solution wasn’t working earlier (which I kind of noticed, but still not). I had refused to completely use recvfrom and sendto, which seemed to bind the sockets in a TCP-like fashion, and the UDP test was also not working as intended. Both of these seem to have been resolved now, and I think I noticed slight improvements with using UDP even on localhost (when spamming >100 updates per second, totalling to around 45kb/s in bandwidth).
Along with this I improved the UI system a bit more, so that I can now compile and insert complete UI interfaces or elements from other files wherever I want. So if you want to look at how many packets the UDP test has sent and received you can just press “U” in any game state and it will be pushed to the top of the UI stack (exit with ESC or right mouse button).
Beside that I have taken some time off, during which I’ve managed to create some new music to that game too. I’ll have to take a day or two to re-implement the Vorbis stream again which I left broken after Theora was added.