21 changed files with 305 additions and 163 deletions
@ -0,0 +1,30 @@
|
||||
package delayer |
||||
|
||||
import ( |
||||
"fmt" |
||||
"runtime/debug" |
||||
"texas-poker-bk/tool/async" |
||||
"time" |
||||
) |
||||
|
||||
var ( |
||||
GameDelayer *async.DelayQueue[func()] |
||||
) |
||||
|
||||
func init() { |
||||
GameDelayer = async.NewDelayQueue(time.Second, 128, handleDelayTask) |
||||
} |
||||
|
||||
func handleDelayTask(task func(), _ time.Time) { |
||||
if task == nil { |
||||
return |
||||
} |
||||
defer func() { |
||||
if err := recover(); err != nil { |
||||
fmt.Printf("consumer handler error: %v \n", err) |
||||
// 输出堆栈信息
|
||||
fmt.Println(string(debug.Stack())) |
||||
} |
||||
}() |
||||
task() |
||||
} |
||||
@ -0,0 +1,62 @@
|
||||
package event |
||||
|
||||
import ( |
||||
"texas-poker-bk/internal/game" |
||||
"texas-poker-bk/internal/logic/store" |
||||
"texas-poker-bk/tool/collect" |
||||
"texas-poker-bk/tool/watcher" |
||||
) |
||||
|
||||
// 回合结束时,自动清除离线玩家
|
||||
|
||||
var ( |
||||
GameRoundEndWatcher *watcher.Watcher[int32, bool] |
||||
) |
||||
|
||||
func init() { |
||||
GameRoundEndWatcher = watcher.NewWatcher(32, handleGameRoundEnd) |
||||
go GameRoundEndWatcher.Run() |
||||
} |
||||
|
||||
func handleGameRoundEnd(e *watcher.Event[int32, bool]) { |
||||
table := game.LobbyTables.Get(e.Publisher) |
||||
if table == nil || collect.NotIn(table.Stage, 1, 7) { |
||||
return |
||||
} |
||||
table.Lock.Lock() |
||||
defer table.Lock.Unlock() |
||||
table.PlayersLock.Lock() |
||||
defer table.PlayersLock.Unlock() |
||||
|
||||
notice := true |
||||
for i, player := range table.Players { |
||||
if player == nil { |
||||
continue |
||||
} |
||||
if !player.Client.IsOnline() { |
||||
// 踢了
|
||||
table.Players[i] = nil |
||||
// 结算玩家金额
|
||||
store.NetAccounts.Get(player.Id).SettlePlayerChip() |
||||
// 被踢玩家消息
|
||||
// player.Client.Write(&api.ResKickOutTable{})
|
||||
|
||||
// 该离线玩家是房主, 房主给到下个位置玩家
|
||||
if table.MasterId == player.Id { |
||||
nextMasterPos := table.NextPlayerPos(i) |
||||
if nextMasterPos == i { |
||||
// 没有玩家了, 解散牌桌
|
||||
notice = false |
||||
table.Stage = 9 |
||||
game.LobbyTables.Delete(player.GameTable.TableNo) |
||||
return |
||||
} |
||||
table.MasterId = table.Players[nextMasterPos].Id |
||||
} |
||||
} |
||||
} |
||||
// 通知牌桌所有玩家
|
||||
if notice { |
||||
table.NoticeGameFullStatus() |
||||
} |
||||
} |
||||
@ -0,0 +1,22 @@
|
||||
package game |
||||
|
||||
import ( |
||||
"strconv" |
||||
"sync/atomic" |
||||
"texas-poker-bk/tool/cache" |
||||
) |
||||
|
||||
// LobbyTables 存储当前进行中的牌桌
|
||||
var ( |
||||
TableNo = &atomic.Int32{} // 牌桌编号计数器
|
||||
LobbyTables *cache.KVCache[int32, *Table] |
||||
) |
||||
|
||||
func init() { |
||||
TableNo = &atomic.Int32{} // 牌桌编号计数器
|
||||
|
||||
var tableZeroValue *Table = nil |
||||
LobbyTables = cache.NewKVCache(tableZeroValue, func(k int32) string { |
||||
return strconv.Itoa(int(k)) |
||||
}) |
||||
} |
||||
@ -1,11 +1,11 @@
|
||||
package event |
||||
package delayer |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/golang/protobuf/proto" |
||||
"texas-poker-bk/api" |
||||
"texas-poker-bk/internal/game" |
||||
"texas-poker-bk/internal/service/store" |
||||
"texas-poker-bk/internal/logic/store" |
||||
"texas-poker-bk/tool/async" |
||||
"time" |
||||
) |
||||
@ -0,0 +1,25 @@
|
||||
package delayer |
||||
|
||||
import ( |
||||
"texas-poker-bk/internal/logic/store" |
||||
"texas-poker-bk/tool/async" |
||||
"time" |
||||
) |
||||
|
||||
// 清理离线用户
|
||||
|
||||
var ( |
||||
OfflineCleanDelayer *async.DelayQueue[int64] |
||||
) |
||||
|
||||
func init() { |
||||
OfflineCleanDelayer = async.NewDelayQueue(time.Second, 128, removeMemoryAccount) |
||||
} |
||||
|
||||
// func removeMemoryAccount(account *session.NetAccount) {
|
||||
func removeMemoryAccount(accountId int64, now time.Time) { |
||||
_ = store.NetAccounts.Get(accountId) |
||||
store.NetAccounts.Delete(accountId) |
||||
store.TokenVersions.Delete(accountId) |
||||
// TODO 持久化账户金额
|
||||
} |
||||
@ -1,7 +1,7 @@
|
||||
package event |
||||
|
||||
import ( |
||||
"texas-poker-bk/internal/service/store" |
||||
"texas-poker-bk/internal/logic/store" |
||||
"texas-poker-bk/tool/watcher" |
||||
) |
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package service |
||||
package logic |
||||
|
||||
import ( |
||||
"bytes" |
||||
@ -0,0 +1,38 @@
|
||||
package store |
||||
|
||||
import ( |
||||
"strconv" |
||||
"texas-poker-bk/internal/session" |
||||
"texas-poker-bk/tool/cache" |
||||
) |
||||
|
||||
var ( |
||||
//TableNo *atomic.Int32
|
||||
|
||||
// LobbyTables 存储当前进行中的牌桌
|
||||
//LobbyTables *cache.KVCache[int32, *game.Table]
|
||||
|
||||
// NetAccounts 存储一下在线用户, TODO 连接终端,未在牌局或牌局未开始中回收账号,机器人代打后回收账号
|
||||
NetAccounts *cache.KVCache[int64, *session.NetAccount] |
||||
|
||||
// TokenVersions 存储token版本号,登录时+1,一个账户同一时间只允许一个token有效
|
||||
TokenVersions *cache.KVCache[int64, int32] |
||||
) |
||||
|
||||
func init() { |
||||
//TableNo = &atomic.Int32{} // 牌桌编号计数器
|
||||
|
||||
//var tableZeroValue *game.Table = nil
|
||||
//LobbyTables = cache.NewKVCache(tableZeroValue, func(k int32) string {
|
||||
// return strconv.Itoa(int(k))
|
||||
//})
|
||||
|
||||
var accountZeroValue *session.NetAccount = nil |
||||
NetAccounts = cache.NewKVCache(accountZeroValue, func(k int64) string { |
||||
return strconv.FormatInt(k, 10) |
||||
}) |
||||
|
||||
TokenVersions = cache.NewKVCache(int32(-1), func(k int64) string { |
||||
return strconv.FormatInt(k, 10) |
||||
}) |
||||
} |
||||
@ -1,94 +0,0 @@
|
||||
package store |
||||
|
||||
import ( |
||||
"github.com/patrickmn/go-cache" |
||||
"strconv" |
||||
"sync/atomic" |
||||
"texas-poker-bk/internal/game" |
||||
"texas-poker-bk/internal/session" |
||||
"time" |
||||
) |
||||
|
||||
var ( |
||||
TableNo *atomic.Int32 |
||||
|
||||
// LobbyTables 存储当前进行中的牌桌
|
||||
LobbyTables *Store[int32, *game.Table] |
||||
|
||||
// NetAccounts 存储一下在线用户, TODO 连接终端,未在牌局或牌局未开始中回收账号,机器人代打后回收账号
|
||||
NetAccounts *Store[int64, *session.NetAccount] |
||||
|
||||
// TokenVersions 存储token版本号,登录时+1,一个账户同一时间只允许一个token有效
|
||||
TokenVersions *Store[int64, int32] |
||||
) |
||||
|
||||
const ( |
||||
NoExpiration time.Duration = cache.NoExpiration |
||||
DefaultExpiration time.Duration = cache.DefaultExpiration |
||||
) |
||||
|
||||
func init() { |
||||
TableNo = &atomic.Int32{} // 牌桌编号计数器
|
||||
|
||||
var tableZeroValue *game.Table = nil |
||||
LobbyTables = NewStore(tableZeroValue, func(k int32) string { |
||||
return strconv.Itoa(int(k)) |
||||
}) |
||||
|
||||
var accountZeroValue *session.NetAccount = nil |
||||
NetAccounts = NewStore(accountZeroValue, func(k int64) string { |
||||
return strconv.FormatInt(k, 10) |
||||
}) |
||||
|
||||
TokenVersions = NewStore(int32(-1), func(k int64) string { |
||||
return strconv.FormatInt(k, 10) |
||||
}) |
||||
} |
||||
|
||||
type Store[K any, V any] struct { |
||||
c *cache.Cache |
||||
zeroValue V // 默认值
|
||||
k2str func(K) string |
||||
} |
||||
|
||||
func NewStore[K any, V any](zeroValue V, k2str func(K) string) *Store[K, V] { |
||||
return NewExpireStore(cache.NoExpiration, cache.NoExpiration, zeroValue, k2str) |
||||
} |
||||
|
||||
func NewExpireStore[K any, V any](defaultExpiration, cleanupInterval time.Duration, zeroValue V, k2str func(K) string) *Store[K, V] { |
||||
return &Store[K, V]{ |
||||
c: cache.New(defaultExpiration, cleanupInterval), |
||||
zeroValue: zeroValue, |
||||
k2str: k2str, |
||||
} |
||||
} |
||||
|
||||
func (s *Store[K, V]) SetDefault(k K, v V) { |
||||
s.c.SetDefault(s.k2str(k), v) |
||||
} |
||||
|
||||
func (s *Store[K, V]) Set(k K, v V, d time.Duration) { |
||||
s.c.Set(s.k2str(k), v, d) |
||||
} |
||||
|
||||
func (s *Store[K, V]) Get(k K) (zero V) { |
||||
v, found := s.c.Get(s.k2str(k)) |
||||
if !found { |
||||
return s.zeroValue |
||||
} |
||||
return v.(V) |
||||
} |
||||
|
||||
func (s *Store[K, V]) Delete(k K) { |
||||
s.c.Delete(s.k2str(k)) |
||||
} |
||||
|
||||
func (s *Store[K, V]) ForEach(f func(k string, v V)) { |
||||
for k, v := range s.c.Items() { |
||||
f(k, v.Object.(V)) |
||||
} |
||||
} |
||||
|
||||
func (s *Store[K, V]) Count() int { |
||||
return s.c.ItemCount() |
||||
} |
||||
@ -0,0 +1,59 @@
|
||||
package cache |
||||
|
||||
import ( |
||||
"github.com/patrickmn/go-cache" |
||||
"time" |
||||
) |
||||
|
||||
const ( |
||||
NoExpiration time.Duration = cache.NoExpiration |
||||
DefaultExpiration time.Duration = cache.DefaultExpiration |
||||
) |
||||
|
||||
type KVCache[K any, V any] struct { |
||||
c *cache.Cache |
||||
zeroValue V // 默认值
|
||||
k2str func(K) string |
||||
} |
||||
|
||||
func NewKVCache[K any, V any](zeroValue V, k2str func(K) string) *KVCache[K, V] { |
||||
return NewExpireStore(cache.NoExpiration, cache.NoExpiration, zeroValue, k2str) |
||||
} |
||||
|
||||
func NewExpireStore[K any, V any](defaultExpiration, cleanupInterval time.Duration, zeroValue V, k2str func(K) string) *KVCache[K, V] { |
||||
return &KVCache[K, V]{ |
||||
c: cache.New(defaultExpiration, cleanupInterval), |
||||
zeroValue: zeroValue, |
||||
k2str: k2str, |
||||
} |
||||
} |
||||
|
||||
func (s *KVCache[K, V]) SetDefault(k K, v V) { |
||||
s.c.SetDefault(s.k2str(k), v) |
||||
} |
||||
|
||||
func (s *KVCache[K, V]) Set(k K, v V, d time.Duration) { |
||||
s.c.Set(s.k2str(k), v, d) |
||||
} |
||||
|
||||
func (s *KVCache[K, V]) Get(k K) (zero V) { |
||||
v, found := s.c.Get(s.k2str(k)) |
||||
if !found { |
||||
return s.zeroValue |
||||
} |
||||
return v.(V) |
||||
} |
||||
|
||||
func (s *KVCache[K, V]) Delete(k K) { |
||||
s.c.Delete(s.k2str(k)) |
||||
} |
||||
|
||||
func (s *KVCache[K, V]) ForEach(f func(k string, v V)) { |
||||
for k, v := range s.c.Items() { |
||||
f(k, v.Object.(V)) |
||||
} |
||||
} |
||||
|
||||
func (s *KVCache[K, V]) Count() int { |
||||
return s.c.ItemCount() |
||||
} |
||||
Loading…
Reference in new issue