mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
- Huge update to network play
- Updated protocol: now used everywhere for type checking - No more locks between server and client: client no longer expects any replies - More code reuse - Fixed issue with location of multiple abilities selection popup menu - Improved stability; actual games should now be possible - Other updates - Mobile version player panel now uses same code as desktop - Remove automatic "view all cards" cheat in hotseat (no longer necessary) - Code cleanup
This commit is contained in:
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -17715,6 +17715,8 @@ forge-gui/src/main/java/forge/model/MultipleForgeJarsFoundError.java -text
|
|||||||
forge-gui/src/main/java/forge/model/UnOpenedMeta.java -text
|
forge-gui/src/main/java/forge/model/UnOpenedMeta.java -text
|
||||||
forge-gui/src/main/java/forge/model/package-info.java svneol=native#text/plain
|
forge-gui/src/main/java/forge/model/package-info.java svneol=native#text/plain
|
||||||
forge-gui/src/main/java/forge/net/GameProtocol.java -text
|
forge-gui/src/main/java/forge/net/GameProtocol.java -text
|
||||||
|
forge-gui/src/main/java/forge/net/GameProtocolHandler.java -text
|
||||||
|
forge-gui/src/main/java/forge/net/GameProtocolSender.java -text
|
||||||
forge-gui/src/main/java/forge/net/IRemote.java -text
|
forge-gui/src/main/java/forge/net/IRemote.java -text
|
||||||
forge-gui/src/main/java/forge/net/ReplyPool.java -text
|
forge-gui/src/main/java/forge/net/ReplyPool.java -text
|
||||||
forge-gui/src/main/java/forge/net/client/ClientGameLobby.java -text
|
forge-gui/src/main/java/forge/net/client/ClientGameLobby.java -text
|
||||||
@@ -17735,6 +17737,7 @@ forge-gui/src/main/java/forge/net/event/UpdateLobbyPlayerEvent.java -text
|
|||||||
forge-gui/src/main/java/forge/net/event/package-info.java -text
|
forge-gui/src/main/java/forge/net/event/package-info.java -text
|
||||||
forge-gui/src/main/java/forge/net/package-info.java -text
|
forge-gui/src/main/java/forge/net/package-info.java -text
|
||||||
forge-gui/src/main/java/forge/net/server/FServerManager.java -text
|
forge-gui/src/main/java/forge/net/server/FServerManager.java -text
|
||||||
|
forge-gui/src/main/java/forge/net/server/GameServerHandler.java -text
|
||||||
forge-gui/src/main/java/forge/net/server/IToClient.java -text
|
forge-gui/src/main/java/forge/net/server/IToClient.java -text
|
||||||
forge-gui/src/main/java/forge/net/server/NetGuiGame.java -text
|
forge-gui/src/main/java/forge/net/server/NetGuiGame.java -text
|
||||||
forge-gui/src/main/java/forge/net/server/RemoteClient.java -text
|
forge-gui/src/main/java/forge/net/server/RemoteClient.java -text
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public class PlayerControllerAi extends PlayerController {
|
|||||||
brains.setUseSimulation(value);
|
brains.setUseSimulation(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
|
public SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
|
||||||
if (abilities.size() == 0) {
|
if (abilities.size() == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,6 @@ package forge.util;
|
|||||||
|
|
||||||
public interface ITriggerEvent {
|
public interface ITriggerEvent {
|
||||||
int getButton();
|
int getButton();
|
||||||
|
int getX();
|
||||||
|
int getY();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package forge.util;
|
package forge.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.reflect.TypeUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static utilities related to reflection.
|
* Static utilities related to reflection.
|
||||||
*
|
*
|
||||||
@@ -62,4 +65,10 @@ public final class ReflectionUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isInstance(final Object obj, final Class<?> type) {
|
||||||
|
if (Array.class.equals(type)) {
|
||||||
|
return obj.getClass().isArray();
|
||||||
|
}
|
||||||
|
return TypeUtils.isInstance(obj, type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,6 @@ import forge.util.FCollectionView;
|
|||||||
public class GameView extends TrackableObject {
|
public class GameView extends TrackableObject {
|
||||||
private static final long serialVersionUID = 8522884512960961528L;
|
private static final long serialVersionUID = 8522884512960961528L;
|
||||||
|
|
||||||
/*private final TrackableIndex<CardView> cards = new TrackableIndex<CardView>();
|
|
||||||
private final TrackableIndex<PlayerView> players = new TrackableIndex<PlayerView>();
|
|
||||||
private final TrackableIndex<SpellAbilityView> spellAbilities = new TrackableIndex<SpellAbilityView>();
|
|
||||||
private final TrackableIndex<StackItemView> stackItems = new TrackableIndex<StackItemView>();*/
|
|
||||||
private final TrackableCollection<PlayerView> players;
|
private final TrackableCollection<PlayerView> players;
|
||||||
private CombatView combatView;
|
private CombatView combatView;
|
||||||
private final transient Game game; //TODO: Remove this when possible before network support added
|
private final transient Game game; //TODO: Remove this when possible before network support added
|
||||||
|
|||||||
@@ -720,7 +720,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
if (sas.isEmpty()) {
|
if (sas.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SpellAbility tgtSA = decider.getController().getAbilityToPlay(sas);
|
SpellAbility tgtSA = decider.getController().getAbilityToPlay(tgtCard, sas);
|
||||||
if (!decider.getController().confirmAction(tgtSA, null, "Do you want to play " + tgtCard + "?")) {
|
if (!decider.getController().confirmAction(tgtSA, null, "Do you want to play " + tgtCard + "?")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import forge.StaticData;
|
import forge.StaticData;
|
||||||
import forge.card.CardStateName;
|
|
||||||
import forge.card.CardRulesPredicates;
|
import forge.card.CardRulesPredicates;
|
||||||
|
import forge.card.CardStateName;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.SpellAbilityEffect;
|
import forge.game.ability.SpellAbilityEffect;
|
||||||
@@ -23,11 +28,6 @@ import forge.item.PaperCard;
|
|||||||
import forge.util.Aggregates;
|
import forge.util.Aggregates;
|
||||||
import forge.util.Lang;
|
import forge.util.Lang;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class PlayEffect extends SpellAbilityEffect {
|
public class PlayEffect extends SpellAbilityEffect {
|
||||||
@Override
|
@Override
|
||||||
protected String getStackDescription(SpellAbility sa) {
|
protected String getStackDescription(SpellAbility sa) {
|
||||||
@@ -160,13 +160,13 @@ public class PlayEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
Card original = tgtCard;
|
Card original = tgtCard;
|
||||||
if (sa.hasParam("CopyCard")) {
|
if (sa.hasParam("CopyCard")) {
|
||||||
Zone zone = tgtCard.getZone();
|
final Zone zone = tgtCard.getZone();
|
||||||
tgtCard = Card.fromPaperCard(tgtCard.getPaperCard(), sa.getActivatingPlayer());
|
tgtCard = Card.fromPaperCard(tgtCard.getPaperCard(), sa.getActivatingPlayer());
|
||||||
|
|
||||||
tgtCard.setToken(true);
|
tgtCard.setToken(true);
|
||||||
tgtCard.setZone(zone);
|
tgtCard.setZone(zone);
|
||||||
if (zone != null) {
|
if (zone != null) {
|
||||||
zone.add(tgtCard);
|
zone.add(tgtCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useEncoded) {
|
if (useEncoded) {
|
||||||
@@ -197,7 +197,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// only one mode can be used
|
// only one mode can be used
|
||||||
SpellAbility tgtSA = sa.getActivatingPlayer().getController().getAbilityToPlay(sas);
|
SpellAbility tgtSA = sa.getActivatingPlayer().getController().getAbilityToPlay(tgtCard, sas);
|
||||||
boolean noManaCost = sa.hasParam("WithoutManaCost");
|
boolean noManaCost = sa.hasParam("WithoutManaCost");
|
||||||
if (noManaCost) {
|
if (noManaCost) {
|
||||||
tgtSA = tgtSA.copyWithNoManaCost();
|
tgtSA = tgtSA.copyWithNoManaCost();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package forge.game.player;
|
package forge.game.player;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -10,7 +11,9 @@ import forge.game.zone.ZoneType;
|
|||||||
* Stores information to reveal cards after a delay unless those cards can be
|
* Stores information to reveal cards after a delay unless those cards can be
|
||||||
* revealed in the same dialog as cards being selected
|
* revealed in the same dialog as cards being selected
|
||||||
*/
|
*/
|
||||||
public class DelayedReveal {
|
public class DelayedReveal implements Serializable {
|
||||||
|
private static final long serialVersionUID = 5516713460440436615L;
|
||||||
|
|
||||||
private final Collection<CardView> cards;
|
private final Collection<CardView> cards;
|
||||||
private final ZoneType zone;
|
private final ZoneType zone;
|
||||||
private final PlayerView owner;
|
private final PlayerView owner;
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ public abstract class PlayerController {
|
|||||||
public Player getPlayer() { return player; }
|
public Player getPlayer() { return player; }
|
||||||
public LobbyPlayer getLobbyPlayer() { return lobbyPlayer; }
|
public LobbyPlayer getLobbyPlayer() { return lobbyPlayer; }
|
||||||
|
|
||||||
public final SpellAbility getAbilityToPlay(List<SpellAbility> abilities) { return getAbilityToPlay(abilities, null); }
|
public final SpellAbility getAbilityToPlay(final Card hostCard, final List<SpellAbility> abilities) { return getAbilityToPlay(hostCard, abilities, null); }
|
||||||
public abstract SpellAbility getAbilityToPlay(List<SpellAbility> abilities, ITriggerEvent triggerEvent);
|
public abstract SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent);
|
||||||
|
|
||||||
//public abstract void playFromSuspend(Card c);
|
//public abstract void playFromSuspend(Card c);
|
||||||
public abstract void playSpellAbilityForFree(SpellAbility copySA, boolean mayChoseNewTargets);
|
public abstract void playSpellAbilityForFree(SpellAbility copySA, boolean mayChoseNewTargets);
|
||||||
|
|||||||
@@ -375,6 +375,8 @@ public class PlayerView extends GameEntityView {
|
|||||||
}
|
}
|
||||||
public String getDetails() {
|
public String getDetails() {
|
||||||
final StringBuilder builder = new StringBuilder();
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append(getName());
|
||||||
|
builder.append('\n');
|
||||||
for (final String detailsPart : getDetailsList()) {
|
for (final String detailsPart : getDetailsList()) {
|
||||||
builder.append(detailsPart);
|
builder.append(detailsPart);
|
||||||
builder.append('\n');
|
builder.append('\n');
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package forge.screens.match;
|
package forge.screens.match;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -32,11 +32,10 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
import javax.swing.JMenu;
|
import javax.swing.JMenu;
|
||||||
import javax.swing.JPopupMenu;
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import javax.swing.MenuElement;
|
|
||||||
import javax.swing.MenuSelectionManager;
|
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
import forge.FThreads;
|
import forge.FThreads;
|
||||||
@@ -56,7 +55,6 @@ import forge.game.combat.CombatView;
|
|||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.DelayedReveal;
|
import forge.game.player.DelayedReveal;
|
||||||
import forge.game.player.IHasIcon;
|
import forge.game.player.IHasIcon;
|
||||||
import forge.game.player.Player;
|
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.game.spellability.SpellAbilityView;
|
import forge.game.spellability.SpellAbilityView;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
@@ -72,11 +70,9 @@ import forge.gui.framework.IVDoc;
|
|||||||
import forge.gui.framework.SDisplayUtil;
|
import forge.gui.framework.SDisplayUtil;
|
||||||
import forge.gui.framework.SLayoutIO;
|
import forge.gui.framework.SLayoutIO;
|
||||||
import forge.gui.framework.VEmptyDoc;
|
import forge.gui.framework.VEmptyDoc;
|
||||||
import forge.interfaces.IButton;
|
|
||||||
import forge.item.InventoryItem;
|
import forge.item.InventoryItem;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
import forge.match.AbstractGuiGame;
|
import forge.match.AbstractGuiGame;
|
||||||
import forge.match.MatchButtonType;
|
|
||||||
import forge.menus.IMenuProvider;
|
import forge.menus.IMenuProvider;
|
||||||
import forge.model.FModel;
|
import forge.model.FModel;
|
||||||
import forge.player.PlayerZoneUpdate;
|
import forge.player.PlayerZoneUpdate;
|
||||||
@@ -97,7 +93,6 @@ import forge.toolbox.FButton;
|
|||||||
import forge.toolbox.FOptionPane;
|
import forge.toolbox.FOptionPane;
|
||||||
import forge.toolbox.FSkin;
|
import forge.toolbox.FSkin;
|
||||||
import forge.toolbox.FSkin.SkinImage;
|
import forge.toolbox.FSkin.SkinImage;
|
||||||
import forge.toolbox.MouseTriggerEvent;
|
|
||||||
import forge.toolbox.special.PhaseIndicator;
|
import forge.toolbox.special.PhaseIndicator;
|
||||||
import forge.toolbox.special.PhaseLabel;
|
import forge.toolbox.special.PhaseLabel;
|
||||||
import forge.trackable.TrackableCollection;
|
import forge.trackable.TrackableCollection;
|
||||||
@@ -149,13 +144,13 @@ public final class CMatchUI
|
|||||||
Singletons.getView().getLpnDocument().add(targetingOverlay.getPanel(), FView.TARGETING_LAYER);
|
Singletons.getView().getLpnDocument().add(targetingOverlay.getPanel(), FView.TARGETING_LAYER);
|
||||||
targetingOverlay.getPanel().setSize(Singletons.getControl().getDisplaySize());
|
targetingOverlay.getPanel().setSize(Singletons.getControl().getDisplaySize());
|
||||||
this.myDocs = new EnumMap<EDocID, IVDoc<? extends ICDoc>>(EDocID.class);
|
this.myDocs = new EnumMap<EDocID, IVDoc<? extends ICDoc>>(EDocID.class);
|
||||||
this.myDocs.put(EDocID.CARD_PICTURE, getCDetailPicture().getCPicture().getView());
|
this.myDocs.put(EDocID.CARD_PICTURE, cDetailPicture.getCPicture().getView());
|
||||||
this.myDocs.put(EDocID.CARD_DETAIL, getCDetailPicture().getCDetail().getView());
|
this.myDocs.put(EDocID.CARD_DETAIL, cDetailPicture.getCDetail().getView());
|
||||||
this.myDocs.put(EDocID.CARD_ANTES, getCAntes().getView());
|
this.myDocs.put(EDocID.CARD_ANTES, cAntes.getView());
|
||||||
this.myDocs.put(EDocID.REPORT_MESSAGE, getCPrompt().getView());
|
this.myDocs.put(EDocID.REPORT_MESSAGE, getCPrompt().getView());
|
||||||
this.myDocs.put(EDocID.REPORT_STACK, getCStack().getView());
|
this.myDocs.put(EDocID.REPORT_STACK, getCStack().getView());
|
||||||
this.myDocs.put(EDocID.REPORT_COMBAT, getCCombat().getView());
|
this.myDocs.put(EDocID.REPORT_COMBAT, cCombat.getView());
|
||||||
this.myDocs.put(EDocID.REPORT_LOG, getCLog().getView());
|
this.myDocs.put(EDocID.REPORT_LOG, cLog.getView());
|
||||||
this.myDocs.put(EDocID.DEV_MODE, getCDev().getView());
|
this.myDocs.put(EDocID.DEV_MODE, getCDev().getView());
|
||||||
this.myDocs.put(EDocID.BUTTON_DOCK, getCDock().getView());;
|
this.myDocs.put(EDocID.BUTTON_DOCK, getCDock().getView());;
|
||||||
}
|
}
|
||||||
@@ -212,25 +207,13 @@ public final class CMatchUI
|
|||||||
getCDev().update();
|
getCDev().update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CAntes getCAntes() {
|
|
||||||
return cAntes;
|
|
||||||
}
|
|
||||||
public CCombat getCCombat() {
|
|
||||||
return cCombat;
|
|
||||||
}
|
|
||||||
public CDetailPicture getCDetailPicture() {
|
|
||||||
return cDetailPicture;
|
|
||||||
}
|
|
||||||
public CDev getCDev() {
|
public CDev getCDev() {
|
||||||
return cDev;
|
return cDev;
|
||||||
}
|
}
|
||||||
public CDock getCDock() {
|
public CDock getCDock() {
|
||||||
return cDock;
|
return cDock;
|
||||||
}
|
}
|
||||||
public CLog getCLog() {
|
CPrompt getCPrompt() {
|
||||||
return cLog;
|
|
||||||
}
|
|
||||||
public CPrompt getCPrompt() {
|
|
||||||
return cPrompt;
|
return cPrompt;
|
||||||
}
|
}
|
||||||
public CStack getCStack() {
|
public CStack getCStack() {
|
||||||
@@ -338,24 +321,6 @@ public final class CMatchUI
|
|||||||
return idx < 0 || idx >= allHands.size() ? null : allHands.get(idx);
|
return idx < 0 || idx >= allHands.size() ? null : allHands.get(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if game control should stop at a phase, for either a forced
|
|
||||||
* programmatic stop, or a user-induced phase toggle.
|
|
||||||
*
|
|
||||||
* @param turn
|
|
||||||
* the {@link Player} at whose phase might be stopped.
|
|
||||||
* @param phase
|
|
||||||
* the {@link PhaseType} at which might be stopped.
|
|
||||||
* @return boolean whether the current GUI calls for a stop at the specified
|
|
||||||
* phase of the specified player.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final boolean stopAtPhase(final PlayerView turn, final PhaseType phase) {
|
|
||||||
final VField vf = getFieldViewFor(turn);
|
|
||||||
final PhaseLabel label = vf.getPhaseIndicator().getLabelFor(phase);
|
|
||||||
return label == null || label.getEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCard(final CardView c) {
|
public void setCard(final CardView c) {
|
||||||
this.setCard(c, false);
|
this.setCard(c, false);
|
||||||
@@ -395,8 +360,8 @@ public final class CMatchUI
|
|||||||
SDisplayUtil.showTab(selectedDocBeforeCombat);
|
SDisplayUtil.showTab(selectedDocBeforeCombat);
|
||||||
selectedDocBeforeCombat = null;
|
selectedDocBeforeCombat = null;
|
||||||
}
|
}
|
||||||
getCCombat().setModel(combat);
|
cCombat.setModel(combat);
|
||||||
getCCombat().update();
|
cCombat.update();
|
||||||
} // showCombat(CombatView)
|
} // showCombat(CombatView)
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -548,26 +513,60 @@ public final class CMatchUI
|
|||||||
return panels;
|
return panels;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public IButton getBtnOK(final PlayerView playerView) {
|
* Find the card panel belonging to a card, bringing up the corresponding
|
||||||
return view.getBtnOK();
|
* window or tab if necessary.
|
||||||
|
*
|
||||||
|
* @param card
|
||||||
|
* the {@link CardView} to find a panel for.
|
||||||
|
* @return a {@link CardPanel}, or {@code null} if no corresponding panel is
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
private CardPanel findCardPanel(final CardView card) {
|
||||||
|
final int id = card.getId();
|
||||||
|
switch (card.getZone()) {
|
||||||
|
case Battlefield:
|
||||||
|
for (final VField f : view.getFieldViews()) {
|
||||||
|
final CardPanel panel = f.getTabletop().getCardPanel(id);
|
||||||
|
if (panel != null) {
|
||||||
|
SDisplayUtil.showTab(f);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Hand:
|
||||||
|
for (final VHand h : view.getHands()) {
|
||||||
|
final CardPanel panel = h.getHandArea().getCardPanel(id);
|
||||||
|
if (panel != null) {
|
||||||
|
SDisplayUtil.showTab(h);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Command:
|
||||||
|
case Exile:
|
||||||
|
case Graveyard:
|
||||||
|
case Library:
|
||||||
|
return FloatingCardArea.getCardPanel(this, card);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void updateButtons(final PlayerView owner, final String label1, final String label2, final boolean enable1, final boolean enable2, final boolean focus1) {
|
||||||
public IButton getBtnCancel(final PlayerView playerView) {
|
final FButton btn1 = view.getBtnOK(), btn2 = view.getBtnCancel();
|
||||||
return view.getBtnCancel();
|
btn1.setText(label1);
|
||||||
}
|
btn2.setText(label2);
|
||||||
|
btn1.setEnabled(enable1);
|
||||||
|
btn2.setEnabled(enable2);
|
||||||
|
|
||||||
@Override
|
final FButton toFocus = enable1 && focus1 ? btn1 : (enable2 ? btn2 : null);
|
||||||
public void focusButton(final MatchButtonType button) {
|
|
||||||
// ensure we don't steal focus from an overlay
|
// ensure we don't steal focus from an overlay
|
||||||
if (!SOverlayUtils.overlayHasFocus()) {
|
if (toFocus != null && !SOverlayUtils.overlayHasFocus()) {
|
||||||
FThreads.invokeInEdtLater(new Runnable() {
|
FThreads.invokeInEdtLater(new Runnable() {
|
||||||
@Override public final void run() {
|
@Override public final void run() {
|
||||||
final FButton btn = button == MatchButtonType.OK
|
toFocus.requestFocusInWindow();
|
||||||
? getCPrompt().getView().getBtnOK()
|
|
||||||
: getCPrompt().getView().getBtnCancel();
|
|
||||||
btn.requestFocusInWindow();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -671,7 +670,7 @@ public final class CMatchUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpellAbilityView getAbilityToPlay(final List<SpellAbilityView> abilities, final ITriggerEvent triggerEvent) {
|
public SpellAbilityView getAbilityToPlay(final CardView hostCard, final List<SpellAbilityView> abilities, final ITriggerEvent triggerEvent) {
|
||||||
if (triggerEvent == null) {
|
if (triggerEvent == null) {
|
||||||
if (abilities.isEmpty()) {
|
if (abilities.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
@@ -696,19 +695,20 @@ public final class CMatchUI
|
|||||||
final JPopupMenu menu = new JPopupMenu("Abilities");
|
final JPopupMenu menu = new JPopupMenu("Abilities");
|
||||||
|
|
||||||
boolean enabled;
|
boolean enabled;
|
||||||
boolean hasEnabled = false;
|
int firstEnabled = -1;
|
||||||
int shortcut = KeyEvent.VK_1; //use number keys as shortcuts for abilities 1-9
|
int shortcut = KeyEvent.VK_1; //use number keys as shortcuts for abilities 1-9
|
||||||
|
int index = 0;
|
||||||
for (final SpellAbilityView ab : abilities) {
|
for (final SpellAbilityView ab : abilities) {
|
||||||
enabled = ab.canPlay();
|
enabled = ab.canPlay();
|
||||||
if (enabled) {
|
if (enabled && firstEnabled < 0) {
|
||||||
hasEnabled = true;
|
firstEnabled = index;
|
||||||
}
|
}
|
||||||
GuiUtils.addMenuItem(menu, FSkin.encodeSymbols(ab.toString(), true),
|
GuiUtils.addMenuItem(menu, FSkin.encodeSymbols(ab.toString(), true),
|
||||||
shortcut > 0 ? KeyStroke.getKeyStroke(shortcut, 0) : null,
|
shortcut > 0 ? KeyStroke.getKeyStroke(shortcut, 0) : null,
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
cPrompt.selectAbility(ab);
|
getGameController().selectAbility(ab);
|
||||||
}
|
}
|
||||||
}, enabled);
|
}, enabled);
|
||||||
if (shortcut > 0) {
|
if (shortcut > 0) {
|
||||||
@@ -717,15 +717,38 @@ public final class CMatchUI
|
|||||||
shortcut = 0; //stop adding shortcuts after 9
|
shortcut = 0; //stop adding shortcuts after 9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
if (hasEnabled) { //only show menu if at least one ability can be played
|
|
||||||
SwingUtilities.invokeLater(new Runnable() { //use invoke later to ensure first ability selected by default
|
if (firstEnabled >= 0) { //only show menu if at least one ability can be played
|
||||||
public void run() {
|
final CardPanel panel = findCardPanel(hostCard);
|
||||||
MenuSelectionManager.defaultManager().setSelectedPath(new MenuElement[]{menu, menu.getSubElements()[0]});
|
final Component menuParent;
|
||||||
|
final int x, y;
|
||||||
|
if (panel == null) {
|
||||||
|
// Fall back to showing in VPrompt if no panel can be found
|
||||||
|
menuParent = getCPrompt().getView().getTarMessage();
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
SDisplayUtil.showTab(getCPrompt().getView());
|
||||||
|
} else {
|
||||||
|
final ZoneType zone = hostCard.getZone();
|
||||||
|
if (ImmutableList.of(ZoneType.Command, ZoneType.Exile, ZoneType.Graveyard, ZoneType.Library).contains(zone)) {
|
||||||
|
FloatingCardArea.show(this, hostCard.getController(), zone);
|
||||||
|
}
|
||||||
|
menuParent = panel.getParent();
|
||||||
|
x = triggerEvent.getX();
|
||||||
|
y = triggerEvent.getY();
|
||||||
|
}
|
||||||
|
menu.show(menuParent, x, y);
|
||||||
|
|
||||||
|
final int _firstEnabled = firstEnabled;
|
||||||
|
SwingUtilities.invokeLater(new Runnable() { //use invoke later to ensure first enabled ability selected by default
|
||||||
|
@Override public final void run() {
|
||||||
|
for (int i = 0; i <= _firstEnabled; i++) {
|
||||||
|
menu.dispatchEvent(new KeyEvent(menu, KeyEvent.KEY_PRESSED, 0, 0, KeyEvent.VK_DOWN, KeyEvent.CHAR_UNDEFINED));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
MouseEvent mouseEvent = ((MouseTriggerEvent)triggerEvent).getMouseEvent();
|
|
||||||
menu.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null; //delay ability until choice made
|
return null; //delay ability until choice made
|
||||||
@@ -772,7 +795,7 @@ public final class CMatchUI
|
|||||||
@Override
|
@Override
|
||||||
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
||||||
final GameView gameView = getGameView();
|
final GameView gameView = getGameView();
|
||||||
gameView.getGameLog().addObserver(getCLog());
|
gameView.getGameLog().addObserver(cLog);
|
||||||
|
|
||||||
// Sort players
|
// Sort players
|
||||||
FCollectionView<PlayerView> players = gameView.getPlayers();
|
FCollectionView<PlayerView> players = gameView.getPlayers();
|
||||||
|
|||||||
@@ -32,6 +32,6 @@ public class ZoneAction extends ForgeAction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(final ActionEvent e) {
|
public void actionPerformed(final ActionEvent e) {
|
||||||
FloatingCardArea.show(matchUI, player, zone);
|
FloatingCardArea.showOrHide(matchUI, player, zone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ public class CDock implements ICDoc {
|
|||||||
* End turn.
|
* End turn.
|
||||||
*/
|
*/
|
||||||
public void endTurn() {
|
public void endTurn() {
|
||||||
matchUI.getCPrompt().passPriorityUntilEndOfTurn();
|
matchUI.getGameController().passPriorityUntilEndOfTurn();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class CField implements ICDoc {
|
|||||||
private final MouseListener madAvatar = new MouseAdapter() {
|
private final MouseListener madAvatar = new MouseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(final MouseEvent e) {
|
public void mousePressed(final MouseEvent e) {
|
||||||
matchUI.getCPrompt().selectPlayer(player, new MouseTriggerEvent(e));
|
matchUI.getGameController().selectPlayer(player, new MouseTriggerEvent(e));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,9 +71,11 @@ public class CField implements ICDoc {
|
|||||||
final ZoneAction commandAction = new ZoneAction(matchUI, player, ZoneType.Command, MatchConstants.HUMANCOMMAND);
|
final ZoneAction commandAction = new ZoneAction(matchUI, player, ZoneType.Command, MatchConstants.HUMANCOMMAND);
|
||||||
|
|
||||||
final Function<Byte, Boolean> manaAction = new Function<Byte, Boolean>() {
|
final Function<Byte, Boolean> manaAction = new Function<Byte, Boolean>() {
|
||||||
public Boolean apply(Byte colorCode) {
|
public Boolean apply(final Byte colorCode) {
|
||||||
if (CField.this.player.isLobbyPlayer(Singletons.getControl().getGuiPlayer())) {
|
if (CField.this.player.isLobbyPlayer(Singletons.getControl().getGuiPlayer())) {
|
||||||
return matchUI.getGameController().useMana(colorCode.byteValue());
|
final int oldMana = player.getMana(colorCode);
|
||||||
|
matchUI.getGameController().useMana(colorCode.byteValue());
|
||||||
|
return oldMana != player.getMana(colorCode);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,22 +23,17 @@ import java.awt.event.ActionListener;
|
|||||||
import java.awt.event.FocusAdapter;
|
import java.awt.event.FocusAdapter;
|
||||||
import java.awt.event.FocusEvent;
|
import java.awt.event.FocusEvent;
|
||||||
import java.awt.event.FocusListener;
|
import java.awt.event.FocusListener;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
|
|
||||||
import forge.FThreads;
|
import forge.FThreads;
|
||||||
import forge.UiCommand;
|
import forge.UiCommand;
|
||||||
import forge.game.GameView;
|
import forge.game.GameView;
|
||||||
import forge.game.card.CardView;
|
|
||||||
import forge.game.player.PlayerView;
|
|
||||||
import forge.game.spellability.SpellAbilityView;
|
|
||||||
import forge.gui.framework.ICDoc;
|
import forge.gui.framework.ICDoc;
|
||||||
import forge.gui.framework.SDisplayUtil;
|
import forge.gui.framework.SDisplayUtil;
|
||||||
import forge.screens.match.CMatchUI;
|
import forge.screens.match.CMatchUI;
|
||||||
import forge.screens.match.views.VPrompt;
|
import forge.screens.match.views.VPrompt;
|
||||||
import forge.toolbox.FSkin;
|
import forge.toolbox.FSkin;
|
||||||
import forge.util.ITriggerEvent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls the prompt panel in the match UI.
|
* Controls the prompt panel in the match UI.
|
||||||
@@ -96,34 +91,14 @@ public class CPrompt implements ICDoc {
|
|||||||
_initButton(view.getBtnOK(), actOK);
|
_initButton(view.getBtnOK(), actOK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectButtonOk() {
|
private void selectButtonOk() {
|
||||||
matchUI.getGameController().selectButtonOk();
|
matchUI.getGameController().selectButtonOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectButtonCancel() {
|
private void selectButtonCancel() {
|
||||||
matchUI.getGameController().selectButtonCancel();
|
matchUI.getGameController().selectButtonCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean passPriority() {
|
|
||||||
return matchUI.getGameController().passPriority();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean passPriorityUntilEndOfTurn() {
|
|
||||||
return matchUI.getGameController().passPriorityUntilEndOfTurn();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void selectPlayer(final PlayerView playerView, final ITriggerEvent triggerEvent) {
|
|
||||||
matchUI.getGameController().selectPlayer(playerView, triggerEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean selectCard(final CardView cardView, final List<CardView> otherCardViewsToSelect, final ITriggerEvent triggerEvent) {
|
|
||||||
return matchUI.getGameController().selectCard(cardView, otherCardViewsToSelect, triggerEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void selectAbility(final SpellAbilityView sa) {
|
|
||||||
matchUI.getGameController().selectAbility(sa);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessage(String s0) {
|
public void setMessage(String s0) {
|
||||||
view.getTarMessage().setText(FSkin.encodeSymbols(s0, false));
|
view.getTarMessage().setText(FSkin.encodeSymbols(s0, false));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public final class GameMenu {
|
|||||||
return new ActionListener() {
|
return new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(final ActionEvent e) {
|
public void actionPerformed(final ActionEvent e) {
|
||||||
matchUI.getGameController().tryUndoLastAction();
|
matchUI.getGameController().undoLastAction();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ public class VStack implements IVDoc<CStack> {
|
|||||||
// Other fields
|
// Other fields
|
||||||
private final AbilityMenu abilityMenu = new AbilityMenu();
|
private final AbilityMenu abilityMenu = new AbilityMenu();
|
||||||
|
|
||||||
private static StackInstanceTextArea hoveredItem;
|
private StackInstanceTextArea hoveredItem;
|
||||||
|
|
||||||
public StackInstanceTextArea getHoveredItem() {
|
public StackInstanceTextArea getHoveredItem() {
|
||||||
return hoveredItem;
|
return hoveredItem;
|
||||||
@@ -267,7 +267,7 @@ public class VStack implements IVDoc<CStack> {
|
|||||||
controller.getMatchUI().setShouldAutoYield(key, !autoYield);
|
controller.getMatchUI().setShouldAutoYield(key, !autoYield);
|
||||||
if (!autoYield && controller.getMatchUI().getGameView().peekStack() == item) {
|
if (!autoYield && controller.getMatchUI().getGameView().peekStack() == item) {
|
||||||
//auto-pass priority if ability is on top of stack
|
//auto-pass priority if ability is on top of stack
|
||||||
controller.getMatchUI().getCPrompt().passPriority();
|
controller.getMatchUI().getGameController().passPriority();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,6 +17,24 @@
|
|||||||
*/
|
*/
|
||||||
package forge.toolbox;
|
package forge.toolbox;
|
||||||
|
|
||||||
|
import java.awt.AlphaComposite;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.FocusAdapter;
|
||||||
|
import java.awt.event.FocusEvent;
|
||||||
|
import java.awt.event.KeyAdapter;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
|
import javax.swing.BorderFactory;
|
||||||
|
|
||||||
import forge.UiCommand;
|
import forge.UiCommand;
|
||||||
import forge.assets.FSkinProp;
|
import forge.assets.FSkinProp;
|
||||||
import forge.gui.framework.ILocalRepaint;
|
import forge.gui.framework.ILocalRepaint;
|
||||||
@@ -25,11 +43,6 @@ import forge.toolbox.FSkin.Colors;
|
|||||||
import forge.toolbox.FSkin.SkinImage;
|
import forge.toolbox.FSkin.SkinImage;
|
||||||
import forge.toolbox.FSkin.SkinnedButton;
|
import forge.toolbox.FSkin.SkinnedButton;
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The core JButton used throughout the Forge project. Follows skin font and
|
* The core JButton used throughout the Forge project. Follows skin font and
|
||||||
* theme button styling.
|
* theme button styling.
|
||||||
|
|||||||
@@ -7,20 +7,28 @@ import forge.util.ITriggerEvent;
|
|||||||
|
|
||||||
//MouseEvent wrapper used for passing trigger to input classes
|
//MouseEvent wrapper used for passing trigger to input classes
|
||||||
public class MouseTriggerEvent implements ITriggerEvent, Serializable {
|
public class MouseTriggerEvent implements ITriggerEvent, Serializable {
|
||||||
private static final long serialVersionUID = -4746127117012991732L;
|
private static final long serialVersionUID = -5440485066050000298L;
|
||||||
|
|
||||||
private final MouseEvent event;
|
private final int button, x, y;
|
||||||
|
|
||||||
public MouseTriggerEvent(MouseEvent event0) {
|
public MouseTriggerEvent(final MouseEvent event) {
|
||||||
event = event0;
|
this.button = event.getButton();
|
||||||
|
this.x = event.getX();
|
||||||
|
this.y = event.getY();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getButton() {
|
public int getButton() {
|
||||||
return event.getButton();
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MouseEvent getMouseEvent() {
|
@Override
|
||||||
return event;
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.awt.event.MouseEvent;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.swing.ScrollPaneConstants;
|
import javax.swing.ScrollPaneConstants;
|
||||||
import javax.swing.Timer;
|
import javax.swing.Timer;
|
||||||
@@ -55,12 +56,20 @@ public class FloatingCardArea extends CardArea {
|
|||||||
private static final String COORD_DELIM = ",";
|
private static final String COORD_DELIM = ",";
|
||||||
|
|
||||||
private static final ForgePreferences prefs = FModel.getPreferences();
|
private static final ForgePreferences prefs = FModel.getPreferences();
|
||||||
private static final HashMap<Integer, FloatingCardArea> floatingAreas = new HashMap<Integer, FloatingCardArea>();
|
private static final Map<Integer, FloatingCardArea> floatingAreas = new HashMap<Integer, FloatingCardArea>();
|
||||||
|
|
||||||
private static int getKey(final PlayerView player, final ZoneType zone) {
|
private static int getKey(final PlayerView player, final ZoneType zone) {
|
||||||
return 40 * player.getId() + zone.hashCode();
|
return 40 * player.getId() + zone.hashCode();
|
||||||
}
|
}
|
||||||
|
public static void showOrHide(final CMatchUI matchUI, final PlayerView player, final ZoneType zone) {
|
||||||
|
final FloatingCardArea cardArea = _init(matchUI, player, zone);
|
||||||
|
cardArea.showOrHideWindow();
|
||||||
|
}
|
||||||
public static void show(final CMatchUI matchUI, final PlayerView player, final ZoneType zone) {
|
public static void show(final CMatchUI matchUI, final PlayerView player, final ZoneType zone) {
|
||||||
|
final FloatingCardArea cardArea = _init(matchUI, player, zone);
|
||||||
|
cardArea.showWindow();
|
||||||
|
}
|
||||||
|
private static FloatingCardArea _init(final CMatchUI matchUI, final PlayerView player, final ZoneType zone) {
|
||||||
final int key = getKey(player, zone);
|
final int key = getKey(player, zone);
|
||||||
FloatingCardArea cardArea = floatingAreas.get(key);
|
FloatingCardArea cardArea = floatingAreas.get(key);
|
||||||
if (cardArea == null || cardArea.getMatchUI() != matchUI) {
|
if (cardArea == null || cardArea.getMatchUI() != matchUI) {
|
||||||
@@ -69,7 +78,11 @@ public class FloatingCardArea extends CardArea {
|
|||||||
} else {
|
} else {
|
||||||
cardArea.setPlayer(player); //ensure player is updated if needed
|
cardArea.setPlayer(player); //ensure player is updated if needed
|
||||||
}
|
}
|
||||||
cardArea.showWindow();
|
return cardArea;
|
||||||
|
}
|
||||||
|
public static CardPanel getCardPanel(final CMatchUI matchUI, final CardView card) {
|
||||||
|
final FloatingCardArea window = _init(matchUI, card.getController(), card.getZone());
|
||||||
|
return window.getCardPanel(card.getId());
|
||||||
}
|
}
|
||||||
public static void refresh(final PlayerView player, final ZoneType zone) {
|
public static void refresh(final PlayerView player, final ZoneType zone) {
|
||||||
FloatingCardArea cardArea = floatingAreas.get(getKey(player, zone));
|
FloatingCardArea cardArea = floatingAreas.get(getKey(player, zone));
|
||||||
@@ -188,16 +201,22 @@ public class FloatingCardArea extends CardArea {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showWindow() {
|
private void showWindow() {
|
||||||
|
onShow();
|
||||||
|
window.setVisible(true);
|
||||||
|
}
|
||||||
|
private void showOrHideWindow() {
|
||||||
|
onShow();
|
||||||
|
window.setVisible(!window.isVisible());
|
||||||
|
}
|
||||||
|
private void onShow() {
|
||||||
if (!hasBeenShown) {
|
if (!hasBeenShown) {
|
||||||
loadLocation();
|
loadLocation();
|
||||||
window.getTitleBar().addMouseListener(new FMouseAdapter() {
|
window.getTitleBar().addMouseListener(new FMouseAdapter() {
|
||||||
@Override
|
@Override public final void onLeftDoubleClick(final MouseEvent e) {
|
||||||
public void onLeftDoubleClick(MouseEvent e) {
|
|
||||||
window.setVisible(false); //hide window if titlebar double-clicked
|
window.setVisible(false); //hide window if titlebar double-clicked
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
window.setVisible(!window.isVisible());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadLocation() {
|
private void loadLocation() {
|
||||||
@@ -251,7 +270,7 @@ public class FloatingCardArea extends CardArea {
|
|||||||
window.setSize(mainFrame.getWidth() / 5, mainFrame.getHeight() / 2);
|
window.setSize(mainFrame.getWidth() / 5, mainFrame.getHeight() / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refresh() {
|
private void refresh() {
|
||||||
if (!window.isVisible()) { return; } //don't refresh while window hidden
|
if (!window.isVisible()) { return; } //don't refresh while window hidden
|
||||||
|
|
||||||
List<CardPanel> cardPanels = new ArrayList<CardPanel>();
|
List<CardPanel> cardPanels = new ArrayList<CardPanel>();
|
||||||
@@ -292,7 +311,7 @@ public class FloatingCardArea extends CardArea {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final Timer layoutTimer = new Timer(250, new ActionListener() {
|
private final Timer layoutTimer = new Timer(250, new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
layoutTimer.stop();
|
layoutTimer.stop();
|
||||||
@@ -311,12 +330,12 @@ public class FloatingCardArea extends CardArea {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public final void mouseLeftClicked(final CardPanel panel, final MouseEvent evt) {
|
public final void mouseLeftClicked(final CardPanel panel, final MouseEvent evt) {
|
||||||
getMatchUI().getCPrompt().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt));
|
getMatchUI().getGameController().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt));
|
||||||
super.mouseLeftClicked(panel, evt);
|
super.mouseLeftClicked(panel, evt);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public final void mouseRightClicked(final CardPanel panel, final MouseEvent evt) {
|
public final void mouseRightClicked(final CardPanel panel, final MouseEvent evt) {
|
||||||
getMatchUI().getCPrompt().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt));
|
getMatchUI().getGameController().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt));
|
||||||
super.mouseRightClicked(panel, evt);
|
super.mouseRightClicked(panel, evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,14 +60,14 @@ public class HandArea extends CardArea {
|
|||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final void mouseLeftClicked(final CardPanel panel, final MouseEvent evt) {
|
public final void mouseLeftClicked(final CardPanel panel, final MouseEvent evt) {
|
||||||
getMatchUI().getCPrompt().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt));
|
getMatchUI().getGameController().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt));
|
||||||
super.mouseLeftClicked(panel, evt);
|
super.mouseLeftClicked(panel, evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final void mouseRightClicked(final CardPanel panel, final MouseEvent evt) {
|
public final void mouseRightClicked(final CardPanel panel, final MouseEvent evt) {
|
||||||
getMatchUI().getCPrompt().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt));
|
getMatchUI().getGameController().selectCard(panel.getCard(), null, new MouseTriggerEvent(evt));
|
||||||
super.mouseRightClicked(panel, evt);
|
super.mouseRightClicked(panel, evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -543,7 +543,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (getMatchUI().getCPrompt().selectCard(panel.getCard(), otherCardViewsToSelect, triggerEvent)) {
|
if (getMatchUI().getGameController().selectCard(panel.getCard(), otherCardViewsToSelect, triggerEvent)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//if panel can't do anything with card selection, try selecting previous panel in stack
|
//if panel can't do anything with card selection, try selecting previous panel in stack
|
||||||
|
|||||||
@@ -473,8 +473,9 @@ public class PlayerControllerForTests extends PlayerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
|
public SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
|
||||||
return getAbilityToPlay(abilities);
|
// Isn't this a method invocation loop? --elcnesh
|
||||||
|
return getAbilityToPlay(hostCard, abilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -34,11 +34,9 @@ import forge.game.player.IHasIcon;
|
|||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.game.spellability.SpellAbilityView;
|
import forge.game.spellability.SpellAbilityView;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.interfaces.IButton;
|
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
import forge.match.AbstractGuiGame;
|
import forge.match.AbstractGuiGame;
|
||||||
import forge.match.HostedMatch;
|
import forge.match.HostedMatch;
|
||||||
import forge.match.MatchButtonType;
|
|
||||||
import forge.model.FModel;
|
import forge.model.FModel;
|
||||||
import forge.player.PlayerZoneUpdate;
|
import forge.player.PlayerZoneUpdate;
|
||||||
import forge.properties.ForgePreferences;
|
import forge.properties.ForgePreferences;
|
||||||
@@ -50,6 +48,7 @@ import forge.screens.match.views.VPlayerPanel;
|
|||||||
import forge.screens.match.views.VPlayerPanel.InfoTab;
|
import forge.screens.match.views.VPlayerPanel.InfoTab;
|
||||||
import forge.screens.match.views.VPrompt;
|
import forge.screens.match.views.VPrompt;
|
||||||
import forge.screens.match.winlose.ViewWinLose;
|
import forge.screens.match.winlose.ViewWinLose;
|
||||||
|
import forge.toolbox.FButton;
|
||||||
import forge.toolbox.FDisplayObject;
|
import forge.toolbox.FDisplayObject;
|
||||||
import forge.toolbox.FOptionPane;
|
import forge.toolbox.FOptionPane;
|
||||||
import forge.trackable.TrackableCollection;
|
import forge.trackable.TrackableCollection;
|
||||||
@@ -142,24 +141,18 @@ public class MatchController extends AbstractGuiGame {
|
|||||||
Forge.openScreen(view);
|
Forge.openScreen(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public IButton getBtnOK(PlayerView player) {
|
|
||||||
return view.getPrompt(player).getBtnOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IButton getBtnCancel(PlayerView player) {
|
|
||||||
return view.getPrompt(player).getBtnCancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showPromptMessage(final PlayerView player, final String message) {
|
public void showPromptMessage(final PlayerView player, final String message) {
|
||||||
view.getPrompt(player).setMessage(message);
|
view.getPrompt(player).setMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void updateButtons(final PlayerView owner, final String label1, final String label2, final boolean enable1, final boolean enable2, final boolean focus1) {
|
||||||
public void focusButton(final MatchButtonType button) {
|
final VPrompt prompt = view.getPrompt(owner);
|
||||||
//not needed for mobile game
|
final FButton btn1 = prompt.getBtnOk(), btn2 = prompt.getBtnCancel();
|
||||||
|
btn1.setText(label1);
|
||||||
|
btn2.setText(label2);
|
||||||
|
btn1.setEnabled(enable1);
|
||||||
|
btn2.setEnabled(enable2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -224,7 +217,7 @@ public class MatchController extends AbstractGuiGame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpellAbilityView getAbilityToPlay(List<SpellAbilityView> abilities, ITriggerEvent triggerEvent) {
|
public SpellAbilityView getAbilityToPlay(final CardView hostCard, final List<SpellAbilityView> abilities, final ITriggerEvent triggerEvent) {
|
||||||
if (abilities.isEmpty()) {
|
if (abilities.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -320,11 +313,6 @@ public class MatchController extends AbstractGuiGame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean stopAtPhase(PlayerView turn, PhaseType phase) {
|
|
||||||
return view.stopAtPhase(turn, phase);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate) {
|
public void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate) {
|
||||||
view.updateZones(zonesToUpdate);
|
view.updateZones(zonesToUpdate);
|
||||||
|
|||||||
@@ -384,7 +384,7 @@ public class MatchScreen extends FScreen {
|
|||||||
break;
|
break;
|
||||||
case Keys.Z: //undo on Ctrl+Z
|
case Keys.Z: //undo on Ctrl+Z
|
||||||
if (KeyInputAdapter.isCtrlKeyDown()) {
|
if (KeyInputAdapter.isCtrlKeyDown()) {
|
||||||
getGameController().tryUndoLastAction();
|
getGameController().undoLastAction();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -91,7 +91,13 @@ public class VManaPool extends VDisplayArea {
|
|||||||
public boolean flick(float x, float y) {
|
public boolean flick(float x, float y) {
|
||||||
if (player.isLobbyPlayer(GamePlayerUtil.getGuiPlayer())) {
|
if (player.isLobbyPlayer(GamePlayerUtil.getGuiPlayer())) {
|
||||||
//on two finger tap, keep using mana until it runs out or no longer can be put towards the cost
|
//on two finger tap, keep using mana until it runs out or no longer can be put towards the cost
|
||||||
while (MatchController.instance.getGameController().useMana(colorCode)) {}
|
int oldMana, newMana = player.getMana(colorCode);
|
||||||
|
do {
|
||||||
|
oldMana = newMana;
|
||||||
|
MatchController.instance.getGameController().useMana(colorCode);
|
||||||
|
newMana = player.getMana(colorCode);
|
||||||
|
}
|
||||||
|
while (oldMana != newMana);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,8 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
|
|||||||
import forge.Graphics;
|
import forge.Graphics;
|
||||||
import forge.assets.FImage;
|
import forge.assets.FImage;
|
||||||
import forge.assets.FSkinFont;
|
import forge.assets.FSkinFont;
|
||||||
import forge.game.card.CardView;
|
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.menu.FDropDown;
|
import forge.menu.FDropDown;
|
||||||
import forge.model.FModel;
|
|
||||||
import forge.properties.ForgePreferences.FPref;
|
|
||||||
import forge.screens.match.MatchController;
|
import forge.screens.match.MatchController;
|
||||||
import forge.toolbox.FContainer;
|
import forge.toolbox.FContainer;
|
||||||
import forge.toolbox.FDisplayObject;
|
import forge.toolbox.FDisplayObject;
|
||||||
@@ -65,33 +62,7 @@ public class VPlayers extends FDropDown {
|
|||||||
g.drawImage(avatarImage, x, y, h, h);
|
g.drawImage(avatarImage, x, y, h, h);
|
||||||
x += h + PADDING;
|
x += h + PADDING;
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
g.drawText(player.getDetails(), FONT, FList.FORE_COLOR, x, y, getWidth() - PADDING - x, h, true, HAlignment.LEFT, true);
|
||||||
builder.append(player.getName());
|
|
||||||
builder.append("\nLife: " + String.valueOf(player.getLife()));
|
|
||||||
builder.append(" | Poison counters: " + String.valueOf(player.getPoisonCounters()));
|
|
||||||
builder.append(" | Maximum hand size: " + String.valueOf(player.getMaxHandSize()));
|
|
||||||
builder.append(" | Cards drawn this turn: " + String.valueOf(player.getNumDrawnThisTurn()));
|
|
||||||
builder.append(" | Damage Prevention: " + String.valueOf(player.getPreventNextDamage()));
|
|
||||||
if (!player.getKeywords().isEmpty()) {
|
|
||||||
builder.append(" | " + player.getKeywords().toString());
|
|
||||||
}
|
|
||||||
if (FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE)) {
|
|
||||||
Iterable<CardView> list = player.getAnte();
|
|
||||||
builder.append(" | Ante'd: ");
|
|
||||||
boolean needDelim = false;
|
|
||||||
for (CardView cv : list) {
|
|
||||||
if (needDelim) {
|
|
||||||
builder.append(", ");
|
|
||||||
}
|
|
||||||
else { needDelim = true; }
|
|
||||||
builder.append(cv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (MatchController.instance.getGameView().isCommander()) {
|
|
||||||
builder.append(" | " + player.getCommanderInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
g.drawText(builder.toString(), FONT, FList.FORE_COLOR, x, y, getWidth() - PADDING - x, h, true, HAlignment.LEFT, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -126,7 +126,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
|||||||
}
|
}
|
||||||
synchronized (zonesUpdate) {
|
synchronized (zonesUpdate) {
|
||||||
if (!zonesUpdate.isEmpty()) {
|
if (!zonesUpdate.isEmpty()) {
|
||||||
matchController.updateZones(zonesUpdate);
|
// Copy to prevent concurrency issues
|
||||||
|
matchController.updateZones(new PlayerZoneUpdates(zonesUpdate));
|
||||||
zonesUpdate.clear();
|
zonesUpdate.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,7 @@ public class WatchLocalGame extends PlayerControllerHuman {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean tryUndoLastAction() {
|
public void undoLastAction() {
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -63,18 +62,15 @@ public class WatchLocalGame extends PlayerControllerHuman {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean passPriority() {
|
public void passPriority() {
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean passPriorityUntilEndOfTurn() {
|
public void passPriorityUntilEndOfTurn() {
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean useMana(final byte mana) {
|
public void useMana(final byte mana) {
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,15 +18,15 @@ public interface IGameController {
|
|||||||
|
|
||||||
void alphaStrike();
|
void alphaStrike();
|
||||||
|
|
||||||
boolean useMana(byte color);
|
void useMana(byte color);
|
||||||
|
|
||||||
void selectButtonOk();
|
void selectButtonOk();
|
||||||
|
|
||||||
void selectButtonCancel();
|
void selectButtonCancel();
|
||||||
|
|
||||||
boolean passPriority();
|
void passPriority();
|
||||||
|
|
||||||
boolean passPriorityUntilEndOfTurn();
|
void passPriorityUntilEndOfTurn();
|
||||||
|
|
||||||
void selectPlayer(PlayerView playerView, ITriggerEvent triggerEvent);
|
void selectPlayer(PlayerView playerView, ITriggerEvent triggerEvent);
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ public interface IGameController {
|
|||||||
|
|
||||||
void selectAbility(SpellAbilityView sa);
|
void selectAbility(SpellAbilityView sa);
|
||||||
|
|
||||||
boolean tryUndoLastAction();
|
void undoLastAction();
|
||||||
|
|
||||||
IDevModeCheats cheat();
|
IDevModeCheats cheat();
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import forge.game.player.PlayerView;
|
|||||||
import forge.game.spellability.SpellAbilityView;
|
import forge.game.spellability.SpellAbilityView;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
import forge.match.MatchButtonType;
|
|
||||||
import forge.player.PlayerZoneUpdate;
|
import forge.player.PlayerZoneUpdate;
|
||||||
import forge.trackable.TrackableCollection;
|
import forge.trackable.TrackableCollection;
|
||||||
import forge.util.ITriggerEvent;
|
import forge.util.ITriggerEvent;
|
||||||
@@ -31,10 +30,8 @@ public interface IGuiGame {
|
|||||||
void afterGameEnd();
|
void afterGameEnd();
|
||||||
void showCombat();
|
void showCombat();
|
||||||
void showPromptMessage(PlayerView playerView, String message);
|
void showPromptMessage(PlayerView playerView, String message);
|
||||||
boolean stopAtPhase(PlayerView playerTurn, PhaseType phase);
|
void updateButtons(PlayerView owner, boolean okEnabled, boolean cancelEnabled, boolean focusOk);
|
||||||
IButton getBtnOK(PlayerView playerView);
|
void updateButtons(PlayerView owner, String label1, String label2, boolean enable1, boolean enable2, boolean focus1);
|
||||||
IButton getBtnCancel(PlayerView playerView);
|
|
||||||
void focusButton(MatchButtonType button);
|
|
||||||
void flashIncorrectAction();
|
void flashIncorrectAction();
|
||||||
void updatePhase();
|
void updatePhase();
|
||||||
void updateTurn(PlayerView player);
|
void updateTurn(PlayerView player);
|
||||||
@@ -52,11 +49,8 @@ public interface IGuiGame {
|
|||||||
void updateManaPool(Iterable<PlayerView> manaPoolUpdate);
|
void updateManaPool(Iterable<PlayerView> manaPoolUpdate);
|
||||||
void updateLives(Iterable<PlayerView> livesUpdate);
|
void updateLives(Iterable<PlayerView> livesUpdate);
|
||||||
void setPanelSelection(CardView hostCard);
|
void setPanelSelection(CardView hostCard);
|
||||||
SpellAbilityView getAbilityToPlay(List<SpellAbilityView> abilities,
|
SpellAbilityView getAbilityToPlay(CardView hostCard, List<SpellAbilityView> abilities, ITriggerEvent triggerEvent);
|
||||||
ITriggerEvent triggerEvent);
|
Map<CardView, Integer> assignDamage(CardView attacker, List<CardView> blockers, int damage, GameEntityView defender, boolean overrideOrder);
|
||||||
Map<CardView, Integer> assignDamage(CardView attacker,
|
|
||||||
List<CardView> blockers, int damage, GameEntityView defender,
|
|
||||||
boolean overrideOrder);
|
|
||||||
|
|
||||||
void message(String message);
|
void message(String message);
|
||||||
void message(String message, String title);
|
void message(String message, String title);
|
||||||
@@ -163,10 +157,6 @@ public interface IGuiGame {
|
|||||||
void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi);
|
void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi);
|
||||||
boolean openZones(Collection<ZoneType> zones, Map<PlayerView, Object> players);
|
boolean openZones(Collection<ZoneType> zones, Map<PlayerView, Object> players);
|
||||||
void restoreOldZones(Map<PlayerView, Object> playersToRestoreZonesFor);
|
void restoreOldZones(Map<PlayerView, Object> playersToRestoreZonesFor);
|
||||||
void updateButtons(PlayerView owner, boolean okEnabled,
|
|
||||||
boolean cancelEnabled, boolean focusOk);
|
|
||||||
void updateButtons(PlayerView owner, String okLabel, String cancelLabel,
|
|
||||||
boolean okEnabled, boolean cancelEnabled, boolean focusOk);
|
|
||||||
void setHighlighted(PlayerView pv, boolean b);
|
void setHighlighted(PlayerView pv, boolean b);
|
||||||
void setUsedToPay(CardView card, boolean value);
|
void setUsedToPay(CardView card, boolean value);
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import forge.game.GameView;
|
|||||||
import forge.game.card.CardView;
|
import forge.game.card.CardView;
|
||||||
import forge.game.card.CardView.CardStateView;
|
import forge.game.card.CardView.CardStateView;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.interfaces.IButton;
|
|
||||||
import forge.interfaces.IGameController;
|
import forge.interfaces.IGameController;
|
||||||
import forge.interfaces.IGuiGame;
|
import forge.interfaces.IGuiGame;
|
||||||
import forge.interfaces.IMayViewCards;
|
import forge.interfaces.IMayViewCards;
|
||||||
@@ -195,20 +194,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateButtons(final PlayerView owner, final String okLabel, final String cancelLabel, final boolean okEnabled, final boolean cancelEnabled, final boolean focusOk) {
|
public abstract void updateButtons(PlayerView owner, String label1, String label2, boolean enable1, boolean enable2, boolean focus1);
|
||||||
final IButton btnOk = getBtnOK(owner);
|
|
||||||
final IButton btnCancel = getBtnCancel(owner);
|
|
||||||
|
|
||||||
btnOk.setText(okLabel);
|
|
||||||
btnCancel.setText(cancelLabel);
|
|
||||||
btnOk.setEnabled(okEnabled);
|
|
||||||
btnCancel.setEnabled(cancelEnabled);
|
|
||||||
if (okEnabled && focusOk) {
|
|
||||||
focusButton(MatchButtonType.OK);
|
|
||||||
} else if (cancelEnabled) {
|
|
||||||
focusButton(MatchButtonType.CANCEL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-yield and other input-related code
|
// Auto-yield and other input-related code
|
||||||
|
|
||||||
|
|||||||
@@ -193,11 +193,6 @@ public class HostedMatch {
|
|||||||
gui.setGameController(null, humanController);
|
gui.setGameController(null, humanController);
|
||||||
|
|
||||||
gui.openView(null);
|
gui.openView(null);
|
||||||
} else if (humanCount == players.size()) {
|
|
||||||
//if there are no AI's, allow all players to see all cards (hotseat mode).
|
|
||||||
for (final PlayerControllerHuman humanController : humanControllers) {
|
|
||||||
humanController.setMayLookAtAllCards(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//prompt user for player one name if needed
|
//prompt user for player one name if needed
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ public class InputPassPriority extends InputSyncronizedBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final SpellAbility ability = getController().getAbilityToPlay(abilities, triggerEvent);
|
final SpellAbility ability = getController().getAbilityToPlay(card, abilities, triggerEvent);
|
||||||
if (ability != null) {
|
if (ability != null) {
|
||||||
chosenSa = new ArrayList<SpellAbility>();
|
chosenSa = new ArrayList<SpellAbility>();
|
||||||
chosenSa.add(ability);
|
chosenSa.add(ability);
|
||||||
|
|||||||
@@ -153,14 +153,12 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
|||||||
return abilities;
|
return abilities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean useManaFromPool(byte colorCode) {
|
public void useManaFromPool(byte colorCode) {
|
||||||
// find the matching mana in pool.
|
// find the matching mana in pool.
|
||||||
if (player.getManaPool().tryPayCostWithColor(colorCode, saPaidFor, manaCost)) {
|
if (player.getManaPool().tryPayCostWithColor(colorCode, saPaidFor, manaCost)) {
|
||||||
onManaAbilityPaid();
|
onManaAbilityPaid();
|
||||||
showMessage();
|
showMessage();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean activateManaAbility(final Card card, ManaCostBeingPaid manaCost) {
|
protected boolean activateManaAbility(final Card card, ManaCostBeingPaid manaCost) {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import java.util.Map;
|
|||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
|
||||||
import forge.UiCommand;
|
|
||||||
import forge.assets.FSkinProp;
|
import forge.assets.FSkinProp;
|
||||||
import forge.deck.CardPool;
|
import forge.deck.CardPool;
|
||||||
import forge.game.GameEntityView;
|
import forge.game.GameEntityView;
|
||||||
@@ -18,11 +17,12 @@ import forge.game.phase.PhaseType;
|
|||||||
import forge.game.player.DelayedReveal;
|
import forge.game.player.DelayedReveal;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.game.spellability.SpellAbilityView;
|
import forge.game.spellability.SpellAbilityView;
|
||||||
import forge.interfaces.IButton;
|
import forge.interfaces.IGameController;
|
||||||
import forge.interfaces.IGuiGame;
|
import forge.interfaces.IGuiGame;
|
||||||
import forge.match.MatchButtonType;
|
import forge.match.NextGameDecision;
|
||||||
import forge.trackable.TrackableCollection;
|
import forge.trackable.TrackableCollection;
|
||||||
import forge.util.ITriggerEvent;
|
import forge.util.ITriggerEvent;
|
||||||
|
import forge.util.ReflectionUtil;
|
||||||
|
|
||||||
public final class GameProtocol {
|
public final class GameProtocol {
|
||||||
|
|
||||||
@@ -36,101 +36,146 @@ public final class GameProtocol {
|
|||||||
return ProtocolMethod.valueOf(name);
|
return ProtocolMethod.valueOf(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum Mode {
|
||||||
|
SERVER(IGuiGame.class),
|
||||||
|
CLIENT(IGameController.class);
|
||||||
|
|
||||||
|
private final Class<?> toInvoke;
|
||||||
|
private Mode(final Class<?> toInvoke) {
|
||||||
|
this.toInvoke = toInvoke;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The methods that can be sent through this protocol.
|
* The methods that can be sent through this protocol.
|
||||||
*/
|
*/
|
||||||
public enum ProtocolMethod {
|
public enum ProtocolMethod {
|
||||||
setGameView(Void.TYPE, GameView.class),
|
// Server -> Client
|
||||||
openView(Void.TYPE, TrackableCollection.class),
|
setGameView (Mode.SERVER, Void.TYPE, GameView.class),
|
||||||
afterGameEnd(),
|
openView (Mode.SERVER, Void.TYPE, TrackableCollection/*PlayerView*/.class),
|
||||||
showCombat(),
|
afterGameEnd (Mode.SERVER),
|
||||||
showPromptMessage(Void.TYPE, PlayerView.class, String.class),
|
showCombat (Mode.SERVER),
|
||||||
stopAtPhase(Boolean.TYPE, PlayerView.class, PhaseType.class),
|
showPromptMessage (Mode.SERVER, Void.TYPE, PlayerView.class, String.class),
|
||||||
focusButton(Void.TYPE, MatchButtonType.class),
|
updateButtons (Mode.SERVER, Void.TYPE, PlayerView.class, String.class, String.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE),
|
||||||
flashIncorrectAction(),
|
flashIncorrectAction(Mode.SERVER),
|
||||||
updatePhase(),
|
updatePhase (Mode.SERVER),
|
||||||
updateTurn(Void.TYPE, PlayerView.class),
|
updateTurn (Mode.SERVER, Void.TYPE, PlayerView.class),
|
||||||
updatePlayerControl(),
|
updatePlayerControl (Mode.SERVER),
|
||||||
enableOverlay(),
|
enableOverlay (Mode.SERVER),
|
||||||
disableOverlay(),
|
disableOverlay (Mode.SERVER),
|
||||||
finishGame(),
|
finishGame (Mode.SERVER),
|
||||||
showManaPool(Void.TYPE, PlayerView.class),
|
showManaPool (Mode.SERVER, Object.class, PlayerView.class),
|
||||||
hideManaPool(Void.TYPE, PlayerView.class),
|
hideManaPool (Mode.SERVER, Void.TYPE, PlayerView.class),
|
||||||
updateStack(),
|
updateStack (Mode.SERVER),
|
||||||
updateZones(Void.TYPE, Iterable.class),
|
updateZones (Mode.SERVER, Void.TYPE, Iterable/*PlayerZoneUpdate*/.class),
|
||||||
updateCards(Void.TYPE, Iterable.class),
|
updateCards (Mode.SERVER, Void.TYPE, Iterable/*CardView*/.class),
|
||||||
updateManaPool(Void.TYPE, Iterable.class),
|
updateManaPool (Mode.SERVER, Void.TYPE, Iterable/*PlayerView*/.class),
|
||||||
updateLives(Void.TYPE, Iterable.class),
|
updateLives (Mode.SERVER, Void.TYPE, Iterable/*PlayerView*/.class),
|
||||||
setPanelSelection(Void.TYPE, CardView.class),
|
setPanelSelection (Mode.SERVER, Void.TYPE, CardView.class),
|
||||||
getAbilityToPlay(SpellAbilityView.class, List.class, ITriggerEvent.class),
|
getAbilityToPlay (Mode.SERVER, SpellAbilityView.class, CardView.class, List/*SpellAbilityView*/.class, ITriggerEvent.class),
|
||||||
assignDamage(Map.class, CardView.class, List.class, Integer.TYPE, GameEntityView.class, Boolean.TYPE),
|
assignDamage (Mode.SERVER, Map.class, CardView.class, List/*CardView*/.class, Integer.TYPE, GameEntityView.class, Boolean.TYPE),
|
||||||
message(Void.TYPE, String.class, String.class),
|
message (Mode.SERVER, Void.TYPE, String.class, String.class),
|
||||||
showErrorDialog(Void.TYPE, String.class, String.class),
|
showErrorDialog (Mode.SERVER, Void.TYPE, String.class, String.class),
|
||||||
showConfirmDialog(Boolean.TYPE, String.class, String.class, String.class, String.class, Boolean.TYPE),
|
showConfirmDialog (Mode.SERVER, Boolean.TYPE, String.class, String.class, String.class, String.class, Boolean.TYPE),
|
||||||
showOptionDialog(Integer.TYPE, String.class, String.class, FSkinProp.class, Array.class, Integer.TYPE),
|
showOptionDialog (Mode.SERVER, Integer.TYPE, String.class, String.class, FSkinProp.class, Array/*String*/.class, Integer.TYPE),
|
||||||
showCardOptionDialog(Integer.TYPE, CardView.class, String.class, String.class, FSkinProp.class, String.class, Array.class),
|
showCardOptionDialog(Mode.SERVER, Integer.TYPE, CardView.class, String.class, String.class, FSkinProp.class, String.class, Array/*String*/.class),
|
||||||
showInputDialog(String.class, String.class, String.class, FSkinProp.class, String.class, Array.class),
|
showInputDialog (Mode.SERVER, String.class, String.class, String.class, FSkinProp.class, String.class, Array/*String*/.class),
|
||||||
confirm(Boolean.TYPE, CardView.class, String.class, Boolean.TYPE, Array.class),
|
confirm (Mode.SERVER, Boolean.TYPE, CardView.class, String.class, Boolean.TYPE, Array/*String*/.class),
|
||||||
getChoices(List.class, String.class, Integer.TYPE, Integer.TYPE, Collection.class, Object.class, Function.class),
|
getChoices (Mode.SERVER, List.class, String.class, Integer.TYPE, Integer.TYPE, Collection.class, Object.class, Function.class),
|
||||||
order(List.class, String.class, String.class, Integer.TYPE, Integer.TYPE, List.class, List.class, CardView.class, Boolean.TYPE),
|
order (Mode.SERVER, List.class, String.class, String.class, Integer.TYPE, Integer.TYPE, List.class, List.class, CardView.class, Boolean.TYPE),
|
||||||
sideboard(List.class, CardPool.class, CardPool.class),
|
sideboard (Mode.SERVER, List.class, CardPool.class, CardPool.class),
|
||||||
chooseSingleEntityForEffect(GameEntityView.class, String.class, TrackableCollection.class, DelayedReveal.class, Boolean.TYPE),
|
chooseSingleEntityForEffect(Mode.SERVER, GameEntityView.class, String.class, TrackableCollection.class, DelayedReveal.class, Boolean.TYPE),
|
||||||
setCard(Void.TYPE, CardView.class),
|
setCard (Mode.SERVER, Void.TYPE, CardView.class),
|
||||||
// TODO case "setPlayerAvatar":
|
// TODO case "setPlayerAvatar":
|
||||||
openZones(Boolean.TYPE, Collection.class, Map.class),
|
openZones (Mode.SERVER, Boolean.TYPE, Collection/*ZoneType*/.class, Map/*PlayerView,Object*/.class),
|
||||||
restoreOldZones(Void.TYPE, Map.class),
|
restoreOldZones (Mode.SERVER, Void.TYPE, Map/*PlayerView,Object*/.class),
|
||||||
isUiSetToSkipPhase(Boolean.TYPE, PlayerView.class, PhaseType.class),
|
isUiSetToSkipPhase (Mode.SERVER, Boolean.TYPE, PlayerView.class, PhaseType.class),
|
||||||
// BUTTONS
|
|
||||||
btn_setEnabled(Void.TYPE, Boolean.TYPE),
|
|
||||||
btn_setVisible(Void.TYPE, Boolean.TYPE),
|
|
||||||
btn_setText(Void.TYPE, String.class),
|
|
||||||
btn_isSelected(Boolean.TYPE),
|
|
||||||
btn_setSelected(Void.TYPE, Boolean.TYPE),
|
|
||||||
btn_requestFocusInWindows(Boolean.TYPE),
|
|
||||||
btn_setCommand(Void.TYPE, UiCommand.class),
|
|
||||||
btn_setImage(Void.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE),
|
|
||||||
btn_setTextImage(Void.TYPE, FSkinProp.class);
|
|
||||||
|
|
||||||
|
// Client -> Server
|
||||||
|
// Note: these should all return void, to avoid awkward situations in
|
||||||
|
// which client and server wait for one another's response and block
|
||||||
|
// the threads that're supposed to give that response
|
||||||
|
useMana (Mode.CLIENT, Void.TYPE, Byte.TYPE),
|
||||||
|
undoLastAction (Mode.CLIENT, Void.TYPE, Boolean.TYPE),
|
||||||
|
selectPlayer (Mode.CLIENT, Void.TYPE, PlayerView.class, ITriggerEvent.class),
|
||||||
|
selectCard (Mode.CLIENT, Void.TYPE, CardView.class, List.class, ITriggerEvent.class),
|
||||||
|
selectButtonOk (Mode.CLIENT),
|
||||||
|
selectButtonCancel (Mode.CLIENT),
|
||||||
|
selectAbility (Mode.CLIENT, Void.TYPE, SpellAbilityView.class),
|
||||||
|
passPriorityUntilEndOfTurn(Mode.CLIENT),
|
||||||
|
passPriority (Mode.CLIENT),
|
||||||
|
nextGameDecision (Mode.CLIENT, Void.TYPE, NextGameDecision.class),
|
||||||
|
getActivateDescription (Mode.CLIENT, Void.TYPE, String.class, CardView.class),
|
||||||
|
concede (Mode.CLIENT),
|
||||||
|
alphaStrike (Mode.CLIENT),
|
||||||
|
reorderHand (Mode.CLIENT, Void.TYPE, CardView.class, Integer.TYPE);
|
||||||
|
|
||||||
|
private final Mode mode;
|
||||||
private final Class<?> returnType;
|
private final Class<?> returnType;
|
||||||
private final Class<?>[] args;
|
private final Class<?>[] args;
|
||||||
|
|
||||||
private ProtocolMethod() {
|
private ProtocolMethod(final Mode mode) {
|
||||||
this(Void.TYPE);
|
this(mode, Void.TYPE);
|
||||||
}
|
}
|
||||||
private ProtocolMethod(final Class<?> returnType) {
|
private ProtocolMethod(final Mode mode, final Class<?> returnType) {
|
||||||
this(returnType, (Class<?>[]) null);
|
this(mode, returnType, (Class<?>[]) null);
|
||||||
}
|
}
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
private ProtocolMethod(final Class<?> returnType, final Class<?> ... args) {
|
private ProtocolMethod(final Mode mode, final Class<?> returnType, final Class<?> ... args) {
|
||||||
|
this.mode = mode;
|
||||||
this.returnType = returnType;
|
this.returnType = returnType;
|
||||||
this.args = args == null ? new Class<?>[] {} : args;
|
this.args = args == null ? new Class<?>[] {} : args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Method getMethod() {
|
public Method getMethod() {
|
||||||
try {
|
try {
|
||||||
final String name;
|
final Class<?> toCall = mode.toInvoke;
|
||||||
final Class<?> toCall;
|
final Method candidate = toCall.getMethod(name(), args);
|
||||||
if (name().startsWith("btn_")) {
|
// Don't check Client return values for now as some use void
|
||||||
name = name().substring("btn_".length());
|
// and a default return value, to improve performance
|
||||||
toCall = IButton.class;
|
if (mode == Mode.SERVER && !candidate.getReturnType().equals(returnType)) {
|
||||||
} else {
|
|
||||||
name = name();
|
|
||||||
toCall = IGuiGame.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Method candidate = toCall.getMethod(name, args);
|
|
||||||
if (!candidate.getReturnType().equals(returnType)) {
|
|
||||||
throw new NoSuchMethodException(String.format("Wrong return type for method %s", name()));
|
throw new NoSuchMethodException(String.format("Wrong return type for method %s", name()));
|
||||||
}
|
}
|
||||||
return candidate;
|
return candidate;
|
||||||
} catch (final NoSuchMethodException | SecurityException e) {
|
} catch (final NoSuchMethodException | SecurityException e) {
|
||||||
System.err.println(String.format("Warning: class contains no method named %s", name()));
|
System.err.println(String.format("Warning: class contains no accessible method named %s", name()));
|
||||||
return null;
|
return getMethodNoArgs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean invokeOnButton() {
|
private Method getMethodNoArgs() {
|
||||||
return name().startsWith("btn_");
|
try {
|
||||||
|
return mode.toInvoke.getMethod(name(), (Class<?>[]) null);
|
||||||
|
} catch (final NoSuchMethodException | SecurityException e) {
|
||||||
|
System.err.println(String.format("Warning: class contains no accessible arg-less method named %s", name()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Class<?> getReturnType() {
|
||||||
|
return returnType;
|
||||||
|
}
|
||||||
|
public Class<?>[] getArgTypes() {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkArgs(final Object[] args) {
|
||||||
|
for (int iArg = 0; iArg < args.length; iArg++) {
|
||||||
|
final Object arg = args[iArg];
|
||||||
|
final Class<?> type = this.args[iArg];
|
||||||
|
if (!ReflectionUtil.isInstance(arg, type)) {
|
||||||
|
throw new InternalError(String.format("Protocol method %s: illegal argument (%d) of type %s, %s expected", name(), iArg, arg.getClass().getName(), type.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkReturnValue(final Object value) {
|
||||||
|
if (returnType.equals(Void.TYPE)) {
|
||||||
|
// If void is expected, any return value is fine
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!ReflectionUtil.isInstance(value, returnType)) {
|
||||||
|
throw new IllegalStateException(String.format("Protocol method %s: illegal return object type %s returned by client, expected %s", name(), value.getClass().getName(), getReturnType().getName()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
96
forge-gui/src/main/java/forge/net/GameProtocolHandler.java
Normal file
96
forge-gui/src/main/java/forge/net/GameProtocolHandler.java
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package forge.net;
|
||||||
|
|
||||||
|
import forge.FThreads;
|
||||||
|
import forge.net.GameProtocol.ProtocolMethod;
|
||||||
|
import forge.net.event.GuiGameEvent;
|
||||||
|
import forge.net.event.ReplyEvent;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public abstract class GameProtocolHandler<T> extends ChannelInboundHandlerAdapter {
|
||||||
|
|
||||||
|
private final boolean runInEdt;
|
||||||
|
protected GameProtocolHandler(final boolean runInEdt) {
|
||||||
|
this.runInEdt = runInEdt;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract ReplyPool getReplyPool(ChannelHandlerContext ctx);
|
||||||
|
protected abstract IRemote getRemote(ChannelHandlerContext ctx);
|
||||||
|
|
||||||
|
protected abstract T getToInvoke(ChannelHandlerContext ctx);
|
||||||
|
protected abstract void beforeCall(ProtocolMethod protocolMethod, Object[] args);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void channelRead(final ChannelHandlerContext ctx, final Object msg) {
|
||||||
|
System.out.println("Received: " + msg);
|
||||||
|
if (msg instanceof ReplyEvent) {
|
||||||
|
final ReplyEvent event = (ReplyEvent) msg;
|
||||||
|
getReplyPool(ctx).complete(event.getIndex(), event.getReply());
|
||||||
|
} else if (msg instanceof GuiGameEvent) {
|
||||||
|
final GuiGameEvent event = (GuiGameEvent) msg;
|
||||||
|
final ProtocolMethod protocolMethod = event.getMethod();
|
||||||
|
final String methodName = protocolMethod.name();
|
||||||
|
|
||||||
|
final Method method = protocolMethod.getMethod();
|
||||||
|
if (method == null) {
|
||||||
|
throw new IllegalStateException(String.format("Method %s not found", protocolMethod.name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object[] args = event.getObjects();
|
||||||
|
protocolMethod.checkArgs(args);
|
||||||
|
|
||||||
|
final Object toInvoke = getToInvoke(ctx);
|
||||||
|
|
||||||
|
// Pre-call actions
|
||||||
|
beforeCall(protocolMethod, args);
|
||||||
|
|
||||||
|
final Class<?> returnType = protocolMethod.getReturnType();
|
||||||
|
final Runnable toRun = new Runnable() {
|
||||||
|
@Override public final void run() {
|
||||||
|
if (returnType.equals(Void.TYPE)) {
|
||||||
|
try {
|
||||||
|
method.invoke(toInvoke, args);
|
||||||
|
} catch (final IllegalAccessException | IllegalArgumentException e) {
|
||||||
|
System.err.println(String.format("Unknown protocol method %s with %d args", methodName, args == null ? 0 : args.length));
|
||||||
|
} catch (final InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serializable reply = null;
|
||||||
|
try {
|
||||||
|
final Object theReply = method.invoke(toInvoke, args);
|
||||||
|
if (theReply instanceof Serializable) {
|
||||||
|
protocolMethod.checkReturnValue(theReply);
|
||||||
|
reply = (Serializable) theReply;
|
||||||
|
} else if (theReply != null) {
|
||||||
|
System.err.println(String.format("Non-serializable return type %s for method %s, returning null", returnType.getName(), methodName));
|
||||||
|
}
|
||||||
|
} catch (final IllegalAccessException | IllegalArgumentException e) {
|
||||||
|
System.err.println(String.format("Unknown protocol method %s with %d args, replying with null", methodName, args == null ? 0 : args.length));
|
||||||
|
} catch (final InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
getRemote(ctx).send(new ReplyEvent(event.getId(), reply));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (runInEdt) {
|
||||||
|
FThreads.invokeInEdtNowOrLater(toRun);
|
||||||
|
} else {
|
||||||
|
FThreads.invokeInBackgroundThread(toRun);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
|
||||||
|
cause.printStackTrace();
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
32
forge-gui/src/main/java/forge/net/GameProtocolSender.java
Normal file
32
forge-gui/src/main/java/forge/net/GameProtocolSender.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package forge.net;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import forge.net.GameProtocol.ProtocolMethod;
|
||||||
|
import forge.net.event.GuiGameEvent;
|
||||||
|
|
||||||
|
public final class GameProtocolSender {
|
||||||
|
|
||||||
|
private final IRemote remote;
|
||||||
|
public GameProtocolSender(final IRemote remote) {
|
||||||
|
this.remote = remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(final ProtocolMethod method, final Object... args) {
|
||||||
|
method.checkArgs(args);
|
||||||
|
remote.send(new GuiGameEvent(method, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T sendAndWait(final ProtocolMethod method, final Object... args) {
|
||||||
|
method.checkArgs(args);
|
||||||
|
try {
|
||||||
|
final Object returned = remote.sendAndWait(new GuiGameEvent(method, args));
|
||||||
|
method.checkReturnValue(returned);
|
||||||
|
return (T) returned;
|
||||||
|
} catch (final TimeoutException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,26 +1,18 @@
|
|||||||
package forge.net.client;
|
package forge.net.client;
|
||||||
|
|
||||||
import forge.FThreads;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.interfaces.IGuiGame;
|
import forge.interfaces.IGuiGame;
|
||||||
import forge.match.MatchButtonType;
|
|
||||||
import forge.model.FModel;
|
import forge.model.FModel;
|
||||||
import forge.net.GameProtocol;
|
|
||||||
import forge.net.GameProtocol.ProtocolMethod;
|
import forge.net.GameProtocol.ProtocolMethod;
|
||||||
import forge.net.event.GuiGameEvent;
|
import forge.net.GameProtocolHandler;
|
||||||
|
import forge.net.IRemote;
|
||||||
|
import forge.net.ReplyPool;
|
||||||
import forge.net.event.LoginEvent;
|
import forge.net.event.LoginEvent;
|
||||||
import forge.net.event.ReplyEvent;
|
|
||||||
import forge.properties.ForgePreferences.FPref;
|
import forge.properties.ForgePreferences.FPref;
|
||||||
import forge.trackable.TrackableCollection;
|
import forge.trackable.TrackableCollection;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
final class GameClientHandler extends GameProtocolHandler<IGuiGame> {
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
class GameClientHandler extends ChannelInboundHandlerAdapter {
|
|
||||||
private final FGameClient client;
|
private final FGameClient client;
|
||||||
private final IGuiGame gui;
|
private final IGuiGame gui;
|
||||||
|
|
||||||
@@ -28,93 +20,43 @@ class GameClientHandler extends ChannelInboundHandlerAdapter {
|
|||||||
* Creates a client-side game handler.
|
* Creates a client-side game handler.
|
||||||
*/
|
*/
|
||||||
public GameClientHandler(final FGameClient client) {
|
public GameClientHandler(final FGameClient client) {
|
||||||
|
super(true);
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.gui = client.getGui();
|
this.gui = client.getGui();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ReplyPool getReplyPool(final ChannelHandlerContext ctx) {
|
||||||
|
return client.getReplyPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IRemote getRemote(final ChannelHandlerContext ctx) {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IGuiGame getToInvoke(final ChannelHandlerContext ctx) {
|
||||||
|
return gui;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
protected void beforeCall(final ProtocolMethod protocolMethod, final Object[] args) {
|
||||||
|
switch (protocolMethod) {
|
||||||
|
case openView:
|
||||||
|
final TrackableCollection<PlayerView> myPlayers = (TrackableCollection<PlayerView>) args[0];
|
||||||
|
client.setGameControllers(myPlayers);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelActive(final ChannelHandlerContext ctx) {
|
public void channelActive(final ChannelHandlerContext ctx) {
|
||||||
// Don't use send() here, as this.channel is not yet set!
|
// Don't use send() here, as this.channel is not yet set!
|
||||||
ctx.channel().writeAndFlush(new LoginEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",")[0])));
|
ctx.channel().writeAndFlush(new LoginEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",")[0])));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
|
|
||||||
System.out.println("Client received: " + msg);
|
|
||||||
if (msg instanceof ReplyEvent) {
|
|
||||||
final ReplyEvent event = (ReplyEvent) msg;
|
|
||||||
client.getReplyPool().complete(event.getIndex(), event.getReply());
|
|
||||||
} else if (msg instanceof GuiGameEvent) {
|
|
||||||
final GuiGameEvent event = (GuiGameEvent) msg;
|
|
||||||
final String methodName = event.getMethod();
|
|
||||||
|
|
||||||
final Object[] originalArgs = event.getObjects();
|
|
||||||
final ProtocolMethod protocolMethod = GameProtocol.getProtocolMethod(methodName);
|
|
||||||
if (protocolMethod == null) {
|
|
||||||
throw new IllegalStateException(String.format("Protocol method %s unknown", methodName));
|
|
||||||
}
|
|
||||||
final Method method = protocolMethod.getMethod();
|
|
||||||
if (method == null) {
|
|
||||||
throw new IllegalStateException(String.format("Method %s not found", protocolMethod.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
final Object toInvoke;
|
|
||||||
final Object[] args;
|
|
||||||
if (protocolMethod.invokeOnButton()) {
|
|
||||||
toInvoke = originalArgs[1] == MatchButtonType.OK ? gui.getBtnOK((PlayerView) originalArgs[0]) : gui.getBtnCancel((PlayerView) originalArgs[0]);
|
|
||||||
// Remove the player and button type from the args passed to the method
|
|
||||||
args = Arrays.copyOfRange(originalArgs, 2, originalArgs.length);
|
|
||||||
} else {
|
|
||||||
toInvoke = gui;
|
|
||||||
args = originalArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pre-call actions
|
|
||||||
switch (protocolMethod) {
|
|
||||||
case openView:
|
|
||||||
final TrackableCollection<PlayerView> myPlayers = (TrackableCollection<PlayerView>) args[0];
|
|
||||||
client.setGameControllers(myPlayers);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Class<?> returnType = method.getReturnType();
|
|
||||||
if (returnType.equals(Void.TYPE)) {
|
|
||||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
|
||||||
@Override public final void run() {
|
|
||||||
try {
|
|
||||||
method.invoke(toInvoke, args);
|
|
||||||
} catch (final IllegalAccessException | IllegalArgumentException e) {
|
|
||||||
System.err.println(String.format("Unknown protocol method %s with %d args", methodName, args == null ? 0 : args.length));
|
|
||||||
} catch (final InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Serializable reply = null;
|
|
||||||
try {
|
|
||||||
final Object theReply = method.invoke(toInvoke, args);
|
|
||||||
if (theReply instanceof Serializable) {
|
|
||||||
reply = (Serializable) method.invoke(toInvoke, args);
|
|
||||||
} else {
|
|
||||||
System.err.println(String.format("Non-serializable return type %s for method %s", returnType.getName(), methodName));
|
|
||||||
}
|
|
||||||
} catch (final IllegalAccessException | IllegalArgumentException e) {
|
|
||||||
System.err.println(String.format("Unknown protocol method %s with %d args, replying with null", methodName, args == null ? 0 : args.length));
|
|
||||||
} catch (final InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
client.send(new ReplyEvent(event.getId(), reply));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
|
|
||||||
cause.printStackTrace();
|
|
||||||
ctx.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package forge.net.client;
|
package forge.net.client;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import forge.game.card.CardView;
|
import forge.game.card.CardView;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
@@ -9,90 +8,77 @@ import forge.game.spellability.SpellAbilityView;
|
|||||||
import forge.interfaces.IDevModeCheats;
|
import forge.interfaces.IDevModeCheats;
|
||||||
import forge.interfaces.IGameController;
|
import forge.interfaces.IGameController;
|
||||||
import forge.match.NextGameDecision;
|
import forge.match.NextGameDecision;
|
||||||
import forge.net.event.GuiGameEvent;
|
import forge.net.GameProtocol.ProtocolMethod;
|
||||||
|
import forge.net.GameProtocolSender;
|
||||||
import forge.util.ITriggerEvent;
|
import forge.util.ITriggerEvent;
|
||||||
|
|
||||||
public class NetGameController implements IGameController {
|
public class NetGameController implements IGameController {
|
||||||
|
|
||||||
private final IToServer server;
|
private final GameProtocolSender sender;
|
||||||
public NetGameController(final IToServer server) {
|
public NetGameController(final IToServer server) {
|
||||||
this.server = server;
|
this.sender = new GameProtocolSender(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String methodName() {
|
private void send(final ProtocolMethod method, final Object... args) {
|
||||||
boolean passedFirst = false;
|
sender.send(method, args);
|
||||||
for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) {
|
|
||||||
if (ste.getClassName() == getClass().getName()) {
|
|
||||||
if (passedFirst) {
|
|
||||||
return ste.getMethodName();
|
|
||||||
}
|
|
||||||
passedFirst = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void send(final String method, final Object... args) {
|
private <T> T sendAndWait(final ProtocolMethod method, final Object... args) {
|
||||||
server.send(new GuiGameEvent(method, args));
|
return sender.sendAndWait(method, args);
|
||||||
}
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <T> T sendAndWait(final String method, final Object... args) {
|
|
||||||
try {
|
|
||||||
return (T) server.sendAndWait(new GuiGameEvent(method, args));
|
|
||||||
} catch (final TimeoutException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean useMana(final byte color) {
|
public void useMana(final byte color) {
|
||||||
return sendAndWait(methodName(), color);
|
send(ProtocolMethod.useMana, Byte.valueOf(color));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean tryUndoLastAction() {
|
public void undoLastAction() {
|
||||||
return sendAndWait(methodName());
|
send(ProtocolMethod.undoLastAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void selectPlayer(final PlayerView playerView, final ITriggerEvent triggerEvent) {
|
public void selectPlayer(final PlayerView playerView, final ITriggerEvent triggerEvent) {
|
||||||
send(methodName(), playerView, triggerEvent);
|
send(ProtocolMethod.selectPlayer, playerView, triggerEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean selectCard(final CardView cardView, final List<CardView> otherCardViewsToSelect, final ITriggerEvent triggerEvent) {
|
public boolean selectCard(final CardView cardView, final List<CardView> otherCardViewsToSelect, final ITriggerEvent triggerEvent) {
|
||||||
return sendAndWait(methodName(), cardView, otherCardViewsToSelect, triggerEvent);
|
send(ProtocolMethod.selectCard, cardView, otherCardViewsToSelect, triggerEvent);
|
||||||
|
// Difference from local games! Always consider a card as successfully selected,
|
||||||
|
// to avoid blocks where server and client wait for each other to respond.
|
||||||
|
// Some cost in functionality but a huge gain in stability & speed.
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void selectButtonOk() {
|
public void selectButtonOk() {
|
||||||
send(methodName());
|
send(ProtocolMethod.selectButtonOk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void selectButtonCancel() {
|
public void selectButtonCancel() {
|
||||||
send(methodName());
|
send(ProtocolMethod.selectButtonCancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void selectAbility(final SpellAbilityView sa) {
|
public void selectAbility(final SpellAbilityView sa) {
|
||||||
send(methodName(), sa);
|
send(ProtocolMethod.selectAbility, sa);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean passPriorityUntilEndOfTurn() {
|
public void passPriorityUntilEndOfTurn() {
|
||||||
return sendAndWait(methodName());
|
send(ProtocolMethod.passPriorityUntilEndOfTurn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean passPriority() {
|
public void passPriority() {
|
||||||
return sendAndWait(methodName());
|
send(ProtocolMethod.passPriority);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void nextGameDecision(final NextGameDecision decision) {
|
public void nextGameDecision(final NextGameDecision decision) {
|
||||||
send(methodName(), decision);
|
send(ProtocolMethod.nextGameDecision, decision);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -102,31 +88,33 @@ public class NetGameController implements IGameController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getActivateDescription(final CardView card) {
|
public String getActivateDescription(final CardView card) {
|
||||||
return sendAndWait(methodName(), card);
|
return sendAndWait(ProtocolMethod.getActivateDescription, card);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void concede() {
|
public void concede() {
|
||||||
send(methodName());
|
send(ProtocolMethod.concede);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IDevModeCheats cheat() {
|
public IDevModeCheats cheat() {
|
||||||
|
// No cheating in network games!
|
||||||
return IDevModeCheats.NO_CHEAT;
|
return IDevModeCheats.NO_CHEAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canPlayUnlimitedLands() {
|
public boolean canPlayUnlimitedLands() {
|
||||||
|
// Don't do this over network
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void alphaStrike() {
|
public void alphaStrike() {
|
||||||
send(methodName());
|
send(ProtocolMethod.alphaStrike);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reorderHand(CardView card, int index) {
|
public void reorderHand(CardView card, int index) {
|
||||||
send(methodName(), card, index);
|
send(ProtocolMethod.reorderHand, card, Integer.valueOf(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package forge.net.event;
|
package forge.net.event;
|
||||||
|
|
||||||
|
import forge.net.GameProtocol.ProtocolMethod;
|
||||||
import forge.net.server.RemoteClient;
|
import forge.net.server.RemoteClient;
|
||||||
|
|
||||||
public final class GuiGameEvent implements IdentifiableNetEvent {
|
public final class GuiGameEvent implements IdentifiableNetEvent {
|
||||||
@@ -7,10 +8,10 @@ public final class GuiGameEvent implements IdentifiableNetEvent {
|
|||||||
private static int staticId = 0;
|
private static int staticId = 0;
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
private final String method;
|
private final ProtocolMethod method;
|
||||||
private final Object[] objects;
|
private final Object[] objects;
|
||||||
|
|
||||||
public GuiGameEvent(final String method, final Object ... objects) {
|
public GuiGameEvent(final ProtocolMethod method, final Object ... objects) {
|
||||||
this.id = staticId++;
|
this.id = staticId++;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.objects = objects == null ? new Object[0] : objects;
|
this.objects = objects == null ? new Object[0] : objects;
|
||||||
@@ -30,7 +31,7 @@ public final class GuiGameEvent implements IdentifiableNetEvent {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMethod() {
|
public ProtocolMethod getMethod() {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,19 @@
|
|||||||
package forge.net.server;
|
package forge.net.server;
|
||||||
|
|
||||||
import forge.FThreads;
|
|
||||||
import forge.GuiBase;
|
import forge.GuiBase;
|
||||||
import forge.LobbyPlayer;
|
|
||||||
import forge.game.GameView;
|
import forge.game.GameView;
|
||||||
import forge.game.card.CardView;
|
|
||||||
import forge.game.player.PlayerView;
|
|
||||||
import forge.game.spellability.SpellAbilityView;
|
|
||||||
import forge.interfaces.IGameController;
|
import forge.interfaces.IGameController;
|
||||||
import forge.interfaces.IGuiGame;
|
import forge.interfaces.IGuiGame;
|
||||||
import forge.interfaces.ILobbyListener;
|
import forge.interfaces.ILobbyListener;
|
||||||
import forge.match.LobbySlot;
|
import forge.match.LobbySlot;
|
||||||
import forge.match.LobbySlotType;
|
import forge.match.LobbySlotType;
|
||||||
import forge.match.NextGameDecision;
|
|
||||||
import forge.net.event.GuiGameEvent;
|
|
||||||
import forge.net.event.LobbyUpdateEvent;
|
import forge.net.event.LobbyUpdateEvent;
|
||||||
import forge.net.event.LoginEvent;
|
import forge.net.event.LoginEvent;
|
||||||
import forge.net.event.LogoutEvent;
|
import forge.net.event.LogoutEvent;
|
||||||
import forge.net.event.MessageEvent;
|
import forge.net.event.MessageEvent;
|
||||||
import forge.net.event.NetEvent;
|
import forge.net.event.NetEvent;
|
||||||
import forge.net.event.ReplyEvent;
|
|
||||||
import forge.net.event.UpdateLobbyPlayerEvent;
|
import forge.net.event.UpdateLobbyPlayerEvent;
|
||||||
import forge.properties.ForgeConstants;
|
import forge.properties.ForgeConstants;
|
||||||
import forge.util.ITriggerEvent;
|
|
||||||
import io.netty.bootstrap.ServerBootstrap;
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
@@ -40,12 +31,10 @@ import io.netty.handler.codec.serialization.ObjectEncoder;
|
|||||||
import io.netty.handler.logging.LogLevel;
|
import io.netty.handler.logging.LogLevel;
|
||||||
import io.netty.handler.logging.LoggingHandler;
|
import io.netty.handler.logging.LoggingHandler;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.log4j.PropertyConfigurator;
|
import org.apache.log4j.PropertyConfigurator;
|
||||||
@@ -79,6 +68,16 @@ public final class FServerManager {
|
|||||||
private FServerManager() {
|
private FServerManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemoteClient getClient(final Channel ch) {
|
||||||
|
return clients.get(ch);
|
||||||
|
}
|
||||||
|
GameView getGameView() {
|
||||||
|
return localLobby.getGameView();
|
||||||
|
}
|
||||||
|
IGameController getController(final int index) {
|
||||||
|
return localLobby.getController(index);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the singleton instance of {@link FServerManager}.
|
* Get the singleton instance of {@link FServerManager}.
|
||||||
*
|
*
|
||||||
@@ -126,7 +125,7 @@ public final class FServerManager {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
//mapNatPort(port);
|
mapNatPort(port);
|
||||||
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||||
isHosting = true;
|
isHosting = true;
|
||||||
} catch (final InterruptedException e) {
|
} catch (final InterruptedException e) {
|
||||||
@@ -229,197 +228,6 @@ public final class FServerManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GameServerHandler extends ChannelInboundHandlerAdapter {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
|
|
||||||
System.out.println("Server received: " + msg);
|
|
||||||
final RemoteClient client = clients.get(ctx.channel());
|
|
||||||
if (msg instanceof ReplyEvent) {
|
|
||||||
client.setReply(((ReplyEvent) msg).getIndex(), ((ReplyEvent) msg).getReply());
|
|
||||||
} else if (msg instanceof GuiGameEvent) {
|
|
||||||
final GuiGameEvent event = (GuiGameEvent) msg;
|
|
||||||
final GameView gameView = localLobby.getGameView();
|
|
||||||
final IGameController controller = localLobby.getController(client.getIndex());
|
|
||||||
final Object[] args = event.getObjects();
|
|
||||||
|
|
||||||
FThreads.invokeInBackgroundThread(new Runnable() {
|
|
||||||
@Override public final void run() {
|
|
||||||
Serializable reply = null;
|
|
||||||
boolean doReply = false;
|
|
||||||
|
|
||||||
switch (event.getMethod()) {
|
|
||||||
// From GameController
|
|
||||||
case "useMana":
|
|
||||||
controller.useMana((byte) args[0]);
|
|
||||||
break;
|
|
||||||
case "tryUndoLastAction":
|
|
||||||
reply = controller.tryUndoLastAction();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "selectPlayer":
|
|
||||||
controller.selectPlayer((PlayerView) args[0], (ITriggerEvent) args[1]);
|
|
||||||
break;
|
|
||||||
case "selectCard":
|
|
||||||
reply = controller.selectCard((CardView) args[0], (List<CardView>) args[1], (ITriggerEvent) args[2]);
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "selectButtonOk":
|
|
||||||
controller.selectButtonOk();
|
|
||||||
break;
|
|
||||||
case "selectButtonCancel":
|
|
||||||
controller.selectButtonCancel();
|
|
||||||
break;
|
|
||||||
case "selectAbility":
|
|
||||||
controller.selectAbility((SpellAbilityView) args[0]);
|
|
||||||
break;
|
|
||||||
case "passPriorityUntilEndOfTurn":
|
|
||||||
reply = controller.passPriorityUntilEndOfTurn();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "passPriority":
|
|
||||||
reply = controller.passPriority();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "nextGameDecision":
|
|
||||||
controller.nextGameDecision((NextGameDecision) args[0]);
|
|
||||||
break;
|
|
||||||
case "mayLookAtAllCards":
|
|
||||||
reply = controller.mayLookAtAllCards();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getActivateDescription":
|
|
||||||
reply = controller.getActivateDescription((CardView) args[0]);
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "concede":
|
|
||||||
controller.concede();
|
|
||||||
break;
|
|
||||||
case "alphaStrike":
|
|
||||||
controller.alphaStrike();
|
|
||||||
break;
|
|
||||||
// From GameView
|
|
||||||
case "getPlayers":
|
|
||||||
reply = (Serializable) gameView.getPlayers();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getTitle":
|
|
||||||
reply = gameView.getTitle();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "isCommander":
|
|
||||||
reply = gameView.isCommander();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getGameType":
|
|
||||||
reply = gameView.getGameType();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getPoisonCountersToLose":
|
|
||||||
reply = gameView.getPoisonCountersToLose();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getNumGamesInMatch":
|
|
||||||
reply = gameView.getNumGamesInMatch();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getTurn":
|
|
||||||
reply = gameView.getTurn();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getPhase":
|
|
||||||
reply = gameView.getPhase();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getPlayerTurn":
|
|
||||||
reply = gameView.getPlayerTurn();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getStack":
|
|
||||||
reply = (Serializable) gameView.getStack();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "peekStack":
|
|
||||||
reply = gameView.peekStack();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getStormCount":
|
|
||||||
reply = gameView.getStormCount();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "isFirstGameInMatch":
|
|
||||||
reply = gameView.isFirstGameInMatch();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getNumPlayedGamesInMatch":
|
|
||||||
reply = gameView.getNumPlayedGamesInMatch();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "isGameOver":
|
|
||||||
reply = gameView.isGameOver();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "isMatchOver":
|
|
||||||
reply = gameView.isMatchOver();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getWinningTeam":
|
|
||||||
reply = gameView.getWinningTeam();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getGameLog":
|
|
||||||
reply = gameView.getGameLog();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getCombat":
|
|
||||||
reply = gameView.getCombat();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "isMatchWonBy":
|
|
||||||
reply = gameView.isMatchWonBy((LobbyPlayer) args[0]);
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getOutcomesOfMatch":
|
|
||||||
reply = (Serializable) gameView.getOutcomesOfMatch();
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
// TODO case "getWinningPlayer":
|
|
||||||
case "isWinner":
|
|
||||||
reply = gameView.isWinner((LobbyPlayer) args[0]);
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getGamesWonBy":
|
|
||||||
reply = gameView.getGamesWonBy((LobbyPlayer) args[0]);
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getDeck":
|
|
||||||
reply = gameView.getDeck((String) args[0]);
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
case "getAnteResult":
|
|
||||||
reply = gameView.getAnteResult((PlayerView) args[0]);
|
|
||||||
doReply = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
System.err.println(String.format("Unknown incoming client command %s", event.getMethod()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doReply) {
|
|
||||||
client.send(new ReplyEvent(event.getId(), reply));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
|
|
||||||
cause.printStackTrace();
|
|
||||||
ctx.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class RegisterClientHandler extends ChannelInboundHandlerAdapter {
|
private class RegisterClientHandler extends ChannelInboundHandlerAdapter {
|
||||||
@Override
|
@Override
|
||||||
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
|
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package forge.net.server;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import forge.interfaces.IGameController;
|
||||||
|
import forge.net.GameProtocol.ProtocolMethod;
|
||||||
|
import forge.net.GameProtocolHandler;
|
||||||
|
import forge.net.IRemote;
|
||||||
|
import forge.net.ReplyPool;
|
||||||
|
|
||||||
|
final class GameServerHandler extends GameProtocolHandler<IGameController> {
|
||||||
|
|
||||||
|
private final FServerManager server = FServerManager.getInstance();
|
||||||
|
GameServerHandler() {
|
||||||
|
super(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RemoteClient getClient(final ChannelHandlerContext ctx) {
|
||||||
|
return server.getClient(ctx.channel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ReplyPool getReplyPool(final ChannelHandlerContext ctx) {
|
||||||
|
return getClient(ctx).getReplyPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IRemote getRemote(final ChannelHandlerContext ctx) {
|
||||||
|
return getClient(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IGameController getToInvoke(final ChannelHandlerContext ctx) {
|
||||||
|
return server.getController(getClient(ctx).getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void beforeCall(final ProtocolMethod protocolMethod, final Object[] args) {
|
||||||
|
// Nothing needs to be done here
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,16 +1,12 @@
|
|||||||
package forge.net.server;
|
package forge.net.server;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.EnumMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
|
|
||||||
import forge.LobbyPlayer;
|
import forge.LobbyPlayer;
|
||||||
import forge.UiCommand;
|
|
||||||
import forge.assets.FSkinProp;
|
import forge.assets.FSkinProp;
|
||||||
import forge.deck.CardPool;
|
import forge.deck.CardPool;
|
||||||
import forge.game.GameEntityView;
|
import forge.game.GameEntityView;
|
||||||
@@ -22,54 +18,31 @@ import forge.game.player.IHasIcon;
|
|||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.game.spellability.SpellAbilityView;
|
import forge.game.spellability.SpellAbilityView;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.interfaces.IButton;
|
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
import forge.match.AbstractGuiGame;
|
import forge.match.AbstractGuiGame;
|
||||||
import forge.match.MatchButtonType;
|
import forge.net.GameProtocol.ProtocolMethod;
|
||||||
import forge.net.event.GuiGameEvent;
|
import forge.net.GameProtocolSender;
|
||||||
import forge.player.PlayerZoneUpdate;
|
import forge.player.PlayerZoneUpdate;
|
||||||
import forge.trackable.TrackableCollection;
|
import forge.trackable.TrackableCollection;
|
||||||
import forge.util.ITriggerEvent;
|
import forge.util.ITriggerEvent;
|
||||||
|
|
||||||
public class NetGuiGame extends AbstractGuiGame {
|
public class NetGuiGame extends AbstractGuiGame {
|
||||||
|
|
||||||
private final IToClient client;
|
private final GameProtocolSender sender;
|
||||||
private final Map<MatchButtonType, Map<PlayerView, NetButton>> btns = new EnumMap<MatchButtonType, Map<PlayerView,NetButton>>(MatchButtonType.class);
|
|
||||||
public NetGuiGame(final IToClient client) {
|
public NetGuiGame(final IToClient client) {
|
||||||
this.client = client;
|
this.sender = new GameProtocolSender(client);
|
||||||
for (final MatchButtonType type : MatchButtonType.values()) {
|
|
||||||
btns.put(type, Maps.<PlayerView, NetButton>newHashMap());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String methodName() {
|
private void send(final ProtocolMethod method, final Object... args) {
|
||||||
boolean passedFirst = false;
|
sender.send(method, args);
|
||||||
for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) {
|
|
||||||
if (ste.getClassName() == getClass().getName()) {
|
|
||||||
if (passedFirst) {
|
|
||||||
return ste.getMethodName();
|
|
||||||
}
|
|
||||||
passedFirst = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void send(final String method, final Object... args) {
|
private <T> T sendAndWait(final ProtocolMethod method, final Object... args) {
|
||||||
client.send(new GuiGameEvent(method, args));
|
return sender.sendAndWait(method, args);
|
||||||
}
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <T> T sendAndWait(final String method, final Object... args) {
|
|
||||||
try {
|
|
||||||
return (T) client.sendAndWait(new GuiGameEvent(method, args));
|
|
||||||
} catch (final TimeoutException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateGameView() {
|
private void updateGameView() {
|
||||||
send("setGameView", getGameView());
|
send(ProtocolMethod.setGameView, getGameView());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -80,227 +53,206 @@ public class NetGuiGame extends AbstractGuiGame {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
||||||
for (final MatchButtonType type : MatchButtonType.values()) {
|
send(ProtocolMethod.openView, myPlayers);
|
||||||
btns.get(type).clear();
|
|
||||||
for (final PlayerView player : myPlayers) {
|
|
||||||
btns.get(type).put(player, new NetButton(player, type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
send(methodName(), myPlayers);
|
|
||||||
updateGameView();
|
updateGameView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterGameEnd() {
|
public void afterGameEnd() {
|
||||||
send(methodName());
|
send(ProtocolMethod.afterGameEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showCombat() {
|
public void showCombat() {
|
||||||
send(methodName());
|
send(ProtocolMethod.showCombat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showPromptMessage(final PlayerView playerView, final String message) {
|
public void showPromptMessage(final PlayerView playerView, final String message) {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName(), playerView, message);
|
send(ProtocolMethod.showPromptMessage, playerView, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean stopAtPhase(final PlayerView playerTurn, final PhaseType phase) {
|
public void updateButtons(final PlayerView owner, final String label1, final String label2, final boolean enable1, final boolean enable2, final boolean focus1) {
|
||||||
return sendAndWait(methodName(), playerTurn, phase);
|
send(ProtocolMethod.updateButtons, owner, label1, label2, enable1, enable2, focus1);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IButton getBtnOK(final PlayerView playerView) {
|
|
||||||
return btns.get(MatchButtonType.OK).get(playerView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IButton getBtnCancel(final PlayerView playerView) {
|
|
||||||
return btns.get(MatchButtonType.CANCEL).get(playerView);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void focusButton(final MatchButtonType button) {
|
|
||||||
send(methodName(), button);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flashIncorrectAction() {
|
public void flashIncorrectAction() {
|
||||||
send(methodName());
|
send(ProtocolMethod.flashIncorrectAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updatePhase() {
|
public void updatePhase() {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName());
|
send(ProtocolMethod.updatePhase);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateTurn(final PlayerView player) {
|
public void updateTurn(final PlayerView player) {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName(), player);
|
send(ProtocolMethod.updateTurn, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updatePlayerControl() {
|
public void updatePlayerControl() {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName());
|
send(ProtocolMethod.updatePlayerControl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void enableOverlay() {
|
public void enableOverlay() {
|
||||||
send(methodName());
|
send(ProtocolMethod.enableOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disableOverlay() {
|
public void disableOverlay() {
|
||||||
send(methodName());
|
send(ProtocolMethod.disableOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finishGame() {
|
public void finishGame() {
|
||||||
send(methodName());
|
send(ProtocolMethod.finishGame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object showManaPool(final PlayerView player) {
|
public Object showManaPool(final PlayerView player) {
|
||||||
send(methodName(), player);
|
send(ProtocolMethod.showManaPool, player);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hideManaPool(final PlayerView player, final Object zoneToRestore) {
|
public void hideManaPool(final PlayerView player, final Object zoneToRestore) {
|
||||||
send(methodName(), player, zoneToRestore);
|
send(ProtocolMethod.hideManaPool, player, zoneToRestore);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateStack() {
|
public void updateStack() {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName());
|
send(ProtocolMethod.updateStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateZones(final Iterable<PlayerZoneUpdate> zonesToUpdate) {
|
public void updateZones(final Iterable<PlayerZoneUpdate> zonesToUpdate) {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName(), zonesToUpdate);
|
send(ProtocolMethod.updateZones, zonesToUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateCards(final Iterable<CardView> cards) {
|
public void updateCards(final Iterable<CardView> cards) {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName(), cards);
|
send(ProtocolMethod.updateCards, cards);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) {
|
public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName(), manaPoolUpdate);
|
send(ProtocolMethod.updateManaPool, manaPoolUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateLives(final Iterable<PlayerView> livesUpdate) {
|
public void updateLives(final Iterable<PlayerView> livesUpdate) {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName(), livesUpdate);
|
send(ProtocolMethod.updateLives, livesUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPanelSelection(final CardView hostCard) {
|
public void setPanelSelection(final CardView hostCard) {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName(), hostCard);
|
send(ProtocolMethod.setPanelSelection, hostCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SpellAbilityView getAbilityToPlay(final List<SpellAbilityView> abilities, final ITriggerEvent triggerEvent) {
|
public SpellAbilityView getAbilityToPlay(final CardView hostCard, final List<SpellAbilityView> abilities, final ITriggerEvent triggerEvent) {
|
||||||
return sendAndWait(methodName(), abilities, triggerEvent);
|
return sendAndWait(ProtocolMethod.getAbilityToPlay, hostCard, abilities, triggerEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<CardView, Integer> assignDamage(final CardView attacker, final List<CardView> blockers, final int damage, final GameEntityView defender, final boolean overrideOrder) {
|
public Map<CardView, Integer> assignDamage(final CardView attacker, final List<CardView> blockers, final int damage, final GameEntityView defender, final boolean overrideOrder) {
|
||||||
return sendAndWait(methodName(), attacker, blockers, damage, defender, overrideOrder);
|
return sendAndWait(ProtocolMethod.assignDamage, attacker, blockers, damage, defender, overrideOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void message(final String message, final String title) {
|
public void message(final String message, final String title) {
|
||||||
send(methodName(), message, title);
|
send(ProtocolMethod.message, message, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showErrorDialog(final String message, final String title) {
|
public void showErrorDialog(final String message, final String title) {
|
||||||
send(methodName(), message, title);
|
send(ProtocolMethod.showErrorDialog, message, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean showConfirmDialog(final String message, final String title, final String yesButtonText, final String noButtonText, final boolean defaultYes) {
|
public boolean showConfirmDialog(final String message, final String title, final String yesButtonText, final String noButtonText, final boolean defaultYes) {
|
||||||
return sendAndWait(methodName(), message, title, yesButtonText, noButtonText, defaultYes);
|
return sendAndWait(ProtocolMethod.showConfirmDialog, message, title, yesButtonText, noButtonText, defaultYes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int showOptionDialog(final String message, final String title, final FSkinProp icon, final String[] options, final int defaultOption) {
|
public int showOptionDialog(final String message, final String title, final FSkinProp icon, final String[] options, final int defaultOption) {
|
||||||
return sendAndWait(methodName(), message, title, icon, options, defaultOption);
|
return sendAndWait(ProtocolMethod.showOptionDialog, message, title, icon, options, defaultOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int showCardOptionDialog(final CardView card, final String message, final String title, final FSkinProp icon, final String[] options, final int defaultOption) {
|
public int showCardOptionDialog(final CardView card, final String message, final String title, final FSkinProp icon, final String[] options, final int defaultOption) {
|
||||||
return sendAndWait(methodName(), card, message, title, icon, options, defaultOption);
|
return sendAndWait(ProtocolMethod.showCardOptionDialog, card, message, title, icon, options, defaultOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String showInputDialog(final String message, final String title, final FSkinProp icon, final String initialInput, final String[] inputOptions) {
|
public String showInputDialog(final String message, final String title, final FSkinProp icon, final String initialInput, final String[] inputOptions) {
|
||||||
return sendAndWait(methodName(), message, title, icon, initialInput, inputOptions);
|
return sendAndWait(ProtocolMethod.showInputDialog, message, title, icon, initialInput, inputOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean confirm(final CardView c, final String question, final boolean defaultIsYes, final String[] options) {
|
public boolean confirm(final CardView c, final String question, final boolean defaultIsYes, final String[] options) {
|
||||||
return sendAndWait(methodName(), c, question, defaultIsYes, options);
|
return sendAndWait(ProtocolMethod.confirm, c, question, defaultIsYes, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
|
public <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display) {
|
||||||
return sendAndWait(methodName(), message, min, max, choices, selected, display);
|
return sendAndWait(ProtocolMethod.getChoices, message, min, max, choices, selected, display);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> List<T> order(final String title, final String top, final int remainingObjectsMin, final int remainingObjectsMax, final List<T> sourceChoices, final List<T> destChoices, final CardView referenceCard, final boolean sideboardingMode) {
|
public <T> List<T> order(final String title, final String top, final int remainingObjectsMin, final int remainingObjectsMax, final List<T> sourceChoices, final List<T> destChoices, final CardView referenceCard, final boolean sideboardingMode) {
|
||||||
return sendAndWait(methodName(), title, top, remainingObjectsMin, remainingObjectsMax, sourceChoices, destChoices, referenceCard, sideboardingMode);
|
return sendAndWait(ProtocolMethod.order, title, top, remainingObjectsMin, remainingObjectsMax, sourceChoices, destChoices, referenceCard, sideboardingMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PaperCard> sideboard(final CardPool sideboard, final CardPool main) {
|
public List<PaperCard> sideboard(final CardPool sideboard, final CardPool main) {
|
||||||
return sendAndWait(methodName(), sideboard, main);
|
return sendAndWait(ProtocolMethod.sideboard, sideboard, main);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GameEntityView chooseSingleEntityForEffect(final String title, final Collection<? extends GameEntityView> optionList, final DelayedReveal delayedReveal, final boolean isOptional) {
|
public GameEntityView chooseSingleEntityForEffect(final String title, final Collection<? extends GameEntityView> optionList, final DelayedReveal delayedReveal, final boolean isOptional) {
|
||||||
return sendAndWait(methodName(), title, optionList, delayedReveal, isOptional);
|
return sendAndWait(ProtocolMethod.chooseSingleEntityForEffect, title, optionList, delayedReveal, isOptional);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCard(final CardView card) {
|
public void setCard(final CardView card) {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
send(methodName(), card);
|
send(ProtocolMethod.setCard, card);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi) {
|
public void setPlayerAvatar(final LobbyPlayer player, final IHasIcon ihi) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean openZones(final Collection<ZoneType> zones, final Map<PlayerView, Object> players) {
|
public boolean openZones(final Collection<ZoneType> zones, final Map<PlayerView, Object> players) {
|
||||||
updateGameView();
|
updateGameView();
|
||||||
return sendAndWait(methodName(), zones, players);
|
return sendAndWait(ProtocolMethod.openZones, zones, players);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void restoreOldZones(final Map<PlayerView, Object> playersToRestoreZonesFor) {
|
public void restoreOldZones(final Map<PlayerView, Object> playersToRestoreZonesFor) {
|
||||||
send(methodName(), playersToRestoreZonesFor);
|
send(ProtocolMethod.restoreOldZones, playersToRestoreZonesFor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUiSetToSkipPhase(final PlayerView playerTurn, final PhaseType phase) {
|
public boolean isUiSetToSkipPhase(final PlayerView playerTurn, final PhaseType phase) {
|
||||||
return sendAndWait(methodName(), playerTurn, phase);
|
return sendAndWait(ProtocolMethod.isUiSetToSkipPhase, playerTurn, phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -308,71 +260,4 @@ public class NetGuiGame extends AbstractGuiGame {
|
|||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class NetButton implements IButton {
|
|
||||||
|
|
||||||
private String methodName() {
|
|
||||||
boolean passedFirst = false;
|
|
||||||
for (final StackTraceElement ste : Thread.currentThread().getStackTrace()) {
|
|
||||||
if (ste.getClassName() == getClass().getName()) {
|
|
||||||
if (passedFirst) {
|
|
||||||
return ste.getMethodName();
|
|
||||||
}
|
|
||||||
passedFirst = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final PlayerView playerView;
|
|
||||||
private final MatchButtonType type;
|
|
||||||
private NetButton(final PlayerView playerView, final MatchButtonType type) {
|
|
||||||
this.playerView = playerView;
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEnabled(final boolean b0) {
|
|
||||||
send("btn_" + methodName(), playerView, type, b0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setVisible(final boolean b0) {
|
|
||||||
send("btn_" + methodName(), playerView, type, b0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setText(final String text0) {
|
|
||||||
send("btn_" + methodName(), playerView, type, text0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSelected() {
|
|
||||||
return sendAndWait("btn_" + methodName(), playerView, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSelected(final boolean b0) {
|
|
||||||
send("btn_" + methodName(), playerView, type, b0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean requestFocusInWindow() {
|
|
||||||
return sendAndWait("btn_" + methodName(), playerView, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCommand(final UiCommand command0) {
|
|
||||||
send("btn_" + methodName(), playerView, type, command0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setImage(final FSkinProp color) {
|
|
||||||
send("btn_" + methodName(), playerView, type, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTextColor(final int r, final int g, final int b) {
|
|
||||||
send("btn_" + methodName(), playerView, type, r, g, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public final class RemoteClient implements IToClient {
|
|||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setReply(final int id, final Object reply) {
|
ReplyPool getReplyPool() {
|
||||||
replies.complete(id, reply);
|
return replies;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ public class HumanPlay {
|
|||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
final List<SpellAbility> abilities = GameActionUtil.getOptionalCosts(original);
|
final List<SpellAbility> abilities = GameActionUtil.getOptionalCosts(original);
|
||||||
return p.getController().getAbilityToPlay(abilities);
|
return p.getController().getAbilityToPlay(original.getHostCard(), abilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean payManaCostIfNeeded(final PlayerControllerHuman controller, final Player p, final SpellAbility sa) {
|
private static boolean payManaCostIfNeeded(final PlayerControllerHuman controller, final Player p, final SpellAbility sa) {
|
||||||
|
|||||||
@@ -219,8 +219,8 @@ public class PlayerControllerHuman
|
|||||||
/**
|
/**
|
||||||
* Uses GUI to learn which spell the player (human in our case) would like to play
|
* Uses GUI to learn which spell the player (human in our case) would like to play
|
||||||
*/
|
*/
|
||||||
public SpellAbility getAbilityToPlay(final List<SpellAbility> abilities, final ITriggerEvent triggerEvent) {
|
public SpellAbility getAbilityToPlay(final Card hostCard, final List<SpellAbility> abilities, final ITriggerEvent triggerEvent) {
|
||||||
final SpellAbilityView resultView = getGui().getAbilityToPlay(SpellAbilityView.getCollection(abilities), triggerEvent);
|
final SpellAbilityView resultView = getGui().getAbilityToPlay(CardView.get(hostCard), SpellAbilityView.getCollection(abilities), triggerEvent);
|
||||||
return getGame().getSpellAbility(resultView);
|
return getGame().getSpellAbility(resultView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1304,6 +1304,12 @@ public class PlayerControllerHuman
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void undoLastAction() {
|
||||||
|
tryUndoLastAction();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean tryUndoLastAction() {
|
public boolean tryUndoLastAction() {
|
||||||
if (!canUndoLastAction()) {
|
if (!canUndoLastAction()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1333,37 +1339,33 @@ public class PlayerControllerHuman
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean passPriority() {
|
public void passPriority() {
|
||||||
return passPriority(false);
|
passPriority(false);
|
||||||
}
|
}
|
||||||
public boolean passPriorityUntilEndOfTurn() {
|
public void passPriorityUntilEndOfTurn() {
|
||||||
return passPriority(true);
|
passPriority(true);
|
||||||
}
|
}
|
||||||
private boolean passPriority(final boolean passUntilEndOfTurn) {
|
private void passPriority(final boolean passUntilEndOfTurn) {
|
||||||
final Input inp = inputProxy.getInput();
|
final Input inp = inputProxy.getInput();
|
||||||
if (inp instanceof InputPassPriority) {
|
if (inp instanceof InputPassPriority) {
|
||||||
if (passUntilEndOfTurn) {
|
if (passUntilEndOfTurn) {
|
||||||
autoPassUntilEndOfTurn();
|
autoPassUntilEndOfTurn();
|
||||||
}
|
}
|
||||||
inp.selectButtonOK();
|
inp.selectButtonOK();
|
||||||
return true;
|
} else {
|
||||||
|
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||||
|
@Override public final void run() {
|
||||||
|
getGui().message("Cannot pass priority at this time.");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
getGui().message("Cannot pass priority at this time.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean useMana(final byte mana) {
|
public void useMana(final byte mana) {
|
||||||
final Input input = inputQueue.getInput();
|
final Input input = inputQueue.getInput();
|
||||||
if (input instanceof InputPayMana) {
|
if (input instanceof InputPayMana) {
|
||||||
return ((InputPayMana) input).useManaFromPool(mana);
|
((InputPayMana) input).useManaFromPool(mana);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectPlayer(final PlayerView playerView, final ITriggerEvent triggerEvent) {
|
public void selectPlayer(final PlayerView playerView, final ITriggerEvent triggerEvent) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package forge.player;
|
package forge.player;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -11,11 +12,21 @@ import forge.game.player.PlayerView;
|
|||||||
public class PlayerZoneUpdates implements Iterable<PlayerZoneUpdate>, Serializable {
|
public class PlayerZoneUpdates implements Iterable<PlayerZoneUpdate>, Serializable {
|
||||||
private static final long serialVersionUID = 7023549243041119023L;
|
private static final long serialVersionUID = 7023549243041119023L;
|
||||||
|
|
||||||
private final Map<PlayerView, PlayerZoneUpdate> updates = Maps.newHashMap();
|
private final Map<PlayerView, PlayerZoneUpdate> updates = Collections.synchronizedMap(Maps.<PlayerView, PlayerZoneUpdate>newHashMap());
|
||||||
|
|
||||||
public PlayerZoneUpdates() {
|
public PlayerZoneUpdates() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy constructor.
|
||||||
|
*
|
||||||
|
* @param other
|
||||||
|
* the {@link PlayerZoneUpdates} to copy.
|
||||||
|
*/
|
||||||
|
public PlayerZoneUpdates(final PlayerZoneUpdates other) {
|
||||||
|
this.updates.putAll(other.updates);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<PlayerZoneUpdate> iterator() {
|
public Iterator<PlayerZoneUpdate> iterator() {
|
||||||
return updates.values().iterator();
|
return updates.values().iterator();
|
||||||
|
|||||||
Reference in New Issue
Block a user