package main import ( "flag" "fmt" "io" "os" "reflect" "strconv" "strings" "sync" "github.com/Mrs4s/MiraiGo/binary/jce" ) const head = `// Code generated by structs_parser; DO NOT EDIT. package jce ` func main() { f := flag.String("f", "structs_tobytes.go", "output file.") flag.Parse() fmt.Println("gen runs on arg", *f) w, err := os.Create(*f) if err != nil { panic(err) } w.WriteString(head) WriteJceStruct(w, &jce.RequestPacket{}) WriteJceStruct(w, &jce.RequestDataVersion3{}) WriteJceStruct(w, &jce.RequestDataVersion2{}) WriteJceStruct(w, &jce.SvcReqRegister{}) WriteJceStruct(w, &jce.FriendListRequest{}) WriteJceStruct(w, &jce.SummaryCardReq{}) WriteJceStruct(w, &jce.SummaryCardReqSearch{}) WriteJceStruct(w, &jce.TroopListRequest{}) WriteJceStruct(w, &jce.TroopMemberListRequest{}) WriteJceStruct(w, &jce.SvcRespPushMsg{}) WriteJceStruct(w, &jce.ModifyGroupCardRequest{}) WriteJceStruct(w, &jce.SvcReqGetDevLoginInfo{}) WriteJceStruct(w, &jce.SvcReqRegisterNew{}) WriteJceStruct(w, &jce.DelFriendReq{}) err = w.Close() if err != nil { panic(err) } } func writeObject(w io.Writer, v reflect.Value, tag byte, name string) { k := v.Kind() if k == reflect.Map { switch v.Interface().(type) { case map[string]string: w.Write([]byte(fmt.Sprintf("\tw.writeMapStrStr(pkt.%s, %d)\n", name, tag))) case map[string][]byte: w.Write([]byte(fmt.Sprintf("\tw.writeMapStrBytes(pkt.%s, %d)\n", name, tag))) case map[string]map[string][]byte: w.Write([]byte(fmt.Sprintf("\tw.writeMapStrMapStrBytes(pkt.%s, %d)\n", name, tag))) default: w.Write([]byte(fmt.Sprintf("\tw.writeMap(pkt.%s, %d)\n", name, tag))) } return } if k == reflect.Slice { switch v.Interface().(type) { case []byte: w.Write([]byte(fmt.Sprintf("\tw.WriteBytes(pkt.%s, %d)\n", name, tag))) case []int64: w.Write([]byte(fmt.Sprintf("\tw.WriteInt64Slice(pkt.%s, %d)\n", name, tag))) case [][]byte: w.Write([]byte(fmt.Sprintf("\tw.WriteBytesSlice(pkt.%s, %d)\n", name, tag))) case []jce.IJceStruct: w.Write([]byte(fmt.Sprintf("\tw.WriteJceStructSlice(pkt.%s, %d)\n", name, tag))) default: w.Write([]byte(fmt.Sprintf("\tw.writeSlice(pkt.%s, %d)\n", name, tag))) } return } switch k { case reflect.Uint8, reflect.Int8: w.Write([]byte(fmt.Sprintf("\tw.WriteByte(pkt.%s, %d)\n", name, tag))) case reflect.Uint16, reflect.Int16: w.Write([]byte(fmt.Sprintf("\tw.WriteInt16(pkt.%s, %d)\n", name, tag))) case reflect.Uint32, reflect.Int32: w.Write([]byte(fmt.Sprintf("\tw.WriteInt32(pkt.%s, %d)\n", name, tag))) case reflect.Uint64, reflect.Int64: w.Write([]byte(fmt.Sprintf("\tw.WriteInt64(pkt.%s, %d)\n", name, tag))) case reflect.String: w.Write([]byte(fmt.Sprintf("\tw.WriteString(pkt.%s, %d)\n", name, tag))) default: switch v.Interface().(type) { case jce.IJceStruct: w.Write([]byte(fmt.Sprintf("\tw.WriteJceStruct(pkt.%s, %d)\n", name, tag))) case float32: w.Write([]byte(fmt.Sprintf("\tw.WriteFloat32(pkt.%s, %d)\n", name, tag))) case float64: w.Write([]byte(fmt.Sprintf("\tw.WriteFloat64(pkt.%s, %d)\n", name, tag))) } } } type decoder struct { index int id int name string } var decoderCache = sync.Map{} // writeJceStructRaw 写入 Jce 结构体 func writeJceStructRaw(w io.Writer, s interface{}) { t := reflect.TypeOf(s) if t.Kind() != reflect.Ptr { return } t = t.Elem() v := reflect.ValueOf(s).Elem() var jceDec []decoder dec, ok := decoderCache.Load(t) if ok { // 从缓存中加载 jceDec = dec.([]decoder) } else { // 初次反射 jceDec = make([]decoder, 0, t.NumField()) for i := 0; i < t.NumField(); i++ { field := t.Field(i) strId := field.Tag.Get("jceId") if strId == "" { continue } id, err := strconv.Atoi(strId) if err != nil { continue } jceDec = append(jceDec, decoder{ index: i, id: id, name: field.Name, }) } decoderCache.Store(t, jceDec) // 存入缓存 } for _, dec := range jceDec { obj := v.Field(dec.index) writeObject(w, obj, byte(dec.id), dec.name) } } func WriteJceStruct(w io.Writer, s jce.IJceStruct) { w.Write([]byte(fmt.Sprintf("\nfunc (pkt %s) ToBytes() []byte {\n", strings.ReplaceAll(reflect.TypeOf(s).String(), "jce.", "")))) w.Write([]byte("\tw := NewJceWriter()\n")) writeJceStructRaw(w, s) w.Write([]byte("\treturn w.Bytes()\n")) w.Write([]byte("}\n")) }