Skip to content

Dev Log · Anpfiff1, Update, Measuring, Saves

Anpfiff1 2.2.1: three seconds less standstill and statistics that add up

20 to 27 September 2026:

Since 27 September, Anpfiff1 2.2.1 has been on Google Play, Steam and itch.io, and since 28 September on the App Store too. It is an optimisation patch, and this time without a feature you could advertise. It rests on two audit passes over the whole code, every finding checked individually before it made the list. Nearly all of it can be backed with a number.

Measure first, touch later

Before the first change, each of the 148 test scenes ran three times on its own, and the result is fixed as the starting point: green, red, flaky or hangs. After that, one rule applies to every step: no scene gets worse, and the red list only gets shorter. Whoever touches cups or tables lets the finance checks run along.

Then comes the mandatory check on real saves. No step may make an existing save impossible to load.

Three seconds of standstill after every week

The automatic save after every match week stopped the game on a PC for a good 3 seconds, with a fresh career. On a phone it is a multiple of that. Now a background process writes the file, a small "Saving…" notice appears, and input is locked meanwhile so the save stays consistent.

A counter makes sure a faster, explicit save overtakes the running background save and is not overwritten by it. A dedicated scene checks that, eight out of eight cases pass.

More timings, each measured before and after:

  • Career start: the player lists load in parallel, 3.9 down to 1.9 seconds, with a bit-identical result.
  • First interview after a matchday: the data is preloaded in the background, from 1,054 milliseconds to 0.
  • Typeface: Chinese, Japanese and Korean used to share one typeface with Japanese letter shapes. Each language now has its own, 13 instead of 19 MB together.

What was measured and then not built

One lever was planned to speed up the background simulation: skip empty minutes. So 200 matches were profiled, 27.5 milliseconds per match. The time sits elsewhere:

  • Chances including their events: 36 percent
  • Setting up the match: 24 percent
  • Checking the AI substitutions: 15 percent
  • Discipline: 11 percent

Thanks to a random draw moved forward, empty minutes now cost almost nothing. The lever would have brought less than 5 percent and shifted the random sequence in return, that is the results. It is dropped. So is an interview file per language: 49 times 0.9 MB would have been 45 MB instead of 11.

One source for the statistics

The inventory was quite something:

  • two separate stores for match reports, with different field names for the same thing
  • five places building match identifiers, in about ten formats altogether
  • around 50 places in 12 files walking through the reports directly
  • around 20 side counters counting on their own, six of them never read

That is where the bugs players had reported came from: own goals for the scorer, yellow-red as red, substitutes as starters.

Now every match has one identifier, one report lies under it, and every statistic asks a single point of contact. A checking tool finds direct access, 75 before, 0 now. Measured on a whole season of all countries (7,867 reports), it costs 4.4 MB of memory and 1.4 MB in the save, and seven counters disappear. A compact storage format was not needed at all.

Saves from 2.2.0 stay loadable, and the other way round too: a save written with the new counting opens in the old version. There was a single gap. 2.2.0 reads the card counters without checking, and an empty field threw a script error on every card, 79 in four weeks. So the rebuild keeps writing the old scaffold alongside.

Carry on after loading as before

A number that only reports changes says nothing about errors. So a stricter rule applies: after loading, the game has to carry on exactly as it would without loading. It is checked with the same random seed, once with loading and once without, and afterwards both recordings must be equal.

That found five save bugs:

  • Youth and medical costs were only saved for your own club. After every load, 591 clubs paid no medical costs and 104 no youth costs, with more money and different transfers as a result.
  • The All-Time Table cleaned up after every load and took every relegated club's top-flight history.
  • Historical tables came back as decimals, 5338 turned into 5338.0.
  • The rating screen at the end of a season was a list of empty entries after loading.
  • The promotion and relegation screen showed no promoted clubs.

As a cross-check, eight real saves were loaded and played, from seasons 1 to 10 and seven countries, without errors. On the side it turned out that the tests ran a different sequence than the game: career start and pre-season lived only in screens. Now screen and test call the same functions.

Two things players had reported

Crests. 654 of 1,771 clubs wore a crest that looked like another club's, mostly after the new countries. Now it is 1,771 of 1,771, all different. Not a single kit changed in the process, and running saves keep their crests.

Commentary and match situation. No more offside after a throw-in, no thinly filled stands at 150,000 spectators, no snow in South America, no "straight red" for a second yellow. The crowd line had lost its number before kick-off and calculated with 0. It is a long list of small contradictions, each one reproduced individually.

Security and privacy

  • A tampered save with embedded program code is never executed.
  • Purchases on Google are checked against the app's licence key, and the purchase record is sealed. Content already bought stays.
  • Ads only appear after consent.
  • Every device signs in to the cloud with a secret of its own. The identifier alone is no longer enough.
  • The server has been hardened since 23 September.
  • "Delete account" honestly says whether the online data was deleted as well.

Under the hood

366 unused functions with about 5,850 lines are removed, the version now lives in a single place, and the Godot editor stays open during builds because builds only end their own process.

What deliberately stays open

Arabic now runs from right to left. 13 screens tied to background pictures deliberately stay unmirrored, their texts still run from right to left.

A patch in which almost nothing feels different except what used to stutter is a successful one.

Warm regards from the workshopDigitale Manufaktur Rudolstadt