You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

166 lines
3.6 KiB

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 // <playerId string, *MjPlayer>
tables *sync.Map // <tableId string, *MjTable> 在线麻将牌桌列表
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 {
continue
}
_, err = s.deliver.DeliverBatch(context.Background(), msg, receivers)
if err != nil {
logger.Error("deliver batch store state error: ", err)
continue
}
}
}
}()
}
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
}