feat: updated lobby to pipeline-based model

This commit is contained in:
Yannik Bretschneider 2021-06-02 18:28:02 +02:00
parent 96f131e50c
commit 6557e748af

View File

@ -1,6 +1,6 @@
package uulm.teamname.marvelous.server.lobby; package uulm.teamname.marvelous.server.lobby;
import uulm.teamname.marvelous.gamelibrary.IntVector2; import org.tinylog.Logger;
import uulm.teamname.marvelous.gamelibrary.events.Event; import uulm.teamname.marvelous.gamelibrary.events.Event;
import uulm.teamname.marvelous.gamelibrary.events.EventBuilder; import uulm.teamname.marvelous.gamelibrary.events.EventBuilder;
import uulm.teamname.marvelous.gamelibrary.events.EventType; import uulm.teamname.marvelous.gamelibrary.events.EventType;
@ -10,7 +10,6 @@ import uulm.teamname.marvelous.gamelibrary.config.CharacterConfig;
import uulm.teamname.marvelous.gamelibrary.config.PartyConfig; import uulm.teamname.marvelous.gamelibrary.config.PartyConfig;
import uulm.teamname.marvelous.gamelibrary.config.ScenarioConfig; import uulm.teamname.marvelous.gamelibrary.config.ScenarioConfig;
import uulm.teamname.marvelous.gamelibrary.requests.Request; import uulm.teamname.marvelous.gamelibrary.requests.Request;
import uulm.teamname.marvelous.gamelibrary.requests.RequestType;
import uulm.teamname.marvelous.server.lobby.pipelining.*; import uulm.teamname.marvelous.server.lobby.pipelining.*;
import uulm.teamname.marvelous.server.lobbymanager.LobbyConnection; import uulm.teamname.marvelous.server.lobbymanager.LobbyConnection;
import uulm.teamname.marvelous.server.lobbymanager.Participant; import uulm.teamname.marvelous.server.lobbymanager.Participant;
@ -22,8 +21,9 @@ public class Lobby {
public final LobbyConnection connection; public final LobbyConnection connection;
public final GameInstance game; public final GameInstance game;
public final Pipeline pipeline; public final Pipeline pipeline;
public final PauseSegment pauseSegment; private Participant activePlayer;
private final PauseHandler pause = new PauseHandler(); private int badRequests;
private PauseSegment pauseSegment;
public Lobby( public Lobby(
String gameID, String gameID,
@ -34,6 +34,8 @@ public class Lobby {
this.gameID = gameID; this.gameID = gameID;
this.connection = connection; this.connection = connection;
//partyConfig.maxRoundTime;
this.game = new GameInstance( this.game = new GameInstance(
partyConfig, partyConfig,
characterConfig, characterConfig,
@ -41,79 +43,77 @@ public class Lobby {
); //TODO: Add config objects here ); //TODO: Add config objects here
this.pipeline = new Pipeline(); this.pipeline = new Pipeline();
var reqSegment = new RequestGameStateSegment(this.game); var reqSegment = new RequestGameStateSegment(this.game);
this.pauseSegment = new PauseSegment(); this.pauseSegment = new PauseSegment();
var disconnectSegment = new DisconnectSegment(this); var disconnectSegment = new DisconnectSegment(this);
var gameStateSegment = new GameStateSegment(this.game); var gameStateSegment = new GameStateSegment(this.game);
pipeline.addSegment(reqSegment)
.addSegment(pauseSegment)
.addSegment(disconnectSegment)
.addSegment(gameStateSegment);
} }
public void receiveRequests(Participant source, Request[] requests) { /**
ArrayList<Request> stateRelevant = new ArrayList<>(); * Called by {@link LobbyConnection} to handle requests
* @param requests to be processed
for(Request request: requests) { * @param source the player executing the requests
switch(request.type) { */
case MeleeAttackRequest, RangedAttackRequest, MoveRequest, ExchangeInfinityStoneRequest, UseInfinityStoneRequest, EndRoundRequest -> { public void receiveRequests(Request[] requests, Participant source) {
if(!pause.isPaused()) { if(activePlayer != source && source.type != ParticipantType.Spectator) {
stateRelevant.add(request); activePlayer = source;
}else { badRequests = 0;
// if game is paused, no actions should happen
reject(source);
}
}
case PauseStartRequest, PauseStopRequest -> {
if(request.type == RequestType.PauseStartRequest || pause.isPaused()) {
processRequest(source, request);
}else {
reject(source);
}
return; // only one of these will ever be sent at once, and if that is the case, we wont have any other state relevant events
}
case DisconnectRequest, Req -> {
processRequest(source, request);
return; // only one of these will ever be sent at once, and if that is the case, we wont have any other state relevant events
}
}
} }
//
// if(!game.checkRequestsAndApply(stateRelevant.toArray(new Request[0]))) { TODO: Fix this.
// // requests don't apply, tell the client that they need to update their state
// reject(source);
// }
}
private void processRequest(Participant source, Request request) { Logger.info("got {} requests from participant {}", requests.length, source);
// TODO: Implement as pipeline
switch(request.type) { Logger.trace("Processing requests through pipeline");
case PauseStopRequest -> { Optional<Event[]> resultingEvents = pipeline.processRequests(requests, source);
pause.stop();
connection.sendEvents(source, new EventBuilder(EventType.PauseStopEvent).buildGameStateEvent(), game.getGameStateEvent()); //resultingEvents isEmpty when a wrong request appeared
} if (resultingEvents.isEmpty()) {
case PauseStartRequest -> { reject(source);
pause.start(); } else {
connection.sendEvents(source, new EventBuilder(EventType.PauseStartEvent).buildGameStateEvent(), game.getGameStateEvent()); var events = resultingEvents.get();
} connection.sendEvents(source, events);
case DisconnectRequest -> { badRequests = 0;
connection.removePlayer(source);
connection.sendEvents(source, new EventBuilder(EventType.DisconnectEvent).buildGameStateEvent(), game.getGameStateEvent());
}
case Req -> {
connection.sendEvents(source, game.getGameStateEvent());
}
} }
} }
/**
* If the player executed a false request the request gets rejected.
* @param source the executing player
*/
private void reject(Participant source) { private void reject(Participant source) {
connection.sendEvents(source, new EventBuilder(EventType.Nack).buildGameEvent(), game.getGameStateEvent()); connection.sendEvents(source, new EventBuilder(EventType.Nack).buildGameEvent(), game.getGameStateEvent());
badRequests ++;
//if the player sends 2 bad messages after one another, the player gets kicked out of the lobby.
if(badRequests == 2){
connection.removePlayer(source);
if(connection.hasPlayer1()){
generateWin(connection.getPlayer1());
}
else if(connection.hasPlayer2()) {
generateWin(connection.getPlayer2());
}
}
} }
/**
* Warns the player he get timeouted soon.
* @param source soon to be timeouted player
*/
public void soonTimeout (Participant source){ public void soonTimeout (Participant source){
connection.sendEvents( connection.sendEvents(
source, source,
new EventBuilder(EventType.TimeoutWarningEvent).buildGameStateEvent()); new EventBuilder(EventType.TimeoutWarningEvent).buildGameStateEvent());
} }
/**
* If a player times out the other player automatically wins.
* @param source is the timeouted player
*/
public void Timeout(Participant source){ public void Timeout(Participant source){
connection.sendEvents( connection.sendEvents(
source, source,
@ -146,4 +146,8 @@ public class Lobby {
.buildGameStateEvent()); .buildGameStateEvent());
connection.terminateConnection(); connection.terminateConnection();
} }
public PauseSegment getPauseSegment() {
return pauseSegment;
}
} }