//go:build gl // 客户端联机:netclient 接入(多人同步.md §2 权威链路客户端侧)。 package main import ( "mc/internal/block" "mc/internal/netclient" "mc/internal/netproto" "mc/internal/save" ) // mpHandler 联机回调:区块安装与方块变更应用(多人同步.md §4–§5)。 type mpHandler struct { app *clientApp } // OnLogin 登录结果。 func (h *mpHandler) OnLogin(code uint8) { if code != 0 { h.app.logf("服务器拒绝登录(码 %d)", code) h.app.net.Close() h.app.net = nil h.app.screen = 0 } } // OnChunk 收到区块:反序列化并安装到世界(多人同步.md §4)。 func (h *mpHandler) OnChunk(data []byte) { c, err := save.DecodeChunk(data) if err != nil { h.app.logf("区块解码失败: %v", err) return } h.app.sess.World.InstallChunk(c) } // OnBlockChange 方块变更(服务器权威广播,多人同步.md §5)。 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} nc, err := netclient.Dial(addr, netproto.Handshake{ProtocolVersion: 1, ClientID: name}, h) if err != nil { return err } a.net = nc return nil }