diff --git a/game/builtin/room.go b/game/builtin/room.go index c5ee1c3..ba6daf7 100644 --- a/game/builtin/room.go +++ b/game/builtin/room.go @@ -2,6 +2,7 @@ package builtin import ( "github.com/kercylan98/minotaur/game" + "github.com/kercylan98/minotaur/utils/hash" "github.com/kercylan98/minotaur/utils/log" "github.com/kercylan98/minotaur/utils/synchronization" "go.uber.org/zap" @@ -43,7 +44,7 @@ func (slf *Room[PlayerID, Player]) GetPlayer(id PlayerID) Player { return slf.players.Get(id) } -func (slf *Room[PlayerID, Player]) GetPlayers() synchronization.MapReadonly[PlayerID, Player] { +func (slf *Room[PlayerID, Player]) GetPlayers() hash.MapReadonly[PlayerID, Player] { return slf.players } diff --git a/game/builtin/world.go b/game/builtin/world.go index 8d1f5ac..0f36968 100644 --- a/game/builtin/world.go +++ b/game/builtin/world.go @@ -2,6 +2,7 @@ package builtin import ( "github.com/kercylan98/minotaur/game" + "github.com/kercylan98/minotaur/utils/hash" "github.com/kercylan98/minotaur/utils/log" "github.com/kercylan98/minotaur/utils/synchronization" "go.uber.org/zap" @@ -56,7 +57,7 @@ func (slf *World[PlayerID, Player]) GetPlayer(id PlayerID) Player { return slf.players.Get(id) } -func (slf *World[PlayerID, Player]) GetPlayers() synchronization.MapReadonly[PlayerID, Player] { +func (slf *World[PlayerID, Player]) GetPlayers() hash.MapReadonly[PlayerID, Player] { return slf.players } @@ -64,7 +65,7 @@ func (slf *World[PlayerID, Player]) GetActor(guid int64) game.Actor { return slf.actors.Get(guid) } -func (slf *World[PlayerID, Player]) GetActors() synchronization.MapReadonly[int64, game.Actor] { +func (slf *World[PlayerID, Player]) GetActors() hash.MapReadonly[int64, game.Actor] { return slf.actors } @@ -75,7 +76,7 @@ func (slf *World[PlayerID, Player]) GetPlayerActor(id PlayerID, guid int64) game return nil } -func (slf *World[PlayerID, Player]) GetPlayerActors(id PlayerID) synchronization.MapReadonly[int64, game.Actor] { +func (slf *World[PlayerID, Player]) GetPlayerActors(id PlayerID) hash.MapReadonly[int64, game.Actor] { return slf.playerActors.Get(id) } diff --git a/game/room.go b/game/room.go index 075bca1..9c7a18a 100644 --- a/game/room.go +++ b/game/room.go @@ -1,6 +1,8 @@ package game -import "github.com/kercylan98/minotaur/utils/synchronization" +import ( + "github.com/kercylan98/minotaur/utils/hash" +) // Room 房间类似于简版的游戏世界,不过没有游戏实体 type Room[PlayerID comparable, P Player[PlayerID]] interface { @@ -11,7 +13,7 @@ type Room[PlayerID comparable, P Player[PlayerID]] interface { // GetPlayer 根据玩家id获取玩家 GetPlayer(id PlayerID) P // GetPlayers 获取房间中的所有玩家 - GetPlayers() synchronization.MapReadonly[PlayerID, P] + GetPlayers() hash.MapReadonly[PlayerID, P] // GetPlayerCount 获取玩家数量 GetPlayerCount() int // IsExistPlayer 检查房间中是否存在特定玩家 diff --git a/game/world.go b/game/world.go index 6a5bc6f..3755559 100644 --- a/game/world.go +++ b/game/world.go @@ -1,6 +1,8 @@ package game -import "github.com/kercylan98/minotaur/utils/synchronization" +import ( + "github.com/kercylan98/minotaur/utils/hash" +) // World 游戏世界接口定义 type World[PlayerID comparable, P Player[PlayerID]] interface { @@ -11,15 +13,15 @@ type World[PlayerID comparable, P Player[PlayerID]] interface { // GetPlayer 根据玩家id获取玩家 GetPlayer(id PlayerID) P // GetPlayers 获取世界中的所有玩家 - GetPlayers() synchronization.MapReadonly[PlayerID, P] + GetPlayers() hash.MapReadonly[PlayerID, P] // GetActor 根据唯一标识符获取世界中的游戏对象 GetActor(guid int64) Actor // GetActors 获取世界中的所有游戏对象 - GetActors() synchronization.MapReadonly[int64, Actor] + GetActors() hash.MapReadonly[int64, Actor] // GetPlayerActor 获取游戏世界中归属特定玩家的特定游戏对象 GetPlayerActor(id PlayerID, guid int64) Actor // GetPlayerActors 获取游戏世界中归属特定玩家的所有游戏对象 - GetPlayerActors(id PlayerID) synchronization.MapReadonly[int64, Actor] + GetPlayerActors(id PlayerID) hash.MapReadonly[int64, Actor] // IsExistPlayer 检查游戏世界中是否存在特定玩家 IsExistPlayer(id PlayerID) bool // IsExistActor 检查游戏世界中是否存在特定游戏对象 diff --git a/utils/asynchronization/map.go b/utils/asynchronization/map.go new file mode 100644 index 0000000..1d27089 --- /dev/null +++ b/utils/asynchronization/map.go @@ -0,0 +1,194 @@ +package asynchronization + +import ( + "encoding/json" +) + +func NewMap[Key comparable, value any]() *Map[Key, value] { + return &Map[Key, value]{ + data: make(map[Key]value), + } +} + +// Map 非并发安全的字典数据结构 +// - 可用于对 synchronization.Map 的替代 +type Map[Key comparable, Value any] struct { + data map[Key]Value +} + +func (slf *Map[Key, Value]) Set(key Key, value Value) { + slf.data[key] = value +} + +func (slf *Map[Key, Value]) Get(key Key) Value { + return slf.data[key] +} + +// AtomGetSet 原子方式获取一个值并在之后进行赋值 +func (slf *Map[Key, Value]) AtomGetSet(key Key, handle func(value Value, exist bool) (newValue Value, isSet bool)) { + value, exist := slf.data[key] + if newValue, isSet := handle(value, exist); isSet { + slf.data[key] = newValue + } +} + +// Atom 原子操作 +func (slf *Map[Key, Value]) Atom(handle func(m *Map[Key, Value])) { + handle(slf) +} + +func (slf *Map[Key, Value]) Exist(key Key) bool { + _, exist := slf.data[key] + return exist +} + +func (slf *Map[Key, Value]) GetExist(key Key) (Value, bool) { + value, exist := slf.data[key] + return value, exist +} + +func (slf *Map[Key, Value]) Length() int { + return len(slf.data) +} + +func (slf *Map[Key, Value]) Delete(key Key) { + delete(slf.data, key) +} + +func (slf *Map[Key, Value]) DeleteGet(key Key) Value { + v := slf.data[key] + delete(slf.data, key) + return v +} + +func (slf *Map[Key, Value]) DeleteGetExist(key Key) (Value, bool) { + v, exist := slf.data[key] + delete(slf.data, key) + return v, exist +} + +func (slf *Map[Key, Value]) DeleteExist(key Key) bool { + if _, exist := slf.data[key]; !exist { + return exist + } + delete(slf.data, key) + return true +} + +func (slf *Map[Key, Value]) Clear() { + for k := range slf.data { + delete(slf.data, k) + } +} + +func (slf *Map[Key, Value]) ClearHandle(handle func(key Key, value Value)) { + for k, v := range slf.data { + handle(k, v) + delete(slf.data, k) + } +} + +func (slf *Map[Key, Value]) Range(handle func(key Key, value Value)) { + for k, v := range slf.data { + key, value := k, v + handle(key, value) + } +} + +func (slf *Map[Key, Value]) RangeSkip(handle func(key Key, value Value) bool) { + for k, v := range slf.data { + key, value := k, v + if !handle(key, value) { + continue + } + } +} + +func (slf *Map[Key, Value]) RangeBreakout(handle func(key Key, value Value) bool) { + slf.rangeBreakout(handle) +} + +func (slf *Map[Key, Value]) rangeBreakout(handle func(key Key, value Value) bool) bool { + for k, v := range slf.data { + key, value := k, v + if !handle(key, value) { + return true + } + } + return false +} + +func (slf *Map[Key, Value]) RangeFree(handle func(key Key, value Value, skip func(), breakout func())) { + slf.rangeFree(handle) +} + +func (slf *Map[Key, Value]) rangeFree(handle func(key Key, value Value, skip func(), breakout func())) bool { + var skipExec, breakoutExec bool + var skip = func() { + skipExec = true + } + var breakout = func() { + breakoutExec = true + } + for k, v := range slf.data { + key, value := k, v + handle(key, value, skip, breakout) + if skipExec { + continue + } + if breakoutExec { + break + } + } + return breakoutExec +} + +func (slf *Map[Key, Value]) Keys() []Key { + var s = make([]Key, 0, len(slf.data)) + for k, _ := range slf.data { + s = append(s, k) + } + return s +} + +func (slf *Map[Key, Value]) Slice() []Value { + var s = make([]Value, 0, len(slf.data)) + for _, v := range slf.data { + s = append(s, v) + } + return s +} + +func (slf *Map[Key, Value]) Map() map[Key]Value { + var m = make(map[Key]Value) + for k, v := range slf.data { + m[k] = v + } + return m +} + +func (slf *Map[Key, Value]) Size() int { + return len(slf.data) +} + +// GetOne 获取一个 +func (slf *Map[Key, Value]) GetOne() (value Value) { + for _, v := range slf.data { + return v + } + return value +} + +func (slf *Map[Key, Value]) MarshalJSON() ([]byte, error) { + m := slf.Map() + return json.Marshal(m) +} + +func (slf *Map[Key, Value]) UnmarshalJSON(bytes []byte) error { + var m = make(map[Key]Value) + if err := json.Unmarshal(bytes, &m); err != nil { + return err + } + slf.data = m + return nil +} diff --git a/utils/synchronization/map_readonly.go b/utils/hash/map_readonly.go similarity index 95% rename from utils/synchronization/map_readonly.go rename to utils/hash/map_readonly.go index 2a9181d..8add611 100644 --- a/utils/synchronization/map_readonly.go +++ b/utils/hash/map_readonly.go @@ -1,4 +1,4 @@ -package synchronization +package hash // MapReadonly 并发安全的只读字典接口 type MapReadonly[Key comparable, Value any] interface {