threadsafe_table_safe.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. package frame
  2. import (
  3. "fmt"
  4. "strings"
  5. "time"
  6. "bet24.com/log"
  7. "bet24.com/servers/insecureframe/gate"
  8. "bet24.com/servers/insecureframe/message"
  9. privateroom "bet24.com/servers/micros/privateroom/proto"
  10. task "bet24.com/servers/micros/task/proto"
  11. "bet24.com/servers/user"
  12. "bet24.com/utils"
  13. )
  14. func (t *ThreadsafeTable) AddUser_safe(userIndex int32, chairId int, replay bool, toWatch bool) bool {
  15. // 我本身就在里面?
  16. for i := 0; i < t.chairCount; i++ {
  17. if t.users[i] == userIndex {
  18. log.Debug("ThreadsafeTable.AddUser already in table %d chair[%d] prefered ChairId[%d]", userIndex, i, chairId)
  19. return false
  20. }
  21. }
  22. usr := gate.GetUserInfo(userIndex)
  23. if usr == nil {
  24. log.Debug("ThreadsafeTable.AddUser invalid userIndex %d", userIndex)
  25. return false
  26. }
  27. if t.isPrivate() && !toWatch {
  28. if !t.isValidChair(chairId) {
  29. log.Release("ThreadsafeTable.AddUser invalid chairId %d for privateRoom", chairId)
  30. return false
  31. }
  32. // 是否能坐下
  33. if privateroom.UserSit(t.roomNo, usr.GetUserId(), chairId) != 1 {
  34. log.Release("ThreadsafeTable.AddUser PrivateRoomUserSit failed roomNo:%d,userId:%d,chairId:%d",
  35. t.roomNo, usr.GetUserId(), chairId)
  36. return false
  37. }
  38. }
  39. watchString := ""
  40. if toWatch {
  41. watchString = "Watching"
  42. }
  43. log.Debug("ThreadsafeTable.AddUser [%d,%d],[%d.%d] %s", userIndex, usr.GetUserId(), t.tableId, chairId, watchString)
  44. if chairId == -1 {
  45. if toWatch {
  46. chairId = 0
  47. } else {
  48. chairId = t.getEmptyChair()
  49. if chairId == -1 {
  50. log.Debug("ThreadsafeTable.AddUser no empty chair %d", t.tableId)
  51. return false
  52. }
  53. }
  54. }
  55. if !t.isValidChair(chairId) {
  56. log.Debug("ThreadsafeTable.AddUser invalid chairId %d", chairId)
  57. return false
  58. }
  59. if !toWatch {
  60. // 本身就有人了
  61. if t.users[chairId] != -1 {
  62. log.Debug("ThreadsafeTable.AddUser chair[%d] taken[%d]", chairId, t.users[chairId])
  63. return false
  64. }
  65. t.users[chairId] = userIndex
  66. // 删除旁观用户
  67. t.removeWatchUser(userIndex, 0)
  68. }
  69. usr.SetTableChairId(t.tableId, chairId)
  70. if toWatch {
  71. gameFrame.setUserStatus(userIndex, user.UserStatus_Watch)
  72. } else {
  73. if replay && t.IsPlaying() {
  74. gameFrame.setUserStatus(userIndex, user.UserStatus_Play)
  75. } else {
  76. gameFrame.setUserStatus(userIndex, user.UserStatus_Sit)
  77. }
  78. }
  79. // 先发自己
  80. t.sendUserEnter(usr, userIndex)
  81. // 发其他人
  82. for i := 0; i < t.chairCount; i++ {
  83. if i == chairId && !toWatch {
  84. continue
  85. }
  86. if t.users[i] == -1 {
  87. continue
  88. }
  89. otherUser := t.getPlayer(t.users[i])
  90. if otherUser == nil {
  91. log.Debug("ThreadsafeTable.AddUser otherUser == nil %d:%d", i, t.users[i])
  92. continue
  93. }
  94. t.sendUserEnter(otherUser, userIndex)
  95. // 发给其他人
  96. if !replay {
  97. go t.sendUserEnter(usr, t.users[i])
  98. }
  99. }
  100. // 不需要发旁观用户给玩家,但要把玩家发给旁观用户
  101. if !replay {
  102. for _, v := range t.watchUsers {
  103. t.sendUserEnter(usr, v.UserIndex)
  104. // 语音房先特殊处理
  105. if gameFrame.GetGameID() == 70 {
  106. watcher, _ := t.GetUser(v.UserIndex)
  107. if watcher != nil {
  108. t.sendUserEnter(watcher, userIndex)
  109. }
  110. }
  111. }
  112. }
  113. if toWatch {
  114. t.addWatchUser(userIndex, chairId, usr.GetUserId())
  115. }
  116. // 如果是私人场,并且是房主
  117. if t.isPrivate() {
  118. // 获取玩家分数信息
  119. roomUser := privateroom.GetUserRoomInfo(usr.GetUserId(), t.roomNo)
  120. if roomUser != nil {
  121. log.Debug("ThreadsafeTable.AddUser 私人场玩家信息 %v", roomUser)
  122. usr.SetScore(roomUser.Score)
  123. usr.SetBaseScore(roomUser.BaseScore)
  124. usr.SetSetCount(roomUser.SetCount)
  125. } else {
  126. log.Release("ThreadsafeTable.AddUser 获取私人场信息失败")
  127. }
  128. gate.SendMessage(userIndex, message.Frame_PrivateRoom_No, fmt.Sprintf("%d", t.roomNo))
  129. }
  130. if !replay {
  131. t.tableSink.OnUserEnterTable(userIndex, chairId)
  132. } else {
  133. t.tableSink.OnUserReplay(chairId)
  134. }
  135. // 发送场景
  136. if t.IsPlaying() {
  137. t.sendGameSceneToUser(userIndex)
  138. }
  139. return true
  140. }
  141. func (t *ThreadsafeTable) RemoveUser_safe(userIndex int32, toWatch bool, changeChair bool) {
  142. log.Debug("ThreadsafeTable.RemoveUser_safe[%d] %d toWatch = %v changeChair = %v", t.tableId, userIndex, toWatch, changeChair)
  143. usr, isPlayer := t.GetUser(userIndex)
  144. if usr == nil {
  145. log.Debug("ThreadsafeTable.RemoveUser invalid userIndex %d", userIndex)
  146. return
  147. }
  148. chairId := usr.GetUserChairId()
  149. if !t.isValidChair(chairId) {
  150. log.Debug("ThreadsafeTable.RemoveUser invalid chairId %d", chairId)
  151. return
  152. }
  153. userId := usr.GetUserId()
  154. // 设置玩家状态
  155. if toWatch {
  156. gameFrame.setUserStatus(userIndex, user.UserStatus_Watch)
  157. t.addWatchUser(userIndex, chairId, userId)
  158. } else {
  159. gameFrame.setUserStatus(userIndex, user.UserStatus_Free)
  160. }
  161. t.sendUserExit(userId, chairId, userIndex, toWatch)
  162. //先回调再删
  163. t.tableSink.OnUserExitTable(userIndex, chairId)
  164. if isPlayer {
  165. t.users[chairId] = -1
  166. } else {
  167. t.removeWatchUser(userIndex, usr.GetUserId())
  168. }
  169. // 发其他人
  170. for i := 0; i < t.chairCount; i++ {
  171. if t.users[i] == -1 {
  172. continue
  173. }
  174. if i == chairId {
  175. continue
  176. }
  177. t.sendUserExit(userId, chairId, t.users[i], toWatch)
  178. }
  179. for _, v := range t.watchUsers {
  180. // 不发给自己
  181. if v.UserIndex == userIndex {
  182. continue
  183. }
  184. t.sendUserExit(userId, chairId, v.UserIndex, toWatch)
  185. }
  186. // 不是玩家,不需要检查空桌
  187. if !isPlayer {
  188. return
  189. }
  190. if t.isPrivate() {
  191. status := privateroom.GetRoomStatus(t.roomNo)
  192. if status == privateroom.PrivateRoomStatus_Ended {
  193. t.checkEmpty(true)
  194. }
  195. if status != privateroom.PrivateRoomStatus_Playing && !changeChair {
  196. privateroom.UserLeave(t.roomNo, userId)
  197. }
  198. } else {
  199. if t.checkEmpty(true) {
  200. return
  201. }
  202. if t.isTableCloseByLogic() {
  203. return
  204. }
  205. // 如果桌子已经超时,并且只有机器人了
  206. isOvertime := time.Now().Unix()-t.createTime >= 3600
  207. if isOvertime && t.onlyRobot() {
  208. go t.dismiss()
  209. }
  210. }
  211. }
  212. func (t *ThreadsafeTable) onlyRobot() bool {
  213. for i := 0; i < t.chairCount; i++ {
  214. p := t.GetUserByChair(i)
  215. if p != nil && !p.IsRobot() {
  216. return false
  217. }
  218. }
  219. return true
  220. }
  221. func (t *ThreadsafeTable) dismiss_safe() {
  222. t.EndGame()
  223. t.removeAllWatchUsers()
  224. var toRemove []int32
  225. for i := 0; i < t.chairCount; i++ {
  226. if t.users[i] != -1 {
  227. toRemove = append(toRemove, t.users[i])
  228. }
  229. }
  230. for _, v := range toRemove {
  231. t.RemoveUser_safe(v, false, false)
  232. }
  233. }
  234. func (t *ThreadsafeTable) userReplay_safe(oldUserIndex, newUserIndex int32) {
  235. usr := gate.GetUserInfo(newUserIndex)
  236. if usr == nil {
  237. log.Debug("ThreadsafeTable.userReplay usr == nil %d", newUserIndex)
  238. return
  239. }
  240. log.Debug("ThreadsafeTable.userReplay %d,%d", oldUserIndex, usr.GetUserId())
  241. // 该玩家是否处于这个桌子
  242. chairId := -1
  243. for i := 0; i < t.chairCount; i++ {
  244. if t.users[i] == oldUserIndex {
  245. chairId = i
  246. break
  247. }
  248. }
  249. if chairId == -1 {
  250. log.Debug("ThreadsafeTable.userReplay offlineUser not exist tableId %d oldUserIndex %d", t.tableId, oldUserIndex)
  251. return
  252. }
  253. t.users[chairId] = -1
  254. t.AddUser_safe(newUserIndex, chairId, true, false)
  255. }
  256. func (t *ThreadsafeTable) dumpScene_safe() {
  257. t.tableSink.DumpScene()
  258. }
  259. func (t *ThreadsafeTable) dumpTimers_safe() {
  260. t.timerLock.RLock()
  261. for k, v := range t.timers {
  262. if v == nil {
  263. continue
  264. }
  265. log.Release(" TimerId[%d] %v", k, v)
  266. }
  267. t.timerLock.RUnlock()
  268. }
  269. func (t *ThreadsafeTable) dump_safe() {
  270. log.Release(" tableId %d status %d data %s", t.tableId, t.tableStatus, t.privateData)
  271. for i := 0; i < t.chairCount; i++ {
  272. if t.users[i] == -1 {
  273. continue
  274. }
  275. usr := t.GetUserByChair(i)
  276. if usr == nil {
  277. log.Release(" Chair[%d] userIndex[%d] not exist", i, t.users[i])
  278. continue
  279. }
  280. gold := 0
  281. goldDesc := "gold"
  282. privateRoomNo := ""
  283. if t.isPrivate() {
  284. privateRoomNo = fmt.Sprintf("{RoomNo:%d}", t.roomNo)
  285. }
  286. if gameFrame.gameSink.IsChipRoom() {
  287. gold = usr.GetChip()
  288. goldDesc = "chip"
  289. } else {
  290. gold = usr.GetUserGold()
  291. }
  292. log.Release(" Chair[%d] %d:%d:%s status[%d] %s[%d] %s", i, usr.GetUserIndex(), usr.GetUserId(), usr.GetUserNickName(),
  293. usr.GetUserStatus(), goldDesc, gold, privateRoomNo)
  294. }
  295. //var toRemove []int32
  296. if len(t.watchUsers) > 0 {
  297. log.Release(" ==== wach users")
  298. for _, v := range t.watchUsers {
  299. usr, _ := t.GetUser(v.UserIndex)
  300. if usr == nil {
  301. log.Release(" %d:%d is nil", v.UserIndex, v.ChairId)
  302. continue
  303. }
  304. gold := 0
  305. goldDesc := "gold"
  306. if gameFrame.gameSink.IsChipRoom() {
  307. gold = usr.GetChip()
  308. goldDesc = "chip"
  309. } else {
  310. gold = usr.GetUserGold()
  311. }
  312. log.Release(" %d:%d:%s status[%d] %s[%d]", usr.GetUserIndex(), usr.GetUserId(), usr.GetUserNickName(),
  313. usr.GetUserStatus(), goldDesc, gold)
  314. }
  315. }
  316. }
  317. func (t *ThreadsafeTable) getUserCount_safe() int {
  318. return t.getPlayerCount() + t.getWatcherCount()
  319. }
  320. func (t *ThreadsafeTable) onTableMessage_safe(userIndex int32, msg, data string) bool {
  321. usr := gate.GetUserInfo(userIndex)
  322. if usr == nil {
  323. log.Debug("ThreadsafeTable.onTableMessage user not found %d", userIndex)
  324. return false
  325. }
  326. if gameFrame.gameSink.GetChairCount() >= 2 && !usr.IsPlayer() {
  327. log.Debug("ThreadsafeTable.onTableMessage not a player %d", usr.GetUserIndex())
  328. return false
  329. }
  330. switch {
  331. default:
  332. // 如果是发送表情道具,则加入任务
  333. if msg == "CMD_TABLECHAT" {
  334. if strings.Contains(data, "3/") {
  335. task.DoTaskAction(usr.GetUserId(), task.TaskAction_gameinteract, 1, task.TaskScope{})
  336. }
  337. }
  338. return t.tableSink.OnGameMessage(userIndex, msg, data)
  339. }
  340. }
  341. func (t *ThreadsafeTable) UserWatch(userIndex int32) {
  342. // 如果用户不是playing状态,直接转换成watch即可
  343. usr := t.GetPlayer(userIndex)
  344. if usr == nil {
  345. log.Debug("ThreadsafeTable.UserWatch user %d not exist", userIndex)
  346. return
  347. }
  348. toWatch := true
  349. if usr.IsRobot() {
  350. toWatch = false
  351. }
  352. chairId := usr.GetUserChairId()
  353. if chairId < 0 || chairId >= t.chairCount {
  354. return
  355. }
  356. if usr.GetUserStatus() != user.UserStatus_Play {
  357. //gameFrame.setUserStatus(userIndex, user.UserStatus_Watch)
  358. t.RemoveUser_safe(userIndex, toWatch, false)
  359. return
  360. }
  361. }
  362. func (t *ThreadsafeTable) SetUserReadyStatus(userIndex int32, isReady bool) bool {
  363. defer utils.TimeCost(fmt.Sprintf("ThreadsafeTable.SetUserReadyStatus %d", userIndex))()
  364. usr := t.GetPlayer(userIndex)
  365. if usr == nil {
  366. log.Debug("ThreadsafeTable.SetUserReadyStatus failed user[%d] not exist", userIndex)
  367. return false
  368. }
  369. chairId := usr.GetUserChairId()
  370. if chairId < 0 {
  371. log.Debug("ThreadsafeTable.SetUserReadyStatus failed chairId = %d", chairId)
  372. return false
  373. }
  374. curStatus := usr.GetUserStatus()
  375. if isReady && curStatus != user.UserStatus_Sit {
  376. log.Debug("ThreadsafeTable.SetUserReady %d user status[%d] not sit", userIndex, curStatus)
  377. return false
  378. }
  379. if !isReady && curStatus != user.UserStatus_Ready {
  380. log.Debug("ThreadsafeTable.CancelUserReady %d user status[%d] not ready", userIndex, curStatus)
  381. return false
  382. }
  383. newStatus := user.UserStatus_Ready
  384. if !isReady {
  385. newStatus = user.UserStatus_Sit
  386. }
  387. if isReady && t.isPrivate() {
  388. // 游戏已经结束,不能再开始了
  389. if privateroom.GetRoomStatus(t.roomNo) == privateroom.PrivateRoomStatus_Ended {
  390. log.Release("ThreadsafeTable.SetUserReadyStatus to ready failed privateroom ended")
  391. return false
  392. }
  393. }
  394. // 设置状态并广播状态变化
  395. gameFrame.setUserStatus(userIndex, newStatus)
  396. // 回调给游戏
  397. t.onUserReady(userIndex, chairId, isReady)
  398. return true
  399. }
  400. func (t *ThreadsafeTable) setBaseScore_safe(baseScore int) {
  401. t.tableSink.OnBaseScoreChanged(baseScore)
  402. }
  403. func (t *ThreadsafeTable) Destroy() {
  404. t.stopped = true
  405. close(t.stopChan)
  406. }
  407. func (t *ThreadsafeTable) addWatchUser(userIndex int32, chair int, userId int) {
  408. if chair < 0 || chair >= t.chairCount {
  409. log.Debug("addWatchUser %d,%d", userIndex, chair)
  410. chair = 0
  411. }
  412. for _, v := range t.watchUsers {
  413. if v.UserIndex == userIndex {
  414. log.Debug("ThreadsafeTable.addWatchUser userIndex %d already exist", userIndex)
  415. v.ChairId = chair
  416. return
  417. }
  418. }
  419. t.watchUsers = append(t.watchUsers, WatchUser{UserIndex: userIndex, ChairId: chair, UserId: userId})
  420. }
  421. func (t *ThreadsafeTable) removeWatchUser(userIndex int32, userId int) {
  422. for i := 0; i < len(t.watchUsers); {
  423. if t.watchUsers[i].UserIndex == userIndex {
  424. if userId > 0 {
  425. t.sendUserExit(userId, 0, userIndex, false)
  426. t.broadcastUserExit(userId, 0, false)
  427. }
  428. t.watchUsers = append(t.watchUsers[:i], t.watchUsers[i+1:]...)
  429. if gameFrame.gameSink.GetChairCount() >= 2 {
  430. t.checkEmpty(false)
  431. }
  432. return
  433. } else {
  434. i++
  435. }
  436. }
  437. log.Debug("ThreadsafeTable.removeWatchUser userIndex %d not exist", userIndex)
  438. }
  439. func (t *ThreadsafeTable) isTableCloseByLogic() bool {
  440. gameSink_FishRoom, ok := gameFrame.gameSink.(GameSink_FishRoom)
  441. if !ok {
  442. return false
  443. }
  444. return gameSink_FishRoom.IsTableCloseByLogic()
  445. }
  446. func (t *ThreadsafeTable) ignoreSameIP() bool {
  447. gameSink_FishRoom, ok := gameFrame.gameSink.(GameSink_FishRoom)
  448. if !ok {
  449. return false
  450. }
  451. return gameSink_FishRoom.IgnoreSameIP()
  452. }
  453. func (t *ThreadsafeTable) enterPlayingRoomFirst() bool {
  454. gameSink_FishRoom, ok := gameFrame.gameSink.(GameSink_FishRoom)
  455. if !ok {
  456. return false
  457. }
  458. return gameSink_FishRoom.EnterPlayingRoomFirst()
  459. }
  460. func (t *ThreadsafeTable) checkEmpty(playerLeft bool) bool {
  461. if t.isTableCloseByLogic() {
  462. return false
  463. }
  464. // 私人场旁观离开不检查
  465. if gameFrame.gameSink.IsPrivateRoom() && !playerLeft {
  466. return false
  467. }
  468. for i := 0; i < t.chairCount; i++ {
  469. if t.users[i] == -1 {
  470. continue
  471. }
  472. return false
  473. }
  474. if len(t.watchUsers) > 0 {
  475. return false
  476. }
  477. go gameFrame.removeTable(t.tableId)
  478. return true
  479. }
  480. func (t *ThreadsafeTable) privateRoomStatusChanged_safe(oldStatus int, newStatus int) {
  481. t.tableSink_privateRoom.OnPrivateRoomStatusChanged(oldStatus, newStatus)
  482. }
  483. func (t *ThreadsafeTable) privateRoomDismissed_safe() {
  484. t.tableSink_privateRoom.OnPrivateRoomDismissed()
  485. t.SendGameData(-1, message.Frame_PrivateRoom_Dismissed, "")
  486. // 如果是百人游戏,先不要解散
  487. if gameFrame.gameSink.GetChairCount() < 2 {
  488. return
  489. }
  490. t.dismiss_safe()
  491. }
  492. func (t *ThreadsafeTable) kickUser(toUserIndex int32) bool {
  493. ret := false
  494. for i := 0; i < t.chairCount; i++ {
  495. if t.users[i] == toUserIndex {
  496. ret = t.KickUserByChair(i, false)
  497. break
  498. }
  499. }
  500. return ret
  501. }