mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18: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/package-info.java svneol=native#text/plain
|
||||
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/ReplyPool.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/package-info.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/NetGuiGame.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);
|
||||
}
|
||||
|
||||
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
|
||||
public SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
|
||||
if (abilities.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -2,4 +2,6 @@ package forge.util;
|
||||
|
||||
public interface ITriggerEvent {
|
||||
int getButton();
|
||||
int getX();
|
||||
int getY();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package forge.util;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import org.apache.commons.lang3.reflect.TypeUtils;
|
||||
|
||||
/**
|
||||
* Static utilities related to reflection.
|
||||
*
|
||||
@@ -62,4 +65,10 @@ public final class ReflectionUtil {
|
||||
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 {
|
||||
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 CombatView combatView;
|
||||
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()) {
|
||||
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 + "?")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
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.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.StaticData;
|
||||
import forge.card.CardStateName;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.card.CardStateName;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
@@ -23,11 +28,6 @@ import forge.item.PaperCard;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Lang;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PlayEffect extends SpellAbilityEffect {
|
||||
@Override
|
||||
protected String getStackDescription(SpellAbility sa) {
|
||||
@@ -160,13 +160,13 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
}
|
||||
Card original = tgtCard;
|
||||
if (sa.hasParam("CopyCard")) {
|
||||
Zone zone = tgtCard.getZone();
|
||||
final Zone zone = tgtCard.getZone();
|
||||
tgtCard = Card.fromPaperCard(tgtCard.getPaperCard(), sa.getActivatingPlayer());
|
||||
|
||||
tgtCard.setToken(true);
|
||||
tgtCard.setZone(zone);
|
||||
if (zone != null) {
|
||||
zone.add(tgtCard);
|
||||
zone.add(tgtCard);
|
||||
}
|
||||
|
||||
if (useEncoded) {
|
||||
@@ -197,7 +197,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
// 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");
|
||||
if (noManaCost) {
|
||||
tgtSA = tgtSA.copyWithNoManaCost();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.player;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
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
|
||||
* 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 ZoneType zone;
|
||||
private final PlayerView owner;
|
||||
|
||||
@@ -90,8 +90,8 @@ public abstract class PlayerController {
|
||||
public Player getPlayer() { return player; }
|
||||
public LobbyPlayer getLobbyPlayer() { return lobbyPlayer; }
|
||||
|
||||
public final SpellAbility getAbilityToPlay(List<SpellAbility> abilities) { return getAbilityToPlay(abilities, null); }
|
||||
public abstract SpellAbility getAbilityToPlay(List<SpellAbility> abilities, ITriggerEvent triggerEvent);
|
||||
public final SpellAbility getAbilityToPlay(final Card hostCard, final List<SpellAbility> abilities) { return getAbilityToPlay(hostCard, abilities, null); }
|
||||
public abstract SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent);
|
||||
|
||||
//public abstract void playFromSuspend(Card c);
|
||||
public abstract void playSpellAbilityForFree(SpellAbility copySA, boolean mayChoseNewTargets);
|
||||
|
||||
@@ -375,6 +375,8 @@ public class PlayerView extends GameEntityView {
|
||||
}
|
||||
public String getDetails() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append(getName());
|
||||
builder.append('\n');
|
||||
for (final String detailsPart : getDetailsList()) {
|
||||
builder.append(detailsPart);
|
||||
builder.append('\n');
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
package forge.screens.match;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -32,11 +32,10 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.MenuElement;
|
||||
import javax.swing.MenuSelectionManager;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import forge.FThreads;
|
||||
@@ -56,7 +55,6 @@ import forge.game.combat.CombatView;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -72,11 +70,9 @@ import forge.gui.framework.IVDoc;
|
||||
import forge.gui.framework.SDisplayUtil;
|
||||
import forge.gui.framework.SLayoutIO;
|
||||
import forge.gui.framework.VEmptyDoc;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.AbstractGuiGame;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.menus.IMenuProvider;
|
||||
import forge.model.FModel;
|
||||
import forge.player.PlayerZoneUpdate;
|
||||
@@ -97,7 +93,6 @@ import forge.toolbox.FButton;
|
||||
import forge.toolbox.FOptionPane;
|
||||
import forge.toolbox.FSkin;
|
||||
import forge.toolbox.FSkin.SkinImage;
|
||||
import forge.toolbox.MouseTriggerEvent;
|
||||
import forge.toolbox.special.PhaseIndicator;
|
||||
import forge.toolbox.special.PhaseLabel;
|
||||
import forge.trackable.TrackableCollection;
|
||||
@@ -149,13 +144,13 @@ public final class CMatchUI
|
||||
Singletons.getView().getLpnDocument().add(targetingOverlay.getPanel(), FView.TARGETING_LAYER);
|
||||
targetingOverlay.getPanel().setSize(Singletons.getControl().getDisplaySize());
|
||||
this.myDocs = new EnumMap<EDocID, IVDoc<? extends ICDoc>>(EDocID.class);
|
||||
this.myDocs.put(EDocID.CARD_PICTURE, getCDetailPicture().getCPicture().getView());
|
||||
this.myDocs.put(EDocID.CARD_DETAIL, getCDetailPicture().getCDetail().getView());
|
||||
this.myDocs.put(EDocID.CARD_ANTES, getCAntes().getView());
|
||||
this.myDocs.put(EDocID.CARD_PICTURE, cDetailPicture.getCPicture().getView());
|
||||
this.myDocs.put(EDocID.CARD_DETAIL, cDetailPicture.getCDetail().getView());
|
||||
this.myDocs.put(EDocID.CARD_ANTES, cAntes.getView());
|
||||
this.myDocs.put(EDocID.REPORT_MESSAGE, getCPrompt().getView());
|
||||
this.myDocs.put(EDocID.REPORT_STACK, getCStack().getView());
|
||||
this.myDocs.put(EDocID.REPORT_COMBAT, getCCombat().getView());
|
||||
this.myDocs.put(EDocID.REPORT_LOG, getCLog().getView());
|
||||
this.myDocs.put(EDocID.REPORT_COMBAT, cCombat.getView());
|
||||
this.myDocs.put(EDocID.REPORT_LOG, cLog.getView());
|
||||
this.myDocs.put(EDocID.DEV_MODE, getCDev().getView());
|
||||
this.myDocs.put(EDocID.BUTTON_DOCK, getCDock().getView());;
|
||||
}
|
||||
@@ -212,25 +207,13 @@ public final class CMatchUI
|
||||
getCDev().update();
|
||||
}
|
||||
|
||||
public CAntes getCAntes() {
|
||||
return cAntes;
|
||||
}
|
||||
public CCombat getCCombat() {
|
||||
return cCombat;
|
||||
}
|
||||
public CDetailPicture getCDetailPicture() {
|
||||
return cDetailPicture;
|
||||
}
|
||||
public CDev getCDev() {
|
||||
return cDev;
|
||||
}
|
||||
public CDock getCDock() {
|
||||
return cDock;
|
||||
}
|
||||
public CLog getCLog() {
|
||||
return cLog;
|
||||
}
|
||||
public CPrompt getCPrompt() {
|
||||
CPrompt getCPrompt() {
|
||||
return cPrompt;
|
||||
}
|
||||
public CStack getCStack() {
|
||||
@@ -338,24 +321,6 @@ public final class CMatchUI
|
||||
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
|
||||
public void setCard(final CardView c) {
|
||||
this.setCard(c, false);
|
||||
@@ -395,8 +360,8 @@ public final class CMatchUI
|
||||
SDisplayUtil.showTab(selectedDocBeforeCombat);
|
||||
selectedDocBeforeCombat = null;
|
||||
}
|
||||
getCCombat().setModel(combat);
|
||||
getCCombat().update();
|
||||
cCombat.setModel(combat);
|
||||
cCombat.update();
|
||||
} // showCombat(CombatView)
|
||||
|
||||
@Override
|
||||
@@ -548,26 +513,60 @@ public final class CMatchUI
|
||||
return panels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IButton getBtnOK(final PlayerView playerView) {
|
||||
return view.getBtnOK();
|
||||
/**
|
||||
* Find the card panel belonging to a card, bringing up the corresponding
|
||||
* 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 IButton getBtnCancel(final PlayerView playerView) {
|
||||
return view.getBtnCancel();
|
||||
}
|
||||
public void updateButtons(final PlayerView owner, final String label1, final String label2, final boolean enable1, final boolean enable2, final boolean focus1) {
|
||||
final FButton btn1 = view.getBtnOK(), btn2 = view.getBtnCancel();
|
||||
btn1.setText(label1);
|
||||
btn2.setText(label2);
|
||||
btn1.setEnabled(enable1);
|
||||
btn2.setEnabled(enable2);
|
||||
|
||||
@Override
|
||||
public void focusButton(final MatchButtonType button) {
|
||||
final FButton toFocus = enable1 && focus1 ? btn1 : (enable2 ? btn2 : null);
|
||||
// ensure we don't steal focus from an overlay
|
||||
if (!SOverlayUtils.overlayHasFocus()) {
|
||||
if (toFocus != null && !SOverlayUtils.overlayHasFocus()) {
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override public final void run() {
|
||||
final FButton btn = button == MatchButtonType.OK
|
||||
? getCPrompt().getView().getBtnOK()
|
||||
: getCPrompt().getView().getBtnCancel();
|
||||
btn.requestFocusInWindow();
|
||||
toFocus.requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -671,7 +670,7 @@ public final class CMatchUI
|
||||
}
|
||||
|
||||
@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 (abilities.isEmpty()) {
|
||||
return null;
|
||||
@@ -696,19 +695,20 @@ public final class CMatchUI
|
||||
final JPopupMenu menu = new JPopupMenu("Abilities");
|
||||
|
||||
boolean enabled;
|
||||
boolean hasEnabled = false;
|
||||
int firstEnabled = -1;
|
||||
int shortcut = KeyEvent.VK_1; //use number keys as shortcuts for abilities 1-9
|
||||
int index = 0;
|
||||
for (final SpellAbilityView ab : abilities) {
|
||||
enabled = ab.canPlay();
|
||||
if (enabled) {
|
||||
hasEnabled = true;
|
||||
if (enabled && firstEnabled < 0) {
|
||||
firstEnabled = index;
|
||||
}
|
||||
GuiUtils.addMenuItem(menu, FSkin.encodeSymbols(ab.toString(), true),
|
||||
shortcut > 0 ? KeyStroke.getKeyStroke(shortcut, 0) : null,
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
cPrompt.selectAbility(ab);
|
||||
getGameController().selectAbility(ab);
|
||||
}
|
||||
}, enabled);
|
||||
if (shortcut > 0) {
|
||||
@@ -717,15 +717,38 @@ public final class CMatchUI
|
||||
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
|
||||
public void run() {
|
||||
MenuSelectionManager.defaultManager().setSelectedPath(new MenuElement[]{menu, menu.getSubElements()[0]});
|
||||
|
||||
if (firstEnabled >= 0) { //only show menu if at least one ability can be played
|
||||
final CardPanel panel = findCardPanel(hostCard);
|
||||
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
|
||||
@@ -772,7 +795,7 @@ public final class CMatchUI
|
||||
@Override
|
||||
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
||||
final GameView gameView = getGameView();
|
||||
gameView.getGameLog().addObserver(getCLog());
|
||||
gameView.getGameLog().addObserver(cLog);
|
||||
|
||||
// Sort players
|
||||
FCollectionView<PlayerView> players = gameView.getPlayers();
|
||||
|
||||
@@ -32,6 +32,6 @@ public class ZoneAction extends ForgeAction {
|
||||
|
||||
@Override
|
||||
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.
|
||||
*/
|
||||
public void endTurn() {
|
||||
matchUI.getCPrompt().passPriorityUntilEndOfTurn();
|
||||
matchUI.getGameController().passPriorityUntilEndOfTurn();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,7 @@ public class CField implements ICDoc {
|
||||
private final MouseListener madAvatar = new MouseAdapter() {
|
||||
@Override
|
||||
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 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())) {
|
||||
return matchUI.getGameController().useMana(colorCode.byteValue());
|
||||
final int oldMana = player.getMana(colorCode);
|
||||
matchUI.getGameController().useMana(colorCode.byteValue());
|
||||
return oldMana != player.getMana(colorCode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -23,22 +23,17 @@ import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JButton;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.UiCommand;
|
||||
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.SDisplayUtil;
|
||||
import forge.screens.match.CMatchUI;
|
||||
import forge.screens.match.views.VPrompt;
|
||||
import forge.toolbox.FSkin;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
/**
|
||||
* Controls the prompt panel in the match UI.
|
||||
@@ -96,34 +91,14 @@ public class CPrompt implements ICDoc {
|
||||
_initButton(view.getBtnOK(), actOK);
|
||||
}
|
||||
|
||||
public void selectButtonOk() {
|
||||
private void selectButtonOk() {
|
||||
matchUI.getGameController().selectButtonOk();
|
||||
}
|
||||
|
||||
public void selectButtonCancel() {
|
||||
private void 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) {
|
||||
view.getTarMessage().setText(FSkin.encodeSymbols(s0, false));
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ public final class GameMenu {
|
||||
return new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
matchUI.getGameController().tryUndoLastAction();
|
||||
matchUI.getGameController().undoLastAction();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public class VStack implements IVDoc<CStack> {
|
||||
// Other fields
|
||||
private final AbilityMenu abilityMenu = new AbilityMenu();
|
||||
|
||||
private static StackInstanceTextArea hoveredItem;
|
||||
private StackInstanceTextArea hoveredItem;
|
||||
|
||||
public StackInstanceTextArea getHoveredItem() {
|
||||
return hoveredItem;
|
||||
@@ -267,7 +267,7 @@ public class VStack implements IVDoc<CStack> {
|
||||
controller.getMatchUI().setShouldAutoYield(key, !autoYield);
|
||||
if (!autoYield && controller.getMatchUI().getGameView().peekStack() == item) {
|
||||
//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;
|
||||
|
||||
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.assets.FSkinProp;
|
||||
import forge.gui.framework.ILocalRepaint;
|
||||
@@ -25,11 +43,6 @@ import forge.toolbox.FSkin.Colors;
|
||||
import forge.toolbox.FSkin.SkinImage;
|
||||
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
|
||||
* theme button styling.
|
||||
|
||||
@@ -7,20 +7,28 @@ import forge.util.ITriggerEvent;
|
||||
|
||||
//MouseEvent wrapper used for passing trigger to input classes
|
||||
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) {
|
||||
event = event0;
|
||||
public MouseTriggerEvent(final MouseEvent event) {
|
||||
this.button = event.getButton();
|
||||
this.x = event.getX();
|
||||
this.y = event.getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getButton() {
|
||||
return event.getButton();
|
||||
return button;
|
||||
}
|
||||
|
||||
public MouseEvent getMouseEvent() {
|
||||
return event;
|
||||
@Override
|
||||
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.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.Timer;
|
||||
@@ -55,12 +56,20 @@ public class FloatingCardArea extends CardArea {
|
||||
private static final String COORD_DELIM = ",";
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
FloatingCardArea cardArea = floatingAreas.get(key);
|
||||
if (cardArea == null || cardArea.getMatchUI() != matchUI) {
|
||||
@@ -69,7 +78,11 @@ public class FloatingCardArea extends CardArea {
|
||||
} else {
|
||||
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) {
|
||||
FloatingCardArea cardArea = floatingAreas.get(getKey(player, zone));
|
||||
@@ -188,16 +201,22 @@ public class FloatingCardArea extends CardArea {
|
||||
}
|
||||
|
||||
private void showWindow() {
|
||||
onShow();
|
||||
window.setVisible(true);
|
||||
}
|
||||
private void showOrHideWindow() {
|
||||
onShow();
|
||||
window.setVisible(!window.isVisible());
|
||||
}
|
||||
private void onShow() {
|
||||
if (!hasBeenShown) {
|
||||
loadLocation();
|
||||
window.getTitleBar().addMouseListener(new FMouseAdapter() {
|
||||
@Override
|
||||
public void onLeftDoubleClick(MouseEvent e) {
|
||||
@Override public final void onLeftDoubleClick(final MouseEvent e) {
|
||||
window.setVisible(false); //hide window if titlebar double-clicked
|
||||
}
|
||||
});
|
||||
}
|
||||
window.setVisible(!window.isVisible());
|
||||
}
|
||||
|
||||
private void loadLocation() {
|
||||
@@ -251,7 +270,7 @@ public class FloatingCardArea extends CardArea {
|
||||
window.setSize(mainFrame.getWidth() / 5, mainFrame.getHeight() / 2);
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
private void refresh() {
|
||||
if (!window.isVisible()) { return; } //don't refresh while window hidden
|
||||
|
||||
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
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
layoutTimer.stop();
|
||||
@@ -311,12 +330,12 @@ public class FloatingCardArea extends CardArea {
|
||||
}
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,14 +60,14 @@ public class HandArea extends CardArea {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
//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
|
||||
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
|
||||
return getAbilityToPlay(abilities);
|
||||
public SpellAbility getAbilityToPlay(Card hostCard, List<SpellAbility> abilities, ITriggerEvent triggerEvent) {
|
||||
// Isn't this a method invocation loop? --elcnesh
|
||||
return getAbilityToPlay(hostCard, abilities);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,11 +34,9 @@ import forge.game.player.IHasIcon;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.AbstractGuiGame;
|
||||
import forge.match.HostedMatch;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.model.FModel;
|
||||
import forge.player.PlayerZoneUpdate;
|
||||
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.VPrompt;
|
||||
import forge.screens.match.winlose.ViewWinLose;
|
||||
import forge.toolbox.FButton;
|
||||
import forge.toolbox.FDisplayObject;
|
||||
import forge.toolbox.FOptionPane;
|
||||
import forge.trackable.TrackableCollection;
|
||||
@@ -142,24 +141,18 @@ public class MatchController extends AbstractGuiGame {
|
||||
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
|
||||
public void showPromptMessage(final PlayerView player, final String message) {
|
||||
view.getPrompt(player).setMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusButton(final MatchButtonType button) {
|
||||
//not needed for mobile game
|
||||
public void updateButtons(final PlayerView owner, final String label1, final String label2, final boolean enable1, final boolean enable2, final boolean focus1) {
|
||||
final VPrompt prompt = view.getPrompt(owner);
|
||||
final FButton btn1 = prompt.getBtnOk(), btn2 = prompt.getBtnCancel();
|
||||
btn1.setText(label1);
|
||||
btn2.setText(label2);
|
||||
btn1.setEnabled(enable1);
|
||||
btn2.setEnabled(enable2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -224,7 +217,7 @@ public class MatchController extends AbstractGuiGame {
|
||||
}
|
||||
|
||||
@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()) {
|
||||
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
|
||||
public void updateZones(Iterable<PlayerZoneUpdate> zonesToUpdate) {
|
||||
view.updateZones(zonesToUpdate);
|
||||
|
||||
@@ -384,7 +384,7 @@ public class MatchScreen extends FScreen {
|
||||
break;
|
||||
case Keys.Z: //undo on Ctrl+Z
|
||||
if (KeyInputAdapter.isCtrlKeyDown()) {
|
||||
getGameController().tryUndoLastAction();
|
||||
getGameController().undoLastAction();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -91,7 +91,13 @@ public class VManaPool extends VDisplayArea {
|
||||
public boolean flick(float x, float y) {
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -5,11 +5,8 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
|
||||
import forge.Graphics;
|
||||
import forge.assets.FImage;
|
||||
import forge.assets.FSkinFont;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.menu.FDropDown;
|
||||
import forge.model.FModel;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.screens.match.MatchController;
|
||||
import forge.toolbox.FContainer;
|
||||
import forge.toolbox.FDisplayObject;
|
||||
@@ -65,33 +62,7 @@ public class VPlayers extends FDropDown {
|
||||
g.drawImage(avatarImage, x, y, h, h);
|
||||
x += h + PADDING;
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
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);
|
||||
g.drawText(player.getDetails(), FONT, FList.FORE_COLOR, x, y, getWidth() - PADDING - x, h, true, HAlignment.LEFT, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -126,7 +126,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
}
|
||||
synchronized (zonesUpdate) {
|
||||
if (!zonesUpdate.isEmpty()) {
|
||||
matchController.updateZones(zonesUpdate);
|
||||
// Copy to prevent concurrency issues
|
||||
matchController.updateZones(new PlayerZoneUpdates(zonesUpdate));
|
||||
zonesUpdate.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,7 @@ public class WatchLocalGame extends PlayerControllerHuman {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryUndoLastAction() {
|
||||
return false;
|
||||
public void undoLastAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,18 +62,15 @@ public class WatchLocalGame extends PlayerControllerHuman {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriority() {
|
||||
return false;
|
||||
public void passPriority() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriorityUntilEndOfTurn() {
|
||||
return false;
|
||||
public void passPriorityUntilEndOfTurn() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useMana(final byte mana) {
|
||||
return false;
|
||||
public void useMana(final byte mana) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,15 +18,15 @@ public interface IGameController {
|
||||
|
||||
void alphaStrike();
|
||||
|
||||
boolean useMana(byte color);
|
||||
void useMana(byte color);
|
||||
|
||||
void selectButtonOk();
|
||||
|
||||
void selectButtonCancel();
|
||||
|
||||
boolean passPriority();
|
||||
void passPriority();
|
||||
|
||||
boolean passPriorityUntilEndOfTurn();
|
||||
void passPriorityUntilEndOfTurn();
|
||||
|
||||
void selectPlayer(PlayerView playerView, ITriggerEvent triggerEvent);
|
||||
|
||||
@@ -35,7 +35,7 @@ public interface IGameController {
|
||||
|
||||
void selectAbility(SpellAbilityView sa);
|
||||
|
||||
boolean tryUndoLastAction();
|
||||
void undoLastAction();
|
||||
|
||||
IDevModeCheats cheat();
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.player.PlayerZoneUpdate;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.ITriggerEvent;
|
||||
@@ -31,10 +30,8 @@ public interface IGuiGame {
|
||||
void afterGameEnd();
|
||||
void showCombat();
|
||||
void showPromptMessage(PlayerView playerView, String message);
|
||||
boolean stopAtPhase(PlayerView playerTurn, PhaseType phase);
|
||||
IButton getBtnOK(PlayerView playerView);
|
||||
IButton getBtnCancel(PlayerView playerView);
|
||||
void focusButton(MatchButtonType button);
|
||||
void updateButtons(PlayerView owner, boolean okEnabled, boolean cancelEnabled, boolean focusOk);
|
||||
void updateButtons(PlayerView owner, String label1, String label2, boolean enable1, boolean enable2, boolean focus1);
|
||||
void flashIncorrectAction();
|
||||
void updatePhase();
|
||||
void updateTurn(PlayerView player);
|
||||
@@ -52,11 +49,8 @@ public interface IGuiGame {
|
||||
void updateManaPool(Iterable<PlayerView> manaPoolUpdate);
|
||||
void updateLives(Iterable<PlayerView> livesUpdate);
|
||||
void setPanelSelection(CardView hostCard);
|
||||
SpellAbilityView getAbilityToPlay(List<SpellAbilityView> abilities,
|
||||
ITriggerEvent triggerEvent);
|
||||
Map<CardView, Integer> assignDamage(CardView attacker,
|
||||
List<CardView> blockers, int damage, GameEntityView defender,
|
||||
boolean overrideOrder);
|
||||
SpellAbilityView getAbilityToPlay(CardView hostCard, List<SpellAbilityView> abilities, ITriggerEvent triggerEvent);
|
||||
Map<CardView, Integer> assignDamage(CardView attacker, List<CardView> blockers, int damage, GameEntityView defender, boolean overrideOrder);
|
||||
|
||||
void message(String message);
|
||||
void message(String message, String title);
|
||||
@@ -163,10 +157,6 @@ public interface IGuiGame {
|
||||
void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi);
|
||||
boolean openZones(Collection<ZoneType> zones, Map<PlayerView, Object> players);
|
||||
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 setUsedToPay(CardView card, boolean value);
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CardView.CardStateView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.interfaces.IMayViewCards;
|
||||
@@ -195,20 +194,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateButtons(final PlayerView owner, final String okLabel, final String cancelLabel, final boolean okEnabled, final boolean cancelEnabled, final boolean focusOk) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
public abstract void updateButtons(PlayerView owner, String label1, String label2, boolean enable1, boolean enable2, boolean focus1);
|
||||
|
||||
// Auto-yield and other input-related code
|
||||
|
||||
|
||||
@@ -193,11 +193,6 @@ public class HostedMatch {
|
||||
gui.setGameController(null, humanController);
|
||||
|
||||
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
|
||||
|
||||
@@ -129,7 +129,7 @@ public class InputPassPriority extends InputSyncronizedBase {
|
||||
return false;
|
||||
}
|
||||
|
||||
final SpellAbility ability = getController().getAbilityToPlay(abilities, triggerEvent);
|
||||
final SpellAbility ability = getController().getAbilityToPlay(card, abilities, triggerEvent);
|
||||
if (ability != null) {
|
||||
chosenSa = new ArrayList<SpellAbility>();
|
||||
chosenSa.add(ability);
|
||||
|
||||
@@ -153,14 +153,12 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
return abilities;
|
||||
}
|
||||
|
||||
public boolean useManaFromPool(byte colorCode) {
|
||||
public void useManaFromPool(byte colorCode) {
|
||||
// find the matching mana in pool.
|
||||
if (player.getManaPool().tryPayCostWithColor(colorCode, saPaidFor, manaCost)) {
|
||||
onManaAbilityPaid();
|
||||
showMessage();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean activateManaAbility(final Card card, ManaCostBeingPaid manaCost) {
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.util.Map;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.UiCommand;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntityView;
|
||||
@@ -18,11 +17,12 @@ import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.ReflectionUtil;
|
||||
|
||||
public final class GameProtocol {
|
||||
|
||||
@@ -36,101 +36,146 @@ public final class GameProtocol {
|
||||
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.
|
||||
*/
|
||||
public enum ProtocolMethod {
|
||||
setGameView(Void.TYPE, GameView.class),
|
||||
openView(Void.TYPE, TrackableCollection.class),
|
||||
afterGameEnd(),
|
||||
showCombat(),
|
||||
showPromptMessage(Void.TYPE, PlayerView.class, String.class),
|
||||
stopAtPhase(Boolean.TYPE, PlayerView.class, PhaseType.class),
|
||||
focusButton(Void.TYPE, MatchButtonType.class),
|
||||
flashIncorrectAction(),
|
||||
updatePhase(),
|
||||
updateTurn(Void.TYPE, PlayerView.class),
|
||||
updatePlayerControl(),
|
||||
enableOverlay(),
|
||||
disableOverlay(),
|
||||
finishGame(),
|
||||
showManaPool(Void.TYPE, PlayerView.class),
|
||||
hideManaPool(Void.TYPE, PlayerView.class),
|
||||
updateStack(),
|
||||
updateZones(Void.TYPE, Iterable.class),
|
||||
updateCards(Void.TYPE, Iterable.class),
|
||||
updateManaPool(Void.TYPE, Iterable.class),
|
||||
updateLives(Void.TYPE, Iterable.class),
|
||||
setPanelSelection(Void.TYPE, CardView.class),
|
||||
getAbilityToPlay(SpellAbilityView.class, List.class, ITriggerEvent.class),
|
||||
assignDamage(Map.class, CardView.class, List.class, Integer.TYPE, GameEntityView.class, Boolean.TYPE),
|
||||
message(Void.TYPE, String.class, String.class),
|
||||
showErrorDialog(Void.TYPE, String.class, String.class),
|
||||
showConfirmDialog(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),
|
||||
showCardOptionDialog(Integer.TYPE, CardView.class, String.class, String.class, FSkinProp.class, String.class, Array.class),
|
||||
showInputDialog(String.class, String.class, String.class, FSkinProp.class, String.class, Array.class),
|
||||
confirm(Boolean.TYPE, CardView.class, String.class, Boolean.TYPE, Array.class),
|
||||
getChoices(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),
|
||||
sideboard(List.class, CardPool.class, CardPool.class),
|
||||
chooseSingleEntityForEffect(GameEntityView.class, String.class, TrackableCollection.class, DelayedReveal.class, Boolean.TYPE),
|
||||
setCard(Void.TYPE, CardView.class),
|
||||
// Server -> Client
|
||||
setGameView (Mode.SERVER, Void.TYPE, GameView.class),
|
||||
openView (Mode.SERVER, Void.TYPE, TrackableCollection/*PlayerView*/.class),
|
||||
afterGameEnd (Mode.SERVER),
|
||||
showCombat (Mode.SERVER),
|
||||
showPromptMessage (Mode.SERVER, Void.TYPE, PlayerView.class, String.class),
|
||||
updateButtons (Mode.SERVER, Void.TYPE, PlayerView.class, String.class, String.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE),
|
||||
flashIncorrectAction(Mode.SERVER),
|
||||
updatePhase (Mode.SERVER),
|
||||
updateTurn (Mode.SERVER, Void.TYPE, PlayerView.class),
|
||||
updatePlayerControl (Mode.SERVER),
|
||||
enableOverlay (Mode.SERVER),
|
||||
disableOverlay (Mode.SERVER),
|
||||
finishGame (Mode.SERVER),
|
||||
showManaPool (Mode.SERVER, Object.class, PlayerView.class),
|
||||
hideManaPool (Mode.SERVER, Void.TYPE, PlayerView.class),
|
||||
updateStack (Mode.SERVER),
|
||||
updateZones (Mode.SERVER, Void.TYPE, Iterable/*PlayerZoneUpdate*/.class),
|
||||
updateCards (Mode.SERVER, Void.TYPE, Iterable/*CardView*/.class),
|
||||
updateManaPool (Mode.SERVER, Void.TYPE, Iterable/*PlayerView*/.class),
|
||||
updateLives (Mode.SERVER, Void.TYPE, Iterable/*PlayerView*/.class),
|
||||
setPanelSelection (Mode.SERVER, Void.TYPE, CardView.class),
|
||||
getAbilityToPlay (Mode.SERVER, SpellAbilityView.class, CardView.class, List/*SpellAbilityView*/.class, ITriggerEvent.class),
|
||||
assignDamage (Mode.SERVER, Map.class, CardView.class, List/*CardView*/.class, Integer.TYPE, GameEntityView.class, Boolean.TYPE),
|
||||
message (Mode.SERVER, Void.TYPE, String.class, String.class),
|
||||
showErrorDialog (Mode.SERVER, Void.TYPE, String.class, String.class),
|
||||
showConfirmDialog (Mode.SERVER, Boolean.TYPE, String.class, String.class, String.class, String.class, Boolean.TYPE),
|
||||
showOptionDialog (Mode.SERVER, Integer.TYPE, String.class, String.class, FSkinProp.class, Array/*String*/.class, Integer.TYPE),
|
||||
showCardOptionDialog(Mode.SERVER, Integer.TYPE, CardView.class, String.class, String.class, FSkinProp.class, String.class, Array/*String*/.class),
|
||||
showInputDialog (Mode.SERVER, String.class, String.class, String.class, FSkinProp.class, String.class, Array/*String*/.class),
|
||||
confirm (Mode.SERVER, Boolean.TYPE, CardView.class, String.class, Boolean.TYPE, Array/*String*/.class),
|
||||
getChoices (Mode.SERVER, List.class, String.class, Integer.TYPE, Integer.TYPE, Collection.class, Object.class, Function.class),
|
||||
order (Mode.SERVER, List.class, String.class, String.class, Integer.TYPE, Integer.TYPE, List.class, List.class, CardView.class, Boolean.TYPE),
|
||||
sideboard (Mode.SERVER, List.class, CardPool.class, CardPool.class),
|
||||
chooseSingleEntityForEffect(Mode.SERVER, GameEntityView.class, String.class, TrackableCollection.class, DelayedReveal.class, Boolean.TYPE),
|
||||
setCard (Mode.SERVER, Void.TYPE, CardView.class),
|
||||
// TODO case "setPlayerAvatar":
|
||||
openZones(Boolean.TYPE, Collection.class, Map.class),
|
||||
restoreOldZones(Void.TYPE, Map.class),
|
||||
isUiSetToSkipPhase(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);
|
||||
openZones (Mode.SERVER, Boolean.TYPE, Collection/*ZoneType*/.class, Map/*PlayerView,Object*/.class),
|
||||
restoreOldZones (Mode.SERVER, Void.TYPE, Map/*PlayerView,Object*/.class),
|
||||
isUiSetToSkipPhase (Mode.SERVER, Boolean.TYPE, PlayerView.class, PhaseType.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<?>[] args;
|
||||
|
||||
private ProtocolMethod() {
|
||||
this(Void.TYPE);
|
||||
private ProtocolMethod(final Mode mode) {
|
||||
this(mode, Void.TYPE);
|
||||
}
|
||||
private ProtocolMethod(final Class<?> returnType) {
|
||||
this(returnType, (Class<?>[]) null);
|
||||
private ProtocolMethod(final Mode mode, final Class<?> returnType) {
|
||||
this(mode, returnType, (Class<?>[]) null);
|
||||
}
|
||||
@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.args = args == null ? new Class<?>[] {} : args;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
try {
|
||||
final String name;
|
||||
final Class<?> toCall;
|
||||
if (name().startsWith("btn_")) {
|
||||
name = name().substring("btn_".length());
|
||||
toCall = IButton.class;
|
||||
} else {
|
||||
name = name();
|
||||
toCall = IGuiGame.class;
|
||||
}
|
||||
|
||||
final Method candidate = toCall.getMethod(name, args);
|
||||
if (!candidate.getReturnType().equals(returnType)) {
|
||||
final Class<?> toCall = mode.toInvoke;
|
||||
final Method candidate = toCall.getMethod(name(), args);
|
||||
// Don't check Client return values for now as some use void
|
||||
// and a default return value, to improve performance
|
||||
if (mode == Mode.SERVER && !candidate.getReturnType().equals(returnType)) {
|
||||
throw new NoSuchMethodException(String.format("Wrong return type for method %s", name()));
|
||||
}
|
||||
return candidate;
|
||||
} catch (final NoSuchMethodException | SecurityException e) {
|
||||
System.err.println(String.format("Warning: class contains no method named %s", name()));
|
||||
return null;
|
||||
System.err.println(String.format("Warning: class contains no accessible method named %s", name()));
|
||||
return getMethodNoArgs();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean invokeOnButton() {
|
||||
return name().startsWith("btn_");
|
||||
private Method getMethodNoArgs() {
|
||||
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;
|
||||
|
||||
import forge.FThreads;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.model.FModel;
|
||||
import forge.net.GameProtocol;
|
||||
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.ReplyEvent;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
class GameClientHandler extends ChannelInboundHandlerAdapter {
|
||||
final class GameClientHandler extends GameProtocolHandler<IGuiGame> {
|
||||
private final FGameClient client;
|
||||
private final IGuiGame gui;
|
||||
|
||||
@@ -28,93 +20,43 @@ class GameClientHandler extends ChannelInboundHandlerAdapter {
|
||||
* Creates a client-side game handler.
|
||||
*/
|
||||
public GameClientHandler(final FGameClient client) {
|
||||
super(true);
|
||||
this.client = client;
|
||||
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
|
||||
public void channelActive(final ChannelHandlerContext ctx) {
|
||||
// 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])));
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
@@ -9,90 +8,77 @@ import forge.game.spellability.SpellAbilityView;
|
||||
import forge.interfaces.IDevModeCheats;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.net.event.GuiGameEvent;
|
||||
import forge.net.GameProtocol.ProtocolMethod;
|
||||
import forge.net.GameProtocolSender;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class NetGameController implements IGameController {
|
||||
|
||||
private final IToServer server;
|
||||
private final GameProtocolSender sender;
|
||||
public NetGameController(final IToServer server) {
|
||||
this.server = server;
|
||||
this.sender = new GameProtocolSender(server);
|
||||
}
|
||||
|
||||
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 void send(final ProtocolMethod method, final Object... args) {
|
||||
sender.send(method, args);
|
||||
}
|
||||
|
||||
private void send(final String method, final Object... args) {
|
||||
server.send(new GuiGameEvent(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;
|
||||
private <T> T sendAndWait(final ProtocolMethod method, final Object... args) {
|
||||
return sender.sendAndWait(method, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useMana(final byte color) {
|
||||
return sendAndWait(methodName(), color);
|
||||
public void useMana(final byte color) {
|
||||
send(ProtocolMethod.useMana, Byte.valueOf(color));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryUndoLastAction() {
|
||||
return sendAndWait(methodName());
|
||||
public void undoLastAction() {
|
||||
send(ProtocolMethod.undoLastAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectPlayer(final PlayerView playerView, final ITriggerEvent triggerEvent) {
|
||||
send(methodName(), playerView, triggerEvent);
|
||||
send(ProtocolMethod.selectPlayer, playerView, triggerEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
public void selectButtonOk() {
|
||||
send(methodName());
|
||||
send(ProtocolMethod.selectButtonOk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
send(methodName());
|
||||
send(ProtocolMethod.selectButtonCancel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectAbility(final SpellAbilityView sa) {
|
||||
send(methodName(), sa);
|
||||
send(ProtocolMethod.selectAbility, sa);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriorityUntilEndOfTurn() {
|
||||
return sendAndWait(methodName());
|
||||
public void passPriorityUntilEndOfTurn() {
|
||||
send(ProtocolMethod.passPriorityUntilEndOfTurn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriority() {
|
||||
return sendAndWait(methodName());
|
||||
public void passPriority() {
|
||||
send(ProtocolMethod.passPriority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextGameDecision(final NextGameDecision decision) {
|
||||
send(methodName(), decision);
|
||||
send(ProtocolMethod.nextGameDecision, decision);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,31 +88,33 @@ public class NetGameController implements IGameController {
|
||||
}
|
||||
|
||||
public String getActivateDescription(final CardView card) {
|
||||
return sendAndWait(methodName(), card);
|
||||
return sendAndWait(ProtocolMethod.getActivateDescription, card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void concede() {
|
||||
send(methodName());
|
||||
send(ProtocolMethod.concede);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDevModeCheats cheat() {
|
||||
// No cheating in network games!
|
||||
return IDevModeCheats.NO_CHEAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayUnlimitedLands() {
|
||||
// Don't do this over network
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alphaStrike() {
|
||||
send(methodName());
|
||||
send(ProtocolMethod.alphaStrike);
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
import forge.net.GameProtocol.ProtocolMethod;
|
||||
import forge.net.server.RemoteClient;
|
||||
|
||||
public final class GuiGameEvent implements IdentifiableNetEvent {
|
||||
@@ -7,10 +8,10 @@ public final class GuiGameEvent implements IdentifiableNetEvent {
|
||||
private static int staticId = 0;
|
||||
|
||||
private final int id;
|
||||
private final String method;
|
||||
private final ProtocolMethod method;
|
||||
private final Object[] objects;
|
||||
|
||||
public GuiGameEvent(final String method, final Object ... objects) {
|
||||
public GuiGameEvent(final ProtocolMethod method, final Object ... objects) {
|
||||
this.id = staticId++;
|
||||
this.method = method;
|
||||
this.objects = objects == null ? new Object[0] : objects;
|
||||
@@ -30,7 +31,7 @@ public final class GuiGameEvent implements IdentifiableNetEvent {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
public ProtocolMethod getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,19 @@
|
||||
package forge.net.server;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
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.IGuiGame;
|
||||
import forge.interfaces.ILobbyListener;
|
||||
import forge.match.LobbySlot;
|
||||
import forge.match.LobbySlotType;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.net.event.GuiGameEvent;
|
||||
import forge.net.event.LobbyUpdateEvent;
|
||||
import forge.net.event.LoginEvent;
|
||||
import forge.net.event.LogoutEvent;
|
||||
import forge.net.event.MessageEvent;
|
||||
import forge.net.event.NetEvent;
|
||||
import forge.net.event.ReplyEvent;
|
||||
import forge.net.event.UpdateLobbyPlayerEvent;
|
||||
import forge.properties.ForgeConstants;
|
||||
import forge.util.ITriggerEvent;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
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.LoggingHandler;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.log4j.PropertyConfigurator;
|
||||
@@ -79,6 +68,16 @@ public final class 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}.
|
||||
*
|
||||
@@ -126,7 +125,7 @@ public final class FServerManager {
|
||||
|
||||
}
|
||||
}).start();
|
||||
//mapNatPort(port);
|
||||
mapNatPort(port);
|
||||
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||
isHosting = true;
|
||||
} 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 {
|
||||
@Override
|
||||
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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.UiCommand;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntityView;
|
||||
@@ -22,54 +18,31 @@ import forge.game.player.IHasIcon;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.AbstractGuiGame;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.net.event.GuiGameEvent;
|
||||
import forge.net.GameProtocol.ProtocolMethod;
|
||||
import forge.net.GameProtocolSender;
|
||||
import forge.player.PlayerZoneUpdate;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class NetGuiGame extends AbstractGuiGame {
|
||||
|
||||
private final IToClient client;
|
||||
private final Map<MatchButtonType, Map<PlayerView, NetButton>> btns = new EnumMap<MatchButtonType, Map<PlayerView,NetButton>>(MatchButtonType.class);
|
||||
private final GameProtocolSender sender;
|
||||
public NetGuiGame(final IToClient client) {
|
||||
this.client = client;
|
||||
for (final MatchButtonType type : MatchButtonType.values()) {
|
||||
btns.put(type, Maps.<PlayerView, NetButton>newHashMap());
|
||||
}
|
||||
this.sender = new GameProtocolSender(client);
|
||||
}
|
||||
|
||||
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 void send(final ProtocolMethod method, final Object... args) {
|
||||
sender.send(method, args);
|
||||
}
|
||||
|
||||
private void send(final String method, final Object... args) {
|
||||
client.send(new GuiGameEvent(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 <T> T sendAndWait(final ProtocolMethod method, final Object... args) {
|
||||
return sender.sendAndWait(method, args);
|
||||
}
|
||||
|
||||
private void updateGameView() {
|
||||
send("setGameView", getGameView());
|
||||
send(ProtocolMethod.setGameView, getGameView());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,227 +53,206 @@ public class NetGuiGame extends AbstractGuiGame {
|
||||
|
||||
@Override
|
||||
public void openView(final TrackableCollection<PlayerView> myPlayers) {
|
||||
for (final MatchButtonType type : MatchButtonType.values()) {
|
||||
btns.get(type).clear();
|
||||
for (final PlayerView player : myPlayers) {
|
||||
btns.get(type).put(player, new NetButton(player, type));
|
||||
}
|
||||
}
|
||||
send(methodName(), myPlayers);
|
||||
send(ProtocolMethod.openView, myPlayers);
|
||||
updateGameView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterGameEnd() {
|
||||
send(methodName());
|
||||
send(ProtocolMethod.afterGameEnd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCombat() {
|
||||
send(methodName());
|
||||
send(ProtocolMethod.showCombat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPromptMessage(final PlayerView playerView, final String message) {
|
||||
updateGameView();
|
||||
send(methodName(), playerView, message);
|
||||
send(ProtocolMethod.showPromptMessage, playerView, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stopAtPhase(final PlayerView playerTurn, final PhaseType phase) {
|
||||
return sendAndWait(methodName(), playerTurn, phase);
|
||||
}
|
||||
|
||||
@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);
|
||||
public void updateButtons(final PlayerView owner, final String label1, final String label2, final boolean enable1, final boolean enable2, final boolean focus1) {
|
||||
send(ProtocolMethod.updateButtons, owner, label1, label2, enable1, enable2, focus1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flashIncorrectAction() {
|
||||
send(methodName());
|
||||
send(ProtocolMethod.flashIncorrectAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePhase() {
|
||||
updateGameView();
|
||||
send(methodName());
|
||||
send(ProtocolMethod.updatePhase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTurn(final PlayerView player) {
|
||||
updateGameView();
|
||||
send(methodName(), player);
|
||||
send(ProtocolMethod.updateTurn, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlayerControl() {
|
||||
updateGameView();
|
||||
send(methodName());
|
||||
send(ProtocolMethod.updatePlayerControl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableOverlay() {
|
||||
send(methodName());
|
||||
send(ProtocolMethod.enableOverlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableOverlay() {
|
||||
send(methodName());
|
||||
send(ProtocolMethod.disableOverlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishGame() {
|
||||
send(methodName());
|
||||
send(ProtocolMethod.finishGame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object showManaPool(final PlayerView player) {
|
||||
send(methodName(), player);
|
||||
send(ProtocolMethod.showManaPool, player);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideManaPool(final PlayerView player, final Object zoneToRestore) {
|
||||
send(methodName(), player, zoneToRestore);
|
||||
send(ProtocolMethod.hideManaPool, player, zoneToRestore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStack() {
|
||||
updateGameView();
|
||||
send(methodName());
|
||||
send(ProtocolMethod.updateStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateZones(final Iterable<PlayerZoneUpdate> zonesToUpdate) {
|
||||
updateGameView();
|
||||
send(methodName(), zonesToUpdate);
|
||||
send(ProtocolMethod.updateZones, zonesToUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCards(final Iterable<CardView> cards) {
|
||||
updateGameView();
|
||||
send(methodName(), cards);
|
||||
send(ProtocolMethod.updateCards, cards);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) {
|
||||
updateGameView();
|
||||
send(methodName(), manaPoolUpdate);
|
||||
send(ProtocolMethod.updateManaPool, manaPoolUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLives(final Iterable<PlayerView> livesUpdate) {
|
||||
updateGameView();
|
||||
send(methodName(), livesUpdate);
|
||||
send(ProtocolMethod.updateLives, livesUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPanelSelection(final CardView hostCard) {
|
||||
updateGameView();
|
||||
send(methodName(), hostCard);
|
||||
send(ProtocolMethod.setPanelSelection, hostCard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAbilityView getAbilityToPlay(final List<SpellAbilityView> abilities, final ITriggerEvent triggerEvent) {
|
||||
return sendAndWait(methodName(), abilities, triggerEvent);
|
||||
public SpellAbilityView getAbilityToPlay(final CardView hostCard, final List<SpellAbilityView> abilities, final ITriggerEvent triggerEvent) {
|
||||
return sendAndWait(ProtocolMethod.getAbilityToPlay, hostCard, abilities, triggerEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
public void message(final String message, final String title) {
|
||||
send(methodName(), message, title);
|
||||
send(ProtocolMethod.message, message, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showErrorDialog(final String message, final String title) {
|
||||
send(methodName(), message, title);
|
||||
send(ProtocolMethod.showErrorDialog, message, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
public List<PaperCard> sideboard(final CardPool sideboard, final CardPool main) {
|
||||
return sendAndWait(methodName(), sideboard, main);
|
||||
return sendAndWait(ProtocolMethod.sideboard, sideboard, main);
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
public void setCard(final CardView card) {
|
||||
updateGameView();
|
||||
send(methodName(), card);
|
||||
send(ProtocolMethod.setCard, card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi) {
|
||||
public void setPlayerAvatar(final LobbyPlayer player, final IHasIcon ihi) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean openZones(final Collection<ZoneType> zones, final Map<PlayerView, Object> players) {
|
||||
updateGameView();
|
||||
return sendAndWait(methodName(), zones, players);
|
||||
return sendAndWait(ProtocolMethod.openZones, zones, players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreOldZones(final Map<PlayerView, Object> playersToRestoreZonesFor) {
|
||||
send(methodName(), playersToRestoreZonesFor);
|
||||
send(ProtocolMethod.restoreOldZones, playersToRestoreZonesFor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUiSetToSkipPhase(final PlayerView playerTurn, final PhaseType phase) {
|
||||
return sendAndWait(methodName(), playerTurn, phase);
|
||||
return sendAndWait(ProtocolMethod.isUiSetToSkipPhase, playerTurn, phase);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -308,71 +260,4 @@ public class NetGuiGame extends AbstractGuiGame {
|
||||
// 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;
|
||||
}
|
||||
|
||||
public void setReply(final int id, final Object reply) {
|
||||
replies.complete(id, reply);
|
||||
ReplyPool getReplyPool() {
|
||||
return replies;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ public class HumanPlay {
|
||||
return 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) {
|
||||
|
||||
@@ -219,8 +219,8 @@ public class PlayerControllerHuman
|
||||
/**
|
||||
* 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) {
|
||||
final SpellAbilityView resultView = getGui().getAbilityToPlay(SpellAbilityView.getCollection(abilities), triggerEvent);
|
||||
public SpellAbility getAbilityToPlay(final Card hostCard, final List<SpellAbility> abilities, final ITriggerEvent triggerEvent) {
|
||||
final SpellAbilityView resultView = getGui().getAbilityToPlay(CardView.get(hostCard), SpellAbilityView.getCollection(abilities), triggerEvent);
|
||||
return getGame().getSpellAbility(resultView);
|
||||
}
|
||||
|
||||
@@ -1304,6 +1304,12 @@ public class PlayerControllerHuman
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void undoLastAction() {
|
||||
tryUndoLastAction();
|
||||
}
|
||||
|
||||
public boolean tryUndoLastAction() {
|
||||
if (!canUndoLastAction()) {
|
||||
return false;
|
||||
@@ -1333,37 +1339,33 @@ public class PlayerControllerHuman
|
||||
}
|
||||
}
|
||||
|
||||
public boolean passPriority() {
|
||||
return passPriority(false);
|
||||
public void passPriority() {
|
||||
passPriority(false);
|
||||
}
|
||||
public boolean passPriorityUntilEndOfTurn() {
|
||||
return passPriority(true);
|
||||
public void passPriorityUntilEndOfTurn() {
|
||||
passPriority(true);
|
||||
}
|
||||
private boolean passPriority(final boolean passUntilEndOfTurn) {
|
||||
private void passPriority(final boolean passUntilEndOfTurn) {
|
||||
final Input inp = inputProxy.getInput();
|
||||
if (inp instanceof InputPassPriority) {
|
||||
if (passUntilEndOfTurn) {
|
||||
autoPassUntilEndOfTurn();
|
||||
}
|
||||
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();
|
||||
if (input instanceof InputPayMana) {
|
||||
return ((InputPayMana) input).useManaFromPool(mana);
|
||||
((InputPayMana) input).useManaFromPool(mana);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void selectPlayer(final PlayerView playerView, final ITriggerEvent triggerEvent) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package forge.player;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -11,11 +12,21 @@ import forge.game.player.PlayerView;
|
||||
public class PlayerZoneUpdates implements Iterable<PlayerZoneUpdate>, Serializable {
|
||||
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() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @param other
|
||||
* the {@link PlayerZoneUpdates} to copy.
|
||||
*/
|
||||
public PlayerZoneUpdates(final PlayerZoneUpdates other) {
|
||||
this.updates.putAll(other.updates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PlayerZoneUpdate> iterator() {
|
||||
return updates.values().iterator();
|
||||
|
||||
Reference in New Issue
Block a user