On 'Life is Strange'

A story first, skip ahead for the actual review.

Not long after the game's initial release I picked up the first episode and was immediately hooked. Played through it in a weekend, and then for a second time with different choices.

I immersed myself completely into the world and story, and it was intense. Couldn't even think about playing another episode for a whole week. It actually took well over a month before I could play the second episode.

And the second episode was even better. Now I had to take an even longer break.

When I finally resumed playing, both ep3 and ep4 were out, and ep5 just two weeks away. I tried to pace myself by just playing ep3 during one weekend, and then ep4 the next.

I failed. Ended up playing ep3 in a single day. And because it ended with such a cliffhanger I just had to play ep4 the next day.

That was a dire mistake. Now I'm broken and feel empty and hollow. Couldn't even function properly for the rest of the day(or the next).

* * *

This game is larger than life. The game's protagonist is a photographer, and through her eyes it is seen how vibrant and colorful the world actually is. The atmosphere is truly captivating and full of wonder, and the plot something unexpected.

It took a long time to quantify, but I finally figured out why the game resonated so strongly with me. My life is quite dull and boring, and immersing myself completely to the game world and its characters allowed me to break free from that grayness, and experience the full spectrum of the shades that is life.

There is also the role playing aspect. I'm normally not that social. I stick to the routine and am quite cautious on trying out new things. But the game's protagonist is social. Routine is broken by the unfolding events and that leads to trying out new things. Even the character interactions allow for experimentation thanks to the rewind ability.

This all is so much more than the gray ordinariness of (my) real life. The withdrawals from stopping playing are real and hit me hard. Combine this with an awesome plot that you can influence in a real way. Add a setting that allows to partly (re?)live what I kinda missed growing up. And finally add the very likeable protagonist, a great selection of songs and the very fitting and beautiful graphics(and not a single problem with performance).

6/5. Will play again - when I recover.

Be sure to read the second part, too.

(Also, there was a great opinion piece on PCGamer by Jody Macgregor, I highly recommend reading it.)

Plotting GPS data

Sometimes going out for just a walk isn’t that easy and some extra motivation is needed. Luckily I had just that extra: going for a walk allowed me to get some rather important real-world data for the GPS tracking service I have been working for quite some time.

During those walks I had the idea to further use the recorded data. The forest was filled with paths and I thought it’d be great to map those. And maybe even have some kind of heatmap of the most traveled routes!
Work, studies, gaming and general procrastination kept me busy, but here it finally is:

Investigating TCP timeouts

As hinted by an earlier post, one of my latest work projects was a building a WebRTC based video streaming system. This system features a Websocket backend server handling the client sessions and signaling, written in Python with Gevent. My co-worker was performing some testing and everything seemed to be working just fine. Except one point he encountered a situation, where the server insisted another client was already connected, when it clearly wasn’t. Even netstat said that the TCP connection was ‘established’.

Some Websocket client connections were arbitrarily staying open even if the browser was closed! I had just added some hooks to the server to better detect disconnected / timed-out clients and a good guess was that I had messed something up. Nope. Debugged the thing for hours but couldn’t find single bug.

That is, until I tried toggling network connections. Being a system targeted for mobile devices, one facet of testing is to check how well it works with different network connections. If the network connection was turned of while the client was connected, the server couldn’t detect that until after about ten to fifteen minutes, even though it was sending keep-alive packets every 20 seconds. Strange indeed.

But maybe it wasn’t, maybe the write call was blocking the specific greenlet? That is an easy thing to test, just dump some stack traces. But nope again. How about if I run the server via strace and try to spot the writes there? It took bit of an effort, but the strace output revealed that the write calls were performed just fine! This is starting to be most troubling…

But then a revelation; write returned EPIPE. After quite a bit of research I had finally found the reason for this behavior: TCP timeouts. Turning off the network connection really did what it did. It turned off the connection without giving the protocol stack time to say its goodbyes. The server then though the client just had a really bad connection and tried resending the queued data with an exponential delay back off per TCP spec. My math didn’t quite match, but in an old thread the total timeout was calculated to be 924.6 seconds with the default TCP parameters. This was quite close to the actual timeout observed with the server.

* * *

I sighed and changed the keep-alive protocol so that timely replies were required instead of just relying on failed writes. Now it works beautifully.

Tl;dr: TCP was just really hard trying to resend data after it detected packet loss, only giving up when about fifteen whole minutes had passed.

Investigating slow startup of a gevent-based server application

Fast iteration time is critical when developing new things, and everything is fine when the server takes half a second to start. But when that server takes ten seconds to start, that's when things get annoying. So annoying that I had no choice but to spend several hours digging around for a reason for that slowdown.

The server in question was a Python/gevent/pywsgi server kinds of which I have been using quite some time now. And this was a new problem, one I had not previously encountered before: of course I wanted to get to the bottom of this.

First I tried to place some strategic print statements here and there, but those didn't help. Next I fired up the debugger and suspended the process during the startup. Nothing low-level blocking socket creation, and gevent has happily running its event loop; can't be its fault. Gevent has always done a great job not blocking anything, so that couldn't be it. (This is where I made a 'mistake', see the last paragraph.)

I was determined that it was something low-level, so it was time bring out the big guns: API Monitor. It could log every low-level API call, and then it would just be matter of digging through them all. And there indeed was some digging to be done. Then finally I found what I was looking for. The gevent event loop really did spin as it should, but the socket began processing data only after a gethostbyaddr-call returned.

That strange character is actually FE 80 00, rest of the address not rendering as a string.


This low-lever function was taking a long time to execute, and was actually executed in another thread, communicating its results via a socket. back to the main thread. For its argument it was given a link-local IPv6 address of (the first adapter from ipconfig) Hyper-V bridge adapter. Maybe due to some kind of misconfiguration or whatever that call took an excessive amount of time.

Now that I knew what was happening I wanted to know why. Intuition brought me to gevent's socket.py wrapper, where I inserted some tracking code to its implementation of gethostbyaddr. That in turn told me that as part of creating the socket the server's environmental variables were initialized. One of these was SERVER_NAME. If it was not already set, it was resolved via getfqdn - which called gethostname and that devil-ish gethostbyaddr. Only after the server name was resolved could the socket begin accepting connections.

Now that I had the general reason I didn't want to bother myself more that I had to. As the mechanism was already there, all it took was to pass environ={'SERVER_NAME': 'whatever'} as a kwargs to WSGIServer.

* * *

Had I though a bit more before letting go of the debugger and starting the API Monitor, I would probably have though about looking at the individual greenlet stacktraces. Those would have clearly told that the getfqdn call was blocking the main server greenlet.

WebRTC primer

As a relatively new technology WebRTC is still quite unheard of even though it will likely be the next Big Thing. It offers a whole new way to create interactive peer to peer multimedia applications within a browser - without requiring any additional plugins. Support is already built-in to the newest versions of Chrome on both desktops and Android. Firefox and Opera also have WebRTC capabilities, but still have some features missing.

It's bit of a chicken-egg problem really. There is not yet widespread adaptation so development doesn't have the highest priorty, and the development is not the highest priority because there is no widespread adaptation. While I can't really do much about the APIs, I can still try and present my take on the basic WebRTC connection flow. Hopefully this helps someone to create a cool WebRTC application and thereby indirectly contributing to development priorities.

But please note that this text is written as part of a project I've been working on and is not meant to be the singular introduction to WebRTC, nor is this meant to primarily be a tutorial. If you are looking for a more thorough introduction, see the great tutorial on HTML5 Rocks. After you have read that tutorial and still feel disoriented, I hope you came back here and read what I've written. Hopefully at least my diagram will clarify something.

WebRTC connection flow

In short, to establish a connection between two peers the following needs to be done:
  • Create a signaling channel between the peers
  • Get local media, and negotiate codecs
  • Perform interactive connection establishment assisted by the signaling channel
  • And finally start streaming data
This is my take on the issue. It is not the one and only way to do things, especially with the signaling channel. But then again, signaling is not covered in the WebRTC specification even though it's a very important piece of the puzzle. The easiest way is to roll your own asynchronous server using something like python-gevent or node.js, but you could as well adapt something like SIP or XMPP for this purpose.

At the very beginning both of the clients connect to this signaling / management server and mutually agree on a session. Later they then use this session to exchange the messages necessary to build their own direct connection with the steps illustrated in the diagram 1 below(use a state machine, you'll thank yourself later). Most of the functions in the diagram refer to the WebRTC-stack but some are just to illustrate a point. Also note that some functions might fail due to user actions, and some due to timeouts. Application-defined timeouts can also occur waiting for state transitions. Finally, the traffic between the peers is the traffic via the signaling server.

Diagram 1. Basic connection flow

Reverse engineering a binary code modification of an Unity3D game

This happened a while ago, but found the time to write about this only now(no surprises there).

* * *

So, during a casual conversation it came up that a single player FPS game I used to play on Android also had an official PC version. This made me quite happy, though my joy was crushed soon after: 60 degree field of view is the recipe for instant headaches. disorientation and general discomfort.

But I won’t let that stop me! No way. Although I’m quite a noob, I’ve still had some success reverse engineering various games. The game uses Unity3d web player, so I’ll just unpack that and find some strings referencing fov, and then take a look at the code and modify that pesky 60 to a more manageable number. Not that easy. And yeah, it’s not C, but C#. That’s a whole different kind of beast with it’s execution model.

But hey, there actually seems to be a CheatEngine table on Google with fov mod! Piecing it together I was finally able to modify the fov with it. Great, I just downloaded some stuff and pressed a button. l33t hax.

* * *

So, how does that thing work? Well, I also found out that the game’s code was not obsfucated. Running the game dll through a decompiler produced lovely human readable code. And look! A camera class! And it has that pesky 60 fov hardcoded in to several places! Maybe the CE script searches for it and replaces the entries? Converting 60.0f to hex and doing some manual comparisons verified that to be the likely scenario.

Then some more reading about C# IL code etc. and comparing the bytes in the script with the IL code of the relevant camera methods. Perfect match! Indeed the CE script was searching for the camera code and replacing it with one where the hardcoded fov value was different. This also explains why the script didn’t work if a level was already loaded. The IL code was already JIT compiled to another form.

* * *

This discovery means that I can look for arbitrary code in the game, parse the IL dump with my Python script and then make the relevant changes. Then use that same CE script to replace those parts of the game’s code.

Using this new ability, I also found that pesky code that was responsible for aim assist. A few NOPs and welcome full manual aiming! Though, some time later the game received an update, breaking the aim assist disabling. I’d like to revisit that section of the code some day and see what needs to be done to fix it.

Some thoughts about the new desktop – part II

So, a new desktop and life is wonderful? Sure, maybe for a month. Then the random BSODs started to happen. Then some more BSODs, at worst daily. Long hours of analyzing minidumps, tracking possibly bad drivers, upgrading and disabling them. Reading message boards. Adjusting power settings. Adjusting voltages. Running memtests. Nothing seems to be helping and nothing helpful emerges. I’m beginning to suspect the BSODs have something to do with sleep or hibernate, but nothing conclusive as the BSODs take too long a time to get certainty about the causality. Might just as well try upgrading to Windows 8.1 now that all hope is lost.

Of course setting up a fresh OS install brings daily restarts, so the BSODs seem to be gone for a moment. But then, again, they start happening. Checking drivers once again, nothing. Well, it was as if removing Gigabyte's chipset drivers somewhat reduced the BDOSs, but they were not gone completely. Then, with heavy heart, I disabled the sleep-mode just to test it. No more BSODs.

* * *

Now, according to dump files, it’s been almost four months without a single BSODs. A hardware problem with sleep-mode RAM voltage regulation? Software issue? No idea…

Some thoughts about the new desktop – part I

So I finally did what I had been slowly planning for about two years: I upgraded my desktop computer! It’s been a couple of months now, so I’ve had time to get accustomed to it and test it in everyday use.

* * *

During the years I used my previous setup, there was one particular goal in my mind that was clearer than all the others: silence. This was due to the hideous stock cooler of the previous i7 930. Now I would be wiser and select the best the market has to offer, a Noctua NH-D14 cooling a i7 4790k. Combine that beast with a spacious, sound proofed, Fractal Design Define R4 case and a 550W XTR PSU and the result is almost total silence. The low hum of the fans can be heard, but only faintly, in a silent room, laying still in a bed about 1.5 meters from the case.

The trend of low acoustic emissions continued in the selection of the GPU: Gigabyte GTX 770 OC Windforce 3x. Three fans, but on a typical desktop/movie use-case they spin so silently that they barely add any additional noise.

But amidst all that serenity a new, and loud, problem surfaced when I connected the HDDs: the abysmal noise of the older 7200rpm 1 TB disk. I may have to replace it or move it somewhere else. For now it’s still connected but offline in disk management most of the time to prevent accidental spin-ups.

Other than that I had a sweet upgrade in the system disk. From HDD to a Samsung 840 Evo SSD. The system is now so fast! Especially in all the reboots a new system requires. Not going back to HDDs, that is for sure.

* * *

But let’s not get ahead of ourselves. The components needed to be put together first. No big deal, right? Not quite. First: it takes frighteningly large amount of force to close the CPU-socket.  And secondly: after reapplying the thermal paste for the third time and seeing 50c+ in the bios every time I started to think that maybe the thermal paste was not the real issue here. I nervously installed Windows and all the required drivers and behold: idle temps only few degrees higher than ambient. Lesson learned: don’t trust the bios to provide the correct, real-world CPU idle temps.

* * *

But that was just the beginning, only now the dark clouds of system instability are really starting to gather atop the soothing silence that is my new rig. Stay tuned for part II.

Generating a procedural planet/asteroid field

Lately I've been working with a game project where the player flies along a swarm of planetoids, placing bombs, collecting coins and dodging bad asteroids. As it would be quite dull to have a single hand-crafted map for the game, procedural content generation was required. The ultimate goal in map generation would be to create a path for the player to loosely follow. The path should have occasional obstacles but mostly it just contains lots of coins for extra score. Who wouldn't want to get a score as high as possible?

White is the main path, yellow is the obstacle option four. Read more later on.
So we need a path. And not just any path, a naturally looking path that shouldn't zigzag around too wildly. Rather, it should have small, smooth hops from one node to another. And to make the player stay on the path there should be obstacles. In theory there can be obstacles everywhere, just as long as they are not on the path. But note that complete coverage is not a necessity, as long as there is enough obstacles. There can be some open areas that function as alternative routes for the player. But how to create the path?

Proof-of-concept: energy metering with TI Stellaris Launchpad and Python

One afternoon I was trying to think of some quick and easy thing to do with my Stellaris Launchpad and remembered that for a long time I had been pondering on the possibility of semi-accurately measuring the real-time electricity consumption of a whole house. And finally I can present a raw proof-of-concept on that.

I had the MCU, but lacked a sensor. Thinking that I had an LDR tucked somewhere I searched my stashes but unfortunately all I could find was an old calculator solar cell. Might as well give it a try. Knowing practically no theory on connecting anything to MCUs I just plugged its ground to GND and + to an analog input pin via a 4k7 resistor I had lying around. And behold! After some tinkering with the code, I was able to poll meaningful light values with rather non-existent latency. See a video.

Next step: taping the solar cell to the electricity meter and hanging the Stellaris board from a nearby cloth hook. The readings were then transmitted over wi-fi to my desktop for visualization. I implemented an extremely simple pulse detector with on-off thresholds, but it required constant adjustment due to the sun. But the concept was verified, it is very possible to do real-time energy metering with high accuracy.

Maybe I’ll find time some other afternoon to make/find better (delta-based?) pulse detection algorithm and then offload it to the MCU, leaving it to only emit the actual time stamped pulses and kW/h readings.

Edit: had to try the deltas: works great.