Refactor net connection logic to be reusable by app

This commit is contained in:
drdev
2015-05-31 11:21:50 +00:00
parent 0bf8ed9546
commit f4f49627cf
9 changed files with 189 additions and 140 deletions

4
.gitattributes vendored
View File

@@ -17635,6 +17635,7 @@ forge-gui/src/main/java/forge/interfaces/IGameController.java -text
forge-gui/src/main/java/forge/interfaces/IGuiBase.java -text forge-gui/src/main/java/forge/interfaces/IGuiBase.java -text
forge-gui/src/main/java/forge/interfaces/IGuiGame.java -text forge-gui/src/main/java/forge/interfaces/IGuiGame.java -text
forge-gui/src/main/java/forge/interfaces/ILobbyListener.java -text forge-gui/src/main/java/forge/interfaces/ILobbyListener.java -text
forge-gui/src/main/java/forge/interfaces/ILobbyView.java -text
forge-gui/src/main/java/forge/interfaces/IMayViewCards.java -text forge-gui/src/main/java/forge/interfaces/IMayViewCards.java -text
forge-gui/src/main/java/forge/interfaces/IPlayerChangeListener.java -text forge-gui/src/main/java/forge/interfaces/IPlayerChangeListener.java -text
forge-gui/src/main/java/forge/interfaces/IProgressBar.java -text forge-gui/src/main/java/forge/interfaces/IProgressBar.java -text
@@ -17711,7 +17712,10 @@ forge-gui/src/main/java/forge/model/UnOpenedMeta.java -text
forge-gui/src/main/java/forge/model/package-info.java svneol=native#text/plain forge-gui/src/main/java/forge/model/package-info.java svneol=native#text/plain
forge-gui/src/main/java/forge/net/GameProtocolHandler.java -text forge-gui/src/main/java/forge/net/GameProtocolHandler.java -text
forge-gui/src/main/java/forge/net/GameProtocolSender.java -text forge-gui/src/main/java/forge/net/GameProtocolSender.java -text
forge-gui/src/main/java/forge/net/IOnlineChatInterface.java -text
forge-gui/src/main/java/forge/net/IOnlineLobby.java -text
forge-gui/src/main/java/forge/net/IRemote.java -text forge-gui/src/main/java/forge/net/IRemote.java -text
forge-gui/src/main/java/forge/net/NetConnectUtil.java -text
forge-gui/src/main/java/forge/net/ProtocolMethod.java -text forge-gui/src/main/java/forge/net/ProtocolMethod.java -text
forge-gui/src/main/java/forge/net/ReplyPool.java -text forge-gui/src/main/java/forge/net/ReplyPool.java -text
forge-gui/src/main/java/forge/net/client/ClientGameLobby.java -text forge-gui/src/main/java/forge/net/client/ClientGameLobby.java -text

View File

@@ -18,6 +18,7 @@ import org.apache.commons.lang3.StringUtils;
import forge.Singletons; import forge.Singletons;
import forge.gui.framework.SDisplayUtil; import forge.gui.framework.SDisplayUtil;
import forge.model.FModel; import forge.model.FModel;
import forge.net.IOnlineChatInterface;
import forge.net.IRemote; import forge.net.IRemote;
import forge.net.event.MessageEvent; import forge.net.event.MessageEvent;
import forge.properties.ForgePreferences; import forge.properties.ForgePreferences;
@@ -34,7 +35,7 @@ import forge.view.FDialog;
import forge.view.FFrame; import forge.view.FFrame;
public enum FNetOverlay { public enum FNetOverlay implements IOnlineChatInterface {
SINGLETON_INSTANCE; SINGLETON_INSTANCE;
private static final String COORD_DELIM = ","; private static final String COORD_DELIM = ",";

View File

@@ -35,8 +35,8 @@ import forge.deckchooser.FDeckChooser;
import forge.game.GameType; import forge.game.GameType;
import forge.game.card.CardView; import forge.game.card.CardView;
import forge.gui.CardDetailPanel; import forge.gui.CardDetailPanel;
import forge.interfaces.ILobbyView;
import forge.interfaces.IPlayerChangeListener; import forge.interfaces.IPlayerChangeListener;
import forge.interfaces.IUpdateable;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.match.GameLobby; import forge.match.GameLobby;
import forge.match.LobbySlot; import forge.match.LobbySlot;
@@ -66,7 +66,7 @@ import forge.util.storage.IStorage;
* *
* <br><br><i>(V at beginning of class name denotes a view class.)</i> * <br><br><i>(V at beginning of class name denotes a view class.)</i>
*/ */
public class VLobby implements IUpdateable { public class VLobby implements ILobbyView {
static final int MAX_PLAYERS = 8; static final int MAX_PLAYERS = 8;
private static final ForgePreferences prefs = FModel.getPreferences(); private static final ForgePreferences prefs = FModel.getPreferences();

View File

@@ -6,40 +6,18 @@ import java.util.List;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.apache.commons.lang3.StringUtils;
import forge.FThreads; import forge.FThreads;
import forge.GuiBase;
import forge.assets.FSkinProp;
import forge.gui.FNetOverlay; import forge.gui.FNetOverlay;
import forge.gui.SOverlayUtils; import forge.gui.SOverlayUtils;
import forge.gui.framework.EDocID; import forge.gui.framework.EDocID;
import forge.gui.framework.ICDoc; import forge.gui.framework.ICDoc;
import forge.interfaces.IGuiGame;
import forge.interfaces.ILobbyListener;
import forge.interfaces.IPlayerChangeListener;
import forge.interfaces.IUpdateable;
import forge.match.GameLobby.GameLobbyData;
import forge.menus.IMenuProvider; import forge.menus.IMenuProvider;
import forge.menus.MenuUtil; import forge.menus.MenuUtil;
import forge.model.FModel; import forge.net.NetConnectUtil;
import forge.net.IRemote;
import forge.net.client.ClientGameLobby;
import forge.net.client.FGameClient;
import forge.net.event.IdentifiableNetEvent;
import forge.net.event.MessageEvent;
import forge.net.event.NetEvent;
import forge.net.event.UpdateLobbyPlayerEvent;
import forge.net.server.FServerManager;
import forge.net.server.ServerGameLobby;
import forge.player.GamePlayerUtil;
import forge.properties.ForgePreferences.FPref;
import forge.properties.ForgeProfileProperties;
import forge.screens.home.CHomeUI; import forge.screens.home.CHomeUI;
import forge.screens.home.CLobby; import forge.screens.home.CLobby;
import forge.screens.home.VLobby; import forge.screens.home.VLobby;
import forge.screens.home.sanctioned.ConstructedGameMenu; import forge.screens.home.sanctioned.ConstructedGameMenu;
import forge.util.gui.SOptionPane;
public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider { public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
SINGLETON_INSTANCE; SINGLETON_INSTANCE;
@@ -52,14 +30,9 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
} }
void connectToServer() { void connectToServer() {
final String url = SOptionPane.showInputDialog("Enter URL of server to join. Leave blank to host your own server.", "Connect to Server"); final String url = NetConnectUtil.getServerUrl();
if (url == null) { return; } if (url == null) { return; }
//prompt user for player one name if needed
if (StringUtils.isBlank(FModel.getPreferences().getPref(FPref.PLAYER_NAME))) {
GamePlayerUtil.setPlayerName();
}
FThreads.invokeInBackgroundThread(new Runnable() { FThreads.invokeInBackgroundThread(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -82,66 +55,13 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
} }
}); });
final int port = ForgeProfileProperties.getServerPort(); final String result = NetConnectUtil.host(VSubmenuOnlineLobby.SINGLETON_INSTANCE, FNetOverlay.SINGLETON_INSTANCE);
final FServerManager server = FServerManager.getInstance();
final ServerGameLobby lobby = new ServerGameLobby();
final VLobby view = VSubmenuOnlineLobby.SINGLETON_INSTANCE.setLobby(lobby);
server.startServer(port);
server.setLobby(lobby);
lobby.setListener(new IUpdateable() {
@Override
public final void update(final boolean fullUpdate) {
view.update(fullUpdate);
server.updateLobbyState();
}
});
view.setPlayerChangeListener(new IPlayerChangeListener() {
@Override
public final void update(final int index, final UpdateLobbyPlayerEvent event) {
server.updateSlot(index, event);
server.updateLobbyState();
}
});
server.setLobbyListener(new ILobbyListener() {
@Override
public final void update(final GameLobbyData state, final int slot) {
// NO-OP, lobby connected directly
}
@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) {
if (event instanceof MessageEvent) {
final MessageEvent message = (MessageEvent) event;
FNetOverlay.SINGLETON_INSTANCE.addMessage(message.getSource(), message.getMessage());
server.broadcast(event);
}
}
@Override
public final Object sendAndWait(final IdentifiableNetEvent event) {
send(event);
return null;
}
});
view.update(true);
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
SOverlayUtils.hideOverlay(); SOverlayUtils.hideOverlay();
FNetOverlay.SINGLETON_INSTANCE.show(String.format("Hosting on port %d", port)); FNetOverlay.SINGLETON_INSTANCE.show(result);
if (CHomeUI.SINGLETON_INSTANCE.getCurrentDocID() == EDocID.HOME_NETWORK) { if (CHomeUI.SINGLETON_INSTANCE.getCurrentDocID() == EDocID.HOME_NETWORK) {
VSubmenuOnlineLobby.SINGLETON_INSTANCE.populate(); VSubmenuOnlineLobby.SINGLETON_INSTANCE.populate();
} }
@@ -158,61 +78,13 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
} }
}); });
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame(); final String result = NetConnectUtil.join(url, VSubmenuOnlineLobby.SINGLETON_INSTANCE, FNetOverlay.SINGLETON_INSTANCE);
final FGameClient client = new FGameClient(FModel.getPreferences().getPref(FPref.PLAYER_NAME), "0", gui);
VSubmenuOnlineLobby.SINGLETON_INSTANCE.setClient(client);
FNetOverlay.SINGLETON_INSTANCE.setGameClient(client);
final ClientGameLobby lobby = new ClientGameLobby();
final VLobby view = VSubmenuOnlineLobby.SINGLETON_INSTANCE.setLobby(lobby);
lobby.setListener(view);
client.addLobbyListener(new ILobbyListener() {
@Override
public final void message(final String source, final String message) {
FNetOverlay.SINGLETON_INSTANCE.addMessage(source, message);
}
@Override
public final void update(final GameLobbyData state, final int slot) {
lobby.setLocalPlayer(slot);
lobby.setData(state);
}
@Override
public final void close() {
SOptionPane.showMessageDialog("Connection to the host was interrupted.", "Error", FSkinProp.ICO_WARNING);
VSubmenuOnlineLobby.SINGLETON_INSTANCE.setClient(null);
}
});
view.setPlayerChangeListener(new IPlayerChangeListener() {
@Override
public final void update(final int index, final UpdateLobbyPlayerEvent event) {
client.send(event);
}
});
final String hostname;
int port0 = ForgeProfileProperties.getServerPort();
//see if port specified in URL
int index = url.indexOf(':');
if (index >= 0) {
hostname = url.substring(0, index);
String portStr = url.substring(index + 1);
try {
port0 = Integer.parseInt(portStr);
}
catch (Exception ex) {}
}
else {
hostname = url;
}
final int port = port0;
client.connect(hostname, port);
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
SOverlayUtils.hideOverlay(); SOverlayUtils.hideOverlay();
FNetOverlay.SINGLETON_INSTANCE.show(String.format("Connected to %s:%d", hostname, port)); FNetOverlay.SINGLETON_INSTANCE.show(result);
if (CHomeUI.SINGLETON_INSTANCE.getCurrentDocID() == EDocID.HOME_NETWORK) { if (CHomeUI.SINGLETON_INSTANCE.getCurrentDocID() == EDocID.HOME_NETWORK) {
VSubmenuOnlineLobby.SINGLETON_INSTANCE.populate(); VSubmenuOnlineLobby.SINGLETON_INSTANCE.populate();
} }

View File

@@ -15,7 +15,9 @@ import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID; import forge.gui.framework.EDocID;
import forge.gui.framework.FScreen; import forge.gui.framework.FScreen;
import forge.gui.framework.IVTopLevelUI; import forge.gui.framework.IVTopLevelUI;
import forge.interfaces.ILobbyView;
import forge.match.GameLobby; import forge.match.GameLobby;
import forge.net.IOnlineLobby;
import forge.net.client.FGameClient; import forge.net.client.FGameClient;
import forge.net.server.FServerManager; import forge.net.server.FServerManager;
import forge.screens.home.EMenuGroup; import forge.screens.home.EMenuGroup;
@@ -26,7 +28,7 @@ import forge.toolbox.FButton;
import forge.toolbox.FSkin; import forge.toolbox.FSkin;
import forge.util.gui.SOptionPane; import forge.util.gui.SOptionPane;
public enum VSubmenuOnlineLobby implements IVSubmenu<CSubmenuOnlineLobby>, IVTopLevelUI { public enum VSubmenuOnlineLobby implements IVSubmenu<CSubmenuOnlineLobby>, IOnlineLobby, IVTopLevelUI {
SINGLETON_INSTANCE; SINGLETON_INSTANCE;
private DragCell parentCell; private DragCell parentCell;
@@ -37,13 +39,13 @@ public enum VSubmenuOnlineLobby implements IVSubmenu<CSubmenuOnlineLobby>, IVTop
private VSubmenuOnlineLobby() { private VSubmenuOnlineLobby() {
} }
VLobby setLobby(final GameLobby lobby) { public ILobbyView setLobby(final GameLobby lobby) {
this.lobby = new VLobby(lobby); this.lobby = new VLobby(lobby);
getLayoutControl().setLobby(this.lobby); getLayoutControl().setLobby(this.lobby);
return this.lobby; return this.lobby;
} }
void setClient(final FGameClient client) { public void setClient(final FGameClient client) {
this.client = client; this.client = client;
} }

View File

@@ -0,0 +1,5 @@
package forge.interfaces;
public interface ILobbyView extends IUpdateable {
void setPlayerChangeListener(IPlayerChangeListener iPlayerChangeListener);
}

View File

@@ -0,0 +1,6 @@
package forge.net;
public interface IOnlineChatInterface {
void setGameClient(IRemote iRemote);
void addMessage(String source, String message);
}

View File

@@ -0,0 +1,10 @@
package forge.net;
import forge.interfaces.ILobbyView;
import forge.match.GameLobby;
import forge.net.client.FGameClient;
public interface IOnlineLobby {
ILobbyView setLobby(GameLobby lobby);
void setClient(FGameClient client);
}

View File

@@ -0,0 +1,149 @@
package forge.net;
import org.apache.commons.lang3.StringUtils;
import forge.GuiBase;
import forge.assets.FSkinProp;
import forge.interfaces.IGuiGame;
import forge.interfaces.ILobbyListener;
import forge.interfaces.ILobbyView;
import forge.interfaces.IPlayerChangeListener;
import forge.interfaces.IUpdateable;
import forge.match.GameLobby.GameLobbyData;
import forge.model.FModel;
import forge.net.client.ClientGameLobby;
import forge.net.client.FGameClient;
import forge.net.event.IdentifiableNetEvent;
import forge.net.event.MessageEvent;
import forge.net.event.NetEvent;
import forge.net.event.UpdateLobbyPlayerEvent;
import forge.net.server.FServerManager;
import forge.net.server.ServerGameLobby;
import forge.player.GamePlayerUtil;
import forge.properties.ForgeProfileProperties;
import forge.properties.ForgePreferences.FPref;
import forge.util.gui.SOptionPane;
public class NetConnectUtil {
private NetConnectUtil() { }
public static String getServerUrl() {
final String url = SOptionPane.showInputDialog("Enter URL of server to join. Leave blank to host your own server.", "Connect to Server");
if (url == null) { return null; }
//prompt user for player one name if needed
if (StringUtils.isBlank(FModel.getPreferences().getPref(FPref.PLAYER_NAME))) {
GamePlayerUtil.setPlayerName();
}
return url;
}
public static String host(final IOnlineLobby onlineLobby, final IOnlineChatInterface chatInterface) {
final int port = ForgeProfileProperties.getServerPort();
final FServerManager server = FServerManager.getInstance();
final ServerGameLobby lobby = new ServerGameLobby();
final ILobbyView view = onlineLobby.setLobby(lobby);
server.startServer(port);
server.setLobby(lobby);
lobby.setListener(new IUpdateable() {
@Override
public final void update(final boolean fullUpdate) {
view.update(fullUpdate);
server.updateLobbyState();
}
});
view.setPlayerChangeListener(new IPlayerChangeListener() {
@Override
public final void update(final int index, final UpdateLobbyPlayerEvent event) {
server.updateSlot(index, event);
server.updateLobbyState();
}
});
server.setLobbyListener(new ILobbyListener() {
@Override
public final void update(final GameLobbyData state, final int slot) {
// NO-OP, lobby connected directly
}
@Override
public final void message(final String source, final String message) {
chatInterface.addMessage(source, message);
}
@Override
public final void close() {
// NO-OP, server can't receive close message
}
});
chatInterface.setGameClient(new IRemote() {
@Override
public final void send(final NetEvent event) {
if (event instanceof MessageEvent) {
final MessageEvent message = (MessageEvent) event;
chatInterface.addMessage(message.getSource(), message.getMessage());
server.broadcast(event);
}
}
@Override
public final Object sendAndWait(final IdentifiableNetEvent event) {
send(event);
return null;
}
});
view.update(true);
return String.format("Hosting on port %d", port);
}
public static String join(final String url, final IOnlineLobby onlineLobby, final IOnlineChatInterface chatInterface) {
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame();
final FGameClient client = new FGameClient(FModel.getPreferences().getPref(FPref.PLAYER_NAME), "0", gui);
onlineLobby.setClient(client);
chatInterface.setGameClient(client);
final ClientGameLobby lobby = new ClientGameLobby();
final ILobbyView view = onlineLobby.setLobby(lobby);
lobby.setListener(view);
client.addLobbyListener(new ILobbyListener() {
@Override
public final void message(final String source, final String message) {
chatInterface.addMessage(source, message);
}
@Override
public final void update(final GameLobbyData state, final int slot) {
lobby.setLocalPlayer(slot);
lobby.setData(state);
}
@Override
public final void close() {
SOptionPane.showMessageDialog("Connection to the host was interrupted.", "Error", FSkinProp.ICO_WARNING);
onlineLobby.setClient(null);
}
});
view.setPlayerChangeListener(new IPlayerChangeListener() {
@Override
public final void update(final int index, final UpdateLobbyPlayerEvent event) {
client.send(event);
}
});
String hostname = url;
int port = ForgeProfileProperties.getServerPort();
//see if port specified in URL
int index = url.indexOf(':');
if (index >= 0) {
hostname = url.substring(0, index);
String portStr = url.substring(index + 1);
try {
port = Integer.parseInt(portStr);
}
catch (Exception ex) {}
}
client.connect(hostname, port);
return String.format("Connected to %s:%d", hostname, port);
}
}