package frame import ( "encoding/json" "fmt" "time" "bet24.com/log" coreservice "bet24.com/servers/coreservice/client" "bet24.com/servers/insecureframe/gate" "bet24.com/servers/insecureframe/message" activityservice "bet24.com/servers/micros/activityservice/proto" audioroom "bet24.com/servers/micros/audioroom/proto" _ "bet24.com/servers/micros/ladderservice/proto" notification "bet24.com/servers/micros/notification/proto" privateroom "bet24.com/servers/micros/privateroom/proto" task "bet24.com/servers/micros/task/proto" userservices "bet24.com/servers/micros/userservices/proto" "bet24.com/servers/transaction" "bet24.com/servers/user" ) func (t *ThreadsafeTable) GetTableID() int { return t.tableId } func (t *ThreadsafeTable) IsPrivate() bool { return t.isPrivate() } func (t *ThreadsafeTable) GetRoomNo() int { return t.roomNo } func (t *ThreadsafeTable) GetOwner() int { return t.owner } // 游戏准备好后,即可调用框架StartGame进行场景广播 func (t *ThreadsafeTable) StartGame() { if t.tableStatus != TableStatus_Free { log.Release("ThreadsafeTable.StartGame not free status") return } t.startTime = time.Now().Unix() var userIds []int // 将所有用户状态改变 for i := 0; i < t.chairCount; i++ { if t.users[i] == -1 { continue } usr := gate.GetUserInfo(t.users[i]) if usr == nil || !usr.IsPlayer() { continue } gameFrame.setUserStatus(t.users[i], user.UserStatus_Play) userIds = append(userIds, usr.GetUserId()) } t.tableStatus = TableStatus_Playing // 广播场景 t.broadcastScene() if t.isPrivate() { go privateroom.SetRoomStatus(t.roomNo, privateroom.PrivateRoomStatus_Playing) } // 潜在好友 go func(users []int) { reason := fmt.Sprintf("play %s", gameFrame.GetGameName()) for i := 0; i < len(users)-1; i++ { for j := i + 1; j < len(users); j++ { coreservice.FriendAddPotential(users[i], users[j], reason) coreservice.FriendAddPotential(users[j], users[i], reason) } } }(userIds) } // 游戏结算后,调用 func (t *ThreadsafeTable) EndGame() { if t.tableStatus != TableStatus_Playing { log.Debug("ThreadsafeTable.EndGame not playing status") return } // 将所有用户状态改变 for i := 0; i < t.chairCount; i++ { if t.users[i] == -1 { continue } usr := gate.GetUserInfo(t.users[i]) if usr == nil { // t.users[i] = -1 continue } // 如果玩家得状态是准备,就不处理了 if usr.GetUserStatus() == user.UserStatus_Ready { // 模拟发个准备 go t.onUserReady(t.users[i], i, true) continue } gameFrame.setUserStatus(t.users[i], user.UserStatus_Sit) } t.tableStatus = TableStatus_Free gameFrame.removeOfflineByTableId(t.tableId) t.broadcastData(message.Table_GameEnd, "") if t.isPrivate() { go privateroom.SetRoomStatus(t.roomNo, privateroom.PrivateRoomStatus_Ended) } } func (t *ThreadsafeTable) MultiSetStart() { t.multiSetStatus = MultiSetStatus_Playing } func (t *ThreadsafeTable) MultiSetEnd() { t.multiSetStatus = MultiSetStatus_Free } func (t *ThreadsafeTable) GetUserByChair(chairId int) *user.UserInfo { if chairId < 0 || chairId >= len(t.users) { log.Debug("ThreadsafeTable.GetUserByChair %d not in %d", chairId, len(t.users)) return nil } if t.users[chairId] == -1 { //log.Debug("ThreadsafeTable.GetUserByChair chair %d have no user", chairId) return nil } usr := t.getPlayer(t.users[chairId]) if usr == nil { log.Debug("ThreadsafeTable.GetUserByChair chair %d user not exist", chairId) t.users[chairId] = -1 return nil } return usr } // 踢人,fource表示就算玩家状态为Playing也踢走 func (t *ThreadsafeTable) KickUser(userIndex int32, force bool) bool { for i := 0; i < t.chairCount; i++ { if t.users[i] == userIndex { return t.KickUserByChair(i, force) } } return false } func (t *ThreadsafeTable) KickUserByChair(chairId int, force bool) bool { usr := t.GetUserByChair(chairId) if usr == nil { return false } if !force && usr.GetUserStatus() == user.UserStatus_Play { log.Debug("ThreadsafeTable.KickUserByChair user is playing") return false } userIndex := usr.GetUserIndex() t.RemoveUser_safe(userIndex, !usr.IsRobot(), false) if force { gate.KickUser(userIndex) } return true } func (t *ThreadsafeTable) SendGameData(userIndex int32, msg, data string) { if userIndex == -1 { t.broadcastData(msg, data) return } // 检查userIndex是否有效 for i := 0; i < t.chairCount; i++ { if t.users[i] == userIndex { gate.SendMessage(userIndex, msg, data) return } } for _, v := range t.watchUsers { if v.UserIndex == userIndex { gate.SendMessage(userIndex, msg, data) return } } log.Debug("ThreadsafeTable.SendGameData userIndex[%d][%s] not in table", userIndex, msg) } func (t *ThreadsafeTable) SendGameDataToChair(chairId int, msg, data string) { if chairId == -1 { t.broadcastData(msg, data) return } usr := t.GetUserByChair(chairId) if usr == nil { return } t.sendData(usr.GetUserIndex(), msg, data) } func (t *ThreadsafeTable) BroadcastToWatcher(msg, data string) { for _, v := range t.watchUsers { t.sendData(v.UserIndex, msg, data) } } func (t *ThreadsafeTable) GetPlayer(userIndex int32) *user.UserInfo { for i := 0; i < t.chairCount; i++ { if t.users[i] == userIndex { ret := gate.GetUserInfo(userIndex) if ret == nil { ret = gameFrame.getOfflineUser(userIndex) } return ret } } return nil } func (t *ThreadsafeTable) getPlayer(userIndex int32) *user.UserInfo { return t.GetPlayer(userIndex) } func (t *ThreadsafeTable) GetUserByUserId(userId int) *user.UserInfo { return gate.GetUserByUserId(userId) } func (t *ThreadsafeTable) GetPlayerByUserId(userId int) *user.UserInfo { for i := 0; i < t.chairCount; i++ { if t.users[i] == -1 { continue } usr := t.getPlayer(t.users[i]) if usr == nil { continue } if usr.GetUserId() == userId { return usr } } return nil } func (t *ThreadsafeTable) GetUser(userIndex int32) (*user.UserInfo, bool) { usr := t.GetPlayer(userIndex) if usr != nil { return usr, true } // 旁观列表 for _, v := range t.watchUsers { if v.UserIndex == userIndex { return gate.GetUserInfo(userIndex), false } } return nil, false } func (t *ThreadsafeTable) NotifySceneChanged(chairId int) { if chairId == -1 { t.broadcastScene() return } if !t.sendGameScene(chairId) { log.Debug("ThreadsafeTable NotifySceneChanged chairId[%d] is empty", chairId) } } func (t *ThreadsafeTable) onUserReady(userIndex int32, chairId int, isReady bool) { if isReady { t.tableSink.OnUserReady(userIndex, chairId) } else { t.tableSink.OnUserCancelReady(userIndex, chairId) } } func (t *ThreadsafeTable) WriteUserMoney(userId int, amount, tax int, status, scoreType int, sourceName string) (bool, int) { if scoreType < 100 { scoreType += gameFrame.gameSink.GetGameID() * 100 } ret, amount := gate.WriteUserMoney(userId, amount, tax, status, scoreType, sourceName, gameFrame.gameSink.IsChipRoom()) return ret, amount } func (t *ThreadsafeTable) WriteUserMoneyWithModifyAmount(userId int, amount, tax int, status, scoreType int, sourceName string) int { if scoreType < 100 { scoreType += gameFrame.gameSink.GetGameID() * 100 } return gate.WriteUserMoneyWithModifyAmount(userId, amount, tax, status, scoreType, sourceName, gameFrame.gameSink.IsChipRoom()) } func (t *ThreadsafeTable) WriteBetRecordWithPlayTime(userId int, betAmount int, winAmount int, winRate float64, betDesc string, resultDesc string, roomName string, secsBefore int) { //log.Debug("ThreadsafeTable.WriteBetRecordWithPlayTime[%d]", userId) // 机器人不写分 usr := t.GetUserByUserId(userId) if usr != nil && usr.IsRobot() { log.Debug("ThreadsafeTable.WriteBetRecordWithPlayTime[%d] robot return", userId) return } t.writeBetRecordWithPlayTime(userId, betAmount, winAmount, winRate, betDesc, resultDesc, roomName, secsBefore) } func (t *ThreadsafeTable) delayReportUserBet() { t.reportUserBetsTimer = nil if len(t.tmpUserBets) == 0 { return } log.Debug("ThreadsafeTable.delayReportUserBet owner[%d] roomNo[%d] %v", t.owner, t.roomNo, t.tmpUserBets) audioroom.ReportUserBet(t.owner, t.roomNo, gameFrame.gameSink.GetGameID(), gameFrame.gameSink.GetRoomName(), t.tmpUserBets, gameFrame.IsChipRoom()) t.tmpUserBets = []audioroom.UserBet{} } func (t *ThreadsafeTable) writeBetRecordWithPlayTime(userId int, betAmount int, winAmount int, winRate float64, betDesc string, resultDesc string, roomName string, secsBefore int) { gameId := gameFrame.gameSink.GetGameID() if gameFrame.gameSink.IsChipRoom() { transaction.WriteChipBetRecordAction(userId, gameId, "", betAmount, winAmount, 0, winRate, betDesc, resultDesc, secsBefore, "", roomName) } else { transaction.WriteBetRecordAction(userId, gameId, "", betAmount, winAmount, 0, winRate, betDesc, resultDesc, secsBefore, "", roomName) } go func() { if t.isMatch() { // 在比赛模块中完成任务 //coreservice.DoTaskAction(userId, task.TaskAction_playmatch, 1, task.TaskScope{GameName: gameFrame.gameSink.GetGameName()}) } else { task.DoTaskAction(userId, task.TaskAction_playgame, 1, task.TaskScope{GameName: gameFrame.gameSink.GetGameName()}) task.DoTaskAction(userId, task.TaskAction_fire, betAmount, task.TaskScope{GameName: gameFrame.gameSink.GetGameName()}) if winAmount-betAmount > 0 { task.DoTaskAction(userId, task.TaskAction_earn, winAmount-betAmount, task.TaskScope{GameName: gameFrame.gameSink.GetGameName()}) task.DoTaskAction(userId, task.TaskAction_wingame, 1, task.TaskScope{GameName: gameFrame.gameSink.GetGameName()}) } if winAmount > 0 { task.DoTaskAction(userId, task.TaskAction_betWin, winAmount, task.TaskScope{GameName: gameFrame.gameSink.GetGameName()}) } } if !gameFrame.gameSink.IsChipRoom() { notification.AddNotification(userId, notification.Notification_Gold, "") //coreservice.AddGameExp(userId, gameId, winAmount-betAmount) coreservice.AddUserWinScore(userId, winAmount-betAmount) score := winAmount - betAmount if score < 0 { score = -score } if score > 0 { activityservice.TriggerSavingPot(userId, gameFrame.gameSink.GetGameID(), score) } } // 如果是语聊房游戏,存储并上报投注日志 if t.GetOwner() > 0 && gameFrame.gameSink.GetChairCount() < 2 { t.tmpUserBets = append(t.tmpUserBets, audioroom.UserBet{ UserId: userId, TotalBet: betAmount, TotalWin: winAmount, }) if t.reportUserBetsTimer == nil { t.reportUserBetsTimer = time.AfterFunc(2*time.Second, t.delayReportUserBet) } } if gameFrame.IsLadderRoom() { //ladderservice.AddUserLadderScore(userId, gameId, roomName, winAmount-betAmount) } }() } func (t *ThreadsafeTable) WriteBetRecord(userId int, betAmount int, winAmount int, winRate float64, betDesc string, resultDesc string, roomName string) { // 机器人不写分 usr := t.GetUserByUserId(userId) if usr != nil && usr.IsRobot() { return } secsBefore := int(time.Now().Unix() - t.startTime) t.writeBetRecordWithPlayTime(userId, betAmount, winAmount, winRate, betDesc, resultDesc, roomName, secsBefore) } func (t *ThreadsafeTable) WriteBetRecordWithSetcount(userId int, betAmount int, winAmount int, winRate float64, betDesc string, resultDesc string, roomName string, setCount int) { usr := t.GetUserByUserId(userId) if usr != nil && usr.IsRobot() { return } secsBefore := int(time.Now().Unix() - t.startTime) t.writeBetRecordWithPlayTime(userId, betAmount, winAmount, winRate, betDesc, resultDesc, roomName, secsBefore) go transaction.WriteBetRecordSetCount(userId, gameFrame.gameSink.GetGameID(), secsBefore, setCount) } func (t *ThreadsafeTable) FinishGame(userId int, baseScore, gameType, playerCount int) { if gameFrame.gameSink.IsChipRoom() { return } usr := t.GetPlayerByUserId(userId) if usr == nil || usr.IsRobot() { return } go coreservice.TriggerCouponTask(userId, gameFrame.gameSink.GetGameID(), baseScore, gameType, playerCount) } func (t *ThreadsafeTable) GetTableStatus() int { return t.tableStatus } func (t *ThreadsafeTable) IsPlaying() bool { return t.tableStatus == TableStatus_Playing } func (t *ThreadsafeTable) IsMultiSetPlaying() bool { return t.multiSetStatus == MultiSetStatus_Playing } func (t *ThreadsafeTable) RequestADAward(userIndex int32, losingAmount int) { if gameFrame.gameSink.IsChipRoom() { return } if losingAmount >= 0 { log.Debug("ThreadsafeTable.RequestADAward %d not losing %d", userIndex, losingAmount) return } usr := t.GetPlayer(userIndex) if usr == nil { log.Debug("ThreadsafeTable.RequestADAward user %d not exist", userIndex) return } if usr.IsRobot() { return } ret := coreservice.VideoSettleInfo(usr.GetUserId(), losingAmount, gameFrame.gameSink.GetGameID()) if !ret.Success { log.Debug("coreservice.VideoSettleInfo failed %d %d", usr.GetUserId(), losingAmount) return } var rewardInfo message.AdRewardInfo rewardInfo.SerialNo = ret.TimeStamp rewardInfo.ReturnGold = ret.ReturnAmount rewardInfo.UserId = usr.GetUserId() rewardInfo.LosingGold = losingAmount rewardInfo.MaxTimes = ret.MaxTimes rewardInfo.SettleAmount = ret.SettleAmount log.Debug("coreservice.VideoSettleInfo Success %d %d", usr.GetUserId(), rewardInfo.ReturnGold) d, _ := json.Marshal(rewardInfo) // 发给客户端 t.sendData(userIndex, message.Frame_ADRewardInfo, string(d)) } func (t *ThreadsafeTable) LogWithTableId(format string, a ...interface{}) { f := fmt.Sprintf("[%d] %v", t.tableId, format) log.Debug(fmt.Sprintf(f, a...)) } func (t *ThreadsafeTable) SetUserEndGame(chairId int) { t.LogWithTableId("SetUserEndGame %d", chairId) usr := t.GetUserByChair(chairId) if usr == nil { log.Debug("ThreadsafeTable.SetUserEndGame chair %d not exist", chairId) return } gameFrame.setUserStatus(usr.GetUserIndex(), user.UserStatus_Sit) //gameFrame.remove(t.tableId) // 如果掉线 go gameFrame.removeOfflineUser(usr.GetUserId(), usr) } func (t *ThreadsafeTable) SetTimer(timerId int, delayMs int) { //log.Debug("[%d]ThreadsafeTable.SetTimer %d %d time[%d]", t.tableId, timerId, delayMs, time.Now().UnixNano()/1000000) t.KillTimer(timerId) timer := time.AfterFunc(time.Duration(delayMs)*time.Millisecond, func() { //log.Debug("[%d]ThreadsafeTable.OnTimer %d time[%d]", t.tableId, timerId, time.Now().UnixNano()/1000000) t.timerChan <- timerId t.timerLock.Lock() delete(t.timers, timerId) t.timerLock.Unlock() }) t.timerLock.Lock() t.timers[timerId] = timer t.timerLock.Unlock() } func (t *ThreadsafeTable) KillTimer(timerId int) { t.timerLock.RLock() timer, ok := t.timers[timerId] t.timerLock.RUnlock() if !ok { return } t.timerLock.Lock() delete(t.timers, timerId) t.timerLock.Unlock() timer.Stop() } func (t *ThreadsafeTable) KillAllTimer() { t.killAllTimer() } func (t *ThreadsafeTable) killAllTimer() { t.timerLock.RLock() for _, v := range t.timers { v.Stop() } t.timerLock.RUnlock() } func (t *ThreadsafeTable) SendBroadcast(userId int, userName string, score int) { gameId := gameFrame.gameSink.GetGameID() gameName := gameFrame.gameSink.GetGameName() go coreservice.SendGameWinBroadcast(userId, userName, score, gameId, gameName) } func (t *ThreadsafeTable) Dismiss() { t.dismiss_safe() } func (t *ThreadsafeTable) GetUserChipOrGold(userIndex int32) int { return t.GetUserChipOrGoldByUser(t.GetPlayer(userIndex)) } func (t *ThreadsafeTable) GetUserChipOrGoldByUserId(userId int) int { //return t.GetUserChipOrGoldByUser(t.GetPlayerByUserId(userId)) u := gate.GetUserByUserId(userId) if u == nil { return 0 } return t.GetUserChipOrGoldByUser(u) } func (t *ThreadsafeTable) GetUserChipOrGoldByUser(usr *user.UserInfo) int { if usr == nil { return 0 } if gameFrame.gameSink.IsChipRoom() { return usr.GetChip() } return usr.GetUserGold() } func (t *ThreadsafeTable) GetPlayerCount() int { return t.getPlayerCount() } func (t *ThreadsafeTable) UpdateGameScore(userId, scoreDelta int) { if !t.isPrivate() { //log.Release("ThreadsafeTable.UpdateGameScore not private room") return } go privateroom.UpdateUserGameScore(t.roomNo, userId, scoreDelta) } func (t *ThreadsafeTable) DismissPrivateRoom() { if !t.isPrivate() { log.Release("ThreadsafeTable.DismissPrivateRoom not private room") return } go privateroom.DismissPrivateRoom(t.roomNo) } func (t *ThreadsafeTable) PrivateRoomSetWinners(winners []int) { if !t.isPrivate() { log.Release("ThreadsafeTable.PrivateRoomSetWinners not private room") return } privateroom.SetWinners(t.roomNo, winners) // 如果是百人场,就释放房间 if gameFrame.gameSink.GetChairCount() < 2 { go gameFrame.removeTable(t.tableId) } } func (t *ThreadsafeTable) AddExperience(userId, exp int) int { if exp <= 0 { log.Release("ThreadsafeTable.AddExperience [%d:%d] invalid exp", userId, exp) return 0 } return userservices.AddExperience(userId, exp) } func (t *ThreadsafeTable) GetUserList() []*user.UserInfo { var ret []*user.UserInfo for _, v := range t.watchUsers { usr, _ := t.GetUser(v.UserIndex) if usr != nil { ret = append(ret, usr) } } return ret } func (t *ThreadsafeTable) PrivateRoomGetRoomType() string { if !t.isPrivate() { log.Release("ThreadsafeTable.PrivateRoomGetRoomType not private room") return "" } return privateroom.GetRoomType(t.roomNo) } func (t *ThreadsafeTable) PrivateRoomGetFeeAndPrize(userId int) (int, int) { if !t.isPrivate() { log.Release("ThreadsafeTable.PrivateRoomGetFeeAndPrize not private room") return 0, 0 } return privateroom.GetFeeAndPrize(t.roomNo, userId) } func (t *ThreadsafeTable) CloseTable() { go gameFrame.removeTable(t.tableId) }