2026-07-21 12:41:24 +08:00

108 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"context"
"strings"
"time"
roomv1 "hyapp.local/api/proto/room/v1"
walletv1 "hyapp.local/api/proto/wallet/v1"
"hyapp/pkg/appcode"
"hyapp/pkg/xerr"
"hyapp/services/room-service/internal/room/command"
"hyapp/services/room-service/internal/room/outbox"
"hyapp/services/room-service/internal/room/rank"
"hyapp/services/room-service/internal/room/state"
)
// ApplyRoomRPSGift 把 room-rps 最终由败者支付的一份礼物应用到火箭。
// 钱包已由 game-service 结算,因此本入口只接受服务端锁定的 heat_value并用 command_id 保证重试不重复充能。
func (s *Service) ApplyRoomRPSGift(ctx context.Context, req *roomv1.ApplyRoomRPSGiftRequest) (*roomv1.ApplyRoomRPSGiftResponse, error) {
ctx = contextFromMeta(ctx, req.GetMeta())
if req.GetSenderUserId() <= 0 || req.GetTargetUserId() <= 0 || strings.TrimSpace(req.GetGiftId()) == "" || req.GetHeatValue() <= 0 {
return nil, xerr.New(xerr.InvalidArgument, "room rps settled gift is incomplete")
}
cmd := command.ApplyRoomRPSGift{
Base: baseFromMeta(req.GetMeta()),
TargetUserID: req.GetTargetUserId(),
GiftID: strings.TrimSpace(req.GetGiftId()),
HeatValue: req.GetHeatValue(),
}
cmd.Base.Room = strings.TrimSpace(req.GetRoomId())
cmd.Base.ActorID = req.GetSenderUserId()
result, err := s.mutateRoom(ctx, cmd, true, func(now time.Time, current *state.RoomState, _ *rank.LocalRank) (mutationResult, []outbox.Record, error) {
roomMeta, exists, err := s.repository.GetRoomMeta(ctx, cmd.RoomID())
if err != nil {
return mutationResult{}, nil, err
}
if !exists {
return mutationResult{}, nil, xerr.New(xerr.NotFound, "room not found")
}
cfg, err := s.roomRocketConfig(ctx)
if err != nil {
return mutationResult{}, nil, err
}
// 复用普通送礼的唯一火箭规则实现,但不进入钱包、房间热度、礼物榜或 RoomGiftSent 链路。
giftCmd := command.SendGift{Base: cmd.Base, TargetUserID: cmd.TargetUserID, TargetUserIDs: []int64{cmd.TargetUserID}, GiftID: cmd.GiftID, GiftCount: 1, HeatValue: cmd.HeatValue}
settledGift := giftCmd
billing := &walletv1.DebitGiftResponse{HeatValue: cmd.HeatValue}
rocketApply, err := s.applyRoomRocketGift(now, current, cfg, giftCmd, &settledGift, billing, roomMeta)
if err != nil {
return mutationResult{}, nil, err
}
copyRoomRPSRocketSnapshot(&cmd, settledGift)
payload, err := command.Serialize(cmd)
if err != nil {
return mutationResult{}, nil, err
}
current.Version++
records := make([]outbox.Record, 0, 1)
var progress *roomRocketProgressPending
if rocketApply.progressEvent != nil {
progressRecord, err := outbox.Build(current.RoomID, "RoomRocketFuelChanged", current.Version, now, rocketApply.progressEvent)
if err != nil {
return mutationResult{}, nil, err
}
progressRecord.AppCode = appcode.FromContext(ctx)
if progressRecord.Envelope != nil {
progressRecord.Envelope.AppCode = progressRecord.AppCode
}
progress = &roomRocketProgressPending{record: progressRecord, rocketID: rocketApply.progressEvent.GetRocketId(), level: rocketApply.progressEvent.GetLevel(), currentFuel: rocketApply.progressEvent.GetCurrentFuel(), roomVersion: current.Version}
}
if rocketApply.ignited != nil {
ignitedRecord, err := outbox.Build(current.RoomID, "RoomRocketIgnited", current.Version, now, rocketApply.ignited)
if err != nil {
return mutationResult{}, nil, err
}
records = append(records, ignitedRecord)
}
return mutationResult{snapshot: current.ToProto(), commandPayload: payload, roomRocketProgress: progress}, records, nil
})
if err != nil {
return nil, err
}
return &roomv1.ApplyRoomRPSGiftResponse{Result: commandResult(result.applied, result.snapshot.GetVersion(), s.clock.Now()), Rocket: result.snapshot.GetRocket()}, nil
}
func copyRoomRPSRocketSnapshot(target *command.ApplyRoomRPSGift, source command.SendGift) {
target.RocketTouched = source.RocketTouched
target.RocketAddedFuel = source.RocketAddedFuel
target.RocketEffectiveFuel = source.RocketEffectiveFuel
target.RocketOverflowFuel = source.RocketOverflowFuel
target.RocketLevel = source.RocketLevel
target.RocketFuel = source.RocketFuel
target.RocketStatus = source.RocketStatus
target.RocketFuelThreshold = source.RocketFuelThreshold
target.RocketIgnitedAtMS = source.RocketIgnitedAtMS
target.RocketLaunchAtMS = source.RocketLaunchAtMS
target.RocketResetAtMS = source.RocketResetAtMS
target.RocketTop1UserID = source.RocketTop1UserID
target.RocketIgniterUserID = source.RocketIgniterUserID
target.RocketID = source.RocketID
target.RocketConfigVersion = source.RocketConfigVersion
target.RocketPendingLaunches = source.RocketPendingLaunches
target.RocketCurrentContributions = source.RocketCurrentContributions
}