Godot 接口手册
适用插件 0.1.1、协议 v1(既有 request 方法仍兼容 0.1.0);本文对照平台运行时 1.0.1。最新方法是否可用以当前会话协商为准。SDK 与源码 · 冻结协议基线。本页为开发参考,不修改旧协议。
调用约定
先 await INeed.initialize(),检查 result.ok,再 INeed.supports("完整方法名")。所有异步方法返回 Dictionary;数据仅允许 JSON 类型,不传 Node、Resource、Callable、Vector2 或二进制对象。向量应由游戏明确转换为普通字段。
var result: Dictionary = await INeed.request("payments.inventory", {"productKey": "entry_ticket"})
if result.get("ok", false):
var remaining := int(result.get("value", 0))
print("当前会话剩余次数:", remaining)
else:
var error: Dictionary = result.get("error", {})
print(error.get("code", "REQUEST_FAILED"), ": ", error.get("message", ""))
成功外层是 {ok:true,value:...};失败外层是 {ok:false,error:{code,message}}。某些底层业务返回自身的 ok 字段,仍放在 value 内。不得假定所有 value 都是数组或都有 data 字段。
插件简写
| GDScript | 对应桥接方法 | 说明 |
|---|---|---|
| initialize() | hello | 协商协议;返回 protocol/runtimeVersion/capabilities |
| supports(method) | 本地能力查询 | 仅初始化成功后有效,返回 bool |
| request(method, params = {}) | 指定方法 | 通用异步调用 |
| login() | login | 平台认证;返回会话数据 |
| buy(product_key) | payments.buy | 单个商品的可信确认与购买 |
| open_store() | ui.store | 平台商品列表,选购后返回购买结果 |
| open_leaderboard(board_key, scope = "world") | ui.leaderboard | 平台排行榜窗口 |
| show_rewarded(placement, action_id) | ads.rewarded | 真实广告与可信结算 |
插件 0.1.1 新增以下包装器;旧 0.1.0 使用 request 接口。没有 INeed.get_account() 简写。
| GDScript | 行为 |
|---|---|
| ensure_logged_in() | 返回当前账号;游客先登录,失败就停止 |
| consume(product_key, quantity, request_id) | 确保登录,只消费,不购买 |
| buy_and_consume(product_key, quantity, request_id) | 确保登录,先消费已有库存,不足时购买一次再消费 |
buy 会先确保登录;账号取消或失败时不购买。组合的完整结果、部分成功和幂等恢复见商品购买与消耗。组合失败可能附加 context.purchase/stage/requestId,原 error 不被隐藏;它不是原子交易。stage=purchase_unknown 表示购买结果待核实,after_purchase 表示已取得购买成功回执。新包装器可返回 PURCHASE_UNCONFIRMED,阻止未知购买结果下再买;这不是新增的远程协议错误。
账号及购买数据
下表“返回”均指外层成功结果的 value。读取账号、商品、库存、权益的是当前 SDK 会话快照,不能作为服务端授权依据。
| 方法 | params | 返回与读取位置 |
|---|---|---|
| account.get | 空 | 账号对象或 null;id、nickname、avatarUrl、username、balanceCoins 等;字段为空须处理 |
| login | 空 | 会话对象,内含 account;推荐登录结束后重新 account.get |
| payments.products | 空 | 商品数组;productKey、name、description、priceCoins、type、grantQuantity;type 为 permanent/consumable;不要销售 systemManaged 项 |
| payments.inventory | 空 | [{productKey,quantity}];无库存可能为空数组 |
| payments.inventory | productKey: String | 此商品数量 Number,没找到返回 0 |
| payments.entitlements | 空 | {buyout,products:[{productKey,acquiredAt}]};不包含消耗品库存 |
| payments.buy | productKey: String | 购买结果,可能含 orderId、noCharge、fulfillment、session;最终 UI 从更新后的会话权益/库存读取 |
| payments.consume | productKey、quantity、requestId | consumptionId、noChange、productKey、quantity、remainingQuantity、session;noChange=true 表示相同操作重放 |
| ui.store | 空 | 选商品并购买;返回与 buy 相同业务结果;关闭可能为 CANCELLED |
consume 的 quantity 为正整数,服务端上限 1,000,000;requestId 为 16–80 位英文字母、数字、下划线或连字符。一个真实动作一个 ID,同动作重试完全相同,新动作用新 ID。buy 当前公开参数只有 productKey;不要传入自造 requestId 并声称购买已经跨刷新幂等。
排行榜数据与提交
| 方法 | params | 返回与读取位置 |
|---|---|---|
| leaderboards.list | 空 | {ok,boards,profile};boards 为榜单配置数组 |
| leaderboards.get | boardKey;scope 默认 world;page 默认 1;可选 pageSize | {ok,board,scope,region,entries,personalBest,personalRank,total,page,pageSize} |
| leaderboards.submit | boardKey、runId、score、durationMs;可选 endedAt、stats | {ok,receipt};receipt 含 runId、boardKey、score、previousBest、personalBest、isPersonalBest、deltaToBest、rank、submittedAt、replayed |
| leaderboards.profile | 空 | {ok,profile},profile 为昵称、头像、地区及修改地区时间信息 |
| leaderboards.region | countryCode、provinceCode;可选 cityCode | {ok,profile};提交平台认可的地区代码,不能把中文地区名当代码 |
| ui.leaderboard | boardKey;scope 默认 world | 点击返回通常 {closed:true};其他关闭路径可能 CANCELLED |
scope 为 world/province/city。boards 项含 boardKey/title/sortOrder/minScore/maxScore/minDurationMs/maxDurationMs;entries 项含 rank/userId/nickname/avatarUrl/score/achievedAt/isMe。按返回的 pageSize 和 total 分页,不依赖私有上限。地区未知时提示选择或返回世界榜;不要自行定位用户精确位置。
runId 在真实开局时生成,结束后冻结 score、durationMs 及可选 ISO 8601 endedAt。stats 为数值或布尔值的对象;不要放玩家秘密或聊天全文。示例:
var frozen_run: Dictionary = {
"boardKey": "survival_score",
"runId": "run_" + Crypto.new().generate_random_bytes(16).hex_encode(),
"score": 1200,
"durationMs": 85000
}
# 上述数值只演示形状,正式游戏须用真实开局与结算值。
var result: Dictionary = await INeed.request("leaderboards.submit", frozen_run)
if result.get("ok", false):
var receipt: Dictionary = result.get("value", {}).get("receipt", {})
print(receipt.get("personalBest"))
# 网络重试复用 frozen_run;示例成绩禁止提交正式榜单。
激励广告
ads.rewarded params 为 {placement,actionId}。placement 为 1–64 位英文字母、数字、下划线或连字符;actionId 为 16–80 位同类字符。
成功 value 是 {receiptId,actionId,placement,reward,replayed}。reward 是平台为该广告位配置并在创建动作时固定的 JSON 对象,没有通用的 coins 或 quantity 必填字段;与平台约定后才能解释。replayed=true 仍是同一凭据,不能重复应用奖励。取消、无填充、超时均不得当成功。详见广告 Skill。
存档
| 方法 | params | 返回 |
|---|---|---|
| storage.load | 空 | {value,version,schemaVersion,scope};首次 value=null、version=0 |
| storage.save | value: JSON;baseVersion: 非负整数;schemaVersion 默认 1 | 至少 {version,scope};不要依赖保存响应一定回传 value |
scope 为 guest/preview/account。schemaVersion 由游戏维护,平台不会自动转换玩法数据。当前运行时要求 schemaVersion 正整数且不超过 1,000,000。先 load 取得 version,再作为 baseVersion 保存;成功后更新本地版本。1 MiB 包含平台存储编码开销和既有数据,游戏内容应留余量,最终以服务器校验为准。
事件
INeed.platform_event.connect(handler),handler 签名为 (name: String, data: Dictionary)。
| name | data | 游戏责任 |
|---|---|---|
| pause | reason 为触发弹窗的方法 | 保存先前暂停/音频状态,暂停游戏 |
| resume | reason | 恢复先前状态;不是交易成功通知 |
| account.changed | account 对象或 null | 使旧账号异步结果失效,清理显示缓存,重读新身份数据 |
当前没有 purchase.completed、inventory.changed 等通用 Godot 事件;以调用结果和会话读取驱动 UI。同一时间只允许一个平台模态调用,重复可能 BUSY。游戏生命周期处理代码见界面建议。
错误处理与数据来源
常见代码及重试策略见异常与恢复。桥接不会返回任意 HTTP 响应头,所以不要假设每个结果都有 traceId。排错记录作品、环境、时间、账号标识、方法、业务 ID 和实际返回码;向平台申请查询交易/消费/奖励账本。不要记录 token、密码和完整私密存档。
本文依据公开插件及平台同版本实现整理;不要求创作者调用内部管理 API。API 扩展必须先由平台实现并公告,再按 supports 接入。