diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java index 90f4efeeb..098092f9f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoorBlockBehavior.java @@ -184,6 +184,11 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior { immutableBlockState.ifPresent(state -> FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], LocationUtils.above(pos), state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags())); } + @Override + public boolean hasMultiState(ImmutableBlockState baseState) { + return baseState.get(this.halfProperty) == DoubleBlockHalf.LOWER; + } + @Override public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { World world = context.getLevel(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java index e27a43b73..a384ceb20 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java @@ -117,6 +117,11 @@ public class DoubleHighBlockBehavior extends AbstractCanSurviveBlockBehavior { immutableBlockState.ifPresent(state -> FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], LocationUtils.above(pos), state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags())); } + @Override + public boolean hasMultiState(ImmutableBlockState baseState) { + return baseState.get(this.halfProperty) == DoubleBlockHalf.LOWER; + } + @Override public boolean canPlaceMultiState(BlockAccessor accessor, BlockPos pos, ImmutableBlockState state) { if (pos.y() >= accessor.worldHeight().getMaxBuildHeight() - 1) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java index 9be6f101b..c487b4ab1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java @@ -121,7 +121,6 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior return previous; } - @Override public Object getContainer(Object thisBlock, Object[] args) throws Exception { for (AbstractBlockBehavior behavior : this.behaviors) { @@ -411,4 +410,14 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior } return true; } + + @Override + public boolean hasMultiState(ImmutableBlockState baseState) { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (behavior.hasMultiState(baseState)) { + return true; + } + } + return false; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index ed0f725db..aca7c652c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -129,6 +129,11 @@ public class BukkitCraftEngine extends CraftEngine { } catch (Exception e) { throw new InjectionException("Error injecting loot entries", e); } + try { + FeatureInjector.init(); + } catch (Exception e) { + throw new InjectionException("Error injecting features", e); + } try { BlockStateProviderInjector.init(); } catch (Exception e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateProviderInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateProviderInjector.java index a910fb889..aace908c9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateProviderInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateProviderInjector.java @@ -10,6 +10,8 @@ import java.util.Set; public final class BlockStateProviderInjector { + private BlockStateProviderInjector() {} + public static void init() throws ReflectiveOperationException { CoreReflections.field$MappedRegistry$frozen.set(MBuiltInRegistries.BLOCKSTATE_PROVIDER_TYPE, false); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/FeatureInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/FeatureInjector.java new file mode 100644 index 000000000..9c7ff2cb7 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/FeatureInjector.java @@ -0,0 +1,25 @@ +package net.momirealms.craftengine.bukkit.plugin.injector; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Set; + +public final class FeatureInjector { + + private FeatureInjector() {} + + public static void init() throws ReflectiveOperationException { + Object registry = MBuiltInRegistries.FEATURE; + CoreReflections.field$MappedRegistry$frozen.set(registry, false); + Object resourceLocation = KeyUtils.toResourceLocation(Key.of("craftengine:simple_block")); + Object type = FastNMS.INSTANCE.getCraftEngineCustomSimpleBlockFeature(); + Object holder = CoreReflections.method$Registry$registerForHolder.invoke(null, registry, resourceLocation, type); + CoreReflections.method$Holder$Reference$bindValue.invoke(holder, type); + CoreReflections.field$Holder$Reference$tags.set(holder, Set.of()); + CoreReflections.field$MappedRegistry$frozen.set(registry, true); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/ProtectedFieldVisitor.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/ProtectedFieldVisitor.java index 2aa8e66c3..e53215bed 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/ProtectedFieldVisitor.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/ProtectedFieldVisitor.java @@ -18,6 +18,8 @@ import java.lang.reflect.Modifier; public final class ProtectedFieldVisitor { private static FieldAccessor internalFieldAccessor; + private ProtectedFieldVisitor() {} + public static void init() throws ReflectiveOperationException { ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); // InternalFieldAccessor Interface diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java index 179b62e47..056cac825 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/RecipeInjector.java @@ -40,6 +40,8 @@ public final class RecipeInjector { private static Class clazz$InjectedRepairItemRecipe; private static Class clazz$InjectedFireworkStarFadeRecipe; + private RecipeInjector() {} + public static void init() { ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java index fd65f8003..0d90bceef 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java @@ -43,6 +43,8 @@ public final class WorldStorageInjector { private static Class clazz$InjectedPalettedContainer; private static MethodHandle constructor$InjectedLevelChunkSection; + private WorldStorageInjector() {} + public static void init() throws ReflectiveOperationException { ByteBuddy byteBuddy = new ByteBuddy(ClassFileVersion.JAVA_V17); // Paletted Container diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index bcefb896d..4bef1277b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -639,7 +639,6 @@ public final class CoreReflections { ), VersionHelper.isOrAbove1_21_5()); - public static final Method method$Registry$getId = requireNonNull( ReflectionUtils.getMethod(clazz$Registry, int.class, Object.class) ); @@ -4566,4 +4565,11 @@ public final class CoreReflections { "world.level.levelgen.feature.stateproviders.BlockStateProviderType" ) ); + + public static final Class clazz$Feature = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.level.levelgen.feature.WorldGenerator", + "world.level.levelgen.feature.Feature" + ) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java index 41b238800..a5f47d97f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java @@ -27,6 +27,7 @@ public final class MBuiltInRegistries { public static final Object LOOT_POOL_ENTRY_TYPE; public static final Object GAME_EVENT; public static final Object BLOCKSTATE_PROVIDER_TYPE; + public static final Object FEATURE; static { Field[] fields = CoreReflections.clazz$BuiltInRegistries.getDeclaredFields(); @@ -46,6 +47,7 @@ public final class MBuiltInRegistries { Object registries$LootPoolEntryType = null; Object registries$GameEvent = null; Object registries$BlockStateProviderType = null; + Object registries$Feature = null; for (Field field : fields) { Type fieldType = field.getGenericType(); @@ -63,6 +65,8 @@ public final class MBuiltInRegistries { registries$BlockEntityType = field.get(null); } else if (rawType == CoreReflections.clazz$BlockStateProviderType) { registries$BlockStateProviderType = field.get(null); + } else if (rawType == CoreReflections.clazz$Feature) { + registries$Feature = field.get(null); } else if (VersionHelper.isOrAbove1_20_5() && rawType == CoreReflections.clazz$DataComponentType && registries$DataComponentType == null) { registries$DataComponentType = field.get(null); } else if (VersionHelper.isOrAbove1_21_5() && rawType == CoreReflections.clazz$DataComponentPredicate$Type) { @@ -103,6 +107,7 @@ public final class MBuiltInRegistries { DATA_COMPONENT_TYPE = registries$DataComponentType; GAME_EVENT = requireNonNull(registries$GameEvent); BLOCKSTATE_PROVIDER_TYPE = requireNonNull(registries$BlockStateProviderType); + FEATURE = requireNonNull(registries$Feature); DATA_COMPONENT_PREDICATE_TYPE = registries$DataComponentPredicateType; } catch (ReflectiveOperationException e) { throw new ReflectionInitException("Failed to init BuiltInRegistries", e); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java index 230782fde..310131a79 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java @@ -189,15 +189,18 @@ public abstract class BlockBehavior { public void onProjectileHit(Object thisBlock, Object[] args, Callable superMethod) throws Exception { } - // Level level, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack + // Level/WorldGenLevel level, BlockPos pos, BlockState state, LivingEntity placer, ItemStack itemStack public void placeMultiState(Object thisBlock, Object[] args, Callable superMethod) throws Exception { } - // Level level, BlockPos pos, BlockState state public boolean canPlaceMultiState(BlockAccessor accessor, BlockPos pos, ImmutableBlockState state) { return true; } + public boolean hasMultiState(ImmutableBlockState baseState) { + return false; + } + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { return state; } diff --git a/gradle.properties b/gradle.properties index 05903929a..3d0dc883d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -48,7 +48,7 @@ byte_buddy_version=1.17.8 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=1.0.4 -nms_helper_version=1.0.132 +nms_helper_version=1.0.134 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5