package frame import ( "encoding/json" "fmt" "math/rand" "sync" "time" //utils2 "bet24.com/servers/insecureframe/gate/Utils" "bet24.com/log" "bet24.com/redis" "bet24.com/servers/insecureframe/gate" "bet24.com/servers/insecureframe/message" "bet24.com/servers/insecureframe/robot" "bet24.com/servers/user" ) func NewGameFrame(gameSink GameSink) *GameFrame { f := new(GameFrame) f.gameSink = gameSink f.tables = make(map[int]*ThreadsafeTable) f.lock_table = &sync.RWMutex{} f.lock_user = &sync.RWMutex{} f.lock_changeTable = &sync.RWMutex{} f.tableIndex = 1 f.offlineUsers = make(map[int]offlineUser) time.AfterFunc(10*time.Second, f.checkOfflineUsers) f.changeTableCount = make(map[int32]int) f.roomDatas = gameSink.GetRoomDatas() if len(f.roomDatas) > 0 { time.AfterFunc(10*time.Second, f.checkCreateRobotRoom) } log.Debug("gameframe running...") return f } type offlineUser struct { userInfo *user.UserInfo offlineTime int64 tableId int userIndex int32 } type GameFrame struct { gameSink GameSink tableIndex int // --GameTable++ tables map[int]*ThreadsafeTable lock_table *sync.RWMutex lock_user *sync.RWMutex offlineUsers map[int]offlineUser roomDatas []string lock_changeTable *sync.RWMutex changeTableCount map[int32]int } func (f *GameFrame) CreateBacTable() { // 如果是百人游戏,不是私人场 if f.gameSink.GetChairCount() < 2 && !f.gameSink.IsPrivateRoom() { // 创建一张默认桌子 f.createTable("") } } // implement GateSink func (f *GameFrame) GetServerPort() int { return f.gameSink.GetServerPort() } func (f *GameFrame) checkCreateRobotRoom() { if !robot.IsRunning() { return } if stopping { return } for _, v := range f.roomDatas { minRoomCount := f.gameSink.GetMinRoomCount(v) //log.Debug("checkCreateRobotRoom %s:%d", v, minRoomCount) if minRoomCount == 0 { continue } existCount := f.getTableCount(v) for i := 0; i < minRoomCount-existCount; i++ { t := f.createTable(v) if t == nil { log.Debug("checkCreateRobotRoom creating table failed %s", v) continue } min, max := f.gameSink.GetRoomRobotGoldLimit(v) enterRobotCount := 2 if f.gameSink.GetChairCount() == 1 { enterRobotCount = f.gameSink.GetRoomRobotCount(v) } for i := 0; i < enterRobotCount; i++ { go robot.GetOneRobotEnterTableAndReady(t.tableId, min, max) } } } time.AfterFunc(60*time.Second, f.checkCreateRobotRoom) } func (f *GameFrame) checkAndCreateTable(roomData string) { } func (f *GameFrame) checkOfflineUsers() { offlineSeconds := f.gameSink.GetOfflineSeconds() if offlineSeconds <= 0 { log.Debug("GameFrame.checkOfflineUsers 不支持断线续玩") return } //log.Debug("GameFrame.checkOfflineUsers offlineSeconds = %d", offlineSeconds) time.AfterFunc(10*time.Second, f.checkOfflineUsers) now := time.Now().Unix() f.lock_user.RLock() for k, v := range f.offlineUsers { if now-v.offlineTime >= offlineSeconds { go f.removeOfflineUser(k, v.userInfo) } } f.lock_user.RUnlock() } func (f *GameFrame) OnUserEnter(userIndex int32) { } func (f *GameFrame) delayUserWatchTable(userIndex int32, tableId int) { table := f.getTable(1) if table == nil { return } //time.Sleep(50 * time.Millisecond) go table.AddTableUser(userIndex, 0, false, true) } func (f *GameFrame) OnUserLogined(userIndex int32) { // 是否属于断线玩家 usr := gate.GetUserInfo(userIndex) if usr == nil { log.Debug("GameFrame.OnUserLogined user not exist") return } // 发送一下自己进入的消息 //user2 := utils2.GetUserInfoData(1) // fmt.Printf("用户登录成功==",user2) // usr.SetUserNickName(user2.Data[0].NickName) // usr.SetUserGold(user2.Data[0].GoldCoins) info := usr.GetUserInfo_Table(true) d, _ := json.Marshal(info) fmt.Println("获取用户信息=====",info) gate.SendMessage(userIndex, message.Frame_UserEnter, string(d)) // 如果是百人场,直接进入旁观 /*if f.gameSink.GetChairCount() < 2 && !f.gameSink.IsPrivateRoom() { go f.delayUserWatchTable(userIndex, 1) return }*/ //发送场次列表 // d, _ = json.Marshal(f.gameSink.GetRoomList()) // gate.SendMessage(userIndex, message.Frame_GetRoomList, string(d)) userId := usr.GetUserId() f.lock_user.RLock() offlineUser, ok := f.offlineUsers[userId] f.lock_user.RUnlock() if !ok { return } table := f.getTable(offlineUser.tableId) if table == nil /*table.tableStatus != TableStatus_Playing*/ { log.Debug("GameFrame.OnUserLogined replay table[%d] not found", offlineUser.tableId) return } log.Debug("GameFrame.OnUserLogined 用户 %d 断线回来了", userId) usr.SetUserStatus(user.UserStatus_Offline) table.userReplay(offlineUser.userInfo.GetUserIndex(), usr) // 通知完桌子后再删除断线用户信息 f.lock_user.Lock() delete(f.offlineUsers, userId) f.lock_user.Unlock() } func (f *GameFrame) OnUserExit(userIndex int32) { if robot.IsRunning() { robot.UserExit(userIndex) } f.lock_changeTable.Lock() delete(f.changeTableCount, userIndex) f.lock_changeTable.Unlock() usr := gate.GetUserInfo(userIndex) if usr == nil { log.Debug("GameFrame.OnUserExit user[%d] not exist", userIndex) return } table := f.getTable(usr.GetUserTableId()) if table == nil { log.Debug("GameFrame.OnUserExit user[%d] table[%d] not found", userIndex, usr.GetUserTableId()) return } // 是否断线? oldStatus := usr.GetUserStatus() if oldStatus == user.UserStatus_Play { if f.addOfflineUser(usr) { table.tableSink.OnUserOffline(usr.GetUserChairId()) // 广播玩家断线状态 d, _ := json.Marshal(message.UserStatusChange{UserId: usr.GetUserId(), OldStatus: oldStatus, NewStatus: user.UserStatus_Offline, TableId: usr.GetUserTableId(), ChairId: usr.GetUserChairId()}) gate.BroadcastData(message.Frame_UserStatusChange, string(d)) return } } f.setOfflineStatus(usr.GetUserId(), false, table.privateData) table.RemoveUser(userIndex, false, false) } func (f *GameFrame) addOfflineUser(usr *user.UserInfo) bool { if f.gameSink.GetOfflineSeconds() <= 0 { return false } userId := usr.GetUserId() f.lock_user.Lock() defer f.lock_user.Unlock() _, ok := f.offlineUsers[userId] if ok { log.Debug("GameFrame.addOfflineUser userId[%d] already exist", userId) return false } log.Debug("addOfflineUser %d", userId) usr.SetUserStatus(user.UserStatus_Offline) f.offlineUsers[userId] = offlineUser{userInfo: usr.GetCopy(), offlineTime: time.Now().Unix(), tableId: usr.GetUserTableId(), userIndex: usr.GetUserIndex()} return true } func (f *GameFrame) removeOfflineUser(userIdKey int, usr *user.UserInfo) { userId := usr.GetUserId() userIndex := usr.GetUserIndex() f.lock_user.Lock() ou, ok := f.offlineUsers[userIdKey] if !ok { log.Debug("GameFrame.removeOfflineUser userId[%d] not found,userIdKey = %d", userId, userIdKey) delete(f.offlineUsers, userIdKey) f.lock_user.Unlock() return } f.lock_user.Unlock() log.Debug("GameFrame.removeOfflineUser removing %d %d %d ", userId, userIndex, ou.userIndex) table := f.getTable(ou.tableId) if table != nil { table.RemoveUser(userIndex, false, false) } log.Debug("GameFrame.removeOfflineUser removed %d ", userId) f.lock_user.Lock() delete(f.offlineUsers, userIdKey) f.lock_user.Unlock() } func (f *GameFrame) removeOfflineByTableId(tableId int) { f.lock_user.RLock() defer f.lock_user.RUnlock() for k, v := range f.offlineUsers { if v.tableId == tableId { go f.removeOfflineUser(k, v.userInfo) go f.setOfflineStatus(k, false, "") } } } func (f *GameFrame) OnGameMessage(userIndex int32, userID int, msg, data string) bool { switch msg { case message.Frame_AutoSit: return f.recvAutoSit(userIndex, data, false, false) case message.Frame_NewUserAutoSit: return f.recvAutoSit(userIndex, data, false, true) case message.Frame_ChangeTable: return f.recvChangeTable(userIndex, data) case message.Frame_Sit: return f.recvSitTable(userIndex, data) case message.Frame_WatchTable: return f.recvWatchTable(userIndex, data) case message.Frame_Standup: return f.recvStandup(userIndex, data) case message.Frame_Watch: return f.recvWatch(userIndex, data) case message.Frame_Ready: return f.recvReady(userIndex, true) case message.Frame_CancelReady: return f.recvReady(userIndex, false) // case message.Frame_GetRoomList: // return f.recvGetRoomList(userIndex, msg) case message.Frame_ADReward: return f.recvAdReward(userIndex, data) case message.Frame_Ping: return f.recvFramePing(userIndex, data) /*case message.Frame_CreatePrivateRoom: return f.createPrivateRoom(userIndex, data) case message.Frame_PrivateRoom_SetBaseScore: return f.privateRoomSetBaseScore(userIndex, data)*/ case message.Frame_PrivateRoom_RequestDismiss: return f.recvPrivateRoomRequestDismiss(userIndex, msg, data) case message.Frame_PrivateRoom_DismissResp: return f.recvPrivateRoomDismissResp(userIndex, msg, data) case message.Frame_Voice: return f.recvFrameVoiceMessage(userIndex, userID, msg, data) case message.Frame_PrivateRoom_KickUser: return f.recvPrivateRoomKick(userIndex, msg, data) default: return f.recvTableMessage(userIndex, userID, msg, data) } } func (f *GameFrame) GetGameID() int { return f.gameSink.GetGameID() } func (f *GameFrame) GetGameName() string { return f.gameSink.GetGameName() } func (f *GameFrame) GetRoomName() string { return f.gameSink.GetRoomName() } func (f *GameFrame) GetCertFile() string { return f.gameSink.GetCertFile() } func (f *GameFrame) GetKeyFile() string { return f.gameSink.GetKeyFile() } // 机器人配置 func (f *GameFrame) GetRobotCount() int { return f.gameSink.GetRobotCount() } func (f *GameFrame) GetRobotGoldLimit() (min, max int) { min, max = f.gameSink.GetRobotGoldLimit() return } func (f *GameFrame) GetRobotOnlineSec() int { return f.gameSink.GetRobotOnlineSec() } func (f *GameFrame) IsChipRoom() bool { return f.gameSink.IsChipRoom() } func (f *GameFrame) IsLadderRoom() bool { gameSink_LadderRoom, ok := f.gameSink.(GameSink_LadderRoom) return ok && gameSink_LadderRoom.IsLadderRoom() } func (f *GameFrame) GetChipRoom() int { if f.gameSink.IsChipRoom() { return 1 } else { return 0 } } func (f *GameFrame) OnPlatformConfig(key string) { f.gameSink.OnPlatformConfig(key) } func (f *GameFrame) IsPrivateRoom() bool { return f.gameSink.IsPrivateRoom() } func (f *GameFrame) GetVersionID() int { return f.gameSink.GetVersionID() } func (f *GameFrame) setUserStatus(userIndex int32, status int) { usr := gate.GetUserInfo(userIndex) if usr == nil { log.Debug("GameFrame.setUserStatus user not exist %d", userIndex) return } if status == user.UserStatus_Free { usr.SetTableChairId(-1, -1) } oldStatus := usr.GetUserStatus() if oldStatus == status { log.Debug("GameFrame.setUserStatus user[%d] status not changed status = %d", userIndex, status) return } usr.SetUserStatus(status) //go func() { // 取消协程,保证按顺序发送用户状态 d, _ := json.Marshal(message.UserStatusChange{UserId: usr.GetUserId(), OldStatus: oldStatus, NewStatus: status, TableId: usr.GetUserTableId(), ChairId: usr.GetUserChairId()}) gate.BroadcastData(message.Frame_UserStatusChange, string(d)) if status == user.UserStatus_Play { t := f.getTable(usr.GetUserTableId()) data := "" if t != nil { data = t.privateData if t.isPrivate() { // 私人场不写断线信息 return } } f.setOfflineStatus(usr.GetUserId(), true, data) } else { f.setOfflineStatus(usr.GetUserId(), false, "") } //}() } func (f *GameFrame) dump() { log.Release("----------GameFrame.dump----------") log.Release(" current table index : %d", f.tableIndex) defer func() { log.Release("++++++++++GameFrame.dump++++++++++") }() f.lock_table.RLock() defer f.lock_table.RUnlock() for _, v := range f.tables { log.Release(" table[%d] status[%d] usercount[%d] started[%d] Room[%s]", v.tableId, v.tableStatus, v.getUserCount(), v.getStartTime(), v.privateData) } } func (f *GameFrame) dumpTable(tableId int) { log.Release("----------GameFrame.dumpTable----------") defer func() { log.Release("++++++++++GameFrame.dumpTable++++++++++") }() table := f.getTable(tableId) if table == nil { log.Release(" table %d not exist", tableId) return } table.dump() } func (f *GameFrame) dumpTimers(tableId int) { log.Release("----------GameFrame.dumpTimers----------") defer func() { log.Release("++++++++++GameFrame.dumpTimers++++++++++") }() table := f.getTable(tableId) if table == nil { log.Release(" table %d not exist", tableId) return } table.dumpTimers() } func (f *GameFrame) dumpScene(tableId int) { log.Release("----------GameFrame.dumpScene----------") defer func() { log.Release("++++++++++GameFrame.dumpScene++++++++++") }() table := f.getTable(tableId) if table == nil { log.Release(" table %d not exist", tableId) return } table.dumpScene() } func (f *GameFrame) dumpOffline() { log.Release("----------GameFrame.dumpOffline----------") defer func() { log.Release("++++++++++GameFrame.dumpOffline++++++++++") }() f.lock_user.RLock() defer f.lock_user.RUnlock() log.Release(" count %d", len(f.offlineUsers)) for _, v := range f.offlineUsers { log.Release(" %d:%d %s offline:%d", v.userIndex, v.userInfo.GetUserId(), v.userInfo.GetUserNickName(), time.Now().Unix()-v.offlineTime) } } func (f *GameFrame) dismissTable(tableId int) { table := f.getTable(tableId) if table != nil { table.dismiss() } } func (f *GameFrame) getOfflineUser(userIndex int32) *user.UserInfo { f.lock_user.RLock() defer f.lock_user.RUnlock() for _, v := range f.offlineUsers { if v.userIndex == userIndex { return v.userInfo } } return nil } func (f *GameFrame) setOfflineStatus(userId int, offline bool, roomName string) { keyName := fmt.Sprintf("UserGameStatus:UserID:%v:", userId) if offline { o := struct { GameName string RoomName string ServerAddr string GameId int }{ GameName: f.gameSink.GetGameName(), RoomName: roomName, ServerAddr: f.gameSink.GetServerAddr(), GameId: f.gameSink.GetGameID(), } d, _ := json.Marshal(o) redis.String_SetEx(keyName, string(d), int(f.gameSink.GetOfflineSeconds())) } else { redis.Key_Del(keyName) } } func (f *GameFrame) getUserCount(privateData string) int { ret := 0 f.lock_table.RLock() defer f.lock_table.RUnlock() for _, v := range f.tables { if v.privateData != privateData { continue } ret += v.getUserCount() } return ret } func (f *GameFrame) GetVirtualUserCount(userCount int, roomType int) int { if roomType < 0 { roomType = 0 } else { roomType = roomType % 8 } userCounts := [][]int{} userCounts = append(userCounts, []int{72, 134, 326, 265, 534}) userCounts = append(userCounts, []int{52, 168, 287, 201, 384}) userCounts = append(userCounts, []int{11, 76, 163, 143, 176}) userCounts = append(userCounts, []int{13, 42, 76, 103, 202}) userCounts = append(userCounts, []int{43, 86, 126, 134, 286}) userCounts = append(userCounts, []int{25, 62, 96, 76, 146}) userCounts = append(userCounts, []int{10, 32, 62, 53, 76}) userCounts = append(userCounts, []int{8, 21, 72, 62, 92}) hour := time.Now().Hour() hourIndex := 0 if hour >= 18 { hourIndex = 4 } else if hour >= 14 { hourIndex = 3 } else if hour >= 11 { hourIndex = 2 } else if hour >= 6 { hourIndex = 1 } param := 10 return userCount*param + userCounts[roomType][hourIndex]*4 - 10 + rand.Intn(20) }