From 60e4db7a9af1d46e37768c77dc3e53f65e526831 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 14 May 2025 15:54:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=B8=8A=E4=B8=8B=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 10 +- .../src/main/resources/translations/zh_cn.yml | 12 ++- .../bukkit/block/BlockEventListener.java | 10 ++ .../bukkit/block/BukkitBlockManager.java | 53 +-------- .../furniture/BukkitFurnitureManager.java | 8 +- .../bukkit/item/BukkitCustomItem.java | 28 ++++- .../bukkit/item/BukkitItemManager.java | 2 + .../factory/ComponentItemFactory1_20_5.java | 16 +-- .../item/listener/ItemEventListener.java | 102 +++++++++++++----- .../plugin/network/PacketConsumers.java | 28 ++++- .../entity/furniture/CustomFurniture.java | 14 +++ .../craftengine/core/item/CustomItem.java | 10 +- .../AbstractChainParameterContext.java | 6 ++ .../parameter/DirectContextParameters.java | 9 ++ .../parameter/ItemParameterProvider.java | 25 +++++ .../parameter/WorldParameterProvider.java | 1 + .../plugin/event/BlockEventFunctions.java | 40 ------- ...ntConditions.java => EventConditions.java} | 22 ++-- .../core/plugin/event/EventFunctions.java | 101 +++++++++++++++++ .../core/plugin/event/EventTrigger.java | 3 +- .../core/registry/BuiltInRegistries.java | 4 +- .../craftengine/core/registry/Registries.java | 4 +- gradle.properties | 2 +- 23 files changed, 353 insertions(+), 157 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java rename core/src/main/java/net/momirealms/craftengine/core/plugin/event/{BlockEventConditions.java => EventConditions.java} (81%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 456d2405d..e8dca66a7 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -225,8 +225,6 @@ warning.config.block.behavior.leaves.missing_distance: "Issue found in f warning.config.block.behavior.sapling.missing_stage: "Issue found in file - The block '' is missing the required 'stage' property for 'sapling_block' behavior." warning.config.block.behavior.sapling.missing_feature: "Issue found in file - The block '' is missing the required 'feature' argument for 'sapling_block' behavior." warning.config.block.behavior.strippable.missing_stripped: "Issue found in file - The block '' is missing the required 'stripped' argument for 'strippable_block' behavior." -warning.config.block.event.condition.missing_type: "Issue found in file - The block '' is missing the required 'type' argument for event condition." -warning.config.block.event.condition.invalid_type: "Issue found in file - The block '' is using an invalid 'type' argument '' for event condition." 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.invalid_display_position: "Issue found in file - The config '' is using an invalid display position '' in 'generation.display' section. Allowed display positions: []" warning.config.model.generation.invalid_gui_light: "Issue found in file - The config '' is using an invalid gui-light option '' in 'generation' section. Allowed gui light options: []" @@ -298,6 +296,10 @@ warning.config.conflict_matcher.all_of.missing_terms: "Issue found in co warning.config.conflict_matcher.any_of.missing_terms: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'terms' argument for 'any_of' matcher." warning.config.conflict_resolution.missing_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - Missing required 'type' argument for one of the resolutions." warning.config.conflict_resolution.invalid_type: "Issue found in config.yml at 'resource-pack.duplicated-files-handler' - One of the resolutions is using the invalid type ''." -warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." warning.config.event.missing_trigger: "Issue found in file - The config '' is missing the required 'on' argument for event triggers." -warning.config.event.invalid_trigger: "Issue found in file - The config '' is using an invalid event trigger ''." \ No newline at end of file +warning.config.event.invalid_trigger: "Issue found in file - The config '' is using an invalid event trigger ''." +warning.config.event.condition.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for event condition." +warning.config.event.condition.invalid_type: "Issue found in file - The config '' is using an invalid 'type' argument '' for event condition." +warning.config.function.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for function." +warning.config.function.invalid_type: "Issue found in file - The config '' is using an invalid function type ''." +warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/translations/zh_cn.yml b/bukkit/loader/src/main/resources/translations/zh_cn.yml index 9a75a659e..a8c511c27 100644 --- a/bukkit/loader/src/main/resources/translations/zh_cn.yml +++ b/bukkit/loader/src/main/resources/translations/zh_cn.yml @@ -90,6 +90,7 @@ warning.config.condition.match_block_property.missing_properties: "在 warning.config.condition.match_item.missing_id: "在文件 发现问题 - 配置项 '' 缺少 'match_item' 条件所需的 'id' 参数" warning.config.condition.table_bonus.missing_enchantment: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'enchantment' 参数" warning.config.condition.table_bonus.missing_chances: "在文件 发现问题 - 配置项 '' 缺少 'table_bonus' 条件所需的 'chances' 参数" +warning.config.condition.click_type.missing_click_type: "Issue found in file - The config '' is missing the required 'click-type' argument for 'click_type' condition." warning.config.structure.not_section: "在文件 发现问题 - 配置项 '' 应为配置段落 但实际类型为 ''" warning.config.image.duplicate: "在文件 发现问题 - 重复的图片配置 '' 请检查其他文件中是否存在相同配置" warning.config.image.missing_height: "在文件 发现问题 - 图片 '' 缺少必需的 'height' 参数" @@ -224,8 +225,6 @@ warning.config.block.behavior.leaves.missing_distance: "在文件 在文件 发现问题 - 方块 '' 的 'sapling_block' 行为缺少必需的 'stage' 属性" warning.config.block.behavior.sapling.missing_feature: "在文件 发现问题 - 方块 '' 的 'sapling_block' 行为缺少必需的 'feature' 参数" warning.config.block.behavior.strippable.missing_stripped: "在文件 发现问题 - 方块 '' 的 'strippable_block' 行为缺少必需的 'stripped' 参数" -warning.config.block.event.condition.missing_type: "在文件 - 方块 '' 的事件条件缺少 'type' 参数" -warning.config.block.event.condition.invalid_type: "在文件 - 方块 '' 使用了无效的事件条件类型 ''" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" @@ -296,4 +295,11 @@ warning.config.conflict_matcher.inverted.missing_term: "在 config.yml warning.config.conflict_matcher.all_of.missing_terms: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 全匹配器缺少必需的 'terms' 参数" warning.config.conflict_matcher.any_of.missing_terms: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 任一匹配器缺少必需的 'terms' 参数" warning.config.conflict_resolution.missing_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案缺少必需的 'type' 参数" -warning.config.conflict_resolution.invalid_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案使用了无效类型 ''" \ No newline at end of file +warning.config.conflict_resolution.invalid_type: "在 config.yml 的 'resource-pack.duplicated-files-handler' 处发现问题 - 文件冲突处理器的某个解决方案使用了无效类型 ''" +warning.config.event.missing_trigger: "Issue found in file - The config '' is missing the required 'on' argument for event triggers." +warning.config.event.invalid_trigger: "Issue found in file - The config '' is using an invalid event trigger ''." +warning.config.event.condition.missing_type: "在文件 - 配置项 '' 的事件条件缺少 'type' 参数" +warning.config.event.condition.invalid_type: "在文件 - 配置项 '' 使用了无效的事件条件类型 ''" +warning.config.function.missing_type: "Issue found in file - The config '' is missing the required 'type' argument for function." +warning.config.function.invalid_type: "Issue found in file - The config '' is using an invalid function type ''." +warning.config.function.command.missing_command: "Issue found in file - The config '' is missing the required 'command' argument for 'command' function." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 013583c6d..f8fa97ab0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.properties.Property; @@ -14,7 +15,9 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; @@ -136,7 +139,13 @@ public class BlockEventListener implements Listener { return; } + // execute functions net.momirealms.craftengine.core.world.World world = new BukkitWorld(location.getWorld()); + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) + .withParameter(DirectContextParameters.BLOCK_STATE, state)); + state.owner().value().execute(context, EventTrigger.BREAK); + // handle waterlogged blocks @SuppressWarnings("unchecked") Property waterloggedProperty = (Property) state.owner().value().getProperty("waterlogged"); @@ -146,6 +155,7 @@ public class BlockEventListener implements Listener { location.getWorld().setBlockData(location, Material.WATER.createBlockData()); } } + // play sound WorldPosition position = new WorldPosition(world, location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); world.playBlockSound(position, state.sounds().breakSound()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 0fa67030c..7d77e45fe 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -25,7 +25,7 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.event.BlockEventFunctions; +import net.momirealms.craftengine.core.plugin.event.EventFunctions; import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; @@ -459,7 +459,7 @@ public class BukkitBlockManager extends AbstractBlockManager { } Object eventsObj = ResourceConfigUtils.get(section, "events", "event"); - EnumMap>> events = parseEvents(eventsObj); + EnumMap>> events = EventFunctions.parseEvents(eventsObj); Map behaviors = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false); CustomBlock block = BukkitCustomBlock.builder(id) @@ -513,55 +513,6 @@ public class BukkitBlockManager extends AbstractBlockManager { } } - private EnumMap>> parseEvents(Object eventsObj) { - EnumMap>> events = new EnumMap<>(EventTrigger.class); - if (eventsObj instanceof Map eventsSection) { - Map eventsSectionMap = MiscUtils.castToMap(eventsSection, false); - for (Map.Entry eventEntry : eventsSectionMap.entrySet()) { - try { - EventTrigger eventTrigger = EventTrigger.byName(eventEntry.getKey()); - if (eventEntry.getValue() instanceof List list) { - if (list.size() == 1) { - events.put(eventTrigger, List.of(BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)))); - } else if (list.size() == 2) { - events.put(eventTrigger, List.of( - BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)), - BlockEventFunctions.fromMap(MiscUtils.castToMap(list.get(1), false)) - )); - } else { - List> eventsList = new ArrayList<>(); - for (Object event : list) { - eventsList.add(BlockEventFunctions.fromMap(MiscUtils.castToMap(event, false))); - } - events.put(eventTrigger, eventsList); - } - } else if (eventEntry.getValue() instanceof Map eventSection) { - events.put(eventTrigger, List.of(BlockEventFunctions.fromMap(MiscUtils.castToMap(eventSection, false)))); - } - } catch (IllegalArgumentException e) { - throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", eventEntry.getKey()); - } - } - } else if (eventsObj instanceof List list) { - @SuppressWarnings("unchecked") - List> eventsList = (List>) list; - for (Map eventSection : eventsList) { - Object onObj = eventSection.get("on"); - if (onObj == null) { - throw new LocalizedResourceConfigException("warning.config.event.missing_trigger"); - } - try { - EventTrigger eventTrigger = EventTrigger.byName(onObj.toString()); - Function function = BlockEventFunctions.fromMap(eventSection); - events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(function); - } catch (IllegalArgumentException e) { - throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", onObj.toString()); - } - } - } - return events; - } - private Map> parseProperties(Map propertiesSection) { Map> properties = new HashMap<>(); for (Map.Entry entry : propertiesSection.entrySet()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index 38329375e..5d35be647 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -16,10 +16,15 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.sound.SoundData; 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.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldPosition; import org.bukkit.*; @@ -212,7 +217,8 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager { // get loot table LootTable lootTable = lootMap == null ? null : LootTable.fromMap(lootMap); - CustomFurniture furniture = new CustomFurniture(id, settings, placements, lootTable); + EnumMap>> events = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); + CustomFurniture furniture = new CustomFurniture(id, settings, placements, events, lootTable); byId.put(id, furniture); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java index 93e2ad6db..f3ac95c70 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitCustomItem.java @@ -6,14 +6,15 @@ import net.momirealms.craftengine.bukkit.util.MaterialUtils; import net.momirealms.craftengine.core.item.*; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.util.Key; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; public class BukkitCustomItem implements CustomItem { private final Key id; @@ -26,6 +27,7 @@ public class BukkitCustomItem implements CustomItem { private final NetworkItemDataProcessor[] networkItemDataProcessors; private final List behaviors; private final ItemSettings settings; + private final EnumMap>> events; @SuppressWarnings("unchecked") public BukkitCustomItem(Key id, @@ -34,10 +36,12 @@ public class BukkitCustomItem implements CustomItem { List> modifiers, List> clientBoundModifiers, List behaviors, - ItemSettings settings) { + ItemSettings settings, + EnumMap>> events) { this.id = id; this.material = material; this.materialKey = materialKey; + this.events = events; // unchecked cast this.modifiers = modifiers.toArray(new ItemDataModifier[0]); // unchecked cast @@ -65,6 +69,13 @@ public class BukkitCustomItem implements CustomItem { this.networkItemDataProcessors = networkItemDataProcessors.toArray(new NetworkItemDataProcessor[0]); } + @Override + public void execute(PlayerOptionalContext context, EventTrigger trigger) { + for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { + function.run(context); + } + } + @Override public Key id() { return this.id; @@ -145,6 +156,7 @@ public class BukkitCustomItem implements CustomItem { private Material material; private Key materialKey; private ItemSettings settings; + private EnumMap>> events = new EnumMap<>(EventTrigger.class); private final List behaviors = new ArrayList<>(); private final List> modifiers = new ArrayList<>(); private final List> clientBoundModifiers = new ArrayList<>(); @@ -204,10 +216,16 @@ public class BukkitCustomItem implements CustomItem { return this; } + @Override + public Builder events(EnumMap>> events) { + this.events = events; + return this; + } + @Override public CustomItem build() { this.modifiers.addAll(this.settings.modifiers()); - return new BukkitCustomItem(this.id, this.materialKey, this.material, this.modifiers, this.clientBoundModifiers, this.behaviors, this.settings); + return new BukkitCustomItem(this.id, this.materialKey, this.material, this.modifiers, this.clientBoundModifiers, this.behaviors, this.settings, this.events); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 89798dd29..c4d9295ab 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -33,6 +33,7 @@ import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectPrope import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -357,6 +358,7 @@ public class BukkitItemManager extends AbstractItemManager { itemSettings.canPlaceRelatedVanillaBlock(true); } itemBuilder.settings(itemSettings); + itemBuilder.events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))); CustomItem customItem = itemBuilder.build(); customItems.put(id, customItem); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index 2cf775754..9261ae98d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -247,12 +247,16 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory dyedColor(ComponentItemWrapper item) { if (!item.hasComponent(ComponentTypes.DYED_COLOR)) return Optional.empty(); - return Optional.ofNullable( - (Integer) ComponentType.encodeJava( - ComponentTypes.DYED_COLOR, - item.getComponent(ComponentTypes.DYED_COLOR) - ).orElse(null) - ); + Object javaObj = ComponentType.encodeJava( + ComponentTypes.DYED_COLOR, + item.getComponent(ComponentTypes.DYED_COLOR) + ).orElse(null); + if (javaObj instanceof Integer integer) { + return Optional.of(integer); + } else if (javaObj instanceof Map map) { + return Optional.of((int) map.get("rgb")); + } + return Optional.empty(); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index 424c35b6a..95f404fef 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.plugin.context.CommonParameterProvider; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; @@ -33,6 +34,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; @@ -97,11 +99,10 @@ public class ItemEventListener implements Listener { // run custom functions CustomBlock customBlock = immutableBlockState.owner().value(); PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withParameter(DirectContextParameters.PLAYER, serverPlayer) .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) .withParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) - .withParameter(DirectContextParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT) - .build()); + .withParameter(DirectContextParameters.HAND, hand) + .withParameter(DirectContextParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT)); customBlock.execute(context, EventTrigger.CLICK); if (action.isRightClick()) customBlock.execute(context, EventTrigger.RIGHT_CLICK); else customBlock.execute(context, EventTrigger.LEFT_CLICK); @@ -156,6 +157,18 @@ public class ItemEventListener implements Listener { } } + // execute item functions + if (hasCustomItem) { + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) + .withOptionalParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withParameter(DirectContextParameters.HAND, hand) + .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.RIGHT)); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.CLICK); + customItem.execute(context, EventTrigger.RIGHT_CLICK); + } + // 检查其他的物品行为,物品行为理论只在交互时处理 Optional> optionalItemBehaviors = itemInHand.getItemBehavior(); // 物品类型是否包含自定义物品行为,行为不一定来自于自定义物品,部分原版物品也包含了新的行为 @@ -181,42 +194,83 @@ public class ItemEventListener implements Listener { } } } + + if (hasCustomItem && action == Action.LEFT_CLICK_BLOCK) { + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.BLOCK, new BukkitBlockInWorld(block)) + .withOptionalParameter(DirectContextParameters.BLOCK_STATE, immutableBlockState) + .withParameter(DirectContextParameters.HAND, hand) + .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.LEFT)); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.CLICK); + customItem.execute(context, EventTrigger.LEFT_CLICK); + } } @EventHandler public void onInteractAir(PlayerInteractEvent event) { - if (event.getAction() != Action.RIGHT_CLICK_AIR) + Action action = event.getAction(); + if (action != Action.RIGHT_CLICK_AIR && action != Action.LEFT_CLICK_AIR) return; - Player bukkitPlayer = event.getPlayer(); - BukkitServerPlayer player = this.plugin.adapt(bukkitPlayer); - InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; - if (cancelEventIfHasInteraction(event, player, hand)) { + Player player = event.getPlayer(); + BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + if (serverPlayer.isSpectatorMode()) return; - } - if (player.isSpectatorMode()) { - return; - } - // Gets the item in hand - Item itemInHand = player.getItemInHand(hand); + InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + Item itemInHand = serverPlayer.getItemInHand(hand); // should never be null if (itemInHand == null) return; - Optional> optionalItemBehaviors = itemInHand.getItemBehavior(); - if (optionalItemBehaviors.isPresent()) { - for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) { - InteractionResult result = itemBehavior.use(player.world(), player, hand); - if (result == InteractionResult.SUCCESS_AND_CANCEL) { - event.setCancelled(true); - return; - } - if (result != InteractionResult.PASS) { - return; + if (cancelEventIfHasInteraction(event, serverPlayer, hand)) { + return; + } + + Optional> optionalCustomItem = itemInHand.getCustomItem(); + if (optionalCustomItem.isPresent()) { + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.HAND, hand) + .withParameter(DirectContextParameters.CLICK_TYPE, action.isRightClick() ? ClickType.RIGHT : ClickType.LEFT)); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.CLICK); + if (action.isRightClick()) customItem.execute(context, EventTrigger.RIGHT_CLICK); + else customItem.execute(context, EventTrigger.LEFT_CLICK); + } + + if (action.isRightClick()) { + Optional> optionalItemBehaviors = itemInHand.getItemBehavior(); + if (optionalItemBehaviors.isPresent()) { + for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) { + InteractionResult result = itemBehavior.use(serverPlayer.world(), serverPlayer, hand); + if (result == InteractionResult.SUCCESS_AND_CANCEL) { + event.setCancelled(true); + return; + } + if (result != InteractionResult.PASS) { + return; + } } } } } + @EventHandler(ignoreCancelled = true) + public void onConsumeItem(PlayerItemConsumeEvent event) { + ItemStack consumedItem = event.getItem(); + if (ItemUtils.isEmpty(consumedItem)) return; + Item wrapped = this.plugin.itemManager().wrap(consumedItem); + Optional> optionalCustomItem = wrapped.getCustomItem(); + if (optionalCustomItem.isEmpty()) { + return; + } + CustomItem customItem = optionalCustomItem.get(); + PlayerOptionalContext context = PlayerOptionalContext.of(this.plugin.adapt(event.getPlayer()), ContextHolder.builder() + .withParameter(DirectContextParameters.CONSUMED_ITEM, wrapped) + .withParameter(DirectContextParameters.HAND, event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND) + ); + customItem.execute(context, EventTrigger.CONSUME); + } + private boolean cancelEventIfHasInteraction(PlayerInteractEvent event, BukkitServerPlayer player, InteractionHand hand) { if (hand == InteractionHand.OFF_HAND) { int currentTicks = player.gameTicks(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index cec73f88d..d0326c8cc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -33,12 +33,13 @@ import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.plugin.network.*; import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.world.BlockHitResult; -import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.EntityHitResult; -import net.momirealms.craftengine.core.world.WorldEvents; +import net.momirealms.craftengine.core.world.*; import net.momirealms.craftengine.core.world.chunk.Palette; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; @@ -46,6 +47,7 @@ import net.momirealms.craftengine.core.world.chunk.packet.MCSection; import net.momirealms.craftengine.core.world.collision.AABB; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.*; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; @@ -1688,6 +1690,16 @@ public class PacketConsumers { if (EventUtils.fireAndCheckCancel(breakEvent)) { return; } + + // execute functions + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position())) + .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.LEFT)); + furniture.config().execute(context, EventTrigger.LEFT_CLICK); + furniture.config().execute(context, EventTrigger.CLICK); + furniture.config().execute(context, EventTrigger.BREAK); + CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); } } else if (actionType == Reflections.instance$ServerboundInteractPacket$ActionType$INTERACT_AT) { @@ -1710,6 +1722,14 @@ public class PacketConsumers { return; } + // execute functions + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.POSITION, new WorldPosition(furniture.world(), furniture.position())) + .withParameter(DirectContextParameters.CLICK_TYPE, ClickType.RIGHT)); + furniture.config().execute(context, EventTrigger.RIGHT_CLICK); + furniture.config().execute(context, EventTrigger.CLICK); + if (player.isSneaking()) { // try placing another furniture above it AABB hitBox = furniture.aabbByEntityId(entityId); diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java index cbf5f12c9..8d2d93885 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/CustomFurniture.java @@ -1,12 +1,17 @@ package net.momirealms.craftengine.core.entity.furniture; import net.momirealms.craftengine.core.loot.LootTable; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; +import java.util.Collections; import java.util.EnumMap; +import java.util.List; import java.util.Optional; public class CustomFurniture { @@ -14,20 +19,29 @@ public class CustomFurniture { private final FurnitureSettings settings; private final EnumMap placements; private final AnchorType anyType; + private final EnumMap>> events; @Nullable private final LootTable lootTable; public CustomFurniture(@NotNull Key id, @NotNull FurnitureSettings settings, @NotNull EnumMap placements, + @NotNull EnumMap>> events, @Nullable LootTable lootTable) { this.id = id; this.settings = settings; this.placements = placements; this.lootTable = lootTable; + this.events = events; this.anyType = placements.keySet().stream().findFirst().orElse(null); } + public void execute(PlayerOptionalContext context, EventTrigger trigger) { + for (Function function : Optional.ofNullable(this.events.get(trigger)).orElse(Collections.emptyList())) { + function.run(context); + } + } + public Key id() { return id; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java index b4ff58f2a..b30c543a9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/CustomItem.java @@ -3,11 +3,13 @@ package net.momirealms.craftengine.core.item; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.modifier.ItemDataModifier; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.event.EventTrigger; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; -import java.util.List; -import java.util.Map; +import java.util.*; public interface CustomItem extends BuildableItem { @@ -39,6 +41,8 @@ public interface CustomItem extends BuildableItem { Item buildItem(ItemBuildContext context); + void execute(PlayerOptionalContext context, EventTrigger trigger); + @NotNull List behaviors(); @@ -61,6 +65,8 @@ public interface CustomItem extends BuildableItem { Builder settings(ItemSettings settings); + Builder events(EnumMap>> events); + CustomItem build(); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java index b35bed0ee..fc9b57f60 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/AbstractChainParameterContext.java @@ -14,6 +14,12 @@ public abstract class AbstractChainParameterContext extends AbstractCommonContex CHAIN_PARAMETERS.put(DirectContextParameters.WORLD, new WorldParameterProvider()); CHAIN_PARAMETERS.put(DirectContextParameters.BLOCK, new BlockParameterProvider()); CHAIN_PARAMETERS.put(DirectContextParameters.POSITION, new PositionParameterProvider()); + ItemParameterProvider itemProvider = new ItemParameterProvider(); + CHAIN_PARAMETERS.put(DirectContextParameters.MAIN_HAND_ITEM, itemProvider); + CHAIN_PARAMETERS.put(DirectContextParameters.OFF_HAND_ITEM, itemProvider); + CHAIN_PARAMETERS.put(DirectContextParameters.FURNITURE_ITEM, itemProvider); + CHAIN_PARAMETERS.put(DirectContextParameters.CONSUMED_ITEM, itemProvider); + CHAIN_PARAMETERS.put(DirectContextParameters.TOOL, itemProvider); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java index 6bfc4237e..0d930d0f9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/DirectContextParameters.java @@ -2,11 +2,14 @@ package net.momirealms.craftengine.core.plugin.context.parameter; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.furniture.AnchorType; import net.momirealms.craftengine.core.entity.furniture.Furniture; +import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextKey; import net.momirealms.craftengine.core.util.ClickType; +import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.*; import java.util.UUID; @@ -18,6 +21,8 @@ public final class DirectContextParameters { public static final ContextKey LAST_RANDOM = ContextKey.direct("last_random"); public static final ContextKey WORLD = ContextKey.direct("world"); public static final ContextKey> FURNITURE_ITEM = ContextKey.direct("furniture_item"); + public static final ContextKey> CONSUMED_ITEM = ContextKey.direct("consumed_item"); + public static final ContextKey> TOOL = ContextKey.direct("tool"); public static final ContextKey FALLING_BLOCK = ContextKey.direct("falling_block"); public static final ContextKey EXPLOSION_RADIUS = ContextKey.direct("explosion_radius"); public static final ContextKey PLAYER = ContextKey.direct("player"); @@ -38,5 +43,9 @@ public final class DirectContextParameters { public static final ContextKey CUSTOM_BLOCK = ContextKey.direct("custom_block"); public static final ContextKey BLOCK = ContextKey.direct("block"); public static final ContextKey TIME = ContextKey.direct("time"); + public static final ContextKey ID = ContextKey.direct("id"); + public static final ContextKey CUSTOM_MODEL_DATA = ContextKey.direct("custom_model_data"); public static final ContextKey FURNITURE = ContextKey.direct("furniture"); + public static final ContextKey ANCHOR_TYPE = ContextKey.direct("anchor_type"); + public static final ContextKey HAND = ContextKey.direct("hand"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java new file mode 100644 index 000000000..8557ea408 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/ItemParameterProvider.java @@ -0,0 +1,25 @@ +package net.momirealms.craftengine.core.plugin.context.parameter; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; +import net.momirealms.craftengine.core.plugin.context.ContextKey; +import net.momirealms.craftengine.core.world.World; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +public class ItemParameterProvider implements ChainParameterProvider> { + private static final Map, Function, Object>> CONTEXT_FUNCTIONS = new HashMap<>(); + static { + CONTEXT_FUNCTIONS.put(DirectContextParameters.ID, Item::id); + CONTEXT_FUNCTIONS.put(DirectContextParameters.CUSTOM_MODEL_DATA, i -> i.customModelData().orElse(null)); + } + + @SuppressWarnings("unchecked") + @Override + public Optional getOptionalParameter(ContextKey parameter, Item world) { + return (Optional) Optional.ofNullable(CONTEXT_FUNCTIONS.get(parameter)).map(f -> f.apply(world)); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java index cacf39e98..ddc921a0a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/WorldParameterProvider.java @@ -14,6 +14,7 @@ public class WorldParameterProvider implements ChainParameterProvider { static { CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, World::name); CONTEXT_FUNCTIONS.put(DirectContextParameters.TIME, World::time); + CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, World::uuid); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java deleted file mode 100644 index 21f735b3c..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventFunctions.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.momirealms.craftengine.core.plugin.event; - -import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.function.CommandFunction; -import net.momirealms.craftengine.core.plugin.context.function.CommonFunctions; -import net.momirealms.craftengine.core.plugin.context.function.Function; -import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; -import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.registry.BuiltInRegistries; -import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.registry.Registries; -import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.ResourceKey; - -import java.util.Map; - -public class BlockEventFunctions { - - static { - register(CommonFunctions.COMMAND, new CommandFunction.FactoryImpl<>(BlockEventConditions::fromMap)); - } - - public static void register(Key key, FunctionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.PLAYER_BLOCK_FUNCTION_FACTORY.location(), key)); - holder.bindValue(factory); - } - - public static Function fromMap(Map map) { - String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "TODO I18N"); - Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); - FunctionFactory factory = BuiltInRegistries.PLAYER_BLOCK_FUNCTION_FACTORY.getValue(key); - if (factory == null) { - throw new LocalizedResourceConfigException("TODO I18N", type); - } - return factory.create(map); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java similarity index 81% rename from core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java rename to core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java index 146afc563..c55f3cf4f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/BlockEventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventConditions.java @@ -14,17 +14,17 @@ import net.momirealms.craftengine.core.util.ResourceKey; import java.util.Map; -public class BlockEventConditions { +public class EventConditions { static { register(CommonConditions.MATCH_ITEM, new MatchItemCondition.FactoryImpl<>()); register(CommonConditions.MATCH_BLOCK_PROPERTY, new MatchBlockPropertyCondition.FactoryImpl<>()); register(CommonConditions.TABLE_BONUS, new TableBonusCondition.FactoryImpl<>()); register(CommonConditions.SURVIVES_EXPLOSION, new SurvivesExplosionCondition.FactoryImpl<>()); - register(CommonConditions.ANY_OF, new AnyOfCondition.FactoryImpl<>(BlockEventConditions::fromMap)); - register(CommonConditions.ALL_OF, new AllOfCondition.FactoryImpl<>(BlockEventConditions::fromMap)); + register(CommonConditions.ANY_OF, new AnyOfCondition.FactoryImpl<>(EventConditions::fromMap)); + register(CommonConditions.ALL_OF, new AllOfCondition.FactoryImpl<>(EventConditions::fromMap)); register(CommonConditions.ENCHANTMENT, new EnchantmentCondition.FactoryImpl<>()); - register(CommonConditions.INVERTED, new InvertedCondition.FactoryImpl<>(BlockEventConditions::fromMap)); + register(CommonConditions.INVERTED, new InvertedCondition.FactoryImpl<>(EventConditions::fromMap)); register(CommonConditions.FALLING_BLOCK, new FallingBlockCondition.FactoryImpl<>()); register(CommonConditions.RANDOM, new RandomCondition.FactoryImpl<>()); register(CommonConditions.DISTANCE, new DistanceCondition.FactoryImpl<>()); @@ -32,24 +32,24 @@ public class BlockEventConditions { } public static void register(Key key, ConditionFactory factory) { - Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY) - .registerForHolder(new ResourceKey<>(Registries.PLAYER_BLOCK_CONDITION_FACTORY.location(), key)); + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.EVENT_CONDITION_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.EVENT_CONDITION_FACTORY.location(), key)); holder.bindValue(factory); } public static Condition fromMap(Map map) { - String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.block.event.condition.missing_type"); + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.event.condition.missing_type"); Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); if (key.value().charAt(0) == '!') { - ConditionFactory factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); + ConditionFactory factory = BuiltInRegistries.EVENT_CONDITION_FACTORY.getValue(new Key(key.namespace(), key.value().substring(1))); if (factory == null) { - throw new LocalizedResourceConfigException("warning.config.block.event.condition.invalid_type", type); + throw new LocalizedResourceConfigException("warning.config.event.condition.invalid_type", type); } return new InvertedCondition<>(factory.create(map)); } else { - ConditionFactory factory = BuiltInRegistries.PLAYER_BLOCK_CONDITION_FACTORY.getValue(key); + ConditionFactory factory = BuiltInRegistries.EVENT_CONDITION_FACTORY.getValue(key); if (factory == null) { - throw new LocalizedResourceConfigException("warning.config.block.event.condition.invalid_type", type); + throw new LocalizedResourceConfigException("warning.config.event.condition.invalid_type", type); } return factory.create(map); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java new file mode 100644 index 000000000..91dc5df2a --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventFunctions.java @@ -0,0 +1,101 @@ +package net.momirealms.craftengine.core.plugin.event; + +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.CommandFunction; +import net.momirealms.craftengine.core.plugin.context.function.CommonFunctions; +import net.momirealms.craftengine.core.plugin.context.function.Function; +import net.momirealms.craftengine.core.plugin.context.function.FunctionFactory; +import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.registry.Registries; +import net.momirealms.craftengine.core.registry.WritableRegistry; +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.util.ResourceKey; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +public class EventFunctions { + + static { + register(CommonFunctions.COMMAND, new CommandFunction.FactoryImpl<>(EventConditions::fromMap)); + } + + public static void register(Key key, FunctionFactory factory) { + Holder.Reference> holder = ((WritableRegistry>) BuiltInRegistries.EVENT_FUNCTION_FACTORY) + .registerForHolder(new ResourceKey<>(Registries.EVENT_FUNCTION_FACTORY.location(), key)); + holder.bindValue(factory); + } + + public static Function fromMap(Map map) { + String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.function.missing_type"); + Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); + FunctionFactory factory = BuiltInRegistries.EVENT_FUNCTION_FACTORY.getValue(key); + if (factory == null) { + throw new LocalizedResourceConfigException("warning.config.function.invalid_type", type); + } + return factory.create(map); + } + + public static EnumMap>> parseEvents(Object eventsObj) { + EnumMap>> events = new EnumMap<>(EventTrigger.class); + if (eventsObj instanceof Map eventsSection) { + Map eventsSectionMap = MiscUtils.castToMap(eventsSection, false); + for (Map.Entry eventEntry : eventsSectionMap.entrySet()) { + try { + EventTrigger eventTrigger = EventTrigger.byName(eventEntry.getKey()); + if (eventEntry.getValue() instanceof List list) { + if (list.size() == 1) { + events.put(eventTrigger, List.of(EventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)))); + } else if (list.size() == 2) { + events.put(eventTrigger, List.of( + EventFunctions.fromMap(MiscUtils.castToMap(list.get(0), false)), + EventFunctions.fromMap(MiscUtils.castToMap(list.get(1), false)) + )); + } else { + List> eventsList = new ArrayList<>(); + for (Object event : list) { + eventsList.add(EventFunctions.fromMap(MiscUtils.castToMap(event, false))); + } + events.put(eventTrigger, eventsList); + } + } else if (eventEntry.getValue() instanceof Map eventSection) { + events.put(eventTrigger, List.of(EventFunctions.fromMap(MiscUtils.castToMap(eventSection, false)))); + } + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", eventEntry.getKey()); + } + } + } else if (eventsObj instanceof List list) { + @SuppressWarnings("unchecked") + List> eventsList = (List>) list; + for (Map eventSection : eventsList) { + Object onObj = eventSection.get("on"); + if (onObj == null) { + throw new LocalizedResourceConfigException("warning.config.event.missing_trigger"); + } + try { + EventTrigger eventTrigger = EventTrigger.byName(onObj.toString()); + if (eventSection.containsKey("type")) { + Function function = EventFunctions.fromMap(eventSection); + events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(function); + } else if (eventSection.containsKey("functions")) { + @SuppressWarnings("unchecked") + List> functionList = (List>) eventSection.get("functions"); + for (Map function : functionList) { + events.computeIfAbsent(eventTrigger, k -> new ArrayList<>(4)).add(EventFunctions.fromMap(function)); + } + } + } catch (IllegalArgumentException e) { + throw new LocalizedResourceConfigException("warning.config.event.invalid_trigger", onObj.toString()); + } + } + } + return events; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java index 7e9ef2820..72dd20745 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/event/EventTrigger.java @@ -9,7 +9,8 @@ public enum EventTrigger { LEFT_CLICK("attack", "left_click"), RIGHT_CLICK("right_click", "use_on", "use", "use_item_on"), CONSUME("eat", "consume", "drink"), - BREAK("break", "dig"),; + BREAK("break", "dig"), + PLACE("place", "build"),; public static final Map BY_NAME = new HashMap<>(); private final String[] names; diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java index 70a3666b1..708f00d80 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/BuiltInRegistries.java @@ -52,8 +52,8 @@ public class BuiltInRegistries { public static final Registry SMITHING_RESULT_PROCESSOR_FACTORY = createRegistry(Registries.SMITHING_RESULT_PROCESSOR_FACTORY); public static final Registry HITBOX_FACTORY = createRegistry(Registries.HITBOX_FACTORY); public static final Registry RESOURCE_PACK_HOST_FACTORY = createRegistry(Registries.RESOURCE_PACK_HOST_FACTORY); - public static final Registry> PLAYER_BLOCK_FUNCTION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_FUNCTION_FACTORY); - public static final Registry> PLAYER_BLOCK_CONDITION_FACTORY = createRegistry(Registries.PLAYER_BLOCK_CONDITION_FACTORY); + public static final Registry> EVENT_FUNCTION_FACTORY = createRegistry(Registries.EVENT_FUNCTION_FACTORY); + public static final Registry> EVENT_CONDITION_FACTORY = createRegistry(Registries.EVENT_CONDITION_FACTORY); private static Registry createRegistry(ResourceKey> key) { return new MappedRegistry<>(key); diff --git a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java index e8b6abaeb..5d0ab47b6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/Registries.java @@ -53,6 +53,6 @@ public class Registries { public static final ResourceKey> SMITHING_RESULT_PROCESSOR_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("smithing_result_processor_factory")); public static final ResourceKey> HITBOX_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("hitbox_factory")); public static final ResourceKey> RESOURCE_PACK_HOST_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("resource_pack_host_factory")); - public static final ResourceKey>> PLAYER_BLOCK_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_function_factory")); - public static final ResourceKey>> PLAYER_BLOCK_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_condition_factory")); + public static final ResourceKey>> EVENT_FUNCTION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_function_factory")); + public static final ResourceKey>> EVENT_CONDITION_FACTORY = new ResourceKey<>(ROOT_REGISTRY, Key.withDefaultNamespace("player_block_condition_factory")); } diff --git a/gradle.properties b/gradle.properties index 31dd432b9..8a3975c14 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.53.6 +project_version=0.0.53.7 config_version=32 lang_version=12 project_group=net.momirealms