Make game offers, withdrawals (untested) and requests work
git-svn-id: svn://sunsvr01.isp.uni-luebeck.de/swproj13/trunk@408 72836036-5685-4462-b002-a69064685172
This commit is contained in:
parent
e176dc4608
commit
630cdea1d9
3 changed files with 254 additions and 31 deletions
|
@ -1,19 +1,36 @@
|
||||||
package jrummikub.control.network;
|
package jrummikub.control.network;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
import jrummikub.util.Event;
|
import jrummikub.util.Event;
|
||||||
|
import jrummikub.util.Event1;
|
||||||
import jrummikub.util.IEvent;
|
import jrummikub.util.IEvent;
|
||||||
|
import jrummikub.util.IEvent1;
|
||||||
import jrummikub.util.LoginData;
|
import jrummikub.util.LoginData;
|
||||||
|
import jrummikub.view.IGameListPanel.GameData;
|
||||||
|
|
||||||
import org.jivesoftware.smack.Connection;
|
import org.jivesoftware.smack.Connection;
|
||||||
|
import org.jivesoftware.smack.PacketListener;
|
||||||
import org.jivesoftware.smack.XMPPConnection;
|
import org.jivesoftware.smack.XMPPConnection;
|
||||||
import org.jivesoftware.smack.XMPPException;
|
import org.jivesoftware.smack.XMPPException;
|
||||||
|
import org.jivesoftware.smack.filter.AndFilter;
|
||||||
|
import org.jivesoftware.smack.filter.PacketExtensionFilter;
|
||||||
|
import org.jivesoftware.smack.filter.PacketTypeFilter;
|
||||||
|
import org.jivesoftware.smack.packet.DefaultPacketExtension;
|
||||||
|
import org.jivesoftware.smack.packet.Message;
|
||||||
|
import org.jivesoftware.smack.packet.Packet;
|
||||||
|
import org.jivesoftware.smack.packet.PacketExtension;
|
||||||
import org.jivesoftware.smack.packet.XMPPError;
|
import org.jivesoftware.smack.packet.XMPPError;
|
||||||
import org.jivesoftware.smack.packet.XMPPError.Type;
|
import org.jivesoftware.smack.packet.XMPPError.Type;
|
||||||
|
import org.jivesoftware.smackx.muc.DiscussionHistory;
|
||||||
import org.jivesoftware.smackx.muc.MultiUserChat;
|
import org.jivesoftware.smackx.muc.MultiUserChat;
|
||||||
|
|
||||||
class ConnectionControl {
|
class ConnectionControl {
|
||||||
|
private final static String ELEMENT_NAME = "rummikub";
|
||||||
|
private final static String NAMESPACE = "http://home.universe-factory.net/rummikub/";
|
||||||
|
|
||||||
private final LoginData loginData;
|
private final LoginData loginData;
|
||||||
private volatile Connection connection;
|
private volatile Connection connection;
|
||||||
private volatile MultiUserChat muc;
|
private volatile MultiUserChat muc;
|
||||||
|
@ -21,6 +38,11 @@ class ConnectionControl {
|
||||||
private Event connectedEvent = new Event();
|
private Event connectedEvent = new Event();
|
||||||
private Event connectionFailedEvent = new Event();
|
private Event connectionFailedEvent = new Event();
|
||||||
|
|
||||||
|
private Event1<GameData> gameOfferEvent = new Event1<GameData>();
|
||||||
|
private Event1<UUID> gameWithdrawalEvent = new Event1<UUID>();
|
||||||
|
|
||||||
|
private volatile GameData offeredGame;
|
||||||
|
|
||||||
ConnectionControl(LoginData loginData) {
|
ConnectionControl(LoginData loginData) {
|
||||||
this.loginData = loginData;
|
this.loginData = loginData;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +66,30 @@ class ConnectionControl {
|
||||||
return connectionFailedEvent;
|
return connectionFailedEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IEvent1<GameData> getGameOfferEvent() {
|
||||||
|
return gameOfferEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEvent1<UUID> getGameWithdrawalEvent() {
|
||||||
|
return gameWithdrawalEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void offerGame(GameData data) {
|
||||||
|
offeredGame = data;
|
||||||
|
|
||||||
|
sendGameOffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void withdrawGame(UUID uuid) {
|
||||||
|
offeredGame = null;
|
||||||
|
|
||||||
|
new Thread(new SendGameWithdrawRunner(uuid)).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendGameOffer() {
|
||||||
|
new Thread(new SendGameOfferRunner(offeredGame)).start();
|
||||||
|
}
|
||||||
|
|
||||||
private static void emitLater(final Event event) {
|
private static void emitLater(final Event event) {
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,40 +99,97 @@ class ConnectionControl {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Message createMessage(PacketExtension extension) {
|
||||||
|
Message message = muc.createMessage();
|
||||||
|
message.addExtension(extension);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DefaultPacketExtension createJRummikubExtension() {
|
||||||
|
return new DefaultPacketExtension(ELEMENT_NAME, NAMESPACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processPacket(Packet packet) {
|
||||||
|
DefaultPacketExtension extension = (DefaultPacketExtension) packet
|
||||||
|
.getExtension(ELEMENT_NAME, NAMESPACE);
|
||||||
|
|
||||||
|
String messageType = extension.getValue("messageType");
|
||||||
|
|
||||||
|
if (messageType.equals("game_offer")) {
|
||||||
|
String host = packet.getFrom();
|
||||||
|
host = host.substring(host.indexOf('/') + 1);
|
||||||
|
|
||||||
|
UUID uuid = UUID.fromString(extension.getValue("uuid"));
|
||||||
|
int currentPlayerCount = Integer.parseInt(extension
|
||||||
|
.getValue("currentPlayerCount"));
|
||||||
|
int maxPlayerCount = Integer.parseInt(extension
|
||||||
|
.getValue("maxPlayerCount"));
|
||||||
|
|
||||||
|
GameData gameData = new GameData(uuid, host);
|
||||||
|
gameData.setCurrentPlayerCount(currentPlayerCount);
|
||||||
|
gameData.setMaxPlayerCount(maxPlayerCount);
|
||||||
|
gameOfferEvent.emit(gameData);
|
||||||
|
} else if (messageType.equals("game_withdrawal")) {
|
||||||
|
gameWithdrawalEvent.emit(UUID.fromString(extension.getValue("uuid")));
|
||||||
|
} else if (messageType.equals("game_request")) {
|
||||||
|
if (offeredGame != null) {
|
||||||
|
sendGameOffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message createGameOfferMessage(GameData data) {
|
||||||
|
DefaultPacketExtension extension = createJRummikubExtension();
|
||||||
|
|
||||||
|
extension.setValue("messageType", "game_offer");
|
||||||
|
extension.setValue("uuid", data.getGameID().toString());
|
||||||
|
extension.setValue("currentPlayerCount",
|
||||||
|
Integer.toString(data.getCurrentPlayerCount()));
|
||||||
|
extension.setValue("maxPlayerCount",
|
||||||
|
Integer.toString(data.getMaxPlayerCount()));
|
||||||
|
|
||||||
|
return createMessage(extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message createGameWithdrawMessage(UUID uuid) {
|
||||||
|
DefaultPacketExtension extension = createJRummikubExtension();
|
||||||
|
|
||||||
|
extension.setValue("messageType", "game_withdrawal");
|
||||||
|
extension.setValue("uuid", uuid.toString());
|
||||||
|
|
||||||
|
return createMessage(extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message createGameRequestMessage() {
|
||||||
|
DefaultPacketExtension extension = createJRummikubExtension();
|
||||||
|
|
||||||
|
extension.setValue("messageType", "game_request");
|
||||||
|
|
||||||
|
return createMessage(extension);
|
||||||
|
}
|
||||||
|
|
||||||
private class ConnectRunner implements Runnable {
|
private class ConnectRunner implements Runnable {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (ConnectionControl.this) {
|
synchronized (ConnectionControl.this) {
|
||||||
connection = new XMPPConnection(loginData.getServerName());
|
connection = new XMPPConnection(loginData.getServerName());
|
||||||
try {
|
|
||||||
connection.connect();
|
|
||||||
connection.login(loginData.getUserName(),
|
|
||||||
loginData.getPassword(), "JRummikub");
|
|
||||||
muc = new MultiUserChat(connection,
|
|
||||||
loginData.getChannelName());
|
|
||||||
|
|
||||||
String nickname = loginData.getUserName();
|
connection.addPacketListener(new PacketListener() {
|
||||||
// Loop until a unused nickname is found
|
@Override
|
||||||
while (true) {
|
public void processPacket(final Packet packet) {
|
||||||
try {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
muc.join(nickname);
|
@Override
|
||||||
break; // Join was successful, break the loop
|
public void run() {
|
||||||
} catch (XMPPException e) {
|
ConnectionControl.this.processPacket(packet);
|
||||||
XMPPError error = e.getXMPPError();
|
|
||||||
if (error.getType() == Type.CANCEL
|
|
||||||
&& error.getCode() == 409) {
|
|
||||||
// There was a conflict, try again with another
|
|
||||||
// nickname
|
|
||||||
nickname += "_";
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
// An unknown error has occurred, cancel connect
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
emitLater(connectedEvent);
|
}
|
||||||
|
}, new AndFilter(new PacketTypeFilter(Message.class),
|
||||||
|
new PacketExtensionFilter(ELEMENT_NAME, NAMESPACE)));
|
||||||
|
|
||||||
|
try {
|
||||||
|
doConnect();
|
||||||
} catch (XMPPException e) {
|
} catch (XMPPException e) {
|
||||||
connection.disconnect();
|
connection.disconnect();
|
||||||
connection = null;
|
connection = null;
|
||||||
|
@ -98,6 +201,84 @@ class ConnectionControl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void doConnect() throws XMPPException {
|
||||||
|
connection.connect();
|
||||||
|
connection.login(loginData.getUserName(), loginData.getPassword(),
|
||||||
|
"JRummikub");
|
||||||
|
muc = new MultiUserChat(connection, loginData.getChannelName());
|
||||||
|
DiscussionHistory history = new DiscussionHistory();
|
||||||
|
history.setMaxStanzas(0);
|
||||||
|
|
||||||
|
String nickname = loginData.getUserName();
|
||||||
|
// Loop until a unused nickname is found
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
muc.join(nickname, null, history, 10000);
|
||||||
|
break; // Join was successful, break the loop
|
||||||
|
} catch (XMPPException e) {
|
||||||
|
XMPPError error = e.getXMPPError();
|
||||||
|
if (error.getType() == Type.CANCEL && error.getCode() == 409) {
|
||||||
|
// There was a conflict, try again with another
|
||||||
|
// nickname
|
||||||
|
nickname += "_";
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// An unknown error has occurred, cancel connect
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emitLater(connectedEvent);
|
||||||
|
|
||||||
|
new Thread(new SendGameRequestRunner()).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SendGameOfferRunner implements Runnable {
|
||||||
|
private GameData data;
|
||||||
|
|
||||||
|
public SendGameOfferRunner(GameData data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
synchronized (ConnectionControl.this) {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.sendPacket(createGameOfferMessage(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SendGameWithdrawRunner implements Runnable {
|
||||||
|
private UUID uuid;
|
||||||
|
|
||||||
|
public SendGameWithdrawRunner(UUID uuid) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
synchronized (ConnectionControl.this) {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.sendPacket(createGameWithdrawMessage(uuid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SendGameRequestRunner implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
synchronized (ConnectionControl.this) {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.sendPacket(createGameRequestMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DisconnectRunner implements Runnable {
|
private class DisconnectRunner implements Runnable {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package jrummikub.control.network;
|
package jrummikub.control.network;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import jrummikub.util.Connection;
|
import jrummikub.util.Connection;
|
||||||
|
@ -20,6 +22,8 @@ public class NetworkControl {
|
||||||
private List<Connection> connections = new ArrayList<Connection>();
|
private List<Connection> connections = new ArrayList<Connection>();
|
||||||
private Event stopNetworkEvent = new Event();
|
private Event stopNetworkEvent = new Event();
|
||||||
|
|
||||||
|
private Map<UUID, GameData> gameMap = new HashMap<UUID, GameData>();
|
||||||
|
|
||||||
public NetworkControl(final LoginData loginData, final IView view) {
|
public NetworkControl(final LoginData loginData, final IView view) {
|
||||||
this.view = view;
|
this.view = view;
|
||||||
connectionControl = new ConnectionControl(loginData);
|
connectionControl = new ConnectionControl(loginData);
|
||||||
|
@ -33,7 +37,8 @@ public class NetworkControl {
|
||||||
GameData testData = new GameData(UUID.randomUUID(), "NeoRaider");
|
GameData testData = new GameData(UUID.randomUUID(), "NeoRaider");
|
||||||
testData.setCurrentPlayerCount(2);
|
testData.setCurrentPlayerCount(2);
|
||||||
testData.setMaxPlayerCount(4);
|
testData.setMaxPlayerCount(4);
|
||||||
view.getGameListPanel().addGame(testData);
|
|
||||||
|
connectionControl.offerGame(testData);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -46,6 +51,36 @@ public class NetworkControl {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
connections.add(connectionControl.getGameOfferEvent().add(
|
||||||
|
new IListener1<IGameListPanel.GameData>() {
|
||||||
|
@Override
|
||||||
|
public void handle(GameData value) {
|
||||||
|
GameData game = gameMap.get(value.getGameID());
|
||||||
|
|
||||||
|
if (game == null) {
|
||||||
|
game = value;
|
||||||
|
gameMap.put(value.getGameID(), value);
|
||||||
|
} else {
|
||||||
|
game.setCurrentPlayerCount(value.getCurrentPlayerCount());
|
||||||
|
game.setMaxPlayerCount(value.getMaxPlayerCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
view.getGameListPanel().addGame(game);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
connections.add(connectionControl.getGameWithdrawalEvent().add(
|
||||||
|
new IListener1<UUID>() {
|
||||||
|
@Override
|
||||||
|
public void handle(UUID value) {
|
||||||
|
GameData game = gameMap.get(value);
|
||||||
|
|
||||||
|
if (game != null) {
|
||||||
|
view.getGameListPanel().removeGame(game);
|
||||||
|
gameMap.remove(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
connections.add(view.getGameListPanel().getJoinEvent()
|
connections.add(view.getGameListPanel().getJoinEvent()
|
||||||
.add(new IListener1<IGameListPanel.GameData>() {
|
.add(new IListener1<IGameListPanel.GameData>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,7 +4,6 @@ import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.GridBagConstraints;
|
import java.awt.GridBagConstraints;
|
||||||
import java.awt.GridBagLayout;
|
import java.awt.GridBagLayout;
|
||||||
import java.awt.GridLayout;
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -163,16 +162,24 @@ class GameListPanel extends JPanel implements IGameListPanel {
|
||||||
JLabel hostLabel, playerCountLabel;
|
JLabel hostLabel, playerCountLabel;
|
||||||
|
|
||||||
GameDataCellRenderer() {
|
GameDataCellRenderer() {
|
||||||
setLayout(new GridLayout(1, 2));
|
setLayout(new GridBagLayout());
|
||||||
|
GridBagConstraints c = new GridBagConstraints();
|
||||||
|
c.fill = GridBagConstraints.BOTH;
|
||||||
|
c.gridwidth = 1;
|
||||||
|
c.weightx = 1;
|
||||||
|
c.weighty = 1;
|
||||||
|
|
||||||
hostLabel = new JLabel();
|
hostLabel = new JLabel();
|
||||||
hostLabel.setOpaque(true);
|
hostLabel.setOpaque(true);
|
||||||
hostLabel.setHorizontalAlignment(JLabel.LEFT);
|
hostLabel.setHorizontalAlignment(JLabel.LEFT);
|
||||||
add(hostLabel);
|
add(hostLabel, c);
|
||||||
|
|
||||||
playerCountLabel = new JLabel();
|
playerCountLabel = new JLabel();
|
||||||
playerCountLabel.setOpaque(true);
|
playerCountLabel.setOpaque(true);
|
||||||
playerCountLabel.setHorizontalAlignment(JLabel.RIGHT);
|
playerCountLabel.setHorizontalAlignment(JLabel.RIGHT);
|
||||||
add(playerCountLabel);
|
|
||||||
|
c.gridwidth = GridBagConstraints.REMAINDER;
|
||||||
|
add(playerCountLabel, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Reference in a new issue