hub.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. package game
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. "microGame/app/usercenter/cmd/api/internal/types"
  7. "microGame/pkg/common"
  8. "microGame/pkg/result"
  9. "sync"
  10. "time"
  11. )
  12. // Hub maintains the set of active Players and broadcasts messages to the Players.
  13. type Hub struct {
  14. Rooms map[int64]*Room // 保存所有连接实例
  15. Players map[int64]*Player // 保存所有连接实例
  16. Broadcast chan []byte // 消息存放在这里
  17. Register chan *Player
  18. Unregister chan *Player
  19. Mutex sync.Mutex // 并发安全锁
  20. }
  21. func NewHub() *Hub {
  22. return &Hub{
  23. Broadcast: make(chan []byte),
  24. Register: make(chan *Player),
  25. Unregister: make(chan *Player),
  26. Rooms: make(map[int64]*Room),
  27. Players: make(map[int64]*Player),
  28. }
  29. }
  30. func (r *Hub) Run() {
  31. // 启动调度任务
  32. //go r.GoCronRoom(3 * time.Second)
  33. for {
  34. select {
  35. case player := <-r.Register:
  36. r.handleRegister(player)
  37. case player := <-r.Unregister:
  38. r.handleUnregister(player)
  39. case message := <-r.Broadcast:
  40. r.handleBroadcast(message)
  41. }
  42. }
  43. }
  44. // 处理用户注册逻辑 此处仅仅记录所有的长连接用户
  45. func (r *Hub) handleRegister(o *Player) {
  46. if _, ok := r.Players[o.Uid]; !ok {
  47. r.Players[o.Uid] = o
  48. }
  49. o.WriteMsg(result.WSSuccess("register", types.MSG_SUCCESS))
  50. fmt.Printf("Player %d registered in Players", o.Uid)
  51. }
  52. // 处理用户注销逻辑
  53. func (r *Hub) handleUnregister(p *Player) {
  54. if r.removePlayerFromRoom(p.Uid, p.RoomId) {
  55. close(p.Send)
  56. close(p.actions)
  57. }
  58. r.tellUserLeave(p)
  59. fmt.Printf("Player %d unregistered from Room %d\n", p.Uid, p.RoomId)
  60. }
  61. // 处理消息广播逻辑
  62. func (r *Hub) handleBroadcast(message []byte) {
  63. d := &types.WSMessage{}
  64. if err := json.Unmarshal(message, d); err != nil {
  65. fmt.Printf("Failed to unmarshal message: %v\n", err)
  66. return
  67. }
  68. switch d.Type {
  69. case "join":
  70. //判断游戏是否开始,如果游戏已经开始 用户进入观察者组;如果没开始 用户直接进入room
  71. room, code := r.addPlayerToRoom(d)
  72. if code == 200 {
  73. room.startGame()
  74. }
  75. case "leave":
  76. r.removePlayerFromRoom(d.Uid, d.Rid)
  77. log.Printf("玩家/观察者 %d 退出", d.Uid)
  78. case "destroy":
  79. r.destroyRoom(d.Rid)
  80. log.Printf("玩家/观察者 %d 退出", d.Uid)
  81. case "bet":
  82. room, exists := r.Rooms[d.Rid]
  83. if exists {
  84. room.bet(d, r.Players[d.Uid])
  85. }
  86. log.Printf("玩家下注 %d 退出", d.Uid)
  87. case "sitDown":
  88. room, exists := r.Rooms[d.Rid]
  89. if exists {
  90. room.sitDown(d, r.Players[d.Uid])
  91. }
  92. case "standUp":
  93. room, exists := r.Rooms[d.Rid]
  94. if exists {
  95. room.standUp(d, r.Players[d.Uid])
  96. }
  97. default:
  98. log.Println("未知消息类型:", d.Type)
  99. }
  100. }
  101. // 将玩家添加到房间
  102. func (r *Hub) addPlayerToRoom(d *types.WSMessage) (*Room, int) {
  103. r.Mutex.Lock()
  104. o, ok := r.Players[d.Uid]
  105. if !ok {
  106. r.Mutex.Unlock()
  107. log.Printf("观察者 %s 加入房间", o.Username)
  108. return nil, -1000
  109. }
  110. room, exists := r.Rooms[d.Rid]
  111. if !exists {
  112. room = NewRoom(9, SB, BB, CHIPS, Timeout)
  113. r.Rooms[d.Rid] = room
  114. }
  115. r.Mutex.Unlock()
  116. //加入房间之前先判断房间是否已经满了
  117. if room.Len() >= room.Cap() {
  118. o.WriteMsg(result.WSError("register", types.MSG_ROOM_FULL, -1001))
  119. return nil, -1001
  120. }
  121. joinRoom := &types.JoinRoom{Uid: d.Uid, RoomNumber: r.Rooms[d.Rid].RoomNumber, RoomPwd: ""}
  122. res := room.joinRoom(joinRoom, o)
  123. if !res {
  124. return nil, -1002
  125. }
  126. return room, 200
  127. }
  128. // 从房间移除玩家
  129. func (r *Hub) removePlayerFromRoom(uid int64, rid int64) bool {
  130. r.Mutex.Lock()
  131. defer r.Mutex.Unlock()
  132. p, ok := r.Players[uid]
  133. if !ok {
  134. r.Mutex.Unlock()
  135. log.Printf("从房间移除玩家 %s", p.Username)
  136. return false
  137. }
  138. room, exists := r.Rooms[rid]
  139. if !exists {
  140. return false
  141. }
  142. p.RoomId = 0
  143. room.removePlayer(p)
  144. room.removeObserve(p)
  145. return true
  146. }
  147. // CreateRoom 创建房间
  148. func (r *Hub) CreateRoom(uid int64) *Room {
  149. r.Mutex.Lock()
  150. defer r.Mutex.Unlock()
  151. p, ok := r.Players[uid]
  152. if !ok {
  153. return nil
  154. }
  155. room, exists := r.Rooms[p.RoomId]
  156. if !exists {
  157. room = NewRoom(9, SB, BB, CHIPS, Timeout)
  158. r.Rooms[p.RoomId] = room
  159. p.RoomId = room.Rid
  160. fmt.Printf("房间 %d 创建成功\n", p.RoomId)
  161. return room
  162. }
  163. fmt.Printf("房间 %d 已存在\n", p.RoomId)
  164. go room.startGame()
  165. return room
  166. }
  167. // GoCronRoom 启动房间 Goroutine
  168. func (r *Hub) GoCronRoom(tickerInterval time.Duration) {
  169. ticker := time.NewTicker(tickerInterval)
  170. defer ticker.Stop()
  171. for {
  172. select {
  173. case <-ticker.C:
  174. r.checkAndStartRooms()
  175. }
  176. }
  177. }
  178. func (r *Hub) checkAndStartRooms() {
  179. r.Mutex.Lock()
  180. rooms := make(map[int64]*Room, len(r.Rooms))
  181. for rid, v := range r.Rooms {
  182. rooms[rid] = v
  183. }
  184. r.Mutex.Unlock()
  185. for rid, room := range rooms {
  186. if room == nil || room.isEmpty() {
  187. r.destroyRoom(rid) // 清理无效或空房间
  188. continue
  189. }
  190. // 防止重复启动
  191. if room.isRunning {
  192. continue
  193. }
  194. // 标记房间正在运行
  195. room.isRunning = true
  196. go common.RunWithRecover(func() {
  197. room.startGame()
  198. })
  199. }
  200. }
  201. // **destroyRoom**: 房间销毁时调用
  202. func (r *Hub) destroyRoom(roomID int64) {
  203. //如果房间中游戏正在进行中 不允许销毁房间
  204. r.Mutex.Lock()
  205. room, exists := r.Rooms[roomID]
  206. if !exists {
  207. r.Mutex.Unlock()
  208. return
  209. }
  210. if room.status == 1 {
  211. r.Mutex.Unlock()
  212. return
  213. }
  214. // 关闭房间,通知 Goroutine 退出
  215. room.CloseRoomChannel()
  216. delete(r.Rooms, roomID) // 从 Hub 中删除
  217. r.Mutex.Unlock()
  218. log.Printf("房间 %d 已销毁\n", roomID)
  219. }
  220. // GetRoom 获取房间
  221. func (r *Hub) GetRoom(roomID int64) *Room {
  222. if room, exists := r.Rooms[roomID]; exists {
  223. return room
  224. }
  225. return nil
  226. }
  227. // DeleteRoom 删除房间
  228. func (r *Hub) DeleteRoom(roomID int64) {
  229. r.Mutex.Lock()
  230. defer r.Mutex.Unlock()
  231. delete(r.Rooms, roomID)
  232. }
  233. // 用户离开 广播给所有其他会员用户离开
  234. func (r *Hub) tellUserLeave(o *Player) {
  235. r.Mutex.Lock()
  236. room, exists := r.Rooms[o.RoomId]
  237. r.Mutex.Unlock() // 提前释放锁,避免阻塞
  238. if !exists {
  239. o.WriteMsg(result.WSSuccess("register", types.MSG_NOT_IN_ROOM))
  240. return
  241. }
  242. // 构造广播消息
  243. msg := &types.WSMessage{
  244. Type: "leave",
  245. Data: "",
  246. Uid: 100,
  247. Rid: 100,
  248. }
  249. // 发送广播
  250. room.Broadcast(result.WSSuccess("leave", msg), true, 100)
  251. }
  252. //func (r *Hub) getMapKeys(m map[int64]*Player) []int64 {
  253. // keys := make([]int64, 0, len(m))
  254. // for k := range m {
  255. // keys = append(keys, k)
  256. // }
  257. // return keys
  258. //}