diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4c363e1d..43671da5 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -15,10 +15,10 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v2
- - name: Set up JDK 17
- uses: actions/setup-java@v3
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
with:
- java-version: 17
+ java-version: 21
distribution: 'temurin'
# Step that caches and restores maven dependencies
- name: Cache maven dependencies
@@ -32,3 +32,7 @@ jobs:
run: sudo apt-get install -y genisoimage
- name: Build with Maven
run: mvn -B install --file pom.xml
+ - name: Build Docker image
+ uses: docker/build-push-action@v5
+ with:
+ tags: philippvk/minigolf:latest
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 43af4dd6..4737b92b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -18,10 +18,10 @@ jobs:
uses: metcalfc/changelog-generator@v0.4.3
with:
myToken: ${{ secrets.GITHUB_TOKEN }}
- - name: Set up JDK 17
- uses: actions/setup-java@v3
+ - name: Set up JDK 21
+ uses: actions/setup-java@v4
with:
- java-version: 17
+ java-version: 21
distribution: 'temurin'
# Step that caches and restores maven dependencies
- name: Cache maven dependencies
diff --git a/Dockerfile b/Dockerfile
index bf1f8521..5d067365 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,16 +1,15 @@
#
# Build stage
#
-FROM maven:3.6.0-jdk-8-slim AS build
+FROM maven:3.9.7-eclipse-temurin-21 AS build
COPY . /home/app/
RUN mvn -f /home/app/pom.xml -pl server -am clean package
#
# Package stage
#
-FROM openjdk:8-alpine
+FROM eclipse-temurin:21-alpine
COPY --from=build /home/app/server/target/server-*.jar /home/minigolf/server.jar
-COPY tracks/ /home/minigolf/tracks/
EXPOSE 4242
WORKDIR /home/minigolf
ENTRYPOINT ["java","-jar","server.jar"]
\ No newline at end of file
diff --git a/README.md b/README.md
index 28c0fba2..6e32f15e 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ The Java Applet-based Minigolf Client was one of the most popular multiplayer ga
### Prerequisites
- Clone this repo: `git clone git@github.com:PhilippvK/playforia-minigolf.git`
-- Install Java Development Kit 17 (https://adoptium.net/en-GB/temurin/releases/)
+- Install Java Development Kit 21 (https://adoptium.net/en-GB/temurin/releases/)
- Install Apache `maven` for building: https://maven.apache.org/install.html
- *Optional:* Install IntelliJ IDEA Java IDE (https://www.jetbrains.com/idea/download/) and import this repository as project
@@ -62,7 +62,13 @@ java -jar client.jar -server 192.168.1.7 -lang en_US # Replace IP with the one o
#### Running Minigolf Server in Docker Container
-We provide an experimental Dockerfile for easy hosting of the server application. You can either build the image by yourself or download the pre-build images from [quay.io](https://quay.io/repository/philippvk/minigolf) via `docker pull quay.io/philippvk/minigolf:latest`.
+We provide an experimental Dockerfile for easy hosting of the server application.
+You can either build and run the image:
+```sh
+docker build -t pfmg .
+docker run pfmg
+```
+or download the pre-built images from [quay.io](https://quay.io/repository/philippvk/minigolf) via `docker pull quay.io/philippvk/minigolf:latest`.
Running the Editor is quite straightforward as it can be started like expected: `java -jar editor.jar`
@@ -83,7 +89,7 @@ Client CLI options:
## Compatibility
Tested:
-- Ubuntu 22.04 with Java version `17.0.6`
+- Ubuntu 22.04 with Java version `21.0.3`
- Windows 10/11
## Problems
diff --git a/client/pom.xml b/client/pom.xml
index 82ac99c6..20887f87 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -15,8 +15,8 @@
org.moparforia.client.Launcher
Playforia Minigolf Client
${project.build.directory}/downloads
- https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.7%2B7/OpenJDK17U-jre_x64_mac_hotspot_17.0.7_7.tar.gz
- jdk-17.0.7+7-jre
+ https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2%2B13/OpenJDK21U-jre_aarch64_mac_hotspot_21.0.2_13.tar.gz
+ jdk-21.0.2+13-jre
@@ -84,7 +84,7 @@
com.googlecode.maven-download-plugin
download-maven-plugin
- 1.6.8
+ 1.9.0
download-osx-jre
@@ -104,7 +104,6 @@
sh.tak.appbundler
appbundle-maven-plugin
- 1.2.0
${project.name}
src/main/resources/icons/playforia.icns
@@ -133,7 +132,6 @@
com.akathist.maven.plugins.launch4j
launch4j-maven-plugin
- 2.3.3
windows-build
@@ -154,7 +152,7 @@
src/main/resources/icons/playforia.ico
jre
- 17
+ 21
1.0.0.0
@@ -174,7 +172,7 @@
plantuml-generator-maven-plugin
de.elnarion.maven
- 1.1.2
+ 2.4.1
generate-simple-diagram
diff --git a/client/src/test/java/org/moparforia/client/LauncherCLITest.java b/client/src/test/java/org/moparforia/client/LauncherCLITest.java
index c0d7e069..13434423 100644
--- a/client/src/test/java/org/moparforia/client/LauncherCLITest.java
+++ b/client/src/test/java/org/moparforia/client/LauncherCLITest.java
@@ -5,6 +5,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.quality.Strictness;
import picocli.CommandLine;
import javax.swing.JFrame;
@@ -42,7 +43,7 @@ class LauncherCLITest {
void setUp() throws Exception {
// Mock game
launcher = mock(Launcher.class, withSettings()
- .lenient()
+ .strictness(Strictness.LENIENT)
.withoutAnnotations());
// Use real methods
diff --git a/pom.xml b/pom.xml
index 0f4b3fc3..63d497e7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,6 +7,11 @@
pom
2.1.2.0-BETA
Playforia Minigolf
+
+ Playforia
+
+ 2002
+ An online multiplayer minigolf game
server
@@ -18,7 +23,7 @@
UTF-8
test.mainClass
- 4.5.2
+ 4.7.6
@@ -26,16 +31,16 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.11.0
+ 3.13.0
- 17
- 17
+ 21
+ 21
org.apache.maven.plugins
maven-shade-plugin
- 3.2.4
+ 3.5.3
package
@@ -55,6 +60,7 @@
+ false
@@ -67,16 +73,20 @@
com.akathist.maven.plugins.launch4j
launch4j-maven-plugin
- 1.7.25
+ 2.5.0
org.codehaus.mojo
exec-maven-plugin
- 3.0.0
+ 3.3.0
+ org.apache.maven.plugins
maven-surefire-plugin
- 2.22.2
+ 3.2.5
+
+ -XX:+EnableDynamicAgentLoading
+
@@ -105,37 +115,31 @@
org.junit.jupiter
junit-jupiter-engine
- 5.6.2
+ 5.10.2
test
org.mockito
mockito-core
- 3.5.10
+ 5.12.0
test
org.mockito
mockito-junit-jupiter
- 3.5.10
+ 5.12.0
test
com.github.marschall
memoryfilesystem
- 2.1.0
- test
-
-
- org.softsmithy.lib
- softsmithy-lib-core
- 2.1.1
+ 2.8.0
test
de.elnarion.util
plantuml-generator-util
- 1.1.2
+ 2.4.1
diff --git a/server/pom.xml b/server/pom.xml
index 2b543bdc..c8678bbd 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -81,7 +81,7 @@
plantuml-generator-maven-plugin
de.elnarion.maven
- 1.1.2
+ 2.4.1
generate-simple-diagram
diff --git a/server/src/main/java/org/moparforia/server/Server.java b/server/src/main/java/org/moparforia/server/Server.java
index 8659aeb8..1fe8a4f7 100644
--- a/server/src/main/java/org/moparforia/server/Server.java
+++ b/server/src/main/java/org/moparforia/server/Server.java
@@ -50,6 +50,9 @@ public class Server implements Runnable {
private int port;
private Optional tracksDirectory;
+ private Channel serverChannel;
+ private boolean running;
+
private HashMap lobbies = new HashMap();
//private ArrayList lobbies = new ArrayList();
//private HashMap games = new HashMap();
@@ -188,17 +191,23 @@ public void start() {
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
try {
- bootstrap.bind(new InetSocketAddress(host, port));
+ this.serverChannel = bootstrap.bind(new InetSocketAddress(host, port));
+ this.running = true;
new Thread(this).start();
} catch (Exception ex) {
ex.printStackTrace();
}
}
+ public void stop() throws InterruptedException {
+ this.serverChannel.close().sync();
+ this.running = false;
+ }
+
@Override
public void run() {
System.out.println("Started server on host " + this.host + " with port " + this.port);
- while (true) {
+ while (this.running) {
try {
Thread.sleep(10);
Iterator iterator = events.iterator();
diff --git a/server/src/main/java/org/moparforia/server/event/ClientDisconnectedEvent.java b/server/src/main/java/org/moparforia/server/event/ClientDisconnectedEvent.java
index 09852fd8..6c24f985 100644
--- a/server/src/main/java/org/moparforia/server/event/ClientDisconnectedEvent.java
+++ b/server/src/main/java/org/moparforia/server/event/ClientDisconnectedEvent.java
@@ -18,7 +18,7 @@ public void process(Server server) {
Player player;
if ((player = (Player)channel.getAttachment()) != null) {
if (player.getLobby() != null) {
- player.getLobby().removePlayer(player, Lobby.PART_REASON_USERLEFT,null);
+ player.getLobby().removePlayer(player, Lobby.PART_REASON_USERLEFT);
}
}
System.out.println("Client disconnected: " + channel);
diff --git a/server/src/main/java/org/moparforia/server/net/packethandlers/QuitHandler.java b/server/src/main/java/org/moparforia/server/net/packethandlers/QuitHandler.java
index 815b72e3..454bfa90 100644
--- a/server/src/main/java/org/moparforia/server/net/packethandlers/QuitHandler.java
+++ b/server/src/main/java/org/moparforia/server/net/packethandlers/QuitHandler.java
@@ -28,7 +28,7 @@ public Pattern getPattern() {
public boolean handle(Server server, Packet packet, Matcher message) {
Player player = (Player) packet.getChannel().getAttachment();
if (message.group(1).contains("lobby")) {
- player.getLobby().removePlayer(player, Lobby.PART_REASON_USERLEFT, null);
+ player.getLobby().removePlayer(player, Lobby.PART_REASON_USERLEFT);
}
packet.getChannel().disconnect();
packet.getChannel().close();
diff --git a/server/src/test/java/org/moparforia/server/ServerTest.java b/server/src/test/java/org/moparforia/server/ServerTest.java
new file mode 100644
index 00000000..65dbe18e
--- /dev/null
+++ b/server/src/test/java/org/moparforia/server/ServerTest.java
@@ -0,0 +1,117 @@
+package org.moparforia.server;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.Socket;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class ServerTest {
+
+ private void sendMessage(BufferedWriter writer, String message) throws IOException {
+ writer.write(message);
+ writer.newLine();
+ writer.flush();
+ }
+
+ @Test
+ void testSinglePlayerFlow() throws IOException, InterruptedException {
+ Server server = new Server("127.0.0.1", 4243, Optional.empty());
+ server.start();
+
+ Socket socket = new Socket("127.0.0.1", 4243);
+ InputStream in = socket.getInputStream();
+ OutputStream out = socket.getOutputStream();
+ InputStreamReader r = new InputStreamReader(in);
+ OutputStreamWriter w = new OutputStreamWriter(out);
+ BufferedReader reader = new BufferedReader(r);
+ BufferedWriter writer = new BufferedWriter(w);
+
+ // init
+ String h = reader.readLine();
+ String cIo = reader.readLine();
+ String cCrt = reader.readLine();
+ String cCtr = reader.readLine();
+ assertEquals("h 1", h);
+ assertTrue(cIo.matches("c io \\d+"));
+ assertEquals("c crt 250", cCrt);
+ assertEquals("c ctr", cCtr);
+
+ String nickname = "nick";
+
+ // client id
+ this.sendMessage(writer, "c new");
+ String cId = reader.readLine();
+ assertEquals("c id 0", cId);
+
+ // version
+ this.sendMessage(writer, "d 0 version\t35");
+ String statusLogin = reader.readLine();
+ assertEquals("d 0 status\tlogin", statusLogin);
+
+ // login
+ this.sendMessage(writer, "d 1 ttlogin\t" + nickname + "\t");
+ String basicInfo = reader.readLine();
+ String statusLobbyselect = reader.readLine();
+ assertEquals("d 1 basicinfo\tt\t0\tt\tf", basicInfo);
+ assertEquals("d 2 status\tlobbyselect\t300", statusLobbyselect);
+
+ // number of players
+ this.sendMessage(writer, "d 2 lobbyselect\trnop");
+ String lobbySelectNop = reader.readLine();
+ assertEquals("d 3 lobbyselect\tnop\t0\t0\t0", lobbySelectNop);
+
+ // select single player
+ this.sendMessage(writer, "d 3 lobbyselect\tselect\t1");
+ String statusLobby = reader.readLine();
+ String lobbyUsers = reader.readLine();
+ String lobbyOwnjoin = reader.readLine();
+ assertEquals("d 4 status\tlobby\t1", statusLobby);
+ assertEquals("d 5 lobby\tusers", lobbyUsers);
+ assertEquals("d 6 lobby\townjoin\t3:" + nickname + "^w^10000^-^-^-", lobbyOwnjoin);
+ this.sendMessage(writer, "d 4 lobby\ttracksetlist");
+ String tracksetlist = reader.readLine();
+ assertEquals(tracksetlist, "d 7 lobby\ttracksetlist\tBirchwood\t1\t9\tNo one\t1\tNo one\t1\tNo one\t1\tNo one\t1\tOak Park\t1\t18\tNo one\t1\tNo one\t1\tNo one\t1\tNo one\t1\tOne by One\t2\t18\tNo one\t1\tNo one\t1\tNo one\t1\tNo one\t1\tScary Set\t3\t9\tNo one\t1\tNo one\t1\tNo one\t1\tNo one\t1\tSpruce Corpse\t2\t9\tNo one\t1\tNo one\t1\tNo one\t1\tNo one\t1\tThe First\t2\t18\tNo one\t1\tNo one\t1\tNo one\t1\tNo one\t1\tTorment Fields\t3\t18\tNo one\t1\tNo one\t1\tNo one\t1\tNo one\t1");
+
+ // start championship game
+ this.sendMessage(writer, "d 5 lobby\tcspc\t6");
+ String statusGame = reader.readLine();
+ String gameInfo = reader.readLine();
+ String players = reader.readLine();
+ String ownInfo = reader.readLine();
+ String gameStart = reader.readLine();
+ String resetVoteSkip = reader.readLine();
+ String startTrack = reader.readLine();
+ String startTurn = reader.readLine();
+ assertEquals("d 8 status\tgame", statusGame);
+ assertEquals("d 9 game\tgameinfo\tderp\tf\t0\t1\t18\t0\t0\t0\t0\t1\t0\t0\tf", gameInfo);
+ assertEquals("d 10 game\tplayers", players);
+ assertEquals("d 11 game\towninfo\t0\t" + nickname + "\t-", ownInfo);
+ assertEquals("d 12 game\tstart", gameStart);
+ assertEquals("d 13 game\tresetvoteskip", resetVoteSkip);
+ assertTrue(startTrack.matches("d 14 game\tstarttrack\tt\t0\tV 1\tA Leonardo\tN Revocations\tT BAMM21DBAQQ7DBAMM18DBAQQDB3ADDBAQQ6DEDDBAQQ7DB3A11DBHAQBGAQB3ABAQQ4DB3ADDBHAMEDEB3A10DEDDB3A3DBHAQBGAQB3AEE14DBAGABAIADDBAKAE3DEDEE10DEDDE6DEE6DBAQQE6DEEDDEE3DEDEE10DEDDE4DBIAHBAIAEE6DEE6DEEDDEE3DEDEE10DEDDE4DBAGA3EDBGMABHMAEDDEE6DEEDDEE3DEDEE10DEDDE4D4EDBHAMBGAMEDDEE6DEEDDEE3DEDEE10DEDDE4D4E6DEE6DEEDDEE3DEDEE9DBGLABAEADDBHFAE3DBAQQ3E6DEE6DEEDDEE3DEDEE9DBAKAGDDBAGAE3D4E6DEEDBAQQ6DEG7DBAMMEDBEAQBFAQE5DEEDDEE3D4E6DEE5DEDDEE7DEEDBHAQBAQQDE4DEEDDEE3DEBAGADE6DEE5DEG9D3EDDEBGAQE4DEEDDEE3DEDDE6DEE5DEE9DEBAQQE9DEEDDEE5DEE6DEE5DBGAQE9D3E9DEEDDEE5DEE4DBAQQDDE16D3E5DBAQQ4DEDDBAQQ7DE4DEBAGADE5DBEAQBAQQDDBGAQEDDBGMABAMMDDEBFAQE4DEBAMM3DEDDBAMA7DE4DEBAEAGE5DBAQQBGAQH4DBGMABAMM3DEDFE3DEE3DEDDE7DE4D4E5DEG5DBHAMEBGAMB3ABAQQEDDFEDDEEBIMAB3A17D4E5DEE6DBSAMGDEE3DFEDEEB3A18DBAGA3E5DEE9DEEBIQAB3A4DEEBLMAE17D4EDDBQAMEDEE9DEEB3ACBAE3DEE3DEDDBAMA7DE4D4EDBEAMBAMMBFAM3E7DCAA3EBLQAF4DEE3DEDDE7DEDBEAQBFAQ5EBEAMBAMMDBEMA3E9DEE11DEDDBAQQ15DBAMMDDBEMAB3ADE11DBAMM10DE4DBAMM32D,Ads:C0204\tI 308939,4480252,4,2203\tB d2b,\\d+\tR 633,173,118,129,125,546,495,461,467,556,4472"));
+ assertEquals("d 15 game\tstartturn\t0", startTurn);
+
+ // leave game
+ this.sendMessage(writer, "d 6 game\tback");
+ statusLobby = reader.readLine();
+ lobbyUsers = reader.readLine();
+ lobbyOwnjoin = reader.readLine();
+ assertEquals("d 16 status\tlobby\t1", statusLobby);
+ assertEquals("d 17 lobby\tusers", lobbyUsers);
+ assertEquals("d 18 lobby\townjoin\t3:" + nickname + "^w^10000^-^-^-", lobbyOwnjoin);
+
+ // quit game
+ this.sendMessage(writer, "d 7 lobby\tquit");
+ server.stop();
+ }
+}
diff --git a/shared/pom.xml b/shared/pom.xml
index dca5fc52..6692a2b0 100644
--- a/shared/pom.xml
+++ b/shared/pom.xml
@@ -38,11 +38,6 @@
memoryfilesystem
test
-
- org.softsmithy.lib
- softsmithy-lib-core
- test
-
@@ -53,7 +48,7 @@
plantuml-generator-maven-plugin
de.elnarion.maven
- 1.1.2
+ 2.4.1
generate-simple-diagram
diff --git a/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManager.java b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManager.java
index 00030f3a..c0c3c12f 100644
--- a/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManager.java
+++ b/shared/src/main/java/org/moparforia/shared/tracks/filesystem/FileSystemTrackManager.java
@@ -95,7 +95,7 @@ private List loadTrackSets(TracksLocation tracksLocation) throws IOExc
Scanner scanner = new Scanner(filePath);
String setName = scanner.nextLine();
TrackSetDifficulty trackSetDifficulty = TrackSetDifficulty.valueOf(scanner.nextLine());
- List trackNames = new ArrayList();
+ List trackNames = new ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (!line.isEmpty()) {
@@ -106,8 +106,9 @@ private List loadTrackSets(TracksLocation tracksLocation) throws IOExc
// Convert fileNames to already loaded tracks
List