From 736627ab8bc1a62c5b58870e621ee0246e0054d3 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 20:25:31 +0800 Subject: [PATCH] refactor crops --- .../default/configuration/categories.yml | 2 +- .../resources/default/configuration/i18n.yml | 4 +- .../default/configuration/plants.yml | 87 ++++++------- .../default/configuration/templates.yml | 115 +++++++++++++++++- .../models/block/custom/tinted_cross.json | 26 ---- .../bukkit/api/CraftEngineBlocks.java | 5 - .../bukkit/block/BlockEventListener.java | 10 -- .../block/behavior/BushBlockBehavior.java | 5 - .../block/behavior/CropBlockBehavior.java | 3 + .../config/additional-real-blocks.yml | 6 +- .../craftengine/core/loot/LootTable.java | 9 +- .../loot/condition/CropRipeCondition.java | 29 ----- .../core/loot/condition/LootConditions.java | 4 +- .../MatchBlockPropertyCondition.java | 58 +++++++++ .../function/ApplyBonusCountFunction.java | 39 ++++++ .../core/loot/parameter/LootParameters.java | 1 - .../craftengine/core/util/MiscUtils.java | 10 ++ 17 files changed, 270 insertions(+), 143 deletions(-) delete mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml index 328706d8c..f7678758f 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml @@ -62,4 +62,4 @@ categories: - default:flame_cane - default:gunpowder_block - default:solid_gunpowder_block - - default:ender_pearl_crop_seed \ No newline at end of file + - default:ender_pearl_flower_seed \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml index 4e3cc366f..23a9f8b8a 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml @@ -4,7 +4,7 @@ i18n: item.fairy_flower: "Fairy Flower" item.reed: "Reed" item.flame_cane: "Flame Cane" - item.ender_pearl_crop_seed: "Ender Pearl Flower Seeds" + item.ender_pearl_flower_seed: "Ender Pearl Flower Seeds" item.bench: "Bench" item.table_lamp: "Table Lamp" item.wooden_chair: "Wooden Chair" @@ -44,7 +44,7 @@ i18n: item.fairy_flower: "仙灵花" item.reed: "芦苇" item.flame_cane: "烈焰甘蔗" - item.ender_pearl_crop_seed: "末影珍珠花种子" + item.ender_pearl_flower_seed: "末影珍珠花种子" item.bench: "长椅" item.table_lamp: "台灯" item.wooden_chair: "木椅" diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 988d348dd..961e7bdbc 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -35,18 +35,18 @@ items: behavior: type: block_item block: default:flame_cane - default:ender_pearl_crop_seed: + default:ender_pearl_flower_seed: material: paper custom-model-data: 4003 data: - item-name: "" + item-name: "" model: template: default:model/simplified_generated arguments: - path: "minecraft:block/custom/ender_pearl_crop_seed" + path: "minecraft:block/custom/ender_pearl_flower_seed" behavior: type: block_item - block: default:ender_pearl_crop + block: default:ender_pearl_flower blocks: default:fairy_flower: settings: @@ -179,15 +179,15 @@ blocks: age=5: appearance: default id: 7 - default:ender_pearl_crop: + default:ender_pearl_flower: settings: template: - default:hardness/none - default:sound/grass overrides: - item: default:ender_pearl_crop_seed + item: default:ender_pearl_flower_seed push-reaction: DESTROY - map-color: 15 + map-color: 24 is-randomly-ticking: true behavior: type: crop_block @@ -196,64 +196,47 @@ blocks: bottom-blocks: - minecraft:end_stone loot: - pools: - - rolls: 1 - entries: - - type: item - item: "default:ender_pearl_crop_seed" - conditions: - - type: survives_explosion - - rolls: - type: uniform - min: "1" - max: "5" - entries: - - type: item - item: "minecraft:ender_pearl" - conditions: - - type: crop_ripe + template: default:loot_table/seed_crop + arguments: + crop_item: minecraft:ender_pearl + crop_seed: default:ender_pearl_flower_seed + ripe_age: 4 states: properties: age: type: int default: 0 - range: 0~5 + range: 0~3 appearances: - default: + stage_0: + state: "tripwire:0" + models: + - path: "minecraft:block/custom/ender_pearl_flower_stage_0" + stage_1: + state: "tripwire:1" + models: + - path: "minecraft:block/custom/ender_pearl_flower_stage_1" + stage_2: + state: "tripwire:2" + models: + - path: "minecraft:block/custom/ender_pearl_flower_stage_2" + stage_3: state: "sugar_cane:3" models: - - path: "minecraft:block/custom/ender_pearl_crop_stage1" - generation: - parent: "minecraft:block/custom/tinted_cross" - textures: - "cross": "minecraft:block/custom/ender_pearl_crop_stage1" - ripe: - state: "sugar_cane:4" - models: - - path: "minecraft:block/custom/ender_pearl_crop_stage2" - generation: - parent: "minecraft:block/custom/tinted_cross" - textures: - "cross": "minecraft:block/custom/ender_pearl_crop_stage2" + - path: "minecraft:block/custom/ender_pearl_flower_stage_3" variants: age=0: - appearance: default - id: 8 + appearance: stage_0 + id: 0 age=1: - appearance: default - id: 9 + appearance: stage_1 + id: 1 age=2: - appearance: default - id: 10 + appearance: stage_2 + id: 2 age=3: - appearance: default - id: 11 - age=4: - appearance: default - id: 12 - age=5: - appearance: ripe - id: 13 + appearance: stage_3 + id: 8 recipes: default:paper_from_reed: type: shaped diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml b/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml index f20f99fcc..641bf7396 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml @@ -953,7 +953,12 @@ templates#recipes: # loot tables templates#loot_tables: + # drop one item + + # template: default:loot_table/basic + # arguments: + # item: the item default:loot_table/basic: pools: - rolls: 1 @@ -962,7 +967,12 @@ templates#loot_tables: entries: - type: item item: "{item}" + # drop with silk touch + + # template: default:loot_table/silk_touch + # arguments: + # item: the item default:loot_table/silk_touch: pools: - rolls: 1 @@ -972,7 +982,78 @@ templates#loot_tables: entries: - type: item item: "{item}" - # drop ores + + # crop drops + + # template: default:loot_table/seed_crop + # arguments: + # crop_item: the ripe crop + # crop_seed: the seed of the crop + # ripe_age: the max age + default:loot_table/seed_crop: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: "{crop_item}" + conditions: + - type: match_block_property + properties: + age: "{ripe_age}" + - type: item + item: "{crop_seed}" + - rolls: 1 + conditions: + - type: match_block_property + properties: + age: "{ripe_age}" + entries: + - type: item + item: "{crop_seed}" + functions: + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: binomial_with_bonus_count + extra: 3 + probability: 0.5714286 + + # template: default:loot_table/crop + # arguments: + # crop_item: the ripe crop + # ripe_age: the max age + default:loot_table/crop: + pools: + - rolls: 1 + entries: + - type: item + item: "{crop_item}" + - rolls: 1 + conditions: + - type: match_block_property + properties: + age: "{ripe_age}" + entries: + - type: item + item: "{crop_item}" + functions: + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: binomial_with_bonus_count + extra: 3 + probability: 0.5714286 + + # ore drops + + # template: default:loot_table/ore + # arguments: + # ore_block: the ore block + # ore_drop: the drops of the ore + # min_exp: the min exp to drop + # max_exp: the max exp to drop default:loot_table/ore: pools: - rolls: 1 @@ -997,7 +1078,37 @@ templates#loot_tables: type: uniform min: "{min_exp}" max: "{max_exp}" - # leaves + + # template: default:loot_table/ore_no_exp + # arguments: + # ore_block: the ore block + # ore_drop: the drops of the ore + default:loot_table/ore_no_exp: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: "{ore_block}" + conditions: + - type: enchantment + predicate: minecraft:silk_touch>=1 + - type: item + item: "{ore_drop}" + functions: + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: ore_drops + - type: explosion_decay + + # leaves drops + + # template: default:loot_table/leaves + # arguments: + # leaves: the leaves block + # sapling: the sapling item default:loot_table/leaves: pools: - rolls: 1 diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json deleted file mode 100644 index 37c8b09f2..000000000 --- a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "ambientocclusion": false, - "textures": { - "particle": "#cross" - }, - "elements": [ - { "from": [ 0.8, 0, 8 ], - "to": [ 15.2, 16, 8 ], - "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": 45, "rescale": true }, - "shade": false, - "faces": { - "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" }, - "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" } - } - }, - { "from": [ 8, 0, 0.8 ], - "to": [ 8, 16, 15.2 ], - "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": 45, "rescale": true }, - "shade": false, - "faces": { - "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" }, - "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" } - } - } - ] -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index 7f2ad0a7b..7c716c0a6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -182,11 +182,6 @@ public final class CraftEngineBlocks { builder.withParameter(LootParameters.PLAYER, serverPlayer); builder.withOptionalParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); } - if (state.behavior() instanceof CropBlockBehavior cropBlockBehavior) { - if (cropBlockBehavior.isMaxAge(state)) { - builder.withParameter(LootParameters.CROP_RIPE, true); - } - } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } 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 0bdc7364f..58ef2c0c0 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 @@ -139,11 +139,6 @@ public class BlockEventListener implements Listener { builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.PLAYER, serverPlayer); builder.withOptionalParameter(LootParameters.TOOL, itemInHand); - if (state.behavior() instanceof CropBlockBehavior cropBlockBehavior) { - if (cropBlockBehavior.isMaxAge(state)) { - builder.withParameter(LootParameters.CROP_RIPE, true); - } - } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } @@ -302,11 +297,6 @@ public class BlockEventListener implements Listener { if (yield < 1f) { builder.withParameter(LootParameters.EXPLOSION_RADIUS, 1.0f / yield); } - if (state.behavior() instanceof CropBlockBehavior cropBlockBehavior) { - if (cropBlockBehavior.isMaxAge(state)) { - builder.withParameter(LootParameters.CROP_RIPE, true); - } - } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index f5226c5f8..13b6e32ae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -71,11 +71,6 @@ public class BushBlockBehavior extends AbstractBlockBehavior { net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.WORLD, world); - if (this instanceof CropBlockBehavior cropBlockBehavior) { - if (cropBlockBehavior.isMaxAge(state)) { - builder.withParameter(LootParameters.CROP_RIPE, true); - } - } for (Item item : previousState.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index a9449b023..a90f2366e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.block.CustomBlock; @@ -37,6 +38,7 @@ public class CropBlockBehavior extends BushBlockBehavior { public final boolean isMaxAge(Object state) { return this.getAge(state) >= this.ageProperty.max; } + public final boolean isMaxAge(ImmutableBlockState state) { return this.getAge(state) >= this.ageProperty.max; } @@ -48,6 +50,7 @@ public class CropBlockBehavior extends BushBlockBehavior { public final int getAge(Object state) { return getCEBlockState(state).get(ageProperty); } + public final int getAge(ImmutableBlockState state) { return state.get(ageProperty); } diff --git a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/config/additional-real-blocks.yml b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/config/additional-real-blocks.yml index 91993a87d..4fe5d6d61 100644 --- a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/config/additional-real-blocks.yml +++ b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/config/additional-real-blocks.yml @@ -14,9 +14,7 @@ # Q: When do I need to configure this file? # A: When the number of real block IDs is insufficient, but there are still available appearances. -# By default, the plugin only registers an additional 112 oak leaf block states (for the default configuration needs [>=28 states]). minecraft:oak_leaves: 112 - minecraft:oak_sapling: 1 minecraft:birch_sapling: 1 minecraft:spruce_sapling: 1 @@ -24,5 +22,5 @@ minecraft:jungle_sapling: 1 minecraft:dark_oak_sapling: 1 minecraft:acacia_sapling: 1 minecraft:cherry_sapling: 1 - -minecraft:anvil: 2 \ No newline at end of file +minecraft:anvil: 2 +minecraft:sugarcane: 14 \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java index 94bc14963..0af5630ca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.loot.function.LootFunction; import net.momirealms.craftengine.core.loot.function.LootFunctions; import net.momirealms.craftengine.core.loot.number.NumberProvider; import net.momirealms.craftengine.core.loot.number.NumberProviders; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.World; import org.jetbrains.annotations.Nullable; @@ -43,19 +44,19 @@ public class LootTable { NumberProvider rolls = NumberProviders.fromObject(pool.getOrDefault("rolls", 1)); NumberProvider bonus_rolls = NumberProviders.fromObject(pool.getOrDefault("bonus_rolls", 0)); List conditions = Optional.ofNullable(pool.get("conditions")) - .map(it -> LootConditions.fromMapList((List>) it)) + .map(it -> LootConditions.fromMapList(MiscUtils.castToMapListOrThrow(it, () -> new RuntimeException("'conditions' should be a map list, current type: " + it.getClass().getSimpleName())))) .orElse(Lists.newArrayList()); List> containers = Optional.ofNullable(pool.get("entries")) - .map(it -> (List>) new ArrayList>(LootEntryContainers.fromMapList((List>) it))) + .map(it -> (List>) new ArrayList>(LootEntryContainers.fromMapList(MiscUtils.castToMapListOrThrow(it, () -> new RuntimeException("'entries' should be a map list, current type: " + it.getClass().getSimpleName()))))) .orElse(Lists.newArrayList()); List> functions = Optional.ofNullable(pool.get("functions")) - .map(it -> (List>) new ArrayList>(LootFunctions.fromMapList((List>) it))) + .map(it -> (List>) new ArrayList>(LootFunctions.fromMapList(MiscUtils.castToMapListOrThrow(it, () -> new RuntimeException("'functions' should be a map list, current type: " + it.getClass().getSimpleName()))))) .orElse(Lists.newArrayList()); lootPools.add(new LootPool<>(containers, conditions, functions, rolls, bonus_rolls)); } return new LootTable<>(lootPools, Optional.ofNullable(map.get("functions")) - .map(it -> (List>) new ArrayList>(LootFunctions.fromMapList((List>) it))) + .map(it -> (List>) new ArrayList>(LootFunctions.fromMapList(MiscUtils.castToMapListOrThrow(it, () -> new RuntimeException("'functions' should be a map list, current type: " + it.getClass().getSimpleName()))))) .orElse(Lists.newArrayList()) ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java deleted file mode 100644 index 10d30ac74..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; -import net.momirealms.craftengine.core.util.Key; - -import java.util.Map; - -public class CropRipeCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); - public static final CropRipeCondition INSTANCE = new CropRipeCondition(); - - @Override - public Key type() { - return LootConditions.CROP_RIPE; - } - - @Override - public boolean test(LootContext lootContext) { - return lootContext.getOptionalParameter(LootParameters.CROP_RIPE).orElse(false); - } - - public static class Factory implements LootConditionFactory { - @Override - public LootCondition create(Map arguments) { - return INSTANCE; - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java index 4dd4ffabc..1ee957df9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java @@ -14,6 +14,7 @@ import java.util.function.Predicate; public class LootConditions { public static final Key MATCH_ITEM = Key.from("craftengine:match_item"); + public static final Key MATCH_BLOCK_PROPERTY = Key.from("craftengine:match_block_property"); public static final Key TABLE_BONUS = Key.from("craftengine:table_bonus"); public static final Key SURVIVES_EXPLOSION = Key.from("craftengine:survives_explosion"); public static final Key ANY_OF = Key.from("craftengine:any_of"); @@ -21,10 +22,10 @@ public class LootConditions { public static final Key ENCHANTMENT = Key.from("craftengine:enchantment"); public static final Key INVERTED = Key.from("craftengine:inverted"); public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); - public static final Key CROP_RIPE = Key.from("craftengine:crop_ripe"); static { register(MATCH_ITEM, MatchItemCondition.FACTORY); + register(MATCH_BLOCK_PROPERTY, MatchBlockPropertyCondition.FACTORY); register(TABLE_BONUS, TableBonusCondition.FACTORY); register(SURVIVES_EXPLOSION, SurvivesExplosionCondition.FACTORY); register(ANY_OF, AnyOfCondition.FACTORY); @@ -32,7 +33,6 @@ public class LootConditions { register(ENCHANTMENT, EnchantmentCondition.FACTORY); register(INVERTED, InvertedCondition.FACTORY); register(FALLING_BLOCK, FallingCondition.FACTORY); - register(CROP_RIPE, CropRipeCondition.FACTORY); } public static void register(Key key, LootConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java new file mode 100644 index 000000000..a56ea70ea --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java @@ -0,0 +1,58 @@ +package net.momirealms.craftengine.core.loot.condition; + +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.loot.LootContext; +import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.Pair; + +import java.util.*; + +public class MatchBlockPropertyCondition implements LootCondition { + public static final Factory FACTORY = new Factory(); + private final List> properties; + + public MatchBlockPropertyCondition(List> properties) { + this.properties = properties; + } + + @Override + public Key type() { + return LootConditions.MATCH_BLOCK_PROPERTY; + } + + @Override + public boolean test(LootContext lootContext) { + return lootContext.getOptionalParameter(LootParameters.BLOCK_STATE).map(state -> { + CustomBlock block = state.owner().value(); + for (Pair property : this.properties) { + Property propertyIns = block.getProperty(property.left()); + if (propertyIns == null) { + return false; + } + if (!state.get(propertyIns).toString().toLowerCase(Locale.ENGLISH).equals(property.right())) { + return false; + } + } + return true; + }).orElse(false); + } + + public static class Factory implements LootConditionFactory { + + @SuppressWarnings("unchecked") + @Override + public LootCondition create(Map arguments) { + Map properties = (Map) arguments.get("properties"); + if (properties == null) { + throw new IllegalArgumentException("Missing 'properties' argument for 'match_block_property'"); + } + List> propertyList = new ArrayList<>(); + for (Map.Entry entry : properties.entrySet()) { + propertyList.add(new Pair<>(entry.getKey(), entry.getValue().toString())); + } + return new MatchBlockPropertyCondition(propertyList); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java index 219f0f44f..180e6c100 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java @@ -12,6 +12,7 @@ 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.RandomUtils; import net.momirealms.craftengine.core.util.ResourceKey; import java.util.Collections; @@ -78,9 +79,11 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< public static class Formulas { public static final Key ORE_DROPS = Key.of("craftengine:ore_drops"); + public static final Key CROP_DROPS = Key.of("craftengine:binomial_with_bonus_count"); static { register(ORE_DROPS, OreDrops.FACTORY); + register(CROP_DROPS, CropDrops.FACTORY); } public static void register(Key key, FormulaFactory factory) { @@ -133,4 +136,40 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< } } } + + public static class CropDrops implements Formula { + public static final Factory FACTORY = new Factory(); + private final int extra; + private final float probability; + + public CropDrops(int extra, float probability) { + this.extra = extra; + this.probability = probability; + } + + @Override + public int apply(int initialCount, int enchantmentLevel) { + for (int i = 0; i < enchantmentLevel + this.extra; i++) { + if (RandomUtils.generateRandomFloat(0,1) < this.probability) { + initialCount++; + } + } + return initialCount; + } + + @Override + public Key type() { + return Formulas.CROP_DROPS; + } + + public static class Factory implements FormulaFactory { + + @Override + public Formula create(Map arguments) { + int extra = MiscUtils.getAsInt(arguments.getOrDefault("extra", 1)); + float probability = MiscUtils.getAsFloat(arguments.getOrDefault("probability", 0.5f)); + return new CropDrops(extra, probability); + } + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java b/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java index 35e145b56..ca09453ea 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java @@ -18,5 +18,4 @@ public class LootParameters { public static final ContextKey PLAYER = new ContextKey<>(Key.of("craftengine:player")); public static final ContextKey> TOOL = new ContextKey<>(Key.of("craftengine:tool")); public static final ContextKey BLOCK_STATE = new ContextKey<>(Key.of("craftengine:block_state")); - public static final ContextKey CROP_RIPE = new ContextKey<>(Key.of("craftengine:crop_ripe")); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java index 28b8f4a42..dfb84b83e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java @@ -6,6 +6,7 @@ import org.joml.Vector3f; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.function.Supplier; public class MiscUtils { @@ -22,6 +23,15 @@ public class MiscUtils { throw new IllegalArgumentException("Expected Map, got: " + obj.getClass().getSimpleName()); } + @SuppressWarnings("unchecked") + public static List> castToMapListOrThrow(Object obj, Supplier exceptionSupplier) { + if (obj instanceof List list) { + return (List>) list; + } else { + throw exceptionSupplier.get(); + } + } + @SuppressWarnings("unchecked") public static List castToList(Object obj, boolean allowNull) { if (allowNull && obj == null) {