Town::cargo_accepted, Town::cargo_produced saveload and consistency issues #7603
Version of OpenTTD
Town::cargo_accepted is a TileMatrix with a 2x2 grid, of data type CargoTypes (i.e. uint64).
The 3 argument form of UpdateTownCargoes calculates the acceptance of each 2x2 square using an area up to 6x6 as returned by AcceptanceMatrix::GetAreaForTile with extent 1.
In the case where a house is removed (in ClearTownHouse), the 2x2 square in which the northernmost house tile is, is updated by use of the 3 argument form of UpdateTownCargoes.
In the case where the last house which accepts a particular cargo is removed, adjacent 2x2 squares can incorrectly retain the acceptance bit for that cargo, such that Town::cargo_accepted_total has the bit incorrectly set (see UpdateTownCargoTotal). This is used in subsidy generation.
UpdateTownCargoes is called both monthly (from TownsMonthlyLoop), and at load (as described above). In the case where Town::cargo_accepted/Town::cargo_accepted_total has become incorrect since the last TownsMonthlyLoop, and this a multiplayer server, if a new client joins it will recalculate Town::cargo_accepted and Town::cargo_accepted_total immediately with different values from those on the server, and this creates an opportunity for multiplayer desyncs.
Town::cargo_produced is also used in subsidy generation. It is added to from the 3 argument form of UpdateTownCargoes which is called on house add/remove, but removals are only made monthly or on load/join. In the event where the last house which produces a particular cargo is removed between a call to TownsMonthlyLoop and a multiplayer client join, the client and server would have differing values for Town::cargo_produced, and this also creates an opportunity for multiplayer desyncs.
What is the rationale for using a TileMatrix of bitmasks for acceptance and a single bitmask for production?
The acceptance and production of a house may be defined by means of NewGRF callbacks. If the results of the callbacks differ between the start the month and mid-month when a multiplayer client joins, this could also result in a multiplayer desync for the same reason as above.
Less importantly, enabling desync logging results in UpdateTownCargoes being called periodically from CheckCaches via RebuildTownCaches, however Town::cargo_accepted, Town::cargo_accepted_total and Town::cargo_produced are not among the variables which are checked for changes, and the old values are not restored. Consequently enabling desync logging masks the problem rather than highlighting it.
The text was updated successfully, but these errors were encountered:
There are unresolved desync issues at present, and this could be an area of interest for investigation.
These are not directly rebasable but could point to potentially interesting areas of the code to look into for debugging:
I will see if I can tidy all this up at some point.
In 11ab3c4 the number of cargo types was changed from 32 to 64. The save/load of Town::cargo_accepted was not updated, such that only half of the data structure is saved/loaded in savegame versions 199 to 218. Discard and regenerate data from all savegame versions prior to 219. Partially fixes: OpenTTD#7603
In 11ab3c4 the number of cargo types was changed from 32 to 64. The save/load of Town::cargo_accepted was not updated, such that only half of the data structure is saved/loaded in savegame versions 199 to 218. Discard and regenerate data from all savegame versions prior to 219. Partial fix for: OpenTTD#7603