From d315308c2faf1ea00a5f4f531e693eabb3d8056a Mon Sep 17 00:00:00 2001 From: Christian Schindler Date: Sat, 15 Aug 2026 09:15:34 +0200 Subject: [PATCH] fix: boot ProjectCapture on Hytale 0.5.9 --- .gitignore | 1 + README.md | 17 +++++++++++ .../hytale/ProjectCapturePlugin.java | 6 +++- .../src/main/resources/manifest.json | 2 +- .../hytale/HytaleManifestTest.java | 23 +++++++++++++++ scripts/install-mod-in-dev-server.sh | 14 ++++++++++ scripts/setup-isolated-dev-server.sh | 28 +++++++++++++++++++ scripts/start-isolated-dev-server.sh | 23 +++++++++++++++ 8 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 hytale-adapter/src/test/java/dev/projectcapture/hytale/HytaleManifestTest.java create mode 100755 scripts/install-mod-in-dev-server.sh create mode 100755 scripts/setup-isolated-dev-server.sh create mode 100755 scripts/start-isolated-dev-server.sh diff --git a/.gitignore b/.gitignore index 6a6ce3a..8a851d1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # Local Hytale runtime and proprietary game data .hytale/ dev-runtime/ +ProjectCapture-devserver/ local.properties gradle-local.properties **/HytaleServer.jar diff --git a/README.md b/README.md index f43f1e8..766023a 100644 --- a/README.md +++ b/README.md @@ -23,4 +23,21 @@ Requirements are Java 25 and the checked-in Gradle wrapper. The build downloads ./gradlew fanBuild ``` +## Isolierter Multiplayer-Testserver + +Nach einer lokalen Hytale-0.5.9-Installation kann eine getrennte, nur lokal +gebundene Test-Runtime angelegt werden. Sie kopiert Server und Assets neben das +Repository, lässt Launcher-Daten unverändert und wird nie eingecheckt. + +```shell +scripts/setup-isolated-dev-server.sh +scripts/install-mod-in-dev-server.sh +scripts/start-isolated-dev-server.sh +``` + +Der Testserver lauscht ausschließlich auf `127.0.0.1:5521` und nutzt dafür den +unsicheren lokalen Auth-Modus. Er ist weder für ein LAN noch für das Internet +geeignet. Zwei lokale Clients können damit den gemeinsamen, serverautoritativen +Mod-Status prüfen. + Public releases require a documented policy/rights review; the repository never bundles Hytale server JARs, `Assets.zip`, extracted base assets or secrets. See the [fan-project policy](docs/UNOFFICIAL_FAN_PROJECT_POLICY.md), [third-party notice](THIRD_PARTY_NOTICE.md) and [implementation plan](docs/IMPLEMENTATION_PLAN.md). diff --git a/hytale-adapter/src/main/java/dev/projectcapture/hytale/ProjectCapturePlugin.java b/hytale-adapter/src/main/java/dev/projectcapture/hytale/ProjectCapturePlugin.java index 6a23d04..58a4e56 100644 --- a/hytale-adapter/src/main/java/dev/projectcapture/hytale/ProjectCapturePlugin.java +++ b/hytale-adapter/src/main/java/dev/projectcapture/hytale/ProjectCapturePlugin.java @@ -30,10 +30,14 @@ public final class ProjectCapturePlugin extends JavaPlugin { stateStore.initialize(); contentCatalog = RuntimeContentCatalog.load(getClass().getClassLoader()); multiplayerService = new MultiplayerCreatureService(stateStore, contentCatalog); - ProjectCaptureCommands.register(this, multiplayerService); return CompletableFuture.completedFuture(null); } + @Override + protected void setup() { + ProjectCaptureCommands.register(this, multiplayerService); + } + JsonStateStore stateStore() { return stateStore; } diff --git a/hytale-adapter/src/main/resources/manifest.json b/hytale-adapter/src/main/resources/manifest.json index 15ecead..0b1bf14 100644 --- a/hytale-adapter/src/main/resources/manifest.json +++ b/hytale-adapter/src/main/resources/manifest.json @@ -8,7 +8,7 @@ "Name": "Christian Schindler" } ], - "ServerVersion": "0.5.9", + "ServerVersion": "=0.5.9", "Dependencies": {}, "OptionalDependencies": {}, "DisabledByDefault": false, diff --git a/hytale-adapter/src/test/java/dev/projectcapture/hytale/HytaleManifestTest.java b/hytale-adapter/src/test/java/dev/projectcapture/hytale/HytaleManifestTest.java new file mode 100644 index 0000000..66a575e --- /dev/null +++ b/hytale-adapter/src/test/java/dev/projectcapture/hytale/HytaleManifestTest.java @@ -0,0 +1,23 @@ +package dev.projectcapture.hytale; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; + +import java.io.InputStream; + +import static org.assertj.core.api.Assertions.assertThat; + +class HytaleManifestTest { + @Test + void pinsTheExactSupportedServerVersionWithValidSemverRangeSyntax() throws Exception { + try (InputStream resource = getClass().getClassLoader().getResourceAsStream("manifest.json")) { + assertThat(resource).as("plugin manifest resource").isNotNull(); + JsonNode manifest = new ObjectMapper().readTree(resource); + + assertThat(manifest.path("ServerVersion").asText()).isEqualTo("=0.5.9"); + assertThat(manifest.path("IncludesAssetPack").asBoolean()).isTrue(); + assertThat(manifest.path("Main").asText()).isEqualTo("dev.projectcapture.hytale.ProjectCapturePlugin"); + } + } +} diff --git a/scripts/install-mod-in-dev-server.sh b/scripts/install-mod-in-dev-server.sh new file mode 100755 index 0000000..3623721 --- /dev/null +++ b/scripts/install-mod-in-dev-server.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +project_root="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)" +runtime_root="${PROJECT_CAPTURE_DEV_SERVER:-$(CDPATH= cd -- "${project_root}/.." && pwd -P)/ProjectCapture-devserver}" +mods_directory="${runtime_root}/mods" + +[[ -d "${mods_directory}" && ! -L "${mods_directory}" ]] || { + printf 'Isolierte Runtime fehlt; zuerst setup-isolated-dev-server.sh ausführen.\n' >&2 + exit 1 +} + +"${project_root}/gradlew" -p "${project_root}" :hytale-adapter:installToDevMods \ + -PprojectCapture.devModsDir="${mods_directory}" diff --git a/scripts/setup-isolated-dev-server.sh b/scripts/setup-isolated-dev-server.sh new file mode 100755 index 0000000..0e917e5 --- /dev/null +++ b/scripts/setup-isolated-dev-server.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Creates a disposable, local Hytale 0.5.9 server beside the repository. It +# never writes to the launcher installation or the project's tracked files. +project_root="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)" +runtime_root="${PROJECT_CAPTURE_DEV_SERVER:-$(CDPATH= cd -- "${project_root}/.." && pwd -P)/ProjectCapture-devserver}" +launcher_root="/Users/christianschindler/Library/Application Support/Hytale/install/release/package/game/latest" +server_source="${launcher_root}/Server/HytaleServer.jar" +assets_source="${launcher_root}/Assets.zip" + +for source_path in "${server_source}" "${assets_source}"; do + [[ -f "${source_path}" && ! -L "${source_path}" ]] || { + printf 'Fehlende oder unsichere Hytale-Quelldatei: %s\n' "${source_path}" >&2 + exit 1 + } +done + +[[ ! -e "${runtime_root}" && ! -L "${runtime_root}" ]] || { + printf 'Ziel existiert bereits; nichts wurde überschrieben: %s\n' "${runtime_root}" >&2 + exit 1 +} + +mkdir -p "${runtime_root}/Server" "${runtime_root}/mods" "${runtime_root}/universe" +cp -- "${server_source}" "${runtime_root}/Server/HytaleServer.jar" +cp -- "${assets_source}" "${runtime_root}/Assets.zip" + +printf 'Isolierte Hytale-0.5.9-Runtime angelegt: %s\n' "${runtime_root}" diff --git a/scripts/start-isolated-dev-server.sh b/scripts/start-isolated-dev-server.sh new file mode 100755 index 0000000..ce6181b --- /dev/null +++ b/scripts/start-isolated-dev-server.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Local-only multiplayer test runtime. Insecure authentication is deliberately +# restricted to loopback so two local clients can exercise shared state. +project_root="$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)" +runtime_root="${PROJECT_CAPTURE_DEV_SERVER:-$(CDPATH= cd -- "${project_root}/.." && pwd -P)/ProjectCapture-devserver}" +server_directory="${runtime_root}/Server" + +[[ -f "${server_directory}/HytaleServer.jar" && -f "${runtime_root}/Assets.zip" ]] || { + printf 'Isolierte Runtime fehlt; zuerst setup-isolated-dev-server.sh ausführen.\n' >&2 + exit 1 +} + +cd "${server_directory}" +export HYTALE_DISABLE_UPDATES=true +exec java -Xmx4G -jar HytaleServer.jar \ + --assets "${runtime_root}/Assets.zip" \ + --mods "${runtime_root}/mods" \ + --universe "${runtime_root}/universe" \ + --auth-mode insecure \ + --bind 127.0.0.1:5521 \ + --disable-sentry