Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions forge-core/src/main/java/forge/card/CardTypeView.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ public interface CardTypeView extends Serializable {
boolean hasABasicLandType();
boolean hasANonBasicLandType();

public boolean sharesCreaturetypeWith(final CardTypeView ctOther);
public boolean sharesLandTypeWith(final CardTypeView ctOther);
public boolean sharesPermanentTypeWith(final CardTypeView ctOther);
public boolean sharesCardTypeWith(final CardTypeView ctOther);
public boolean sharesAllCardTypesWith(final CardTypeView ctOther);
boolean sharesCreaturetypeWith(final CardTypeView ctOther);
boolean sharesLandTypeWith(final CardTypeView ctOther);
boolean sharesPermanentTypeWith(final CardTypeView ctOther);
boolean sharesCardTypeWith(final CardTypeView ctOther);
boolean sharesAllCardTypesWith(final CardTypeView ctOther);

boolean isPermanent();
boolean isCreature();
Expand Down
30 changes: 10 additions & 20 deletions forge-game/src/main/java/forge/game/card/CardView.java
Original file line number Diff line number Diff line change
Expand Up @@ -453,12 +453,14 @@ void updateChosenColors(Card c) {
set(TrackableProperty.ChosenColors, c.getChosenColors());
flagAsChanged(TrackableProperty.ChosenColors);
}

public boolean hasPaperFoil() {
return get(TrackableProperty.PaperFoil);
}
void updatePaperFoil(boolean v) {
set(TrackableProperty.PaperFoil, v);
}

public ColorSet getMarkedColors() {
return get(TrackableProperty.MarkedColors);
}
Expand Down Expand Up @@ -527,15 +529,6 @@ void updateIntensity(Card c) {
set(TrackableProperty.Intensity, c.getIntensity(true));
}

public boolean wasDestroyed() {
if (get(TrackableProperty.WasDestroyed) == null)
return false;
return get(TrackableProperty.WasDestroyed);
}
void updateWasDestroyed(boolean value) {
set(TrackableProperty.WasDestroyed, value);
}

public int getClassLevel() {
return get(TrackableProperty.ClassLevel);
}
Expand Down Expand Up @@ -600,7 +593,7 @@ void updateRemembered(Card c) {
sb.append("\r\nRemembered: \r\n");
for (final Object o : c.getRemembered()) {
if (o != null) {
sb.append(o.toString());
sb.append(o);
sb.append("\r\n");
}
}
Expand Down Expand Up @@ -727,7 +720,6 @@ public boolean canBeShownTo(final PlayerView viewer) {

public boolean canFaceDownBeShownToAny(final Iterable<PlayerView> viewers) {
if (viewers == null || Iterables.isEmpty(viewers)) { return true; }

return IterableUtil.any(viewers, this::canFaceDownBeShownTo);
}

Expand Down Expand Up @@ -1011,25 +1003,26 @@ void updateBackSide(String stateName, boolean hasBackSide) {
set(TrackableProperty.HasBackSide, hasBackSide);
set(TrackableProperty.BackSideName, stateName);
}

public boolean wasDestroyed() {
return get(TrackableProperty.WasDestroyed);
}
void updateWasDestroyed(boolean value) {
set(TrackableProperty.WasDestroyed, value);
}
public boolean needsUntapAnimation() {
if (get(TrackableProperty.NeedsUntapAnimation) == null)
return false;
return get(TrackableProperty.NeedsUntapAnimation);
}
public void updateNeedsUntapAnimation(boolean value) {
set(TrackableProperty.NeedsUntapAnimation, value);
}
public boolean needsTapAnimation() {
if (get(TrackableProperty.NeedsTapAnimation) == null)
return false;
return get(TrackableProperty.NeedsTapAnimation);
}
public void updateNeedsTapAnimation(boolean value) {
set(TrackableProperty.NeedsTapAnimation, value);
}
public boolean needsTransformAnimation() {
if (get(TrackableProperty.NeedsTransformAnimation) == null)
return false;
return get(TrackableProperty.NeedsTransformAnimation);
}
public void updateNeedsTransformAnimation(boolean value) {
Expand Down Expand Up @@ -1070,8 +1063,6 @@ void updateState(Card c) {
updateBackSide(c.getAlternateState().getName(), c.isDoubleFaced());

final Card cloner = c.getCloner();

//CardStateView cloner = CardView.getState(c, CardStateName.Cloner);
set(TrackableProperty.Cloner, cloner == null ? null : cloner.getName() + " (" + cloner.getId() + ")");

CardCollection mergedCollection = new CardCollection();
Expand Down Expand Up @@ -1194,7 +1185,6 @@ void updateBlockAdditional(Card c) {
public boolean isRingBearer() {
return get(TrackableProperty.IsRingBearer);
}

void updateRingBearer(Card c) {
set(TrackableProperty.IsRingBearer, c.isRingBearer());
}
Expand Down
20 changes: 1 addition & 19 deletions forge-game/src/main/java/forge/game/player/PlayerView.java
Original file line number Diff line number Diff line change
Expand Up @@ -197,17 +197,13 @@ void updateCounters(Player p) {
public boolean getIsExtraTurn() {
return get(TrackableProperty.IsExtraTurn);
}

public void setIsExtraTurn(final boolean val) {
set(TrackableProperty.IsExtraTurn, val);
}

public boolean getHasLost() {
if (get(TrackableProperty.HasLost) == null)
return false;
return get(TrackableProperty.HasLost);
}

public void setHasLost(final boolean val) {
set(TrackableProperty.HasLost, val);
}
Expand All @@ -216,8 +212,6 @@ public int getAvatarLifeDifference() {
return (int)get(TrackableProperty.AvatarLifeDifference);
}
public boolean wasAvatarLifeChanged() {
if ((int)get(TrackableProperty.AvatarLifeDifference) == 0)
return false;
return (int)get(TrackableProperty.AvatarLifeDifference) != 0;
}
public void setAvatarLifeDifference(final int val) {
Expand All @@ -227,7 +221,6 @@ public void setAvatarLifeDifference(final int val) {
public int getExtraTurnCount() {
return get(TrackableProperty.ExtraTurnCount);
}

public void setExtraTurnCount(final int val) {
set(TrackableProperty.ExtraTurnCount, val);
}
Expand Down Expand Up @@ -497,19 +490,8 @@ void updateFlashback(Player p) {
set(TrackableProperty.Flashback, CardView.getCollection(p.getCardsIn(ZoneType.Flashback)));
}

public int getMana(final int manaAtom) {
return getMana((byte) manaAtom);
}
public int getMana(final byte color) {
Integer count = null;
try {
count = getMana().get(color);
}
catch (Exception e) {
e.printStackTrace();
count = null;
}
return count != null ? count : 0;
return getMana().getOrDefault(color, 0);
}
private Map<Byte, Integer> getMana() {
return get(TrackableProperty.Mana);
Expand Down
14 changes: 6 additions & 8 deletions forge-gui-mobile/src/forge/toolbox/FChoiceList.java
Original file line number Diff line number Diff line change
Expand Up @@ -604,14 +604,12 @@ public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor,
else
CardRenderer.drawCard(g, cv, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate, true, false);
}
} else {
if (cv != null) {
boolean showAlternate = CardRendererUtils.canShowAlternate(cv, value.toString());
if (!cv.isFaceDown())
CardRenderer.drawCardWithOverlays(g, cv, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate, true);
else
CardRenderer.drawCard(g, cv, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate, true, false);
}
} else if (cv != null) {
boolean showAlternate = CardRendererUtils.canShowAlternate(cv, value.toString());
if (!cv.isFaceDown())
CardRenderer.drawCardWithOverlays(g, cv, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate, true);
else
CardRenderer.drawCard(g, cv, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate, true, false);
}
} catch (Exception ignored) {
//fixme: java.lang.ClassCastException for cards like Subtlety which should be cancelable instead...
Expand Down
1 change: 0 additions & 1 deletion forge-gui-mobile/src/forge/util/CardRendererUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ public static boolean hasAftermath(final CardView card) {
return false;
}


public static boolean isPreferenceEnabled(final ForgePreferences.FPref preferenceName) {
return FModel.getPreferences().getPrefBoolean(preferenceName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,26 +63,33 @@ static TrackableType<?> trackableTypeFor(byte typeTag) {
* ({@code eventMode = true}). When the tracker holds a different object
* for the CardView's id (zone-change copy), {@code preserveSnapshot} is
* set so the receiver decodes a detached CardView from the carried name
* and image key. When {@code tracker} is null, the snapshot check is
* skipped (used by the client encoder, which has no game-state awareness).
* and image key.
* <p>
* In non-event mode, CardViews missing from the tracker pass through
* unchanged so Java serializes the full object inline (covers ephemeral
* choice copies that never enter a tracked zone).
*/
static Object replace(Object obj, Tracker tracker, boolean eventMode) {
if (obj instanceof TrackableObject trackable) {
byte tag = typeTagFor(trackable);
if (tag < 0) return obj;

if (!eventMode || tag == TYPE_PLAYER_VIEW) {
if (tag == TYPE_PLAYER_VIEW) {
return new IdRef(tag, trackable.getId());
}

if (!eventMode) {
if (tracker != null && tracker.getObj(trackableTypeFor(tag), trackable.getId()) != null) {
return new IdRef(tag, trackable.getId());
}
return obj;
}

boolean preserveSnapshot = false;
if (tracker != null) {
TrackableType<?> type = trackableTypeFor(tag);
if (type != null) {
Object tracked = tracker.getObj(type, trackable.getId());
if (tracked != null && tracked != trackable) {
preserveSnapshot = true;
}
Object tracked = tracker.getObj(trackableTypeFor(tag), trackable.getId());
if (tracked != null && tracked != trackable) {
preserveSnapshot = true;
}
}
CardView cv = (CardView) trackable;
Expand Down Expand Up @@ -114,14 +121,11 @@ static Object resolve(Object obj, Tracker tracker) {
return detached;
}
if (obj instanceof IdRef ref) {
TrackableType<?> type = trackableTypeFor(ref.typeTag());
if (type != null) {
Object resolved = tracker.getObj(type, ref.id());
if (resolved == null) {
netLog.warn("Could not resolve IdRef(tag={}, id={}) from Tracker", ref.typeTag(), ref.id());
}
return resolved;
Object resolved = tracker.getObj(trackableTypeFor(ref.typeTag()), ref.id());
if (resolved == null) {
netLog.warn("Could not resolve IdRef(tag={}, id={}) from Tracker", ref.typeTag(), ref.id());
}
return resolved;
}
return obj;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import forge.game.card.CardView;
import forge.game.player.PlayerView;
import forge.gamemodes.net.CompatibleObjectDecoder;
import forge.gamemodes.net.CompatibleObjectEncoder;
import forge.gamemodes.net.GameProtocolHandler;
import forge.gui.GuiBase;
import forge.util.IHasForgeLog;
Expand Down Expand Up @@ -74,12 +75,13 @@ protected void beforeCall(final ChannelHandlerContext ctx, final ProtocolMethod
if (args.length > 0 && args[0] instanceof GameView gameView) {
if (this.tracker == null) {
this.tracker = new Tracker();
// Set tracker on decoder for IdRef resolution in server messages.
// The client encoder does NOT get a tracker — it uses simple
// IdRef replacement without stale detection. Stale detection
// on the client would create StaleCardRef markers for cards
// updated by delta sync, causing the server to create detached
// CardViews that don't match real game objects.
// Encoder uses the tracker to emit IdRef for client→server CardView args
// (presence check only — stale detection is server-only).
// Ephemerals absent from the tracker serialize as full objects in both directions.
CompatibleObjectEncoder encoder = ctx.pipeline().get(CompatibleObjectEncoder.class);
if (encoder != null) {
encoder.setTracker(this.tracker);
}
CompatibleObjectDecoder decoder = ctx.pipeline().get(CompatibleObjectDecoder.class);
if (decoder != null) {
decoder.setTracker(this.tracker);
Expand Down Expand Up @@ -128,6 +130,10 @@ protected void beforeCall(final ChannelHandlerContext ctx, final ProtocolMethod
* This method is used to recursively update the <b>tracker</b>
* references on all objects and their props.
*
* <p>Inline-serialized CardViews are intentionally NOT registered in the
* tracker's id lookup: a tracker miss is the symmetric signal that a
* CardView is ephemeral, mirroring the host's encoder check.
*
* @param objs
*/
private void updateTrackers(final Object[] objs) {
Expand Down
Loading