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 78ea579f3..4863daacb 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 @@ -31,6 +31,7 @@ import net.momirealms.craftengine.core.util.Tristate; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.Registry; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -416,19 +417,26 @@ public final class BukkitBlockManager extends AbstractBlockManager { @SuppressWarnings("unchecked") private void deceiveBukkitRegistry() { try { - Material material; - try { - material = Material.valueOf(Config.deceiveBukkitMaterial().value().toUpperCase(Locale.ROOT)); - } catch (IllegalArgumentException e) { - this.plugin.logger().warn(Config.deceiveBukkitMaterial() + " is not a valid material", e); - material = Material.STONE; - } - if (!material.isBlock()) { - this.plugin.logger().warn(Config.deceiveBukkitMaterial() + " is not a valid bukkit block material"); - material = Material.STONE; - } Map magicMap = (Map) CraftBukkitReflections.field$CraftMagicNumbers$BLOCK_MATERIAL.get(null); - for (DelegatingBlock customBlock : this.customBlocks) { + Set invalid = new HashSet<>(); + for (int i = 0; i < this.customBlocks.length; i++) { + DelegatingBlock customBlock = this.customBlocks[i]; + String value = Config.deceiveBukkitMaterial(i).value(); + Material material; + try { + material = Material.valueOf(value.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException e) { + if (invalid.add(value)) { + this.plugin.logger().warn("Cannot load 'deceive-bukkit-material'. '" + value + "' is an invalid bukkit material", e); + } + material = Material.BRICKS; + } + if (!material.isBlock()) { + if (invalid.add(value)) { + this.plugin.logger().warn("Cannot load 'deceive-bukkit-material'. '" + value + "' is an invalid bukkit block material"); + } + material = Material.BRICKS; + } magicMap.put(customBlock, material); } } catch (ReflectiveOperationException e) { diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index f2f55ecfd..2f76bcea0 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -13,57 +13,6 @@ resource-pack: # This option determines the location of the generated resource pack # You can use either an absolute path or a relative path here path: "./generated/resource_pack.zip" - # Should those images in minecraft:default font also work in minecraft:uniform - override-uniform-font: true - # Generate assets for CraftEngine fabric mod - # Note: fabric mod is used for clientside Axiom/WorldEdit mod - generate-mod-assets: false - # Resource pack protection - protection: - # Warning: Do not attempt to unzip the resource pack with crash tools enabled. - # You can enable all the methods at the same time. - crash-tools: - method-1: false - method-2: false - method-3: false # Enable this would increase the resource pack size by 0.67MB - # [Premium Exclusive] - # Obfuscate your resource pack - obfuscation: - enable: false - seed: 0 # 0 = random seed - fake-directory: false - escape-unicode: false - resource-location: - enable: true - random-namespace: - amount: 16 # 0 = disable - length: 9 - random-path: - source: obf - depth: 16 - anti-unzip: false - random-atlas: - images-per-canvas: 32 # 0 = disable - # Sometimes, some vanilla files that have been overwritten might be mistakenly obfuscated. - # Please add the ignored textures/models/sounds here. - bypass-textures: - # - minecraft:block/farmland - - "@legacy_unicode" - - "@vanilla_textures" - bypass-models: - - "@vanilla_models" - bypass-sounds: [] - bypass-equipments: [] - # Validate if there is any error in the resource pack, such as missing textures or models - # If your resource pack is compliant with the standard, you can disable validation to improve the resource pack generation speed. - validation: - enable: true - # [Premium Exclusive] - # Fix images that are not within the texture atlas. It is unreasonable to always rely on plugins to fix your mistakes. - # You should strive to make your resource pack more standardized after gaining some experience with resource packs. - fix-atlas: true - # Define the name of the overlay folders - overlay-format: "ce_overlay_{version}" # Allowed values: # - 1.20.1, 1.21, 1.21.8, etc. # - LATEST: the latest client version @@ -73,42 +22,24 @@ resource-pack: max: LATEST # Remove 1.21.5+ tinted_leaves particles remove-tinted-leaves-particle: true + # Define the name of the overlay folders + overlay-format: "ce_overlay_{version}" + # Should those images in minecraft:default font also work in minecraft:uniform + override-uniform-font: true + # Generate assets for CraftEngine fabric mod + # Note: fabric mod is used for clientside Axiom/WorldEdit mod + generate-mod-assets: false + # Exclude the shaders when generating the resource pack + exclude-core-shaders: false + # Merge other packs merge-external-folders: - "ModelEngine/resource pack" merge-external-zip-files: - "CustomNameplates/resourcepack.zip" - "BetterModel/build.zip" exclude-file-extensions: ["md", "psd", "bbmodel", "db", "ini", "DS_Store"] - # Exclude the shaders when generating the resource pack - exclude-core-shaders: false - delivery: - # Send the resource pack on joining the server - send-on-join: true - kick-if-declined: true - kick-if-failed-to-apply: false - prompt: "To fully experience our server,please accept our custom resource pack." - # If you are hosting the resource pack by yourself, replace `localhost` with your server ip otherwise it would only work on your local pc - # If using BungeeCord or Velocity, consider using a proxy-side plugin to handle resource pack delivery. - # Read this page for more host types: https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host - hosting: - - type: "self" - ip: "localhost" - port: 8163 - protocol: "http" - deny-non-minecraft-request: true - one-time-token: true - rate-limit: - max-requests: 10 - reset-interval: 30 - # Upload the resource pack automatically on generation - # When disabled, you must manually trigger uploads using the /ce upload command - auto-upload: true - # The file to upload - file-to-upload: "./generated/resource_pack.zip" - # Resend the resource pack to players upon successful upload - resend-on-upload: true - # Whether a verified player UUID is required to get the resource pack - strict-player-uuid-validation: true + # Provide the solution for when a file conflict is encountered + # https://xiao-momi.github.io/craft-engine-wiki/reference/file_conflict duplicated-files-handler: - term: type: any_of @@ -150,6 +81,88 @@ resource-pack: suffix: "minecraft/atlases" resolution: type: merge_atlas + # Validate if there is any error in the resource pack, such as missing textures or models + # If your resource pack is compliant with the standard, you can disable validation to improve the resource pack generation speed. + validation: + enable: true + # [Premium Exclusive] + # Fix images that are not within the texture atlas. It is unreasonable to always rely on plugins to fix your mistakes. + # You should strive to make your resource pack more standardized after gaining some experience with resource packs. + fix-atlas: true + # Optimize your resource pack by reducing its size +# optimization: +# enable: true +# png: +# color-quantization: true +# lossless-bit-depth: true +# remove-metadata: true +# model: +# minimize: true +# bypass-textures: [] + # Protect your resource pack from being cracked by others + protection: + # Prevent thieves from extracting your resource pack. These options will crash their software. + crash-tools: + method-1: false + method-2: false + method-3: false # Enable this would increase the resource pack size by 0.67MB + # [Premium Exclusive] + # Obfuscate your resource pack to prevent thieves from restoring its original structure + obfuscation: + enable: false + seed: 0 # 0 = random seed + fake-directory: false # Create fake folders to deceive thieves + escape-unicode: false # Escape the JSON to make it human-unreadable + resource-location: + enable: true + random-namespace: + amount: 8 # 0 = disable + length: 9 + random-path: + source: obf + depth: 8 + anti-unzip: false + random-atlas: + images-per-canvas: 256 # 0 = disable + # Sometimes, some vanilla files that have been overwritten might be mistakenly obfuscated + # Please add the ignored textures/models/sounds here if that happens + bypass-textures: + # - minecraft:block/farmland + - "@legacy_unicode" + - "@vanilla_textures" + bypass-models: + - "@vanilla_models" + bypass-sounds: [] + bypass-equipments: [] + # This section controls how to send the resource pack to players + delivery: + # Send the resource pack on joining the server + send-on-join: true + kick-if-declined: true + kick-if-failed-to-apply: false + prompt: "To fully experience our server,please accept our custom resource pack." + # Whether a verified player UUID is required to download the resource pack + strict-player-uuid-validation: true + # Upload the resource pack automatically on generation + # When disabled, you must manually trigger uploads using the /ce upload command + auto-upload: true + # Resend the resource pack to players upon successful upload + resend-on-upload: true + # The file to upload + file-to-upload: "./generated/resource_pack.zip" + # If you are hosting the resource pack by yourself, replace `localhost` with your server ip otherwise it would only work on your local pc + # If using BungeeCord or Velocity, consider using a proxy-side plugin to handle resource pack delivery. + # Read this page for more host types: https://xiao-momi.github.io/craft-engine-wiki/getting_start/set_up_host + hosting: + - type: "self" + ip: "localhost" + port: 8163 + protocol: "http" + deny-non-minecraft-request: true + one-time-token: true + rate-limit: + max-requests: 10 + reset-interval: 30 item: # [Premium Exclusive] @@ -208,7 +221,7 @@ equipment: block: # This decides the amount of real blocks on serverside. You should only consider increasing this value when your server state is insufficient. - # It is recommended to increase it by 500 each time. This option requires a restart to apply. + # It is recommended to increase it by 1000 each time. This option requires a restart to apply. serverside-blocks: 2000 # Enables the sound system, which prevents the client from hearing some non-custom block sounds and improves the client experience. sound-system: @@ -238,7 +251,14 @@ block: extended-interaction-range: 0.5 # Defines the value returned by Bukkit block.getMaterial() # If another plugin causes incompatibility due to its reliance on this method, try changing this option to a different vanilla block. - deceive-bukkit-material: stone + deceive-bukkit-material: + default: bricks + # The numbers here represent the internal real IDs of the blocks. + # This means that overriding certain blocks needs to be done under the condition of forcibly assigning internal IDs. + # A restart is required to apply the changes. + overrides: + 0: bricks + 1~8: bricks furniture: # Hide technical entities used for storing furniture metadata. diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml b/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml index 1966ea9b1..0847ee653 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml @@ -64,11 +64,8 @@ blocks: - type: match_block_property properties: age: 2 - - type: '!is_null' - argument: item_in_hand - - type: equals - value1: - value2: default:ender_pearl_flower_seeds + - type: match_item + id: default:ender_pearl_flower_seeds functions: - type: break_block x: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/magma_plant.yml b/common-files/src/main/resources/resources/default/configuration/blocks/magma_plant.yml index 6161f21e8..7eb0e196b 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/magma_plant.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/magma_plant.yml @@ -132,10 +132,9 @@ blocks: - type: match_block_property properties: age: 3 - - type: 'is_null' - argument: item_in_hand - type: hand hand: main_hand + - type: '!has_item' functions: - type: break_block x: diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 7ebdaae1c..9ebd2a6fb 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -472,6 +472,10 @@ warning.config.function.toast.invalid_advancement_type: "Issue found in warning.config.function.merchant_trade.missing_offers: "Issue found in file - The config '' is missing the required 'offers' argument for 'merchant_trade' function." warning.config.function.merchant_trade.offer.missing_cost_1: "Issue found in file - The config '' is missing the required 'cost-1' argument for merchant trade offers." warning.config.function.merchant_trade.offer.missing_result: "Issue found in file - The config '' is missing the required 'result' argument for merchant trade offers." +warning.config.function.when.missing_source: "Issue found in file - The config '' is missing the required 'source' argument for 'when' function." +warning.config.function.if_else.missing_rules: "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.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/core/build.gradle.kts b/core/build.gradle.kts index 9efbbf559..9ad35c52d 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -21,7 +21,7 @@ dependencies { implementation("net.momirealms:sparrow-nbt-codec:${rootProject.properties["sparrow_nbt_version"]}") implementation("net.momirealms:sparrow-nbt-legacy-codec:${rootProject.properties["sparrow_nbt_version"]}") // S3 - implementation("net.momirealms:craft-engine-s3:0.7") + implementation("net.momirealms:craft-engine-s3:0.8") // Util compileOnly("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}") // Adventure diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java index 48a06d68d..eea0f0f4b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootConditions.java @@ -25,6 +25,7 @@ public class LootConditions { register(CommonConditions.ANY_OF, new AnyOfCondition.FactoryImpl<>(LootConditions::fromMap)); register(CommonConditions.ALL_OF, new AllOfCondition.FactoryImpl<>(LootConditions::fromMap)); register(CommonConditions.HAS_PLAYER, new HasPlayerCondition.FactoryImpl<>()); + register(CommonConditions.HAS_ITEM, new HasItemCondition.FactoryImpl<>()); register(CommonConditions.ENCHANTMENT, new EnchantmentCondition.Factory<>()); register(CommonConditions.INVERTED, new InvertedCondition.FactoryImpl<>(LootConditions::fromMap)); register(CommonConditions.FALLING_BLOCK, new FallingBlockCondition.FactoryImpl<>()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AlternativesLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AlternativesLootEntryContainer.java index 9ed2f42e4..18cb4ff0b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AlternativesLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AlternativesLootEntryContainer.java @@ -4,6 +4,7 @@ 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.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.*; @@ -40,7 +41,7 @@ public class AlternativesLootEntryContainer extends AbstractCompositeLootEntr @SuppressWarnings("unchecked") @Override public LootEntryContainer create(Map arguments) { - List> containers = Optional.ofNullable(arguments.get("children")) + List> containers = Optional.ofNullable(ResourceConfigUtils.get(arguments, "children", "terms", "branches")) .map(it -> (List>) new ArrayList>(LootEntryContainers.fromMapList((List>) it))) .orElse(Collections.emptyList()); List> conditions = Optional.ofNullable(arguments.get("conditions")) diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java index d2d8abaeb..82c667a40 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/LootEntryContainers.java @@ -14,12 +14,14 @@ import java.util.Map; public class LootEntryContainers { public static final Key ALTERNATIVES = Key.from("craftengine:alternatives"); + public static final Key IF_ELSE = Key.from("craftengine:if_else"); public static final Key ITEM = Key.from("craftengine:item"); public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item"); public static final Key EXP = Key.from("craftengine:exp"); static { register(ALTERNATIVES, AlternativesLootEntryContainer.FACTORY); + register(IF_ELSE, AlternativesLootEntryContainer.FACTORY); register(ITEM, SingleItemLootEntryContainer.FACTORY); register(EXP, ExpLootEntryContainer.FACTORY); register(FURNITURE_ITEM, FurnitureItemLootEntryContainer.FACTORY); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index 05ada618e..f6034b052 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -126,7 +126,8 @@ public class Config { protected int block$predict_breaking_interval; protected double block$extended_interaction_range; protected boolean block$chunk_relighter; - protected Key block$deceive_bukkit_material; + protected Key block$deceive_bukkit_material$default; + protected Map block$deceive_bukkit_material$overrides; protected int block$serverside_blocks = -1; protected boolean recipe$enable; @@ -250,6 +251,7 @@ public class Config { .addIgnoredRoute(PluginProperties.getValue("config"), "chunk-system.process-invalid-blocks.convert", '.') .addIgnoredRoute(PluginProperties.getValue("config"), "chunk-system.process-invalid-furniture.convert", '.') .addIgnoredRoute(PluginProperties.getValue("config"), "item.custom-model-data-starting-value.overrides", '.') + .addIgnoredRoute(PluginProperties.getValue("config"), "block.deceive-bukkit-material.overrides", '.') .build()); } try { @@ -439,8 +441,25 @@ public class Config { block$predict_breaking_interval = Math.max(config.getInt("block.predict-breaking.interval", 10), 1); block$extended_interaction_range = Math.max(config.getDouble("block.predict-breaking.extended-interaction-range", 0.5), 0.0); block$chunk_relighter = config.getBoolean("block.chunk-relighter", true); - block$deceive_bukkit_material = Key.of(config.getString("block.deceive-bukkit-material", "stone")); if (firstTime) { + block$deceive_bukkit_material$default = Key.of(config.getString("block.deceive-bukkit-material.default", "bricks")); + block$deceive_bukkit_material$overrides = new HashMap<>(); + Section overridesSection = config.getSection("block.deceive-bukkit-material.overrides"); + if (overridesSection != null) { + for (Map.Entry entry : overridesSection.getStringRouteMappedValues(false).entrySet()) { + String key = entry.getKey(); + Key value = Key.of(String.valueOf(entry.getValue())); + if (key.contains("~")) { + int min = Integer.parseInt(key.split("~")[0]); + int max = Integer.parseInt(key.split("~")[1]); + for (int i = min; i <= max; i++) { + block$deceive_bukkit_material$overrides.put(i, value); + } + } else { + block$deceive_bukkit_material$overrides.put(Integer.valueOf(key), value); + } + } + } block$serverside_blocks = Math.min(config.getInt("block.serverside-blocks", 2000), 10_0000); if (block$serverside_blocks < 0) block$serverside_blocks = 0; } @@ -774,8 +793,8 @@ public class Config { return instance.resource_pack$protection$obfuscation$resource_location$bypass_equipments; } - public static Key deceiveBukkitMaterial() { - return instance.block$deceive_bukkit_material; + public static Key deceiveBukkitMaterial(int id) { + return instance.block$deceive_bukkit_material$overrides.getOrDefault(id, instance.block$deceive_bukkit_material$default); } public static boolean generateModAssets() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java index ea6b27e80..991ea9e0a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/CommonConditions.java @@ -11,6 +11,7 @@ public final class CommonConditions { public static final Key ANY_OF = Key.of("craftengine:any_of"); public static final Key INVERTED = Key.of("craftengine:inverted"); public static final Key MATCH_ITEM = Key.of("craftengine:match_item"); + public static final Key HAS_ITEM = Key.of("craftengine:has_item"); public static final Key MATCH_ENTITY = Key.of("craftengine:match_entity"); public static final Key MATCH_BLOCK = Key.of("craftengine:match_block"); public static final Key MATCH_BLOCK_PROPERTY = Key.from("craftengine:match_block_property"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HasItemCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HasItemCondition.java new file mode 100644 index 000000000..213ffd206 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HasItemCondition.java @@ -0,0 +1,38 @@ +package net.momirealms.craftengine.core.plugin.context.condition; + +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.ItemUtils; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Map; +import java.util.Optional; + +public class HasItemCondition implements Condition { + + public HasItemCondition() { + } + + @Override + public Key type() { + return CommonConditions.HAS_ITEM; + } + + @Override + public boolean test(CTX ctx) { + Optional> item = ctx.getOptionalParameter(DirectContextParameters.ITEM_IN_HAND); + if (item.isEmpty()) return false; + Item itemInHand = item.get(); + return !ItemUtils.isEmpty(itemInHand); + } + + public static class FactoryImpl implements ConditionFactory { + + @Override + public Condition create(Map arguments) { + return new HasItemCondition<>(); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HasPlayerCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HasPlayerCondition.java index 580a34b95..69d6f211e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HasPlayerCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/HasPlayerCondition.java @@ -14,7 +14,7 @@ public class HasPlayerCondition implements Condition { @Override public Key type() { - return CommonConditions.IS_NULL; + return CommonConditions.HAS_PLAYER; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java index f6c7f78a8..ae467cf1b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchItemCondition.java @@ -35,7 +35,7 @@ public class MatchItemCondition implements Condition { @Override public Condition create(Map arguments) { - List ids = MiscUtils.getAsStringList(arguments.get("id")); + List ids = MiscUtils.getAsStringList(ResourceConfigUtils.get(arguments, "id", "item")); if (ids.isEmpty()) { throw new LocalizedResourceConfigException("warning.config.condition.match_item.missing_id"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java index e6cd3a304..6e34277e6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/event/EventConditions.java @@ -17,6 +17,7 @@ public class EventConditions { static { register(CommonConditions.HAS_PLAYER, new HasPlayerCondition.FactoryImpl<>()); + register(CommonConditions.HAS_ITEM, new HasItemCondition.FactoryImpl<>()); register(CommonConditions.MATCH_ITEM, new MatchItemCondition.FactoryImpl<>()); register(CommonConditions.MATCH_ENTITY, new MatchEntityCondition.FactoryImpl<>()); register(CommonConditions.MATCH_BLOCK, new MatchBlockCondition.FactoryImpl<>()); 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 4646eeb92..16cadd38a 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 @@ -24,6 +24,8 @@ public class EventFunctions { register(CommonFunctions.CANCEL_EVENT, new CancelEventFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.RUN, new RunFunction.FactoryImpl<>(EventFunctions::fromMap, EventConditions::fromMap)); register(CommonFunctions.PLACE_BLOCK, new PlaceBlockFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.UPDATE_BLOCK_PROPERTY, new UpdateBlockPropertyFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.TRANSFORM_BLOCK, new TransformBlockFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.BREAK_BLOCK, new BreakBlockFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.UPDATE_INTERACTION_TICK, new UpdateInteractionFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.SET_COUNT, new SetCountFunction.FactoryImpl<>(EventConditions::fromMap)); @@ -48,6 +50,9 @@ public class EventFunctions { register(CommonFunctions.DAMAGE, new DamageFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.MERCHANT_TRADE, new MerchantTradeFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.REMOVE_ENTITY, new RemoveEntityFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.IF_ELSE, new IfElseFunction.FactoryImpl<>(EventConditions::fromMap, EventFunctions::fromMap)); + register(CommonFunctions.ALTERNATIVES, new IfElseFunction.FactoryImpl<>(EventConditions::fromMap, EventFunctions::fromMap)); + register(CommonFunctions.WHEN, new WhenFunction.FactoryImpl<>(EventConditions::fromMap, EventFunctions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java index 4c20d65a7..1f90610f2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java @@ -28,29 +28,73 @@ public abstract class AbstractConditionalFunction implement protected abstract void runInternal(CTX ctx); public static abstract class AbstractFactory implements FunctionFactory { - private final java.util.function.Function, Condition> factory; + protected final java.util.function.Function, Condition> conditionFactory; - public AbstractFactory(java.util.function.Function, Condition> factory) { - this.factory = factory; + public AbstractFactory(java.util.function.Function, Condition> conditionFactory) { + this.conditionFactory = conditionFactory; } public java.util.function.Function, Condition> conditionFactory() { - return factory; + return this.conditionFactory; } protected List> getPredicates(Map arguments) { + if (arguments == null) return List.of(); Object predicates = arguments.get("conditions"); if (predicates == null) return List.of(); - if (predicates instanceof List list) { - List> conditions = new ArrayList<>(list.size()); - for (Object o : list) { - conditions.add(factory.apply(MiscUtils.castToMap(o, false))); + switch (predicates) { + case List list -> { + List> conditions = new ArrayList<>(list.size()); + for (Object o : list) { + conditions.add(this.conditionFactory.apply(MiscUtils.castToMap(o, false))); + } + return conditions; + } + case Map map -> { + return List.of(this.conditionFactory.apply(MiscUtils.castToMap(map, false))); + } + default -> { + return List.of(); + } + } + } + } + + public static abstract class AbstractFunctionalFactory extends AbstractFactory { + protected final java.util.function.Function, Function> functionFactory; + + public AbstractFunctionalFactory(java.util.function.Function, Condition> factory, java.util.function.Function, Function> functionFactory) { + super(factory); + this.functionFactory = functionFactory; + } + + public java.util.function.Function, Function> functionFactory() { + return functionFactory; + } + + protected List> getFunctions(Map arguments) { + if (arguments == null) return List.of(); + Object functions = arguments.get("functions"); + return parseFunctions(functions); + } + + protected List> parseFunctions(Object functions) { + if (functions == null) return List.of(); + switch (functions) { + case List list -> { + List> conditions = new ArrayList<>(list.size()); + for (Object o : list) { + conditions.add(this.functionFactory.apply(MiscUtils.castToMap(o, false))); + } + return conditions; + } + case Map map -> { + return List.of(this.functionFactory.apply(MiscUtils.castToMap(map, false))); + } + default -> { + return List.of(); } - return conditions; - } else if (predicates instanceof Map map) { - return List.of(factory.apply(MiscUtils.castToMap(map, false))); } - throw new UnsupportedOperationException("Unsupported conditions argument class type: " + predicates.getClass().getSimpleName()); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AllOfFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AllOfFunction.java new file mode 100644 index 000000000..1f2810c24 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AllOfFunction.java @@ -0,0 +1,31 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Collection; + +public class AllOfFunction implements Function { + private final Function[] functions; + + public AllOfFunction(Function[] functions) { + this.functions = functions; + } + + @SuppressWarnings("unchecked") + public AllOfFunction(Collection> functions) { + this.functions = functions.toArray(new Function[0]); + } + + @Override + public void run(CTX ctx) { + for (Function function : this.functions) { + function.run(ctx); + } + } + + @Override + public Key type() { + return CommonFunctions.ALL_OF; + } +} 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 ce9dff89a..a9be4559c 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 @@ -20,6 +20,8 @@ public final class CommonFunctions { public static final Key UPDATE_INTERACTION_TICK = Key.of("craftengine:update_interaction_tick"); public static final Key SET_COUNT = Key.of("craftengine:set_count"); public static final Key PLACE_BLOCK = Key.of("craftengine:place_block"); + public static final Key TRANSFORM_BLOCK = Key.of("craftengine:transform_block"); + public static final Key UPDATE_BLOCK_PROPERTY = Key.of("craftengine:update_block_property"); public static final Key SET_FOOD = Key.of("craftengine:set_food"); public static final Key SET_COOLDOWN = Key.of("craftengine:set_cooldown"); public static final Key REMOVE_COOLDOWN = Key.of("craftengine:remove_cooldown"); @@ -37,4 +39,9 @@ public final class CommonFunctions { public static final Key DAMAGE = Key.of("craftengine:damage"); public static final Key MERCHANT_TRADE = Key.of("craftengine:merchant_trade"); public static final Key REMOVE_ENTITY = Key.of("craftengine:remove_entity"); + public static final Key IF_ELSE = Key.of("craftengine:if_else"); + public static final Key ALTERNATIVES = Key.of("craftengine:alternatives"); + public static final Key WHEN = Key.of("craftengine:when"); + public static final Key ALL_OF = Key.of("craftengine:all_of"); + public static final Key DUMMY = Key.of("craftengine:dummy"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DummyFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DummyFunction.java new file mode 100644 index 000000000..080be0808 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DummyFunction.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; + +public class DummyFunction implements Function { + + @Override + public void run(CTX ctx) { + } + + @Override + public Key type() { + return CommonFunctions.DUMMY; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/Function.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/Function.java index 968feb369..9296ba624 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/Function.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/Function.java @@ -3,9 +3,32 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.util.Key; +import java.util.List; + public interface Function { void run(CTX ctx); Key type(); + + static Function allOf(List> functions) { + if (functions == null || functions.isEmpty()) { + return new DummyFunction<>(); + } + if (functions.size() == 1) { + return functions.getFirst(); + } + return new AllOfFunction<>(functions); + } + + @SafeVarargs + static Function allOf(Function... functions) { + if (functions == null || functions.length == 0) { + return new DummyFunction<>(); + } + if (functions.length == 1) { + return functions[0]; + } + return new AllOfFunction<>(functions); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/IfElseFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/IfElseFunction.java new file mode 100644 index 000000000..70611d061 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/IfElseFunction.java @@ -0,0 +1,56 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.Pair; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +public class IfElseFunction extends AbstractConditionalFunction { + private final List, Function>> conditions; + + public IfElseFunction(List> predicates, List, Function>> conditions) { + super(predicates); + this.conditions = conditions; + } + + @Override + public void runInternal(CTX ctx) { + for (Pair, Function> condition : this.conditions) { + if (condition.left().test(ctx)) { + condition.right().run(ctx); + break; + } + } + } + + @Override + public Key type() { + return CommonFunctions.IF_ELSE; + } + + public static class FactoryImpl extends AbstractFunctionalFactory { + + public FactoryImpl(java.util.function.Function, Condition> conditionFactory, java.util.function.Function, Function> functionFactory) { + super(conditionFactory, functionFactory); + } + + @Override + public Function create(Map arguments) { + List, Function>> branches = ResourceConfigUtils.parseConfigAsList( + ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(arguments, "rules", "rule"), "warning.config.function.if_else.missing_rules"), + map -> { + List> conditions = getPredicates(map); + List> functions = getFunctions(map); + return new Pair<>(MiscUtils.allOf(conditions), Function.allOf(functions)); + } + ); + return new IfElseFunction<>(getPredicates(arguments), branches); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java index 3068766eb..4734cb594 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/PlaceBlockFunction.java @@ -58,11 +58,12 @@ public class PlaceBlockFunction extends AbstractConditional @Override public Function create(Map arguments) { String state = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("block-state"), "warning.config.function.place_block.missing_block_state"); - NumberProvider x = NumberProviders.fromObject(arguments.getOrDefault("x", "")); - NumberProvider y = NumberProviders.fromObject(arguments.getOrDefault("y", "")); - NumberProvider z = NumberProviders.fromObject(arguments.getOrDefault("z", "")); - NumberProvider flags = Optional.ofNullable(arguments.get("update-flags")).map(NumberProviders::fromObject).orElse(NumberProviders.direct(UpdateOption.UPDATE_ALL.flags())); - return new PlaceBlockFunction<>(LazyReference.lazyReference(() -> CraftEngine.instance().blockManager().createBlockState(state)), x, y, z, flags, getPredicates(arguments)); + return new PlaceBlockFunction<>(LazyReference.lazyReference(() -> CraftEngine.instance().blockManager().createBlockState(state)), + 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())), + getPredicates(arguments)); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TransformBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TransformBlockFunction.java new file mode 100644 index 000000000..2183d51c6 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TransformBlockFunction.java @@ -0,0 +1,96 @@ +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.plugin.CraftEngine; +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.LazyReference; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldPosition; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +public class TransformBlockFunction extends AbstractConditionalFunction { + private final LazyReference lazyBlockState; + private final CompoundTag properties; + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final NumberProvider updateFlags; + + public TransformBlockFunction(LazyReference lazyBlockState, CompoundTag properties, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider updateFlags, List> predicates) { + super(predicates); + this.properties = properties; + this.x = x; + this.y = y; + this.z = z; + this.updateFlags = updateFlags; + this.lazyBlockState = lazyBlockState; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isPresent()) { + 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)); + BlockStateWrapper existingBlockState = world.getBlockAt(x, y, z).blockState().withProperties(this.properties); + CompoundTag newProperties = new CompoundTag(); + for (String propertyName : existingBlockState.getPropertyNames()) { + newProperties.putString(propertyName, String.valueOf(existingBlockState.getProperty(propertyName)).toLowerCase(Locale.ROOT)); + } + if (!this.properties.isEmpty()) { + for (Map.Entry tagEntry : this.properties.entrySet()) { + newProperties.put(tagEntry.getKey(), tagEntry.getValue()); + } + } + world.setBlockAt(x, y, z, this.lazyBlockState.get().withProperties(newProperties), this.updateFlags.getInt(ctx)); + } + } + + @Override + public Key type() { + return CommonFunctions.TRANSFORM_BLOCK; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + String block = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("block"), "warning.config.function.transform_block.missing_block"); + CompoundTag properties = new CompoundTag(); + Map propertiesMap = MiscUtils.castToMap(arguments.get("properties"), true); + if (propertiesMap != null) { + for (Map.Entry entry : propertiesMap.entrySet()) { + properties.putString(entry.getKey(), String.valueOf(entry.getValue())); + } + } + return new TransformBlockFunction<>( + LazyReference.lazyReference(() -> CraftEngine.instance().blockManager().createBlockState(block)), + properties, + 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())), + getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateBlockPropertyFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateBlockPropertyFunction.java new file mode 100644 index 000000000..4993e5465 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/UpdateBlockPropertyFunction.java @@ -0,0 +1,78 @@ +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.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 net.momirealms.sparrow.nbt.CompoundTag; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class UpdateBlockPropertyFunction extends AbstractConditionalFunction { + private final CompoundTag properties; + private final NumberProvider x; + private final NumberProvider y; + private final NumberProvider z; + private final NumberProvider updateFlags; + + public UpdateBlockPropertyFunction(CompoundTag properties, NumberProvider x, NumberProvider y, NumberProvider z, NumberProvider updateFlags, List> predicates) { + super(predicates); + this.properties = properties; + this.x = x; + this.y = y; + this.z = z; + this.updateFlags = updateFlags; + } + + @Override + public void runInternal(CTX ctx) { + Optional optionalWorldPosition = ctx.getOptionalParameter(DirectContextParameters.POSITION); + if (optionalWorldPosition.isPresent()) { + 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); + BlockStateWrapper wrapper = blockAt.blockState().withProperties(this.properties); + world.setBlockAt(x, y, z, wrapper, this.updateFlags.getInt(ctx)); + } + } + + @Override + public Key type() { + return CommonFunctions.UPDATE_BLOCK_PROPERTY; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + Map state = ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(arguments.get("properties"), "warning.config.function.update_block_property.missing_properties"), "properties"); + CompoundTag properties = new CompoundTag(); + for (Map.Entry entry : state.entrySet()) { + properties.putString(entry.getKey(), String.valueOf(entry.getValue())); + } + return new UpdateBlockPropertyFunction<>(properties, + 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())), + getPredicates(arguments)); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/WhenFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/WhenFunction.java new file mode 100644 index 000000000..fa55a77a9 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/WhenFunction.java @@ -0,0 +1,63 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.plugin.context.text.TextProvider; +import net.momirealms.craftengine.core.plugin.context.text.TextProviders; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.Pair; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class WhenFunction extends AbstractConditionalFunction { + private final TextProvider source; + private final Map> whenMap; + private final Function fallback; + + public WhenFunction(List> predicates, TextProvider source, Map> whenMap, Function fallback) { + super(predicates); + this.whenMap = whenMap; + this.source = source; + this.fallback = fallback; + } + + @Override + public void runInternal(CTX ctx) { + String text = this.source.get(ctx); + Function function = this.whenMap.getOrDefault(text, this.fallback); + function.run(ctx); + } + + @Override + public Key type() { + return CommonFunctions.IF_ELSE; + } + + public static class FactoryImpl extends AbstractFunctionalFactory { + + public FactoryImpl(java.util.function.Function, Condition> conditionFactory, java.util.function.Function, Function> functionFactory) { + super(conditionFactory, functionFactory); + } + + @Override + public Function create(Map arguments) { + TextProvider source = TextProviders.fromString(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("source"), "warning.config.function.when.missing_source")); + List, Function>> list = ResourceConfigUtils.parseConfigAsList(arguments.get("cases"), map -> { + List when = MiscUtils.getAsStringList(map.get("when")); + List> functions = getFunctions(map); + return Pair.of(when, Function.allOf(functions)); + }); + Map> whenMap = new HashMap<>(); + for (Pair, Function> pair : list) { + for (String when : pair.left()) { + whenMap.put(when, pair.right()); + } + } + return new WhenFunction<>(getPredicates(arguments), source, whenMap, Function.allOf(parseFunctions(arguments.get("fallback")))); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TagTextProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TagTextProvider.java index 11c63ac21..4942d64cb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TagTextProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/text/TagTextProvider.java @@ -18,8 +18,8 @@ public class TagTextProvider implements TextProvider { @Override public String get(Context context) { - Component resultComponent = AdventureHelper.customMiniMessage().deserialize(this.text, context.tagResolvers()); - return AdventureHelper.plainTextContent(resultComponent); + Component resultComponent = AdventureHelper.miniMessage().deserialize(this.text, context.tagResolvers()); + return AdventureHelper.strictMiniMessage().serialize(resultComponent); } @Override diff --git a/gradle.properties b/gradle.properties index 369a66b0f..64dbd1a1a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.64.19 -config_version=49 -lang_version=35 +project_version=0.0.64.20 +config_version=50 +lang_version=36 project_group=net.momirealms latest_supported_version=1.21.10