SirenHytale
本节页面
  1. 修真
  2. 开服指南
  3. 事件

事件

Cultivation 在 plugin.siren.API 下的 54 个 *Events 类中,暴露了 391 个事件:159 个可取消的 Pre* 前置事件,在变更发生之前触发;232 个后置事件,在变更落定之后触发。模组中几乎每一项机制都被暴露了两次:一次在变更之前,监听器可以否决它,或重新调整它的数值;一次在变更之后。v0.11.1 本版新增三个类:DaoDomainEvents(8 个事件,其中四个属于首领道域与共鸣)、SectArrayEvents(3 个)与 VeinTapEvents(7 个)。道印没有任何事件类;扩展转而能观察什么,见道域一节下的说明。v0.11.2 没有新增类,但新增了三个事件:CultivationEvents 上服务于死亡惩罚的 PreDeathPenaltyEvent 与 DeathPenaltyAppliedEvent,以及 SectEvents 上、在宗门大殿灵脉化为龙脉时触发的 SectVeinAscendedEvent。

每个类都遵循 CultivationEvents 上所记载的约定,因此学会一个便学会了全部 54 个。下面的表格由 plugin.siren.API 中的 Java 源码生成:每个事件、它能否取消,以及它身上的每一个 getter 与 setter,都是从代码里读出来的,所以数目不会与 jar 脱节。

有四个名字出现了两次

PreXpGainEvent、XpGainEvent、PreLevelUpEvent 与 LevelUpEvent 同时存在于 BodyTemperingEvents 与 FistEvents 之中。务必用类名加以限定 —— 写 FistEvents.onXpGain(...),而不要裸引一个 XpGainEvent。

前置与后置

Pre* 事件继承自 plugin.siren.API.CancellableEvent,并在任何东西被施加之前触发。它给你两项能力:

  • event.setCancelled(true) 否决该操作。派发一返回,模组即刻检查这个标志并放弃操作,不留下任何状态变更。之所以什么都不必回滚,是因为什么都还没被施加 —— 这正是这些事件先于事实触发的全部理由。一个被取消的前置事件,意味着与之配对的后置事件永不触发。
  • 事件上的 setter 用于重新调整驱动该操作的数字 —— 一次突破的灵气消耗、一门功法的冷却、一道天劫落雷的伤害、一次收服的概率。派发结束时监听器留在那些字段里的东西,就是模组实际采用的东西。这是从扩展中重塑一项机制、而不必碰配置文件的受支持途径。

后置事件是一个普通的 Java record。它无法被取消,纯粹是一则通知;待它触发时,变更早已在组件上可见。

CancellableEvent 恰好暴露两个方法:

方法返回说明
isCancelled()boolean是否已有某个监听器否决了此操作。
setCancelled(boolean cancelled)否决该操作;传 false 则撤销否决。

即便有人取消了,每一个监听器仍会运行。 靠后的监听器尽可调用 setCancelled(false) 把操作放行,因此插件加载顺序决定了分歧中谁胜出。若你只想旁观,请改为监听后置事件。

并非每个前置事件都有同名的后置孪生,也并非每个后置事件都有前置事件:其中不少纯粹是通知,没有什么可否决的(SeasonEvents、DepthsEvents、SecretRealmEvents 就是刻意只设后置)。下面每张表里,前置事件都紧挨着列在它所守护的后置事件之前,「可取消」一列则标明哪些行是 Pre* 事件。

注册与线程

每个事件在其所属类上都有一个配套的 on* 注册方法 —— 共 391 个,一事件一个 —— 接受该事件类型的一个 Consumer:

CultivationEvents.onPreQiGain(event -> event.setAmount(event.amount() * 1.25F));
DaoEvents.onPathChange(event -> myPlugin.announce(event.player(), event.newPath()));

注册就是一次普通的 CopyOnWriteArrayList.add,可安全地从任何插件的 setup() 中、以任何加载顺序调用。没有反注册 —— 监听器的生命周期就是服务器的生命周期。

监听器是在事件所发生玩家的世界线程上同步调用的。在监听器内部经由惯常的访问器读取组件是安全的,但请勿阻塞;在触碰任何位于另一世界的东西之前,请自行切换线程(例如 CompletableFuture.runAsync(task, otherWorld))。抛出异常的监听器会被记录并跳过,因此一个写坏的扩展,既弄不垮模组自己的系统,也弄不垮监听同一事件的其他扩展。

许多类以 java.util.UUID 而非 PlayerRef 标识玩家,因为这些操作经常触及离线玩家 —— 一个被逐的门人、一场比会话活得更久的斗法、一位挂单在他离线时售出的卖家。BountyEvents、DaoDomainEvents、DaoDuelEvents、DepthsEvents、DuelEvents、LegacyEvents、MarketEvents、OathEvents、PagodaEvents、PartyEvents、RivalEvents、RogueEvents、SectArrayEvents、SectEvents、SoulEscapeEvents、StoreBenefitEvents、TeaEvents、TreasureEvents、VeinTapEvents、WagerEvents 与 WeiqiEvents 通篇如此;DwellingEvents、FormationEvents、PartnerEvents 与 SermonEvents 则把 UUID 标识符与 PlayerRef 玩家混着用。用 Universe.get().getPlayer(uuid) 解析 UUID,并检查 isValid()。

少数几个类带有额外约束,都在各自的 javadoc 里有所声明:

类触发于此时持有该怎么做
SectEvents相关玩家的世界线程。SectManager 的锁。读走你要的东西、交接出去、然后返回。切勿调用 SectManager 的变更方法。
MarketEvents相关玩家的世界线程。AuctionManager 的锁。同理:切勿回调 AuctionManager 的变更方法。
BountyEvents引发该事件之物所在的世界线程。BountyManager 的监视器。不要阻塞,不要重入 BountyManager,也绝不要去碰扩展自己的监视器 —— 锁序是 SeasonManager,然后你的扩展,然后 BountyManager。
SeasonEvents最先走到赛季泵的那条世界线程 —— 全服范围,而非某一位玩家的世界。SeasonManager 的监视器。不要阻塞;碰组件之前先按玩家切换线程。启动时的赛季更替到不了任何扩展监听器,所以请改问 getCurrentSeasonId()。
WagerEvents对前置事件与 WagerPlacedEvent,是下注玩家的指令线程;对两个盘口结算事件,是锦标赛泵。在 WagerMarketResolvedEvent 与 WagerMarketVoidedEvent 上,持有 DaoDuelTournamentManager 的监视器。这两个事件上不加锁、不跨管理器调用;把需要的东西抄进你自己的队列。
DaoDomainEvents v0.11.1施放者的世界线程,来自展开交互或道域自己的 tick。无。保持轻量,绝不在监听器里写入 Store。DomainClashEvent 在道域脉冲之内触发,就在它所引发的崩塌之前。
VeinTapEvents v0.11.1布阵或劫掠玩家的世界线程,或某条指令线程(释放)。不持有 VeinTapManager 的任何锁 —— 每个事件都在它的监视器之外触发。保持轻量,不要在监听器里写入 Store。前置事件在所有关卡都通过之后才询问,所以否决不会留下任何已消耗的东西。
SectArrayEvents v0.11.1升起事件在升起者的指令线程;SectArrayEndedEvent 则在最先察觉到结束的那条线程 —— 某个世界每秒一次的守阵机制,或撤下大阵的那条指令。不持有 SectArrayManager 的任何东西 —— 三个事件都在它的监视器之外触发。从活的 Sect 上读走你要的东西、交接出去、然后返回。切勿回调大阵的升起或撤下。
StoreBenefitEvents远程检查线程 —— 不是世界线程。无。找到玩家,检查 isValid(),碰任何组件之前先切到他的世界线程。
ProfileEvents所属的世界线程,处于任何 tick 系统之外。无。少有的例外:此处经由 Store 直接写入组件是安全的。
BodyTemperingEvents、FistEvents伤害管线之内,位于拥有受击实体的那条世界线程。无。保持轻量;绝不写入 Store。
LifespanEventsLifespanSystem 的 tick,或某个指令处理器。无。经由访问器读取;写入则排到 CommandBuffer 上。

WagerEvents 的 javadoc 还记载:DuelEvents.DuelEndEvent、DaoDuelEvents.DaoDuelEndEvent 以及 CelestialEvents 那一对,是从同步的管理器方法内部触发的,因此同样的规矩也适用于这些事件上的监听器。

如何找到某个事件

54 个类,分成 8 组:

  • 进阶、阶梯与存档 —— 8 个类,86 个事件。境界天梯本身、与之并列的两条肉身阶梯、伤患、第二条命,以及玩家保留的存档。
  • 大道、功法与誓言 —— 6 个类,60 个事件。元素、阴阳与业力,天道与个人之道,道域,功法,战斗深度与天道誓言。
  • 物品与炼制 —— 5 个类,31 个事件。掉落、丹药、灵核与秘籍,以及造出新物的诸般手艺:炼器、炼丹、锻造与符箓,外加兵器之中的灵。
  • 灵兽 —— 2 个类,24 个事件。伙伴,以及繁育出新伙伴的过程。
  • 宗门、坊市与同道 —— 10 个类,88 个事件。宗门与宗门之间的战事,被围宗门的战时大阵,侍奉大殿的人,功德,队伍与道侣,拍卖行与悬赏令。
  • 斗法与较量 —— 5 个类,26 个事件。两位玩家出于自愿而彼此对抗、或并肩进行的一切。
  • 世界 —— 14 个类,63 个事件。阵法与洞府,灵脉上的引脉阵,天穹,全服范围的遭遇,你前往的去处,以及你在那里的所获。
  • 任务、赛季与宝阁 —— 4 个类,13 个事件。剧情,共享的赛季时钟,以及从网络商店送达的购买。
类涵盖事件数可取消
CultivationEvents修炼核心4822
BodyTemperingEvents淬体63
FistEvents拳法42
LifespanEvents寿元62
MeridianEvents经脉损伤53
SoulEscapeEvents元婴遁走83
LegacyEvents修行传承21
ProfileEvents修炼存档73
DaoEvents大道与业力146
DaoComprehensionEvents大道领悟115
DaoDomainEvents v0.11.1道域、首领道域与共鸣82
TechniqueEvents功法157
CombatDepthEvents战斗深度42
OathEvents天道誓言84
ItemEvents物品126
AlchemyEvents炼丹52
ForgingEvents锻造21
TalismanEvents符箓63
WeaponSpiritEvents器灵63
BeastEvents灵兽2010
BreedingEvents灵兽繁育42
SectEvents宗门4118
WarEvents战事94
SectArrayEvents v0.11.1宗门大阵31
GuardianEvents护山傀儡41
SermonEvents讲道41
MeritEvents功德31
PartyEvents队伍51
PartnerEvents双修31
MarketEvents拍卖行与行商123
BountyEvents悬赏令42
DuelEvents斗法83
DaoDuelEvents大道赌斗32
WagerEvents赛事押注41
TeaEvents茶道41
WeiqiEvents围棋72
FormationEvents阵法84
DwellingEvents洞府126
VeinTapEvents v0.11.1引脉阵72
CelestialEvents天象31
TideEvents兽潮63
WorldBossEvents灾劫兽41
RiftEvents虚空裂隙51
RogueEvents散修客31
RivalEvents游历道友21
SecretRealmEvents秘境20
DepthsEvents秘境深渊40
PagodaEvents试炼塔31
TreasureEvents宝藏与遗迹21
ArrayEvents传送阵21
QuestEvents云游任务51
CampaignEvents主线31
SeasonEvents赛季20
StoreBenefitEvents宝阁权益30

每个类的标题都有一个形如 #<name>-events 的固定锚点,见上表第一列。

进阶、阶梯与存档

境界天梯本身、与之并列的两条肉身阶梯、伤患、第二条命,以及玩家保留的存档。

修炼核心

plugin.siren.API.CultivationEvents —— 48 个事件(22 个可取消),涵盖灵气、打坐、仪式、突破、晋阶、跌境、v0.11.2 死亡惩罚、天劫、心魔劫、走火入魔、幻境劫、心魔宿敌之战、洗髓之礼、飞升、轮回、种族、本命法宝、天赋树与玩家击杀。面向玩家的文档:境界与阶段、聚灵采气、天劫、种族、本命法宝、天赋树、飞升、轮回、走火入魔、幻境劫、心魔宿敌之战、死亡惩罚。

v0.11.2 两个死亡惩罚事件由濒死玩家的死亡回调触发,位于其世界线程上,此时该次死亡的 CommandBuffer 仍然开着。读取你需要的内容;若必须修改这位修士,请通过那个缓冲区进行,而不要直接写入 Store。PreDeathPenaltyEvent 是唯一的否决点:取消它既免去这次损失,也不会把这次死亡记作一次受罚;而 setPercent(0) 虽然什么都不取走,这次死亡仍计入阶梯的下一档(DeathPenaltyAppliedEvent 也仍会触发,其 qiLost() 为 0)。

此类中声明的枚举:

  • RitualType:BREAKTHROUGH —— 巅峰阶段 → 下一重境界;ADVANCEMENT —— 当前境界之内的一次子阶段晋阶;REFINEMENT —— 炼器:淬炼手中所持的兵器,而非修士本人。
  • MeditationStopReason:COMMAND —— 他们用 /cultivation meditate 自行关掉了它;MOVEMENT —— 他们离开了落座之处;RITUAL_COMPLETE —— 一次境界突破或子阶段晋阶完成,修士从挣得它的座位上起身。
事件可取消触发时机暴露
PreQiGainEvent是灵气即将入账,对每一处来源皆然 —— 打坐周期、赌斗结算、管理授予 —— 且在模组自身所有倍率之后。ref()、player()、amount() / setAmount(float)、baseAmount()(任何监听器动手之前的值)。
QiGainEvent否灵气已入账。ref()、player()、amount()、totalQi()。
PreMeditationStartEvent是玩家即将盘坐打坐。取消则让他继续站着。ref()、player()。
MeditationStartEvent否玩家已盘坐打坐。ref()、player()。
PreMeditationStopEvent是玩家即将停止打坐。取消可让一场仪式不可打断,或压制移动中断。ref()、player()、reason()。
MeditationStopEvent否玩家已停止。任何仪式惩罚都已施加。ref()、player()、reason()。
PreRitualStartEvent是一场计时仪式即将开始。取消后玩家继续打坐(照常存灵气),却永不进入仪式。ref()、player()、type()、requiredSeconds() / setRequiredSeconds(float)。
RitualStartEvent否首次累积仪式进度的那一 tick。ref()、player()、type()。
PreBreakthroughEvent是一次境界突破即将完成。取消可把他按在巅峰阶段 —— 进度重置,他可以再试。ref()、player()、fromRealm()、toRealm()、qiCost() / setQiCost(float)。
BreakthroughEvent否突破已完成;其阶段为 EARLY。ref()、player()、newRealm()。
PreAdvancementEvent是一次子阶段晋阶即将完成。取消可把他按在原处。ref()、player()、realm()、fromStage()、toStage()、qiCost() / setQiCost(float)。
AdvancementEvent否晋阶已完成。ref()、player()、realm()、newStage()。
PreDemotionEvent是玩家即将因放弃仪式而折损一个子阶段。取消则他全身而退 —— 存蓄的灵气也保住了。ref()、player()、realm()、oldStage()、newStage()、wasBreakthrough()。
DemotionEvent否跌境已落定;存蓄灵气被清空,随之授予的天赋点被收回。ref()、player()、realm()、oldStage()、newStage()、wasBreakthrough()。
PreDeathPenaltyEvent v0.11.2是一次死亡即将按死亡惩罚折损修士的灵气。取消则免去这次死亡的惩罚 —— 这一击也不会被记录,因此不会计入下一次死亡的档位。调用 setPercent 则改为扣除当前小阶灵气的另一个比例。它只会在这次死亡尚未被豁免(渡劫、斗法、副本、绕过等)时被询问,且在单个击杀者上限之后,因此本就免罚的死亡永远不会到达监听器。ref()、player()、strike()(这是滚动窗口中的第几次死亡,1 为第一次,含本次)、percent() / setPercent(float)(即将取走的当前小阶灵气的百分比;100 为一整阶)、basePercent()(任何监听器改动之前的值)。
DeathPenaltyAppliedEvent v0.11.2否惩罚已落定。灵气已被取走,若 stageLost() 为 true,则小阶也已跌落(经由常规的跌境,所以 PreDemotionEvent 与 DemotionEvent 会先触发)。被取消的 PreDeathPenaltyEvent 永远不会产生此事件。ref()、player()、strike()、strikesInWindow()(仍有效的受罚次数,含本次)、percent()(经前置事件监听器改动之后)、qiLost()(从灵气池中取走的量,早于跨阶跌落时的余量结转)、stageLost()、oldRealm()(跌阶绝不会改变境界)、oldStage()、newStage()、newQi()。
PreTribulationStrikeEvent是天劫雷霆即将劈向仪式中的修士。取消可完全放过他 —— 无雷、无声、无伤。把伤害设为 0 则让雷落得无伤无害。ref()、player()、damage() / setDamage(float)(在致死上限之后、护甲之前)、breakthroughRitual()。
TribulationStrikeEvent否雷已落下。ref()、player()、damage()、breakthroughRitual()。
PreHeartDevilTrialEvent是一次心魔侵扰即将折磨仪式中的修士。把扣减设为 0 可让那幻象纯粹成为装饰。ref()、player()、composureDrain() / setComposureDrain(float)、leanFraction()(0–1)、pulseIndex()(自 0 起)、breakthroughRitual()。
HeartDevilTrialEvent否一次侵扰已结算。ref()、player()、composureRemaining()、deviated()、breakthroughRitual()。
PreQiDeviationEvent是道心已碎,走火入魔即将施加。取消可免去这份惩罚 —— 仪式仍然结束。ref()、player()、demotes() / setDemotes(boolean)、qiLoss() / setQiLoss(float)、breakthroughRitual()。
QiDeviationEvent否惩罚已落定。demoted() 与 qiLost() 中恰有一个承载它。ref()、player()、demoted()、qiLost()、breakthroughRitual()。
PreRaceChangeEvent是种族即将改变。取消后种族菜单只会报告「未发生变更」。ref()、player()、oldRace()、newRace()、adminOverride()。
RaceChangeEvent否种族已改变。管理员把种族设为玩家已有的那一个时不触发。ref()、player()、oldRace()、newRace()、adminOverride()。
PreSkillUnlockEvent是一个天赋树节点即将解锁。取消则他的点数不会被花掉。ref()、player()、node()、pointCost() / setPointCost(int)。
SkillUnlockEvent否节点已解锁;点数已花,各项修正已重新施加。ref()、player()、node()。
PreRespecEvent是一次天赋树洗点即将执行。ref()、player()、refundedPoints() / setRefundedPoints(int)。
RespecEvent否每个节点都已清空,点数已返还。ref()、player()、refundedPoints()。
PreLifeBoundLevelUpEvent是一件本命法宝即将升级。取消可把它按在当前等级 —— 经验仍会存下。owner()、item()(写入升级之前的那一叠)、oldLevel()、newLevel()。
LifeBoundLevelUpEvent否法宝已升级。owner()、item()(已更新)、newLevel()。
PreAscensionEvent v0.8.0是一位修士即将开始飞升渡劫。取消则让他未经一试地留在巅峰 —— 这是服务器把天梯的结局挂在自家某样东西(一条任务、一件物品、一个日期)之后所需的唯一钩子。ref()、player()、prestiged()(他是否打算重修再起,而非留驻巅峰)。
AscensionEvent v0.8.0否一次飞升已被熬过。若结局是重修,则此事件触发时已经重置回第一重境界。它刻意不是带着特殊境界的 BreakthroughEvent —— 飞升不是突破,把它当作突破的监听者会记错东西。ref()、player()、ascensionCount()、prestiged()。
AscensionFailedEvent v0.8.0否一次尝试以失败告终。ref()、player()、abandoned()(中途离场,而非身死)。
PreTribulationOmenEvent是一场仪式的风暴征兆判定即将裁定,就在仪式的首个 tick 上。取消可强制无征兆,不论天空掷出了什么(无消息、不锁定;选择加入的请求仍保持待命);setStorm 则可朝任一方向强行定下结果。ref()、player()、naturalStormDetected()、storm() / setStorm(boolean)、breakthroughRitual()。
TribulationOmenEvent否一场仪式的风暴征兆已在首个 tick 上裁定。storm 表示它是否锁定:为 true 则仅在这一次仪式尝试的余下时段里,启用更凶险、回报更丰厚的版本。仅当判定确实发生时才触发(玩家已选择加入,或 Tribulation-Storm-Omen-Opt-In-Required 为 false)。ref()、player()、storm()、breakthroughRitual()。
PreDreamTrialEvent是一次幻境劫的侵扰即将考验空镜之中的修士。取消可整次跳过;调整 setComposureDrain 可改变它咬得多狠(设为 0 则让那倒影纯属装饰)。ref()、player()、composureDrain() / setComposureDrain(float)、pressure()、pulseIndex()。
DreamTrialEvent否幻境劫的空镜在一次尝试途中考验了一名修士。composureRemaining 是本次侵扰扣减之后剩下的道心(碎裂时为 0),broken 仅在击碎道心、令此次尝试失败的那一次侵扰上为 true,pressure 则是缩放扣减量的 0–1 比例。ref()、player()、composureRemaining()、broken()、pressure()。
PreInnerDemonTrialEvent是一次心魔宿敌之战的侵扰即将冲击决战中的修士。取消可整次跳过;调整 setComposureDrain 可改变它咬得多狠(设为 0 则让那幻象纯属装饰)。ref()、player()、composureDrain() / setComposureDrain(float)、echoIntensity()、pulseIndex()、nemesisEcho()。
InnerDemonTrialEvent否一场心魔宿敌之战冲击了决战中的修士。composureRemaining 与 broken 的含义同幻境劫;echoIntensity 是缩放扣减量的 0–1 比例,nemesisEcho 则在幻影顶着一位当前宿敌的面孔时为 true。ref()、player()、composureRemaining()、broken()、echoIntensity()、nemesisEcho()。
PreCleanseRiteEvent是洗髓之礼的一轮即将检验仪式中的修士。取消可整轮跳过;调整 setComposureDrain 可改变它咬得多狠(设为 0 则让这一轮纯属装饰)。ref()、player()、composureDrain() / setComposureDrain(float)、targetMagnitude()、pulseIndex()、companionPresent()。
CleanseRiteEvent否洗髓之礼的一轮检验了仪式中的修士。broken 仅在致使洗髓失败的那一轮上为 true(所针对的损伤随之加深),targetMagnitude 是所针对损伤入礼时的强度,companionPresent 则在结缘的道侣、师父或弟子近到足以减轻扣减时为 true。ref()、player()、composureRemaining()、broken()、targetMagnitude()、companionPresent()。
PreRitualAbortEvent是修士请求从已启动的突破或晋阶中退出。/cultivation meditate abort 报价时触发一次,abort confirm 时再触发一次,因此否决会赶在玩家被告知代价之前就回绝;于是同一次退出可能触发两次。取消即回绝;此时尚未扣任何东西。取消后指令自己不发任何消息,所以监听器应当自行说明缘由。ref()、player()、type()、qiLost()。
RitualAbortEvent否修士以 /cultivation meditate abort 从已启动的突破或晋阶中退出。qiLost 是散去的存蓄灵气(已扣除);不会跌境。他们是经一次普通的 COMMAND 停止而起身的,所以 MeditationStopEvent 也会触发。ref()、player()、type()、qiLost()。
AscensionLegacyEvent否一次飞升以传承结局告终(/ascend legacy sect 或 /ascend legacy self)。总是在同一次飞升的 AscensionEvent 之后紧接着触发,因为传承结局本身也是一种重修式的重置。sectBeneficiary 表示实际授予了谁:为宗门铭刻传承碑则为 true,授予传承之尘则为 false —— 包括那种本欲惠及宗门、却因宗门已不在而退为传承之尘的尝试,由 sectFallback 加以区分。仅当 sectBeneficiary 为 true 时才设置 sectName。ref()、player()、sectBeneficiary()、sectFallback()、sectName()。
PreReincarnationEvent是一位修士即将开始轮回。取消则让他未经一试地留在当前境界 —— 这是服务器把这一结局挂在自家某样东西(一条任务、一件物品、一个日期)之后所需的唯一钩子,与 PreAscensionEvent 对另一个终章所起的作用相同。ref()、player()。
ReincarnationEvent否一位修士完成了轮回(转世)—— 与飞升并列的另一个终章。fromRealm / toRealm 分别是舍下的境界,与部分重置之后落脚的境界;bloodlinePointsGranted 是刚刚加入其 ReincarnationLedger 条目的血脉点数(是累计增量,不是新的总数)。ref()、player()、fromRealm()、toRealm()、bloodlinePointsGranted()。
ReincarnationFailedEvent否一位修士的轮回尝试以失败告终。ref()、player()、abandoned()。
PlayerKillEvent否一位修士击杀了另一位,且这次击杀有报酬。通用的玩家对玩家钩子:模组自己为一次击杀支付的一切(魔道灵气、大道行止、五行奖励、掉落的秘籍)都在它触发之后立即记账。仅对通过防刷关卡(Pk-Same-Victim-Cooldown-Seconds、Pk-Min-Victim-Realm)的击杀触发,对自杀、环境致死,以及正在遁走的元婴所落下的击杀则永不触发。刻意不设 Pre 孪生事件。sanctionedDuel 在这场死亡了结了一场斗法时为 true;模组此时会扣下自己的 PvP 奖励,替击杀付酬的扩展也该如此。killer()、killerPlayer()、victim()、victimPlayer()、sanctionedDuel()。

声明为 @Nullable 的有:player()(所有携带它的事件);sectName();victimPlayer()。

这些所覆写的配置键:setRequiredSeconds 对应 Breakthrough-Base-Seconds 与 Advancement-Base-Seconds;PreTribulationStrikeEvent.setDamage 对应 Tribulation-Damage-Percent-Of-Max-Health 与 Advancement-Tribulation-Damage-Percent-Of-Max-Health;setComposureDrain 对应 HeartDevil-Composure-Drain-Per-Pulse;setDemotes / setQiLoss 对应 HeartDevil-Deviation-Demotes 与 HeartDevil-Deviation-Qi-Loss-Percent;PreRespecEvent 映照 Respec-Enabled 与 /cultivation respec 指令。见配置与指令。

淬体

plugin.siren.API.BodyTemperingEvents v0.7.1 —— 6 个事件(3 个可取消),涵盖第二条进阶阶梯:不靠采气、只靠挨打攀登的那一条 —— 伤害所换来的经验、经验所换来的层数,以及这些层数所归并成的九个淬体阶段(锻体境)。面向玩家的文档:淬体。

这里的每个监听器都运行在伤害管线之内,位于拥有受击实体的那条世界线程上:经由给你的访问器读取,绝不从中写入 Store,并保持轻量。PreXpGainEvent 可以缩放或拒绝一击的价值,扩展正是借此添加倍率,而不必重新实现护甲扫描;PreLevelUpEvent 则让躯体停在当前层数,同时经验照旧存着。

事件可取消触发时机暴露
PreXpGainEvent是修士即将因落在身上的伤害获得淬体经验。数额可改,而不只是可拒 —— 这是为单个玩家或单个场景重新调整整条阶梯的受支持做法。ref()、player()、amount() / setAmount(float)、level()。
XpGainEvent否经验已入账。ref()、player()、amount()、level()。
PreLevelUpEvent是即将提升一级淬体。取消则维持原位。ref()、player()、fromLevel()、toLevel()。
LevelUpEvent否已提升。一击跨越多级时逐级触发。ref()、player()、fromLevel()、toLevel()。
PreStageBreakthroughEvent是一次淬体阶段突破即将庆贺。与 PreLevelUpEvent 不同,取消并不会把躯体按在旧阶段上 —— 阶段由层数推出,而层数早已入账。它压制的是那番庆典:标题、音效、粒子与全服广播。ref()、player()、fromStage()、toStage()。
StageBreakthroughEvent否一副躯体跨入了新的淬体阶段(锻体境)—— 由层数推出的九级里程碑。每次经验入账至多触发一次,哪怕一击跨越了好几层。ref()、player()、fromStage()、toStage()。

声明为 @Nullable 的有:player()(所有携带它的事件)。

整套系统的总开关:Body-Tempering-Enabled。注意经验是按护甲之后计算的,因此监听器读到的 amount() 是真正穿透过来的那一部分,而非挥出的那一下。

拳法

plugin.siren.API.FistEvents v0.7.4 —— 4 个事件(2 个可取消),涵盖第三条阶梯,靠空手击中敌人攀登 —— 它是淬体的镜像,后者的收入是承受的伤害。经验按真正穿透的伤害计算,所以一记被护盾整个吃掉的拳头什么也教不会你。面向玩家的文档:拳法。

修士空手打出的每一记击打都会触发这些事件,且从伤害管线内部触发:保持监听器轻量,绝不从中写入 Store。PreXpGainEvent 携带一个可变的数额,把它设为 0 或更小,则直接取消这次入账。这四个事件的名字与 BodyTemperingEvents 的相同 —— 请用类名加以限定。

事件可取消触发时机暴露
PreXpGainEvent是即将为一记空手之击入账经验。与淬体的对应事件一样,它不止可取消 —— 它携带可变的数额,监听器因而可以缩放奖励,而不只是放行或禁止。把数额设为 0 或更小,则直接取消这次入账。ref()、player()、level()、amount() / setAmount(float)。
XpGainEvent否经验已入账。amount 是实际授予的量,已计入前置事件的缩放。ref()、player()、level()、amount()。
PreLevelUpEvent是即将升一级。取消则让修士留在原处;经验仍会存下。ref()、player()、fromLevel()、toLevel()。
LevelUpEvent否修士的拳法升了一级。一击跨越多级时逐级触发。ref()、player()、fromLevel()、toLevel()。

声明为 @Nullable 的有:player()(所有携带它的事件)。

寿元

plugin.siren.API.LifespanEvents v0.10.2 —— 6 个事件(2 个可取消),涵盖寿元:每份存档按其所达最高境界定下的在线游玩小时预算 —— 延寿、凋零、复原与到期。该系统本身在服务器上默认关闭;CultivationAPI.isLifespanEnabled() 可查知它是否开启。面向玩家的文档:寿元。

每个监听器都运行于 LifespanSystem 的 tick,或拥有该实体的世界线程上的某个指令处理器之中。经由给你的访问器读取,并把写入排到 CommandBuffer 上。

此类中声明的枚举:

  • ExtendSource:BREAKTHROUGH —— 境界最高纪录的上升,纯属告知性质(它为何跳过前置事件,见 LifespanManager 自己的文档);PILL —— 延寿丹;ADMIN —— /cultivation admin extendlifespan。
事件可取消触发时机暴露
PreLifespanExtendEvent是即将授予额外小时(仅限 ExtendSource.PILL / ExtendSource.ADMIN —— ExtendSource.BREAKTHROUGH 的境界纪录上升,在寿元察觉时早已发生,故只触发后置事件)。取消可直接拒绝这次授予,或缩放 setHours 以改变实际存入的量。ref()、player()、source()、hours() / setHours(float)。
LifespanExtendEvent否额外小时已实际存入(对 ExtendSource.BREAKTHROUGH 而言,则是境界纪录所定的预算上升了)。hours 是实际施加的量,已计入 PreLifespanExtendEvent 的缩放。ref()、player()、hours()、source()。
LifespanWitherEvent否一位修士的寿元预算归零,进入凋零的宽限状态。ref()、player()。
LifespanRestoreEvent否一位修士的寿元时钟被重置为一份新的预算 —— 一次真正的轮回、一次真正的飞升、LifespanConfig.ExpiryAction.NOTHING 化解凋零,或寿终自己的重置(后者另会触发 LifespanExpireEvent)。ref()、player()。
PreLifespanExpireEvent是一位修士的寿元预算即将归零并进入凋零。在此取消,则对本次越线彻底否决凋零 —— 时钟停在 0,下个 tick 又会触发,所以意图给予缓刑的扩展还应同时延长预算(否则立刻又会被问一遍)。ref()、player()。
LifespanExpireEvent否一位修士的凋零宽限已耗尽,Lifespan-Expiry-Action 即将执行。此事件不可取消 —— 触发时宽限期已然过去;要否决凋零本身,请在更上游使用 PreLifespanExpireEvent。ref()、player()、action()。

声明为 @Nullable 的有:player()(所有携带它的事件)。

经脉损伤

plugin.siren.API.MeridianEvents v0.9.1 —— 5 个事件(3 个可取消),涵盖一处命名的经脉损伤被施加或加深、被治愈,以及丹田龟裂的灵气外溢被启动。面向玩家的文档:经脉损伤。

事件可取消触发时机暴露
PreMeridianInjuryEvent是一处损伤即将落下(若已背负则是加深)。取消可直接回绝;用 setMagnitude / setDurationSeconds 可在写入之前重新缩放这次掷出的结果。ref()、player()、injury()、cause()、magnitude() / setMagnitude(float)、durationSeconds() / setDurationSeconds(float)。
MeridianInjuryEvent否一处损伤已落下(或已加深)—— 写入早已完成。ref()、player()、injury()、magnitude()、durationSeconds()。
PreMeridianCureEvent是一处损伤即将治愈。取消可回绝(它仍然留着)。ref()、player()、injury()、cureSource()。
MeridianCureEvent否一处损伤彻底消退(静候自愈、打坐调养,或一次明确的治疗)。ref()、player()、injury()、cureSource()。
PreMeridianSpillEvent是丹田龟裂的灵气外溢即将启动(仅在落下/加深时触发一次,而非每个 tick)。取消则把此后的灵气增长封顶在新的上限,而不抽走已存的超额部分;用 setRatePerSecond 可调整超额部分流失的快慢。ref()、player()、excessQi()、ratePerSecond() / setRatePerSecond(float)。

声明为 @Nullable 的有:player()(所有携带它的事件)。

元婴遁走

plugin.siren.API.SoulEscapeEvents v0.10.2 —— 8 个事件(3 个可取消),涵盖致命一击下的缓刑(元婴遁走)、追杀,以及它如何收场:存活、湮灭、超时或放弃。面向玩家的文档:元婴遁走。

没有任何公开门面可以开启一场遁走;只有一记符合条件的致命一击才会开启。这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

此处有两个枚举:SanctuaryKind(ABODE、SECT_HALL、FORMATION)与 ForfeitReason(DISCONNECT、RELOG_RESOLVED、WORLD_CHANGE、PLUGIN_RELOAD)。

事件可取消触发时机暴露
PreSoulEscapeBeginEvent是致命一击即将被取消,元婴即将开始逃亡。取消则不遁走:不扣任何东西,那一击仍是致命的。三个 setter 可重新调整时限与各项代价。soul()、killer()、realm()、windowSeconds() / setWindowSeconds(float)、qiCostPercent() / setQiCostPercent(float)、lifespanHours() / setLifespanHours(float)。
SoulEscapeBeginEvent否遁走开始:致命一击被取消,元婴正在逃亡。windowSeconds 是时限的长度;qiSpent 与 lifespanHoursSpent 是这次尝试所扣的代价。soul()、killer()、realm()、windowSeconds()、qiSpent()、lifespanHoursSpent()。
PreSoulSurviveEvent是一个逃亡中的元婴刚刚进入一处庇护所。取消则这处庇护所不算数:元婴继续逃亡。setter 可调整恢复的生命、虚弱的时长,以及付给击杀者的功德。soul()、killer()、kind()、world()、chunkX()、chunkZ()、restoreHealthPercent() / setRestoreHealthPercent(float)、weakenedMinutes() / setWeakenedMinutes(float)、spareMerit() / setSpareMerit(float)。
SoulEscapeSurviveEvent否逃亡的元婴抵达庇护所并回归肉身,虚弱 weakenedMinutes 分钟。kind 表明是哪一类庇护所;meritToKiller 是因饶恕他们而记在击杀者名下的功德。soul()、killer()、kind()、world()、chunkX()、chunkZ()、weakenedMinutes()、meritToKiller()。
PreSoulExtinguishEvent是一击刚刚落在逃亡的元婴身上。取消则这一击不起作用;元婴继续逃亡。soul()、extinguisher()、hitsSoFar()、hitsRequired()、extraKarma() / setExtraKarma(float)、extraYinShift() / setExtraYinShift(float)。
SoulEscapeExtinguishEvent否一个逃亡的元婴在抵达安全之处前再度被击中,遁走就此以真正的死亡告终。extraKarma 与 extraYinShift 是在寻常击杀自身的代价之上,另记在湮灭者名下的额外惩罚。soul()、extinguisher()、extraKarma()、extraYinShift()。
SoulEscapeTimeoutEvent否时限已尽而元婴仍未抵达庇护所,遁走以真正的死亡告终。soul()、killer()。
SoulEscapeForfeitEvent否遁走未能归结为存活、湮灭或超时便告终止。reason() 说明缘由:DISCONNECT、RELOG_RESOLVED、WORLD_CHANGE 或 PLUGIN_RELOAD。soul()、killer()、reason()。

声明为 @Nullable 的有:killer()(所有携带它的事件)。

修行传承

plugin.siren.API.LegacyEvents v0.10.1 —— 2 个事件(1 个可取消),涵盖一位隐退修士的突破消耗减免加成送达他所选定的传人。这份馈赠可取消,也可重新调整。面向玩家的文档:修行传承。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

事件可取消触发时机暴露
PreLegacyPayoutEvent是一份传承加成即将授予或排入队列。取消可直接回绝 —— 此时尚未写入或排队任何东西。监听器也可在派发结束前用 setReductionPercent / setExpiresAtMillis 重新缩放;留在这些字段里的值,就是实际授予或排队的值。benefactorUuid()、benefactorName()、heirUuid()、retiringRealmOrdinal()、sourceProfileName()、reductionPercent() / setReductionPercent(float)、expiresAtMillis() / setExpiresAtMillis(long)。
LegacyPayoutEvent否一份传承加成已实际送达(或已排入)传人 —— 这里所述的减免是最终数额:即时发放时是计入近期存档缩减之后的值,排队发放时则是缩减之前的基础值(见 queued)。benefactorUuid()、benefactorName()、heirUuid()、reductionPercent()、expiresAtMillis()、sourceProfileName()、queued()。

修炼存档

plugin.siren.API.ProfileEvents v0.7.0 —— 7 个事件(3 个可取消),涵盖玩家的修炼存档:在已存的修士之间切换、创建一位、抹去一位,以及试炼存档到期。面向玩家的文档:修炼存档。

这些事件携带一个 Profile 负载(CultivationProfilesComponent.Profile)—— 常用的成员有 getName()、isTest()、getExpiresAtMillis() 与 remainingMillis(long)。注意到期没有前置事件:试炼存档的时限无法被否决。

这些监听器可以写入。 在整个接口中独此一处:存档监听器运行在所属世界线程上,且不处于任何 tick 系统之内,因此在此处经由 Store 直接读取并写入组件是安全的 —— 这是「监听器内绝不写入」这条通则唯一的例外。这是刻意为之:一个进阶体系扩展必须能在切换存档时保存并载入自己的状态(见 ProgressionProvider.supportsProfiles())。

事件可取消触发时机暴露
PreProfileSwitchEvent是玩家即将切换存档。取消可回绝这次切换 —— 指令会报告切换被拦下。ref()、player()、from()(首次补建存档时为 null)、to()。
ProfileSwitchEvent否切换已生效 —— 抵达存档所对应的境界、灵气、种族、大道、天赋树与功法皆已写入组件。请在此载入你自己的按存档状态。ref()、player()、from()(首次补建存档时为 null)、to()。
PreProfileCreateEvent是一份全新存档即将创建。取消可回绝之 —— 不占用任何存档位。ref()、player()。
ProfileCreateEvent否存档已存在,玩家已切换至其上。ref()、player()、profile()。
PreProfileDeleteEvent是一份存档即将被永久删除。取消可保留它。ref()、player()、profile()。
ProfileDeleteEvent否存档已被删除。请在此清除你自己为其保存的状态。ref()、player()、profile()。
ProfileExpireEvent否一份试炼存档的墙上时限已到期。wasActive() 表明玩家此前是否正在游玩它 —— 若是,他此刻刚被放回了一份真正的存档上。ref()、player()、profile()、wasActive()。

声明为 @Nullable 的有:from()(所有携带它的事件)。

若你的扩展自行维系一套进阶体系,请处理 PreProfileSwitchEvent(保存即将离开的那份存档)与 ProfileSwitchEvent(载入抵达的那份),随后令 ProgressionProvider.supportsProfiles() 返回 true —— 在你这样做之前,只要你的进阶体系仍装着,切换就会被直接回绝,而非做到一半。上限同样可由扩展提升:接口参考上的 registerProfileCap 可将默认的三个存档位上调(上限为六,取最高的注册值,且上限下调时绝不会销毁任何东西)。

大道、功法与誓言

元素、阴阳与业力,天道与个人之道,道域,功法,战斗深度与天道誓言。

大道与业力

plugin.siren.API.DaoEvents —— 14 个事件(6 个可取消),涵盖元素、偏移、阴阳之衡、德行道途与业力。面向玩家的文档:灵根、天道与业力。

阴阳与业力几乎在每个打坐周期与每次击杀时都在变动,因此这些事件触发得很频繁。请让监听器保持轻量;若你只关心结果,请优先用道途与偏移事件。

此类中声明的枚举:

  • ElementChangeReason:CHOSEN —— 他们亲自择定的:免费的首次选择,或付费的改换;DRIFT —— 他们的行止压倒了所择之道,于是它自行转化。
事件可取消触发时机暴露
PreDaoElementChangeEvent是修士即将择定或改换某一元素。取消后它会报告「道未变更」。ref()、player()、dao()、oldElement()(首次择道时为 null)、newElement() / setNewElement(DaoElement)、reason()、qiCost() / setQiCost(float)(首次择道与 DRIFT 时恒为 0)。
DaoElementChangeEvent否元素已改变。ref()、player()、dao()、oldElement()、newElement()、reason()、qiCost()。
PreDaoAffinityGainEvent是行止亲和即将被加到某一元素上 —— 那正是最终导致偏移的压力。player()、dao()、element()、amount() / setAmount(float)。
DaoAffinityGainEvent否亲和已加上。player()、dao()、element()、amount()。
DaoDriftWarningEvent否修士已被警示其道正在偏移。每出现一个新的威胁元素触发一次。player()、dao()、chosenElement()、driftingTo()。
PreAlignmentShiftEvent是一次阴阳偏移即将施加。种族偏向的分流发生在此之后。dao()、amount() / setAmount(float)(原始偏移量)、towardYin()。
AlignmentShiftEvent否阴阳之衡已移动。dao()、yin()、yang() —— 种族偏向分流之后实际加上的量。
PrePathChangeEvent是德行道途即将改变。取消后底层的阴阳之衡分毫不动,因此这只是压制了那次重新归类。player()、dao()、oldPath()、newPath()。
PathChangeEvent否道途已改变并已昭告。player()、dao()、oldPath()、newPath()。
PreKarmaGainEvent是业力即将因一次击杀而记账。取消可让账簿保持清白。player()、dao()、amount() / setAmount(float)、farmedKill()(防刷窗口内的重复击杀 —— 不产灵气,业力却更重)。
KarmaGainEvent否业力已记账。player()、dao()、amount()、total()(在 Karma-Max 封顶之后)、farmedKill()。
KarmaClearedEvent否业力已消解 —— 或因挺过一道天劫落雷,或因久不杀生的墙上时钟衰减。dao()、amount()、total()、fromTribulation()。
PreDevilHarvestEvent是一名魔道修士即将从被斩杀的玩家身上掠夺存蓄灵气。killer()、killerPlayer()、qi() / setQi(float)。
DevilHarvestEvent否掠夺已发生。killer()、killerPlayer()、qi()。

声明为 @Nullable 的有:ref()(所有携带它的事件);player()(所有携带它的事件);oldElement()(所有携带它的事件)。

这些所覆写的配置键:PreDaoElementChangeEvent.setQiCost 对应 Dao-Switch-Base-Qi-Cost 与 Dao-Switch-Qi-Cost-Realm-Multiplier;PreDaoAffinityGainEvent.setAmount 对应 Dao-Affinity-Per-Elemental-Kill(由 Dao-Drift-Margin 决定偏移何时触发);PreAlignmentShiftEvent.setAmount 对应 Meditation-Alignment-Shift-Per-Tick 与 Kill-Yin-Amount,其后置事件的分流则由 Qi-Alignment-Yin-Bias-Percent 支配;PreKarmaGainEvent.setAmount 对应 Karma-Per-Player-Kill 与 Karma-Per-Farmed-Kill;PreDevilHarvestEvent.setQi 对应 Path-Devil-PK-Qi-Reward。

大道领悟

plugin.siren.API.DaoComprehensionEvents v0.9.0 —— 11 个事件(5 个可取消),涵盖叠在元素之道上的那一层:天道的领悟轨道、开放的个人之道注册表(内置七门 —— 剑道、杀戮道、时空道、灵兽道、魔道、炼体道与元素道 —— 外加模组在它们之侧添加的任何一门),以及悟道。它与 DaoEvents 并列而不取而代之。面向玩家的文档:天道。

HeavenlyDaoGainEvent 对每位打坐的玩家每打坐一秒触发一次(外加每挺过一道天劫落雷、每次晋阶与突破各一次),PersonalDaoComprehensionEvent 则在每次符合条件的击杀与每次功法施展时触发 —— 这两者的监听器都请保持轻量。

事件可取消触发时机暴露
PreHeavenlyDaoGainEvent是天道的领悟进度即将推进。取消可回绝;用 setAmount 可重新缩放。player()、comprehension()、amount() / setAmount(float)。
HeavenlyDaoGainEvent否天道的领悟进度已推进。amount 是实际施加的量(已计入监听器的缩放);total 是其后的值。player()、comprehension()、amount()、total()。
PreHeavenlyDaoRankChangeEvent是玩家的天道品阶即将变更。取消则让他留在当前品阶 —— 底层的数值分毫不动,所以这只是压制了重新归类与昭告。player()、comprehension()、oldRank()、newRank()。
HeavenlyDaoRankChangeEvent否玩家的天道品阶已变更(并已告知本人)。player()、comprehension()、oldRank()、newRank()。
PrePersonalDaoComprehensionEvent是某门个人之道的领悟即将推进。取消可回绝;用 setAmount 可重新缩放。player()、comprehension()、dao()、amount() / setAmount(float)。
PersonalDaoComprehensionEvent否某门个人之道的领悟已推进。amount 是实际施加的量;total 是其后的值。player()、comprehension()、dao()、amount()、total()。
PrePersonalDaoManifestEvent是某门个人之道即将显化。取消则让它停在已领悟而未显化的状态。player()、comprehension()、dao()。
PersonalDaoManifestEvent否某门个人之道为该玩家显化了。player()、comprehension()、dao()。
PersonalDaoSetAsideEvent否一门已显化的个人之道被放下了。player()、comprehension()、dao()。
PreDaoEnlightenmentEvent是一次悟道即将触发。取消即视同这次掷骰从未发生;用 setComprehensionGain 与 setQiGain 可重新缩放奖励。setQiGain 能压低灵气爆发,却无法把它抬过服务器的绝对上限 —— 该上限在本事件之前施加一次,读回 qiGain() 之后又施加一次。player()、comprehension()、subject()、comprehensionGain() / setComprehensionGain(float)、qiGain() / setQiGain(float)。
DaoEnlightenmentEvent否一次悟道触发了。subject 是引发它的那门天道或个人之道。player()、comprehension()、subject()、comprehensionGain()、qiGain()。

声明为 @Nullable 的有:player()(所有携带它的事件)。

道域

plugin.siren.API.DaoDomainEvents v0.11.1 —— 8 个事件(2 个可取消),涵盖修士以道域之心展开的那片锚定区域:展开、崩塌,以及敌对道域、首领的道域或敌对宗门大阵与之重叠时的交锋;此外还有首领道域与共鸣所需的生灵自己的展开与崩塌,以及盟友道域的配对。面向玩家的文档:道域,交锋部分见道域交锋。

这里的玩家与生灵以 UUID 而非 PlayerRef 标识:一方道域可能在其施放者的实体消失之后才崩塌。用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。element() 是施放者的大道元素;若道域是以天地灵气施放的(没有大道,或所修元素没有属于自己的风貌),则为 null。因施放者断线而造成的崩塌不触发任何事件:持有道域的实体已经不在,也没有什么会来察觉,其效果会在一秒之内自行消退。

每个监听器都在施放者的世界线程上运行(生灵事件则在生灵的世界线程上)。保持轻量,且不要在监听器里写入 Store。

此类中声明的枚举:

  • CollapseReason:EXPIRED —— 持续时间耗尽;LEFT_AREA —— 施放者走出了道域;DIED —— 施放者死亡(或化作逃遁的魂体);LEFT_WORLD —— 施放者换了世界,锚点不在他所处的世界里;GATE —— 道域进行中某道拒绝关口触发:打坐、突破途中、试炼、识海、庇护之所;DISABLED —— 道域(或功法使用)被关闭;CLASHED —— 该道域在与敌对道域或宗门大阵的交锋中落败,或与之打成平局(平局使双方道域皆碎裂)。为同一次交锋触发的 DomainClashEvent,就在它之前。
  • NpcDomainKind:CALAMITY —— 灾劫兽;EVENT_BOSS —— 活动世界首领;WARDEN —— 虚空裂隙守护者;ROGUE —— 元婴及以上的散修客;TEST —— 管理员在普通生灵身上设下的测试道域。
  • NpcCollapseReason:EXPIRED —— 持续时间耗尽;LEFT_AREA —— 生灵走出自己道域的时间超过了宽限;DIED —— 生灵死亡;ENCOUNTER_ENDED —— 遭遇战结束或生灵被移出世界;DISABLED —— 首领道域、道域或功法被关闭;CLASHED —— 被玩家的道域击败或打成平局。它自成一个枚举,这样给 CollapseReason 添加常量就不会破坏穷举 switch。
  • ResonanceMode:FULL —— 一种元素生养另一种;LESSER —— 天地灵气与元素道域谐和,威力减半。
  • Outcome:FIRST_WON —— first 的交锋威势更高(对手是大阵时:道域胜过了大阵);SECOND_WON —— second 的交锋威势更高(对手是大阵时:大阵胜过了道域);TIE —— 威势相等。两方道域皆碎裂;道域对大阵时,只有道域碎裂,大阵屹立不倒。
事件可取消触发时机暴露
PreDomainUnfoldEvent是一方道域即将展开:这次施放的各道关口都已通过,尚未扣任何灵气。取消则施放与被拒绝一样地失败 —— 不扣任何东西,不触发冷却,也没有道域 —— 并告知施放者有某种力量阻止了它。用 setRadius、setDurationSeconds 与 setQiCost 可重新调整。caster()、element()、tier()(0 为下限境界,1 为高一个境界,2 为高两个及以上)、radius() / setRadius(float)、durationSeconds() / setDurationSeconds(float)、qiCost() / setQiCost(float)(管理员绕过或创造模式的施放者为 0,他们分文不付)。
DomainUnfoldEvent否道域立起。它在第一次脉冲之前宣告 —— 那次脉冲就可能裁决一场交锋、碎裂这方新道域,而监听器会先看到展开,再看到它所引发的崩塌。caster()、element()、tier()、radius()、durationSeconds()、qiSpent()。
DomainCollapseEvent否一方道域结束。施放者断线时不触发。caster()、element()、reason()、secondsActive()。
DomainClashEvent否两方敌对道域,或一方道域与一座敌对宗门大阵发生重叠,并已裁决出这场交锋。每次交锋触发一次,在它所引发的各个 DomainCollapseEvent 之前。first()(其脉冲发现了重叠的施放者 —— 通常是最后展开的那一位)、second()(对手是宗门大阵时为 null;管理员召出测试对手时,是一个不对应任何玩家的合成 id)、arraySect()(对手是大阵时为守方宗门的名字,否则为 null)、firstPower()、secondPower()(交锋威势,已含克制加成)、outcome()、counterDecided()(五行克制改变了结果时为 true:去掉加成,结果本会不同)。
PreNpcDomainUnfoldEvent是一只生灵即将开始蓄势展开道域:越过了某个生命节点,或管理员的测试触发。取消则不展开(该节点已被消耗)。setRealmOrdinal、setRadius 与 setDurationSeconds 可重新调整,钳制在引擎认可的范围内。npc()(生灵的实体 UUID)、roleId()、kind()、element()(天地灵气为 null)、realmOrdinal() / setRealmOrdinal(int)、radius() / setRadius(float)、durationSeconds() / setDurationSeconds(float)。
NpcDomainUnfoldEvent否生灵的道域在蓄势之后迸发。npc()、roleId()、kind()、element()、realmOrdinal()、radius()、durationSeconds()、worldName()、x()、y()、z()。
NpcDomainCollapseEvent否生灵的道域结束;原因为 CLASHED 时,在引发它的 DomainClashEvent 之后。npc()、roleId()、kind()、element()、reason()、secondsActive()、shatteredBy()(获胜的玩家,否则为 null)、staggerSeconds()(不踉跄时为 0)。
DomainResonanceEvent否两方盟友道域开始或停止共鸣。每位施放者各触发一次,从该施放者一侧看,所以一对真实玩家每次变化触发两次;管理员的测试回响只触发管理员一侧。施放者崩塌时,对每个伙伴都触发 started 为 false 的事件。caster()、partner()(测试回响为合成 id)、casterElement()、partnerElement()、mode()、casterFeeds()(LESSER 谐和中,天地灵气一方算作生养者)、started()。

声明为 @Nullable 的有:element()、casterElement() 与 partnerElement()(所有携带它们的事件);second();arraySect();shatteredBy()。

交锋按威势来裁决。一方道域的威势是其施放者的境界序号(炼体 0 至炼虚 6),若该道域的大道元素在五行相克中克制对方的元素,再加上克制加成;天地灵气的道域从不克制他人,也不被克制。宗门大阵的威势,取其配置的基础境界与领地内最强守方境界之高者,若其宗门的元素克制该道域的元素,同样再加上这一加成。威势更高者胜;威势相等为 TIE。交锋只发生在双方主人互视为敌人的道域之间 —— PvP 世界、斗法、正魔之战的对立一方,或其宗门之间一场正在进行的围攻 —— 绝不发生在盟友或中立者之间。

这些所覆写的配置键,都在 Arts/DaoDomainConfig.json:PreDomainUnfoldEvent.setRadius 对应 Domain-Radius 与 Domain-Radius-Per-Tier;setDurationSeconds 对应 Domain-Duration-Seconds 与 Domain-Duration-Per-Tier-Seconds;setQiCost 对应 Domain-Qi-Cost 与 Domain-Qi-Cost-Per-Tier。监听器留下的值在使用前会被限制范围 —— 半径 1 至 32 格,持续时间 1 至 25 秒,灵气不低于 0 —— 非有限的数字会被忽略,施放仍沿用它自己算出的值。DomainClashEvent 只读;其背后的数值是 Domain-Clash-Counter-Bonus(默认 1),由 Domain-Clash-Enabled 与 Domain-Clash-Arrays-Enabled 把关,共鸣中的施放者另加 Domain-Resonance-Clash-Bonus(默认 1)。对手是生灵的道域时,second() 为该生灵的实体 UUID。PreNpcDomainUnfoldEvent 重新调整的是 Npc-Domain-Boss-Radius、Npc-Domain-Boss-Duration-Seconds 与各境界键(Npc-Domain-Calamity-Realm 及其同类);门禁为 Npc-Domains-Enabled 与 Domain-Resonance-Enabled。整个系统的门禁:Dao-Domains-Enabled。

道印没有事件

v0.11.1 没有 DaoSealEvents 这个类。道印的反应是在 Cultivation 自己的伤害管线里结算的,那里尚未设计任何钩子。扩展转而能观察的,是道印留下的各种编号:伤害类别 Cultivation_Seal_<Element>(共十个 —— 道印自身的命中,或被转化道印转化的原版符文)与 Cultivation_DaoReaction(反应的爆发),以及实体效果 Cultivation_SealMark_<Element>、Cultivation_SealBurst_<Element>、Cultivation_SealReaction_<Element> 与隐藏的 Cultivation_SealReaction_Cooldown。DaoElement.fromDamageCause(DamageCause) 沿着伤害类别的 Inherits 链把它归到元素:道印的伤害类别解析到它的元素,Cultivation_DaoReaction 则什么也解析不到 —— 见伤害类别与元素。完整清单,连同渐进式解锁、典籍与管理员的编号,见道印。

功法

plugin.siren.API.TechniqueEvents —— 15 个事件(7 个可取消),涵盖功法的施展与习得、两门合为第三门的合道、熟练度、御剑飞行的开关,以及计时战斗增益。面向玩家的文档:功法与秘籍。

对经由 CultivationAPI.registerTechnique 注册的第三方功法,这些事件与对内置功法完全一样地触发 —— 关卡、消耗与冷却的管线是共用的。

此类中声明的枚举:

  • BuffType:IRON_BODY —— 金刚不坏:固定的受伤减免;QI_INFUSION —— 真气灌注:输出伤害加成;QI_BARRIER —— 护体真气:吸收伤害的护盾池;CLOUD_STEP —— 疾风步:移动速度倍率。
  • FlightStopReason:TOGGLE —— 他们自己关掉了它;QI_EXHAUSTED —— 飞行途中灵气耗尽;DEATH —— 他们死了;飞行状态被稳妥地清理掉。
事件可取消触发时机暴露
PreTechniquePerformEvent是一门功法即将施展 —— 每道关卡都已通过。取消可静默回绝:不耗灵气,不进冷却。ref()、player()、technique()、qiCost() / setQiCost(float)、cooldownSeconds() / setCooldownSeconds(float)(小于等于 0 则不盖冷却戳)。
TechniquePerformEvent否灵气已耗、冷却已盖戳、效果已运行。ref()、player()、technique()、qiCost()。
PreTechniqueLearnEvent是一门功法即将被永久习得。取消可回绝之 —— 无论如何秘籍都会被消耗,正如一本传授已知功法的秘籍照样会被用掉。ref()、player()、techniqueId()。
TechniqueLearnEvent否功法已习得。宗门所授的功法是实时解算的,永不触发此事件 —— 请改为监听宗门碑文事件。ref()、player()、techniqueId()。
PreSwordFlightStartEvent是修士即将御剑升空。ref()、player()、horizontalSpeed() / setHorizontalSpeed(float)、verticalSpeed() / setVerticalSpeed(float)。
SwordFlightStartEvent否他已凌空。ref()、player()、horizontalSpeed()、verticalSpeed()。
PreSwordFlightStopEvent是修士即将落地。对 TOGGLE 取消是安全的,但取消一次 DEATH 落地会把飞行状态留在一具尸体上 —— 请按 reason() 加以判别。ref()、player()、reason()。
SwordFlightStopEvent否他已落地;其坐骑(若有)也已消失。ref()、player()、reason()。
PreTechniqueBuffApplyEvent是一项计时功法增益即将施加。ref()、player()、type()、durationSeconds() / setDurationSeconds(float)、magnitude() / setMagnitude(float)。
TechniqueBuffApplyEvent否增益已生效。magnitude 表示该增益所度量的东西 —— 一个减伤百分比、一个伤害百分比、一个护盾池、一个速度倍率。ref()、player()、type()、durationSeconds()、magnitude()。
TechniqueBuffExpireEvent否疾风步的速度倍率已被撤回,或因到期,或因清理。ref()、player()、type()。
PreTechniqueMasteryAdvanceEvent是一门功法即将升上一级熟练阶。取消则让它停在原处 —— 经验与已研读的秘籍仍存着,所以只要它的任何情形再有变动,便会重新尝试。ref()、player()、techniqueId()、stage()(它正在升至的那一级)。
TechniqueMasteryAdvanceEvent否一门功法的熟练度升了一阶。ref()、player()、techniqueId()、stage()。
PreTechniqueFusionEvent v0.8.0是一次合道即将尝试 —— 每一道关卡(两门母法皆臻顶峰、境界下限、灵气、冷却)都已通过。取消即无声回绝:不扣灵气、不记冷却、两门母法分毫无损。三个 setter 可在不改动 TechniqueConfig.json 的前提下,只为这一次尝试重新调参。ref()、player()、fusionId()、resultTechniqueId()、qiCost() / setQiCost(float)、consumeParents() / setConsumeParents(boolean)、failureChancePercent() / setFailureChancePercent(float)。
TechniqueFusionEvent v0.8.0否一次合道已成,结果功法已授予。ref()、player()、fusionId()、resultTechniqueId()。

声明为 @Nullable 的有:TechniqueLearnEvent、TechniqueBuffApplyEvent、TechniqueFusionEvent、TechniqueBuffExpireEvent、TechniqueMasteryAdvanceEvent、PreTechniqueLearnEvent、PreTechniqueBuffApplyEvent、PreTechniqueFusionEvent、PreTechniqueMasteryAdvanceEvent 上的 player()。

这些所覆写的配置键:PreTechniquePerformEvent 映照功法规则中各门功法自己的 Qi-Cost 与 Cooldown-Seconds 条目(见配置),以及指令页上的 /cultivation technique <id> 指令。PreTechniqueLearnEvent 会为玩家求得的每一门功法触发,无论出自哪一条解锁途径 —— 阅读秘籍、打坐中的顿悟、突破所开、宗门铭刻,或师父亲授 —— 故监听者无须理会究竟是哪一条。

一次合道是否消耗了两门母法,刻意不由 TechniqueFusionEvent 携带:请监听授予时触发的普通 TechniqueLearnEvent,并留意消耗型配方是经 TechniqueUnlockManager.revoke 移除母法的,而后者不触发自己的事件 —— 在正常玩法中,除了合道与管理员工具,没有任何东西会剥夺所学之物。

战斗深度

plugin.siren.API.CombatDepthEvents v0.10.1 —— 4 个事件(2 个可取消),涵盖功法被打断,以及元素克制占优时所发放的五行 PvP 奖励。破绽窗口不触发任何自己的事件 —— 它是战斗系统内部消耗的一个伤害倍率。面向玩家的文档:战斗深度。

事件可取消触发时机暴露
PreTechniqueInterruptEvent是一位正在蓄力的修士所凝聚的功法即将被一记足够重的击打打断。取消可让蓄势不受打断地继续;setDamageAmount 可重新缩放带入配对后置事件的数值(此事件触发之后,打断本身仍会发生 —— 引发它的伤害早已落下)。ref()、player()、damageAmount() / setDamageAmount(float)。
TechniqueInterruptEvent否一位蓄力的修士所凝聚的功法被一记足够重的击打打断了。damageAmount 是 PreTechniqueInterruptEvent 最终定下的(可能已重新缩放的)数值。ref()、player()、damageAmount()。
PreWuxingPvpRewardEvent是一次五行克制占优的 PvP 击杀即将发放五行奖励。取消即拒发;用 setSpiritStones 可重新缩放实际授予的数量。killer()、killerPlayer()、spiritStones() / setSpiritStones(int)。
WuxingPvpRewardEvent否一次五行克制占优的 PvP 击杀发放了五行奖励。killer()、killerPlayer()、spiritStones()。

声明为 @Nullable 的有:player()(所有携带它的事件)。

天道誓言

plugin.siren.API.OathEvents v0.9.0 —— 8 个事件(4 个可取消),涵盖立下、违背与和平解除一道天道誓言,以及平复背誓所留下的道心破损。面向玩家的文档:天道誓言。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

此类中声明的枚举:

  • FlawCleanseRoute:EXPIRED —— 其墙上时钟的计时自行走完;ITEM —— 消耗了一件平复之物;COMPANION —— 在所负誓约之人身旁打坐,提前将其烧尽。
事件可取消触发时机暴露
PreOathSwearEvent是一份待决的邀约即将被接受,成为有约束力的誓言。取消可回绝 —— 无论如何这份邀约都已消耗,所以发起者须再发一份新的。offerer()、accepter()、type()、stake() / setStake(int)、sectId()。
OathSwornEvent否一份待决邀约被接受,誓言就此立下(生效)。oathId()、type()、partyA()、partyB()、stake()、sectId()。
PreOathBreachEvent是一道已立之誓即将被记为背誓,并施加惩罚。取消可径直赦免这次背誓(分毫不变 —— 无灵气损失、无业力、无道心破损);改用各 setter 则只是重新调整惩罚。oathId()、type()、breaker()、victim()、qiLossPercent() / setQiLossPercent(float)、karmaSwing() / setKarmaSwing(float)、flawDurationMinutes() / setFlawDurationMinutes(float)、flawSeverity() / setFlawSeverity(float)。
OathBreachEvent否一道已立之誓被违背了,惩罚已经施加。oathId()、type()、breaker()、victim()、qiLost()、karmaGained()。
PreOathFlawCleanseEvent是一处道心破损即将平复。取消可回绝这次尝试(物品若有,是否消耗仍由调用方决定 —— 见调用点)。player()、route()。
OathFlawCleanseEvent否一位修士的道心破损经 route 途径平复了。player()、route()。
PreOathDissolveEvent是一道已立之誓即将和平解除。取消则让它继续有效(不起变化 —— 提出的一方须再请求一次)。oathId()、type()、partyA()、partyB()。
OathDissolveEvent否一道已立之誓和平解除了 —— 无惩罚,或是出于双方一致的 /cultivation oath dissolve,或是那一种由系统触发的无过错情形(见 OathManager.dissolveActiveOath)。oathId()、type()、partyA()、partyB()。

物品与炼制

掉落、丹药、灵核与秘籍,以及造出新物的诸般手艺:炼器、炼丹、锻造与符箓,外加兵器之中的灵。

物品

plugin.siren.API.ItemEvents —— 12 个事件(6 个可取消),涵盖修炼掉落、丹药、修行之核、秘籍与炼器。面向玩家的文档:聚灵采气、炼丹、秘籍、炼器。

从秘籍中习得功法会触发 TechniqueEvents 中的功法习得事件;传授天赋节点的秘籍则走 CultivationEvents 里的天赋解锁事件。本类涵盖的是秘籍物品本身。

此类中声明的枚举:

  • LootType:CULTIVATION_CORE —— 某一品阶的修行之核:灵核、玄核或神核(读 itemId 可知是哪一种);BEAST_EGG —— 灵兽蛋;SPIRIT_STONE —— 灵石,洞府供奉所用的通货;MANUAL —— 一本修炼秘籍;TREASURE_MATERIAL —— 在埋藏宝藏或遗迹宝库中找到的制作材料 —— 见 plugin.siren.Utils.Treasure.TreasureCacheManager。
  • RefinementOutcome:SUCCESS —— 兵器受了元素,抵达目标阶位;DESTROYED —— 尝试失败,兵器被毁;DEMOTED —— 尝试失败,兵器跌了一个阶位;FAILED —— 尝试失败却无伤大雅 —— 只损失了灵气。
事件可取消触发时机暴露
PreLootDropEvent是一份修炼掉落即将交付。取消可拒绝它。ref()、player()、type()、itemId() / setItemId(String) —— 可整个替换成另一件物品。
LootDropEvent否掉落已落入玩家背包并已昭告。判定未中、或物品放不下时永不触发。ref()、player()、type()、itemId()。
PreManualReadEvent是一本秘籍即将授法。取消可回绝之 —— 无论如何秘籍都会被消耗。ref()、player()、techniqueId()(传授功法时有值)、skillNodeId()(传授节点时有值)。
ManualReadEvent否秘籍已被阅读,其所授已施加。ref()、player()、techniqueId()、skillNodeId()。
PrePillConsumeEvent是一枚灵丹即将生效。取消则该丹药不会被消耗。ref()、player()、effect() —— 该交互所配置的效果 id。
PillConsumeEvent否丹药已服下,其药力已施加。ref()、player()、effect()。
PreSpiritCoreConsumeEvent是一枚修行之核即将被吸收。取消则该核不会被消耗。ref()、player()、qi() / setQi(float)(打坐加成已折入其中)、meditating()。
SpiritCoreConsumeEvent否核已被吸收。ref()、player()、qi() —— 实际入账的量。
PreRefinementStartEvent是一场炼器仪式即将开始。取消则不耗灵气。ref()、player()、element()、targetTier()、qiCost() / setQiCost(float)。
RefinementStartEvent否仪式已开始;灵气已耗,修士已落座。ref()、player()、element()、targetTier()、qiCost()。
PreRefinementCompleteEvent是一场炼器仪式即将结算。取消可静默中止 —— 兵器分毫不动,但预先付出的灵气仍是耗掉了。ref()、player()、element()、targetTier()、successChance() / setSuccessChance(float) —— 填 1 必成,填 0 必败。
RefinementCompleteEvent否仪式已结算。ref()、player()、element()、targetTier()、outcome()、stack() —— 事后的兵器,若已毁则为 null。

声明为 @Nullable 的有:LootDropEvent、PreLootDropEvent 上的 player();techniqueId()(所有携带它的事件);skillNodeId()(所有携带它的事件);stack()。

这些所覆写的配置键:PreLootDropEvent 对应各项掉落概率键(Spirit-Core-Drop-Chance、Profound-Core-Drop-Chance、Divine-Core-Drop-Chance、Egg-Kill-Drop-Chance、SpiritStone-Kill-Drop-Chance、Manual-Tribulation-Drop-Chance、Manual-Player-Kill-Drop-Chance);PreSpiritCoreConsumeEvent.setQi 对应 Spirit-Core-Qi-Value / Profound-Core-Qi-Value / Divine-Core-Qi-Value 与 Meditation-Core-Bonus-Multiplier;PreRefinementStartEvent.setQiCost 对应 Refinement-Base-Qi-Cost 与 Refinement-Qi-Cost-Tier-Multiplier;PreRefinementCompleteEvent.setSuccessChance 对应 Refinement-Base-Success-Chance、Refinement-Success-Chance-Loss-Per-Tier 与 Refinement-Min-Success-Chance。

炼丹

plugin.siren.API.AlchemyEvents v0.10.0 —— 5 个事件(2 个可取消),涵盖丹炉的炼制仪式 —— 开始、结算,以及沿途的火候照看提示。它与 ItemEvents.PillConsumeEvent 互为补充,后者涵盖的是服下一枚成丹,而非炼制一枚。面向玩家的文档:炼丹。

此类中声明的枚举:

  • RefineOutcome:SUCCESS;FAILED —— 彻底失败:白白耗掉所用的灵草与灵气,别无他事发生;BOTCH —— 失败,且丹炉反噬了炼丹者 —— 见 AlchemyConfig 的 Refine-Botch-* 字段。
事件可取消触发时机暴露
PreRefineStartEvent是一场炼制仪式即将开始。取消可回绝(不耗灵草与灵气)。ref()、player()、effect()、durationSeconds() / setDurationSeconds(float)。
RefineStartEvent否一场炼制仪式开始了;灵草与灵气下限的检查早已通过。ref()、player()、effect()、qiDrainPerSecond()。
PreRefineCompleteEvent是一场炼制仪式即将结算出品阶。取消可静默中止 —— 灵草与灵气照样耗掉,不产出任何东西,与 ItemEvents.PreRefinementCompleteEvent 和 TalismanEvents.PreInscribeCompleteEvent 所用的形态相同。各 setter 重新权衡品阶掷骰实际用到的输入(灵草品质、熟练度与火候调整)。仅在自然完成时触发,被打断时绝不触发。ref()、player()、effect()、herbQualityAvg() / setHerbQualityAvg(float)、masteryLadderFraction() / setMasteryLadderFraction(float)、tendDelta() / setTendDelta(float)。
RefineCompleteEvent否一场炼制仪式结算了。除非 outcome 为 SUCCESS,否则 grade 为 null。ref()、player()、effect()、outcome()、grade()。
TendPromptResolvedEvent否一次火候照看提示被处理了 —— 应答(迅捷或稳当)、错过或失手 —— 发生在一场进行中的炼制仪式里。promptIndex 从 0 起算(这是本场仪式送出的第 N 条提示);promptCount 是该仪式所配置的 Tend-Prompts-Max 上限,并非已经触发了多少条。ref()、player()、action()、outcome()、promptIndex()、promptCount()。

声明为 @Nullable 的有:grade()。

锻造

plugin.siren.API.ForgingEvents v0.9.1 —— 2 个事件(1 个可取消),涵盖在锻造台上淬炼一件已造好的修炼兵器或护甲 —— 成功、失败与反噬三种结果。面向玩家的文档:锻造。

此类中声明的枚举:

  • ForgeOutcome:SUCCESS;FAILED —— 彻底失败:白白耗掉所用的材料,且若 Forge-Demote-On-Fail-From-Tier 如此规定,物品还会降一阶;BOTCH —— 失败,且锻炉反噬了锻造者 —— 见 ForgingConfig 的 Forge-Botch-* 字段。
事件可取消触发时机暴露
PreForgeEvent是一次锻造尝试即将开始 —— 所有检查都已通过,但材料和物品都还没被动过。取消可彻底回绝;什么都不扣,也不会启动仪式。ref()、player()、itemId()、targetTier()。
ForgeCompleteEvent否一次锻造尝试结算了。除非 outcome 为 SUCCESS,否则 grade 为 null。resultStack 是物品此刻的样子(已锻、已降阶或不变)—— 仅当修士的背包里无处放回时才为 null(见 ForgingManager.placeItem),随之而来的玩家消息已会如此告知。ref()、player()、targetTier()、outcome()、grade()、resultStack()。

声明为 @Nullable 的有:grade();resultStack()。

符箓

plugin.siren.API.TalismanEvents v0.9.0 —— 6 个事件(3 个可取消),涵盖在符箓案前刻画(开始与完成,结果有成功、失败与反噬)以及使用一张成品符箓。面向玩家的文档:符箓。

此类中声明的枚举:

  • InscribeOutcome:SUCCESS;FAILED —— 彻底失败:白白耗掉所用的材料与灵气,别无他事发生;BOTCH —— 失败,且符火反噬了刻画者 —— 见 TalismanConfig 的 Inscribe-Botch-* 字段。
事件可取消触发时机暴露
PreInscribeStartEvent是一场刻画仪式即将开始。取消可回绝(不耗材料与灵气)。ref()、player()、talismanId()、element()。
InscribeStartEvent否一场刻画仪式开始了;材料与灵气下限的检查早已通过。ref()、player()、talismanId()、element()、qiDrainPerSecond()。
PreInscribeCompleteEvent是一场刻画仪式即将结算出品阶。取消可静默中止 —— 材料与灵气已然沉没,不产出任何东西,与 ItemEvents.PreRefinementCompleteEvent 所用的形态相同。各 setter 重新权衡品阶掷骰实际用到的两项输入,这是扩展改动符箓品阶几率的受支持做法(例如仅为这一次掷骰加一份固定的亲和加成),而无须触碰已存的大道。仅在自然完成时触发,被打断时绝不触发。ref()、player()、talismanId()、element()、masteryLadderFraction() / setMasteryLadderFraction(float)、affinityFraction() / setAffinityFraction(float)。
InscribeCompleteEvent否一场刻画仪式结算了。除非 outcome 为 SUCCESS,否则 grade / stack 为 null。ref()、player()、talismanId()、element()、outcome()、grade()、stack()。
PreTalismanUseEvent是一张符箓即将被使用。取消可回绝(不消耗这一次使用次数)。ref()、player()、talismanId()、grade()。
TalismanUseEvent否一张符箓被使用,其效果已施加。remainingCharges 是这次使用之后剩下的次数 —— 降到 0 时这叠符箓即告消失。ref()、player()、talismanId()、grade()、remainingCharges()。

声明为 @Nullable 的有:InscribeCompleteEvent 上的 grade();stack()。

器灵

plugin.siren.API.WeaponSpiritEvents v0.9.0 —— 6 个事件(3 个可取消),涵盖一件本命法宝的器灵苏醒、升级,以及经 /cultivation spirit nurture 以灵气喂养。每个事件都携带当前主人的 PlayerRef。面向玩家的文档:器灵。

事件可取消触发时机暴露
PreWeaponSpiritAwakenEvent是一件兵器的器灵即将苏醒 —— 炼数与击杀两道门槛皆已达成。取消可让它恰好停在门槛上;已存的击杀数分毫不动,所以下一次符合条件的击杀会再度触发此事件。owner()、item()、killsAtAwaken()。
WeaponSpiritAwakenEvent否一件兵器的器灵刚刚苏醒;item 是苏醒写入之后的那一叠。owner()、item()、killsAtAwaken()。
PreWeaponSpiritLevelUpEvent是一件兵器的器灵即将升级。取消可让它停在当前等级(经验仍会存下)。owner()、item()、oldLevel()、newLevel()。
WeaponSpiritLevelUpEvent否一件兵器的器灵刚刚升了一级;item 是升级写入之后的那一叠。owner()、item()、newLevel()、reachedMaturity()。
PreWeaponSpiritNurtureEvent是玩家即将以灵气喂养他的器灵。取消可彻底回绝这次喂养(不耗灵气、不得经验)。setQiToConvert 改变所献灵气中有多少被转化;WeaponSpirit-Nurture-Max-Qi-Per-Use 默认就是在这里施加的,所以扩展应当调整这个字段,而不是配置。owner()、item()、qiToConvert() / setQiToConvert(float)。
WeaponSpiritNurtureEvent否玩家刚刚以灵气喂养了他的器灵;每次成功的 nurture 调用触发一次,无论它是否同时让器灵升了级。owner()、item()、qiConverted()、xpGained()。

灵兽

伙伴,以及繁育出新伙伴的过程。

灵兽

plugin.siren.API.BeastEvents —— 20 个事件(10 个可取消),涵盖收服、孵化、结契、召唤与伙伴自身的修行,并自 0.7.2 起涵盖它的兽技、进化与坐骑,以及灵兽巢穴所孕育的一窝幼兽。面向玩家的文档:灵兽。

此类中声明的枚举:

  • BindSource:TAME —— 在野外降伏并收服;HATCH —— 由灵兽蛋孵化而来;DEN —— 从一座备齐供品的灵兽巢穴中认领。
  • DismissReason:DISMISSED —— 遣归,所修一概不损;RELEASED —— 永久放归,契约就此断绝;EXPEDITION —— 派去历练:所修一概不损,计时一满便回来。
事件可取消触发时机暴露
PreBeastTameAttemptEvent是一次收服判定即将掷出。取消可直接回绝这次尝试 —— 不耗符箓。ref()、player()、species()、chance() / setChance(float) —— 0–1,已计入境界与道之共鸣的加权。
BeastTameAttemptEvent否判定已结算。ref()、player()、species()、chance()、success()。
PreBeastBindEvent是一头伙伴即将结契。取消则修士保留他原有的灵兽 —— 符箓或蛋照样耗掉。ref()、player()、species()、source()。
BeastBindEvent否伙伴已结契,取代此前的那一头。ref()、player()、species()、source()。
PreBeastSummonEvent是伙伴之身即将生成。取消则玩家会被告知召唤失败。owner()、player()、species()。
BeastSummonEvent否其身已生成于主人身侧。owner()、player()、beast()(生成的实体)、species()。
PreBeastDismissEvent是伙伴即将被遣归或放归。owner()、player()、reason()。
BeastDismissEvent否其身已离世间。owner()、player()、reason()。
PreBeastXpGainEvent是伙伴即将获得经验。对每一处来源皆触发 —— 打坐分成、击杀与亲手喂食一视同仁。owner()、player()、beast()(当前的 SpiritBeastComponent —— 境界、阶段、已存经验)、amount() / setAmount(float)。
BeastXpGainEvent否经验已入账。owner()、player()、amount()、stagesGained()(只存了进度时为 0)。
PreBeastAdvanceEvent是伙伴即将进阶一个阶段。取消可把它按在原处 —— 那一阶段的经验已经花掉了,因此这会让它白丢那份进度。owner()、player()、fromRealm()、fromStage()。
BeastAdvanceEvent否伙伴已进阶。每一阶段触发一次。owner()、player()、realm()、stage()。
PreBeastArtEvent是一头伙伴即将施展一门兽技。取消可制止它 —— 冷却只在效果真正运行之后才盖戳,所以被否决的兽技不让灵兽损失任何东西,它会在下一次得空时重试。owner()、player()、beast()、art()、commanded()(灵兽自己选的则为 false)。
BeastArtEvent否一头伙伴施展了它的一门兽技。owner()、player()、beast()、art()、commanded()。
PreBeastEvolveEvent是一头伙伴即将接受进化仪式。此时灵气尚未被取走,所以否决不让修士损失任何东西。owner()、player()、beast()、from()、to()、successChance() / setSuccessChance(float)。
BeastEvolveEvent否仪式结算了。succeeded() 表明结果走向,失败时 to() 为 null。owner()、player()、beast()、from()、to()、succeeded()。
PreBeastMountEvent是一头伙伴即将以可骑乘之身被召出。取消可回绝坐骑。owner()、player()、beast()、species()。
BeastMountEvent否伙伴以可骑乘之身被召出了。owner()、player()、beast()、species()。
PreBeastDenBroodEvent是一座灵兽巢穴即将掷出一窝。取消则让巢穴没有这一窝 —— 下次它的评估扫描运行时会再试。此时尚未持久化任何东西,所以否决不让供养者损失任何东西。world()、x()、y()、z()、species()、appraisalScore()。
BeastDenBroodEvent否一座灵兽巢穴掷出了一窝,待到期后供人认领。world()、x()、y()、z()、species()、appraisalScore()。

声明为 @Nullable 的有:player()(所有携带它的事件);BeastEvolveEvent 上的 to()。

这些所覆写的配置键:PreBeastTameAttemptEvent.setChance 对应 Tame-Chance-Bonus-Per-Realm、Tame-Chance-Element-Match-Bonus 与 Tame-Chance-Max(由 Tame-Consume-Talisman-On-Failure 决定失手的代价);PreBeastXpGainEvent.setAmount 对应 Beast-Xp-Per-Kill、Beast-Xp-Own-Kill-Multiplier 与 Beast-Xp-Per-Qi-Item-Point。整套系统的门禁:Beasts-Enabled;Beast-Arts-Enabled、Beast-Evolution-Enabled 与 Beast-Mounts-Enabled 则分别控制 0.7.2 新增的三项系统。

灵兽繁育

plugin.siren.API.BreedingEvents v0.9.0 —— 4 个事件(2 个可取消),涵盖两位修士在灵兽栏中产出一枚蛋的仪式,以及把繁育所得的蛋孵化成结契的伙伴。一枚繁育所得的蛋孵化时仍会触发 BeastEvents.BeastBindEvent。面向玩家的文档:灵兽。

事件可取消触发时机暴露
PreBeastBreedEvent是一场繁育仪式即将落到两位修士身上 —— 在二人都确认位于同一兽栏、灵气足够之后、任何一方的灵气被动用之前触发。取消可直接回绝;此时尚未花费任何东西。offerer()、accepter()、parentA()、parentB()。
BeastBreedEvent否一场繁育仪式完成,并为 recipient(发出邀约的一方)产下一枚蛋。只触发一次,出自仪式自身的完成,而非邀约或接受。recipient()、partner()、parentA()、parentB()、offspring()、quality()。
PreBeastEggHatchEvent是一枚繁育所得的蛋即将孵化。取消可回绝 —— 蛋不会被消耗,与休眠的野生孵化蛋一致(见 BeastEggHatchInteraction 的繁育分支)。ref()、player()、offspring()、metadata()。
BeastEggHatchEvent否一枚繁育所得的蛋孵化成了结契的伙伴。ref()、player()、offspring()、metadata()。

声明为 @Nullable 的有:partner();player()(所有携带它的事件)。

宗门、坊市与同道

宗门与宗门之间的战事,被围宗门的战时大阵,侍奉大殿的人,功德,队伍与道侣,拍卖行与悬赏令。

宗门

plugin.siren.API.SectEvents —— 41 个事件(18 个可取消),涵盖开宗、解散、门籍、职位、简称、大殿、大殿灵脉、殿上碑文、旗帜、外交与宗门藏书阁。面向玩家的文档:宗门,以及指令页上的 /sect 系列。

监听器持有 SectManager 的锁 —— 见注册与线程。这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

此类中声明的枚举:

  • JoinMethod:INVITE —— 他们接受了一份待决邀约;OPEN —— 他们走进了一个 OPEN 的宗门;REQUEST —— 管理者批准了他们待决的入门申请。
  • LeaveReason:LEFT —— 他们自行离去;KICKED —— 宗主或长老将他们逐出。
事件可取消触发时机暴露
PreSectCreateEvent是玩家即将开宗立派。取消后它会报告创立被回绝。leader()、name() / setName(String) —— 事后仍会重新校验形状与唯一性。
SectCreateEvent否宗门已创立并已建索引。leader()、sect()。
PreSectDisbandEvent是宗门即将解散。取消可保其不倒。leader()、sect()。
SectDisbandEvent否门人索引已解除、阵法已释放。sect 是那个已成孤儿的对象,仍可读取其最后的名录。leader()、sect()。
PreSectInviteEvent是一份邀约即将发出。inviter()、invitee()、sect()、expiryMillis() / setExpiryMillis(long) —— 其失效的墙上时钟毫秒数。
SectInviteEvent否邀约处于未决状态,尚未被接受。inviter()、invitee()、sect()。
PreSectJoinEvent是玩家即将入门。取消后邀约或申请仍存续,因此他可以再试。player()、sect()、method()。
SectJoinEvent否他已在名录之上。player()、sect()、method()。
PreSectLeaveEvent是玩家即将离去或被逐。取消可把他留在名录上。player()、sect()、reason()、actor()。
SectLeaveEvent否他已不在名录上。KICKED 时 actor 是执行驱逐者,LEFT 时则是玩家本人。player()、sect()、reason()、actor()。
PreSectJoinRequestEvent是一份入门申请即将排入某个 REQUEST 规矩的宗门。player()、sect()。
SectJoinRequestEvent否申请已排入队列。player()、sect()。
SectJoinRequestDeniedEvent否管理者驳回了一份未决申请。manager()、applicant()、sect()。
PreSectRankChangeEvent是长老职位即将变更。leader()、target()、sect()、promoted() —— 由弟子擢升为长老时为 true。
SectRankChangeEvent否职位已变更。leader()、target()、sect()、promoted()。
PreSectMottoChangeEvent是宗训即将设定。manager()、sect()、oldMotto()、motto() / setMotto(String) —— 事后仍适用 60 字符上限。
SectMottoChangeEvent否宗训已替换。manager()、sect()、oldMotto()、newMotto()。
PreSectJoinPolicyChangeEvent是入门规矩即将变更。leader()、sect()、oldPolicy()、policy() / setPolicy(Sect.JoinPolicy)。
SectJoinPolicyChangeEvent否规矩已变更。leader()、sect()、oldPolicy()、newPolicy()。
PreSectRenameEvent是宗门即将改名。leader()、sect()、oldName()、newName() / setNewName(String) —— 事后仍会重新校验。
SectRenameEvent否已改名;阵法、山门灵泉与未决邀约都已随之带过。leader()、sect()、oldName()、newName()。
PreSectInscriptionChangeEvent是殿上碑文即将变更。leader()、sect()、oldTechniqueId()、newTechniqueId() / setNewTechniqueId(String) —— 传空则将其抹去。
SectInscriptionChangeEvent否碑文已变更。leader()、sect()、oldTechniqueId()、newTechniqueId()。
PreSectHallClaimEvent是大殿即将设立。取消后它会报告该区块已被占据。leader()、sect()、world()、chunkX()、chunkZ()、veinTier()。
SectHallClaimEvent否宗门已在一条灵脉上设立或迁移了大殿。leader()、sect()、world()、chunkX()、chunkZ()、veinTier()。
PreSectHallCaptureEvent是大殿即将易主给得胜的围攻方。取消可让它留在守方手中 —— 围攻仍判为胜。attacker()、defender()、world()、chunkX()、chunkZ()、veinTier()。
SectHallCaptureEvent否一场获胜的围攻已移交大殿;守方现已无殿。attacker()、defender()、world()、chunkX()、chunkZ()、veinTier()。
SectVeinAscendedEvent v0.11.2否宗门的大殿灵脉由丰沛升华为龙脉(见宗门灵脉)。龙脉是挂在宗门身上的叠加层,绝不会写入区块自身的灵脉,所以世界本身并未改变。在清扫线程上、SectManager 的监视器之内触发:读取后交接出去。没有前置事件;何时发生由宗门自己的计时决定。sect()、world()、chunkX()、chunkZ()。
PreSectBannerChangeEvent是宗门的旗帜即将变更。取消可让旧旗继续飘扬。监听器改写该 id 之后,它不会被重新校验 —— 一个未注册的 id 并非错误,只会解算为对应灵脉品阶的默认灯火。manager()、sect()、oldBannerId()、bannerId() / setBannerId(String)。
SectBannerChangeEvent否旗帜已变更。大殿的常置灯火会在其下一次脉动时切换为新旗。manager()、sect()、oldBannerId()、newBannerId()。
PreSectAbbreviationChangeEvent v0.8.0是一宗的简称即将变更。取消即回绝;setAbbreviation 可改写它 —— 3–6 个字母/数字的规则与全服唯一性检查仍会在其后照常执行。leader()、sect()、oldAbbreviation()、abbreviation() / setAbbreviation(String)。
SectAbbreviationChangeEvent v0.8.0否简称已变更。leader()、sect()、oldAbbreviation()、newAbbreviation()。
SectAllianceFormedEvent否两个宗门结成了同盟。actor 是接受提议的人。actor()、sectA()、sectB()。
SectAllianceBrokenEvent否一份既有的同盟终止了;任何一方的宗主都可单方面解除。actor 是解除者。actor()、sectA()、sectB()。
SectRelationChangedEvent否两宗之间的 NON_AGGRESSION(互不侵犯)或 TRADE(通商)关系结成或终止。ALLIANCE 永不触发它:上面那一对同盟事件已覆盖那一级,所以同时监听二者的监听器不会被重复通知。formed 在关系刚刚开始时为 true。actor()、sectA()、sectB()、kind()、formed()。
PreSectLibraryResearchStartEvent是宗门藏书阁即将开始研究新的课题。取消则让它继续研究原来的东西(或什么都不研究)。actor()、sect()、oldTechniqueId()、newTechniqueId()。
SectLibraryResearchStartEvent否宗门藏书阁开始研究新的课题(取代它此前所研究的东西,如果有的话)。actor()、sect()、techniqueId()。
PreSectLibraryCompileEvent是宗门藏书阁即将编成一门独门功法。取消则把它拦在门口 —— 进度保持在耗费之上,下一次结算时再度触发。sect()、techniqueId()。
SectLibraryCompileEvent否宗门藏书阁编成了一本独门功法秘籍。sect()、techniqueId()。
PreSectLibraryRedeemEvent是一名门人即将兑取他那份已编成的藏书阁秘籍。取消可回绝(不标记为已兑取,故可重试);用 setManualItemId 可换成另一件物品。member()、sect()、techniqueId()、manualItemId() / setManualItemId(String)。
SectLibraryRedeemEvent否一名门人兑取了自己那份已编成的藏书阁秘籍。member()、sect()、techniqueId()、manualItemId()。

这些所覆写的配置键:PreSectInviteEvent.setExpiryMillis 对应 Sect-Invite-Expiry-Seconds;大殿的设立受 Sect-Hall-Min-Vein-Tier 管辖(v0.11.2 并由 Sect-Hall-Claim-Anywhere 在任意土地上豁免);碑文受 Sect-Inscription-Enabled 管辖;整个子系统受 Sects-Enabled 与 Sect-Max-Members 管辖。旗帜事件所携带的旗帜 id,皆取自旗帜注册表 —— 六种内置旗帜,外加任何扩展经由 registerSectBanner 添加的旗帜。

战事

plugin.siren.API.WarEvents —— 9 个事件(4 个可取消),涵盖向敌方大殿宣布围攻、它如何结算、阵法 2.0 的攻城旗,以及盟宗增援所赚得的奖励。面向玩家的文档:宗门攻伐。

一场围攻要么是镇压(Suppress,默认:获胜绝不会让大殿易主,因此不触发夺取事件),要么是征服(Conquest),获胜时经 SectManager.captureHall 移交大殿。那次移交就是 SectEvents.PreSectHallCaptureEvent 与 SectHallCaptureEvent:否决其中的前置事件,即可让征服获胜而大殿不动。这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

此类中声明的枚举:

  • SiegeFailReason:LAPSED —— 攻方未能在 CONTEST 窗口耗尽之前占据大殿足够久;DEFENDER_GONE —— 检查时,攻方或守方宗门(或守方大殿)已不复存在;MUSTER_FAILED —— MUSTER 的期限已过,而双方未能凑齐各自的最低在场人数 —— 彻底无事发生,守方也不进冷却;DEFENDER_ABSENT —— CONTEST 被强制叫停:大殿所在世界中守方的实时在场人数在宽限期过后仍为零 —— 以守方胜出了结,守方无损;ABORTED —— 管理员或 Wars-Enabled 总开关径直取消了围攻 —— 对双方都不产生后果,攻方的宣战花费也予以退还。
  • BannerBreakSide:ATTACKER;DEFENDER;THIRD_PARTY。
事件可取消触发时机暴露
PreWarDeclareEvent是一场围攻即将宣布。取消后调用方会被告知战事系统已禁用。attacker()、defender()、windowMillis() / setWindowMillis(long) —— 攻方有多久去完成其占据。
WarDeclareEvent否围攻已生效,双方均已收到告知。attacker()、defender()、siege()。
PreSiegeCaptureEvent是一场围攻即将获胜。取消可让它继续进行 —— 攻方仍在占据,并会在其下一个在场判定周期再次触发此事件,因此请仅在你自己的某个条件尚未满足时取消。attacker()、defender()、siege()。
SiegeCaptureEvent否攻方已占据足够久。大殿的移交已经尝试过,守方的免战冷却也已开始。attacker()、defender()、siege()。
SiegeFailEvent否围攻结束,大殿仍在守方手中。siege()、reason()。
PreSiegeBannerPlaceEvent是阵法 2.0:一面攻城旗即将被安放。取消可回绝(安放者会被告知有东西阻止了此处安放)。在取任何监视器之前触发,所以不持有任何锁,监听器可以读取 WarManager 的状态;登记上限与围攻是否仍在进行,会在其后重新权威核对。attackerSect()、defenderSect()、world()、x()、y()、z()。
SiegeBannerPlaceEvent否阵法 2.0:一面攻城旗已安放,此刻正立着。banner()。
SiegeBannerBreakEvent否阵法 2.0:一面攻城旗被毁 —— 无论何人所毁,不受保护。breakerSide 表明毁旗者(如有)属于哪一方。banner()、breaker()、breakerSide()。
PreWarReinforcementRewardEvent是一个盟宗对成功守住(LAPSED)的围攻所作的增援,即将获得奖励。取消则扣下这一个盟友的奖励,而不影响任何其他合格的盟友;每个增援宗门各有一个自己的事件。setContributionPerMember 只重新缩放这一份发放。reinforcingSect()、defender()、siege()、contributionPerMember() / setContributionPerMember(int)。

这些所覆写的配置键:PreWarDeclareEvent.setWindowMillis 对应 War-Window-Seconds;相关键还有 War-Required-Hold-Seconds、War-Cooldown-Hours、War-Defender-Grace-Seconds、War-Requires-Defender-Online 以及 Wars-Enabled 这道门禁。

宗门大阵

plugin.siren.API.SectArrayEvents v0.11.1 —— 3 个事件(1 个可取消),涵盖被围宗门在自家所占地界上升起的战时护佑:宗主或一位长老从自己的余额里付出贡献点,大阵一直撑到围攻了结,并以五种缘由之一撤下。它不放置任何方块,也不生成任何实体 —— 只有实体效果、边界粒子与声响。面向玩家的文档:宗门大阵。

宗门是活的 Sect 对象,与 SectEvents 交出来的完全一样:读走你要的东西然后返回。不要在监听器里回头调用大阵的升起或撤下。升起者是 UUID 而非 PlayerRef,因为在后续事件被读取时,他可能已经离线;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

管理员用测试指令升起的大阵,跳过战时与代价两道关口。它会触发 SectArrayRaisedEvent(adminRaised() 为 true),但绝不触发 PreSectArrayRaiseEvent,后者只属于要花钱的游戏内升起。

此类中声明的枚举:

  • EndReason:SIEGE_ENDED —— 针对该宗门的围攻已了结 —— 得胜、落败、战期耗尽或被取消。最常见的结束。被取消的围攻(管理员取消,或攻伐系统被关闭)还会把升起者所付的贡献点退还给他;HALL_LOST —— 该宗门不再持有大殿(被征服夺走)或已不复存在(已解散);LOWERED —— 宗主或长老用 /sect array lower 撤下。概不退还;ADMIN —— 管理员用 /cultivation admin array lower 撤下,或管理员升起的测试大阵到了配置的存续时限(Sect-Array-Admin-Test-Minutes);DISABLED —— 宗门大阵(或宗门系统)在配置里被关闭。
事件可取消触发时机暴露
PreSectArrayRaiseEvent是宗主或长老即将升起大阵。所有关口都已通过 —— 功能已开启,有一场围攻正针对该宗门,宗门持有大殿而尚无大阵,升起者付得起配置的代价 —— 但尚未花费任何东西。取消则升起失败,回话是一句泛泛的「此刻有某种力量阻止了这一操作」:不扣任何东西,也没有大阵。用 setCost 可重新调整代价(比如为持有某件圣物的宗门打折);留下的值会被限制在 0 至 1,000,000,升起者仍须付得起,否则升起以贡献点不足而失败。针对配置代价的检查先于本事件进行,所以打折能降低扣款,却救不了本来就付不起配置代价的升起者。sect()、raiser()、cost() / setCost(int) —— 从升起者自己的余额里扣的贡献点。
SectArrayRaisedEvent否大阵升起了。sect()、raiser()(管理员升起时为 null)、cost()(实际扣下的贡献点;管理员升起为 0)、adminRaised()。
SectArrayEndedEvent否大阵撤下了。sect()(HALL_LOST 时,它的名字可能已不在名册里)、reason()、secondsActive()。

声明为 @Nullable 的有:raiser()(仅限 SectArrayRaisedEvent)。

升起事件在升起者的指令线程上触发;结束事件则在最先察觉到结束的那条线程上触发 —— 某个世界每秒一次的守阵机制,或撤下它的那条指令 —— 所以它不绑定于该宗门自己的世界。三个事件都在 SectArrayManager 自己的监视器之外触发。

这些所覆写的配置键,都在 Society/SectArrayConfig.json:PreSectArrayRaiseEvent.setCost 对应 Sect-Array-Cost-Contribution(默认 100)。相关键有 Sect-Array-Defender-Damage-Reduction-Percent、Sect-Array-Siege-Slow-Percent、Sect-Array-Base-Realm、Sect-Array-Border-Seconds、Sect-Array-Border-Max-Posts 与 Sect-Array-Admin-Test-Minutes。整个系统的门禁:Sect-Array-Enabled。大阵与道域之间的交锋,由 DaoDomainEvents.DomainClashEvent 上报,不在这里。

护山傀儡

plugin.siren.API.GuardianEvents v0.10.2 —— 4 个事件(1 个可取消),涵盖在宗门大殿派驻一尊护山傀儡、其中一尊倒下,以及最后一尊倒下。派驻可以取消。面向玩家的文档:宗门。

事件可取消触发时机暴露
PreSectGuardianStationEvent是一名门人即将派驻一处新的护山傀儡岗位。取消可回绝(对执行者而言,表现为派驻尝试直接失败)—— 在 SectGuardianManager.station 中所有关卡都通过之后、贡献消耗被扣之前触发,所以否决不让执行者损失任何东西。sect()、actor()、postIndex()。
SectGuardianStationedEvent否一名门人成功在其宗门大殿派驻了一处新的护山傀儡岗位 —— 岗位已购得;待其区块驻留后,在 SectGuardianSystem 的下一次心跳里,实体傀儡本身才会现身。sect()、actor()、postIndex()。
SectGuardianFellEvent否一尊在世的护山傀儡倒下了。当致命一击始终没能归到某位玩家头上(环境伤害、阵法陷阱,或击杀者在判定前已消失)时,killerPlayerRef 为 null。sect()、postIndex()、killerPlayerRef()、consumed()。
SectGuardiansFallenEvent否该宗大殿的最后一尊在世护山傀儡刚刚倒下(或化入永久消耗状态而消失),此刻已无一尊留存。纯属通知:无占据时长加成,也无惩罚。sect()。

声明为 @Nullable 的有:killerPlayerRef()。

讲道

plugin.siren.API.SermonEvents v0.10.2 —— 4 个事件(1 个可取消),涵盖修士在自己宗门的大殿开坛讲道、一位打坐中的听众首次合格的结算,以及讲道如何收场。开坛可以取消。面向玩家的文档:讲道。

此类混用 UUID 与 PlayerRef 两种标识;用 Universe.get().getPlayer(uuid) 解析 UUID,并检查 isValid()。

事件可取消触发时机暴露
PreSermonStartEvent是一名宗门成员即将开坛讲道。取消可回绝(对执行者而言,表现为开坛尝试直接失败)—— 在 SermonManager.start 中所有关卡都通过之后、贡献消耗被扣或冷却被盖戳之前触发,所以否决不让执行者损失任何东西。sect()、lecturer()、element()。
SermonStartEvent否一名宗门成员在本宗大殿成功开坛讲道。sect()、lecturer()、element()、endsAtMillis()。
SermonListenerQualifiedEvent否一名听众在本次讲道中的首次合格结算 —— 每个(讲道,听众)配对仅触发一次,即便经过降速或强制停止的转换,同一配对也不会再次触发。lecturerUuid()、listener()、element()、amountApplied()。
SermonEndEvent否一场讲道结束了 —— 自然(时长耗尽)、提前(/cultivation sermon stop),或异常(讲者离开大殿区块/世界、大殿丢失、宗门被围攻、功能被禁用)。lecturerUuid()、sectName()、qualifiedListenerCount()、meritAwarded()、forfeited()。

功德

plugin.siren.API.MeritEvents v0.10.2 —— 3 个事件(1 个可取消),涵盖功德的获得与据此晋升品阶。获得可取消,也可重新衡量。面向玩家的文档:功德。

事件可取消触发时机暴露
PreMeritGainEvent是功德即将因一桩善举而记入。取消则一文不付;用 setAmount 可重新衡量这桩善举。player()、deed()、amount() / setAmount(float)。
MeritGainEvent否功德已实际记入 —— total / multiplier 是节流与上限施加之后的值。player()、deed()、amount()、total()、multiplier()。
MeritRankUpEvent否该玩家的功德品阶变了 —— 每次跨越触发一次,去重方式与 DaoEvents.PathChangeEvent 相同。player()、from()、to()。

声明为 @Nullable 的有:player()(所有携带它的事件)。

v0.11.1 deed() 是一个 MeritDeed,该枚举新增了一个常量 BREACH_CLEAR:在原版哥布林突袭、哥布林宝匣、虚空猎杀或地宫首领了结之时站在其近旁所得的功德(见突袭与首领之赏)。它可重复、没有受益人,所以既不受配对冷却约束,也不受 Merit-Min-Realm-Gap 约束;它受 Merit-Daily-Cap 限制,而对突袭与宝匣,还受 Breach-Reward-Daily-Cap 限制。两个功德事件都像对待其他善举一样携带它,所以针对 0.11.0 编译、对 MeritDeed 的 switch 表达式又没有 default 的扩展,在它出现时会于运行期抛出异常。

队伍

plugin.siren.API.PartyEvents v0.9.1 —— 5 个事件(1 个可取消),涵盖临时的、仅限当次会话的结伙:组建、加入、离开、解散与邀请。面向玩家的文档:队伍与秘境副本。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

事件可取消触发时机暴露
PrePartyInviteEvent是一份邀请即将发出。取消可静默回绝(邀请者仍会收到管理器自己的结果)。inviterUuid()、targetUuid()。
PartyFormedEvent否一位孤身队长的第一份邀请被接受 —— 队伍此刻成了一个群体,而不只是一位独自等待的队长。leaderUuid()、firstMemberUuid()。
PartyMemberJoinedEvent否一位修士加入了已成型的队伍 —— 不是队伍的第一名成员,那一个是 PartyFormedEvent。leaderUuid()、memberUuid()。
PartyMemberLeftEvent否一位修士离开了一支此后仍有成员的队伍。若离开的是队长,leaderUuid 就是新擢升的队长。leaderUuid()、memberUuid()。
PartyDisbandedEvent否一支队伍不复存在 —— 或是队长径直解散,或是最后一名成员离开。formerMembers 是快照,而非实时视图。leaderUuid()、formerMembers()。

双修

plugin.siren.API.PartnerEvents v0.9.1 —— 3 个事件(1 个可取消),涵盖两位已结为道侣的修士同汲一条灵脉:结伴、解伴,以及结伴所授的灵气加成。除非安装了 Marriage 模组(CultivationAPI.isMarriageInstalled()),否则不起作用。面向玩家的文档:双修。

此类混用 UUID 与 PlayerRef 两种标识;用 Universe.get().getPlayer(uuid) 解析 UUID,并检查 isValid()。

事件可取消触发时机暴露
PartnerPairedEvent否一位修士由未结伴转为结伴 —— 两位道侣在同一世界、彼此 Partner-Radius-Blocks 范围之内都坐下打坐。ref()、player()、partnerUuid()。
PartnerUnpairedEvent否一位修士由结伴回到未结伴:道侣起身、离开半径、更换世界,或这一对以其他方式失效。formerPartnerUuid 是他原先的搭档。对先起身的那位道侣不触发 —— 只告知仍然坐着的一方。ref()、player()、formerPartnerUuid()。
PrePartnerQiBonusEvent是一位结伴修士的打坐灵气加成即将生效。取消则本 tick 完全取消该加成(等同独坐);调整 setMultiplier 可重新缩放这一对搭档额外汲取多少灵气。ref()、player()、partnerUuid()、multiplier() / setMultiplier(float)。

声明为 @Nullable 的有:player()(所有携带它的事件);PrePartnerQiBonusEvent 上的 partnerUuid()。

拍卖行与行商

plugin.siren.API.MarketEvents v0.9.0 —— 12 个事件(3 个可取消),涵盖拍卖挂单的上架、购买、竞价、撤下与过期,以及云游行商 NPC 的开张与收摊。面向玩家的文档:拍卖行。

拍卖的变更都运行在 AuctionManager 的 synchronized 方法之内,因此这里的监听器正持有那把锁:读走你要的东西、交接出去、然后返回。切勿从监听器回调进 AuctionManager 的变更方法。这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

事件可取消触发时机暴露
PreAuctionListEvent是玩家即将挂出一件物品。取消可回绝(报告为被拦下)—— 此时卖家的背包尚未被动过。seller()、itemId()、quantity()、price() / setPrice(long)。
AuctionListingCreatedEvent否一条挂单创建了,此刻已上架。seller()、listing()。
PreAuctionBuyEvent是玩家即将买下一条挂单。取消可回绝 —— 此时尚无东西易手,挂单仍在架上。buyer()、listing()。
AuctionListingSoldEvent否一条挂单售出了。listing 是已被移除的货架条目;sellerProceeds 是扣除坊市抽成之后记给卖家的数额。listing()、buyer()、sellerProceeds()。
AuctionListingCancelledEvent否卖家撤下了自己仍在架上的挂单。listing()。
AuctionListingExpiredEvent否一条未售出的挂单超过了 Market-Auction-Listing-Duration-Hours,已作为可领取的包裹退还卖家。listing()。
MerchantOpenedEvent否云游行商在某个世界开张了。world()、x()、y()、z()。
MerchantClosedEvent否云游行商的驻留结束,NPC 消失了。world()。
PreAuctionBidEvent是玩家即将在限时拍卖上出价。取消可回绝 —— 此时尚无东西易手,前一位最高出价者也尚未被退款。刻意不设 setter:悄悄改动玩家刚刚承诺的数额会令人意外,所以重新调整一次出价的受支持做法就是取消它。bidder()、listing()、amount()。
AuctionBidPlacedEvent否限时拍卖上有人出价,此刻成了在位的最高价。listing()、bidder()、amount()。
AuctionOutbidEvent否在位的最高出价者被人超过,或其出价输给了提前一口价买断 —— 他们的灵石刚刚落入可领取的包裹(见 /market claim),即便人在离线。listing()、outbidBidder()、refundedAmount()。
AuctionClosedEvent否一场至少有一次出价的限时拍卖结束 —— 最高出价者赢得物品,卖家在扣除坊市抽成之后获得 sellerProceeds。对限时拍卖路径而言,形状与 AuctionListingSoldEvent 一致;零出价的结束则改为触发现有的 AuctionListingExpiredEvent,保持不变。listing()、winner()、sellerProceeds()。

悬赏令

plugin.siren.API.BountyEvents v0.10.2 —— 4 个事件(2 个可取消),涵盖经 BountyManager.post 张贴一份委托、一次击杀即将计入某份 SLAY 委托,以及领取一份已完成的委托。面向玩家的文档:悬赏令。

悬赏榜自身轮换生成的委托不会触发 BountyPostedEvent —— 只有经 BountyManager.post 推上去的才会。这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

事件可取消触发时机暴露
BountyPostedEvent否一份委托被明确张贴到榜上 —— 它已在榜单之中并已持久化。bounty 是榜上的实时对象,不是副本。请读取它,不要改动。bounty()。
PreBountyClaimEvent是一份已完成的委托即将发放。取消可径直回绝这次领取 —— 此时尚未发放任何东西,也尚未标记为已领取,所以这份接取只是停留在「已完成但未领取」,玩家可以再试。bountyId()、claimantUuid()。
PreBountyCreditEvent是一次玩家击杀即将推进某份 SLAY 委托的进度。取消则整次接取一概跳过 —— 不记录任何进度,也不告知击杀者。这是悬赏榜与张贴诛令者双方共同遵从的唯一裁决:张贴者在此监听,套用它给自己的奖励所用的那些规则(配对冷却、赛季上限、沙盒与管理员绕过排除),并在自己的回答为否时取消。每个匹配的在世接取触发一次,在榜这边的所有关卡之后、任何进度被写入之前。bountyId()、killerUuid()、victimUuid()、bounty()。
BountyClaimedEvent否一份委托被完整领取 —— 所许诺的每一项奖励都已到账,这份接取已标记为已领取。对 BountyManager.Result.PARTIAL 的领取永不触发,那种情形会让接取停在「已完成但未领取」以便重试。bountyId()、claimantUuid()、rewardQi()。
锁

这里的每个事件都在引发它之物所在的世界线程上触发,且此时持有 BountyManager 自己的监视器。不要阻塞,也不要从监听器回调进 BountyManager 的变更方法(post、takeDown、retire、accept、claim、creditPlayerSlain、sweep):它们同步于同一个监视器,重入其中任何一个,都会在触发此事件的那个操作的半途中运行它。本模组确立的锁序是 SeasonManager,然后你的扩展,然后 BountyManager,所以这里的监听器已经持有了那条链上的最后一把锁 —— 在这些事件之内去碰扩展的监视器,等于倒着走,可能与另一条世界线程上正在开启的赛季死锁。请让监听器的主体不带任何锁。

斗法与较量

两位玩家出于自愿而彼此对抗、或并肩进行的一切。

斗法

plugin.siren.API.DuelEvents —— 8 个事件(3 个可取消),涵盖发起、接受,以及一场灵气赌斗如何结算。面向玩家的文档:斗法,以及指令页上的 /cultivation duel。

一场斗法经常比其中一名参与者的会话活得更久 —— 而那恰恰正是它作罢的缘由。这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

此类中声明的枚举:

  • DuelEndReason:DEATH —— 一名斗者阵亡;押注易主;YIELD —— 一名斗者认输(/cultivation duel yield);押注易主,与 DEATH 完全一样 —— 这是胜者已知、结果已定的了结,绝不是「什么都没发生」;VOIDED —— 无法判定 —— 有参与者离开,或这场斗法超出了其最长时限。
事件可取消触发时机暴露
PreDuelChallengeEvent是一份邀约即将发出。challenger()、challenged()、wager() / setWager(int) —— 事后仍会重新核对所配置的上限。
DuelChallengeEvent否邀约正等待对方应答。challenger()、challenged()、wager()。
DuelDeclineEvent否邀约已被拒绝;赌斗未开始。challenger()、challenged()。
PreDuelStartEvent是一场赌斗即将开始。取消可回绝之 —— 无论如何邀约都已消耗,因此挑战者须重新发起一份。challenger()、challenged()、wager() / setWager(int) —— 在此重新调整的值,才是这场赌斗实际结算的数额。
DuelStartEvent否赌斗已生效;双方均被标记为赌斗中。challenger()、challenged()、wager()。
DuelEndEvent否赌斗结束。DEATH 与 YIELD 时胜者与败者是有意义的,且结算已排队;VOIDED 时二者不过是那两名参与者,什么也不易手。winner()、loser()、wager()、reason()、killer() —— DEATH 时指以自身伤害落下致命一击的玩家;若致命一击并非来自玩家(熔岩、坠落、阵法陷阱)或无法归因,则为 null;YIELD 与 VOIDED 时恒为 null。
PreDuelPayoutEvent是一场已判定赌斗的押注即将转移。取消可让胜者一无所得。winner()、loser()、amount() / setAmount(int) —— 实际转移的量仍受败者所持数额的封顶。
DuelPayoutEvent否押注已转移。amount 是败者所能拿出的数额,也正是胜者所得。winner()、loser()、amount()。

声明为 @Nullable 的有:killer()。

这些所覆写的配置键:setWager 对应 Duel-Max-Wager;相关键还有 Duel-Challenge-Expiry-Seconds、Duel-Max-Duration-Seconds、Duel-Overrides-World-Pvp 以及 Duels-Enabled 这道门禁。

大道赌斗

plugin.siren.API.DaoDuelEvents v0.10.1 —— 3 个事件(2 个可取消),涵盖叠在 DuelEvents 那种单纯灵气赌斗之上的灵石托管:挑战与结算可以取消,托管结清之后则报告结局。面向玩家的文档:斗法。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

此类中声明的枚举:

  • DaoDuelEndReason:DEATH —— 一名斗者阵亡;灵石彩池已结清;YIELD —— 败者认输(/cultivation duel yield),而非被击杀;灵石彩池照样向他结清。
事件可取消触发时机暴露
PreDaoDuelChallengeEvent是一份大道赌斗的挑战即将发出(灵气押注若有,完全由 DuelEvents.PreDuelChallengeEvent 处理 —— 这里只管灵石那一边)。取消可回绝;用 setSpiritStoneAmount 可重新调整押注(所配置的上限在其后重新核对)。challenger()、challenged()、spiritStoneAmount() / setSpiritStoneAmount(long)。
PreDaoDuelPayoutEvent是一场已判定的大道赌斗的灵石彩池即将易手。取消则把败者的押注原封不动退还败者;setAmount 重新缩放败者被托管的押注中有多少被没收,以实际托管的数额封顶。无论哪种,胜者自己的押注都不受影响。winner()、loser()、amount() / setAmount(long)。
DaoDuelEndEvent否一场已判定的大道赌斗的灵石彩池已结清 —— spiritStoneAmountPaid 是实际从败者托管中转给胜者的数额(外加任何能够收取的元素加成);胜者自己的押注总是另行退还给他,不计在这里。winner()、loser()、spiritStoneAmountPaid()、winnerElement()、loserElement()、winnerCountered()、reason()、decidedByOpponentDamage()。

声明为 @Nullable 的有:winnerElement();loserElement()。

赛事押注

plugin.siren.API.WagerEvents v0.10.2 —— 4 个事件(1 个可取消),涵盖观战者在大道赌斗大会的单场对局上押注灵石 —— 一个没有庄家账户的彩池式盘口。面向玩家的文档:斗法。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

此类中声明的枚举:

  • WagerVoidReason:FORFEIT —— 一名斗者被判胜出,却并未真正打过一场(缺席/逾期弃权);DOUBLE_ELIMINATION —— 到期限时双方都不够资格,于是双双淘汰;VOIDED_DUEL —— 底层的斗法作废 —— 掉线,或超出 Duel-Max-Duration-Seconds;YIELD —— 败者认输(/cultivation duel yield),而非被打败;NOT_OPPONENT_KILL —— 败者死了,却不是死于对手自己的伤害 —— 熔岩、坠落、溺水、阵法陷阱、第三方,或死亡路径根本无法归因的来源;TOO_FEW_BETTORS —— 对局确实分出了胜负,但某一方的不同押注者不足 Wager-Min-Bettors-Per-Side 人 —— 防串通规则;POOL_TOO_THIN —— 对局确实分出了胜负,但某一方的押注总额低于 Wager-Min-Pool-Per-Side —— 让攻击者付出真实灵石的防串通规则;TOURNAMENT_RESET —— 此盘口存续期间,整届大会被重置、取消或重新开启;ACCOUNTING_FAILURE —— 守恒不变式的自检失败,于是不付一文,每一注原额退还。
事件可取消触发时机暴露
PreWagerPlacedEvent是一位观战者即将为一注被扣费。所有已配置的关卡(功能启用、盘口开放、非斗者、非仍在参赛者、非同宗、单注/单届/单池限额)都已通过。取消可回绝这一注,不动灵石、不记任何东西。数额刻意不可设置。matchNumber()、bettor()、backed()、amount()。
WagerPlacedEvent否一位观战者的灵石已被扣下,其押注已记录。backed 是他们所押注的斗者。matchNumber()、bettor()、backed()、amount()。
WagerMarketResolvedEvent否一个盘口结算并派彩。payouts 把每位押注者映射到退回的灵石总额(本金加上其在败方彩池中的份额),stakes 映射到各自投入的数额,burned 是抽成加上不可整除的余数 —— 被销毁而非派发的灵石。在持有锦标赛管理器的监视器时触发;见下面的锁说明。matchNumber()、winner()、stakes()、payouts()、winnersPool()、losersPool()、burned()。
WagerMarketVoidedEvent否一个盘口无人获彩,refunds 中的每一注都原额退还。reason() 说明缘由。在持有锦标赛管理器的监视器时触发;见下面的锁说明。matchNumber()、reason()、refunds()。
锁

PreWagerPlacedEvent 与 WagerPlacedEvent 触发时,不持有本模组的任何监视器,运行在下注玩家自己的指令线程上。WagerMarketResolvedEvent 与 WagerMarketVoidedEvent 则在 DaoDuelTournamentManager 的监视器被持有时触发,位于其对局结算内部。对这两个事件的规矩是绝对的:不加锁、不跨管理器调用。不要加 synchronized,不要去碰另一条线程可能正持有的并发原语,也绝不要回调 DaoDuelTournamentManager、TournamentWagerManager、DaoDuelManager 或 DuelManager。把需要的东西从事件里抄出来,交给你自己的队列。重启时的退款什么都不触发 —— 它们运行在 Cultivation 的 setup() 之内,早于任何扩展登记监听器 —— 所以请改读可领取的包裹。

茶道

plugin.siren.API.TeaEvents v0.10.3 —— 4 个事件(1 个可取消),涵盖两人配合、考验反应时机的合奏(茶道):开始(可取消)、每一步的结算,以及茶会如何收场。面向玩家的文档:茶道。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

此类中声明的枚举:

  • EndReason:COMPLETED —— 每条提示都已送出并评分 —— 正常收尾;LEFT —— 有参与者执行了 /cultivation tea leave;DRIFTED —— 两位参与者相距超过 Tea-Radius-Blocks 的时间长过 Tea-Grace-Seconds;DISCONNECTED —— 有参与者掉线;COMBAT —— 有参与者进入战斗(有一个生效的 PunishWindowComponent);DISABLED —— 茶会进行到一半时,Tea-Enabled 被关掉了。
事件可取消触发时机暴露
PreTeaCeremonyStartEvent是一份待决邀约即将被接受,一场茶会即将开始(灵草尚未花费)。取消可回绝 —— 无论如何邀约都已消耗,所以发起者须再发一份新的。offerer()、accepter()、herbCost() / setHerbCost(int)。
TeaCeremonyStartEvent否一场茶会真正开始了 —— 灵草已花费,会话已生效。sessionId()、playerA()、playerB()。
TeaStepResolvedEvent否一条提示(单个 BOIL/STEEP/POUR/SERVE 步骤)被评分了。sessionId()、round()、step()、playerACorrect()、playerBCorrect()、scoreDelta()。
TeaCeremonyEndEvent否一场茶会以某种方式结束了 —— 只有 reason 为 EndReason.COMPLETED 时,harmony / band 才有意义;所有作废的缘由都报告 harmony=0f / band=DISCORDANT 与 rewarded=false,因为异常结束绝不发放奖励(灵草无论如何都已花掉 —— 此事件不涉及这一点,它在茶会开始时无条件施加)。sessionId()、playerA()、playerB()、reason()、harmony()、band()、rewarded()。

围棋

plugin.siren.API.WeiqiEvents v0.10.3 —— 7 个事件(2 个可取消),涵盖围棋(Go):邀请与拒绝、对局开始、每一手,以及一局如何结算。邀请与开局可以取消。面向玩家的文档:围棋。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

事件可取消触发时机暴露
PreWeiqiInviteEvent是一份邀请即将发出。取消可径直回绝(例如扩展所执行的冷却或黑名单)。inviter()、invitee()。
WeiqiInviteEvent否一份邀请已发出,正等待对方应答。inviter()、invitee()。
WeiqiDeclineEvent否一份邀请被拒绝;没有开局。inviter()、invitee()。
PreWeiqiMatchStartEvent是一局棋即将开始(接受方刚刚接受了一份待决邀请)。取消可回绝 —— 无论如何邀请都已消耗,所以邀请者须再发一份新的。blackUuid()、whiteUuid()、boardSize()、komi() / setKomi(float)。
WeiqiMatchStartEvent否一局棋已然开始。blackUuid 恒为接受方(先手,对受邀者的一份礼让);whiteUuid 是最初的邀请者。matchId()、blackUuid()、whiteUuid()、boardSize()、komi()。
WeiqiMoveEvent否一手棋结算 —— 要么在 index 处落下一子(平铺的 y * boardSize + x 棋盘索引,可经 WeiqiBoard.xOf / yOf 解码),要么虚着,二者不会同时发生。matchId()、player()、color()、index()、pass()、capturedCount()。
WeiqiMatchEndEvent否一局棋结束。对 WeiqiMatch.Outcome.ABANDONED / WeiqiMatch.Outcome.TIMED_OUT,winner 为 null(未分胜负的对局无人获胜);对 WeiqiMatch.Outcome.TWO_PASS / WeiqiMatch.Outcome.RESIGNED 则恒有值。matchId()、blackUuid()、whiteUuid()、winner()、outcome()、blackScore()、whiteScore()、totalMoves()。

声明为 @Nullable 的有:winner()。

世界

阵法与洞府,天穹,全服范围的遭遇,你前往的去处,以及你在那里的所获。

阵法

plugin.siren.API.FormationEvents —— 8 个事件(4 个可取消),涵盖锚定于区块的灵阵之布设与驱散、以祭坛为锚的阵法变更阶位,以及困仙阵伤及入侵者。面向玩家的文档:阵法。

此类混用 UUID 与 PlayerRef 两种标识;用 Universe.get().getPlayer(uuid) 解析 UUID,并检查 isValid()。

事件可取消触发时机暴露
PreFormationPlaceEvent是一座阵法即将布下。取消后它会报告此地已被设防。owner()、sectName()(阵法归其个人时为空)、world()、chunkX()、chunkZ()、type()、radiusChunks() / setRadiusChunks(int)。
FormationPlaceEvent否阵法已在其区块上生效。owner()、sectName()、formation()。
PreFormationRemoveEvent是一座阵法即将被其掌阵者驱散。取消可让它继续矗立。owner()、sectName()、formation()。
FormationRemoveEvent否已驱散。formation 是那个已被移除的对象。owner()、sectName()、formation()。
PreFormationTrapStrikeEvent是困仙阵即将伤及一名入侵者。取消可让他完全逃过这一次结算 —— 无粒子、无减益、无伤害。把伤害设为 0 则只定住他而不伤其身。ref()、player()、world()、chunkX()、chunkZ()、damage() / setDamage(float) —— 在致死上限之后、护甲之前;入侵者的生命值无法解析时为 0。
FormationTrapStrikeEvent否入侵者已受伤。ref()、player()、world()、chunkX()、chunkZ()、damage()。
PreFormationTierChangeEvent是一座以祭坛为锚的阵法的阶位即将变更。取消可彻底回绝这次变更;用 setToTier 可压低(但不能完全阻止)一次上升。formation()、fromTier()、toTier() / setToTier(int)。
FormationTierChangeEvent否一座以祭坛为锚的阵法的阶位刚刚变了。纯属通知 —— 此事件触发时,新阶位已经在 formation 上生效。formation()、fromTier()、toTier()。

声明为 @Nullable 的有:player()(所有携带它的事件)。

这些所覆写的配置键:setRadiusChunks 视 type() 而定,对应 QiGathering-Radius-Chunks、Warding-Radius-Chunks 或 Trapping-Radius-Chunks;PreFormationTrapStrikeEvent.setDamage 对应 Trapping-Damage-Percent-Of-Max-Health(与之并列的还有 Trapping-Lethal、Trapping-Interval-Seconds 与 Trapping-Debuff-Duration-Seconds)。整套系统的门禁:Formations-Enabled 与 Max-Formations-Per-Controller。

洞府

plugin.siren.API.DwellingEvents —— 12 个事件(6 个可取消),涵盖洞府的开辟、其灵泉、供奉与闭关。面向玩家的文档:洞府。

宗门山门灵泉是自动创建并随其宗门大殿迁移的;那套内务处理刻意不触发任何事件。请改为监听宗门大殿的设立与夺取事件 —— 它们才是其成因。此类混用 UUID 与 PlayerRef 两种标识;用 Universe.get().getPlayer(uuid) 解析 UUID,并检查 isValid()。

事件可取消触发时机暴露
PreDwellingClaimEvent是一座洞府即将开辟或迁移。取消后它会报告此地已被设防。owner()、world()、chunkX()、chunkZ()、veinTier()、moved()、radiusChunks() / setRadiusChunks(int)。
DwellingClaimEvent否洞府已开辟,或已有的一座完成迁移 —— 迁移会保留所蓄灵泉与已付供奉。owner()、dwelling()、moved()。
PreDwellingAbandonEvent是一座洞府即将被舍弃。取消可保其不失。owner()、dwelling()。
DwellingAbandonEvent否已舍弃;灵泉中所存也随之而去。owner()、dwelling()。
PreDwellingLapseEvent是一座洞府即将因未付供奉而被收回。取消可为其缓刑 —— 它只能撑到下一次扫描重新检验它为止,因此请从一个「持续在做判断」的监听器中取消,而非一次性的。dwelling()。
DwellingLapseEvent否一处私人洞府在其宽限期过后被世界收回。dwelling()。
PreSpringCollectEvent是一眼灵泉即将被饮尽。取消可让它保持满盈。dwelling()、amount() / setAmount(float) —— 改变取用者带走的量;灵泉无论如何都会被清空。
SpringCollectEvent否灵泉已被清空。amount 是交付出去的灵气 —— 由调用方为其入账。dwelling()、amount()。
PreUpkeepDepositEvent是供奉即将付讫。取消后它会报告未蓄存任何东西。dwelling()、itemId()、quantity()、hours() / setHours(float) —— 整份献纳所值几何,在蓄存时长封顶之前。
UpkeepDepositEvent否供奉已缴入。hoursGranted 是实际蓄存下来的量,一旦触顶便少于所献纳的量。dwelling()、itemId()、quantity()、hoursGranted()。
PreSeclusionSettleEvent是一次闭关即将结算。取消可使其作废 —— 玩家会被告知灵泉已干涸。ref()、player()、dwelling()、hours()(已被 Seclusion-Max-Hours 封顶)、qi() / setQi(float)(当 Seclusion-Drains-Spring 为开时,已被限制在灵泉所能覆盖的范围内)。
SeclusionSettleEvent否修士已出关,并已为其离开的时日付讫。ref()、player()、dwelling()、hours()、qi()。

声明为 @Nullable 的有:player()(所有携带它的事件)。

这些所覆写的配置键:PreDwellingClaimEvent.setRadiusChunks 对应 Dwelling-Radius-Chunks;PreSpringCollectEvent.setAmount 对应 Spring-Qi-Per-Hour、Spring-Pool-Base-Cap 与 Spring-Pool-Cap-Per-Realm;PreUpkeepDepositEvent.setHours 对应 Upkeep-Item-Hours,并受 Upkeep-Max-Banked-Hours 封顶;PreDwellingLapseEvent 对应 Upkeep-Grace-Hours;PreSeclusionSettleEvent.setQi 对应 Seclusion-Qi-Per-Hour。整套系统的门禁:Dwellings-Enabled、Upkeep-Enabled、Seclusion-Enabled。

引脉阵

plugin.siren.API.VeinTapEvents v0.11.1 —— 7 个事件(2 个可取消),涵盖修士布在丰沛灵脉或龙脉上的阵法:布阵、阵主从中领取、对手劫掠,以及释放。面向玩家的文档:引脉阵。

玩家以 UUID 标识。监听器在引发该事件的线程上运行(布阵或劫掠玩家的世界线程,或某条指令线程),此时不持有阵法管理器的任何锁,所以请保持轻量,且不要在监听器里写入 Store。

此类中声明的枚举:

  • Reason(阵法为何不再矗立):RELEASED —— 阵主,或宗门的宗主或长老,将其释放;UPROOTED —— 阵法所在地界的主人将其拔除;SECT_DISBANDED —— 阵主宗门被解散;ADMIN —— 管理员以 /cultivation admin tap clear 将其移除;EXPIRED —— 管理员的测试阵法到了时限。
  • Outcome(劫掠如何结束):SIPHONED —— 抽取守住了:劫掠者取走了他的份额,阵法随即休眠;BROKEN —— 劫掠者离开灵脉、死亡、断线,或阵法不复存在。什么都没被取走。
事件可取消触发时机暴露
PreVeinTapAnchorEvent是每道关卡(功能开启、境界、灵脉、地面、间隔、数量上限)都已通过,但尚未消耗或写入任何东西。取消则布阵以一句笼统的“有什么东西阻止了”失败;阵旗不会被消耗。placer()、sectName()(个人阵法为空)、world()、chunkX()、chunkZ()、tier()(1 丰沛,2 龙脉)。
PreVeinTapRaidEvent是一场劫掠已通过每道关卡,但引导尚未开始,也尚未警告任何阵主。取消则劫掠以一句笼统的“有什么东西阻止了这次劫掠”失败。raider()、tapId()、controllerSect()、controllerOwner()。
VeinTapAnchoredEvent否一座阵法已布下。placer、tapId、sectName、world、chunkX、chunkZ、tier。
VeinTapCollectedEvent否阵主从阵法领取了产出。分文未得的领取不触发。collector、tapId、stones(进入行囊的)、qi(计入倍率后入账的)。
VeinTapRaidStartedEvent否一场劫掠的引导开始。raider、tapId、requiredSeconds。
VeinTapRaidEndedEvent否一场劫掠结束。raider、tapId、outcome、stones、qi(SIPHONED 时所取的份额;若行囊已满,灵石仍可能被保管)。
VeinTapReleasedEvent否一座阵法不再矗立。actor(解散、到期或管理员所致时为 null)、tapId、sectName、ownerUuid、world、chunkX、chunkZ、reason。

声明为 @Nullable 的有:actor()。

这些事件没有可重新调整的配置键,只能否决或观察。开关:Vein-Tap-Enabled、Vein-Tap-Raid-Enabled。

天象

plugin.siren.API.CelestialEvents v0.8.0 —— 3 个事件(1 个可取消),涵盖全服共享的天穹。两个钩子对每种天象类型都是通用的,而不是每种异象各设一对,所以要对某一种作出反应,请按 type().id() 分支。面向玩家的文档:天象。

事件可取消触发时机暴露
PreCelestialEventStartEvent是一场异象即将开始,无论出自调度还是 /celestial start。取消即否决它 —— 调度器只会重新排期,而不会换一场别的。setDurationMinutes 可让它比其类型的默认时长更长或更短。type()、durationMinutes() / setDurationMinutes(float)、forcedByAdmin()。
CelestialEventStartEvent否它已开始。除身处天劫风暴者外,所有玩家的天穹都已在切换。type()、startedAtMillis()、endsAtMillis()、forcedByAdmin()。
CelestialEventEndEvent否它已结束,无论出自计时还是 /celestial stop。type()、startedAtMillis()、endedAtMillis()、forcedByAdmin()。

注册属于自己的异象类型是另一个调用 —— 见注册表。这些事件携带的是 CelestialEventType,因此监听者眼中扩展模组贡献的异象,与内置异象完全平起平坐。CelestialManager 自己注册四种 —— spirit_tide、meteor_shower、blood_moon 与 starfall_convergence —— 另有三种由拥有它们的子系统注册:heavenly_schism(正魔之战)、beast_tide(兽潮)与 beast_omen(灾劫兽)。后两种以零权重注册,调度器永不会抽到它们;由各自的管理器开启它们,并在这些事件之旁触发各自的事件。

兽潮

plugin.siren.API.TideEvents v0.9.0 —— 6 个事件(3 个可取消),涵盖对宗门大殿或洞府的一场围攻(兽潮):预警阶段、每一波,以及结算。它们与该兽潮自己那个天象类型的 CelestialEvents 并行触发,而非取而代之。面向玩家的文档:兽潮。

事件可取消触发时机暴露
PreTideStartEvent是已选定目标,兽潮即将进入预警(WARNING)阶段。取消则整个放弃这次选取 —— 调度器只是等待下一次检查。worldName()、abode()、targetName()、waveCount() / setWaveCount(int)。
TideStartEvent否兽潮的预警阶段开始了 —— 目标已锁定,信标即将生成。assaultId()、worldName()、abode()、targetName()、waveCount()。
PreTideWaveEvent是一波兽群即将触发。取消只跳过这一次尝试(计时器与波次序号照常推进 —— 守方得到的是喘息,而不是多出来的一波)。assaultId()、waveIndex()。
TideWaveEvent否一波兽群刚刚触发(或曾尝试触发 —— 见 PreTideWaveEvent)。assaultId()、waveIndex()、waveCount()。
PreTideResolveEvent是围攻即将结算。取消则跳过发放奖励(WON)或压制/冷却(LOST)—— 围攻无论如何都会结束并清理,被跳过的只是与结局相关的那项副作用。setSuppressionSteps / setSuppressionDurationMinutes 可重新调整败局;setContributionReward 重新调整胜局。assaultId()、result()、suppressionSteps() / setSuppressionSteps(int)、suppressionDurationMinutes() / setSuppressionDurationMinutes(float)、contributionReward() / setContributionReward(int)。
TideResolveEvent否围攻结束了 —— 结局(以及任何奖励/压制)都已施加。assaultId()、worldName()、abode()、targetName()、result()。

灾劫兽

plugin.siren.API.WorldBossEvents v0.9.1 —— 4 个事件(1 个可取消),涵盖一头游荡的、孑然独行而无固定目标的世界首领(灾劫兽):凶兆阶段开始、首领真正现身,以及遭遇结算。只有开始可以取消。面向玩家的文档:灾劫兽。

事件可取消触发时机暴露
PreWorldBossStartEvent是一头灾劫兽即将开始它的凶兆阶段。取消则整个放弃这次开始 —— 调度器只是等待下一次检查。它不携带可重新调整的数值。worldName()、roleId()、position()。
WorldBossStartEvent否一头灾劫兽的凶兆(OMEN)阶段开始了 —— 它的出生点与物种已锁定,凶兆天空与公告已然生效。encounterId()、worldName()、roleId()、position()。
WorldBossSpawnEvent否凶兆结束,首领 NPC 此刻真正存在于世间(进入 ACTIVE 活跃阶段)。encounterId()、worldName()、roleId()、position()、bossRef()。
WorldBossResolveEvent否遭遇结束了,无论因何缘故 —— 任何奖励发放都已排入队列。encounterId()、worldName()、roleId()、result()、contributorCount()、totalContribution()。

虚空裂隙

plugin.siren.API.RiftEvents v0.10.0 —— 5 个事件(1 个可取消),涵盖一场随机触发的全服世界事件:裂隙开启,掷出固定数目的波次,召出一头首领级的守护者,随后以 SEALED 或 COLLAPSED 收场。v0.11.1 默认的波次如今是随第 7 版本而来的虚空阵营(Void Larva、Void Crawler、Voidtaken Goblin、Void Eye 与 Void Spawn),不再是堕化的兽群;事件本身没有变化。只有开启可以取消。面向玩家的文档:虚空裂隙。

事件可取消触发时机暴露
PreRiftOpenEvent是一道虚空裂隙即将开始它的开启阶段。取消则整个放弃这次开启 —— 调度器只是等待下一次检查。它不携带可重新调整的数值。worldName()、position()。
RiftOpenEvent否一道虚空裂隙的开启(OPENING)阶段开始了 —— 它的锚点与出生点已锁定,世界事件标记与公告已然生效。riftId()、worldName()、position()。
RiftWaveEvent否突袭(ASSAULT)阶段中刚刚掷出了一波。waveIndex 从 0 起数;waveCount 是这道裂隙的总波数。riftId()、worldName()、position()、waveIndex()、waveCount()、spawnConfigId() —— 这一波所用的刷怪器资产,即 Rift-Wave-Spawn-Config-Ids 中的一项。v0.11.1 默认是 Cultivation_VoidRift_Surge_Fodder、Cultivation_VoidRift_Surge_Bruiser 或 Cultivation_VoidRift_Surge_Elite,此前是 Cultivation_VoidRift_Fodder、Cultivation_VoidRift_Bruiser 或 Cultivation_VoidRift_Elite;保存的列表若仍与旧默认值相同,加载时会自动升级,自定义过的列表则原样保留。
RiftWardenSpawnEvent否突袭阶段结束,守护者 NPC 此刻真正存在于世间(进入 WARDEN 守护阶段)。riftId()、worldName()、roleId()、position()、wardenRef()。
RiftResolveEvent否遭遇结束了,无论因何缘故 —— 任何奖励发放都已排入队列。outcome 恒为 RiftPhase.SEALED 或 RiftPhase.COLLAPSED。riftId()、worldName()、position()、outcome()、contributorCount()、totalContribution()。

散修客

plugin.siren.API.RogueEvents v0.10.2 —— 3 个事件(1 个可取消),涵盖一名散修客 NPC 的刷出与被击杀。刷出可以取消。面向玩家的文档:散修客。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

事件可取消触发时机暴露
PreRogueCultivatorSpawnEvent是一名散修客即将在 worldName 的 anchorPosition 附近刷出。取消可彻底回绝这次刷出 —— 该世界的下次刷出计时照常推进,与一次因找不到合适地面而被拒的判定无异。worldName()、anchorPosition()、anchorPlayerUuid()、realmOrdinal() / setRealmOrdinal(int)、daoElementName() / setDaoElementName(String)。
RogueCultivatorSpawnedEvent否一名散修客刷出完毕,已在世间打上标记并生效。encounterId()、npcRef()、worldName()、realmOrdinal()、daoElementName()。
RogueCultivatorSlainEvent否一名散修客被击杀了 —— 此事件触发时,任何秘籍/灵核/遗泽的掷骰都已结算。encounterId()、killerUuid()、worldName()、manualAwarded()、bonusCoreAwarded()、testamentAwarded()。

声明为 @Nullable 的有:killerUuid()。

游历道友

plugin.siren.API.RivalEvents v0.9.1 —— 2 个事件(1 个可取消),涵盖向一名游历道友 NPC 发起挑战,以及击败它的奖励。面向玩家的文档:游历道友。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

事件可取消触发时机暴露
PreRivalChallengeEvent是玩家右键点击,向一名游历道友发起挑战。取消可彻底回绝这次挑战 —— 对手仍保持 ROAMING,这次交互不起作用,与 DuelEvents.PreDuelChallengeEvent 给予斗法挑战的「沉默也是一种有效回答」形态相同。encounterId()、challengerUuid()、npcRef()。
RivalDefeatedEvent否一名被挑战的游历道友已被击败 —— 胜者的奖励已经发放。encounterId()、winnerUuid()、worldName()、qiAwarded()、manualAwarded()、materialAwarded()。

秘境

plugin.siren.API.SecretRealmEvents v0.9.0 —— 2 个事件(均不可取消),涵盖一处洞天的结界落下(可进入)或重新升起(封闭)。只设后置事件:开启与封闭是调度器的确定性结果,而不是下游有可能真正否决的请求。面向玩家的文档:秘境。

事件可取消触发时机暴露
SecretRealmOpenEvent否一处秘境开启了 —— 结界已然落下,可以进入。siteId()、tier()、world()、chunkX()、chunkZ()、source()、sectName()、closesAtMillis()。
SecretRealmCloseEvent否一处秘境封闭了。forced 仅在管理员立即强制关闭时为 true(SecretRealmManager.forceClose);秘境在时长/宽限期满后自然关闭则为 false。siteId()、tier()、world()、chunkX()、chunkZ()、forced()。

秘境深渊

plugin.siren.API.DepthsEvents v0.9.1 —— 4 个事件(均不可取消),涵盖一场单人的深渊探索:开始、一层通关(附带它刚掷出的托管奖励)、撤出真正发放奖励,以及探索因任何缘故结束。只设后置事件,缘由同 SecretRealmEvents。面向玩家的文档:深渊。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

事件可取消触发时机暴露
DepthsRunStartEvent否一场单人深渊探索开始了,第 1 层即将刷出。runId()、ownerUuid()、siteId()、world()。
DepthsFloorClearEvent否一层的灵兽尽数毙命 —— escrowSize 是计入本层这次掷骰之后,这趟探索尚未入账的托管总数(比此前多 0 或 1,因为掷骰可能落空)。runId()、ownerUuid()、floor()、escrowSize()。
DepthsExtractEvent否这趟探索的托管奖励刚刚真正发放 —— 仅当 rewardsGranted 大于零时才触发,无论玩家选择了撤出,还是探索自动撤出(登出/秘境关闭)。runId()、ownerUuid()、depthReached()、rewardsGranted()。
DepthsRunEndEvent否探索结束了,无论因何缘故 —— 只触发一次,位于同一结局所产生的任何 DepthsExtractEvent 之后。runId()、ownerUuid()、reason()、depthReached()。

试炼塔

plugin.siren.API.PagodaEvents v0.10.2 —— 3 个事件(1 个可取消),涵盖一层通关、一趟攀登结束,以及通关奖励 —— 后者可以取消,也可重新缩放。面向玩家的文档:试炼塔。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

此处有一个枚举:PagodaRunEndReason(DIED、LEFT、TIMED_OUT、DISCONNECTED)。

事件可取消触发时机暴露
PrePagodaRewardEvent是一层通关奖励即将发放。取消则什么也不发;调用方无论如何都会推进这趟攀登与记录。playerUuid()、floor()、spiritStoneAmount() / setSpiritStoneAmount(long)、qiAmount() / setQiAmount(float)。
PagodaFloorClearedEvent否试炼塔的一层通关了 —— 仅在首次通关(最高层记录真正推进)时 newRecord 为 true,重玩时为 false。playerUuid()、floor()、newRecord()。
PagodaRunEndedEvent否一趟试炼塔攀登结束了,无论因何缘故。floorReached 是攀登结束时所在的那一层,不一定是已通关的一层 —— 层中死亡永不推进玩家自己的记录。playerUuid()、floorReached()、reason()。

宝藏与遗迹

plugin.siren.API.TreasureEvents v0.9.1 —— 2 个事件(1 个可取消),涵盖领取一处埋藏宝藏或进入一座遗迹宝库 —— 一对事件同时涵盖两个品阶,因为二者领取的是同一类地点。面向玩家的文档:寻宝与遗迹探索。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

事件可取消触发时机暴露
PreTreasureClaimEvent是玩家即将领取一处埋藏宝藏或进入一座遗迹宝库。取消可彻底回绝 —— 该处仍未被领取,指令不起作用,与 RivalEvents.PreRivalChallengeEvent 给予游历道友挑战的「沉默也是一种有效回答」形态相同。siteId()、tier()、playerUuid()。
TreasureClaimedEvent否一处宝藏被领取/进入了 —— 奖励已经发放。siteId()、tier()、playerUuid()、worldName()、qiAwarded()、manualAwarded()、materialAwarded()。

传送阵

plugin.siren.API.ArrayEvents v0.10.3 —— 2 个事件(1 个可取消),涵盖经传送阵网络在洞府、宗门大殿、秘境之地、识海或天界之间往来。这趟行程可以取消,也可重新定价。面向玩家的文档:传送阵。

事件可取消触发时机暴露
PreArrayTravelEvent是一位修士即将经传送阵出行。取消可回绝这趟行程(不扣任何东西,也不移动);用 setQiCost 可重新定价。该费用在此事件触发之后才扣,并对照旅者存蓄的灵气重新核对。ref()、player()、destinationKind()、destinationId()、qiCost() / setQiCost(float)。
ArrayTravelEvent否一位修士成功经传送阵出行。qiCost 是实际扣下的最终数额(管理员绕过时为 0)。ref()、player()、destinationKind()、destinationId()、qiCost()。

声明为 @Nullable 的有:ref()(所有携带它的事件);player()(所有携带它的事件)。

任务、赛季与宝阁

剧情,共享的赛季时钟,以及从网络商店送达的购买。

云游任务

plugin.siren.API.QuestEvents v0.9.1 —— 5 个事件(1 个可取消),涵盖从云游 NPC 发布者手中接下一条任务链、逐步推进、完成并足额领到奖励,或将其放弃。只有接取可以取消。面向玩家的文档:游历任务。

PreQuestAcceptEvent 是唯一可以否决的决定(扩展有正当理由不让某位玩家接某条任务链);其余事件所报告的,是一台早已在运转的状态机的下一个状态。

事件可取消触发时机暴露
PreQuestAcceptEvent是玩家即将接下一条任务链。所有内置的拒绝条件(境界门槛、每账号一次、冷却、任务链上限)都已通过;取消则无论如何都回绝。监听器取消时不写入任何东西。ref()、player()、chainId()、giverRoleId()。
QuestAcceptEvent否玩家接下了一条任务链 —— 进度行已写入,对于地点型任务链,其地点也已掷出。ref()、player()、chainId()、giverRoleId()。
QuestStepAdvanceEvent否一条任务链的一步刚刚完成。ref()、player()、chainId()、completedStepIndex()、nextStepIndex()、finalStep()。
QuestCompleteEvent否一条任务链已完全结束,并且已完全付酬 —— 每一项奖励都已到账。每趟只触发一次,即这趟进度转为 COMPLETED 的那一刻。ref()、player()、chainId()、completionCount()。
QuestAbandonEvent否玩家放弃了一趟进行中的任务。正等候发放奖励的那一趟永不触发 —— 那样的无法放弃。ref()、player()、chainId()、stepIndex()。

声明为 @Nullable 的有:player()(所有携带它的事件)。

主线

plugin.siren.API.CampaignEvents v0.9.1 —— 3 个事件(1 个可取消),涵盖任务系统中的章节推进(包括一条主线的第一章)与主线完结。只有推进可以取消。面向玩家的文档:游历任务。

PreCampaignChapterAdvanceEvent 是唯一可以否决的决定。它也会在一条主线的第一章触发,此时 fromChapterIndex() 为 -1,所以扩展可以像回绝任何后续推进那样,回绝一条主线的开启。

事件可取消触发时机暴露
PreCampaignChapterAdvanceEvent是玩家即将进入新的一章(当 fromChapterIndex 为 -1 时,则是开启主线的第一章)。所有内置的拒绝条件(境界门槛、已在进行/已完成)都已通过;取消则无论如何都回绝。ref()、player()、campaignId()、fromChapterIndex()、toChapterIndex()。
CampaignChapterAdvanceEvent否一章刚刚成为玩家的当前章 —— 或是主线的第一章(经 CampaignManager.start),或是接在已完结的一章之后推进而来。newChapterIndex 可能仍被它自己的境界门槛锁着;若监听器在乎这一点,请查看 CampaignManager.getProgress。ref()、player()、campaignId()、previousChapterIndex()、newChapterIndex()。
CampaignCompleteEvent否一条主线的所有章节都已完结。每趟只触发一次,即最后一章的任务链完成的那一刻。ref()、player()、campaignId()。

声明为 @Nullable 的有:player()(所有携带它的事件)。

赛季

plugin.siren.API.SeasonEvents v0.10.2 —— 2 个事件(均不可取消),涵盖共享的赛季节律开启与结束一个赛季。只设后置事件。面向玩家的文档:赛季循环与英名阁。

事件可取消触发时机暴露
SeasonOpenEvent否一个新赛季开启了,其开始时间戳已持久化。seasonId 是此刻在跑的赛季(即将结束那个赛季的 id 加一,全新安装时为 1)。在赛季更替时,它紧接在上一赛季的 SeasonCloseEvent 之后触发;全新安装,或 Season-Enabled 被开启后的第一个 tick,则单独触发。seasonId()、startedAtMillis()。
SeasonCloseEvent否一个赛季结束了:它的英名阁条目与冠军名单已写入,排行榜基线即将在下一次开启时作废。seasonId 是刚刚结束的那个赛季。在正魔之战的赛季总计被重置之前触发,所以监听器看到的仍是完整的收官赛季总计。seasonId()、closedAtMillis()。
去问,别去等

一台在赛季边界上离线的服务器,会在 Cultivation 自己的 setup() 期间结束并重开该赛季,而那早于任何扩展的 setup()。这次开启到不了任何扩展监听器,因为监听器列表此时仍是空的。一个必须知道当前是哪个赛季的扩展,得在自己的 setup() 或首个 tick 里去问 CultivationAPI.getCurrentSeasonId(),并把这些事件纯粹当作「我在旁观时它变了」。

两者都在最先走到赛季泵的那条世界线程上触发 —— 全服范围,而非某位玩家的世界 —— 且此时持有 SeasonManager 自己的监视器。不要阻塞,并在触碰任何人的组件之前,先按玩家切换线程(CompletableFuture.runAsync(task, theirWorld))。这两个事件是悬赏令一节所述那条锁链的链首。

宝阁权益

plugin.siren.API.StoreBenefitEvents v0.8.0 —— 3 个事件(均不可取消),涵盖宝阁同步。三者皆不可取消:权益名单是关于一笔购买的事实,而不是服务器有权表决的决定。

这里的玩家以 UUID 而非 PlayerRef 标识;用 Universe.get().getPlayer(uuid) 解析,并检查 isValid()。

事件可取消触发时机暴露
BenefitGrantedEvent否本次运行中首次发现某玩家对某项权益有权。playerUuid()、benefit()。
BenefitRevokedEvent否某玩家不再出现在名单上 —— 退款,或该权益在本服被禁用。playerUuid()、benefit()。
SyncCompletedEvent否一轮完整同步结束,无论出自周期还是 /cultivation store recheck 强制触发。products()、granted()、revoked()、failedProducts()。

failedProducts() 正是监听者用来分辨「无人拥有它」与「我们联系不上服务器」的依据 —— 同步是失败即放行的,因此端点不可达会让所有人保持原状,而不是把权益撤销。

与玩法事件不同,这些事件触发在远程检查线程上,而不是世界线程:授予与撤销是由一次 HTTP 扫描发现的,手边并没有世界。需要触碰玩家的监听器,必须用 Universe.get().getPlayer(uuid) 找到他们,检查 isValid(),并在读写任何组件之前先切到他们的世界线程。

另见

  • 注册表 —— 添加你自己的种族、功法、灵气吸收物品、称号、宗门旗帜、配色、天象与宝阁权益。
  • 接口参考 —— 直接读取玩家的修炼状态。
  • 配置 —— 事件允许你逐玩家覆写的每一个面向服主的键。
  • 指令 —— 这些事件大多所依托的那些指令。