9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2026-01-04 15:41:38 +00:00

Merge pull request #490 from jhqwqmc/feat/function-and-condition

添加清理物品函数和物品栏存在物品条件
This commit is contained in:
XiaoMoMi
2025-12-05 02:55:39 +08:00
committed by GitHub
11 changed files with 126 additions and 6 deletions

View File

@@ -108,11 +108,6 @@ public class CheckItemExpansion extends PlaceholderExpansion {
}
private int getItemCount(BukkitServerPlayer player, String[] param) {
Key itemId = Key.of(param[0], param[1]);
Predicate<Object> predicate = nmsStack -> this.plugin.itemManager().wrap(ItemStackUtils.asCraftMirror(nmsStack)).id().equals(itemId);
Object inventory = FastNMS.INSTANCE.method$Player$getInventory(player.serverPlayer());
Object inventoryMenu = FastNMS.INSTANCE.field$Player$inventoryMenu(player.serverPlayer());
Object craftSlots = FastNMS.INSTANCE.method$InventoryMenu$getCraftSlots(inventoryMenu);
return FastNMS.INSTANCE.method$Inventory$clearOrCountMatchingItems(inventory, predicate, 0, craftSlots);
return player.clearOrCountMatchingInventoryItems(Key.of(param[0], param[1]), 0);
}
}

View File

@@ -75,6 +75,7 @@ import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
public class BukkitServerPlayer extends Player {
public static final Key SELECTED_LOCALE_KEY = Key.of("craftengine:locale");
@@ -1492,6 +1493,15 @@ public class BukkitServerPlayer extends Player {
this.trackedBlockEntityRenderers.clear();
}
@Override
public int clearOrCountMatchingInventoryItems(Key itemId, int count) {
Predicate<Object> predicate = nmsStack -> this.plugin.itemManager().wrap(ItemStackUtils.asCraftMirror(nmsStack)).id().equals(itemId);
Object inventory = FastNMS.INSTANCE.method$Player$getInventory(serverPlayer());
Object inventoryMenu = FastNMS.INSTANCE.field$Player$inventoryMenu(serverPlayer());
Object craftSlots = FastNMS.INSTANCE.method$InventoryMenu$getCraftSlots(inventoryMenu);
return FastNMS.INSTANCE.method$Inventory$clearOrCountMatchingItems(inventory, predicate, count, craftSlots);
}
@Override
public void addTrackedFurniture(int entityId, Furniture furniture) {
this.trackedFurniture.put(entityId, new VirtualCullableObject(furniture));

View File

@@ -170,6 +170,7 @@ warning.config.condition.is_null.missing_argument: "<yellow>Issue found in file
warning.config.condition.hand.missing_hand: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'hand' argument for 'hand' condition.</yellow>"
warning.config.condition.hand.invalid_hand: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid 'hand' argument '<arg:2>' for 'hand' condition. Allowed hand types: [<arg:3>]</yellow>"
warning.config.condition.on_cooldown.missing_id: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'id' argument for 'on_cooldown' condition.</yellow>"
warning.config.condition.inventory_has_item.missing_id: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'id' argument for 'inventory_has_item' condition.</yellow>"
warning.config.structure.not_section: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is expected to be a config section while it's actually a(n) '<arg:2>'.</yellow>"
warning.config.image.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated image '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
warning.config.image.missing_height: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is missing the required 'height' argument.</yellow>"
@@ -543,6 +544,7 @@ warning.config.function.transform_block.missing_block: "<yellow>Issue found in f
warning.config.function.cycle_block_property.missing_property: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'property' argument for 'cycle_block_property' function.</yellow>"
warning.config.function.set_exp.missing_count: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'count' argument for 'set_exp' function.</yellow>"
warning.config.function.set_level.missing_count: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'count' argument for 'set_level' function.</yellow>"
warning.config.function.clear_item.missing_id: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'id' argument for 'clear_item' function.</yellow>"
warning.config.selector.missing_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'type' argument for selector.</yellow>"
warning.config.selector.invalid_type: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid selector type '<arg:2>'.</yellow>"
warning.config.selector.invalid_target: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid selector target '<arg:2>'.</yellow>"

View File

@@ -167,6 +167,7 @@ warning.config.condition.is_null.missing_argument: "<yellow>在文件 <arg:0>
warning.config.condition.hand.missing_hand: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'hand' 条件必需的 'hand' 参数</yellow>"
warning.config.condition.hand.invalid_hand: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的 'hand' 参数 '<arg:2>' ('hand' 条件). 允许的手部类型: [<arg:3>]</yellow>"
warning.config.condition.on_cooldown.missing_id: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'on_cooldown' 条件必需的 'id' 参数</yellow>"
warning.config.condition.inventory_has_item.missing_id: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'inventory_has_item' 条件必需的 'id' 参数</yellow>"
warning.config.structure.not_section: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 应为配置段落 但实际类型为 '<arg:2>'</yellow>"
warning.config.image.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的图片配置 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
warning.config.image.missing_height: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 缺少必需的 'height' 参数</yellow>"
@@ -535,6 +536,7 @@ warning.config.function.transform_block.missing_block: "<yellow>在文件 <arg:0
warning.config.function.cycle_block_property.missing_property: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'cycle_block_property' 函数所需的 'property' 参数</yellow>"
warning.config.function.set_exp.missing_count: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'set_exp' 函数所需的 'count' 参数</yellow>"
warning.config.function.set_level.missing_count: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'set_level' 函数所需的 'count' 参数</yellow>"
warning.config.function.clear_item.missing_id: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少 'clear_item' 函数所需的 'id' 参数</yellow>"
warning.config.selector.missing_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 缺少选择器必需的 'type' 参数</yellow>"
warning.config.selector.invalid_type: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器类型 '<arg:2>'</yellow>"
warning.config.selector.invalid_target: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 使用了无效的选择器目标 '<arg:2>'</yellow>"

View File

@@ -226,6 +226,8 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
public abstract void clearTrackedBlockEntities();
public abstract int clearOrCountMatchingInventoryItems(Key itemId, int count);
@Override
public void remove() {
}

View File

@@ -31,4 +31,5 @@ public final class CommonConditions {
public static final Key IS_NULL = Key.from("craftengine:is_null");
public static final Key HAND = Key.from("craftengine:hand");
public static final Key HAS_PLAYER = Key.from("craftengine:has_player");
public static final Key INVENTORY_HAS_ITEM = Key.from("craftengine:inventory_has_item");
}

View File

@@ -0,0 +1,51 @@
package net.momirealms.craftengine.core.plugin.context.condition;
import net.momirealms.craftengine.core.entity.player.Player;
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.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.ItemUtils;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Optional;
public class InventoryHasItemCondition<CTX extends Context> implements Condition<CTX> {
private final Key itemId;
private final NumberProvider count;
public InventoryHasItemCondition(Key itemId, NumberProvider count) {
this.itemId = itemId;
this.count = count;
}
@Override
public Key type() {
return CommonConditions.INVENTORY_HAS_ITEM;
}
@Override
public boolean test(CTX ctx) {
Optional<Player> optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER);
if (optionalPlayer.isEmpty()) {
return false;
}
Player player = optionalPlayer.get();
return player.clearOrCountMatchingInventoryItems(this.itemId, 0) >= this.count.getInt(ctx);
}
public static class FactoryImpl<CTX extends Context> implements ConditionFactory<CTX> {
@Override
public Condition<CTX> create(Map<String, Object> arguments) {
Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(arguments, "id", "item"), "warning.config.condition.inventory_has_item.missing_id"));
NumberProvider count = NumberProviders.fromObject(arguments.getOrDefault("count", 1));
return new InventoryHasItemCondition<>(itemId, count);
}
}
}

View File

@@ -40,6 +40,7 @@ public class EventConditions {
register(CommonConditions.IS_NULL, new IsNullCondition.FactoryImpl<>());
register(CommonConditions.HAND, new HandCondition.FactoryImpl<>());
register(CommonConditions.ON_COOLDOWN, new OnCooldownCondition.FactoryImpl<>());
register(CommonConditions.INVENTORY_HAS_ITEM, new InventoryHasItemCondition.FactoryImpl<>());
}
public static void register(Key key, ConditionFactory<Context> factory) {

View File

@@ -59,6 +59,7 @@ public class EventFunctions {
register(CommonFunctions.SET_LEVEL, new SetLevelFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.PLAY_TOTEM_ANIMATION, new PlayTotemAnimationFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.CLOSE_INVENTORY, new CloseInventoryFunction.FactoryImpl<>(EventConditions::fromMap));
register(CommonFunctions.CLEAR_ITEM, new ClearItemFunction.FactoryImpl<>(EventConditions::fromMap));
}
public static void register(Key key, FunctionFactory<Context> factory) {

View File

@@ -0,0 +1,54 @@
package net.momirealms.craftengine.core.plugin.context.function;
import net.momirealms.craftengine.core.entity.player.Player;
import net.momirealms.craftengine.core.plugin.context.Condition;
import net.momirealms.craftengine.core.plugin.context.Context;
import net.momirealms.craftengine.core.plugin.context.number.NumberProvider;
import net.momirealms.craftengine.core.plugin.context.number.NumberProviders;
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class ClearItemFunction<CTX extends Context> extends AbstractConditionalFunction<CTX> {
private final Key itemId;
private final NumberProvider count;
public ClearItemFunction(List<Condition<CTX>> predicates, Key itemId, NumberProvider count) {
super(predicates);
this.itemId = itemId;
this.count = count;
}
@Override
protected void runInternal(CTX ctx) {
Optional<Player> optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER);
if (optionalPlayer.isEmpty()) {
return;
}
Player player = optionalPlayer.get();
player.clearOrCountMatchingInventoryItems(itemId, count.getInt(ctx));
}
@Override
public Key type() {
return CommonFunctions.CLEAR_ITEM;
}
public static class FactoryImpl<CTX extends Context> extends AbstractFactory<CTX> {
public FactoryImpl(java.util.function.Function<Map<String, Object>, Condition<CTX>> factory) {
super(factory);
}
@Override
public Function<CTX> create(Map<String, Object> arguments) {
Key itemId = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(arguments, "id", "item"), "warning.config.function.clear_item.missing_id"));
NumberProvider count = NumberProviders.fromObject(arguments.getOrDefault("count", 1));
return new ClearItemFunction<>(getPredicates(arguments), itemId, count);
}
}
}

View File

@@ -50,4 +50,5 @@ public final class CommonFunctions {
public static final Key SET_LEVEL = Key.of("craftengine:set_level");
public static final Key PLAY_TOTEM_ANIMATION = Key.of("craftengine:play_totem_animation");
public static final Key CLOSE_INVENTORY = Key.of("craftengine:close_inventory");
public static final Key CLEAR_ITEM = Key.of("craftengine:clear_item");
}