From 013fc6dadf48cd3771886ec59f5f621f9f50bb69 Mon Sep 17 00:00:00 2001 From: thisismartin321 Date: Tue, 13 Oct 2026 04:29:20 +0000 Subject: [PATCH] Port to Minecraft 26.2, NeoForge 26.2.0.90 - Bump MC/NeoForge versions - Replace the mc-26.1.2 test module with mc-26.2 and adapt the tests to the 26.2 API: LevelRenderer#renderLevel was renamed to render and its ChunkSectionsToRender parameter was dropped - NeoForge 26.2.0.90 bundles Mixin 0.17.4, matching the versions used by the rest of the 26.2 stack --- gradle.properties | 6 +- settings.gradle.kts | 4 +- test/mc-26.2/build.gradle.kts | 25 ++++++ .../mixin/BytecodeFixerUpperTestFrontend.java | 47 +++++++++++ .../mc_26_2/mixin/DynamicMixinPatchTest.java | 84 +++++++++++++++++++ .../resources/META-INF/neoforge.mods.toml | 11 +++ .../mc_26_2/mixin/LevelRendererMixin.java | 32 +++++++ .../test/mc_26_2/mixin/LivingEntityMixin.java | 38 +++++++++ 8 files changed, 242 insertions(+), 5 deletions(-) create mode 100644 test/mc-26.2/build.gradle.kts create mode 100644 test/mc-26.2/src/test/java/org/sinytra/adapter/patch/test/mc_26_2/mixin/BytecodeFixerUpperTestFrontend.java create mode 100644 test/mc-26.2/src/test/java/org/sinytra/adapter/patch/test/mc_26_2/mixin/DynamicMixinPatchTest.java create mode 100644 test/mc-26.2/src/test/resources/META-INF/neoforge.mods.toml create mode 100644 test/mc-26.2/src/testClasses/java/org/sinytra/adapter/test/mc_26_2/mixin/LevelRendererMixin.java create mode 100644 test/mc-26.2/src/testClasses/java/org/sinytra/adapter/test/mc_26_2/mixin/LivingEntityMixin.java diff --git a/gradle.properties b/gradle.properties index 6580acb..f26e282 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,8 +6,8 @@ org.gradle.parallel=true #org.gradle.caching=true #org.gradle.configuration-cache=true -versionMc=26.1.2 -versionNeoForge=26.1.2.77 -versionModDevGradle=2.0.141 +versionMc=26.2 +versionNeoForge=26.2.0.90 +versionModDevGradle=2.0.148 runtimeVersion=1.0.0 diff --git a/settings.gradle.kts b/settings.gradle.kts index 136b29b..8a68e98 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,5 +31,5 @@ include("runtime", "test") include("test:mc-1.21.1") project(":test:mc-1.21.1").projectDir = file("test/mc-1.21.1") -include("test:mc-26.1.2") -project(":test:mc-26.1.2").projectDir = file("test/mc-26.1.2") +include("test:mc-26.2") +project(":test:mc-26.2").projectDir = file("test/mc-26.2") diff --git a/test/mc-26.2/build.gradle.kts b/test/mc-26.2/build.gradle.kts new file mode 100644 index 0000000..19429f9 --- /dev/null +++ b/test/mc-26.2/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + id("net.neoforged.moddev") +} + +java { + toolchain.languageVersion = JavaLanguageVersion.of(25) +} + +neoForge { + version = "26.2.0.90" + + addModdingDependenciesTo(sourceSets.getByName("testClasses")) + + unitTest { + enable() + } +} + +dependencies { + testImplementation("org.sinytra.adapter:core") { + isTransitive = false + } + + testImplementation(project(":test")) +} diff --git a/test/mc-26.2/src/test/java/org/sinytra/adapter/patch/test/mc_26_2/mixin/BytecodeFixerUpperTestFrontend.java b/test/mc-26.2/src/test/java/org/sinytra/adapter/patch/test/mc_26_2/mixin/BytecodeFixerUpperTestFrontend.java new file mode 100644 index 0000000..2bb70e3 --- /dev/null +++ b/test/mc-26.2/src/test/java/org/sinytra/adapter/patch/test/mc_26_2/mixin/BytecodeFixerUpperTestFrontend.java @@ -0,0 +1,47 @@ +package org.sinytra.adapter.patch.test.mc_26_2.mixin; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.TypeInsnNode; +import org.sinytra.adapter.types.BytecodeFixerUpper; +import org.sinytra.adapter.types.SimpleTypeAdapter; +import org.sinytra.adapter.types.TypeAdapter; +import org.sinytra.adapter.util.provider.ClassLookup; + +import java.util.List; + +import static org.sinytra.adapter.util.AdapterUtil.insnList; + +public class BytecodeFixerUpperTestFrontend { + private static final List FIELD_TYPE_ADAPTERS = List.of( + new SimpleTypeAdapter(Type.getObjectType("net/minecraft/world/item/ItemStack"), Type.getObjectType("net/minecraft/world/item/Item"), (list, insn) -> + list.insert(insn, new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "net/minecraft/world/item/ItemStack", "getItem", "()Lnet/minecraft/world/item/Item;"))), + new SimpleTypeAdapter( + Type.getObjectType("java/util/function/Consumer"), + Type.getObjectType("net/neoforged/neoforge/network/bundle/PacketAndPayloadAcceptor"), + (list, insn) -> + list.insert(insn, insnList( + new TypeInsnNode(Opcodes.NEW, "net/neoforged/neoforge/network/bundle/PacketAndPayloadAcceptor"), + new InsnNode(Opcodes.DUP), + new MethodInsnNode(Opcodes.INVOKESPECIAL, "net/neoforged/neoforge/network/bundle/PacketAndPayloadAcceptor", "", "(Ljava/util/function/Consumer;)V") + ))), + new SimpleTypeAdapter( + Type.getObjectType("net/neoforged/neoforge/network/bundle/PacketAndPayloadAcceptor"), + Type.getObjectType("java/util/function/Consumer"), + (list, insn) -> + list.insert(insn, new FieldInsnNode(Opcodes.GETFIELD, "net/neoforged/neoforge/network/bundle/PacketAndPayloadAcceptor", "consumer", "Ljava/util/function/Consumer;"))) + ); + + private final BytecodeFixerUpper bfu; + + public BytecodeFixerUpperTestFrontend(ClassLookup cleanLookup, ClassLookup dirtyLookup) { + this.bfu = new BytecodeFixerUpper(cleanLookup, dirtyLookup, FIELD_TYPE_ADAPTERS); + } + + public BytecodeFixerUpper unwrap() { + return this.bfu; + } +} diff --git a/test/mc-26.2/src/test/java/org/sinytra/adapter/patch/test/mc_26_2/mixin/DynamicMixinPatchTest.java b/test/mc-26.2/src/test/java/org/sinytra/adapter/patch/test/mc_26_2/mixin/DynamicMixinPatchTest.java new file mode 100644 index 0000000..ef67ff4 --- /dev/null +++ b/test/mc-26.2/src/test/java/org/sinytra/adapter/patch/test/mc_26_2/mixin/DynamicMixinPatchTest.java @@ -0,0 +1,84 @@ +package org.sinytra.adapter.patch.test.mc_26_2.mixin; + +import com.mojang.logging.LogUtils; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.objectweb.asm.tree.ClassNode; +import org.sinytra.adapter.env.ctx.PatchEnvironment; +import org.sinytra.adapter.env.ctx.RefmapHolder; +import org.sinytra.adapter.patch.DynamicPatches; +import org.sinytra.adapter.patch.Patcher; +import org.sinytra.adapter.patch.test_main.mixin.MinecraftMixinPatchTest; +import org.sinytra.adapter.types.FieldTypeUsageTransformer; +import org.sinytra.adapter.util.provider.ClassLookup; +import org.slf4j.Logger; +import org.spongepowered.asm.mixin.FabricUtil; + +import java.util.List; + +public class DynamicMixinPatchTest extends MinecraftMixinPatchTest { + private static final Logger LOGGER = LogUtils.getLogger(); + + private static Patcher patcher; + private static PatchEnvironment patchEnvironment; + + @BeforeAll + static void initialize() { + ClassLookup cleanLookup = createCleanLookup(); + ClassLookup dirtyLookup = createDirtyLookup(); + patchEnvironment = PatchEnvironment.create( + new RefmapHolder() { + @Override + public String remap(String cls, String reference) { + return reference; + } + + @Override + public void copyEntries(String from, String to) { + } + }, + cleanLookup, + dirtyLookup, + new BytecodeFixerUpperTestFrontend(cleanLookup, dirtyLookup).unwrap(), + FabricUtil.COMPATIBILITY_LATEST + ); + patcher = Patcher.builder(patchEnvironment) + .classTransformer(new FieldTypeUsageTransformer()) + .methodTransformers(DynamicPatches.methodTransformers(List.of())) + .build(); + } + + @AfterAll + static void postTest() { + LOGGER.info("Complete report:\n\n{}", patchEnvironment.auditTrail().getCompleteReport()); + } + + @Test + void testExtractUsingCodePath() throws Exception { + assertSameCodeExtracted( + "org/sinytra/adapter/test/mc_26_2/mixin/LivingEntityMixin", + "playSoundCorrectlyForBlocks", + "org/sinytra/adapter/test/mc_26_2/mixin/adapter_generated_net_neoforged_neoforge_common_extensions_IBlockExtension", + assertTargetMethod() + ); + } + + @Test + void testModifyArgChangedTargetDesc() throws Exception { + assertSameCode( + "org/sinytra/adapter/test/mc_26_2/mixin/LevelRendererMixin", + "clampMaxValue", + assertTargetMethod(), + assertInjectionPoint() + ); + } + + @Override + protected LoadResult load(String className, List allowedMethods) throws Exception { + ClassNode patched = loadClass(className); + patched.methods.removeIf(m -> !allowedMethods.contains(m.name)); + patcher.process(patched); + return new LoadResult(patchEnvironment, patched, loadClass(className)); + } +} diff --git a/test/mc-26.2/src/test/resources/META-INF/neoforge.mods.toml b/test/mc-26.2/src/test/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..ad96245 --- /dev/null +++ b/test/mc-26.2/src/test/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,11 @@ +modLoader="javafml" +loaderVersion="*" +license="MIT" + +[[mods]] +modId="adapter_test_26_2" +version="1.0" +displayName="Adapter Test mod" +authors="Sinytra" +description=''' +''' diff --git a/test/mc-26.2/src/testClasses/java/org/sinytra/adapter/test/mc_26_2/mixin/LevelRendererMixin.java b/test/mc-26.2/src/testClasses/java/org/sinytra/adapter/test/mc_26_2/mixin/LevelRendererMixin.java new file mode 100644 index 0000000..8a8bff7 --- /dev/null +++ b/test/mc-26.2/src/testClasses/java/org/sinytra/adapter/test/mc_26_2/mixin/LevelRendererMixin.java @@ -0,0 +1,32 @@ +package org.sinytra.adapter.test.mc_26_2.mixin; + +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import net.minecraft.client.renderer.LevelRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(LevelRenderer.class) +public class LevelRendererMixin { + @ModifyArg( + method = "render(Lcom/mojang/blaze3d/resource/GraphicsResourceAllocator;Lnet/minecraft/client/DeltaTracker;ZLnet/minecraft/client/renderer/state/level/CameraRenderState;Lorg/joml/Matrix4fc;Lcom/mojang/blaze3d/buffers/GpuBufferSlice;Lorg/joml/Vector4f;Z)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/LevelRenderer;addSkyPass(Lcom/mojang/blaze3d/framegraph/FrameGraphBuilder;Lnet/minecraft/client/renderer/state/level/CameraRenderState;Lcom/mojang/blaze3d/buffers/GpuBufferSlice;)V" + ) + ) + private GpuBufferSlice clampMaxValue(GpuBufferSlice fogBuffer) { + return fogBuffer; + } + + @ModifyArg( + method = "render(Lcom/mojang/blaze3d/resource/GraphicsResourceAllocator;Lnet/minecraft/client/DeltaTracker;ZLnet/minecraft/client/renderer/state/level/CameraRenderState;Lorg/joml/Matrix4fc;Lcom/mojang/blaze3d/buffers/GpuBufferSlice;Lorg/joml/Vector4f;Z)V", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/LevelRenderer;addSkyPass(Lcom/mojang/blaze3d/framegraph/FrameGraphBuilder;Lnet/minecraft/client/renderer/state/level/CameraRenderState;Lcom/mojang/blaze3d/buffers/GpuBufferSlice;Lorg/joml/Matrix4fc;)V" + ) + ) + private GpuBufferSlice clampMaxValueExpected(GpuBufferSlice fogBuffer) { + return fogBuffer; + } +} diff --git a/test/mc-26.2/src/testClasses/java/org/sinytra/adapter/test/mc_26_2/mixin/LivingEntityMixin.java b/test/mc-26.2/src/testClasses/java/org/sinytra/adapter/test/mc_26_2/mixin/LivingEntityMixin.java new file mode 100644 index 0000000..ac30e33 --- /dev/null +++ b/test/mc-26.2/src/testClasses/java/org/sinytra/adapter/test/mc_26_2/mixin/LivingEntityMixin.java @@ -0,0 +1,38 @@ +package org.sinytra.adapter.test.mc_26_2.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(LivingEntity.class) +public class LivingEntityMixin { + public LivingEntityMixin() { + } + + @WrapOperation( + method = "playBlockFallSound", + at = {@At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;playSound(Lnet/minecraft/sounds/SoundEvent;FF)V" + )} + ) + private void playSoundCorrectlyForBlocks(LivingEntity instance, SoundEvent sound, float volume, float pitch, Operation original, @Local BlockState state) { + original.call(instance, sound, volume, pitch); + } + + @WrapOperation( + method = "playFallSound(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/LivingEntity;)V", + at = {@At( + value = "INVOKE", + target = "Lnet/minecraft/world/entity/LivingEntity;playSound(Lnet/minecraft/sounds/SoundEvent;FF)V" + )} + ) + private void playSoundCorrectlyForBlocksExpected(LivingEntity instance, SoundEvent sound, float volume, float pitch, Operation original, @Local BlockState state) { + original.call(instance, sound, volume, pitch); + } +}