联网与插件
弱联网脚本
用条件树、分组、聚合和限流查询公开玩家快照,并明确隐私与完整存档边界。
脚本系统 · 弱联网
在不开放完整存档的前提下共享玩家状态
弱联网适合排行榜、队伍/公会成员、世界状态和玩家名片。玩家主动上传插件映射的数值和动态字符串,以及所选对象类中的完整可序列化运行时对象;其他玩家只能按条件查询快照,不能读取或修改对方存档。
# 先定义公开快照契约
告诉 AI 哪些数值、字符串和对象类可以公开,玩家何时主动上传,其他玩家按什么条件查询,以及页面如何展示昵称和头像。AI 必须先配置弱联网插件映射,再编写上传/查询脚本。对象类不是逐字段白名单:弱联网会序列化该类下对象的完整可序列化运行时数据。不得上传完整存档、包含秘密的对象类或私密文本。
上传有三分钟限流,查询/聚合有三秒限流和缓存。渲染布局只展示查询结果,不能把网络返回内容当成可执行脚本或 Canvas 模块源码。
# 配置与脚本的边界
纯 AI 路径让 AI 同时维护插件映射和异步脚本;打开传统模式文档后,作者需在插件中选择公开字段,并在脚本里构造条件树、分页、排序和分组。下面的 API、返回结构、缓存和隐私边界两种路径都必须遵守。
# 先完成插件配置
在编辑器的弱联网插件中配置会变成公开数据的资源:
| 映射 | 上限 | 实际上传内容 |
|---|---|---|
| 数值属性或组合属性 | 30 个槽位 | 玩家当前的有限数值;已映射的数值属性还可用于筛选、排序、分组和聚合。 |
| 动态字符串 | 20 个槽位 | 解析后的玩家字符串,每次上传每项最多 1000 个字符。 |
| 对象类 | 20 个类 | 该类下玩家拥有的每个对象的全部可序列化字段,共享 20000 个字符的序列化预算。内容可能包含名称、描述、ObjectPropertyCount 和其他可序列化运行时状态。 |
对象映射不是字段级公开白名单。启用一个对象类前,必须审查它完整的运行时结构。对象类按照插件列表顺序序列化;共享 20000 字符预算不足时,后面的对象会被跳过,因此应把重要对象类放在前面。
脚本运行时不能自行选择上传资源。tools.uploadWeakOnline() 只读取插件映射;插件关闭、没有资源配置,或正式环境中的匿名玩家仍叫 "Player" 时返回 false。保存、删除或调整映射只影响之后的上传,不会重写历史快照;每次改映射后都必须重新上传。
# 上传快照
tools.uploadWeakOnline()
.then((ok) => {
if (ok) tools.showToast(tools.tr("状态已同步"), "success");
})
.catch(() => {
tools.showToast(tools.tr("同步太频繁,请稍后再试"), "warning");
});
上传是异步操作,只上传弱联网快照,不会保存本地存档,也不会触发云存档。FangZhi 和后端共同限制:同一玩家在同一项目中每 3 分钟最多上传一次。失败或限流会 reject,不能放在每帧脚本、js_move 或循环中调用。
正式运行中,匿名玩家 "Player" 不能上传;查询和聚合会返回空结果,直到玩家完成认证。编辑器测试服使用隔离的测试服项目命名空间,测试数据不会与正式数据混合。
# 查询快照
// 必须替换为 AI 从当前项目查询到的真实 ID
const levelPropertyId = "实际等级属性ID";
const powerPropertyId = "实际战力属性ID";
const result = await tools.queryWeakOnline(
{ and: [{ field: levelPropertyId, operator: "gte", value: 10 }] },
1,
10,
{ field: powerPropertyId, order: "desc" }
);
for (const item of result.items) {
// username 字段为兼容旧脚本保留,实际值是公开昵称
tools.showNotify(`${item.username}:${item.numbers[powerPropertyId] ?? 0}`);
}
签名:
tools.queryWeakOnline(filters, page?, limit?, sort?, groupBy?)
filters 是条件树,不能传任意 SQL 或字符串。每个 field 都必须是弱联网插件已启用的数值属性真实 ID,每个 value 都必须是有限数值:
const levelPropertyId = "实际等级属性ID";
const factionCodePropertyId = "实际阵营编码属性ID";
// 叶子条件
{ field: levelPropertyId, operator: "gte", value: 10 }
// 任意嵌套 and / or
{ and: [
{ field: levelPropertyId, operator: "gte", value: 10 },
{ or: [
{ field: factionCodePropertyId, operator: "eq", value: 1 },
{ field: factionCodePropertyId, operator: "eq", value: 2 }
] }
] }
支持的操作符:eq、neq、gt、gte、lt、lte。{ and: [] } 表示查询全部。sort 只能按已配置的数值属性 ID 排序,例如 { field: powerPropertyId, order: "desc" };普通查询可传 { order: "random" } 随机抽取,但只支持第 1 页,不使用随机数据库排序,也不走 15 分钟结果缓存。
普通查询返回:
{
items: [
{
username: "公开昵称",
avatar: "<svg ...>",
numbers: { "实际战力属性ID": 1200 },
strings: { "实际称号动态字符串ID": "探索者" },
object: { "实际伙伴对象类ID": [] },
updatetime: "2026-01-01T00:00:00Z"
}
],
page: 1,
limit: 10,
hasMore: false
}
numbers、strings、object 分别以插件配置的属性 ID、动态字符串 ID、对象类 ID 为键,不是显示名称,也不是内部的 num_XX 槽位。运行时和后端只在内部把真实资源 ID 转为存储槽位。avatar 是完整 SVG 字符串;旧快照缺少字段时,数值、字符串和对象分别按 0、空字符串和空数组处理。修改插件配置不会重写历史快照。
非随机查询结果会缓存约 15 分钟;任意玩家上传新快照时,会使该项目的弱联网查询与聚合缓存失效。
每次普通查询最多返回 10 条。查询与聚合共享同一个运行时限流:任一操作完成后,同一玩家必须等待 3 秒才能再次执行这两种操作中的任意一种。
# 按队伍或公会分组
将第五个参数传入已配置的分组属性 ID:
const powerPropertyId = "实际战力属性ID";
const guildIdPropertyId = "实际公会ID属性ID";
const result = await tools.queryWeakOnline(
{ and: [] },
1,
10,
{ field: powerPropertyId, order: "desc" },
guildIdPropertyId
);
for (const group of result.groups) {
console.log(group.value, group.memberCount, group.items);
}
分组返回 { groups, page, limit, hasMore }。每组包含 { value, memberCount, items },items 固定最多 5 条详情;每页最多 10 组。组按分组值升序排列,分组模式不支持 random 排序,sort 只控制组内详情顺序。
# 聚合数值
需要统计世界平均战力、最高分或总人数时,用独立的聚合接口:
const levelPropertyId = "实际等级属性ID";
const powerPropertyId = "实际战力属性ID";
const result = await tools.aggregateWeakOnline({
and: [{ field: levelPropertyId, operator: "gte", value: 10 }]
});
console.log(result.totalCount, result.metrics[powerPropertyId]);
// { count, min, max, avg, sum }
filters 省略或传 { and: [] } 表示匹配全部快照。每个数值属性都会返回 count、min、max、avg、sum;没有上传该属性时 count 为 0,其他值为 null。聚合结果服务端缓存 15 分钟;任意玩家上传新快照会使该项目的聚合缓存失效。聚合与普通/分组查询共用同一个 3 秒间隔。
# 与传统联网能力的边界
- 弱联网是“公开快照查询”,不是实时通信;不要用它实现即时战斗同步。
- 查询结果只读,脚本不能修改其他玩家的属性、字符串或对象。
- 选择对象类会公开完整可序列化运行时对象,而不是所选字段;不要映射包含私密或秘密状态的对象类。
- 需要完整进度、多槽存档或跨设备恢复时,使用本地/云存档流程。
- 不能通过弱联网接口上传密码、令牌、私密文本或未经玩家同意的个人信息。