diff --git a/common/api/src/main/java/com/dfsek/terra/api/util/reflection/ReflectionUtil.java b/common/api/src/main/java/com/dfsek/terra/api/util/reflection/ReflectionUtil.java index 8e35c3f9f..6b0c8fd28 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/util/reflection/ReflectionUtil.java +++ b/common/api/src/main/java/com/dfsek/terra/api/util/reflection/ReflectionUtil.java @@ -8,6 +8,7 @@ package com.dfsek.terra.api.util.reflection; import org.jetbrains.annotations.NotNull; +import sun.misc.Unsafe; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; @@ -26,6 +27,18 @@ import java.util.stream.Stream; public final class ReflectionUtil { + private static final Unsafe UNSAFE; + + static { + try{ + final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + UNSAFE = (Unsafe) unsafeField.get(null); + } catch(NoSuchFieldException | IllegalAccessException e){ + throw new RuntimeException(e); + } + } + public static Field[] getFields(@NotNull Class type) { Field[] result = type.getDeclaredFields(); Class parentClass = type.getSuperclass(); @@ -35,6 +48,14 @@ public final class ReflectionUtil { return result; } + public static void setFinalField(Object obj, String fieldName, Object value) throws NoSuchFieldException { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + long fieldOffset = UNSAFE.objectFieldOffset(field); + + UNSAFE.putObject(obj, fieldOffset, value); + } + public static Method[] getMethods(@NotNull Class type) { Method[] result = type.getDeclaredMethods(); Class parentClass = type.getSuperclass(); diff --git a/platforms/bukkit/nms/v1_21/src/main/java/com/dfsek/terra/bukkit/nms/v1_21/NMSInjectListener.java b/platforms/bukkit/nms/v1_21/src/main/java/com/dfsek/terra/bukkit/nms/v1_21/NMSInjectListener.java index 98510ff88..b471faa88 100644 --- a/platforms/bukkit/nms/v1_21/src/main/java/com/dfsek/terra/bukkit/nms/v1_21/NMSInjectListener.java +++ b/platforms/bukkit/nms/v1_21/src/main/java/com/dfsek/terra/bukkit/nms/v1_21/NMSInjectListener.java @@ -1,9 +1,12 @@ package com.dfsek.terra.bukkit.nms.v1_21; +import com.dfsek.terra.api.util.reflection.ReflectionUtil; + import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.status.WorldGenContext; +import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.event.EventHandler; @@ -12,7 +15,6 @@ import org.bukkit.event.world.WorldInitEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.reflect.Field; import java.util.HashSet; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; @@ -41,21 +43,17 @@ public class NMSInjectListener implements Listener { ChunkGenerator vanilla = serverWorld.getChunkSource().getGenerator(); NMSBiomeProvider provider = new NMSBiomeProvider(pack.getBiomeProvider(), craftWorld.getSeed()); ChunkMap chunkMap = serverWorld.getChunkSource().chunkMap; + WorldGenContext worldGenContext = chunkMap.worldGenContext; try { - Field worldGenContextField = chunkMap.getClass().getDeclaredField("worldGenContext"); - worldGenContextField.setAccessible(true); - - WorldGenContext worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap); - worldGenContextField.set(chunkMap, - new WorldGenContext( - worldGenContext.level(), - new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed()), - worldGenContext.structureManager(), - worldGenContext.lightEngine(), - worldGenContext.mainThreadMailBox() - )); - } catch(NoSuchFieldException | IllegalAccessException e) { + ReflectionUtil.setFinalField(chunkMap, "worldGenContext", new WorldGenContext( + worldGenContext.level(), + new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed()), + worldGenContext.structureManager(), + worldGenContext.lightEngine(), + worldGenContext.mainThreadMailBox() + )); + } catch(NoSuchFieldException e) { throw new RuntimeException(e); }