fix room rocket top1 contribution tracking

This commit is contained in:
zhx 2026-06-11 16:54:55 +08:00
parent 70c928c38b
commit 6fc9499a4b
7 changed files with 1116 additions and 805 deletions

File diff suppressed because it is too large Load Diff

View File

@ -139,6 +139,13 @@ message RoomRocketRewardGrant {
string status = 8;
}
// RoomRocketContribution
message RoomRocketContribution {
int64 user_id = 1;
int64 fuel = 2;
int64 updated_at_ms = 3;
}
// RoomRocketPendingLaunch
message RoomRocketPendingLaunch {
string rocket_id = 1;
@ -169,6 +176,7 @@ message RoomRocketState {
int64 config_version = 12;
repeated RoomRocketRewardGrant last_rewards = 13;
repeated RoomRocketPendingLaunch pending_launches = 14;
repeated RoomRocketContribution current_contributions = 15;
}
// RoomRocketInfo App UI

View File

@ -457,6 +457,8 @@ type SendGift struct {
RocketConfigVersion int64 `json:"rocket_config_version,omitempty"`
// RocketPendingLaunches 是送礼提交后的待发射队列,恢复时不能只保存当前进度。
RocketPendingLaunches []RocketPendingLaunch `json:"rocket_pending_launches,omitempty"`
// RocketCurrentContributions 保存当前等级真实加燃料贡献,恢复时用于继续按本级贡献锁 top1。
RocketCurrentContributions []RocketContribution `json:"rocket_current_contributions,omitempty"`
}
// Type 返回命令类型。
@ -474,6 +476,13 @@ type RocketRewardGrant struct {
Status string `json:"status"`
}
// RocketContribution 记录当前火箭等级内的实际燃料贡献快照。
type RocketContribution struct {
UserID int64 `json:"user_id"`
Fuel int64 `json:"fuel"`
UpdatedAtMS int64 `json:"updated_at_ms"`
}
// RocketPendingLaunch 记录一枚已点火火箭的延迟发射快照。
type RocketPendingLaunch struct {
RocketID string `json:"rocket_id"`
@ -507,6 +516,7 @@ type LaunchRoomRocket struct {
IgniterUserID int64 `json:"igniter_user_id,omitempty"`
LaunchedAtMS int64 `json:"launched_at_ms"`
InRoomUserIDs []int64 `json:"in_room_user_ids,omitempty"`
CurrentContributions []RocketContribution `json:"current_contributions,omitempty"`
Rewards []RocketRewardGrant `json:"rewards,omitempty"`
PendingLaunches []RocketPendingLaunch `json:"pending_launches,omitempty"`
}
@ -564,6 +574,7 @@ func IdempotencyPayload(payload []byte) ([]byte, error) {
delete(values, "rocket_id")
delete(values, "rocket_config_version")
delete(values, "rocket_pending_launches")
delete(values, "rocket_current_contributions")
// LaunchRoomRocket 的以下字段是 worker 在发射时结算出的结果,不属于触发发射的幂等语义。
delete(values, "current_level")
delete(values, "current_fuel")
@ -576,6 +587,7 @@ func IdempotencyPayload(payload []byte) ([]byte, error) {
delete(values, "igniter_user_id")
delete(values, "launched_at_ms")
delete(values, "in_room_user_ids")
delete(values, "current_contributions")
delete(values, "rewards")
delete(values, "pending_launches")
// SetRoomPassword 的哈希带随机盐;通用 payload 比较先去掉哈希service 层再用 transient 明文和已存 bcrypt 哈希确认是否同一密码。

View File

@ -443,36 +443,53 @@ func sendGiftTargetGiftValues(cmd *command.SendGift) map[int64]int64 {
func rocketStateFromSettledGift(cmd *command.SendGift) *state.RocketState {
return &state.RocketState{
CurrentLevel: cmd.RocketLevel,
CurrentFuel: cmd.RocketFuel,
FuelThreshold: cmd.RocketFuelThreshold,
Status: cmd.RocketStatus,
IgnitedAtMS: cmd.RocketIgnitedAtMS,
LaunchAtMS: cmd.RocketLaunchAtMS,
ResetAtMS: cmd.RocketResetAtMS,
Top1UserID: cmd.RocketTop1UserID,
IgniterUserID: cmd.RocketIgniterUserID,
RocketID: cmd.RocketID,
ConfigVersion: cmd.RocketConfigVersion,
PendingLaunches: rocketPendingLaunchesFromCommand(cmd.RocketPendingLaunches),
CurrentLevel: cmd.RocketLevel,
CurrentFuel: cmd.RocketFuel,
FuelThreshold: cmd.RocketFuelThreshold,
Status: cmd.RocketStatus,
IgnitedAtMS: cmd.RocketIgnitedAtMS,
LaunchAtMS: cmd.RocketLaunchAtMS,
ResetAtMS: cmd.RocketResetAtMS,
Top1UserID: cmd.RocketTop1UserID,
IgniterUserID: cmd.RocketIgniterUserID,
RocketID: cmd.RocketID,
ConfigVersion: cmd.RocketConfigVersion,
PendingLaunches: rocketPendingLaunchesFromCommand(cmd.RocketPendingLaunches),
CurrentContributions: rocketContributionsFromCommand(cmd.RocketCurrentContributions),
}
}
func rocketStateFromLaunchCommand(cmd *command.LaunchRoomRocket) *state.RocketState {
return &state.RocketState{
CurrentLevel: cmd.CurrentLevel,
CurrentFuel: cmd.CurrentFuel,
FuelThreshold: cmd.CurrentFuelThreshold,
Status: cmd.CurrentStatus,
LaunchedAtMS: cmd.LaunchedAtMS,
ResetAtMS: cmd.ResetAtMS,
RocketID: cmd.CurrentRocketID,
ConfigVersion: cmd.ConfigVersion,
PendingLaunches: rocketPendingLaunchesFromCommand(cmd.PendingLaunches),
LastRewards: rocketRewardsFromCommand(cmd.Rewards),
CurrentLevel: cmd.CurrentLevel,
CurrentFuel: cmd.CurrentFuel,
FuelThreshold: cmd.CurrentFuelThreshold,
Status: cmd.CurrentStatus,
LaunchedAtMS: cmd.LaunchedAtMS,
ResetAtMS: cmd.ResetAtMS,
RocketID: cmd.CurrentRocketID,
ConfigVersion: cmd.ConfigVersion,
PendingLaunches: rocketPendingLaunchesFromCommand(cmd.PendingLaunches),
CurrentContributions: rocketContributionsFromCommand(cmd.CurrentContributions),
LastRewards: rocketRewardsFromCommand(cmd.Rewards),
}
}
func rocketContributionsFromCommand(input []command.RocketContribution) []state.RocketContribution {
contributions := make([]state.RocketContribution, 0, len(input))
for _, contribution := range input {
if contribution.UserID <= 0 || contribution.Fuel <= 0 {
continue
}
contributions = append(contributions, state.RocketContribution{
UserID: contribution.UserID,
Fuel: contribution.Fuel,
UpdatedAtMS: contribution.UpdatedAtMS,
})
}
return contributions
}
func rocketPendingLaunchExists(input []state.RocketPendingLaunch, rocketID string, level int32) bool {
for _, launch := range input {
if launch.RocketID == rocketID && launch.Level == level {

View File

@ -243,20 +243,21 @@ func roomRocketProtoStateForView(current *roomv1.RoomRocketState, config RoomRoc
internal := state.RocketState{}
if current != nil {
internal = state.RocketState{
CurrentLevel: current.GetCurrentLevel(),
CurrentFuel: current.GetCurrentFuel(),
FuelThreshold: current.GetFuelThreshold(),
Status: current.GetStatus(),
IgnitedAtMS: current.GetIgnitedAtMs(),
LaunchAtMS: current.GetLaunchAtMs(),
LaunchedAtMS: current.GetLaunchedAtMs(),
ResetAtMS: current.GetResetAtMs(),
Top1UserID: current.GetTop1UserId(),
IgniterUserID: current.GetIgniterUserId(),
RocketID: current.GetRocketId(),
ConfigVersion: current.GetConfigVersion(),
PendingLaunches: statePendingLaunchesFromProto(current.GetPendingLaunches()),
LastRewards: stateRewardsFromProto(current.GetLastRewards()),
CurrentLevel: current.GetCurrentLevel(),
CurrentFuel: current.GetCurrentFuel(),
FuelThreshold: current.GetFuelThreshold(),
Status: current.GetStatus(),
IgnitedAtMS: current.GetIgnitedAtMs(),
LaunchAtMS: current.GetLaunchAtMs(),
LaunchedAtMS: current.GetLaunchedAtMs(),
ResetAtMS: current.GetResetAtMs(),
Top1UserID: current.GetTop1UserId(),
IgniterUserID: current.GetIgniterUserId(),
RocketID: current.GetRocketId(),
ConfigVersion: current.GetConfigVersion(),
PendingLaunches: statePendingLaunchesFromProto(current.GetPendingLaunches()),
CurrentContributions: stateContributionsFromProto(current.GetCurrentContributions()),
LastRewards: stateRewardsFromProto(current.GetLastRewards()),
}
}
normalized := rocketStateForNow(&internal, config, now, false)
@ -299,6 +300,21 @@ func statePendingLaunchesFromProto(input []*roomv1.RoomRocketPendingLaunch) []st
return out
}
func stateContributionsFromProto(input []*roomv1.RoomRocketContribution) []state.RocketContribution {
out := make([]state.RocketContribution, 0, len(input))
for _, contribution := range input {
if contribution.GetUserId() <= 0 || contribution.GetFuel() <= 0 {
continue
}
out = append(out, state.RocketContribution{
UserID: contribution.GetUserId(),
Fuel: contribution.GetFuel(),
UpdatedAtMS: contribution.GetUpdatedAtMs(),
})
}
return out
}
func roomRocketLevelsToProto(levels []RoomRocketLevelConfig) []*roomv1.RoomRocketLevel {
out := make([]*roomv1.RoomRocketLevel, 0, len(levels))
for _, level := range levels {
@ -367,11 +383,17 @@ func (s *Service) applyRoomRocketGift(now time.Time, current *state.RoomState, c
overflowFuel = addedFuel - effectiveFuel
if effectiveFuel > 0 {
rocket.CurrentFuel += effectiveFuel
rocket.CurrentContributions = addRocketContribution(rocket.CurrentContributions, cmd.ActorUserID(), effectiveFuel, nowMS)
progressFuel = rocket.CurrentFuel
result.touched = true
}
if rocket.CurrentFuel >= rocket.FuelThreshold {
levelCfg := roomRocketLevelByNumber(cfg, rocket.CurrentLevel)
top1UserID := firstRocketContributionUserID(rocket.CurrentContributions)
if top1UserID <= 0 {
// 理论上 effectiveFuel > 0 后一定有当前等级贡献;兜底用点火人,避免历史脏状态把 top1 奖励发给 0。
top1UserID = cmd.ActorUserID()
}
pending := state.RocketPendingLaunch{
RocketID: rocket.RocketID,
Level: rocket.CurrentLevel,
@ -379,7 +401,7 @@ func (s *Service) applyRoomRocketGift(now time.Time, current *state.RoomState, c
IgnitedAtMS: nowMS,
LaunchAtMS: nowMS + cfg.LaunchDelayMS,
ResetAtMS: rocket.ResetAtMS,
Top1UserID: firstRankUserID(current.GiftRank),
Top1UserID: top1UserID,
IgniterUserID: cmd.ActorUserID(),
ConfigVersion: cfg.ConfigVersion,
CoverURL: levelCfg.CoverURL,
@ -420,10 +442,12 @@ func (s *Service) applyRoomRocketGift(now time.Time, current *state.RoomState, c
rocket.FuelThreshold = nextLevelCfg.FuelThreshold
rocket.Status = state.RocketStatusCharging
rocket.RocketID = idgen.New("room_rocket")
rocket.CurrentContributions = nil
} else {
// 5 级是当天最高等级;点火后不再生成第 6 级UTC 日界统一重置回 1 级。
rocket.Status = state.RocketStatusCompleted
rocket.RocketID = ""
rocket.CurrentContributions = nil
}
}
}
@ -468,6 +492,7 @@ func (s *Service) applyRoomRocketGift(now time.Time, current *state.RoomState, c
settled.RocketID = rocket.RocketID
settled.RocketConfigVersion = rocket.ConfigVersion
settled.RocketPendingLaunches = rocketPendingLaunchesToCommand(rocket.PendingLaunches)
settled.RocketCurrentContributions = rocketContributionsToCommand(rocket.CurrentContributions)
}
return result, nil
}
@ -634,11 +659,61 @@ func roomRocketFuelByRule(base int64, rule GiftFuelRuleConfig) int64 {
return fuel
}
func firstRankUserID(items []state.RankItem) int64 {
if len(items) == 0 {
func addRocketContribution(input []state.RocketContribution, userID int64, fuel int64, updatedAtMS int64) []state.RocketContribution {
if userID <= 0 || fuel <= 0 {
return normalizeRocketContributions(input)
}
out := append([]state.RocketContribution(nil), input...)
for index := range out {
if out[index].UserID == userID {
// top1 只看当前火箭等级真实写入燃料的累计;溢出部分不会带到下一等级,也不会影响当前等级排名。
out[index].Fuel += fuel
out[index].UpdatedAtMS = updatedAtMS
return normalizeRocketContributions(out)
}
}
out = append(out, state.RocketContribution{UserID: userID, Fuel: fuel, UpdatedAtMS: updatedAtMS})
return normalizeRocketContributions(out)
}
func normalizeRocketContributions(input []state.RocketContribution) []state.RocketContribution {
out := make([]state.RocketContribution, 0, len(input))
for _, item := range input {
if item.UserID <= 0 || item.Fuel <= 0 {
continue
}
out = append(out, item)
}
slices.SortFunc(out, func(left, right state.RocketContribution) int {
if left.Fuel != right.Fuel {
if left.Fuel > right.Fuel {
return -1
}
return 1
}
if left.UpdatedAtMS != right.UpdatedAtMS {
if left.UpdatedAtMS > right.UpdatedAtMS {
return -1
}
return 1
}
if left.UserID < right.UserID {
return -1
}
if left.UserID > right.UserID {
return 1
}
return 0
})
return out
}
func firstRocketContributionUserID(items []state.RocketContribution) int64 {
normalized := normalizeRocketContributions(items)
if len(normalized) == 0 {
return 0
}
return items[0].UserID
return normalized[0].UserID
}
func minInt64(left int64, right int64) int64 {
@ -680,21 +755,30 @@ func rocketStateToRoomProto(input *state.RocketState) *roomv1.RoomRocketState {
CoverUrl: launch.CoverURL,
})
}
contributions := make([]*roomv1.RoomRocketContribution, 0, len(input.CurrentContributions))
for _, contribution := range normalizeRocketContributions(input.CurrentContributions) {
contributions = append(contributions, &roomv1.RoomRocketContribution{
UserId: contribution.UserID,
Fuel: contribution.Fuel,
UpdatedAtMs: contribution.UpdatedAtMS,
})
}
return &roomv1.RoomRocketState{
CurrentLevel: input.CurrentLevel,
CurrentFuel: input.CurrentFuel,
FuelThreshold: input.FuelThreshold,
Status: input.Status,
IgnitedAtMs: input.IgnitedAtMS,
LaunchAtMs: input.LaunchAtMS,
LaunchedAtMs: input.LaunchedAtMS,
ResetAtMs: input.ResetAtMS,
Top1UserId: input.Top1UserID,
IgniterUserId: input.IgniterUserID,
RocketId: input.RocketID,
ConfigVersion: input.ConfigVersion,
LastRewards: rewards,
PendingLaunches: pending,
CurrentLevel: input.CurrentLevel,
CurrentFuel: input.CurrentFuel,
FuelThreshold: input.FuelThreshold,
Status: input.Status,
IgnitedAtMs: input.IgnitedAtMS,
LaunchAtMs: input.LaunchAtMS,
LaunchedAtMs: input.LaunchedAtMS,
ResetAtMs: input.ResetAtMS,
Top1UserId: input.Top1UserID,
IgniterUserId: input.IgniterUserID,
RocketId: input.RocketID,
ConfigVersion: input.ConfigVersion,
LastRewards: rewards,
PendingLaunches: pending,
CurrentContributions: contributions,
}
}
@ -863,6 +947,7 @@ func (s *Service) launchRoomRocket(ctx context.Context, cmd command.LaunchRoomRo
settledCommand.IgniterUserID = pending.IgniterUserID
settledCommand.LaunchedAtMS = nowMS
settledCommand.InRoomUserIDs = inRoomUserIDs
settledCommand.CurrentContributions = rocketContributionsToCommand(current.Rocket.CurrentContributions)
settledCommand.Rewards = rocketRewardsToCommand(rewards)
settledCommand.PendingLaunches = rocketPendingLaunchesToCommand(pendingAfter)
commandPayload, err := command.Serialize(settledCommand)
@ -1073,6 +1158,19 @@ func rocketRewardsToCommand(input []state.RocketRewardGrant) []command.RocketRew
return out
}
func rocketContributionsToCommand(input []state.RocketContribution) []command.RocketContribution {
normalized := normalizeRocketContributions(input)
out := make([]command.RocketContribution, 0, len(normalized))
for _, contribution := range normalized {
out = append(out, command.RocketContribution{
UserID: contribution.UserID,
Fuel: contribution.Fuel,
UpdatedAtMS: contribution.UpdatedAtMS,
})
}
return out
}
func rocketPendingLaunchesToCommand(input []state.RocketPendingLaunch) []command.RocketPendingLaunch {
out := make([]command.RocketPendingLaunch, 0, len(input))
for _, launch := range input {

View File

@ -436,6 +436,74 @@ func TestRoomRocketLaunchGrantsLockedTop1AndIgniterAfterLeave(t *testing.T) {
}
}
func TestRoomRocketTop1UsesCurrentLevelFuelContributionNotRoomGiftRank(t *testing.T) {
ctx := context.Background()
repository := mysqltest.NewRepository(t)
now := &fixedRoomRocketClock{now: time.Date(2026, 5, 20, 12, 0, 0, 0, time.UTC)}
wallet := &rocketTestWallet{debits: []*walletv1.DebitGiftResponse{
{BillingReceiptId: "receipt-old-rank", GiftPointAdded: 10, HeatValue: 10, GiftTypeCode: "normal"},
{BillingReceiptId: "receipt-current-level", GiftPointAdded: 90, HeatValue: 90, GiftTypeCode: "normal"},
}}
svc := newRocketTestService(t, repository, wallet, now)
writeRocketConfig(t, ctx, repository, rocketConfigForTest(100, 1_000))
roomID := "room-rocket-current-level-top1"
ownerID := int64(501)
igniterID := int64(502)
createRocketRoom(t, ctx, svc, roomID, ownerID, 9004)
joinRocketRoom(t, ctx, svc, roomID, igniterID)
if _, err := svc.SendGift(ctx, &roomv1.SendGiftRequest{
Meta: rocketMeta(roomID, ownerID, "old-room-rank"),
TargetType: "user",
TargetUserId: igniterID,
GiftId: "gift-old-room-rank",
GiftCount: 1,
}); err != nil {
t.Fatalf("seed old room gift rank failed: %v", err)
}
if _, err := svc.LeaveRoom(ctx, &roomv1.LeaveRoomRequest{Meta: rocketMeta(roomID, ownerID, "owner-leave")}); err != nil {
t.Fatalf("owner leave room failed: %v", err)
}
if _, err := svc.SendGift(ctx, &roomv1.SendGiftRequest{
Meta: rocketMeta(roomID, igniterID, "current-level-fill"),
TargetType: "user",
TargetUserId: igniterID,
GiftId: "gift-current-level-fill",
GiftCount: 1,
}); err != nil {
t.Fatalf("ignite current level rocket failed: %v", err)
}
now.now = now.now.Add(1100 * time.Millisecond)
if err := svc.SweepRoomRocketLaunchings(ctx); err != nil {
t.Fatalf("sweep current-level top1 rocket failed: %v", err)
}
if hasRocketGrant(wallet.grants, ownerID, 2001) {
t.Fatalf("left historical room GiftRank top1 must not receive current-level top1 reward: %+v", wallet.grants)
}
if !hasRocketGrant(wallet.grants, igniterID, 2001) || !hasRocketGrant(wallet.grants, igniterID, 3001) || !hasRocketGrant(wallet.grants, igniterID, 1001) {
t.Fatalf("only current-level contributor/igniter/in-room user must receive all level rewards: %+v", wallet.grants)
}
info, err := svc.GetRoomRocket(ctx, &roomv1.GetRoomRocketRequest{
Meta: &roomv1.RequestMeta{AppCode: appcode.Default, RoomId: roomID},
RoomId: roomID,
ViewerUserId: igniterID,
})
if err != nil {
t.Fatalf("get current-level top1 rocket failed: %v", err)
}
rewards := info.GetRocket().GetState().GetLastRewards()
if len(rewards) != 3 || countRocketRewards(rewards, ownerID, "top1") != 0 ||
countRocketRewards(rewards, igniterID, "top1") != 1 ||
countRocketRewards(rewards, igniterID, "igniter") != 1 ||
countRocketRewards(rewards, igniterID, "in_room") != 1 {
t.Fatalf("reward view must not include historical room GiftRank top1: %+v", rewards)
}
}
func TestRoomRocketLaunchStacksAllSpecialPoolsAndRandomInRoomReward(t *testing.T) {
ctx := context.Background()
repository := mysqltest.NewRepository(t)

View File

@ -171,6 +171,16 @@ type RocketPendingLaunch struct {
CoverURL string
}
// RocketContribution 保存当前火箭等级里真正进入燃料条的用户贡献。
type RocketContribution struct {
// UserID 是加燃料的送礼人top1 只从这一批当前等级贡献里选。
UserID int64
// Fuel 是当前等级内实际写入进度条的燃料,溢出部分不算入下一等级。
Fuel int64
// UpdatedAtMS 用于贡献相同时按最近贡献排序,保持榜单和 UI 直觉一致。
UpdatedAtMS int64
}
// RocketState 保存 Room Cell 内当前火箭进度和最近一次发射结果。
type RocketState struct {
// CurrentLevel 是当前正在积攒的火箭等级UTC 日重置后回到 1。
@ -196,6 +206,8 @@ type RocketState struct {
ConfigVersion int64
// PendingLaunches 是已经满阈值但还没到延迟发射时间的火箭队列。
PendingLaunches []RocketPendingLaunch
// CurrentContributions 只记录当前正在积攒等级的实际燃料贡献,点火进入下一等级后清空。
CurrentContributions []RocketContribution
// LastRewards 保存最近一次发射发奖结果,用于断线重连后补 UI。
LastRewards []RocketRewardGrant
}
@ -207,6 +219,7 @@ func (t *RocketState) Clone() *RocketState {
}
cloned := *t
cloned.PendingLaunches = append([]RocketPendingLaunch(nil), t.PendingLaunches...)
cloned.CurrentContributions = append([]RocketContribution(nil), t.CurrentContributions...)
cloned.LastRewards = append([]RocketRewardGrant(nil), t.LastRewards...)
return &cloned
}
@ -628,6 +641,7 @@ func cloneRocketState(input *RocketState) *RocketState {
}
cloned := *input
cloned.PendingLaunches = append([]RocketPendingLaunch(nil), input.PendingLaunches...)
cloned.CurrentContributions = append([]RocketContribution(nil), input.CurrentContributions...)
cloned.LastRewards = append([]RocketRewardGrant(nil), input.LastRewards...)
return &cloned
}
@ -664,21 +678,30 @@ func rocketStateToProto(input *RocketState) *roomv1.RoomRocketState {
CoverUrl: launch.CoverURL,
})
}
contributions := make([]*roomv1.RoomRocketContribution, 0, len(input.CurrentContributions))
for _, contribution := range input.CurrentContributions {
contributions = append(contributions, &roomv1.RoomRocketContribution{
UserId: contribution.UserID,
Fuel: contribution.Fuel,
UpdatedAtMs: contribution.UpdatedAtMS,
})
}
return &roomv1.RoomRocketState{
CurrentLevel: input.CurrentLevel,
CurrentFuel: input.CurrentFuel,
FuelThreshold: input.FuelThreshold,
Status: input.Status,
IgnitedAtMs: input.IgnitedAtMS,
LaunchAtMs: input.LaunchAtMS,
LaunchedAtMs: input.LaunchedAtMS,
ResetAtMs: input.ResetAtMS,
Top1UserId: input.Top1UserID,
IgniterUserId: input.IgniterUserID,
RocketId: input.RocketID,
ConfigVersion: input.ConfigVersion,
LastRewards: rewards,
PendingLaunches: pending,
CurrentLevel: input.CurrentLevel,
CurrentFuel: input.CurrentFuel,
FuelThreshold: input.FuelThreshold,
Status: input.Status,
IgnitedAtMs: input.IgnitedAtMS,
LaunchAtMs: input.LaunchAtMS,
LaunchedAtMs: input.LaunchedAtMS,
ResetAtMs: input.ResetAtMS,
Top1UserId: input.Top1UserID,
IgniterUserId: input.IgniterUserID,
RocketId: input.RocketID,
ConfigVersion: input.ConfigVersion,
LastRewards: rewards,
PendingLaunches: pending,
CurrentContributions: contributions,
}
}
@ -714,20 +737,29 @@ func rocketStateFromProto(input *roomv1.RoomRocketState) *RocketState {
CoverURL: launch.GetCoverUrl(),
})
}
contributions := make([]RocketContribution, 0, len(input.GetCurrentContributions()))
for _, contribution := range input.GetCurrentContributions() {
contributions = append(contributions, RocketContribution{
UserID: contribution.GetUserId(),
Fuel: contribution.GetFuel(),
UpdatedAtMS: contribution.GetUpdatedAtMs(),
})
}
return &RocketState{
CurrentLevel: input.GetCurrentLevel(),
CurrentFuel: input.GetCurrentFuel(),
FuelThreshold: input.GetFuelThreshold(),
Status: input.GetStatus(),
IgnitedAtMS: input.GetIgnitedAtMs(),
LaunchAtMS: input.GetLaunchAtMs(),
LaunchedAtMS: input.GetLaunchedAtMs(),
ResetAtMS: input.GetResetAtMs(),
Top1UserID: input.GetTop1UserId(),
IgniterUserID: input.GetIgniterUserId(),
RocketID: input.GetRocketId(),
ConfigVersion: input.GetConfigVersion(),
PendingLaunches: pending,
LastRewards: rewards,
CurrentLevel: input.GetCurrentLevel(),
CurrentFuel: input.GetCurrentFuel(),
FuelThreshold: input.GetFuelThreshold(),
Status: input.GetStatus(),
IgnitedAtMS: input.GetIgnitedAtMs(),
LaunchAtMS: input.GetLaunchAtMs(),
LaunchedAtMS: input.GetLaunchedAtMs(),
ResetAtMS: input.GetResetAtMs(),
Top1UserID: input.GetTop1UserId(),
IgniterUserID: input.GetIgniterUserId(),
RocketID: input.GetRocketId(),
ConfigVersion: input.GetConfigVersion(),
PendingLaunches: pending,
CurrentContributions: contributions,
LastRewards: rewards,
}
}