Skip to content

Conversation

@Sleet01
Copy link
Collaborator

@Sleet01 Sleet01 commented Jan 31, 2026

This fixes an issue where some save game files - including autosaves - could not be loaded at all due to XStream stupidity regarding Records.
Huge props to @BTSS88 for tracking down the root cause: auto-hit artillery markers (or to be more precise, the BoardLocation data storing those markers' locations, which used to be a class but got refactored to a Record)

XStream 1.4, the version we currently depend on, does not natively support deserializing Records.
This is deeply stupid, but made even more offensive by the fact that it can serialize them just fine.

So every time we add a Record data type that is Serializable, we have to also add a new Converter in SerializationHelper.java to ensure that this data type can be loaded after saving it.
This was not done when BoardLocation was converted to a Record, but it turns out XStream doesn't care if there are no actual BoardLocation entries populated in the save game file so few players noticed.

This patch adds the missing Converter, as well as making sure to call context.convertAnother() so that any Coords created as part of the BoardLocation load are also registered with proper ID references so that later things like the special hex HashTable don't explode.

Testing:

  • Loaded the OP failing save game and played through some turns
  • Ran all 3 projects' unit tests

Fix MegaMek/mekhq#8679

@Sleet01 Sleet01 requested a review from a team as a code owner January 31, 2026 10:26
@codecov
Copy link

codecov bot commented Jan 31, 2026

Codecov Report

❌ Patch coverage is 0% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 29.78%. Comparing base (ab70ba0) to head (e9e1177).
⚠️ Report is 45 commits behind head on main.

Files with missing lines Patch % Lines
...k/src/megamek/common/util/SerializationHelper.java 0.00% 22 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #7949      +/-   ##
============================================
- Coverage     29.79%   29.78%   -0.01%     
- Complexity    16633    16676      +43     
============================================
  Files          3133     3134       +1     
  Lines        301519   301887     +368     
  Branches      52756    52864     +108     
============================================
+ Hits          89839    89926      +87     
- Misses       202325   202623     +298     
+ Partials       9355     9338      -17     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes a critical bug where save game files (including autosaves) could not be loaded due to XStream 1.4's inability to deserialize Java Records. The issue was introduced when BoardLocation was refactored from a class to a Record without adding the necessary XStream converter.

Changes:

  • Added a custom XStream converter for BoardLocation Records in SerializationHelper.java to enable proper deserialization
  • Used context.convertAnother() to ensure Coords objects are properly registered in XStream's reference tracking system
  • Accidentally added an unused import to WeaponHandler.java

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
megamek/src/megamek/common/weapons/handlers/WeaponHandler.java Adds an unused AbstractReflectionConverter import
megamek/src/megamek/common/util/SerializationHelper.java Implements a custom converter for BoardLocation Records to fix save game deserialization

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

import java.util.List;
import java.util.Vector;

import com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter;
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This import is unused. AbstractReflectionConverter is not referenced anywhere in this file or the broader WeaponHandler class. This should be removed.

Suggested change
import com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter;

Copilot uses AI. Check for mistakes.
} catch (NumberFormatException e) {
return null;
}
if (coords != null && boardId != -1) {
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation logic may incorrectly reject valid BoardLocation instances. The condition checks for boardId != -1, but Board.BOARD_NONE = -1 is a valid board ID value used by BoardLocation.NO_LOCATION. This means NO_LOCATION instances would be rejected during deserialization and return null instead.

Consider using the isNoLocation flag in the validation logic, or checking against Board.BOARD_NONE specifically. For example: if (coords != null && (boardId >= 0 || isNoLocation)) would allow both regular BoardLocations with valid board IDs and NO_LOCATION instances.

Suggested change
if (coords != null && boardId != -1) {
if (coords != null && (boardId >= 0 || isNoLocation)) {

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cannot load combat saves from mekhq

1 participant