threadsafe_table.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. package frame
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "math/rand"
  6. "sync"
  7. "time"
  8. "bet24.com/log"
  9. "bet24.com/servers/insecureframe/gate"
  10. audioroom "bet24.com/servers/micros/audioroom/proto"
  11. privateroom "bet24.com/servers/micros/privateroom/proto"
  12. "bet24.com/servers/user"
  13. "bet24.com/utils"
  14. )
  15. type WatchUser struct {
  16. UserIndex int32
  17. ChairId int
  18. UserId int
  19. }
  20. type ThreadsafeTable struct {
  21. tableSink TableSink
  22. tableSink_privateRoom TableSink_PrivateRoom
  23. users []int32
  24. tableId int
  25. chairCount int
  26. tableStatus int
  27. multiSetStatus int
  28. privateData string
  29. watchUsers []WatchUser
  30. startTime int64
  31. timers map[int]*time.Timer
  32. stopChan chan int
  33. timerChan chan int
  34. messageChan chan *threadsafe_message
  35. timerLock *sync.RWMutex
  36. owner int // 桌主,如果大于0表示私人房间,桌主离开后房间解散
  37. roomNo int
  38. dismissRequest []int
  39. dismissTimer *time.Timer
  40. stopped bool
  41. createTime int64
  42. tmpUserBets []audioroom.UserBet
  43. reportUserBetsTimer *time.Timer
  44. }
  45. func newThreadSafeTable(tableId int, owner int) *ThreadsafeTable {
  46. t := new(ThreadsafeTable)
  47. t.tableId = tableId
  48. t.timers = make(map[int]*time.Timer)
  49. t.stopChan = make(chan int)
  50. t.timerChan = make(chan int)
  51. t.timerLock = &sync.RWMutex{}
  52. t.messageChan = make(chan *threadsafe_message)
  53. t.owner = owner
  54. t.createTime = time.Now().Unix()
  55. return t
  56. }
  57. func (t *ThreadsafeTable) setRoomNo(roomNo int) {
  58. t.roomNo = roomNo
  59. }
  60. func (t *ThreadsafeTable) isPrivate() bool {
  61. return t.owner != 0
  62. }
  63. func (t *ThreadsafeTable) isMatch() bool {
  64. return t.owner == -1
  65. }
  66. func (t *ThreadsafeTable) setTableSink(sink TableSink) {
  67. t.tableSink = sink
  68. if t.isPrivate() {
  69. mid := (sink.(interface{})).(TableSink_PrivateRoom)
  70. t.tableSink_privateRoom = mid
  71. t.dismissRequest = make([]int, t.tableSink.OnGetChairCount())
  72. }
  73. t.clear()
  74. go t.mainLoop()
  75. }
  76. func (t *ThreadsafeTable) clear() {
  77. t.chairCount = t.tableSink.OnGetChairCount()
  78. t.users = make([]int32, t.chairCount)
  79. for i := 0; i < t.chairCount; i++ {
  80. t.users[i] = -1
  81. }
  82. }
  83. // 主线程
  84. func (t *ThreadsafeTable) mainLoop() {
  85. log.Debug("newThreadSafeTable tableId[%d] running", t.tableId)
  86. for {
  87. select {
  88. case <-t.stopChan:
  89. log.Debug("ThreadsafeTable tableId[%d] exiting mainLoop", t.tableId)
  90. t.tableSink.Destroy()
  91. t.killAllTimer()
  92. if t.isPrivate() {
  93. privateroom.ClosePrivateRoom(t.roomNo)
  94. t.roomNo = 0
  95. }
  96. return
  97. case timerId := <-t.timerChan:
  98. start := time.Now()
  99. t.tableSink.OnTimer(timerId)
  100. tc := time.Since(start)
  101. if tc.Milliseconds() >= 200 {
  102. log.Release("ThreadsafeTable.handleTimer[%d] run cost %v", timerId, tc)
  103. }
  104. case msg := <-t.messageChan:
  105. t.handleMsg(msg.Msg, msg.Data, msg.Callback)
  106. }
  107. }
  108. }
  109. func (t *ThreadsafeTable) handleMsg(msg, data string, callback chan byte) {
  110. if callback != nil {
  111. defer func() {
  112. callback <- 1
  113. }()
  114. }
  115. defer utils.TimeCost(fmt.Sprintf("ThreadsafeTable.handleMsg[%s],%s", msg, data))()
  116. switch msg {
  117. case "AddUser":
  118. var addUser msg_AddUser
  119. err := json.Unmarshal([]byte(data), &addUser)
  120. if err != nil {
  121. log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
  122. return
  123. }
  124. t.AddUser_safe(addUser.UserIndex, addUser.ChairId, addUser.Replay, addUser.ToWatch)
  125. case "RemoveUser":
  126. var removeUser msg_RemoveUser
  127. err := json.Unmarshal([]byte(data), &removeUser)
  128. if err != nil {
  129. log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
  130. return
  131. }
  132. t.RemoveUser_safe(removeUser.UserIndex, removeUser.ToWatch, removeUser.ChangeTable)
  133. case "dismiss":
  134. t.dismiss_safe()
  135. case "userReplay":
  136. var replay msg_UserReplay
  137. err := json.Unmarshal([]byte(data), &replay)
  138. if err != nil {
  139. log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
  140. return
  141. }
  142. t.userReplay_safe(replay.OldUserIndex, replay.NewUserIndex)
  143. case "dump":
  144. t.dump_safe()
  145. case "dumpScene":
  146. t.dumpScene_safe()
  147. case "dumpTimers":
  148. t.dumpTimers_safe()
  149. case "TableMessage":
  150. var tm msg_TableMessage
  151. err := json.Unmarshal([]byte(data), &tm)
  152. if err != nil {
  153. log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
  154. return
  155. }
  156. t.onTableMessage_safe(tm.UserIndex, tm.Msg, tm.Data)
  157. case "UserWatch":
  158. var watch msg_UserIndex
  159. err := json.Unmarshal([]byte(data), &watch)
  160. if err != nil {
  161. log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
  162. return
  163. }
  164. t.UserWatch(watch.UserIndex)
  165. case "SetUserReadyStatus":
  166. var ready msg_SetReadyStatus
  167. err := json.Unmarshal([]byte(data), &ready)
  168. if err != nil {
  169. log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
  170. return
  171. }
  172. t.SetUserReadyStatus(ready.UserIndex, ready.IsReady)
  173. case "SetBaseScore":
  174. var baseScore msg_SetBaseScore
  175. err := json.Unmarshal([]byte(data), &baseScore)
  176. if err != nil {
  177. log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
  178. return
  179. }
  180. t.setBaseScore_safe(baseScore.BaseScore)
  181. case "privateRoomStatusChanged":
  182. var statusChanged msg_statusChanged
  183. err := json.Unmarshal([]byte(data), &statusChanged)
  184. if err != nil {
  185. log.Debug("ThreadsafeTable.handleMsg %s error %v", msg, err)
  186. return
  187. }
  188. t.privateRoomStatusChanged_safe(statusChanged.OldStatus, statusChanged.NewStatus)
  189. case "privateRoomDismissed":
  190. t.privateRoomDismissed_safe()
  191. default:
  192. log.Debug("ThreadsafeTable.handleMsg unhandled %s", msg)
  193. }
  194. }
  195. func (t *ThreadsafeTable) getWatcherCount() int {
  196. return len(t.watchUsers)
  197. }
  198. func (t *ThreadsafeTable) getPlayerCount() int {
  199. count := 0
  200. for i := 0; i < t.chairCount; i++ {
  201. if t.users[i] != -1 {
  202. count++
  203. }
  204. }
  205. return count
  206. }
  207. func (t *ThreadsafeTable) getUserCount() int {
  208. return t.getPlayerCount() + t.getWatcherCount()
  209. }
  210. func (t *ThreadsafeTable) getEmptyChair() int {
  211. if t.tableSink.IsDual() {
  212. for i := 0; i < 3; i += 2 {
  213. if t.users[i] == -1 {
  214. return i
  215. }
  216. }
  217. return -1
  218. }
  219. // 随机分配
  220. start := rand.Intn(t.chairCount)
  221. for i := 0; i < t.chairCount; i++ {
  222. chair := (start + i) % t.chairCount
  223. if t.users[chair] == -1 {
  224. return chair
  225. }
  226. }
  227. return -1
  228. }
  229. func (t *ThreadsafeTable) isChairEmpty(chairId int) bool {
  230. if chairId < 0 || chairId >= t.chairCount {
  231. return false
  232. }
  233. if t.tableSink.IsDual() && chairId != 0 && chairId != 2 {
  234. log.Debug("ThreadsafeTable.isChairEmpty isdual and %d", chairId)
  235. return false
  236. }
  237. return t.users[chairId] == -1
  238. }
  239. func (t *ThreadsafeTable) isValidChair(chairId int) bool {
  240. return chairId >= 0 && chairId < t.tableSink.OnGetChairCount()
  241. }
  242. func (t *ThreadsafeTable) removeAllWatchUsers() {
  243. for _, v := range t.watchUsers {
  244. go gameFrame.setUserStatus(v.UserIndex, user.UserStatus_Free)
  245. }
  246. t.watchUsers = []WatchUser{}
  247. }
  248. func (t *ThreadsafeTable) getStartTime() int64 {
  249. if t.tableStatus != TableStatus_Playing {
  250. return 0
  251. }
  252. return time.Now().Unix() - t.startTime
  253. }
  254. func (t *ThreadsafeTable) isIdled() bool {
  255. return t.getStartTime() >= 300
  256. }
  257. func (t *ThreadsafeTable) isAllRobot() bool {
  258. return t.tableSink.IsAllRobot()
  259. }
  260. func (t *ThreadsafeTable) isFull() bool {
  261. if t.tableSink.IsDual() {
  262. for i := 0; i < 3; i += 2 {
  263. if t.users[i] == -1 {
  264. return false
  265. }
  266. }
  267. return true
  268. }
  269. for i := 0; i < t.chairCount; i++ {
  270. if t.users[i] == -1 {
  271. return false
  272. }
  273. }
  274. return true
  275. }
  276. func (t *ThreadsafeTable) isSameRoom(data string) bool {
  277. if len(data) == 0 {
  278. return true
  279. }
  280. return data == t.privateData
  281. }
  282. func (t *ThreadsafeTable) checkSameIp(userIp string) bool {
  283. // 百人场不限制
  284. if gameFrame.gameSink.GetChairCount() < 2 {
  285. return false
  286. }
  287. if t.ignoreSameIP() {
  288. return false
  289. }
  290. // 机器人不限制
  291. if userIp == "" || userIp == "127.0.0.1" {
  292. return false
  293. }
  294. // 2人场 不限制
  295. if t.tableSink.IsDual() {
  296. return false
  297. }
  298. for i := 0; i < t.chairCount; i++ {
  299. if t.users[i] == -1 {
  300. continue
  301. }
  302. usr := gate.GetUserInfo(t.users[i])
  303. if usr == nil {
  304. continue
  305. }
  306. if usr.GetUserIp() == userIp {
  307. return true
  308. }
  309. }
  310. // 如果有旁观也挡一下
  311. for _, v := range t.watchUsers {
  312. usr := gate.GetUserInfo(v.UserIndex)
  313. if usr == nil {
  314. continue
  315. }
  316. if usr.GetUserIp() == userIp {
  317. return true
  318. }
  319. }
  320. return false
  321. }
  322. func (t *ThreadsafeTable) canRemoveOneRobot() bool {
  323. // 这个函数有锁死风险
  324. if true {
  325. return false
  326. }
  327. if t.tableSink.IsDual() {
  328. for i := 0; i < 3; i += 2 {
  329. if t.users[i] == -1 {
  330. return false
  331. }
  332. usr := gate.GetUserInfo(t.users[i])
  333. if usr == nil {
  334. t.users[i] = -1
  335. return false
  336. }
  337. if usr.IsRobot() {
  338. t.RemoveUser(t.users[i], false, false)
  339. return true
  340. }
  341. }
  342. return false
  343. }
  344. for i := 0; i < t.chairCount; i++ {
  345. if t.users[i] == -1 {
  346. return false
  347. }
  348. usr := gate.GetUserInfo(t.users[i])
  349. if usr == nil {
  350. t.users[i] = -1
  351. return false
  352. }
  353. if usr.IsRobot() {
  354. t.RemoveUser(t.users[i], false, false)
  355. return true
  356. }
  357. }
  358. return false
  359. }
  360. func (t *ThreadsafeTable) adjustPrivateChairId(chairId int) int {
  361. if !t.isPrivate() {
  362. return chairId
  363. }
  364. if t.tableSink.OnGetChairCount() == 4 && t.tableSink.IsDual() && chairId == 1 {
  365. return 2
  366. }
  367. return chairId
  368. }