Update stability and fix issues in lobby and network games.

- Fix closing the lobby/client so that it notifies the clients/server.
- Improve deck selection in lobby (no longer adds Planes to deck and saves)
- Improve responsiveness of lobby over network
- In 2-player game over network, always assign local player to slot 0
- Warn when starting a commander deck without a commander
- Put poison counters next to life total (frees up space in the details panel)
This commit is contained in:
elcnesh
2015-04-02 08:56:31 +00:00
parent d3bcc089e3
commit 6bc69d0935
12 changed files with 235 additions and 138 deletions

View File

@@ -110,6 +110,7 @@ public enum FControl implements KeyEventDispatcher {
}
}
}
/**
* <p>
* FControl.

View File

@@ -239,7 +239,8 @@ public class VLobby implements IUpdateable {
isNewPanel = true;
}
panel.setType(slot.getType());
final LobbySlotType type = slot.getType();
panel.setType(type);
panel.setPlayerName(slot.getName());
panel.setAvatar(slot.getAvatarIndex());
panel.setTeam(slot.getTeam());
@@ -253,7 +254,7 @@ public class VLobby implements IUpdateable {
final FDeckChooser deckChooser = getDeckChooser(i);
deckChooser.setIsAi(slot.getType() == LobbySlotType.AI);
if (fullUpdate) {
if (fullUpdate && (type == LobbySlotType.LOCAL || type == LobbySlotType.AI)) {
selectDeck(i);
}
if (isNewPanel) {
@@ -298,7 +299,9 @@ public class VLobby implements IUpdateable {
}
}
private void fireDeckSectionChangeListener(final int index, final DeckSection section, final CardPool cards) {
decks[index].putSection(section, cards);
final Deck copy = new Deck(decks[index]);
copy.putSection(section, cards);
decks[index] = copy;
if (playerChangeListener != null) {
playerChangeListener.update(index, UpdateLobbyPlayerEvent.deckUpdate(section, cards));
}
@@ -486,7 +489,7 @@ public class VLobby implements IUpdateable {
}
private void selectPlanarDeck(final int playerIndex) {
if (playerIndex >= activePlayersNum) {
if (playerIndex >= activePlayersNum || !hasVariant(GameType.Planechase)) {
return;
}

View File

@@ -8,6 +8,7 @@ import javax.swing.JMenu;
import forge.GuiBase;
import forge.Singletons;
import forge.UiCommand;
import forge.assets.FSkinProp;
import forge.gui.FNetOverlay;
import forge.gui.framework.FScreen;
import forge.gui.framework.ICDoc;
@@ -31,6 +32,7 @@ import forge.net.game.UpdateLobbyPlayerEvent;
import forge.properties.ForgePreferences.FPref;
import forge.screens.home.VLobby;
import forge.screens.home.sanctioned.ConstructedGameMenu;
import forge.util.gui.SOptionPane;
public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
SINGLETON_INSTANCE;
@@ -64,6 +66,9 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
@Override public final void message(final String source, final String message) {
FNetOverlay.SINGLETON_INSTANCE.addMessage(source, message);
}
@Override public final void close() {
// NO-OP, server can't receive close message
}
});
FNetOverlay.SINGLETON_INSTANCE.setGameClient(new IRemote() {
@Override public final void send(final NetEvent event) {
@@ -79,6 +84,7 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
}
});
view.populate();
view.update(true);
Singletons.getControl().setCurrentScreen(FScreen.ONLINE_LOBBY);
@@ -88,6 +94,7 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
final void join(final String hostname, final int port) {
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame();
final FGameClient client = new FGameClient(FModel.getPreferences().getPref(FPref.PLAYER_NAME), "0", gui);
VOnlineLobby.SINGLETON_INSTANCE.setClient(client);
FNetOverlay.SINGLETON_INSTANCE.setGameClient(client);
final ClientGameLobby lobby = new ClientGameLobby();
final VLobby view = VOnlineLobby.SINGLETON_INSTANCE.setLobby(lobby);
@@ -100,6 +107,11 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
lobby.setLocalPlayer(slot);
lobby.setData(state);
}
@Override public final void close() {
SOptionPane.showMessageDialog("Connection to the host was interrupted.", "Error", FSkinProp.ICO_WARNING);
VOnlineLobby.SINGLETON_INSTANCE.setClient(null);
FScreen.ONLINE_LOBBY.close();
}
});
view.setPlayerChangeListener(new IPlayerChangeListener() {
@Override public final void update(final int index, final UpdateLobbyPlayerEvent event) {
@@ -109,7 +121,7 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
client.connect(hostname, port);
Singletons.getControl().setCurrentScreen(FScreen.ONLINE_LOBBY);
FNetOverlay.SINGLETON_INSTANCE.showUp(String.format("Connected to %s:%s", hostname, port));
FNetOverlay.SINGLETON_INSTANCE.showUp(String.format("Connected to %s:%d", hostname, port));
}
@Override

View File

@@ -6,6 +6,7 @@ import net.miginfocom.swing.MigLayout;
import forge.deckchooser.DecksComboBoxEvent;
import forge.deckchooser.FDeckChooser;
import forge.deckchooser.IDecksComboBoxListener;
import forge.gui.FNetOverlay;
import forge.gui.framework.DragCell;
import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID;
@@ -13,6 +14,8 @@ import forge.gui.framework.FScreen;
import forge.gui.framework.IVDoc;
import forge.gui.framework.IVTopLevelUI;
import forge.match.GameLobby;
import forge.net.FGameClient;
import forge.net.FServerManager;
import forge.screens.home.VLobby;
import forge.toolbox.FPanel;
import forge.util.gui.SOptionPane;
@@ -26,6 +29,7 @@ public enum VOnlineLobby implements IVDoc<COnlineLobby>, IVTopLevelUI {
// General variables
private VLobby lobby;
private FGameClient client;
private VOnlineLobby() {
}
@@ -39,10 +43,15 @@ public enum VOnlineLobby implements IVDoc<COnlineLobby>, IVTopLevelUI {
return this.lobby;
}
void setClient(final FGameClient client) {
this.client = client;
}
@Override
public void populate() {
final JPanel outerContainer = FView.SINGLETON_INSTANCE.getPnlInsets();
outerContainer.removeAll();
final FPanel container = new FPanel(new MigLayout("insets 0, gap 0, wrap 1, ax right"));
outerContainer.add(container);
lobby.getLblTitle().setText("Online Multiplayer: Lobby");
@@ -106,7 +115,23 @@ public enum VOnlineLobby implements IVDoc<COnlineLobby>, IVTopLevelUI {
@Override
public boolean onClosing(final FScreen screen) {
return SOptionPane.showConfirmDialog("Leave lobby?", "Leave");
final FServerManager server = FServerManager.getInstance();
if (server.isHosting()) {
if (SOptionPane.showConfirmDialog("Leave lobby? Doing so will shut down all connections and stop hosting.", "Leave")) {
FServerManager.getInstance().stopServer();
return true;
}
} else {
if (client == null || SOptionPane.showConfirmDialog("Leave lobby?", "Leave")) {
if (client != null) {
client.close();
client = null;
}
FNetOverlay.SINGLETON_INSTANCE.setGameClient(null);
return true;
}
}
return false;
}
}

View File

@@ -104,6 +104,7 @@ import forge.toolbox.MouseTriggerEvent;
import forge.toolbox.special.PhaseIndicator;
import forge.toolbox.special.PhaseLabel;
import forge.trackable.TrackableCollection;
import forge.util.FCollection;
import forge.util.FCollectionView;
import forge.util.ITriggerEvent;
import forge.util.gui.SOptionPane;
@@ -260,11 +261,6 @@ public final class CMatchUI
return FSkin.getAvatars().get(avatarIdx >= 0 ? avatarIdx : defaultIndex);
}
private void setAvatar(VField view, SkinImage img) {
view.getLblAvatar().setIcon(img);
view.getLblAvatar().getResizeTimer().start();
}
private void initMatch(final FCollectionView<PlayerView> sortedPlayers, final Iterable<PlayerView> myPlayers) {
this.sortedPlayers = sortedPlayers;
this.setLocalPlayers(myPlayers);
@@ -290,8 +286,7 @@ public final class CMatchUI
commands.add(c);
myDocs.put(commandDoc, c);
//setAvatar(f, new ImageIcon(FSkin.getAvatars().get()));
setAvatar(f, getPlayerAvatar(p, Integer.parseInt(indices[i > 2 ? 1 : 0])));
f.setAvatar(getPlayerAvatar(p, Integer.parseInt(indices[i > 2 ? 1 : 0])));
f.getLayoutControl().initialize();
c.getLayoutControl().initialize();
i++;
@@ -436,7 +431,7 @@ public final class CMatchUI
if (vHand != null) {
vHand.getLayoutControl().updateHand();
}
vf.getDetailsPanel().updateZones();
vf.updateZones();
vf.updateDetails();
FloatingCardArea.refresh(owner, zt);
break;
@@ -448,7 +443,7 @@ public final class CMatchUI
break;
default:
if (vf != null) {
vf.getDetailsPanel().updateZones();
vf.updateZones();
}
FloatingCardArea.refresh(owner, zt);
break;
@@ -460,7 +455,7 @@ public final class CMatchUI
@Override
public void updateManaPool(final Iterable<PlayerView> manaPoolUpdate) {
for (final PlayerView p : manaPoolUpdate) {
getFieldViewFor(p).getDetailsPanel().updateManaPool();
getFieldViewFor(p).updateManaPool();
}
}
@@ -795,7 +790,12 @@ public final class CMatchUI
final GameView gameView = getGameView();
gameView.getGameLog().addObserver(getCLog());
initMatch(gameView.getPlayers(), myPlayers);
// Sort players
FCollectionView<PlayerView> players = gameView.getPlayers();
if (players.size() == 2 && myPlayers.size() == 1 && myPlayers.get(0).equals(players.get(1))) {
players = new FCollection<PlayerView>(new PlayerView[] { players.get(1), players.get(0) });
}
initMatch(players, myPlayers);
actuateMatchPreferences();

View File

@@ -28,6 +28,7 @@ import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import net.miginfocom.swing.MigLayout;
import forge.assets.FSkinProp;
import forge.game.player.PlayerView;
import forge.game.zone.ZoneType;
import forge.gui.framework.DragCell;
@@ -39,6 +40,7 @@ import forge.screens.match.controllers.CField;
import forge.toolbox.FLabel;
import forge.toolbox.FScrollPane;
import forge.toolbox.FSkin;
import forge.toolbox.FSkin.SkinImage;
import forge.toolbox.FSkin.SkinnedPanel;
import forge.toolbox.special.PhaseIndicator;
import forge.toolbox.special.PlayerDetailsPanel;
@@ -50,6 +52,9 @@ import forge.view.arcane.PlayArea;
* <br><br><i>(V at beginning of class name denotes a view class.)</i>
*/
public class VField implements IVDoc<CField> {
private final static int LIFE_CRITICAL = 5;
private final static int POISON_CRITICAL = 8;
// Fields used with interface IVDoc
private final CField control;
private DragCell parentCell;
@@ -57,7 +62,7 @@ public class VField implements IVDoc<CField> {
private final DragTab tab = new DragTab("Field");
// Other fields
private PlayerView player = null;
private final PlayerView player;
// Top-level containers
private final FScrollPane scroller = new FScrollPane(false);
@@ -69,6 +74,7 @@ public class VField implements IVDoc<CField> {
// Avatar area
private final FLabel lblAvatar = new FLabel.Builder().fontAlign(SwingConstants.CENTER).iconScaleFactor(1.0f).build();
private final FLabel lblLife = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).build();
private final FLabel lblPoison = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).icon(FSkin.getImage(FSkinProp.IMG_ZONE_POISON)).iconInBackground().build();
private final PhaseIndicator phaseIndicator = new PhaseIndicator();
@@ -100,12 +106,13 @@ public class VField implements IVDoc<CField> {
lblAvatar.setFocusable(false);
lblLife.setFocusable(false);
lblPoison.setFocusable(false);
avatarArea.setOpaque(false);
avatarArea.setBackground(FSkin.getColor(FSkin.Colors.CLR_HOVER));
avatarArea.setLayout(new MigLayout("insets 0, gap 0"));
avatarArea.add(lblAvatar, "w 100%-6px!, h 100%-23px!, wrap, gap 3 3 3 0");
avatarArea.add(lblLife, "w 100%!, h 20px!");
avatarArea.add(lblLife, "w 100%!, h 20px!, wrap");
// Player area hover effect
avatarArea.addMouseListener(new MouseAdapter() {
@@ -170,10 +177,6 @@ public class VField implements IVDoc<CField> {
return this.parentCell;
}
public PlayerView getPlayer() {
return this.player;
}
public PlayArea getTabletop() {
return this.tabletop;
}
@@ -182,14 +185,6 @@ public class VField implements IVDoc<CField> {
return this.avatarArea;
}
public FLabel getLblAvatar() {
return this.lblAvatar;
}
public FLabel getLblLife() {
return this.lblLife;
}
public PhaseIndicator getPhaseIndicator() {
return phaseIndicator;
}
@@ -198,23 +193,67 @@ public class VField implements IVDoc<CField> {
return detailsPanel;
}
public boolean isHighlighted() {
private boolean isHighlighted() {
return control.getMatchUI().isHighlighted(player);
}
public void setAvatar(final SkinImage avatar) {
lblAvatar.setIcon(avatar);
lblAvatar.getResizeTimer().start();
}
public void updateManaPool() {
detailsPanel.updateManaPool();
}
public void updateZones() {
detailsPanel.updateZones();
}
private void addLblPoison() {
if (lblPoison.isShowing()) {
return;
}
avatarArea.remove(lblLife);
avatarArea.add(lblLife, "w 50%!, h 20px!, split 2");
avatarArea.add(lblPoison, "w 50%!, h 20px!, wrap");
}
private void removeLblPoison() {
if (!lblPoison.isShowing()) {
return;
}
avatarArea.remove(lblPoison);
avatarArea.remove(lblLife);
avatarArea.add(lblLife, "w 100%!, h 20px!, wrap");
}
public void updateDetails() {
control.getMatchUI().getCPlayers().update();
detailsPanel.updateDetails();
this.getLblLife().setText("" + player.getLife());
if (player.getLife() > 5) {
this.getLblLife().setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
}
else {
this.getLblLife().setForeground(Color.red);
// Update life total
final int life = player.getLife();
lblLife.setText(String.valueOf(life));
if (life > LIFE_CRITICAL) {
lblLife.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
} else {
lblLife.setForeground(Color.RED);
}
boolean highlighted = isHighlighted();
// Update poison counters
final int poison = player.getPoisonCounters();
if (poison > 0) {
addLblPoison();
lblPoison.setText(String.valueOf(poison));
if (poison < POISON_CRITICAL) {
lblPoison.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
} else {
lblPoison.setForeground(Color.RED);
}
} else {
removeLblPoison();
}
final boolean highlighted = isHighlighted();
this.avatarArea.setBorder(highlighted ? borderAvatarHighlighted : borderAvatarSimple );
this.avatarArea.setOpaque(highlighted);
this.avatarArea.setToolTipText(player.getDetailsHtml());

View File

@@ -1,6 +1,7 @@
package forge.toolbox.special;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
@@ -33,23 +34,23 @@ public class PlayerDetailsPanel extends JPanel {
private final PlayerView player;
// Info labels
private final FLabel lblHand = new DetailLabel(FSkinProp.IMG_ZONE_HAND, "99", "Cards in hand");
private final FLabel lblGraveyard = new DetailLabel(FSkinProp.IMG_ZONE_GRAVEYARD, "99", "Cards in graveyard");
private final FLabel lblLibrary = new DetailLabel(FSkinProp.IMG_ZONE_LIBRARY, "99", "Cards in library");
private final FLabel lblExile = new DetailLabel(FSkinProp.IMG_ZONE_EXILE, "99", "Exiled cards");
private final FLabel lblFlashback = new DetailLabel(FSkinProp.IMG_ZONE_FLASHBACK, "99", "Flashback cards");
private final FLabel lblPoison = new DetailLabel(FSkinProp.IMG_ZONE_POISON, "99", "Poison counters");
private final DetailLabel lblHand = new DetailLabel(FSkinProp.IMG_ZONE_HAND, "Hand (%s/%s)");
private final DetailLabel lblGraveyard = new DetailLabel(FSkinProp.IMG_ZONE_GRAVEYARD, "Graveyard (%s)");
private final DetailLabel lblLibrary = new DetailLabel(FSkinProp.IMG_ZONE_LIBRARY, "Library (%s)");
private final DetailLabel lblExile = new DetailLabel(FSkinProp.IMG_ZONE_EXILE, "Exile (%s)");
private final DetailLabel lblFlashback = new DetailLabel(FSkinProp.IMG_ZONE_FLASHBACK, "Flashback cards (%s)");
private final DetailLabel lblPoison = new DetailLabel(FSkinProp.IMG_ZONE_POISON, "Poison counters (%s)");
private final List<Pair<DetailLabel, Byte>> manaLabels = new ArrayList<Pair<DetailLabel, Byte>>();
public PlayerDetailsPanel(final PlayerView player0) {
player = player0;
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_B, "99", "Black mana"), MagicColor.BLACK));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_U, "99", "Blue mana"), MagicColor.BLUE));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_G, "99", "Green mana"), MagicColor.GREEN));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_R, "99", "Red mana"), MagicColor.RED));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_W, "99", "White mana"), MagicColor.WHITE));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_COLORLESS, "99", "Colorless mana"), (byte)0));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_W, "White mana (%s)"), MagicColor.WHITE));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_U, "Blue mana (%s)"), MagicColor.BLUE));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_B, "Black mana (%s)"), MagicColor.BLACK));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_R, "Red mana (%s)"), MagicColor.RED));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_G, "Green mana (%s)"), MagicColor.GREEN));
manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_COLORLESS, "Colorless mana (%s)"), MagicColor.COLORLESS));
setOpaque(false);
setLayout(new MigLayout("insets 0, gap 0, wrap"));
@@ -105,74 +106,59 @@ public class PlayerDetailsPanel extends JPanel {
add(row6, constraintsRow);
}
public Component getLblLibrary() {
return lblLibrary;
}
/**
* Handles observer update of player Zones - hand, graveyard, etc.
*
* @param p0 &emsp; {@link forge.game.player.Player}
*/
public void updateZones() {
getLblHand().setText("" + player.getHandSize());
final String handMaxToolTip = player.hasUnlimitedHandSize()
? "no maximum hand size" : String.valueOf(player.getMaxHandSize());
getLblHand().setToolTipText("Cards in hand (max: " + handMaxToolTip + ")");
getLblGraveyard().setText("" + player.getGraveyardSize());
getLblLibrary().setText("" + player.getLibrarySize());
getLblFlashback().setText("" + player.getFlashbackSize());
getLblExile().setText("" + player.getExileSize());
final String handSize = String.valueOf(player.getHandSize()),
graveyardSize = String.valueOf(player.getGraveyardSize()),
librarySize = String.valueOf(player.getLibrarySize()),
flashbackSize = String.valueOf(player.getFlashbackSize()),
exileSize = String.valueOf(player.getExileSize());
lblHand.setText(handSize);
lblHand.setToolTip(handSize, player.getMaxHandString());
lblGraveyard.setText(graveyardSize);
lblGraveyard.setToolTip(graveyardSize);
lblLibrary.setText(librarySize);
lblLibrary.setToolTip(librarySize);
lblFlashback.setText(flashbackSize);
lblFlashback.setToolTip(flashbackSize);
lblExile.setText(exileSize);
lblExile.setToolTip(exileSize);
}
/**
* Handles observer update of non-Zone details - life, poison, etc. Also
* updates "players" panel in tabber for this player.
*
* @param p0 &emsp; {@link forge.game.player.Player}
* Handles observer update of non-Zone details (poison).
*/
public void updateDetails() {
// Poison/life
getLblPoison().setText("" + player.getPoisonCounters());
if (player.getPoisonCounters() < 8) {
getLblPoison().setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
}
else {
getLblPoison().setForeground(Color.red);
// Poison
final int poison = player.getPoisonCounters();
lblPoison.setText(String.valueOf(poison));
lblPoison.setToolTip(String.valueOf(poison));
if (poison < 8) {
lblPoison.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
} else {
lblPoison.setForeground(Color.red);
}
}
/**
* Handles observer update of the mana pool.
*
* @param p0 &emsp; {@link forge.game.player.Player}
*/
public void updateManaPool() {
for (final Pair<DetailLabel, Byte> label : manaLabels) {
label.getKey().setText(Integer.toString(player.getMana(label.getRight())));
final String mana = String.valueOf(player.getMana(label.getRight().byteValue()));
label.getKey().setText(mana);
label.getKey().setToolTip(mana);
}
}
public FLabel getLblHand() {
return lblHand;
}
public FLabel getLblLibrary() {
return lblLibrary;
}
public FLabel getLblGraveyard() {
return lblGraveyard;
}
public FLabel getLblExile() {
return lblExile;
}
public FLabel getLblFlashback() {
return lblFlashback;
}
public FLabel getLblPoison() {
return lblPoison;
}
public void setupMouseActions(final ForgeAction handAction, final ForgeAction libraryAction, final ForgeAction exileAction,
final ForgeAction graveAction, final ForgeAction flashBackAction, final Function<Byte, Boolean> manaAction) {
// Detail label listeners
@@ -212,7 +198,8 @@ public class PlayerDetailsPanel extends JPanel {
@Override
public void onLeftClick(final MouseEvent e) {
//if shift key down, keep using mana until it runs out or no longer can be put towards the cost
while (manaAction.apply(labelPair.getRight()) && e.isShiftDown()) {}
final Byte mana = labelPair.getRight();
while (manaAction.apply(mana) && e.isShiftDown()) {}
}
});
}
@@ -220,33 +207,39 @@ public class PlayerDetailsPanel extends JPanel {
@SuppressWarnings("serial")
private class DetailLabel extends FLabel {
private DetailLabel(FSkinProp p0, String s0, String s1) {
super(new FLabel.Builder().icon(FSkin.getImage(p0))
private final String tooltip;
private DetailLabel(final FSkinProp icon, final String tooltip) {
super(new FLabel.Builder().icon(FSkin.getImage(icon))
.opaque(false).fontSize(14).hoverable()
.fontStyle(Font.BOLD).iconInBackground()
.text(s0).tooltip(s1).fontAlign(SwingConstants.RIGHT));
.fontAlign(SwingConstants.RIGHT));
this.tooltip = tooltip;
setFocusable(false);
}
public void setText(String text0) {
public void setText(final String text0) {
super.setText(text0);
autoSizeFont();
}
public void setToolTip(final String... args) {
super.setToolTipText(String.format(tooltip, (Object[]) args));
}
protected void resetIcon() {
super.resetIcon();
autoSizeFont();
}
private void autoSizeFont() {
String text = getText();
final String text = getText();
if (StringUtils.isEmpty(text)) { return; }
Graphics g = getGraphics();
final Graphics g = getGraphics();
if (g == null) { return; }
int max = getMaxTextWidth();
final int max = getMaxTextWidth();
SkinFont font = null;
for (int fontSize = 14; fontSize > 5; fontSize--) {

View File

@@ -5,4 +5,5 @@ import forge.match.GameLobby.GameLobbyData;
public interface ILobbyListener {
void message(String source, String message);
void update(GameLobbyData state, int slot);
void close();
}

View File

@@ -41,6 +41,7 @@ public abstract class GameLobby {
private final static int MAX_PLAYERS = 8;
private GameLobbyData data = new GameLobbyData();
private GameType currentGameType = GameType.Constructed;
private int lastArchenemy = 0;
private IUpdateable listener;
@@ -69,10 +70,10 @@ public abstract class GameLobby {
}
public GameType getGameType() {
return data.currentGameMode;
return currentGameType;
}
public void setGameType(final GameType type) {
data.currentGameMode = type;
currentGameType = type;
}
public boolean hasVariant(final GameType variant) {
@@ -90,7 +91,7 @@ public abstract class GameLobby {
}
public void applyToSlot(final int index, final UpdateLobbyPlayerEvent event) {
final LobbySlot slot = getSlot(index);
if (slot == null) {
if (slot == null || event == null) {
throw new NullPointerException();
}
@@ -130,10 +131,10 @@ public abstract class GameLobby {
}
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);
protected abstract IGuiGame getGui(final int index);
public abstract boolean mayEdit(int index);
public abstract boolean mayControl(int index);
public abstract boolean mayRemove(int index);
protected abstract IGuiGame getGui(int index);
protected abstract void onGameStarted();
public void addSlot() {
@@ -142,6 +143,9 @@ public abstract class GameLobby {
addSlot(new LobbySlot(type, null, newIndex, newIndex, false, !allowNetworking, Collections.<AIOption>emptySet()));
}
protected final void addSlot(final LobbySlot slot) {
if (slot == null) {
throw new NullPointerException();
}
if (data.slots.size() >= MAX_PLAYERS) {
return;
}
@@ -197,7 +201,7 @@ public abstract class GameLobby {
}
public void applyVariant(final GameType variant) {
data.currentGameMode = variant;
setGameType(variant);
data.appliedVariants.add(variant);
//ensure other necessary variants are unchecked
@@ -231,17 +235,21 @@ public abstract class GameLobby {
}
public void removeVariant(final GameType variant) {
data.appliedVariants.remove(variant);
final boolean changed = data.appliedVariants.remove(variant);
if (!changed) {
return;
}
if (data.appliedVariants.isEmpty()) {
data.appliedVariants.add(GameType.Constructed);
}
if (variant == data.currentGameMode) {
if (variant == currentGameType) {
if (hasVariant(GameType.Commander)) {
data.currentGameMode = GameType.Commander;
currentGameType = GameType.Commander;
} else if (hasVariant(GameType.TinyLeaders)) {
data.currentGameMode = GameType.TinyLeaders;
currentGameType = GameType.TinyLeaders;
} else {
data.currentGameMode = GameType.Constructed;
currentGameType = GameType.Constructed;
}
}
updateView(true);
@@ -275,7 +283,7 @@ public abstract class GameLobby {
}
final List<LobbySlot> activeSlots = Lists.newArrayListWithCapacity(getNumberOfSlots());
for (final LobbySlot slot : data.getSlots()) {
for (final LobbySlot slot : data.slots) {
if (slot.getType() != LobbySlotType.OPEN) {
activeSlots.add(slot);
}
@@ -290,6 +298,12 @@ public abstract class GameLobby {
SOptionPane.showMessageDialog(String.format("Please specify a deck for %s", slot.getName()));
return;
}
if (hasVariant(GameType.Commander) || hasVariant(GameType.TinyLeaders)) {
if (!slot.getDeck().has(DeckSection.Commander)) {
SOptionPane.showMessageDialog(String.format("%s doesn't have a commander", slot.getName()));
return;
}
}
}
final Set<GameType> variantTypes = data.appliedVariants;
@@ -391,7 +405,7 @@ public abstract class GameLobby {
return;
}
}
schemes = schemePool.toFlatList();
schemes = schemePool == null ? Collections.<PaperCard>emptyList() : schemePool.toFlatList();
}
//Planechase
@@ -404,7 +418,7 @@ public abstract class GameLobby {
return;
}
}
planes = planePool.toFlatList();
planes = planePool == null ? Collections.<PaperCard>emptyList() : planePool.toFlatList();
}
//Vanguard
@@ -441,23 +455,12 @@ public abstract class GameLobby {
}
public final static class GameLobbyData implements Serializable {
private static final long serialVersionUID = -9038854736144187540L;
private static final long serialVersionUID = 9184758307999646864L;
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);
public GameLobbyData() {
}
}
}

View File

@@ -62,10 +62,11 @@ public final class LobbySlot implements Serializable {
setAiOptions(data.getAiOptions());
changed = true;
}
final Deck oldDeck = getDeck();
if (data.getDeck() != null) {
setDeck(data.getDeck());
} else if (getDeck() != null && data.getSection() != null && data.getCards() != null) {
getDeck().putSection(data.getSection(), data.getCards());
} else if (oldDeck != null && data.getSection() != null && data.getCards() != null) {
oldDeck.putSection(data.getSection(), data.getCards());
}
return changed;
}

View File

@@ -104,6 +104,10 @@ public class FGameClient implements IToServer {
}
}
public void close() {
channel.close();
}
@Override
public void send(final NetEvent event) {
System.out.println("Client sent " + event);
@@ -382,5 +386,13 @@ public class FGameClient implements IToServer {
}
super.channelRead(ctx, msg);
}
@Override
public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
for (final ILobbyListener listener : lobbyListeners) {
listener.close();
}
super.channelInactive(ctx);
}
}
}

View File

@@ -52,6 +52,7 @@ import com.google.common.collect.Maps;
public final class FServerManager {
private static FServerManager instance = null;
private boolean isHosting = false;
private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
private final EventLoopGroup workerGroup = new NioEventLoopGroup();
private final Map<Channel, RemoteClient> clients = Maps.newTreeMap();
@@ -102,6 +103,7 @@ public final class FServerManager {
}
}).start();
isHosting = true;
} catch (final InterruptedException e) {
e.printStackTrace();
}
@@ -110,6 +112,11 @@ public final class FServerManager {
public void stopServer() {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
isHosting = false;
}
public boolean isHosting() {
return isHosting;
}
public void broadcast(final NetEvent event) {