feat(mpsync): 实体位置广播(EntityMove)与客户端在线玩家显示;mesh 顶点池复用(性能与内存.md §2)
This commit is contained in:
@@ -57,6 +57,10 @@ type clientApp struct {
|
||||
net *netclient.Client
|
||||
log *logx.Logger
|
||||
|
||||
// 其他玩家位置(多人同步.md §3;渲染插值后置)
|
||||
remoteMu sync.Mutex
|
||||
remotePlayers map[uint32][3]float64
|
||||
|
||||
meshBuilder *mesh.Builder
|
||||
|
||||
mu sync.Mutex
|
||||
@@ -90,6 +94,11 @@ func (a *clientApp) Tick(dt float64) {
|
||||
} else {
|
||||
a.screen = 1
|
||||
a.rend.SetCursorMode(true)
|
||||
a.hud.OnlineCount = func() int {
|
||||
a.remoteMu.Lock()
|
||||
defer a.remoteMu.Unlock()
|
||||
return len(a.remotePlayers) + 1 // 含自己
|
||||
}
|
||||
a.logf("已连接服务器")
|
||||
}
|
||||
case "quit":
|
||||
@@ -174,6 +183,7 @@ func (a *clientApp) Render() {
|
||||
a.mu.Unlock()
|
||||
for _, j := range pending {
|
||||
a.rend.UploadChunk(j.cx, j.cz, j.m)
|
||||
mesh.Release(j.m) // 上传完毕归还顶点池(性能与内存.md §2)
|
||||
}
|
||||
|
||||
// 视图投影
|
||||
@@ -365,19 +375,20 @@ func main() {
|
||||
in := newInputState(rend.Window())
|
||||
|
||||
app := &clientApp{
|
||||
sess: sess,
|
||||
rend: rend,
|
||||
reg: reg,
|
||||
in: in,
|
||||
uiR: uiR,
|
||||
hud: hud,
|
||||
titleScreen: titleScreen,
|
||||
pauseScreen: pauseScreen,
|
||||
log: log,
|
||||
meshBuilder: mesh.NewBuilder(reg, uvFn),
|
||||
winW: cfg.Client.WindowWidth,
|
||||
winH: cfg.Client.WindowHeight,
|
||||
lastTime: time.Now(),
|
||||
sess: sess,
|
||||
rend: rend,
|
||||
reg: reg,
|
||||
in: in,
|
||||
uiR: uiR,
|
||||
hud: hud,
|
||||
titleScreen: titleScreen,
|
||||
pauseScreen: pauseScreen,
|
||||
log: log,
|
||||
remotePlayers: make(map[uint32][3]float64),
|
||||
meshBuilder: mesh.NewBuilder(reg, uvFn),
|
||||
winW: cfg.Client.WindowWidth,
|
||||
winH: cfg.Client.WindowHeight,
|
||||
lastTime: time.Now(),
|
||||
}
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
|
||||
|
||||
@@ -40,6 +40,13 @@ func (h *mpHandler) OnBlockChange(m netproto.BlockChange) {
|
||||
h.app.sess.World.SetBlock(m.X, m.Y, m.Z, block.NewState(m.BlockID, m.Meta))
|
||||
}
|
||||
|
||||
// OnEntityMove 其他玩家移动(多人同步.md §3:客户端存储位置,渲染插值后置)。
|
||||
func (h *mpHandler) OnEntityMove(m netproto.EntityMove) {
|
||||
h.app.remoteMu.Lock()
|
||||
h.app.remotePlayers[m.EntityID] = [3]float64{float64(m.X), float64(m.Y), float64(m.Z)}
|
||||
h.app.remoteMu.Unlock()
|
||||
}
|
||||
|
||||
// dialServer 连接服务器(多人游戏按钮,多人同步.md §2)。
|
||||
func dialServer(a *clientApp, addr string, name string) error {
|
||||
h := &mpHandler{app: a}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"mc/internal/engine"
|
||||
"mc/internal/logx"
|
||||
"mc/internal/mods"
|
||||
"mc/internal/mpsync"
|
||||
"mc/internal/netproto"
|
||||
"mc/internal/netserver"
|
||||
"mc/internal/save"
|
||||
@@ -31,6 +32,7 @@ type serverApp struct {
|
||||
reg *block.Registry
|
||||
world *world.World
|
||||
net *netserver.Server
|
||||
hub *mpsync.Hub
|
||||
modReg *mods.Registry
|
||||
luaMods []*mods.LuaMod
|
||||
seed int64
|
||||
@@ -44,25 +46,27 @@ func (s *serverApp) OnConnect(c *netserver.Conn) {
|
||||
s.log.Infof("玩家连接 #%d", c.ID())
|
||||
}
|
||||
|
||||
// OnHandshake 握手校验(网络协议.md §4:协议版本不匹配拒绝)。
|
||||
// OnHandshake 握手校验(网络协议.md §4:协议版本不匹配拒绝)+ 加入同步中心。
|
||||
func (s *serverApp) OnHandshake(c *netserver.Conn, hs netproto.Handshake) uint8 {
|
||||
if hs.ProtocolVersion != 1 {
|
||||
s.log.Warnf("玩家 #%d 协议版本 %d 不匹配,拒绝", c.ID(), hs.ProtocolVersion)
|
||||
return 1
|
||||
}
|
||||
s.log.Infof("玩家 %q 登录(连接 #%d)", hs.ClientID, c.ID())
|
||||
// 登录成功:加入广播集并发送区块(多人同步.md §4)
|
||||
s.hub.AddPlayer(c, 8, 8)
|
||||
return 0
|
||||
}
|
||||
|
||||
// OnMove 玩家移动(MVP:仅记录,完整同步见 Todo 8)。
|
||||
// OnMove 玩家移动:广播给其他客户端(多人同步.md §3)。
|
||||
func (s *serverApp) OnMove(c *netserver.Conn, m netproto.PlayerMove) {
|
||||
// TODO(多人同步): 更新玩家实体并广播给视距内其他玩家(多人同步.md §3)
|
||||
_ = m
|
||||
s.hub.BroadcastEntityMove(c, uint32(c.ID()), m)
|
||||
}
|
||||
|
||||
// OnDisconnect 连接断开。
|
||||
// OnDisconnect 连接断开:移出同步中心。
|
||||
func (s *serverApp) OnDisconnect(c *netserver.Conn) {
|
||||
s.log.Infof("玩家 #%d 断开", c.ID())
|
||||
s.hub.RemovePlayer(c)
|
||||
}
|
||||
|
||||
// Tick 每 tick(20Hz)服务器逻辑(架构.md §3.2:tick 内不做 IO)。
|
||||
@@ -128,6 +132,7 @@ func main() {
|
||||
}
|
||||
|
||||
app := &serverApp{cfg: cfg, log: log, reg: reg, world: w, seed: seed}
|
||||
app.hub = mpsync.NewHub(w, cfg.Server.ViewDistance)
|
||||
|
||||
// Mod 加载(设计.md §3.3:扫描 mods/,type=mod 且有入口脚本的执行;热更新.md 由注册表支持)
|
||||
am := assets.New()
|
||||
|
||||
Reference in New Issue
Block a user