mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
Refactor lobby and add network support.
- Lobby code has been revised completely to support network lobbies; code has been separated into model and view parts. - Added preliminary network game support; most of it should be working but hasn't been tested thoroughly. - Fixed issue where controlling another player wouldn't be recognised by the GUI. - Fixed issue where hand panels wouldn't display anymore. - Minor fixes/cleanup.
This commit is contained in:
@@ -242,6 +242,9 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
if (ev.player.getGame().isGameOver()) {
|
||||
return null;
|
||||
}
|
||||
if (ev.newController instanceof PlayerControllerHuman) {
|
||||
matchController.setGameController(PlayerView.get(ev.player), (PlayerControllerHuman) ev.newController);
|
||||
}
|
||||
needPlayerControlUpdate = true;
|
||||
return processEvent();
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import forge.LobbyPlayer;
|
||||
import forge.game.Game;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.interfaces.IDevModeCheats;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.input.Input;
|
||||
@@ -90,7 +90,7 @@ public class WatchLocalGame extends PlayerControllerHuman {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectAbility(final SpellAbility sa) {
|
||||
public void selectAbility(final SpellAbilityView sa) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,11 +4,8 @@ import forge.UiCommand;
|
||||
import forge.assets.FSkinProp;
|
||||
|
||||
public interface IButton {
|
||||
boolean isEnabled();
|
||||
void setEnabled(boolean b0);
|
||||
boolean isVisible();
|
||||
void setVisible(boolean b0);
|
||||
String getText();
|
||||
void setText(String text0);
|
||||
boolean isSelected();
|
||||
void setSelected(boolean b0);
|
||||
|
||||
@@ -4,7 +4,7 @@ import java.util.List;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
@@ -33,7 +33,7 @@ public interface IGameController {
|
||||
boolean selectCard(CardView cardView,
|
||||
List<CardView> otherCardViewsToSelect, ITriggerEvent triggerEvent);
|
||||
|
||||
void selectAbility(SpellAbility sa);
|
||||
void selectAbility(SpellAbilityView sa);
|
||||
|
||||
boolean tryUndoLastAction();
|
||||
|
||||
|
||||
@@ -51,5 +51,4 @@ public interface IGuiBase {
|
||||
void showBazaar();
|
||||
IGuiGame getNewGuiGame();
|
||||
HostedMatch hostMatch();
|
||||
void netMessage(String origin, String message);
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import com.google.common.base.Function;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
@@ -19,25 +18,24 @@ import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.item.PaperCard;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.FCollectionView;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public interface IGuiGame {
|
||||
void setGameView(GameView gameView);
|
||||
void setGameController(PlayerView player, IGameController gameController);
|
||||
boolean resetForNewGame();
|
||||
void openView(Iterable<PlayerView> myPlayers);
|
||||
void openView(TrackableCollection<PlayerView> myPlayers);
|
||||
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(IButton button);
|
||||
void focusButton(MatchButtonType button);
|
||||
void flashIncorrectAction();
|
||||
void updatePhase();
|
||||
void updateTurn(PlayerView player);
|
||||
@@ -54,8 +52,7 @@ public interface IGuiGame {
|
||||
void updateManaPool(Iterable<PlayerView> manaPoolUpdate);
|
||||
void updateLives(Iterable<PlayerView> livesUpdate);
|
||||
void setPanelSelection(CardView hostCard);
|
||||
void hear(LobbyPlayer player, String message);
|
||||
SpellAbility getAbilityToPlay(List<SpellAbility> abilities,
|
||||
SpellAbilityView getAbilityToPlay(List<SpellAbilityView> abilities,
|
||||
ITriggerEvent triggerEvent);
|
||||
Map<CardView, Integer> assignDamage(CardView attacker,
|
||||
List<CardView> blockers, int damage, GameEntityView defender,
|
||||
@@ -161,9 +158,8 @@ public interface IGuiGame {
|
||||
|
||||
List<PaperCard> sideboard(CardPool sideboard, CardPool main);
|
||||
GameEntityView chooseSingleEntityForEffect(String title,
|
||||
FCollectionView<? extends GameEntity> optionList,
|
||||
DelayedReveal delayedReveal, boolean isOptional,
|
||||
PlayerControllerHuman controller);
|
||||
Collection<? extends GameEntityView> optionList,
|
||||
DelayedReveal delayedReveal, boolean isOptional);
|
||||
void setCard(CardView card);
|
||||
void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi);
|
||||
boolean openZones(Collection<ZoneType> zones, Map<PlayerView, Object> players);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import forge.net.game.LobbyState;
|
||||
import forge.match.GameLobby;
|
||||
import forge.net.game.server.RemoteClient;
|
||||
|
||||
public interface ILobby {
|
||||
LobbyState getState();
|
||||
GameLobby getState();
|
||||
int login(RemoteClient client);
|
||||
void logout(RemoteClient client);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import forge.match.GameLobby.GameLobbyData;
|
||||
|
||||
public interface ILobbyListener {
|
||||
void message(String source, String message);
|
||||
void update(GameLobbyData state, int slot);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import forge.net.game.LobbyState.LobbyPlayerData;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
|
||||
public interface IPlayerChangeListener {
|
||||
void update(LobbyPlayerData data);
|
||||
void update(int index, UpdateLobbyPlayerEvent event);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package forge.interfaces;
|
||||
|
||||
public interface IUpdateable {
|
||||
void update();
|
||||
}
|
||||
@@ -210,9 +210,9 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
btnOk.setEnabled(okEnabled);
|
||||
btnCancel.setEnabled(cancelEnabled);
|
||||
if (okEnabled && focusOk) {
|
||||
focusButton(btnOk);
|
||||
focusButton(MatchButtonType.OK);
|
||||
} else if (cancelEnabled) {
|
||||
focusButton(btnCancel);
|
||||
focusButton(MatchButtonType.CANCEL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
442
forge-gui/src/main/java/forge/match/GameLobby.java
Normal file
442
forge-gui/src/main/java/forge/match/GameLobby.java
Normal file
@@ -0,0 +1,442 @@
|
||||
package forge.match;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckFormat;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.game.GameType;
|
||||
import forge.game.GameView;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.interfaces.IUpdateable;
|
||||
import forge.item.PaperCard;
|
||||
import forge.model.FModel;
|
||||
import forge.net.game.LobbySlotType;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.NameGenerator;
|
||||
import forge.util.gui.SOptionPane;
|
||||
|
||||
public abstract class GameLobby {
|
||||
private final static int MAX_PLAYERS = 8;
|
||||
|
||||
private GameLobbyData data = new GameLobbyData();
|
||||
private int lastArchenemy = 0;
|
||||
|
||||
private IUpdateable listener;
|
||||
|
||||
private final boolean allowNetworking;
|
||||
private HostedMatch hostedMatch;
|
||||
private final Map<LobbySlot, IGameController> gameControllers = Maps.newHashMap();
|
||||
protected GameLobby(final boolean allowNetworking) {
|
||||
this.allowNetworking = allowNetworking;
|
||||
}
|
||||
|
||||
public final boolean isAllowNetworking() {
|
||||
return allowNetworking;
|
||||
}
|
||||
|
||||
public void setListener(final IUpdateable listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public GameLobbyData getData() {
|
||||
return data;
|
||||
}
|
||||
public void setData(final GameLobbyData data) {
|
||||
this.data = data;
|
||||
updateView();
|
||||
}
|
||||
|
||||
public GameType getGameType() {
|
||||
return data.currentGameMode;
|
||||
}
|
||||
public void setGameType(final GameType type) {
|
||||
data.currentGameMode = type;
|
||||
updateView();
|
||||
}
|
||||
|
||||
public boolean hasVariant(final GameType variant) {
|
||||
return data.appliedVariants.contains(variant);
|
||||
}
|
||||
|
||||
public int getNumberOfSlots() {
|
||||
return data.slots.size();
|
||||
}
|
||||
public LobbySlot getSlot(final int index) {
|
||||
if (index < 0 || index >= getNumberOfSlots()) {
|
||||
return null;
|
||||
}
|
||||
return data.slots.get(index);
|
||||
}
|
||||
public void applyToSlot(final int index, final UpdateLobbyPlayerEvent event) {
|
||||
final LobbySlot slot = getSlot(index);
|
||||
if (slot == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
final int nSlots = getNumberOfSlots();
|
||||
final boolean triesToChangeArchenemy = event.getArchenemy() != null;
|
||||
final boolean archenemyRemoved = triesToChangeArchenemy && !event.getArchenemy().booleanValue();
|
||||
final boolean hasArchenemyChanged = triesToChangeArchenemy && slot.isArchenemy() != event.getArchenemy().booleanValue();
|
||||
slot.apply(event);
|
||||
|
||||
// Change archenemy teams
|
||||
if (hasVariant(GameType.Archenemy) && hasArchenemyChanged) {
|
||||
final int newArchenemy = archenemyRemoved ? lastArchenemy : index;
|
||||
if (archenemyRemoved) {
|
||||
lastArchenemy = index;
|
||||
}
|
||||
for (int otherIndex = 0; otherIndex < nSlots; otherIndex++) {
|
||||
final LobbySlot otherSlot = getSlot(otherIndex);
|
||||
final boolean becomesArchenemy = otherIndex == newArchenemy;
|
||||
if (!archenemyRemoved && otherSlot.isArchenemy() && !becomesArchenemy) {
|
||||
lastArchenemy = otherIndex;
|
||||
}
|
||||
otherSlot.setIsArchenemy(becomesArchenemy);
|
||||
}
|
||||
updateView();
|
||||
}
|
||||
}
|
||||
|
||||
public IGameController getController(final int index) {
|
||||
return gameControllers.get(getSlot(index));
|
||||
}
|
||||
public GameView getGameView() {
|
||||
return hostedMatch.getGameView();
|
||||
}
|
||||
|
||||
public abstract boolean hasControl();
|
||||
public abstract boolean mayEdit(final int index);
|
||||
public abstract boolean mayControl(final int index);
|
||||
public abstract boolean mayRemove(final int index);
|
||||
public abstract IGuiGame getGui(final int index);
|
||||
|
||||
public void addSlot() {
|
||||
final int newIndex = getNumberOfSlots();
|
||||
addSlot(new LobbySlot(allowNetworking ? LobbySlotType.OPEN : LobbySlotType.LOCAL, null, newIndex, newIndex, false, Collections.<AIOption>emptySet()));
|
||||
}
|
||||
protected final void addSlot(final LobbySlot slot) {
|
||||
if (data.slots.size() >= MAX_PLAYERS) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.slots.add(slot);
|
||||
if (StringUtils.isEmpty(slot.getName())) {
|
||||
slot.setName(randomName());
|
||||
}
|
||||
if (data.slots.size() == 1) {
|
||||
// If first slot, make archenemy
|
||||
slot.setIsArchenemy(true);
|
||||
lastArchenemy = 0;
|
||||
}
|
||||
updateView();
|
||||
}
|
||||
private String randomName() {
|
||||
final List<String> names = Lists.newArrayListWithCapacity(MAX_PLAYERS);
|
||||
for (final LobbySlot slot : data.slots) {
|
||||
names.add(slot.getName());
|
||||
}
|
||||
return NameGenerator.getRandomName("Any", "Any", names);
|
||||
}
|
||||
protected final String localName() {
|
||||
return FModel.getPreferences().getPref(FPref.PLAYER_NAME);
|
||||
}
|
||||
protected final int[] localAvatarIndices() {
|
||||
final String[] sAvatars = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",");
|
||||
final int[] result = new int[sAvatars.length];
|
||||
for (int i = 0; i < sAvatars.length; i++) {
|
||||
final Integer val = Ints.tryParse(sAvatars[i]);
|
||||
result[i] = val == null ? -1 : val.intValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void removeSlot(final int index) {
|
||||
if (index < 0 || index >= data.slots.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getSlot(index).isArchenemy()) {
|
||||
getSlot(lastArchenemy).setIsArchenemy(true);
|
||||
// Should actually be a stack here, but that's rather involved for
|
||||
// such a nonimportant feature
|
||||
lastArchenemy = 0;
|
||||
} else if (lastArchenemy == index) {
|
||||
lastArchenemy = 0;
|
||||
} else {
|
||||
lastArchenemy--;
|
||||
}
|
||||
data.slots.remove(index);
|
||||
updateView();
|
||||
}
|
||||
|
||||
public void applyVariant(final GameType variant) {
|
||||
data.currentGameMode = variant;
|
||||
data.appliedVariants.add(variant);
|
||||
|
||||
//ensure other necessary variants are unchecked
|
||||
switch (variant) {
|
||||
case Archenemy:
|
||||
data.appliedVariants.remove(GameType.ArchenemyRumble);
|
||||
break;
|
||||
case ArchenemyRumble:
|
||||
data.appliedVariants.remove(GameType.Archenemy);
|
||||
break;
|
||||
case Commander:
|
||||
data.appliedVariants.remove(GameType.TinyLeaders);
|
||||
data.appliedVariants.remove(GameType.MomirBasic);
|
||||
break;
|
||||
case TinyLeaders:
|
||||
data.appliedVariants.remove(GameType.Commander);
|
||||
data.appliedVariants.remove(GameType.MomirBasic);
|
||||
break;
|
||||
case Vanguard:
|
||||
data.appliedVariants.remove(GameType.MomirBasic);
|
||||
break;
|
||||
case MomirBasic:
|
||||
data.appliedVariants.remove(GameType.Commander);
|
||||
data.appliedVariants.remove(GameType.Vanguard);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
updateView();
|
||||
}
|
||||
|
||||
public void removeVariant(final GameType variant) {
|
||||
data.appliedVariants.remove(variant);
|
||||
if (data.appliedVariants.isEmpty()) {
|
||||
data.appliedVariants.add(GameType.Constructed);
|
||||
}
|
||||
updateView();
|
||||
}
|
||||
|
||||
private boolean isEnoughTeams() {
|
||||
int lastTeam = -1;
|
||||
final boolean useArchenemyTeams = data.appliedVariants.contains(GameType.Archenemy);
|
||||
for (final LobbySlot slot : data.slots) {
|
||||
final int team = useArchenemyTeams ? (slot.isArchenemy() ? 0 : 1) : slot.getTeam();
|
||||
if (lastTeam == -1) {
|
||||
lastTeam = team;
|
||||
} else if (lastTeam != team) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected final void updateView() {
|
||||
if (listener != null) {
|
||||
listener.update();
|
||||
}
|
||||
}
|
||||
|
||||
/** Starts a match with the applied variants. */
|
||||
public void startGame() {
|
||||
if (!isEnoughTeams()) {
|
||||
SOptionPane.showMessageDialog("There are not enough teams! Please adjust team allocations.");
|
||||
return;
|
||||
}
|
||||
|
||||
final List<LobbySlot> activeSlots = Lists.newArrayListWithCapacity(getNumberOfSlots());
|
||||
for (final LobbySlot slot : data.getSlots()) {
|
||||
if (slot.getType() != LobbySlotType.OPEN) {
|
||||
activeSlots.add(slot);
|
||||
}
|
||||
}
|
||||
|
||||
for (final LobbySlot slot : activeSlots) {
|
||||
if (slot.getDeck() == null) {
|
||||
SOptionPane.showMessageDialog(String.format("Please specify a deck for %s", slot.getName()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final Set<GameType> variantTypes = data.appliedVariants;
|
||||
|
||||
GameType autoGenerateVariant = null;
|
||||
boolean isCommanderMatch = false;
|
||||
boolean isTinyLeadersMatch = false;
|
||||
if (!variantTypes.isEmpty()) {
|
||||
isTinyLeadersMatch = variantTypes.contains(GameType.TinyLeaders);
|
||||
isCommanderMatch = isTinyLeadersMatch || variantTypes.contains(GameType.Commander);
|
||||
if (!isCommanderMatch) {
|
||||
for (final GameType variant : variantTypes) {
|
||||
if (variant.isAutoGenerated()) {
|
||||
autoGenerateVariant = variant;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean checkLegality = FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY);
|
||||
|
||||
//Auto-generated decks don't need to be checked here
|
||||
//Commander deck replaces regular deck and is checked later
|
||||
if (checkLegality && autoGenerateVariant == null && !isCommanderMatch) {
|
||||
for (final LobbySlot slot : activeSlots) {
|
||||
final String name = slot.getName();
|
||||
String errMsg = GameType.Constructed.getDeckFormat().getDeckConformanceProblem(slot.getDeck());
|
||||
if (null != errMsg) {
|
||||
SOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final List<RegisteredPlayer> players = new ArrayList<RegisteredPlayer>();
|
||||
final Map<RegisteredPlayer, IGuiGame> guis = Maps.newHashMap();
|
||||
final Map<RegisteredPlayer, LobbySlot> playerToSlot = Maps.newHashMap();
|
||||
boolean hasNameBeenSet = false;
|
||||
for (final LobbySlot slot : activeSlots) {
|
||||
final IGuiGame gui = getGui(data.slots.indexOf(slot));
|
||||
final String name = slot.getName();
|
||||
final int avatar = slot.getAvatarIndex();
|
||||
final int team = slot.getTeam();
|
||||
final boolean isArchenemy = slot.isArchenemy();
|
||||
final Set<AIOption> aiOptions = slot.getAiOptions();
|
||||
|
||||
final boolean isAI = slot.getType() == LobbySlotType.AI;
|
||||
final LobbyPlayer lobbyPlayer;
|
||||
if (isAI) {
|
||||
lobbyPlayer = GamePlayerUtil.createAiPlayer(name, avatar, aiOptions);
|
||||
} else {
|
||||
boolean setNameNow = false;
|
||||
if (!hasNameBeenSet && slot.getType() == LobbySlotType.LOCAL) {
|
||||
setNameNow = true;
|
||||
hasNameBeenSet = true;
|
||||
}
|
||||
lobbyPlayer = GamePlayerUtil.getGuiPlayer(name, setNameNow);
|
||||
}
|
||||
|
||||
Deck deck = slot.getDeck();
|
||||
RegisteredPlayer rp = new RegisteredPlayer(deck);
|
||||
|
||||
if (variantTypes.isEmpty()) {
|
||||
rp.setTeamNumber(team);
|
||||
players.add(rp.setPlayer(lobbyPlayer));
|
||||
} else {
|
||||
PaperCard vanguardAvatar = null;
|
||||
if (isCommanderMatch) {
|
||||
final GameType commanderGameType = isTinyLeadersMatch ? GameType.TinyLeaders : GameType.Commander;
|
||||
if (checkLegality) {
|
||||
String errMsg = commanderGameType.getDeckFormat().getDeckConformanceProblem(deck);
|
||||
if (null != errMsg) {
|
||||
SOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid " + commanderGameType + " Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (autoGenerateVariant != null) {
|
||||
deck = autoGenerateVariant.autoGenerateDeck(rp);
|
||||
final CardPool avatarPool = deck.get(DeckSection.Avatar);
|
||||
if (avatarPool != null) {
|
||||
vanguardAvatar = avatarPool.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialise variables for other variants
|
||||
deck = deck == null ? rp.getDeck() : deck;
|
||||
Iterable<PaperCard> schemes = null;
|
||||
Iterable<PaperCard> planes = null;
|
||||
|
||||
//Archenemy
|
||||
if (variantTypes.contains(GameType.ArchenemyRumble)
|
||||
|| (variantTypes.contains(GameType.Archenemy) && isArchenemy)) {
|
||||
final CardPool schemePool = deck.get(DeckSection.Schemes);
|
||||
if (checkLegality) {
|
||||
String errMsg = DeckFormat.getSchemeSectionConformanceProblem(schemePool);
|
||||
if (null != errMsg) {
|
||||
SOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Scheme Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
schemes = schemePool.toFlatList();
|
||||
}
|
||||
|
||||
//Planechase
|
||||
if (variantTypes.contains(GameType.Planechase)) {
|
||||
final CardPool planePool = deck.get(DeckSection.Planes);
|
||||
if (checkLegality) {
|
||||
String errMsg = DeckFormat.getPlaneSectionConformanceProblem(planePool);
|
||||
if (null != errMsg) {
|
||||
SOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Planar Deck");
|
||||
return;
|
||||
}
|
||||
}
|
||||
planes = planePool.toFlatList();
|
||||
}
|
||||
|
||||
//Vanguard
|
||||
if (variantTypes.contains(GameType.Vanguard)) {
|
||||
if (vanguardAvatar == null) { //ERROR! null if avatar deselected on list
|
||||
SOptionPane.showMessageDialog("No Vanguard avatar selected for " + name
|
||||
+ ". Please choose one or disable the Vanguard variant");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rp = RegisteredPlayer.forVariants(variantTypes, deck, schemes, isArchenemy, planes, vanguardAvatar);
|
||||
rp.setTeamNumber(team);
|
||||
players.add(rp.setPlayer(lobbyPlayer));
|
||||
}
|
||||
|
||||
if (!isAI) {
|
||||
guis.put(rp, gui);
|
||||
}
|
||||
playerToSlot.put(rp, slot);
|
||||
}
|
||||
|
||||
hostedMatch = GuiBase.getInterface().hostMatch();
|
||||
hostedMatch.startMatch(GameType.Constructed, variantTypes, players, guis);
|
||||
|
||||
for (final Player p : hostedMatch.getGame().getPlayers()) {
|
||||
final LobbySlot slot = playerToSlot.get(p.getRegisteredPlayer());
|
||||
if (p.getController() instanceof IGameController) {
|
||||
gameControllers.put(slot, (IGameController) p.getController());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final static class GameLobbyData implements Serializable {
|
||||
private static final long serialVersionUID = -9038854736144187540L;
|
||||
|
||||
private transient GameType currentGameMode = GameType.Constructed;
|
||||
private final Set<GameType> appliedVariants = EnumSet.of(GameType.Constructed);
|
||||
private final List<LobbySlot> slots = Lists.newArrayList();
|
||||
|
||||
public GameType getCurrentGameMode() {
|
||||
return currentGameMode;
|
||||
}
|
||||
public void setCurrentGameMode(GameType currentGameMode) {
|
||||
this.currentGameMode = currentGameMode;
|
||||
}
|
||||
public Set<GameType> getAppliedVariants() {
|
||||
return Collections.unmodifiableSet(appliedVariants);
|
||||
}
|
||||
public List<LobbySlot> getSlots() {
|
||||
return Collections.unmodifiableList(slots);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,8 +44,8 @@ import forge.properties.ForgePreferences.FPref;
|
||||
import forge.quest.QuestController;
|
||||
import forge.sound.MusicPlaylist;
|
||||
import forge.sound.SoundSystem;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.CollectionSuppliers;
|
||||
import forge.util.FCollection;
|
||||
import forge.util.GuiDisplayUtil;
|
||||
import forge.util.NameGenerator;
|
||||
import forge.util.maps.HashMapOfLists;
|
||||
@@ -137,8 +137,6 @@ public class HostedMatch {
|
||||
game.subscribeToEvents(SoundSystem.instance);
|
||||
game.subscribeToEvents(visitor);
|
||||
|
||||
final String[] indices = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",");
|
||||
|
||||
// Instantiate all required field slots (user at 0)
|
||||
final List<Player> sortedPlayers = Lists.newArrayList(game.getRegisteredPlayers());
|
||||
Collections.sort(sortedPlayers, new Comparator<Player>() {
|
||||
@@ -150,18 +148,23 @@ public class HostedMatch {
|
||||
}
|
||||
});
|
||||
|
||||
final String[] avatarIndices = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",");
|
||||
final GameView gameView = getGameView();
|
||||
|
||||
int i = 0;
|
||||
int avatarIndex = 0;
|
||||
humanCount = 0;
|
||||
final MapOfLists<IGuiGame, PlayerView> playersPerGui = new HashMapOfLists<IGuiGame, PlayerView>(CollectionSuppliers.<PlayerView>arrayLists());
|
||||
for (final Player p : sortedPlayers) {
|
||||
if (i < indices.length) {
|
||||
avatarIndex = Integer.parseInt(indices[i]);
|
||||
i++;
|
||||
for (int iPlayer = 0; iPlayer < sortedPlayers.size(); iPlayer++) {
|
||||
final RegisteredPlayer rp = match.getPlayers().get(iPlayer);
|
||||
final Player p = sortedPlayers.get(iPlayer);
|
||||
|
||||
p.getLobbyPlayer().setAvatarIndex(rp.getPlayer().getAvatarIndex());
|
||||
if (p.getLobbyPlayer().getAvatarIndex() == -1) {
|
||||
if (iPlayer < avatarIndices.length) {
|
||||
p.getLobbyPlayer().setAvatarIndex(Integer.parseInt(avatarIndices[iPlayer]));
|
||||
} else {
|
||||
p.getLobbyPlayer().setAvatarIndex(0);
|
||||
}
|
||||
}
|
||||
p.getLobbyPlayer().setAvatarIndex(avatarIndex);
|
||||
p.updateAvatar();
|
||||
|
||||
if (p.getController() instanceof PlayerControllerHuman) {
|
||||
@@ -177,8 +180,9 @@ public class HostedMatch {
|
||||
humanCount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (final Entry<IGuiGame, Collection<PlayerView>> e : playersPerGui.entrySet()) {
|
||||
e.getKey().openView(new FCollection<PlayerView>(e.getValue()));
|
||||
e.getKey().openView(new TrackableCollection<PlayerView>(e.getValue()));
|
||||
}
|
||||
|
||||
if (humanCount == 0) { //watch game but do not participate
|
||||
|
||||
109
forge-gui/src/main/java/forge/match/LobbySlot.java
Normal file
109
forge-gui/src/main/java/forge/match/LobbySlot.java
Normal file
@@ -0,0 +1,109 @@
|
||||
package forge.match;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.deck.Deck;
|
||||
import forge.net.game.LobbySlotType;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
|
||||
public final class LobbySlot implements Serializable {
|
||||
private static final long serialVersionUID = 6918205436608794289L;
|
||||
|
||||
private LobbySlotType type;
|
||||
private String name;
|
||||
private int avatarIndex;
|
||||
private int team;
|
||||
private boolean isArchenemy;
|
||||
private Deck deck;
|
||||
private ImmutableSet<AIOption> aiOptions;
|
||||
|
||||
public LobbySlot(final LobbySlotType type, final String name, final int avatarIndex, final int team, final boolean isArchenemy, final Set<AIOption> aiOptions) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.avatarIndex = avatarIndex;
|
||||
this.team = team;
|
||||
this.isArchenemy = isArchenemy;
|
||||
this.setAiOptions(aiOptions);
|
||||
}
|
||||
|
||||
void apply(final UpdateLobbyPlayerEvent data) {
|
||||
if (data.getType() != null) {
|
||||
setType(data.getType());
|
||||
}
|
||||
if (data.getName() != null) {
|
||||
setName(data.getName());
|
||||
}
|
||||
if (data.getAvatarIndex() != -1) {
|
||||
setAvatarIndex(data.getAvatarIndex());
|
||||
}
|
||||
if (data.getTeam() != -1) {
|
||||
setTeam(data.getTeam());
|
||||
}
|
||||
if (data.getArchenemy() != null) {
|
||||
setIsArchenemy(data.getArchenemy().booleanValue());
|
||||
}
|
||||
if (data.getAiOptions() != null) {
|
||||
setAiOptions(data.getAiOptions());
|
||||
}
|
||||
if (data.getDeck() != null) {
|
||||
setDeck(data.getDeck());
|
||||
} else if (getDeck() != null && data.getSection() != null && data.getCards() != null) {
|
||||
getDeck().putSection(data.getSection(), data.getCards());
|
||||
}
|
||||
}
|
||||
|
||||
public LobbySlotType getType() {
|
||||
return type;
|
||||
}
|
||||
public void setType(final LobbySlotType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getAvatarIndex() {
|
||||
return avatarIndex;
|
||||
}
|
||||
public void setAvatarIndex(final int avatarIndex) {
|
||||
this.avatarIndex = avatarIndex;
|
||||
}
|
||||
|
||||
public int getTeam() {
|
||||
return team;
|
||||
}
|
||||
public void setTeam(final int team) {
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
public boolean isArchenemy() {
|
||||
return isArchenemy;
|
||||
}
|
||||
public void setIsArchenemy(final boolean isArchenemy) {
|
||||
this.isArchenemy = isArchenemy;
|
||||
}
|
||||
|
||||
public Deck getDeck() {
|
||||
return deck;
|
||||
}
|
||||
public void setDeck(final Deck deck) {
|
||||
this.deck = deck;
|
||||
}
|
||||
|
||||
public ImmutableSet<AIOption> getAiOptions() {
|
||||
return aiOptions;
|
||||
}
|
||||
|
||||
public void setAiOptions(final Set<AIOption> aiOptions) {
|
||||
this.aiOptions = aiOptions == null ? ImmutableSet.<AIOption>of() : ImmutableSet.copyOf(aiOptions);
|
||||
}
|
||||
|
||||
}
|
||||
44
forge-gui/src/main/java/forge/match/LocalLobby.java
Normal file
44
forge-gui/src/main/java/forge/match/LocalLobby.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package forge.match;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.GuiBase;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.net.game.LobbySlotType;
|
||||
|
||||
public final class LocalLobby extends GameLobby {
|
||||
|
||||
public LocalLobby() {
|
||||
super(false);
|
||||
|
||||
final String humanName = localName();
|
||||
final int[] avatarIndices = localAvatarIndices();
|
||||
|
||||
final LobbySlot slot0 = new LobbySlot(LobbySlotType.LOCAL, humanName, avatarIndices[0], 0, true, Collections.<AIOption>emptySet());
|
||||
addSlot(slot0);
|
||||
|
||||
final LobbySlot slot1 = new LobbySlot(LobbySlotType.AI, null, avatarIndices[1], 1, false, Collections.<AIOption>emptySet());
|
||||
addSlot(slot1);
|
||||
}
|
||||
|
||||
@Override public boolean hasControl() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean mayEdit(final int index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean mayControl(final int index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean mayRemove(final int index) {
|
||||
return index >= 2;
|
||||
}
|
||||
|
||||
@Override public IGuiGame getGui(final int index) {
|
||||
return GuiBase.getInterface().getNewGuiGame();
|
||||
}
|
||||
}
|
||||
6
forge-gui/src/main/java/forge/match/MatchButtonType.java
Normal file
6
forge-gui/src/main/java/forge/match/MatchButtonType.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package forge.match;
|
||||
|
||||
public enum MatchButtonType {
|
||||
OK,
|
||||
CANCEL;
|
||||
}
|
||||
@@ -1,415 +0,0 @@
|
||||
package forge.match;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.UiCommand;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.item.PaperCard;
|
||||
import forge.net.game.GuiGameEvent;
|
||||
import forge.net.game.server.IToClient;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.trackable.TrackableObject;
|
||||
import forge.util.FCollectionView;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class NetGuiGame extends AbstractGuiGame {
|
||||
|
||||
private final IToClient client;
|
||||
public NetGuiGame(final IToClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
private void send(final String method) {
|
||||
send(method, Collections.<TrackableObject>emptySet());
|
||||
}
|
||||
private void send(final String method, final TrackableObject object) {
|
||||
send(method, Collections.singleton(object));
|
||||
}
|
||||
private void send(final String method, final Iterable<? extends TrackableObject> objects) {
|
||||
client.send(new GuiGameEvent(method, objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameView(final GameView gameView) {
|
||||
super.setGameView(gameView);
|
||||
send("setGameView", gameView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resetForNewGame() {
|
||||
send("resetForNewGame");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openView(final Iterable<PlayerView> myPlayers) {
|
||||
send("openView", myPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterGameEnd() {
|
||||
send("afterGameEnd");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCombat() {
|
||||
send("showCombat");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPromptMessage(PlayerView playerView, String message) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stopAtPhase(PlayerView playerTurn, PhaseType phase) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IButton getBtnOK(final PlayerView playerView) {
|
||||
return new NetButton(playerView, "OK");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IButton getBtnCancel(final PlayerView playerView) {
|
||||
return new NetButton(playerView, "Cancel");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void focusButton(IButton button) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flashIncorrectAction() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePhase() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTurn(PlayerView player) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlayerControl() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableOverlay() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableOverlay() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishGame() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object showManaPool(PlayerView player) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideManaPool(PlayerView player, Object zoneToRestore) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStack() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateZones(List<Pair<PlayerView, ZoneType>> zonesToUpdate) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSingleCard(CardView card) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateManaPool(Iterable<PlayerView> manaPoolUpdate) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLives(Iterable<PlayerView> livesUpdate) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPanelSelection(CardView hostCard) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hear(LobbyPlayer player, String message) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAbility getAbilityToPlay(List<SpellAbility> abilities,
|
||||
ITriggerEvent triggerEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<CardView, Integer> assignDamage(CardView attacker,
|
||||
List<CardView> blockers, int damage, GameEntityView defender,
|
||||
boolean overrideOrder) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(String message, String title) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showErrorDialog(String message, String title) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showConfirmDialog(String message, String title,
|
||||
String yesButtonText, String noButtonText, boolean defaultYes) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int showOptionDialog(String message, String title, FSkinProp icon,
|
||||
String[] options, int defaultOption) {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int showCardOptionDialog(CardView card, String message,
|
||||
String title, FSkinProp icon, String[] options, int defaultOption) {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String showInputDialog(String message, String title, FSkinProp icon,
|
||||
String initialInput, String[] inputOptions) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirm(CardView c, String question, boolean defaultIsYes,
|
||||
String[] options) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getChoices(String message, int min, int max,
|
||||
Collection<T> choices, T selected, Function<T, String> display) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> order(String title, String top, int remainingObjectsMin,
|
||||
int remainingObjectsMax, List<T> sourceChoices,
|
||||
List<T> destChoices, CardView referenceCard,
|
||||
boolean sideboardingMode) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaperCard> sideboard(CardPool sideboard, CardPool main) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameEntityView chooseSingleEntityForEffect(String title,
|
||||
FCollectionView<? extends GameEntity> optionList,
|
||||
DelayedReveal delayedReveal, boolean isOptional,
|
||||
PlayerControllerHuman controller) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCard(CardView card) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean openZones(Collection<ZoneType> zones,
|
||||
Map<PlayerView, Object> players) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreOldZones(Map<PlayerView, Object> playersToRestoreZonesFor) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUiSetToSkipPhase(PlayerView playerTurn, PhaseType phase) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateCurrentPlayer(PlayerView player) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
private final static class NetButton implements IButton {
|
||||
|
||||
private final PlayerView playerView;
|
||||
private final String button;
|
||||
private NetButton(final PlayerView playerView, final String button) {
|
||||
this.playerView = playerView;
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean b0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean b0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(String text0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelected() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelected(boolean b0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestFocusInWindow() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCommand(UiCommand command0) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(FSkinProp color) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextColor(int r, int g, int b) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,11 @@ public class InputConfirmMulligan extends InputSyncronizedBase {
|
||||
showMessage(sb.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final boolean allowAwaitNextInput() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected final void onOk() {
|
||||
|
||||
@@ -125,13 +125,13 @@ public class InputPassPriority extends InputSyncronizedBase {
|
||||
@Override
|
||||
protected boolean onCardSelected(final Card card, final List<Card> otherCardsToSelect, final ITriggerEvent triggerEvent) {
|
||||
//remove unplayable unless triggerEvent specified, in which case unplayable may be shown as disabled options
|
||||
List<SpellAbility> abilities = card.getAllPossibleAbilities(getController().getPlayer(), triggerEvent == null);
|
||||
if (abilities.isEmpty()) {
|
||||
List<SpellAbility> abilities = card.getAllPossibleAbilities(getController().getPlayer(), triggerEvent == null);
|
||||
if (abilities.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final SpellAbility ability = getController().getAbilityToPlay(abilities, triggerEvent);
|
||||
if (ability != null) {
|
||||
if (ability != null) {
|
||||
chosenSa = new ArrayList<SpellAbility>();
|
||||
chosenSa.add(ability);
|
||||
if (otherCardsToSelect != null && ability.isManaAbility()) {
|
||||
|
||||
@@ -149,7 +149,7 @@ public class InputProxy implements Observer {
|
||||
}
|
||||
|
||||
public final void selectAbility(final SpellAbility sa) {
|
||||
final Input inp = getInput();
|
||||
final Input inp = getInput();
|
||||
if (inp != null) {
|
||||
if (sa != null) {
|
||||
inp.selectAbility(sa);
|
||||
|
||||
36
forge-gui/src/main/java/forge/net/ClientGameLobby.java
Normal file
36
forge-gui/src/main/java/forge/net/ClientGameLobby.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package forge.net;
|
||||
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.GameLobby;
|
||||
|
||||
public final class ClientGameLobby extends GameLobby {
|
||||
private int localPlayer = -1;
|
||||
|
||||
public ClientGameLobby() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
public void setLocalPlayer(final int index) {
|
||||
this.localPlayer = index;
|
||||
}
|
||||
|
||||
@Override public boolean hasControl() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean mayEdit(final int index) {
|
||||
return index == localPlayer;
|
||||
}
|
||||
|
||||
@Override public boolean mayControl(final int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public boolean mayRemove(final int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public IGuiGame getGui(final int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -15,22 +15,44 @@ import io.netty.handler.codec.serialization.ClassResolvers;
|
||||
import io.netty.handler.codec.serialization.ObjectDecoder;
|
||||
import io.netty.handler.codec.serialization.ObjectEncoder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.UiCommand;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.interfaces.ILobbyListener;
|
||||
import forge.match.MatchButtonType;
|
||||
import forge.model.FModel;
|
||||
import forge.net.game.GuiGameEvent;
|
||||
import forge.net.game.LobbyUpdateEvent;
|
||||
import forge.net.game.IdentifiableNetEvent;
|
||||
import forge.net.game.LoginEvent;
|
||||
import forge.net.game.MessageEvent;
|
||||
import forge.net.game.NetEvent;
|
||||
import forge.net.game.client.ILobbyListener;
|
||||
import forge.net.game.ReplyEvent;
|
||||
import forge.net.game.client.IToServer;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.trackable.TrackableCollection;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class FGameClient implements IToServer {
|
||||
private final IGuiGame clientGui;
|
||||
@@ -39,6 +61,7 @@ public class FGameClient implements IToServer {
|
||||
}
|
||||
|
||||
private final List<ILobbyListener> lobbyListeners = Lists.newArrayList();
|
||||
private final ReplyPool replies = new ReplyPool();
|
||||
|
||||
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
|
||||
|
||||
@@ -81,14 +104,32 @@ public class FGameClient implements IToServer {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(final NetEvent event) {
|
||||
System.out.println("Client sent " + event);
|
||||
channel.writeAndFlush(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object sendAndWait(final IdentifiableNetEvent event) throws TimeoutException {
|
||||
replies.initialize(event.getId());
|
||||
|
||||
send(event);
|
||||
|
||||
// Wait for reply
|
||||
return replies.get(event.getId());
|
||||
}
|
||||
|
||||
public void addLobbyListener(final ILobbyListener listener) {
|
||||
lobbyListeners.add(listener);
|
||||
}
|
||||
|
||||
private void setGameControllers(final Iterable<PlayerView> myPlayers) {
|
||||
for (final PlayerView p : myPlayers) {
|
||||
clientGui.setGameController(p, new NetGameController(this));
|
||||
}
|
||||
}
|
||||
|
||||
private class GameClientHandler extends ChannelInboundHandlerAdapter {
|
||||
/**
|
||||
* Creates a client-side handler.
|
||||
@@ -98,24 +139,214 @@ public class FGameClient implements IToServer {
|
||||
|
||||
@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)));
|
||||
// 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 GuiGameEvent) {
|
||||
if (msg instanceof ReplyEvent) {
|
||||
final ReplyEvent event = (ReplyEvent) msg;
|
||||
replies.complete(event.getIndex(), event.getReply());
|
||||
} else if (msg instanceof GuiGameEvent) {
|
||||
final GuiGameEvent event = (GuiGameEvent) msg;
|
||||
final Object[] args = event.getObjects();
|
||||
Serializable reply = null;
|
||||
boolean doReply = false;
|
||||
|
||||
final IButton btn;
|
||||
if (args.length >= 2 && args[0] instanceof PlayerView && args[1] instanceof MatchButtonType) {
|
||||
btn = args[1] == MatchButtonType.OK ? clientGui.getBtnOK((PlayerView) args[0]) : clientGui.getBtnCancel((PlayerView) args[0]);
|
||||
} else {
|
||||
btn = null;
|
||||
}
|
||||
|
||||
switch (event.getMethod()) {
|
||||
case "setGameView":
|
||||
clientGui.setGameView((GameView) event.getObject());
|
||||
clientGui.setGameView((GameView) args[0]);
|
||||
break;
|
||||
case "openView":
|
||||
clientGui.openView((Iterable<PlayerView>) event.getObjects());
|
||||
default:
|
||||
final TrackableCollection<PlayerView> myPlayers = (TrackableCollection<PlayerView>) args[0];
|
||||
setGameControllers(myPlayers);
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public final void run() {
|
||||
//clientGui.setGameView(new NetGameView(FGameClient.this));
|
||||
clientGui.openView(myPlayers);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "afterGameEnd":
|
||||
clientGui.afterGameEnd();
|
||||
break;
|
||||
case "showCombat":
|
||||
clientGui.showCombat();
|
||||
break;
|
||||
case "showPromptMessage":
|
||||
clientGui.showPromptMessage((PlayerView) args[0], (String) args[1]);
|
||||
break;
|
||||
case "stopAtPhase":
|
||||
reply = clientGui.stopAtPhase((PlayerView) args[0], (PhaseType) args[1]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "focusButton":
|
||||
clientGui.focusButton((MatchButtonType) args[0]);
|
||||
break;
|
||||
case "flashIncorrectAction":
|
||||
clientGui.flashIncorrectAction();
|
||||
break;
|
||||
case "updatePhase":
|
||||
clientGui.updatePhase();
|
||||
break;
|
||||
case "updateTurn":
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public final void run() {
|
||||
clientGui.updateTurn((PlayerView) args[0]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "udpdatePlayerControl":
|
||||
clientGui.updatePlayerControl();
|
||||
break;
|
||||
case "enableOverlay":
|
||||
clientGui.enableOverlay();
|
||||
break;
|
||||
case "disbleOverlay":
|
||||
clientGui.disableOverlay();
|
||||
break;
|
||||
case "finishGame":
|
||||
clientGui.finishGame();
|
||||
break;
|
||||
case "showManaPool":
|
||||
clientGui.showManaPool((PlayerView) args[0]);
|
||||
break;
|
||||
case "hideManaPool":
|
||||
clientGui.hideManaPool((PlayerView) args[0], args[1]);
|
||||
break;
|
||||
case "updateStack":
|
||||
clientGui.updateStack();
|
||||
break;
|
||||
case "updateZones":
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public final void run() {
|
||||
clientGui.updateZones((List<Pair<PlayerView, ZoneType>>) args[0]);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "updateSingleCard":
|
||||
clientGui.updateSingleCard((CardView) args[0]);
|
||||
break;
|
||||
case "updateManaPool":
|
||||
clientGui.updateManaPool((Iterable<PlayerView>) args[0]);
|
||||
break;
|
||||
case "updateLives":
|
||||
clientGui.updateLives((Iterable<PlayerView>) args[0]);
|
||||
break;
|
||||
case "setPanelSelection":
|
||||
clientGui.setPanelSelection((CardView) args[0]);
|
||||
break;
|
||||
case "getAbilityToPlay":
|
||||
reply = clientGui.getAbilityToPlay((List<SpellAbilityView>) args[0], (ITriggerEvent) args[1]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "assignDamage":
|
||||
reply = (Serializable) clientGui.assignDamage((CardView) args[0], (List<CardView>) args[1], (int) args[2], (GameEntityView) args[3], (boolean) args[4]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "message":
|
||||
clientGui.message((String) args[0], (String) args[1]);
|
||||
break;
|
||||
case "showErrorDialog":
|
||||
clientGui.showErrorDialog((String) args[0], (String) args[1]);
|
||||
break;
|
||||
case "showConfirmDialog":
|
||||
reply = clientGui.showConfirmDialog((String) args[0], (String) args[1], (String) args[2], (String) args[3], (boolean) args[4]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "showOptionDialog":
|
||||
reply = clientGui.showOptionDialog((String) args[0], (String) args[1], (FSkinProp) args[2], (String[]) args[3], (int) args[4]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "showCardOptionDialog":
|
||||
reply = clientGui.showCardOptionDialog((CardView) args[0], (String) args[1], (String) args[2], (FSkinProp) args[3], (String[]) args[4], (int) args[5]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "showInputDialog":
|
||||
reply = clientGui.showInputDialog((String) args[0], (String) args[1], (FSkinProp) args[2], (String) args[3], (String[]) args[4]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "confirm":
|
||||
reply = clientGui.confirm((CardView) args[0], (String) args[1], (boolean) args[2], (String[]) args[3]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "getChoices":
|
||||
reply = (Serializable) clientGui.getChoices((String) args[0], (int) args[1], (int) args[2], (Collection<Object>) args[3], args[4], (Function<Object, String>) args[5]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "order":
|
||||
reply = (Serializable) clientGui.order((String) args[0], (String) args[1], (int) args[2], (int) args[3], (List<Object>) args[4], (List<Object>) args[5], (CardView) args[6], (boolean) args[7]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "sideboard":
|
||||
reply = (Serializable) clientGui.sideboard((CardPool) args[0], (CardPool) args[1]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "chooseSingleEntityForEffect":
|
||||
reply = clientGui.chooseSingleEntityForEffect((String) args[0], (TrackableCollection<GameEntityView>) args[1], (DelayedReveal) args[2], (boolean) args[3]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "setCard":
|
||||
clientGui.setCard((CardView) args[0]);
|
||||
break;
|
||||
// TODO case "setPlayerAvatar":
|
||||
case "openZones":
|
||||
reply = clientGui.openZones((Collection<ZoneType>) args[0], (Map<PlayerView, Object>) args[1]);
|
||||
doReply = true;
|
||||
break;
|
||||
case "restoreOldZones":
|
||||
clientGui.restoreOldZones((Map<PlayerView, Object>) args[0]);
|
||||
break;
|
||||
case "isUiSetToSkipPhase":
|
||||
reply = clientGui.isUiSetToSkipPhase((PlayerView) args[0], (PhaseType) args[1]);
|
||||
doReply = true;
|
||||
break;
|
||||
// BUTTONS
|
||||
case "btn_setEnabled":
|
||||
btn.setEnabled((boolean) args[2]);
|
||||
break;
|
||||
case "btn_setVisible":
|
||||
btn.setVisible((boolean) args[2]);
|
||||
break;
|
||||
case "btn_setText":
|
||||
btn.setText((String) args[2]);
|
||||
break;
|
||||
case "btn_isSelected":
|
||||
reply = btn.isSelected();
|
||||
doReply = true;
|
||||
break;
|
||||
case "btn_setSelected":
|
||||
btn.setSelected((boolean) args[2]);
|
||||
break;
|
||||
case "btn_requestFocusInWindows":
|
||||
reply = btn.requestFocusInWindow();
|
||||
doReply = true;
|
||||
break;
|
||||
case "btn_setCommand":
|
||||
btn.setCommand((UiCommand) args[2]);
|
||||
break;
|
||||
case "btn_setTextColor":
|
||||
if (args.length == 3) {
|
||||
btn.setTextColor((FSkinProp) args[2]);
|
||||
} else {
|
||||
btn.setTextColor((int) args[2], (int) args[3], (int) args[4]);
|
||||
}
|
||||
default:
|
||||
System.err.println("Unsupported game event " + event.getMethod());
|
||||
break;
|
||||
}
|
||||
if (doReply) {
|
||||
send(new ReplyEvent(event.getId(), reply));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,7 +376,8 @@ public class FGameClient implements IToServer {
|
||||
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
|
||||
if (msg instanceof LobbyUpdateEvent) {
|
||||
for (final ILobbyListener listener : lobbyListeners) {
|
||||
listener.update(((LobbyUpdateEvent) msg).getState());
|
||||
final LobbyUpdateEvent event = (LobbyUpdateEvent) msg;
|
||||
listener.update(event.getState(), event.getSlot());
|
||||
}
|
||||
}
|
||||
super.channelRead(ctx, msg);
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
package forge.net;
|
||||
|
||||
import forge.game.GameRules;
|
||||
import forge.interfaces.ILobby;
|
||||
import forge.net.game.LobbyState;
|
||||
import forge.net.game.LobbyUpdateEvent;
|
||||
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.NextGameDecision;
|
||||
import forge.net.game.GuiGameEvent;
|
||||
import forge.net.game.LobbySlotType;
|
||||
import forge.net.game.LoginEvent;
|
||||
import forge.net.game.LogoutEvent;
|
||||
import forge.net.game.MessageEvent;
|
||||
import forge.net.game.NetEvent;
|
||||
import forge.net.game.RegisterDeckEvent;
|
||||
import forge.net.game.ReplyEvent;
|
||||
import forge.net.game.UpdateLobbyPlayerEvent;
|
||||
import forge.net.game.server.RemoteClient;
|
||||
import forge.util.ITriggerEvent;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
@@ -27,8 +39,14 @@ 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.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public final class FServerManager {
|
||||
@@ -36,18 +54,13 @@ public final class FServerManager {
|
||||
|
||||
private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
private final EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
private final Map<Integer, NetGame> games = Maps.newTreeMap();
|
||||
private int id = 0;
|
||||
private final Map<Channel, RemoteClient> clients = Maps.newTreeMap();
|
||||
private ILobby localLobby;
|
||||
private ServerGameLobby localLobby;
|
||||
private ILobbyListener lobbyListener;
|
||||
|
||||
private FServerManager() {
|
||||
}
|
||||
|
||||
private int nextId() {
|
||||
return id++;
|
||||
}
|
||||
|
||||
public static FServerManager getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new FServerManager();
|
||||
@@ -62,15 +75,14 @@ public final class FServerManager {
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.handler(new LoggingHandler(LogLevel.INFO))
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
public void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline p = ch.pipeline();
|
||||
@Override public final void initChannel(final SocketChannel ch) {
|
||||
final ChannelPipeline p = ch.pipeline();
|
||||
p.addLast(
|
||||
new ObjectEncoder(),
|
||||
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
|
||||
new MessageHandler(),
|
||||
new RegisterClientHandler(),
|
||||
new ToLobbyListenersHandler(),
|
||||
new LobbyInputHandler(),
|
||||
new DeregisterClientHandler(),
|
||||
new GameServerHandler());
|
||||
}
|
||||
@@ -101,29 +113,53 @@ public final class FServerManager {
|
||||
}
|
||||
|
||||
public void broadcast(final NetEvent event) {
|
||||
for (final RemoteClient client : clients.values()) {
|
||||
broadcastTo(event, clients.values());
|
||||
}
|
||||
public void broadcastExcept(final NetEvent event, final RemoteClient notTo) {
|
||||
broadcastExcept(event, Collections.singleton(notTo));
|
||||
}
|
||||
public void broadcastExcept(final NetEvent event, final Collection<RemoteClient> notTo) {
|
||||
broadcastTo(event, Iterables.filter(clients.values(), Predicates.not(Predicates.in(notTo))));
|
||||
}
|
||||
private void broadcastTo(final NetEvent event, final Iterable<RemoteClient> to) {
|
||||
for (final RemoteClient client : to) {
|
||||
event.updateForClient(client);
|
||||
client.send(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLobby(final ILobby lobby) {
|
||||
public void setLobby(final ServerGameLobby lobby) {
|
||||
this.localLobby = lobby;
|
||||
}
|
||||
|
||||
public NetGame hostGame(final GameRules rules) {
|
||||
final int id = nextId();
|
||||
final NetGame game = new NetGame(rules);
|
||||
games.put(id, game);
|
||||
return game;
|
||||
public void setLobbyListener(final ILobbyListener listener) {
|
||||
this.lobbyListener = listener;
|
||||
}
|
||||
|
||||
public void updateLobbyState() {
|
||||
final LobbyState state = localLobby.getState();
|
||||
final LobbyUpdateEvent event = new LobbyUpdateEvent(state);
|
||||
final LobbyUpdateEvent event = new LobbyUpdateEvent(localLobby.getData());
|
||||
broadcast(event);
|
||||
}
|
||||
|
||||
public void updateSlot(final int index, final UpdateLobbyPlayerEvent event) {
|
||||
localLobby.applyToSlot(index, event);
|
||||
}
|
||||
|
||||
public IGuiGame getGui(final int index) {
|
||||
final LobbySlot slot = localLobby.getSlot(index);
|
||||
final LobbySlotType type = slot.getType();
|
||||
if (type == LobbySlotType.LOCAL) {
|
||||
return GuiBase.getInterface().getNewGuiGame();
|
||||
} else if (type == LobbySlotType.REMOTE) {
|
||||
for (final RemoteClient client : clients.values()) {
|
||||
if (client.getIndex() == index) {
|
||||
return new NetGuiGame(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
@@ -141,9 +177,187 @@ 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
|
||||
@@ -158,8 +372,7 @@ public final class FServerManager {
|
||||
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
|
||||
final RemoteClient client = new RemoteClient(ctx.channel());
|
||||
clients.put(ctx.channel(), client);
|
||||
games.get(0).addClient(client);
|
||||
System.out.println("User connected to server at " + ctx.channel().remoteAddress());
|
||||
System.out.println("Client connected to server at " + ctx.channel().remoteAddress());
|
||||
updateLobbyState();
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
@@ -168,47 +381,45 @@ public final class FServerManager {
|
||||
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
|
||||
final RemoteClient client = clients.get(ctx.channel());
|
||||
if (msg instanceof LoginEvent) {
|
||||
client.setUsername(((LoginEvent) msg).getUsername());
|
||||
final String username = ((LoginEvent) msg).getUsername();
|
||||
client.setUsername(username);
|
||||
broadcast(new MessageEvent(null, String.format("%s joined the room", username)));
|
||||
updateLobbyState();
|
||||
} else if (msg instanceof RegisterDeckEvent) {
|
||||
games.get(0).registerDeck(client, ((RegisterDeckEvent) msg).getDeck());
|
||||
} else if (msg instanceof UpdateLobbyPlayerEvent) {
|
||||
localLobby.applyToSlot(client.getIndex(), (UpdateLobbyPlayerEvent) msg);
|
||||
}
|
||||
super.channelRead(ctx, msg);
|
||||
}
|
||||
}
|
||||
|
||||
private class ToLobbyListenersHandler extends ChannelInboundHandlerAdapter {
|
||||
private class LobbyInputHandler extends ChannelInboundHandlerAdapter {
|
||||
@Override public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
|
||||
final RemoteClient client = clients.get(ctx.channel());
|
||||
if (msg instanceof LoginEvent) {
|
||||
final LoginEvent event = (LoginEvent) msg;
|
||||
final int index = localLobby.login(client);
|
||||
final int index = localLobby.connectPlayer(event.getUsername(), event.getAvatarIndex());
|
||||
if (index == -1) {
|
||||
ctx.close();
|
||||
} else {
|
||||
client.setIndex(index);
|
||||
broadcast(event);
|
||||
updateLobbyState();
|
||||
}
|
||||
} else if (msg instanceof UpdateLobbyPlayerEvent) {
|
||||
updateSlot(client.getIndex(), (UpdateLobbyPlayerEvent) msg);
|
||||
} else if (msg instanceof MessageEvent) {
|
||||
final MessageEvent event = (MessageEvent) msg;
|
||||
broadcast(event);
|
||||
lobbyListener.message(event.getSource(), event.getMessage());
|
||||
}
|
||||
super.channelRead(ctx, msg);
|
||||
}
|
||||
|
||||
@Override public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
|
||||
final RemoteClient client = clients.get(ctx.channel());
|
||||
localLobby.logout(client);
|
||||
updateLobbyState();
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
private class DeregisterClientHandler extends ChannelInboundHandlerAdapter {
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
final RemoteClient client = clients.remove(ctx.channel());
|
||||
// TODO remove client from games
|
||||
localLobby.disconnectPlayer(client.getIndex());
|
||||
broadcast(new LogoutEvent(client.getUsername()));
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
|
||||
28
forge-gui/src/main/java/forge/net/LobbyUpdateEvent.java
Normal file
28
forge-gui/src/main/java/forge/net/LobbyUpdateEvent.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package forge.net;
|
||||
|
||||
import forge.match.GameLobby.GameLobbyData;
|
||||
import forge.net.game.NetEvent;
|
||||
import forge.net.game.server.RemoteClient;
|
||||
|
||||
public class LobbyUpdateEvent implements NetEvent {
|
||||
private static final long serialVersionUID = 7114918637727047985L;
|
||||
|
||||
private final GameLobbyData state;
|
||||
private int slot;
|
||||
public LobbyUpdateEvent(final GameLobbyData state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateForClient(final RemoteClient client) {
|
||||
this.slot = client.getIndex();
|
||||
}
|
||||
|
||||
public GameLobbyData getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public int getSlot() {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package forge.net;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.ai.LobbyPlayerAi;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.GameRules;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.HostedMatch;
|
||||
import forge.match.NetGuiGame;
|
||||
import forge.net.game.server.RemoteClient;
|
||||
import forge.player.LobbyPlayerHuman;
|
||||
|
||||
public final class NetGame {
|
||||
|
||||
private final Map<RemoteClient, NetPlayer> clients = Maps.newHashMap();
|
||||
private final GameRules rules;
|
||||
private final HostedMatch match = new HostedMatch();
|
||||
public NetGame(final GameRules rules) {
|
||||
this.rules = rules;
|
||||
}
|
||||
|
||||
public void addClient(final RemoteClient client) {
|
||||
clients.put(client, new NetPlayer(client, new NetGuiGame(client)));
|
||||
}
|
||||
|
||||
public void startMatch() {
|
||||
final List<RegisteredPlayer> registeredPlayers = Lists.newArrayListWithCapacity(clients.size());
|
||||
final Map<RegisteredPlayer, IGuiGame> guis = Maps.newHashMap();
|
||||
for (final NetPlayer np : clients.values()) {
|
||||
if (np.player == null) {
|
||||
System.err.println("No deck registered for player " + np.client.getUsername());
|
||||
return;
|
||||
}
|
||||
registeredPlayers.add(np.player);
|
||||
guis.put(np.player, np.gui);
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
if (registeredPlayers.size() == 1) {
|
||||
RegisteredPlayer r = new RegisteredPlayer(new Deck());
|
||||
registeredPlayers.add(r);
|
||||
r.setPlayer(new LobbyPlayerAi("AI", new HashMap<String, String>()));
|
||||
}
|
||||
match.startMatch(rules, null, registeredPlayers, guis);
|
||||
}
|
||||
|
||||
public void registerDeck(final RemoteClient client, final Deck deck) {
|
||||
final RegisteredPlayer r = new RegisteredPlayer(deck);
|
||||
clients.get(client).player = r;
|
||||
r.setPlayer(new LobbyPlayerHuman(client.getUsername()));
|
||||
}
|
||||
|
||||
private static final class NetPlayer {
|
||||
private final RemoteClient client;
|
||||
private RegisteredPlayer player = null;
|
||||
private final IGuiGame gui;
|
||||
private NetPlayer(final RemoteClient client, final IGuiGame gui) {
|
||||
this.client = client;
|
||||
this.gui = gui;
|
||||
}
|
||||
}
|
||||
}
|
||||
129
forge-gui/src/main/java/forge/net/NetGameController.java
Normal file
129
forge-gui/src/main/java/forge/net/NetGameController.java
Normal file
@@ -0,0 +1,129 @@
|
||||
package forge.net;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.interfaces.IDevModeCheats;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.net.game.GuiGameEvent;
|
||||
import forge.net.game.client.IToServer;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class NetGameController implements IGameController {
|
||||
|
||||
private final IToServer server;
|
||||
public NetGameController(final IToServer server) {
|
||||
this.server = 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 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useMana(final byte color) {
|
||||
return sendAndWait(methodName(), color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryUndoLastAction() {
|
||||
return sendAndWait(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectPlayer(final PlayerView playerView, final ITriggerEvent triggerEvent) {
|
||||
send(methodName(), playerView, triggerEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean selectCard(final CardView cardView, final List<CardView> otherCardViewsToSelect, final ITriggerEvent triggerEvent) {
|
||||
return sendAndWait(methodName(), cardView, otherCardViewsToSelect, triggerEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonOk() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectAbility(final SpellAbilityView sa) {
|
||||
send(methodName(), sa);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriorityUntilEndOfTurn() {
|
||||
return sendAndWait(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriority() {
|
||||
return sendAndWait(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextGameDecision(final NextGameDecision decision) {
|
||||
send(methodName(), decision);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayLookAtAllCards() {
|
||||
// Don't do this over network
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getActivateDescription(final CardView card) {
|
||||
return sendAndWait(methodName(), card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void concede() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDevModeCheats cheat() {
|
||||
return IDevModeCheats.NO_CHEAT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayUnlimitedLands() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alphaStrike() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
}
|
||||
380
forge-gui/src/main/java/forge/net/NetGuiGame.java
Normal file
380
forge-gui/src/main/java/forge/net/NetGuiGame.java
Normal file
@@ -0,0 +1,380 @@
|
||||
package forge.net;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
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;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
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.game.GuiGameEvent;
|
||||
import forge.net.game.server.IToClient;
|
||||
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);
|
||||
public NetGuiGame(final IToClient client) {
|
||||
this.client = client;
|
||||
for (final MatchButtonType type : MatchButtonType.values()) {
|
||||
btns.put(type, Maps.<PlayerView, NetButton>newHashMap());
|
||||
}
|
||||
}
|
||||
|
||||
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 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 void updateGameView() {
|
||||
send("setGameView", getGameView());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameView(final GameView gameView) {
|
||||
super.setGameView(gameView);
|
||||
updateGameView();
|
||||
}
|
||||
|
||||
@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);
|
||||
updateGameView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterGameEnd() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showCombat() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPromptMessage(final PlayerView playerView, final String message) {
|
||||
updateGameView();
|
||||
send(methodName(), 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flashIncorrectAction() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePhase() {
|
||||
updateGameView();
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTurn(final PlayerView player) {
|
||||
updateGameView();
|
||||
send(methodName(), player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePlayerControl() {
|
||||
updateGameView();
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableOverlay() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableOverlay() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishGame() {
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object showManaPool(final PlayerView player) {
|
||||
send(methodName(), player);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideManaPool(final PlayerView player, final Object zoneToRestore) {
|
||||
send(methodName(), player, zoneToRestore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStack() {
|
||||
updateGameView();
|
||||
send(methodName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateZones(final List<Pair<PlayerView, ZoneType>> zonesToUpdate) {
|
||||
updateGameView();
|
||||
send(methodName(), zonesToUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSingleCard(final CardView card) {
|
||||
updateGameView();
|
||||
send(methodName(), card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) {
|
||||
updateGameView();
|
||||
send(methodName(), manaPoolUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLives(final Iterable<PlayerView> livesUpdate) {
|
||||
updateGameView();
|
||||
send(methodName(), livesUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPanelSelection(final CardView hostCard) {
|
||||
updateGameView();
|
||||
send(methodName(), hostCard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpellAbilityView getAbilityToPlay(final List<SpellAbilityView> abilities, final ITriggerEvent triggerEvent) {
|
||||
return sendAndWait(methodName(), 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(final String message, final String title) {
|
||||
send(methodName(), message, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showErrorDialog(final String message, final String title) {
|
||||
send(methodName(), 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);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirm(final CardView c, final String question, final boolean defaultIsYes, final String[] options) {
|
||||
return sendAndWait(methodName(), 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);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaperCard> sideboard(final CardPool sideboard, final CardPool main) {
|
||||
return sendAndWait(methodName(), 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCard(final CardView card) {
|
||||
updateGameView();
|
||||
send(methodName(), card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerAvatar(LobbyPlayer player, 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreOldZones(final Map<PlayerView, Object> playersToRestoreZonesFor) {
|
||||
send(methodName(), playersToRestoreZonesFor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUiSetToSkipPhase(final PlayerView playerTurn, final PhaseType phase) {
|
||||
return sendAndWait(methodName(), playerTurn, phase);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateCurrentPlayer(final PlayerView player) {
|
||||
// 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 setTextColor(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
forge-gui/src/main/java/forge/net/ServerGameLobby.java
Normal file
65
forge-gui/src/main/java/forge/net/ServerGameLobby.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package forge.net;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.GameLobby;
|
||||
import forge.match.LobbySlot;
|
||||
import forge.net.game.LobbySlotType;
|
||||
|
||||
public final class ServerGameLobby extends GameLobby {
|
||||
|
||||
public ServerGameLobby() {
|
||||
super(true);
|
||||
addSlot(new LobbySlot(LobbySlotType.LOCAL, localName(), localAvatarIndices()[0], 0, true, Collections.<AIOption>emptySet()));
|
||||
addSlot(new LobbySlot(LobbySlotType.OPEN, null, -1, 1, false, Collections.<AIOption>emptySet()));
|
||||
}
|
||||
|
||||
public int connectPlayer(final String name, final int avatarIndex) {
|
||||
final int nSlots = getNumberOfSlots();
|
||||
for (int index = 0; index < nSlots; index++) {
|
||||
final LobbySlot slot = getSlot(index);
|
||||
if (slot.getType() == LobbySlotType.OPEN) {
|
||||
connectPlayer(name, avatarIndex, slot);
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private void connectPlayer(final String name, final int avatarIndex, final LobbySlot slot) {
|
||||
slot.setType(LobbySlotType.REMOTE);
|
||||
slot.setName(name);
|
||||
slot.setAvatarIndex(avatarIndex);
|
||||
updateView();
|
||||
}
|
||||
public void disconnectPlayer(final int index) {
|
||||
final LobbySlot slot = getSlot(index);
|
||||
slot.setType(LobbySlotType.OPEN);
|
||||
slot.setName(StringUtils.EMPTY);
|
||||
updateView();
|
||||
}
|
||||
|
||||
@Override public boolean hasControl() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public boolean mayEdit(final int index) {
|
||||
final LobbySlotType type = getSlot(index).getType();
|
||||
return type != LobbySlotType.REMOTE && type != LobbySlotType.OPEN;
|
||||
}
|
||||
|
||||
@Override public boolean mayControl(final int index) {
|
||||
return getSlot(index).getType() != LobbySlotType.REMOTE;
|
||||
}
|
||||
|
||||
@Override public boolean mayRemove(final int index) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public IGuiGame getGui(final int index) {
|
||||
return FServerManager.getInstance().getGui(index);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
package forge.player;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.AIOption;
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.ai.AiProfileUtil;
|
||||
@@ -13,8 +16,6 @@ import forge.util.GuiDisplayUtil;
|
||||
import forge.util.MyRandom;
|
||||
import forge.util.gui.SOptionPane;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public final class GamePlayerUtil {
|
||||
private GamePlayerUtil() { };
|
||||
|
||||
@@ -22,8 +23,8 @@ public final class GamePlayerUtil {
|
||||
public static final LobbyPlayer getGuiPlayer() {
|
||||
return guiPlayer;
|
||||
}
|
||||
public static final LobbyPlayer getGuiPlayer(String name, int index) {
|
||||
if (index == 0) {
|
||||
public static final LobbyPlayer getGuiPlayer(final String name, final boolean writePref) {
|
||||
if (writePref) {
|
||||
if (!name.equals(guiPlayer.getName())) {
|
||||
guiPlayer.setName(name);
|
||||
FModel.getPreferences().setPref(FPref.PLAYER_NAME, name);
|
||||
@@ -49,7 +50,7 @@ public final class GamePlayerUtil {
|
||||
public final static LobbyPlayer createAiPlayer(String name, int avatarIndex) {
|
||||
return createAiPlayer(name, avatarIndex, null);
|
||||
}
|
||||
public final static LobbyPlayer createAiPlayer(String name, int avatarIndex, Map<String, String> options) {
|
||||
public final static LobbyPlayer createAiPlayer(String name, int avatarIndex, Set<AIOption> options) {
|
||||
LobbyPlayerAi player = new LobbyPlayerAi(name, options);
|
||||
|
||||
// TODO: implement specific AI profiles for quest mode.
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
package forge.player;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.interfaces.IDevModeCheats;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.net.game.client.IToServer;
|
||||
import forge.trackable.TrackableObject;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public class NetGameController implements IGameController {
|
||||
|
||||
private final IToServer server;
|
||||
public NetGameController(final IToServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
private void send(final String method) {
|
||||
send(method, Collections.<TrackableObject>emptySet());
|
||||
}
|
||||
private void send(final String method, final TrackableObject object) {
|
||||
send(method, Collections.singleton(object));
|
||||
}
|
||||
private void send(final String method, final Iterable<? extends TrackableObject> objects) {
|
||||
//server.send(new (method, objects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayLookAtAllCards() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayUnlimitedLands() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void concede() {
|
||||
send("concede");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void alphaStrike() {
|
||||
send("alphaStrike");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useMana(byte color) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonOk() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectButtonCancel() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriority() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean passPriorityUntilEndOfTurn() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectPlayer(PlayerView playerView, ITriggerEvent triggerEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean selectCard(CardView cardView,
|
||||
List<CardView> otherCardViewsToSelect, ITriggerEvent triggerEvent) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectAbility(SpellAbility sa) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryUndoLastAction() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDevModeCheats cheat() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextGameDecision(NextGameDecision decision) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivateDescription(CardView card) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileWriter;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -74,6 +75,7 @@ import forge.game.spellability.AbilityManaPart;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.spellability.SpellAbilityView;
|
||||
import forge.game.spellability.TargetChoices;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.WrappedAbility;
|
||||
@@ -217,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) {
|
||||
return getGui().getAbilityToPlay(abilities, triggerEvent);
|
||||
//return HostedMatch.getController().getAbilityToPlay(abilities, triggerEvent);
|
||||
final SpellAbilityView resultView = getGui().getAbilityToPlay(SpellAbilityView.getCollection(abilities), triggerEvent);
|
||||
return getGame().getSpellAbility(resultView);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -389,13 +391,13 @@ public class PlayerControllerHuman
|
||||
// Human is supposed to read the message and understand from it what to choose
|
||||
if (optionList.isEmpty()) {
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(this);
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (!isOptional && optionList.size() == 1) {
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(this);
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
return Iterables.getFirst(optionList, null);
|
||||
}
|
||||
@@ -416,7 +418,7 @@ public class PlayerControllerHuman
|
||||
|
||||
if (canUseSelectCardsInput) {
|
||||
if (delayedReveal != null) {
|
||||
delayedReveal.reveal(this);
|
||||
reveal(delayedReveal.getCards(), delayedReveal.getZone(), delayedReveal.getOwner(), delayedReveal.getMessagePrefix());
|
||||
}
|
||||
InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<T>(this, isOptional ? 0 : 1, 1, optionList);
|
||||
input.setCancelAllowed(isOptional);
|
||||
@@ -425,8 +427,10 @@ public class PlayerControllerHuman
|
||||
return Iterables.getFirst(input.getSelected(), null);
|
||||
}
|
||||
|
||||
final GameEntityView result = getGui().chooseSingleEntityForEffect(title, optionList, delayedReveal, isOptional, this);
|
||||
endTempShowCards(); //assume tempShow called by GuiBase.getInterface().chooseSingleEntityForEffect
|
||||
tempShow(optionList);
|
||||
final GameEntityView result = getGui().chooseSingleEntityForEffect(title, GameEntityView.getEntityCollection(optionList), delayedReveal, isOptional);
|
||||
endTempShowCards();
|
||||
|
||||
if (result instanceof CardView) {
|
||||
return (T) game.getCard((CardView)result);
|
||||
}
|
||||
@@ -438,16 +442,16 @@ public class PlayerControllerHuman
|
||||
|
||||
@Override
|
||||
public int chooseNumber(SpellAbility sa, String title, int min, int max) {
|
||||
if (min >= max) {
|
||||
return min;
|
||||
}
|
||||
if (min >= max) {
|
||||
return min;
|
||||
}
|
||||
final Integer[] choices = new Integer[max + 1 - min];
|
||||
for (int i = 0; i <= max - min; i++) {
|
||||
choices[i] = Integer.valueOf(i + min);
|
||||
}
|
||||
return getGui().one(title, choices).intValue();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int chooseNumber(SpellAbility sa, String title, List<Integer> choices, Player relatedPlayer) {
|
||||
return getGui().one(title, choices).intValue();
|
||||
@@ -563,19 +567,22 @@ public class PlayerControllerHuman
|
||||
|
||||
@Override
|
||||
public void reveal(CardCollectionView cards, ZoneType zone, Player owner, String message) {
|
||||
reveal(CardView.getCollection(cards), zone, PlayerView.get(owner), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal(Collection<CardView> cards, ZoneType zone, PlayerView owner, String message) {
|
||||
if (StringUtils.isBlank(message)) {
|
||||
message = "Looking at cards in {player's} " + zone.name().toLowerCase();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
message += "{player's} " + zone.name().toLowerCase();
|
||||
}
|
||||
String fm = MessageUtil.formatMessage(message, player, owner);
|
||||
if (!cards.isEmpty()) {
|
||||
tempShowCards(cards);
|
||||
getGui().reveal(fm, CardView.getCollection(cards));
|
||||
tempShowCards(game.getCardList(cards));
|
||||
getGui().reveal(fm, cards);
|
||||
endTempShowCards();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
getGui().message(MessageUtil.formatMessage("There are no cards in {player's} " +
|
||||
zone.name().toLowerCase(), player, owner), fm);
|
||||
}
|
||||
@@ -993,17 +1000,18 @@ public class PlayerControllerHuman
|
||||
return Iterables.getFirst(allTargets, null);
|
||||
}
|
||||
|
||||
final Function<Pair<SpellAbilityStackInstance, GameObject>, String> fnToString = new Function<Pair<SpellAbilityStackInstance, GameObject>, String>() {
|
||||
@Override
|
||||
public String apply(Pair<SpellAbilityStackInstance, GameObject> targ) {
|
||||
return targ.getRight().toString() + " - " + targ.getLeft().getStackDescription();
|
||||
}
|
||||
};
|
||||
|
||||
List<Pair<SpellAbilityStackInstance, GameObject>> chosen = getGui().getChoices(saSpellskite.getHostCard().getName(), 1, 1, allTargets, null, fnToString);
|
||||
final List<Pair<SpellAbilityStackInstance, GameObject>> chosen = getGui().getChoices(saSpellskite.getHostCard().getName(), 1, 1, allTargets, null, new FnTargetToString());
|
||||
return Iterables.getFirst(chosen, null);
|
||||
}
|
||||
|
||||
private final static class FnTargetToString implements Function<Pair<SpellAbilityStackInstance, GameObject>, String>, Serializable {
|
||||
private static final long serialVersionUID = -4779137632302777802L;
|
||||
|
||||
@Override public String apply(final Pair<SpellAbilityStackInstance, GameObject> targ) {
|
||||
return targ.getRight().toString() + " - " + targ.getLeft().getStackDescription();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyOfValue(SpellAbility sa, GameObject realtedTarget, String value) {
|
||||
String message = MessageUtil.formatNotificationMessage(sa, player, realtedTarget, value);
|
||||
@@ -1352,8 +1360,8 @@ public class PlayerControllerHuman
|
||||
return inputProxy.selectCard(cardView, otherCardViewsToSelect, triggerEvent);
|
||||
}
|
||||
|
||||
public void selectAbility(final SpellAbility sa) {
|
||||
inputProxy.selectAbility(sa);
|
||||
public void selectAbility(final SpellAbilityView sa) {
|
||||
inputProxy.selectAbility(getGame().getSpellAbility(sa));
|
||||
}
|
||||
|
||||
public void alphaStrike() {
|
||||
|
||||
Reference in New Issue
Block a user