Commit 3662627241c795495249727ea2f28d08ed1149df

Authored by 王家文
1 parent 83ef3ff9
Exists in master and in 1 other branch dev-wjw

feat✨:房间排行活动逻辑

models/roomrank.go
@@ -14,13 +14,15 @@ type RspRoomRankGetConfig struct { @@ -14,13 +14,15 @@ type RspRoomRankGetConfig struct {
14 14
15 // RoomRankInfo 房间排行信息 15 // RoomRankInfo 房间排行信息
16 type RoomRankInfo struct { 16 type RoomRankInfo struct {
17 - RoomUid int64 `form:"room_uid" json:"room_uid"` // 房间唯一ID 17 + SettleHas bool `form:"settle_has" json:"settle_has"` // 有结算内容未领取
  18 + SettleAward string `form:"settle_award" json:"settle_award"` // 结算奖励内容
18 } 19 }
19 20
20 // ReqRoomRankInfo 请求 房间排行信息 21 // ReqRoomRankInfo 请求 房间排行信息
21 type ReqRoomRankInfo struct { 22 type ReqRoomRankInfo struct {
22 BaseLoginInfo 23 BaseLoginInfo
23 BaseSign 24 BaseSign
  25 + PlayerLevel int `form:"player_level" json:"player_level"` // 玩家等级
24 } 26 }
25 27
26 // RspRoomRankInfo 返回 房间排行信息 28 // RspRoomRankInfo 返回 房间排行信息
service-common/svmysql/dto.go
@@ -52,8 +52,7 @@ func First(obj IMysqlData, suffix string) (has bool, err error) { @@ -52,8 +52,7 @@ func First(obj IMysqlData, suffix string) (has bool, err error) {
52 return 52 return
53 } 53 }
54 54
55 -func Find(obj IMysqlData, suffix string) (has bool, err error) {  
56 - info := obj.MysqlInfo(suffix) 55 +func Find(obj any, info *MysqlInfo) (has bool, err error) {
57 db := info.DbMysql 56 db := info.DbMysql
58 result := db.Table(info.TableName).Find(obj) 57 result := db.Table(info.TableName).Find(obj)
59 58
service/cardholder/dto-game.go
@@ -1,87 +0,0 @@ @@ -1,87 +0,0 @@
1 -package cardholder  
2 -  
3 -import (  
4 - "apigame/service-common/svconst"  
5 - "apigame/service-common/svmysql"  
6 - "apigame/util/util-lx/lxalilog"  
7 - "apigame/util/util-lx/lxtime"  
8 - "encoding/json"  
9 - "fmt"  
10 -)  
11 -  
12 -// DataCardHolder 卡牌活动持久数据  
13 -type DataCardHolder struct {  
14 - Uid int64 `gorm:"column:uid;primaryKey;comment:玩家唯一ID"`  
15 - ActivityId int64 `gorm:"comment:活动ID"`  
16 -  
17 - Details *DataCardHolderDetails `gorm:"-"` // 活动详情  
18 - DetailsText string `gorm:"comment:活动详情封装"`  
19 -  
20 - CreateTime int64 `gorm:"comment:创建时间戳"`  
21 - UpdateTime int64 `gorm:"comment:修改时间戳"`  
22 -}  
23 -  
24 -func (d *DataCardHolder) MysqlInfo(suffix string) *svmysql.MysqlInfo {  
25 - tableName := svconst.MYSQL_TABLE_S_CARDHOLDER_DATA  
26 - return &svmysql.MysqlInfo{  
27 - DbMysql: svconst.DbCommon,  
28 - TableName: fmt.Sprintf("%s_%s", tableName, suffix),  
29 - }  
30 -}  
31 -  
32 -// DataCardHolderDetails 卡牌活动详情  
33 -type DataCardHolderDetails struct {  
34 - Cards map[int]int // 每张卡集了多少张 k=卡牌ID v=数量  
35 - Album map[int]int // 卡组奖励领取 k=卡组ID v=数量  
36 - StarSequenceScales map[string]int // 星级序列刻度 k=ID_用户序列_用户分组 v=刻度  
37 - CardSequenceScales map[string]int // 卡牌序列刻度 k=ID_用户序列_用户分组 v=刻度  
38 - Round int // 卡册当前轮次  
39 - StarCount int // 星星点数  
40 - LastStarCount int // 上期活动剩余星星点数  
41 - AutoExchangeHolder []int // 活动切换时自动兑换的卡包列表  
42 -}  
43 -  
44 -func NewDataCardHolder(uid int64) *DataCardHolder {  
45 - d := &DataCardHolder{  
46 - Uid: uid,  
47 - Details: NewDataCardHolderDetails(),  
48 - }  
49 - d.Encode()  
50 - return d  
51 -}  
52 -  
53 -func NewDataCardHolderDetails() *DataCardHolderDetails {  
54 - return &DataCardHolderDetails{  
55 - Cards: make(map[int]int),  
56 - Album: make(map[int]int),  
57 - StarSequenceScales: make(map[string]int),  
58 - CardSequenceScales: make(map[string]int),  
59 - Round: 1,  
60 - StarCount: 0,  
61 - AutoExchangeHolder: make([]int, 0),  
62 - }  
63 -}  
64 -  
65 -func (d *DataCardHolder) Init(uid int64) {  
66 - d.Uid = uid  
67 - d.CreateTime = lxtime.NowUninx()  
68 -}  
69 -  
70 -// Encode 打包数据  
71 -func (d *DataCardHolder) Encode() {  
72 - details, err := json.Marshal(d.Details)  
73 - if err != nil {  
74 - lxalilog.Errors(err, "DataCardHolder Encode Error", d.Uid, d.ActivityId)  
75 - return  
76 - }  
77 - d.DetailsText = string(details)  
78 -}  
79 -  
80 -// Decode 分包数据  
81 -func (d *DataCardHolder) Decode() {  
82 - err := json.Unmarshal([]byte(d.DetailsText), d.Details)  
83 - if err != nil {  
84 - lxalilog.Errors(err, "DataCardHolder Decode Error", d.Uid, d.ActivityId)  
85 - return  
86 - }  
87 -}  
service/cardholder/dto-player.go 0 → 100644
@@ -0,0 +1,87 @@ @@ -0,0 +1,87 @@
  1 +package cardholder
  2 +
  3 +import (
  4 + "apigame/service-common/svconst"
  5 + "apigame/service-common/svmysql"
  6 + "apigame/util/util-lx/lxalilog"
  7 + "apigame/util/util-lx/lxtime"
  8 + "encoding/json"
  9 + "fmt"
  10 +)
  11 +
  12 +// Player 卡牌活动持久数据
  13 +type Player struct {
  14 + Uid int64 `gorm:"column:uid;primaryKey;comment:玩家唯一ID"`
  15 + ActivityId int64 `gorm:"comment:活动ID"`
  16 +
  17 + Details *PlayerDetails `gorm:"-"` // 详情
  18 + DetailsText string `gorm:"comment:详情封装"`
  19 +
  20 + CreateTime int64 `gorm:"comment:创建时间戳"`
  21 + UpdateTime int64 `gorm:"comment:修改时间戳"`
  22 +}
  23 +
  24 +func (d *Player) MysqlInfo(suffix string) *svmysql.MysqlInfo {
  25 + tableName := svconst.MYSQL_TABLE_S_CARDHOLDER_DATA
  26 + return &svmysql.MysqlInfo{
  27 + DbMysql: svconst.DbCommon,
  28 + TableName: fmt.Sprintf("%s_%s", tableName, suffix),
  29 + }
  30 +}
  31 +
  32 +func NewPlayer(uid int64) *Player {
  33 + d := &Player{
  34 + Uid: uid,
  35 + Details: NewPlayerDetails(),
  36 + }
  37 + d.Encode()
  38 + return d
  39 +}
  40 +
  41 +// PlayerDetails 详情
  42 +type PlayerDetails struct {
  43 + Cards map[int]int // 每张卡集了多少张 k=卡牌ID v=数量
  44 + Album map[int]int // 卡组奖励领取 k=卡组ID v=数量
  45 + StarSequenceScales map[string]int // 星级序列刻度 k=ID_用户序列_用户分组 v=刻度
  46 + CardSequenceScales map[string]int // 卡牌序列刻度 k=ID_用户序列_用户分组 v=刻度
  47 + Round int // 卡册当前轮次
  48 + StarCount int // 星星点数
  49 + LastStarCount int // 上期活动剩余星星点数
  50 + AutoExchangeHolder []int // 活动切换时自动兑换的卡包列表
  51 +}
  52 +
  53 +func NewPlayerDetails() *PlayerDetails {
  54 + return &PlayerDetails{
  55 + Cards: make(map[int]int),
  56 + Album: make(map[int]int),
  57 + StarSequenceScales: make(map[string]int),
  58 + CardSequenceScales: make(map[string]int),
  59 + Round: 1,
  60 + StarCount: 0,
  61 + AutoExchangeHolder: make([]int, 0),
  62 + }
  63 +}
  64 +
  65 +func (d *Player) Init(uid int64) {
  66 + d.Uid = uid
  67 + d.CreateTime = lxtime.NowUninx()
  68 +}
  69 +
  70 +// Encode 打包数据
  71 +func (d *Player) Encode() {
  72 + details, err := json.Marshal(d.Details)
  73 + if err != nil {
  74 + lxalilog.Errors(err, "Player Encode Error", d.Uid, d.ActivityId)
  75 + return
  76 + }
  77 + d.DetailsText = string(details)
  78 +}
  79 +
  80 +// Decode 分包数据
  81 +func (d *Player) Decode() {
  82 + err := json.Unmarshal([]byte(d.DetailsText), d.Details)
  83 + if err != nil {
  84 + lxalilog.Errors(err, "Player Decode Error", d.Uid, d.ActivityId)
  85 + return
  86 + }
  87 +}
service/cardholder/logic.go
@@ -31,7 +31,7 @@ func CheckStatus(conf *confcardholder.ActivityConfig) string { @@ -31,7 +31,7 @@ func CheckStatus(conf *confcardholder.ActivityConfig) string {
31 } 31 }
32 32
33 // CheckGameData 检查游戏数据 轮次等 33 // CheckGameData 检查游戏数据 轮次等
34 -func CheckGameData(d *DataCardHolder, conf *confcardholder.ActivityConfig) string { 34 +func CheckGameData(d *Player, conf *confcardholder.ActivityConfig) string {
35 if d.Details.Round > conf.Round { 35 if d.Details.Round > conf.Round {
36 return code_msg.RECODE_MERGE_CARDHOLDER_ROUNDFINISH_ERROR 36 return code_msg.RECODE_MERGE_CARDHOLDER_ROUNDFINISH_ERROR
37 } 37 }
@@ -74,7 +74,7 @@ func GetListFromArray(array []string, scale, count int) []string { @@ -74,7 +74,7 @@ func GetListFromArray(array []string, scale, count int) []string {
74 } 74 }
75 75
76 // GetNewCard 按顺序查找数目最少的一张卡抽取 76 // GetNewCard 按顺序查找数目最少的一张卡抽取
77 -func GetNewCard(player *DataCardHolder, conf *confcardholder.ActivityConfig) int { 77 +func GetNewCard(player *Player, conf *confcardholder.ActivityConfig) int {
78 if len(conf.CardConfig) < 1 { 78 if len(conf.CardConfig) < 1 {
79 return 0 79 return 0
80 } 80 }
@@ -91,7 +91,7 @@ func GetNewCard(player *DataCardHolder, conf *confcardholder.ActivityConfig) int @@ -91,7 +91,7 @@ func GetNewCard(player *DataCardHolder, conf *confcardholder.ActivityConfig) int
91 } 91 }
92 92
93 // CheckAlbumFinish 判断卡组是否已集齐 93 // CheckAlbumFinish 判断卡组是否已集齐
94 -func CheckAlbumFinish(albumId int, player *DataCardHolder, config *confcardholder.ActivityConfig) bool { 94 +func CheckAlbumFinish(albumId int, player *Player, config *confcardholder.ActivityConfig) bool {
95 for _, conf := range config.CardConfig { 95 for _, conf := range config.CardConfig {
96 if conf.SetId == albumId { 96 if conf.SetId == albumId {
97 count := player.Details.Cards[conf.Id] 97 count := player.Details.Cards[conf.Id]
@@ -104,7 +104,7 @@ func CheckAlbumFinish(albumId int, player *DataCardHolder, config *confcardholde @@ -104,7 +104,7 @@ func CheckAlbumFinish(albumId int, player *DataCardHolder, config *confcardholde
104 } 104 }
105 105
106 // CheckRoundFinish 判断轮次是否已集齐(所有卡组集齐) 106 // CheckRoundFinish 判断轮次是否已集齐(所有卡组集齐)
107 -func CheckRoundFinish(player *DataCardHolder, config *confcardholder.ActivityConfig) bool { 107 +func CheckRoundFinish(player *Player, config *confcardholder.ActivityConfig) bool {
108 for _, conf := range config.AlbumConfig { 108 for _, conf := range config.AlbumConfig {
109 count := player.Details.Album[conf.SetId] 109 count := player.Details.Album[conf.SetId]
110 if count < 1 { 110 if count < 1 {
@@ -115,14 +115,14 @@ func CheckRoundFinish(player *DataCardHolder, config *confcardholder.ActivityCon @@ -115,14 +115,14 @@ func CheckRoundFinish(player *DataCardHolder, config *confcardholder.ActivityCon
115 } 115 }
116 116
117 // HandleNextRound 处理轮次完成 星级序列刻度 卡牌序列刻度 117 // HandleNextRound 处理轮次完成 星级序列刻度 卡牌序列刻度
118 -func HandleNextRound(player *DataCardHolder) { 118 +func HandleNextRound(player *Player) {
119 player.Details.Round += 1 119 player.Details.Round += 1
120 player.Details.Cards = make(map[int]int) 120 player.Details.Cards = make(map[int]int)
121 player.Details.Album = make(map[int]int) 121 player.Details.Album = make(map[int]int)
122 } 122 }
123 123
124 // GetInfo 玩家卡牌活动信息 124 // GetInfo 玩家卡牌活动信息
125 -func GetInfo(player *DataCardHolder, conf *confcardholder.ActivityConfig) models.CardHolderInfo { 125 +func GetInfo(player *Player, config *confcardholder.ActivityConfig) models.CardHolderInfo {
126 info := models.CardHolderInfo{ 126 info := models.CardHolderInfo{
127 Cards: make(map[int]int), 127 Cards: make(map[int]int),
128 Album: make(map[int]int), 128 Album: make(map[int]int),
@@ -142,7 +142,7 @@ func GetInfo(player *DataCardHolder, conf *confcardholder.ActivityConfig) models @@ -142,7 +142,7 @@ func GetInfo(player *DataCardHolder, conf *confcardholder.ActivityConfig) models
142 // DoOpen 封装的抽卡逻辑 142 // DoOpen 封装的抽卡逻辑
143 // openMode:开包类型0客户端驱动1星星商店购买2剩余星星兑换 143 // openMode:开包类型0客户端驱动1星星商店购买2剩余星星兑换
144 func DoOpen(gameId string, 144 func DoOpen(gameId string,
145 - player *DataCardHolder, 145 + player *Player,
146 config *confcardholder.ActivityConfig, 146 config *confcardholder.ActivityConfig,
147 confCardholder confcardholder.OpenCardholderConfig, 147 confCardholder confcardholder.OpenCardholderConfig,
148 sequenceId, cohort string, 148 sequenceId, cohort string,
@@ -206,7 +206,7 @@ func DoOpen(gameId string, @@ -206,7 +206,7 @@ func DoOpen(gameId string,
206 206
207 // DoOpenCheckAward 封装的新卡判断是否出发卡组和轮次奖励的逻辑 207 // DoOpenCheckAward 封装的新卡判断是否出发卡组和轮次奖励的逻辑
208 func DoOpenCheckAward(gameId string, 208 func DoOpenCheckAward(gameId string,
209 - player *DataCardHolder, 209 + player *Player,
210 config *confcardholder.ActivityConfig, 210 config *confcardholder.ActivityConfig,
211 sequenceId, cohort string, 211 sequenceId, cohort string,
212 newCards []int, 212 newCards []int,
@@ -270,7 +270,7 @@ func DoOpenCheckAward(gameId string, @@ -270,7 +270,7 @@ func DoOpenCheckAward(gameId string,
270 } 270 }
271 271
272 // CalculateStarCount 计算星星点数 272 // CalculateStarCount 计算星星点数
273 -func CalculateStarCount(player *DataCardHolder, config *confcardholder.ActivityConfig) { 273 +func CalculateStarCount(player *Player, config *confcardholder.ActivityConfig) {
274 starCount := 0 274 starCount := 0
275 for cardId, cardCount := range player.Details.Cards { 275 for cardId, cardCount := range player.Details.Cards {
276 if cardCount <= 1 { 276 if cardCount <= 1 {
@@ -292,7 +292,7 @@ func CalculateStarCount(player *DataCardHolder, config *confcardholder.ActivityC @@ -292,7 +292,7 @@ func CalculateStarCount(player *DataCardHolder, config *confcardholder.ActivityC
292 } 292 }
293 293
294 // GetStarCardList 按照规则扣除星星数找到需要扣除的卡牌列表 294 // GetStarCardList 按照规则扣除星星数找到需要扣除的卡牌列表
295 -func GetStarCardList(player *DataCardHolder, config *confcardholder.ActivityConfig, needStar int) (enough bool, cardList map[int]int) { 295 +func GetStarCardList(player *Player, config *confcardholder.ActivityConfig, needStar int) (enough bool, cardList map[int]int) {
296 enough = false 296 enough = false
297 cardList = make(map[int]int) 297 cardList = make(map[int]int)
298 starAmount := 0 298 starAmount := 0
@@ -361,7 +361,7 @@ func GetStarCardList(player *DataCardHolder, config *confcardholder.ActivityConf @@ -361,7 +361,7 @@ func GetStarCardList(player *DataCardHolder, config *confcardholder.ActivityConf
361 } 361 }
362 362
363 // NextActivityAutoExchange 活动切换时自动兑换卡包 363 // NextActivityAutoExchange 活动切换时自动兑换卡包
364 -func NextActivityAutoExchange(gameId string, player *DataCardHolder, config *confcardholder.ActivityConfig) { 364 +func NextActivityAutoExchange(gameId string, player *Player, config *confcardholder.ActivityConfig) {
365 starCount := player.Details.LastStarCount 365 starCount := player.Details.LastStarCount
366 // 把星星的配置按照需要的星星数降序排列 366 // 把星星的配置按照需要的星星数降序排列
367 list := lo.Values[int, confcardholder.StarShopConfig](config.StarShopConfig) 367 list := lo.Values[int, confcardholder.StarShopConfig](config.StarShopConfig)
service/cardholder/player.go
@@ -8,26 +8,26 @@ import ( @@ -8,26 +8,26 @@ import (
8 ) 8 )
9 9
10 // SavePlayer 存储数据 10 // SavePlayer 存储数据
11 -func SavePlayer(gameId string, d *DataCardHolder) {  
12 - d.UpdateTime = lxtime.NowUninx()  
13 - d.Encode() 11 +func SavePlayer(gameId string, player *Player) {
  12 + player.UpdateTime = lxtime.NowUninx()
  13 + player.Encode()
14 14
15 - err := svmysql.Save(d, gameId) 15 + err := svmysql.Save(player, gameId)
16 if err != nil { 16 if err != nil {
17 - lxalilog.Errors(err, "cardholder.SavePlayer error", gameId, d.Uid, d.ActivityId) 17 + lxalilog.Errors(err, "cardholder.SavePlayer error", gameId, player.Uid, player.ActivityId)
18 } 18 }
19 } 19 }
20 20
21 -func _LoadPlayer(gameId string, playerUid int64) (d *DataCardHolder) {  
22 - d = NewDataCardHolder(playerUid)  
23 - has, err := svmysql.First(d, gameId) 21 +func _LoadPlayer(gameId string, playerUid int64) (player *Player) {
  22 + player = NewPlayer(playerUid)
  23 + has, err := svmysql.First(player, gameId)
24 if has { 24 if has {
25 - d.Decode() 25 + player.Decode()
26 } else { 26 } else {
27 - d.Init(playerUid)  
28 - err = svmysql.Create(d, gameId) 27 + player.Init(playerUid)
  28 + err = svmysql.Create(player, gameId)
29 if err != nil { 29 if err != nil {
30 - lxalilog.Errors(err, "cardholder._LoadPlayer Create error", gameId, d.Uid, d.ActivityId) 30 + lxalilog.Errors(err, "cardholder._LoadPlayer Create error", gameId, player.Uid, player.ActivityId)
31 return 31 return
32 } 32 }
33 } 33 }
@@ -35,24 +35,24 @@ func _LoadPlayer(gameId string, playerUid int64) (d *DataCardHolder) { @@ -35,24 +35,24 @@ func _LoadPlayer(gameId string, playerUid int64) (d *DataCardHolder) {
35 } 35 }
36 36
37 // LoadPlayer 获取数据 外部接口 37 // LoadPlayer 获取数据 外部接口
38 -func LoadPlayer(gameId string, playerUid int64, config *confcardholder.ActivityConfig) (d *DataCardHolder) { 38 +func LoadPlayer(gameId string, playerUid int64, config *confcardholder.ActivityConfig) (player *Player) {
39 configId := config.Id 39 configId := config.Id
40 - d = _LoadPlayer(gameId, playerUid) 40 + player = _LoadPlayer(gameId, playerUid)
41 // 如果当前有上线活动(活动ID不为0),且活动ID和玩家数据不同,说明活动已切换 需更新 41 // 如果当前有上线活动(活动ID不为0),且活动ID和玩家数据不同,说明活动已切换 需更新
42 if configId != 0 && 42 if configId != 0 &&
43 - configId != d.ActivityId { 43 + configId != player.ActivityId {
44 44
45 // 剩余的星星数 45 // 剩余的星星数
46 - starCount := d.Details.StarCount 46 + starCount := player.Details.StarCount
47 47
48 - d.ActivityId = configId  
49 - d.Details = NewDataCardHolderDetails() 48 + player.ActivityId = configId
  49 + player.Details = NewPlayerDetails()
50 50
51 // 使用剩余的星星数来自动兑换卡包 51 // 使用剩余的星星数来自动兑换卡包
52 - d.Details.LastStarCount = starCount  
53 - NextActivityAutoExchange(gameId, d, config) 52 + player.Details.LastStarCount = starCount
  53 + NextActivityAutoExchange(gameId, player, config)
54 54
55 - SavePlayer(gameId, d) 55 + SavePlayer(gameId, player)
56 } 56 }
57 return 57 return
58 } 58 }
service/init.go
@@ -12,14 +12,14 @@ func Init() { @@ -12,14 +12,14 @@ func Init() {
12 // create table 12 // create table
13 // 卡牌卡包 13 // 卡牌卡包
14 for _, gameId := range svconst.GameListCardHolder { 14 for _, gameId := range svconst.GameListCardHolder {
15 - svmysql.InitTable(new(cardholder.DataCardHolder), gameId, true) 15 + svmysql.InitTable(new(cardholder.Player), gameId, true)
16 svmysql.InitTable(new(cardholder.RecordCardHolderOpen), gameId, true) 16 svmysql.InitTable(new(cardholder.RecordCardHolderOpen), gameId, true)
17 svmysql.InitTable(new(cardholder.RecordCardHolderRewardAlbum), gameId, true) 17 svmysql.InitTable(new(cardholder.RecordCardHolderRewardAlbum), gameId, true)
18 svmysql.InitTable(new(cardholder.RecordCardHolderRewardRound), gameId, true) 18 svmysql.InitTable(new(cardholder.RecordCardHolderRewardRound), gameId, true)
19 } 19 }
20 - // 卡牌卡包 20 + // 房间排行
21 for _, gameId := range svconst.GameListRoomRank { 21 for _, gameId := range svconst.GameListRoomRank {
22 - svmysql.InitTable(new(roomrank.DataRoomRankPlayer), gameId, true) 22 + svmysql.InitTable(new(roomrank.Player), gameId, true)
23 } 23 }
24 24
25 } 25 }
service/roomrank/consts.go 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +package roomrank
  2 +
  3 +const (
  4 + UserClassMin = 1 // 最小评级
  5 + UserClassMax = 5 // 最大评级
  6 +
  7 + RoomCloseSecond = 180 // 房间关闭时间
  8 +)
service/roomrank/dto-player.go
@@ -4,10 +4,11 @@ import ( @@ -4,10 +4,11 @@ import (
4 "apigame/service-common/svconst" 4 "apigame/service-common/svconst"
5 "apigame/service-common/svmysql" 5 "apigame/service-common/svmysql"
6 "apigame/util/util-lx/lxtime" 6 "apigame/util/util-lx/lxtime"
  7 + "fmt"
7 ) 8 )
8 9
9 -// DataRoomRankPlayer 房间排行持久数据  
10 -type DataRoomRankPlayer struct { 10 +// Player 房间排行持久数据
  11 +type Player struct {
11 Uid int64 `gorm:"column:uid;primaryKey;comment:玩家唯一ID"` 12 Uid int64 `gorm:"column:uid;primaryKey;comment:玩家唯一ID"`
12 ActivityId int64 `gorm:"comment:活动ID"` 13 ActivityId int64 `gorm:"comment:活动ID"`
13 14
@@ -17,26 +18,48 @@ type DataRoomRankPlayer struct { @@ -17,26 +18,48 @@ type DataRoomRankPlayer struct {
17 18
18 RoomUid int64 `gorm:"comment:所在房间唯一ID"` 19 RoomUid int64 `gorm:"comment:所在房间唯一ID"`
19 20
  21 + SettleHas bool `gorm:"comment:有结算内容未领取"`
  22 + SettleAward string `gorm:"comment:结算奖励内容"`
  23 +
20 CreateTime int64 `gorm:"comment:创建时间戳"` 24 CreateTime int64 `gorm:"comment:创建时间戳"`
21 UpdateTime int64 `gorm:"comment:修改时间戳"` 25 UpdateTime int64 `gorm:"comment:修改时间戳"`
22 } 26 }
23 27
24 -func (d *DataRoomRankPlayer) MysqlInfo(suffix string) *svmysql.MysqlInfo { 28 +func (d *Player) MysqlInfo(suffix string) *svmysql.MysqlInfo {
25 tableName := svconst.MYSQL_TABLE_S_ROOMRANK_PLAYER 29 tableName := svconst.MYSQL_TABLE_S_ROOMRANK_PLAYER
26 return &svmysql.MysqlInfo{ 30 return &svmysql.MysqlInfo{
27 DbMysql: svconst.DbCommon, 31 DbMysql: svconst.DbCommon,
28 - TableName: tableName + suffix, 32 + TableName: fmt.Sprintf("%s_%s", tableName, suffix),
29 } 33 }
30 } 34 }
31 35
32 -func NewDataRoomRankPlayer(uid int64) *DataRoomRankPlayer {  
33 - d := &DataRoomRankPlayer{ 36 +func NewPlayer(uid int64) *Player {
  37 + d := &Player{
34 Uid: uid, 38 Uid: uid,
35 } 39 }
36 return d 40 return d
37 } 41 }
38 42
39 -func (d *DataRoomRankPlayer) Init(uid int64) { 43 +func (d *Player) Init(uid int64) {
40 d.Uid = uid 44 d.Uid = uid
41 d.CreateTime = lxtime.NowUninx() 45 d.CreateTime = lxtime.NowUninx()
42 } 46 }
  47 +
  48 +func (d *Player) AddUserScore(count int) {
  49 + d.UserScore += count
  50 + userScoreMin := UserClassMin * 10
  51 + userScoreMax := UserClassMax*10 + 20
  52 + if d.UserScore < userScoreMin {
  53 + d.UserScore = userScoreMin
  54 + }
  55 + if d.UserScore > userScoreMax {
  56 + d.UserScore = userScoreMax
  57 + }
  58 + d.UserClass = d.UserScore / 10
  59 + if d.UserClass < UserClassMin {
  60 + d.UserClass = UserClassMin
  61 + }
  62 + if d.UserClass > UserClassMax {
  63 + d.UserClass = UserClassMax
  64 + }
  65 +}
service/roomrank/dto-room.go
@@ -3,23 +3,111 @@ package roomrank @@ -3,23 +3,111 @@ package roomrank
3 import ( 3 import (
4 "apigame/service-common/svconst" 4 "apigame/service-common/svconst"
5 "apigame/service-common/svmysql" 5 "apigame/service-common/svmysql"
  6 + "apigame/util/util-lx/lxalilog"
  7 + "apigame/util/util-lx/lxtime"
  8 + "encoding/json"
6 "fmt" 9 "fmt"
  10 + "github.com/samber/lo"
7 ) 11 )
8 12
9 -// DataRoomRankRoom 房间排行持久数据  
10 -type DataRoomRankRoom struct { 13 +// Room 房间排行持久数据
  14 +type Room struct {
11 Id int64 `gorm:"column:id;primaryKey;comment:房间唯一ID"` 15 Id int64 `gorm:"column:id;primaryKey;comment:房间唯一ID"`
12 - Uid int64 `gorm:"comment:玩家唯一ID"`  
13 ActivityId int64 `gorm:"comment:活动ID"` 16 ActivityId int64 `gorm:"comment:活动ID"`
  17 + ConfigId int `gorm:"comment:房间配置ID"`
  18 +
  19 + Details *RoomDetails `gorm:"-"` // 详情
  20 + DetailsText string `gorm:"comment:详情封装"`
  21 +
  22 + Closed bool `gorm:"comment:房间已关闭"`
14 23
15 CreateTime int64 `gorm:"comment:创建时间戳"` 24 CreateTime int64 `gorm:"comment:创建时间戳"`
16 UpdateTime int64 `gorm:"comment:修改时间戳"` 25 UpdateTime int64 `gorm:"comment:修改时间戳"`
17 } 26 }
18 27
19 -func (d *DataRoomRankRoom) MysqlInfo(suffix string) *svmysql.MysqlInfo { 28 +func (d *Room) MysqlInfo(suffix string) *svmysql.MysqlInfo {
20 tableName := svconst.MYSQL_TABLE_S_ROOMRANK_ROOM 29 tableName := svconst.MYSQL_TABLE_S_ROOMRANK_ROOM
21 return &svmysql.MysqlInfo{ 30 return &svmysql.MysqlInfo{
22 DbMysql: svconst.DbCommon, 31 DbMysql: svconst.DbCommon,
23 TableName: fmt.Sprintf("%s_%s_%d", tableName, suffix, d.ActivityId), 32 TableName: fmt.Sprintf("%s_%s_%d", tableName, suffix, d.ActivityId),
24 } 33 }
25 } 34 }
  35 +
  36 +// RoomPlayer 房间玩家
  37 +type RoomPlayer struct {
  38 + Uid int64 // 玩家唯一ID
  39 + Score int64 // 玩家排行分数
  40 + JoinTime int64 // 加入时间
  41 + UserType int // 用户类型
  42 + RobotConfigId int // 0=玩家
  43 +}
  44 +
  45 +func NewRoomRobot(robotConfigId int, userType int) *RoomPlayer {
  46 + d := &RoomPlayer{
  47 + Uid: 0,
  48 + Score: 0,
  49 + JoinTime: lxtime.NowUninx(),
  50 + UserType: userType,
  51 + RobotConfigId: robotConfigId,
  52 + }
  53 + return d
  54 +}
  55 +
  56 +func NewRoomPlayer(player *Player) *RoomPlayer {
  57 + d := &RoomPlayer{
  58 + Uid: player.Uid,
  59 + Score: 0,
  60 + JoinTime: lxtime.NowUninx(),
  61 + UserType: player.UserType,
  62 + RobotConfigId: 0,
  63 + }
  64 + return d
  65 +}
  66 +
  67 +// RoomDetails 详情
  68 +type RoomDetails struct {
  69 + Players []*RoomPlayer // 房间玩家列表
  70 +}
  71 +
  72 +// Encode 打包数据
  73 +func (d *Room) Encode() {
  74 + details, err := json.Marshal(d.Details)
  75 + if err != nil {
  76 + lxalilog.Errors(err, "Player Encode Error", d.Id, d.ActivityId)
  77 + return
  78 + }
  79 + d.DetailsText = string(details)
  80 +}
  81 +
  82 +// Decode 分包数据
  83 +func (d *Room) Decode() {
  84 + d.Details = &RoomDetails{
  85 + Players: make([]*RoomPlayer, 0),
  86 + }
  87 + err := json.Unmarshal([]byte(d.DetailsText), d.Details)
  88 + if err != nil {
  89 + lxalilog.Errors(err, "Player Decode Error", d.Id, d.ActivityId)
  90 + return
  91 + }
  92 +}
  93 +
  94 +// FindPlayer 找到玩家排名 -1=没找到
  95 +func (d *Room) FindPlayer(playerUid int64) int {
  96 + count := len(d.Details.Players)
  97 + if count > 0 {
  98 + for i := 0; i < count; i++ {
  99 + p := d.Details.Players[i]
  100 + if p.Uid == playerUid {
  101 + return i
  102 + }
  103 + }
  104 + }
  105 +
  106 + return -1
  107 +}
  108 +
  109 +func (d *Room) GetPlayerTypeCount(userType int) int {
  110 + return lo.CountBy(d.Details.Players, func(p *RoomPlayer) bool {
  111 + return p.UserType == userType
  112 + })
  113 +}
service/roomrank/handle.go
@@ -27,31 +27,29 @@ func HandleInfo(req *models.ReqRoomRankInfo) (code string, rsp models.RspRoomRan @@ -27,31 +27,29 @@ func HandleInfo(req *models.ReqRoomRankInfo) (code string, rsp models.RspRoomRan
27 code = code_msg.RECODE_OK 27 code = code_msg.RECODE_OK
28 gameId := req.GameID 28 gameId := req.GameID
29 playerUid := req.UID 29 playerUid := req.UID
  30 + playerLevel := req.PlayerLevel
30 31
31 // 尝试更新配置 32 // 尝试更新配置
32 config, hasConfig := confroomrank.GetCurrent(gameId) 33 config, hasConfig := confroomrank.GetCurrent(gameId)
33 if !hasConfig { 34 if !hasConfig {
34 - code = code_msg.RECODE_MERGE_ROOMRANK_NOTOPEN_ERROR  
35 - return 35 + config = new(confroomrank.ActivityConfig)
36 } 36 }
37 37
38 - // todo 检查是否在结算中  
39 - //// 判断预告时间  
40 - //sec := lxtime.NowUninx()  
41 - //if sec < config.StartTime {  
42 - // code = code_msg.RECODE_MERGE_CARDHOLDER_NOTOPEN_ERROR  
43 - // return  
44 - //}  
45 -  
46 // 读取游戏数据 38 // 读取游戏数据
47 player := LoadPlayer(gameId, playerUid) 39 player := LoadPlayer(gameId, playerUid)
48 40
49 - // todo 检查是否有领取的结算奖励 41 + // 尝试判断结算
  42 + hasSettle := TrySettle(gameId, player, config)
  43 +
  44 + // 尝试加入房间
  45 + room, hasRoom := TryGetRoom(gameId, player, config, playerLevel)
50 46
51 - //hasRoom := player.RoomUid != 0  
52 - //if hasRoom {  
53 - // room, has := LoadRoom(gameId, player.RoomUid,)  
54 - //} 47 + if hasSettle || hasRoom {
  48 + SavePlayer(gameId, player)
  49 + }
  50 + if hasRoom {
  51 + SaveRoom(gameId, room)
  52 + }
55 53
56 rsp.RoomRankInfo = GetInfo(player, config) 54 rsp.RoomRankInfo = GetInfo(player, config)
57 55
service/roomrank/logic.go
1 package roomrank 1 package roomrank
  2 +
  3 +import (
  4 + "apigame/configs/confroomrank"
  5 +)
  6 +
  7 +// TrySettle 尝试判断结算
  8 +func TrySettle(gameId string, player *Player, config *confroomrank.ActivityConfig) (hasChange bool) {
  9 + hasChange = false
  10 + if player.SettleHas {
  11 + return
  12 + }
  13 + if player.ActivityId == 0 {
  14 + return
  15 + }
  16 + if player.ActivityId == config.Id {
  17 + return
  18 + }
  19 + // 查找玩家所在的房间
  20 + room, hasRoom := LoadRoom(gameId, player.ActivityId, player.RoomUid)
  21 + if !hasRoom {
  22 + return
  23 + }
  24 + // 找到玩家在房间里的名次
  25 + rankIndex := room.FindPlayer(player.Uid)
  26 + if rankIndex < 0 {
  27 + return
  28 + }
  29 + confActivity, hasConfActivity := confroomrank.GetConfig(gameId, room.ActivityId)
  30 + if !hasConfActivity {
  31 + return
  32 + }
  33 + // 设置玩家奖励等数据
  34 + hasChange = true
  35 + player.SettleHas = true
  36 + confRoom, hasConfRoom := confActivity.Room[room.ConfigId]
  37 + if !hasConfRoom {
  38 + return
  39 + }
  40 + if len(confRoom.Awards) > rankIndex {
  41 + player.SettleAward = confRoom.Awards[rankIndex]
  42 + }
  43 + if len(confRoom.SettleScores) > rankIndex {
  44 + player.AddUserScore(confRoom.SettleScores[rankIndex])
  45 + }
  46 + if len(confRoom.SettleUserType) > rankIndex {
  47 + player.UserType = confRoom.SettleUserType[rankIndex]
  48 + }
  49 + return
  50 +}
service/roomrank/player.go
@@ -9,26 +9,26 @@ import ( @@ -9,26 +9,26 @@ import (
9 ) 9 )
10 10
11 // SavePlayer 存储数据 11 // SavePlayer 存储数据
12 -func SavePlayer(gameId string, d *DataRoomRankPlayer) {  
13 - d.UpdateTime = lxtime.NowUninx() 12 +func SavePlayer(gameId string, player *Player) {
  13 + player.UpdateTime = lxtime.NowUninx()
14 14
15 - err := svmysql.Save(d, gameId) 15 + err := svmysql.Save(player, gameId)
16 if err != nil { 16 if err != nil {
17 - lxalilog.Errors(err, "roomrank.SavePlayer error", gameId, d.Uid, d.ActivityId) 17 + lxalilog.Errors(err, "roomrank.SavePlayer error", gameId, player.Uid, player.ActivityId)
18 return 18 return
19 } 19 }
20 } 20 }
21 21
22 // LoadPlayer 获取数据 外部接口 22 // LoadPlayer 获取数据 外部接口
23 -func LoadPlayer(gameId string, playerUid int64) (d *DataRoomRankPlayer) {  
24 - d = NewDataRoomRankPlayer(playerUid)  
25 - has, err := svmysql.First(d, gameId) 23 +func LoadPlayer(gameId string, playerUid int64) (player *Player) {
  24 + player = NewPlayer(playerUid)
  25 + has, err := svmysql.First(player, gameId)
26 if has { 26 if has {
27 } else { 27 } else {
28 - d.Init(playerUid)  
29 - err = svmysql.Create(d, gameId) 28 + player.Init(playerUid)
  29 + err = svmysql.Create(player, gameId)
30 if err != nil { 30 if err != nil {
31 - lxalilog.Errors(err, "roomrank._LoadPlayer Create error", gameId, d.Uid, d.ActivityId) 31 + lxalilog.Errors(err, "roomrank._LoadPlayer Create error", gameId, player.Uid, player.ActivityId)
32 return 32 return
33 } 33 }
34 } 34 }
@@ -36,7 +36,11 @@ func LoadPlayer(gameId string, playerUid int64) (d *DataRoomRankPlayer) { @@ -36,7 +36,11 @@ func LoadPlayer(gameId string, playerUid int64) (d *DataRoomRankPlayer) {
36 } 36 }
37 37
38 // GetInfo 活动信息 38 // GetInfo 活动信息
39 -func GetInfo(player *DataRoomRankPlayer, conf *confroomrank.ActivityConfig) models.RoomRankInfo { 39 +func GetInfo(player *Player, conf *confroomrank.ActivityConfig) models.RoomRankInfo {
40 info := models.RoomRankInfo{} 40 info := models.RoomRankInfo{}
  41 + if player.SettleHas {
  42 + info.SettleHas = player.SettleHas
  43 + info.SettleAward = player.SettleAward
  44 + }
41 return info 45 return info
42 } 46 }
service/roomrank/room.go
1 package roomrank 1 package roomrank
2 2
3 import ( 3 import (
  4 + "apigame/configs/confroomrank"
4 "apigame/service-common/svmysql" 5 "apigame/service-common/svmysql"
5 "apigame/util/util-lx/lxalilog" 6 "apigame/util/util-lx/lxalilog"
6 "apigame/util/util-lx/lxtime" 7 "apigame/util/util-lx/lxtime"
7 ) 8 )
8 9
9 -func tryInitTable(gameId string, d *DataRoomRankRoom) {  
10 - svmysql.InitTable(d, gameId, false) 10 +func tryInitTable(gameId string, room *Room) {
  11 + svmysql.InitTable(room, gameId, false)
11 } 12 }
12 13
13 // SaveRoom 存储数据 14 // SaveRoom 存储数据
14 -func SaveRoom(gameId string, d *DataRoomRankRoom) {  
15 - tryInitTable(gameId, d) 15 +func SaveRoom(gameId string, room *Room) {
  16 + tryInitTable(gameId, room)
16 17
17 - d.UpdateTime = lxtime.NowUninx() 18 + room.UpdateTime = lxtime.NowUninx()
  19 + room.Encode()
18 20
19 - err := svmysql.Save(d, gameId) 21 + err := svmysql.Save(room, gameId)
20 if err != nil { 22 if err != nil {
21 - lxalilog.Errors(err, "roomrank.SaveRoom error", gameId, d.Uid, d.ActivityId) 23 + lxalilog.Errors(err, "roomrank.SaveRoom error", gameId, room.Id, room.ActivityId)
22 return 24 return
23 } 25 }
24 } 26 }
25 27
26 -// LoadRoom 获取数据 外部接口  
27 -func LoadRoom(gameId string, id int64, activityId int64) (d *DataRoomRankRoom, has bool) {  
28 - d = &DataRoomRankRoom{Id: id, ActivityId: activityId}  
29 - tryInitTable(gameId, d) 28 +// LoadRoom 获取数据
  29 +func LoadRoom(gameId string, activityId int64, roomUid int64) (room *Room, has bool) {
  30 + room = &Room{Id: roomUid, ActivityId: activityId}
  31 + if roomUid == 0 {
  32 + has = false
  33 + return
  34 + }
  35 + tryInitTable(gameId, room)
30 36
31 var err error 37 var err error
32 - has, err = svmysql.First(d, gameId) 38 + has, err = svmysql.First(room, gameId)
33 if err != nil { 39 if err != nil {
34 - lxalilog.Errors(err, "roomrank.LoadRoom error", gameId, id, activityId) 40 + lxalilog.Errors(err, "roomrank.LoadRoom error", gameId, roomUid, activityId)
35 return 41 return
36 } 42 }
  43 + room.Decode()
  44 +
  45 + return
  46 +}
37 47
  48 +func CreateRoom(gameId string, activityId int64, roomConfigId int) (room *Room, has bool) {
  49 + room = new(Room)
  50 + room.ActivityId = activityId
  51 + room.ConfigId = roomConfigId
  52 + room.Closed = false
  53 + room.CreateTime = lxtime.NowUninx()
  54 + details := new(RoomDetails)
  55 + details.Players = make([]*RoomPlayer, 0)
  56 + room.Details = details
  57 +
  58 + err := svmysql.Save(room, gameId)
  59 + if err != nil {
  60 + has = false
  61 + } else {
  62 + has = true
  63 + }
38 return 64 return
39 } 65 }
  66 +
  67 +// FindRoom 查找
  68 +func FindRoom(gameId string, activityId int64, roomConfigId int) (rooms []*Room, has bool) {
  69 + roomDemo := &Room{ActivityId: activityId}
  70 + tryInitTable(gameId, roomDemo)
  71 + info := roomDemo.MysqlInfo(gameId)
  72 +
  73 + info.DbMysql = info.DbMysql.Where("config_id = ? AND closed = false", roomConfigId)
  74 + has, _ = svmysql.Find(&rooms, info)
  75 + for _, room := range rooms {
  76 + room.Decode()
  77 + }
  78 +
  79 + return
  80 +}
  81 +
  82 +// TryGetRoom 尝试获取房间
  83 +func TryGetRoom(gameId string, player *Player, config *confroomrank.ActivityConfig, playerLevel int) (room *Room, hasRoom bool) {
  84 + hasRoom = false
  85 + if player.SettleHas {
  86 + return
  87 + }
  88 + if player.ActivityId != config.Id {
  89 + player.ActivityId = config.Id
  90 + }
  91 + // 查找玩家所在的房间
  92 + room, hasRoom = LoadRoom(gameId, config.Id, player.RoomUid)
  93 + if hasRoom {
  94 + return
  95 + }
  96 +
  97 + // 根据等级和分数范围查找合适的房间配置ID
  98 + roomConfigId := 0
  99 + roomConfig := confroomrank.RoomConfig{}
  100 + for _, i2 := range config.Room {
  101 + if playerLevel >= i2.Levels[0] &&
  102 + playerLevel <= i2.Levels[1] &&
  103 + player.UserClass == i2.UserClass {
  104 + roomConfigId = i2.Id
  105 + roomConfig = i2
  106 + }
  107 + }
  108 + if roomConfigId == 0 {
  109 + lxalilog.Errors("TryGetRoom find roomConfigId error", playerLevel, player.UserClass)
  110 + return
  111 + }
  112 + // 数据库查找合适条件的房间列表
  113 + rooms, has := FindRoom(gameId, config.Id, roomConfigId)
  114 + if has {
  115 + for i := 0; i < len(rooms); i++ {
  116 + roomTemp := rooms[i]
  117 + TryCloseRoom(gameId, roomTemp, roomConfig)
  118 + if roomTemp.Closed {
  119 + continue
  120 + }
  121 + // 可容纳玩家类型数量
  122 + canJoinCount := GetTypeCanJoinCount(roomTemp, roomConfig, player.UserType)
  123 + if canJoinCount > 0 {
  124 + room = roomTemp
  125 + hasRoom = true
  126 + break
  127 + }
  128 + }
  129 + }
  130 + if hasRoom {
  131 + // 如果有 就加入
  132 + PlayerJoinRoom(room, player)
  133 + } else {
  134 + // 如果没有合适条件的房间 创建一个
  135 + roomCreate, hasCreate := CreateRoom(gameId, config.Id, roomConfigId)
  136 + if hasCreate {
  137 + room = roomCreate
  138 + PlayerJoinRoom(room, player)
  139 + hasRoom = hasCreate
  140 + }
  141 + }
  142 +
  143 + return
  144 +}
  145 +
  146 +func PlayerJoinRoom(room *Room, player *Player) {
  147 + roomPlayer := NewRoomPlayer(player)
  148 + room.Details.Players = append(room.Details.Players, roomPlayer)
  149 + player.RoomUid = room.Id
  150 +}
  151 +
  152 +// TryCloseRoom 尝试关闭房间
  153 +func TryCloseRoom(gameId string, room *Room, roomConfig confroomrank.RoomConfig) {
  154 + secNow := lxtime.NowUninx()
  155 + if secNow > room.CreateTime+RoomCloseSecond {
  156 + room.Closed = true
  157 + // 根据缺口自动填充机器人
  158 + for i := 0; i < len(roomConfig.PlayerTypeCount); i++ {
  159 + pair := roomConfig.PlayerTypeCount[i]
  160 + userType := pair[0]
  161 + canJoinCount := pair[1] - room.GetPlayerTypeCount(userType)
  162 + robotConfigId := roomConfig.AutoRobot[i]
  163 + for i := 0; i < canJoinCount; i++ {
  164 + roomPlayer := NewRoomRobot(robotConfigId, userType)
  165 + room.Details.Players = append(room.Details.Players, roomPlayer)
  166 + }
  167 + }
  168 + SaveRoom(gameId, room)
  169 + }
  170 +}
  171 +
  172 +// GetTypeCanJoinCount 房间获取某种类型玩家可加入数量
  173 +func GetTypeCanJoinCount(room *Room, roomConfig confroomrank.RoomConfig, userType int) int {
  174 + maxCount := 0
  175 + for i := 0; i < len(roomConfig.PlayerTypeCount); i++ {
  176 + pair := roomConfig.PlayerTypeCount[i]
  177 + if pair[0] == userType {
  178 + maxCount = pair[1]
  179 + break
  180 + }
  181 + }
  182 + return maxCount - room.GetPlayerTypeCount(userType)
  183 +}