mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
Use delayed event queue to improve performance of game startup and event processing in general
This commit is contained in:
@@ -5,6 +5,8 @@ import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
@@ -57,6 +59,7 @@ import forge.model.FModel;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.Lang;
|
||||
import forge.util.ThreadUtil;
|
||||
import forge.util.gui.SGuiChoose;
|
||||
import forge.util.maps.MapOfLists;
|
||||
import forge.view.CardView;
|
||||
@@ -64,17 +67,50 @@ import forge.view.LocalGameView;
|
||||
import forge.view.PlayerView;
|
||||
|
||||
public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
private static FControlGameEventHandler mainHandler;
|
||||
|
||||
public static void processEventsAfterInput() {
|
||||
if (mainHandler.processEventsSchedule != null) {
|
||||
mainHandler.processEventsSchedule.cancel(false); //cancel any currently scheduled processing
|
||||
}
|
||||
mainHandler.processEventsDelay = 10; //speed up event processing until an event has been raised
|
||||
mainHandler.processEventsSchedule = ThreadUtil.delay(mainHandler.processEventsDelay, mainHandler.processEvents);
|
||||
}
|
||||
|
||||
private final LocalGameView gameView;
|
||||
private final boolean isMainHandler;
|
||||
private final ConcurrentLinkedQueue<GameEvent> eventQueue = new ConcurrentLinkedQueue<GameEvent>();
|
||||
|
||||
public FControlGameEventHandler(final LocalGameView gameView0, final boolean isMainHandler0) {
|
||||
gameView = gameView0;
|
||||
isMainHandler = isMainHandler0;
|
||||
if (isMainHandler) {
|
||||
mainHandler = this;
|
||||
}
|
||||
processEvents.run(); //start event processing loop
|
||||
}
|
||||
|
||||
private ScheduledFuture<?> processEventsSchedule;
|
||||
private int processEventsDelay = 100;
|
||||
private final Runnable processEvents = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!eventQueue.isEmpty()) {
|
||||
processEventsDelay = 100; //reset to 100 once an event has been raised
|
||||
gameView.updateViews();
|
||||
|
||||
GameEvent ev;
|
||||
while ((ev = eventQueue.poll()) != null) {
|
||||
ev.visit(FControlGameEventHandler.this);
|
||||
}
|
||||
}
|
||||
processEventsSchedule = ThreadUtil.delay(processEventsDelay, this); //only process events 10 times per second by default to improve performance
|
||||
}
|
||||
};
|
||||
|
||||
@Subscribe
|
||||
public void receiveGameEvent(final GameEvent ev) {
|
||||
ev.visit(this);
|
||||
eventQueue.add(ev);
|
||||
}
|
||||
|
||||
private final AtomicBoolean phaseUpdPlanned = new AtomicBoolean(false);
|
||||
@@ -103,11 +139,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
}
|
||||
|
||||
private void updateCombat() {
|
||||
if (!isMainHandler) { return; }
|
||||
|
||||
gameView.updateViews();
|
||||
|
||||
if (combatUpdPlanned.getAndSet(true)) { return; }
|
||||
if (!isMainHandler || combatUpdPlanned.getAndSet(true)) { return; }
|
||||
|
||||
FThreads.invokeInEdtNowOrLater(gameView.getGui(), new Runnable() {
|
||||
@Override
|
||||
@@ -144,7 +176,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventAnteCardsSelected ev) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
final List<CardView> options = Lists.newArrayList();
|
||||
for (final Entry<Player, Card> kv : ev.cards.entries()) {
|
||||
final CardView fakeCard = new CardView(-1); //use fake card so real cards appear with proper formatting
|
||||
@@ -162,7 +193,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
gameView.updateViews();
|
||||
FThreads.invokeInEdtNowOrLater(gameView.getGui(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -187,9 +217,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
|
||||
@Override
|
||||
public Void visit(GameEventGameFinished ev) {
|
||||
if (isMainHandler) {
|
||||
gameView.updateViews();
|
||||
}
|
||||
FThreads.invokeInEdtNowOrLater(gameView.getGui(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -200,6 +227,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
if (isMainHandler) {
|
||||
MatchUtil.getController().finishGame();
|
||||
gameView.updateAchievements();
|
||||
mainHandler = null; //this can be reset after game is finished
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -219,7 +247,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventSpellAbilityCast event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
if (!stackUpdPlanned.getAndSet(true)) {
|
||||
FThreads.invokeInEdtNowOrLater(gameView.getGui(), updStack);
|
||||
}
|
||||
@@ -229,7 +256,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventSpellResolved event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
if (!stackUpdPlanned.getAndSet(true)) {
|
||||
FThreads.invokeInEdtNowOrLater(gameView.getGui(), updStack);
|
||||
}
|
||||
@@ -239,7 +265,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventSpellRemovedFromStack event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
if (!stackUpdPlanned.getAndSet(true)) {
|
||||
FThreads.invokeInEdtNowOrLater(gameView.getGui(), updStack);
|
||||
}
|
||||
@@ -263,7 +288,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
|
||||
if (event.player != null) {
|
||||
// anything except stack will get here
|
||||
gameView.updateViews();
|
||||
updateZone(Pair.of(gameView.getPlayerView(event.player), event.zoneType));
|
||||
}
|
||||
return null;
|
||||
@@ -273,7 +297,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventCardAttachment event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
final Game game = event.equipment.getGame();
|
||||
final PlayerZone zEq = (PlayerZone)game.getZoneOf(event.equipment);
|
||||
if (event.oldEntiy instanceof Card) {
|
||||
@@ -318,7 +341,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(final GameEventCardTapped event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
return updateSingleCard(gameView.getCardView(event.card));
|
||||
}
|
||||
|
||||
@@ -326,7 +348,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(final GameEventCardPhased event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
return updateSingleCard(gameView.getCardView(event.card));
|
||||
}
|
||||
|
||||
@@ -334,7 +355,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(final GameEventCardDamaged event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
return updateSingleCard(gameView.getCardView(event.card));
|
||||
}
|
||||
|
||||
@@ -342,7 +362,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(final GameEventCardCounters event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
return updateSingleCard(gameView.getCardView(event.card));
|
||||
}
|
||||
|
||||
@@ -350,7 +369,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(final GameEventBlockersDeclared event) { // This is to draw icons on blockers declared by AI
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
for (MapOfLists<Card, Card> kv : event.blockers.values()) {
|
||||
for (Collection<Card> blockers : kv.values()) {
|
||||
updateManyCards(gameView.getCardViews(blockers));
|
||||
@@ -368,8 +386,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
gameView.updateViews();
|
||||
|
||||
// Update all attackers.
|
||||
// Although they might have been updated when they were tapped, there could be someone with vigilance, not redrawn yet.
|
||||
updateManyCards(gameView.getCardViews(event.attackersMap.values()));
|
||||
@@ -379,8 +395,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
|
||||
@Override
|
||||
public Void visit(GameEventCombatChanged event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.refreshCombat();
|
||||
updateCombat();
|
||||
return null;
|
||||
@@ -429,7 +443,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventCardChangeZone event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
if (event.from != null) {
|
||||
updateZone(event.from);
|
||||
}
|
||||
@@ -446,7 +459,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventCardStatsChanged event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
final Iterable<CardView> cardViews = gameView.getCardViews(event.cards);
|
||||
MatchUtil.getController().refreshCardDetails(cardViews);
|
||||
return updateManyCards(cardViews);
|
||||
@@ -456,7 +468,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventPlayerStatsChanged event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
for (final Player p : event.players) {
|
||||
MatchUtil.getController().refreshCardDetails(gameView.getCardViews(p.getAllCards()));
|
||||
}
|
||||
@@ -467,7 +478,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventShuffle event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
updateZone(event.player.getZone(ZoneType.Library));
|
||||
return null;
|
||||
}
|
||||
@@ -487,7 +497,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventManaPool event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
boolean invokeUpdate = false;
|
||||
synchronized (manaPoolUpdate) {
|
||||
if (!manaPoolUpdate.contains(event.player)) {
|
||||
@@ -515,7 +524,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventPlayerLivesChanged event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
boolean invokeUpdate = false;
|
||||
synchronized (livesUpdate) {
|
||||
if (!livesUpdate.contains(event.player)) {
|
||||
@@ -533,7 +541,6 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public Void visit(GameEventPlayerPoisoned event) {
|
||||
if (!isMainHandler) { return null; }
|
||||
|
||||
gameView.updateViews();
|
||||
boolean invokeUpdate = false;
|
||||
synchronized (livesUpdate) {
|
||||
if (!livesUpdate.contains(event.receiver)) {
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Observer;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.control.FControlGameEventHandler;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
@@ -66,7 +67,8 @@ public class InputProxy implements Observer {
|
||||
*/
|
||||
input.set(nextInput);
|
||||
Runnable showMessage = new Runnable() {
|
||||
@Override public void run() {
|
||||
@Override
|
||||
public void run() {
|
||||
Input current = getInput();
|
||||
gameView.getInputQueue().syncPoint();
|
||||
//System.out.printf("\t%s > showMessage @ %s/%s during %s%n", FThreads.debugGetCurrThreadId(), nextInput.getClass().getSimpleName(), current.getClass().getSimpleName(), game.getPhaseHandler().debugPrintState());
|
||||
@@ -84,6 +86,7 @@ public class InputProxy implements Observer {
|
||||
public final void selectButtonOK() {
|
||||
Input inp = getInput();
|
||||
if (inp != null) {
|
||||
FControlGameEventHandler.processEventsAfterInput();
|
||||
inp.selectButtonOK();
|
||||
}
|
||||
}
|
||||
@@ -96,6 +99,7 @@ public class InputProxy implements Observer {
|
||||
public final void selectButtonCancel() {
|
||||
Input inp = getInput();
|
||||
if (inp != null) {
|
||||
FControlGameEventHandler.processEventsAfterInput();
|
||||
inp.selectButtonCancel();
|
||||
}
|
||||
}
|
||||
@@ -105,6 +109,7 @@ public class InputProxy implements Observer {
|
||||
if (inp != null) {
|
||||
final Player player = gameView.getPlayer(playerView);
|
||||
if (player != null) {
|
||||
FControlGameEventHandler.processEventsAfterInput();
|
||||
inp.selectPlayer(player, triggerEvent);
|
||||
}
|
||||
}
|
||||
@@ -115,6 +120,7 @@ public class InputProxy implements Observer {
|
||||
if (inp != null) {
|
||||
final Card card = gameView.getCard(cardView);
|
||||
if (card != null) {
|
||||
FControlGameEventHandler.processEventsAfterInput();
|
||||
return inp.selectCard(card, triggerEvent);
|
||||
}
|
||||
}
|
||||
@@ -126,6 +132,7 @@ public class InputProxy implements Observer {
|
||||
if (inp != null) {
|
||||
final SpellAbility sa = gameView.getSpellAbility(ab);
|
||||
if (sa != null) {
|
||||
FControlGameEventHandler.processEventsAfterInput();
|
||||
inp.selectAbility(sa);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user