package player import ( "blazing/common/socket/errorcode" "blazing/common/utils/bytearray" "blazing/cool" "context" "bytes" "fmt" "reflect" "github.com/gogf/gf/v2/os/glog" "github.com/lunixbochs/struc" "github.com/panjf2000/gnet/v2" ) // 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() 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() } // var _ Blazingservice = (*TomeeHeader)(nil) // type Blazingservice interface { // Ret() []byte // } // MergeBytes 将多个字节数组合并为一个 func MergeBytes(arrays ...[]byte) []byte { // 计算所有数组的总长度 totalLen := 0 for _, arr := range arrays { totalLen += len(arr) } // 创建结果切片 result := make([]byte, totalLen) // 逐个复制数组内容 currentIndex := 0 for _, arr := range arrays { copy(result[currentIndex:], arr) currentIndex += len(arr) } return result } // 遍历结构体方法并执行RECV_cmd func Recv(c gnet.Conn, data TomeeHeader) { cmdlister, ok := cool.CmdCache.Load(data.CMD) if !ok { glog.Debug(context.Background(), data.CMD, "cmd未注册") return //TODO 待实现cmd未注册 } // fmt.Println(cmdlister) glog.Debug(context.Background(), "接收数据", data.UserID, data.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 { fmt.Println(err) } //fmt.Println(tt1) ptrValue1 := ptrValue.Elem().Addr() // 设置 Name 字段 nameField := ptrValue.Elem().Field(0) //首个为header if nameField.IsValid() && nameField.CanSet() { nameField.Set(reflect.ValueOf(data)) } clientdata := c.Context().(*ClientData) if cmdlister.Type().In(1) == reflect.TypeOf(&Player{}) { //t := GetPlayer(c, data.UserID) if clientdata.Player == nil { return } // fmt.Println(data.CMD, "接收 变量的地址 ", &t.Info, t.Info.UserID) params = append(params, ptrValue1, reflect.ValueOf(clientdata.Player)) } else { params = append(params, ptrValue1, reflect.ValueOf(c)) } 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 := GetPlayer(c, data.UserID) if t == nil { return } 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())) }