Skip max_pollution_to_restore_trees in 2.1.18+ exchange strings (#1132)

Factorio 2.1.18 removed PollutionSettings::max_pollution_to_restore_trees,
but readPollution still read it for every version, so every map setting
after it was read 9 bytes late: enemy_attack_pollution_consumption_modifier
came out as garbage, the enemy_evolution factors shifted by one field and
enemy_expansion.enabled and both expansion distances came out null.

Read the field only for strings older than 2.1.18. Add modified_v2_1_17
and modified_v2_1_18 fixtures generated with headless 2.1.17 and 2.1.18
from the modified 2.1 settings (base game only), unit tests asserting
their full decoded output, and use the 2.1.18 string for the
load-scenario integration test on 2.1.18 and later.

Fixes #1131

Co-authored-by: ColumbusLabs <287001685+ColumbusLabs@users.noreply.github.com>
Co-authored-by: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-10-22 17:22:09 +01:00
1 parent 5d7ecff418
commit c3abf27266
5 files changed
+67 -2

No files matched your search

+3 -1
View File
@@ -239,7 +239,9 @@ function readPollution(state: MapReaderState) {
pollution_with_max_forest_damage: readOptional(state, readDouble),
pollution_per_tree_damage: readOptional(state, readDouble),
pollution_restored_per_tree_damage: readOptional(state, readDouble),
max_pollution_to_restore_trees: readOptional(state, readDouble),
...state.versionAtLeast(2, 1, 18) ? {} : {
max_pollution_to_restore_trees: readOptional(state, readDouble), // removed v2.1.18
},
enemy_attack_pollution_consumption_modifier: readOptional(state, readDouble),
};
}
+4 -1
View File
@@ -1289,8 +1289,11 @@ describe("Integration of Clusterio", function() {
const isV2 = version > lib.integerPartialVersion("2.0");
const isV2_1 = version > lib.integerPartialVersion("2.1");
const isV2_1_13 = version >= lib.integerPartialVersion("2.1.13");
const isV2_1_18 = version >= lib.integerPartialVersion("2.1.18");
let exchangeString = testStrings.modified;
if (isV2_1_13) {
if (isV2_1_18) {
exchangeString = testStrings.modified_v2_1_18;
} else if (isV2_1_13) {
exchangeString = testStrings.modified_v2_1_13;
} else if (isV2_1) {
exchangeString = testStrings.modified_v2_1;
+20
View File
@@ -78,6 +78,26 @@ describe("lib/factorio/exchange_string", function() {
});
});
it("should parse v2.1.17 strings", function() {
assert.deepEqual(lib.readMapExchangeString(testStrings.modified_v2_1_17), {
version: [2, 1, 17, 0],
unknown: 0,
map_gen_settings: testSettings.modified_v2_1_map_gen_settings,
map_settings: testSettings.modified_v2_1_13_map_settings,
checksum: 1073352633,
});
});
it("should parse post v2.1.18 strings", function() {
assert.deepEqual(lib.readMapExchangeString(testStrings.modified_v2_1_18), {
version: [2, 1, 18, 4],
unknown: 0,
map_gen_settings: testSettings.modified_v2_1_map_gen_settings,
map_settings: testSettings.modified_v2_1_18_map_settings,
checksum: 1437579271,
});
});
it("should handle malformed strings", function() {
assert.throws(
() => lib.readMapExchangeString("<<blah>>"),
+8
View File
@@ -622,6 +622,14 @@ export const modified_v2_1_13_map_settings = {
},
};
export const modified_v2_1_18_map_settings = {
...modified_v2_1_13_map_settings,
"pollution": Object.fromEntries(
Object.entries(modified_v2_1_13_map_settings.pollution)
.filter(([key]) => key !== "max_pollution_to_restore_trees")
),
};
export const modified_space_age_map_gen_settings = {
autoplace_controls: {
"aquilo_crude_oil": { frequency: 1, size: 1, richness: 1 },
+32
View File
@@ -100,3 +100,35 @@ JYkZpmFakZGd1AkjtxhSQjYziizPKvHmmTPmUDWuYoiVKOgP57RB9yS
0Dvo1NMEfJJWw1i+YLmuywM1C1jwbPKaGnjffEMETl1yE9Qxu/9C7rp
u3nVP+RQebGLpzeY4SxwbkUKGDDtjU/J9P3/nrIfNHXdPAWgFF7JHkZ
0L+YLmXPjcc3XoAz1D69BVjk1sULxb83nuUA<<<`;
export const modified_v2_1_17 = `
>>>eNp1U89rE0EUftMmNYnVRoiCIjWHHkRICNFTkezoRTx4ELxKnGwm
unS7087uVqsHc/DgQRCkF73o1YpexIO3gBd7k/oPVOrB3lopUkSI8zI
7kzXBB+/x7fd+v2EngMAxUDKdcQXzAbqO0YIrlpa4rAjJld/SeVfGbV
4Rnp9iaYEHfHG10mIhBlOA3sCV86QIdIWerTAdsHjFC5uu73U66Y5ZK
dyFMM2cCCMmIy+43WSSs+ai8MIoxmqppDASQdI0YSLJefhmfd1R2kDm
cCxZ4MWLepIu8jryLou4xD1MJJD3P29udB/NAmr/IZT7fVSFtlQcKpC
ujiaKTCRbdEUQSeHPs/jefMtjYb5Sq9ZrKMfTro7kyzEP3NVcvVr712
2WG0k/NeYf1qhVzw8kz32+wiJPBDMWNX22wMNscmQoX1J62R6OEPKg9
O7Kt/trDtErVGkCDhKm1zLM1QQ8e0v/58oYF1wwYNdRTfbubD/+cLDf
IH9e721ea91yyI3vxeXw3E5DOY/gMSfRTFmkc7fMVDk6yijw4jnKjkO
ymFEaphUp2V2bAFK7PgVkM6P44lFlXj1RpnzahjVM0RIlnYH8coi+5L
YBX8cmmKPkIraaRfMZTXbYGajaR4OnlNAzxntyGKLy65CeoY1fepcN0
/ZTqv/IIHNjF07vMcLY4FwKFLBh25ofk+l7fzlkvuhLOngLwKh9krwM
6F9Ml7LnxuMbL8BZap/eAizycea38xdDLuYt<<<`;
export const modified_v2_1_18 = `
>>>eNp1U89rE0EUftMmbRKrBomCIjWHHkRICNFTkezoRTx4EPQocbKZ
6NLNTju7W60ezMGDB0GQXvSiVyvqQQSPBS/2JvUfqNSDvbVSpAchzsv
sTNZUH7zHt9/7/SYZAwJHIAMwlXEF8wF6jtGCK+bnuawIyQHA0nlXxm
1eEZ6fYmmBB7y7VGmxEIMpwOrAlfOkCHSFVVthKmDxohc2Xd/rdNIds
1K4c2GaORZGTEZecKvJJGfNrvDCKMZqqaQwEkHSNGEiyXn4emXFUdpA
5kAsWeDFXT1JD3kdeYdFXOIeJhLI+5831noPpwG1/wDK/T6qQhsqDhV
IT0cTRSaSLboiiKTwZ1l8d7blsTBfqVXrNZSjaVdH8oWYB+5Srl6t/e
02y42kn9jnH9aoVc8OJM99vsgiTwSHLWr6bI6H2eTIUL6g9KI9HCHkf
untpW/3lh2iV6jSBOwlzGrLMJcT8PQN/Z8rY1yw7ajaO7c3H33Y222Q
36921q+0bjrk2vfiQnhmq6GcB/GG42gmLNK5G2aYHB1lFHj+DGXLIVn
MKA3TipRsL48BqV2dALKufsykeEiZl4+VKZ+0YQ1TtERJZyC/HKIPuG
nA130TzFByHltNo/mMJjvsDFTto8ETSugp4z0+DFH5dUjP0MYvvcuaa
fsp1X9kkBkzyDn6jz1GGBucS4ECNmxb82M8fe8vk+aLvqCDtwCM2iXJ
y4D+Z+lS9tx4fOMFOE3t01uARSY/vrv+B8BC5X8=<<<`;