package reward_pool import ( "git.noahlan.cn/northlan/ntools-go/kafka" "github.com/shopspring/decimal" pbMq "live-service/app/pb/mq" "live-service/app/user_center/rpc/pb" "sort" "sync" ) type ( pool struct { id int64 // 奖池ID(对局ID) initReward int64 // 初始奖池 battleReward int64 // 积分奖池 giftReward int64 // 礼物奖池 otherReward int64 // 其它奖池 userBattleReward map[int64]int64 // 用户战斗积分[暴兵|造墙|技能 等等],用于计算分配比例 userGiftReward map[int64]int64 // 用户送礼积分,扩充奖池 userOtherReward map[int64]int64 // 用户其它积分[抽奖|兑换 等等],扩充奖池 manager *PoolManager // 管理器 mutex sync.RWMutex // 锁 } PoolManager struct { welfarePool int64 // 福利池,开服重置 pools map[int64]*pool // 奖池 initReward int64 // 初始奖池 ratio Ratio // 比例 producer *kafka.Producer // kafka mutex sync.Mutex } Ratio struct { Ratio float64 // 奖池比例 BattleRatio float64 // 战斗积分投入奖池比例 GiftRatio float64 // 礼物算作奖池比例 ReturnRatio float64 // 回收比例 WelfareRatio float64 // 从奖金扣除福利比例 } // DrawResult 结算结果 DrawResult struct { UserReturns map[int64]int64 // 用户回收积分,投放多少回收多少,战败方不回收 DrawRewards map[int64]int64 // 用户瓜分奖池,根据回收后的剩余奖池,逐级投放 AddonWelfare int64 // 本次结算添加的福利 } // DrawRequest 结算请求 DrawRequest struct { UserId int64 // 用户ID Position int32 // 排名 Ratio float64 // 其它因素计算的比例 } ) // NewRewardPoolManager 构建奖池 func NewRewardPoolManager(initReward int64, ratio Ratio, producer *kafka.Producer) *PoolManager { return &PoolManager{ initReward: initReward, pools: make(map[int64]*pool), producer: producer, ratio: ratio, } } // Pool 创建或获取 pool func (p *PoolManager) Pool(battleId int64) *pool { resp, ok := p.pools[battleId] if !ok { resp = newRewardPool(battleId, p.initReward, p) p.pools[battleId] = resp } return resp } // Draw 结算 func (p *PoolManager) Draw(battleId int64, req []DrawRequest) *DrawResult { result := p.Pool(battleId).draw(req) p.AddWelfare(result.AddonWelfare) // 移除奖池 p.Remain(battleId) // 变动通知 _ = p.producer.SendMessageAsync(&pbMq.MqRewardPool{ WelfarePool: p.welfarePool, BattleId: battleId, InitReward: 0, GiftReward: 0, BattleReward: 0, OtherReward: 0, AllRewards: 0, }) return result } // Remain 移除 pool func (p *PoolManager) Remain(battleId int64) { p.mutex.Lock() defer p.mutex.Unlock() if _, ok := p.pools[battleId]; ok { delete(p.pools, battleId) } } func (p *PoolManager) AddWelfare(welfare int64) { p.mutex.Lock() defer p.mutex.Unlock() p.welfarePool += welfare } func newRewardPool(battleId int64, initReward int64, manager *PoolManager) *pool { return &pool{ id: battleId, initReward: initReward, userBattleReward: make(map[int64]int64), userGiftReward: make(map[int64]int64), userOtherReward: make(map[int64]int64), manager: manager, } } // draw 奖池结算 func (p *pool) draw(req []DrawRequest) *DrawResult { p.mutex.Lock() defer p.mutex.Unlock() sort.SliceStable(req, func(i, j int) bool { return req[i].Position < req[j].Position }) resp := DrawResult{ UserReturns: make(map[int64]int64), DrawRewards: make(map[int64]int64), } remainRewards := p.rewards() var addonWelfare int64 // 福利池 // 获胜方战斗总投入 var winBattleRewards int64 for _, item := range req { // 用户回收战斗积分 if reward, ok := p.userBattleReward[item.UserId]; ok { returnsReward := decimal.NewFromInt(reward).Mul(decimal.NewFromFloat(p.manager.ratio.ReturnRatio)).Round(0).IntPart() resp.UserReturns[item.UserId] = returnsReward // 玩家回收,比例回收 remainRewards -= reward // 奖池回收,完全回收 addonWelfare += reward - returnsReward // 玩家比例回收,奖池完全回收,多余奖金加入福利池 winBattleRewards += reward // 获胜方战斗总投入 //fmt.Printf("用户 %d 回收战斗积分 %d\n", item.UserId, reward) } } //fmt.Printf("剩余奖池: %d\n", remainRewards) //fmt.Printf("获胜方战斗总投入 %d\n", winBattleRewards) // 福利池抽取 { tmp := decimal.NewFromInt(remainRewards).Mul(decimal.NewFromFloat(p.manager.ratio.WelfareRatio)).Round(0).IntPart() addonWelfare += tmp remainRewards -= tmp } // TODO 奖池分的其余用途 // 用户瓜分奖池 for _, item := range req { // 计算战斗积分分配比例 var ratio float64 if reward, ok := p.userBattleReward[item.UserId]; ok { ratio, _ = decimal.NewFromInt(reward).Div(decimal.NewFromInt(winBattleRewards)).Round(2).Float64() } // 其它因素计算比例 var poolRatio float64 if item.Ratio == 0 { poolRatio = ratio * 1.0 } else { poolRatio = ratio * p.manager.ratio.Ratio } ratio, _ = decimal.NewFromFloat(poolRatio).Add(decimal.NewFromFloat(item.Ratio * (1.0 - p.manager.ratio.Ratio))).Round(2).Float64() //fmt.Printf("用户: %d 瓜分比例 %v\n", item.UserId, ratio) reward := decimal.NewFromInt(remainRewards).Mul(decimal.NewFromFloat(ratio)).Round(0).IntPart() resp.DrawRewards[item.UserId] = reward remainRewards -= reward //fmt.Printf("用户: %d 瓜分奖金 %d\n", item.UserId, reward) //fmt.Printf("剩余奖池: %d\n", remainRewards) } addonWelfare += remainRewards //fmt.Printf("积分 %d 加入福利池\n", remainRewards) resp.AddonWelfare = addonWelfare return &resp } // Rewards 获取当前总积分 func (p *pool) Rewards() int64 { p.mutex.RLock() defer p.mutex.RUnlock() return p.rewards() } func (p *pool) rewards() int64 { return p.initReward + p.battleReward + p.giftReward + p.otherReward } // Add 积分加入奖池 func (p *pool) Add(userId, val int64, integralType pb.IntegralType) int64 { switch integralType { case pb.IntegralType_Battle: p.addBattle(userId, val) case pb.IntegralType_Gift: p.addGift(userId, val) case pb.IntegralType_Other: p.addOther(userId, val) default: p.addOther(userId, val) } result := p.Rewards() // 变动通知 _ = p.manager.producer.SendMessageAsync(&pbMq.MqRewardPool{ WelfarePool: p.manager.initReward, BattleId: p.id, InitReward: p.initReward, GiftReward: p.giftReward, BattleReward: p.battleReward, OtherReward: p.otherReward, AllRewards: result, }) return result } func (p *pool) addBattle(userId, val int64) int64 { p.mutex.Lock() defer p.mutex.Unlock() if val == 0 || val > 0 { return p.battleReward } val = -val val = decimal.NewFromInt(val).Mul(decimal.NewFromFloat(p.manager.ratio.BattleRatio)).Round(0).IntPart() reward, ok := p.userBattleReward[userId] if !ok { reward = val p.userBattleReward[userId] = reward } else { p.userBattleReward[userId] = reward + val } p.battleReward += val //fmt.Printf("用户 %d 战斗积分 %d 加入奖池\n", userId, val) return p.battleReward } func (p *pool) addGift(userId, val int64) int64 { p.mutex.Lock() defer p.mutex.Unlock() if val == 0 || val < 0 { return p.giftReward } val = decimal.NewFromInt(val).Mul(decimal.NewFromFloat(p.manager.ratio.GiftRatio)).Round(0).IntPart() reward, ok := p.userGiftReward[userId] if !ok { reward = val p.userGiftReward[userId] = reward } else { p.userGiftReward[userId] = reward + val } p.giftReward += val //fmt.Printf("用户 %d 礼物积分 %d 加入奖池\n", userId, val) return p.giftReward } func (p *pool) addOther(userId, val int64) int64 { p.mutex.Lock() defer p.mutex.Unlock() if val == 0 || val > 0 { return p.otherReward } val = -val reward, ok := p.userOtherReward[userId] if !ok { reward = val p.userOtherReward[userId] = reward } else { p.userOtherReward[userId] = reward + val } p.otherReward += val //fmt.Printf("用户 %d 其它消耗积分 %d 加入奖池\n", userId, val) return p.otherReward }