fix(base): support Purpur 26.3
This commit is contained in:
1 parent
0fe6a14451
commit
5949eff7fd
5 files changed
+41
-19
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
# Purpur Base
|
# Purpur Base
|
||||||
|
|
||||||
A Purpur 26.2 plugin providing progression-gated player bases and quality-of-life unlocks.
|
A Purpur 26.3 plugin providing progression-gated player bases and quality-of-life unlocks.
|
||||||
|
|
||||||
Players begin by breaking Survival-mode grass blocks or dirt. The progression paths provide a persistent base, navigation particles, expanding base bounds, controlled flight, personal teleportation, and visitor teleportation.
|
Players begin by breaking Survival-mode grass blocks or dirt. The progression paths provide a persistent base, navigation particles, expanding base bounds, controlled flight, personal teleportation, and visitor teleportation.
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ The repository and new artifacts are named `purpur-base`. Runtime identity remai
|
|||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Purpur 26.2 build 2618
|
- Purpur 26.3 build 2651
|
||||||
- Java 25 or newer
|
- Java 25 or newer
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
@@ -19,7 +19,7 @@ The repository and new artifacts are named `purpur-base`. Runtime identity remai
|
|||||||
./gradlew clean check jar
|
./gradlew clean check jar
|
||||||
```
|
```
|
||||||
|
|
||||||
The plugin JAR is written to `build/libs/`. `check` includes native label packet tests against the SHA-256-verified Purpur 2618 runtime. The build downloads/patches that runtime under `build/label-runtime/`, loads its registries, and exercises codecs without starting a listening Minecraft server.
|
The plugin JAR is written to `build/libs/`. `check` includes native label packet tests against the SHA-256-verified Purpur 2651 runtime. The build downloads/patches that runtime under `build/label-runtime/`, loads its registries, and exercises codecs without starting a listening Minecraft server.
|
||||||
|
|
||||||
## Player commands
|
## Player commands
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -26,9 +26,9 @@ tasks.withType<JavaCompile>().configureEach {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("org.purpurmc.purpur:purpur-api:26.2.build.2618-stable")
|
compileOnly("org.purpurmc.purpur:purpur-api:26.3.build.2651-stable")
|
||||||
|
|
||||||
testImplementation("org.purpurmc.purpur:purpur-api:26.2.build.2618-stable")
|
testImplementation("org.purpurmc.purpur:purpur-api:26.3.build.2651-stable")
|
||||||
testImplementation(platform("org.junit:junit-bom:5.13.4"))
|
testImplementation(platform("org.junit:junit-bom:5.13.4"))
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
testImplementation("org.mockito:mockito-core:5.18.0")
|
testImplementation("org.mockito:mockito-core:5.18.0")
|
||||||
@@ -46,18 +46,18 @@ tasks.test {
|
|||||||
// Verify client-only label packets against the declared runtime, without starting a server.
|
// Verify client-only label packets against the declared runtime, without starting a server.
|
||||||
val labelRuntime = layout.buildDirectory.dir("label-runtime")
|
val labelRuntime = layout.buildDirectory.dir("label-runtime")
|
||||||
val downloadLabelRuntime = tasks.register("downloadLabelRuntime") {
|
val downloadLabelRuntime = tasks.register("downloadLabelRuntime") {
|
||||||
val launcher = labelRuntime.map { it.file("purpur-26.2-2618.jar") }
|
val launcher = labelRuntime.map { it.file("purpur-26.3-2651.jar") }
|
||||||
outputs.file(launcher)
|
outputs.file(launcher)
|
||||||
doLast {
|
doLast {
|
||||||
val file = launcher.get().asFile
|
val file = launcher.get().asFile
|
||||||
file.parentFile.mkdirs()
|
file.parentFile.mkdirs()
|
||||||
val connection = URI("https://api.purpurmc.org/v2/purpur/26.2/2618/download").toURL().openConnection()
|
val connection = URI("https://api.purpurmc.org/v2/purpur/26.3/2651/download").toURL().openConnection()
|
||||||
connection.connectTimeout = 30_000
|
connection.connectTimeout = 30_000
|
||||||
connection.readTimeout = 120_000
|
connection.readTimeout = 120_000
|
||||||
val bytes = connection.getInputStream().use { it.readBytes() }
|
val bytes = connection.getInputStream().use { it.readBytes() }
|
||||||
val digest = MessageDigest.getInstance("SHA-256").digest(bytes).joinToString("") { "%02x".format(it) }
|
val digest = MessageDigest.getInstance("SHA-256").digest(bytes).joinToString("") { "%02x".format(it) }
|
||||||
check(digest == "4a32d046a118804d89ca74ba89b798c98f6d8d1f310c18077ac573597049de31") {
|
check(digest == "0677c1febecfbc2e5b0a7f76abd647b70a1f38d3cbdf3dd6a82e401b4262a598") {
|
||||||
"Purpur 2618 checksum mismatch"
|
"Purpur 2651 checksum mismatch"
|
||||||
}
|
}
|
||||||
file.writeBytes(bytes)
|
file.writeBytes(bytes)
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ val downloadLabelRuntime = tasks.register("downloadLabelRuntime") {
|
|||||||
val prepareLabelRuntime = tasks.register<JavaExec>("prepareLabelRuntime") {
|
val prepareLabelRuntime = tasks.register<JavaExec>("prepareLabelRuntime") {
|
||||||
dependsOn(downloadLabelRuntime)
|
dependsOn(downloadLabelRuntime)
|
||||||
javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(25) }
|
javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(25) }
|
||||||
classpath = files(labelRuntime.map { it.file("purpur-26.2-2618.jar") })
|
classpath = files(labelRuntime.map { it.file("purpur-26.3-2651.jar") })
|
||||||
mainClass = "io.papermc.paperclip.Main"
|
mainClass = "io.papermc.paperclip.Main"
|
||||||
jvmArgs("-Dpaperclip.patchonly=true")
|
jvmArgs("-Dpaperclip.patchonly=true")
|
||||||
workingDir(labelRuntime)
|
workingDir(labelRuntime)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class NativeBaseLabelPacketsTest {
|
|||||||
try {
|
try {
|
||||||
net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket.STREAM_CODEC.encode(buffer, remove);
|
net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket.STREAM_CODEC.encode(buffer, remove);
|
||||||
var decoded = net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket.STREAM_CODEC.decode(buffer);
|
var decoded = net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket.STREAM_CODEC.decode(buffer);
|
||||||
assertEquals(java.util.List.of(42), decoded.getEntityIds());
|
assertEquals(java.util.List.of(42), decoded.entityIds());
|
||||||
} finally { buffer.release(); }
|
} finally { buffer.release(); }
|
||||||
var player = mock(org.bukkit.craftbukkit.entity.CraftPlayer.class);
|
var player = mock(org.bukkit.craftbukkit.entity.CraftPlayer.class);
|
||||||
var handle = mock(net.minecraft.server.level.ServerPlayer.class);
|
var handle = mock(net.minecraft.server.level.ServerPlayer.class);
|
||||||
|
|||||||
@@ -43,12 +43,12 @@ final class NativeRuntime {
|
|||||||
try (var resources = new MultiPackResourceManager(PackType.SERVER_DATA, packs.openAllSelected())) {
|
try (var resources = new MultiPackResourceManager(PackType.SERVER_DATA, packs.openAllSelected())) {
|
||||||
LayeredRegistryAccess<RegistryLayer> layers = RegistryLayer.createRegistryAccess();
|
LayeredRegistryAccess<RegistryLayer> layers = RegistryLayer.createRegistryAccess();
|
||||||
List<Registry.PendingTags<?>> tags = TagLoader.loadTagsForExistingRegistries(resources, layers.getLayer(RegistryLayer.STATIC));
|
List<Registry.PendingTags<?>> tags = TagLoader.loadTagsForExistingRegistries(resources, layers.getLayer(RegistryLayer.STATIC));
|
||||||
List<HolderLookup.RegistryLookup<?>> lookups = TagLoader.buildUpdatedLookups(layers.getAccessForLoading(RegistryLayer.WORLDGEN), tags);
|
List<HolderLookup.RegistryLookup<?>> lookups = TagLoader.buildUpdatedLookups(layers.getAccessForLoading(RegistryLayer.WORLD), tags);
|
||||||
RegistryAccess.Frozen worldgen = RegistryDataLoader.load(resources, lookups,
|
RegistryAccess.Frozen world = RegistryDataLoader.load(resources, lookups,
|
||||||
RegistryDataLoader.WORLDGEN_REGISTRIES, Util.backgroundExecutor()).join();
|
RegistryDataLoader.WORLD_REGISTRIES, Util.backgroundExecutor()).join();
|
||||||
layers = layers.replaceFrom(RegistryLayer.WORLDGEN, worldgen);
|
layers = layers.replaceFrom(RegistryLayer.WORLD, world);
|
||||||
RegistryAccess.Frozen dimensions = RegistryDataLoader.load(resources,
|
RegistryAccess.Frozen dimensions = RegistryDataLoader.load(resources,
|
||||||
Stream.concat(lookups.stream(), worldgen.listRegistries()).toList(),
|
Stream.concat(lookups.stream(), world.listRegistries()).toList(),
|
||||||
RegistryDataLoader.DIMENSION_REGISTRIES, Util.backgroundExecutor()).join();
|
RegistryDataLoader.DIMENSION_REGISTRIES, Util.backgroundExecutor()).join();
|
||||||
layers = layers.replaceFrom(RegistryLayer.DIMENSIONS, dimensions);
|
layers = layers.replaceFrom(RegistryLayer.DIMENSIONS, dimensions);
|
||||||
Class.forName(org.bukkit.Registry.class.getName());
|
Class.forName(org.bukkit.Registry.class.getName());
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -31,16 +32,37 @@ class PurpurDistributionTest {
|
|||||||
bytecode.readUnsignedShort();
|
bytecode.readUnsignedShort();
|
||||||
assertEquals(69, bytecode.readUnsignedShort(), "Plugin bytecode must target Java 25");
|
assertEquals(69, bytecode.readUnsignedShort(), "Plugin bytecode must target Java 25");
|
||||||
}
|
}
|
||||||
assertFalse(jar.stream().anyMatch(entry -> entry.getName().startsWith("org/bukkit/")
|
List<String> forbiddenPrefixes = List.of(
|
||||||
|| entry.getName().startsWith("org/purpurmc/") || entry.getName().endsWith("Test.class")));
|
"com/comphenix/protocol/",
|
||||||
|
"com/destroystokyo/paper/",
|
||||||
|
"io/papermc/",
|
||||||
|
"net/minecraft/",
|
||||||
|
"org/bukkit/",
|
||||||
|
"org/purpurmc/",
|
||||||
|
"org/spigotmc/",
|
||||||
|
"mockito-extensions/"
|
||||||
|
);
|
||||||
|
assertFalse(jar.stream().anyMatch(entry -> forbiddenPrefixes.stream().anyMatch(entry.getName()::startsWith)
|
||||||
|
|| entry.getName().endsWith("Test.class")
|
||||||
|
|| entry.getName().equals("games/dmg/spigotbase/NativeRuntime.class")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void releaseAndCiAgreeWithThePurpurDistributionNameAndToolchain() throws Exception {
|
void releaseAndCiAgreeWithThePurpurDistributionNameAndToolchain() throws Exception {
|
||||||
String build = Files.readString(Path.of("build.gradle.kts"));
|
String build = Files.readString(Path.of("build.gradle.kts"));
|
||||||
assertTrue(build.contains("purpur-api:26.2.build.2618-stable"));
|
assertTrue(build.contains("purpur-api:26.3.build.2651-stable"));
|
||||||
|
assertTrue(build.contains("purpur-26.3-2651.jar"));
|
||||||
|
assertTrue(build.contains("https://api.purpurmc.org/v2/purpur/26.3/2651/download"));
|
||||||
|
assertTrue(build.contains("0677c1febecfbc2e5b0a7f76abd647b70a1f38d3cbdf3dd6a82e401b4262a598"));
|
||||||
|
assertFalse(build.contains("26.2"));
|
||||||
|
assertFalse(build.contains("2618"));
|
||||||
assertFalse(build.contains("org.spigotmc:spigot-api"));
|
assertFalse(build.contains("org.spigotmc:spigot-api"));
|
||||||
|
|
||||||
|
String readme = Files.readString(Path.of("README.md"));
|
||||||
|
assertTrue(readme.contains("Purpur 26.3 build 2651"));
|
||||||
|
assertFalse(readme.contains("Purpur 26.2"));
|
||||||
|
assertFalse(readme.contains("2618"));
|
||||||
for (String workflow : new String[] {"ci.yml", "release.yml"}) {
|
for (String workflow : new String[] {"ci.yml", "release.yml"}) {
|
||||||
String content = Files.readString(Path.of(".gitea/workflows", workflow));
|
String content = Files.readString(Path.of(".gitea/workflows", workflow));
|
||||||
assertTrue(content.contains("java-version: 25"));
|
assertTrue(content.contains("java-version: 25"));
|
||||||
|
|||||||
Reference in new issue
Block a user