From e03156cd0c02f1012abeade4e1511e813b67bb79 Mon Sep 17 00:00:00 2001 From: drdev Date: Sat, 27 Jun 2015 22:41:04 +0000 Subject: [PATCH] Refactor TrackableObjects to support copy forward changed properties without completely overwriting references --- .../src/main/java/forge/game/GameView.java | 4 +- .../forge/trackable/TrackableCollection.java | 12 --- .../java/forge/trackable/TrackableObject.java | 23 +----- .../forge/trackable/TrackableProperty.java | 4 + .../java/forge/trackable/TrackableTypes.java | 77 +++++++++++++++++-- .../java/forge/screens/match/CMatchUI.java | 14 ++-- .../java/forge/match/AbstractGuiGame.java | 11 ++- .../main/java/forge/match/HostedMatch.java | 7 ++ 8 files changed, 102 insertions(+), 50 deletions(-) diff --git a/forge-game/src/main/java/forge/game/GameView.java b/forge-game/src/main/java/forge/game/GameView.java index 679483df891..721695bd2ed 100644 --- a/forge-game/src/main/java/forge/game/GameView.java +++ b/forge-game/src/main/java/forge/game/GameView.java @@ -37,7 +37,7 @@ public class GameView extends TrackableObject { set(TrackableProperty.WinningTeam, -1); GameRules rules = game.getRules(); - set(TrackableProperty.Commander, rules.hasCommander()); + set(TrackableProperty.IsCommander, rules.hasCommander()); set(TrackableProperty.GameType, rules.getGameType()); set(TrackableProperty.PoisonCountersToLose, rules.getPoisonCountersToLose()); set(TrackableProperty.NumGamesInMatch, rules.getGamesPerMatch()); @@ -56,7 +56,7 @@ public class GameView extends TrackableObject { return get(TrackableProperty.Title); } public boolean isCommander() { - return get(TrackableProperty.Commander); + return get(TrackableProperty.IsCommander); } public GameType getGameType() { return get(TrackableProperty.GameType); diff --git a/forge-game/src/main/java/forge/trackable/TrackableCollection.java b/forge-game/src/main/java/forge/trackable/TrackableCollection.java index a6b85400081..89c8c48c125 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableCollection.java +++ b/forge-game/src/main/java/forge/trackable/TrackableCollection.java @@ -18,16 +18,4 @@ public class TrackableCollection extends FCollection< public TrackableCollection(Iterable i) { super(i); } - - @Override - public boolean add(T item) { - //TODO: Track change - return super.add(item); - } - - @Override - public boolean remove(Object item) { - //TODO: Track change - return super.remove(item); - } } diff --git a/forge-game/src/main/java/forge/trackable/TrackableObject.java b/forge-game/src/main/java/forge/trackable/TrackableObject.java index 0797b6d58fc..de0d708a5cb 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableObject.java +++ b/forge-game/src/main/java/forge/trackable/TrackableObject.java @@ -64,26 +64,11 @@ public abstract class TrackableObject implements IIdentifiable, Serializable { } /** - * Copy to this Trackable object the first object of the provided iterator - * whose id matches. - * - * @see TrackableObject#copy(TrackableObject) + * Copy all change properties of another Trackable object to this object. */ - public final void copy(final Iterable others) { - for (final TrackableObject other : others) { - if (this.equals(other)) { - copy(other); - break; - } - } - } - - /** - * Copy all properties of another Trackable object to this object. - */ - public final void copy(final TrackableObject other) { - for (final TrackableProperty prop : other.props.keySet()) { - set(prop, other.get(prop)); + public final void copyChangedProps(final TrackableObject from) { + for (final TrackableProperty prop : from.changedProps) { + prop.copyChangedProps(from, this); } } diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index 3e0278c0485..86abe8d92e9 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -166,6 +166,10 @@ public enum TrackableProperty { return respectFreeze; } + public void copyChangedProps(TrackableObject from, TrackableObject to) { + type.copyChangedProps(from, to, this); + } + @SuppressWarnings("unchecked") public T getDefaultValue() { return ((TrackableType)type).getDefaultValue(); diff --git a/forge-game/src/main/java/forge/trackable/TrackableTypes.java b/forge-game/src/main/java/forge/trackable/TrackableTypes.java index 78d2b62cb3a..ab37001dd9a 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableTypes.java +++ b/forge-game/src/main/java/forge/trackable/TrackableTypes.java @@ -24,11 +24,72 @@ public class TrackableTypes { private TrackableType() { } + protected void copyChangedProps(TrackableObject from, TrackableObject to, TrackableProperty prop) { + to.set(prop, from.get(prop)); + } protected abstract T getDefaultValue(); protected abstract T deserialize(TrackableDeserializer td, T oldValue); protected abstract void serialize(TrackableSerializer ts, T value); } + public static abstract class TrackableObjectType extends TrackableType { + private final HashMap objLookup = new HashMap(); + + private TrackableObjectType() { + } + + public void clearLookupDictionary() { + objLookup.clear(); + } + + @Override + protected void copyChangedProps(TrackableObject from, TrackableObject to, TrackableProperty prop) { + T newObj = from.get(prop); + if (newObj != null) { + T existingObj = objLookup.get(newObj.getId()); + if (existingObj != null) { //if object exists already, update its changed properties + existingObj.copyChangedProps(newObj); + newObj = existingObj; + } + else { //if object is new, cache in object lookup + objLookup.put(newObj.getId(), newObj); + } + } + to.set(prop, newObj); + } + } + + private static abstract class TrackableCollectionType extends TrackableType> { + private final TrackableObjectType itemType; + + private TrackableCollectionType(TrackableObjectType itemType0) { + itemType = itemType0; + } + + @Override + protected void copyChangedProps(TrackableObject from, TrackableObject to, TrackableProperty prop) { + TrackableCollection newCollection = from.get(prop); + if (newCollection != null) { + //swap in objects in old collection for objects in new collection + for (int i = 0; i < newCollection.size(); i++) { + T newObj = newCollection.get(i); + if (newObj != null) { + T existingObj = itemType.objLookup.get(newObj.getId()); + if (existingObj != null) { //if object exists already, update its changed properties + existingObj.copyChangedProps(newObj); + newCollection.remove(i); + newCollection.add(i, existingObj); + } + else { //if object is new, cache in object lookup + itemType.objLookup.put(newObj.getId(), newObj); + } + } + } + } + to.set(prop, newCollection); + } + } + public static final TrackableType BooleanType = new TrackableType() { @Override public Boolean getDefaultValue() { @@ -111,7 +172,7 @@ public class TrackableTypes { return type; } - public static final TrackableType CardViewType = new TrackableType() { + public static final TrackableObjectType CardViewType = new TrackableObjectType() { @Override protected CardView getDefaultValue() { return null; @@ -131,7 +192,7 @@ public class TrackableTypes { ts.write(value == null ? -1 : value.getId()); //just write ID for lookup via index when deserializing } }; - public static final TrackableType> CardViewCollectionType = new TrackableType>() { + public static final TrackableCollectionType CardViewCollectionType = new TrackableCollectionType(CardViewType) { @Override protected TrackableCollection getDefaultValue() { return null; @@ -147,7 +208,7 @@ public class TrackableTypes { ts.write(value); } }; - public static final TrackableType CardStateViewType = new TrackableType() { + public static final TrackableObjectType CardStateViewType = new TrackableObjectType() { @Override protected CardStateView getDefaultValue() { return null; @@ -191,7 +252,7 @@ public class TrackableTypes { } } }; - public static final TrackableType PlayerViewType = new TrackableType() { + public static final TrackableObjectType PlayerViewType = new TrackableObjectType() { @Override protected PlayerView getDefaultValue() { return null; @@ -211,7 +272,7 @@ public class TrackableTypes { ts.write(value == null ? -1 : value.getId()); //just write ID for lookup via index when deserializing } }; - public static final TrackableType> PlayerViewCollectionType = new TrackableType>() { + public static final TrackableCollectionType PlayerViewCollectionType = new TrackableCollectionType(PlayerViewType) { @Override protected TrackableCollection getDefaultValue() { return null; @@ -227,7 +288,7 @@ public class TrackableTypes { ts.write(value); } }; - public static final TrackableType GameEntityViewType = new TrackableType() { + public static final TrackableObjectType GameEntityViewType = new TrackableObjectType() { @Override protected GameEntityView getDefaultValue() { return null; @@ -262,7 +323,7 @@ public class TrackableTypes { } } }; - public static final TrackableType StackItemViewType = new TrackableType() { + public static final TrackableObjectType StackItemViewType = new TrackableObjectType() { @Override protected StackItemView getDefaultValue() { return null; @@ -284,7 +345,7 @@ public class TrackableTypes { } } }; - public static final TrackableType> StackItemViewListType = new TrackableType>() { + public static final TrackableCollectionType StackItemViewListType = new TrackableCollectionType(StackItemViewType) { @Override protected TrackableCollection getDefaultValue() { return new TrackableCollection(); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index 81b67879cac..bc7c2b4fd6b 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -174,14 +174,14 @@ public final class CMatchUI } @Override - public void setGameView(final GameView gameView) { - super.setGameView(gameView); - cDetailPicture.setGameView(gameView); - screen.setTabCaption(gameView.getTitle()); + public void setGameView(GameView gameView0) { + super.setGameView(gameView0); + gameView0 = getGameView(); //ensure updated game view used for below logic + if (gameView0 == null) { return; } + + cDetailPicture.setGameView(gameView0); + screen.setTabCaption(gameView0.getTitle()); if (sortedPlayers != null) { - for (final PlayerView pv : sortedPlayers) { - pv.copy(gameView.getPlayers()); - } FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public final void run() { for (final VField f : getFieldViews()) { diff --git a/forge-gui/src/main/java/forge/match/AbstractGuiGame.java b/forge-gui/src/main/java/forge/match/AbstractGuiGame.java index fa886853c48..85e08db22f1 100644 --- a/forge-gui/src/main/java/forge/match/AbstractGuiGame.java +++ b/forge-gui/src/main/java/forge/match/AbstractGuiGame.java @@ -65,8 +65,15 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { return gameView; } @Override - public void setGameView(final GameView gameView) { - this.gameView = gameView; + public void setGameView(final GameView gameView0) { + if (gameView == null || gameView0 == null) { + gameView = gameView0; + return; + } + + //if game view set to another instance without being first cleared, + //update existing game view object instead of overwriting it + gameView.copyChangedProps(gameView0); } public final IGameController getGameController() { diff --git a/forge-gui/src/main/java/forge/match/HostedMatch.java b/forge-gui/src/main/java/forge/match/HostedMatch.java index 7655c37f97f..22956594123 100644 --- a/forge-gui/src/main/java/forge/match/HostedMatch.java +++ b/forge-gui/src/main/java/forge/match/HostedMatch.java @@ -44,6 +44,7 @@ import forge.quest.QuestController; import forge.sound.MusicPlaylist; import forge.sound.SoundSystem; import forge.trackable.TrackableCollection; +import forge.trackable.TrackableTypes; import forge.util.CollectionSuppliers; import forge.util.collect.FCollectionView; import forge.util.maps.HashMapOfLists; @@ -127,6 +128,11 @@ public class HostedMatch { } public void startGame() { + //ensure lookup dictionaries are cleared before each game + TrackableTypes.CardViewType.clearLookupDictionary(); + TrackableTypes.PlayerViewType.clearLookupDictionary(); + TrackableTypes.StackItemViewType.clearLookupDictionary(); + nextGameDecisions.clear(); SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MATCH); @@ -168,6 +174,7 @@ public class HostedMatch { final PlayerControllerHuman humanController = (PlayerControllerHuman) p.getController(); final IGuiGame gui = guis.get(p.getRegisteredPlayer()); humanController.setGui(gui); + gui.setGameView(null); //clear out game view first so we don't copy into old game view gui.setGameView(gameView); gui.setOriginalGameController(p.getView(), humanController);