Skip to content

Commit ab8fe51

Browse files
committed
build: provision Sparrow runtime on Java 21
1 parent 3028a62 commit ab8fe51

13 files changed

Lines changed: 398 additions & 80 deletions

File tree

.github/CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Thanks for helping improve MahjongEngine.
1111
## Local Setup
1212

1313
1. Fork and clone the repository.
14-
2. Use JDK 21+ for the default build. The released jar is built with Java 17 bytecode and `api-version: 1.20`, so a single jar runs on Paper/Folia 1.20.1 through 26.2.
14+
2. Use JDK 21+ for the default build. The released jar uses Java 21 bytecode and `api-version: 1.20`, so its server runtime must also provide Java 21 or newer.
1515
3. Build the project:
1616

1717
```powershell

.github/workflows/build.yml

Lines changed: 183 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ jobs:
4646
# Gate the build on tests so a native-platform build never ships a jar
4747
# with broken Java/Kotlin. Native tasks are skipped here; they are
4848
# exercised in the build-platform matrix below.
49-
run: ./gradlew test "-PmahjongPaperDevBundle=1.20.1-R0.1-SNAPSHOT" "-PmahjongJavaToolchain=25" "-PmahjongJavaTarget=17" -x configureGbMahjongNative -x buildGbMahjongNative -x packageGbMahjongNative
49+
run: ./gradlew test "-PmahjongPaperDevBundle=1.20.1-R0.1-SNAPSHOT" "-PmahjongJavaToolchain=25" "-PmahjongJavaTarget=21" -x configureGbMahjongNative -x buildGbMahjongNative -x packageGbMahjongNative
5050

5151
build-platform:
5252
needs: test-gate
@@ -126,7 +126,7 @@ jobs:
126126
# Pin to the lowest supported Paper baseline so the released jar stays runtime-compatible
127127
# with Paper/Folia 1.20.1 -> 26.2. PaperCompatibility handles newer APIs at runtime.
128128
# Quote each -P argument because PowerShell on Windows runners mis-parses `1.20.1-R0.1-SNAPSHOT`.
129-
run: ${{ matrix.gradle }} build -x test "-PmahjongPaperDevBundle=1.20.1-R0.1-SNAPSHOT" "-PmahjongJavaTarget=17" "-PmahjongJavaToolchain=25"
129+
run: ${{ matrix.gradle }} build -x test "-PmahjongPaperDevBundle=1.20.1-R0.1-SNAPSHOT" "-PmahjongJavaTarget=21" "-PmahjongJavaToolchain=25"
130130

131131
- name: Verify artifact compatibility (Linux only)
132132
if: runner.os == 'Linux'
@@ -147,7 +147,7 @@ jobs:
147147
python3 - "$JAR" <<'PY'
148148
import sys, zipfile, struct
149149
jar = sys.argv[1]
150-
allowed_max = 61 # Java 17
150+
allowed_max = 65 # Java 21
151151
bad = []
152152
with zipfile.ZipFile(jar) as z:
153153
for n in z.namelist():
@@ -161,11 +161,11 @@ jobs:
161161
if major > allowed_max:
162162
bad.append((n, major))
163163
if bad:
164-
print(f'::error::Found {len(bad)} class files compiled above Java 17:')
164+
print(f'::error::Found {len(bad)} class files compiled above Java 21:')
165165
for n, m in bad[:20]:
166166
print(f' {n}: major={m} (Java {m-44})')
167167
sys.exit(1)
168-
print('All classes compiled to Java 17 or lower.')
168+
print('All classes compiled to Java 21 or lower.')
169169
PY
170170
171171
- name: Upload platform jar
@@ -237,3 +237,181 @@ jobs:
237237
with:
238238
name: mahjong-paper-jars
239239
path: build/universal/*.jar
240+
241+
compatibility-smoke:
242+
name: Standard Paper ${{ matrix.minecraft }} + latest CraftEngine Paper
243+
needs: build-platform
244+
runs-on: ubuntu-latest
245+
timeout-minutes: 15
246+
strategy:
247+
fail-fast: false
248+
matrix:
249+
include:
250+
- minecraft: "1.20.1"
251+
java: "21"
252+
paper_file: paper-1.20.1-196.jar
253+
paper_url: https://fill-data.papermc.io/v1/objects/234a9b32098100c6fc116664d64e36ccdb58b5b649af0f80bcccb08b0255eaea/paper-1.20.1-196.jar
254+
paper_sha256: 234a9b32098100c6fc116664d64e36ccdb58b5b649af0f80bcccb08b0255eaea
255+
- minecraft: "1.20.4"
256+
java: "21"
257+
paper_file: paper-1.20.4-499.jar
258+
paper_url: https://fill-data.papermc.io/v1/objects/cabed3ae77cf55deba7c7d8722bc9cfd5e991201c211665f9265616d9fe5c77b/paper-1.20.4-499.jar
259+
paper_sha256: cabed3ae77cf55deba7c7d8722bc9cfd5e991201c211665f9265616d9fe5c77b
260+
- minecraft: "1.21.1"
261+
java: "21"
262+
paper_file: paper-1.21.1-133.jar
263+
paper_url: https://fill-data.papermc.io/v1/objects/39bd8c00b9e18de91dcabd3cc3dcfa5328685a53b7187a2f63280c22e2d287b9/paper-1.21.1-133.jar
264+
paper_sha256: 39bd8c00b9e18de91dcabd3cc3dcfa5328685a53b7187a2f63280c22e2d287b9
265+
- minecraft: "26.1.2"
266+
java: "25"
267+
paper_file: paper-26.1.2-74.jar
268+
paper_url: https://fill-data.papermc.io/v1/objects/1d70b1dab9cf4a6de615209a536f3a45a2186240253c428213ce2188ab95e5f7/paper-26.1.2-74.jar
269+
paper_sha256: 1d70b1dab9cf4a6de615209a536f3a45a2186240253c428213ce2188ab95e5f7
270+
271+
steps:
272+
- name: Set up server JDK ${{ matrix.java }}
273+
uses: actions/setup-java@v5
274+
with:
275+
distribution: temurin
276+
java-version: ${{ matrix.java }}
277+
278+
- name: Download Linux plugin artifact
279+
uses: actions/download-artifact@v8
280+
with:
281+
name: mahjong-paper-jar-linux
282+
path: artifacts/linux
283+
284+
- name: Prepare checksum-locked standard server.jar stack
285+
shell: bash
286+
env:
287+
PAPER_URL: ${{ matrix.paper_url }}
288+
PAPER_FILE: ${{ matrix.paper_file }}
289+
PAPER_SHA256: ${{ matrix.paper_sha256 }}
290+
CRAFTENGINE_URL: https://cdn.modrinth.com/data/tRX6FMfQ/versions/Len451or/craft-engine-paper-plugin-26.7.3.jar
291+
CRAFTENGINE_SHA512: e87351417e4f99504cf0a8868bad03a88b12bc9bda5c36f0ee4c7451e3525f08146b2130b61cd34b222ee41c38ca75aa9ced9ada65bc3540c80aa66c3d39d689
292+
run: |
293+
set -euo pipefail
294+
mkdir -p smoke/plugins
295+
curl --fail --location --retry 3 --output "smoke/$PAPER_FILE" "$PAPER_URL"
296+
printf '%s %s\n' "$PAPER_SHA256" "smoke/$PAPER_FILE" | sha256sum --check --strict
297+
cp "smoke/$PAPER_FILE" smoke/server.jar
298+
299+
curl --fail --location --retry 3 \
300+
--output smoke/plugins/craft-engine-paper-plugin-26.7.3.jar \
301+
"$CRAFTENGINE_URL"
302+
printf '%s %s\n' \
303+
"$CRAFTENGINE_SHA512" \
304+
smoke/plugins/craft-engine-paper-plugin-26.7.3.jar \
305+
| sha512sum --check --strict
306+
307+
PLUGIN_JAR="$(find artifacts/linux -type f -name '*.jar' ! -name '*-sources.jar' ! -name '*-dev.jar' | sort | head -n 1)"
308+
test -n "$PLUGIN_JAR"
309+
cp "$PLUGIN_JAR" smoke/plugins/mahjong-paper.jar
310+
printf 'eula=true\n' > smoke/eula.txt
311+
cat > smoke/server.properties <<'EOF'
312+
online-mode=false
313+
server-ip=127.0.0.1
314+
server-port=25565
315+
max-players=1
316+
view-distance=3
317+
simulation-distance=3
318+
spawn-protection=0
319+
allow-nether=false
320+
generate-structures=false
321+
enable-query=false
322+
enable-rcon=false
323+
EOF
324+
325+
- name: Cold-start, execute /mahjong help, and stop cleanly
326+
shell: bash
327+
working-directory: smoke
328+
run: |
329+
set -euo pipefail
330+
mkfifo console.pipe
331+
exec 3<>console.pipe
332+
java -Xms512m -Xmx1g -jar server.jar --nogui <&3 >server.log 2>&1 &
333+
SERVER_PID=$!
334+
335+
cleanup() {
336+
if kill -0 "$SERVER_PID" 2>/dev/null; then
337+
printf 'stop\n' >&3 || true
338+
for _ in $(seq 1 30); do
339+
kill -0 "$SERVER_PID" 2>/dev/null || break
340+
sleep 1
341+
done
342+
kill "$SERVER_PID" 2>/dev/null || true
343+
fi
344+
}
345+
trap cleanup EXIT
346+
347+
READY=false
348+
for _ in $(seq 1 240); do
349+
if grep -Eq 'Done \([^)]+\)! For help' server.log; then
350+
READY=true
351+
break
352+
fi
353+
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
354+
echo '::error::Paper exited before reaching the ready state'
355+
cat server.log
356+
exit 1
357+
fi
358+
sleep 1
359+
done
360+
if [[ "$READY" != true ]]; then
361+
echo '::error::Paper did not become ready within 240 seconds'
362+
cat server.log
363+
exit 1
364+
fi
365+
366+
grep -Eq '\[MahjongPaper\].*Enabling MahjongPaper v' server.log
367+
grep -Eq '\[CraftEngine\].*Enabling CraftEngine v26\.7\.3' server.log
368+
369+
COMMAND_START=$(wc -l < server.log)
370+
printf 'mahjong help\n' >&3
371+
sleep 5
372+
tail -n "+$((COMMAND_START + 1))" server.log > command.log
373+
if grep -Eiq 'unknown command|unknown or incomplete command|command exception' command.log; then
374+
echo '::error::The /mahjong command was not executable'
375+
cat command.log
376+
exit 1
377+
fi
378+
grep -Fq 'MahjongPaper' command.log
379+
380+
verify_library() {
381+
local filename="$1"
382+
local expected="$2"
383+
local found
384+
found="$(find libraries -type f -name "$filename" -print -quit)"
385+
if [[ -z "$found" ]]; then
386+
echo "::error::Loader did not resolve $filename"
387+
exit 1
388+
fi
389+
printf '%s %s\n' "$expected" "$found" | sha256sum --check --strict
390+
}
391+
verify_library sparrow-heart-0.72.jar a539b7b6db55a2369599b643e5b2d20ec12184ad2798eb858f17a64dcde1d7ea
392+
verify_library sparrow-reflection-0.33.jar 7c34a0839650be8025634077656a00569cbedbad9999e03af3482391ccd14a93
393+
verify_library asm-9.9.1.jar 6f3828a215c920059a5efa2fb55c233d6c54ec5cadca99ce1b1bdd10077c7ddd
394+
verify_library caffeine-3.2.4.jar 9d9d2cfd681fd9272ded3d27c9930db12f89f732345975aa113ebc223bbf1224
395+
396+
printf 'stop\n' >&3
397+
for _ in $(seq 1 60); do
398+
kill -0 "$SERVER_PID" 2>/dev/null || break
399+
sleep 1
400+
done
401+
if kill -0 "$SERVER_PID" 2>/dev/null; then
402+
echo '::error::Paper did not stop cleanly within 60 seconds'
403+
exit 1
404+
fi
405+
wait "$SERVER_PID"
406+
trap - EXIT
407+
408+
- name: Upload compatibility evidence
409+
if: always()
410+
uses: actions/upload-artifact@v7
411+
with:
412+
name: compatibility-smoke-${{ matrix.minecraft }}
413+
path: |
414+
smoke/server.log
415+
smoke/command.log
416+
smoke/logs/latest.log
417+
if-no-files-found: warn

.github/workflows/release.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ jobs:
7777
# Pin to the lowest supported Paper baseline so the released jar stays runtime-compatible
7878
# with Paper/Folia 1.20.1 -> 26.2. PaperCompatibility handles newer APIs at runtime.
7979
# Quote each -P argument because PowerShell on Windows runners mis-parses `1.20.1-R0.1-SNAPSHOT`.
80-
run: ${{ matrix.gradle }} build -x test "-PmahjongPaperDevBundle=1.20.1-R0.1-SNAPSHOT" "-PmahjongJavaTarget=17" "-PmahjongJavaToolchain=25"
80+
run: ${{ matrix.gradle }} build -x test "-PmahjongPaperDevBundle=1.20.1-R0.1-SNAPSHOT" "-PmahjongJavaTarget=21" "-PmahjongJavaToolchain=25"
8181

8282
- name: Verify artifact compatibility (Linux only)
8383
if: runner.os == 'Linux'
@@ -98,7 +98,7 @@ jobs:
9898
python3 - "$JAR" <<'PY'
9999
import sys, zipfile, struct
100100
jar = sys.argv[1]
101-
allowed_max = 61 # Java 17
101+
allowed_max = 65 # Java 21
102102
bad = []
103103
with zipfile.ZipFile(jar) as z:
104104
for n in z.namelist():
@@ -112,11 +112,11 @@ jobs:
112112
if major > allowed_max:
113113
bad.append((n, major))
114114
if bad:
115-
print(f'::error::Found {len(bad)} class files compiled above Java 17:')
115+
print(f'::error::Found {len(bad)} class files compiled above Java 21:')
116116
for n, m in bad[:20]:
117117
print(f' {n}: major={m} (Java {m-44})')
118118
sys.exit(1)
119-
print('All classes compiled to Java 17 or lower.')
119+
print('All classes compiled to Java 21 or lower.')
120120
PY
121121
122122
- name: Upload platform jar

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ jobs:
7979
# Pin to the lowest supported Paper baseline so the released jar stays
8080
# runtime-compatible with Paper/Folia 1.20.1 -> 26.2. Skip native tasks
8181
# on non-Linux runners where the CMake toolchain may not be configured.
82-
run: ${{ matrix.gradle }} ${{ matrix.test_task }} "-PmahjongPaperDevBundle=1.20.1-R0.1-SNAPSHOT" "-PmahjongJavaToolchain=25" "-PmahjongJavaTarget=17" -x configureGbMahjongNative -x buildGbMahjongNative -x packageGbMahjongNative
82+
run: ${{ matrix.gradle }} ${{ matrix.test_task }} "-PmahjongPaperDevBundle=1.20.1-R0.1-SNAPSHOT" "-PmahjongJavaToolchain=25" "-PmahjongJavaTarget=21" -x configureGbMahjongNative -x buildGbMahjongNative -x packageGbMahjongNative
8383

8484
- name: Upload test reports
8585
if: always()

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Contributor notes: [CONTRIBUTING.md](./CONTRIBUTING.md)
1717

1818
## Current Scope
1919

20+
MahjongPaper requires a Java 21 or newer server runtime and build JDK.
21+
2022
The current branch already supports playable Riichi Mahjong, GB Mahjong, and Sichuan Mahjong flows on Paper/Folia:
2123

2224
- lobby-style tables that can persist across restart

THIRD_PARTY_NOTICES.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,14 @@ The Amitaro recordings may be redistributed only as part of a work such as this
2121

2222
## Separate platforms and runtime libraries
2323

24-
Paper, Folia, and CraftEngine are separate server components supplied by the server operator. Paper's plugin loader resolves mahjong-utils, MariaDB Connector/J, MySQL Connector/J, H2, HikariCP, Caffeine, Kotlin, and kotlinx.serialization as separate libraries under their respective upstream licenses. See the README and build files for links, versions, and license identifiers.
24+
Paper, Folia, and CraftEngine are separate server components supplied by the server operator. Paper's plugin loader resolves mahjong-utils, MariaDB Connector/J, MySQL Connector/J, H2, HikariCP, Caffeine, Kotlin, kotlinx.serialization, and the Sparrow libraries below as separate libraries under their respective upstream licenses. See the README and build files for links, versions, and license identifiers.
25+
26+
The distribution also uses the following Xiao-MoMi ecosystem libraries:
27+
28+
- **sparrow-heart 0.72**, Copyright (c) 2024 XiaoMoMi, under the MIT License, is resolved by Paper's plugin loader: <https://github.com/Xiao-MoMi/sparrow-heart>.
29+
- **sparrow-reflection 0.33** under the GNU General Public License v3.0 is resolved by Paper's plugin loader: <https://github.com/Xiao-MoMi/sparrow-reflection>.
30+
- **Mapping-IO 0.8.0** by FabricMC under the Apache License 2.0 is bundled by the upstream Sparrow Reflection artifact: <https://github.com/FabricMC/mapping-io>.
31+
- **ASM 9.9.1** under the BSD 3-Clause License is resolved by Paper's plugin loader: <https://gitlab.ow2.org/asm/asm>.
2532

2633
## Trademark and affiliation notice
2734

0 commit comments

Comments
 (0)