diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index 46cb7fc86..cf8ef367f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -240,6 +240,6 @@ public final class CraftEngineBlocks { */ @NotNull public static BlockData createBukkitBlockData(@NotNull ImmutableBlockState blockState) { - return BlockStateUtils.createBlockData(blockState.customBlockState().handle()); + return BlockStateUtils.fromBlockData(blockState.customBlockState().handle()); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index e83945789..312486736 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.api.event.CustomBlockAttemptPlaceEvent; import net.momirealms.craftengine.bukkit.api.event.CustomBlockPlaceEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.EventUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; @@ -158,8 +159,8 @@ public class BlockItemBehavior extends ItemBehavior { Object world = Reflections.field$CraftWorld$ServerLevel.get(context.getLevel().platformWorld()); boolean defaultReturn = ((!this.checkStatePlacement() || (boolean) Reflections.method$BlockStateBase$canSurvive.invoke(blockState, world, blockPos)) && (boolean) Reflections.method$ServerLevel$checkEntityCollision.invoke(world, blockState, player, voxelShape, blockPos, true)); - Block block = (Block) Reflections.method$CraftBlock$at.invoke(null, world, blockPos); - BlockData blockData = (BlockData) Reflections.method$CraftBlockData$fromData.invoke(null, blockState); + Block block = FastNMS.INSTANCE.method$CraftBlock$at(world, blockPos); + BlockData blockData = FastNMS.INSTANCE.method$CraftBlockData$fromData(blockState); BlockCanBuildEvent canBuildEvent = new BlockCanBuildEvent(block, (org.bukkit.entity.Player) context.getPlayer().platformPlayer(), blockData, defaultReturn, context.getHand() == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND); Bukkit.getPluginManager().callEvent(canBuildEvent); return canBuildEvent.isBuildable(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java index 4dea40da0..3f24226df 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java @@ -61,10 +61,6 @@ public class BukkitInjector { private static final BukkitBlockShape STONE_SHAPE = new BukkitBlockShape(Reflections.instance$Blocks$STONE$defaultState); private static Class clazz$InjectedPalettedContainer; - private static Field field$InjectedPalettedContainer$target; - private static Field field$InjectedPalettedContainer$section; - private static Field field$InjectedPalettedContainer$world; - private static Field field$InjectedPalettedContainer$pos; private static Class clazz$OptimizedItemDisplay; private static Constructor constructor$OptimizedItemDisplay; @@ -79,44 +75,18 @@ public class BukkitInjector { private static Field field$CraftEngineBlock$isNoteBlock; private static Class clazz$InjectedCacheChecker; - private static Field field$InjectedCacheChecker$recipeType; - private static Field field$InjectedCacheChecker$lastRecipe; - private static Field field$InjectedCacheChecker$lastCustomRecipe; public static void init() { try { - clazz$InjectedCacheChecker = byteBuddy - .subclass(Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING) - .implement(Reflections.clazz$RecipeManager$CachedCheck) - .defineField("recipeType", Reflections.clazz$RecipeType, Visibility.PUBLIC) - .defineField("lastRecipe", Object.class, Visibility.PUBLIC) - .defineField("lastCustomRecipe", Key.class, Visibility.PUBLIC) - .method(ElementMatchers.named("getRecipeFor").or(ElementMatchers.named("a"))) - .intercept(MethodDelegation.to( - VersionHelper.isVersionNewerThan1_21_2() ? - GetRecipeForMethodInterceptor1_21_2.INSTANCE : - (VersionHelper.isVersionNewerThan1_21() ? - GetRecipeForMethodInterceptor1_21.INSTANCE : - VersionHelper.isVersionNewerThan1_20_5() ? - GetRecipeForMethodInterceptor1_20_5.INSTANCE : - GetRecipeForMethodInterceptor1_20.INSTANCE) - )) - .make() - .load(BukkitInjector.class.getClassLoader()) - .getLoaded(); - field$InjectedCacheChecker$recipeType = clazz$InjectedCacheChecker.getDeclaredField("recipeType"); - field$InjectedCacheChecker$lastRecipe = clazz$InjectedCacheChecker.getDeclaredField("lastRecipe"); - field$InjectedCacheChecker$lastCustomRecipe = clazz$InjectedCacheChecker.getDeclaredField("lastCustomRecipe"); - // Paletted Container clazz$InjectedPalettedContainer = byteBuddy .subclass(Reflections.clazz$PalettedContainer) .name("net.minecraft.world.level.chunk.InjectedPalettedContainer") .implement(InjectedPalettedContainerHolder.class) - .defineField("target", Reflections.clazz$PalettedContainer, Visibility.PRIVATE) - .defineField("cesection", CESection.class, Visibility.PRIVATE) - .defineField("ceworld", CEWorld.class, Visibility.PRIVATE) - .defineField("cepos", SectionPos.class, Visibility.PRIVATE) + .defineField("target", Object.class, Visibility.PUBLIC) + .defineField("cesection", CESection.class, Visibility.PUBLIC) + .defineField("ceworld", CEWorld.class, Visibility.PUBLIC) + .defineField("cepos", SectionPos.class, Visibility.PUBLIC) .method(ElementMatchers.any() .and(ElementMatchers.not(ElementMatchers.is(Reflections.method$PalettedContainer$getAndSet))) .and(ElementMatchers.not(ElementMatchers.isDeclaredBy(Object.class))) @@ -135,10 +105,6 @@ public class BukkitInjector { .make() .load(BukkitInjector.class.getClassLoader()) .getLoaded(); - field$InjectedPalettedContainer$target = ReflectionUtils.getDeclaredField(clazz$InjectedPalettedContainer, "target"); - field$InjectedPalettedContainer$section = ReflectionUtils.getDeclaredField(clazz$InjectedPalettedContainer, "cesection"); - field$InjectedPalettedContainer$world = ReflectionUtils.getDeclaredField(clazz$InjectedPalettedContainer, "ceworld"); - field$InjectedPalettedContainer$pos = ReflectionUtils.getDeclaredField(clazz$InjectedPalettedContainer, "cepos"); // State Predicate DynamicType.Unloaded alwaysTrue = byteBuddy .subclass(Reflections.clazz$StatePredicate) @@ -275,6 +241,36 @@ public class BukkitInjector { field$CraftEngineBlock$behavior = clazz$CraftEngineBlock.getField("behaviorHolder"); field$CraftEngineBlock$shape = clazz$CraftEngineBlock.getField("shapeHolder"); field$CraftEngineBlock$isNoteBlock = clazz$CraftEngineBlock.getField("isClientSideNoteBlock"); + + clazz$InjectedCacheChecker = byteBuddy + .subclass(Object.class, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING) + .name("net.momirealms.craftengine.bukkit.entity.InjectedCacheChecker") + .implement(Reflections.clazz$RecipeManager$CachedCheck) + .implement(InjectedCacheCheck.class) + .defineField("recipeType", Object.class, Visibility.PUBLIC) + .method(ElementMatchers.named("recipeType")) + .intercept(FieldAccessor.ofField("recipeType")) + .defineField("lastRecipe", Object.class, Visibility.PUBLIC) + .method(ElementMatchers.named("lastRecipe")) + .intercept(FieldAccessor.ofField("lastRecipe")) + .method(ElementMatchers.named("setLastRecipe")) + .intercept(FieldAccessor.ofField("lastRecipe")) + .defineField("lastCustomRecipe", Key.class, Visibility.PUBLIC) + .method(ElementMatchers.named("lastCustomRecipe")) + .intercept(FieldAccessor.ofField("lastCustomRecipe")) + .method(ElementMatchers.named("getRecipeFor").or(ElementMatchers.named("a"))) + .intercept(MethodDelegation.to( + VersionHelper.isVersionNewerThan1_21_2() ? + GetRecipeForMethodInterceptor1_21_2.INSTANCE : + (VersionHelper.isVersionNewerThan1_21() ? + GetRecipeForMethodInterceptor1_21.INSTANCE : + VersionHelper.isVersionNewerThan1_20_5() ? + GetRecipeForMethodInterceptor1_20_5.INSTANCE : + GetRecipeForMethodInterceptor1_20.INSTANCE) + )) + .make() + .load(BukkitInjector.class.getClassLoader()) + .getLoaded(); } catch (Throwable e) { CraftEngine.instance().logger().severe("Failed to init injector", e); } @@ -284,15 +280,15 @@ public class BukkitInjector { if (Reflections.clazz$AbstractFurnaceBlockEntity.isInstance(entity)) { Object quickCheck = Reflections.field$AbstractFurnaceBlockEntity$quickCheck.get(entity); if (clazz$InjectedCacheChecker.isInstance(quickCheck)) return; // already injected - Object recipeType = Reflections.field$AbstractFurnaceBlockEntity$recipeType.get(entity); - Object injectedChecker = Reflections.UNSAFE.allocateInstance(clazz$InjectedCacheChecker); - field$InjectedCacheChecker$recipeType.set(injectedChecker, recipeType); + Object recipeType = FastNMS.INSTANCE.field$AbstractFurnaceBlockEntity$recipeType(entity); + InjectedCacheCheck injectedChecker = (InjectedCacheCheck) Reflections.UNSAFE.allocateInstance(clazz$InjectedCacheChecker); + injectedChecker.recipeType(recipeType); Reflections.field$AbstractFurnaceBlockEntity$quickCheck.set(entity, injectedChecker); } else if (!VersionHelper.isVersionNewerThan1_21_2() && Reflections.clazz$CampfireBlockEntity.isInstance(entity)) { Object quickCheck = Reflections.field$CampfireBlockEntity$quickCheck.get(entity); if (clazz$InjectedCacheChecker.isInstance(quickCheck)) return; // already injected - Object injectedChecker = Reflections.UNSAFE.allocateInstance(clazz$InjectedCacheChecker); - field$InjectedCacheChecker$recipeType.set(injectedChecker, Reflections.instance$RecipeType$CAMPFIRE_COOKING); + InjectedCacheCheck injectedChecker = (InjectedCacheCheck) Reflections.UNSAFE.allocateInstance(clazz$InjectedCacheChecker); + injectedChecker.recipeType(Reflections.instance$RecipeType$CAMPFIRE_COOKING); Reflections.field$CampfireBlockEntity$quickCheck.set(entity, injectedChecker); } } @@ -312,13 +308,13 @@ public class BukkitInjector { public static void injectLevelChunkSection(Object targetSection, CESection ceSection, CEWorld ceWorld, SectionPos pos) { try { - Object container = Reflections.field$LevelChunkSection$states.get(targetSection); + Object container = FastNMS.INSTANCE.field$LevelChunkSection$states(targetSection); if (!clazz$InjectedPalettedContainer.isInstance(container)) { - Object injectedObject = Reflections.UNSAFE.allocateInstance(clazz$InjectedPalettedContainer); - field$InjectedPalettedContainer$target.set(injectedObject, container); - field$InjectedPalettedContainer$section.set(injectedObject, ceSection); - field$InjectedPalettedContainer$world.set(injectedObject, ceWorld); - field$InjectedPalettedContainer$pos.set(injectedObject, pos); + InjectedPalettedContainerHolder injectedObject = (InjectedPalettedContainerHolder) Reflections.UNSAFE.allocateInstance(clazz$InjectedPalettedContainer); + injectedObject.target(container); + injectedObject.ceSection(ceSection); + injectedObject.ceWorld(ceWorld); + injectedObject.cePos(pos); Reflections.field$PalettedContainer$data.set(injectedObject, Reflections.field$PalettedContainer$data.get(container)); Reflections.field$LevelChunkSection$states.set(targetSection, injectedObject); } @@ -329,9 +325,9 @@ public class BukkitInjector { public static void uninjectLevelChunkSection(Object section) { try { - Object states = Reflections.field$LevelChunkSection$states.get(section); - if (clazz$InjectedPalettedContainer.isInstance(states)) { - Reflections.field$LevelChunkSection$states.set(section, field$InjectedPalettedContainer$target.get(states)); + Object states = FastNMS.INSTANCE.field$LevelChunkSection$states(section); + if (states instanceof InjectedPalettedContainerHolder holder) { + Reflections.field$LevelChunkSection$states.set(section, holder.target()); } } catch (Exception e) { CraftEngine.instance().logger().severe("Failed to inject chunk section", e); @@ -345,8 +341,9 @@ public class BukkitInjector { @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); - Object type = field$InjectedCacheChecker$recipeType.get(thisObj); - Object lastRecipe = field$InjectedCacheChecker$lastRecipe.get(thisObj); + InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; + Object type = injectedCacheCheck.recipeType(); + Object lastRecipe = injectedCacheCheck.lastRecipe(); Optional> optionalRecipe = (Optional>) Reflections.method$RecipeManager$getRecipeFor0.invoke(mcRecipeManager, type, args[0], args[1], lastRecipe); if (optionalRecipe.isPresent()) { Pair pair = optionalRecipe.get(); @@ -361,12 +358,12 @@ public class BukkitInjector { } else { items = (List) Reflections.field$AbstractFurnaceBlockEntity$items.get(args[0]); } - itemStack = (ItemStack) Reflections.method$CraftItemStack$asCraftMirror.invoke(null, items.get(0)); + itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(items.get(0)); // it's a recipe from other plugins boolean isCustom = recipeManager.isCustomRecipe(recipeId); if (!isCustom) { - field$InjectedCacheChecker$lastRecipe.set(thisObj, resourceLocation); + injectedCacheCheck.lastRecipe(resourceLocation); return Optional.of(pair.getSecond()); } @@ -378,7 +375,7 @@ public class BukkitInjector { SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); CustomCookingRecipe ceRecipe; - Key lastCustomRecipe = (Key) field$InjectedCacheChecker$lastCustomRecipe.get(thisObj); + Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { @@ -395,9 +392,9 @@ public class BukkitInjector { } // Cache recipes, it might be incorrect on reloading - field$InjectedCacheChecker$lastCustomRecipe.set(thisObj, ceRecipe.id()); + injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all - field$InjectedCacheChecker$lastRecipe.set(thisObj, resourceLocation); + injectedCacheCheck.lastRecipe(resourceLocation); return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(pair.getSecond())); } else { return Optional.empty(); @@ -412,12 +409,13 @@ public class BukkitInjector { @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); - Object type = field$InjectedCacheChecker$recipeType.get(thisObj); - Object lastRecipe = field$InjectedCacheChecker$lastRecipe.get(thisObj); + InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; + Object type = injectedCacheCheck.recipeType(); + Object lastRecipe = injectedCacheCheck.lastRecipe(); Optional optionalRecipe = (Optional) Reflections.method$RecipeManager$getRecipeFor0.invoke(mcRecipeManager, type, args[0], args[1], lastRecipe); if (optionalRecipe.isPresent()) { Object holder = optionalRecipe.get(); - Object id = Reflections.field$RecipeHolder$id.get(holder); + Object id = FastNMS.INSTANCE.field$RecipeHolder$id(holder); Key recipeId = Key.of(id.toString()); BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); @@ -428,12 +426,12 @@ public class BukkitInjector { } else { items = (List) Reflections.field$AbstractFurnaceBlockEntity$items.get(args[0]); } - itemStack = (ItemStack) Reflections.method$CraftItemStack$asCraftMirror.invoke(null, items.get(0)); + itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(items.get(0)); // it's a recipe from other plugins boolean isCustom = recipeManager.isCustomRecipe(recipeId); if (!isCustom) { - field$InjectedCacheChecker$lastRecipe.set(thisObj, id); + injectedCacheCheck.lastRecipe(id); return optionalRecipe; } @@ -445,7 +443,7 @@ public class BukkitInjector { SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); CustomCookingRecipe ceRecipe; - Key lastCustomRecipe = (Key) field$InjectedCacheChecker$lastCustomRecipe.get(thisObj); + Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { @@ -462,9 +460,9 @@ public class BukkitInjector { } // Cache recipes, it might be incorrect on reloading - field$InjectedCacheChecker$lastCustomRecipe.set(thisObj, ceRecipe.id()); + injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all - field$InjectedCacheChecker$lastRecipe.set(thisObj, id); + injectedCacheCheck.lastRecipe(id); return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(holder)); } else { return Optional.empty(); @@ -479,20 +477,21 @@ public class BukkitInjector { @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); - Object type = field$InjectedCacheChecker$recipeType.get(thisObj); - Object lastRecipe = field$InjectedCacheChecker$lastRecipe.get(thisObj); + InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; + Object type = injectedCacheCheck.recipeType(); + Object lastRecipe = injectedCacheCheck.lastRecipe(); Optional optionalRecipe = (Optional) Reflections.method$RecipeManager$getRecipeFor0.invoke(mcRecipeManager, type, args[0], args[1], lastRecipe); if (optionalRecipe.isPresent()) { Object holder = optionalRecipe.get(); - Object id = Reflections.field$RecipeHolder$id.get(holder); + Object id = FastNMS.INSTANCE.field$RecipeHolder$id(holder); Key recipeId = Key.of(id.toString()); BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); - ItemStack itemStack = (ItemStack) Reflections.method$CraftItemStack$asCraftMirror.invoke(null, Reflections.field$SingleRecipeInput$item.get(args[0])); + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(Reflections.field$SingleRecipeInput$item.get(args[0])); // it's a recipe from other plugins boolean isCustom = recipeManager.isCustomRecipe(recipeId); if (!isCustom) { - field$InjectedCacheChecker$lastRecipe.set(thisObj, id); + injectedCacheCheck.lastRecipe(id); return optionalRecipe; } @@ -504,7 +503,7 @@ public class BukkitInjector { SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); CustomCookingRecipe ceRecipe; - Key lastCustomRecipe = (Key) field$InjectedCacheChecker$lastCustomRecipe.get(thisObj); + Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { @@ -521,9 +520,9 @@ public class BukkitInjector { } // Cache recipes, it might be incorrect on reloading - field$InjectedCacheChecker$lastCustomRecipe.set(thisObj, ceRecipe.id()); + injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all - field$InjectedCacheChecker$lastRecipe.set(thisObj, id); + injectedCacheCheck.lastRecipe(id); return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(holder)); } else { return Optional.empty(); @@ -538,21 +537,22 @@ public class BukkitInjector { @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); - Object type = field$InjectedCacheChecker$recipeType.get(thisObj); - Object lastRecipe = field$InjectedCacheChecker$lastRecipe.get(thisObj); + InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; + Object type = injectedCacheCheck.recipeType(); + Object lastRecipe = injectedCacheCheck.lastRecipe(); Optional optionalRecipe = (Optional) Reflections.method$RecipeManager$getRecipeFor1.invoke(mcRecipeManager, type, args[0], args[1], lastRecipe); if (optionalRecipe.isPresent()) { Object holder = optionalRecipe.get(); - Object id = Reflections.field$RecipeHolder$id.get(holder); - Object resourceLocation = Reflections.field$ResourceKey$location.get(id); + Object id = FastNMS.INSTANCE.field$RecipeHolder$id(holder); + Object resourceLocation = FastNMS.INSTANCE.field$ResourceKey$location(id); Key recipeId = Key.of(resourceLocation.toString()); BukkitRecipeManager recipeManager = BukkitRecipeManager.instance(); - ItemStack itemStack = (ItemStack) Reflections.method$CraftItemStack$asCraftMirror.invoke(null, Reflections.field$SingleRecipeInput$item.get(args[0])); + ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(Reflections.field$SingleRecipeInput$item.get(args[0])); // it's a recipe from other plugins boolean isCustom = recipeManager.isCustomRecipe(recipeId); if (!isCustom) { - field$InjectedCacheChecker$lastRecipe.set(thisObj, id); + injectedCacheCheck.lastRecipe(id); return optionalRecipe; } @@ -564,7 +564,7 @@ public class BukkitInjector { SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); CustomCookingRecipe ceRecipe; - Key lastCustomRecipe = (Key) field$InjectedCacheChecker$lastCustomRecipe.get(thisObj); + Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { @@ -579,9 +579,9 @@ public class BukkitInjector { } // Cache recipes, it might be incorrect on reloading - field$InjectedCacheChecker$lastCustomRecipe.set(thisObj, ceRecipe.id()); + injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all - field$InjectedCacheChecker$lastRecipe.set(thisObj, id); + injectedCacheCheck.lastRecipe(id); return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(holder)); } else { return Optional.empty(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java new file mode 100644 index 000000000..728547596 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/InjectedCacheCheck.java @@ -0,0 +1,18 @@ +package net.momirealms.craftengine.bukkit.plugin.injector; + +import net.momirealms.craftengine.core.util.Key; + +public interface InjectedCacheCheck { + + Object recipeType(); + + void recipeType(Object recipeType); + + Object lastRecipe(); + + void lastRecipe(Object lastRecipe); + + Key lastCustomRecipe(); + + void lastCustomRecipe(Key lastCustomRecipe); +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java index 468feaf9f..332f66dbf 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.PushReaction; import net.momirealms.craftengine.core.util.Instrument; @@ -46,29 +47,12 @@ public class BlockStateUtils { } } - public static BlockData createBlockData(Object blockState) { - try { - return (BlockData) Reflections.method$CraftBlockData$createData.invoke(null, blockState); - } catch (InvocationTargetException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - public static BlockData fromBlockData(Object blockState) { - try { - return (BlockData) Reflections.method$CraftBlockData$fromData.invoke(null, blockState); - } catch (InvocationTargetException | IllegalAccessException e) { - throw new RuntimeException(e); - } + return (BlockData) FastNMS.INSTANCE.method$CraftBlockData$fromData(blockState); } public static int blockDataToId(BlockData blockData) { - try { - Object blockState = Reflections.field$CraftBlockData$data.get(blockData); - return (int) Reflections.method$IdMapper$getId.invoke(Reflections.instance$BLOCK_STATE_REGISTRY, blockState); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } + return blockStateToId(blockDataToBlockState(blockData)); } public static Key getBlockOwnerId(Block block) { @@ -90,27 +74,15 @@ public class BlockStateUtils { } public static Object blockDataToBlockState(BlockData blockData) { - try { - return Reflections.field$CraftBlockData$data.get(blockData); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } + return FastNMS.INSTANCE.method$CraftBlockData$getState(blockData); } public static Object idToBlockState(int id) { - try { - return Reflections.method$IdMapper$byId.invoke(Reflections.instance$BLOCK_STATE_REGISTRY, id); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } + return FastNMS.INSTANCE.method$IdMapper$byId(Reflections.instance$BLOCK_STATE_REGISTRY, id); } public static int blockStateToId(Object blockState) { - try { - return (int) Reflections.method$IdMapper$getId.invoke(Reflections.instance$BLOCK_STATE_REGISTRY, blockState); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } + return FastNMS.INSTANCE.method$IdMapper$getId(Reflections.instance$BLOCK_STATE_REGISTRY, blockState); } public static Object getBlockOwner(Object blockState) { @@ -136,8 +108,8 @@ public class BlockStateUtils { Reflections.field$BlockStateBase$lightEmission.set(state, emission); } - public static int getLightEmission(Object state) throws ReflectiveOperationException { - return (int) Reflections.field$BlockStateBase$lightEmission.get(state); + public static int getLightEmission(Object state) { + return FastNMS.INSTANCE.method$BlockStateBase$getLightEmission(state); } public static void setMapColor(Object state, MapColor color) throws ReflectiveOperationException { @@ -180,7 +152,7 @@ public class BlockStateUtils { } public static boolean isOcclude(Object state) throws ReflectiveOperationException { - return (boolean) Reflections.field$BlockStateBase$canOcclude.get(state); + return FastNMS.INSTANCE.method$BlockStateBase$canOcclude(state); } public static void setIsRedstoneConductor(Object state, Object predicate) throws ReflectiveOperationException { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 707181184..aa0a81585 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -1543,11 +1543,11 @@ public class Reflections { ) ); - public static final Method method$CraftBlock$at = requireNonNull( - ReflectionUtils.getStaticMethod( - clazz$CraftBlock, clazz$CraftBlock, clazz$LevelAccessor, clazz$BlockPos - ) - ); +// public static final Method method$CraftBlock$at = requireNonNull( +// ReflectionUtils.getStaticMethod( +// clazz$CraftBlock, clazz$CraftBlock, clazz$LevelAccessor, clazz$BlockPos +// ) +// ); public static final Method method$CraftBlockStates$getBlockState = requireNonNull( ReflectionUtils.getStaticMethod( @@ -1573,12 +1573,14 @@ public class Reflections { ) ); + @Deprecated public static final Method method$CraftBlockData$createData = requireNonNull( ReflectionUtils.getStaticMethod( clazz$CraftBlockData, clazz$CraftBlockData, new String[]{"createData"}, clazz$BlockState ) ); + @Deprecated public static final Method method$CraftBlockData$fromData = requireNonNull( ReflectionUtils.getStaticMethod( clazz$CraftBlockData, clazz$CraftBlockData, new String[]{"fromData"}, clazz$BlockState @@ -1801,11 +1803,11 @@ public class Reflections { ) ); - public static final Method method$ServerChunkCache$getChunkAtIfLoadedMainThread = requireNonNull( - ReflectionUtils.getMethod( - clazz$ServerChunkCache, clazz$LevelChunk, int.class, int.class - ) - ); +// public static final Method method$ServerChunkCache$getChunkAtIfLoadedMainThread = requireNonNull( +// ReflectionUtils.getMethod( +// clazz$ServerChunkCache, clazz$LevelChunk, int.class, int.class +// ) +// ); public static final Field field$ChunkAccess$sections = requireNonNull( ReflectionUtils.getDeclaredField( @@ -1834,33 +1836,35 @@ public class Reflections { ) ); - public static final Field field$ChunkAccess$blockEntities; - - static { - Field targetField = null; - for (Field field : clazz$ChunkAccess.getDeclaredFields()) { - if (Map.class.isAssignableFrom(field.getType())) { - Type genericType = field.getGenericType(); - if (genericType instanceof ParameterizedType parameterizedType) { - Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); - if (actualTypeArguments.length == 2 && - actualTypeArguments[0].equals(clazz$BlockPos) && - actualTypeArguments[1].equals(clazz$BlockEntity)) { - field.setAccessible(true); - targetField = field; - } - } - } - } - field$ChunkAccess$blockEntities = targetField; - } +// public static final Field field$ChunkAccess$blockEntities; +// +// static { +// Field targetField = null; +// for (Field field : clazz$ChunkAccess.getDeclaredFields()) { +// if (Map.class.isAssignableFrom(field.getType())) { +// Type genericType = field.getGenericType(); +// if (genericType instanceof ParameterizedType parameterizedType) { +// Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); +// if (actualTypeArguments.length == 2 && +// actualTypeArguments[0].equals(clazz$BlockPos) && +// actualTypeArguments[1].equals(clazz$BlockEntity)) { +// field.setAccessible(true); +// targetField = field; +// } +// } +// } +// } +// field$ChunkAccess$blockEntities = targetField; +// } + @Deprecated public static final Method method$LevelChunkSection$setBlockState = requireNonNull( ReflectionUtils.getMethod( clazz$LevelChunkSection, clazz$BlockState, int.class, int.class, int.class, clazz$BlockState, boolean.class ) ); + @Deprecated public static final Method method$LevelChunkSection$getBlockState = requireNonNull( ReflectionUtils.getMethod( clazz$LevelChunkSection, clazz$BlockState, int.class, int.class, int.class @@ -4643,11 +4647,11 @@ public class Reflections { ) ); - public static final Field field$AbstractFurnaceBlockEntity$recipeType = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$AbstractFurnaceBlockEntity, clazz$RecipeType, 0 - ) - ); +// public static final Field field$AbstractFurnaceBlockEntity$recipeType = requireNonNull( +// ReflectionUtils.getDeclaredField( +// clazz$AbstractFurnaceBlockEntity, clazz$RecipeType, 0 +// ) +// ); public static final Field field$AbstractFurnaceBlockEntity$quickCheck = requireNonNull( ReflectionUtils.getDeclaredField( diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index 8b6a9a69c..eb4f7653f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.world; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; @@ -203,30 +204,26 @@ public class BukkitWorldManager implements WorldManager, Listener { return; } finally { if (ConfigManager.restoreVanillaBlocks()) { - try { - CESection[] ceSections = ceChunk.sections(); - Object worldServer = Reflections.field$CraftChunk$worldServer.get(chunk); - Object chunkSource = Reflections.field$ServerLevel$chunkSource.get(worldServer); - Object levelChunk = Reflections.method$ServerChunkCache$getChunkAtIfLoadedMainThread.invoke(chunkSource, chunk.getX(), chunk.getZ()); - Object[] sections = (Object[]) Reflections.field$ChunkAccess$sections.get(levelChunk); - for (int i = 0; i < ceSections.length; i++) { - CESection ceSection = ceSections[i]; - Object section = sections[i]; - BukkitInjector.uninjectLevelChunkSection(section); - if (ceSection.statesContainer().isEmpty()) continue; - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - for (int y = 0; y < 16; y++) { - ImmutableBlockState customState = ceSection.getBlockState(x, y, z); - if (!customState.isEmpty() && customState.vanillaBlockState() != null) { - Reflections.method$LevelChunkSection$setBlockState.invoke(section, x, y, z, customState.vanillaBlockState().handle(), false); - } + CESection[] ceSections = ceChunk.sections(); + Object worldServer = FastNMS.INSTANCE.field$CraftChunk$worldServer(chunk); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); + Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ()); + Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); + for (int i = 0; i < ceSections.length; i++) { + CESection ceSection = ceSections[i]; + Object section = sections[i]; + BukkitInjector.uninjectLevelChunkSection(section); + if (ceSection.statesContainer().isEmpty()) continue; + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + for (int y = 0; y < 16; y++) { + ImmutableBlockState customState = ceSection.getBlockState(x, y, z); + if (!customState.isEmpty() && customState.vanillaBlockState() != null) { + FastNMS.INSTANCE.method$LevelChunkSection$setBlockState(section, x, y, z, customState.vanillaBlockState().handle(), false); } } } } - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to restore chunk at " + chunk.getX() + " " + chunk.getZ(), e); } } } @@ -247,15 +244,15 @@ public class BukkitWorldManager implements WorldManager, Listener { } try { CESection[] ceSections = ceChunk.sections(); - Object worldServer = Reflections.field$CraftChunk$worldServer.get(chunk); - Object chunkSource = Reflections.field$ServerLevel$chunkSource.get(worldServer); - Object levelChunk = Reflections.method$ServerChunkCache$getChunkAtIfLoadedMainThread.invoke(chunkSource, chunk.getX(), chunk.getZ()); - Object[] sections = (Object[]) Reflections.field$ChunkAccess$sections.get(levelChunk); + Object worldServer = FastNMS.INSTANCE.field$CraftChunk$worldServer(chunk); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); + Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ()); + Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); for (int i = 0; i < ceSections.length; i++) { CESection ceSection = ceSections[i]; Object section = sections[i]; if (ConfigManager.syncCustomBlocks()) { - Object statesContainer = Reflections.field$LevelChunkSection$states.get(section); + Object statesContainer = FastNMS.INSTANCE.field$LevelChunkSection$states(section); Object data = Reflections.field$PalettedContainer$data.get(statesContainer); Object palette = Reflections.field$PalettedContainer$Data$palette.get(data); boolean requiresSync = false; @@ -292,7 +289,7 @@ public class BukkitWorldManager implements WorldManager, Listener { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { - Object mcState = Reflections.method$LevelChunkSection$getBlockState.invoke(section, x, y, z); + Object mcState = FastNMS.INSTANCE.method$LevelChunkSection$getBlockState(section, x, y, z); int stateId = BlockStateUtils.blockStateToId(mcState); ImmutableBlockState customState = this.plugin.blockManager().getImmutableBlockState(stateId); if (customState != null) { @@ -310,7 +307,7 @@ public class BukkitWorldManager implements WorldManager, Listener { for (int y = 0; y < 16; y++) { ImmutableBlockState customState = ceSection.getBlockState(x, y, z); if (!customState.isEmpty() && customState.customBlockState() != null) { - Reflections.method$LevelChunkSection$setBlockState.invoke(section, x, y, z, customState.customBlockState().handle(), false); + FastNMS.INSTANCE.method$LevelChunkSection$setBlockState(section, x, y, z, customState.customBlockState().handle(), false); } } } @@ -321,7 +318,7 @@ public class BukkitWorldManager implements WorldManager, Listener { } if (ConfigManager.enableRecipeSystem()) { @SuppressWarnings("unchecked") - Map blockEntities = (Map) Reflections.field$ChunkAccess$blockEntities.get(levelChunk); + Map blockEntities = (Map) FastNMS.INSTANCE.field$ChunkAccess$blockEntities(levelChunk); for (Object blockEntity : blockEntities.values()) { BukkitInjector.injectCookingBlockEntity(blockEntity); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/InjectedPalettedContainerHolder.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/InjectedPalettedContainerHolder.java index 9ca107310..0dc9d1db8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/InjectedPalettedContainerHolder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/InjectedPalettedContainerHolder.java @@ -7,9 +7,17 @@ public interface InjectedPalettedContainerHolder { Object target(); + void target(Object target); + CESection ceSection(); + void ceSection(CESection section); + CEWorld ceWorld(); + void ceWorld(CEWorld world); + SectionPos cePos(); + + void cePos(SectionPos pos); } diff --git a/gradle.properties b/gradle.properties index 4a6305c08..dd0543dbb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,7 +49,7 @@ mojang_brigadier_version=1.0.18 byte_buddy_version=1.15.11 snake_yaml_version=2.3 anti_grief_version=0.13 -nms_helper_version=0.1 +nms_helper_version=0.6 # Ignite Dependencies mixinextras_version=0.4.1 mixin_version=0.15.2+mixin.0.8.7