# 语音房火箭接口对接

## 规则

- 火箭最高 5 级。
- 房间送礼成功后，按礼物 `heat_value` 增加当前等级火箭燃料。
- 当前等级满后立刻点火，并把该等级火箭放入 `pending_launches` 等待发射。
- 点火后下一等级马上开始累计燃料。
- 单次送礼超过当前等级阈值时，超过部分直接作废，不顺延到下一等级。
- 发射延迟由后台 `launch_delay_ms` 配置。
- 发射结算三类奖励：点火人、贡献第一、在房用户。在房用户按发射瞬间房间 presence 抽奖。

## 获取火箭

地址：`GET /api/v1/rooms/{room_id}/rocket`

参数：

| 参数 | 位置 | 必填 | 说明 |
| --- | --- | --- | --- |
| `room_id` | path | 是 | 房间 ID |

返回值：

| 字段 | 说明 |
| --- | --- |
| `enabled` | 火箭是否开启 |
| `levels` | 1 到 5 级配置 |
| `levels[].fuel_threshold` | 等级燃料阈值 |
| `levels[].cover_url` | 火箭小封面图 |
| `levels[].animation_url` | 常态动效 |
| `levels[].launch_animation_url` | 发射动效 |
| `levels[].launched_image_url` | 发射后图 |
| `levels[].in_room_rewards` | 在房奖励候选 |
| `levels[].top1_rewards` | 贡献第一奖励候选 |
| `levels[].igniter_rewards` | 点火人奖励候选 |
| `levels[].*_rewards[].resource_group_id` | 奖励资源组 ID |
| `levels[].*_rewards[].resource_group` | 奖励资源组详情 |
| `levels[].*_rewards[].resource_group.items` | 资源组明细 |
| `levels[].*_rewards[].resource_group.items[].item_type` | `wallet_asset` 或 `resource` |
| `levels[].*_rewards[].resource_group.items[].wallet_asset_type` | 金币等奖励资产类型，例如 `COIN` |
| `levels[].*_rewards[].resource_group.items[].wallet_asset_amount` | 金币等奖励数量 |
| `levels[].*_rewards[].resource_group.items[].resource` | 聊天气泡、麦位特效等资源素材 |
| `levels[].*_rewards[].resource_group.items[].resource.resource_type` | 资源类型，例如 `chat_bubble`、`mic_effect` |
| `levels[].*_rewards[].resource_group.items[].resource.asset_url` | 资源主素材 |
| `levels[].*_rewards[].resource_group.items[].resource.preview_url` | 资源预览图 |
| `levels[].*_rewards[].resource_group.items[].resource.animation_url` | 资源动效 |
| `levels[].*_rewards[].resource_group.items[].duration_ms` | 资源有效期毫秒，`0` 表示永久 |
| `state.current_level` | 当前正在累计的等级 |
| `state.current_fuel` | 当前等级已累计燃料 |
| `state.fuel_threshold` | 当前等级阈值 |
| `state.status` | `charging` 或 `completed` |
| `state.rocket_id` | 当前正在累计火箭 ID |
| `state.pending_launches` | 已点火待发射火箭列表 |
| `state.pending_launches[].rocket_id` | 待发射火箭 ID |
| `state.pending_launches[].level` | 待发射等级 |
| `state.pending_launches[].ignited_at_ms` | 点火 UTC 毫秒 |
| `state.pending_launches[].launch_at_ms` | 预计发射 UTC 毫秒 |
| `state.pending_launches[].top1_user_id` | 点火时锁定贡献第一 |
| `state.pending_launches[].igniter_user_id` | 点火人 |
| `state.pending_launches[].cover_url` | 小封面图 |
| `state.last_rewards` | 最近一次发射奖励结果 |
| `state.last_rewards[].resource_group_id` | 本次中奖资源组 ID |
| `state.last_rewards[].resource_group` | 本次中奖资源组详情，字段同上 |
| `server_time_ms` | 服务端 UTC 毫秒 |

`levels[].*_rewards` 表示 `in_room_rewards`、`top1_rewards`、`igniter_rewards` 三个奖励池。客户端展示金币数量、奖励天数、聊天气泡、麦位特效时，直接读 `resource_group.items`。

## 送礼

地址：`POST /api/v1/rooms/gift/send`

参数：

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `room_id` | 是 | 房间 ID |
| `command_id` | 是 | 客户端本次送礼幂等 ID |
| `target_type` | 否 | 默认 `user` |
| `target_user_id` | 否 | 单收礼用户 ID |
| `target_user_ids` | 否 | 多收礼用户 ID |
| `gift_id` | 是 | 礼物 ID |
| `gift_count` | 是 | 礼物数量 |
| `pool_id` | 否 | 幸运礼物奖池 ID |

返回值：

| 字段 | 说明 |
| --- | --- |
| `result` | 命令提交结果 |
| `billing_receipt_id` | 钱包扣费回执 |
| `room_heat` | 最新房间热度 |
| `gift_rank` | 最新房间礼物榜 |
| `rocket` | 送礼后的火箭状态，字段同 `state` |
| `lucky_gift` | 本次送礼聚合幸运礼物结果 |
| `lucky_gifts` | 多目标送礼时每个目标的幸运礼物结果 |

## 后台配置

地址：`GET /v1/admin/activity/room-rocket/config`

参数：无

返回值：

| 字段 | 说明 |
| --- | --- |
| `enabled` | 是否开启 |
| `fuelSource` | 固定为 `heat_value` |
| `launchDelayMs` | 点火后延迟发射毫秒 |
| `broadcastEnabled` | 是否发区域或全局飘屏 |
| `broadcastScope` | `region`、`global`、`none` |
| `rewardStackPolicy` | `allow_stack` 或 `priority_only` |
| `levels` | 5 级配置 |
| `giftFuelRules` | 礼物燃料规则 |

地址：`PUT /v1/admin/activity/room-rocket/config`

参数：

| 参数 | 必填 | 说明 |
| --- | --- | --- |
| `enabled` | 是 | 是否开启 |
| `fuelSource` | 是 | 固定传 `heat_value` |
| `launchDelayMs` | 是 | 点火后延迟发射毫秒 |
| `broadcastEnabled` | 是 | 是否发飘屏 |
| `broadcastScope` | 是 | `region`、`global`、`none` |
| `broadcastDelayMs` | 是 | 保留字段，当前点火后立即入 outbox |
| `rewardStackPolicy` | 是 | `allow_stack` 或 `priority_only` |
| `levels` | 是 | 必须 5 级 |
| `levels[].fuelThreshold` | 是 | 等级阈值 |
| `levels[].coverUrl` | 否 | 小封面图 |
| `levels[].animationUrl` | 否 | 常态动效 |
| `levels[].launchAnimationUrl` | 否 | 发射动效 |
| `levels[].launchedImageUrl` | 否 | 发射后图 |
| `levels[].inRoomRewards` | 否 | 在房奖励池 |
| `levels[].top1Rewards` | 否 | 贡献第一奖励池 |
| `levels[].igniterRewards` | 否 | 点火人奖励池 |
| `giftFuelRules[].giftId` | 否 | 指定礼物 ID |
| `giftFuelRules[].giftTypeCode` | 否 | 指定礼物类型 |
| `giftFuelRules[].multiplierPpm` | 否 | 燃料倍率，1 倍为 `1000000` |
| `giftFuelRules[].fixedFuel` | 否 | 固定燃料 |
| `giftFuelRules[].excluded` | 否 | 是否排除该礼物 |

返回值：同获取后台配置。

## 房间 IM

来源：腾讯云 IM 房间群。

基础字段：

| 字段 | 说明 |
| --- | --- |
| `TIMCustomElem.Ext` | `room_system_message` |
| `event_type` | 事件类型 |
| `room_id` | 房间 ID |
| `event_id` | 消息 ID |
| `occurred_at_ms` | 服务端 UTC 毫秒 |

### room_rocket_fuel_changed

用途：刷新当前等级进度。

字段：

| 字段 | 说明 |
| --- | --- |
| `rocket_id` | 当前累计火箭 ID |
| `level` | 当前累计等级 |
| `added_fuel` | 本次理论燃料 |
| `effective_added_fuel` | 本次实际计入燃料 |
| `overflow_fuel` | 本次作废燃料 |
| `current_fuel` | 当前等级燃料 |
| `fuel_threshold` | 当前等级阈值 |
| `status` | `charging` 或本次满阈值时的 `ignited` |
| `gift_id` | 礼物 ID |
| `gift_count` | 礼物数量 |

### room_rocket_ignited

用途：当前等级满阈值，加入待发射队列；客户端立即把下一等级作为当前进度。

字段：

| 字段 | 说明 |
| --- | --- |
| `rocket_id` | 待发射火箭 ID |
| `level` | 待发射等级 |
| `rocket_level` | 同 `level` |
| `room_short_id` | 房间短号 |
| `rocket_cover_url` | 小封面图 |
| `current_fuel` | 满阈值燃料 |
| `fuel_threshold` | 满阈值 |
| `ignited_at_ms` | 点火时间 |
| `launch_at_ms` | 预计发射时间 |
| `reset_at_ms` | UTC 日重置时间 |
| `top1_user_id` | 点火时贡献第一 |
| `igniter_user_id` | 点火人 |

### room_rocket_launched

用途：火箭已到点发射，客户端播放发射表现。

字段：

| 字段 | 说明 |
| --- | --- |
| `rocket_id` | 已发射火箭 ID |
| `level` | 已发射等级 |
| `next_level` | 当前正在累计等级 |
| `launched_at_ms` | 发射时间 |
| `top1_user_id` | 贡献第一 |
| `igniter_user_id` | 点火人 |
| `rewards_json` | 奖励摘要 |

## 区域或全局飘屏 IM

来源：腾讯云 IM 区域群或全局群。

基础字段：

| 字段 | 说明 |
| --- | --- |
| `TIMCustomElem.Ext` | `im_broadcast` |
| `TIMCustomElem.Desc` | `room_rocket` |

消息体：

| 字段 | 说明 |
| --- | --- |
| `broadcast_type` | `room_rocket` |
| `scope` | `region` 或 `global` |
| `room_id` | 房间 ID |
| `room_short_id` | 房间短号 |
| `rocket_id` | 待发射火箭 ID |
| `rocket_level` | 火箭等级 |
| `rocket_cover_url` | 小封面图 |
| `launch_at_ms` | 预计发射时间 |
| `igniter.user_id` | 点火人用户 ID |
| `igniter.short_id` | 点火人短 ID |
| `igniter.nickname` | 点火人昵称 |
| `igniter.avatar` | 点火人头像 |

## 奖励房间 IM

来源：腾讯云 IM 房间群。

基础字段：

| 字段 | 说明 |
| --- | --- |
| `TIMCustomElem.Ext` | `im_broadcast` |
| `TIMCustomElem.Desc` | `room_rocket_reward_granted` |

消息体：

| 字段 | 说明 |
| --- | --- |
| `broadcast_type` | `room_rocket_reward_granted` |
| `scope` | `room` |
| `room_id` | 房间 ID |
| `rocket_id` | 已发射火箭 ID |
| `rocket_level` | 已发射等级 |
| `rewards` | 本次所有获得奖励的人 |
| `rewards[].reward_role` | `in_room`、`top1`、`igniter` |
| `rewards[].user.user_id` | 用户 ID |
| `rewards[].user.short_id` | 用户短 ID |
| `rewards[].user.nickname` | 用户昵称 |
| `rewards[].user.avatar` | 用户头像 |
| `rewards[].resource_group_id` | 资源组 ID |
| `rewards[].display_name` | 奖励展示名 |
| `rewards[].icon_url` | 奖励图标 |
| `rewards[].grant_id` | 发奖回执 |
| `rewards[].status` | 发奖状态 |

奖励 IM 用于通知本次哪些人中奖。top1 和点火人命中后会发完整配置池，同一用户可能同时收到多条 `top1`、`igniter` 和 1 条在房随机奖励。需要渲染金币数量、奖励天数、聊天气泡或麦位特效素材时，收到 IM 后调用 `GET /api/v1/rooms/{room_id}/rocket`，读取 `state.last_rewards[].resource_group`。

## 客户端处理

- 进房先调 `GET /api/v1/rooms/{room_id}/rocket`。
- 送礼成功优先用返回的 `rocket` 刷新状态。
- 收到 `room_rocket_fuel_changed` 刷新进度。
- 收到 `room_rocket_ignited` 把该火箭加入待发射队列，并显示下一等级当前进度。
- 收到 `room_rocket_launched` 播放发射表现。
- 收到 `room_rocket_reward_granted` 展示本次所有中奖人和奖励。
- 如果 IM 丢失或乱序，用 GET 接口兜底。
- 不要用普通 `room_gift_sent` 自行推算火箭燃料。

## 高频和延迟处理

- 送礼只同步写 Room Cell 状态和 room outbox，不同步请求腾讯 IM。
- 房间进度 IM 走 room outbox 补偿投递，失败会重试。
- 点火后延迟发射通过 RocketMQ delayed wakeup 唤醒；到点后 room-service 重新校验 `rocket_id`、`level`、`launch_at_ms`、UTC 重置边界。
- 奖励 IM 一次性包含所有中奖人，避免按用户逐条发 IM。
