From 5cfc4eaa651b888616b4626d001c0f4606e66002 Mon Sep 17 00:00:00 2001 From: alezhshede Date: Thu, 9 Jul 2026 12:07:48 +0200 Subject: [PATCH 1/2] Update Fabric target to 26.2 --- build.gradle.kts | 24 ++- bukkit/build.gradle.kts | 10 +- common/build.gradle.kts | 6 +- fabric/build.gradle.kts | 43 +++-- .../ChunkyBorderFabricClient.java | 6 +- .../mixin/WorldBorderRenderingMixin.java | 174 ++++++++++++------ .../chunkyborder/ChunkyBorderFabric.java | 60 +++--- .../bridge/RespawningPlayerBridge.java | 4 +- .../mixin/PlayerManagerMixin.java | 24 +-- .../mixin/ServerPlayNetworkHandlerMixin.java | 28 +-- .../chunkyborder/packet/BorderPayload.java | 16 +- .../main/resources/chunkyborder.mixins.json | 2 +- fabric/src/main/resources/fabric.mod.json | 8 +- forge/build.gradle.kts | 16 +- gradle.properties | 1 + gradle/wrapper/gradle-wrapper.properties | 2 +- neoforge/build.gradle.kts | 16 +- 17 files changed, 261 insertions(+), 179 deletions(-) rename fabric/src/{main => client}/java/org/popcraft/chunkyborder/ChunkyBorderFabricClient.java (90%) rename fabric/src/{main => client}/java/org/popcraft/chunkyborder/mixin/WorldBorderRenderingMixin.java (63%) diff --git a/build.gradle.kts b/build.gradle.kts index 72973f3..5943a40 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,18 +1,18 @@ -import java.io.ByteArrayOutputStream +import org.gradle.api.Project plugins { id("java-library") id("maven-publish") - id("io.github.goooler.shadow") version "8.1.7" + id("com.gradleup.shadow") version "9.5.1" } subprojects { plugins.apply("java-library") plugins.apply("maven-publish") - plugins.apply("io.github.goooler.shadow") + plugins.apply("com.gradleup.shadow") group = "${project.property("group")}" - version = "${project.property("version")}.${commitsSinceLastTag()}" + version = "${project.property("version")}.${project.commitsSinceLastTag()}" repositories { mavenCentral() @@ -27,7 +27,7 @@ subprojects { java { toolchain { - languageVersion.set(JavaLanguageVersion.of(21)) + languageVersion.set(JavaLanguageVersion.of(25)) } withSourcesJar() } @@ -35,7 +35,7 @@ subprojects { tasks { withType { options.encoding = "UTF-8" - options.release = 21 + options.release = 25 } jar { archiveClassifier.set("noshade") @@ -72,14 +72,12 @@ subprojects { } } -fun commitsSinceLastTag(): String { - val tagDescription = ByteArrayOutputStream() - exec { +fun Project.commitsSinceLastTag(): String { + val tagDescription = providers.exec { commandLine("git", "describe", "--tags") - standardOutput = tagDescription - } - if (tagDescription.toString().indexOf('-') < 0) { + }.standardOutput.asText.get() + if (tagDescription.indexOf('-') < 0) { return "0" } - return tagDescription.toString().split('-')[1] + return tagDescription.split('-')[1] } diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 02028b0..db239db 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -25,10 +25,12 @@ tasks { processResources { filesMatching("plugin.yml") { expand( - "version" to project.version, - "group" to project.group, - "author" to project.property("author"), - "description" to project.property("description") + mapOf( + "version" to project.version.toString(), + "group" to project.group.toString(), + "author" to project.property("author").toString(), + "description" to project.property("description").toString() + ) ) } } diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 8ea277e..a530077 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -18,8 +18,10 @@ tasks { processResources { filesMatching("version.properties") { expand( - "version" to project.version, - "target" to project.property("target") + mapOf( + "version" to project.version.toString(), + "target" to project.property("target").toString() + ) ) } } diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 65a2d2e..1916f5d 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("dev.architectury.loom") version "1.10-SNAPSHOT" + id("net.fabricmc.fabric-loom") version "1.17.13" } val shade: Configuration by configurations.creating @@ -13,12 +13,21 @@ repositories { } } +loom { + splitEnvironmentSourceSets() + mods { + create(rootProject.name) { + sourceSet(sourceSets["main"]) + sourceSet(sourceSets["client"]) + } + } +} + dependencies { - minecraft(group = "com.mojang", name = "minecraft", version = "1.21.4") - mappings(group = "net.fabricmc", name = "yarn", version = "1.21.4+build.1", classifier = "v2") - modImplementation(group = "net.fabricmc", name = "fabric-loader", version = "0.16.7") - modImplementation(group = "net.fabricmc.fabric-api", name = "fabric-api", version = "0.111.0+1.21.4") - modImplementation(group = "org.popcraft", name = "chunky-fabric", version = "${project.property("target")}") + minecraft("com.mojang:minecraft:26.2") + implementation("net.fabricmc:fabric-loader:0.19.3") + implementation("net.fabricmc.fabric-api:fabric-api:0.154.2+26.2") + implementation("org.popcraft:chunky-fabric:${project.property("target_fabric")}") compileOnly(group = "us.dynmap", name = "DynmapCoreAPI", version = "${project.property("target_dynmap")}") compileOnly(group = "com.github.BlueMap-Minecraft", name = "BlueMapAPI", version = "${project.property("target_bluemap")}") compileOnly(group = "xyz.jpenilla", name = "squaremap-api", version = "${project.property("target_squaremap")}") @@ -31,23 +40,23 @@ tasks { processResources { filesMatching("fabric.mod.json") { expand( - "id" to rootProject.name, - "version" to project.version, - "name" to project.property("artifactName"), - "description" to project.property("description"), - "author" to project.property("author"), - "github" to project.property("github"), - "target" to project.property("target") + mapOf( + "id" to rootProject.name, + "version" to project.version.toString(), + "name" to project.property("artifactName").toString(), + "description" to project.property("description").toString(), + "author" to project.property("author").toString(), + "github" to project.property("github").toString(), + "target" to project.property("target_fabric").toString() + ) ) } } shadowJar { + dependsOn("clientClasses") + from(sourceSets["client"].output) configurations = listOf(shade) archiveClassifier.set("dev") - archiveFileName.set(null as String?) - } - remapJar { - inputFile.set(shadowJar.get().archiveFile) archiveFileName.set("${project.property("artifactName")}-Fabric-${project.version}.jar") } } diff --git a/fabric/src/main/java/org/popcraft/chunkyborder/ChunkyBorderFabricClient.java b/fabric/src/client/java/org/popcraft/chunkyborder/ChunkyBorderFabricClient.java similarity index 90% rename from fabric/src/main/java/org/popcraft/chunkyborder/ChunkyBorderFabricClient.java rename to fabric/src/client/java/org/popcraft/chunkyborder/ChunkyBorderFabricClient.java index 04a6bcb..ccf5105 100644 --- a/fabric/src/main/java/org/popcraft/chunkyborder/ChunkyBorderFabricClient.java +++ b/fabric/src/client/java/org/popcraft/chunkyborder/ChunkyBorderFabricClient.java @@ -6,8 +6,8 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.network.packet.CustomPayload; -import net.minecraft.util.Identifier; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.Identifier; import org.popcraft.chunkyborder.packet.BorderPayload; import org.popcraft.chunkyborder.platform.Config; import org.popcraft.chunkyborder.shape.BorderShape; @@ -40,7 +40,7 @@ public void onInitializeClient() { final Path configPath = FabricLoader.getInstance().getConfigDir().resolve("chunkyborder/config.json"); ChunkyBorderFabricClient.setConfig(new FabricConfig(configPath)); BorderColor.parseColor(config.visualizerColor()); - PayloadTypeRegistry.playS2C().register(BorderPayload.ID, CustomPayload.codecOf(BorderPayload::write, BorderPayload::new)); + PayloadTypeRegistry.clientboundPlay().register(BorderPayload.ID, CustomPacketPayload.codec(BorderPayload::write, BorderPayload::new)); ClientPlayNetworking.registerGlobalReceiver(BorderPayload.ID, (borderPayload, context) -> { final ClientBorder clientBorder = borderPayload.getBorder(); if (clientBorder.worldKey() == null) { diff --git a/fabric/src/main/java/org/popcraft/chunkyborder/mixin/WorldBorderRenderingMixin.java b/fabric/src/client/java/org/popcraft/chunkyborder/mixin/WorldBorderRenderingMixin.java similarity index 63% rename from fabric/src/main/java/org/popcraft/chunkyborder/mixin/WorldBorderRenderingMixin.java rename to fabric/src/client/java/org/popcraft/chunkyborder/mixin/WorldBorderRenderingMixin.java index 72d60c1..ecc5e28 100644 --- a/fabric/src/main/java/org/popcraft/chunkyborder/mixin/WorldBorderRenderingMixin.java +++ b/fabric/src/client/java/org/popcraft/chunkyborder/mixin/WorldBorderRenderingMixin.java @@ -1,22 +1,30 @@ package org.popcraft.chunkyborder.mixin; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.PrimitiveTopology; +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.systems.RenderPass; import com.mojang.blaze3d.systems.RenderSystem; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gl.ShaderProgramKeys; -import net.minecraft.client.render.BufferBuilder; -import net.minecraft.client.render.BufferRenderer; -import net.minecraft.client.render.BuiltBuffer; -import net.minecraft.client.render.Tessellator; -import net.minecraft.client.render.VertexFormat; -import net.minecraft.client.render.VertexFormats; -import net.minecraft.client.render.WorldBorderRendering; -import net.minecraft.client.world.ClientWorld; -import net.minecraft.util.Identifier; +import com.mojang.blaze3d.textures.GpuTextureView; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.ByteBufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.MeshData; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.client.renderer.WorldBorderRenderer; +import net.minecraft.client.renderer.state.level.WorldBorderRenderState; +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.resources.Identifier; +import net.minecraft.util.Mth; import net.minecraft.util.Util; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.border.WorldBorder; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector4f; import org.popcraft.chunky.platform.util.Vector2; import org.popcraft.chunky.shape.ShapeUtil; import org.popcraft.chunkyborder.ChunkyBorderFabricClient; @@ -27,29 +35,39 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(WorldBorderRendering.class) +import java.util.Optional; +import java.util.OptionalDouble; + +@Mixin(WorldBorderRenderer.class) public class WorldBorderRenderingMixin { @Shadow @Final - private static Identifier FORCEFIELD; + private static Identifier FORCEFIELD_LOCATION; + + @Unique + private GpuBuffer chunkyborder$vertexBuffer; + + @Unique + private RenderSystem.AutoStorageIndexBuffer chunkyborder$indices; @Inject(method = "render", at = @At("HEAD"), cancellable = true) @SuppressWarnings("java:S3776") - private void render(WorldBorder border, Vec3d pos, double renderDistanceBlocks, double height, CallbackInfo ci) { - final ClientWorld clientWorld = MinecraftClient.getInstance().world; + private void render(WorldBorderRenderState state, Vec3 pos, double renderDistanceBlocks, double height, CallbackInfo ci) { + final ClientLevel clientWorld = Minecraft.getInstance().level; if (clientWorld == null) { return; } - final BorderShape borderShape = ChunkyBorderFabricClient.getBorderShape(clientWorld.getRegistryKey().getValue()); + final BorderShape borderShape = ChunkyBorderFabricClient.getBorderShape(clientWorld.dimension().identifier()); if (borderShape == null) { return; } - final double posX = pos.getX(); - final double posZ = pos.getZ(); + final double posX = pos.x(); + final double posZ = pos.z(); double distanceInsideBorder = Double.MAX_VALUE; if (borderShape instanceof final PolygonBorderShape polygon) { final double[] pointsX = polygon.getPointsX(); @@ -74,27 +92,17 @@ private void render(WorldBorder border, Vec3d pos, double renderDistanceBlocks, final Vector2 pointOnBorder = ShapeUtil.pointOnEllipse(centerX, centerZ, radiusX, radiusZ, cameraAngle); distanceInsideBorder = ShapeUtil.distanceBetweenPoints(posX, posZ, pointOnBorder.getX(), pointOnBorder.getZ()); } - if (distanceInsideBorder < renderDistanceBlocks) { - double alpha = 1.0D - distanceInsideBorder / renderDistanceBlocks; - alpha = Math.pow(alpha, 4.0D); - alpha = clamp(alpha, 0.0D, 1.0D); - RenderSystem.enableBlend(); - RenderSystem.enableDepthTest(); - RenderSystem.blendFuncSeparate(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE, GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ZERO); - RenderSystem.setShaderTexture(0, FORCEFIELD); - RenderSystem.depthMask(MinecraftClient.isFabulousGraphicsOrBetter()); - final int color = BorderColor.getColor(); - final float red = (color >> 16 & 255) / 255.0F; - final float green = (color >> 8 & 255) / 255.0F; - final float blue = (color & 255) / 255.0F; - RenderSystem.setShaderColor(red, green, blue, (float) alpha); - RenderSystem.setShader(ShaderProgramKeys.POSITION_TEX); - RenderSystem.polygonOffset(-3.0F, -3.0F); - RenderSystem.enablePolygonOffset(); - RenderSystem.disableCull(); - final float offset = (Util.getMeasuringTimeMs() % 3000L) / 3000.0F; - float textureVertical = (float) (height - MathHelper.fractionalPart(pos.getY())); - final BufferBuilder bufferBuilder = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE); + if (distanceInsideBorder >= renderDistanceBlocks) { + ci.cancel(); + return; + } + + double alpha = 1.0D - distanceInsideBorder / renderDistanceBlocks; + alpha = Mth.clamp(Math.pow(alpha, 4.0D), 0.0D, 1.0D); + final float offset = (Util.getMillis() % 3000L) / 3000.0F; + final float textureVertical = (float) (height - Mth.frac(pos.y())); + try (ByteBufferBuilder byteBufferBuilder = new ByteBufferBuilder(DefaultVertexFormat.POSITION_TEX.getVertexSize() * 1024)) { + final BufferBuilder bufferBuilder = new BufferBuilder(byteBufferBuilder, PrimitiveTopology.QUADS, DefaultVertexFormat.POSITION_TEX); final float textureSize = 0.5F; if (borderShape instanceof final PolygonBorderShape polygon) { final double[] pointsX = polygon.getPointsX(); @@ -194,27 +202,84 @@ private void render(WorldBorder border, Vec3d pos, double renderDistanceBlocks, b += angle; } } - final BuiltBuffer builtBuffer = bufferBuilder.endNullable(); - if (builtBuffer != null) { - BufferRenderer.drawWithGlobalProgram(builtBuffer); + final MeshData meshData = bufferBuilder.build(); + if (meshData != null) { + try (meshData) { + drawCustomBorder(meshData, pos, alpha); + } } - RenderSystem.enableCull(); - RenderSystem.polygonOffset(0.0F, 0.0F); - RenderSystem.disablePolygonOffset(); - RenderSystem.disableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.depthMask(true); } ci.cancel(); } + @Inject(method = "close", at = @At("HEAD")) + private void closeCustomBorderBuffer(CallbackInfo ci) { + if (chunkyborder$vertexBuffer != null) { + chunkyborder$vertexBuffer.close(); + chunkyborder$vertexBuffer = null; + } + } + + @Unique + private void drawCustomBorder(final MeshData meshData, final Vec3 pos, final double alpha) { + final Minecraft minecraft = Minecraft.getInstance(); + final int indexCount = meshData.drawState().indexCount(); + if (indexCount <= 0) { + return; + } + final long vertexBufferSize = meshData.vertexBuffer().remaining(); + if (chunkyborder$vertexBuffer == null || chunkyborder$vertexBuffer.isClosed() || chunkyborder$vertexBuffer.size() < vertexBufferSize) { + if (chunkyborder$vertexBuffer != null && !chunkyborder$vertexBuffer.isClosed()) { + chunkyborder$vertexBuffer.close(); + } + chunkyborder$vertexBuffer = RenderSystem.getDevice().createBuffer( + () -> "ChunkyBorder custom border vertex buffer", + GpuBuffer.USAGE_VERTEX | GpuBuffer.USAGE_COPY_DST, + vertexBufferSize + ); + } + RenderSystem.getDevice().createCommandEncoder().writeToBuffer(chunkyborder$vertexBuffer.slice(0, vertexBufferSize), meshData.vertexBuffer()); + if (chunkyborder$indices == null) { + chunkyborder$indices = RenderSystem.getSequentialBuffer(PrimitiveTopology.QUADS); + } + final GpuBuffer indexBuffer = chunkyborder$indices.getBuffer(indexCount); + final AbstractTexture texture = minecraft.getTextureManager().getTexture(FORCEFIELD_LOCATION); + final RenderTarget mainTarget = minecraft.gameRenderer.mainRenderTarget(); + final RenderTarget weatherTarget = minecraft.levelRenderer.weatherTarget(); + final GpuTextureView colorTexture = weatherTarget == null ? mainTarget.getColorTextureView() : weatherTarget.getColorTextureView(); + final GpuTextureView depthTexture = weatherTarget == null ? mainTarget.getDepthTextureView() : weatherTarget.getDepthTextureView(); + final int color = BorderColor.getColor(); + final GpuBufferSlice transforms = RenderSystem.getDynamicUniforms().writeTransform( + RenderSystem.getModelViewMatrixCopy(), + new Vector4f((color >> 16 & 255) / 255.0F, (color >> 8 & 255) / 255.0F, (color & 255) / 255.0F, (float) alpha), + new Vector3f(0.0F, (float) -pos.y(), 0.0F), + new Matrix4f() + ); + try (RenderPass renderPass = RenderSystem.getDevice().createCommandEncoder().createRenderPass( + () -> "ChunkyBorder custom world border", + colorTexture, + Optional.empty(), + depthTexture, + OptionalDouble.empty() + )) { + renderPass.setPipeline(RenderPipelines.WORLD_BORDER); + RenderSystem.bindDefaultUniforms(renderPass); + renderPass.setUniform("DynamicTransforms", transforms); + renderPass.setIndexBuffer(indexBuffer, chunkyborder$indices.type()); + renderPass.bindTexture("Sampler0", texture.getTextureView(), texture.getSampler()); + renderPass.setVertexBuffer(0, chunkyborder$vertexBuffer.slice(0, vertexBufferSize)); + renderPass.drawIndexed(0, 0, indexCount, 1, 0); + } + } + + @Unique private double clamp(final double value, final double p1, final double p2) { final double min = Math.min(p1, p2); final double max = Math.max(p1, p2); return Math.max(min, Math.min(max, value)); } + @Unique private void addWall(final BufferBuilder bufferBuilder, final double height, final double posX, final double posZ, final double x1, final double z1, final double x2, final double z2, final float offset, final float texturePosition, final float textureHorizontal, final float textureVertical) { addVertex(bufferBuilder, -height, posX, posZ, x1, z1, offset + texturePosition, offset + textureVertical); addVertex(bufferBuilder, -height, posX, posZ, x2, z2, offset + texturePosition + textureHorizontal, offset + textureVertical); @@ -222,7 +287,8 @@ private void addWall(final BufferBuilder bufferBuilder, final double height, fin addVertex(bufferBuilder, height, posX, posZ, x1, z1, offset + texturePosition, offset); } + @Unique private void addVertex(final BufferBuilder bufferBuilder, final double height, final double x1, final double z1, final double x2, final double z2, final float u, final float v) { - bufferBuilder.vertex((float) (x2 - x1), (float) height, (float) (z2 - z1)).texture(u, v); + bufferBuilder.addVertex((float) (x2 - x1), (float) height, (float) (z2 - z1)).setUv(u, v); } } diff --git a/fabric/src/main/java/org/popcraft/chunkyborder/ChunkyBorderFabric.java b/fabric/src/main/java/org/popcraft/chunkyborder/ChunkyBorderFabric.java index 654881e..9478f34 100644 --- a/fabric/src/main/java/org/popcraft/chunkyborder/ChunkyBorderFabric.java +++ b/fabric/src/main/java/org/popcraft/chunkyborder/ChunkyBorderFabric.java @@ -4,18 +4,18 @@ import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; +import net.fabricmc.fabric.api.networking.v1.ClientboundPlayChannelEvents; import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; -import net.fabricmc.fabric.api.networking.v1.S2CPlayChannelEvents; import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.fabricmc.fabric.impl.networking.PayloadTypeRegistryImpl; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.network.RegistryByteBuf; -import net.minecraft.network.packet.CustomPayload; -import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket; -import net.minecraft.particle.DustParticleEffect; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.DustParticleOptions; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import org.popcraft.chunky.Chunky; import org.popcraft.chunky.ChunkyProvider; import org.popcraft.chunky.platform.FabricPlayer; @@ -54,10 +54,10 @@ public void onInitialize() { Translator.addCustomTranslation("custom_border_message", config.message()); BorderColor.parseColor(config.visualizerColor()); new BorderInitializationTask(chunkyBorder).run(); - final PayloadTypeRegistry payloadTypeRegistry = PayloadTypeRegistry.playS2C(); - if (payloadTypeRegistry instanceof final PayloadTypeRegistryImpl payloadTypeRegistryImpl) { + final PayloadTypeRegistry payloadTypeRegistry = PayloadTypeRegistry.clientboundPlay(); + if (payloadTypeRegistry instanceof final PayloadTypeRegistryImpl payloadTypeRegistryImpl) { if (payloadTypeRegistryImpl.get(BorderPayload.ID) == null) { - PayloadTypeRegistry.playS2C().register(BorderPayload.ID, CustomPayload.codecOf(BorderPayload::write, BorderPayload::new)); + PayloadTypeRegistry.clientboundPlay().register(BorderPayload.ID, CustomPacketPayload.codec(BorderPayload::write, BorderPayload::new)); } } ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { @@ -66,30 +66,30 @@ public void onInitialize() { sendBorderPacket(List.of(handler.player), world, shape); } }); - S2CPlayChannelEvents.REGISTER.register((handler, sender, server, channels) -> { + ClientboundPlayChannelEvents.REGISTER.register((handler, sender, server, channels) -> { if (!registered) { - chunkyBorder.getChunky().getEventBus().subscribe(BorderChangeEvent.class, e -> sendBorderPacket(server.getPlayerManager().getPlayerList(), e.world(), e.shape())); + chunkyBorder.getChunky().getEventBus().subscribe(BorderChangeEvent.class, e -> sendBorderPacket(server.getPlayerList().getPlayers(), e.world(), e.shape())); registered = true; } if (channels.contains(BorderPayload.ID.id())) { - chunkyBorder.getPlayerData(handler.player.getUuid()).setUsingMod(true); + chunkyBorder.getPlayerData(handler.player.getUUID()).setUsingMod(true); } }); ServerLifecycleEvents.SERVER_STOPPING.register(minecraftServer -> chunkyBorder.disable()); final long checkInterval = Math.max(1, chunkyBorder.getConfig().checkInterval()); final BorderCheckTask borderCheckTask = new BorderCheckTask(chunkyBorder); ServerTickEvents.END_SERVER_TICK.register(server -> { - if (server.getTicks() % checkInterval == 0) { + if (server.getTickCount() % checkInterval == 0) { borderCheckTask.run(); } }); PlayerBlockBreakEvents.BEFORE.register((world, player, pos, state, blockEntity) -> { - if (!(player instanceof ServerPlayerEntity serverPlayer)) { + if (!(player instanceof ServerPlayer serverPlayer)) { return true; } - final BlockBreakEvent breakEvent = new BlockBreakEvent(new FabricPlayer(serverPlayer), new Location(new FabricWorld((ServerWorld) world), pos.getX(), pos.getY(), pos.getZ())); + final BlockBreakEvent breakEvent = new BlockBreakEvent(new FabricPlayer(serverPlayer), new Location(new FabricWorld((ServerLevel) world), pos.getX(), pos.getY(), pos.getZ())); chunky.getEventBus().call(breakEvent); return !breakEvent.isCancelled(); // Return false when cancelled to indicate we want to cancel this block break }); @@ -106,9 +106,9 @@ private void startVisualizer() { final int maxRange = chunkyBorder.getConfig().visualizerRange(); Particles.setMaxDistance(maxRange); ServerTickEvents.END_SERVER_TICK.register(server -> { - final long tick = server.getTicks(); - server.getPlayerManager().getPlayerList().forEach(fabricPlayer -> { - final ServerWorld serverWorld = fabricPlayer.getServerWorld(); + final long tick = server.getTickCount(); + server.getPlayerList().getPlayers().forEach(fabricPlayer -> { + final ServerLevel serverWorld = fabricPlayer.level(); final World world = new FabricWorld(serverWorld); final Player player = new FabricPlayer(fabricPlayer); final Shape border = chunkyBorder.getBorder(world.getName()).map(BorderData::getBorder).orElse(null); @@ -116,14 +116,14 @@ private void startVisualizer() { if (border != null && !isUsingMod) { final List particleLocations = Particles.at(player, border, (tick % 20) / 20d); for (final Vector3 location : particleLocations) { - final BlockPos pos = BlockPos.ofFloored(location.getX(), location.getY(), location.getZ()); - final boolean fullyOccluded = serverWorld.getBlockState(pos).isOpaqueFullCube() - && serverWorld.getBlockState(pos.north()).isOpaqueFullCube() - && serverWorld.getBlockState(pos.east()).isOpaqueFullCube() - && serverWorld.getBlockState(pos.south()).isOpaqueFullCube() - && serverWorld.getBlockState(pos.west()).isOpaqueFullCube(); + final BlockPos pos = BlockPos.containing(location.getX(), location.getY(), location.getZ()); + final boolean fullyOccluded = serverWorld.getBlockState(pos).isSolidRender() + && serverWorld.getBlockState(pos.north()).isSolidRender() + && serverWorld.getBlockState(pos.east()).isSolidRender() + && serverWorld.getBlockState(pos.south()).isSolidRender() + && serverWorld.getBlockState(pos.west()).isSolidRender(); if (!fullyOccluded) { - serverWorld.spawnParticles(fabricPlayer, new DustParticleEffect(BorderColor.getColor(), 1f), false, false, location.getX(), location.getY(), location.getZ(), 1, 0d, 0d, 0d, 0d); + serverWorld.sendParticles(fabricPlayer, new DustParticleOptions(BorderColor.getColor(), 1f), false, false, location.getX(), location.getY(), location.getZ(), 1, 0d, 0d, 0d, 0d); } } } @@ -131,9 +131,9 @@ private void startVisualizer() { }); } - private void sendBorderPacket(final Collection players, final World world, final Shape shape) { - for (final ServerPlayerEntity player : players) { - player.networkHandler.sendPacket(new CustomPayloadS2CPacket(new BorderPayload(world, shape))); + private void sendBorderPacket(final Collection players, final World world, final Shape shape) { + for (final ServerPlayer player : players) { + player.connection.send(new ClientboundCustomPayloadPacket(new BorderPayload(world, shape))); } } } diff --git a/fabric/src/main/java/org/popcraft/chunkyborder/bridge/RespawningPlayerBridge.java b/fabric/src/main/java/org/popcraft/chunkyborder/bridge/RespawningPlayerBridge.java index 08e8a85..e81f5a2 100644 --- a/fabric/src/main/java/org/popcraft/chunkyborder/bridge/RespawningPlayerBridge.java +++ b/fabric/src/main/java/org/popcraft/chunkyborder/bridge/RespawningPlayerBridge.java @@ -1,7 +1,7 @@ package org.popcraft.chunkyborder.bridge; -import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.level.ServerPlayer; public interface RespawningPlayerBridge { - void chunkyborder$setRespawningPlayer(ServerPlayerEntity player); + void chunkyborder$setRespawningPlayer(ServerPlayer player); } diff --git a/fabric/src/main/java/org/popcraft/chunkyborder/mixin/PlayerManagerMixin.java b/fabric/src/main/java/org/popcraft/chunkyborder/mixin/PlayerManagerMixin.java index 5b25756..61ae508 100644 --- a/fabric/src/main/java/org/popcraft/chunkyborder/mixin/PlayerManagerMixin.java +++ b/fabric/src/main/java/org/popcraft/chunkyborder/mixin/PlayerManagerMixin.java @@ -1,12 +1,12 @@ package org.popcraft.chunkyborder.mixin; -import net.minecraft.entity.Entity; -import net.minecraft.server.PlayerManager; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.TeleportTarget; -import net.minecraft.world.WorldProperties; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.players.PlayerList; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.portal.TeleportTransition; +import net.minecraft.world.level.storage.LevelData; +import net.minecraft.world.phys.Vec3; import org.popcraft.chunkyborder.bridge.RespawningPlayerBridge; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -14,19 +14,19 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; -@Mixin(PlayerManager.class) +@Mixin(PlayerList.class) public class PlayerManagerMixin { @Inject( - method = "respawnPlayer", + method = "respawn", at = @At( value = "INVOKE", - target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;requestTeleport(DDDFF)V", + target = "Lnet/minecraft/server/network/ServerGamePacketListenerImpl;teleport(DDDFF)V", shift = At.Shift.BEFORE ), locals = LocalCapture.CAPTURE_FAILHARD ) - private void handleRespawningPlayerBridge(ServerPlayerEntity player, boolean alive, Entity.RemovalReason removalReason, CallbackInfoReturnable cir, TeleportTarget target, ServerWorld serverWorld, ServerPlayerEntity respawningPlayer, Vec3d vec3d, byte b, ServerWorld serverWorld2, WorldProperties worldProperties) { - ((RespawningPlayerBridge) respawningPlayer.networkHandler).chunkyborder$setRespawningPlayer(respawningPlayer); + private void handleRespawningPlayerBridge(ServerPlayer player, boolean alive, Entity.RemovalReason removalReason, CallbackInfoReturnable cir, TeleportTransition target, ServerLevel serverWorld, ServerPlayer respawningPlayer, Vec3 vec3d, byte b, ServerLevel serverWorld2, LevelData worldProperties) { + ((RespawningPlayerBridge) respawningPlayer.connection).chunkyborder$setRespawningPlayer(respawningPlayer); } } diff --git a/fabric/src/main/java/org/popcraft/chunkyborder/mixin/ServerPlayNetworkHandlerMixin.java b/fabric/src/main/java/org/popcraft/chunkyborder/mixin/ServerPlayNetworkHandlerMixin.java index aa370e0..c1a0bf1 100644 --- a/fabric/src/main/java/org/popcraft/chunkyborder/mixin/ServerPlayNetworkHandlerMixin.java +++ b/fabric/src/main/java/org/popcraft/chunkyborder/mixin/ServerPlayNetworkHandlerMixin.java @@ -1,7 +1,5 @@ package org.popcraft.chunkyborder.mixin; -import net.minecraft.server.network.ServerPlayNetworkHandler; -import net.minecraft.server.network.ServerPlayerEntity; import org.popcraft.chunky.ChunkyProvider; import org.popcraft.chunky.platform.FabricPlayer; import org.popcraft.chunky.platform.FabricWorld; @@ -18,27 +16,29 @@ import java.util.Objects; import java.util.Optional; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; -@Mixin(ServerPlayNetworkHandler.class) +@Mixin(ServerGamePacketListenerImpl.class) public class ServerPlayNetworkHandlerMixin implements RespawningPlayerBridge { @Shadow - public ServerPlayerEntity player; + public ServerPlayer player; @Unique private Location redirect; @Unique - private ServerPlayerEntity respawningPlayer; + private ServerPlayer respawningPlayer; @Inject( - method = "requestTeleport(DDDFF)V", + method = "teleport(DDDFF)V", at = @At("HEAD") ) private void requestTeleport(final double x, final double y, final double z, final float yaw, final float pitch, final CallbackInfo ci) { - ServerPlayerEntity player = Objects.requireNonNullElse(this.respawningPlayer, this.player); + ServerPlayer player = Objects.requireNonNullElse(this.respawningPlayer, this.player); this.respawningPlayer = null; // Reset respawning player, that way it keeps using 'this.player' until it's respawning again final FabricPlayer fabricPlayer = new FabricPlayer(player); - final FabricWorld world = new FabricWorld(player.getServerWorld()); + final FabricWorld world = new FabricWorld(player.level()); final Location location = new Location(world, x, y, z, yaw, pitch); final PlayerTeleportEvent playerTeleportEvent = new PlayerTeleportEvent(fabricPlayer, location); ChunkyProvider.get().getEventBus().call(playerTeleportEvent); @@ -47,7 +47,7 @@ private void requestTeleport(final double x, final double y, final double z, fin } @ModifyVariable( - method = "requestTeleport(DDDFF)V", + method = "teleport(DDDFF)V", at = @At("HEAD"), argsOnly = true, index = 1 @@ -57,7 +57,7 @@ private double requestTeleportX(final double x) { } @ModifyVariable( - method = "requestTeleport(DDDFF)V", + method = "teleport(DDDFF)V", at = @At("HEAD"), argsOnly = true, index = 3 @@ -67,7 +67,7 @@ private double requestTeleportY(final double y) { } @ModifyVariable( - method = "requestTeleport(DDDFF)V", + method = "teleport(DDDFF)V", at = @At("HEAD"), argsOnly = true, index = 5 @@ -77,7 +77,7 @@ private double requestTeleportZ(final double z) { } @ModifyVariable( - method = "requestTeleport(DDDFF)V", + method = "teleport(DDDFF)V", at = @At("HEAD"), argsOnly = true, index = 7 @@ -87,7 +87,7 @@ private float requestTeleportYaw(final float yaw) { } @ModifyVariable( - method = "requestTeleport(DDDFF)V", + method = "teleport(DDDFF)V", at = @At("HEAD"), argsOnly = true, index = 8 @@ -97,7 +97,7 @@ private float requestTeleportPitch(final float pitch) { } @Override - public void chunkyborder$setRespawningPlayer(ServerPlayerEntity player) { + public void chunkyborder$setRespawningPlayer(ServerPlayer player) { this.respawningPlayer = player; } } diff --git a/fabric/src/main/java/org/popcraft/chunkyborder/packet/BorderPayload.java b/fabric/src/main/java/org/popcraft/chunkyborder/packet/BorderPayload.java index a15b06d..1100b08 100644 --- a/fabric/src/main/java/org/popcraft/chunkyborder/packet/BorderPayload.java +++ b/fabric/src/main/java/org/popcraft/chunkyborder/packet/BorderPayload.java @@ -1,30 +1,30 @@ package org.popcraft.chunkyborder.packet; import io.netty.buffer.ByteBuf; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.CustomPayload; -import net.minecraft.util.Identifier; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.Identifier; import org.popcraft.chunky.platform.World; import org.popcraft.chunky.shape.Shape; import org.popcraft.chunkyborder.util.ClientBorder; import org.popcraft.chunkyborder.util.PluginMessage; -public class BorderPayload implements CustomPayload { - public static final CustomPayload.Id ID = new CustomPayload.Id<>(Identifier.of("chunky:border")); +public class BorderPayload implements CustomPacketPayload { + public static final CustomPacketPayload.Type ID = new CustomPacketPayload.Type<>(Identifier.parse("chunky:border")); private final ClientBorder border; public BorderPayload(final World world, final Shape shape) { this.border = new ClientBorder(world.getKey(), shape); } - public BorderPayload(final PacketByteBuf buf) { + public BorderPayload(final FriendlyByteBuf buf) { final ByteBuf unwrapped = buf.unwrap(); final byte[] bytes = new byte[unwrapped.readableBytes()]; unwrapped.readBytes(bytes); this.border = PluginMessage.readBorder(bytes); } - public void write(final PacketByteBuf buf) { + public void write(final FriendlyByteBuf buf) { buf.writeBytes(PluginMessage.writeBorder(this.border)); } @@ -33,7 +33,7 @@ public ClientBorder getBorder() { } @Override - public CustomPayload.Id getId() { + public CustomPacketPayload.Type type() { return ID; } } diff --git a/fabric/src/main/resources/chunkyborder.mixins.json b/fabric/src/main/resources/chunkyborder.mixins.json index 3db307e..aa735b4 100644 --- a/fabric/src/main/resources/chunkyborder.mixins.json +++ b/fabric/src/main/resources/chunkyborder.mixins.json @@ -2,7 +2,7 @@ "required": true, "minVersion": "0.8", "package": "org.popcraft.chunkyborder.mixin", - "compatibilityLevel": "JAVA_8", + "compatibilityLevel": "JAVA_25", "mixins": [ "PlayerManagerMixin", "ServerPlayNetworkHandlerMixin" diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 69ccb7e..e8d66c3 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -32,10 +32,10 @@ "chunkyborder.mixins.json" ], "depends": { - "fabricloader": ">=0.16.7", - "fabric": "*", - "minecraft": ">=1.21.4", - "java": ">=21", + "fabricloader": ">=0.19.3", + "fabric-api": "*", + "minecraft": ">=26.2", + "java": ">=25", "chunky": ">=${target}" }, "custom": { diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index f07f8ff..c429435 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -30,13 +30,15 @@ tasks { processResources { filesMatching("META-INF/mods.toml") { expand( - "id" to rootProject.name, - "version" to project.version, - "name" to project.property("artifactName"), - "description" to project.property("description"), - "author" to project.property("author"), - "github" to project.property("github"), - "target" to project.property("target") + mapOf( + "id" to rootProject.name, + "version" to project.version.toString(), + "name" to project.property("artifactName").toString(), + "description" to project.property("description").toString(), + "author" to project.property("author").toString(), + "github" to project.property("github").toString(), + "target" to project.property("target").toString() + ) ) } } diff --git a/gradle.properties b/gradle.properties index 8a55d6b..a0246c8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,6 +3,7 @@ group=org.popcraft artifactName=ChunkyBorder version=1.2 target=1.4.10 +target_fabric=1.5.3 target_dynmap=3.3 target_bluemap=v2.1.0 target_squaremap=1.1.2 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ed4c299..317a32c 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-8.13-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 54b9f0e..930b670 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -31,13 +31,15 @@ tasks { processResources { filesMatching("META-INF/neoforge.mods.toml") { expand( - "id" to rootProject.name, - "version" to project.version, - "name" to project.property("artifactName"), - "description" to project.property("description"), - "author" to project.property("author"), - "github" to project.property("github"), - "target" to project.property("target") + mapOf( + "id" to rootProject.name, + "version" to project.version.toString(), + "name" to project.property("artifactName").toString(), + "description" to project.property("description").toString(), + "author" to project.property("author").toString(), + "github" to project.property("github").toString(), + "target" to project.property("target").toString() + ) ) } } From 60d498175726508f8fc094db9bba0c543995884e Mon Sep 17 00:00:00 2001 From: alezhshede Date: Thu, 9 Jul 2026 22:53:28 +0200 Subject: [PATCH 2/2] Update NeoForge target to 26.2 --- build.gradle.kts | 2 +- fabric/build.gradle.kts | 9 ++ gradle.properties | 1 + neoforge/build.gradle.kts | 26 +-- .../chunkyborder/ChunkyBorderNeoForge.java | 13 +- .../ServerGamePacketListenerImplMixin.java | 2 +- .../client/WorldBorderRendererMixin.java | 149 +++++++++++++----- .../chunkyborder/packet/BorderPayload.java | 4 +- .../resources/META-INF/neoforge.mods.toml | 4 +- .../main/resources/chunkyborder.mixins.json | 2 +- 10 files changed, 146 insertions(+), 66 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 5943a40..2765798 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,7 +35,7 @@ subprojects { tasks { withType { options.encoding = "UTF-8" - options.release = 25 + options.release = 21 } jar { archiveClassifier.set("noshade") diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 1916f5d..2a714f1 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -23,6 +23,12 @@ loom { } } +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(25)) + } +} + dependencies { minecraft("com.mojang:minecraft:26.2") implementation("net.fabricmc:fabric-loader:0.19.3") @@ -37,6 +43,9 @@ dependencies { } tasks { + withType { + options.release = 25 + } processResources { filesMatching("fabric.mod.json") { expand( diff --git a/gradle.properties b/gradle.properties index a0246c8..29a8c6c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,6 +4,7 @@ artifactName=ChunkyBorder version=1.2 target=1.4.10 target_fabric=1.5.3 +target_neoforge=1.5.3 target_dynmap=3.3 target_bluemap=v2.1.0 target_squaremap=1.1.2 diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 930b670..efc2e97 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("dev.architectury.loom") version "1.10-SNAPSHOT" + id("dev.architectury.loom-no-remap") version "1.17.491" } val shade: Configuration by configurations.creating @@ -15,10 +15,9 @@ repositories { } dependencies { - minecraft(group = "com.mojang", name = "minecraft", version = "1.21.4") - mappings(loom.officialMojangMappings()) - neoForge(group = "net.neoforged", name = "neoforge", version = "21.4.10-beta") - modImplementation(group = "org.popcraft", name = "chunky-neoforge", version = "${project.property("target")}") + minecraft(group = "com.mojang", name = "minecraft", version = "26.2") + neoForge(group = "net.neoforged", name = "neoforge", version = "26.2.0.9-beta") + implementation(group = "org.popcraft", name = "chunky-neoforge", version = "${project.property("target_neoforge")}") compileOnly(group = "us.dynmap", name = "DynmapCoreAPI", version = "${project.property("target_dynmap")}") compileOnly(group = "com.github.BlueMap-Minecraft", name = "BlueMapAPI", version = "${project.property("target_bluemap")}") compileOnly(group = "xyz.jpenilla", name = "squaremap-api", version = "${project.property("target_squaremap")}") @@ -27,7 +26,16 @@ dependencies { shade(project(":chunkyborder-common")) } +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(25)) + } +} + tasks { + withType { + options.release = 25 + } processResources { filesMatching("META-INF/neoforge.mods.toml") { expand( @@ -38,7 +46,7 @@ tasks { "description" to project.property("description").toString(), "author" to project.property("author").toString(), "github" to project.property("github").toString(), - "target" to project.property("target").toString() + "target" to project.property("target_neoforge").toString() ) ) } @@ -56,11 +64,7 @@ tasks { } shadowJar { configurations = listOf(shade) - archiveClassifier.set("dev") - archiveFileName.set(null as String?) - } - remapJar { - inputFile.set(shadowJar.get().archiveFile) + archiveClassifier.set("") archiveFileName.set("${project.property("artifactName")}-NeoForge-${project.version}.jar") } } diff --git a/neoforge/src/main/java/org/popcraft/chunkyborder/ChunkyBorderNeoForge.java b/neoforge/src/main/java/org/popcraft/chunkyborder/ChunkyBorderNeoForge.java index 2ff0f1b..3a14cca 100644 --- a/neoforge/src/main/java/org/popcraft/chunkyborder/ChunkyBorderNeoForge.java +++ b/neoforge/src/main/java/org/popcraft/chunkyborder/ChunkyBorderNeoForge.java @@ -4,7 +4,7 @@ import net.minecraft.core.particles.DustParticleOptions; import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -15,6 +15,7 @@ import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent; import net.neoforged.neoforge.event.level.BlockEvent; +import net.neoforged.neoforge.event.level.block.BreakBlockEvent; import net.neoforged.neoforge.event.server.ServerStartedEvent; import net.neoforged.neoforge.event.server.ServerStoppingEvent; import net.neoforged.neoforge.event.tick.ServerTickEvent; @@ -53,7 +54,7 @@ @Mod(ChunkyBorderNeoForge.MOD_ID) public class ChunkyBorderNeoForge { public static final String MOD_ID = "chunkyborder"; - private static final Map borderShapes = new ConcurrentHashMap<>(); + private static final Map borderShapes = new ConcurrentHashMap<>(); private static Config config; private ChunkyBorder chunkyBorder; private BorderCheckTask borderCheckTask; @@ -74,7 +75,7 @@ public ChunkyBorderNeoForge(final IEventBus modBus) { if (clientBorder.worldKey() == null) { return; } - final ResourceLocation identifier = ResourceLocation.tryParse(clientBorder.worldKey()); + final Identifier identifier = Identifier.tryParse(clientBorder.worldKey()); if (identifier == null) { return; } @@ -137,7 +138,7 @@ public void onServerTick(final ServerTickEvent.Post event) { final int maxRange = chunkyBorder.getConfig().visualizerRange(); Particles.setMaxDistance(maxRange); server.getPlayerList().getPlayers().forEach(neoForgePlayer -> { - final ServerLevel serverLevel = neoForgePlayer.serverLevel(); + final ServerLevel serverLevel = neoForgePlayer.level(); final World world = new NeoForgeWorld(serverLevel); final Player player = new NeoForgePlayer(neoForgePlayer); final Shape border = chunkyBorder.getBorder(world.getName()).map(BorderData::getBorder).orElse(null); @@ -173,7 +174,7 @@ public void onBlockPlace(final BlockEvent.EntityPlaceEvent event) { } @SubscribeEvent - public void onBlockBreak(final BlockEvent.BreakEvent event) { + public void onBlockBreak(final BreakBlockEvent event) { if (!(event.getPlayer() instanceof ServerPlayer player)) { return; } @@ -194,7 +195,7 @@ private void sendBorderPacket(final Collection players, final Worl } } - public static BorderShape getBorderShape(final ResourceLocation identifier) { + public static BorderShape getBorderShape(final Identifier identifier) { return ChunkyBorderNeoForge.borderShapes.get(identifier); } diff --git a/neoforge/src/main/java/org/popcraft/chunkyborder/mixin/ServerGamePacketListenerImplMixin.java b/neoforge/src/main/java/org/popcraft/chunkyborder/mixin/ServerGamePacketListenerImplMixin.java index b6e2d49..37155dd 100644 --- a/neoforge/src/main/java/org/popcraft/chunkyborder/mixin/ServerGamePacketListenerImplMixin.java +++ b/neoforge/src/main/java/org/popcraft/chunkyborder/mixin/ServerGamePacketListenerImplMixin.java @@ -31,7 +31,7 @@ public class ServerGamePacketListenerImplMixin { ) private void requestTeleport(final double x, final double y, final double z, final float yaw, final float pitch, final CallbackInfo ci) { final NeoForgePlayer neoForgePlayer = new NeoForgePlayer(this.player); - final NeoForgeWorld world = new NeoForgeWorld(this.player.serverLevel()); + final NeoForgeWorld world = new NeoForgeWorld(this.player.level()); final Location location = new Location(world, x, y, z, yaw, pitch); final PlayerTeleportEvent playerTeleportEvent = new PlayerTeleportEvent(neoForgePlayer, location); ChunkyProvider.get().getEventBus().call(playerTeleportEvent); diff --git a/neoforge/src/main/java/org/popcraft/chunkyborder/mixin/client/WorldBorderRendererMixin.java b/neoforge/src/main/java/org/popcraft/chunkyborder/mixin/client/WorldBorderRendererMixin.java index 4192b72..2fd5613 100644 --- a/neoforge/src/main/java/org/popcraft/chunkyborder/mixin/client/WorldBorderRendererMixin.java +++ b/neoforge/src/main/java/org/popcraft/chunkyborder/mixin/client/WorldBorderRendererMixin.java @@ -1,22 +1,29 @@ package org.popcraft.chunkyborder.mixin.client; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.PrimitiveTopology; +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.systems.RenderPass; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.GpuTextureView; import com.mojang.blaze3d.vertex.BufferBuilder; -import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.ByteBufferBuilder; import com.mojang.blaze3d.vertex.DefaultVertexFormat; import com.mojang.blaze3d.vertex.MeshData; -import com.mojang.blaze3d.vertex.Tesselator; -import com.mojang.blaze3d.vertex.VertexFormat; -import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.client.renderer.CoreShaders; +import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.client.renderer.WorldBorderRenderer; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.client.renderer.state.level.WorldBorderRenderState; +import net.minecraft.client.renderer.texture.AbstractTexture; +import net.minecraft.resources.Identifier; import net.minecraft.util.Mth; -import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.util.Util; import net.minecraft.world.phys.Vec3; +import org.joml.Matrix4f; +import org.joml.Vector3f; +import org.joml.Vector4f; import org.popcraft.chunky.platform.util.Vector2; import org.popcraft.chunky.shape.ShapeUtil; import org.popcraft.chunkyborder.ChunkyBorderNeoForge; @@ -27,24 +34,34 @@ import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.Optional; +import java.util.OptionalDouble; + @Mixin(WorldBorderRenderer.class) public class WorldBorderRendererMixin { @Shadow @Final - private static ResourceLocation FORCEFIELD_LOCATION; + private static Identifier FORCEFIELD_LOCATION; + + @Unique + private GpuBuffer chunkyborder$vertexBuffer; + + @Unique + private RenderSystem.AutoStorageIndexBuffer chunkyborder$indices; @Inject(method = "render", at = @At("HEAD"), cancellable = true) @SuppressWarnings("java:S3776") - private void renderWorldBorder(WorldBorder border, Vec3 pos, double renderDistanceBlocks, double height, CallbackInfo ci) { + private void renderWorldBorder(WorldBorderRenderState state, Vec3 pos, double renderDistanceBlocks, double height, CallbackInfo ci) { final ClientLevel clientLevel = Minecraft.getInstance().level; if (clientLevel == null) { return; } - final BorderShape borderShape = ChunkyBorderNeoForge.getBorderShape(clientLevel.dimension().location()); + final BorderShape borderShape = ChunkyBorderNeoForge.getBorderShape(clientLevel.dimension().identifier()); if (borderShape == null) { return; } @@ -74,27 +91,17 @@ private void renderWorldBorder(WorldBorder border, Vec3 pos, double renderDistan final Vector2 pointOnBorder = ShapeUtil.pointOnEllipse(centerX, centerZ, radiusX, radiusZ, cameraAngle); distanceInsideBorder = ShapeUtil.distanceBetweenPoints(posX, posZ, pointOnBorder.getX(), pointOnBorder.getZ()); } - if (distanceInsideBorder < renderDistanceBlocks) { - double alpha = 1.0D - distanceInsideBorder / renderDistanceBlocks; - alpha = Math.pow(alpha, 4.0D); - alpha = clamp(alpha, 0.0D, 1.0D); - RenderSystem.enableBlend(); - RenderSystem.enableDepthTest(); - RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); - RenderSystem.setShaderTexture(0, FORCEFIELD_LOCATION); - RenderSystem.depthMask(Minecraft.useShaderTransparency()); - final int color = BorderColor.getColor(); - final float red = (color >> 16 & 255) / 255.0F; - final float green = (color >> 8 & 255) / 255.0F; - final float blue = (color & 255) / 255.0F; - RenderSystem.setShaderColor(red, green, blue, (float) alpha); - RenderSystem.setShader(CoreShaders.POSITION_TEX); - RenderSystem.polygonOffset(-3.0F, -3.0F); - RenderSystem.enablePolygonOffset(); - RenderSystem.disableCull(); - final float offset = (Util.getMillis() % 3000L) / 3000.0F; - float textureVertical = (float) (height - Mth.frac(pos.y())); - final BufferBuilder bufferBuilder = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); + if (distanceInsideBorder >= renderDistanceBlocks) { + ci.cancel(); + return; + } + + double alpha = 1.0D - distanceInsideBorder / renderDistanceBlocks; + alpha = Mth.clamp(Math.pow(alpha, 4.0D), 0.0D, 1.0D); + final float offset = (Util.getMillis() % 3000L) / 3000.0F; + final float textureVertical = (float) (height - Mth.frac(pos.y())); + try (ByteBufferBuilder byteBufferBuilder = new ByteBufferBuilder(DefaultVertexFormat.POSITION_TEX.getVertexSize() * 1024)) { + final BufferBuilder bufferBuilder = new BufferBuilder(byteBufferBuilder, PrimitiveTopology.QUADS, DefaultVertexFormat.POSITION_TEX); final float textureSize = 0.5F; if (borderShape instanceof final PolygonBorderShape polygon) { final double[] pointsX = polygon.getPointsX(); @@ -194,27 +201,84 @@ private void renderWorldBorder(WorldBorder border, Vec3 pos, double renderDistan b += angle; } } - final MeshData meshdata = bufferBuilder.build(); - if (meshdata != null) { - BufferUploader.drawWithShader(meshdata); + final MeshData meshData = bufferBuilder.build(); + if (meshData != null) { + try (meshData) { + drawCustomBorder(meshData, pos, alpha); + } } - RenderSystem.enableCull(); - RenderSystem.polygonOffset(0.0F, 0.0F); - RenderSystem.disablePolygonOffset(); - RenderSystem.disableBlend(); - RenderSystem.defaultBlendFunc(); - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - RenderSystem.depthMask(true); } ci.cancel(); } + @Inject(method = "close", at = @At("HEAD")) + private void closeCustomBorderBuffer(CallbackInfo ci) { + if (chunkyborder$vertexBuffer != null) { + chunkyborder$vertexBuffer.close(); + chunkyborder$vertexBuffer = null; + } + } + + @Unique + private void drawCustomBorder(final MeshData meshData, final Vec3 pos, final double alpha) { + final Minecraft minecraft = Minecraft.getInstance(); + final int indexCount = meshData.drawState().indexCount(); + if (indexCount <= 0) { + return; + } + final long vertexBufferSize = meshData.vertexBuffer().remaining(); + if (chunkyborder$vertexBuffer == null || chunkyborder$vertexBuffer.isClosed() || chunkyborder$vertexBuffer.size() < vertexBufferSize) { + if (chunkyborder$vertexBuffer != null && !chunkyborder$vertexBuffer.isClosed()) { + chunkyborder$vertexBuffer.close(); + } + chunkyborder$vertexBuffer = RenderSystem.getDevice().createBuffer( + () -> "ChunkyBorder custom border vertex buffer", + GpuBuffer.USAGE_VERTEX | GpuBuffer.USAGE_COPY_DST, + vertexBufferSize + ); + } + RenderSystem.getDevice().createCommandEncoder().writeToBuffer(chunkyborder$vertexBuffer.slice(0, vertexBufferSize), meshData.vertexBuffer()); + if (chunkyborder$indices == null) { + chunkyborder$indices = RenderSystem.getSequentialBuffer(PrimitiveTopology.QUADS); + } + final GpuBuffer indexBuffer = chunkyborder$indices.getBuffer(indexCount); + final AbstractTexture texture = minecraft.getTextureManager().getTexture(FORCEFIELD_LOCATION); + final RenderTarget mainTarget = minecraft.gameRenderer.mainRenderTarget(); + final RenderTarget weatherTarget = minecraft.levelRenderer.weatherTarget(); + final GpuTextureView colorTexture = weatherTarget == null ? mainTarget.getColorTextureView() : weatherTarget.getColorTextureView(); + final GpuTextureView depthTexture = weatherTarget == null ? mainTarget.getDepthTextureView() : weatherTarget.getDepthTextureView(); + final int color = BorderColor.getColor(); + final GpuBufferSlice transforms = RenderSystem.getDynamicUniforms().writeTransform( + RenderSystem.getModelViewMatrixCopy(), + new Vector4f((color >> 16 & 255) / 255.0F, (color >> 8 & 255) / 255.0F, (color & 255) / 255.0F, (float) alpha), + new Vector3f(0.0F, (float) -pos.y(), 0.0F), + new Matrix4f() + ); + try (RenderPass renderPass = RenderSystem.getDevice().createCommandEncoder().createRenderPass( + () -> "ChunkyBorder custom world border", + colorTexture, + Optional.empty(), + depthTexture, + OptionalDouble.empty() + )) { + renderPass.setPipeline(RenderPipelines.WORLD_BORDER); + RenderSystem.bindDefaultUniforms(renderPass); + renderPass.setUniform("DynamicTransforms", transforms); + renderPass.setIndexBuffer(indexBuffer, chunkyborder$indices.type()); + renderPass.bindTexture("Sampler0", texture.getTextureView(), texture.getSampler()); + renderPass.setVertexBuffer(0, chunkyborder$vertexBuffer.slice(0, vertexBufferSize)); + renderPass.drawIndexed(0, 0, indexCount, 1, 0); + } + } + + @Unique private double clamp(final double value, final double p1, final double p2) { final double min = Math.min(p1, p2); final double max = Math.max(p1, p2); return Math.max(min, Math.min(max, value)); } + @Unique private void addWall(final BufferBuilder bufferBuilder, final double height, final double posX, final double posZ, final double x1, final double z1, final double x2, final double z2, final float offset, final float texturePosition, final float textureHorizontal, final float textureVertical) { addVertex(bufferBuilder, -height, posX, posZ, x1, z1, offset + texturePosition, offset + textureVertical); addVertex(bufferBuilder, -height, posX, posZ, x2, z2, offset + texturePosition + textureHorizontal, offset + textureVertical); @@ -222,6 +286,7 @@ private void addWall(final BufferBuilder bufferBuilder, final double height, fin addVertex(bufferBuilder, height, posX, posZ, x1, z1, offset + texturePosition, offset); } + @Unique private void addVertex(final BufferBuilder bufferBuilder, final double height, final double x1, final double z1, final double x2, final double z2, final float u, final float v) { bufferBuilder.addVertex((float) (x2 - x1), (float) height, (float) (z2 - z1)).setUv(u, v); } diff --git a/neoforge/src/main/java/org/popcraft/chunkyborder/packet/BorderPayload.java b/neoforge/src/main/java/org/popcraft/chunkyborder/packet/BorderPayload.java index 2eb0c70..216e742 100644 --- a/neoforge/src/main/java/org/popcraft/chunkyborder/packet/BorderPayload.java +++ b/neoforge/src/main/java/org/popcraft/chunkyborder/packet/BorderPayload.java @@ -3,7 +3,7 @@ import io.netty.buffer.ByteBuf; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import org.jetbrains.annotations.NotNull; import org.popcraft.chunky.platform.World; import org.popcraft.chunky.shape.Shape; @@ -11,7 +11,7 @@ import org.popcraft.chunkyborder.util.PluginMessage; public class BorderPayload implements CustomPacketPayload { - public static final CustomPacketPayload.Type ID = new CustomPacketPayload.Type<>(ResourceLocation.parse("chunky:border")); + public static final CustomPacketPayload.Type ID = new CustomPacketPayload.Type<>(Identifier.parse("chunky:border")); private final ClientBorder border; public BorderPayload(final World world, final Shape shape) { diff --git a/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/neoforge/src/main/resources/META-INF/neoforge.mods.toml index e0d8632..00031c2 100644 --- a/neoforge/src/main/resources/META-INF/neoforge.mods.toml +++ b/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -13,13 +13,13 @@ description="${description}" [[dependencies.chunkyborder]] modId="neoforge" type="required" - versionRange="[21.4.0-beta,)" + versionRange="[26.2.0.0-beta,)" ordering="NONE" side="BOTH" [[dependencies.chunkyborder]] modId="minecraft" type="required" - versionRange="[1.21.4,1.22)" + versionRange="[26.2,26.3)" ordering="NONE" side="BOTH" [[dependencies.chunkyborder]] diff --git a/neoforge/src/main/resources/chunkyborder.mixins.json b/neoforge/src/main/resources/chunkyborder.mixins.json index 1e6fa96..45ff44a 100644 --- a/neoforge/src/main/resources/chunkyborder.mixins.json +++ b/neoforge/src/main/resources/chunkyborder.mixins.json @@ -2,7 +2,7 @@ "required": true, "minVersion": "0.8", "package": "org.popcraft.chunkyborder.mixin", - "compatibilityLevel": "JAVA_17", + "compatibilityLevel": "JAVA_25", "mixins": [ "ServerGamePacketListenerImplMixin" ],