I worked on a few improvements for the battlegame thing – quite a few actually.
Clientside position inter- and extrapolation and smoothing
One of the most important things was to make the interpolation work to counter lags. This seemed to be a complicated issue but turned out to be solved quite easily when not trying to make it “perfect”. First the facts: The simulation runs at 20 fps on the server, thus I receive one message every 5ms in a perfect network environment. The client runs with a framerate of about 60 frames per second.
However, due to the network traffic and network buffering (which I have not full control on in flash and I don’t know how flash deals with it), the network packages come in in intervals of 0-20ms. AS3 supports only TCP connections. On the upside, this means that it’s quite stable and there’s no packet loss. On the downside, if a packet is lost, the client (or server) tells the other side to resend it – and that costs plenty of time. Meanwhile, many more packets arrive – but I can’t receive them as the OS holds them back until the lost package was received. And then it flushes the whole buffer at once. This behavior is highly undesirable when dealing with fast paced games – which is why I thought a battle ship game with slow controls is better suited for this kind of network technology.
The solution to the lagging when representing the actual scene of received data instantly is to inter- and extrapolate values next to smoothing the final results. What sounds complex is actually really pretty simple: When a ship moves, I calculate the current velocity and angular velocity from the previously received data. I could also include movement speed, but that isn’t really needed since velocities don’t change so quickly. I decided to let the client lag by 5ms compared to the server simulation, so when receiving the state from the server, I don’t move the ships instantly to the “new” positions, but I interpolate the position for the next 5 ms. When the 5ms are over and I haven’t received new data, I extrapolate the position from the known velocity. Both, inter- and extrapolation are however one single term: position + velocity*time_fraction – where time_fraction is a value between 0 and 1 for the 5ms intervals. When no new data is received, I simply let the time_fraction go on to higher values, effectively extrapolating the position of the ship on the server.
If I would do only that, the ship would jump whenever a network delay is corrected since the extrapolation isn’t showing the correct solution. To prevent visual lags from happening, I simply smooth move the ship only for a fraction towards the interpolated values (which can change suddenly when receiving a delayed package). So the actual formula is
screen_position = screen_position*.7 + .3*(position + velocity*time_fraction).
The values .7 and .3 are chosen pretty randomly – for these numbers, sudden movement changes will get smoothed over 3-4 frames until a relatively close screen position is reached (close to the actual position).
So nothing fancy and actually not applicable for faster games, but fine for this one. Oh, and the cannon balls are simulated on the client side from knowing the shot’s origin and the speed at that time.
Extended statistics
I extended the statistics I am gathering. I track now the amount of incoming and outgoing data and also log certain events (coming, going and sinking of ships). This was actually much more work than anticipated – I am using sqlite as database backend and Lua as the server side language. Since I do not use threading on the server, database access would introduce too much delays. So I needed to come up with something more fancy than simple query execution inside the game logic. Oh boy, this took a while…
After having found out that the db access is introducing lags, I thought about using Lua lanes, a multithreading library for Lua. But then again, I didn’t want to add more libraries on top of my requirements. So I decided that I “simply” start a second process using io.popen and communicate with it through stdin and stdout. There were a few shortcomings to that and I finally ended up with one process that listens on a tcp port for sql execution statements. The game process sends data in batched packages to the database socket and doesn’t wait for it’s completion. There’s a fair chance of data loss when something goes wrong, but for this kind of data (statistics), it’s quite unimportant… so it’s sort of acceptable.
Webfrontend
To have a simple way to look up the stats, I wrote a small webservice that presents the current statistics. It’s listening on port 9293, so if you follow the link, you can see the current stats.
So what’s next? I think I want to add a bot that provides a challenge when other players aren’t available.