9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

Merge pull request #486 from jhqwqmc/feat/drop-experience-block

添加掉落经验方块
This commit is contained in:
XiaoMoMi
2025-12-04 05:50:11 +08:00
committed by GitHub
4 changed files with 118 additions and 7 deletions

View File

@@ -47,6 +47,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key SURFACE_SPREADING_BLOCK = Key.from("craftengine:surface_spreading_block");
public static final Key SNOWY_BLOCK = Key.from("craftengine:snowy_block");
public static final Key HANGABLE_BLOCK = Key.from("craftengine:hangable_block");
public static final Key DROP_EXPERIENCE_BLOCK = Key.from("craftengine:drop_experience_block");
public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -92,5 +93,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(SURFACE_SPREADING_BLOCK, SurfaceSpreadingBlockBehavior.FACTORY);
register(SNOWY_BLOCK, SnowyBlockBehavior.FACTORY);
register(HANGABLE_BLOCK, HangableBlockBehavior.FACTORY);
register(DROP_EXPERIENCE_BLOCK, DropExperienceBlockBehavior.FACTORY);
}
}

View File

@@ -0,0 +1,104 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.LocationUtils;
import net.momirealms.craftengine.bukkit.world.BukkitWorldManager;
import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.BlockSettings;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.loot.LootContext;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.plugin.context.condition.AllOfCondition;
import net.momirealms.craftengine.core.plugin.context.event.EventConditions;
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.ResourceConfigUtils;
import net.momirealms.craftengine.core.world.BlockPos;
import net.momirealms.craftengine.core.world.Vec3d;
import net.momirealms.craftengine.core.world.World;
import net.momirealms.craftengine.core.world.WorldPosition;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
public class DropExperienceBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private final NumberProvider amount;
private final Condition<Context> conditions;
public DropExperienceBlockBehavior(CustomBlock customBlock, NumberProvider amount, Condition<Context> conditions) {
super(customBlock);
this.amount = amount;
this.conditions = conditions;
}
@Override
public void spawnAfterBreak(Object thisBlock, Object[] args, Callable<Object> superMethod) {
boolean dropExperience = (boolean) args[4]; // 通常来说是 false
Item<ItemStack> item = BukkitItemManager.instance().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(args[3]));
if (!dropExperience) {
ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null);
if (state == null) {
return;
}
BlockSettings settings = state.settings();
if (settings.requireCorrectTool()) {
if (item.isEmpty()) {
return;
}
boolean cannotBreak = !settings.isCorrectTool(item.id())
&& (!settings.respectToolComponent()
|| !FastNMS.INSTANCE.method$ItemStack$isCorrectToolForDrops(args[3], state.customBlockState().literalObject()));
if (cannotBreak) {
return;
}
}
}
World world = BukkitWorldManager.instance().wrap(FastNMS.INSTANCE.method$Level$getCraftWorld(args[1]));
BlockPos pos = LocationUtils.fromBlockPos(args[2]);
tryDropExperience(world, pos, item);
}
private void tryDropExperience(World world, BlockPos pos, Item<ItemStack> item) {
Vec3d dropPos = Vec3d.atCenterOf(pos);
ContextHolder holder = ContextHolder.builder()
.withParameter(DirectContextParameters.POSITION, new WorldPosition(world, dropPos))
.withParameter(DirectContextParameters.ITEM_IN_HAND, item)
.build();
LootContext context = new LootContext(world, null, 1.0f, holder);
if (this.conditions != null && !this.conditions.test(context)) {
return;
}
int finalAmount = this.amount.getInt(context);
if (finalAmount <= 0) {
return;
}
world.dropExp(dropPos, finalAmount);
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
NumberProvider amount = NumberProviders.fromObject(arguments.getOrDefault("amount", 0));
Condition<Context> conditions = null;
List<Condition<Context>> conditionList = ResourceConfigUtils.parseConfigAsList(ResourceConfigUtils.get(arguments, "conditions", "condition"), EventConditions::fromMap);
if (conditionList.size() == 1) {
conditions = conditionList.getFirst();
} else if (!conditionList.isEmpty()) {
conditions = new AllOfCondition<>(conditionList);
}
return new DropExperienceBlockBehavior(block, amount, conditions);
}
}
}

View File

@@ -27,13 +27,17 @@ items:
texture: minecraft:item/custom/topaz
blocks:
default:topaz_ore:
behavior:
type: drop_experience_block
amount: 3~7
condition:
type: enchantment
predicate: minecraft:silk_touch<=0
loot:
template: default:loot_table/ore
arguments:
ore_drop: default:topaz
ore_block: default:topaz_ore
min_exp: 3
max_exp: 7
settings:
template: default:settings/ore
arguments:
@@ -45,13 +49,17 @@ blocks:
arguments:
path: minecraft:block/custom/topaz_ore
default:deepslate_topaz_ore:
behavior:
type: drop_experience_block
amount: 3~7
condition:
type: enchantment
predicate: minecraft:silk_touch<=0
loot:
template: default:loot_table/ore
arguments:
ore_drop: default:topaz
ore_block: default:deepslate_topaz_ore
min_exp: 3
max_exp: 7
settings:
template: default:settings/deepslate_ore
arguments:

View File

@@ -180,7 +180,6 @@ templates:
# ore_block: the ore block
# ore_drop: the drops of the ore material
# ore_drop_count: the amount of the ore materials
# exp: the exp to drop
default:loot_table/ore:
pools:
- rolls: 1
@@ -203,8 +202,6 @@ templates:
formula:
type: ore_drops
- type: explosion_decay
- type: drop_exp
count: ${exp:-2~4}
# Using Silk Touch or shears will cause the leaves block itself to drop.
# Using Fortune, however, increases the drop rates of sticks and saplings.