开发者/事件·

事件

Cultivation 在 plugin.siren.API 下的十二个 *Events 类中,暴露了 156 个事件。模组中几乎每一项机制都被暴露了两次 —— 一次是变更发生之前触发的可取消 Pre* 事件,一次是变更落定之后触发的普通后置事件。

每个类都遵循 CultivationEvents 上所记载的约定,因此学会一个便学会了全部十二个。

前置与后置

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

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

CancellableEvent 恰好暴露两个方法:

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

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

注册与线程

每个事件都有一个配套的 on* 注册方法,接受该事件类型的一个 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))。抛出异常的监听器会被记录并跳过,因此一个写坏的扩展,既弄不垮模组自己的系统,也弄不垮监听同一事件的其他扩展。

有两个子系统带有额外约束,二者都在各自的源码中有所声明:

修炼核心

plugin.siren.API.CultivationEvents —— 28 个事件,涵盖灵气、打坐、仪式、突破、晋阶、跌境、天劫、心魔劫、走火入魔、种族、本命法宝与天赋树。面向玩家的文档:境界与阶段聚灵采气天劫种族本命法宝天赋树

此类上有两个枚举:RitualTypeBREAKTHROUGHADVANCEMENTREFINEMENT)与 MeditationStopReasonCOMMANDMOVEMENT)。

事件可取消触发时机暴露
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突破已完成;其阶段为 EARLYref()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()
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()

这些所覆写的配置键:setRequiredSeconds 对应 Breakthrough-Base-SecondsAdvancement-Base-SecondsPreTribulationStrikeEvent.setDamage 对应 Tribulation-Damage-Percent-Of-Max-HealthAdvancement-Tribulation-Damage-Percent-Of-Max-HealthsetComposureDrain 对应 HeartDevil-Composure-Drain-Per-PulsesetDemotes / setQiLoss 对应 HeartDevil-Deviation-DemotesHeartDevil-Deviation-Qi-Loss-PercentPreRespecEvent 映照 Respec-Enabled/cultivation respec 指令。见配置指令

本类中的 player() 通篇皆为 @Nullable —— 唯有 PlayerRef 组件不可用时它才为 null。

大道与业力

plugin.siren.API.DaoEvents —— 14 个事件,涵盖元素、偏移、阴阳之衡、德行道途与业力。面向玩家的文档:大道业力

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

事件可取消触发时机暴露
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()

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

功法

plugin.siren.API.TechniqueEvents —— 13 个事件,涵盖功法的施展与习得、御剑飞行的开关,以及计时战斗增益。面向玩家的文档:功法秘籍

对经由 CultivationAPI.registerTechnique 注册的第三方功法,这些事件与对内置功法完全一样地触发 —— 关卡、消耗与冷却的管线是共用的。此处有两个枚举:BuffTypeIRON_BODYQI_INFUSIONQI_BARRIERCLOUD_STEP)与 FlightStopReasonTOGGLEQI_EXHAUSTEDDEATH)。

事件可取消触发时机暴露
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()

这些所覆写的配置键:PreTechniquePerformEvent 映照功法规则中各门功法自己的 Qi-CostCooldown-Seconds 条目(见配置),以及指令页上的 /cultivation technique <id> 指令。PreTechniqueLearnEvent 只会为规则中设了 Requires-Manual 的功法触发。

物品

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

从秘籍中习得功法会触发上文的功法习得事件;传授天赋节点的秘籍则走核心的天赋解锁事件。本类涵盖的是秘籍物品本身。此处有两个枚举:LootTypeCULTIVATION_COREBEAST_EGGSPIRIT_STONEMANUAL)与 RefinementOutcomeSUCCESSDESTROYEDDEMOTEDFAILED)。

事件可取消触发时机暴露
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。

这些所覆写的配置键:PreLootDropEvent 对应各项掉落概率键(Spirit-Core-Drop-ChanceProfound-Core-Drop-ChanceDivine-Core-Drop-ChanceEgg-Kill-Drop-ChanceSpiritStone-Kill-Drop-ChanceManual-Tribulation-Drop-ChanceManual-Player-Kill-Drop-Chance);PreSpiritCoreConsumeEvent.setQi 对应 Spirit-Core-Qi-Value / Profound-Core-Qi-Value / Divine-Core-Qi-ValueMeditation-Core-Bonus-MultiplierPreRefinementStartEvent.setQiCost 对应 Refinement-Base-Qi-CostRefinement-Qi-Cost-Tier-MultiplierPreRefinementCompleteEvent.setSuccessChance 对应 Refinement-Base-Success-ChanceRefinement-Success-Chance-Loss-Per-TierRefinement-Min-Success-Chance

灵兽

plugin.siren.API.BeastEvents —— 18 个事件,涵盖收服、孵化、召唤,以及伙伴自身的修行。面向玩家的文档:灵兽

此处有两个枚举:BindSourceTAMEHATCH)与 DismissReasonDISMISSED —— 遣归,所修一概不损;RELEASED —— 永久放归,契约就此断绝)。

事件可取消触发时机暴露
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()

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

宗门

plugin.siren.API.SectEvents —— 29 个事件,涵盖开宗、门籍、职位、大殿、殿上碑文与旗帜。面向玩家的文档:宗门,以及指令页上的 /sect 系列。

记住上文那两条约束:监听器持有 SectManager 的锁,且此处的玩家是 UUID。此类上有两个枚举:JoinMethodINVITEOPENREQUEST)与 LeaveReasonLEFTKICKED)。

事件可取消触发时机暴露
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他已不在名录上。KICKEDactor 是执行驱逐者,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()
PreSectBannerChangeEvent宗门的旗帜即将变更。取消可让旧旗继续飘扬。监听器改写该 id 之后,它不会被重新校验 —— 一个未注册的 id 并非错误,只会解算为对应灵脉品阶的默认灯火。manager()sect()oldBannerId()bannerId() / setBannerId(String)
SectBannerChangeEvent旗帜已变更。大殿的常置灯火会在其下一次脉动时切换为新旗。manager()sect()oldBannerId()newBannerId()

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

战事

plugin.siren.API.WarEvents —— 5 个事件,涵盖向敌方大殿宣战及其如何结算。面向玩家的文档:宗门攻伐

大殿真正易主的是 SectEvents.SectHallCaptureEvent,它在夺取过程内部触发 —— 否决那一个,即可让围攻获胜而大殿不动。此处有一个枚举:SiegeFailReasonLAPSEDDEFENDER_GONE)。

事件可取消触发时机暴露
PreWarDeclareEvent一场围攻即将宣布。取消后调用方会被告知战事系统已禁用。attacker()defender()windowMillis() / setWindowMillis(long) —— 攻方有多久去完成其占据。
WarDeclareEvent围攻已生效,双方均已收到告知。attacker()defender()siege()
PreSiegeCaptureEvent一场围攻即将获胜。取消可让它继续进行 —— 攻方仍在占据,并会在其下一个在场判定周期再次触发此事件,因此请仅在你自己的某个条件尚未满足时取消。attacker()defender()siege()
SiegeCaptureEvent攻方已占据足够久。大殿的移交已经尝试过,守方的免战冷却也已开始。attacker()defender()siege()
SiegeFailEvent围攻结束,大殿仍在守方手中。siege()reason()

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

斗法

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

此处的玩家是 UUID,因为一场赌斗经常比其中一名参与者的会话活得更久 —— 而那恰恰正是它作罢的缘由。此处有一个枚举:DuelEndReasonDEATH —— 押注易主;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 时胜者与败者是有意义的,且结算已排队;VOIDED 时二者不过是那两名参与者。winner()loser()wager()reason()
PreDuelPayoutEvent一场已判定赌斗的押注即将转移。取消可让胜者一无所得。winner()loser()amount() / setAmount(int) —— 实际转移的量仍受败者所持数额的封顶。
DuelPayoutEvent押注已转移。amount 是败者所能拿出的数额,也正是胜者所得。winner()loser()amount()

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

阵法

plugin.siren.API.FormationEvents —— 6 个事件,涵盖锚定于区块的灵阵之布设与驱散,以及困仙阵伤及入侵者。面向玩家的文档:阵法

事件可取消触发时机暴露
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()

这些所覆写的配置键:setRadiusChunkstype() 而定,对应 QiGathering-Radius-ChunksWarding-Radius-ChunksTrapping-Radius-ChunksPreFormationTrapStrikeEvent.setDamage 对应 Trapping-Damage-Percent-Of-Max-Health(与之并列的还有 Trapping-LethalTrapping-Interval-SecondsTrapping-Debuff-Duration-Seconds)。整套系统的门禁:Formations-EnabledMax-Formations-Per-Controller

洞府

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

宗门山门灵泉是自动创建并随其宗门大殿迁移的;那套内务处理刻意不触发任何事件。请改为监听宗门大殿的设立与夺取事件 —— 它们才是其成因。

事件可取消触发时机暴露
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()

这些所覆写的配置键:PreDwellingClaimEvent.setRadiusChunks 对应 Dwelling-Radius-ChunksPreSpringCollectEvent.setAmount 对应 Spring-Qi-Per-HourSpring-Pool-Base-CapSpring-Pool-Cap-Per-RealmPreUpkeepDepositEvent.setHours 对应 Upkeep-Item-Hours,并受 Upkeep-Max-Banked-Hours 封顶;PreDwellingLapseEvent 对应 Upkeep-Grace-HoursPreSeclusionSettleEvent.setQi 对应 Seclusion-Qi-Per-Hour。整套系统的门禁:Dwellings-EnabledUpkeep-EnabledSeclusion-Enabled

淬体

plugin.siren.API.BodyTemperingEvents —— 4 个事件,涵盖第二条修行之路:不靠采气、只靠挨打的那一条。面向玩家的文档:淬体

事件可取消触发时机暴露
PreXpGainEvent即将因落在身上的伤害获得淬体熟练度。数额可改,而不只是可拒 —— 这是为单个玩家或单个场景重调整条阶梯的正规做法。ref()player()amount() / setAmount(float)level()
XpGainEvent熟练度已入账。ref()player()amount()level()
PreLevelUpEvent即将提升一级淬体。取消则维持原位。ref()player()fromLevel()toLevel()
LevelUpEvent已提升。一击跨越多级时逐级触发。ref()player()fromLevel()toLevel()

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

修炼存档

plugin.siren.API.ProfileEvents —— 7 个事件,涵盖玩家的修炼存档:在存档间切换、创建一份、删除一份,以及试炼存档到期。面向玩家的文档:修炼存档

这些事件携带一个 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()

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

另见