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 14  
15 15 // RoomRankInfo 房间排行信息
16 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 21 // ReqRoomRankInfo 请求 房间排行信息
21 22 type ReqRoomRankInfo struct {
22 23 BaseLoginInfo
23 24 BaseSign
  25 + PlayerLevel int `form:"player_level" json:"player_level"` // 玩家等级
24 26 }
25 27  
26 28 // RspRoomRankInfo 返回 房间排行信息
... ...
service-common/svmysql/dto.go
... ... @@ -52,8 +52,7 @@ func First(obj IMysqlData, suffix string) (has bool, err error) {
52 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 56 db := info.DbMysql
58 57 result := db.Table(info.TableName).Find(obj)
59 58  
... ...
service/cardholder/dto-game.go
... ... @@ -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 @@
  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 31 }
32 32  
33 33 // CheckGameData 检查游戏数据 轮次等
34   -func CheckGameData(d *DataCardHolder, conf *confcardholder.ActivityConfig) string {
  34 +func CheckGameData(d *Player, conf *confcardholder.ActivityConfig) string {
35 35 if d.Details.Round > conf.Round {
36 36 return code_msg.RECODE_MERGE_CARDHOLDER_ROUNDFINISH_ERROR
37 37 }
... ... @@ -74,7 +74,7 @@ func GetListFromArray(array []string, scale, count int) []string {
74 74 }
75 75  
76 76 // GetNewCard 按顺序查找数目最少的一张卡抽取
77   -func GetNewCard(player *DataCardHolder, conf *confcardholder.ActivityConfig) int {
  77 +func GetNewCard(player *Player, conf *confcardholder.ActivityConfig) int {
78 78 if len(conf.CardConfig) < 1 {
79 79 return 0
80 80 }
... ... @@ -91,7 +91,7 @@ func GetNewCard(player *DataCardHolder, conf *confcardholder.ActivityConfig) int
91 91 }
92 92  
93 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 95 for _, conf := range config.CardConfig {
96 96 if conf.SetId == albumId {
97 97 count := player.Details.Cards[conf.Id]
... ... @@ -104,7 +104,7 @@ func CheckAlbumFinish(albumId int, player *DataCardHolder, config *confcardholde
104 104 }
105 105  
106 106 // CheckRoundFinish 判断轮次是否已集齐(所有卡组集齐)
107   -func CheckRoundFinish(player *DataCardHolder, config *confcardholder.ActivityConfig) bool {
  107 +func CheckRoundFinish(player *Player, config *confcardholder.ActivityConfig) bool {
108 108 for _, conf := range config.AlbumConfig {
109 109 count := player.Details.Album[conf.SetId]
110 110 if count < 1 {
... ... @@ -115,14 +115,14 @@ func CheckRoundFinish(player *DataCardHolder, config *confcardholder.ActivityCon
115 115 }
116 116  
117 117 // HandleNextRound 处理轮次完成 星级序列刻度 卡牌序列刻度
118   -func HandleNextRound(player *DataCardHolder) {
  118 +func HandleNextRound(player *Player) {
119 119 player.Details.Round += 1
120 120 player.Details.Cards = make(map[int]int)
121 121 player.Details.Album = make(map[int]int)
122 122 }
123 123  
124 124 // GetInfo 玩家卡牌活动信息
125   -func GetInfo(player *DataCardHolder, conf *confcardholder.ActivityConfig) models.CardHolderInfo {
  125 +func GetInfo(player *Player, config *confcardholder.ActivityConfig) models.CardHolderInfo {
126 126 info := models.CardHolderInfo{
127 127 Cards: make(map[int]int),
128 128 Album: make(map[int]int),
... ... @@ -142,7 +142,7 @@ func GetInfo(player *DataCardHolder, conf *confcardholder.ActivityConfig) models
142 142 // DoOpen 封装的抽卡逻辑
143 143 // openMode:开包类型0客户端驱动1星星商店购买2剩余星星兑换
144 144 func DoOpen(gameId string,
145   - player *DataCardHolder,
  145 + player *Player,
146 146 config *confcardholder.ActivityConfig,
147 147 confCardholder confcardholder.OpenCardholderConfig,
148 148 sequenceId, cohort string,
... ... @@ -206,7 +206,7 @@ func DoOpen(gameId string,
206 206  
207 207 // DoOpenCheckAward 封装的新卡判断是否出发卡组和轮次奖励的逻辑
208 208 func DoOpenCheckAward(gameId string,
209   - player *DataCardHolder,
  209 + player *Player,
210 210 config *confcardholder.ActivityConfig,
211 211 sequenceId, cohort string,
212 212 newCards []int,
... ... @@ -270,7 +270,7 @@ func DoOpenCheckAward(gameId string,
270 270 }
271 271  
272 272 // CalculateStarCount 计算星星点数
273   -func CalculateStarCount(player *DataCardHolder, config *confcardholder.ActivityConfig) {
  273 +func CalculateStarCount(player *Player, config *confcardholder.ActivityConfig) {
274 274 starCount := 0
275 275 for cardId, cardCount := range player.Details.Cards {
276 276 if cardCount <= 1 {
... ... @@ -292,7 +292,7 @@ func CalculateStarCount(player *DataCardHolder, config *confcardholder.ActivityC
292 292 }
293 293  
294 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 296 enough = false
297 297 cardList = make(map[int]int)
298 298 starAmount := 0
... ... @@ -361,7 +361,7 @@ func GetStarCardList(player *DataCardHolder, config *confcardholder.ActivityConf
361 361 }
362 362  
363 363 // NextActivityAutoExchange 活动切换时自动兑换卡包
364   -func NextActivityAutoExchange(gameId string, player *DataCardHolder, config *confcardholder.ActivityConfig) {
  364 +func NextActivityAutoExchange(gameId string, player *Player, config *confcardholder.ActivityConfig) {
365 365 starCount := player.Details.LastStarCount
366 366 // 把星星的配置按照需要的星星数降序排列
367 367 list := lo.Values[int, confcardholder.StarShopConfig](config.StarShopConfig)
... ...
service/cardholder/player.go
... ... @@ -8,26 +8,26 @@ import (
8 8 )
9 9  
10 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 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 24 if has {
25   - d.Decode()
  25 + player.Decode()
26 26 } else {
27   - d.Init(playerUid)
28   - err = svmysql.Create(d, gameId)
  27 + player.Init(playerUid)
  28 + err = svmysql.Create(player, gameId)
29 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 31 return
32 32 }
33 33 }
... ... @@ -35,24 +35,24 @@ func _LoadPlayer(gameId string, playerUid int64) (d *DataCardHolder) {
35 35 }
36 36  
37 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 39 configId := config.Id
40   - d = _LoadPlayer(gameId, playerUid)
  40 + player = _LoadPlayer(gameId, playerUid)
41 41 // 如果当前有上线活动(活动ID不为0),且活动ID和玩家数据不同,说明活动已切换 需更新
42 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 57 return
58 58 }
... ...
service/init.go
... ... @@ -12,14 +12,14 @@ func Init() {
12 12 // create table
13 13 // 卡牌卡包
14 14 for _, gameId := range svconst.GameListCardHolder {
15   - svmysql.InitTable(new(cardholder.DataCardHolder), gameId, true)
  15 + svmysql.InitTable(new(cardholder.Player), gameId, true)
16 16 svmysql.InitTable(new(cardholder.RecordCardHolderOpen), gameId, true)
17 17 svmysql.InitTable(new(cardholder.RecordCardHolderRewardAlbum), gameId, true)
18 18 svmysql.InitTable(new(cardholder.RecordCardHolderRewardRound), gameId, true)
19 19 }
20   - // 卡牌卡包
  20 + // 房间排行
21 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 @@
  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 4 "apigame/service-common/svconst"
5 5 "apigame/service-common/svmysql"
6 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 12 Uid int64 `gorm:"column:uid;primaryKey;comment:玩家唯一ID"`
12 13 ActivityId int64 `gorm:"comment:活动ID"`
13 14  
... ... @@ -17,26 +18,48 @@ type DataRoomRankPlayer struct {
17 18  
18 19 RoomUid int64 `gorm:"comment:所在房间唯一ID"`
19 20  
  21 + SettleHas bool `gorm:"comment:有结算内容未领取"`
  22 + SettleAward string `gorm:"comment:结算奖励内容"`
  23 +
20 24 CreateTime int64 `gorm:"comment:创建时间戳"`
21 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 29 tableName := svconst.MYSQL_TABLE_S_ROOMRANK_PLAYER
26 30 return &svmysql.MysqlInfo{
27 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 38 Uid: uid,
35 39 }
36 40 return d
37 41 }
38 42  
39   -func (d *DataRoomRankPlayer) Init(uid int64) {
  43 +func (d *Player) Init(uid int64) {
40 44 d.Uid = uid
41 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 3 import (
4 4 "apigame/service-common/svconst"
5 5 "apigame/service-common/svmysql"
  6 + "apigame/util/util-lx/lxalilog"
  7 + "apigame/util/util-lx/lxtime"
  8 + "encoding/json"
6 9 "fmt"
  10 + "github.com/samber/lo"
7 11 )
8 12  
9   -// DataRoomRankRoom 房间排行持久数据
10   -type DataRoomRankRoom struct {
  13 +// Room 房间排行持久数据
  14 +type Room struct {
11 15 Id int64 `gorm:"column:id;primaryKey;comment:房间唯一ID"`
12   - Uid int64 `gorm:"comment:玩家唯一ID"`
13 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 24 CreateTime int64 `gorm:"comment:创建时间戳"`
16 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 29 tableName := svconst.MYSQL_TABLE_S_ROOMRANK_ROOM
21 30 return &svmysql.MysqlInfo{
22 31 DbMysql: svconst.DbCommon,
23 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 27 code = code_msg.RECODE_OK
28 28 gameId := req.GameID
29 29 playerUid := req.UID
  30 + playerLevel := req.PlayerLevel
30 31  
31 32 // 尝试更新配置
32 33 config, hasConfig := confroomrank.GetCurrent(gameId)
33 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 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 54 rsp.RoomRankInfo = GetInfo(player, config)
57 55  
... ...
service/roomrank/logic.go
1 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 9 )
10 10  
11 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 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 18 return
19 19 }
20 20 }
21 21  
22 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 26 if has {
27 27 } else {
28   - d.Init(playerUid)
29   - err = svmysql.Create(d, gameId)
  28 + player.Init(playerUid)
  29 + err = svmysql.Create(player, gameId)
30 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 32 return
33 33 }
34 34 }
... ... @@ -36,7 +36,11 @@ func LoadPlayer(gameId string, playerUid int64) (d *DataRoomRankPlayer) {
36 36 }
37 37  
38 38 // GetInfo 活动信息
39   -func GetInfo(player *DataRoomRankPlayer, conf *confroomrank.ActivityConfig) models.RoomRankInfo {
  39 +func GetInfo(player *Player, conf *confroomrank.ActivityConfig) models.RoomRankInfo {
40 40 info := models.RoomRankInfo{}
  41 + if player.SettleHas {
  42 + info.SettleHas = player.SettleHas
  43 + info.SettleAward = player.SettleAward
  44 + }
41 45 return info
42 46 }
... ...
service/roomrank/room.go
1 1 package roomrank
2 2  
3 3 import (
  4 + "apigame/configs/confroomrank"
4 5 "apigame/service-common/svmysql"
5 6 "apigame/util/util-lx/lxalilog"
6 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 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 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 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 37 var err error
32   - has, err = svmysql.First(d, gameId)
  38 + has, err = svmysql.First(room, gameId)
33 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 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 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 +}
... ...