← 返回巡游运营工作台

巡游开始与现场运营

默认由工作人员从后台发出“巡游开始”,设备才开始正式内容体验。资源下载和定位校准不会自动计入体验启动。

工作人员的日常流程

  1. 在“店铺与引导员”建立自己的店铺、人员和收费平台。在“项目管理”配置项目入场规则。
  2. 在“设备管理”登记设备号、所属店铺、项目和引擎。首次生成的设备凭据只写入对应设备,不能打进公开资源包。
  3. 设备连接后台,确认下载并加载内容,完成校准和佩戴,设备卡片显示“等待开始”。离线以最后一次心跳超过 20 秒判断。
  4. 有票体验:在“核销卡券”查询票码 / 订单,选择未核销票、项目、人数、设备和引导员,确认分配。无票体验、招待可直接选设备;前台收款还需记录收费平台和实际收款总额。每位体验者对应一台设备。
  5. 选择已就绪设备,点击“巡游开始”。后台下发指令,设备确认当前项目和就绪状态,服务端确认场次开始后,客户端触发内容开始事件,再回传执行结果。
  6. 观察指令表中的“执行成功”。“等待设备确认”不代表已经开始;60 秒未执行会超时,可检查网络后重新下发。多人批量下发原子提交,但网络设备不会被承诺毫秒级同步播放。
  7. 体验完成后客户端上报完成;提前停止可单台或批量回收。回收会取消尚未执行的开始指令,等待客户端停止内容、结束场次并确认。离线设备不能伪装成已回收,可在运营统计的场次页人工结束并注明原因,设备重连后会核对状态。

测试环境与正式环境拥有各自的数据库、资源目录、设备凭据和运营记录。开发用途设备始终无票,收入统计独立。测试环境的“前台收款”只是模拟记录,不会连接真实资金渠道。

Dev / Pro 内容发布

  1. 在 Dev 制作项目,通过 Unity 编辑器上传 Addressables、内容包、定位图片、布局和图片事件;Godot 可上传自己的内容包。
  2. 后台项目管理可维护类型、定位遮罩和美术遮罩,生成限时邀请码。店铺 Key 和项目邀请码共同用于新设备接入;已存在设备不能被邀请码覆盖。
  3. 点击“发布到 Pro”查看内容版本、平台资源包和图片数量,填写正式环境管理凭据并确认。服务端复制文件并校验 SHA256,然后提交正式配置。
  4. 发布不迁移店铺、设备、订单、票、收入、Key 和邀请码。正式项目内容在本工作台只读;正式运营规则可独立调整。重复发布相同快照返回原结果,预览后 Dev 内容改变则要求重新预览。
  5. “全局数据管理”按应用编号维护 Unity/Godot 的发布版本、Addressables/资源版本、Localization/定位配置及更新时间。采用版本冲突检测,避免覆盖他人编辑。

Unity 发布目录中的二进制 catalog 保持原校验值。新版 Unity 客户端使用当前项目私有资源定位器,将该发布的资源依赖定位到当前环境目录;正式使用本次发布功能前需更新客户端代码。原始图像定位和空间校准解算器保持原有算法。

Unity 接入

场景中使用 ALabNextLaunchController 后自动启用 ALabNextTourControl。在项目配置启用运营记录并填写设备号,在设备首次配置中保存凭据。默认 allowLocalStart=false,加载完成后等待外部指令。无需改变图像校准算法。

// 其他事件统一调用此入口,而不是直接广播项目内部 StartExperience。
await launch.RequestExternalStartAsync();
// 或发送配置的请求事件(默认 RequestExperienceStart):
ALabNextTriggerMessages.Publish("RequestExperienceStart");
// 平台有自己的佩戴状态接口时:
launch.SetWearReady(isWorn);

有 XR userPresence 能力时自动读取佩戴状态;编辑器允许使用明确的模拟定位。PICO/Meta/visionOS 提供不同能力时只适配佩戴 / 跟踪接口。打包后的客户端默认等待佩戴确认;未提供可靠佩戴信号的设备,必须由平台适配层调用 SetWearReady。编辑器预览默认使用已佩戴状态。

Godot 接入

下载 HTTP 设备接口 和 巡游控制组件 放入项目。后台使用相同场次和指令协议,Godot 的素材、地图及内容播放逻辑由该项目自己实现。

var transport := ALabNextOperationsClient.new()
add_child(transport)
transport.configure(environment_url, device_id, device_token)
var tour := ALabNextTourController.new()
add_child(tour)
tour.configure(transport, start_actual_content, stop_actual_content)
# 只有资源、定位和佩戴均完成后才 ready。
tour.set_readiness("ready", headset_is_worn, project_code, content_version)

func start_actual_content() -> bool:
    # 在这里接入自己项目的正式体验开始事件。
    experience.start()
    return true

func stop_actual_content() -> bool:
    experience.stop_and_clear()
    return true

# 正常完成时:
await tour.finish_experience("completed", "体验正常结束")

控制组件只有配置真实回调才上报巡游能力。它保存未完成场次和待确认回执,重启时结束旧场次,避免重复播放;独立场景素材与头显上的最终效果仍须由 Godot 项目接入验证。

引擎无关的 HTTP 协议 v2

所有路径都拼接在 https://webadmin.allinxr.com/environments/test 或 /environments/production 后。设备请求使用 Authorization: Bearer 设备凭据 和 X-ALabNext-Environment;管理接口使用对应环境运营管理凭据。不要使用另一环境凭据。

请求作用与关键参数
POST /api/runtime/v1/telemetrydeviceId、projectCode、state、appVersion、contentVersion、battery 可选;capabilities=["tour.start","tour.recycle"]。建议每 2~5 秒上报;ready 代表可执行开始。
GET /api/runtime/v1/control?deviceId=…返回当前 session 和待执行 commands;只包含本设备。建议每 2 秒轮询,掉线后自动重连。
POST /api/runtime/v1/sessions/{sessionId}/startdeviceId、commandId。外部指令必须传原 commandId,服务端会拒绝取消/过期指令。重复启动只计一次,须检查 status=running 后才触发内容。
POST /api/runtime/v1/commands/{id}/ackdeviceId、status=succeeded/failed、message。开始成功须先确认场次开始;回收成功须先结束场次。回执网络失败复用同一指令重试,不能重新开始内容。
POST /api/runtime/v1/sessions/{id}/heartbeatdeviceId,运行中每 30 秒上报。若服务端场次结束,客户端应停止并清理本地内容。
POST /api/runtime/v1/sessions/{id}/finishdeviceId、outcome=completed/failed/aborted、reason。未启动的预约只能取消或失败,不能当作完成。
GET /api/runtime/v1/apps/{appId}/config?deviceId=…当前环境的应用全局配置和 revision。
POST /api/runtime/v1/enrollstoreCode、storeKey、invite、deviceId、deviceName、engine;仅新设备,返回一次性设备凭据。店铺 Key 撤销不影响已注册设备凭据。

离线缓存与场次补传(Unity / Godot 通用)

首次启动必须联网。完整下载后,以环境、设备和内容平台为作用域保存配置、资源目录、场景、定位图片和资源包;仅完整成功的一代缓存可离线使用。离线时只能使用最后一次完整项目,不能假定云端分配未变。恢复网络后重新获取项目才能接收新巡游指令。

请求规则
POST /api/runtime/v1/offline/permitsdeviceId、projectCode、contentVersion、buildTarget(Unity 必填,例如 StandaloneWindows64;须匹配该平台当前启用的资源版本)。仅当前分配且版本匹配的开发/无票设备,返回 permitId、token、issuedAt、expiresAt、environment。有效期 24 小时;正式有票必须在线核销。
POST /api/runtime/v1/offline/sessionsdeviceId、permitId、token、requestId(唯一且不超过56字符)、startedAt、endedAt(ISO8601 UTC)、outcome(completed/aborted/failed)、appVersion、reason。先持久保存,服务器确认后才移出队列;同一 requestId 重试只记一次,不得修改原内容。

离线下载/校准不计体验次数。具备有效许可后,由明确的本机或外部事件开始内容;客户端落盘保存启动与结束时间。补传仅生成历史无票场次,不占用实时设备、不消耗票、不生成收入。开始时间须在许可内,场次最长12小时,结束后30天内补传。Godot 可使用相同 HTTP 协议,具体 PCK/场景缓存与本地队列需由 Godot 项目实现。

管理接口与统计口径

新增管理前缀 /api/admin/operations/management。bootstrap 读取店铺、人员、项目、渠道和全局配置;board 返回在线设备和指令结果;admissions 原子分配多人场次;commands 下发单台/批量指令;lookup 查询订单核销链;invoices 登记发票;publication/preview、publication/publish 提供内容发布。发布额外要求 X-Production-Authorization。

POST /api/admin/operations/management/commands
{"requestId":"每次操作的稳定唯一编号","kind":"start","deviceIds":["TOUR-01","TOUR-02"]}

POST /api/admin/operations/management/admissions
{"requestId":"稳定唯一编号","storeCode":"STORE01","projectCode":"PROJECT01",
 "kind":"ticket","people":2,"deviceIds":["TOUR-01","TOUR-02"],
 "ticketCodes":["票码1","票码2"],"guideId":"GUIDE01","notes":"团体备注"}

人数与设备数须一致。有票/前台收款需要生产用途设备;无票/招待不消耗票码。重试复用 requestId,修改内容须新建请求。人数、设备、订单和付款任一验证失败时整组回滚。

启动次数以服务端首次接受 start 为准;资源加载、校准、预约、指令下发均不计数。票码在开始时消耗。收入按已确认收款减退款计算,不能用设备启动数乘票价替代实际流水。开票只登记,不直接对接税务系统。更多支付回调和 CSV 规则见 原运营接口文档。