Create practice controller, add skip button
This commit is contained in:
parent
fc849d2b0d
commit
84c47862d5
@ -24,6 +24,8 @@ public class Destinations {
|
|||||||
|
|
||||||
public static final String PRACTICE_REPORTS = topicDestination("practiceReports");
|
public static final String PRACTICE_REPORTS = topicDestination("practiceReports");
|
||||||
|
|
||||||
|
public static final String PRACTICE_WORD_SKIPPED = topicDestination("practiceWordSkipped");
|
||||||
|
|
||||||
public static final String SESSION_USERNAME = topicDestination("sessionUsername");
|
public static final String SESSION_USERNAME = topicDestination("sessionUsername");
|
||||||
|
|
||||||
public static final String USER_JOINED = topicDestination("userJoined");
|
public static final String USER_JOINED = topicDestination("userJoined");
|
||||||
|
@ -9,10 +9,11 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationListener;
|
|
||||||
import org.springframework.messaging.MessageHeaders;
|
import org.springframework.messaging.MessageHeaders;
|
||||||
import org.springframework.messaging.handler.annotation.Header;
|
import org.springframework.messaging.handler.annotation.Header;
|
||||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||||
@ -20,12 +21,8 @@ import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
|||||||
import org.springframework.messaging.simp.SimpMessageType;
|
import org.springframework.messaging.simp.SimpMessageType;
|
||||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
import org.springframework.messaging.simp.annotation.SubscribeMapping;
|
import org.springframework.messaging.simp.annotation.SubscribeMapping;
|
||||||
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.socket.messaging.AbstractSubProtocolEvent;
|
|
||||||
import org.springframework.web.socket.messaging.SessionConnectedEvent;
|
|
||||||
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
|
|
||||||
|
|
||||||
import lingo.client.api.Destinations;
|
import lingo.client.api.Destinations;
|
||||||
import lingo.common.ChatMessage;
|
import lingo.common.ChatMessage;
|
||||||
@ -36,13 +33,16 @@ import lingo.common.Report;
|
|||||||
import lingo.common.SetUsernameMessage;
|
import lingo.common.SetUsernameMessage;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
public class LingoController implements ApplicationListener<AbstractSubProtocolEvent> {
|
public class LingoController {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(LingoController.class);
|
private static final Logger log = LoggerFactory.getLogger(LingoController.class);
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SimpMessagingTemplate messagingTemplate;
|
private SimpMessagingTemplate messagingTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SessionManager sessionManager;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private WordRepository wordRepo;
|
private WordRepository wordRepo;
|
||||||
|
|
||||||
@ -50,15 +50,11 @@ public class LingoController implements ApplicationListener<AbstractSubProtocolE
|
|||||||
|
|
||||||
private final Map<Player, Game> gameByPlayer = new HashMap<>();
|
private final Map<Player, Game> gameByPlayer = new HashMap<>();
|
||||||
|
|
||||||
private final Map<Player, Game> practiceByPlayer = new HashMap<>();
|
|
||||||
|
|
||||||
private final Map<String, Player> playerBySession = new HashMap<>();
|
|
||||||
|
|
||||||
private final Set<String> usernames = new HashSet<>();
|
private final Set<String> usernames = new HashSet<>();
|
||||||
|
|
||||||
@MessageMapping("/chat")
|
@MessageMapping("/chat")
|
||||||
public ChatMessage chat(String message, @Header(SESSION_ID_HEADER) String sessionId) {
|
public ChatMessage chat(String message, @Header(SESSION_ID_HEADER) String sessionId) {
|
||||||
final Player player = playerBySession.get(sessionId);
|
final Player player = sessionManager.getPlayer(sessionId);
|
||||||
final String username = player.getUsername();
|
final String username = player.getUsername();
|
||||||
if (username == null) {
|
if (username == null) {
|
||||||
log.warn("No username for session {}", sessionId);
|
log.warn("No username for session {}", sessionId);
|
||||||
@ -74,7 +70,7 @@ public class LingoController implements ApplicationListener<AbstractSubProtocolE
|
|||||||
|
|
||||||
@MessageMapping("/guess")
|
@MessageMapping("/guess")
|
||||||
public void guess(String guess, @Header(SESSION_ID_HEADER) String sessionId) {
|
public void guess(String guess, @Header(SESSION_ID_HEADER) String sessionId) {
|
||||||
final Player player = playerBySession.get(sessionId);
|
final Player player = sessionManager.getPlayer(sessionId);
|
||||||
final String username = player.getUsername();
|
final String username = player.getUsername();
|
||||||
if (username == null) {
|
if (username == null) {
|
||||||
log.warn("No username for session {}", sessionId);
|
log.warn("No username for session {}", sessionId);
|
||||||
@ -114,7 +110,7 @@ public class LingoController implements ApplicationListener<AbstractSubProtocolE
|
|||||||
|
|
||||||
@MessageMapping("/hostGame")
|
@MessageMapping("/hostGame")
|
||||||
public synchronized void hostGame(@Header(SESSION_ID_HEADER) String sessionId) {
|
public synchronized void hostGame(@Header(SESSION_ID_HEADER) String sessionId) {
|
||||||
final Player player = playerBySession.get(sessionId);
|
final Player player = sessionManager.getPlayer(sessionId);
|
||||||
final String username = player.getUsername();
|
final String username = player.getUsername();
|
||||||
if (username == null) {
|
if (username == null) {
|
||||||
log.warn("No username for session {}", sessionId);
|
log.warn("No username for session {}", sessionId);
|
||||||
@ -133,7 +129,7 @@ public class LingoController implements ApplicationListener<AbstractSubProtocolE
|
|||||||
|
|
||||||
@MessageMapping("/joinGame")
|
@MessageMapping("/joinGame")
|
||||||
public synchronized void joinGame(Integer gameId, @Header(SESSION_ID_HEADER) String sessionId) {
|
public synchronized void joinGame(Integer gameId, @Header(SESSION_ID_HEADER) String sessionId) {
|
||||||
final Player player = playerBySession.get(sessionId);
|
final Player player = sessionManager.getPlayer(sessionId);
|
||||||
final String username = player.getUsername();
|
final String username = player.getUsername();
|
||||||
if (username == null) {
|
if (username == null) {
|
||||||
log.warn("No username for session {}", sessionId);
|
log.warn("No username for session {}", sessionId);
|
||||||
@ -171,8 +167,7 @@ public class LingoController implements ApplicationListener<AbstractSubProtocolE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void leave(String sessionId) {
|
private synchronized void leave(Player player) {
|
||||||
final Player player = playerBySession.remove(sessionId);
|
|
||||||
final String username = player.getUsername();
|
final String username = player.getUsername();
|
||||||
usernames.remove(username);
|
usernames.remove(username);
|
||||||
final Game game = gameByPlayer.remove(player);
|
final Game game = gameByPlayer.remove(player);
|
||||||
@ -188,7 +183,7 @@ public class LingoController implements ApplicationListener<AbstractSubProtocolE
|
|||||||
|
|
||||||
@MessageMapping("/leaveGame")
|
@MessageMapping("/leaveGame")
|
||||||
public synchronized void leaveGame(@Header(SESSION_ID_HEADER) String sessionId) {
|
public synchronized void leaveGame(@Header(SESSION_ID_HEADER) String sessionId) {
|
||||||
final Player player = playerBySession.get(sessionId);
|
final Player player = sessionManager.getPlayer(sessionId);
|
||||||
final Game game = gameByPlayer.remove(player);
|
final Game game = gameByPlayer.remove(player);
|
||||||
if (game == null) {
|
if (game == null) {
|
||||||
log.warn("{} is not in a game", player);
|
log.warn("{} is not in a game", player);
|
||||||
@ -218,67 +213,14 @@ public class LingoController implements ApplicationListener<AbstractSubProtocolE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onApplicationEvent(AbstractSubProtocolEvent event) {
|
|
||||||
if (event instanceof SessionConnectedEvent) {
|
|
||||||
onSessionConnected((SessionConnectedEvent) event);
|
|
||||||
} else if (event instanceof SessionDisconnectEvent) {
|
|
||||||
onSessionDisconnect((SessionDisconnectEvent) event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onSessionConnected(SessionConnectedEvent event) {
|
|
||||||
final String sessionId = StompHeaderAccessor.wrap(event.getMessage()).getSessionId();
|
|
||||||
log.info("Session connected: {}", sessionId);
|
|
||||||
playerBySession.put(sessionId, new Player(sessionId));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onSessionDisconnect(SessionDisconnectEvent event) {
|
|
||||||
final String sessionId = event.getSessionId();
|
|
||||||
log.info("Session disconnected: {}", sessionId);
|
|
||||||
leave(sessionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeMapping("/topic/sessionId")
|
@SubscribeMapping("/topic/sessionId")
|
||||||
public String onSessionId(@Header(SESSION_ID_HEADER) String sessionId) {
|
public String onSessionId(@Header(SESSION_ID_HEADER) String sessionId) {
|
||||||
return sessionId;
|
return sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@MessageMapping("/practiceGame")
|
@PostConstruct
|
||||||
public void practiceGame(@Header(SESSION_ID_HEADER) String sessionId) {
|
public void postConstruct() {
|
||||||
final Player player = playerBySession.get(sessionId);
|
sessionManager.addListener(new PlayerLeftListener());
|
||||||
log.info("{} wants a practice session", sessionId);
|
|
||||||
final Game game = new Game(player);
|
|
||||||
game.setAcceptableGuesses(wordRepo.getGuesses());
|
|
||||||
game.setPossibleWords(wordRepo.getWords());
|
|
||||||
practiceByPlayer.put(player, game);
|
|
||||||
final String firstWord = game.newGame();
|
|
||||||
final String firstLetter = String.valueOf(firstWord.charAt(0));
|
|
||||||
log.info("First word: {}", firstWord);
|
|
||||||
sendToPlayer(player, Destinations.PRACTICE_GAME, firstLetter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MessageMapping("/practiceGuess")
|
|
||||||
public void practiceGuess(String guess, @Header(SESSION_ID_HEADER) String sessionId) {
|
|
||||||
final Player player = playerBySession.get(sessionId);
|
|
||||||
guess = guess.toUpperCase();
|
|
||||||
log.info("{} guessed {}", player, guess);
|
|
||||||
final Game game = practiceByPlayer.get(player);
|
|
||||||
final int[] result = game.evaluate(guess);
|
|
||||||
|
|
||||||
// Generate report
|
|
||||||
final Report report = new Report();
|
|
||||||
report.setGuess(guess);
|
|
||||||
if (Game.isCorrect(result)) {
|
|
||||||
final String newWord = game.newWord();
|
|
||||||
final String firstLetter = String.valueOf(newWord.charAt(0));
|
|
||||||
log.info("New word: {}", newWord);
|
|
||||||
report.setCorrect(true);
|
|
||||||
report.setFirstLetter(firstLetter);
|
|
||||||
} else {
|
|
||||||
report.setResult(result);
|
|
||||||
}
|
|
||||||
sendToPlayer(player, Destinations.PRACTICE_REPORTS, report);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void send(String destination, Object payload) {
|
private void send(String destination, Object payload) {
|
||||||
@ -300,12 +242,12 @@ public class LingoController implements ApplicationListener<AbstractSubProtocolE
|
|||||||
|
|
||||||
@MessageMapping("/setUsername")
|
@MessageMapping("/setUsername")
|
||||||
public synchronized void setUsername(String username, @Header(SESSION_ID_HEADER) String sessionId) {
|
public synchronized void setUsername(String username, @Header(SESSION_ID_HEADER) String sessionId) {
|
||||||
final Player player = playerBySession.get(sessionId);
|
final Player player = sessionManager.getPlayer(sessionId);
|
||||||
if (usernames.add(username)) {
|
if (usernames.add(username)) {
|
||||||
player.setUsername(username);
|
player.setUsername(username);
|
||||||
log.info("{} --> {}", sessionId, username);
|
log.info("{} --> {}", sessionId, username);
|
||||||
sendToPlayer(player, Destinations.SESSION_USERNAME, new SetUsernameMessage(true, username, null));
|
sendToPlayer(player, Destinations.SESSION_USERNAME, new SetUsernameMessage(true, username, null));
|
||||||
send(Destinations.USER_JOINED, new Object[] { username, playerBySession.size() });
|
send(Destinations.USER_JOINED, new Object[] { username, sessionManager.getPlayerCount() });
|
||||||
} else {
|
} else {
|
||||||
log.warn("{} -/> {} : Username taken", sessionId, username);
|
log.warn("{} -/> {} : Username taken", sessionId, username);
|
||||||
final SetUsernameMessage response = new SetUsernameMessage(false, null, "Username taken");
|
final SetUsernameMessage response = new SetUsernameMessage(false, null, "Username taken");
|
||||||
@ -313,4 +255,18 @@ public class LingoController implements ApplicationListener<AbstractSubProtocolE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class PlayerLeftListener implements SessionManager.Listener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void playerJoined(Player player) {
|
||||||
|
// Ignore joining players for now
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void playerLeft(Player player) {
|
||||||
|
leave(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
100
server/src/main/java/lingo/server/PracticeController.java
Normal file
100
server/src/main/java/lingo/server/PracticeController.java
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package lingo.server;
|
||||||
|
|
||||||
|
import static org.springframework.messaging.simp.SimpMessageHeaderAccessor.SESSION_ID_HEADER;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.messaging.MessageHeaders;
|
||||||
|
import org.springframework.messaging.handler.annotation.Header;
|
||||||
|
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||||
|
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||||
|
import org.springframework.messaging.simp.SimpMessageType;
|
||||||
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import lingo.client.api.Destinations;
|
||||||
|
import lingo.common.Game;
|
||||||
|
import lingo.common.Player;
|
||||||
|
import lingo.common.Report;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class PracticeController {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(PracticeController.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SimpMessagingTemplate messagingTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SessionManager sessionManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WordRepository wordRepo;
|
||||||
|
|
||||||
|
private final Map<Player, Game> practiceByPlayer = new HashMap<>();
|
||||||
|
|
||||||
|
@MessageMapping("/practiceGame")
|
||||||
|
public void practiceGame(@Header(SESSION_ID_HEADER) String sessionId) {
|
||||||
|
final Player player = sessionManager.getPlayer(sessionId);
|
||||||
|
log.info("{} is practicing", sessionId);
|
||||||
|
final Game game = new Game(player);
|
||||||
|
game.setAcceptableGuesses(wordRepo.getGuesses());
|
||||||
|
game.setPossibleWords(wordRepo.getWords());
|
||||||
|
practiceByPlayer.put(player, game);
|
||||||
|
final String firstWord = game.newGame();
|
||||||
|
final String firstLetter = String.valueOf(firstWord.charAt(0));
|
||||||
|
log.info("First word: {}", firstWord);
|
||||||
|
sendToPlayer(player, Destinations.PRACTICE_GAME, firstLetter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MessageMapping("/practiceGuess")
|
||||||
|
public void practiceGuess(String guess, @Header(SESSION_ID_HEADER) String sessionId) {
|
||||||
|
final Player player = sessionManager.getPlayer(sessionId);
|
||||||
|
guess = guess.toUpperCase();
|
||||||
|
log.info("{} guessed {}", player, guess);
|
||||||
|
final Game game = practiceByPlayer.get(player);
|
||||||
|
final int[] result = game.evaluate(guess);
|
||||||
|
|
||||||
|
// Generate report
|
||||||
|
final Report report = new Report();
|
||||||
|
report.setGuess(guess);
|
||||||
|
if (Game.isCorrect(result)) {
|
||||||
|
final String newWord = game.newWord();
|
||||||
|
final String firstLetter = String.valueOf(newWord.charAt(0));
|
||||||
|
log.info("New word: {}", newWord);
|
||||||
|
report.setCorrect(true);
|
||||||
|
report.setFirstLetter(firstLetter);
|
||||||
|
} else {
|
||||||
|
report.setResult(result);
|
||||||
|
}
|
||||||
|
sendToPlayer(player, Destinations.PRACTICE_REPORTS, report);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MessageMapping("/practiceSkip")
|
||||||
|
public void practiceSkip(@Header(SESSION_ID_HEADER) String sessionId) {
|
||||||
|
final Player player = sessionManager.getPlayer(sessionId);
|
||||||
|
final Game game = practiceByPlayer.get(player);
|
||||||
|
final String newWord = game.newWord();
|
||||||
|
final String firstLetter = String.valueOf(newWord.charAt(0));
|
||||||
|
log.info("New word: {}", newWord);
|
||||||
|
sendToPlayer(player, Destinations.PRACTICE_WORD_SKIPPED, firstLetter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendToPlayer(Player player, String destination, Object payload) {
|
||||||
|
sendToSession(player.getSessionId(), destination, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendToSession(String sessionId, String destination, Object payload) {
|
||||||
|
// TODO: cache the headers?
|
||||||
|
final SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
|
||||||
|
headerAccessor.setSessionId(sessionId);
|
||||||
|
headerAccessor.setLeaveMutable(true);
|
||||||
|
final MessageHeaders headers = headerAccessor.getMessageHeaders();
|
||||||
|
messagingTemplate.convertAndSendToUser(sessionId, destination, payload, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
85
server/src/main/java/lingo/server/SessionManager.java
Normal file
85
server/src/main/java/lingo/server/SessionManager.java
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package lingo.server;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.socket.messaging.AbstractSubProtocolEvent;
|
||||||
|
import org.springframework.web.socket.messaging.SessionConnectedEvent;
|
||||||
|
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
|
||||||
|
|
||||||
|
import lingo.common.Player;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class SessionManager implements ApplicationListener<AbstractSubProtocolEvent> {
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
void playerJoined(Player player);
|
||||||
|
void playerLeft(Player player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SessionManager.class);
|
||||||
|
|
||||||
|
private final Map<String, Player> playerBySession = new HashMap<>();
|
||||||
|
|
||||||
|
private final Set<Listener> listeners = new HashSet<>();
|
||||||
|
|
||||||
|
public void addListener(Listener listener) {
|
||||||
|
synchronized (listeners) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer(String sessionId) {
|
||||||
|
return playerBySession.get(sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPlayerCount() {
|
||||||
|
return playerBySession.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onApplicationEvent(AbstractSubProtocolEvent event) {
|
||||||
|
if (event instanceof SessionConnectedEvent) {
|
||||||
|
onSessionConnected((SessionConnectedEvent) event);
|
||||||
|
} else if (event instanceof SessionDisconnectEvent) {
|
||||||
|
onSessionDisconnect((SessionDisconnectEvent) event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSessionConnected(SessionConnectedEvent event) {
|
||||||
|
final String sessionId = StompHeaderAccessor.wrap(event.getMessage()).getSessionId();
|
||||||
|
final Player player = new Player(sessionId);
|
||||||
|
log.info("Player connected: {}", player);
|
||||||
|
playerBySession.put(sessionId, player);
|
||||||
|
synchronized (listeners) {
|
||||||
|
for (Listener listener : listeners) {
|
||||||
|
listener.playerJoined(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSessionDisconnect(SessionDisconnectEvent event) {
|
||||||
|
final String sessionId = event.getSessionId();
|
||||||
|
final Player player = playerBySession.remove(sessionId);
|
||||||
|
log.info("Player disconnected: {}", player);
|
||||||
|
synchronized (listeners) {
|
||||||
|
for (Listener listener : listeners) {
|
||||||
|
listener.playerLeft(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener(Listener listener) {
|
||||||
|
synchronized (listeners) {
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,24 @@
|
|||||||
canvas {
|
canvas {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#skipDiv {
|
||||||
|
margin-top: 20px;
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
|
||||||
|
#skipButton {
|
||||||
|
width: 200px;
|
||||||
|
font-size: 28px;
|
||||||
|
font-variant: small-caps;
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 10px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="canvas" width="300" height="400"></canvas>
|
<canvas id="canvas" width="300" height="400"></canvas>
|
||||||
|
<div id="skipDiv" class="hidden">
|
||||||
|
<button id="skipButton" type="button">Skip Word</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.1/sockjs.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.1/sockjs.min.js"></script>
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
|
<script src="//cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
|
||||||
|
@ -27,6 +27,7 @@ function start() {
|
|||||||
|
|
||||||
addKeydownListener();
|
addKeydownListener();
|
||||||
addKeypressListener();
|
addKeypressListener();
|
||||||
|
addSkipButtonListener();
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
repaint();
|
repaint();
|
||||||
@ -36,6 +37,7 @@ function start() {
|
|||||||
client.connect({}, function(frame) {
|
client.connect({}, function(frame) {
|
||||||
subscribeToPracticeGame();
|
subscribeToPracticeGame();
|
||||||
subscribeToPracticeReports();
|
subscribeToPracticeReports();
|
||||||
|
subscribeToPracticeWordSkipped();
|
||||||
client.send('/app/practiceGame');
|
client.send('/app/practiceGame');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -77,6 +79,13 @@ function addKeypressListener() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip button
|
||||||
|
function addSkipButtonListener() {
|
||||||
|
document.getElementById('skipButton').addEventListener('click', function(e) {
|
||||||
|
client.send("/app/practiceSkip");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function drawMyBoard() {
|
function drawMyBoard() {
|
||||||
var x = 25, y = MARGIN_TOP;
|
var x = 25, y = MARGIN_TOP;
|
||||||
drawScore(x, y, myScore);
|
drawScore(x, y, myScore);
|
||||||
@ -227,6 +236,7 @@ function subscribeToPracticeGame() {
|
|||||||
var firstLetter = message.body;
|
var firstLetter = message.body;
|
||||||
reset(firstLetter, true);
|
reset(firstLetter, true);
|
||||||
repaint();
|
repaint();
|
||||||
|
document.getElementById('skipDiv').classList.remove('hidden');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,4 +273,12 @@ function subscribeToPracticeReports() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function subscribeToPracticeWordSkipped() {
|
||||||
|
client.subscribe('/user/topic/practiceWordSkipped', function(message) {
|
||||||
|
var firstLetter = message.body;
|
||||||
|
reset(firstLetter, false);
|
||||||
|
repaint();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user