diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java new file mode 100644 index 000000000..1e30aafb9 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java @@ -0,0 +1,110 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.IntegerProperty; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.util.*; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Callable; + +public class AttachedStemBlockBehavior extends BushBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final Property facingProperty; + private final Key fruit; + private final Key stem; + + public AttachedStemBlockBehavior(CustomBlock customBlock, + int delay, + boolean blacklist, + List tagsCanSurviveOn, + Set blockStatesCanSurviveOn, + Set customBlocksCansSurviveOn, + Property facingProperty, + Key fruit, + Key stem) { + super(customBlock, delay, blacklist, false, tagsCanSurviveOn, blockStatesCanSurviveOn, customBlocksCansSurviveOn); + this.facingProperty = facingProperty; + this.fruit = fruit; + this.stem = stem; + } + + @Override + public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) { + return FastNMS.INSTANCE.field$FluidState$isEmpty(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(args[0])); + } + + @Override + public boolean isPathFindable(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + return (VersionHelper.isOrAbove1_20_5() ? args[1] : args[3]).equals(CoreReflections.instance$PathComputationType$AIR) + && !FastNMS.INSTANCE.field$BlockBehavior$hasCollision(thisBlock) || (boolean) superMethod.call(); + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object state = args[0]; + HorizontalDirection direction = DirectionUtils.fromNMSDirection(args[updateShape$direction]).toHorizontalDirection(); + Object neighborState = args[updateShape$neighborState]; + Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state); + if (optionalCustomState.isEmpty() || direction != optionalCustomState.get().get(this.facingProperty)) { + return super.updateShape(thisBlock, args, superMethod); + } + Optional optionalCustomNeighborState = BlockStateUtils.getOptionalCustomBlockState(neighborState); + if (optionalCustomNeighborState.isPresent()) { + ImmutableBlockState customNeighborState = optionalCustomNeighborState.get(); + if (!customNeighborState.owner().value().id().equals(this.fruit)) { + Object stemBlock = resetStemBlock(); + if (stemBlock != null) return stemBlock; + } + } else { + if (this.stem.namespace().equals("minecraft")) { + Key neighborBlockId = BlockStateUtils.getBlockOwnerIdFromState(neighborState); + if (!neighborBlockId.equals(this.fruit)) { + Object stemBlock = resetStemBlock(); + if (stemBlock != null) return stemBlock; + } + } else { + Object stemBlock = resetStemBlock(); + if (stemBlock != null) return stemBlock; + } + } + return super.updateShape(thisBlock, args, superMethod); + } + + private Object resetStemBlock() { + Optional optionalStemBlock = BukkitBlockManager.instance().blockById(this.stem); + if (optionalStemBlock.isPresent()) { + CustomBlock stemBlock = optionalStemBlock.get(); + IntegerProperty ageProperty = (IntegerProperty) stemBlock.getProperty("age"); + if (ageProperty == null) return stemBlock.defaultState().customBlockState().literalObject(); + return stemBlock.defaultState().with(ageProperty, ageProperty.max).customBlockState().literalObject(); + } + return null; + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Tuple, Set, Set> tuple = readTagsAndState(arguments, false); + int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); + boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist"); + @SuppressWarnings("unchecked") + Property facingProperty = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.attached_stem.missing_facing"); + Key fruit = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("fruit"), "warning.config.block.behavior.attached_stem.missing_fruit")); + Key stem = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("stem"), "warning.config.block.behavior.attached_stem.missing_stem")); + return new AttachedStemBlockBehavior(block, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), facingProperty, fruit, stem); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index fc8ba1cc6..ce5a59520 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -39,6 +39,8 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key FENCE_BLOCK = Key.from("craftengine:fence_block"); public static final Key BUTTON_BLOCK = Key.from("craftengine:button_block"); public static final Key FACE_ATTACHED_HORIZONTAL_DIRECTIONAL_BLOCK = Key.from("craftengine:face_attached_horizontal_directional_block"); + public static final Key STEM_BLOCK = Key.from("craftengine:stem_block"); + public static final Key ATTACHED_STEM_BLOCK = Key.from("craftengine:attached_stem_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -76,5 +78,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(FENCE_BLOCK, FenceBlockBehavior.FACTORY); register(BUTTON_BLOCK, ButtonBlockBehavior.FACTORY); register(FACE_ATTACHED_HORIZONTAL_DIRECTIONAL_BLOCK, FaceAttachedHorizontalDirectionalBlockBehavior.FACTORY); + register(STEM_BLOCK, StemBlockBehavior.FACTORY); + register(ATTACHED_STEM_BLOCK, AttachedStemBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index 7e0746ead..2e6793e35 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -77,7 +77,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior { return minGrowLight; } - private static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { + public static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { return (int) CoreReflections.method$BlockAndTintGetter$getRawBrightness.invoke(level, pos, 0); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java new file mode 100644 index 000000000..d7d1180c3 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java @@ -0,0 +1,154 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +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.plugin.reflection.minecraft.MRegistries; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.UpdateOption; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.IntegerProperty; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.util.*; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Callable; + +public class StemBlockBehavior extends BushBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final IntegerProperty ageProperty; + private final Key fruit; + private final Key attachedStem; + private final int minGrowLight; + private final Object tagMayPlaceFruit; + private final Object blockMayPlaceFruit; + + public StemBlockBehavior(CustomBlock customBlock, + int delay, + boolean blacklist, + List tagsCanSurviveOn, + Set blockStatesCanSurviveOn, + Set customBlocksCansSurviveOn, + IntegerProperty ageProperty, + Key fruit, + Key attachedStem, + int minGrowLight, + Object tagMayPlaceFruit, + Object blockMayPlaceFruit) { + super(customBlock, delay, blacklist, false, tagsCanSurviveOn, blockStatesCanSurviveOn, customBlocksCansSurviveOn); + this.ageProperty = ageProperty; + this.fruit = fruit; + this.attachedStem = attachedStem; + this.minGrowLight = minGrowLight; + this.tagMayPlaceFruit = tagMayPlaceFruit; + this.blockMayPlaceFruit = blockMayPlaceFruit; + } + + @Override + public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) { + return FastNMS.INSTANCE.field$FluidState$isEmpty(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(args[0])); + } + + @Override + public boolean isPathFindable(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + return (VersionHelper.isOrAbove1_20_5() ? args[1] : args[3]).equals(CoreReflections.instance$PathComputationType$AIR) + && !FastNMS.INSTANCE.field$BlockBehavior$hasCollision(thisBlock) || (boolean) superMethod.call(); + } + + @Override + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object state = args[0]; + Object level = args[1]; + Object pos = args[2]; + if (CropBlockBehavior.getRawBrightness(level, pos) < this.minGrowLight) return; + ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); + if (customState == null || customState.isEmpty()) return; + int age = customState.get(ageProperty); + if (age < ageProperty.max) { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, customState.with(ageProperty, age + 1).customBlockState().literalObject(), 2); + return; + } + Object randomDirection = CoreReflections.instance$Direction$values[RandomUtils.generateRandomInt(2, 6)]; + Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, randomDirection); + if (!FastNMS.INSTANCE.method$BlockStateBase$isAir(FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos))) + return; + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, FastNMS.INSTANCE.method$BlockPos$relative(blockPos, CoreReflections.instance$Direction$DOWN)); + if (mayPlaceFruit(blockState)) { + Optional optionalFruit = BukkitBlockManager.instance().blockById(this.fruit); + Object fruitState = null; + if (optionalFruit.isPresent()) { + fruitState = optionalFruit.get().defaultState().customBlockState().literalObject(); + } else if (fruit.namespace().equals("minecraft")) { + fruitState = FastNMS.INSTANCE.method$Block$defaultState(FastNMS.INSTANCE.method$Registry$getValue( + MBuiltInRegistries.BLOCK, + FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", fruit.value()) + )); + } + Optional optionalAttachedStem = BukkitBlockManager.instance().blockById(this.attachedStem); + if (fruitState == null || optionalAttachedStem.isEmpty()) return; + CustomBlock attachedStem = optionalAttachedStem.get(); + @SuppressWarnings("unchecked") + Property facing = (Property) attachedStem.getProperty("facing"); + if (facing == null) return; + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, fruitState, UpdateOption.UPDATE_ALL.flags()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, attachedStem.defaultState().with(facing, DirectionUtils.fromNMSDirection(randomDirection).toHorizontalDirection()).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); + } + } + + @Override + public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) { + ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[2]).orElse(null); + if (state == null || state.isEmpty()) return false; + return state.get(ageProperty) != ageProperty.max; + } + + @Override + public boolean isBoneMealSuccess(Object thisBlock, Object[] args) { + return true; + } + + @Override + public void performBoneMeal(Object thisBlock, Object[] args) { + ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[3]).orElse(null); + if (state == null || state.isEmpty()) return; + int min = Math.min(7, state.get(ageProperty) + RandomUtils.generateRandomInt(Math.min(ageProperty.min + 2, ageProperty.max), Math.min(ageProperty.max - 2, ageProperty.max))); + Object blockState = state.with(ageProperty, min).customBlockState().literalObject(); + FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], args[2], blockState, 2); + if (min >= ageProperty.max) { + FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$randomTick(blockState, args[0], args[2]); + } + } + + private boolean mayPlaceFruit(Object blockState) { + boolean flag1 = tagMayPlaceFruit != null && FastNMS.INSTANCE.method$BlockStateBase$is(blockState, tagMayPlaceFruit); + boolean flag2 = blockMayPlaceFruit != null && FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, blockMayPlaceFruit); + if (tagMayPlaceFruit == null && blockMayPlaceFruit == null) return true; + return flag1 || flag2; + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Tuple, Set, Set> tuple = readTagsAndState(arguments, false); + int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); + boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist"); + IntegerProperty ageProperty = (IntegerProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("age"), "warning.config.block.behavior.stem.missing_age"); + Key fruit = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("fruit"), "warning.config.block.behavior.stem.missing_fruit")); + Key attachedStem = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("attached-stem"), "warning.config.block.behavior.stem.missing_attached_stem")); + int minGrowLight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("light-requirement", 9), "light-requirement"); + Object tagMayPlaceFruit = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("may-place-fruit", "minecraft:dirt").toString()))); + Object blockMayPlaceFruit = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("may-place-fruit", "minecraft:farmland").toString()))); + return new StemBlockBehavior(block, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), ageProperty, fruit, attachedStem, minGrowLight, tagMayPlaceFruit, blockMayPlaceFruit); + } + } +} 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 2ab839d6b..8e9e4c631 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 @@ -381,4 +381,14 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior } FallOnBlockBehavior.super.updateEntityMovementAfterFallOn(thisBlock, args, superMethod); } -} \ No newline at end of file + + @Override + public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (!behavior.propagatesSkylightDown(thisBlock, args, superMethod)) { + return false; + } + } + return (boolean) superMethod.call(); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java index ae5e8c670..d54835999 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java @@ -170,6 +170,9 @@ public final class BlockGenerator { // stepOn .method(ElementMatchers.is(CoreReflections.method$Block$stepOn)) .intercept(MethodDelegation.to(StepOnInterceptor.INSTANCE)) + // propagatesSkylightDown + .method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$propagatesSkylightDown)) + .intercept(MethodDelegation.to(PropagatesSkylightDownInterceptor.INSTANCE)) ; // 1.21.5+ if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) { @@ -760,4 +763,19 @@ public final class BlockGenerator { } } } + + public static class PropagatesSkylightDownInterceptor { + public static final PropagatesSkylightDownInterceptor INSTANCE = new PropagatesSkylightDownInterceptor(); + + @RuntimeType + public boolean intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); + try { + return holder.value().propagatesSkylightDown(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run propagatesSkylightDown", e); + return false; + } + } + } } \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java index 148fa9e3d..03d0d98b0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockStateGenerator.java @@ -12,7 +12,6 @@ import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.bind.annotation.AllArguments; import net.bytebuddy.implementation.bind.annotation.RuntimeType; -import net.bytebuddy.implementation.bind.annotation.SuperCall; import net.bytebuddy.implementation.bind.annotation.This; import net.bytebuddy.matcher.ElementMatchers; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; @@ -23,15 +22,16 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlockState import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MLootContextParams; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; -import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.block.BlockSettings; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.DelegatingBlockState; +import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.util.ObjectHolder; +import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.World; @@ -42,8 +42,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.List; -import java.util.Optional; -import java.util.concurrent.Callable; public final class BlockStateGenerator { private static MethodHandle constructor$CraftEngineBlockState; @@ -87,11 +85,11 @@ public final class BlockStateGenerator { Class clazz$CraftEngineBlock = stateBuilder.make().load(BlockStateGenerator.class.getClassLoader()).getLoaded(); constructor$CraftEngineBlockState = VersionHelper.isOrAbove1_20_5() ? MethodHandles.publicLookup().in(clazz$CraftEngineBlock) - .findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class)) - .asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class)) : + .findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class)) + .asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class)) : MethodHandles.publicLookup().in(clazz$CraftEngineBlock) - .findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class)) - .asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class)); + .findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class)) + .asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class)); String generatedFactoryClassName = packageWithName.substring(0, packageWithName.lastIndexOf('.')) + ".CraftEngineStateFactory"; DynamicType.Builder factoryBuilder = byteBuddy @@ -210,10 +208,12 @@ public final class BlockStateGenerator { DelegatingBlockState customState = (DelegatingBlockState) thisObj; ImmutableBlockState thisState = customState.blockState(); if (thisState == null) return false; - if (!(args[0] instanceof DelegatingBlock delegatingBlock)) return false; - BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); - if (behavior == null) return false; - return behavior.block().equals(thisState.owner().value()); + if (FastNMS.INSTANCE.method$Block$defaultState(args[0]) instanceof DelegatingBlockState holder) { + ImmutableBlockState holderState = holder.blockState(); + if (holderState == null) return false; + return holderState.owner().equals(thisState.owner()); + } + return false; } } @@ -226,13 +226,15 @@ public final class BlockStateGenerator { DelegatingBlockState customState = (DelegatingBlockState) thisObj; ImmutableBlockState thisState = customState.blockState(); if (thisState == null) return false; - CustomBlock thisBlock = thisState.owner().value(); + Holder owner = thisState.owner(); for (Object holder : (Iterable) args[0]) { Object block = FastNMS.INSTANCE.method$Holder$value(holder); - if (!(block instanceof DelegatingBlock delegatingBlock)) continue; - BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); - if (behavior == null) continue; - if (behavior.block().equals(thisBlock)) return true; + if (block == null) continue; + if (!(FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState customHolder)) + continue; + ImmutableBlockState holderState = customHolder.blockState(); + if (holderState == null) continue; + return holderState.owner().equals(owner); } return false; } @@ -243,15 +245,17 @@ public final class BlockStateGenerator { @RuntimeType public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { - Object block = FastNMS.INSTANCE.method$Holder$value(args[0]); - if (!(block instanceof DelegatingBlock delegatingBlock)) return false; - BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); - if (behavior == null) return false; DelegatingBlockState customState = (DelegatingBlockState) thisObj; ImmutableBlockState thisState = customState.blockState(); if (thisState == null) return false; - CustomBlock thisBlock = thisState.owner().value(); - return behavior.block().equals(thisBlock); + Object block = FastNMS.INSTANCE.method$Holder$value(args[0]); + if (block == null) return false; + if (FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState holder) { + ImmutableBlockState holderState = holder.blockState(); + if (holderState == null) return false; + return holderState.owner().equals(thisState.owner()); + } + return false; } } @@ -260,17 +264,19 @@ public final class BlockStateGenerator { @RuntimeType public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { - Object block = FastNMS.INSTANCE.method$HolderGetter$getResourceKey(MBuiltInRegistries.BLOCK, args[0]) - .map(FastNMS.INSTANCE::method$Holder$value) - .orElse(null); - if (!(block instanceof DelegatingBlock delegatingBlock)) return false; - BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); - if (behavior == null) return false; DelegatingBlockState customState = (DelegatingBlockState) thisObj; ImmutableBlockState thisState = customState.blockState(); if (thisState == null) return false; - CustomBlock thisBlock = thisState.owner().value(); - return behavior.block().equals(thisBlock); + Object block = FastNMS.INSTANCE.method$HolderGetter$getResourceKey(MBuiltInRegistries.BLOCK, args[0]) + .map(FastNMS.INSTANCE::method$Holder$value) + .orElse(null); + if (block == null) return false; + if (FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState holder) { + ImmutableBlockState holderState = holder.blockState(); + if (holderState == null) return false; + return holderState.owner().equals(thisState.owner()); + } + return false; } } 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 65a0549f6..345f5ab28 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 @@ -4434,4 +4434,14 @@ public final class CoreReflections { ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$ResourceKey), VersionHelper.isOrAbove1_20_3() ); + + public static final Method method$BlockBehaviour$propagatesSkylightDown = requireNonNull( + VersionHelper.isOrAbove1_21_2() + ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "e_"}, clazz$BlockState) + : VersionHelper.isOrAbove1_20_5() + ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) + : VersionHelper.isOrAbove1_20_4() + ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) + : ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java index d9c489fba..c08c66559 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlocks.java @@ -6,54 +6,31 @@ import net.momirealms.craftengine.core.util.VersionHelper; public final class MBlocks { private MBlocks() {} - public static final Object AIR; - public static final Object AIR$defaultState; - public static final Object STONE; - public static final Object STONE$defaultState; - public static final Object FIRE; - public static final Object SOUL_FIRE; - public static final Object ICE; - public static final Object SHORT_GRASS; - public static final Object SHORT_GRASS$defaultState; - public static final Object SHULKER_BOX; - public static final Object COMPOSTER; - public static final Object SNOW; - public static final Object WATER; - public static final Object WATER$defaultState; - public static final Object TNT; - public static final Object TNT$defaultState; - public static final Object BARRIER; - public static final Object CARVED_PUMPKIN; - public static final Object JACK_O_LANTERN; - public static final Object MELON; - public static final Object PUMPKIN; + public static final Object AIR = getById("air");; + public static final Object AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR); + public static final Object STONE = getById("stone"); + public static final Object STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE); + public static final Object FIRE = getById("fire"); + public static final Object SOUL_FIRE = getById("soul_fire"); + public static final Object ICE = getById("ice"); + public static final Object SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass"); + public static final Object SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS); + public static final Object SHULKER_BOX = getById("shulker_box"); + public static final Object COMPOSTER = getById("composter"); + public static final Object SNOW = getById("snow"); + public static final Object WATER = getById("water"); + public static final Object WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER); + public static final Object TNT = getById("tnt"); + public static final Object TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT); + public static final Object BARRIER = getById("barrier"); + public static final Object CARVED_PUMPKIN = getById("carved_pumpkin"); + public static final Object JACK_O_LANTERN = getById("jack_o_lantern"); + public static final Object MELON = getById("melon"); + public static final Object PUMPKIN = getById("pumpkin"); + public static final Object FARMLAND = getById("farmland"); private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, rl); } - - static { - AIR = getById("air"); - AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR); - FIRE = getById("fire"); - SOUL_FIRE = getById("soul_fire"); - STONE = getById("stone"); - STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE); - ICE = getById("ice"); - SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass"); - SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS); - SHULKER_BOX = getById("shulker_box"); - COMPOSTER = getById("composter"); - SNOW = getById("snow"); - WATER = getById("water"); - WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER); - TNT = getById("tnt"); - TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT); - BARRIER = getById("barrier"); - CARVED_PUMPKIN = getById("carved_pumpkin"); - JACK_O_LANTERN = getById("jack_o_lantern"); - MELON = getById("melon"); - PUMPKIN = getById("pumpkin"); - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java index fe3440027..3f444599e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java @@ -12,6 +12,7 @@ public final class MTagKeys { public static final Object Block$SHULKER_BOXES = create(MRegistries.BLOCK, "shulker_boxes"); public static final Object Block$FENCES = create(MRegistries.BLOCK, "fences"); public static final Object Block$WOODEN_FENCES = create(MRegistries.BLOCK, "wooden_fences"); + public static final Object Block$DIRT = create(MRegistries.BLOCK, "dirt"); private static Object create(Object registry, String location) { Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location); diff --git a/common-files/src/main/resources/resources/default/configuration/templates.yml b/common-files/src/main/resources/resources/default/configuration/templates.yml index e2c881a6c..8e2458b32 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -48,13 +48,13 @@ templates#models#block: generation: parent: minecraft:block/cube_column textures: - particle: minecraft:block/custom/block_particle - down: minecraft:block/custom/block_down - up: minecraft:block/custom/block_up - north: minecraft:block/custom/block_north - east: minecraft:block/custom/block_east - south: minecraft:block/custom/block_south - west: minecraft:block/custom/block_west + particle: ${particle_texture} + down: ${down_texture} + up: ${up_texture} + north: ${north_texture} + east: ${east_texture} + south: ${south_texture} + west: ${west_texture} # 2D items templates#models#2d: diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index e2ea5b94a..c12ee18f5 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -328,6 +328,12 @@ warning.config.block.behavior.fence.missing_west: "Issue found in file < warning.config.block.behavior.face_attached_horizontal_directional.missing_face: "Issue found in file - The block '' is missing the required 'face' property for 'face_attached_horizontal_directional_block' behavior." warning.config.block.behavior.face_attached_horizontal_directional.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'face_attached_horizontal_directional_block' behavior." warning.config.block.behavior.button.missing_powered: "Issue found in file - The block '' is missing the required 'powered' property for 'button_block' behavior." +warning.config.block.behavior.stem.missing_age: "Issue found in file - The block '' is missing the required 'age' property for 'stem_block' behavior." +warning.config.block.behavior.stem.missing_fruit: "Issue found in file - The block '' is missing the required 'fruit' argument for 'stem_block' behavior." +warning.config.block.behavior.stem.missing_attached_stem: "Issue found in file - The block '' is missing the required 'attached_stem' argument for 'stem_block' behavior." +warning.config.block.behavior.attached_stem.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'attached_stem_block' behavior." +warning.config.block.behavior.attached_stem.missing_fruit: "Issue found in file - The block '' is missing the required 'fruit' argument for 'attached_stem_block' behavior." +warning.config.block.behavior.attached_stem.missing_stem: "Issue found in file - The block '' is missing the required 'stem' argument for 'attached_stem_block' behavior." warning.config.model.generation.missing_parent: "Issue found in file - The config '' is missing the required 'parent' argument in 'generation' section." warning.config.model.generation.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''." warning.config.model.generation.invalid_display_position: "Issue found in file - The config '' is using an invalid display position '' in 'generation.display' section. Allowed display positions: []" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index add5680d3..462138c04 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -322,6 +322,12 @@ warning.config.block.behavior.fence.missing_west: "在文件 发 warning.config.block.behavior.face_attached_horizontal_directional.missing_face: "在文件 发现问题 - 方块 '' 的 'face_attached_horizontal_directional_block' 行为缺少必需的 'face' 属性" warning.config.block.behavior.face_attached_horizontal_directional.missing_facing: "在文件 发现问题 - 方块 '' 的 'face_attached_horizontal_directional_block' 行为缺少必需的 'facing' 属性" warning.config.block.behavior.button.missing_powered: "在文件 发现问题 - 方块 '' 的 'button_block' 行为缺少必需的 'powered' 属性" +warning.config.block.behavior.stem.missing_age: "在文件 发现问题 - 方块 '' 的 'stem_block' 行为缺少必需的 'age' 属性" +warning.config.block.behavior.stem.missing_fruit: "在文件 发现问题 - 方块 '' 的 'stem_block' 行为缺少必需的 'fruit' 选项" +warning.config.block.behavior.stem.missing_attached_stem: "在文件 发现问题 - 方块 '' 的 'stem_block' 行为缺少必需的 'attached_stem' 选项" +warning.config.block.behavior.attached_stem.missing_facing: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'facing' 属性" +warning.config.block.behavior.attached_stem.missing_fruit: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'fruit' 选项" +warning.config.block.behavior.attached_stem.missing_stem: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'stem' 选项" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" 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 d81554d1a..d3b82a4cd 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 @@ -184,6 +184,12 @@ public abstract class BlockBehavior { superMethod.call(); } + // 1.20.1~1.21.1 BlockState state, BlockGetter level, BlockPos pos + // 1.21.2+ BlockState state + public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + return (boolean) superMethod.call(); + } + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { return state; } @@ -217,4 +223,4 @@ public abstract class BlockBehavior { } public abstract CustomBlock block(); -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index 6d228cad0..1aa561ed6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G # Rule: [major update].[feature update].[bug fix] project_version=0.0.63.4 config_version=46 -lang_version=30 +lang_version=31 project_group=net.momirealms latest_supported_version=1.21.8 @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.93 +nms_helper_version=1.0.94 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.33.1