EasyRPG Player 0.8.1.1 “Stun – Patch 1”

Woah, two EasyRPG Player releases in a single year! We decided to release a quick patch because, right after the 0.8.1 release, we noticed a serious regression: The text encoding detection for ZIP archives was broken, but only on Android and our Homebrew platforms. Most games distributed in ZIP archives use legacy encodings rather than modern Unicode (UTF-8), which require us to guess the encoding (the same technique we use to guess the game’s encoding, #3401)

While investigating this bug, we received some LZH archives that failed to load. These archives had the same encoding detection bug, as well as an additional bug that prevented some of them from loading entirely. This has now been fixed, too. (#3394)

How we broke the encoding detection

The explanation of how we broke it is a bit technical: when constructing the input text (a concatenated list of filenames in the archive) for the encoding detection, we filter out all filenames that are ASCII (characters used in English texts). All the encodings that we support are ASCII-compatible, and we found that the encoding detection became more reliable when we discarded the ASCII filenames.

We use the function isascii to check whether a input string consists only of ASCII characters.

return std::all_of(s.begin(), s.end(), [](char c) {
    return isascii(static_cast<int>(c));
});

This statements returns true when all characters (all_of) are in ASCII.

Two weeks before the 0.8.1 release, we were informed that this function was neither portable nor available on all systems. Therefore, we replaced it with:

return std::all_of(s.begin(), s.end(), [](char c) {
    // non-ascii is for signed char in range [-128, 0)
    return c >= 0;
});

Since characters have a range of [-128, 127] and ASCII has a range of [0, 127], we simply check whether the character is positive. This method worked on our computers and in the Android emulator.

Now, the breakage: We learned that char is actually not always signed, but the signedness of a char is implementation-defined. On CPU architectures other than x86 (the ones used in most desktop systems), char is usually unsigned. When char is unsigned, the range becomes [0, 255] and the above check becomes true for all characters, not just ASCII ones. As we mentioned earlier, we throw away ASCII strings and this resulted in discarding all the strings, breaking our encoding detection.

How could we have missed this serious bug? The answer is simple: We have unit tests, but these are executed on x86 machines. The Android emulator also runs on an x86 system, but we did not check it on an Android smartphone (ARM), where the bug would have been visible.

We have improved our testing infrastructure to prevent such a basic error from happening again. GitHub now offers ARM machines. We have added two of these machines with different Ubuntu versions to our testing pipeline, which will enable us to detect such hardware-dependent issues in the future. (#3404)

This urgent bugfix was the reason for the patch release, but we have even more updates for you.

Map, Events & Interpreter

In the game Genkido, it was not possible to continue because the hero could not walk on a tile that was occupied by a barrel. This was a special case: The barrel tile (which is an event) is indeed not passable. On top of the barrel tile, however, is another event tile with ID 0 (transparent default tile) which is passable. RPG Maker events can have two types of graphics: Tiles and Characters. Characters do not modify the passability of an underlying tile. Event tiles can overwrite passability (highest event ID takes precedence). The bug was in some legacy code. Originally, we assumed that events with a tile ID of 0 were characters. However, the correct check is actually that events without a character name are tiles. The collision code was still using this old check and incorrectly considered it a character. After updating the check, the event with tile ID 0 is now considered a passable tile. (#3366)

The Maniac Patch supports new terms for experience gained, levelling up, items received and skills learned. The intention is to allow for more flexibility when formatting messages in various languages. While this is inferior to the placeholder feature in RPG Maker 2000, it is still an improvement. (#3371, contributed by florianessl aka Käsekumpel)

New terms supported by Maniac Patch. Unfortunately, the superior placeholder feature from RPG Maker 2000 was not implemented.

The flags toggled by the EasyRPG Set Interpreter Flag command are now preserved in the savegame and are local to the currently running event interpreter. In the old version they were not saved and altered the behaviour of all interpreters. This was not intended, and unfortunately we did not have enough time before the 0.8.1 release to implement this properly. (#3379, contributed by florianessl aka Käsekumpel)

Cloned and destroyed map events (via EasyRPG command Clone/Destroy Map Event) were not properly restored when a savegame was loaded. Note that the fix is not perfect: The event name is not restored. This requires a new chunk in our parsing library liblcf and to make patch releases less labour-intensive, we do not update liblcf between patch releases. (#3411, contributed by florianessl aka Käsekumpel)

The String Variables debug scene now displays the name of the string variable when SHIFT is pressed. Additionally, an indicator ([J]) is displayed when the string is a JSON string used by the EasyRPG Process JSON command. When it is a JSON string, you can toggle the “Pretty Print” setting in the detail window. (#3398, contributed by florianessl aka Käsekumpel)

The debug scene showing string variables. The string view was already introduced in 0.8.1. New features: [J] indicates whether this is a JSON string (top-left). When you press SHIFT the view is expanded and displays the name of the string variable (top-right). When it is a JSON string you can pretty print it (bottom).
When a translation was active, files in the Text folder were not redirected to the translated variants. When searching for text files, the order of directories searched is: Save, Translation, Game directory. However, the Save and Game directories can be the same, except when running from an archive. In this case, we now skip the lookup in the Save directory.

Battle system

In the game Die Reise ins All, the RPG Maker 2000 battle scene would crash when a party member was removed by an event command and then attacked by a monster (because targeting happens before event commands run). The RPG Maker 2003 battle scene is unaffected, and the fix for the 2000 scene is based on it. (#3415, contributed by florianessl aka Käsekumpel)

In the game Wolfenhain, the battle animation of the boss Zyklop was not displayed correctly. This is one of the rare games that uses a flipped battle animation and uses animation cells at varying coordinates. Turns out we mirrored the image but did not invert the X-axis when rendering the cells. (#3417, contributed by florianessl aka Käsekumpel)

Settings

The settings that configure the screenshot scaling factor and turn off logging were not saved in our configuration file. (#3405, contributed by florianessl aka Käsekumpel)

Two additional screenshot settings were added: by default, screenshots now include a timestamp in the file name ( screenshot_YYYYMMDD_HHMMSS[_C], where _C is a counter that is only appended when the file already exists). This is the new default. If you do not like this, you can disable it to revert to the previous behaviour (screenshot_C).

There were requests to include the map name in the file name but we decided against it:

  • The map name is only used in the editor and may contain a useless name
  • It may contain corrupted data due to incorrect encoding
  • It must be sanitised, as not all characters are legal in filenames

The second new feature is the ability to take automatic screenshots at fixed intervals. The main motivation behind this is to collect screenshots for game preservation sites, such as RM Archiv, and to document bugs. This feature is not suitable for recording purposes (it is too slow) and is limited to one screenshot per second. (#3406, contributed by florianessl aka Käsekumpel)

Screenshots now contain a timestamp in the file name. You can also enable automatic screenshot capture at fixed intervals.

Android

We now target Android SDK 36 (Android 16). This has required us to make two changes:

  • Implementing “Edge-To-Edge”
  • Handling “Predictive back”

Edge-To-Edge was discussed in detail in our 0.8.1 blog post, so we will provide only a brief summary here. With Android SDK 35 (Android 15), the app itself is responsible for calculating the margins. This enables content to be placed under the system bar (the bar displaying icons and the time at the top), and according to Google, makes the app more immersive. We have now implemented this “feature” by manually calculating the margins. Visually, this will be the same for the user, just with more code… (#3373)

Predictive Back is a feature that displays an overlay showing where the back action will move to. This feature is enforced since SDK 36 (Android 16), and prevents reacting to the back action. Unfortunately, this results in games terminating and the input editor closing (both of which should open the sidebar when the back button is pressed). Fortunately, Google has added a new API that allows us to opt out of this behaviour for the two affected scenes. Again no visual change for the user and lost time for us we could use more productive… (#3408)

While we were at it, we also implemented a feature that our users will actually benefit from: Dark Mode. (#3408)

Finally, our users won’t go blind when they open the game browser! ;)

Consoles & More

As already explained at the beginning of this blog post, all homebrew platforms and Android had broken ZIP encoding detection.

The Playstation Vita port failed to start. This was caused by an incorrect compiler optimisation. We actually fixed this in 0.8.1 already by recompiling the VPK. It turns out that the PlayStation Vita has very limited stack space, which is used to store local variables and remember the return addresses of function calls. When developing for the Vita, it is recommended to set the fno-optimize-sibling-calls flag, as this optimisation requires a lot of stack space. We have no idea why it never crashed for us before. Maybe we were just lucky. (#3397)

The startup directory of the Flatpak can now contain whitespaces. (Packaging #19, contributed by trostboot)

Building

Now that Ubuntu 20.04 LTS is no longer supported, our baseline is the slightly newer Debian 11.

This means that the building requirements have changed.

  • CMake 3.18 (from 3.16)
  • SDL 2.0.14 (from SDL 2.0.5)

Both of them are ancient. You shouldn’t usually be affected by this change. (#3391)

Otherwise, there are no significant changes.

  • We do not do patch releases for liblcf, so it still builds against liblcf 0.8.1
  • Autotools (configure) is still deprecated and will be removed in the next major release
  • To opt in to SDL3 (the default is SDL2) invoke CMake with -DPLAYER_TARGET_PLATFORM=SDL3

Leave a Reply

Your email address will not be published. Required fields are marked *