Skip to content

ctx 全量 API ​

生命周期钩子都会收到同一个 ctx 对象。下表是它暴露的全部成员。

生命周期 ​

导出函数时机应当做什么
onLoad(ctx)代码载入后恢复设置、初始化数据结构。不要在此注册事件
onEnable(ctx)被启用时注册事件 / 命令 / 页面,保存返回的取消函数
onDisable(ctx)被禁用时取消上一阶段注册的一切,停止定时器
onUnload(ctx)卸载时释放资源(清理函数也会由 ctx.dispose() 兜底执行)
js
let offEnter;

export function onLoad(ctx) {
    ctx.logger.log('loaded');
}

export function onEnable(ctx) {
    offEnter = ctx.events.on('game:enterBattle', () => ctx.logger.log('进入战斗'));
    ctx.onCleanup(() => ctx.logger.log('清理中'));
}

export function onDisable(ctx) {
    offEnter?.();
}

基础成员 ​

成员类型说明
ctx.modobject当前 Mod 的 manifest
ctx.loaderModLoader加载器实例(列表、安装、启用等)
ctx.loggerModLogger日志,前缀 [Mod:<id>]
ctx.findorCheatobject作弊端根对象(等价于页面里的 findorCheat)
ctx.gameobjectfindorCheat.game 快捷引用
ctx.TOStateobjectfindorCheat.TOState 快捷引用
ctx.featuresobject你自己的功能容器,同时挂到 findorCheat.modFeatures[<id>]
ctx.onCleanup(fn)function注册清理函数(ctx.dispose() 时按逆序执行)

ctx.logger ​

js
ctx.logger.log('普通日志');
ctx.logger.info('信息');
ctx.logger.warn('警告');
ctx.logger.error('错误', someError);
ctx.logger.debug('调试');      // 默认不输出,需 ctx.logger.debugEnabled = true

ctx.storage —— 本地存储 ​

按 Mod 隔离(底层 key 为 findor-mod-storage:<id>,值为 JSON)。

js
ctx.storage.set('settings', { enabled: true, delay: 2000 });
const s = ctx.storage.get('settings', {});   // 第二个参数是默认值
ctx.storage.delete('settings');
ctx.storage.keys();                          // ['settings']
ctx.storage.clear();

ctx.events —— 事件 ​

js
const off = ctx.events.on('game:enterBattle', (payload) => { /* ... */ });
ctx.events.once('announcement:ready', () => { /* 只触发一次 */ });
off();                     // 取消订阅
ctx.events.off('game:enterBattle', handler);
  • on / once 都返回取消订阅函数
  • 全局事件由 cheatEventBus 桥接而来,完整清单见事件清单
  • ctx.events.emit(name, ...args) 只触发本 Mod 自己的监听;要全局广播请用 findorCheat.cheatEventBus.emit(name, ...args)

ctx.commands —— 聊天命令 ​

js
const off = ctx.commands.register('delay', (send, args) => {
    const ms = parseInt(args[0], 10);
    if (isNaN(ms)) return send('用法: /my-mod:delay <毫秒>');
    send(`延迟已设为 ${ms}ms`);
}, { args: 1, usage: '/my-mod:delay <毫秒>' });

注册后的完整命令名是 <modId>:<name>,即 /my-mod:delay 100。

options说明
args'infinite'(默认,任意个数)· 0(不能带参数)· n>0(必须正好 n 个)· n<0(至少 |n| 个)
usage用法提示,默认 /<modId>:<name>
validate自定义校验函数 (providedArgs) => ({ valid, expected, got }),提供后覆盖 args 的默认校验

处理器签名:(send, args) => void,其中 send(text) 把消息回显到聊天。

ctx.ui —— 界面 ​

js
// 通知(会加上 [modId] 前缀)
ctx.ui.notify('已完成', 'success');   // type: 'info' | 'success' | 'error'(默认 info)

// 注册一个自定义页面(config 由 Mods UI 消费),返回取消函数
const remove = ctx.ui.addPage({ id: 'my-page', title: '我的页面', render: () => document.createElement('div') });
remove();

// 对话框
ctx.ui.dialog({ title: '提示', content: '确认继续?' });
方法返回说明
addPage(config)取消函数注册页面并刷新 UI
removePage(id)—移除页面
notify(message, type)—弹通知
dialog(options)—弹对话框(title / content 等)

ctx.models —— 模型访问 ​

js
ctx.models.get('TankModel');                    // Model 实例
ctx.models.getObject('TankModel');              // 对应的 gameObject(可能为 null)
ctx.models.listMethods('TankModel');            // 原型上的方法名列表
ctx.models.call('TankModel', 'setState', arg);  // 在正确上下文里调用 Model 方法
ctx.models.withContext('TankModel', () => {
    // 需要当前 gameObject 上下文的操作放这里
});

与 putGameObject 相关

models.call / models.withContext 内部会切换到目标 gameObject 上下文;如果需要返回值的操作,请用 withContext 并在回调里 return。

ctx.protocol —— 协议 ​

js
// 包钩子
const off1 = ctx.protocol.onSerialize('MethodName', (data) => { /* 发送前 */ });
const off2 = ctx.protocol.onDeserialize('MethodName', (result) => { /* 收到后 */ });

// 上行:客户端 → 服务端
ctx.protocol.send(tankModelInstance, 'MethodName', [param1, param2]);

// 下行:模拟服务端 → 客户端(触发本地 Model 处理)
ctx.protocol.invoke(tankModelInstance, 'MethodName', (buffer) => {
    // 用 buffer 写入编码后的参数
});

ctx.protocol.listMethods();        // 所有可用方法名
ctx.protocol.describe('MethodName');
ctx.protocol.resolveId('MethodName');

ctx.actions —— 拦截游戏 Action ​

js
const off = ctx.actions.on('SomeAction', (action, { name, edit }) => {
    // 返回 false          → 阻止该 Action
    if (name === 'BlockMe') return false;
    // 返回 { modify:true, target } → 改写目标对象(如把目标换成别人)
    return { modify: true, target: otherTarget };
});

ctx.actions.onAny((name, action) => { /* 观察所有 Action */ });
off();
方法说明
on(name, handler)监听指定 Action
once(name, handler)只监听一次
off(name, handler) / offAny(handler)取消
onAny(handler)监听全部 Action,签名 (name, action, { edit })

Action 名来自游戏类的 $metadata$.simpleName(Findor 已填充)。

销毁 ​

ctx.dispose() 会:执行全部 onCleanup 回调(逆序)→ 清空事件监听 → 清理协议钩子、UI 页面与命令。卸载时由加载器自动调用;你也可以在 onUnload 里手动调用以确保幂等。

下一步:事件清单 · 示例 hello-world

仅供学习交流 · 请在遵守游戏与服务条款的前提下使用