From 6db5685906649349d114ed4ad62c6ff82a9db9a9 Mon Sep 17 00:00:00 2001 From: elcnesh Date: Wed, 24 Sep 2014 14:16:42 +0000 Subject: [PATCH] Make LocalGameView a bit faster, plus some minor refactoring. --- .../src/main/java/forge/GuiDesktop.java | 17 ++++---- forge-gui-mobile/src/forge/GuiMobile.java | 9 ++-- .../main/java/forge/interfaces/IGuiBase.java | 2 +- .../forge/player/PlayerControllerHuman.java | 2 +- forge-gui/src/main/java/forge/view/Cache.java | 38 ++++++++++++++--- .../src/main/java/forge/view/CardView.java | 41 ++++--------------- .../main/java/forge/view/LocalGameView.java | 37 ++++++++++------- 7 files changed, 78 insertions(+), 68 deletions(-) diff --git a/forge-gui-desktop/src/main/java/forge/GuiDesktop.java b/forge-gui-desktop/src/main/java/forge/GuiDesktop.java index 34ced7c8fe4..f96331fa3fb 100644 --- a/forge-gui-desktop/src/main/java/forge/GuiDesktop.java +++ b/forge-gui-desktop/src/main/java/forge/GuiDesktop.java @@ -326,25 +326,26 @@ public class GuiDesktop implements IGuiBase { } @Override - public SpellAbilityView getAbilityToPlay(List abilities, ITriggerEvent triggerEvent) { + public int getAbilityToPlay(List abilities, ITriggerEvent triggerEvent) { if (triggerEvent == null) { if (abilities.isEmpty()) { - return null; + return -1; } if (abilities.size() == 1) { - return abilities.get(0); + return abilities.get(0).getId(); } - return GuiChoose.oneOrNone("Choose ability to play", abilities); + final SpellAbilityView choice = GuiChoose.oneOrNone("Choose ability to play", abilities); + return choice == null ? -1 : choice.getId(); } if (abilities.isEmpty()) { - return null; + return -1; } if (abilities.size() == 1 && !abilities.get(0).isPromptIfOnlyPossibleAbility()) { if (abilities.get(0).canPlay()) { - return abilities.get(0); //only return ability if it's playable, otherwise return null + return abilities.get(0).getId(); //only return ability if it's playable, otherwise return null } - return null; + return -1; } //show menu if mouse was trigger for ability @@ -383,7 +384,7 @@ public class GuiDesktop implements IGuiBase { menu.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY()); } - return null; //delay ability until choice made + return -1; //delay ability until choice made } @Override diff --git a/forge-gui-mobile/src/forge/GuiMobile.java b/forge-gui-mobile/src/forge/GuiMobile.java index d53e725c59b..facc1ba8276 100644 --- a/forge-gui-mobile/src/forge/GuiMobile.java +++ b/forge-gui-mobile/src/forge/GuiMobile.java @@ -314,14 +314,15 @@ public class GuiMobile implements IGuiBase { } @Override - public SpellAbilityView getAbilityToPlay(List abilities, ITriggerEvent triggerEvent) { + public int getAbilityToPlay(List abilities, ITriggerEvent triggerEvent) { if (abilities.isEmpty()) { - return null; + return -1; } if (abilities.size() == 1) { - return abilities.get(0); + return abilities.get(0).getId(); } - return SGuiChoose.oneOrNone(this, "Choose ability to play", abilities); + final SpellAbilityView choice = SGuiChoose.oneOrNone(this, "Choose ability to play", abilities); + return choice == null ? -1 : choice.getId(); } @Override diff --git a/forge-gui/src/main/java/forge/interfaces/IGuiBase.java b/forge-gui/src/main/java/forge/interfaces/IGuiBase.java index 0e6e79de2a2..0c9c3ea4bf0 100644 --- a/forge-gui/src/main/java/forge/interfaces/IGuiBase.java +++ b/forge-gui/src/main/java/forge/interfaces/IGuiBase.java @@ -85,7 +85,7 @@ public interface IGuiBase { void setPanelSelection(CardView hostCard); Map getDamageToAssign(CardView attacker, List blockers, int damageDealt, GameEntityView defender, boolean overrideOrder); - SpellAbilityView getAbilityToPlay(List abilities, ITriggerEvent triggerEvent); + int getAbilityToPlay(List abilities, ITriggerEvent triggerEvent); void hear(LobbyPlayer player, String message); int getAvatarCount(); void copyToClipboard(String text); diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 127d4e58ebf..59c71bc145d 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -176,7 +176,7 @@ public class PlayerControllerHuman extends PlayerController { * Uses GUI to learn which spell the player (human in our case) would like to play */ public SpellAbility getAbilityToPlay(final List abilities, final ITriggerEvent triggerEvent) { - final SpellAbilityView choice = getGui().getAbilityToPlay(gameView.getSpellAbilityViews(abilities), triggerEvent); + final int choice = getGui().getAbilityToPlay(gameView.getSpellAbilityViews(abilities), triggerEvent); return gameView.getSpellAbility(choice); } diff --git a/forge-gui/src/main/java/forge/view/Cache.java b/forge-gui/src/main/java/forge/view/Cache.java index 74ad7999608..f5539d6ce54 100644 --- a/forge-gui/src/main/java/forge/view/Cache.java +++ b/forge-gui/src/main/java/forge/view/Cache.java @@ -77,7 +77,7 @@ public class Cache { * @return a value equal to value, if such a value is present in the Cache; * {@code null} otherwise. */ - public synchronized V getValue(final V value) { + public synchronized V getCurrentValue(final V value) { for (final V currentValue : cache.values()) { if (currentValue.equals(value)) { return currentValue; @@ -106,16 +106,42 @@ public class Cache { } synchronized (this) { - final int valueId = value.getId(); + final int keyId = key.getId(), valueId = value.getId(); + + // remove value mapping if it exists already if (inverseCache.containsKey(valueId)) { - cache.remove(inverseCache.get(valueId).getId()); + cache.values().remove(value); inverseCache.remove(valueId); } - final V oldValue = cache.put(key.getId(), value); - if (oldValue != null) { - inverseCache.remove(oldValue.getId()); + // remove key mapping if it exists already + if (cache.containsKey(keyId)) { + inverseCache.values().remove(key); + cache.remove(keyId); } + + // put the new values + cache.put(keyId, value); + inverseCache.put(valueId, key); + } + } + + /** + * Update the key of a particular entry. If the supplied key is {@code null} + * or if the Cache didn't already contain a mapping for the supplied id, + * this method silently returns. + * + * @param valueId + * the id of the value to which the key is associated. + * @param key + * the new key. + */ + public void updateKey(final int valueId, final K key) { + if (key == null || !inverseCache.containsKey(valueId)) { + return; + } + + synchronized (this) { inverseCache.put(valueId, key); } } diff --git a/forge-gui/src/main/java/forge/view/CardView.java b/forge-gui/src/main/java/forge/view/CardView.java index ebc163b7251..eeae117d4da 100644 --- a/forge-gui/src/main/java/forge/view/CardView.java +++ b/forge-gui/src/main/java/forge/view/CardView.java @@ -1,7 +1,6 @@ package forge.view; import java.util.Collections; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -12,8 +11,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import com.google.common.collect.Iterators; -import com.google.common.collect.Lists; import forge.ImageKeys; import forge.card.CardEdition; @@ -34,19 +31,7 @@ import forge.game.zone.ZoneType; */ public class CardView extends GameEntityView { - private static final List randomInts = Lists.newArrayListWithCapacity(1024); - static { - for (int i = 1; i < 1025; i++) { - randomInts.add(Integer.valueOf(i)); - } - Collections.shuffle(randomInts); - } - private static final Iterator randomIntsIterator = Iterators.cycle(randomInts); - private static int nextRandomInt() { - synchronized (randomIntsIterator) { - return randomIntsIterator.next().intValue(); - } - } + public static final CardView EMPTY = new CardView(true); private final CardStateView original = new CardStateView(), @@ -90,7 +75,7 @@ public class CardView extends GameEntityView { public void reset() { final Iterable emptyIterable = ImmutableSet.of(); - this.id = -nextRandomInt(); + this.id = 0; this.hasAltState = false; this.owner = null; this.controller = null; @@ -100,15 +85,15 @@ public class CardView extends GameEntityView { this.isFlipped = false; this.isSplitCard = false; this.isTransformed = false; - this.setCode = StringUtils.EMPTY; + this.setCode = ""; this.rarity = CardRarity.Unknown; this.isAttacking = this.isBlocking = this.isPhasedOut = this.isSick = this.isTapped = false; this.counters = ImmutableMap.of(); this.damage = this.assignedDamage = this.regenerationShields = this.preventNextDamage = 0; - this.chosenType = StringUtils.EMPTY; + this.chosenType = ""; this.chosenColors = ImmutableList.of(); this.chosenPlayer = null; - this.namedCard = StringUtils.EMPTY; + this.namedCard = ""; this.equipping = null; this.equippedBy = emptyIterable; this.enchantingCard = null; @@ -139,17 +124,6 @@ public class CardView extends GameEntityView { this.id = id; } - @Override - public boolean equals(final Object obj) { - return obj instanceof CardView && this.getId() == ((CardView) obj).getId() - && (this.getId() > 0 || this == obj); - } - - @Override - public int hashCode() { - return id > 0 ? id : super.hashCode(); - } - public boolean isUiDisplayable() { return isUiDisplayable; } @@ -773,7 +747,7 @@ public class CardView extends GameEntityView { } public void reset() { - this.name = StringUtils.EMPTY; + this.name = ""; this.colors = ColorSet.getNullColor(); this.imageKey = ImageKeys.TOKEN_PREFIX + ImageKeys.MORPH_IMAGE; this.type = Collections.emptyList(); @@ -781,7 +755,7 @@ public class CardView extends GameEntityView { this.power = 0; this.toughness = 0; this.loyalty = 0; - this.text = StringUtils.EMPTY; + this.text = ""; this.changedColorWords = ImmutableMap.of(); this.changedTypes = ImmutableMap.of(); this.hasDeathtouch = false; @@ -957,7 +931,6 @@ public class CardView extends GameEntityView { this.changedTypes = Collections.unmodifiableMap(changedTypes); } - /** * @return the hasDeathtouch */ diff --git a/forge-gui/src/main/java/forge/view/LocalGameView.java b/forge-gui/src/main/java/forge/view/LocalGameView.java index 8f5d34d04e1..fe29b230296 100644 --- a/forge-gui/src/main/java/forge/view/LocalGameView.java +++ b/forge-gui/src/main/java/forge/view/LocalGameView.java @@ -424,23 +424,30 @@ public abstract class LocalGameView implements IGameView { final boolean mayShow = mayShowCard(c); CardView view = cards.get(c.getId()); + final boolean isNewView; if (view != null) { - // Put here again to ensure the Card reference in the cache + // Update to ensure the Card reference in the cache // is not an outdated Card. - cards.put(c, view); - } - else { - view = new CardView(isDisplayable); - if (isDisplayable && mayShow) { - cards.put(c, view); + if (view.getId() > 0) { + cards.updateKey(view.getId(), c); } + isNewView = false; + } else if (isDisplayable && mayShow) { + view = new CardView(isDisplayable); + view.setId(c.getId()); + cards.put(c, view); + isNewView = true; + } else { + return CardView.EMPTY; } if (mayShow) { writeCardToView(cUi, view); } else if (isDisplayable) { - view.reset(); + if (!isNewView) { + view.reset(); + } } else { return null; @@ -464,7 +471,7 @@ public abstract class LocalGameView implements IGameView { return ViewUtil.transformIfNotNull(cardViews, new Function() { @Override public CardView apply(final CardView input) { - return cards.getValue(input); + return cards.getCurrentValue(input); } }); } @@ -478,8 +485,7 @@ public abstract class LocalGameView implements IGameView { if (mayShowCard(c)) { return view; } else if (view.isUiDisplayable()) { - view.reset(); - return view; + return CardView.EMPTY; } return null; @@ -569,11 +575,14 @@ public abstract class LocalGameView implements IGameView { return ViewUtil.transformIfNotNull(cards, FN_GET_SPAB_VIEW); } - public SpellAbility getSpellAbility(final SpellAbilityView c) { - if (c == null) { + public SpellAbility getSpellAbility(final SpellAbilityView spabView) { + if (spabView == null) { return null; } - return spabs.getKey(c.getId()); + return getSpellAbility(spabView.getId()); + } + public SpellAbility getSpellAbility(final int id) { + return id >= 0 ? spabs.getKey(id) : null; } private final Function FN_GET_SPAB = new Function() {