From ebcc6fa72439004a23103f68f9acd908981e7f21 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Mon, 24 Nov 2025 18:22:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0exp=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/user/BukkitServerPlayer.java | 33 ++++++++-- .../src/main/resources/translations/en.yml | 1 + .../src/main/resources/translations/zh_cn.yml | 4 +- .../core/entity/player/Player.java | 10 +++ .../plugin/context/event/EventFunctions.java | 1 + .../context/function/CommonFunctions.java | 1 + .../plugin/context/function/ExpFunction.java | 65 +++++++++++++++++++ 7 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ExpFunction.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index af6789fab..5384d3146 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -35,10 +35,7 @@ import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.sound.SoundSource; -import net.momirealms.craftengine.core.util.Direction; -import net.momirealms.craftengine.core.util.IntIdentityList; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.*; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.chunk.ChunkStatus; @@ -1253,4 +1250,32 @@ public class BukkitServerPlayer extends Player { platformPlayer().getPersistentDataContainer().remove(KeyUtils.toNamespacedKey(SELECTED_LOCALE_KEY)); } } + + @Override + public void giveExperiencePoints(int xpPoints) { + platformPlayer().giveExp(xpPoints); + } + + @Override + public void giveExperienceLevels(int levels) { + platformPlayer().giveExpLevels(levels); + } + + @Override + public int getXpNeededForNextLevel() { + return platformPlayer().getExperiencePointsNeededForNextLevel(); + } + + @Override + public void setExperiencePoints(int experiencePoints) { + float xpNeededForNextLevel = this.getXpNeededForNextLevel(); + float maxProgressThreshold = (xpNeededForNextLevel - 1.0F) / xpNeededForNextLevel; + float experienceProgress = MiscUtils.clamp(experiencePoints / xpNeededForNextLevel, 0.0F, maxProgressThreshold); + platformPlayer().setExp(experienceProgress); + } + + @Override + public void setExperienceLevels(int level) { + platformPlayer().setLevel(level); + } } diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 761e46f38..e8fbebaaf 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -492,6 +492,7 @@ warning.config.function.if_else.missing_rules: "Issue found in file 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.function.cycle_block_property.missing_property: "Issue found in file - The config '' is missing the required 'property' argument for 'cycle_block_property' function." +warning.config.function.exp.missing_count: "Issue found in file - The config '' is missing the required 'count' argument for 'exp' 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/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 3de669d54..2264fc523 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -388,6 +388,7 @@ warning.config.loot_table.function.apply_bonus.missing_enchantment: "在 warning.config.loot_table.function.apply_bonus.missing_formula: "在文件 发现问题 - '' 的战利品表配置错误 'apply_bonus' 函数缺少必需的 'formula' 参数" warning.config.loot_table.function.drop_exp.missing_count: "在文件 发现问题 - '' 的战利品表配置错误 'drop_exp' 函数缺少必需的 'count' 参数" warning.config.loot_table.function.set_count.missing_count: "在文件 发现问题 - '' 的战利品表配置错误 'set_count' 函数缺少必需的 'count' 参数" +warning.config.loot_table.function.apply_data.missing_data: "在文件 发现问题 - '' 的战利品表配置错误 'apply_data' 函数缺少必需的 'data' 参数" warning.config.loot_table.entry.missing_type: "在文件 发现问题 - '' 的战利品表配置错误 某个条目缺少必需的 'type' 参数" warning.config.loot_table.entry.invalid_type: "在文件 发现问题 - '' 的战利品表配置错误 某个条目使用了无效的条目类型 ''" warning.config.loot_table.entry.exp.missing_count: "在文件 发现问题 - '' 的战利品表配置错误 'exp' 条目缺少必需的 'count' 参数" @@ -490,6 +491,7 @@ warning.config.function.when.missing_source: "在文件 发现 warning.config.function.if_else.missing_rules: "在文件 发现问题 - 配置项 '' 缺少 'if_else' 函数所需的 'rules' 参数" warning.config.function.update_block_property.missing_properties: "在文件 发现问题 - 配置项 '' 缺少 'update_block_property' 函数所需的 'properties' 参数" warning.config.function.transform_block.missing_block: "在文件 发现问题 - 配置项 '' 缺少 'transform_block' 函数所需的 'block' 参数" +warning.config.function.exp.missing_count: "在文件 发现问题 - 配置项 '' 缺少 'exp' 函数所需的 'count' 参数" warning.config.function.cycle_block_property.missing_property: "在文件 发现问题 - 配置项 '' 缺少 'cycle_block_property' 函数所需的 'property' 参数" warning.config.selector.missing_type: "在文件 发现问题 - 配置项 '' 缺少选择器必需的 'type' 参数" warning.config.selector.invalid_type: "在文件 发现问题 - 配置项 '' 使用了无效的选择器类型 ''" @@ -509,4 +511,4 @@ warning.config.resource_pack.invalid_overlay_format: "在 config.yml 的 warning.config.equipment.duplicate: "在文件 发现问题 - 重复的装备配置 ''. 请检查其他文件中是否存在相同配置" warning.config.equipment.missing_type: "在文件 发现问题 - 装备 '' 缺少必需的 'type' 参数" warning.config.equipment.invalid_type: "在文件 发现问题 - 装备 '' 使用了无效的 'type' 参数" -warning.config.equipment.invalid_sacrificed_armor: "在 config.yml 的 'equipment.sacrificed-vanilla-armor' 处发现问题 - 无效的原版盔甲类型 ''" +warning.config.equipment.invalid_sacrificed_armor: "在 config.yml 的 'equipment.sacrificed-vanilla-armor' 处发现问题 - 无效的原版盔甲类型 ''" \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java index c8088ef4f..507def94d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/player/Player.java @@ -184,6 +184,16 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract void setSelectedLocale(@Nullable Locale locale); + public abstract void giveExperiencePoints(int xpPoints); + + public abstract void giveExperienceLevels(int levels); + + public abstract int getXpNeededForNextLevel(); + + public abstract void setExperiencePoints(int experiencePoints); + + public abstract void setExperienceLevels(int level); + @Override public void remove() { } 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 447ce05f0..15a23bcd1 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 @@ -55,6 +55,7 @@ public class EventFunctions { register(CommonFunctions.WHEN, new WhenFunction.FactoryImpl<>(EventConditions::fromMap, EventFunctions::fromMap)); register(CommonFunctions.DAMAGE_ITEM, new DamageItemFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.CYCLE_BLOCK_PROPERTY, new CycleBlockPropertyFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.EXP, new ExpFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { 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 bc638a23d..a8e0ee201 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 @@ -46,4 +46,5 @@ public final class CommonFunctions { public static final Key DUMMY = Key.of("craftengine:dummy"); public static final Key DAMAGE_ITEM = Key.of("craftengine:damage_item"); public static final Key CYCLE_BLOCK_PROPERTY = Key.of("craftengine:cycle_block_property"); + public static final Key EXP = Key.of("craftengine:exp"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ExpFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ExpFunction.java new file mode 100644 index 000000000..663d4618f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ExpFunction.java @@ -0,0 +1,65 @@ +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.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +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.function.BiConsumer; + +public class ExpFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; + private final NumberProvider count; + private final BiConsumer operation; + + public ExpFunction(List> predicates, PlayerSelector selector, NumberProvider count, BiConsumer operation) { + super(predicates); + this.selector = selector; + this.count = count; + this.operation = operation; + } + + @Override + protected void runInternal(CTX ctx) { + for (Player player : this.selector.get(ctx)) { + this.operation.accept(player, this.count.getInt(ctx)); + } + } + + @Override + public Key type() { + return CommonFunctions.EXP; + } + + public static class FactoryImpl extends AbstractFactory { + private static final BiConsumer ADD_POINTS = Player::giveExperiencePoints; + private static final BiConsumer ADD_LEVELS = Player::giveExperienceLevels; + private static final BiConsumer SET_POINTS = (player, experience) -> { + if (experience < player.getXpNeededForNextLevel()) { + player.setExperiencePoints(experience); + } + }; + private static final BiConsumer SET_LEVELS = Player::setExperienceLevels; + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + PlayerSelector selector = PlayerSelectors.fromObject(arguments.getOrDefault("target", "self"), conditionFactory()); + Object value = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("count"), "warning.config.function.exp.missing_count"); + boolean set = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("set", false), "set"); + boolean level = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("level", false), "level"); + BiConsumer operation = level ? (set ? SET_LEVELS : ADD_LEVELS) : (set ? SET_POINTS : ADD_POINTS); + return new ExpFunction<>(getPredicates(arguments), selector, NumberProviders.fromObject(value), operation); + } + } +}