Files
bl/logic/service/player/wscodec.go
昔念 e84d55aec0 ```
feat(player): 优化玩家连接与消息发送逻辑

- 为 `Conn` 结构体新增 `Close()` 方法,并在多处替换原有的 `GetConn().Close()` 调用,
  统一通过 `MainConn` 操作以提高代码一致性。
- 在 `SendPack` 和 `GetPlayer` 等方法中增加互斥锁保护,确保对 `MainConn` 的访问是线程安全的。
- 移除冗余的 `GetConn()` 方法,直接使用 `MainConn` 提升性能并简化结构。

refactor(rpc): 临时将 RPC 客户端地址硬编码为本地地址

- 将 rpcaddr 临时设置为 "127.0.0.1",便于调试和开发环境测试。

refactor(handler): 扩展 JSON-RPC 方法过滤条件

- 增加了对 "Kick" 和 "RegisterLogic" 方法的排除,防止其被注册到 RPC 处理器中。

refactor(fight): 精简战斗服务中的判断逻辑

- 简化 `IsFirst` 函数返回表达式。
- 移除了多余的 defer 语句,提前设置 `closefight` 标志位。

refactor(pet): 改进宠物经验添加机制

- `AddPetExp` 方法新增布尔参数 `bro` 控制是否广播更新。
- 修改调用点以适配新参数,修复潜在的数据同步问题。
- 初始化宠物时禁止触发经验变更广播。

chore(build): 删除旧版二进制文件 logic1

- 清理无用的编译产物,避免混淆项目结构。
```
2025-10-14 01:26:59 +08:00

202 lines
4.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package player
import (
"bytes"
"errors"
"io"
"sync"
"github.com/gobwas/ws"
"github.com/gobwas/ws/wsutil"
"github.com/panjf2000/gnet/v2"
"github.com/panjf2000/gnet/v2/pkg/logging"
)
type Conn struct {
MainConn gnet.Conn `struc:"[0]pad"` //TODO 不序列化,,序列化下面的作为blob存数据库
Mu sync.Mutex
}
func NewConn(c gnet.Conn) *Conn {
return &Conn{MainConn: c}
}
type WsCodec struct {
Tcp bool
Upgraded bool // 链接是否升级
Buf bytes.Buffer // 从实际socket中读取到的数据缓存
wsMsgBuf wsMessageBuf // ws 消息缓存
//Isinitws bool
}
type wsMessageBuf struct {
curHeader *ws.Header
cachedBuf bytes.Buffer
}
type readWrite struct {
io.Reader
io.Writer
}
func CompareLeftBytes(array1, array2 []byte, leftBytesCount int) bool {
// 检查切片长度是否足够比较左边的字节
if len(array1) < leftBytesCount || len(array2) < leftBytesCount {
return false
}
// 提取左边的字节切片
left1 := array1[:leftBytesCount]
left2 := array2[:leftBytesCount]
// 比较左边的字节切片
for i := 0; i < leftBytesCount; i++ {
if left1[i] != left2[i] {
return false
}
}
return true
}
func (w *WsCodec) Upgrade(c gnet.Conn) (ok bool, action gnet.Action) {
if w.Upgraded {
ok = true
return
}
if w.Tcp {
ok = false
return
}
buf := &w.Buf
if CompareLeftBytes(buf.Bytes(), []byte{0, 0}, 2) {
w.Tcp = true
return
}
tmpReader := bytes.NewReader(buf.Bytes())
oldLen := tmpReader.Len()
logging.Infof("do Upgrade")
hs, err := ws.Upgrade(readWrite{tmpReader, c})
skipN := oldLen - tmpReader.Len()
if err != nil {
if err == io.EOF || errors.Is(err, io.ErrUnexpectedEOF) { //数据不完整,不跳过 buf 中的 skipN 字节(此时 buf 中存放的仅是部分 "handshake data" bytes下次再尝试读取
return
}
buf.Next(skipN)
logging.Errorf("conn[%v] [err=%v]", c.RemoteAddr().String(), err.Error())
action = gnet.Close
//ok = true
//w.Tcp = true
return
}
buf.Next(skipN)
logging.Infof("conn[%v] upgrade websocket protocol! Handshake: %v", c.RemoteAddr().String(), hs)
ok = true
w.Upgraded = true
return
}
func (w *WsCodec) ReadBufferBytes(c gnet.Conn) (gnet.Action, int) {
size := c.InboundBuffered()
//buf := make([]byte, size)
read, err := c.Peek(size)
if err != nil {
logging.Errorf("read err! %v", err)
return gnet.Close, 0
}
// if read < size {
// logging.Errorf("read bytes len err! size: %d read: %d", size, read)
// return gnet.Close
// }
w.Buf.Write(read)
return gnet.None, size
}
func (w *WsCodec) Decode(c gnet.Conn) (outs []wsutil.Message, err error) {
// fmt.Println("do Decode")
messages, err := w.readWsMessages()
if err != nil {
logging.Errorf("Error reading message! %v", err)
return nil, err
}
if messages == nil || len(messages) <= 0 { //没有读到完整数据 不处理
return
}
for _, message := range messages {
if message.OpCode.IsControl() {
err = wsutil.HandleClientControlMessage(c, message)
if err != nil {
return
}
continue
}
if message.OpCode == ws.OpText || message.OpCode == ws.OpBinary {
outs = append(outs, message)
}
}
return
}
func (w *WsCodec) readWsMessages() (messages []wsutil.Message, err error) {
msgBuf := &w.wsMsgBuf
in := &w.Buf
for {
// 从 in 中读出 header并将 header bytes 写入 msgBuf.cachedBuf
if msgBuf.curHeader == nil {
if in.Len() < ws.MinHeaderSize { //头长度至少是2
return
}
var head ws.Header
if in.Len() >= ws.MaxHeaderSize {
head, err = ws.ReadHeader(in)
if err != nil {
return messages, err
}
} else { //有可能不完整,构建新的 reader 读取 head读取成功才实际对 in 进行读操作
tmpReader := bytes.NewReader(in.Bytes())
oldLen := tmpReader.Len()
head, err = ws.ReadHeader(tmpReader)
skipN := oldLen - tmpReader.Len()
if err != nil {
if err == io.EOF || errors.Is(err, io.ErrUnexpectedEOF) { //数据不完整
return messages, nil
}
in.Next(skipN)
return nil, err
}
in.Next(skipN)
}
msgBuf.curHeader = &head
err = ws.WriteHeader(&msgBuf.cachedBuf, head)
if err != nil {
return nil, err
}
}
dataLen := (int)(msgBuf.curHeader.Length)
// 从 in 中读出 data并将 data bytes 写入 msgBuf.cachedBuf
if dataLen > 0 {
if in.Len() < dataLen { //数据不完整
logging.Infof("incomplete data")
return
}
_, err = io.CopyN(&msgBuf.cachedBuf, in, int64(dataLen))
if err != nil {
return
}
}
if msgBuf.curHeader.Fin { //当前 header 已经是一个完整消息
messages, err = wsutil.ReadClientMessage(&msgBuf.cachedBuf, messages)
if err != nil {
return nil, err
}
msgBuf.cachedBuf.Reset()
} else {
logging.Infof("The data is split into multiple frames")
}
msgBuf.curHeader = nil
}
}