Ticket #14
parent
bb16c5fa03
commit
9c64f0397a
@ -1,4 +1,15 @@
|
|||||||
|
plugins {
|
||||||
|
id("org.springframework.boot").version("2.5.6")
|
||||||
|
//id("io.spring.dependency-management").version("1.0.7-RELEASE")
|
||||||
|
id("java")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":wizard-core"))
|
implementation(project(":wizard-core"))
|
||||||
|
implementation(project(":wizard-common"))
|
||||||
|
implementation("org.springframework.boot:spring-boot-starter-websocket:2.5.6")
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
package eu.jonahbauer.wizard.server;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.CreateSessionMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.SessionCreatedMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.SessionListMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.SessionRemovedMessage;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.Player;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
public class Lobby {
|
||||||
|
private static final Lobby INSTANCE = new Lobby();
|
||||||
|
public static Lobby getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<UUID, Session> sessions = new ConcurrentHashMap<>();
|
||||||
|
private final List<Player> players = new ArrayList<>();
|
||||||
|
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||||
|
|
||||||
|
private Lobby() {}
|
||||||
|
|
||||||
|
public Session createSession(CreateSessionMessage create) {
|
||||||
|
lock.readLock().lock();
|
||||||
|
try {
|
||||||
|
Session session;
|
||||||
|
do {
|
||||||
|
session = new Session(
|
||||||
|
UUID.randomUUID(),
|
||||||
|
create.getSessionName(),
|
||||||
|
create.getTimeout(),
|
||||||
|
create.getConfiguration()
|
||||||
|
);
|
||||||
|
} while (sessions.putIfAbsent(session.getUuid(), session) != null);
|
||||||
|
|
||||||
|
notifyPlayers(new SessionCreatedMessage(session.toData()));
|
||||||
|
|
||||||
|
return session;
|
||||||
|
} finally {
|
||||||
|
lock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Session getSession(UUID uuid) {
|
||||||
|
return sessions.get(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeSession(UUID uuid) {
|
||||||
|
lock.readLock().lock();
|
||||||
|
try {
|
||||||
|
sessions.remove(uuid);
|
||||||
|
notifyPlayers(new SessionRemovedMessage(uuid));
|
||||||
|
} finally {
|
||||||
|
lock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void join(Player player) {
|
||||||
|
lock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
players.add(player);
|
||||||
|
player.send(new SessionListMessage(sessions.values().stream().map(Session::toData).toList()));
|
||||||
|
} finally {
|
||||||
|
lock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void leave(Player player) {
|
||||||
|
lock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
players.remove(player);
|
||||||
|
} finally {
|
||||||
|
lock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyPlayers(ServerMessage message) {
|
||||||
|
lock.readLock().lock();
|
||||||
|
try {
|
||||||
|
for (Player player : players) {
|
||||||
|
player.send(message);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package eu.jonahbauer.wizard.server;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
|
||||||
|
import org.intellij.lang.annotations.MagicConstant;
|
||||||
|
|
||||||
|
public class NackException extends RuntimeException {
|
||||||
|
private final int code;
|
||||||
|
|
||||||
|
public NackException(@MagicConstant(valuesFromClass = NackMessage.class) int code, String message) {
|
||||||
|
super(message);
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
@MagicConstant(valuesFromClass = NackMessage.class)
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NackMessage toMessage() {
|
||||||
|
return new NackMessage(code, getMessage());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package eu.jonahbauer.wizard.server;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class Server {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Server.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,142 @@
|
|||||||
|
package eu.jonahbauer.wizard.server;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.common.messages.data.PlayerData;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.data.SessionData;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.*;
|
||||||
|
import eu.jonahbauer.wizard.common.model.Configuration;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.Player;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode(of = "uuid")
|
||||||
|
public class Session {
|
||||||
|
private static final int MIN_PLAYERS = 3;
|
||||||
|
private static final int MAX_PLAYERS = 6;
|
||||||
|
|
||||||
|
private final UUID uuid;
|
||||||
|
private final String name;
|
||||||
|
private final long timeout;
|
||||||
|
private final Configuration configuration;
|
||||||
|
|
||||||
|
@Getter(AccessLevel.NONE)
|
||||||
|
private final Map<UUID, SessionPlayer> players = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
public Session(UUID uuid, String name, long timeout, Configuration configuration) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.name = name;
|
||||||
|
this.timeout = timeout;
|
||||||
|
this.configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates the given player with this session, removes him from the lobby, notifies all other players in the
|
||||||
|
* session with a {@link PlayerJoinedMessage}, the joining player with a {@link SessionJoinedMessage} and all
|
||||||
|
* players in the lobby with a {@link SessionModifiedMessage}.
|
||||||
|
*
|
||||||
|
* @param player the player
|
||||||
|
* @param name the players chosen name
|
||||||
|
* @return the players uuid
|
||||||
|
*/
|
||||||
|
public synchronized UUID join(Player player, String name) {
|
||||||
|
if (players.size() == MAX_PLAYERS) {
|
||||||
|
throw new NackException(NackMessage.BAD_REQUEST, "Session is full.");
|
||||||
|
} else if (players.values().stream().anyMatch(p -> p.getName().equalsIgnoreCase(name))) {
|
||||||
|
throw new NackException(NackMessage.BAD_REQUEST, "Name is already taken.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Lobby.getInstance().leave(player);
|
||||||
|
|
||||||
|
SessionPlayer sessionPlayer;
|
||||||
|
do {
|
||||||
|
sessionPlayer = new SessionPlayer(UUID.randomUUID(), name, player);
|
||||||
|
} while (players.putIfAbsent(sessionPlayer.getUuid(), sessionPlayer) != null);
|
||||||
|
|
||||||
|
notifyJoined(sessionPlayer.toData());
|
||||||
|
Lobby.getInstance().notifyPlayers(new SessionModifiedMessage(toData()));
|
||||||
|
|
||||||
|
return sessionPlayer.getUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void leave(UUID player) {
|
||||||
|
if (players.remove(player) != null) {
|
||||||
|
if (players.size() == 0) {
|
||||||
|
Lobby.getInstance().removeSession(uuid);
|
||||||
|
} else {
|
||||||
|
notifyPlayers(new PlayerLeftMessage(player));
|
||||||
|
Lobby.getInstance().notifyPlayers(new SessionModifiedMessage(toData()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void ready(UUID player, boolean ready) {
|
||||||
|
var sessionPlayer = players.get(player);
|
||||||
|
if (sessionPlayer == null) {
|
||||||
|
throw new NackException(NackMessage.BAD_REQUEST, "Who are you?");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sessionPlayer.isReady() != ready) {
|
||||||
|
sessionPlayer.setReady(ready);
|
||||||
|
notifyPlayers(new PlayerModifiedMessage(sessionPlayer.toData()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (players.size() >= MIN_PLAYERS && players.values().stream().allMatch(SessionPlayer::isReady)) {
|
||||||
|
// TODO start game
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyJoined(PlayerData joined) {
|
||||||
|
var message = new PlayerJoinedMessage(joined);
|
||||||
|
for (SessionPlayer player : players.values()) {
|
||||||
|
if (player.getUuid().equals(joined.getUuid())) {
|
||||||
|
player.getPlayer().send(new SessionJoinedMessage(
|
||||||
|
getUuid(),
|
||||||
|
player.getUuid(),
|
||||||
|
players.values().stream().map(SessionPlayer::toData).toList(),
|
||||||
|
player.getSecret()
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
player.getPlayer().send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyPlayers(ServerMessage message) {
|
||||||
|
for (SessionPlayer player : players.values()) {
|
||||||
|
player.getPlayer().send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionData toData() {
|
||||||
|
return new SessionData(uuid, name, players.size(), configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(of = "uuid")
|
||||||
|
private static class SessionPlayer {
|
||||||
|
private final UUID uuid;
|
||||||
|
private final String name;
|
||||||
|
private final Player player;
|
||||||
|
private final String secret = generateSecret();
|
||||||
|
private boolean ready;
|
||||||
|
|
||||||
|
private static String generateSecret() {
|
||||||
|
return ThreadLocalRandom.current()
|
||||||
|
.ints(32, 'a', 'z' + 1)
|
||||||
|
.collect(StringBuilder::new, (sb, i) -> sb.append((char) i), StringBuilder::append)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerData toData() {
|
||||||
|
return new PlayerData(uuid, name, ready);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package eu.jonahbauer.wizard.server.machine;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.common.machine.State;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.ClientMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface ClientState extends State<ClientState, Player> {
|
||||||
|
default Optional<ClientState> onOpen(Player player) {
|
||||||
|
throw new IllegalStateException(); // TODO nachdenken
|
||||||
|
}
|
||||||
|
|
||||||
|
default Optional<ClientState> onMessage(Player player, ClientMessage message) {
|
||||||
|
player.send(new NackMessage(NackMessage.BAD_REQUEST, "Unexpected message."));
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<ClientState> onClose(Player player, CloseStatus status);
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package eu.jonahbauer.wizard.server.machine;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.common.machine.Context;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.ClientMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.ServerMessage;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.states.CreatedState;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
import org.springframework.web.socket.TextMessage;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
|
||||||
|
public class Player extends Context<ClientState, Player> {
|
||||||
|
private final WebSocketSession session;
|
||||||
|
|
||||||
|
public Player(WebSocketSession session) {
|
||||||
|
super(new CreatedState());
|
||||||
|
this.session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleError(Throwable t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onOpen() {
|
||||||
|
execute(s -> s.onOpen(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onMessage(ClientMessage message) {
|
||||||
|
execute(s -> s.onMessage(this, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onClose(CloseStatus status) {
|
||||||
|
execute(s -> s.onClose(this, status));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public void send(ServerMessage message) {
|
||||||
|
synchronized (session) {
|
||||||
|
session.sendMessage(new TextMessage(message.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package eu.jonahbauer.wizard.server.machine.states;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.server.machine.ClientState;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.Player;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class Closed implements ClientState {
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onClose(Player player, CloseStatus status) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package eu.jonahbauer.wizard.server.machine.states;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.server.machine.ClientState;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.Player;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class CreatedState implements ClientState {
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onOpen(Player player) {
|
||||||
|
return Optional.of(new LobbyState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onClose(Player player, CloseStatus status) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package eu.jonahbauer.wizard.server.machine.states;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.ClientMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.LeaveSessionMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.StartingGameMessage;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.ClientState;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.Player;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class InGame implements ClientState {
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onEnter(Player context) {
|
||||||
|
context.send(new StartingGameMessage());
|
||||||
|
|
||||||
|
return ClientState.super.onEnter(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExit(Player context) {
|
||||||
|
ClientState.super.onExit(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onOpen(Player player) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onMessage(Player player, ClientMessage message) {
|
||||||
|
if(message instanceof LeaveSessionMessage) {
|
||||||
|
//?
|
||||||
|
return Optional.empty();
|
||||||
|
} else {
|
||||||
|
player.send(new NackMessage(0, "Error: Invalid Message!"));
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onClose(Player player, CloseStatus status) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package eu.jonahbauer.wizard.server.machine.states;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.ClientMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.CreateSessionMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.JoinSessionMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
|
||||||
|
import eu.jonahbauer.wizard.server.Lobby;
|
||||||
|
import eu.jonahbauer.wizard.server.NackException;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.ClientState;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.Player;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class LobbyState implements ClientState {
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onEnter(Player player) {
|
||||||
|
Lobby.getInstance().join(player);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onMessage(Player player, ClientMessage message) {
|
||||||
|
if (message instanceof CreateSessionMessage create) {
|
||||||
|
Lobby.getInstance().leave(player);
|
||||||
|
var session = Lobby.getInstance().createSession(create);
|
||||||
|
var uuid = session.join(player, create.getPlayerName());
|
||||||
|
return Optional.of(new SessionState(session.getUuid(), uuid, create.getPlayerName()));
|
||||||
|
} else if (message instanceof JoinSessionMessage join) {
|
||||||
|
var session = Lobby.getInstance().getSession(join.getSession());
|
||||||
|
if (session == null) {
|
||||||
|
throw new NackException(NackMessage.NOT_FOUND, "Session not found.");
|
||||||
|
} else {
|
||||||
|
var uuid = session.join(player, join.getPlayerName());
|
||||||
|
return Optional.of(new SessionState(session.getUuid(), uuid, join.getPlayerName()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ClientState.super.onMessage(player, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onClose(Player player, CloseStatus status) {
|
||||||
|
return Optional.of(new Closed());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExit(Player player) {
|
||||||
|
Lobby.getInstance().leave(player);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package eu.jonahbauer.wizard.server.machine.states;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.ClientMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.LeaveSessionMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.ReadyMessage;
|
||||||
|
import eu.jonahbauer.wizard.common.messages.server.NackMessage;
|
||||||
|
import eu.jonahbauer.wizard.server.Lobby;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.ClientState;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.Player;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SessionState implements ClientState {
|
||||||
|
private final UUID session;
|
||||||
|
private final UUID self;
|
||||||
|
private final String name;
|
||||||
|
private boolean ready;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onOpen(Player player) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onMessage(Player player, ClientMessage message) {
|
||||||
|
if (message instanceof ReadyMessage ready) {
|
||||||
|
Lobby.getInstance().getSession(session).ready(self, ready.isReady());
|
||||||
|
this.ready = ready.isReady();
|
||||||
|
return Optional.empty();
|
||||||
|
} else if (message instanceof LeaveSessionMessage) {
|
||||||
|
Lobby.getInstance().getSession(session).leave(self);
|
||||||
|
return Optional.of(new LobbyState());
|
||||||
|
} else {
|
||||||
|
player.send(new NackMessage(0, "Error: Invalid Message!"));
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<ClientState> onClose(Player player, CloseStatus status) {
|
||||||
|
return Optional.of(new Closed());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExit(Player context) {
|
||||||
|
var session = Lobby.getInstance().getSession(this.session);
|
||||||
|
if (session != null) session.leave(self);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package eu.jonahbauer.wizard.server.socket;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSocket
|
||||||
|
public class WebSocketConfig implements WebSocketConfigurer {
|
||||||
|
|
||||||
|
@Getter(AccessLevel.PRIVATE)
|
||||||
|
private final WizardSocketHandler wizardSocketHandler;
|
||||||
|
|
||||||
|
public WebSocketConfig(WizardSocketHandler wizardSocketHandler) {
|
||||||
|
this.wizardSocketHandler = wizardSocketHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerWebSocketHandlers(@NotNull WebSocketHandlerRegistry registry) {
|
||||||
|
registry.addHandler(getWizardSocketHandler(), "/").setAllowedOrigins("*");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package eu.jonahbauer.wizard.server.socket;
|
||||||
|
|
||||||
|
import eu.jonahbauer.wizard.common.messages.client.ClientMessage;
|
||||||
|
import eu.jonahbauer.wizard.server.machine.Player;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.socket.CloseStatus;
|
||||||
|
import org.springframework.web.socket.TextMessage;
|
||||||
|
import org.springframework.web.socket.WebSocketSession;
|
||||||
|
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Log4j2
|
||||||
|
@Component
|
||||||
|
public class WizardSocketHandler extends TextWebSocketHandler {
|
||||||
|
private final Map<String, Player> players = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionEstablished(@NotNull WebSocketSession session) {
|
||||||
|
var player = new Player(session);
|
||||||
|
player.onOpen();
|
||||||
|
|
||||||
|
players.put(session.getId(), player);
|
||||||
|
log.info("Connection #{} from {}.", session.getId(), session.getRemoteAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleTextMessage(@NotNull WebSocketSession session, @NotNull TextMessage text) {
|
||||||
|
players.get(session.getId()).onMessage(ClientMessage.parse(text.getPayload()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterConnectionClosed(@NotNull WebSocketSession session, @NotNull CloseStatus status) {
|
||||||
|
players.get(session.getId()).onClose(status);
|
||||||
|
log.info("Connection #{} closed {}.", session.getId(), status);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue