diff --git a/CLAUDE.md b/CLAUDE.md index 7599f63..1c8bfa3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,17 +2,18 @@ ## Project Overview -Fabric mod for Minecraft 1.21.11 (dedicated server only) that exposes a REST API + WebSocket for monitoring and controlling Minecraft servers. Uses `com.sun.net.httpserver` from the JDK (zero external dependencies for HTTP). +Fabric mod for Minecraft 26.1.2 (dedicated server only) that exposes a REST API + WebSocket for monitoring and controlling Minecraft servers. Uses `com.sun.net.httpserver` from the JDK (zero external dependencies for HTTP). ## Tech Stack | Component | Version | |-----------------|----------------------------| -| Minecraft | 1.21.11 | -| Fabric Loader | 0.18.4 | -| Fabric Loom | 1.15-SNAPSHOT | -| Fabric API | 0.141.3+1.21.11 | -| Java | 21 | +| Minecraft | 26.1.2 | +| Fabric Loader | 0.19.3 | +| Fabric Loom | 1.17.11 | +| Fabric API | 0.151.0+26.1.2 | +| Java | 25 | +| Gradle | 9.5.1 | | Mappings | Mojang official | ## Project Structure @@ -37,35 +38,39 @@ src/main/java/net/natxo/mcrestapi/ └── PlayerTracker.java # Thread-safe player data snapshots ``` -## Inspecting Minecraft API (Mojang Mappings) +## Inspecting Minecraft API (deobfuscated) -Since the project uses Mojang official mappings, you can inspect any Minecraft class using: +Minecraft 26.1+ ships **deobfuscated** — official class/method names with parameter names, no mappings. Inspect any Minecraft class directly from the Loom-provided merged jar: ```bash -# Full class inspection -javap -p -classpath .gradle/loom-cache/minecraftMaven/net/minecraft/minecraft-merged-6dd721cd7d/1.21.11-loom.mappings.1_21_11.layered+hash.2198-v2/minecraft-merged-6dd721cd7d-1.21.11-loom.mappings.1_21_11.layered+hash.2198-v2.jar +# Full class inspection (replace 26.1.2 with the target MC version) +javap -p -classpath ~/.gradle/caches/fabric-loom/26.1.2/minecraft-merged.jar -# Search for specific methods -javap -p -classpath .gradle/loom-cache/minecraftMaven/net/minecraft/minecraft-merged-6dd721cd7d/1.21.11-loom.mappings.1_21_11.layered+hash.2198-v2/minecraft-merged-6dd721cd7d-1.21.11-loom.mappings.1_21_11.layered+hash.2198-v2.jar 2>&1 | grep -i "methodName" +# Search for a specific method +javap -p -classpath ~/.gradle/caches/fabric-loom/26.1.2/minecraft-merged.jar 2>&1 | grep -i "methodName" # List classes in the jar -jar tf .gradle/loom-cache/minecraftMaven/net/minecraft/minecraft-merged-6dd721cd7d/1.21.11-loom.mappings.1_21_11.layered+hash.2198-v2/minecraft-merged-6dd721cd7d-1.21.11-loom.mappings.1_21_11.layered+hash.2198-v2.jar | grep -i "ClassName" +jar tf ~/.gradle/caches/fabric-loom/26.1.2/minecraft-merged.jar | grep -i "ClassName" -# Authlib (GameProfile, etc.) — uses record-style accessors (name() not getName()) -javap -p -classpath ~/.gradle/caches/modules-2/files-2.1/com.mojang/authlib/7.0.61/efee1e6b54e863108576eb3b3ae71144626aaefc/authlib-7.0.61.jar +# Authlib (GameProfile, etc.) — record-style accessors (name() not getName()) +# locate it with: find ~/.gradle -name 'authlib-*.jar' ``` -### Key API differences in 1.21.11 Mojang Mappings +### Key API notes (Minecraft 26.1, official names) -- `GameProfile.name()` not `getName()` (authlib 7.x uses record-style) +- `GameProfile.name()` not `getName()` (authlib uses record-style) - `ResourceKey.identifier()` not `location()` - `ServerPlayer.server` is private — use `player.level().getServer()` instead - `PlayerList.isOp()` takes `NameAndId`, not `GameProfile` — use `new NameAndId(gameProfile)` - `DedicatedServer` has `getProperties()` for server.properties access - `Settings.MutableValue` fields use `.get()` to read values +- `Difficulty.getSerializedName()` not `getKey()` (implements `StringRepresentable`) +- Weather/time moved off `LevelData`: use `Level.isRaining()` / `isThundering()`; the day time is `Level.getOverworldClockTime()` (26.1 WorldClock), and `getDayCount()` was removed (derive `clockTime / 24000`) ## Build & Run +Minecraft 26.1 requires **Java 25** — the Gradle JVM itself must run on JDK 25 (set `JAVA_HOME` to a JDK 25 if it isn't your default). + ```bash ./gradlew build # Compile and produce mod jar ./gradlew runServer # Launch dedicated server with mod loaded (first run: accept EULA in run/eula.txt) @@ -85,7 +90,18 @@ API testing collection in `McRestApi-Bruno/`. Open with Bruno, select the "Local - **Minotaur plugin** configured in `build.gradle` for automated publishing - **Modrinth token** stored in `.env` locally and in GitHub secret `MODRINTH_TOKEN` - **CI/CD:** `.github/workflows/publish.yml` triggers on tag push (`v*`) -- **Two READMEs:** `README.md` (GitHub, full) and `MODRINTH_README.md` (Modrinth, compact) +- **Two READMEs:** `README.md` (GitHub, full, **per-branch**) and `MODRINTH_README.md` (the **single shared** Modrinth description — keep it version-agnostic) + +### Minecraft version support (branches) + +The mod supports multiple Minecraft versions in parallel — **one branch per MC line**: + +- `main` always tracks the **latest** Minecraft version (currently `26.1.2`). Older lines live on a branch named by MC version (e.g. `1.21.11`) and keep getting back-support. +- New MC version → branch off `main`, port it, merge into `main` via PR; the previous version stays on its own branch. +- Per branch, set the versions in `gradle.properties`, `fabric.mod.json`, and `gameVersions` in `build.gradle`. +- Modrinth versions stay unique across lines via `versionNumber = "${mod_version}+${minecraft_version}"` (e.g. `2.0.0+26.1.2`). Keep `mod_version` ranges disjoint per line (26.1 → `2.x`, 1.21.11 → `1.x`) so git tags never collide. +- `MODRINTH_README.md` is the shared Modrinth body across **every** version — never pin it to a single MC version. The GitHub `README.md` is per-branch and may be version-specific. +- Minecraft 26.1+ needs **Java 25**; the CI workflows already run on Java 25. ### How to publish a new version diff --git a/MODRINTH_README.md b/MODRINTH_README.md index 3b6d2af..a54f6f1 100644 --- a/MODRINTH_README.md +++ b/MODRINTH_README.md @@ -1,6 +1,6 @@ # MCRestAPI -A Fabric mod for Minecraft 1.21.11 that exposes a REST API and real-time event stream (SSE) for monitoring and controlling dedicated Minecraft servers. Built on top of the JDK's built-in HTTP server with zero external dependencies. +A Fabric mod that exposes a REST API and real-time event stream (SSE) for monitoring and controlling dedicated Minecraft servers. Built on top of the JDK's built-in HTTP server with zero external dependencies. Available for **Minecraft 1.21.11 and 26.1+** — download the file that matches your version. --- @@ -18,19 +18,21 @@ A Fabric mod for Minecraft 1.21.11 that exposes a REST API and real-time event s - CORS configuration with per-origin allowlist - API keys hashed with PBKDF2-SHA256 (never stored in plain text) - Zero external dependencies (uses JDK built-in HTTP server) -- Virtual threads (Java 21) for lightweight concurrency +- Virtual threads for lightweight concurrency - Server-side only (does not run on clients) --- ## Requirements -| Component | Version | -|----------------|-----------------| -| Minecraft | 1.21.11 | -| Fabric Loader | >= 0.18.4 | -| Fabric API | any | -| Java | >= 21 | +| Component | 1.21.11 line | 26.1 line | +|---------------|--------------|------------| +| Minecraft | 1.21.11 | 26.1.x | +| Java | >= 21 | >= 25 | +| Fabric Loader | >= 0.18.4 | >= 0.19.3 | +| Fabric API | any | any | + +Each release on Modrinth is tagged with its supported Minecraft version — install the one matching your server. --- diff --git a/README.md b/README.md index c121eb6..063010a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MCRestAPI -A Fabric mod for Minecraft 1.21.11 that exposes a REST API and real-time event stream (SSE) for monitoring and controlling dedicated Minecraft servers. Built on top of the JDK's built-in HTTP server with zero external dependencies. +A Fabric mod for Minecraft 26.1.2 that exposes a REST API and real-time event stream (SSE) for monitoring and controlling dedicated Minecraft servers. Built on top of the JDK's built-in HTTP server with zero external dependencies. [![Modrinth Downloads](https://img.shields.io/modrinth/dt/XZCgCz7D?label=Modrinth%20Downloads)](https://modrinth.com/mod/mcrestapi) [![Modrinth Version](https://img.shields.io/modrinth/v/XZCgCz7D?label=Latest%20Version)](https://modrinth.com/mod/mcrestapi/versions) @@ -52,7 +52,7 @@ A Fabric mod for Minecraft 1.21.11 that exposes a REST API and real-time event s - CORS configuration with per-origin allowlist - API keys hashed with PBKDF2-SHA256 (never stored in plain text) - Zero external dependencies (uses JDK built-in HTTP server) -- Virtual threads (Java 21) for lightweight concurrency +- Virtual threads (Java 25) for lightweight concurrency - Server-side only (does not run on clients) --- @@ -61,10 +61,10 @@ A Fabric mod for Minecraft 1.21.11 that exposes a REST API and real-time event s | Component | Version | |----------------|-----------------| -| Minecraft | 1.21.11 | +| Minecraft | 26.1.2 | | Fabric Loader | >= 0.18.4 | | Fabric API | any | -| Java | >= 21 | +| Java | >= 25 | --- @@ -231,7 +231,7 @@ curl -H "Authorization: Bearer mcsapi_xxx" http://localhost:8080/api/server ```json { - "version": "1.21.11", + "version": "26.1.2", "motd": "A Minecraft Server", "server_port": 25565, "online_mode": true, diff --git a/build.gradle b/build.gradle index a26464c..7afb7e8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'net.fabricmc.fabric-loom-remap' version "${loom_version}" + id 'net.fabricmc.fabric-loom' version "${loom_version}" id 'maven-publish' id 'com.modrinth.minotaur' version '2.+' } @@ -22,11 +22,11 @@ repositories { dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings loom.officialMojangMappings() - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + implementation "net.fabricmc:fabric-loader:${project.loader_version}" // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" + implementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}" } @@ -39,7 +39,7 @@ processResources { } tasks.withType(JavaCompile).configureEach { - it.options.release = 21 + it.options.release = 25 } java { @@ -48,8 +48,8 @@ java { // If you remove this line, sources will not be generated. withSourcesJar() - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 } jar { @@ -79,10 +79,11 @@ file('.env').with { envFile -> modrinth { token = System.getenv("MODRINTH_TOKEN") ?: System.getProperty("MODRINTH_TOKEN") projectId = "XZCgCz7D" - versionNumber = project.mod_version + // MC version is appended so 1.21.11 and 26.1 releases stay unique on Modrinth (e.g. 2.0.0+26.1.2) + versionNumber = "${project.mod_version}+${project.minecraft_version}" versionType = "release" - uploadFile = remapJar - gameVersions = ["1.21.11"] + uploadFile = jar + gameVersions = ["26.1.2"] loaders = ["fabric"] changelog = System.getenv("CHANGELOG") ?: "" syncBodyFrom = rootProject.file("MODRINTH_README.md").text diff --git a/gradle.properties b/gradle.properties index 0daae81..99fe111 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,14 +7,14 @@ org.gradle.configuration-cache=false # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.21.11 -loader_version=0.18.4 -loom_version=1.15-SNAPSHOT +minecraft_version=26.1.2 +loader_version=0.19.3 +loom_version=1.17.11 # Mod Properties -mod_version=1.2.0 +mod_version=2.0.0 maven_group=net.natxo.mcrestapi archives_base_name=mcrestapi # Dependencies -fabric_api_version=0.141.3+1.21.11 \ No newline at end of file +fabric_api_version=0.151.0+26.1.2 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 19a6bde..5dd3c01 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/net/natxo/mcrestapi/endpoints/ServerEndpoint.java b/src/main/java/net/natxo/mcrestapi/endpoints/ServerEndpoint.java index ceba535..b95cd2f 100644 --- a/src/main/java/net/natxo/mcrestapi/endpoints/ServerEndpoint.java +++ b/src/main/java/net/natxo/mcrestapi/endpoints/ServerEndpoint.java @@ -152,7 +152,7 @@ private Map buildProperties() { Map properties = new LinkedHashMap<>(); properties.put("gamemode", props.gameMode.get().getName()); - properties.put("difficulty", props.difficulty.get().getKey()); + properties.put("difficulty", props.difficulty.get().getSerializedName()); properties.put("hardcore", props.hardcore); properties.put("allow_flight", props.allowFlight.get()); properties.put("whitelist", props.whiteList.get()); diff --git a/src/main/java/net/natxo/mcrestapi/endpoints/WorldEndpoint.java b/src/main/java/net/natxo/mcrestapi/endpoints/WorldEndpoint.java index 2276e7e..61b2777 100644 --- a/src/main/java/net/natxo/mcrestapi/endpoints/WorldEndpoint.java +++ b/src/main/java/net/natxo/mcrestapi/endpoints/WorldEndpoint.java @@ -98,12 +98,12 @@ private Map buildGlobal(ServerLevel overworld) { Map time = new LinkedHashMap<>(); time.put("game_time", levelData.getGameTime()); - time.put("day_time", levelData.getDayTime()); - time.put("day_count", overworld.getDayCount()); + time.put("day_time", overworld.getOverworldClockTime()); + time.put("day_count", overworld.getOverworldClockTime() / 24000L); Map weather = new LinkedHashMap<>(); - weather.put("raining", levelData.isRaining()); - weather.put("thundering", levelData.isThundering()); + weather.put("raining", overworld.isRaining()); + weather.put("thundering", overworld.isThundering()); Map spawn = new LinkedHashMap<>(); spawn.put("x", spawnPos.getX()); @@ -114,7 +114,7 @@ private Map buildGlobal(ServerLevel overworld) { global.put("seed", overworld.getSeed()); global.put("time", time); global.put("weather", weather); - global.put("difficulty", levelData.getDifficulty().getKey()); + global.put("difficulty", levelData.getDifficulty().getSerializedName()); global.put("difficulty_locked", levelData.isDifficultyLocked()); global.put("hardcore", levelData.isHardcore()); global.put("pvp", overworld.isPvpAllowed()); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index b85b19e..eef57f3 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -21,9 +21,9 @@ ] }, "depends": { - "fabricloader": ">=0.18.4", - "minecraft": "~1.21.11", - "java": ">=21", + "fabricloader": ">=0.19.3", + "minecraft": "~26.1.2", + "java": ">=25", "fabric-api": "*" } } \ No newline at end of file