feat: partially implemented not yet refactored lobbyManager
This commit is contained in:
		@ -1,48 +1,196 @@
 | 
			
		||||
package uulm.teamname.marvelous.server.lobbymanager;
 | 
			
		||||
 | 
			
		||||
import org.tinylog.Logger;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.config.CharacterConfig;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.config.PartyConfig;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.config.ScenarioConfig;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.Tuple;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.config.CharacterProperties;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.events.Event;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.messages.BasicMessage;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.messages.ParticipantType;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.requests.Request;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.messages.client.CharacterSelectionMessage;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.messages.client.RequestMessage;
 | 
			
		||||
import uulm.teamname.marvelous.gamelibrary.messages.server.GameAssignmentMessage;
 | 
			
		||||
import uulm.teamname.marvelous.server.Server;
 | 
			
		||||
import uulm.teamname.marvelous.server.lobby.Lobby;
 | 
			
		||||
import uulm.teamname.marvelous.server.netconnector.UserManager;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.concurrent.BlockingQueue;
 | 
			
		||||
import java.util.concurrent.LinkedBlockingQueue;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
import java.util.function.BiConsumer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A class that handles the connection to the lobby. It contains distinct websockets for player1, player2 and spectators.
 | 
			
		||||
 * A class that handles the connection to the lobby. It contains the participants inside of the lobby.
 | 
			
		||||
 * The class is meant to be used in conjecture with {@link MessageRelay}.
 | 
			
		||||
 */
 | 
			
		||||
public class LobbyConnection implements Runnable {
 | 
			
		||||
    private final Lobby lobby;
 | 
			
		||||
    private Lobby lobby;
 | 
			
		||||
    public final String gameID;
 | 
			
		||||
    private Participant player1, player2;
 | 
			
		||||
    private boolean characterSelection;
 | 
			
		||||
 | 
			
		||||
    /** Whether the character selection phase is reached */
 | 
			
		||||
    private boolean inGame;
 | 
			
		||||
    private final HashSet<Participant> spectators;
 | 
			
		||||
    private final BlockingQueue<Request[]> incomingRequests;
 | 
			
		||||
    private final BlockingQueue<Tuple<Participant, BasicMessage>> incomingMessages;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A callback executed to send a message, originating from the
 | 
			
		||||
     * {@link uulm.teamname.marvelous.server.netconnector.UserManager}
 | 
			
		||||
     */
 | 
			
		||||
    private final BiConsumer<Participant, BasicMessage> sendMessageCallback;
 | 
			
		||||
 | 
			
		||||
    // TODO: FIX THIS JAVADOC
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a new LobbyConnection, whereby a new {@link Lobby} is initialized.
 | 
			
		||||
     */
 | 
			
		||||
    public LobbyConnection(String gameID,
 | 
			
		||||
                           PartyConfig partyConfig,
 | 
			
		||||
                           CharacterConfig characterConfig,
 | 
			
		||||
                           ScenarioConfig scenarioConfig) {
 | 
			
		||||
    /** Creates a new LobbyConnection */
 | 
			
		||||
    public LobbyConnection(String gameID, BiConsumer<Participant, BasicMessage> sendMessageCallback) {
 | 
			
		||||
        this.gameID = gameID;
 | 
			
		||||
        this.sendMessageCallback = sendMessageCallback;
 | 
			
		||||
        this.spectators = new HashSet<>(10);
 | 
			
		||||
        this.incomingMessages = new LinkedBlockingQueue<>();
 | 
			
		||||
        this.characterSelection = false;
 | 
			
		||||
        this.inGame = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void run() {
 | 
			
		||||
        Logger.info("Starting Lobby thread for lobby '{}'", gameID);
 | 
			
		||||
        Logger.trace("Initializing lobby...");
 | 
			
		||||
        initializeLobby();
 | 
			
		||||
 | 
			
		||||
        Logger.trace("Activating characterSelection state");
 | 
			
		||||
        this.characterSelection = true;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Logger.info("Starting character selection process");
 | 
			
		||||
        Logger.trace("Finding twenty-four random characters");
 | 
			
		||||
        Tuple<CharacterProperties[], CharacterProperties[]> selectionPossibilities =
 | 
			
		||||
                Server.getCharacterConfig().getDisjointSetsOfPropertiesOfSize(12);
 | 
			
		||||
 | 
			
		||||
        Logger.info("Sending GameAssignment message with random characters to players");
 | 
			
		||||
        var gameAssignmentMessage = new GameAssignmentMessage();
 | 
			
		||||
        gameAssignmentMessage.gameID = this.gameID;
 | 
			
		||||
 | 
			
		||||
        // Send to player one with characters for player one
 | 
			
		||||
        gameAssignmentMessage.characterSelection = selectionPossibilities.item1;
 | 
			
		||||
        UserManager.getInstance().sendMessage(player1.getConnection(), gameAssignmentMessage);
 | 
			
		||||
 | 
			
		||||
        // And send the others to player 2
 | 
			
		||||
        gameAssignmentMessage.characterSelection = selectionPossibilities.item2;
 | 
			
		||||
        UserManager.getInstance().sendMessage(player2.getConnection(), gameAssignmentMessage);
 | 
			
		||||
 | 
			
		||||
        CharacterProperties[] playerOneSelection = null;
 | 
			
		||||
        CharacterProperties[] playerTwoSelection = null;
 | 
			
		||||
 | 
			
		||||
        Logger.info("Entering GameAssignment state. Waiting for answer about selected characters from players.");
 | 
			
		||||
        while (characterSelection) {
 | 
			
		||||
            Tuple<Participant, BasicMessage> currentMessage = null;
 | 
			
		||||
 | 
			
		||||
            try { // TODO: Exact duplication. Maybe extract?
 | 
			
		||||
                Logger.trace("Checking for messages. Currently the amount of messages is {}",
 | 
			
		||||
                        incomingMessages.size());
 | 
			
		||||
 | 
			
		||||
                if (incomingMessages.isEmpty()) {
 | 
			
		||||
                    Logger.trace("LobbyConnection thread waiting for new messages...");
 | 
			
		||||
                    Thread.currentThread().wait();
 | 
			
		||||
                    Logger.trace("Lobby '{}' woken up", gameID);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Logger.trace("Polling incoming message queue");
 | 
			
		||||
                currentMessage = incomingMessages.poll(100, TimeUnit.MILLISECONDS);
 | 
			
		||||
 | 
			
		||||
            } catch (InterruptedException e) {
 | 
			
		||||
                Logger.warn("LobbyConnection thread got interrupted. Exception: " + e.getMessage());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (currentMessage == null) {
 | 
			
		||||
                continue;
 | 
			
		||||
            } else if (currentMessage.item2 instanceof CharacterSelectionMessage) {
 | 
			
		||||
                var origin = currentMessage.item1;
 | 
			
		||||
                var message = (CharacterSelectionMessage) currentMessage.item2;
 | 
			
		||||
                if (origin.type.equals(ParticipantType.Spectator)) {
 | 
			
		||||
                    Logger.info("Spectator sent CharacterSelectionMessage. Sending error...");
 | 
			
		||||
                    UserManager.getInstance().sendError(
 | 
			
		||||
                            origin.getConnection(),
 | 
			
		||||
                            "Spectators can't select characters");
 | 
			
		||||
                } else if (origin.type.equals(ParticipantType.PlayerOne)) {
 | 
			
		||||
                    if (playerOneSelection == null) { // TODO: Extract this. This isn't beautiful at all.
 | 
			
		||||
                        ArrayList<CharacterProperties> chosenCharacters = new ArrayList<>();
 | 
			
		||||
                        for (int i = 0; i < 12; i++) {
 | 
			
		||||
                            if (message.characters[i]) {
 | 
			
		||||
                                chosenCharacters.add(selectionPossibilities.item1[i]);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        playerOneSelection = chosenCharacters.toArray(new CharacterProperties[0]);
 | 
			
		||||
                    }
 | 
			
		||||
                    Logger.info("Player 1 has selected their characters");
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (playerTwoSelection == null) {
 | 
			
		||||
                        ArrayList<CharacterProperties> chosenCharacters = new ArrayList<>();
 | 
			
		||||
                        for (int i = 0; i < 12; i++) {
 | 
			
		||||
                            if (message.characters[i]) {
 | 
			
		||||
                                chosenCharacters.add(selectionPossibilities.item2[i]);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        playerTwoSelection = chosenCharacters.toArray(new CharacterProperties[0]);
 | 
			
		||||
                    }
 | 
			
		||||
                    Logger.info("Player 2 has selected their characters");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while(inGame) {
 | 
			
		||||
            Tuple<Participant, BasicMessage> currentMessage = null;
 | 
			
		||||
            try {
 | 
			
		||||
                Logger.trace("Checking for messages. Currently the amount of messages is {}",
 | 
			
		||||
                        incomingMessages.size());
 | 
			
		||||
 | 
			
		||||
                if (incomingMessages.isEmpty()) {
 | 
			
		||||
                    Logger.trace("LobbyConnection thread waiting for new messages...");
 | 
			
		||||
                    Thread.currentThread().wait();
 | 
			
		||||
                    Logger.trace("Lobby '{}' woken up", gameID);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Logger.trace("Polling incoming message queue");
 | 
			
		||||
                currentMessage = incomingMessages.poll(100, TimeUnit.MILLISECONDS);
 | 
			
		||||
 | 
			
		||||
            } catch (InterruptedException e) {
 | 
			
		||||
                Logger.warn("LobbyConnection thread got interrupted. Exception: " + e.getMessage());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (currentMessage == null) {
 | 
			
		||||
                Logger.trace("Message was null, continuing");
 | 
			
		||||
                continue;
 | 
			
		||||
            } else if (currentMessage.item2 instanceof CharacterSelectionMessage) {
 | 
			
		||||
                receiveCharacterSelection((CharacterSelectionMessage) currentMessage.item2);
 | 
			
		||||
            } else if (currentMessage.item2 instanceof RequestMessage) {
 | 
			
		||||
                receiveRequests((RequestMessage) currentMessage.item2);
 | 
			
		||||
            } else {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Send messages to the lobbyConnection */
 | 
			
		||||
    public void receiveMessage(Participant participant, BasicMessage message) {
 | 
			
		||||
        this.incomingMessages.add(Tuple.of(participant, message));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void receiveRequests(RequestMessage message) {
 | 
			
		||||
        // TODO: implement this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void receiveCharacterSelection(CharacterSelectionMessage message) {
 | 
			
		||||
        // TODO: Implement proper character selection
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void initializeLobby() {
 | 
			
		||||
        Logger.trace("Initializing lobby...");
 | 
			
		||||
        this.lobby = new Lobby(
 | 
			
		||||
                gameID,
 | 
			
		||||
                this,
 | 
			
		||||
                partyConfig,
 | 
			
		||||
                characterConfig,
 | 
			
		||||
                scenarioConfig);
 | 
			
		||||
        this.gameID = gameID;
 | 
			
		||||
        this.spectators = new HashSet<>(10);
 | 
			
		||||
        this.incomingRequests = new LinkedBlockingQueue<>();
 | 
			
		||||
                Server.getPartyConfig(),
 | 
			
		||||
                Server.getCharacterConfig(),
 | 
			
		||||
                Server.getScenarioConfig());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -52,9 +200,7 @@ public class LobbyConnection implements Runnable {
 | 
			
		||||
        return player1 != null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return whether there is a player2
 | 
			
		||||
     */
 | 
			
		||||
    /** @return whether there is a player2 */
 | 
			
		||||
    public boolean hasPlayer2() {
 | 
			
		||||
        return player2 != null;
 | 
			
		||||
    }
 | 
			
		||||
@ -176,16 +322,35 @@ public class LobbyConnection implements Runnable {
 | 
			
		||||
 | 
			
		||||
    /** Kills all connections to client, as well as the lobby */
 | 
			
		||||
    public void terminateConnection() {
 | 
			
		||||
        MessageRelay.getInstance().terminate(this);
 | 
			
		||||
        // TODO: implement this
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Send requests to the lobby that the LobbyConnection connects to */
 | 
			
		||||
    public void receiveRequests(Request... requests) {
 | 
			
		||||
        this.incomingRequests.add(requests);
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object o) {
 | 
			
		||||
        if (this == o) return true;
 | 
			
		||||
        if (o == null || getClass() != o.getClass()) return false;
 | 
			
		||||
        LobbyConnection that = (LobbyConnection) o;
 | 
			
		||||
        return characterSelection == that.characterSelection && inGame == that.inGame && Objects.equals(lobby, that.lobby) && Objects.equals(gameID, that.gameID) && Objects.equals(player1, that.player1) && Objects.equals(player2, that.player2) && Objects.equals(spectators, that.spectators) && Objects.equals(incomingMessages, that.incomingMessages) && Objects.equals(sendMessageCallback, that.sendMessageCallback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void run() {
 | 
			
		||||
    public int hashCode() {
 | 
			
		||||
        return Objects.hash(lobby, gameID, player1, player2, characterSelection, inGame, spectators, incomingMessages, sendMessageCallback);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return "LobbyConnection{" +
 | 
			
		||||
                "lobby=" + lobby +
 | 
			
		||||
                ", gameID='" + gameID + '\'' +
 | 
			
		||||
                ", player1=" + player1 +
 | 
			
		||||
                ", player2=" + player2 +
 | 
			
		||||
                ", characterSelection=" + characterSelection +
 | 
			
		||||
                ", inGame=" + inGame +
 | 
			
		||||
                ", spectators=" + spectators +
 | 
			
		||||
                ", incomingMessages=" + incomingMessages +
 | 
			
		||||
                ", sendMessageCallback=" + sendMessageCallback +
 | 
			
		||||
                '}';
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user