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..2c2e4d036 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; @@ -20,18 +19,16 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlockStateProperties; -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.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.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.World; @@ -42,8 +39,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; @@ -71,27 +66,15 @@ public final class BlockStateGenerator { .method(ElementMatchers.is(CoreReflections.method$StateHolder$setValue)) .intercept(MethodDelegation.to(SetPropertyValueInterceptor.INSTANCE)) .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isBlock)) - .intercept(MethodDelegation.to(IsBlockInterceptor.INSTANCE)) - .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isHolderSetBlock)) - .intercept(MethodDelegation.to(IsHolderSetBlockInterceptor.INSTANCE)); - if (CoreReflections.method$BlockStateBase$isHolderBlock != null) { - stateBuilder = stateBuilder - .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isHolderBlock)) - .intercept(MethodDelegation.to(IsHolderBlockInterceptor.INSTANCE)); - } - if (CoreReflections.method$BlockStateBase$isResourceKeyBlock != null) { - stateBuilder = stateBuilder - .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isResourceKeyBlock)) - .intercept(MethodDelegation.to(IsResourceKeyBlockInterceptor.INSTANCE)); - } + .intercept(MethodDelegation.to(IsBlockInterceptor.INSTANCE)); 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,70 +193,15 @@ 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()); - } - } - - public static class IsHolderSetBlockInterceptor { - public static final IsHolderSetBlockInterceptor INSTANCE = new IsHolderSetBlockInterceptor(); - - @SuppressWarnings("unchecked") - @RuntimeType - public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { - DelegatingBlockState customState = (DelegatingBlockState) thisObj; - ImmutableBlockState thisState = customState.blockState(); - if (thisState == null) return false; - CustomBlock thisBlock = thisState.owner().value(); - 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 (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; } } - public static class IsHolderBlockInterceptor { - public static final IsHolderBlockInterceptor INSTANCE = new IsHolderBlockInterceptor(); - - @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); - } - } - - public static class IsResourceKeyBlockInterceptor { - public static final IsResourceKeyBlockInterceptor INSTANCE = new IsResourceKeyBlockInterceptor(); - - @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); - } - } - public static class CreateStateInterceptor { public static final CreateStateInterceptor INSTANCE = new CreateStateInterceptor(); 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..f4b0439d1 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 @@ -4419,19 +4419,13 @@ public final class CoreReflections { ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Block) ); - public static final Method method$BlockStateBase$isHolderSetBlock = requireNonNull( - ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$HolderSet) - ); - - // 1.20.2+ - public static final Method method$BlockStateBase$isHolderBlock = MiscUtils.requireNonNullIf( - ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Holder), - VersionHelper.isOrAbove1_20_2() - ); - - // 1.20.3+ - public static final Method method$BlockStateBase$isResourceKeyBlock = MiscUtils.requireNonNullIf( - 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$Block, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) + : ReflectionUtils.getDeclaredMethod(clazz$Block, 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..79389af1c 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/additional-real-blocks.yml b/common-files/src/main/resources/additional-real-blocks.yml index 2c6f2c87d..98472f7de 100644 --- a/common-files/src/main/resources/additional-real-blocks.yml +++ b/common-files/src/main/resources/additional-real-blocks.yml @@ -84,4 +84,6 @@ minecraft:warped_fence_gate: 16 minecraft:barrier: 128 minecraft:white_bed: 1 minecraft:redstone_torch: 1 -minecraft:redstone_wall_torch: 4 \ No newline at end of file +minecraft:redstone_wall_torch: 4 +minecraft:pumpkin_stem: 8 +minecraft:attached_pumpkin_stem: 4 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml b/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml new file mode 100644 index 000000000..0291afcbe --- /dev/null +++ b/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml @@ -0,0 +1,298 @@ +items: + default:honeydew_item: + material: apple + custom-model-data: 1000 + data: + item-name: + model: + template: default:model/simplified_generated + arguments: + path: minecraft:item/custom/honeydew_item + behavior: + type: block_item + block: default:honeydew_stem + default:honeydew: + material: nether_brick + custom-model-data: 3023 + data: + item-name: + model: + path: minecraft:item/custom/honeydew + generation: + parent: minecraft:block/custom/honeydew + behavior: + type: block_item + block: default:honeydew + +blocks: + default:honeydew: + loot: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: default:honeydew + conditions: + - type: enchantment + predicate: minecraft:silk_touch>=1 + - type: item + item: default:honeydew_item + functions: + - type: set_count + add: false + count: 3~7 + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: ore_drops + - type: limit_count + max: 9 + - type: explosion_decay + settings: + map-color: 19 + hardness: 1 + resistance: 1 + push-reaction: DESTROY + is-suffocating: true + is-redstone-conductor: true + item: default:honeydew + tags: + - minecraft:enderman_holdable + - minecraft:mineable/axe + - minecraft:sword_efficient + incorrect-tool-dig-speed: 1 + state: + id: 30 + state: note_block:30 + model: + template: default:model/cube + arguments: + model: minecraft:block/custom/honeydew + particle_texture: minecraft:block/custom/honeydew + down_texture: minecraft:block/custom/honeydew_bottom + up_texture: minecraft:block/custom/honeydew_top + north_texture: minecraft:block/custom/honeydew + east_texture: minecraft:block/custom/honeydew + south_texture: minecraft:block/custom/honeydew + west_texture: minecraft:block/custom/honeydew + default:honeydew_stem: + loot: + pools: + - rolls: 1 + entries: + - type: item + item: default:honeydew_item + functions: + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 0 + count: + type: binomial + extra: 3 + probability: 0.06666667 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 1 + count: + type: binomial + extra: 3 + probability: 0.13333334 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 2 + count: + type: binomial + extra: 3 + probability: 0.2 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 3 + count: + type: binomial + extra: 3 + probability: 0.26666668 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 4 + count: + type: binomial + extra: 3 + probability: 0.33333334 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 5 + count: + type: binomial + extra: 3 + probability: 0.4 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 6 + count: + type: binomial + extra: 3 + probability: 0.46666667 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 7 + count: + type: binomial + extra: 3 + probability: 0.53333336 + functions: + - type: explosion_decay + settings: + map-color: 7 + hardness: 0 + resistance: 0 + push-reaction: DESTROY + is-suffocating: false + is-redstone-conductor: false + item: default:honeydew_item + is-randomly-ticking: true + tags: + - minecraft:bee_growables + - minecraft:crops + - minecraft:maintains_farmland + behaviors: + type: stem_block + fruit: default:honeydew + attached-stem: default:attached_honeydew_stem + blacklist: false + bottom-blocks: + - minecraft:farmland + states: + properties: + age: + type: int + default: 0 + range: 0~7 + appearances: + age=0: + state: pumpkin_stem[age=0] + age=1: + state: pumpkin_stem[age=1] + age=2: + state: pumpkin_stem[age=2] + age=3: + state: pumpkin_stem[age=3] + age=4: + state: pumpkin_stem[age=4] + age=5: + state: pumpkin_stem[age=5] + age=6: + state: pumpkin_stem[age=6] + age=7: + state: pumpkin_stem[age=7] + variants: + age=0: + appearance: age=0 + id: 0 + age=1: + appearance: age=1 + id: 1 + age=2: + appearance: age=2 + id: 2 + age=3: + appearance: age=3 + id: 3 + age=4: + appearance: age=4 + id: 4 + age=5: + appearance: age=5 + id: 5 + age=6: + appearance: age=6 + id: 6 + age=7: + appearance: age=7 + id: 7 + default:attached_honeydew_stem: + loot: + pools: + - rolls: 1 + entries: + - type: item + item: default:honeydew_item + functions: + - type: set_count + add: false + count: + type: binomial + extra: 3 + probability: 0.53333336 + functions: + - type: explosion_decay + settings: + map-color: 7 + hardness: 0 + resistance: 0 + push-reaction: DESTROY + is-suffocating: false + is-redstone-conductor: false + item: default:honeydew_item + is-randomly-ticking: true + tags: + - minecraft:maintains_farmland + behaviors: + type: attached_stem_block + fruit: default:honeydew + stem: default:honeydew_stem + blacklist: false + bottom-blocks: + - minecraft:farmland + states: + properties: + facing: + type: horizontal_direction + default: north + appearances: + facing=east: + state: attached_pumpkin_stem[facing=east] + facing=south: + state: attached_pumpkin_stem[facing=south] + facing=west: + state: attached_pumpkin_stem[facing=west] + facing=north: + state: attached_pumpkin_stem[facing=north] + variants: + facing=east: + appearance: facing=east + id: 0 + facing=south: + appearance: facing=south + id: 1 + facing=west: + appearance: facing=west + id: 2 + facing=north: + appearance: facing=north + id: 3 diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index 55610a412..6f02cfd78 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -78,4 +78,6 @@ categories: - default:bench - default:wooden_chair - default:flower_basket - - default:amethyst_torch \ No newline at end of file + - default:amethyst_torch + - default:honeydew_item + - default:honeydew \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index fa91ebbb0..fbd75318d 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -49,6 +49,8 @@ i18n: item.safe_block: Safe Block item.sofa: Sofa item.amethyst_torch: Amethyst Torch + item.honeydew_item: Honeydew Slice + item.honeydew: Honeydew category.default.name: Default Assets category.default.lore: Contains the default configuration of CraftEngine category.palm_tree: Palm Tree @@ -107,6 +109,8 @@ i18n: item.safe_block: 保险柜 item.sofa: 沙发 item.amethyst_torch: 紫水晶火把 + item.honeydew_item: 哈密瓜片 + item.honeydew: 哈密瓜 category.default.name: 默认资产 category.default.lore: 包含了CraftEngine的默认配置 category.palm_tree: 棕榈树 @@ -149,6 +153,9 @@ lang: block_name:default:sofa: Sofa block_name:default:amethyst_torch: Amethyst Torch block_name:default:amethyst_wall_torch: Amethyst Torch + block_name:default:honeydew: Honeydew + block_name:default:honeydew_stem: Honeydew Stem + block_name:default:default:attached_honeydew_stem: Honeydew Stem zh_cn: block_name:default:chinese_lantern: 灯笼 block_name:default:netherite_anvil: 下界合金砧 @@ -178,4 +185,7 @@ lang: block_name:default:sleeper_sofa: 沙发 block_name:default:sofa: 沙发 block_name:default:amethyst_torch: 紫水晶火把 - block_name:default:amethyst_wall_torch: 紫水晶火把 \ No newline at end of file + block_name:default:amethyst_wall_torch: 紫水晶火把 + block_name:default:honeydew: 哈密瓜 + block_name:default:honeydew_stem: 哈密瓜茎 + block_name:default:default:attached_honeydew_stem: 哈密瓜茎 \ No newline at end of file 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/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png new file mode 100644 index 000000000..df74b134b Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png new file mode 100644 index 000000000..a21c39cec Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_top.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_top.png new file mode 100644 index 000000000..5fffae735 Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_top.png differ diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/honeydew_item.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/honeydew_item.png new file mode 100644 index 000000000..5c46ede57 Binary files /dev/null and b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/honeydew_item.png differ diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index e2ea5b94a..3abacd999 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -87,6 +87,8 @@ warning.config.number.uniform.missing_min: "Issue found in file warning.config.number.uniform.missing_max: "Issue found in file - The config '' is missing the required 'max' argument for 'uniform' number." warning.config.number.gaussian.missing_min: "Issue found in file - The config '' is missing the required 'min' argument for 'gaussian' number." warning.config.number.gaussian.missing_max: "Issue found in file - The config '' is missing the required 'max' argument for 'gaussian' number." +warning.config.number.binomial.missing_extra: "Issue found in file - The config '' is missing the required 'extra' argument for 'binomial' number." +warning.config.number.binomial.missing_probability: "Issue found in file - The config '' is missing the required 'probability' argument for 'binomial' number." warning.config.condition.all_of.missing_terms: "Issue found in file - The config '' is missing the required 'terms' argument for 'all_of' condition." warning.config.condition.all_of.invalid_terms_type: "Issue found in file - The config '' has a misconfigured 'all_of' condition, 'terms' should be a map list, current type: ''." warning.config.condition.any_of.missing_terms: "Issue found in file - The config '' is missing the required 'terms' argument for 'any_of' condition." @@ -328,6 +330,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..6f5171988 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -87,6 +87,8 @@ warning.config.number.uniform.missing_min: "在文件 发现问 warning.config.number.uniform.missing_max: "在文件 发现问题 - 配置项 '' 缺少 'uniform' 数字类型所需的 'max' 参数" warning.config.number.gaussian.missing_min: "在文件 发现问题 - 配置项 '' 缺少 'gaussian' 数字类型所需的 'min' 参数" warning.config.number.gaussian.missing_max: "在文件 发现问题 - 配置项 '' 缺少 'gaussian' 数字类型所需的 'max' 参数" +warning.config.number.binomial.missing_extra: "在文件 发现问题 - 配置项 '' 缺少 'binomial' 数字类型所需的 'extra' 参数" +warning.config.number.binomial.missing_probability: "在文件 发现问题 - 配置项 '' 缺少 'binomial' 数字类型所需的 'probability' 参数" warning.config.condition.all_of.missing_terms: "在文件 发现问题 - 配置项 '' 缺少 'all_of' 条件所需的 'terms' 参数" warning.config.condition.all_of.invalid_terms_type: "在文件 发现问题 - 配置项 '' 的 'all_of' 条件配置错误, 'terms' 应为映射列表, 当前类型: ''" warning.config.condition.any_of.missing_terms: "在文件 发现问题 - 配置项 '' 缺少 'any_of' 条件所需的 'terms' 参数" @@ -322,6 +324,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/core/src/main/java/net/momirealms/craftengine/core/loot/function/LimitCountFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/LimitCountFunction.java new file mode 100644 index 000000000..8ecc4fc2b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/LimitCountFunction.java @@ -0,0 +1,65 @@ +package net.momirealms.craftengine.core.loot.function; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.LootConditions; +import net.momirealms.craftengine.core.loot.LootContext; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class LimitCountFunction extends AbstractLootConditionalFunction { + public static final Factory FACTORY = new Factory<>(); + @Nullable + private final NumberProvider min; + @Nullable + private final NumberProvider max; + + public LimitCountFunction(List> predicates, @Nullable NumberProvider min, @Nullable NumberProvider max) { + super(predicates); + this.min = min; + this.max = max; + } + + @Override + public Key type() { + return LootFunctions.LIMIT_COUNT; + } + + @Override + protected Item applyInternal(Item item, LootContext context) { + int amount = item.count(); + if (min != null) { + int minAmount = min.getInt(context); + if (amount < minAmount) { + item.count(minAmount); + } + } + if (max != null) { + int maxAmount = max.getInt(context); + if (amount > maxAmount) { + item.count(maxAmount); + } + } + return item; + } + + public static class Factory implements LootFunctionFactory { + @SuppressWarnings("unchecked") + @Override + public LootFunction create(Map arguments) { + Object min = arguments.get("min"); + Object max = arguments.get("max"); + List> conditions = Optional.ofNullable(arguments.get("conditions")) + .map(it -> LootConditions.fromMapList((List>) it)) + .orElse(Collections.emptyList()); + return new LimitCountFunction<>(conditions, min == null ? null : NumberProviders.fromObject(min), max == null ? null : NumberProviders.fromObject(max)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java index c2233c20f..c9d221c95 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/LootFunctions.java @@ -20,12 +20,14 @@ public class LootFunctions { public static final Key SET_COUNT = Key.from("craftengine:set_count"); public static final Key EXPLOSION_DECAY = Key.from("craftengine:explosion_decay"); public static final Key DROP_EXP = Key.from("craftengine:drop_exp"); + public static final Key LIMIT_COUNT = Key.from("craftengine:limit_count"); static { register(SET_COUNT, SetCountFunction.FACTORY); register(EXPLOSION_DECAY, ExplosionDecayFunction.FACTORY); register(APPLY_BONUS, ApplyBonusCountFunction.FACTORY); register(DROP_EXP, DropExpFunction.FACTORY); + register(LIMIT_COUNT, LimitCountFunction.FACTORY); } public static void register(Key key, LootFunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 62898220f..b3eafb708 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -431,6 +431,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/configuration/blocks/topaz_ore.yml"); plugin.saveResource("resources/default/configuration/blocks/netherite_anvil.yml"); plugin.saveResource("resources/default/configuration/blocks/amethyst_torch.yml"); + plugin.saveResource("resources/default/configuration/blocks/honeydew.yml"); // assets plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/font/image/emojis.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/chinese_lantern.png"); @@ -537,6 +538,10 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_background.png.mcmeta"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png.mcmeta"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_top.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/honeydew_item.png"); } private TreeMap> updateCachedConfigFiles() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/BinomialNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/BinomialNumberProvider.java new file mode 100644 index 000000000..3d2306df8 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/BinomialNumberProvider.java @@ -0,0 +1,51 @@ +package net.momirealms.craftengine.core.plugin.context.number; + +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public record BinomialNumberProvider(NumberProvider trials, NumberProvider successProbability) implements NumberProvider { + public static final Factory FACTORY = new Factory(); + + @Override + public float getFloat(Context context) { + return getInt(context); + } + + @Override + public double getDouble(Context context) { + return getInt(context); + } + + @Override + public int getInt(Context context) { + int trialCount = this.trials.getInt(context); + float probability = this.successProbability.getFloat(context); + int successCount = 0; + + for (int i = 0; i < trialCount; i++) { + if (RandomUtils.generateRandomFloat(0, 1) < probability) { + successCount++; + } + } + return successCount; + } + + @Override + public Key type() { + return NumberProviders.BINOMIAL; + } + + public static class Factory implements NumberProviderFactory { + + @Override + public NumberProvider create(Map arguments) { + Object trials = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("extra"), "warning.config.number.binomial.missing_extra"); + Object successProbability = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("probability"), "warning.config.number.binomial.missing_probability"); + return new BinomialNumberProvider(NumberProviders.fromObject(trials), NumberProviders.fromObject(successProbability)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java index 49ce77b1a..0b46ffb92 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/NumberProviders.java @@ -18,6 +18,7 @@ public class NumberProviders { public static final Key UNIFORM = Key.of("craftengine:uniform"); public static final Key EXPRESSION = Key.of("craftengine:expression"); public static final Key GAUSSIAN = Key.of("craftengine:gaussian"); + public static final Key BINOMIAL = Key.of("craftengine:binomial"); static { register(FIXED, FixedNumberProvider.FACTORY); @@ -25,6 +26,7 @@ public class NumberProviders { register(UNIFORM, UniformNumberProvider.FACTORY); register(GAUSSIAN, GaussianNumberProvider.FACTORY); register(EXPRESSION, ExpressionNumberProvider.FACTORY); + register(BINOMIAL, BinomialNumberProvider.FACTORY); } public static void register(Key key, NumberProviderFactory factory) { 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