diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/lobby/Lobby.java b/Server/src/main/java/uulm/teamname/marvelous/server/lobby/Lobby.java index c0498d7..8d55469 100644 --- a/Server/src/main/java/uulm/teamname/marvelous/server/lobby/Lobby.java +++ b/Server/src/main/java/uulm/teamname/marvelous/server/lobby/Lobby.java @@ -65,12 +65,14 @@ public class Lobby { this.pauseSegment = new PauseSegment(); var filterEndRoundRequestSegment = new FilterEndRoundRequestSegment(game.state::getActiveCharacter); var disconnectSegment = new DisconnectSegment(this); + var playerFilterSegment = new PlayerFilterSegment(); var gameLogicSegment = new GameLogicSegment(this.game); pipeline.addSegment(reqSegment) .addSegment(pauseSegment) .addSegment(filterEndRoundRequestSegment) .addSegment(disconnectSegment) + .addSegment(playerFilterSegment) .addSegment(gameLogicSegment); Logger.trace("Instantiating timers..."); diff --git a/Server/src/main/java/uulm/teamname/marvelous/server/lobby/pipelining/PlayerFilterSegment.java b/Server/src/main/java/uulm/teamname/marvelous/server/lobby/pipelining/PlayerFilterSegment.java new file mode 100644 index 0000000..386101c --- /dev/null +++ b/Server/src/main/java/uulm/teamname/marvelous/server/lobby/pipelining/PlayerFilterSegment.java @@ -0,0 +1,52 @@ +package uulm.teamname.marvelous.server.lobby.pipelining; + +import org.tinylog.Logger; +import uulm.teamname.marvelous.gamelibrary.entities.EntityType; +import uulm.teamname.marvelous.gamelibrary.events.Event; +import uulm.teamname.marvelous.gamelibrary.messages.ParticipantType; +import uulm.teamname.marvelous.gamelibrary.requests.CharacterRequest; +import uulm.teamname.marvelous.gamelibrary.requests.Request; +import uulm.teamname.marvelous.server.lobbymanager.Participant; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +public class PlayerFilterSegment implements Segment { + @Override + public void processRequests(Packet packet, List carrier, AtomicBoolean abort) { + Logger.trace("PlayerFilterSegment received {} requests", packet.size()); + for (Request request: packet) { + boolean valid = switch (request.type) { + case MeleeAttackRequest, + RangedAttackRequest, + MoveRequest, + ExchangeInfinityStoneRequest, + UseInfinityStoneRequest -> isValid((CharacterRequest) request, packet.getOrigin()); + default -> true; + }; + if (!valid) { + Logger.debug("Invalid request of type {} found, setting abort flag", request.type); + abort.set(true); + break; + } + } + } + + private boolean isValid(CharacterRequest request, Participant participant) { + EntityType type = switch(participant.type) { + case PlayerOne -> EntityType.P1; + case PlayerTwo -> EntityType.P2; + case Spectator -> null; + }; + + if (type == null) { + Logger.warn("Some spectator-sent movement requests arrived in the PlayerFilterSegment.\n" + + "Have you ordered your segments properly?"); + return false; + } else { + return request.originEntity.type.equals(type); + } + + + } +} diff --git a/Server/src/test/java/uulm/teamname/marvelous/server/lobby/pipelining/PlayerFilterSegmentTest.java b/Server/src/test/java/uulm/teamname/marvelous/server/lobby/pipelining/PlayerFilterSegmentTest.java new file mode 100644 index 0000000..cdde662 --- /dev/null +++ b/Server/src/test/java/uulm/teamname/marvelous/server/lobby/pipelining/PlayerFilterSegmentTest.java @@ -0,0 +1,118 @@ +package uulm.teamname.marvelous.server.lobby.pipelining; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import uulm.teamname.marvelous.gamelibrary.IntVector2; +import uulm.teamname.marvelous.gamelibrary.entities.EntityID; +import uulm.teamname.marvelous.gamelibrary.entities.EntityType; +import uulm.teamname.marvelous.gamelibrary.events.Event; +import uulm.teamname.marvelous.gamelibrary.messages.ParticipantType; +import uulm.teamname.marvelous.gamelibrary.requests.Request; +import uulm.teamname.marvelous.gamelibrary.requests.RequestBuilder; +import uulm.teamname.marvelous.gamelibrary.requests.RequestType; +import uulm.teamname.marvelous.server.lobbymanager.Participant; +import uulm.teamname.marvelous.server.netconnector.Client; + +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.*; + +class PlayerFilterSegmentTest { + + PlayerFilterSegment segment; + AtomicBoolean abort; + + @BeforeEach + void beforeEach() { + segment = new PlayerFilterSegment(); + abort = new AtomicBoolean(false); + } + + @Test + void validRequestsRemainUntouched() { + var participant = new Participant(mock(Client.class), null, ParticipantType.PlayerOne, false); + + var requests = new Request[] { + new RequestBuilder(RequestType.MeleeAttackRequest) + .withOriginField(new IntVector2(1, 4)) + .withTargetField(new IntVector2(2, 4)) + .withOriginEntity(new EntityID(EntityType.P1, 3)) + .buildCharacterRequest(), + new RequestBuilder(RequestType.MeleeAttackRequest) + .withOriginField(new IntVector2(2, 4)) + .withTargetField(new IntVector2(3, 5)) + .withOriginEntity(new EntityID(EntityType.P1, 3)) + .withTargetEntity(new EntityID(EntityType.P2, 3)) + .withValue(14) + .buildCharacterRequest() + }; + + var packet = new Packet(requests, participant); + var carrier = new ArrayList(); + + assertThatNoException().isThrownBy(() -> segment.processRequests(packet, carrier, abort)); + + assertThat(packet.toArray(new Request[0])) + .isEqualTo(requests); + assertThat(carrier).isEmpty(); + assertThat(abort).isFalse(); + + } + + @Test + void invalidRequestsTriggerAbort() { + var participant = new Participant(mock(Client.class), null, ParticipantType.PlayerOne, false); + + var requests = new Request[] { + new RequestBuilder(RequestType.MeleeAttackRequest) + .withOriginField(new IntVector2(1, 4)) + .withTargetField(new IntVector2(2, 4)) + .withOriginEntity(new EntityID(EntityType.P2, 3)) + .buildCharacterRequest(), + new RequestBuilder(RequestType.MeleeAttackRequest) + .withOriginField(new IntVector2(2, 4)) + .withTargetField(new IntVector2(3, 5)) + .withOriginEntity(new EntityID(EntityType.P2, 3)) + .withTargetEntity(new EntityID(EntityType.P1, 3)) + .withValue(14) + .buildCharacterRequest() + }; + + var packet = new Packet(requests, participant); + var carrier = new ArrayList(); + + assertThatNoException().isThrownBy(() -> segment.processRequests(packet, carrier, abort)); + + assertThat(packet.toArray(new Request[0])) + .isEqualTo(requests); + assertThat(carrier).isEmpty(); + assertThat(abort).isTrue(); + } + + + @Test + void gameRequestsRemainUntouched() { + var participant = new Participant(mock(Client.class), null, ParticipantType.PlayerOne, false); + + var requests = new Request[] { + new RequestBuilder(RequestType.Req).buildGameRequest(), + new RequestBuilder(RequestType.EndRoundRequest).buildGameRequest(), + new RequestBuilder(RequestType.DisconnectRequest).buildGameRequest() + + }; + + var packet = new Packet(requests, participant); + var carrier = new ArrayList(); + + assertThatNoException().isThrownBy(() -> segment.processRequests(packet, carrier, abort)); + + assertThat(packet.toArray(new Request[0])) + .isEqualTo(requests); + assertThat(carrier).isEmpty(); + assertThat(abort).isFalse(); + } + +}