Skip to content

Commit 0a3d402

Browse files
Fix Android client game events failing to deserialize in cross-platform network play (Card-Forge#10304)
JVM hardcodes serialVersionUID=0 for records, but Android's D8 desugaring computes a different UID, causing InvalidClassException for all GameEvent types in GameEventProxy's inner deserialization. Override readClassDescriptor() to use the local class descriptor when UIDs mismatch, matching the existing pattern in SaveFileData and CObjectInputStream. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5d90c0c commit 0a3d402

4 files changed

Lines changed: 25 additions & 18 deletions

File tree

forge-game/src/main/java/forge/game/event/GameEvent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
public interface GameEvent extends Event, Serializable {
66

7-
public abstract <T> T visit(IGameEventVisitor<T> visitor);
7+
<T> T visit(IGameEventVisitor<T> visitor);
88
}

forge-gui/src/main/java/forge/gamemodes/match/AbstractGuiGame.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,8 @@ public boolean mayView(final CardView c) {
240240
} catch (NullPointerException e) {
241241
return true; // return true so it will work as normal
242242
}
243-
} else {
244-
if (getGameController().mayLookAtAllCards()) {
245-
return true;
246-
}
243+
} else if (getGameController().mayLookAtAllCards()) {
244+
return true;
247245
}
248246
return c.canBeShownToAny(getLocalPlayers());
249247
}

forge-gui/src/main/java/forge/gamemodes/net/GameEventProxy.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,24 @@ boolean hasUnresolvedRefs() {
216216
return unresolvedRefs;
217217
}
218218

219+
// needed for cross-platform play because Android implements Records via desugaring to regular classes,
220+
// causing the serialVersionUID to auto-compute instead of default 0L
221+
// (this approach avoids having to hardcode it on each individual GameEvent instead)
222+
@Override
223+
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
224+
ObjectStreamClass streamDesc = super.readClassDescriptor();
225+
try {
226+
Class<?> localClass = Class.forName(streamDesc.getName());
227+
ObjectStreamClass localDesc = ObjectStreamClass.lookup(localClass);
228+
if (localDesc != null && streamDesc.getSerialVersionUID() != localDesc.getSerialVersionUID()) {
229+
return localDesc;
230+
}
231+
} catch (ClassNotFoundException ignored) {
232+
// Class not found locally — fall through to stream descriptor
233+
}
234+
return streamDesc;
235+
}
236+
219237
@Override
220238
protected Object resolveObject(Object obj) {
221239
if (obj instanceof IdRef ref) {

forge-gui/src/main/java/forge/player/PlayerControllerHuman.java

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -148,25 +148,16 @@ public void setDisableAutoYields(final boolean disableAutoYields0) {
148148
public boolean mayLookAtAllCards() {
149149
return mayLookAtAllCards;
150150
}
151-
/**
152-
* Set this to {@code true} to enable this player to see all cards any other
153-
* player can see.
154-
*
155-
* @param mayLookAtAllCards the mayLookAtAllCards to set
156-
*/
157-
public void setMayLookAtAllCards(final boolean mayLookAtAllCards) {
158-
this.mayLookAtAllCards = mayLookAtAllCards;
159-
}
160151

161152
private final ArrayList<Card> tempShownCards = new ArrayList<>();
162153

163154
public <T> void tempShow(final Iterable<T> objects) {
164155
for (final T t : objects) {
165156
// assume you may see any card passed through here
166-
if (t instanceof Card) {
167-
tempShowCard((Card) t);
168-
} else if (t instanceof CardView) {
169-
tempShowCard(getCard((CardView) t));
157+
if (t instanceof Card c) {
158+
tempShowCard(c);
159+
} else if (t instanceof CardView c) {
160+
tempShowCard(getCard(c));
170161
}
171162
}
172163
}

0 commit comments

Comments
 (0)