Skip to content
MJP
/ PvP 戰鬥標記

Paper API · Paper 玩法

PvP 戰鬥標記

PvP 戰鬥標記:純邏輯核心服務(UUID + 時間戳、可 JUnit)、傷害歸因矩陣、指令白名單、傳送封鎖、戰鬥登出處罰,並以 ServicesManager 公開 CombatTagApi。

Paper API已發布v1.0.0paper-combat-tag更新於 2026年10月9日

觸發關鍵字

戰鬥標記combat tagcombat log戰鬥中登出damage attributionCombatTagApi

Paper Combat Tag

目的

玩家互毆後進入戰鬥狀態:狀態中禁止指令、插件傳送與登出(登出視同死亡)。核心 CombatTagService 只用 UUID 與毫秒時間戳,不含 Bukkit 型別,可直接用 JUnit 測;Listener 只負責把 Bukkit 事件翻成核心輸入。其他插件透過 ServicesManager 取得 CombatTagApi。


平台需求

  • Paper 1.21.11 / 26.2(兩版皆經編譯驗證)
  • 純 Paper API,不需要 Paperweight
  • Java 21(1.21.11)/25(26.2)

傷害歸因矩陣

來源 判斷
近戰 DamageSource#getCausingEntity() 是 Player
射擊物 Projectile#getShooter()
噴濺/滯留藥水、藥水雲 PotionSplashEvent/AreaEffectCloudApplyEvent + 有害效果
TNT TNTPrimed#getSource()
終界水晶、重生錨、床 點擊/打水晶時記帳,爆炸時在 1–2 tick 視窗內回查
馴服的狼 Tameable#getOwnerUniqueId()(主人在線)
火、摔落(受擊後) 不重置標記
自傷、被取消的事件 忽略(MONITOR + ignoreCancelled)

產生的代碼

CombatTagService.java(核心,無 Bukkit)

public Set<UUID> hit(UUID victim, UUID attacker, long now, boolean victimBypass, boolean attackerBypass);
public boolean isTagged(UUID player, long now);
public long remainingSeconds(UUID player, long now);
public Set<UUID> expire(long now);
public void markKicked(UUID player, boolean exemptFromPunishment);
public LogoutVerdict onQuit(UUID player, long now);   // NONE | PUNISH

CommandListener.java(白名單,含別名與命名空間)

String raw = CommandPolicy.rawToken(event.getMessage());
Command command = plugin.getServer().getCommandMap().getCommand(raw);
String name = command != null
    ? command.getName().toLowerCase(Locale.ROOT)
    : CommandPolicy.stripNamespace(raw);
if (!CommandPolicy.allowed(name, config.commandWhitelist())) {
    event.setCancelled(true);
}

CombatTagPlugin.java(註冊 API)

getServer().getServicesManager().register(
    CombatTagApi.class, new CombatTagApiImpl(service, clock), this, ServicePriority.Normal);

規則

  • 核心與 API 只用 JDK 型別;API 只加不改、不可 relocate
  • 傷害與死亡 Listener 用 MONITOR + ignoreCancelled = true
  • 被踢是否免死看 PlayerKickEvent.Cause 白名單,不看 PlayerQuitEvent#getReason()
  • 指令白名單先經 CommandMap 解析成正式指令名再比對
  • 傳送只擋 COMMAND/PLUGIN;珍珠、歌萊果、傳送門放行
  • 全伺服器只有一個每秒 timer,外層邊界 catch 且只記錄一次

執行緒安全

  • 核心與 Listener 只在主執行緒使用,不加鎖
  • 非同步階段只傳 UUID/數值,回主執行緒後再重新驗證玩家在線