From 15d92a9443582cb4a3989fb39b68a7c2d2cc01fb Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Sat, 19 Oct 2019 13:15:31 +0100 Subject: [PATCH 1/5] #18: create a new Java maven based project --- .gitignore | 1 + server/pom.xml | 12 ++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 server/pom.xml diff --git a/.gitignore b/.gitignore index 51e2b02..afd0abb 100644 --- a/.gitignore +++ b/.gitignore @@ -108,6 +108,7 @@ captures/ .idea/dictionaries .idea/libraries .idea/caches +.idea/ # Keystore files # Uncomment the following lines if you do not want to check your keystore files in. diff --git a/server/pom.xml b/server/pom.xml new file mode 100644 index 0000000..ce0c002 --- /dev/null +++ b/server/pom.xml @@ -0,0 +1,12 @@ + + + 4.0.0 + + com.colonelpanic.n64all + server + 1.0-SNAPSHOT + + + \ No newline at end of file From c9f38ea7ab320f0f48f75990e9a57428237b460c Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Sat, 19 Oct 2019 13:26:14 +0100 Subject: [PATCH 2/5] #18: create maven project with dependencies --- server/pom.xml | 58 +++++++++++++++++++ .../server/service/ControllerService.java | 4 ++ 2 files changed, 62 insertions(+) create mode 100644 server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java diff --git a/server/pom.xml b/server/pom.xml index ce0c002..bbf4f71 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -8,5 +8,63 @@ server 1.0-SNAPSHOT + + 1.8 + 5.5.2 + UTF-8 + 1.6.1 + + + + + com.google.inject + guice + 4.2.2 + + + + com.google.guava + guava + 28.0-jre + + + org.junit.jupiter + junit-jupiter-engine + 5.5.0 + test + + + + org.mockito + mockito-core + 2.10.0 + test + + + org.slf4j + slf4j-api + ${slf4jVersion} + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M3 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java b/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java new file mode 100644 index 0000000..9419a4e --- /dev/null +++ b/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java @@ -0,0 +1,4 @@ +package com.colonelpanic.n64all.server.service; + +public class ControllerService { +} From fbd7214d79c1e8adc49c96f77f8bc385f7359d98 Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Sat, 19 Oct 2019 13:59:01 +0100 Subject: [PATCH 3/5] #18: create basic models that are necessary for this to work --- .../server/model/ControllerProperty.java | 46 +++++++++++++++++++ .../n64all/server/model/ControllerState.java | 32 +++++++++++++ .../server/service/ControllerService.java | 4 ++ .../server/service/PlayerController.java | 10 ++++ 4 files changed, 92 insertions(+) create mode 100644 server/src/main/java/com/colonelpanic/n64all/server/model/ControllerProperty.java create mode 100644 server/src/main/java/com/colonelpanic/n64all/server/model/ControllerState.java create mode 100644 server/src/main/java/com/colonelpanic/n64all/server/service/PlayerController.java diff --git a/server/src/main/java/com/colonelpanic/n64all/server/model/ControllerProperty.java b/server/src/main/java/com/colonelpanic/n64all/server/model/ControllerProperty.java new file mode 100644 index 0000000..5c94ce3 --- /dev/null +++ b/server/src/main/java/com/colonelpanic/n64all/server/model/ControllerProperty.java @@ -0,0 +1,46 @@ +package com.colonelpanic.n64all.server.model; + +public enum ControllerProperty { + ANALOG_X(0, -80, 80), + ANALOG_Y(0, -80, 80), + A_BTN(0, 0, 1), + B_BTN(0, 0, 1), + Z_BTN(0, 0, 1), + C_UP_ARROW(0, 0, 1), + C_LEFT_ARROW(0, 0, 1), + C_RIGHT_ARROW(0, 0, 1), + C_DOWN_ARROW(0, 0, 1), + L_TRIGGER(0, 0, 1), + R_TRIGGER(0, 0, 1), + START(0, 0, 1); + + private final int defaultValue; + private final int minValue; + private final int maxValue; + + /** + * The definition of the schema for each player controller property. This defines + * defaults, as well as the allowed values. + * + * @param defaultValue the default value that this property is set to + * @param min the minimum value (inclusive) the property can be + * @param max the maximum value (inclusive) the property can be + */ + ControllerProperty(int defaultValue, int min, int max) { + this.defaultValue = defaultValue; + this.minValue = min; + this.maxValue = max; + } + + public int getDefaultValue() { + return defaultValue; + } + + public int getMinValue() { + return minValue; + } + + public int getMaxValue() { + return maxValue; + } +} diff --git a/server/src/main/java/com/colonelpanic/n64all/server/model/ControllerState.java b/server/src/main/java/com/colonelpanic/n64all/server/model/ControllerState.java new file mode 100644 index 0000000..85622f7 --- /dev/null +++ b/server/src/main/java/com/colonelpanic/n64all/server/model/ControllerState.java @@ -0,0 +1,32 @@ +package com.colonelpanic.n64all.server.model; + +import com.colonelpanic.n64all.server.service.PlayerController; +import com.google.common.collect.Maps; + +import java.util.Map; + +public class ControllerState implements PlayerController { + private Map properties; + + public ControllerState() { + this.properties = Maps.newConcurrentMap(); + + for (ControllerProperty prop : ControllerProperty.values()) { + setState(prop, prop.getDefaultValue()); + } + } + + public void setState(ControllerProperty property, int value) { + if (isValidPropertyValue(property, value)) { + properties.put(property, value); + } + } + + public int getState(ControllerProperty property) { + return properties.get(property); + } + + private boolean isValidPropertyValue(ControllerProperty prop, int value) { + return prop.getMinValue() <= value && prop.getMaxValue() >= value; + } +} diff --git a/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java b/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java index 9419a4e..36fe140 100644 --- a/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java +++ b/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java @@ -1,4 +1,8 @@ package com.colonelpanic.n64all.server.service; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class ControllerService { + private static final Logger logger = LoggerFactory.getLogger(ControllerService.class); } diff --git a/server/src/main/java/com/colonelpanic/n64all/server/service/PlayerController.java b/server/src/main/java/com/colonelpanic/n64all/server/service/PlayerController.java new file mode 100644 index 0000000..1ef33d6 --- /dev/null +++ b/server/src/main/java/com/colonelpanic/n64all/server/service/PlayerController.java @@ -0,0 +1,10 @@ +package com.colonelpanic.n64all.server.service; + +import com.colonelpanic.n64all.server.model.ControllerProperty; + +public interface PlayerController { + void setState(ControllerProperty property, int value); + + int getState(ControllerProperty property); + +} From b9c06a620e26a548bb34cfc479f87f3ee204532f Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Sat, 19 Oct 2019 14:31:25 +0100 Subject: [PATCH 4/5] #18: add a basic command service --- .../server/service/ControllerService.java | 36 +++++++++++++ .../service/PlayerNotFoundException.java | 4 ++ .../server/service/ControllerServiceTest.java | 53 +++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 server/src/main/java/com/colonelpanic/n64all/server/service/PlayerNotFoundException.java create mode 100644 server/src/test/java/com/colonelpanic/n64all/server/service/ControllerServiceTest.java diff --git a/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java b/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java index 36fe140..806093b 100644 --- a/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java +++ b/server/src/main/java/com/colonelpanic/n64all/server/service/ControllerService.java @@ -1,8 +1,44 @@ package com.colonelpanic.n64all.server.service; +import com.colonelpanic.n64all.server.model.ControllerProperty; +import com.colonelpanic.n64all.server.model.ControllerState; +import com.google.common.collect.Maps; +import com.google.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; + +@Singleton public class ControllerService { private static final Logger logger = LoggerFactory.getLogger(ControllerService.class); + private Map players; + + public ControllerService() { + players = Maps.newConcurrentMap(); + } + + public void addPlayer(int playerId) { + + if(players.containsKey(playerId)) + return; + + // TODO use a Guice supplied Factory to get the appropriate state. + players.put(playerId, new ControllerState()); + } + public void updatePlayerState(int playerId, ControllerProperty propToUpdate, int valueToSet) { + if(this.players.get(playerId) == null) { + logger.error("Player with id: {} not found.", playerId); + throw new PlayerNotFoundException(); + } + this.players.get(playerId).setState(propToUpdate, valueToSet); + } + + public int getPlayerState(int playerId, ControllerProperty property) { + if(this.players.get(playerId) == null) { + logger.error("Player with id: {} not found.", playerId); + throw new PlayerNotFoundException(); + } + return this.players.get(playerId).getState(property); + } } diff --git a/server/src/main/java/com/colonelpanic/n64all/server/service/PlayerNotFoundException.java b/server/src/main/java/com/colonelpanic/n64all/server/service/PlayerNotFoundException.java new file mode 100644 index 0000000..a9c7fcb --- /dev/null +++ b/server/src/main/java/com/colonelpanic/n64all/server/service/PlayerNotFoundException.java @@ -0,0 +1,4 @@ +package com.colonelpanic.n64all.server.service; + +public class PlayerNotFoundException extends RuntimeException { +} diff --git a/server/src/test/java/com/colonelpanic/n64all/server/service/ControllerServiceTest.java b/server/src/test/java/com/colonelpanic/n64all/server/service/ControllerServiceTest.java new file mode 100644 index 0000000..ed18690 --- /dev/null +++ b/server/src/test/java/com/colonelpanic/n64all/server/service/ControllerServiceTest.java @@ -0,0 +1,53 @@ +package com.colonelpanic.n64all.server.service; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static com.colonelpanic.n64all.server.model.ControllerProperty.ANALOG_X; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ControllerServiceTest { + + private ControllerService sut; + + @BeforeEach + public void setUp() { + sut = new ControllerService(); + } + + @AfterEach + public void tearDown() { + } + + @Test + public void shouldBarfIfStateUpdatedForUncreatedPlayer() { + //given + int playerId = 15; + + assertThrows(PlayerNotFoundException.class, + () -> sut.updatePlayerState(playerId, ANALOG_X, 5)); + } + + @Test + public void shouldBarfOnGetStateForUncreatedPlayer() { + //given + int playerId = 15; + + assertThrows(PlayerNotFoundException.class, + () -> sut.getPlayerState(playerId, ANALOG_X)); + } + + @Test + public void shouldUpdateStateForPrecreatedPlayer() { + //given + int playerId = 1; + int stateValue = 5; + sut.addPlayer(playerId); + sut.updatePlayerState(playerId, ANALOG_X, 5); + + assertEquals(stateValue, sut.getPlayerState(playerId, ANALOG_X)); + } + +} \ No newline at end of file From aeb95119f3b814d35935d4207b967476ba25abcd Mon Sep 17 00:00:00 2001 From: Ryan Collins Date: Sat, 19 Oct 2019 14:45:03 +0100 Subject: [PATCH 5/5] #18: Add state and tests for ControllerState --- .../n64all/server/model/ControllerState.java | 3 ++ .../server/model/ControllerStateTest.java | 52 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 server/src/test/java/com/colonelpanic/n64all/server/model/ControllerStateTest.java diff --git a/server/src/main/java/com/colonelpanic/n64all/server/model/ControllerState.java b/server/src/main/java/com/colonelpanic/n64all/server/model/ControllerState.java index 85622f7..5b083fc 100644 --- a/server/src/main/java/com/colonelpanic/n64all/server/model/ControllerState.java +++ b/server/src/main/java/com/colonelpanic/n64all/server/model/ControllerState.java @@ -2,10 +2,13 @@ import com.colonelpanic.n64all.server.service.PlayerController; import com.google.common.collect.Maps; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Map; public class ControllerState implements PlayerController { + private static final Logger logger = LoggerFactory.getLogger(ControllerState.class); private Map properties; public ControllerState() { diff --git a/server/src/test/java/com/colonelpanic/n64all/server/model/ControllerStateTest.java b/server/src/test/java/com/colonelpanic/n64all/server/model/ControllerStateTest.java new file mode 100644 index 0000000..8de0350 --- /dev/null +++ b/server/src/test/java/com/colonelpanic/n64all/server/model/ControllerStateTest.java @@ -0,0 +1,52 @@ +package com.colonelpanic.n64all.server.model; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.*; + +class ControllerStateTest { + private static final int NUMBER_OF_TRIALS = 15; + private ControllerState sut; + + @BeforeEach + void setUp() { + sut = new ControllerState(); + } + + @AfterEach + void tearDown() { + } + + @Test + public void shouldSetStateCorrectlyForValidValue() { + Random randGen = new Random(); + + for (int i = 0; i < NUMBER_OF_TRIALS; i++) { + ControllerProperty p = givenRandomControllerProperty(randGen); + int expectedValue = randGen.nextInt(p.getMaxValue() - p.getMinValue()) + p.getMinValue(); + + sut.setState(p, expectedValue); + assertEquals(expectedValue, sut.getState(p)); + } + } + + @Test + public void shouldNotSetStateForInvalidValue() { + int invalidValue = 1000; + + for(ControllerProperty prop : ControllerProperty.values()) { + sut.setState(prop, invalidValue); + assertEquals(prop.getDefaultValue(), sut.getState(prop)); + } + } + + private ControllerProperty givenRandomControllerProperty(Random randGen) { + ControllerProperty[] props = ControllerProperty.values(); + return props[randGen.nextInt(props.length)]; + } + +} \ No newline at end of file