Commit 5a78e911 authored by chenweijian's avatar chenweijian

user服

parent 79607c8d
Pipeline #1726 failed with stages
package event_s
import (
"errors"
"hilo-user/_const/enum/user_e"
"hilo-user/domain"
"hilo-user/domain/event/group_ev"
"hilo-user/domain/event/user_ev"
"hilo-user/domain/model/groupPower_m"
"hilo-user/domain/model/group_m"
"hilo-user/domain/model/user_m"
"hilo-user/domain/service/user_s"
"hilo-user/mycontext"
"hilo-user/req/jwt"
"hilo-user/resource/config"
"hilo-user/resource/mysql"
)
func EventInit() {
GroupInEvents()
GameEventInit()
GroupLeaveEvents()
ModelFuncInit()
}
// 用户进房事件
func GroupInEvents() {
group_ev.AddGroupInEventSync(func(model *domain.Model, event interface{}) error {
e, ok := event.(*group_ev.GroupInEvent)
if !ok {
model.Log.Errorf("AddGroupInEventSync event type err")
return nil
}
txGroupId, err := group_m.ToTxGroupId(model, e.GroupId)
if err != nil {
model.Log.Errorf("AddGroupInEventSync err:%v, imGroupId:%v", err, e.GroupId)
return nil
}
return user_s.NewGameService(mycontext.CreateMyContext(model.Cxt)).PushGameInfo("", e.ExternalId, txGroupId, 0)
})
}
// 用户退房事件
func GroupLeaveEvents() {
group_ev.AddGroupLeaveEventAsync(func(model *domain.Model, event interface{}) error {
e, ok := event.(*group_ev.GroupLeaveEvent)
if !ok || e == nil {
model.Log.Errorf("AddGroupLeaveEventAsync event type err")
return nil
}
txGroupId, err := group_m.ToTxGroupId(model, e.GroupId)
if err != nil {
model.Log.Errorf("ToTxGroupId fail:%v-%v", e.GroupId, err)
}
if err := user_s.NewGameService(model.MyContext).GameOpt(e.UserId, 0, "", e.ExternalId, "", "", txGroupId, user_e.GameOptExit, 0, false); err != nil {
model.Log.Warnf("AddGroupLeaveEventAsync GameOpt fail,e%v,err:%v", *e, err)
}
return nil
})
}
// 游戏上报事件
func GameEventInit() {
user_ev.AddReportGameInfoEventSync(func(model *domain.Model, event interface{}) error {
e, ok := event.(*user_ev.ReportGameInfoEvent)
if !ok {
model.Log.Errorf("AddReportGameInfoEventSync 消息类型错误!event:%+v", event)
return nil
}
switch e.ReportType {
case user_e.ReportTypeGameStart:
// 更新游戏信息
return user_s.NewGameService(model.MyContext).GameStart(e.GameStartObject)
//return user_m.GameStartUpdate(model, e.GameStartObject)
case user_e.ReportTypeGameSettle:
return user_s.NewGameService(model.MyContext).GameSettle(e.GameSettleObject)
}
return nil
})
}
func ModelFuncInit() {
group_m.GetGroupPowerNameByUserId = func(model *domain.Model, userId uint64) (uint64, string, error) {
return groupPower_m.GetUserGroupPower(model, userId)
}
// 编辑游戏-清理机器人
user_ev.AddGameEditEventAsync(func(model *domain.Model, event interface{}) error {
e, ok := event.(*user_ev.GameEditEvent)
if !ok {
return errors.New("GameEditEvent asset fail")
}
robots, err := user_m.GetRoomRobots(model, e.TxGroupId)
if err != nil {
model.Log.Errorf("GetRoomRobots fail:%v", err)
return err
}
model.Log.Infof("AddGameEditEventAsync event:%v,robots:%v", *e, robots)
var userIds []mysql.ID
for _, robot := range robots {
userIds = append(userIds, robot.UserId)
}
users, err := user_m.GetUserMapByIds(model, userIds)
if err != nil {
model.Log.Errorf("GetUserMapByIds fail:%v", err)
return err
}
userService := user_s.NewGameService(model.MyContext)
for i, robot := range robots {
user, ok := users[robot.UserId]
if !ok {
model.Log.Errorf("robot userId not exits:%v", robot)
continue
}
// filled
robots[i].GameOpt = userService.GameOpt // service func -> model func
robots[i].User = users[robot.UserId] // user info
robots[i].Token, _ = jwt.GenerateToken(user.ID, user.ExternalId,
config.GetConfigJWT().ISSUER_API) // jwt
// 离开
robots[i].Leave("GameEdit")
}
return nil
})
}
package event_s
import (
"encoding/json"
"golang.org/x/sync/errgroup"
"hilo-user/domain"
"hilo-user/domain/event/group_ev"
"hilo-user/domain/model/event_m"
"hilo-user/domain/service"
"hilo-user/mycontext"
"hilo-user/resource/mysql"
"runtime/debug"
)
// 每次处理500条
const BatchCount = 500
type GroupInEventService struct {
svc *service.Service
}
func NewGroupInEventService(myContext *mycontext.MyContext) *GroupInEventService {
svc := service.CreateService(myContext)
return &GroupInEventService{svc}
}
//
func (s *GroupInEventService) Consume() error {
defer func() {
if err := recover(); err != nil {
s.svc.Log.Errorf("ExceptionHandle GroupInEventService Consume SYSTEM ACTION PANIC: %v, stack: %v", err, string(debug.Stack()))
}
}()
var model = domain.CreateModel(s.svc.CtxAndDb)
events, offset, err := event_m.FetchEventGroupIn(model, BatchCount)
if err != nil {
return err
}
var wg errgroup.Group
for k := range events {
cpEvent := &event_m.EventGroupIn{
Entity: mysql.Entity{
ID: events[k].ID,
CreatedTime: events[k].CreatedTime,
UpdatedTime: events[k].UpdatedTime,
},
Proto: events[k].Proto,
Payload: events[k].Payload,
Mark: events[k].Mark,
}
wg.Go(func() error {
if cpEvent.Mark == mysql.YES {
model.Log.Warnf("already consume msg :%v", cpEvent)
return nil
}
groupInEvent := new(group_ev.GroupInEvent)
if err := json.Unmarshal(cpEvent.Payload, groupInEvent); err != nil {
model.Log.Errorf("json msg fail,event:%v,err:%v", cpEvent, err)
return nil
}
// 发布事件
if err := group_ev.PublishGroupInEvent(model, groupInEvent); err != nil {
model.Log.Errorf("PublishGroupInEvent,event:%v,err:%v", cpEvent, err)
return err
}
// 标记已经处理
cpEvent.Model = model
err = cpEvent.MarkDone()
if err != nil {
model.Log.Errorf("consume msg fail,event:%v,err:%v", cpEvent, err)
}
return err
})
}
err = wg.Wait()
if err != nil {
model.Log.Errorf("batch consume msg has fail,event,err:%v", err)
// 暂时先允许丢数据,继续mark offset
}
// 最后一次提交offset
if len(events) > 0 {
offset.MarkOffset = events[len(events)-1].ID
return offset.Persistence()
}
return nil
}
package event_s
import (
"encoding/json"
"golang.org/x/sync/errgroup"
"hilo-user/domain"
"hilo-user/domain/event/group_ev"
"hilo-user/domain/model/event_m"
"hilo-user/domain/service"
"hilo-user/mycontext"
"hilo-user/resource/mysql"
"runtime/debug"
)
type GroupLeaveEventService struct {
svc *service.Service
}
func NewGroupLeaveEventService(myContext *mycontext.MyContext) *GroupLeaveEventService {
svc := service.CreateService(myContext)
return &GroupLeaveEventService{svc}
}
//
func (s *GroupLeaveEventService) Consume() error {
defer func() {
if err := recover(); err != nil {
s.svc.Log.Errorf("ExceptionHandle GroupLeaveEventService Consume SYSTEM ACTION PANIC: %v, stack: %v", err, string(debug.Stack()))
}
}()
var model = domain.CreateModel(s.svc.CtxAndDb)
events, offset, err := event_m.FetchEventGroupLeave(model, BatchCount)
if err != nil {
return err
}
var wg errgroup.Group
for k := range events {
cpEvent := &event_m.EventGroupLeave{
Entity: mysql.Entity{
ID: events[k].ID,
CreatedTime: events[k].CreatedTime,
UpdatedTime: events[k].UpdatedTime,
},
Proto: events[k].Proto,
Payload: events[k].Payload,
Mark: events[k].Mark,
}
wg.Go(func() error {
if cpEvent.Mark == mysql.YES {
model.Log.Warnf("already consume msg :%v", cpEvent)
return nil
}
groupLeaveEvent := new(group_ev.GroupLeaveEvent)
if err := json.Unmarshal(cpEvent.Payload, groupLeaveEvent); err != nil {
model.Log.Errorf("json msg fail,event:%v,err:%v", cpEvent, err)
return nil
}
// 发布事件
if err := group_ev.PublishGroupLeaveEvent(model, groupLeaveEvent); err != nil {
model.Log.Errorf("PublishGroupLeaveEvent,event:%v,err:%v", cpEvent, err)
return err
}
// 标记已经处理
cpEvent.Model = model
err = cpEvent.MarkDone()
if err != nil {
model.Log.Errorf("consume msg fail,event:%v,err:%v", cpEvent, err)
}
return err
})
}
err = wg.Wait()
if err != nil {
model.Log.Errorf("batch consume msg has fail,event,err:%v", err)
// 暂时先允许丢数据,继续mark offset
}
// 最后一次提交offset
if len(events) > 0 {
offset.MarkOffset = events[len(events)-1].ID
return offset.Persistence()
}
return nil
}
package user_s
import (
"encoding/json"
"fmt"
"github.com/jinzhu/copier"
"hilo-user/_const/enum/diamond_e"
"hilo-user/_const/enum/group_e"
"hilo-user/_const/enum/user_e"
"hilo-user/common"
"hilo-user/cv/msg_cv"
"hilo-user/cv/user_cv"
"hilo-user/domain"
"hilo-user/domain/cache"
"hilo-user/domain/cache/user_c"
"hilo-user/domain/event/user_ev"
"hilo-user/domain/model/diamond_m"
"hilo-user/domain/model/group_m"
"hilo-user/domain/model/noble_m"
"hilo-user/domain/model/res_m"
"hilo-user/domain/model/user_m"
"hilo-user/domain/service"
"hilo-user/domain/service/group_s"
"hilo-user/mycontext"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/mylogrus"
"hilo-user/req/user_req"
"hilo-user/resource/config"
"hilo-user/resource/mysql"
"hilo-user/sdk/sud"
"hilo-user/sdk/tencentyun"
"math"
"sort"
"strconv"
"time"
)
type GameService struct {
svc *service.Service
}
func NewGameService(myContext *mycontext.MyContext) *GameService {
svc := service.CreateService(myContext)
return &GameService{svc}
}
// 生成App客户端code
// param userId 用户id
// condition
// 1.jwt生成,只带userId
// 2.入库
func (s *GameService) GenClientCode(userId mysql.ID, externalId mysql.Str) (string, error) {
var model = domain.CreateModelContext(s.svc.MyContext)
code, err := generateGameJwtToken(userId, externalId, config.GetConfigGameJWT().ISSUER_CLIENT)
if err != nil {
model.Log.Errorf("generateGameJwtToken fail:%v", err)
return "", err
}
err = s.svc.Transactional(func() error {
// todo 持久化
return nil
})
return code, err
}
// 生成游戏服务器用的ssToken
// return userId ssToken expireDateMs err
func (s *GameService) GetSsToken(code string) (mysql.ID, string, int64, error) {
var model = domain.CreateModelContext(s.svc.MyContext)
userId, externalId, expiresAt, err := ParseJwtToken(code, config.GetConfigGameJWT().ISSUER_CLIENT)
if err != nil {
model.Log.Errorf("ParseJwtToken fail:%v", err)
return userId, "", expiresAt, err
}
ssToken, err := generateGameJwtToken(userId, externalId, config.GetConfigGameJWT().ISSUER_SERVER)
if err != nil {
model.Log.Errorf("generateGameJwtToken fail:%v", err)
return userId, "", expiresAt, err
}
err = s.svc.Transactional(func() error {
// todo 持久化
return nil
})
return userId, ssToken, expiresAt, err
}
// 生成游戏服务器用的ssToken
// return userId ssToken expireDateMs err
func (s *GameService) UpdateSsToken(ssToken string) (mysql.ID, string, int64, error) {
var model = domain.CreateModelContext(s.svc.MyContext)
userId, externalId, expiresAt, err := ParseJwtToken(ssToken, config.GetConfigGameJWT().ISSUER_SERVER)
// err 不需要判断过期
if err != nil && err != bizerr.GameTokenExpire {
model.Log.Errorf("ParseJwtToken fail:%v", err)
return userId, "", expiresAt, err
}
newSsToken, err := generateGameJwtToken(userId, externalId, config.GetConfigGameJWT().ISSUER_SERVER)
if err != nil {
model.Log.Errorf("generateGameJwtToken fail:%v", err)
return userId, "", expiresAt, err
}
err = s.svc.Transactional(func() error {
// todo 持久化
return nil
})
return userId, newSsToken, expiresAt, err
}
// 游戏服务器信息上报
func (s *GameService) ReportGameInfo(userInfo user_req.ReportGameInfoReq) error {
model := domain.CreateModel(s.svc.CtxAndDb)
var (
userRoundId = ""
roomId = ""
)
reportMsg, err := json.Marshal(userInfo.ReportMsg)
if err != nil {
model.Log.Errorf("ReportGameInfo err:%v, userInfo:%v", err, userInfo)
return err
}
event := &user_ev.ReportGameInfoEvent{
ReportType: userInfo.ReportType,
}
if userInfo.ReportType == user_e.ReportTypeGameStart {
event.GameStartObject = new(user_ev.GameStartObject)
err = json.Unmarshal(reportMsg, event.GameStartObject)
if err != nil {
model.Log.Errorf("ReportGameInfo err:%v, userInfo:%v", err, userInfo)
return err
}
userRoundId = event.GameStartObject.GameRoundId
roomId = event.GameStartObject.RoomId
} else if userInfo.ReportType == user_e.ReportTypeGameSettle {
event.GameSettleObject = new(user_ev.GameSettleObject)
err = json.Unmarshal(reportMsg, event.GameSettleObject)
if err != nil {
model.Log.Errorf("ReportGameInfo err:%v, userInfo:%v", err, userInfo)
return err
}
userRoundId = event.GameSettleObject.GameRoundId
roomId = event.GameSettleObject.RoomId
}
// 持久化
err = user_m.SaveGameSdkReport(domain.CreateModelContext(s.svc.MyContext), userRoundId, roomId, string(userInfo.ReportType), string(reportMsg), userInfo.ExternalId, userInfo.SsToken)
if err != nil {
return err
}
return model.Transaction(func(model *domain.Model) error {
userId, err := user_c.ToUserId(model, userInfo.ExternalId)
if err != nil {
return err
}
event.UserId = userId
return user_ev.PublishReportGameInfoEvent(model, event)
})
}
func (s *GameService) GameAdd(userId mysql.ID, extId, code, lang string, para *user_m.GameAddParam) error {
var model = domain.CreateModelContext(s.svc.MyContext)
if !user_c.LockGame(model, para.TxGroupId) {
mylogrus.MyLog.Infof("GameAdd LockGame faild TxGroupId:%v", para.TxGroupId)
return bizerr.ReqTooFrequent
}
defer user_c.UnLockGame(model, para.TxGroupId)
info, err := group_m.GetByTxGroupId(model, para.TxGroupId)
if err != nil {
return myerr.WrapErr(err)
}
// 一个房间只能存在一个还未结束的游戏
// 房主/经理/管理员可以创建游戏,其它用户点击提示“仅房间管理可以创建游戏”
role, err := group_m.GetRoleInGroup(model, userId, info.ImGroupId)
if err != nil {
return err
}
if role < common.GROUP_ADMIN {
return bizerr.GameAddNoPermissions
}
// 在麦上才能创建游戏
micUser, err := group_m.GetMicUserByExternalId(model, extId)
if err != nil {
return err
}
if micUser == nil {
return bizerr.GameAddNotOnMic
}
mgId := ""
switch para.GameType {
case 1:
mgId = user_e.MgIdLudo
case 2:
mgId = user_e.MgIdUno
}
// 创建游戏
userInfo := &user_m.GameInfo{
MgId: mgId,
GameType: para.GameType,
Mode: int32(para.Mode),
Piece: int32(para.Piece),
OnOff1: uint8(para.OnOff1),
Diamond: para.Diamond,
CreateId: userId,
TxGroupId: info.TxGroupId,
AutoMatch: uint8(para.AutoMatch),
}
err = model.Transaction(func(model *domain.Model) error {
err = user_m.Add(model, userInfo)
if err != nil {
return myerr.WrapErr(bizerr.GameHaveNoEnd)
}
// 自己作为游戏成员加入游戏
err = user_m.SaveGamePlayer(model, &user_m.GamePlayer{GameId: userInfo.Id, UserId: userId, UserCode: code, ExternalId: extId, CreatedTime: time.Now(), SeatIdx: 0})
if err != nil {
model.Log.Errorf("CreateGame err:%v", err)
return myerr.WrapErr(bizerr.GameHaveNoEndGame)
}
if userInfo.Diamond > 0 {
// 扣费
diamondAccount, err := diamond_m.CheckEnoughDiamondFrozen(model, userId, mysql.Num(userInfo.Diamond))
if err != nil {
model.Log.Errorf("CreateGame err:%v", err)
return err
}
diamondAccountDetail, err := diamondAccount.ChangeDiamondAccountDetail(diamond_e.GameJoin, userInfo.Id, mysql.Num(userInfo.Diamond))
if err != nil {
model.Log.Errorf("CreateGame err:%v", err)
return err
}
err = diamondAccountDetail.Persistent()
if err != nil {
model.Log.Errorf("CreateGame err:%v", err)
return err
}
}
// 游戏相关操作
err = s.afterCreate(model, userInfo, para.GameCode, extId)
if err != nil {
model.Log.Errorf("CreateGame err:%v", err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("CreateGame err:%v", err)
return err
}
go s.SendGamePublicMsg(model, userId, info.TxGroupId, lang, userInfo.GameType, user_e.GameOptCreate)
go s.PushGameInfo("", extId, "", userInfo.Id)
return nil
}
func (s *GameService) afterCreate(model *domain.Model, userInfo *user_m.GameInfo, userCode, extId string) error {
// 清理房间游戏
err := sud.RoomClear(domain.CreateModelNil(), userInfo.MgId, sud.RoomClearReqData{RoomId: userInfo.TxGroupId})
if err != nil {
model.Log.Errorf("CreateGame err:%v", err)
return myerr.WrapErr(err)
}
mode := int32(0)
if userInfo.MgId == user_e.MgIdLudo {
mode = userInfo.Mode
}
// 加入游戏
err = sud.UserIn(model, userInfo.MgId, sud.UserInReqData{
Code: userCode,
RoomId: userInfo.TxGroupId,
Mode: mode,
Language: "zh-CN",
SeatIndex: -1,
})
// 设置游戏
if userInfo.MgId == user_e.MgIdLudo {
if err = sud.GameSetting(model, userInfo.MgId, sud.GameSettingReqData{
RoomId: userInfo.TxGroupId,
LudoRule: sud.LudoRule{Mode: int(userInfo.Mode), ChessNum: int(userInfo.Piece), Item: int(userInfo.OnOff1)},
}); err != nil {
model.Log.Errorf("CreateGame err:%v", err)
return myerr.WrapErr(err)
}
}
if err != nil {
model.Log.Errorf("CreateGame err:%v", err)
return myerr.WrapErr(err)
}
// 准备游戏
err = sud.UserReady(model, userInfo.MgId, sud.UserReadyReqData{ExternalId: extId, IsReady: true})
if err != nil {
model.Log.Errorf("CreateGame err:%v", err)
return myerr.WrapErr(err)
}
return nil
}
func (s *GameService) GameEdit(para *user_m.GameAddParam, userId uint64, extId, code string) error {
var model = domain.CreateModelContext(s.svc.MyContext)
// 查询游戏是否存在
userInfo, err := user_m.GetGameInfo(model, para.GameId, "", "", -1, -1)
if err != nil {
mylogrus.MyLog.Errorf("GameEdit err:%v", err)
return bizerr.InvalidParameter
}
if userInfo.Id == 0 {
mylogrus.MyLog.Errorf("GameEdit err:%v", err)
return bizerr.GameNotFound
}
// 加锁
if !user_c.LockGame(model, userInfo.TxGroupId) {
mylogrus.MyLog.Infof("GameEdit LockGame faild TxGroupId:%v", para.TxGroupId)
return bizerr.ReqTooFrequent
}
defer user_c.UnLockGame(model, userInfo.TxGroupId)
// 开始了不能编辑
if userInfo.BattleStartAt > 0 {
return bizerr.GameStart
}
// 钻石不能编辑
if userInfo.Diamond != para.Diamond {
return bizerr.GameDiamondCannotEdit
}
// 放入事务
err = model.Transaction(func(model *domain.Model) error {
// 编辑user
err = user_m.Edit(model, userInfo.Id, para)
if err != nil {
model.Log.Errorf("GameEdit err:%v", err)
return err
}
// 设置游戏
if userInfo.MgId == user_e.MgIdLudo {
if err = sud.GameSetting(domain.CreateModelNil(), userInfo.MgId, sud.GameSettingReqData{
RoomId: userInfo.TxGroupId,
LudoRule: sud.LudoRule{Mode: para.Mode, ChessNum: para.Piece, Item: para.OnOff1},
}); err != nil {
model.Log.Errorf("GameEdit err:%v", err)
return myerr.WrapErr(err)
}
}
return nil
})
//err = s.svc.Transactional(func() error {
// model := domain.CreateModelContext(s.svc.MyContext)
// // 编辑user
// err = user_m.Edit(model, userInfo.Id, para)
// if err != nil {
// model.Log.Errorf("GameEdit err:%v", err)
// return err
// }
// //// 钻石前后不一致
// //if userInfo.Diamond != para.Diamond {
// // // 所有用户退款
// // err = s.userRefund(model, userInfo)
// // if err != nil {
// // model.Log.Errorf("GameEdit err:%v", err)
// // return myerr.WrapErr(err)
// // }
// // if para.Diamond > 0 {
// // // 扣费
// // diamondAccount, err := diamond_m.CheckEnoughDiamondFrozen(model, userId, mysql.Num(para.Diamond))
// // if err != nil {
// // model.Log.Errorf("GameEdit err:%v", err)
// // return err
// // }
// // diamondAccountDetail, err := diamondAccount.ChangeDiamondAccountDetail(diamond_e.GameJoin, userInfo.Id, mysql.Num(para.Diamond))
// // if err != nil {
// // model.Log.Errorf("GameEdit err:%v", err)
// // return err
// // }
// // err = diamondAccountDetail.Persistent()
// // if err != nil {
// // model.Log.Errorf("GameEdit err:%v", err)
// // return err
// // }
// // }
// // // 编辑者重新加入游戏
// // err = user_m.SaveGamePlayer(model, &user_m.GamePlayer{GameId: userInfo.Id, UserId: userId, UserCode: code, ExternalId: extId, CreatedTime: time.Now()})
// // if err != nil {
// // model.Log.Errorf("GameEdit err:%v", err)
// // return err
// // }
// // // 游戏相关操作
// // userInfo.Mode, userInfo.Piece, userInfo.OnOff1 = int32(para.Mode), int32(para.Piece), uint8(para.OnOff1)
// // err = s.afterCreate(model, userInfo, para.GameCode, extId)
// // if err != nil {
// // model.Log.Errorf("CreateGame err:%v", err)
// // return err
// // }
// // // 发布事件
// // event := &user_ev.GameEditEvent{GameId: userInfo.Id, TxGroupId: userInfo.TxGroupId}
// // if err = user_ev.PublishGameEditEvent(model, event); err != nil {
// // model.Log.Errorf("PublishGameEditEvent,event:%v,err:%v", event, err)
// // return err
// // }
// //} else {
// // // 设置游戏
// // err = sud.GameSetting(domain.CreateModelNil(), userInfo.MgId, sud.GameSettingReqData{
// // RoomId: userInfo.TxGroupId,
// // LudoRule: sud.LudoRule{Mode: para.Mode, ChessNum: para.Piece, Item: para.OnOff1},
// // })
// //}
// // 设置游戏
// if userInfo.MgId == user_e.MgIdLudo {
// if err = sud.GameSetting(domain.CreateModelNil(), userInfo.MgId, sud.GameSettingReqData{
// RoomId: userInfo.TxGroupId,
// LudoRule: sud.LudoRule{Mode: para.Mode, ChessNum: para.Piece, Item: para.OnOff1},
// }); err != nil {
// model.Log.Errorf("GameEdit err:%v", err)
// return myerr.WrapErr(err)
// }
// }
// return nil
//})
go s.PushGameInfo("", "", "", userInfo.Id)
return nil
}
func (s *GameService) PushGameInfo(sourceExtId, targetExtId, txGroupId string, userId uint64) error {
defer common.CheckGoPanic()
var model = domain.CreateModelContext(s.svc.MyContext)
var userInfo *user_m.GameInfo
var err error
if userId > 0 {
userInfo, err = user_m.GetGameInfo(model, userId, "", "", -1, -1)
} else {
// 房间当前是否有未结束的游戏
userInfo, err = user_m.GetGamingInfo(model, txGroupId)
}
if err != nil {
model.Log.Errorf("PushGameInfo err:%v", err)
return err
}
if userInfo == nil || userInfo.Id == 0 {
return nil
}
// 获取玩家信息
userPlayers, err := user_m.GetGamePlayers(model, userInfo.Id)
if err != nil {
model.Log.Errorf("PushGameInfo err:%v", err)
return err
}
// 组装信令推送消息
var creatorExternalId string
playerMsg := make([]*user_cv.GamePlayerMsg, 0, len(userPlayers))
for _, v := range userPlayers {
tmp := &user_cv.GamePlayerMsg{Status: v.Status, IsEscaped: v.IsEscaped, SeatIdx: v.SeatIdx}
userTiny, err := user_c.GetUserTinyById(model, v.UserId)
if err != nil {
model.Log.Errorf("PushGameInfo err:%v", err)
return err
}
tmp.UserTiny = userTiny
playerMsg = append(playerMsg, tmp)
if v.UserId == userInfo.CreateId {
creatorExternalId = userTiny.ExternalId
}
}
msg := &user_cv.GameMsg{
GameId: userInfo.Id,
MgId: userInfo.MgId,
GameType: userInfo.GameType,
Mode: userInfo.Mode + 1, // 客户端那边是:1.quick 2.classic
Piece: userInfo.Piece,
OnOff1: userInfo.OnOff1,
Diamond: userInfo.Diamond,
Status: userInfo.Status,
AutoMatch: userInfo.AutoMatch,
ExternalId: creatorExternalId,
Players: playerMsg,
}
jsonMsg, err := json.Marshal(msg)
if err != nil {
model.Log.Errorf("PushGameInfo err:%v", err)
return err
}
msgId := group_e.GroupGameInfoLudo
if userInfo.MgId == user_e.MgIdUno {
msgId = group_e.GroupGameInfoUno
}
// 发送腾讯云信令
group_s.SendSignalMsg(model, "", userInfo.TxGroupId, group_m.GroupSystemMsg{
MsgId: msgId,
Source: sourceExtId,
Target: targetExtId,
Content: string(jsonMsg),
}, false)
return nil
}
func (s *GameService) GameOpt(userId, userId uint64, code, extId, lang, userCode, txGroupId string, opt user_e.GameOpt, seatIdx int8, isAi bool) (err error) {
var model = domain.CreateModelContext(s.svc.MyContext)
// log
go user_m.SaveGameOptLog(model, userId, userId, opt, txGroupId)
// 查询游戏是否存在
var userInfo *user_m.GameInfo
if opt == user_e.GameOptExit {
userInfo, err = user_m.GetGamingInfoByUserId(model, userId, txGroupId)
if err != nil {
return bizerr.InvalidParameter
}
if userInfo == nil {
return
}
} else {
userInfo, err = user_m.GetGameInfo(model, userId, "", "", -1, -1)
if err != nil {
return bizerr.InvalidParameter
}
}
if userInfo.Id == 0 {
model.Log.Errorf("GameOpt userInfo.Id = 0")
return bizerr.GameNotFound
}
// 玩家信息
userr, err := user_m.GetGamePlayer(model, userInfo.Id, userId)
if err != nil {
return err
}
switch opt {
case user_e.GameOptJoin:
err = s.joinGame(model, userr, userInfo, userId, code, extId, userCode, seatIdx, isAi)
if err != nil {
model.Log.Errorf("GameOpt joinGame err:%v", err)
return err
}
if !isAi { // 机器人没有加入腾讯云,发不了公屏
go s.SendGamePublicMsg(model, userId, userInfo.TxGroupId, lang, userInfo.GameType, user_e.GameOptJoin)
}
case user_e.GameOptExit:
if userInfo.Status == uint8(user_e.GameStatusNoStart) {
if userInfo.CreateId == userr.UserId {
err = s.OwnerGameClear(model, userInfo.Id)
if err != nil {
model.Log.Errorf("GameOpt err:%v", err)
return err
}
} else {
err = s.exitGame(model, userr, userInfo)
if err != nil {
model.Log.Errorf("GameOpt err:%v", err)
return err
}
}
} else if userInfo.Status == uint8(user_e.GameStatusGaming) && userr.IsAi != 1 { // 给sdk发退出游戏
err = sud.GameEnd(domain.CreateModelNil(), userInfo.MgId, sud.GameEndReqData{
RoomId: userInfo.TxGroupId, ExternalId: userr.ExternalId,
})
if err != nil {
model.Log.Errorf("GameOpt sud.GameEnd err:%v", err)
}
err = user_m.UpdateGamePlayerExit(model, userr.Id)
if err != nil {
model.Log.Errorf("GameOpt sud.GameEnd err:%v", err)
}
if userInfo.GameType == user_e.GameTypeUno {
// 如果只是剩下一个玩家,直接结束掉
if userPlayers, err := user_m.GetGamePlayers(model, userInfo.Id); err != nil {
model.Log.Errorf("GameOpt GetGamePlayers err:%v", err)
return err
} else {
var leftPlayer int
for _, player := range userPlayers {
if player.EndAt == 0 {
leftPlayer++
}
}
if leftPlayer <= 1 {
model.Log.Infof("GameOpt left player 1,roomClear:%v,players:%v", userInfo, userPlayers)
if err := sud.RoomClear(model, userInfo.MgId, sud.RoomClearReqData{RoomId: userInfo.TxGroupId}); err != nil {
model.Log.Infof("GameOpt RoomClear fail,user:%v:%v", *userInfo, err)
}
}
}
}
}
}
go s.PushGameInfo("", "", "", userInfo.Id)
return nil
}
func (s *GameService) joinGame(model *domain.Model, userr *user_m.GamePlayer, userInfo *user_m.GameInfo, userId uint64,
code, extId, userCode string, seatIdx int8, isAi bool) error {
if !isAi && userCode == "" {
model.Log.Errorf("joinGame err:%v", bizerr.InvalidParameter)
return bizerr.InvalidParameter
}
if userr.Id > 0 {
model.Log.Errorf("joinGame err:%v", bizerr.GameAlreadyJoin)
return bizerr.GameAlreadyJoin
}
if userInfo.Status != uint8(user_e.GameStatusNoStart) {
return bizerr.GameJoinFailed
}
// 在麦上才能加入游戏
micUser, err := group_m.GetMicUserByExternalId(model, extId)
if err != nil {
return err
}
if micUser == nil {
return bizerr.GameAddNotOnMic
}
if !user_c.LockGame(model, userInfo.TxGroupId) {
mylogrus.MyLog.Infof("joinGame LockGame faild TxGroupId:%v", userInfo.TxGroupId)
return bizerr.ReqTooFrequent
}
defer user_c.UnLockGame(model, userInfo.TxGroupId)
return model.Transaction(func(model *domain.Model) error {
var isAiInt uint8
if isAi {
isAiInt = 1
}
userInfoNew, err := user_m.GetGameInfo(model, userInfo.Id, "", "", -1, -1)
if err != nil {
return bizerr.InvalidParameter
}
if userInfoNew.Status != uint8(user_e.GameStatusNoStart) { // 游戏状态不对,不能加入
return bizerr.GameJoinFailed
}
if !isAi && userInfo.Diamond > 0 {
// 扣费
diamondAccount, err := diamond_m.CheckEnoughDiamondFrozen(model, userId, mysql.Num(userInfo.Diamond))
if err != nil {
model.Log.Errorf("joinGame err:%v", err)
return err
}
diamondAccountDetail, err := diamondAccount.ChangeDiamondAccountDetail(diamond_e.GameJoin, userInfo.Id, mysql.Num(userInfo.Diamond))
if err != nil {
model.Log.Errorf("joinGame err:%v", err)
return err
}
err = diamondAccountDetail.Persistent()
if err != nil {
model.Log.Errorf("joinGame err:%v", err)
return err
}
}
userr.GameId = userInfo.Id
userr.UserId = userId
userr.UserCode = code
userr.SeatIdx = seatIdx
userr.ExternalId = extId
userr.IsAi = isAiInt
userr.CreatedTime = time.Now()
// 保存游戏玩家信息
err = user_m.SaveGamePlayer(model, userr)
if err != nil {
mylogrus.MyLog.Infof("joinGame SaveGamePlayer faild:%v, err:%v", userr, err)
return bizerr.GameHaveNoEndGame
}
err = s.sendJoinToSDK(model, userr, userInfo, isAi, userCode, extId)
if err != nil {
model.Log.Errorf("joinGame err:%v", err)
return err
}
return nil
})
}
func (s *GameService) exitGame(model *domain.Model, userr *user_m.GamePlayer, userInfo *user_m.GameInfo) error {
lockKey := user_c.GetGameKey(userInfo.TxGroupId)
if !cache.TryLock(model, lockKey, time.Millisecond*150, time.Minute*5) {
mylogrus.MyLog.Infof("exitGame LockGame faild TxGroupId:%v", userInfo.TxGroupId)
return bizerr.ReqTooFrequent
}
defer cache.UnLock(model, lockKey)
//if !user_c.LockGame(model, userInfo.TxGroupId) {
// mylogrus.MyLog.Infof("exitGame LockGame faild TxGroupId:%v", userInfo.TxGroupId)
// return bizerr.ReqTooFrequent
//}
//defer user_c.UnLockGame(model, userInfo.TxGroupId)
return model.Transaction(func(model *domain.Model) error {
err := user_m.DelGamePlayer(model, userr.Id)
if err != nil {
model.Log.Errorf("GameOpt err:%v", err)
return err
}
// 玩家退费
err = s.userrRefund(model, userr, userInfo)
if err != nil {
model.Log.Errorf("GameOpt err:%v", err)
return err
}
// 判断游戏是否还有人
players, err := user_m.GetGamePlayers(model, userInfo.Id)
if err != nil {
model.Log.Errorf("GameOpt err:%v", err)
return err
}
// 是否都是机器人
allAi := true
for _, v := range players {
if v.IsAi != 1 {
allAi = false
break
}
}
if len(players) == 0 || allAi {
// 修改所有游戏玩家状态
err = user_m.GameCloseUpdatePlayer(model, userInfo)
if err != nil {
return err
}
err = sud.RoomClear(domain.CreateModelNil(), userInfo.MgId, sud.RoomClearReqData{
RoomId: userInfo.TxGroupId,
})
// 修改游戏状态
err = user_m.GameCloseUpdate(model, userInfo)
if err != nil {
return err
}
} else {
sud.UserReady(domain.CreateModelNil(), userInfo.MgId, sud.UserReadyReqData{
ExternalId: userr.ExternalId, IsReady: false,
})
//if err != nil {
// model.Log.Errorf("GameOpt err:%v", err)
// //return err
//}
sud.UserOut(domain.CreateModelNil(), userInfo.MgId, sud.UserOutReqData{
ExternalId: userr.ExternalId,
})
//if err != nil {
// model.Log.Errorf("GameOpt err:%v", err)
// //return err
//}
}
return nil
})
}
func (s *GameService) sendJoinToSDK(model *domain.Model, userr *user_m.GamePlayer, userInfo *user_m.GameInfo, isAi bool, userCode, extId string) (err error) {
if isAi {
user, err := user_c.GetUserTinyById(model, userr.UserId)
if err != nil {
model.Log.Errorf("sendJoinToSDK err:%v", err)
return err
}
gender := "male"
if user.Sex == 2 {
gender = "female"
}
return sud.AddAi(domain.CreateModelNil(), userInfo.MgId, sud.AiAddReqData{
RoomId: userInfo.TxGroupId,
AiPlayers: []sud.AiPlayer{{user.ExternalId, user.Avatar, user.Nick, gender}},
IsReady: 1,
})
}
mode := int32(0)
if userInfo.GameType == user_e.GameTypeLudo {
mode = userInfo.Mode
}
err = sud.UserIn(domain.CreateModelNil(), userInfo.MgId, sud.UserInReqData{
Code: userCode,
RoomId: userInfo.TxGroupId,
Mode: mode,
Language: "zh-CN",
SeatIndex: -1,
})
if err != nil {
model.Log.Errorf("sendJoinToSDK err:%v", err)
return myerr.WrapErr(bizerr.GameJoinFailed)
}
err = sud.UserReady(domain.CreateModelNil(), userInfo.MgId, sud.UserReadyReqData{
ExternalId: extId,
IsReady: true,
})
if err != nil {
model.Log.Errorf("sendJoinToSDK err:%v", err)
return myerr.WrapErr(bizerr.GameJoinFailed)
}
return nil
}
func (s *GameService) GameStart(userStart *user_ev.GameStartObject) error {
return s.svc.Transactional(func() error {
model := domain.CreateModel(s.svc.CtxAndDb)
return user_m.GameStartUpdate(model, userStart)
})
}
func (s *GameService) GameSettle(userSettle *user_ev.GameSettleObject) error {
model := domain.CreateModel(s.svc.CtxAndDb)
// 查询游戏
infoKey, err := strconv.Atoi(userSettle.ReportGameInfoKey)
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return myerr.WrapErr(bizerr.GameNotFound)
}
userInfo, err := user_m.GetGameInfo(model, uint64(infoKey), "", "", -1, 1)
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return myerr.WrapErr(bizerr.GameNotFound)
}
if userInfo.Id == 0 {
model.Log.Errorf("GameSettle err:%v, GameRoundId:%v", bizerr.GameNotFound, userSettle.GameRoundId)
return myerr.WrapErr(bizerr.GameNotFound)
}
err = model.Transaction(func(model *domain.Model) error {
// 计算排名奖励
userExtIds, winList, userSettle2, err := s.calcAwardDiamond(userSettle, userInfo)
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return err
}
userSettle = userSettle2
if userInfo.Diamond > 0 {
userMap, err := user_m.GetGamePlayersMap(model, userInfo.Id, userExtIds)
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return err
}
if userInfo.Status == 1 { // 避免多发
// 发奖励
err = s.sendAwardDiamond(model, userInfo, winList, userMap)
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return err
}
}
}
// 更新游戏信息、玩家信息
err = user_m.GameSettleUpdate(model, userSettle)
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return err
}
return nil
})
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return err
}
if userInfo.Status == 1 { // 因为sdk可能有多个settle上报过来,所以这里只处理游戏状态还没转变的
// 组装信令推送消息
model := domain.CreateModelContext(model.MyContext)
go s.userSettlePushMsg(model, userSettle, userInfo.TxGroupId, userInfo.CreateId, userInfo.GameType)
}
return nil
}
func (s *GameService) calcAwardDiamond(userSettle *user_ev.GameSettleObject, userInfo *user_m.GameInfo) ([]string,
[]*user_ev.PlayerResultObject, *user_ev.GameSettleObject, error) {
// 计算奖励
userExtIds := make([]string, 0)
allDiamond := float64(userInfo.Diamond) * float64(len(userSettle.Results))
winList := make([]*user_ev.PlayerResultObject, 0, len(userSettle.Results))
diamondMap := make(map[string]int64)
for _, v := range userSettle.Results {
userExtIds = append(userExtIds, v.Uid)
// 逃跑不算win
if v.IsEscaped != 1 {
tmpWin := new(user_ev.PlayerResultObject)
copier.Copy(tmpWin, &v)
tmpWin.LudoExtras = new(user_ev.LudoExtras)
json.Unmarshal([]byte(tmpWin.Extras), &tmpWin.LudoExtras)
winList = append(winList, tmpWin)
}
}
switch userInfo.GameType {
case user_e.GameTypeLudo:
// 排序:isWin -> score -> steps
sort.Slice(winList, func(i, j int) bool {
if winList[i].IsWin == 2 && winList[j].IsWin != 2 {
return true
}
if winList[i].Score > winList[j].Score {
return true
}
if winList[i].LudoExtras.Steps >= winList[j].LudoExtras.Steps {
return true
}
return false
})
if len(userSettle.Results) > 2 { // 游戏人数大于2人,2人获胜瓜分
for i, v := range winList {
switch i {
case 0:
v.Diamond = int64(math.Floor(allDiamond * 0.65))
case 1:
v.Diamond = int64(math.Floor(allDiamond * 0.30))
default:
v.Diamond = int64(userInfo.Diamond) * -1
}
diamondMap[v.Uid] = v.Diamond
}
} else {
for i, v := range winList {
if i == 0 {
v.Diamond = int64(math.Floor(allDiamond * 0.95))
} else {
v.Diamond = int64(userInfo.Diamond) * -1
}
diamondMap[v.Uid] = v.Diamond
}
}
case user_e.GameTypeUno:
// 排序:isWin -> score
sort.Slice(winList, func(i, j int) bool {
if winList[i].IsWin == 2 && winList[j].IsWin != 2 {
return true
}
return winList[i].Score > winList[j].Score
})
if len(winList) > 0 {
// 第一名获得游戏分成的95%,系统抽成5%
diamond := int64(math.Floor(allDiamond * 0.95))
winList[0].Diamond = diamond
diamondMap[winList[0].Uid] = diamond
}
}
// 给客户端的返回结果赋值
for i, v := range userSettle.Results {
if winDia, ok := diamondMap[v.Uid]; ok {
userSettle.Results[i].Diamond = winDia
if winDia > 0 {
userSettle.Results[i].IsWin = 2
}
} else {
userSettle.Results[i].Diamond = int64(userInfo.Diamond) * -1
}
}
return userExtIds, winList, userSettle, nil
}
func (s *GameService) sendAwardDiamond(model *domain.Model, userInfo *user_m.GameInfo, winList []*user_ev.PlayerResultObject, userMap map[string]*user_m.GamePlayer) error {
if userInfo.Status != uint8(user_e.GamerStatusGaming) {
return nil
}
for _, v := range winList {
if v.Diamond <= 0 || v.IsAi == 1 {
continue
}
player, ok := userMap[v.Uid]
if !ok {
mylogrus.MyLog.Errorf("sendAwardDiamond 找不到用户 extId:%v, userMap:%v", v.Uid, userMap)
continue
}
diamondAccount, err := diamond_m.GetDiamondAccountByUserId(model, player.UserId)
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return err
}
diamondAccountDetail, err := diamondAccount.ChangeDiamondAccountDetail(diamond_e.GameAward, userInfo.Id, mysql.Num(v.Diamond))
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return err
}
err = diamondAccountDetail.Persistent()
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return err
}
}
return nil
}
func (s *GameService) userSettlePushMsg(model *domain.Model, userSettle *user_ev.GameSettleObject, txGroupId string, createId uint64, userType user_e.GameType) {
defer common.CheckGoPanic()
if txGroupId == "" {
model.Log.Errorf("userSettlePushMsg txGroupId is null")
return
}
createExtId := ""
// 组装信令推送消息
playerMsg := make([]*user_cv.GameAwardPlayer, 0, len(userSettle.Results))
for _, v := range userSettle.Results {
tmp := &user_cv.GameAwardPlayer{Rank: v.Rank, IsWin: v.IsWin == 2, Diamond: v.Diamond}
userTiny, err := user_c.GetUserByExternalId(model, v.Uid)
if err != nil {
model.Log.Errorf("PushGameInfo err:%v,v:%v,userSettle:%v", err, v, *userSettle)
continue
}
tmp.UserTiny = userTiny
playerMsg = append(playerMsg, tmp)
if userTiny.ID == createId {
createExtId = userTiny.ExternalId
}
}
msg := &user_cv.GameAward{
OwnerId: createExtId,
Players: playerMsg,
}
jsonMsg, err := json.Marshal(msg)
if err != nil {
model.Log.Errorf("GameSettle err:%v", err)
return
}
//time.Sleep(time.Second * 2) // 延迟两秒,避免客户端棋子没有走完就弹结算
// 发送腾讯云信令
msgId := group_e.GroupGameSettleLudo
if userType == user_e.GameTypeUno {
msgId = group_e.GroupGameSettleUno
}
group_s.SendSignalMsg(model, "", txGroupId, group_m.GroupSystemMsg{
MsgId: msgId,
Content: string(jsonMsg),
}, false)
}
func (s *GameService) SendGamePublicMsg(model *domain.Model, userId uint64, txGroupId, lang string, userType user_e.GameType, opt user_e.GameOpt) error {
defer common.CheckGoPanic()
user, err := user_c.GetUserTinyById(model, userId)
if err != nil {
model.Log.Errorf("SendGamePublicMsg err:%v", err)
return err
}
nobleLevel, err := noble_m.GetNobleLevel(model.Db, userId)
if err != nil {
model.Log.Errorf("SendGamePublicMsg err:%v", err)
return err
}
// 公屏内容
userName := "Game"
switch userType {
case user_e.GameTypeLudo:
userName = "Ludo"
case user_e.GameTypeUno:
userName = "Uno"
}
msgTmp := "Take mic and create a user"
msgId := common.MSG_ID_GAME_CREATE
msgContent := msgTmp
if opt == user_e.GameOptJoin {
msgTmp = "I joined the %s"
msgId = common.MSG_ID_GAME_JOIN
msgContent = fmt.Sprintf(msgTmp, userName)
}
if resMul, _ := res_m.GetResMultiTextBy(model.Db, msgId, lang); resMul != nil {
msgContent = resMul.Content
if opt == user_e.GameOptJoin {
msgContent = fmt.Sprintf(resMul.Content, userName)
}
}
typeScreen := group_e.GameLudoPubMsg
if userType == user_e.GameTypeUno {
typeScreen = group_e.GameUnoPubMsg
}
msg := msg_cv.GamePublicMsg{CommonPublicMsg: msg_cv.CommonPublicMsg{Type: typeScreen, GameType: userType,
ExternalId: user.ExternalId, Nick: user.Nick, Avatar: user.Avatar, NobleLevel: nobleLevel},
Msg: msgContent}
body, err := json.Marshal(msg)
if err != nil {
return myerr.WrapErr(err)
}
//发送公屏消息,
u, err := tencentyun.SendCustomMsg(model.Log, txGroupId, &user.ExternalId, string(body), group_m.GetHiloUserInfo(domain.CreateModelContext(model.MyContext), user.ExternalId))
model.Log.Infof("SendGamePublicMsg result response.MsgSeq:%v, err:%v", u, err)
return err
}
func (s *GameService) GameQuickMatch(userId uint64, externalId string, userType user_e.GameType) (txGroupId, userCode string, err error) {
var model = domain.CreateModelContext(s.svc.MyContext)
txGroupId, err = user_m.GetGamingTxGroupId(model, userType)
if err != nil {
return "", "", myerr.WrapErr(err)
}
if txGroupId == "" {
// 获取自己房间的id
groupInfo, err := group_m.GetGroupInfoByOwner(model, userId)
if err != nil {
return "", "", myerr.WrapErr(err)
}
if groupInfo == nil { // 自己没有房间
return "", "", myerr.WrapErr(bizerr.GameHaveNoMyRoom)
}
txGroupId = groupInfo.TxGroupId
}
// 获取userCode
userCode, err = s.GenClientCode(userId, externalId)
if err != nil {
return "", "", myerr.WrapErr(err)
}
return
}
// 游戏房间主人清理
func (s *GameService) OwnerGameClear(model *domain.Model, userId uint64) error {
userInfo, err := user_m.GetGameInfo(model, userId, "", "", -1, -1)
if err != nil {
model.Log.Errorf("GameClear err:%v", err)
return myerr.WrapErr(err)
}
lockKey := user_c.GetGameKey(userInfo.TxGroupId)
if !cache.TryLock(model, lockKey, time.Millisecond*150, time.Minute*5) {
mylogrus.MyLog.Infof("OwnerGameClear LockGame faild TxGroupId:%v", userInfo.TxGroupId)
return bizerr.ReqTooFrequent
}
defer cache.UnLock(model, lockKey)
//if !user_c.LockGame(model, userInfo.TxGroupId) {
// mylogrus.MyLog.Infof("OwnerGameClear LockGame faild TxGroupId:%v", userInfo.TxGroupId)
// return bizerr.ReqTooFrequent
//}
//defer user_c.UnLockGame(model, userInfo.TxGroupId)
return model.Transaction(func(model *domain.Model) error {
// 修改游戏状态
err = user_m.GameCloseUpdate(model, userInfo)
if err != nil {
model.Log.Errorf("GameClear err:%v", err)
return err
}
// 用户退费
err = s.userRefund(model, userInfo)
if err != nil {
model.Log.Errorf("GameClear err:%v", err)
return myerr.WrapErr(err)
}
// 清理房间游戏
err = sud.RoomClear(domain.CreateModelNil(), userInfo.MgId, sud.RoomClearReqData{RoomId: userInfo.TxGroupId})
if err != nil {
model.Log.Errorf("GameClear err:%v", err)
return myerr.WrapErr(err)
}
return nil
})
}
// 游戏房间清理,所有人踢出游戏,退钻,游戏置为结束;拿到房间锁之后才能调用该方法
func (s *GameService) GameClear(model *domain.Model, userId uint64) error {
userInfo, err := user_m.GetGameInfo(model, userId, "", "", -1, -1)
if err != nil {
model.Log.Errorf("GameClear err:%v", err)
return myerr.WrapErr(err)
}
// 用户退费
err = s.userRefund(model, userInfo)
if err != nil {
model.Log.Errorf("GameClear err:%v", err)
return myerr.WrapErr(err)
}
// 修改游戏状态
err = user_m.GameCloseUpdate(model, userInfo)
if err != nil {
model.Log.Errorf("GameClear err:%v", err)
return err
}
// 清理房间游戏
err = sud.RoomClear(domain.CreateModelNil(), userInfo.MgId, sud.RoomClearReqData{RoomId: userInfo.TxGroupId})
if err != nil {
model.Log.Errorf("GameClear err:%v", err)
return myerr.WrapErr(err)
}
go s.PushGameInfo("", "", "", userInfo.Id)
return nil
}
// 游戏房间玩家退钻
func (s *GameService) userRefund(model *domain.Model, userInfo *user_m.GameInfo) (err error) {
var players []*user_m.GamePlayer
if userInfo.Diamond > 0 {
players, err = user_m.GetGamePlayers(model, userInfo.Id)
if err != nil {
model.Log.Errorf("GameRefund err:%v", err)
return myerr.WrapErr(err)
}
}
err = user_m.DelGamePlayers(model, userInfo.Id)
if err != nil {
model.Log.Errorf("GameRefund err:%v", err)
return myerr.WrapErr(err)
}
if userInfo.Diamond <= 0 {
return nil
}
if userInfo.Diamond > 0 {
for _, v := range players {
err = s.userrRefund(model, v, userInfo)
if err != nil {
model.Log.Errorf("GameRefund err:%v", err)
return err
}
}
}
return nil
}
// 游戏房间玩家退钻
func (s *GameService) userrRefund(model *domain.Model, userr *user_m.GamePlayer, userInfo *user_m.GameInfo) error {
if userr.UserId <= 0 || userr.IsAi == 1 || userInfo.Diamond <= 0 {
return nil
}
// 退费
diamondAccount, err := diamond_m.GetDiamondAccountByUserId(model, userr.UserId)
if err != nil {
model.Log.Errorf("GameRefund err:%v", err)
return err
}
diamondAccountDetail, err := diamondAccount.ChangeDiamondAccountDetail(diamond_e.GameRefund, userInfo.Id, mysql.Num(userInfo.Diamond))
if err != nil {
model.Log.Errorf("GameRefund err:%v", err)
return err
}
err = diamondAccountDetail.Persistent()
if err != nil {
model.Log.Errorf("GameRefund err:%v", err)
return err
}
return nil
}
package user_s
import (
"github.com/dgrijalva/jwt-go"
"hilo-user/myerr"
"hilo-user/myerr/bizerr"
"hilo-user/resource/config"
"hilo-user/resource/mysql"
"time"
)
// 载荷,增加用户别名
type Claims struct {
UserId uint64
ExternalId string
jwt.StandardClaims
}
// 生成App用的jwt token
// issuer 外面传
func generateGameJwtToken(userId uint64, externalId string, issuer string) (string, error) {
jwtConfig := config.GetConfigGameJWT()
duration, err := time.ParseDuration(jwtConfig.EXPIRE)
if err != nil {
return "", myerr.WrapErr(err)
}
expireTime := time.Now().Add(duration)
claims := Claims{
UserId: userId,
ExternalId: externalId,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expireTime.UnixNano() / 1e6, //过期时间
Issuer: issuer, //签名的发行者
},
}
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := tokenClaims.SignedString(getGameJWTSecret())
return token, myerr.WrapErr(err)
}
//解析jwt token
func ParseJwtToken(token, issuer string) (userId mysql.ID, externalId string, expiresAt int64, err error) {
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return getGameJWTSecret(), nil
})
if err != nil {
return
}
if tokenClaims != nil {
claims, ok := tokenClaims.Claims.(*Claims)
if ok && tokenClaims.Valid {
if time.Now().Unix() > claims.ExpiresAt {
err = bizerr.GameTokenExpire
return
}
if claims.Issuer != issuer {
err = bizerr.GameTokenInvalid
return
}
// success
userId, externalId, expiresAt = claims.UserId, claims.ExternalId, claims.ExpiresAt
}
} else {
err = bizerr.GameTokenInvalid
}
return
}
func getGameJWTSecret() []byte {
return []byte(config.GetConfigGameJWT().SECRET)
}
package group_s
import (
"encoding/json"
"github.com/sirupsen/logrus"
"hilo-user/domain"
"hilo-user/domain/model/group_m"
"hilo-user/sdk/tencentyun"
"runtime/debug"
)
// 发送群信令。入参是内部imGroupId,这里做转换
func SendSignalMsg(model *domain.Model, imGroupId, txGroupId string, msg group_m.GroupSystemMsg, async bool) {
model.Log.WithField("imGroupId:", imGroupId)
model.Log.WithField("txGroupId:", txGroupId)
groupId := txGroupId
var err error
if len(groupId) == 0 {
groupId, err = group_m.ToTxGroupId(model, imGroupId)
if err != nil {
return
}
}
buffer, err := json.Marshal(msg)
if err == nil {
str := string(buffer)
model.Log.Infof("SendSignalMsg: %s, async = %v", str, async)
if async {
go func(logger *logrus.Entry) {
defer func() {
if r := recover(); r != nil {
//打印错误堆栈信息
logger.Errorf("SendSignalMsg SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
}
}()
if err = tencentyun.SendSystemMsg(logger, groupId, []string{}, str); err != nil {
logger.Errorf("SendSignalMsg aync failed for %s, msgId = %d, context:%v, err:%v", groupId, msg.MsgId, str, err)
} else {
logger.Infof("SendSignalMsg aync success for %s, msgId = %d, context:%v, err:%v", groupId, msg.MsgId, str)
}
}(model.Log)
} else if err = tencentyun.SendSystemMsg(model.Log, groupId, []string{}, str); err != nil {
model.Log.Errorf("SendSignalMsg sync failed for %s, msgId = %d, context:%v, err:%v", groupId, msg.MsgId, str, err)
} else {
model.Log.Infof("SendSignalMsg sync success for %s, msgId = %d, context:%v", groupId, msg.MsgId, str)
}
} else {
model.Log.Errorln("Marshall failure, msgId = %d : %s", msg.MsgId, err.Error())
}
}
......@@ -11,8 +11,8 @@ import (
)
const (
RegisterName = "hiloGame"
RegisterTag = "游戏中心"
RegisterName = "hiloUser"
RegisterTag = "用户中心"
)
// 异步注册到consul
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment