diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java index b3370a11e..995afd952 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java @@ -59,6 +59,15 @@ public class BukkitCustomBlockStateWrapper extends AbstractBlockStateWrapper imp return this; } + @Override + public BlockStateWrapper cycleProperty(String propertyName, boolean backwards) { + return getImmutableBlockState().map(state -> { + Property property = state.owner().value().getProperty(propertyName); + if (property == null) return null; + return state.cycle(property, backwards).customBlockState(); + }).orElse(this); + } + @Override public boolean hasProperty(String propertyName) { return getImmutableBlockState().map(state -> state.owner().value().getProperty(propertyName) != null).orElse(false); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java index b298f6d66..4b7b3989c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java @@ -54,4 +54,11 @@ public class BukkitVanillaBlockStateWrapper extends AbstractBlockStateWrapper { if (newState == super.blockState) return this; return BlockRegistryMirror.byId(BlockStateUtils.blockStateToId(newState)); } + + @Override + public BlockStateWrapper cycleProperty(String propertyName, boolean backwards) { + Object newState = this.accessor.cycleProperty(propertyName, backwards); + if (newState == super.blockState) return this; + return BlockRegistryMirror.byId(BlockStateUtils.blockStateToId(newState)); + } } diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index b69c610d0..75303d550 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -479,6 +479,7 @@ warning.config.function.when.missing_source: "Issue found in file Issue found in file - The config '' is missing the required 'rules' argument for 'if_else' function." warning.config.function.update_block_property.missing_properties: "Issue found in file - The config '' is missing the required 'properties' argument for 'update_block_property' function." warning.config.function.transform_block.missing_block: "Issue found in file - The config '' is missing the required 'block' argument for 'transform_block' function." +warning.config.function.cycle_block_property.missing_property: "Issue found in file - The config '' is missing the required 'property' argument for 'cycle_block_property' function." warning.config.selector.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for selector." warning.config.selector.invalid_type: "Issue found in file - The config '' is using an invalid selector type ''." warning.config.selector.invalid_target: "Issue found in file - The config '' is using an invalid selector target ''." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 886cb003e..b51193bcb 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -478,6 +478,7 @@ warning.config.function.when.missing_source: "在文件 发现 warning.config.function.if_else.missing_rules: "在文件 发现问题 - 配置项 '' 缺少 'if_else' 函数所需的 'rules' 参数" warning.config.function.update_block_property.missing_properties: "在文件 发现问题 - 配置项 '' 缺少 'update_block_property' 函数所需的 'properties' 参数" warning.config.function.transform_block.missing_block: "在文件 发现问题 - 配置项 '' 缺少 'transform_block' 函数所需的 'block' 参数" +warning.config.function.cycle_block_property.missing_property: "在文件 发现问题 - 配置项 '' 缺少 'cycle_block_property' 函数所需的 'property' 参数" warning.config.selector.missing_type: "在文件 发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 发现问题 - 配置项 '' 使用了无效的选择器类型 ''" warning.config.selector.invalid_target: "在文件 发现问题 - 配置项 '' 使用了无效的选择器目标 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java index 4b86c95c3..4323daf06 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java @@ -23,6 +23,8 @@ public interface BlockStateWrapper extends Comparable { BlockStateWrapper withProperty(String propertyName, String propertyValue); + BlockStateWrapper cycleProperty(String propertyName, boolean backwards); + String getAsString(); boolean isCustom(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index c46a69faf..2c837d796 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.World; import net.momirealms.sparrow.nbt.CompoundTag; @@ -152,6 +153,16 @@ public final class ImmutableBlockState { return this.owner; } + public > ImmutableBlockState cycle(Property property, boolean backwards) { + T currentValue = get(property); + List values = property.possibleValues(); + return with(property, getRelative(values, currentValue, backwards)); + } + + private static T getRelative(List values, T currentValue, boolean backwards) { + return backwards ? MiscUtils.findPreviousInIterable(values, currentValue) : getNextValue(values, currentValue); + } + public > ImmutableBlockState cycle(Property property) { T currentValue = get(property); List values = property.possibleValues(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java b/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java index 41aa0cd1a..f25d3e14d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java @@ -18,5 +18,10 @@ public interface StatePropertyAccessor { Object withProperty(String propertyName, String value); @NotNull - Object cycleProperty(String propertyName); + default Object cycleProperty(String propertyName) { + return cycleProperty(propertyName, false); + } + + @NotNull + Object cycleProperty(String propertyName, boolean backwards); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java index 74592b40a..447ce05f0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventFunctions.java @@ -54,6 +54,7 @@ public class EventFunctions { register(CommonFunctions.ALTERNATIVES, new IfElseFunction.FactoryImpl<>(EventConditions::fromMap, EventFunctions::fromMap)); register(CommonFunctions.WHEN, new WhenFunction.FactoryImpl<>(EventConditions::fromMap, EventFunctions::fromMap)); register(CommonFunctions.DAMAGE_ITEM, new DamageItemFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.CYCLE_BLOCK_PROPERTY, new CycleBlockPropertyFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index 5cd4a5d0a..bc638a23d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -45,4 +45,5 @@ public final class CommonFunctions { public static final Key ALL_OF = Key.of("craftengine:all_of"); public static final Key DUMMY = Key.of("craftengine:dummy"); public static final Key DAMAGE_ITEM = Key.of("craftengine:damage_item"); + public static final Key CYCLE_BLOCK_PROPERTY = Key.of("craftengine:cycle_block_property"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CycleBlockPropertyFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CycleBlockPropertyFunction.java new file mode 100644 index 000000000..c7b2ac317 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CycleBlockPropertyFunction.java @@ -0,0 +1,75 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.block.UpdateOption; +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.ExistingBlock; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class CycleBlockPropertyFunction extends AbstractConditionalFunction { + private final String property; + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final NumberProvider updateFlags; + + public CycleBlockPropertyFunction(List> predicates, String property, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider updateFlags) { + super(predicates); + this.property = property; + this.x = x; + this.y = y; + this.z = z; + this.updateFlags = updateFlags; + } + + @Override + protected void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isEmpty()) return; + World world = optionalWorldPosition.get().world(); + int x = MiscUtils.fastFloor(this.x.getDouble(ctx)); + int y = MiscUtils.fastFloor(this.y.getDouble(ctx)); + int z = MiscUtils.fastFloor(this.z.getDouble(ctx)); + ExistingBlock blockAt = world.getBlockAt(x, y, z); + boolean isSecondaryUseActive = ctx.getOptionalParameter(DirectContextParameters.PLAYER) + .map(Player::isSecondaryUseActive) + .orElse(false); + BlockStateWrapper wrapper = blockAt.blockState().cycleProperty(this.property, isSecondaryUseActive); + world.setBlockAt(x, y, z, wrapper, this.updateFlags.getInt(ctx)); + } + + @Override + public Key type() { + return CommonFunctions.CYCLE_BLOCK_PROPERTY; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + return new CycleBlockPropertyFunction<>(getPredicates(arguments), + ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("property"), "warning.config.function.cycle_block_property.missing_property"), + NumberProviders.fromObject(arguments.getOrDefault("x", "")), + NumberProviders.fromObject(arguments.getOrDefault("y", "")), + NumberProviders.fromObject(arguments.getOrDefault("z", "")), + Optional.ofNullable(arguments.get("update-flags")).map(NumberProviders::fromObject).orElse(NumberProviders.direct(UpdateOption.UPDATE_ALL.flags()))); + } + } +} diff --git a/gradle.properties b/gradle.properties index 66c12e6c9..81a263711 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,7 +49,7 @@ byte_buddy_version=1.17.8 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=1.0.4 -nms_helper_version=1.0.128 +nms_helper_version=1.0.129 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5