feat(map): 实现地图加载和玩家进入地图功能
- 在 Player 结构中添加 MapId 字段,用于记录当前所在地图 ID - 新增地图配置解析功能,支持从 XML 文件中读取地图信息 - 实现玩家进入地图的逻辑,包括设置玩家位置和广播通知 - 更新登录逻辑,在玩家登录时自动进入默认地图 - 重构地图相关的数据结构和接口,为后续地图功能扩展做准备
This commit is contained in:
71
logic/service/space/space.go
Normal file
71
logic/service/space/space.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package space
|
||||
|
||||
import (
|
||||
"blazing/common/data/entity"
|
||||
"blazing/modules/blazing/model"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Space 针对Player的并发安全map,键为uint32类型
|
||||
type Space struct {
|
||||
mu sync.RWMutex // 读写锁,读多写少场景更高效
|
||||
data map[uint32]*entity.Player // 存储玩家数据的map,键为玩家ID
|
||||
CanRefresh bool //是否能够刷怪
|
||||
ID uint32 // 地图ID
|
||||
Name string //地图名称
|
||||
DefaultPos model.Pos //默认位置DefaultPos
|
||||
Positions map[uint32]model.Pos //从上一个地图跳转后默认位置
|
||||
}
|
||||
|
||||
// NewSyncMap 创建一个新的玩家同步map
|
||||
func NewSpace() *Space {
|
||||
return &Space{
|
||||
data: make(map[uint32]*entity.Player),
|
||||
}
|
||||
}
|
||||
|
||||
// Get 根据玩家ID获取玩家实例
|
||||
// 读操作使用RLock,允许多个goroutine同时读取
|
||||
func (m *Space) Get(playerID uint32) (*entity.Player, bool) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
val, exists := m.data[playerID]
|
||||
return val, exists
|
||||
}
|
||||
|
||||
// Set 存储玩家实例(按ID)
|
||||
// 写操作使用Lock,独占锁保证数据一致性
|
||||
func (m *Space) Set(playerID uint32, player *entity.Player) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.data[playerID] = player
|
||||
}
|
||||
|
||||
// Delete 根据玩家ID删除玩家实例
|
||||
// 写操作使用Lock
|
||||
func (m *Space) Delete(playerID uint32) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
delete(m.data, playerID)
|
||||
}
|
||||
|
||||
// Len 获取当前玩家数量
|
||||
// 读操作使用RLock
|
||||
func (m *Space) Len() int {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
return len(m.data)
|
||||
}
|
||||
|
||||
// Range 遍历所有玩家并执行回调函数
|
||||
// 读操作使用RLock,遍历过程中不会阻塞其他读操作
|
||||
func (m *Space) Range(f func(playerID uint32, player *entity.Player) bool) {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
for id, player := range m.data {
|
||||
// 若回调返回false,则停止遍历
|
||||
if !f(id, player) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
76
logic/service/space/walk.go
Normal file
76
logic/service/space/walk.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package space
|
||||
|
||||
import (
|
||||
"blazing/common/data/entity"
|
||||
"blazing/common/data/xml"
|
||||
"blazing/common/socket/handler"
|
||||
"blazing/common/utils"
|
||||
"blazing/modules/blazing/model"
|
||||
)
|
||||
|
||||
// 获取星球
|
||||
func GetPlanet(id uint32) *Space {
|
||||
planet, ok := planetmap.Load(id)
|
||||
if ok {
|
||||
return planet
|
||||
}
|
||||
|
||||
//如果不ok,说明星球未创建,那就新建星球
|
||||
|
||||
for _, v := range xml.MapConfig.Maps {
|
||||
if v.ID == int(id) { //找到这个地图
|
||||
t := NewSpace()
|
||||
t.DefaultPos = model.Pos{X: uint32(v.X), Y: uint32(v.Y)}
|
||||
t.ID = uint32(v.ID)
|
||||
t.Name = v.Name
|
||||
t.Positions = make(map[uint32]model.Pos)
|
||||
for _, v := range v.Entries.Entries { //添加地图入口
|
||||
t.Positions[uint32(v.FromMap)] = model.Pos{X: uint32(v.PosX), Y: uint32(v.PosY)}
|
||||
|
||||
}
|
||||
planetmap.Store(id, t)
|
||||
return t
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var planetmap = &utils.SyncMap[uint32, *Space]{} //玩家数据
|
||||
type InInfo struct {
|
||||
Head handler.TomeeHeader `cmd:"2101" struc:"[0]pad"` //玩家登录
|
||||
// Flag: 0为走,1为飞行模式,对应Java的@UInt long
|
||||
Flag uint32
|
||||
|
||||
// Point: 直接给坐标x,y
|
||||
Point model.Pos `fieldDesc:"直接给坐标x,y"`
|
||||
|
||||
// Reverse2: 暂定 占位字符2
|
||||
Reverse2 string `struc:"[2]byte"`
|
||||
}
|
||||
|
||||
func (t *InInfo) Broadcast(mapid uint32, o OutInfo) {
|
||||
|
||||
GetPlanet(mapid).Range(func(playerID uint32, player *entity.Player) bool {
|
||||
|
||||
player.SendPack(t.Head.Pack(o))
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// PeopleWalkOutboundInfo 对应Java的PeopleWalkOutboundInfo类,实现OutboundMessage接口
|
||||
type OutInfo struct {
|
||||
// Flag: 0为走,1为飞行模式
|
||||
Flag uint32 `fieldDesc:"0为走,1为飞行模式" codec:"uint"`
|
||||
|
||||
// UserID: 走动的人的米米号
|
||||
UserID uint32 `fieldDesc:"走动的人的米米号" codec:"uint"`
|
||||
|
||||
// Point: 直接给坐标x,y
|
||||
Point model.Pos `fieldDesc:"直接给坐标x,y"`
|
||||
|
||||
// Reserve2: 这个字段同C2S_People_Walk中的reserve2
|
||||
Reserve2 string `struc:"[2]byte"`
|
||||
}
|
||||
Reference in New Issue
Block a user