- Remove old net code

- Remove "Start/Stop Server" buttons (related to old code)
- Move new net code to forge-gui/forge/net/**
- Remove all dependencies on project forge-net
This commit is contained in:
elcnesh
2015-04-20 14:40:26 +00:00
parent 62a7b2b98d
commit 705d6cb937
41 changed files with 749 additions and 564 deletions

View File

@@ -1,7 +1,7 @@
package forge.interfaces;
import forge.match.GameLobby;
import forge.net.game.server.RemoteClient;
import forge.net.server.RemoteClient;
public interface ILobby {
GameLobby getState();

View File

@@ -1,6 +1,6 @@
package forge.interfaces;
import forge.net.game.UpdateLobbyPlayerEvent;
import forge.net.event.UpdateLobbyPlayerEvent;
public interface IPlayerChangeListener {
void update(int index, UpdateLobbyPlayerEvent event);

View File

@@ -30,8 +30,7 @@ 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.net.event.UpdateLobbyPlayerEvent;
import forge.player.GamePlayerUtil;
import forge.properties.ForgePreferences.FPref;
import forge.util.NameGenerator;

View File

@@ -7,8 +7,7 @@ import com.google.common.collect.ImmutableSet;
import forge.AIOption;
import forge.deck.Deck;
import forge.net.game.LobbySlotType;
import forge.net.game.UpdateLobbyPlayerEvent;
import forge.net.event.UpdateLobbyPlayerEvent;
public final class LobbySlot implements Serializable {
private static final long serialVersionUID = 6918205436608794289L;

View File

@@ -0,0 +1,8 @@
package forge.match;
public enum LobbySlotType {
LOCAL,
AI,
OPEN,
REMOTE;
}

View File

@@ -5,7 +5,6 @@ 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 {

View File

@@ -1,398 +0,0 @@
package forge.net;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
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 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.IdentifiableNetEvent;
import forge.net.game.LoginEvent;
import forge.net.game.MessageEvent;
import forge.net.game.NetEvent;
import forge.net.game.ReplyEvent;
import forge.net.game.client.IToServer;
import forge.player.PlayerZoneUpdates;
import forge.properties.ForgePreferences.FPref;
import forge.trackable.TrackableCollection;
import forge.util.ITriggerEvent;
public class FGameClient implements IToServer {
private final IGuiGame clientGui;
public FGameClient(final String username, final String roomKey, final IGuiGame clientGui) {
this.clientGui = clientGui;
}
private final List<ILobbyListener> lobbyListeners = Lists.newArrayList();
private final ReplyPool replies = new ReplyPool();
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
private Channel channel;
public void connect(final String host, final int port) {
final EventLoopGroup group = new NioEventLoopGroup();
try {
final Bootstrap b = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(final SocketChannel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(
new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new MessageHandler(),
new LobbyUpdateHandler(),
new GameClientHandler());
}
});
// Start the connection attempt.
channel = b.connect(host, port).sync().channel();
final ChannelFuture ch = channel.closeFuture();
new Thread(new Runnable() {
@Override public void run() {
try {
ch.sync();
} catch (final InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
}).start();
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
public void close() {
channel.close();
}
@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.
*/
public GameClientHandler() {
}
@Override
public void channelActive(final ChannelHandlerContext ctx) {
// Don't use send() here, as this.channel is not yet set!
ctx.channel().writeAndFlush(new LoginEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",")[0])));
}
@SuppressWarnings("unchecked")
@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
System.out.println("Client received: " + msg);
if (msg instanceof ReplyEvent) {
final ReplyEvent event = (ReplyEvent) msg;
replies.complete(event.getIndex(), event.getReply());
} else if (msg instanceof GuiGameEvent) {
final GuiGameEvent event = (GuiGameEvent) msg;
final String method = event.getMethod();
final Object[] args = event.getObjects();
Serializable reply = null;
boolean doReply = false;
final IButton btn;
if (method.startsWith("btn_") && 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 (method) {
case "setGameView":
clientGui.setGameView((GameView) args[0]);
break;
case "openView":
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((PlayerZoneUpdates) 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));
}
}
}
@Override
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
private class MessageHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
if (msg instanceof MessageEvent) {
final MessageEvent event = (MessageEvent) msg;
for (final ILobbyListener listener : lobbyListeners) {
listener.message(event.getSource(), event.getMessage());
}
}
super.channelRead(ctx, msg);
}
}
private class LobbyUpdateHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
if (msg instanceof LobbyUpdateEvent) {
for (final ILobbyListener listener : lobbyListeners) {
final LobbyUpdateEvent event = (LobbyUpdateEvent) msg;
listener.update(event.getState(), event.getSlot());
}
}
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

@@ -0,0 +1,11 @@
package forge.net;
import java.util.concurrent.TimeoutException;
import forge.net.event.IdentifiableNetEvent;
import forge.net.event.NetEvent;
public interface IRemote {
void send(NetEvent event);
Object sendAndWait(IdentifiableNetEvent event) throws TimeoutException;
}

View File

@@ -1,28 +0,0 @@
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;
}
}

View File

@@ -0,0 +1,57 @@
package forge.net;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.google.common.collect.Maps;
public class ReplyPool {
private final Map<Integer, CompletableFuture> pool = Maps.newHashMap();
public ReplyPool() {
}
public void initialize(final int index) {
synchronized (pool) {
pool.put(Integer.valueOf(index), new CompletableFuture());
}
}
public void complete(final int index, final Object value) {
synchronized (pool) {
pool.get(Integer.valueOf(index)).set(value);
}
}
public Object get(final int index) throws TimeoutException {
final CompletableFuture future;
synchronized (pool) {
future = pool.get(Integer.valueOf(index));
}
try {
return future.get(1, TimeUnit.MINUTES);
} catch (final InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
private static final class CompletableFuture extends FutureTask<Object> {
public CompletableFuture() {
super(new Callable<Object>() {
@Override public Object call() throws Exception {
return null;
}
});
}
@Override
public void set(final Object v) {
super.set(v);
}
}
}

View File

@@ -1,4 +1,4 @@
package forge.net;
package forge.net.client;
import forge.interfaces.IGuiGame;
import forge.match.GameLobby;

View File

@@ -0,0 +1,151 @@
package forge.net.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import java.util.List;
import java.util.concurrent.TimeoutException;
import com.google.common.collect.Lists;
import forge.game.player.PlayerView;
import forge.interfaces.IGuiGame;
import forge.interfaces.ILobbyListener;
import forge.net.ReplyPool;
import forge.net.event.IdentifiableNetEvent;
import forge.net.event.LobbyUpdateEvent;
import forge.net.event.MessageEvent;
import forge.net.event.NetEvent;
public class FGameClient implements IToServer {
private final IGuiGame clientGui;
private final List<ILobbyListener> lobbyListeners = Lists.newArrayList();
private final ReplyPool replies = new ReplyPool();
private Channel channel;
public FGameClient(final String username, final String roomKey, final IGuiGame clientGui) {
this.clientGui = clientGui;
}
final IGuiGame getGui() {
return clientGui;
}
final ReplyPool getReplyPool() {
return replies;
}
public void connect(final String host, final int port) {
final EventLoopGroup group = new NioEventLoopGroup();
try {
final Bootstrap b = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(final SocketChannel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(
new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new MessageHandler(),
new LobbyUpdateHandler(),
new GameClientHandler(FGameClient.this));
}
});
// Start the connection attempt.
channel = b.connect(host, port).sync().channel();
final ChannelFuture ch = channel.closeFuture();
new Thread(new Runnable() {
@Override public void run() {
try {
ch.sync();
} catch (final InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
}).start();
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
public void close() {
channel.close();
}
@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);
}
void setGameControllers(final Iterable<PlayerView> myPlayers) {
for (final PlayerView p : myPlayers) {
clientGui.setGameController(p, new NetGameController(this));
}
}
private class MessageHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
if (msg instanceof MessageEvent) {
final MessageEvent event = (MessageEvent) msg;
for (final ILobbyListener listener : lobbyListeners) {
listener.message(event.getSource(), event.getMessage());
}
}
super.channelRead(ctx, msg);
}
}
private class LobbyUpdateHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
if (msg instanceof LobbyUpdateEvent) {
for (final ILobbyListener listener : lobbyListeners) {
final LobbyUpdateEvent event = (LobbyUpdateEvent) msg;
listener.update(event.getState(), event.getSlot());
}
}
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

@@ -0,0 +1,268 @@
package forge.net.client;
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.match.MatchButtonType;
import forge.model.FModel;
import forge.net.event.GuiGameEvent;
import forge.net.event.LoginEvent;
import forge.net.event.ReplyEvent;
import forge.player.PlayerZoneUpdates;
import forge.properties.ForgePreferences.FPref;
import forge.trackable.TrackableCollection;
import forge.util.ITriggerEvent;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.google.common.base.Function;
class GameClientHandler extends ChannelInboundHandlerAdapter {
private final FGameClient client;
private final IGuiGame gui;
/**
* Creates a client-side game handler.
*/
public GameClientHandler(final FGameClient client) {
this.client = client;
this.gui = client.getGui();
}
@Override
public void channelActive(final ChannelHandlerContext ctx) {
// Don't use send() here, as this.channel is not yet set!
ctx.channel().writeAndFlush(new LoginEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",")[0])));
}
@SuppressWarnings("unchecked")
@Override
public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
System.out.println("Client received: " + msg);
if (msg instanceof ReplyEvent) {
final ReplyEvent event = (ReplyEvent) msg;
client.getReplyPool().complete(event.getIndex(), event.getReply());
} else if (msg instanceof GuiGameEvent) {
final GuiGameEvent event = (GuiGameEvent) msg;
final String method = event.getMethod();
final Object[] args = event.getObjects();
Serializable reply = null;
boolean doReply = false;
final IButton btn;
if (method.startsWith("btn_") && args.length >= 2 && args[0] instanceof PlayerView && args[1] instanceof MatchButtonType) {
btn = args[1] == MatchButtonType.OK ? gui.getBtnOK((PlayerView) args[0]) : gui.getBtnCancel((PlayerView) args[0]);
} else {
btn = null;
}
switch (method) {
case "setGameView":
gui.setGameView((GameView) args[0]);
break;
case "openView":
final TrackableCollection<PlayerView> myPlayers = (TrackableCollection<PlayerView>) args[0];
client.setGameControllers(myPlayers);
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public final void run() {
gui.openView(myPlayers);
}
});
break;
case "afterGameEnd":
gui.afterGameEnd();
break;
case "showCombat":
gui.showCombat();
break;
case "showPromptMessage":
gui.showPromptMessage((PlayerView) args[0], (String) args[1]);
break;
case "stopAtPhase":
reply = gui.stopAtPhase((PlayerView) args[0], (PhaseType) args[1]);
doReply = true;
break;
case "focusButton":
gui.focusButton((MatchButtonType) args[0]);
break;
case "flashIncorrectAction":
gui.flashIncorrectAction();
break;
case "updatePhase":
gui.updatePhase();
break;
case "updateTurn":
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public final void run() {
gui.updateTurn((PlayerView) args[0]);
}
});
break;
case "udpdatePlayerControl":
gui.updatePlayerControl();
break;
case "enableOverlay":
gui.enableOverlay();
break;
case "disbleOverlay":
gui.disableOverlay();
break;
case "finishGame":
gui.finishGame();
break;
case "showManaPool":
gui.showManaPool((PlayerView) args[0]);
break;
case "hideManaPool":
gui.hideManaPool((PlayerView) args[0], args[1]);
break;
case "updateStack":
gui.updateStack();
break;
case "updateZones":
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override public final void run() {
gui.updateZones((PlayerZoneUpdates) args[0]);
}
});
break;
case "updateSingleCard":
gui.updateSingleCard((CardView) args[0]);
break;
case "updateManaPool":
gui.updateManaPool((Iterable<PlayerView>) args[0]);
break;
case "updateLives":
gui.updateLives((Iterable<PlayerView>) args[0]);
break;
case "setPanelSelection":
gui.setPanelSelection((CardView) args[0]);
break;
case "getAbilityToPlay":
reply = gui.getAbilityToPlay((List<SpellAbilityView>) args[0], (ITriggerEvent) args[1]);
doReply = true;
break;
case "assignDamage":
reply = (Serializable) gui.assignDamage((CardView) args[0], (List<CardView>) args[1], (int) args[2], (GameEntityView) args[3], (boolean) args[4]);
doReply = true;
break;
case "message":
gui.message((String) args[0], (String) args[1]);
break;
case "showErrorDialog":
gui.showErrorDialog((String) args[0], (String) args[1]);
break;
case "showConfirmDialog":
reply = gui.showConfirmDialog((String) args[0], (String) args[1], (String) args[2], (String) args[3], (boolean) args[4]);
doReply = true;
break;
case "showOptionDialog":
reply = gui.showOptionDialog((String) args[0], (String) args[1], (FSkinProp) args[2], (String[]) args[3], (int) args[4]);
doReply = true;
break;
case "showCardOptionDialog":
reply = gui.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 = gui.showInputDialog((String) args[0], (String) args[1], (FSkinProp) args[2], (String) args[3], (String[]) args[4]);
doReply = true;
break;
case "confirm":
reply = gui.confirm((CardView) args[0], (String) args[1], (boolean) args[2], (String[]) args[3]);
doReply = true;
break;
case "getChoices":
reply = (Serializable) gui.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) gui.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) gui.sideboard((CardPool) args[0], (CardPool) args[1]);
doReply = true;
break;
case "chooseSingleEntityForEffect":
reply = gui.chooseSingleEntityForEffect((String) args[0], (TrackableCollection<GameEntityView>) args[1], (DelayedReveal) args[2], (boolean) args[3]);
doReply = true;
break;
case "setCard":
gui.setCard((CardView) args[0]);
break;
// TODO case "setPlayerAvatar":
case "openZones":
reply = gui.openZones((Collection<ZoneType>) args[0], (Map<PlayerView, Object>) args[1]);
doReply = true;
break;
case "restoreOldZones":
gui.restoreOldZones((Map<PlayerView, Object>) args[0]);
break;
case "isUiSetToSkipPhase":
reply = gui.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]);
}
break;
default:
System.err.println("Unsupported game event " + event.getMethod());
break;
}
if (doReply) {
client.send(new ReplyEvent(event.getId(), reply));
}
}
}
@Override
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

View File

@@ -0,0 +1,6 @@
package forge.net.client;
import forge.net.IRemote;
public interface IToServer extends IRemote {
}

View File

@@ -1,4 +1,4 @@
package forge.net;
package forge.net.client;
import java.util.List;
import java.util.concurrent.TimeoutException;
@@ -9,8 +9,7 @@ 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.net.event.GuiGameEvent;
import forge.util.ITriggerEvent;
public class NetGameController implements IGameController {

View File

@@ -0,0 +1 @@
package forge.net.client;

View File

@@ -0,0 +1,31 @@
package forge.net.event;
import java.io.Serializable;
import forge.net.server.RemoteClient;
public final class ReplyEvent implements NetEvent {
private static final long serialVersionUID = -2814651319617795386L;
private final int index;
private final Serializable reply;
public ReplyEvent(final int index, final Serializable reply) {
this.index = index;
this.reply = reply;
}
public int getIndex() {
return index;
}
public Object getReply() {
return reply;
}
@Override public void updateForClient(final RemoteClient client) {
}
@Override
public String toString() {
return String.format("Reply (%d): %s", index, reply);
}
}

View File

@@ -0,0 +1,83 @@
package forge.net.event;
import java.util.Collections;
import java.util.Set;
import forge.AIOption;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.match.LobbySlotType;
import forge.net.server.RemoteClient;
public final class UpdateLobbyPlayerEvent implements NetEvent {
private static final long serialVersionUID = -5073305607515425968L;
private final LobbySlotType type;
private final String name;
private final int avatarIndex;
private final int team;
private final Boolean isArchenemy;
private final Boolean isReady;
private final Deck deck;
private final DeckSection section;
private final CardPool cards;
private final Set<AIOption> aiOptions;
public static UpdateLobbyPlayerEvent create(final LobbySlotType type, final String name, final int avatarIndex, final int team, final boolean isArchenemy, final boolean isReady, final Set<AIOption> aiOptions) {
return new UpdateLobbyPlayerEvent(type, name, avatarIndex, team, isArchenemy, isReady, null, null, null, aiOptions);
}
public static UpdateLobbyPlayerEvent deckUpdate(final Deck deck) {
return new UpdateLobbyPlayerEvent(null, null, -1, -1, null, null, deck, null, null, null);
}
public static UpdateLobbyPlayerEvent deckUpdate(final DeckSection section, final CardPool cards) {
return new UpdateLobbyPlayerEvent(null, null, -1, -1, null, null, null, section, cards, null);
}
private UpdateLobbyPlayerEvent(final LobbySlotType type, final String name, final int avatarIndex, final int team, final Boolean isArchenemy, final Boolean isReady, final Deck deck, final DeckSection section, final CardPool cards, final Set<AIOption> aiOptions) {
this.type = type;
this.name = name;
this.avatarIndex = avatarIndex;
this.team = team;
this.isArchenemy = isArchenemy;
this.isReady = isReady;
this.deck = deck;
this.section = section;
this.cards = cards;
this.aiOptions = aiOptions;
}
public void updateForClient(final RemoteClient client) {
}
public LobbySlotType getType() {
return type;
}
public String getName() {
return name;
}
public int getAvatarIndex() {
return avatarIndex;
}
public int getTeam() {
return team;
}
public Boolean getArchenemy() {
return isArchenemy;
}
public Boolean getReady() {
return isReady;
}
public Deck getDeck() {
return deck;
}
public DeckSection getSection() {
return section;
}
public CardPool getCards() {
return cards;
}
public Set<AIOption> getAiOptions() {
return aiOptions == null ? null : Collections.unmodifiableSet(aiOptions);
}
}

View File

@@ -0,0 +1 @@
package forge.net.event;

View File

@@ -1,4 +1,4 @@
package forge.net;
package forge.net.server;
import forge.FThreads;
import forge.GuiBase;
@@ -11,16 +11,16 @@ import forge.interfaces.IGameController;
import forge.interfaces.IGuiGame;
import forge.interfaces.ILobbyListener;
import forge.match.LobbySlot;
import forge.match.LobbySlotType;
import forge.match.NextGameDecision;
import forge.net.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.ReplyEvent;
import forge.net.game.UpdateLobbyPlayerEvent;
import forge.net.game.server.RemoteClient;
import forge.net.event.GuiGameEvent;
import forge.net.event.LobbyUpdateEvent;
import forge.net.event.LoginEvent;
import forge.net.event.LogoutEvent;
import forge.net.event.MessageEvent;
import forge.net.event.NetEvent;
import forge.net.event.ReplyEvent;
import forge.net.event.UpdateLobbyPlayerEvent;
import forge.properties.ForgeConstants;
import forge.util.ITriggerEvent;
import io.netty.bootstrap.ServerBootstrap;
@@ -41,7 +41,7 @@ import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import java.io.Serializable;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Collections;
@@ -205,7 +205,7 @@ public final class FServerManager {
private void mapNatPort(final int port) {
final String localAddress;
try {
localAddress = Inet4Address.getLocalHost().getHostAddress();
localAddress = InetAddress.getLocalHost().getHostAddress();
} catch (final UnknownHostException e) {
throw new RuntimeException(e);
}
@@ -436,7 +436,7 @@ public final class FServerManager {
if (msg instanceof LoginEvent) {
final String username = ((LoginEvent) msg).getUsername();
client.setUsername(username);
broadcast(new MessageEvent(null, String.format("%s joined the room", username)));
broadcast(new MessageEvent(String.format("%s joined the room", username)));
updateLobbyState();
} else if (msg instanceof UpdateLobbyPlayerEvent) {
localLobby.applyToSlot(client.getIndex(), (UpdateLobbyPlayerEvent) msg);

View File

@@ -0,0 +1,6 @@
package forge.net.server;
import forge.net.IRemote;
public interface IToClient extends IRemote {
}

View File

@@ -1,4 +1,4 @@
package forge.net;
package forge.net.server;
import java.util.Collection;
import java.util.EnumMap;
@@ -26,8 +26,7 @@ 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.net.event.GuiGameEvent;
import forge.player.PlayerZoneUpdate;
import forge.trackable.TrackableCollection;
import forge.util.ITriggerEvent;

View File

@@ -0,0 +1,52 @@
package forge.net.server;
import forge.net.ReplyPool;
import forge.net.event.IdentifiableNetEvent;
import forge.net.event.NetEvent;
import io.netty.channel.Channel;
import java.util.concurrent.TimeoutException;
public final class RemoteClient implements IToClient {
private final Channel channel;
private String username;
private int index;
private ReplyPool replies = new ReplyPool();
public RemoteClient(final Channel channel) {
this.channel = channel;
}
@Override
public void send(final NetEvent event) {
System.out.println("Sending event " + event + " to " + channel);
channel.writeAndFlush(event);
}
@Override
public Object sendAndWait(final IdentifiableNetEvent event) throws TimeoutException {
replies.initialize(event.getId());
send(event);
return replies.get(event.getId());
}
public String getUsername() {
return username;
}
public void setUsername(final String username) {
this.username = username;
}
public int getIndex() {
return index;
}
public void setIndex(final int index) {
this.index = index;
}
public void setReply(final int id, final Object reply) {
replies.complete(id, reply);
}
}

View File

@@ -1,4 +1,4 @@
package forge.net;
package forge.net.server;
import java.util.Collections;
@@ -8,7 +8,7 @@ import forge.AIOption;
import forge.interfaces.IGuiGame;
import forge.match.GameLobby;
import forge.match.LobbySlot;
import forge.net.game.LobbySlotType;
import forge.match.LobbySlotType;
public final class ServerGameLobby extends GameLobby {

View File

@@ -0,0 +1 @@
package forge.net.server;