Transport Tycoon (Transport Tycoon) - pretty old, but still delivering, especially maniacs, the game in the genre of economic RTS./.../
There is also OpenTTD, an open product of unixoids, so that you can not be distracted from the game even in the outhouse and the metro by installing it on your device or PDA. lurkmore I can honestly say: I killed a huge amount of time playing Transport Tycoon Deluxe. Yes, I'm just a fan of this game. Therefore, when an article appeared on Habré about how the guys from mozilla ported Doom, I fired up this idea - to transfer one of my favorite games here, to the Internet. By the way, the article was scarce, but I learned the main thing - porting can be done using emscripten . From the moment of the birth of the very thought about the possibility of implementing such a project, it took at least a year (my first attempt to break on the rocks of misunderstanding). And today I hurry to make you all happy: I did it! Now you can sit behind the game in the TTD from any point connected to the Internet.
And here is the video: ')
Impatient can start playing now. Please treat with understanding if something goes wrong. This version is only being tested. The game definitely works in FF13 (recommended browser) and Chrome (ium). I hope my slow server can handle the load. And yes, I know about pink tiles, I'm working on it.
OpenTTD
I want to say a few words about the project OpenTTD, which has become a donor of the source code for the JavaScript version. The project includes, according to general estimates, about 300,000 lines of C ++ code. Moreover, the possibilities of the project are amazing. Judge for yourself:
Four graphics subsystems (drivers)
Five sound drivers
little / big-endian
At the source code level, the possibility of single-threaded and multi-threaded execution is supported.
Work in the network environment (download graphic and music sets from the network) and without it
Multiplayer game
Compressing save files with lzma
Caching rendering
Animation of tiles through the rotation of the color palette
Most of the code is written with a twinkle, creatively. It was very interesting to delve into the guts of this project. Unfortunately, one has to pay for such omnivorousness, and in this case I ran into a monstrous assembly system. I had to write a perl script that automates the patching of OpenTTD makefiles for porting.
OpenTTD port managed in the following configuration:
single-flow mode
little-endian
completely disabled network capabilities
Video Driver - Patched SDL
self-written sound driver
patched mechanism for saving games on the server
patched game resource locator
The rest is the default.
Emscipten
Over porting code emscripten conjured, and I conjured over him, so that he could digest this lump. Developing my previous article , I will describe how this esoteric technology works.
The idea is simple: C ++ code is compiled into LLVM bytecode using clang . The byte code is in turn compiled into JavaScript using emscripten. LLVM bytecode is an intermediate code that can run on a low-level virtual machine. The LLVM bytecode specifications are well documented and this is one of the reasons why it was chosen by the authors of the project as an intermediate presentation of the code. The emscripten compiler tries to convert bytecode instructions into one-to-one JavaScript code, as in the figure below (byte code on the left, corresponding to the right of JavaScript).
For most instructions, this scheme works fine. However, it cannot be said that developing such a compiler is an easy task. LLVM bytecode and javascript vary greatly. To implement more complex things (pointer arithmetic, cycles, error handling), additional work has to be done. Here is a simple example of the different behaviors of C ++ and JavaScript.
Performing a division in C ++ will result in a drop of the fractional part of the number. To get the same functionality in JavaScript, you have to resort to tricks like Math.floor (the code is not correct for all cases, it is true for most).
A more complex example is the implementation of a loop in LLVM bytecode and JavaScript:
Implementing similar functionality in JavaScript can be done in numerous ways, but many of them will be poorly productive, and here the task of emscripten is to generate the most efficient code.
In addition to these low-level things, emscripten provides implementations for: libc, libcxx, POSIX, SDL, GL, GLES, and other libraries. Fully implemented file subsystem C (fopen, fclose, fread, ...). Most programs can be compiled using emscripten without any problems. The beauty of the emscripten ideology is that there is no need to edit the source code - it will work that way. In this case, in the case of successful porting of a project to JavaScript, the transition from version to version is carried out easily and naturally. For example, while I sawed emscripten, the community managed to release the next minor version of OpenTTD, I simply synchronized the sources and got the latest port of the latest version, conveniently.
Transport Tycoon Deluxe
Using emscripten in JavaScript, a sufficiently large number of serious projects have already been compiled: Doom, zlib, Poppler, OpenJPEG, FreeType, Bullet, SQLite, Python, Ruby, Lua and others. Now in the emscripten discussion group there is an active Fortran compilation discussion.
However, in order to successfully compile a complex project, you need C ++ knowledge. Here, for example, what result did I get at the first successful compilation of OpenTTD.
In this version, neither the mouse nor the keyboard worked. Only here is the image and all.
The emscripten authors declare support for a large number of libraries, but this support is not fully implemented. For example, emscripten implements only a small subset of SDL 2.0 with an admixture of SDL 1.2. Accordingly, I was faced with the lack of necessary functions in emscripten, and I had to implement them myself. But I became one of the committers of the project ( ChSV !!! ).
The problem captured in the screenshot above was caused by the fact that the SDL 1.2 implementation in emscripten supported only 32-bit surfaces and did not know anything about the SDL_HWPALLETE flag. The image in SDL_HWPALLETE mode is encoded by eight bits (256 colors). This is what is connected with the image compression. Why it is reflected horizontally to me is not clear until now. In addition, I had to implement the following functions: SDL_VideoModeOK, SDL_VideoDriverName, SDL_QuitSubSystem and strndump. I have identified a serious performance problem that was reported to the authors and they fixed it. Unfortunately, my audio subsystem edits are not included in the emscripten code base at the moment.
Many problems have been identified with the emscripten optimization flags. The pink tiles that you see in the video are problems of optimization - without flags, they are the right color. It is very difficult to deal with problems of this kind. The problem itself is irresponsible (only water tiles are pink with an inclination of 45 degrees in two directions) and porting with optimizations turned on takes a very long time (more than 2 hours), so you often don’t test it. But it delivers that the project is developing quite quickly, bugs are closed within a day or two (mine, at least).
In general, porting a complex project using emscripten can, if you really want. In any case, you will have to face the need to make minor changes to emscripten or to the project itself. But, having coped once, you can repeat the porting over and over again without any problems.
It's terribly slow isn't it?
Alon Zakai (the author of the project), speaking at the conference with a report on emscripten, expressed the opinion that JavaScript itself is fast enough and the bottleneck is the compiler and its not always optimal code conversions. He cited the following sign:
SpiderMonker (SM) is a Firefox JavaScript engine; Typed Arrays (TA) is currently the fastest way to emulate heaps in JavaScript, which is provided by emscripten. In the cells of the table, the numbers indicate how many times the execution of the code compiled in JavaScript turned out to be slower than the native code. The scatter, as we see, from one to eight times (although the average is somewhere around 3-5).
The numbers in the figure below show how many times a particular language is slower than C ++ in the test suite http://shootout.alioth.debian.org/ . (note: This information is already quite outdated and aims to show that JavaScript is a fast language. If anyone disagrees with this, please speak, and let's not touch other languages - they probably already have other numbers in these tests.)
In general, I agree with these figures and say that the JavaScript version of OpenTTD works about 5-7 times slower than the native one. But only in the FireFox browser. And this is the most amazing moment that I discovered for myself. I was developing c nodejs + chromium. I myself am a fan of FF, but unfortunately, the debug versions of JavaScript OpenTTD were the size of fifty megabytes and hung FF tightly, while the chromium worked very fast. I thought chromium on the wave, but suddenly it turned out that the release version works non-illusory faster in FF (2-3 times) than in chromium. Therefore, I recommend everyone to play using FireFox.
I am very glad that I took up the project and brought it to completion. I learned a lot about clang, llvm, python and javascript. Talked to interesting people. The community really liked my project, the authors recently added it to the emscripten demonstration projects page. I received great satisfaction from the work done. In general, I wish you all.