QYXT API v1 是什么:《青元仙途》对外开放的跨模组调用接口。
别的模组可以通过 tModLoader 的 Mod.Call 读取玩家境界、灵根、功法、灵气,
查询境界/灵根/功法规则表与世界进度,也能在服务端发放灵气奖励 —— 用来做联动、任务、奖励结算,
而不必反编译本模组。
适合谁看:会写 C# 模组的作者。只想玩游戏的话,这份文档用不上。
概览
| 项目 | 值 |
|---|
| 协议标识(第一个参数) | "QYXT"(全大写,区分大小写) |
| API 主版本号(第二个参数) | 1(Int32) |
| API 版本字段 | ApiMajor = 1,ApiMinor = 0 |
| 接口(命令)总数 | 13 个 |
握手方式与版本协商(单独一节)
调用形式
object result = qyxtMod.Call("QYXT", 1, "命令名", 参数1, 参数2, ...);
三个固定前缀参数:
| 位置 | 名称 | 类型 | 说明 |
|---|
args[0] | 协议标识 | string | 必须是 "QYXT",否则报 InvalidRequest |
args[1] | API 主版本 | int | 必须是 1,否则报 UnsupportedVersion |
args[2] | 命令名 | string | 见下方接口列表,未知命令报 UnknownCommand |
args[3..] | 命令参数 | 视命令而定 | 数量必须精确匹配,多传少传都报 InvalidArgument |
如何判断本模组是否可用
推荐做法:反射拿 Mod 实例 + 探测 Api.GetInfo(因为 Api.GetInfo 不需要世界加载,且在菜单界面即可调用)。
Mod qyxt = null;
if (ModLoader.TryGetMod("QingzhuFengyun", out qyxt))
{
object raw = qyxt.Call("QYXT", 1, "Api.GetInfo");
if (raw is Dictionary<string, object> info
&& info.TryGetValue("Ok", out var ok) && ok is true
&& info.TryGetValue("ApiMajor", out var major) && major is int m && m >= 1)
{
// API 可用
}
}
注意:模组内部名(ModLoader.TryGetMod 的第一个参数)源码中未直接以字符串常量出现,Api.GetInfo 返回的 ModName 字段取自 mod.Name,运行时会返回实际内部名。建议 wiki 中注明「以运行时 Api.GetInfo 返回的 ModName 为准」。
统一返回信封
所有接口永远返回一个 Dictionary<string, object>,从不抛异常到调用方(ApiRouter.Dispatch 内部 try/catch 全部兜住,见 ApiRouter.cs:95-106)。
| 键 | 类型 | 说明 |
|---|
Ok | bool | 成功为 true,失败为 false |
ApiVersion | int | 恒为 1 |
Data | object | 成功时的载荷(bool / long / int / Dictionary / Dictionary[]);失败时为 null |
ErrorCode | string | 成功时为空字符串 "",失败时为错误码 |
Message | string | 成功时为空字符串 "",失败时为英文错误说明 |
错误码总表(源码原文)
| ErrorCode | 触发条件 | Message 原文 |
|---|
InvalidRequest | args 为 null、长度 < 3、args[0] 不是字符串或不等于 "QYXT" | Use Mod.Call("QYXT", 1, command, ...arguments). |
InvalidArgument | args[1] 不是 int | API version must be Int32. |
UnsupportedVersion | args[1] != 1 | Supported API major version: 1. |
InvalidArgument | args[2] 不是 string | Command must be String. |
UnknownCommand | 命令名未注册 | Query Api.GetCommands for supported commands. |
InvalidArgument | 参数个数不等于 Arguments.Length + 3 | {命令名} expects {N} arguments. |
WorldNotReady | 命令标记 RequiresWorld 但当前在菜单/加载界面 | This call requires a loaded world, not a menu/loading screen. |
NotAuthority | 命令标记 ServerOnly 但不是服务端/单人 | Call only on the server or in singleplayer; no packet is sent automatically. |
InvalidArgument | 参数类型不符(ApiArgs.Get<T>) | Argument {index} must be {类型名}. |
InvalidArgument | 数值参数既不是 int 也不是 long | Argument {index} must be Int32 or Int64. |
OutOfRange | 数值参数 <= 0 或 > 上限 | Amount must be between 1 and {maximum}. |
OutOfRange | 境界 ID 不在 0–8 | Realm ID must be between 0 and 8; True Immortal is a separate state. |
OutOfRange | 玩家索引不在 0–254 | Player index is outside Main.player. |
OutOfRange | NPC 索引不在 0–Main.maxNPCs-1 | NPC index is outside Main.npc. |
PlayerInactive | 目标玩家不存在或未激活 | The requested player is not active. |
NpcInactive | 目标 NPC 不存在或未激活 | The requested NPC is not active. |
PlayerDead | 目标玩家已死亡(仅 Player.GrantAura) | Cannot reward a dead player through this API. |
NoBasicTechnique | 玩家未学习基础功法(仅 Player.GrantAura) | The player must learn a basic technique first. |
UnknownKey | 未知秘术键 / 未知内容分类 | Unknown secret technique key; query Rules.GetTechniques. / Supported kinds: Item, NPC, Projectile, Buff, Tile, Wall. |
NotFound | Content.Find 未命中 | Content name was not found; query Content.List. |
InternalError | 处理器抛出未预期异常 | See the QingzhuFengyun log. Do not automatically retry mutations. |
InternalError 有去重机制:同一命令名的内部错误只写一次日志(ApiRouter.cs:101-104)。
世界状态与执行端要求(重要)
RequiresWorld 判定:!Main.gameMenu && Main.ActiveWorldFileData != null(AddonApi.cs:28)。
→ 标记 RequiresWorld: true 的接口必须在已加载的世界中调用,主菜单/加载界面调用会返回 WorldNotReady。
ServerOnly 判定:Main.netMode != 1(即非客户端 = 服务端或单人)。
→ 标记 ServerOnly: true 的接口只能在服务端或单人调用;客户端调用返回 NotAuthority。API 不会自动发包,消息原文强调 no packet is sent automatically.
- 多个返回字段带
IsAuthoritative(值即 Main.netMode != 1),用于让调用方判断数据是否为权威值。
分类一:元数据 / 自省类(2 个)
无需世界,任何时刻可调用。这一组是握手和自文档化的核心。
1. Api.GetInfo
- 参数:无
- 返回值:
Dictionary<string, object>,字段如下
| 字段 | 类型 | 含义 |
|---|
ModName | string | 本模组内部名(运行时取自 mod.Name) |
ModVersion | string | 模组版本字符串(mod.Version.ToString()) |
ApiMajor | int | 恒为 1 |
ApiMinor | int | 恒为 0 |
Commands | string[] | 所有已注册命令名,按 Ordinal 升序排列 |
- 用途:一句话 —— 让别的模组探测「青元仙途是否装了、APK 版本是多少、支持哪些命令」。
- 源码位置:
QingzhuFengyun.Content.Integration/AddonApi.cs:45-52
- 示例代码:
if (ModLoader.TryGetMod("QingzhuFengyun", out Mod qyxt))
{
if (qyxt.Call("QYXT", 1, "Api.GetInfo") is Dictionary<string, object> info
&& info["Ok"] is true)
{
string ver = (string)info["ModVersion"]; // 例如 "2.1.6.10"
int major = (int)info["ApiMajor"]; // 1
int minor = (int)info["ApiMinor"]; // 0
string[] cmds = (string[])info["Commands"]; // 全部 13 个命令名
}
}
- 校验:无参数即无参数校验;仅受通用信封校验(协议名 + 版本号)。
2. Api.GetCommands
- 参数:无
- 返回值:
Dictionary<string, object>[],每个元素是一个「接口自描述」字典:
| 字段 | 类型 | 含义 |
|---|
Name | string | 命令名 |
Arguments | string[] | 参数签名清单,如 ["playerIndex:int", "realmId:int"] |
Returns | string | 返回类型描述,如 "bool"、"Dictionary<string,object>" |
Summary | string | 中文摘要(源码原文,见各接口条目) |
RequiresWorld | bool | 是否要求已加载世界 |
ServerOnly | bool | 是否仅限服务端/单人 |
- 用途:一句话 —— 让别的模组在运行时自动枚举全部接口、参数和执行端要求,做动态适配。
- 源码位置:
QingzhuFengyun.Content.Integration/AddonApi.cs:53(实现为 ApiRouter.Describe(),ApiRouter.cs:42-57)
- 示例代码:
var list = (Dictionary<string, object>[])qyxt.Call("QYXT", 1, "Api.GetCommands")["Data"];
foreach (var ep in list)
{
string name = (string)ep["Name"];
string[] sig = (string[])ep["Arguments"];
string ret = (string)ep["Returns"];
bool needWorld = (bool)ep["RequiresWorld"];
bool srvOnly = (bool)ep["ServerOnly"];
Mod.Logger.Info($"{name}({string.Join(", ", sig)}) -> {ret}");
}
分类二:规则数据查询类(3 个)
全部不需要世界,属于「静态规则表」,可在主菜单调用。返回内容全部来自枚举与规则表,不含玩家/世界状态。
3. Rules.GetRealms
- 参数:无
- 返回值:
Dictionary<string, object>[],每项字段:
| 字段 | 类型 | 含义 |
|---|
Id | int | 境界 ID(0–8) |
Key | string | 枚举稳定键名,如 "QiRefining" |
Name | string | 中文显示名(CultivationRules.GetName) |
BaseAuraThreshold | long | 基础突破门槛(未计个人修正,见下方数值表) |
ApertureLimit | int | 该境界累计秘窍上限 |
- 用途:一句话 —— 让别的模组读取境界体系、基础门槛和秘窍上限,用于自定义 UI 或平衡换算。
- 源码位置:
AddonApi.cs:58-66
- 境界 ID 对照表(源码
CultivationRealm.cs,枚举自 0 递增):
| Id | Key | Name 语言键 |
|---|
| 0 | Mortal | Mods.QingzhuFengyun.Cultivation.Realms.Mortal |
| 1 | QiRefining | ...Realms.QiRefining |
| 2 | Foundation | ...Realms.Foundation |
| 3 | CoreFormation | ...Realms.CoreFormation |
| 4 | NascentSoul | ...Realms.NascentSoul |
| 5 | DeityTransformation | ...Realms.DeityTransformation |
| 6 | SpatialTempering | ...Realms.SpatialTempering |
| 7 | BodyIntegration | ...Realms.BodyIntegration |
| 8 | GrandAscension | ...Realms.GrandAscension |
Name 字段的实现是 Language.GetTextValue($"Mods.QingzhuFengyun.Cultivation.Realms.{realm}")(CultivationRules.cs:33-36),因此运行时返回的是当前语言下的本地化文案,不是硬编码中文。wiki 写作时不要写死中文名。
注意:真仙是独立状态,不在 0–8 之内(错误消息原文:Realm ID must be between 0 and 8; True Immortal is a separate state.)
BaseAuraThreshold 数值表(源码 CultivationRules.cs:21,BaseThresholds 数组,GetThreshold 的 reducedAfterThreeTurns 传入 false 故无 0.8 折扣):
| 境界 | BaseAuraThreshold |
|---|
| Mortal (0) | 0 |
| QiRefining (1) | 100 |
| Foundation (2) | 1,000 |
| CoreFormation (3) | 10,000 |
| NascentSoul (4) | 100,000 |
| DeityTransformation (5) | 1,000,000 |
| SpatialTempering (6) | 2,000,000 |
| BodyIntegration (7) | 3,000,000 |
| GrandAscension (8) | 4,000,000 |
另有境界配色表(CultivationRules.GetColor,CultivationRules.cs:64-75)可供 wiki 排版参考,但该接口不返回配色,如需配色需自行从源码取值:炼气 (245,245,235)、筑基 (90,225,115)、结丹 (85,165,255)、元婴 (190,105,255)、化神 (255,205,65)、炼虚 (20,20,26)、合体 (245,70,70)、大乘 (255,160,195)、默认 (175,185,180)。
- 秘窍上限数值表(源码
CultivationBalance.cs:9-20 等):
| 境界 | ApertureLimit |
|---|
| Mortal | 0 |
| QiRefining | 100 |
| Foundation | 150 |
| CoreFormation | 300 |
| NascentSoul | 500 |
| DeityTransformation | 800 |
| SpatialTempering | 1000 |
| BodyIntegration | 1300 |
var realms = (Dictionary<string, object>[])qyxt.Call("QYXT", 1, "Rules.GetRealms")["Data"];
foreach (var r in realms)
{
int id = (int)r["Id"];
string key = (string)r["Key"];
string name = (string)r["Name"]; // 中文名
int aperture = (int)r["ApertureLimit"];
}
4. Rules.GetSpiritRoots
- 参数:无
- 返回值:
Dictionary<string, object>[](固定 5 项,索引 0–4),每项字段:
| 字段 | 类型 | 含义 |
|---|
Mask | int | 位标记值(1 / 2 / 4 / 8 / 16) |
Key | string | "Metal" / "Wood" / "Water" / "Fire" / "Earth" |
Name | string | 元素名,中文 金/木/水/火/土,英文 Metal/Wood/Water/Fire/Earth(QingzhuText.Lang,跟随语言) |
Rgb | int[3] | 与结丹演出一致的配色,[R, G, B] |
- 用途:一句话 —— 让别的模组按官方配色渲染灵根图标/文字,并拿到位标记常量。
- 源码位置:
AddonApi.cs:67-80
- 灵根位标记对照表(源码
SpiritRootElement.cs,[Flags]):
| Key | Mask | 说明 |
|---|
None | 0 | 无(此接口不返回) |
Metal | 1 | 金 |
Wood | 2 | 木 |
Water | 4 | 水 |
Fire | 8 | 火 |
Earth | 16 | 土 |
All | 31 | 五行齐全(= 1\ | 2\ | 4\ | 8\ | 16) |
灵根数量 = popcount(Mask & 31),源码用 SpiritRootRules.Count(...)。 灵根品质枚举 SpiritRootQuality(SpiritRootQuality.cs):Untested, Heavenly, Superior, Ordinary, Pseudo, FiveElements —— 会在 Player.GetSnapshot 的 SpiritRootQuality 字段以字符串形式返回。
var roots = (Dictionary<string, object>[])qyxt.Call("QYXT", 1, "Rules.GetSpiritRoots")["Data"];
foreach (var r in roots)
{
int mask = (int)r["Mask"];
string key = (string)r["Key"];
int[] rgb = (int[])r["Rgb"]; // 与结丹演出同色
}
// 判断玩家是否同时有金、木灵根:
bool metalWood = (mask & 1) != 0 && (mask & 2) != 0;
5. Rules.GetTechniques
- 参数:无
- 返回值:
Dictionary<string, object>,含三个键,每键是 Dictionary<string, object>[](元素为 { "Key": string, "Name": string }):
| 键 | 内容 |
|---|
Basic | 基础功法(不含 None) |
Advanced | 高阶功法(不含 None) |
Secret | 秘术(不含 None) |
- 用途:一句话 —— 提供全部功法的稳定键名 → 显示名映射,是
Player.HasSecret 等接口传参的前置查询。
- 源码位置:
AddonApi.cs:81-92(辅助方法 Technique 在 :95-102)
Name 字段来源(CultivationRules.cs:78-178)—— 大部分取物品 DisplayName 的本地化键(跟随语言),少数秘术是硬编码中文字符串,见下表标注:
| 类别 | Key | Name 来源 |
|---|
| Basic | ThreeTurnEssence | Items.ThreeTurnEssenceArt.DisplayName |
| Basic | ProfoundYinArt | Items.ProfoundYinArt.DisplayName |
| Basic | EvergreenArt | Items.EvergreenArt.DisplayName |
| Basic | GreatDevelopmentArt | Items.GreatDevelopmentArt.DisplayName |
| Advanced | AzureEssenceSwordArt | Items.AzureEssenceSwordArt.DisplayName |
| Advanced | BrahmaSacredTrueDevilArt | Items.BrahmaSacredTrueDevilArt.DisplayName |
| Advanced | MysteriousYinInfantArt | Items.MysteriousYinInfantArt.DisplayName |
| Advanced | SpiritRefinementArt | Items.SpiritRefinementArt.DisplayName |
| Secret | SuNuReincarnationArt | Items.SuNuReincarnationArt.DisplayName |
| Secret | BloodDemonScripture | Items.BloodDemonScripture.DisplayName |
| Secret | ShaDemonArt | Items.ShaDemonArt.DisplayName |
| Secret | ExorcisingThunderArt | Items.ExorcisingThunderArt.DisplayName |
| Secret | IncompleteDemonScripture | Items.IncompleteDemonScripture.DisplayName |
| Secret | XuanSoulDemonManual | Items.XuanSoulDemonManual.DisplayName |
| Secret | InsectRepellingArt | Items.InsectRepellingSecretArt.DisplayName(注意物品名与键名不同) |
| Secret | GreatGengSwordArray | 硬编码中文 大庚剑阵秘术 |
| Secret | SwordControlArt | 硬编码中文 御剑术 |
| Secret | SixExtremeTrueDemonArt | 硬编码中文 六极真魔功 |
| Secret | MagneticDivineLight | 硬编码中文 元磁神光 |
| Secret | GoldDevouringCultivation | 硬编码中文 噬金虫培养秘籍 |
| Secret | BloodRefiningDivineLight | Items.BloodRefiningDivineLight.DisplayName |
| Secret | ShuraHolyFireArt | Items.ShuraHolyFireSecretArt.DisplayName(注意物品名与键名不同) |
var dict = (Dictionary<string, object>)qyxt.Call("QYXT", 1, "Rules.GetTechniques")["Data"];
var secrets = (Dictionary<string, object>[])dict["Secret"];
foreach (var s in secrets)
Mod.Logger.Info($"{s["Key"]} = {s["Name"]}");
// 输出形如: SuNuReincarnationArt = 素女轮回功
分类三:玩家状态读取类(4 个)
全部 RequiresWorld: true、ServerOnly: false。playerIndex 取值 0 ≤ index < 255,越界返回 OutOfRange;指向的玩家不存在或未激活返回 PlayerInactive。
索引来源即 Main.player[index],一般用 player.whoAmI。
6. Player.GetSnapshot
- 参数:1 个
playerIndex:int —— Main.player 数组索引,必填,范围 0–254
- 返回值:
Dictionary<string, object>,字段全表:
| 字段 | 类型 | 含义 |
|---|
PlayerIndex | int | player.whoAmI |
IsAuthoritative | bool | Main.netMode != 1(是否权威数据) |
NaturalRealm | int | 自然境界(不受场景压制) |
EffectiveRealm | int | 有效境界(受场景压制影响) |
RealmLevel | int | 当前境界内的等级 |
IsTrueImmortal | bool | 是否为真仙 |
RealmSuppressed | bool | 是否被宫殿场景压制(PalaceRealmSuppressed) |
Aura | long | 当前灵气值 |
AuraStorageCap | long | 灵气存储上限(GetAuraStorageCap()) |
ImmortalSpiritQi | long | 真仙仙气值 |
SpiritRootMask | int | 灵根位标记(已 & All) |
SpiritRootCount | int | 灵根数量 |
SpiritRootQuality | string | 灵根品质枚举名字符串 |
RefinedFiveElements | (源码未显式转型,为 int/byte 计数) | 已炼化五行数量 |
AbsorbedSpiritQiMask | int | 已吸收灵气位标记(已 & All) |
BasicTechnique | string | 基础功法键名,未学为 "None" |
AdvancedTechnique | string | 高阶功法键名,未学为 "None" |
SelectedSecret | string | 当前选装秘术键名,未选为 "None" |
UnlockedSecrets | string[] | 已解锁秘术键名数组(不含 None) |
DharmicPower | (数值) | 法力值 |
DharmicPowerMaximum | (数值) | 法力上限 |
DivineSense | (数值) | 神识值 |
DivineSenseMaximum | (数值) | 神识上限 |
ApertureCoresUsed | (数值) | 已用秘窍数 |
ApertureLimit | (数值) | 秘窍上限 |
ApertureRemaining | (数值) | 剩余秘窍(Math.Max(0, 上限 - 已用)) |
- 用途:一句话 —— 一次性拿到某个玩家的全部修仙状态,是外部模组做兼容联动/UI 显示的主入口。
- 源码位置:
AddonApi.cs:106(注册)+ AddonApi.cs:173-209(PlayerSnapshot 实现)
- 示例代码:
var res = (Dictionary<string, object>)qyxt.Call("QYXT", 1, "Player.GetSnapshot", player.whoAmI);
if ((bool)res["Ok"])
{
var d = (Dictionary<string, object>)res["Data"];
Mod.Logger.Info($"境界={d["EffectiveRealm"]} 灵气={d["Aura"]}/{d["AuraStorageCap"]}");
string[] unlocked = (string[])d["UnlockedSecrets"];
}
else Mod.Logger.Warn($"查询失败 {res["ErrorCode"]}: {res["Message"]}");
7. Player.MeetsRealm
- 参数:3 个
playerIndex:int —— 玩家索引,必填,0–254
realmId:int —— 境界 ID,必填,0–8,越界报 OutOfRange
useNaturalRealm:bool —— true 用自然境界比较,false 用受场景压制后的有效境界
- 返回值:
bool(在 Data 中)
- 逻辑:
(useNaturalRealm ? NaturalRealm : Realm) >= realmId
- 用途:一句话 —— 让别的模组判断「该玩家是否已达到某境界」,用于门禁、掉落、对话分支。
- 源码位置:
AddonApi.cs:107-112(境界校验辅助 GetRealm 在 :148-156)
- 示例代码:
// 该玩家是否至少元婴(Id=4),按有效境界判定
bool ok = (bool)qyxt.Call("QYXT", 1, "Player.MeetsRealm", player.whoAmI, 4, false)["Data"];
// 按自然境界判定(忽略宫殿压制)
bool natural = (bool)qyxt.Call("QYXT", 1, "Player.MeetsRealm", player.whoAmI, 4, true)["Data"];
- 校验:
realmId 必须 0–8,否则 OutOfRange:Realm ID must be between 0 and 8; True Immortal is a separate state.
useNaturalRealm 必须是 bool,否则 InvalidArgument:Argument 2 must be Boolean.
- 注意源码中该参数用的是
args.Get<bool>(2),若传 0/1 整数会报错。
8. Player.GetThreshold
- 参数:2 个
playerIndex:int —— 0–254
realmId:int —— 0–8
- 返回值:
long —— 计入个人功法修正后的突破所需灵气门槛
- 源码实现链:
CultivationPlayer.GetRequiredThreshold(realm)(CultivationPlayer.cs:2090-2102),内部按三转减耗、射手基础功法 ×1.1、射手高阶功法(目标 > 4)×1.2 修正,上限 2000000000
- 用途:一句话 —— 查「这个玩家突破到某境界还差多少灵气」,用于外部 UI 显示进度条。
- 源码位置:
AddonApi.cs:113
- ⚠️ 注意:源码 Summary 中文原文明确写道 「不是突破许可判断」 —— 返回的是数值门槛,不代表当前允许突破(世界进度锁等另有限制,见
World.GetProgress 的 RealmCeiling)。
- 示例代码:
long need = (long)qyxt.Call("QYXT", 1, "Player.GetThreshold", player.whoAmI, 5)["Data"];
long aura = (long)((Dictionary<string,object>)qyxt.Call("QYXT",1,"Player.GetSnapshot",player.whoAmI)["Data"])["Aura"];
Mod.Logger.Info($"化神所需 {need},当前 {aura}");
9. Player.HasSecret
- 参数:2 个
playerIndex:int —— 0–254
secretKey:string —— 秘术键名,严格匹配(Enum.TryParse 且 ignoreCase: false),不能是 "None"
- 返回值:
bool —— 该秘术是否已解锁
- 用途:一句话 —— 判断玩家是否解锁了某秘术,用于自定义秘籍物品、商店解锁、任务条件。
- 源码位置:
AddonApi.cs:114-123
- ⚠️ 语义边界(Summary 中文原文):「秘术是否已解锁(沿用原有路线条件),不代表已选装或冷却完毕。」 即:解锁 ≠ 当前选装(选装看
Player.GetSnapshot 的 SelectedSecret)。
- 示例代码:
bool has = (bool)qyxt.Call("QYXT", 1, "Player.HasSecret", player.whoAmI, "SwordControlArt")["Data"];
- 校验(严格):
- 键名必须能被
Enum.TryParse<SecretTechnique> 解析、不等于 None、Enum.IsDefined 通过、且 result.ToString() == 原字符串(即大小写也必须完全一致)
- 失败报
UnknownKey:Unknown secret technique key; query Rules.GetTechniques.
- 传
"none"(小写)或 "None" 都会失败。
分类四:玩家状态写入类(1 个)
10. Player.GrantAura
- 参数:2 个
playerIndex:int —— 0–254
baseAmount:long (int accepted) —— 发放的基础灵气量,必须 > 0 且 ≤ 2000000000;int 与 long 都接受
- 返回值:
Dictionary<string, object>:
| 字段 | 类型 | 含义 |
|---|
Requested | long | 请求发放的量(原样回显) |
Applied | long | 实际生效的量(受上限/加成/转化影响,可能为 0) |
Resource | string | "Aura"(普通灵气)或 "ImmortalSpiritQi"(真仙仙气) |
- 用途:一句话 —— 服务端给玩家发放灵气奖励(例如别的模组打完自己的 Boss 给青元仙途灵气)。
- 源码位置:
AddonApi.cs:124-145
- 执行端要求:
ServerOnly: true —— 只能在服务端或单人调用,客户端调用返回 NotAuthority,且 API 不会自动发包(错误消息原文:Call only on the server or in singleplayer; no packet is sent automatically.)。
- 继承的原有机制(Summary 中文原文):「服务端发放普通灵气奖励,沿用原有上限、禁用状态、补天丹加成和真仙转化。」
- 走
CultivationPlayer.AddCultivationEnergy(CultivationPlayer.cs:1790-1814)
- 若玩家处于煞魔功激活或 MiaoYinPlayer.ShaLock > 0 → 实际生效 0
- 应用
PermanentAuraGainMultiplier(补天丹加成)后再截断到 20 亿
- 真仙玩家:灵气自动转为仙气(
GainImmortalSpiritQiFromAura),Resource 返回 "ImmortalSpiritQi",仙气上限 1000000(MaLiangPlayer.MaximumImmortalSpiritQi)
- 已达灵气存储上限 → 实际生效 0
- 成功变更会调用
SendState() 同步
- 前置条件校验:玩家必须已学习基础功法,否则
NoBasicTechnique:The player must learn a basic technique first.
- 死亡校验:玩家已死亡 →
PlayerDead:Cannot reward a dead player through this API.
- 示例代码:
// 仅服务端执行
if (Main.netMode != NetmodeID.MultiplayerClient)
{
var res = (Dictionary<string, object>)qyxt.Call("QYXT", 1, "Player.GrantAura", player.whoAmI, 5000L);
if ((bool)res["Ok"])
{
var d = (Dictionary<string, object>)res["Data"];
long applied = (long)d["Applied"]; // 实际到账(可能被上限截断为 0)
string res2 = (string)d["Resource"]; // "Aura" 或 "ImmortalSpiritQi"
}
else Mod.Logger.Warn($"发放失败 {res["ErrorCode"]}: {res["Message"]}");
}
- 校验清单:玩家索引 → 死亡 → 数值范围(
OutOfRange: Amount must be between 1 and 2000000000.)→ 类型(InvalidArgument: Argument 1 must be Int32 or Int64.)→ 基础功法。
分类五:世界与 NPC 查询类(2 个)
11. NPC.GetSnapshot
- 参数:1 个
npcIndex:int —— Main.npc 数组索引,必填,范围 0 ≤ index < Main.maxNPCs
- 返回值:
Dictionary<string, object>:
| 字段 | 类型 | 含义 |
|---|
NpcIndex | int | 传入的索引 |
Type | int | NPC 类型 ID |
Realm | int | 该 NPC 的境界 ID(CultivationRules.ClassifyNPC 分类结果) |
IsBoss | bool | `npc.boss \ | \ | Sets.ShouldBeCountedAsBoss[type]` |
ModName | string | 所属模组名(null 时回落为 "Terraria") |
IsAuthoritative | bool | Main.netMode != 1 |
- 用途:一句话 —— 查询某个存活 NPC 的修仙境界与所属模组,用于跨模组 Boss 强度适配。
- 源码位置:
AddonApi.cs:213-236
- ⚠️ 只读保证(Summary 中文原文):「查询存活 NPC 实例当前境界,不改变其数值。」
- 示例代码:
var res = (Dictionary<string, object>)qyxt.Call("QYXT", 1, "NPC.GetSnapshot", npc.whoAmI);
if ((bool)res["Ok"])
{
var d = (Dictionary<string, object>)res["Data"];
int realm = (int)d["Realm"];
bool boss = (bool)d["IsBoss"];
string from = (string)d["ModName"];
}
- 校验:索引范围(
OutOfRange: NPC index is outside Main.npc.)、NPC 激活状态(NpcInactive: The requested NPC is not active.)。
- 依赖世界状态:
RequiresWorld: true。
12. World.GetProgress
- 参数:无
- 返回值:
Dictionary<string, object>:
| 字段 | 类型 | 含义 |
|---|
IsAuthoritative | bool | Main.netMode != 1 |
RealmCeiling | int | 当前世界允许达到的境界上限(CultivationProgressionSystem.GetCurrentRealmCeiling()) |
Bosses | Dictionary<string, object> | 各 Boss 是否已通关(永久记录,已同步) |
Bosses 子键全表(源码原文,共 13 项):
| 键 | 数据来源 |
|---|
InkFloodDragon | InkFloodDragonWorldSystem.DownedInkFloodDragon |
BloodJadeSpider | BloodJadeSpiderWorldSystem.DownedBloodJadeSpider |
KingXu | KingXuWorldSystem.DownedKingXu |
WhiteHairedHealer | WhiteHairedHealerWorldSystem.DownedWhiteHairedHealer |
PoisonFloodDragon | `PoisonFloodDragonWorld.Downed \ | \ | StarSeaBossChecklist.Done(1)` |
HiddenShaMaster | StarSeaBossChecklist.Done(64) |
RuinXuanGu | StarSeaBossChecklist.Done(2) |
VoidFireAntQueen | StarSeaBossChecklist.Done(4) |
VoidHeavenPalace | StarSeaBossChecklist.Done(8) |
WenTianren | StarSeaBossChecklist.Done(16) |
NestBlackPythonEscape | StarSeaBossChecklist.Done(32) |
Yuancha | YuanchaWorldSystem.DownedYuancha |
MaLiang | YuanchaWorldSystem.DownedMaLiang |
- 用途:一句话 —— 让别的模组读取「这个世界打到哪了」,做进度联动、解锁条件、Boss 前置判断。
- 源码位置:
AddonApi.cs:237-257
- 示例代码:
var w = (Dictionary<string,object>)qyxt.Call("QYXT", 1, "World.GetProgress")["Data"];
int ceiling = (int)w["RealmCeiling"];
var bosses = (Dictionary<string,object>)w["Bosses"];
bool killedKingXu = (bool)bosses["KingXu"];
- 校验:无参数;依赖世界状态(
RequiresWorld: true,主菜单调用返回 WorldNotReady)。
分类六:内容 ID 查询类(2 个)
均不需要世界,可在主菜单调用。用于把本模组的内部名解析成运行时 ID。
13. Content.Find
- 参数:2 个
kind:string —— 内容分类,仅接受:Item、NPC、Projectile、Buff、Tile、Wall(区分大小写,见 ContentList 的 switch)
internalName:string —— 本模组内部名(不带模组前缀)。校验规则:非空白、长度 ≤ 160、不含 /
- 返回值:
int —— 该内容的运行时 ID
- 用途:一句话 —— 按内部名拿本模组物品/NPC/弹幕/Buff/物块/墙壁的运行时 ID,用于生成、掉落、判定。
- 源码位置:
AddonApi.cs:258-272
- ⚠️ 限制(Summary 中文原文):「按内部名获取本模组运行时内容 ID;不接受中文名或其他模组。」
- 示例代码:
int itemType = (int)qyxt.Call("QYXT", 1, "Content.Find", "Item", "HeavenBottle")["Data"];
int npcType = (int)qyxt.Call("QYXT", 1, "Content.Find", "NPC", "MaLiang")["Data"];
// 生成一个物品:
Item.NewItem(null, (int)player.position.X, (int)player.position.Y, 0, 0, itemType);
- 校验:
kind 非法 → UnknownKey:Supported kinds: Item, NPC, Projectile, Buff, Tile, Wall.
internalName 为空/超 160 字符/含 / → InvalidArgument:Use a nonempty local internal name, without a mod prefix.
- 未找到 →
NotFound:Content name was not found; query Content.List.
14. Content.List
⚠️ 编号说明:此处序号 14 仅为文档条目编号,接口实际总数为 13(本条目与第 13 条同属内容查询类,文档按节顺序编排)。
- 参数:1 个
kind:string —— 同 Content.Find,仅 Item、NPC、Projectile、Buff、Tile、Wall
- 返回值:
Dictionary<string, object>[],按 Name 做 Ordinal 升序排序,每项字段:
| 字段 | 类型 | 含义 |
|---|
Name | string | 内部名 |
FullName | string | 模组名 + "/" + Name,即完整内容名 |
Id | int | 运行时 ID(ModItem.Type / ModNPC.Type 等;Tile/Wall 取 ModBlockType.Type) |
- 用途:一句话 —— 一次性枚举本模组某分类下的全部内容及其运行时 ID,供外部模组建立映射表。
- 源码位置:
AddonApi.cs:273(实现在 ContentList,AddonApi.cs:276-299)
- ⚠️ 性能提示(Summary 中文原文):「枚举本模组 Item/NPC/Projectile/Buff/Tile/Wall 内部名与运行时 ID;勿逐帧调用。」 —— 应在
Mod.Load/PostSetupContent 阶段调用一次并缓存。
- 示例代码:
var items = (Dictionary<string, object>[])qyxt.Call("QYXT", 1, "Content.List", "Item")["Data"];
foreach (var it in items)
{
string name = (string)it["Name"];
string full = (string)it["FullName"]; // "QingzhuFengyun/HeavenBottle"
int id = (int)it["Id"];
}
- 校验:
kind 非法 → UnknownKey:Supported kinds: Item, NPC, Projectile, Buff, Tile, Wall.
完整接口速查表
| # | 命令名 | 参数 | 返回 | 需世界 | 仅服务端 | 一句话用途 |
|---|
| 1 | Api.GetInfo | — | Dict | ✗ | ✗ | 握手:拿模组版本、API 版本与命令清单 |
| 2 | Api.GetCommands | — | Dict[] | ✗ | ✗ | 自省:运行时枚举全部接口及其签名/要求 |
| 3 | Rules.GetRealms | — | Dict[] | ✗ | ✗ | 境界 ID、基础门槛、秘窍上限全表 |
| 4 | Rules.GetSpiritRoots | — | Dict[] | ✗ | ✗ | 五行灵根位标记与官方 RGB 配色 |
| 5 | Rules.GetTechniques | — | Dict | ✗ | ✗ | 基础/高阶功法与秘术的键名→中文名目录 |
| 6 | Player.GetSnapshot | playerIndex | Dict | ✓ | ✗ | 玩家修仙状态全量只读快照 |
| 7 | Player.MeetsRealm | playerIndex, realmId, useNaturalRealm | bool | ✓ | ✗ | 判断玩家是否达到某境界 |
| 8 | Player.GetThreshold | playerIndex, realmId | long | ✓ | ✗ | 查该玩家突破到某境界所需灵气 |
| 9 | Player.HasSecret | playerIndex, secretKey | bool | ✓ | ✗ | 判断某秘术是否已解锁 |
| 10 | Player.GrantAura | playerIndex, baseAmount | Dict | ✓ | ✓ | 服务端发放灵气奖励 |
| 11 | NPC.GetSnapshot | npcIndex | Dict | ✓ | ✗ | 查 NPC 的境界/是否 Boss/所属模组 |
| 12 | World.GetProgress | — | Dict | ✓ | ✗ | 世界境界上限与 13 项 Boss 通关记录 |
| 13 | Content.Find | kind, internalName | int | ✗ | ✗ | 内部名 → 运行时内容 ID |
| 14 | Content.List | kind | Dict[] | ✗ | ✗ | 枚举某分类全部内容名与 ID |