From edbcda104b4389134ee03b0a4dcd278fb2e4d2c5 Mon Sep 17 00:00:00 2001 From: EndlessPixel Date: Sun, 4 Oct 2026 22:37:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(invulnerable):=20=E6=97=A0=E6=95=8C?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8D=E5=86=8D=E8=A2=AB=E5=88=9B=E9=80=A0?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E7=8E=A9=E5=AE=B6=E7=BB=95=E8=BF=87,=20?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=80=BC=E6=94=B9=E5=9B=9E=E5=BC=80=E5=90=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #67 无敌模式对创造模式玩家无效: - 原版 Entity#isInvulnerableTo() 的条件含 !source.isCreativePlayer(), 创造模式攻击被显式放行 - 因此只 setInvulnerable(true) 挡不住创造模式玩家, 管理员在创造模式下测试即「无敌无效」 - PlayerListener 新增 EntityDamageEvent 监听: 无敌假人 + 直接造成伤害的创造模式玩家 -> 取消事件 - 虚空 / /kill 等原版就该绕过无敌的来源不受影响 #68 默认值与文档不符: - Feature.invulnerable 默认选项 false -> true - config.yml default-features.invulnerable false -> true, version 24 -> 25 - README 一直写「假人默认开启无敌模式」, 现让行为与文档一致 本地实机验证 (Purpur 26.3): 无该配置键时生成即 Invulnerable:1b; 创造模式攻击被挡; /kill 仍生效; 控制台 /damage 被挡。 --- CHANGELOG.md | 12 +++++++++ .../core/listener/PlayerListener.java | 25 +++++++++++++++++++ .../core/repository/model/Feature.java | 2 +- fakeplayer-core/src/main/resources/config.yml | 4 +-- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8970734..4edebf00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,18 @@ Changelog for FakePlayer CE. Version `fp.buildN` matches the git tag / GitHub Re ## fp.build14 - (Not published | 未发布) +## fp.build14 - (Not published | 未发布) + +### English + +- **Invincible mode now really blocks damage.** A fake player with `invulnerable` enabled could still be hurt by players in **creative mode**: vanilla explicitly lets creative attackers bypass invulnerability, so admins testing in creative saw the fake take damage even though the feature was on (`/fp config` showed `true`, and the entity flag was set correctly). Damage dealt by a creative-mode attacker to an invulnerable fake player is now cancelled; sources that are supposed to bypass invulnerability (the void, `/kill`) still work (#67). +- **`invulnerable` is enabled by default again**, matching the documentation ("fake players spawn with invincible mode enabled by default"). It had silently defaulted to disabled since an upstream commit, which the changelog never recorded. `config.yml` bumped to 25 (#68). + +### 中文 + +- **无敌模式现在真的免伤。** 开启 `invulnerable` 的假人此前仍会被**创造模式**玩家打伤:原版对创造模式攻击显式放行无敌判定,导致管理员在创造模式下测试时看到假人掉血——尽管特性确实开着(`/fp config` 显示 `true`,实体标记也已正确设置)。现在创造模式玩家对无敌假人造成的伤害会被取消;原版本就该绕过无敌的来源(虚空、`/kill`)仍然可用(#67)。 +- **`invulnerable` 默认值改回开启**,与文档「假人默认开启无敌模式」一致。此前默认关闭是上游某次提交悄悄改的,更新日志从未记录过。`config.yml` 版本提升至 25(#68)。 + ## fp.build13 - 2026-10-03 ### English diff --git a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/listener/PlayerListener.java b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/listener/PlayerListener.java index aba0ee06..3dfce9c3 100644 --- a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/listener/PlayerListener.java +++ b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/listener/PlayerListener.java @@ -3,10 +3,12 @@ import com.google.inject.Inject; import com.google.inject.Singleton; import io.github.hello09x.fakeplayer.core.manager.FakeplayerManager; +import org.bukkit.GameMode; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.player.PlayerToggleSneakEvent; import org.jetbrains.annotations.NotNull; @@ -41,4 +43,27 @@ public void onSneak(@NotNull PlayerToggleSneakEvent event) { } } + /** + * 无敌模式: 开启无敌的假人不应受到伤害, 包括创造模式玩家的攻击。 + *

原版 {@code Entity#isInvulnerableTo()} 的条件里带 {@code !source.isCreativePlayer()}, + * 即**创造模式玩家的攻击被显式放行** (方便在创造模式下打无敌实体)。因此只靠 + * {@link Player#setInvulnerable(boolean)} 的话, 管理员在创造模式下打假人依然会掉血, + * 看起来就是「无敌模式无效」(实体标记其实已经设上了)。

+ *

这里只拦「直接造成伤害的创造模式玩家」; 原版本就该绕过无敌的来源 + * (虚空、{@code /kill} 等) 不受影响。

+ */ + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) + public void onInvulnerableFakeDamaged(@NotNull EntityDamageEvent event) { + if (!(event.getEntity() instanceof Player victim) + || !victim.isInvulnerable() + || !manager.isFake(victim)) { + return; + } + + if (event.getDamageSource().getDirectEntity() instanceof Player damager + && damager.getGameMode() == GameMode.CREATIVE) { + event.setCancelled(true); + } + } + } diff --git a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/repository/model/Feature.java b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/repository/model/Feature.java index d1ac1e0c..0a897058 100644 --- a/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/repository/model/Feature.java +++ b/fakeplayer-core/src/main/java/io/github/hello09x/fakeplayer/core/repository/model/Feature.java @@ -45,7 +45,7 @@ public enum Feature implements Translatable, Singletons { "fakeplayer.config.invulnerable", List.of(Permission.config), List.of("true", "false"), - "false", + "true", faker -> String.valueOf(faker.isInvulnerable()), (faker, value) -> faker.setInvulnerable(Boolean.parseBoolean(value)) ), diff --git a/fakeplayer-core/src/main/resources/config.yml b/fakeplayer-core/src/main/resources/config.yml index a8d7eec0..95d95f08 100644 --- a/fakeplayer-core/src/main/resources/config.yml +++ b/fakeplayer-core/src/main/resources/config.yml @@ -12,7 +12,7 @@ # DO NOT EDIT # 不要修改 -version: 24 +version: 25 # ============================================================ @@ -211,7 +211,7 @@ default-features: pickup_items: true skin: true look_at_entity: false - invulnerable: false + invulnerable: true replenish: false replace_tools: false autofish: false