Workaround to get JavaFX multiplayer working
This commit is contained in:
parent
075b19cede
commit
394f75cd6e
@ -1,7 +1,9 @@
|
||||
# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
|
||||
|
||||
# Development
|
||||
web.socket.url: ws://localhost:8080/stomp
|
||||
web.base.url: http://localhost:8080
|
||||
web.socket.url: ws://localhost:8080/sockjs
|
||||
|
||||
# Production
|
||||
#web.socket.url: ws://lingo.charego.com/stomp
|
||||
#web.base.url: http://lingo.charego.com
|
||||
#web.socket.url: ws://lingo.charego.com/sockjs
|
||||
|
@ -3,14 +3,17 @@ package lingo.client.multiplayer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.web.client.RootUriTemplateHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.messaging.converter.ByteArrayMessageConverter;
|
||||
import org.springframework.messaging.converter.CompositeMessageConverter;
|
||||
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
|
||||
import org.springframework.messaging.converter.MessageConverter;
|
||||
import org.springframework.messaging.converter.StringMessageConverter;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.socket.client.WebSocketClient;
|
||||
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
|
||||
import org.springframework.web.socket.messaging.WebSocketStompClient;
|
||||
@ -47,4 +50,11 @@ public class MultiplayerConfig {
|
||||
return new CompositeMessageConverter(converters);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(Environment env) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
restTemplate.setUriTemplateHandler(new RootUriTemplateHandler(env.getProperty("web.base.url")));
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package lingo.client.multiplayer;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
@ -10,9 +12,12 @@ import javax.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.messaging.simp.stomp.StompFrameHandler;
|
||||
import org.springframework.messaging.simp.stomp.StompHeaders;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
@ -35,6 +40,7 @@ import lingo.client.view.Board;
|
||||
import lingo.client.view.OpponentBoard;
|
||||
import lingo.client.view.PlayerBoard;
|
||||
import lingo.common.Game;
|
||||
import lingo.common.GameLeftMessage;
|
||||
import lingo.common.Report;
|
||||
|
||||
@Component
|
||||
@ -59,6 +65,9 @@ public class MultiplayerPresenter implements FxmlController {
|
||||
@Autowired
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
private StompTemplate stompTemplate;
|
||||
|
||||
@ -72,7 +81,11 @@ public class MultiplayerPresenter implements FxmlController {
|
||||
|
||||
private OpponentBoard opponentBoard;
|
||||
|
||||
private final CountDownLatch subscriptionsLatch = new CountDownLatch(4);
|
||||
private final CountDownLatch subscriptionsLatch = new CountDownLatch(7);
|
||||
|
||||
private String username;
|
||||
|
||||
private String opponentUsername;
|
||||
|
||||
private void clearBoards(boolean clearScore) {
|
||||
playerBoard.clearBoard();
|
||||
@ -123,7 +136,22 @@ public class MultiplayerPresenter implements FxmlController {
|
||||
ok.printStackTrace();
|
||||
}
|
||||
}
|
||||
stompTemplate.getSession().send("/app/lingo/join", null);
|
||||
|
||||
username = UUID.randomUUID().toString().substring(0, 8);
|
||||
stompTemplate.getSession().send("/app/setUsername", username);
|
||||
|
||||
Collection<Game> games = restTemplate.exchange("/games", HttpMethod.GET, null, new GameList()).getBody();
|
||||
boolean joinedGame = false;
|
||||
for (Game game : games) {
|
||||
if (game.getPlayerTwo() == null) {
|
||||
stompTemplate.getSession().send("/app/joinGame", game.getId());
|
||||
joinedGame = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!joinedGame) {
|
||||
stompTemplate.getSession().send("/app/hostGame", null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -137,7 +165,7 @@ public class MultiplayerPresenter implements FxmlController {
|
||||
} else if (keyCode == KeyCode.ENTER) {
|
||||
final String guess = playerBoard.handleEnter();
|
||||
if (guess != null) {
|
||||
executorService.execute(() -> stompTemplate.getSession().send("/app/lingo/guess", guess));
|
||||
executorService.execute(() -> stompTemplate.getSession().send("/app/guess", guess));
|
||||
repaint();
|
||||
}
|
||||
} else if (keyCode.isLetterKey()) {
|
||||
@ -154,10 +182,16 @@ public class MultiplayerPresenter implements FxmlController {
|
||||
@PostConstruct
|
||||
private void postConstruct() {
|
||||
executorService.execute(() -> {
|
||||
stompTemplate.subscribe(Destinations.GAME_CLOSED, new GameClosedHandler(),
|
||||
subscription -> subscriptionsLatch.countDown());
|
||||
stompTemplate.subscribe(Destinations.GAME_HOSTED, new GameHostedHandler(),
|
||||
subscription -> subscriptionsLatch.countDown());
|
||||
stompTemplate.subscribe(Destinations.GAME_JOINED, new GameJoinedHandler(),
|
||||
subscription -> subscriptionsLatch.countDown());
|
||||
stompTemplate.subscribe(Destinations.GAME_LEFT, new GameLeftHandler(),
|
||||
subscription -> subscriptionsLatch.countDown());
|
||||
stompTemplate.subscribe("/user" + Destinations.OPPONENT_JOINED, new OpponentJoinedHandler(),
|
||||
subscription -> subscriptionsLatch.countDown());
|
||||
//stompTemplate.subscribe("/user" + Destinations.OPPONENT_LEFT, new OpponentLeftHandler(),
|
||||
// subscription -> subscriptionsLatch.countDown());
|
||||
stompTemplate.subscribe("/user" + Destinations.OPPONENT_REPORTS, new OpponentReportHandler(),
|
||||
subscription -> subscriptionsLatch.countDown());
|
||||
stompTemplate.subscribe("/user" + Destinations.PLAYER_REPORTS, new PlayerReportHandler(),
|
||||
@ -185,16 +219,100 @@ public class MultiplayerPresenter implements FxmlController {
|
||||
}
|
||||
}
|
||||
|
||||
private class GameClosedHandler implements StompFrameHandler {
|
||||
|
||||
@Override
|
||||
public Type getPayloadType(StompHeaders headers) {
|
||||
return Game.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFrame(StompHeaders headers, Object payload) {
|
||||
handleMessage((Game) payload);
|
||||
}
|
||||
|
||||
private void handleMessage(Game game) {
|
||||
log.debug("{} closed Game {}", game.getPlayerOne(), game.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private class GameHostedHandler implements StompFrameHandler {
|
||||
|
||||
@Override
|
||||
public Type getPayloadType(StompHeaders headers) {
|
||||
return Game.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFrame(StompHeaders headers, Object payload) {
|
||||
handleMessage((Game) payload);
|
||||
}
|
||||
|
||||
private void handleMessage(Game game) {
|
||||
log.debug("{} hosted Game {}", game.getPlayerOne(), game.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private class GameJoinedHandler implements StompFrameHandler {
|
||||
|
||||
@Override
|
||||
public Type getPayloadType(StompHeaders headers) {
|
||||
return Game.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFrame(StompHeaders headers, Object payload) {
|
||||
handleMessage((Game) payload);
|
||||
}
|
||||
|
||||
private void handleMessage(Game game) {
|
||||
log.debug("{} joined {}'s game", game.getPlayerTwo(), game.getPlayerOne());
|
||||
}
|
||||
}
|
||||
|
||||
private class GameLeftHandler implements StompFrameHandler {
|
||||
|
||||
@Override
|
||||
public Type getPayloadType(StompHeaders headers) {
|
||||
return GameLeftMessage.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFrame(StompHeaders headers, Object payload) {
|
||||
handleMessage((GameLeftMessage) payload);
|
||||
}
|
||||
|
||||
private void handleMessage(GameLeftMessage message) {
|
||||
final Game game = message.getGame();
|
||||
final String gameLeaver = message.getGameLeaver().getUsername();
|
||||
log.debug("{} left {}'s game", gameLeaver, game.getPlayerOne());
|
||||
if (gameLeaver.equals(username) || gameLeaver.equals(opponentUsername)) {
|
||||
Platform.runLater(() -> {
|
||||
clearBoards(true);
|
||||
showWaitingAnimation(true);
|
||||
opponentUsername = null;
|
||||
lastWord = null;
|
||||
repaint();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OpponentJoinedHandler implements StompFrameHandler {
|
||||
|
||||
@Override
|
||||
public Type getPayloadType(StompHeaders headers) {
|
||||
return String.class;
|
||||
return String[].class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFrame(StompHeaders headers, Object payload) {
|
||||
final String firstLetter = payload.toString();
|
||||
handleMessage((String[]) payload);
|
||||
}
|
||||
|
||||
private void handleMessage(String[] message) {
|
||||
final String firstLetter = message[0];
|
||||
opponentUsername = message[1];
|
||||
Platform.runLater(() -> {
|
||||
clearBoards(true);
|
||||
newWord(firstLetter);
|
||||
@ -204,24 +322,6 @@ public class MultiplayerPresenter implements FxmlController {
|
||||
}
|
||||
}
|
||||
|
||||
private class OpponentLeftHandler implements StompFrameHandler {
|
||||
|
||||
@Override
|
||||
public Type getPayloadType(StompHeaders headers) {
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFrame(StompHeaders headers, Object payload) {
|
||||
Platform.runLater(() -> {
|
||||
clearBoards(true);
|
||||
showWaitingAnimation(true);
|
||||
lastWord = null;
|
||||
repaint();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class OpponentReportHandler implements StompFrameHandler {
|
||||
|
||||
@Override
|
||||
@ -319,4 +419,8 @@ public class MultiplayerPresenter implements FxmlController {
|
||||
}
|
||||
}
|
||||
|
||||
private class GameList extends ParameterizedTypeReference<Collection<Game>> {
|
||||
// intentionally left empty
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
<VBox spacing="20" alignment="CENTER">
|
||||
<children>
|
||||
<Button text="Practice" onAction="#showSinglePlayer" prefWidth="350" styleClass="game-mode" />
|
||||
<Button text="Multiplayer" onAction="#showMultiplayer" prefWidth="350" styleClass="game-mode" disable="true" />
|
||||
<Button text="Multiplayer" onAction="#showMultiplayer" prefWidth="350" styleClass="game-mode" />
|
||||
</children>
|
||||
</VBox>
|
||||
</center>
|
||||
|
@ -18,7 +18,7 @@ public class Game {
|
||||
|
||||
private static final AtomicInteger idCounter = new AtomicInteger(0);
|
||||
|
||||
public final int id;
|
||||
private int id;
|
||||
|
||||
private Player playerOne;
|
||||
|
||||
@ -32,6 +32,10 @@ public class Game {
|
||||
|
||||
private int wordIndex = 0;
|
||||
|
||||
public Game() {
|
||||
// Empty constructor required for serialization
|
||||
}
|
||||
|
||||
public Game(Player host) {
|
||||
this.id = idCounter.incrementAndGet();
|
||||
this.playerOne = host;
|
||||
@ -87,6 +91,10 @@ public class Game {
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Player getPlayerOne() {
|
||||
return playerOne;
|
||||
}
|
||||
@ -110,6 +118,10 @@ public class Game {
|
||||
this.acceptableGuesses = value;
|
||||
}
|
||||
|
||||
public void setId(int value) {
|
||||
this.id = value;
|
||||
}
|
||||
|
||||
public void setPlayerOne(Player value) {
|
||||
this.playerOne = value;
|
||||
}
|
||||
|
@ -5,10 +5,14 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
public class Player {
|
||||
|
||||
@JsonIgnore
|
||||
private final String sessionId;
|
||||
private String sessionId;
|
||||
|
||||
private String username;
|
||||
|
||||
public Player() {
|
||||
// Empty constructor required for serialization
|
||||
}
|
||||
|
||||
public Player(String sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
@ -121,9 +121,9 @@ public class LingoController {
|
||||
return;
|
||||
}
|
||||
final Game game = new Game(player);
|
||||
gameById.put(game.id, game);
|
||||
gameById.put(game.getId(), game);
|
||||
gameByPlayer.put(player, game);
|
||||
log.info("{} hosted Game {}", player, game.id);
|
||||
log.info("{} hosted Game {}", player, game.getId());
|
||||
send(Destinations.GAME_HOSTED, game);
|
||||
}
|
||||
|
||||
@ -198,8 +198,8 @@ public class LingoController {
|
||||
if (playerOne == player) {
|
||||
if (playerTwo == null) {
|
||||
// Close the game
|
||||
log.info("{} closed Game {}", player, game.id);
|
||||
gameById.remove(game.id);
|
||||
log.info("{} closed Game {}", player, game.getId());
|
||||
gameById.remove(game.getId());
|
||||
send(Destinations.GAME_CLOSED, game);
|
||||
} else {
|
||||
// Leave the game
|
||||
|
@ -357,7 +357,6 @@ function start() {
|
||||
client.subscribe('/topic/gameJoined', onGameJoined);
|
||||
client.subscribe('/topic/gameLeft', onGameLeft);
|
||||
client.subscribe('/user/topic/opponentJoined', onOpponentJoined);
|
||||
client.subscribe('/user/topic/opponentLeft', onOpponentLeft);
|
||||
client.subscribe('/user/topic/opponentReports', onOpponentReport);
|
||||
client.subscribe('/user/topic/playerReports', onPlayerReport);
|
||||
}
|
||||
@ -495,7 +494,9 @@ function onGameLeft(message) {
|
||||
vm.gameId = null;
|
||||
}
|
||||
if (previousPlayers.indexOf(vm.username) != -1) {
|
||||
onOpponentLeft();
|
||||
vm.opponentUsername = null;
|
||||
vm.lastWord = null;
|
||||
vm.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@ -508,12 +509,6 @@ function onOpponentJoined(message) {
|
||||
vm.repaint();
|
||||
}
|
||||
|
||||
function onOpponentLeft(message) {
|
||||
vm.opponentUsername = null;
|
||||
vm.lastWord = null;
|
||||
vm.repaint();
|
||||
}
|
||||
|
||||
function onOpponentReport(message) {
|
||||
var report = JSON.parse(message.body);
|
||||
if (report.correct === true) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user