diff --git a/matchBrowser/pom.xml b/matchBrowser/pom.xml new file mode 100644 index 00000000..fb8cabe9 --- /dev/null +++ b/matchBrowser/pom.xml @@ -0,0 +1,82 @@ + + + + team-7 + seng302 + 2.0 + + 4.0.0 + + + jar + matchBrowser + matchBrowser + 2.0 + + + + junit + junit + 4.12 + test + + + + + org.mockito + mockito-all + 1.9.5 + + + + org.testng + testng + 6.11 + test + + + + + 1.8 + 1.8 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.3 + + + + + app.Main + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + + package + + shade + + + + + + + + \ No newline at end of file diff --git a/matchBrowser/src/main/java/app/Main.java b/matchBrowser/src/main/java/app/Main.java new file mode 100644 index 00000000..e189c052 --- /dev/null +++ b/matchBrowser/src/main/java/app/Main.java @@ -0,0 +1,7 @@ +package app; + +/** + * Used when starting the matchmaking browser + */ +public class Main { +} diff --git a/matchBrowser/src/main/java/model/MatchTable.java b/matchBrowser/src/main/java/model/MatchTable.java new file mode 100644 index 00000000..d2798939 --- /dev/null +++ b/matchBrowser/src/main/java/model/MatchTable.java @@ -0,0 +1,34 @@ +package model; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Holds a table object that stores current games + */ +public class MatchTable { + private HashMap matchTable; + + public MatchTable() { + this.matchTable = new HashMap(); + } + + public void addEntry(ArrayList newEntry) { + //create a key from the ip and port + TableKey entryKey = new TableKey((String) newEntry.get(0), (Integer) newEntry.get(1)); + + //get the rest of the entry and use it as the value + List entryItems = new ArrayList(); + for(int i = 2; i getMatchTable() { + return matchTable; + } +} diff --git a/matchBrowser/src/main/java/model/TableKey.java b/matchBrowser/src/main/java/model/TableKey.java new file mode 100644 index 00000000..6b803fd9 --- /dev/null +++ b/matchBrowser/src/main/java/model/TableKey.java @@ -0,0 +1,30 @@ +package model; + +/** + * Used to create a key made of an ip and port. + */ +public class TableKey { + + private final String ip; + private final int port; + + public TableKey(String ip, int port) { + this.ip = ip; + this.port = port; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof TableKey)) return false; + TableKey key = (TableKey) o; + return ip == key.ip && port == key.port; + } + + @Override + public int hashCode() { + int result = port; + result = 31 * result + ip.hashCode(); + return result; + } +} diff --git a/matchBrowser/src/main/java/networkInterface/InInterface.java b/matchBrowser/src/main/java/networkInterface/InInterface.java new file mode 100644 index 00000000..5d729e08 --- /dev/null +++ b/matchBrowser/src/main/java/networkInterface/InInterface.java @@ -0,0 +1,46 @@ +package networkInterface; + +import java.io.*; +import java.net.*; + +/** + * Holds the output for the network for + */ +public class InInterface { + private DatagramSocket serverSocket; + private byte[] receiveData = new byte[1024]; + private byte[] sendData = new byte[1024]; + + public InInterface(){ + try { + this.serverSocket = new DatagramSocket(3779); + + this.run(); + } catch (IOException e) { + System.err.println("Error listening on port: " + this.serverSocket.getLocalPort() + "."); + System.exit(-1); + } + + } + + private void run() throws IOException{ + while(true) { + DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); + serverSocket.receive(receivePacket); + + //decode and update table + + //client ip and port + InetAddress IPAddress = receivePacket.getAddress(); + int port = receivePacket.getPort(); + + + +// String capitalizedSentence = sentence.toUpperCase(); +// sendData = capitalizedSentence.getBytes(); +// DatagramPacket sendPacket = +// new DatagramPacket(sendData, sendData.length, IPAddress, port); +// serverSocket.send(sendPacket); + } + } +} diff --git a/matchBrowser/src/main/java/networkInterface/OutInterface.java b/matchBrowser/src/main/java/networkInterface/OutInterface.java new file mode 100644 index 00000000..18746004 --- /dev/null +++ b/matchBrowser/src/main/java/networkInterface/OutInterface.java @@ -0,0 +1,7 @@ +package networkInterface; + +/** + * Holds the connection to the network for output + */ +public class OutInterface { +} diff --git a/matchBrowser/src/test/java/model/MatchTableTest.java b/matchBrowser/src/test/java/model/MatchTableTest.java new file mode 100644 index 00000000..6c16cd9e --- /dev/null +++ b/matchBrowser/src/test/java/model/MatchTableTest.java @@ -0,0 +1,27 @@ +package model; + +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; + +public class MatchTableTest { + private MatchTable testTable; + + @Before + public void setUp() { + testTable = new MatchTable(); + } + + @Test + public void testTable() { + ArrayList entry = new ArrayList(Arrays.asList("127.0.0.1", 4942, 1, 1, 2, 6, 1)); + + testTable.addEntry(entry); + + assertEquals(testTable.getMatchTable().get(new TableKey("127.0.0.1", 4942)), Arrays.asList(1, 1, 2, 6, 1)); + } +} diff --git a/racevisionGame/src/main/java/network/MessageDecoders/HostGameMessageDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/HostGameMessageDecoder.java new file mode 100644 index 00000000..3991b83e --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageDecoders/HostGameMessageDecoder.java @@ -0,0 +1,63 @@ +package network.MessageDecoders; + +import network.Exceptions.InvalidMessageException; +import network.Messages.AC35Data; +import network.Messages.CourseWinds; +import network.Messages.Enums.RaceStatusEnum; +import network.Messages.HostGame; +import network.Messages.RaceStatus; + +import java.util.Arrays; + +import static network.Utils.ByteConverter.bytesToInt; + +public class HostGameMessageDecoder implements MessageDecoder { + + /** + * The encoded message. + */ + private byte[] encodedMessage; + + /** + * The decoded message. + */ + private HostGame message; + + /** + * Constructor + */ + public HostGameMessageDecoder() { + } + + @Override + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { + this.encodedMessage = encodedMessage; + + try{ + byte ipPart1 = encodedMessage[0]; + byte ipPart2 = encodedMessage[1]; + byte ipPart3 = encodedMessage[2]; + byte ipPart4 = encodedMessage[3]; + String ipString = ipPart1 + "." + ipPart2 + "." + ipPart3 + "." + ipPart4; +// System.out.println(ipString); + int port = bytesToInt(Arrays.copyOfRange(encodedMessage, 4, 8)); + byte map = encodedMessage[8]; + byte speed = encodedMessage[9]; + byte status = encodedMessage[10]; + byte requiredNumPlayers = encodedMessage[11]; + byte currentNumPlayers = encodedMessage[12]; + + + message = new HostGame(ipString, port, map, + speed, RaceStatusEnum.fromByte(status), + requiredNumPlayers, currentNumPlayers); + + return message; + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode Host game message.", e); + } + } + + +} diff --git a/racevisionGame/src/main/java/network/MessageDecoders/HostedGamesRequestDecoder.java b/racevisionGame/src/main/java/network/MessageDecoders/HostedGamesRequestDecoder.java new file mode 100644 index 00000000..95f5cf5c --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageDecoders/HostedGamesRequestDecoder.java @@ -0,0 +1,34 @@ +package network.MessageDecoders; + +import network.Exceptions.InvalidMessageException; +import network.Messages.AC35Data; +import network.Messages.HostGame; +import network.Messages.HostGamesRequest; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static network.Utils.ByteConverter.bytesToInt; + +public class HostedGamesRequestDecoder implements MessageDecoder{ + @Override + public AC35Data decode(byte[] encodedMessage) throws InvalidMessageException { + try{ + int numberOfGames = bytesToInt(Arrays.copyOfRange(encodedMessage, 0, 4)); + + HostGameMessageDecoder lineDecoder = new HostGameMessageDecoder(); + List knownGames = new ArrayList<>(); + int byteIndex = 4; + for (int i = 0; i < numberOfGames; i++){ + knownGames.add((HostGame) lineDecoder.decode(Arrays.copyOfRange(encodedMessage, byteIndex, byteIndex+14))); + byteIndex += 14; + } + + return new HostGamesRequest(knownGames); + + } catch (Exception e) { + throw new InvalidMessageException("Could not decode Host game message.", e); + } + } +} diff --git a/racevisionGame/src/main/java/network/MessageEncoders/HostGameMessageEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/HostGameMessageEncoder.java new file mode 100644 index 00000000..0a5c9a08 --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageEncoders/HostGameMessageEncoder.java @@ -0,0 +1,54 @@ +package network.MessageEncoders; + +import network.Exceptions.InvalidMessageException; +import network.Messages.AC35Data; +import network.Messages.HostGame; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.List; + +import static network.Utils.ByteConverter.intToBytes; + + +public class HostGameMessageEncoder implements MessageEncoder{ + + /** + * Constructor + */ + public HostGameMessageEncoder() { + } + + @Override + public byte[] encode(AC35Data message) throws InvalidMessageException { + try{ + //Downcast + HostGame hostGame = (HostGame) message; + + ByteBuffer hostGameMessage = ByteBuffer.allocate(14); + + ByteBuffer ipBytes = ByteBuffer.allocate(4); + String ip = hostGame.getIp(); + String[] ipValues = ip.split("\\."); + for(String value:ipValues){ + ipBytes.put(intToBytes(Integer.parseInt(value), 1)[0]); + } + byte raceStatus = hostGame.getStatus().getValue(); + + hostGameMessage.put(ipBytes.array()); + hostGameMessage.put(intToBytes(hostGame.getPort())); + hostGameMessage.put(hostGame.getMap()); + hostGameMessage.put(hostGame.getSpeed()); + hostGameMessage.put(raceStatus); + hostGameMessage.put(hostGame.getRequiredNumPlayers()); + hostGameMessage.put(hostGame.getCurrentNumPlayers()); + + +// System.out.println(hostGameMessage.array()[4]); + return hostGameMessage.array(); + + } catch (Exception e) { + throw new InvalidMessageException("Could not encode Host game message.", e); + } + } +} diff --git a/racevisionGame/src/main/java/network/MessageEncoders/HostedGamesRequestEncoder.java b/racevisionGame/src/main/java/network/MessageEncoders/HostedGamesRequestEncoder.java new file mode 100644 index 00000000..4b4b52d1 --- /dev/null +++ b/racevisionGame/src/main/java/network/MessageEncoders/HostedGamesRequestEncoder.java @@ -0,0 +1,44 @@ +package network.MessageEncoders; + +import network.Exceptions.InvalidMessageException; +import network.Messages.AC35Data; +import network.Messages.HostGame; +import network.Messages.HostGamesRequest; + +import java.nio.ByteBuffer; +import java.util.List; + +import static network.Utils.ByteConverter.intToBytes; + +public class HostedGamesRequestEncoder implements MessageEncoder{ + + /** + * Constructor + */ + public HostedGamesRequestEncoder() { + } + + @Override + public byte[] encode(AC35Data message) throws InvalidMessageException { + try{ + //Downcast + HostGamesRequest hostGamesRequest = (HostGamesRequest) message; + + int numGames = hostGamesRequest.getKnownGames().size(); + + ByteBuffer hostedGamesRequestMessage = ByteBuffer.allocate(4+14*numGames); + + hostedGamesRequestMessage.put(intToBytes(numGames)); + + HostGameMessageEncoder lineEncoder = new HostGameMessageEncoder(); + for (HostGame line: hostGamesRequest.getKnownGames()) { + hostedGamesRequestMessage.put(lineEncoder.encode(line)); + } + + return hostedGamesRequestMessage.array(); + + }catch(Exception e){ + throw new InvalidMessageException("Could not encode Host game message.", e); + } + } +} diff --git a/racevisionGame/src/main/java/network/Messages/Enums/MessageType.java b/racevisionGame/src/main/java/network/Messages/Enums/MessageType.java index aed5d70a..0941fd08 100644 --- a/racevisionGame/src/main/java/network/Messages/Enums/MessageType.java +++ b/racevisionGame/src/main/java/network/Messages/Enums/MessageType.java @@ -39,6 +39,10 @@ public enum MessageType { */ ASSIGN_PLAYER_BOAT(121), + HOST_GAME(108), + + HOSTED_GAMES_REQUEST(109), + NOTAMESSAGE(0); diff --git a/racevisionGame/src/main/java/network/Messages/HostGame.java b/racevisionGame/src/main/java/network/Messages/HostGame.java new file mode 100644 index 00000000..d03292fe --- /dev/null +++ b/racevisionGame/src/main/java/network/Messages/HostGame.java @@ -0,0 +1,79 @@ +package network.Messages; + + +import network.Messages.Enums.MessageType; +import network.Messages.Enums.RaceStatusEnum; + +public class HostGame extends AC35Data { + + private String ip; + private int port; + private byte map; + private byte speed; + private RaceStatusEnum status; + private byte requiredNumPlayers; + private byte currentNumPlayers; + + public HostGame(String ip, int port, byte map, byte speed, + RaceStatusEnum status, byte requiredNumPlayers, + byte currentNumPlayers) { + super(MessageType.HOST_GAME); + this.ip = ip; + this.port = port; + this.map = map; + this.speed = speed; + this.status = status; + this.requiredNumPlayers = requiredNumPlayers; + this.currentNumPlayers = currentNumPlayers; + + } + + /** + * @return the ip of host + */ + public String getIp() { + return ip; + } + + /** + * @return the port of host + */ + public int getPort() { + return port; + } + + /** + * @return the map index + */ + public byte getMap() { + return map; + } + + /** + * @return the speed value of game + */ + public byte getSpeed() { + return speed; + } + + /** + * @return the status of race + */ + public RaceStatusEnum getStatus() { + return status; + } + + /** + * @return required number of players + */ + public byte getRequiredNumPlayers() { + return requiredNumPlayers; + } + + /** + * @return current number of players + */ + public byte getCurrentNumPlayers() { + return currentNumPlayers; + } +} diff --git a/racevisionGame/src/main/java/network/Messages/HostGamesRequest.java b/racevisionGame/src/main/java/network/Messages/HostGamesRequest.java new file mode 100644 index 00000000..4ecfc2d2 --- /dev/null +++ b/racevisionGame/src/main/java/network/Messages/HostGamesRequest.java @@ -0,0 +1,22 @@ +package network.Messages; + +import network.Messages.Enums.MessageType; + +import java.util.List; + +public class HostGamesRequest extends AC35Data{ + + private List knownGames; + + /** + * Constructor + */ + public HostGamesRequest(List knownGames) { + super(MessageType.HOSTED_GAMES_REQUEST); + this.knownGames = knownGames; + } + + public List getKnownGames() { + return knownGames; + } +} diff --git a/racevisionGame/src/test/java/network/MessageDecoders/HostGameMessageDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/HostGameMessageDecoderTest.java new file mode 100644 index 00000000..2d73241d --- /dev/null +++ b/racevisionGame/src/test/java/network/MessageDecoders/HostGameMessageDecoderTest.java @@ -0,0 +1,36 @@ +package network.MessageDecoders; + +import network.MessageEncoders.HostGameMessageEncoder; +import network.Messages.AC35Data; +import network.Messages.Enums.RaceStatusEnum; +import network.Messages.HostGame; +import org.junit.Assert; +import org.junit.Test; + +public class HostGameMessageDecoderTest { + + @Test + public void hostGameMessageDecoderTest() throws Exception { + HostGame testHost = new HostGame("127.0.0.1", 3779, (byte) 1, (byte) 2, RaceStatusEnum.PRESTART, (byte) 6, (byte) 2); + + + HostGameMessageEncoder encoder = new HostGameMessageEncoder(); + + byte[] encodedMessage = encoder.encode(testHost); + + HostGameMessageDecoder decoder = new HostGameMessageDecoder(); + + HostGame decodedTest = (HostGame) decoder.decode(encodedMessage); + + compareHostGameMessage(testHost, decodedTest); + } + + public static void compareHostGameMessage(HostGame original, HostGame decoded) { + Assert.assertEquals(original.getIp(), decoded.getIp()); + Assert.assertEquals(original.getPort(), decoded.getPort()); + Assert.assertEquals(original.getSpeed(), decoded.getSpeed()); + Assert.assertEquals(original.getStatus(), decoded.getStatus()); + Assert.assertEquals(original.getRequiredNumPlayers(), decoded.getRequiredNumPlayers()); + Assert.assertEquals(original.getCurrentNumPlayers(), decoded.getCurrentNumPlayers()); + } +} diff --git a/racevisionGame/src/test/java/network/MessageDecoders/HostedGamesRequestDecoderTest.java b/racevisionGame/src/test/java/network/MessageDecoders/HostedGamesRequestDecoderTest.java new file mode 100644 index 00000000..7567fe23 --- /dev/null +++ b/racevisionGame/src/test/java/network/MessageDecoders/HostedGamesRequestDecoderTest.java @@ -0,0 +1,38 @@ +package network.MessageDecoders; + + +import network.MessageEncoders.HostGameMessageEncoder; +import network.MessageEncoders.HostedGamesRequestEncoder; +import network.Messages.Enums.RaceStatusEnum; +import network.Messages.HostGame; +import network.Messages.HostGamesRequest; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +public class HostedGamesRequestDecoderTest { + @Test + public void hostGamesRequestMessageDecoderTest() throws Exception { + HostGame testHostGame1 = new HostGame("127.0.0.1", 3779, (byte) 1, (byte) 2, RaceStatusEnum.PRESTART, (byte) 6, (byte) 2); + HostGame testHostGame2 = new HostGame("127.0.0.1", 3780, (byte) 1, (byte) 2, RaceStatusEnum.PRESTART, (byte) 6, (byte) 2); + + List knownGames = Arrays.asList(testHostGame1, testHostGame2); + + HostedGamesRequestEncoder encoder = new HostedGamesRequestEncoder(); + + byte[] encodedMessage = encoder.encode(new HostGamesRequest(knownGames)); + + HostedGamesRequestDecoder decoder = new HostedGamesRequestDecoder(); + + HostGamesRequest decodedTest = (HostGamesRequest) decoder.decode(encodedMessage); + + compareHostGamesRequestMessage(knownGames, decodedTest.getKnownGames()); + } + + public static void compareHostGamesRequestMessage(List original, List decoded) { + Assert.assertEquals(original.get(0).getIp(), decoded.get(0).getIp()); + Assert.assertEquals(original.get(1).getPort(), decoded.get(1).getPort()); + } +}