package store import ( "context" "errors" "fmt" "sonet/api/gen/mahjong" "sonet/internal/mahjong/game" "sonet/internal/mahjong/helper" "sonet/pkg/protocol/deliver" "sonet/pkg/utils/collect" "sonet/pkg/utils/logger" "strconv" "sync" "sync/atomic" ) type Store struct { players *sync.Map // tables *sync.Map // 在线麻将牌桌列表 prevTableId int32 deliver *deliver.Deliver } func NewStore(deliver *deliver.Deliver) *Store { return &Store{ players: &sync.Map{}, tables: &sync.Map{}, prevTableId: 10000, deliver: deliver, } } func (s *Store) StorePlayer(player *game.MjPlayer) { v, ok := s.players.Load(player.PlayerId) if ok { if v == player { return } else { v.(*game.MjPlayer).Close() } } s.players.Store(player.PlayerId, player) c, done := player.Chan() go func() { for { select { case <-done: return case setState := <-c: fmt.Println("player states:", setState) mjState, err := helper.SetState2MjSetState(setState) if err != nil { logger.Error(err) continue } msg := &mahjong.NoticePlayerState{PlayerId: player.PlayerId, State: mjState} var receivers []string if setState.Broadcast { // 广播 if player.MjTable != nil { receivers = player.MjTable.GetPlayerIds(setState.ExcludeReceivers...) } else if collect.NotIn(player.PlayerId, setState.ExcludeReceivers...) { receivers = []string{player.PlayerId} } } else { receivers = setState.IncludeReceivers } if len(receivers) > 0 { // deliver player state change _, _ = s.deliver.DeliverBatch(context.Background(), msg, receivers) } } } }() } func (s *Store) RemovePlayer(playerId string) { defer func() { s.players.Delete(playerId) }() v, ok := s.players.Load(playerId) if !ok { return } v.(*game.MjPlayer).Close() } func (s *Store) StoreTable(table *game.MjTable) { v, ok := s.tables.Load(table.TableId) if ok { if v == table { return } else { v.(*game.MjTable).Close() } } s.tables.Store(table.TableId, table) c, done := table.Chan() go func() { for { select { case <-done: return case setState := <-c: fmt.Println("table states:", setState) mjState, err := helper.SetState2MjSetState(setState) if err != nil { logger.Error(err) continue } msg := &mahjong.NoticeTableState{State: mjState} var receivers []string if setState.Broadcast { // 广播 receivers = table.GetPlayerIds(setState.ExcludeReceivers...) } else { receivers = setState.IncludeReceivers } if len(receivers) > 0 { // deliver players table state change _, _ = s.deliver.DeliverBatch(context.Background(), msg, receivers) } } } }() } func (s *Store) RemoveTable(tableId string) { defer func() { s.tables.Delete(tableId) }() v, ok := s.tables.Load(tableId) if !ok { return } v.(*game.MjTable).Close() } func (s *Store) RangeTable(f func(key, value any) bool) { s.tables.Range(f) } func (s *Store) NextTableId() string { tid := atomic.AddInt32(&s.prevTableId, 1) return strconv.Itoa(int(tid)) } func (s *Store) LoadPlayer(playerId string) (*game.MjPlayer, error) { val, ok := s.players.Load(playerId) if !ok { return nil, errors.New("玩家已离线") } return val.(*game.MjPlayer), nil } func (s *Store) LoadTable(tableId string) (*game.MjTable, error) { val, ok := s.tables.Load(tableId) if !ok { return nil, errors.New("牌桌不存在") } return val.(*game.MjTable), nil }