Use caching for CombatView (plus some random NPE and concurrency fixes).

This commit is contained in:
elcnesh
2014-09-26 07:38:47 +00:00
parent 3c411f3a3c
commit 3f1f199537
18 changed files with 119 additions and 44 deletions

View File

@@ -28,6 +28,7 @@ import forge.game.event.GameEventCardDamaged;
import forge.game.event.GameEventCardPhased;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.event.GameEventCardTapped;
import forge.game.event.GameEventCombatChanged;
import forge.game.event.GameEventCombatEnded;
import forge.game.event.GameEventGameFinished;
import forge.game.event.GameEventGameOutcome;
@@ -97,8 +98,13 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
private final AtomicBoolean combatUpdPlanned = new AtomicBoolean(false);
@Override
public Void visit(GameEventPlayerPriority event) {
if (!isMainHandler || combatUpdPlanned.getAndSet(true)) { return null; }
updateCombat();
return null;
}
public void updateCombat() {
if (!isMainHandler || combatUpdPlanned.getAndSet(true)) { return; }
FThreads.invokeInEdtNowOrLater(gameView.getGui(), new Runnable() {
@Override
public void run() {
@@ -106,7 +112,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
MatchUtil.getController().showCombat(gameView.getCombat());
}
});
return null;
}
private final AtomicBoolean turnUpdPlanned = new AtomicBoolean(false);
@@ -352,9 +357,19 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
return super.visit(event);
}
@Override
public Void visit(GameEventCombatChanged event) {
gameView.refreshCombat();
updateCombat();
return null;
}
@Override
public Void visit(GameEventCombatEnded event) {
if (!isMainHandler) { return null; }
gameView.refreshCombat();
updateCombat();
// This should remove sword/shield icons from combatants by the time game moves to M2
updateManyCards(gameView.getCardViews(event.attackers));

View File

@@ -60,6 +60,7 @@ import forge.util.NameGenerator;
import forge.util.gui.SOptionPane;
import forge.view.Cache;
import forge.view.CardView;
import forge.view.CombatView;
import forge.view.GameEntityView;
import forge.view.LocalGameView;
import forge.view.PlayerView;
@@ -80,6 +81,8 @@ public class MatchUtil {
public static final Cache<SpellAbility, SpellAbilityView> spabs = new Cache<>();
/** Cache of stack items. */
public static final Cache<SpellAbilityStackInstance, StackItemView> stackItems = new Cache<>();
/** Cache of combat. */
public static CombatView cachedCombatView = null;
private static int humanCount;
private static final EventBus uiEvents;

View File

@@ -313,6 +313,6 @@ public class InputAttack extends InputSyncronizedBase {
showMessage(message);
updatePrompt();
MatchUtil.getController().showCombat(getController().getCombat(combat)); // redraw sword icons
MatchUtil.getController().showCombat(getController().getCombat()); // redraw sword icons
}
}

View File

@@ -24,6 +24,7 @@ import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.event.GameEventCombatChanged;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
import forge.match.MatchUtil;
@@ -86,7 +87,7 @@ public class InputBlock extends InputSyncronizedBase {
showMessage(message);
}
MatchUtil.getController().showCombat(getController().getCombat(combat));
MatchUtil.getController().showCombat(getController().getCombat());
}
/** {@inheritDoc} */
@@ -147,7 +148,9 @@ public class InputBlock extends InputSyncronizedBase {
}
}
if (!isCorrectAction) {
if (isCorrectAction) {
card.getGame().fireEvent(new GameEventCombatChanged());
} else {
flashIncorrectAction();
}
}

View File

@@ -1080,11 +1080,11 @@ public class PlayerControllerHuman extends PlayerController {
*/
@Override
public List<AbilitySub> chooseModeForAbility(SpellAbility sa, int min, int num) {
List<AbilitySub> choices = CharmEffect.makePossibleOptions(sa);
List<SpellAbilityView> choices = getSpellAbilityViews(CharmEffect.makePossibleOptions(sa));
String modeTitle = String.format("%s activated %s - Choose a mode", sa.getActivatingPlayer(), sa.getHostCard());
List<AbilitySub> chosen = new ArrayList<AbilitySub>();
List<AbilitySub> chosen = Lists.newArrayListWithCapacity(num);
for (int i = 0; i < num; i++) {
AbilitySub a;
SpellAbilityView a;
if (i < min) {
a = SGuiChoose.one(getGui(), modeTitle, choices);
}
@@ -1096,7 +1096,7 @@ public class PlayerControllerHuman extends PlayerController {
}
choices.remove(a);
chosen.add(a);
chosen.add((AbilitySub) getSpellAbility(a));
}
return chosen;
}
@@ -1556,8 +1556,8 @@ public class PlayerControllerHuman extends PlayerController {
* @return
* @see forge.view.LocalGameView#getCombat(forge.game.combat.Combat)
*/
public CombatView getCombat(Combat c) {
return gameView.getCombat(c);
public CombatView getCombat() {
return gameView.getCombat();
}
/**
@@ -1663,8 +1663,8 @@ public class PlayerControllerHuman extends PlayerController {
* @see forge.view.LocalGameView#getSpellAbilityViews(java.util.List)
*/
public final List<SpellAbilityView> getSpellAbilityViews(
List<SpellAbility> cards) {
return gameView.getSpellAbilityViews(cards);
final List<? extends SpellAbility> spabs) {
return gameView.getSpellAbilityViews(spabs);
}
/**

View File

@@ -186,30 +186,39 @@ public abstract class LocalGameView implements IGameView {
@Override
public CombatView getCombat() {
return getCombat(game.getCombat());
synchronized (MatchUtil.class) {
if (MatchUtil.cachedCombatView != null) {
return MatchUtil.cachedCombatView;
}
final Combat combat = game.getCombat();
final CombatView combatView;
if (combat == null) {
combatView = null;
} else {
combatView = new CombatView();
for (final AttackingBand b : combat.getAttackingBands()) {
if (b == null) continue;
final GameEntity defender = combat.getDefenderByAttacker(b);
final List<Card> blockers = combat.getBlockers(b);
final boolean isBlocked = b.isBlocked() == Boolean.TRUE;
combatView.addAttackingBand(
getCardViews(b.getAttackers()),
getGameEntityView(defender),
blockers == null || !isBlocked ? null : getCardViews(blockers),
blockers == null ? null : getCardViews(blockers));
}
}
MatchUtil.cachedCombatView = combatView;
return combatView;
}
}
/* (non-Javadoc)
* @see forge.view.IGameView#getCombat()
*/
public CombatView getCombat(final Combat combat) {
if (combat == null) {
return null;
public final void refreshCombat() {
synchronized (MatchUtil.class) {
MatchUtil.cachedCombatView = null;
this.getCombat();
}
final CombatView combatView = new CombatView();
for (final AttackingBand b : combat.getAttackingBands()) {
if (b == null) continue;
final GameEntity defender = combat.getDefenderByAttacker(b);
final List<Card> blockers = combat.getBlockers(b);
final boolean isBlocked = b.isBlocked() == Boolean.TRUE;
combatView.addAttackingBand(
getCardViews(b.getAttackers()),
getGameEntityView(defender),
blockers == null || !isBlocked ? null : getCardViews(blockers),
blockers == null ? null : getCardViews(blockers));
}
return combatView;
}
@Override
@@ -559,7 +568,7 @@ public abstract class LocalGameView implements IGameView {
}
};
public final List<SpellAbilityView> getSpellAbilityViews(final List<SpellAbility> cards) {
public final List<SpellAbilityView> getSpellAbilityViews(final List<? extends SpellAbility> cards) {
return ViewUtil.transformIfNotNull(cards, FN_GET_SPAB_VIEW);
}

View File

@@ -135,7 +135,7 @@ public final class ViewUtil {
return view;
}
public static <T,V> List<V> transformIfNotNull(final Iterable<T> input, final Function<T, V> transformation) {
public static <T,V> List<V> transformIfNotNull(final Iterable<? extends T> input, final Function<T, V> transformation) {
final List<V> ret = Lists.newLinkedList();
synchronized (input) {
for (final T t : input) {