package frame import ( "fmt" "strings" "time" "bet24.com/log" "bet24.com/servers/insecureframe/gate" "bet24.com/servers/insecureframe/message" privateroom "bet24.com/servers/micros/privateroom/proto" task "bet24.com/servers/micros/task/proto" "bet24.com/servers/user" "bet24.com/utils" ) func (t *ThreadsafeTable) AddUser_safe(userIndex int32, chairId int, replay bool, toWatch bool) bool { // 我本身就在里面? for i := 0; i < t.chairCount; i++ { if t.users[i] == userIndex { log.Debug("ThreadsafeTable.AddUser already in table %d chair[%d] prefered ChairId[%d]", userIndex, i, chairId) return false } } usr := gate.GetUserInfo(userIndex) if usr == nil { log.Debug("ThreadsafeTable.AddUser invalid userIndex %d", userIndex) return false } if t.isPrivate() && !toWatch { if !t.isValidChair(chairId) { log.Release("ThreadsafeTable.AddUser invalid chairId %d for privateRoom", chairId) return false } // 是否能坐下 if privateroom.UserSit(t.roomNo, usr.GetUserId(), chairId) != 1 { log.Release("ThreadsafeTable.AddUser PrivateRoomUserSit failed roomNo:%d,userId:%d,chairId:%d", t.roomNo, usr.GetUserId(), chairId) return false } } watchString := "" if toWatch { watchString = "Watching" } log.Debug("ThreadsafeTable.AddUser [%d,%d],[%d.%d] %s", userIndex, usr.GetUserId(), t.tableId, chairId, watchString) if chairId == -1 { if toWatch { chairId = 0 } else { chairId = t.getEmptyChair() if chairId == -1 { log.Debug("ThreadsafeTable.AddUser no empty chair %d", t.tableId) return false } } } if !t.isValidChair(chairId) { log.Debug("ThreadsafeTable.AddUser invalid chairId %d", chairId) return false } if !toWatch { // 本身就有人了 if t.users[chairId] != -1 { log.Debug("ThreadsafeTable.AddUser chair[%d] taken[%d]", chairId, t.users[chairId]) return false } t.users[chairId] = userIndex // 删除旁观用户 t.removeWatchUser(userIndex, 0) } usr.SetTableChairId(t.tableId, chairId) if toWatch { gameFrame.setUserStatus(userIndex, user.UserStatus_Watch) } else { if replay && t.IsPlaying() { gameFrame.setUserStatus(userIndex, user.UserStatus_Play) } else { gameFrame.setUserStatus(userIndex, user.UserStatus_Sit) } } // 先发自己 t.sendUserEnter(usr, userIndex) // 发其他人 for i := 0; i < t.chairCount; i++ { if i == chairId && !toWatch { continue } if t.users[i] == -1 { continue } otherUser := t.getPlayer(t.users[i]) if otherUser == nil { log.Debug("ThreadsafeTable.AddUser otherUser == nil %d:%d", i, t.users[i]) continue } t.sendUserEnter(otherUser, userIndex) // 发给其他人 if !replay { go t.sendUserEnter(usr, t.users[i]) } } // 不需要发旁观用户给玩家,但要把玩家发给旁观用户 if !replay { for _, v := range t.watchUsers { t.sendUserEnter(usr, v.UserIndex) // 语音房先特殊处理 if gameFrame.GetGameID() == 70 { watcher, _ := t.GetUser(v.UserIndex) if watcher != nil { t.sendUserEnter(watcher, userIndex) } } } } if toWatch { t.addWatchUser(userIndex, chairId, usr.GetUserId()) } // 如果是私人场,并且是房主 if t.isPrivate() { // 获取玩家分数信息 roomUser := privateroom.GetUserRoomInfo(usr.GetUserId(), t.roomNo) if roomUser != nil { log.Debug("ThreadsafeTable.AddUser 私人场玩家信息 %v", roomUser) usr.SetScore(roomUser.Score) usr.SetBaseScore(roomUser.BaseScore) usr.SetSetCount(roomUser.SetCount) } else { log.Release("ThreadsafeTable.AddUser 获取私人场信息失败") } gate.SendMessage(userIndex, message.Frame_PrivateRoom_No, fmt.Sprintf("%d", t.roomNo)) } if !replay { t.tableSink.OnUserEnterTable(userIndex, chairId) } else { t.tableSink.OnUserReplay(chairId) } // 发送场景 if t.IsPlaying() { t.sendGameSceneToUser(userIndex) } return true } func (t *ThreadsafeTable) RemoveUser_safe(userIndex int32, toWatch bool, changeChair bool) { log.Debug("ThreadsafeTable.RemoveUser_safe[%d] %d toWatch = %v changeChair = %v", t.tableId, userIndex, toWatch, changeChair) usr, isPlayer := t.GetUser(userIndex) if usr == nil { log.Debug("ThreadsafeTable.RemoveUser invalid userIndex %d", userIndex) return } chairId := usr.GetUserChairId() if !t.isValidChair(chairId) { log.Debug("ThreadsafeTable.RemoveUser invalid chairId %d", chairId) return } userId := usr.GetUserId() // 设置玩家状态 if toWatch { gameFrame.setUserStatus(userIndex, user.UserStatus_Watch) t.addWatchUser(userIndex, chairId, userId) } else { gameFrame.setUserStatus(userIndex, user.UserStatus_Free) } t.sendUserExit(userId, chairId, userIndex, toWatch) //先回调再删 t.tableSink.OnUserExitTable(userIndex, chairId) if isPlayer { t.users[chairId] = -1 } else { t.removeWatchUser(userIndex, usr.GetUserId()) } // 发其他人 for i := 0; i < t.chairCount; i++ { if t.users[i] == -1 { continue } if i == chairId { continue } t.sendUserExit(userId, chairId, t.users[i], toWatch) } for _, v := range t.watchUsers { // 不发给自己 if v.UserIndex == userIndex { continue } t.sendUserExit(userId, chairId, v.UserIndex, toWatch) } // 不是玩家,不需要检查空桌 if !isPlayer { return } if t.isPrivate() { status := privateroom.GetRoomStatus(t.roomNo) if status == privateroom.PrivateRoomStatus_Ended { t.checkEmpty(true) } if status != privateroom.PrivateRoomStatus_Playing && !changeChair { privateroom.UserLeave(t.roomNo, userId) } } else { if t.checkEmpty(true) { return } if t.isTableCloseByLogic() { return } // 如果桌子已经超时,并且只有机器人了 isOvertime := time.Now().Unix()-t.createTime >= 3600 if isOvertime && t.onlyRobot() { go t.dismiss() } } } func (t *ThreadsafeTable) onlyRobot() bool { for i := 0; i < t.chairCount; i++ { p := t.GetUserByChair(i) if p != nil && !p.IsRobot() { return false } } return true } func (t *ThreadsafeTable) dismiss_safe() { t.EndGame() t.removeAllWatchUsers() var toRemove []int32 for i := 0; i < t.chairCount; i++ { if t.users[i] != -1 { toRemove = append(toRemove, t.users[i]) } } for _, v := range toRemove { t.RemoveUser_safe(v, false, false) } } func (t *ThreadsafeTable) userReplay_safe(oldUserIndex, newUserIndex int32) { usr := gate.GetUserInfo(newUserIndex) if usr == nil { log.Debug("ThreadsafeTable.userReplay usr == nil %d", newUserIndex) return } log.Debug("ThreadsafeTable.userReplay %d,%d", oldUserIndex, usr.GetUserId()) // 该玩家是否处于这个桌子 chairId := -1 for i := 0; i < t.chairCount; i++ { if t.users[i] == oldUserIndex { chairId = i break } } if chairId == -1 { log.Debug("ThreadsafeTable.userReplay offlineUser not exist tableId %d oldUserIndex %d", t.tableId, oldUserIndex) return } t.users[chairId] = -1 t.AddUser_safe(newUserIndex, chairId, true, false) } func (t *ThreadsafeTable) dumpScene_safe() { t.tableSink.DumpScene() } func (t *ThreadsafeTable) dumpTimers_safe() { t.timerLock.RLock() for k, v := range t.timers { if v == nil { continue } log.Release(" TimerId[%d] %v", k, v) } t.timerLock.RUnlock() } func (t *ThreadsafeTable) dump_safe() { log.Release(" tableId %d status %d data %s", t.tableId, t.tableStatus, t.privateData) for i := 0; i < t.chairCount; i++ { if t.users[i] == -1 { continue } usr := t.GetUserByChair(i) if usr == nil { log.Release(" Chair[%d] userIndex[%d] not exist", i, t.users[i]) continue } gold := 0 goldDesc := "gold" privateRoomNo := "" if t.isPrivate() { privateRoomNo = fmt.Sprintf("{RoomNo:%d}", t.roomNo) } if gameFrame.gameSink.IsChipRoom() { gold = usr.GetChip() goldDesc = "chip" } else { gold = usr.GetUserGold() } log.Release(" Chair[%d] %d:%d:%s status[%d] %s[%d] %s", i, usr.GetUserIndex(), usr.GetUserId(), usr.GetUserNickName(), usr.GetUserStatus(), goldDesc, gold, privateRoomNo) } //var toRemove []int32 if len(t.watchUsers) > 0 { log.Release(" ==== wach users") for _, v := range t.watchUsers { usr, _ := t.GetUser(v.UserIndex) if usr == nil { log.Release(" %d:%d is nil", v.UserIndex, v.ChairId) continue } gold := 0 goldDesc := "gold" if gameFrame.gameSink.IsChipRoom() { gold = usr.GetChip() goldDesc = "chip" } else { gold = usr.GetUserGold() } log.Release(" %d:%d:%s status[%d] %s[%d]", usr.GetUserIndex(), usr.GetUserId(), usr.GetUserNickName(), usr.GetUserStatus(), goldDesc, gold) } } } func (t *ThreadsafeTable) getUserCount_safe() int { return t.getPlayerCount() + t.getWatcherCount() } func (t *ThreadsafeTable) onTableMessage_safe(userIndex int32, msg, data string) bool { usr := gate.GetUserInfo(userIndex) if usr == nil { log.Debug("ThreadsafeTable.onTableMessage user not found %d", userIndex) return false } if gameFrame.gameSink.GetChairCount() >= 2 && !usr.IsPlayer() { log.Debug("ThreadsafeTable.onTableMessage not a player %d", usr.GetUserIndex()) return false } switch { default: // 如果是发送表情道具,则加入任务 if msg == "CMD_TABLECHAT" { if strings.Contains(data, "3/") { task.DoTaskAction(usr.GetUserId(), task.TaskAction_gameinteract, 1, task.TaskScope{}) } } return t.tableSink.OnGameMessage(userIndex, msg, data) } } func (t *ThreadsafeTable) UserWatch(userIndex int32) { // 如果用户不是playing状态,直接转换成watch即可 usr := t.GetPlayer(userIndex) if usr == nil { log.Debug("ThreadsafeTable.UserWatch user %d not exist", userIndex) return } toWatch := true if usr.IsRobot() { toWatch = false } chairId := usr.GetUserChairId() if chairId < 0 || chairId >= t.chairCount { return } if usr.GetUserStatus() != user.UserStatus_Play { //gameFrame.setUserStatus(userIndex, user.UserStatus_Watch) t.RemoveUser_safe(userIndex, toWatch, false) return } } func (t *ThreadsafeTable) SetUserReadyStatus(userIndex int32, isReady bool) bool { defer utils.TimeCost(fmt.Sprintf("ThreadsafeTable.SetUserReadyStatus %d", userIndex))() usr := t.GetPlayer(userIndex) if usr == nil { log.Debug("ThreadsafeTable.SetUserReadyStatus failed user[%d] not exist", userIndex) return false } chairId := usr.GetUserChairId() if chairId < 0 { log.Debug("ThreadsafeTable.SetUserReadyStatus failed chairId = %d", chairId) return false } curStatus := usr.GetUserStatus() if isReady && curStatus != user.UserStatus_Sit { log.Debug("ThreadsafeTable.SetUserReady %d user status[%d] not sit", userIndex, curStatus) return false } if !isReady && curStatus != user.UserStatus_Ready { log.Debug("ThreadsafeTable.CancelUserReady %d user status[%d] not ready", userIndex, curStatus) return false } newStatus := user.UserStatus_Ready if !isReady { newStatus = user.UserStatus_Sit } if isReady && t.isPrivate() { // 游戏已经结束,不能再开始了 if privateroom.GetRoomStatus(t.roomNo) == privateroom.PrivateRoomStatus_Ended { log.Release("ThreadsafeTable.SetUserReadyStatus to ready failed privateroom ended") return false } } // 设置状态并广播状态变化 gameFrame.setUserStatus(userIndex, newStatus) // 回调给游戏 t.onUserReady(userIndex, chairId, isReady) return true } func (t *ThreadsafeTable) setBaseScore_safe(baseScore int) { t.tableSink.OnBaseScoreChanged(baseScore) } func (t *ThreadsafeTable) Destroy() { t.stopped = true close(t.stopChan) } func (t *ThreadsafeTable) addWatchUser(userIndex int32, chair int, userId int) { if chair < 0 || chair >= t.chairCount { log.Debug("addWatchUser %d,%d", userIndex, chair) chair = 0 } for _, v := range t.watchUsers { if v.UserIndex == userIndex { log.Debug("ThreadsafeTable.addWatchUser userIndex %d already exist", userIndex) v.ChairId = chair return } } t.watchUsers = append(t.watchUsers, WatchUser{UserIndex: userIndex, ChairId: chair, UserId: userId}) } func (t *ThreadsafeTable) removeWatchUser(userIndex int32, userId int) { for i := 0; i < len(t.watchUsers); { if t.watchUsers[i].UserIndex == userIndex { if userId > 0 { t.sendUserExit(userId, 0, userIndex, false) t.broadcastUserExit(userId, 0, false) } t.watchUsers = append(t.watchUsers[:i], t.watchUsers[i+1:]...) if gameFrame.gameSink.GetChairCount() >= 2 { t.checkEmpty(false) } return } else { i++ } } log.Debug("ThreadsafeTable.removeWatchUser userIndex %d not exist", userIndex) } func (t *ThreadsafeTable) isTableCloseByLogic() bool { gameSink_FishRoom, ok := gameFrame.gameSink.(GameSink_FishRoom) if !ok { return false } return gameSink_FishRoom.IsTableCloseByLogic() } func (t *ThreadsafeTable) ignoreSameIP() bool { gameSink_FishRoom, ok := gameFrame.gameSink.(GameSink_FishRoom) if !ok { return false } return gameSink_FishRoom.IgnoreSameIP() } func (t *ThreadsafeTable) enterPlayingRoomFirst() bool { gameSink_FishRoom, ok := gameFrame.gameSink.(GameSink_FishRoom) if !ok { return false } return gameSink_FishRoom.EnterPlayingRoomFirst() } func (t *ThreadsafeTable) checkEmpty(playerLeft bool) bool { if t.isTableCloseByLogic() { return false } // 私人场旁观离开不检查 if gameFrame.gameSink.IsPrivateRoom() && !playerLeft { return false } for i := 0; i < t.chairCount; i++ { if t.users[i] == -1 { continue } return false } if len(t.watchUsers) > 0 { return false } go gameFrame.removeTable(t.tableId) return true } func (t *ThreadsafeTable) privateRoomStatusChanged_safe(oldStatus int, newStatus int) { t.tableSink_privateRoom.OnPrivateRoomStatusChanged(oldStatus, newStatus) } func (t *ThreadsafeTable) privateRoomDismissed_safe() { t.tableSink_privateRoom.OnPrivateRoomDismissed() t.SendGameData(-1, message.Frame_PrivateRoom_Dismissed, "") // 如果是百人游戏,先不要解散 if gameFrame.gameSink.GetChairCount() < 2 { return } t.dismiss_safe() } func (t *ThreadsafeTable) kickUser(toUserIndex int32) bool { ret := false for i := 0; i < t.chairCount; i++ { if t.users[i] == toUserIndex { ret = t.KickUserByChair(i, false) break } } return ret }