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 ( |
import ( |
||||||
"fmt" |
"fmt" |
||||||
"github.com/golang/protobuf/proto" |
"github.com/golang/protobuf/proto" |
||||||
"texas-poker-bk/api" |
"texas-poker-bk/api" |
||||||
"texas-poker-bk/internal/game" |
"texas-poker-bk/internal/game" |
||||||
"texas-poker-bk/internal/service/store" |
"texas-poker-bk/internal/logic/store" |
||||||
"texas-poker-bk/tool/async" |
"texas-poker-bk/tool/async" |
||||||
"time" |
"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 |
package event |
||||||
|
|
||||||
import ( |
import ( |
||||||
"texas-poker-bk/internal/service/store" |
"texas-poker-bk/internal/logic/store" |
||||||
"texas-poker-bk/tool/watcher" |
"texas-poker-bk/tool/watcher" |
||||||
) |
) |
||||||
|
|
||||||
@ -1,4 +1,4 @@ |
|||||||
package service |
package logic |
||||||
|
|
||||||
import ( |
import ( |
||||||
"bytes" |
"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