From 2a36c9c703dfdbbf2e36037a1b2453460c9eeb7a Mon Sep 17 00:00:00 2001 From: MostCromulent <201167372+MostCromulent@users.noreply.github.com> Date: Mon, 4 May 2026 13:22:05 +0930 Subject: [PATCH] Restore Android record deserialization fallback in TrackableSerializer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #10343 replaced GameEventProxy with TrackableSerializer but did not carry forward the readClassDescriptor() override added in #10304. Android's D8 desugars records to regular classes with computed serialVersionUIDs, while the JVM hardcodes 0L for records — so every GameEvent now fails to deserialize on Android clients in cross-platform network play (visible as "TrackableSerializer: Failed to unwrap event: ... local class incompatible: stream classdesc serialVersionUID = 0, local class serialVersionUID = ..." warnings). Re-applies the same pattern used in CObjectInputStream and the deleted GameEventProxy: when the stream's UID disagrees with the local class UID, fall through to the local descriptor. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../gamemodes/net/TrackableSerializer.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/forge-gui/src/main/java/forge/gamemodes/net/TrackableSerializer.java b/forge-gui/src/main/java/forge/gamemodes/net/TrackableSerializer.java index 7087500c9db..4219c6339a8 100644 --- a/forge-gui/src/main/java/forge/gamemodes/net/TrackableSerializer.java +++ b/forge-gui/src/main/java/forge/gamemodes/net/TrackableSerializer.java @@ -226,6 +226,23 @@ static class ResolvingInputStream extends ObjectInputStream { enableResolveObject(true); } + // Android desugars records to classes with computed serialVersionUID; the JVM keeps records at 0L. + // Fall through to the local descriptor when UIDs mismatch. + @Override + protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException { + ObjectStreamClass streamDesc = super.readClassDescriptor(); + try { + Class localClass = Class.forName(streamDesc.getName()); + ObjectStreamClass localDesc = ObjectStreamClass.lookup(localClass); + if (localDesc != null && streamDesc.getSerialVersionUID() != localDesc.getSerialVersionUID()) { + return localDesc; + } + } catch (ClassNotFoundException ignored) { + // Class not found locally — fall through to stream descriptor. + } + return streamDesc; + } + @Override protected Object resolveObject(Object obj) { return resolve(obj, tracker);