From 3eeb4d25bd56dd896bad4c784c2f91de27c62f7e Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Sat, 30 Nov 2024 17:58:24 +0100 Subject: [PATCH] start online game --- src/GameController.java | 131 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 9 deletions(-) diff --git a/src/GameController.java b/src/GameController.java index dfa6803..381dfbe 100644 --- a/src/GameController.java +++ b/src/GameController.java @@ -2,10 +2,16 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; public class GameController { + + // Connection timeout for client sockets in milliseconds + public static final int CONNECTION_TIMEOUT = 10 * 1000; public HashMap> supportedVersions = new HashMap<>(Map.of( "1.1.0", OnlinePlayer_1_1_0.class @@ -13,8 +19,12 @@ public class GameController { public void startOnlineGame(Class localPlayerClass, InetSocketAddress address) throws IOException { AsyncSocket clientSocket; - if (address.getHostName() == null) { + + boolean localPlayerIsServer = address.getHostName() == null; + + if (localPlayerIsServer) { // SERVER MODE + ServerSocket serverSocket = new ServerSocket(address.getPort()); System.out.println("Waiting for client connection..."); @@ -23,10 +33,21 @@ public class GameController { serverSocket.close(); } else { + // CLIENT MODE + Socket socket = new Socket(); - socket.connect(address); - clientSocket = new AsyncSocket(socket, null); + try { + socket.connect(address, CONNECTION_TIMEOUT); + + clientSocket = new AsyncSocket(socket, null); + } catch (SocketTimeoutException e) { + e.printStackTrace(); + throw new RuntimeException("Connection timed out"); + } finally { + socket.close(); + } + } clientSocket.send("VERSION", "Gruppe03 " + String.join(" ", supportedVersions.keySet())); @@ -34,15 +55,101 @@ public class GameController { SocketPackage socketPackage = new SocketPackage(message); if (socketPackage.getName().equals("VERSION")) { - // TODO: check version matches - instantiate online player + + List opponentSupportedVersions = socketPackage.splitData(); + + String usedVersion = findMostRecentVersion(new ArrayList(supportedVersions.keySet()), opponentSupportedVersions); + + if (usedVersion == null) { + throw new RuntimeException("No common versions found"); + } + + // instantiate players + Class onlinePlayerClass = supportedVersions.get(usedVersion); + + LocalPlayer localPlayer; + OnlinePlayer onlinePlayer; + try { + localPlayer = localPlayerClass.getDeclaredConstructor().newInstance(); + onlinePlayer = onlinePlayerClass.getDeclaredConstructor().newInstance(); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("Unable to instantiate players"); + } + + localPlayer.isServer = localPlayerIsServer; + onlinePlayer.isServer = !localPlayerIsServer; + + startGameWithInstancedPlayers(localPlayer, onlinePlayer); + } else { - // TODO: received invalid package / package out of order + throw new RuntimeException("Unexpected Package received before game initialisation"); } }); - // TODO: instantiate local player, set server / client roles } + /** + * finds the largest common version in two lists of version strings + * @return null if no common versions are found + */ + public String findMostRecentVersion(List versions1, List versions2) { + if (versions1 == null || versions2 == null) return null; + String largestCommonVersion = null; + for (String v1 : versions1) { + if (!checkVersionString(v1)) continue; + + for (String v2 : versions2) { + if (!checkVersionString(v2)) continue; + + // strings within the lists must be equal + // if no largest common version has been found or currently checked version is larger than + // previous largest common version, new largest version has been found + if (compareVersions(v1, v2) == 0 && (largestCommonVersion == null || compareVersions(v1, largestCommonVersion) >= 1)) { + largestCommonVersion = v1; + continue; + } + } + } + return largestCommonVersion; + } + + /** + * compares two version strings + * @return + * 0 if versions are equal + * 1 if version1 is more recent than version2 + * -1 otherwise + */ + public int compareVersions(String version1, String version2) { + if (!checkVersionString(version1) || !checkVersionString(version2)) { + throw new IllegalArgumentException("Version is not valid version string"); + } + + String[] version1Split = version1.split("\\."); + String[] version2Split = version2.split("\\."); + + for (int i = 0; i < version1Split.length; i++) { + int v1 = Integer.parseInt(version1Split[i]); + int v2 = Integer.parseInt(version2Split[i]); + + if (v1 == v2) continue; + if (v1 > v2) { + return 1; + } else { + return -1; + } + } + return 0; + } + + /** + * checks if a provided string matches the format of a version number + */ + public boolean checkVersionString(String versionString) { + return versionString != null && versionString.matches("\\d+\\.\\d+\\.\\d+"); + } + public void startLocalGame(Class localPlayerClass, Class enemyClass, int size) { LocalPlayer localPlayer; @@ -52,10 +159,16 @@ public class GameController { aiPlayer = enemyClass.getDeclaredConstructor().newInstance(); } catch (Exception e) { e.printStackTrace(); - return; + throw new RuntimeException("Unable to instantiate players"); } - localPlayer.setEnemy(aiPlayer); - aiPlayer.setEnemy(localPlayer); + startGameWithInstancedPlayers(localPlayer, aiPlayer); + } + + private void startGameWithInstancedPlayers(LocalPlayer p1, Player p2) { + p1.setEnemy(p2); + p2.setEnemy(p1); + + // TODO: frontend configuration } } \ No newline at end of file