Files
bl/logic/service/player/pack.go
昔念 6e01848b04 ```
refactor(socket): 移除未使用的网络相关导入和注释掉的 RST 攻击检测逻辑

移除了 `ServerEvent.go` 中未使用的 `net` 和 `strings` 包导入。同时,
将原有的 RST 攻击检测及防护逻辑代码注释掉,便于后续重新设计或彻底删除。

fix(logic): 调整 fight pool 初始化与释放策略

将 `fight/action.go` 中的 `Fightpool` 类型从 `*ants.MultiPool`
改为 `*ants.Pool`,并调整其初始化方式为 `NewPool(-1)` 以适应动态扩容。
此外,在 `main.go` 中将 `ReleaseTimeout` 参数由 100 调整为 0,
确保立即清理超时任务。

feat(fight): 优化战斗输入状态重置逻辑

在 `fight/action.go` 的 `ReadyFight` 方法中提前设置
`GetInputByPlayer(c, false).Finished = true`,避免重复赋值。
同时更新了状态睡眠效果的处理流程,并简化了输入模块的状态缓存机制,
移除了冗余的 `Initeffectcache` 函数调用及相关逻辑。

perf(fight): 动态计算玩家动作等待时间

在 `loop.go` 的 `collectPlayerActions` 方法中,
将固定超时时间替换为基于 `waittime` 的动态等待时间计算公式,
提高响应灵活性。同时修复通道关闭判断条件以增强稳定性。

refactor(fight): 更新技能效果解析和状态持续逻辑

修改 `input.go` 中 `GenSataus` 方法以正确初始化状态数组;
在 `Turn.go` 中重构 `Turn_End` 方法内的执行逻辑,
确保仅在我方后手时增加回合数,提升战斗流程准确性。

chore(service): 删除废弃文件 SocketHandler_Tomee.go

完全移除已弃用的 `SocketHandler_Tomee.go` 文件及其全部内容,
减少项目冗余代码。
```
2025-11-13 05:05:05 +08:00

288 lines
6.9 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 (
"blazing/common/socket/errorcode"
"blazing/common/utils/bytearray"
"blazing/cool"
"sync"
"context"
"bytes"
"fmt"
"reflect"
"github.com/bruceshao/lockfree"
"github.com/gobwas/ws"
"github.com/gobwas/ws/wsutil"
"github.com/gogf/gf/v2/os/glog"
"github.com/lunixbochs/struc"
"github.com/panjf2000/gnet/v2"
"github.com/panjf2000/gnet/v2/pkg/logging"
)
// TomeeHeader 结构体字段定义
type TomeeHeader struct {
Len uint32 `json:"len"`
Version byte `json:"version" struc:"[1]byte"`
CMD uint32 `json:"cmdId" struc:"uint32"`
UserID uint32 `json:"userId"`
//Error uint32 `json:"error" struc:"[0]pad"`
Result uint32 `json:"result"`
Data []byte `json:"data" struc:"skip"` //组包忽略此字段// struc:"[0]pad"
//Return []byte `struc:"[0]pad"` //返回记录
}
func NewTomeeHeader(cmd uint32, userid uint32) *TomeeHeader {
return &TomeeHeader{
CMD: cmd,
// Len: 0,
Version: 49,
Result: 0,
}
}
// Pack 将给定的数据打包成一个字节切片。
// 该方法处理的数据类型包括指针、切片和结构体。
// 对于指针类型,会解引用以获取实际值。
// 切片类型直接转换为字节切片。
// 结构体类型使用struc库进行序列化。
// 最后将数据长度、版本号、命令码、用户ID和结果代码一并打包进返回的字节切片中。
func (h *TomeeHeader) Pack(data any) []byte { //组包
//h.Result = 0//默认置0
//t := reflect.TypeOf(data)
tv := reflect.ValueOf(data)
var datar []byte
// 处理指针类型
if tv.Kind() == reflect.Ptr {
//tv = t.Elem() // 获取指针指向的类型
tv = tv.Elem() // 获取指针指向的值
}
switch tv.Kind() {
case reflect.String:
datar = []byte(tv.String())
case reflect.Slice:
datar = data.([]byte)
//p.Conn.Write(p.pack(cmd, data.([]byte))) //写入数据
case reflect.Struct:
var data1 bytes.Buffer
err := struc.Pack(&data1, data)
if err != nil {
fmt.Println(err)
}
datar = data1.Bytes()
default:
datar = []byte{}
// fmt.Println(err, datar)
// p.Conn.Write(p.pack(cmd, data))
}
h.Len = uint32(len(datar) + 17)
by := bytearray.CreateByteArray(nil)
by.WriteUInt32(h.Len)
by.WriteByte(h.Version)
by.WriteUInt32(uint32(h.CMD))
by.WriteUInt32(h.UserID)
by.WriteUInt32(h.Result)
by.Write(datar)
return by.Bytes()
}
// 遍历结构体方法并执行RECV_cmd
func (h *ClientData) Recv(data TomeeHeader) {
cmdlister, ok := cool.CmdCache.Load(data.CMD)
if !ok {
glog.Debug(context.Background(), data.CMD, "cmd未注册")
return //TODO 待实现cmd未注册
}
params := []reflect.Value{}
//funct := cmdlister.Type().NumIn()
// 如果需要可设置的变量(用于修改值),创建指针并解引用
ptrValue := reflect.New(cmdlister.Type().In(0).Elem())
tt1 := ptrValue.Elem().Addr().Interface()
// fmt.Println(tt1)
err := struc.Unpack(bytes.NewBuffer(data.Data), tt1)
if err != nil {
cool.Loger.Error(context.Background(), data.UserID, data.CMD, "解包失败")
return
}
//fmt.Println(tt1)
ptrValue1 := ptrValue.Elem().Addr()
// 设置 Name 字段
nameField := ptrValue.Elem().Field(0) //首个为header
if nameField.IsValid() && nameField.CanSet() {
nameField.Set(reflect.ValueOf(data))
}
if data.CMD > 1001 { //if cmdlister.Type().In(1) == reflect.TypeOf(&Player{}) {
//t := GetPlayer(c, data.UserID)
// fmt.Println(data.CMD, "接收 变量的地址 ", &t.Info, t.Info.UserID)
params = append(params, ptrValue1, reflect.ValueOf(h.Conn.Context().(*ClientData).Player))
} else {
params = append(params, ptrValue1, reflect.ValueOf(h.Conn))
}
ret := cmdlister.Call(params)
if len(ret) <= 0 { //如果判断没有参数,那就说明这个包没有返回参数
return
}
aa, ok := ret[1].Interface().(errorcode.ErrorCode) //判断错误
data.Result = uint32(aa)
if aa == -1 {
return
}
t := h.Conn.Context().(*ClientData)
if ok && aa != 0 { //这里实现回复错误包
cool.Loger.Error(context.Background(), aa.Code())
t.SendPack(data.Pack(nil))
return
}
//data.Version = 49
t.SendPack(data.Pack(ret[0].Interface()))
}
type ClientData struct {
IsCrossDomain sync.Once //是否跨域过
Player *Player //客户实体
//Mu sync.RWMutex
ERROR_CONNUT int
Wsmsg *WsCodec
Conn gnet.Conn
SaveL sync.Once //保存锁
LF *lockfree.Lockfree[[]byte]
//SaveDone chan struct{}
}
func NewClientData(c gnet.Conn) *ClientData {
// 创建事件处理器
// 创建消费端串行处理的Lockfree
cd := &ClientData{
Conn: c,
Wsmsg: &WsCodec{},
}
cd.LF = lockfree.NewLockfree[[]byte](
16,
cd,
&lockfree.SchedBlockStrategy{},
)
// 启动Lockfree
if err := cd.LF.Start(); err != nil {
panic(err)
}
return cd
}
func XORDecrypt(encryptedData []byte, keyStr string) []byte {
if len(encryptedData) == 0 || keyStr == "" {
return []byte{}
}
// 1. 将密钥字符串转换为UTF-8字节数组对应AS3的writeUTFBytes(_arg_2)
keyBytes := []byte(keyStr) // Go中string转[]byte默认是UTF-8编码与AS3的writeUTFBytes一致
keyLen := len(keyBytes)
if keyLen == 0 {
return encryptedData // 空密钥不加密,直接返回
}
// 2. 执行异或操作(与加密逻辑一致,异或两次还原数据)
decrypted := make([]byte, len(encryptedData))
for i, b := range encryptedData {
// 循环复用密钥字节(索引取模)
keyIndex := i % keyLen
decrypted[i] = b ^ keyBytes[keyIndex]
}
return decrypted
}
func (h *ClientData) OnEvent(v []byte) {
defer func() {
if err := recover(); err != nil { // 恢复 panicerr 为 panic 错误值
// 1. 打印错误信息
cool.Loger.Error(context.TODO(), "panic 错误:", err)
}
}()
header := TomeeHeader{}
tempdata := bytearray.CreateByteArray(v)
header.Len, _ = tempdata.ReadUInt32()
header.Version, _ = tempdata.ReadByte()
header.CMD, _ = tempdata.ReadUInt32()
//header.CMD = cmd.EnumCommandID(_CMD)
header.UserID, _ = tempdata.ReadUInt32()
header.Result, _ = tempdata.ReadUInt32()
header.Data = XORDecrypt(tempdata.BytesAvailable(), "CWF")
if header.CMD > 1001 {
if h.Conn.Context().(*ClientData).Player == nil {
cool.Loger.Error(context.TODO(), header.UserID, "账号未注册")
return
}
if h.Conn.Context().(*ClientData).Player.Info == nil {
cool.Loger.Error(context.TODO(), header.UserID, "未创建角色")
return
}
}
cool.Loger.Debug(context.TODO(), "接收数据", header.UserID, header.CMD)
h.Recv(header)
}
func (p *ClientData) SendPack(b []byte) error {
if _, ok := p.Conn.Context().(*ClientData); !ok {
return fmt.Errorf("链接错误,取消发包")
}
if p.Conn.Context().(*ClientData).Wsmsg.Upgraded {
// This is the echo server
err := wsutil.WriteServerMessage(p.Conn, ws.OpBinary, b)
if err != nil {
logging.Infof("conn[%v] [err=%v]", p.Conn.RemoteAddr().String(), err.Error())
return err
}
} else {
err := p.Conn.AsyncWrite(b, nil)
if err != nil {
glog.Debug(context.Background(), err)
}
}
return nil
}