diff --git a/defs/gen/main.go b/defs/gen/main.go new file mode 100644 index 0000000..56602a0 --- /dev/null +++ b/defs/gen/main.go @@ -0,0 +1,821 @@ +//go:build ignore + +package main + +import ( + "encoding/xml" + "flag" + "fmt" + "io" + "log" + "os" + "path/filepath" + "strings" + "text/template" +) + +// XMLDefinition represents the root element containing structs +type XMLDefinition struct { + XMLName xml.Name `xml:"structs"` + Structs []XMLStruct `xml:"struct"` +} + +// XMLStruct represents a packet structure definition +type XMLStruct struct { + Name string `xml:"name,attr"` + ClientVersion string `xml:"clientVersion,attr"` + OpcodeName string `xml:"opcodeName,attr"` + Fields []XMLData `xml:"data"` +} + +// XMLData represents a field in the packet structure +type XMLData struct { + Name string `xml:"name,attr"` + Type string `xml:"type,attr"` + Size int `xml:"size,attr"` + ArraySizeVariable string `xml:"arraySizeVariable,attr"` + IfVarSet string `xml:"ifVarSet,attr"` + IfVarNotSet string `xml:"ifVarNotSet,attr"` + OversizedValue int `xml:"oversizedValue,attr"` + Children []XMLData `xml:"data"` // For nested array elements +} + +// TypeMapping maps XML types to Go types +var TypeMapping = map[string]string{ + "int8": "int8", + "int16": "int16", + "int32": "int32", + "int64": "int64", + "uint8": "uint8", + "uint16": "uint16", + "uint32": "uint32", + "uint64": "uint64", + "i8": "int8", + "i16": "int16", + "i32": "int32", + "i64": "int64", + "u8": "uint8", + "u16": "uint16", + "u32": "uint32", + "u64": "uint64", + "float": "float32", + "double": "float64", + "str8": "string", + "str16": "string", + "str32": "string", + "EQ2_32Bit_String": "string", + "EQ2_8Bit_String": "string", + "EQ2_16Bit_String": "string", + "char": "byte", + "color": "types.Color", // RGB color as 32-bit value + "equipmentItem": "types.EquipmentItem", // Custom type + "Array": "array", // Capital A variant +} + +// GoStruct represents the generated Go struct +type GoStruct struct { + Name string + ClientVersion string + OpcodeName string + Fields []GoField + PackageName string +} + +// GoField represents a field in the Go struct +type GoField struct { + Name string + GoName string + Type string + IsArray bool + IsDynamicArray bool + ArraySizeVariable string + Size int + Tag string + Comment string + IfVarSet string + IfVarNotSet string + ArrayElements []GoField // For complex array elements (anonymous struct) +} + +// GenerateOutput holds the generated code +type GenerateOutput struct { + SourceFile string + PackageName string + Structs []GoStruct + NeedsMath bool +} + +// parseXMLFile parses an XML definition file +func parseXMLFile(filename string) ([]XMLStruct, error) { + file, err := os.Open(filename) + if err != nil { + return nil, err + } + defer file.Close() + + data, err := io.ReadAll(file) + if err != nil { + return nil, err + } + + // Wrap content in root element if needed + content := string(data) + if !strings.HasPrefix(strings.TrimSpace(content), "") { + content = "" + content + "" + } + + var def XMLDefinition + if err := xml.Unmarshal([]byte(content), &def); err != nil { + return nil, err + } + + return def.Structs, nil +} + +// toGoName converts snake_case to CamelCase +func toGoName(name string) string { + parts := strings.Split(name, "_") + for i, part := range parts { + if len(part) > 0 { + parts[i] = strings.ToUpper(part[:1]) + part[1:] + } + } + return strings.Join(parts, "") +} + +// mapSimpleType maps XML type to Go type +func mapSimpleType(xmlType string) (string, bool) { + goType, ok := TypeMapping[xmlType] + if !ok { + return "byte", false + } + return goType, true +} + +// convertArrayChildren converts nested array data to Go fields +func convertArrayChildren(children []XMLData) []GoField { + fields := make([]GoField, 0, len(children)) + + for _, child := range children { + if child.Type == "array" && len(child.Children) > 0 { + // Nested array - recursive + nestedFields := convertArrayChildren(child.Children) + goField := GoField{ + Name: child.Name, + GoName: toGoName(child.Name), + IsDynamicArray: true, + ArraySizeVariable: child.ArraySizeVariable, + ArrayElements: nestedFields, + } + fields = append(fields, goField) + } else { + // Simple field + goType, _ := mapSimpleType(child.Type) + isArray := child.Size > 0 + + goField := GoField{ + Name: child.Name, + GoName: toGoName(child.Name), + Type: goType, + IsArray: isArray, + Size: child.Size, + } + + if isArray { + goField.Type = fmt.Sprintf("[%d]%s", child.Size, goType) + } + + fields = append(fields, goField) + } + } + + return fields +} + +// buildAnonymousStructType builds the anonymous struct type string +func buildAnonymousStructType(fields []GoField) string { + if len(fields) == 0 { + return "struct{}" + } + + var sb strings.Builder + sb.WriteString("struct {\n") + for _, field := range fields { + sb.WriteString("\t\t") + sb.WriteString(field.GoName) + sb.WriteString(" ") + + if field.IsDynamicArray && len(field.ArrayElements) > 0 { + // Nested array + sb.WriteString("[]") + sb.WriteString(buildAnonymousStructType(field.ArrayElements)) + } else if field.IsArray { + sb.WriteString(field.Type) + } else { + sb.WriteString(field.Type) + } + + // Add struct tag + sb.WriteString(" `eq2:\"") + sb.WriteString(field.Name) + if field.Type == "string" { + // Determine string type from original XML + sb.WriteString(",type:str16") // Default to str16 for now + } + if field.IsArray && field.Size > 0 { + sb.WriteString(fmt.Sprintf(",size:%d", field.Size)) + } + sb.WriteString("\"`") + sb.WriteString("\n") + } + sb.WriteString("\t}") + return sb.String() +} + +// convertToGoStruct converts XML struct definition to Go struct +func convertToGoStruct(xmlStruct XMLStruct, packageName string) GoStruct { + goStruct := GoStruct{ + Name: toGoName(xmlStruct.Name), + ClientVersion: xmlStruct.ClientVersion, + OpcodeName: xmlStruct.OpcodeName, + PackageName: packageName, + Fields: make([]GoField, 0, len(xmlStruct.Fields)), + } + + // Add version suffix if needed + if xmlStruct.ClientVersion != "" && xmlStruct.ClientVersion != "1" { + goStruct.Name = fmt.Sprintf("%sV%s", goStruct.Name, xmlStruct.ClientVersion) + } + + // Track field names to avoid duplicates + fieldNames := make(map[string]int) + + for _, field := range xmlStruct.Fields { + if field.Type == "array" || field.Type == "Array" { + // Handle array with nested structure + if len(field.Children) > 0 { + arrayElements := convertArrayChildren(field.Children) + structType := buildAnonymousStructType(arrayElements) + + // Check for duplicate field names and make unique if needed + baseName := toGoName(field.Name) + finalName := baseName + if count, exists := fieldNames[baseName]; exists { + finalName = fmt.Sprintf("%s_%d", baseName, count+1) + fieldNames[baseName] = count + 1 + } else { + fieldNames[baseName] = 1 + } + + goField := GoField{ + Name: field.Name, + GoName: finalName, + Type: "[]" + structType, + IsDynamicArray: true, + ArraySizeVariable: field.ArraySizeVariable, + ArrayElements: arrayElements, + IfVarSet: field.IfVarSet, + IfVarNotSet: field.IfVarNotSet, + } + + // Generate struct tag + tag := fmt.Sprintf("`eq2:\"%s", field.Name) + if field.ArraySizeVariable != "" { + tag += fmt.Sprintf(",sizeVar:%s", field.ArraySizeVariable) + } + if field.IfVarSet != "" { + tag += fmt.Sprintf(",ifSet:%s", field.IfVarSet) + } + tag += "\"`" + goField.Tag = tag + + goStruct.Fields = append(goStruct.Fields, goField) + } else { + // Simple array (shouldn't happen but handle it) + log.Printf("Warning: array field %s has no children", field.Name) + } + } else if field.Type == "equipmentItem" { + // Handle equipment item arrays + // Check for duplicate field names and make unique if needed + baseName := toGoName(field.Name) + finalName := baseName + if count, exists := fieldNames[baseName]; exists { + finalName = fmt.Sprintf("%s_%d", baseName, count+1) + fieldNames[baseName] = count + 1 + } else { + fieldNames[baseName] = 1 + } + + goField := GoField{ + Name: field.Name, + GoName: finalName, + Type: fmt.Sprintf("[%d]types.EquipmentItem", field.Size), + IsArray: true, + Size: field.Size, + } + + tag := fmt.Sprintf("`eq2:\"%s,size:%d\"`", field.Name, field.Size) + goField.Tag = tag + + goStruct.Fields = append(goStruct.Fields, goField) + } else { + // Regular field + goType, _ := mapSimpleType(field.Type) + isArray := field.Size > 0 + + // Check for duplicate field names and make unique if needed + baseName := toGoName(field.Name) + finalName := baseName + if count, exists := fieldNames[baseName]; exists { + finalName = fmt.Sprintf("%s_%d", baseName, count+1) + fieldNames[baseName] = count + 1 + } else { + fieldNames[baseName] = 1 + } + + goField := GoField{ + Name: field.Name, + GoName: finalName, + Type: goType, + IsArray: isArray, + Size: field.Size, + IfVarSet: field.IfVarSet, + IfVarNotSet: field.IfVarNotSet, + } + + if isArray { + goField.Type = fmt.Sprintf("[%d]%s", field.Size, goType) + } + + // Generate struct tag + tag := fmt.Sprintf("`eq2:\"%s", field.Name) + if field.Type == "str8" || field.Type == "str16" || field.Type == "str32" || + field.Type == "EQ2_32Bit_String" || field.Type == "EQ2_16Bit_String" || field.Type == "EQ2_8Bit_String" { + tag += fmt.Sprintf(",type:%s", field.Type) + } + if isArray && field.Size > 0 { + tag += fmt.Sprintf(",size:%d", field.Size) + } + if field.IfVarSet != "" { + tag += fmt.Sprintf(",ifSet:%s", field.IfVarSet) + } + tag += "\"`" + goField.Tag = tag + + // Add comment if needed + if strings.HasPrefix(field.Name, "unknown") || strings.HasPrefix(field.Name, "Unknown") { + goField.Comment = " // TODO: Identify purpose" + } + + goStruct.Fields = append(goStruct.Fields, goField) + } + } + + return goStruct +} + +const structTemplate = `// Code generated by codegen. DO NOT EDIT. +// Source: {{.SourceFile}} + +package {{.PackageName}} + +import ( + "encoding/binary"{{if .NeedsMath}} + "math"{{end}} + "git.sharkk.net/EQ2/Protocol/types" +) + +{{range .Structs}} +// {{.Name}} represents packet structure for {{if .OpcodeName}}{{.OpcodeName}}{{else}}client version {{.ClientVersion}}{{end}} +type {{.Name}} struct { +{{- range .Fields}} + {{.GoName}} {{.Type}} {{.Tag}}{{if .Comment}} {{.Comment}}{{end}} +{{- end}} +} + +// Serialize writes the packet data to the provided buffer +func (p *{{.Name}}) Serialize(dest []byte) uint32 { + offset := uint32(0) + {{range .Fields}} + {{- if .IsDynamicArray}} + // Write {{.GoName}} array (dynamic size) + for _, elem := range p.{{.GoName}} { + {{- template "serializeFields" .ArrayElements}} + } + {{- else if eq .Type "string"}} + // Write {{.GoName}} as {{if contains .Tag "str16"}}16-bit{{else if contains .Tag "str32"}}32-bit{{else if contains .Tag "EQ2_32Bit_String"}}32-bit{{else}}8-bit{{end}} length-prefixed string + {{- if or (contains .Tag "str16") (contains .Tag "EQ2_16Bit_String")}} + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.{{.GoName}}))) + offset += 2 + {{- else if or (contains .Tag "str32") (contains .Tag "EQ2_32Bit_String")}} + binary.LittleEndian.PutUint32(dest[offset:], uint32(len(p.{{.GoName}}))) + offset += 4 + {{- else}} + dest[offset] = byte(len(p.{{.GoName}})) + offset++ + {{- end}} + copy(dest[offset:], []byte(p.{{.GoName}})) + offset += uint32(len(p.{{.GoName}})) + {{- else if .IsArray}} + // Write {{.GoName}} array + for i := 0; i < {{.Size}}; i++ { + {{- if eq (baseType .Type) "float32"}} + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.{{.GoName}}[i])) + offset += 4 + {{- else if eq (baseType .Type) "float64"}} + binary.LittleEndian.PutUint64(dest[offset:], math.Float64bits(p.{{.GoName}}[i])) + offset += 8 + {{- else if (eq (baseType .Type) "int8")}} + dest[offset] = byte(p.{{.GoName}}[i]) + offset++ + {{- else if or (eq (baseType .Type) "uint8") (eq (baseType .Type) "byte")}} + dest[offset] = p.{{.GoName}}[i] + offset++ + {{- else if or (eq (baseType .Type) "int16") (eq (baseType .Type) "uint16")}} + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.{{.GoName}}[i])) + offset += 2 + {{- else if or (eq (baseType .Type) "int32") (eq (baseType .Type) "uint32")}} + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.{{.GoName}}[i])) + offset += 4 + {{- else if or (eq (baseType .Type) "int64") (eq (baseType .Type) "uint64")}} + binary.LittleEndian.PutUint64(dest[offset:], uint64(p.{{.GoName}}[i])) + offset += 8 + {{- else if eq (baseType .Type) "types.EquipmentItem"}} + binary.LittleEndian.PutUint16(dest[offset:], p.{{.GoName}}[i].Type) + offset += 2 + binary.LittleEndian.PutUint32(dest[offset:], p.{{.GoName}}[i].Color.ToUint32()) + offset += 4 + {{- end}} + } + {{- else}} + // Write {{.GoName}} + {{- if eq .Type "float32"}} + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.{{.GoName}})) + offset += 4 + {{- else if eq .Type "float64"}} + binary.LittleEndian.PutUint64(dest[offset:], math.Float64bits(p.{{.GoName}})) + offset += 8 + {{- else if or (eq .Type "int8") (eq .Type "uint8") (eq .Type "byte")}} + dest[offset] = byte(p.{{.GoName}}) + offset++ + {{- else if or (eq .Type "int16") (eq .Type "uint16")}} + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.{{.GoName}})) + offset += 2 + {{- else if eq .Type "types.Color"}} + binary.LittleEndian.PutUint32(dest[offset:], p.{{.GoName}}.ToUint32()) + offset += 4 + {{- else if or (eq .Type "int32") (eq .Type "uint32")}} + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.{{.GoName}})) + offset += 4 + {{- else if or (eq .Type "int64") (eq .Type "uint64")}} + binary.LittleEndian.PutUint64(dest[offset:], uint64(p.{{.GoName}})) + offset += 8 + {{- end}} + {{- end}} + {{end}} + return offset +} + +// Size returns the serialized size of the packet +func (p *{{.Name}}) Size() uint32 { + size := uint32(0) + {{range .Fields}} + {{- if .IsDynamicArray}} + // Dynamic array: {{.GoName}} + for _, elem := range p.{{.GoName}} { + {{- template "sizeFields" .ArrayElements}} + } + {{- else if eq .Type "string"}} + {{- if or (contains .Tag "str16") (contains .Tag "EQ2_16Bit_String")}} + size += 2 + uint32(len(p.{{.GoName}})) + {{- else if or (contains .Tag "str32") (contains .Tag "EQ2_32Bit_String")}} + size += 4 + uint32(len(p.{{.GoName}})) + {{- else}} + size += 1 + uint32(len(p.{{.GoName}})) + {{- end}} + {{- else if .IsArray}} + {{- if eq (baseType .Type) "types.EquipmentItem"}} + size += {{.Size}} * 6 + {{- else if eq (sizeOf (baseType .Type)) 1}} + size += {{.Size}} + {{- else}} + size += {{.Size}} * {{sizeOf (baseType .Type)}} + {{- end}} + {{- else}} + size += {{sizeOf .Type}} + {{- end}} + {{end}} + return size +} +{{end}} + +{{define "serializeFields"}} +{{- range .}} +{{- if .IsDynamicArray}} + // Write nested {{.GoName}} array + for _, nestedElem := range elem.{{.GoName}} { + {{- template "serializeNestedFields" .ArrayElements}} + } +{{- else if eq .Type "string"}} + // Write {{.GoName}} string field + dest[offset] = byte(len(elem.{{.GoName}})) + offset++ + copy(dest[offset:], []byte(elem.{{.GoName}})) + offset += uint32(len(elem.{{.GoName}})) +{{- else if .IsArray}} + // Write {{.GoName}} array field + for i := 0; i < {{.Size}}; i++ { + {{- if eq (baseType .Type) "float32"}} + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(elem.{{.GoName}}[i])) + offset += 4 + {{- else if eq (baseType .Type) "uint32"}} + binary.LittleEndian.PutUint32(dest[offset:], elem.{{.GoName}}[i]) + offset += 4 + {{- else if eq (baseType .Type) "uint16"}} + binary.LittleEndian.PutUint16(dest[offset:], elem.{{.GoName}}[i]) + offset += 2 + {{- else}} + dest[offset] = byte(elem.{{.GoName}}[i]) + offset++ + {{- end}} + } +{{- else if eq .Type "float32"}} + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(elem.{{.GoName}})) + offset += 4 +{{- else if eq .Type "types.Color"}} + binary.LittleEndian.PutUint32(dest[offset:], elem.{{.GoName}}.ToUint32()) + offset += 4 +{{- else if eq .Type "uint32"}} + binary.LittleEndian.PutUint32(dest[offset:], elem.{{.GoName}}) + offset += 4 +{{- else if eq .Type "int32"}} + binary.LittleEndian.PutUint32(dest[offset:], uint32(elem.{{.GoName}})) + offset += 4 +{{- else if eq .Type "uint16"}} + binary.LittleEndian.PutUint16(dest[offset:], elem.{{.GoName}}) + offset += 2 +{{- else if eq .Type "int16"}} + binary.LittleEndian.PutUint16(dest[offset:], uint16(elem.{{.GoName}})) + offset += 2 +{{- else if eq .Type "int8"}} + dest[offset] = byte(elem.{{.GoName}}) + offset++ +{{- else if eq .Type "uint8"}} + dest[offset] = elem.{{.GoName}} + offset++ +{{- else}} + dest[offset] = byte(elem.{{.GoName}}) + offset++ +{{- end}} +{{- end}} +{{end}} + +{{define "sizeFields"}} + _ = elem // Avoid unused variable warning +{{- range .}} +{{- if .IsDynamicArray}} + // Nested array: {{.GoName}} + for _, nestedElem := range elem.{{.GoName}} { + {{- template "sizeNestedFields" .ArrayElements}} + } +{{- else if eq .Type "string"}} + size += 1 + uint32(len(elem.{{.GoName}})) +{{- else if .IsArray}} + {{- if eq (sizeOf (baseType .Type)) 1}} + size += {{.Size}} + {{- else}} + size += {{.Size}} * {{sizeOf (baseType .Type)}} + {{- end}} +{{- else}} + size += {{sizeOf .Type}} +{{- end}} +{{- end}} +{{end}} + +{{define "serializeNestedFields"}} +{{- range .}} +{{- if .IsDynamicArray}} + // Write deeply nested {{.GoName}} array + for _, deepNested := range nestedElem.{{.GoName}} { + // TODO: Handle deeper nesting if needed + _ = deepNested + } +{{- else if eq .Type "string"}} + // Write {{.GoName}} string field + dest[offset] = byte(len(nestedElem.{{.GoName}})) + offset++ + copy(dest[offset:], []byte(nestedElem.{{.GoName}})) + offset += uint32(len(nestedElem.{{.GoName}})) +{{- else if .IsArray}} + // Write {{.GoName}} array field + for i := 0; i < {{.Size}}; i++ { + {{- if eq (baseType .Type) "float32"}} + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(nestedElem.{{.GoName}}[i])) + offset += 4 + {{- else if eq (baseType .Type) "uint32"}} + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.{{.GoName}}[i]) + offset += 4 + {{- else if eq (baseType .Type) "uint16"}} + binary.LittleEndian.PutUint16(dest[offset:], nestedElem.{{.GoName}}[i]) + offset += 2 + {{- else}} + dest[offset] = nestedElem.{{.GoName}}[i] + offset++ + {{- end}} + } +{{- else if eq .Type "float32"}} + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(nestedElem.{{.GoName}})) + offset += 4 +{{- else if eq .Type "types.Color"}} + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.{{.GoName}}.ToUint32()) + offset += 4 +{{- else if eq .Type "uint32"}} + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.{{.GoName}}) + offset += 4 +{{- else if eq .Type "int32"}} + binary.LittleEndian.PutUint32(dest[offset:], uint32(nestedElem.{{.GoName}})) + offset += 4 +{{- else if eq .Type "uint16"}} + binary.LittleEndian.PutUint16(dest[offset:], nestedElem.{{.GoName}}) + offset += 2 +{{- else if eq .Type "int16"}} + binary.LittleEndian.PutUint16(dest[offset:], uint16(nestedElem.{{.GoName}})) + offset += 2 +{{- else if eq .Type "int8"}} + dest[offset] = byte(nestedElem.{{.GoName}}) + offset++ +{{- else if eq .Type "uint8"}} + dest[offset] = nestedElem.{{.GoName}} + offset++ +{{- else}} + dest[offset] = byte(nestedElem.{{.GoName}}) + offset++ +{{- end}} +{{- end}} +{{end}} + +{{define "sizeNestedFields"}} + _ = nestedElem // Avoid unused variable +{{- range .}} +{{- if .IsDynamicArray}} + // Deeply nested array: {{.GoName}} + for _, deepNested := range nestedElem.{{.GoName}} { + // TODO: Handle deeper nesting if needed + _ = deepNested + } +{{- else if eq .Type "string"}} + size += 1 + uint32(len(nestedElem.{{.GoName}})) +{{- else if .IsArray}} + {{- if eq (sizeOf (baseType .Type)) 1}} + size += {{.Size}} + {{- else}} + size += {{.Size}} * {{sizeOf (baseType .Type)}} + {{- end}} +{{- else}} + size += {{sizeOf .Type}} +{{- end}} +{{- end}} +{{end}} +` + +func contains(s, substr string) bool { + return strings.Contains(s, substr) +} + +func baseType(arrayType string) string { + // Extract base type from array declaration like "[10]uint32" + if strings.HasPrefix(arrayType, "[") { + idx := strings.Index(arrayType, "]") + if idx > 0 { + return arrayType[idx+1:] + } + } + return arrayType +} + +func sizeOf(typeName string) int { + // Return the size in bytes for a given type + switch typeName { + case "int8", "uint8", "byte": + return 1 + case "int16", "uint16": + return 2 + case "int32", "uint32", "float32", "types.Color": + return 4 + case "int64", "uint64", "float64": + return 8 + case "types.EquipmentItem": + return 6 + default: + return 0 + } +} + +func main() { + var ( + input = flag.String("input", "", "Input XML file or directory") + output = flag.String("output", "", "Output Go file or directory") + pkgName = flag.String("package", "generated", "Package name for generated code") + ) + flag.Parse() + + if *input == "" || *output == "" { + fmt.Fprintf(os.Stderr, "Usage: %s -input -output [-package ]\n", os.Args[0]) + os.Exit(1) + } + + // Get file info + info, err := os.Stat(*input) + if err != nil { + log.Fatalf("Error accessing input: %v", err) + } + + if info.IsDir() { + // Process directory + files, err := filepath.Glob(filepath.Join(*input, "*.xml")) + if err != nil { + log.Fatalf("Error listing XML files: %v", err) + } + + for _, xmlFile := range files { + processFile(xmlFile, *output, *pkgName) + } + } else { + // Process single file + processFile(*input, *output, *pkgName) + } +} + +func processFile(inputFile, outputPath, packageName string) { + log.Printf("Processing %s...", inputFile) + + // Parse XML file + structs, err := parseXMLFile(inputFile) + if err != nil { + log.Printf("Error parsing %s: %v", inputFile, err) + return + } + + // Convert to Go structs + goStructs := make([]GoStruct, 0, len(structs)) + + for _, xmlStruct := range structs { + goStructs = append(goStructs, convertToGoStruct(xmlStruct, packageName)) + } + + // Determine output file + outputFile := outputPath + if info, err := os.Stat(outputPath); err == nil && info.IsDir() { + base := strings.TrimSuffix(filepath.Base(inputFile), ".xml") + outputFile = filepath.Join(outputPath, base+".go") + } + + // Generate code + tmpl := template.New("struct") + tmpl.Funcs(template.FuncMap{ + "contains": contains, + "baseType": baseType, + "sizeOf": sizeOf, + }) + + // Parse the main template + tmpl, err = tmpl.Parse(structTemplate) + if err != nil { + log.Fatalf("Error parsing template: %v", err) + } + + // Create output file + out, err := os.Create(outputFile) + if err != nil { + log.Fatalf("Error creating output file: %v", err) + } + defer out.Close() + + // Check if math package is needed (for float types) + needsMath := false + for _, goStruct := range goStructs { + for _, field := range goStruct.Fields { + if strings.Contains(field.Type, "float") { + needsMath = true + break + } + } + if needsMath { + break + } + } + + // Execute template + data := GenerateOutput{ + SourceFile: filepath.Base(inputFile), + PackageName: packageName, + Structs: goStructs, + NeedsMath: needsMath, + } + + if err := tmpl.Execute(out, data); err != nil { + log.Fatalf("Error executing template: %v", err) + } + + log.Printf("Generated %s", outputFile) +} diff --git a/defs/generated/common.go b/defs/generated/common.go new file mode 100644 index 0000000..a40329e --- /dev/null +++ b/defs/generated/common.go @@ -0,0 +1,5941 @@ +// Code generated by codegen. DO NOT EDIT. +// Source: common.xml + +package generated + +import ( + "encoding/binary" + "math" + "git.sharkk.net/EQ2/Protocol/types" +) + + +// CreateCharacter represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacter struct { + AccountId uint32 `eq2:"account_id"` + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint8 `eq2:"starting_zone"` + Unknown1 [2]uint8 `eq2:"unknown1,size:2"` // TODO: Identify purpose + RaceFile string `eq2:"race_file,type:str16"` + SkinColor [3]float32 `eq2:"skin_color,size:3"` + EyeColor [3]float32 `eq2:"eye_color,size:3"` + HairColor1 [3]float32 `eq2:"hair_color1,size:3"` + HairColor2 [3]float32 `eq2:"hair_color2,size:3"` + HairHighlight [3]float32 `eq2:"hair_highlight,size:3"` + Unknown2 [26]uint8 `eq2:"unknown2,size:26"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor [3]float32 `eq2:"hair_type_color,size:3"` + HairTypeHighlightColor [3]float32 `eq2:"hair_type_highlight_color,size:3"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor [3]float32 `eq2:"hair_face_color,size:3"` + HairFaceHighlightColor [3]float32 `eq2:"hair_face_highlight_color,size:3"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor [3]float32 `eq2:"shirt_color,size:3"` + UnknownChestColor [3]float32 `eq2:"unknown_chest_color,size:3"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor [3]float32 `eq2:"pants_color,size:3"` + UnknownLegsColor [3]float32 `eq2:"unknown_legs_color,size:3"` // TODO: Identify purpose + Unknown9 [3]float32 `eq2:"unknown9,size:3"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacter) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + dest[offset] = byte(p.StartingZone) + offset++ + + // Write Unknown1 array + for i := 0; i < 2; i++ { + dest[offset] = p.Unknown1[i] + offset++ + } + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SkinColor[i])) + offset += 4 + } + + // Write EyeColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeColor[i])) + offset += 4 + } + + // Write HairColor1 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairColor1[i])) + offset += 4 + } + + // Write HairColor2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairColor2[i])) + offset += 4 + } + + // Write HairHighlight array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairHighlight[i])) + offset += 4 + } + + // Write Unknown2 array + for i := 0; i < 26; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairTypeColor[i])) + offset += 4 + } + + // Write HairTypeHighlightColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairTypeHighlightColor[i])) + offset += 4 + } + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairFaceColor[i])) + offset += 4 + } + + // Write HairFaceHighlightColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairFaceHighlightColor[i])) + offset += 4 + } + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.ShirtColor[i])) + offset += 4 + } + + // Write UnknownChestColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.UnknownChestColor[i])) + offset += 4 + } + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.PantsColor[i])) + offset += 4 + } + + // Write UnknownLegsColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.UnknownLegsColor[i])) + offset += 4 + } + + // Write Unknown9 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Unknown9[i])) + offset += 4 + } + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacter) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 2 + + size += 2 + uint32(len(p.RaceFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 26 + + size += 2 + uint32(len(p.HairFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + return size +} + +// CreateCharacterV373 represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacterV373 struct { + Unknown0 uint32 `eq2:"unknown0"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint8 `eq2:"starting_zone"` + Unknown1 [2]uint8 `eq2:"unknown1,size:2"` // TODO: Identify purpose + RaceFile string `eq2:"race_file,type:str16"` + SkinColor [3]float32 `eq2:"skin_color,size:3"` + EyeColor [3]float32 `eq2:"eye_color,size:3"` + HairColor1 [3]float32 `eq2:"hair_color1,size:3"` + HairColor2 [3]float32 `eq2:"hair_color2,size:3"` + HairHighlight [3]float32 `eq2:"hair_highlight,size:3"` + Unknown2 [26]uint8 `eq2:"unknown2,size:26"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor [3]float32 `eq2:"hair_type_color,size:3"` + HairTypeHighlightColor [3]float32 `eq2:"hair_type_highlight_color,size:3"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor [3]float32 `eq2:"hair_face_color,size:3"` + HairFaceHighlightColor [3]float32 `eq2:"hair_face_highlight_color,size:3"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor [3]float32 `eq2:"shirt_color,size:3"` + UnknownChestColor [3]float32 `eq2:"unknown_chest_color,size:3"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor [3]float32 `eq2:"pants_color,size:3"` + UnknownLegsColor [3]float32 `eq2:"unknown_legs_color,size:3"` // TODO: Identify purpose + Unknown9 [3]float32 `eq2:"unknown9,size:3"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacterV373) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Unknown0 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown0)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + dest[offset] = byte(p.StartingZone) + offset++ + + // Write Unknown1 array + for i := 0; i < 2; i++ { + dest[offset] = p.Unknown1[i] + offset++ + } + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SkinColor[i])) + offset += 4 + } + + // Write EyeColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeColor[i])) + offset += 4 + } + + // Write HairColor1 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairColor1[i])) + offset += 4 + } + + // Write HairColor2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairColor2[i])) + offset += 4 + } + + // Write HairHighlight array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairHighlight[i])) + offset += 4 + } + + // Write Unknown2 array + for i := 0; i < 26; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairTypeColor[i])) + offset += 4 + } + + // Write HairTypeHighlightColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairTypeHighlightColor[i])) + offset += 4 + } + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairFaceColor[i])) + offset += 4 + } + + // Write HairFaceHighlightColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairFaceHighlightColor[i])) + offset += 4 + } + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.ShirtColor[i])) + offset += 4 + } + + // Write UnknownChestColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.UnknownChestColor[i])) + offset += 4 + } + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.PantsColor[i])) + offset += 4 + } + + // Write UnknownLegsColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.UnknownLegsColor[i])) + offset += 4 + } + + // Write Unknown9 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Unknown9[i])) + offset += 4 + } + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacterV373) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 2 + + size += 2 + uint32(len(p.RaceFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 26 + + size += 2 + uint32(len(p.HairFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + return size +} + +// CreateCharacterV546 represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacterV546 struct { + Unknown0 uint8 `eq2:"unknown0"` // TODO: Identify purpose + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint8 `eq2:"starting_zone"` + CcUnknown0 uint8 `eq2:"cc_unknown_0"` + Version uint8 `eq2:"version"` + RaceFile string `eq2:"race_file,type:str16"` + SkinColor [3]float32 `eq2:"skin_color,size:3"` + EyeColor [3]float32 `eq2:"eye_color,size:3"` + HairColor1 [3]float32 `eq2:"hair_color1,size:3"` + HairColor2 [3]float32 `eq2:"hair_color2,size:3"` + HairHighlight [3]float32 `eq2:"hair_highlight,size:3"` + Unknown2 [26]uint8 `eq2:"unknown2,size:26"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor [3]float32 `eq2:"hair_type_color,size:3"` + HairTypeHighlightColor [3]float32 `eq2:"hair_type_highlight_color,size:3"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor [3]float32 `eq2:"hair_face_color,size:3"` + HairFaceHighlightColor [3]float32 `eq2:"hair_face_highlight_color,size:3"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor [3]float32 `eq2:"shirt_color,size:3"` + UnknownChestColor [3]float32 `eq2:"unknown_chest_color,size:3"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor [3]float32 `eq2:"pants_color,size:3"` + UnknownLegsColor [3]float32 `eq2:"unknown_legs_color,size:3"` // TODO: Identify purpose + Unknown9 [3]float32 `eq2:"unknown9,size:3"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacterV546) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Unknown0 + dest[offset] = byte(p.Unknown0) + offset++ + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + dest[offset] = byte(p.StartingZone) + offset++ + + // Write CcUnknown0 + dest[offset] = byte(p.CcUnknown0) + offset++ + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SkinColor[i])) + offset += 4 + } + + // Write EyeColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeColor[i])) + offset += 4 + } + + // Write HairColor1 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairColor1[i])) + offset += 4 + } + + // Write HairColor2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairColor2[i])) + offset += 4 + } + + // Write HairHighlight array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairHighlight[i])) + offset += 4 + } + + // Write Unknown2 array + for i := 0; i < 26; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairTypeColor[i])) + offset += 4 + } + + // Write HairTypeHighlightColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairTypeHighlightColor[i])) + offset += 4 + } + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairFaceColor[i])) + offset += 4 + } + + // Write HairFaceHighlightColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairFaceHighlightColor[i])) + offset += 4 + } + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.ShirtColor[i])) + offset += 4 + } + + // Write UnknownChestColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.UnknownChestColor[i])) + offset += 4 + } + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.PantsColor[i])) + offset += 4 + } + + // Write UnknownLegsColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.UnknownLegsColor[i])) + offset += 4 + } + + // Write Unknown9 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Unknown9[i])) + offset += 4 + } + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacterV546) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 2 + uint32(len(p.RaceFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 26 + + size += 2 + uint32(len(p.HairFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + return size +} + +// CreateCharacterV561 represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacterV561 struct { + Unknown0 uint8 `eq2:"unknown0"` // TODO: Identify purpose + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint8 `eq2:"starting_zone"` + Version uint8 `eq2:"version"` + RaceFile string `eq2:"race_file,type:str16"` + SkinColor [3]float32 `eq2:"skin_color,size:3"` + EyeColor [3]float32 `eq2:"eye_color,size:3"` + HairColor1 [3]float32 `eq2:"hair_color1,size:3"` + HairColor2 [3]float32 `eq2:"hair_color2,size:3"` + HairHighlight [3]float32 `eq2:"hair_highlight,size:3"` + Unknown2 [26]uint8 `eq2:"unknown2,size:26"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor [3]float32 `eq2:"hair_type_color,size:3"` + HairTypeHighlightColor [3]float32 `eq2:"hair_type_highlight_color,size:3"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor [3]float32 `eq2:"hair_face_color,size:3"` + HairFaceHighlightColor [3]float32 `eq2:"hair_face_highlight_color,size:3"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor [3]float32 `eq2:"shirt_color,size:3"` + UnknownChestColor [3]float32 `eq2:"unknown_chest_color,size:3"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor [3]float32 `eq2:"pants_color,size:3"` + UnknownLegsColor [3]float32 `eq2:"unknown_legs_color,size:3"` // TODO: Identify purpose + Unknown9 [3]float32 `eq2:"unknown9,size:3"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacterV561) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Unknown0 + dest[offset] = byte(p.Unknown0) + offset++ + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + dest[offset] = byte(p.StartingZone) + offset++ + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SkinColor[i])) + offset += 4 + } + + // Write EyeColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeColor[i])) + offset += 4 + } + + // Write HairColor1 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairColor1[i])) + offset += 4 + } + + // Write HairColor2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairColor2[i])) + offset += 4 + } + + // Write HairHighlight array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairHighlight[i])) + offset += 4 + } + + // Write Unknown2 array + for i := 0; i < 26; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairTypeColor[i])) + offset += 4 + } + + // Write HairTypeHighlightColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairTypeHighlightColor[i])) + offset += 4 + } + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairFaceColor[i])) + offset += 4 + } + + // Write HairFaceHighlightColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.HairFaceHighlightColor[i])) + offset += 4 + } + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.ShirtColor[i])) + offset += 4 + } + + // Write UnknownChestColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.UnknownChestColor[i])) + offset += 4 + } + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.PantsColor[i])) + offset += 4 + } + + // Write UnknownLegsColor array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.UnknownLegsColor[i])) + offset += 4 + } + + // Write Unknown9 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Unknown9[i])) + offset += 4 + } + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacterV561) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 2 + uint32(len(p.RaceFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 26 + + size += 2 + uint32(len(p.HairFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + return size +} + +// CreateCharacterV562 represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacterV562 struct { + Unknown0 uint8 `eq2:"unknown0"` // TODO: Identify purpose + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 uint8 `eq2:"unknown3"` // TODO: Identify purpose + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint8 `eq2:"starting_zone"` + Version uint8 `eq2:"version"` + RaceFile string `eq2:"race_file,type:str16"` + SkinColor types.Color `eq2:"skin_color"` + SkinColor2 types.Color `eq2:"skin_color2"` + EyeColor types.Color `eq2:"eye_color"` + HairColor1 types.Color `eq2:"hair_color1"` + HairColor2 types.Color `eq2:"hair_color2"` + Unknown8 [26]uint8 `eq2:"unknown8,size:26"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor types.Color `eq2:"hair_type_color"` + HairTypeHighlightColor types.Color `eq2:"hair_type_highlight_color"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor types.Color `eq2:"hair_face_color"` + HairFaceHighlightColor types.Color `eq2:"hair_face_highlight_color"` + WingFile string `eq2:"wing_file,type:str16"` + WingColor1 types.Color `eq2:"wing_color1"` + WingColor2 types.Color `eq2:"wing_color2"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor types.Color `eq2:"shirt_color"` + UnknownChestColor types.Color `eq2:"unknown_chest_color"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor types.Color `eq2:"pants_color"` + UnknownLegsColor types.Color `eq2:"unknown_legs_color"` // TODO: Identify purpose + Unknown9 types.Color `eq2:"unknown9"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` + SogaVersion uint8 `eq2:"soga_version"` + SogaRaceFile string `eq2:"soga_race_file,type:str16"` + SogaSkinColor types.Color `eq2:"soga_skin_color"` + SogaEyeColor types.Color `eq2:"soga_eye_color"` + SogaHairColor1 types.Color `eq2:"soga_hair_color1"` + SogaHairColor2 types.Color `eq2:"soga_hair_color2"` + SogaHairHighlight types.Color `eq2:"soga_hair_highlight"` + SogaUnknown11 [26]uint8 `eq2:"soga_unknown11,size:26"` + SogaHairFile string `eq2:"soga_hair_file,type:str16"` + SogaHairTypeColor types.Color `eq2:"soga_hair_type_color"` + SogaHairTypeHighlightColor types.Color `eq2:"soga_hair_type_highlight_color"` + SogaFaceFile string `eq2:"soga_face_file,type:str16"` + SogaHairFaceColor types.Color `eq2:"soga_hair_face_color"` + SogaHairFaceHighlightColor types.Color `eq2:"soga_hair_face_highlight_color"` + SogaWingFile string `eq2:"soga_wing_file,type:str16"` + SogaWingColor1 types.Color `eq2:"soga_wing_color1"` + SogaWingColor2 types.Color `eq2:"soga_wing_color2"` + SogaChestFile string `eq2:"soga_chest_file,type:str16"` + SogaShirtColor types.Color `eq2:"soga_shirt_color"` + SogaUnknownChestColor types.Color `eq2:"soga_unknown_chest_color"` + SogaLegsFile string `eq2:"soga_legs_file,type:str16"` + SogaPantsColor types.Color `eq2:"soga_pants_color"` + SogaUnknownLegsColor types.Color `eq2:"soga_unknown_legs_color"` + SogaUnknown12 types.Color `eq2:"soga_unknown12"` + SogaEyes2 [3]float32 `eq2:"soga_eyes2,size:3"` + SogaEars [3]float32 `eq2:"soga_ears,size:3"` + SogaEyeBrows [3]float32 `eq2:"soga_eye_brows,size:3"` + SogaCheeks [3]float32 `eq2:"soga_cheeks,size:3"` + SogaLips [3]float32 `eq2:"soga_lips,size:3"` + SogaChin [3]float32 `eq2:"soga_chin,size:3"` + SogaNose [3]float32 `eq2:"soga_nose,size:3"` + SogaBodySize float32 `eq2:"soga_body_size"` + SogaBodyAge float32 `eq2:"soga_body_age"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacterV562) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Unknown0 + dest[offset] = byte(p.Unknown0) + offset++ + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 + dest[offset] = byte(p.Unknown3) + offset++ + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + dest[offset] = byte(p.StartingZone) + offset++ + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor.ToUint32()) + offset += 4 + + // Write SkinColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor2.ToUint32()) + offset += 4 + + // Write EyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.EyeColor.ToUint32()) + offset += 4 + + // Write HairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor1.ToUint32()) + offset += 4 + + // Write HairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor2.ToUint32()) + offset += 4 + + // Write Unknown8 array + for i := 0; i < 26; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeColor.ToUint32()) + offset += 4 + + // Write HairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceColor.ToUint32()) + offset += 4 + + // Write HairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write WingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.WingFile))) + offset += 2 + copy(dest[offset:], []byte(p.WingFile)) + offset += uint32(len(p.WingFile)) + + // Write WingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor1.ToUint32()) + offset += 4 + + // Write WingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor2.ToUint32()) + offset += 4 + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.ShirtColor.ToUint32()) + offset += 4 + + // Write UnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownChestColor.ToUint32()) + offset += 4 + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.PantsColor.ToUint32()) + offset += 4 + + // Write UnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownLegsColor.ToUint32()) + offset += 4 + + // Write Unknown9 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown9.ToUint32()) + offset += 4 + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + // Write SogaVersion + dest[offset] = byte(p.SogaVersion) + offset++ + + // Write SogaRaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaRaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaRaceFile)) + offset += uint32(len(p.SogaRaceFile)) + + // Write SogaSkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaSkinColor.ToUint32()) + offset += 4 + + // Write SogaEyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaEyeColor.ToUint32()) + offset += 4 + + // Write SogaHairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor1.ToUint32()) + offset += 4 + + // Write SogaHairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor2.ToUint32()) + offset += 4 + + // Write SogaHairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairHighlight.ToUint32()) + offset += 4 + + // Write SogaUnknown11 array + for i := 0; i < 26; i++ { + dest[offset] = p.SogaUnknown11[i] + offset++ + } + + // Write SogaHairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaHairFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaHairFile)) + offset += uint32(len(p.SogaHairFile)) + + // Write SogaHairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeColor.ToUint32()) + offset += 4 + + // Write SogaHairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write SogaFaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaFaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaFaceFile)) + offset += uint32(len(p.SogaFaceFile)) + + // Write SogaHairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write SogaWingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaWingFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaWingFile)) + offset += uint32(len(p.SogaWingFile)) + + // Write SogaWingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor1.ToUint32()) + offset += 4 + + // Write SogaWingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor2.ToUint32()) + offset += 4 + + // Write SogaChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaChestFile)) + offset += uint32(len(p.SogaChestFile)) + + // Write SogaShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaShirtColor.ToUint32()) + offset += 4 + + // Write SogaUnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownChestColor.ToUint32()) + offset += 4 + + // Write SogaLegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaLegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaLegsFile)) + offset += uint32(len(p.SogaLegsFile)) + + // Write SogaPantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaPantsColor.ToUint32()) + offset += 4 + + // Write SogaUnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownLegsColor.ToUint32()) + offset += 4 + + // Write SogaUnknown12 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknown12.ToUint32()) + offset += 4 + + // Write SogaEyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyes2[i])) + offset += 4 + } + + // Write SogaEars array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEars[i])) + offset += 4 + } + + // Write SogaEyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyeBrows[i])) + offset += 4 + } + + // Write SogaCheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaCheeks[i])) + offset += 4 + } + + // Write SogaLips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaLips[i])) + offset += 4 + } + + // Write SogaChin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaChin[i])) + offset += 4 + } + + // Write SogaNose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaNose[i])) + offset += 4 + } + + // Write SogaBodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodySize)) + offset += 4 + + // Write SogaBodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodyAge)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacterV562) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 4 + + size += 4 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 2 + uint32(len(p.RaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 26 + + size += 2 + uint32(len(p.HairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.WingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.SogaRaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 26 + + size += 2 + uint32(len(p.SogaHairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaFaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaWingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaLegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + return size +} + +// CreateCharacterV869 represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacterV869 struct { + Unknown0 uint8 `eq2:"unknown0"` // TODO: Identify purpose + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 uint8 `eq2:"unknown3"` // TODO: Identify purpose + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint8 `eq2:"starting_zone"` + Version uint8 `eq2:"version"` + RaceFile string `eq2:"race_file,type:str16"` + SkinColor types.Color `eq2:"skin_color"` + SkinColor2 types.Color `eq2:"skin_color2"` + EyeColor types.Color `eq2:"eye_color"` + HairColor1 types.Color `eq2:"hair_color1"` + HairColor2 types.Color `eq2:"hair_color2"` + HairHighlight types.Color `eq2:"hair_highlight"` + Unknown8 [26]uint8 `eq2:"unknown8,size:26"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor types.Color `eq2:"hair_type_color"` + HairTypeHighlightColor types.Color `eq2:"hair_type_highlight_color"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor types.Color `eq2:"hair_face_color"` + HairFaceHighlightColor types.Color `eq2:"hair_face_highlight_color"` + WingFile string `eq2:"wing_file,type:str16"` + WingColor1 types.Color `eq2:"wing_color1"` + WingColor2 types.Color `eq2:"wing_color2"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor types.Color `eq2:"shirt_color"` + UnknownChestColor types.Color `eq2:"unknown_chest_color"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor types.Color `eq2:"pants_color"` + UnknownLegsColor types.Color `eq2:"unknown_legs_color"` // TODO: Identify purpose + Unknown9 types.Color `eq2:"unknown9"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` + SogaVersion uint8 `eq2:"soga_version"` + SogaRaceFile string `eq2:"soga_race_file,type:str16"` + SogaSkinColor types.Color `eq2:"soga_skin_color"` + SogaEyeColor types.Color `eq2:"soga_eye_color"` + SogaHairColor1 types.Color `eq2:"soga_hair_color1"` + SogaHairColor2 types.Color `eq2:"soga_hair_color2"` + SogaHairHighlight types.Color `eq2:"soga_hair_highlight"` + SogaUnknownColor1 types.Color `eq2:"soga_unknown_color1"` + SogaUnknown11 [26]uint8 `eq2:"soga_unknown11,size:26"` + SogaHairFile string `eq2:"soga_hair_file,type:str16"` + SogaHairTypeColor types.Color `eq2:"soga_hair_type_color"` + SogaHairTypeHighlightColor types.Color `eq2:"soga_hair_type_highlight_color"` + SogaFaceFile string `eq2:"soga_face_file,type:str16"` + SogaHairFaceColor types.Color `eq2:"soga_hair_face_color"` + SogaHairFaceHighlightColor types.Color `eq2:"soga_hair_face_highlight_color"` + SogaWingFile string `eq2:"soga_wing_file,type:str16"` + SogaWingColor1 types.Color `eq2:"soga_wing_color1"` + SogaWingColor2 types.Color `eq2:"soga_wing_color2"` + SogaChestFile string `eq2:"soga_chest_file,type:str16"` + SogaShirtColor types.Color `eq2:"soga_shirt_color"` + SogaUnknownChestColor types.Color `eq2:"soga_unknown_chest_color"` + SogaLegsFile string `eq2:"soga_legs_file,type:str16"` + SogaPantsColor types.Color `eq2:"soga_pants_color"` + SogaUnknownLegsColor types.Color `eq2:"soga_unknown_legs_color"` + SogaUnknown12 types.Color `eq2:"soga_unknown12"` + SogaEyes2 [3]float32 `eq2:"soga_eyes2,size:3"` + SogaEars [3]float32 `eq2:"soga_ears,size:3"` + SogaEyeBrows [3]float32 `eq2:"soga_eye_brows,size:3"` + SogaCheeks [3]float32 `eq2:"soga_cheeks,size:3"` + SogaLips [3]float32 `eq2:"soga_lips,size:3"` + SogaChin [3]float32 `eq2:"soga_chin,size:3"` + SogaNose [3]float32 `eq2:"soga_nose,size:3"` + SogaBodySize float32 `eq2:"soga_body_size"` + SogaBodyAge float32 `eq2:"soga_body_age"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacterV869) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Unknown0 + dest[offset] = byte(p.Unknown0) + offset++ + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 + dest[offset] = byte(p.Unknown3) + offset++ + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + dest[offset] = byte(p.StartingZone) + offset++ + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor.ToUint32()) + offset += 4 + + // Write SkinColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor2.ToUint32()) + offset += 4 + + // Write EyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.EyeColor.ToUint32()) + offset += 4 + + // Write HairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor1.ToUint32()) + offset += 4 + + // Write HairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor2.ToUint32()) + offset += 4 + + // Write HairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.HairHighlight.ToUint32()) + offset += 4 + + // Write Unknown8 array + for i := 0; i < 26; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeColor.ToUint32()) + offset += 4 + + // Write HairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceColor.ToUint32()) + offset += 4 + + // Write HairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write WingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.WingFile))) + offset += 2 + copy(dest[offset:], []byte(p.WingFile)) + offset += uint32(len(p.WingFile)) + + // Write WingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor1.ToUint32()) + offset += 4 + + // Write WingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor2.ToUint32()) + offset += 4 + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.ShirtColor.ToUint32()) + offset += 4 + + // Write UnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownChestColor.ToUint32()) + offset += 4 + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.PantsColor.ToUint32()) + offset += 4 + + // Write UnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownLegsColor.ToUint32()) + offset += 4 + + // Write Unknown9 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown9.ToUint32()) + offset += 4 + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + // Write SogaVersion + dest[offset] = byte(p.SogaVersion) + offset++ + + // Write SogaRaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaRaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaRaceFile)) + offset += uint32(len(p.SogaRaceFile)) + + // Write SogaSkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaSkinColor.ToUint32()) + offset += 4 + + // Write SogaEyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaEyeColor.ToUint32()) + offset += 4 + + // Write SogaHairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor1.ToUint32()) + offset += 4 + + // Write SogaHairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor2.ToUint32()) + offset += 4 + + // Write SogaHairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairHighlight.ToUint32()) + offset += 4 + + // Write SogaUnknownColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownColor1.ToUint32()) + offset += 4 + + // Write SogaUnknown11 array + for i := 0; i < 26; i++ { + dest[offset] = p.SogaUnknown11[i] + offset++ + } + + // Write SogaHairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaHairFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaHairFile)) + offset += uint32(len(p.SogaHairFile)) + + // Write SogaHairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeColor.ToUint32()) + offset += 4 + + // Write SogaHairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write SogaFaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaFaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaFaceFile)) + offset += uint32(len(p.SogaFaceFile)) + + // Write SogaHairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write SogaWingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaWingFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaWingFile)) + offset += uint32(len(p.SogaWingFile)) + + // Write SogaWingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor1.ToUint32()) + offset += 4 + + // Write SogaWingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor2.ToUint32()) + offset += 4 + + // Write SogaChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaChestFile)) + offset += uint32(len(p.SogaChestFile)) + + // Write SogaShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaShirtColor.ToUint32()) + offset += 4 + + // Write SogaUnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownChestColor.ToUint32()) + offset += 4 + + // Write SogaLegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaLegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaLegsFile)) + offset += uint32(len(p.SogaLegsFile)) + + // Write SogaPantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaPantsColor.ToUint32()) + offset += 4 + + // Write SogaUnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownLegsColor.ToUint32()) + offset += 4 + + // Write SogaUnknown12 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknown12.ToUint32()) + offset += 4 + + // Write SogaEyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyes2[i])) + offset += 4 + } + + // Write SogaEars array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEars[i])) + offset += 4 + } + + // Write SogaEyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyeBrows[i])) + offset += 4 + } + + // Write SogaCheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaCheeks[i])) + offset += 4 + } + + // Write SogaLips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaLips[i])) + offset += 4 + } + + // Write SogaChin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaChin[i])) + offset += 4 + } + + // Write SogaNose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaNose[i])) + offset += 4 + } + + // Write SogaBodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodySize)) + offset += 4 + + // Write SogaBodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodyAge)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacterV869) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 4 + + size += 4 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 2 + uint32(len(p.RaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 26 + + size += 2 + uint32(len(p.HairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.WingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.SogaRaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 26 + + size += 2 + uint32(len(p.SogaHairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaFaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaWingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaLegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + return size +} + +// CreateCharacterV1096 represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacterV1096 struct { + Unknown0 uint8 `eq2:"unknown0"` // TODO: Identify purpose + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 uint8 `eq2:"unknown3"` // TODO: Identify purpose + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint8 `eq2:"starting_zone"` + Version uint8 `eq2:"version"` + RaceFile string `eq2:"race_file,type:str16"` + SkinColor types.Color `eq2:"skin_color"` + SkinColor2 types.Color `eq2:"skin_color2"` + EyeColor types.Color `eq2:"eye_color"` + HairColor1 types.Color `eq2:"hair_color1"` + HairColor2 types.Color `eq2:"hair_color2"` + HairHighlight types.Color `eq2:"hair_highlight"` + Unknown8 [26]uint8 `eq2:"unknown8,size:26"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor types.Color `eq2:"hair_type_color"` + HairTypeHighlightColor types.Color `eq2:"hair_type_highlight_color"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor types.Color `eq2:"hair_face_color"` + HairFaceHighlightColor types.Color `eq2:"hair_face_highlight_color"` + WingFile string `eq2:"wing_file,type:str16"` + WingColor1 types.Color `eq2:"wing_color1"` + WingColor2 types.Color `eq2:"wing_color2"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor types.Color `eq2:"shirt_color"` + UnknownChestColor types.Color `eq2:"unknown_chest_color"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor types.Color `eq2:"pants_color"` + UnknownLegsColor types.Color `eq2:"unknown_legs_color"` // TODO: Identify purpose + Unknown9 types.Color `eq2:"unknown9"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` + SogaVersion uint8 `eq2:"soga_version"` + SogaRaceFile string `eq2:"soga_race_file,type:str16"` + SogaSkinColor types.Color `eq2:"soga_skin_color"` + SogaEyeColor types.Color `eq2:"soga_eye_color"` + SogaHairColor1 types.Color `eq2:"soga_hair_color1"` + SogaHairColor2 types.Color `eq2:"soga_hair_color2"` + SogaHairHighlight types.Color `eq2:"soga_hair_highlight"` + SogaUnknownColor types.Color `eq2:"soga_unknown_color"` + SogaUnknown11 [26]uint8 `eq2:"soga_unknown11,size:26"` + SogaHairFile string `eq2:"soga_hair_file,type:str16"` + SogaHairTypeColor types.Color `eq2:"soga_hair_type_color"` + SogaHairTypeHighlightColor types.Color `eq2:"soga_hair_type_highlight_color"` + SogaFaceFile string `eq2:"soga_face_file,type:str16"` + SogaHairFaceColor types.Color `eq2:"soga_hair_face_color"` + SogaHairFaceHighlightColor types.Color `eq2:"soga_hair_face_highlight_color"` + SogaWingFile string `eq2:"soga_wing_file,type:str16"` + SogaWingColor1 types.Color `eq2:"soga_wing_color1"` + SogaWingColor2 types.Color `eq2:"soga_wing_color2"` + SogaChestFile string `eq2:"soga_chest_file,type:str16"` + SogaShirtColor types.Color `eq2:"soga_shirt_color"` + SogaUnknownChestColor types.Color `eq2:"soga_unknown_chest_color"` + SogaLegsFile string `eq2:"soga_legs_file,type:str16"` + SogaPantsColor types.Color `eq2:"soga_pants_color"` + SogaUnknownLegsColor types.Color `eq2:"soga_unknown_legs_color"` + SogaUnknown12 types.Color `eq2:"soga_unknown12"` + SogaEyes2 [3]float32 `eq2:"soga_eyes2,size:3"` + SogaEars [3]float32 `eq2:"soga_ears,size:3"` + SogaEyeBrows [3]float32 `eq2:"soga_eye_brows,size:3"` + SogaCheeks [3]float32 `eq2:"soga_cheeks,size:3"` + SogaLips [3]float32 `eq2:"soga_lips,size:3"` + SogaChin [3]float32 `eq2:"soga_chin,size:3"` + SogaNose [3]float32 `eq2:"soga_nose,size:3"` + SogaBodySize float32 `eq2:"soga_body_size"` + SogaBodyAge float32 `eq2:"soga_body_age"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacterV1096) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Unknown0 + dest[offset] = byte(p.Unknown0) + offset++ + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 + dest[offset] = byte(p.Unknown3) + offset++ + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + dest[offset] = byte(p.StartingZone) + offset++ + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor.ToUint32()) + offset += 4 + + // Write SkinColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor2.ToUint32()) + offset += 4 + + // Write EyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.EyeColor.ToUint32()) + offset += 4 + + // Write HairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor1.ToUint32()) + offset += 4 + + // Write HairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor2.ToUint32()) + offset += 4 + + // Write HairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.HairHighlight.ToUint32()) + offset += 4 + + // Write Unknown8 array + for i := 0; i < 26; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeColor.ToUint32()) + offset += 4 + + // Write HairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceColor.ToUint32()) + offset += 4 + + // Write HairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write WingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.WingFile))) + offset += 2 + copy(dest[offset:], []byte(p.WingFile)) + offset += uint32(len(p.WingFile)) + + // Write WingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor1.ToUint32()) + offset += 4 + + // Write WingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor2.ToUint32()) + offset += 4 + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.ShirtColor.ToUint32()) + offset += 4 + + // Write UnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownChestColor.ToUint32()) + offset += 4 + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.PantsColor.ToUint32()) + offset += 4 + + // Write UnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownLegsColor.ToUint32()) + offset += 4 + + // Write Unknown9 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown9.ToUint32()) + offset += 4 + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + // Write SogaVersion + dest[offset] = byte(p.SogaVersion) + offset++ + + // Write SogaRaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaRaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaRaceFile)) + offset += uint32(len(p.SogaRaceFile)) + + // Write SogaSkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaSkinColor.ToUint32()) + offset += 4 + + // Write SogaEyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaEyeColor.ToUint32()) + offset += 4 + + // Write SogaHairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor1.ToUint32()) + offset += 4 + + // Write SogaHairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor2.ToUint32()) + offset += 4 + + // Write SogaHairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairHighlight.ToUint32()) + offset += 4 + + // Write SogaUnknownColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownColor.ToUint32()) + offset += 4 + + // Write SogaUnknown11 array + for i := 0; i < 26; i++ { + dest[offset] = p.SogaUnknown11[i] + offset++ + } + + // Write SogaHairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaHairFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaHairFile)) + offset += uint32(len(p.SogaHairFile)) + + // Write SogaHairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeColor.ToUint32()) + offset += 4 + + // Write SogaHairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write SogaFaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaFaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaFaceFile)) + offset += uint32(len(p.SogaFaceFile)) + + // Write SogaHairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write SogaWingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaWingFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaWingFile)) + offset += uint32(len(p.SogaWingFile)) + + // Write SogaWingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor1.ToUint32()) + offset += 4 + + // Write SogaWingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor2.ToUint32()) + offset += 4 + + // Write SogaChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaChestFile)) + offset += uint32(len(p.SogaChestFile)) + + // Write SogaShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaShirtColor.ToUint32()) + offset += 4 + + // Write SogaUnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownChestColor.ToUint32()) + offset += 4 + + // Write SogaLegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaLegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaLegsFile)) + offset += uint32(len(p.SogaLegsFile)) + + // Write SogaPantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaPantsColor.ToUint32()) + offset += 4 + + // Write SogaUnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownLegsColor.ToUint32()) + offset += 4 + + // Write SogaUnknown12 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknown12.ToUint32()) + offset += 4 + + // Write SogaEyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyes2[i])) + offset += 4 + } + + // Write SogaEars array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEars[i])) + offset += 4 + } + + // Write SogaEyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyeBrows[i])) + offset += 4 + } + + // Write SogaCheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaCheeks[i])) + offset += 4 + } + + // Write SogaLips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaLips[i])) + offset += 4 + } + + // Write SogaChin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaChin[i])) + offset += 4 + } + + // Write SogaNose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaNose[i])) + offset += 4 + } + + // Write SogaBodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodySize)) + offset += 4 + + // Write SogaBodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodyAge)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacterV1096) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 4 + + size += 4 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 2 + uint32(len(p.RaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 26 + + size += 2 + uint32(len(p.HairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.WingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.SogaRaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 26 + + size += 2 + uint32(len(p.SogaHairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaFaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaWingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaLegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + return size +} + +// CreateCharacterV57080 represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacterV57080 struct { + Unknown0 uint8 `eq2:"unknown0"` // TODO: Identify purpose + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 uint8 `eq2:"unknown3"` // TODO: Identify purpose + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint8 `eq2:"starting_zone"` + Version uint8 `eq2:"version"` + Unknown10 uint16 `eq2:"unknown10"` // TODO: Identify purpose + RaceFile string `eq2:"race_file,type:str16"` + SkinColor types.Color `eq2:"skin_color"` + EyeColor types.Color `eq2:"eye_color"` + UnknownSkinColor2 types.Color `eq2:"unknown_skin_color2"` // TODO: Identify purpose + HairColor1 types.Color `eq2:"hair_color1"` + HairColor2 types.Color `eq2:"hair_color2"` + HairHighlight types.Color `eq2:"hair_highlight"` + Unknown8 [26]uint8 `eq2:"unknown8,size:26"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor types.Color `eq2:"hair_type_color"` + HairTypeHighlightColor types.Color `eq2:"hair_type_highlight_color"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor types.Color `eq2:"hair_face_color"` + HairFaceHighlightColor types.Color `eq2:"hair_face_highlight_color"` + WingFile string `eq2:"wing_file,type:str16"` + WingColor1 types.Color `eq2:"wing_color1"` + WingColor2 types.Color `eq2:"wing_color2"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor types.Color `eq2:"shirt_color"` + UnknownChestColor types.Color `eq2:"unknown_chest_color"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor types.Color `eq2:"pants_color"` + UnknownLegsColor types.Color `eq2:"unknown_legs_color"` // TODO: Identify purpose + Unknown9 types.Color `eq2:"unknown9"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` + SogaVersion uint8 `eq2:"soga_version"` + SogaRaceFile string `eq2:"soga_race_file,type:str16"` + SogaSkinColor types.Color `eq2:"soga_skin_color"` + SogaEyeColor types.Color `eq2:"soga_eye_color"` + SogaHairColor1 types.Color `eq2:"soga_hair_color1"` + SogaHairColor2 types.Color `eq2:"soga_hair_color2"` + SogaHairHighlight types.Color `eq2:"soga_hair_highlight"` + SogaUnknownColor types.Color `eq2:"soga_unknown_color"` + SogaUnknown11 [26]uint8 `eq2:"soga_unknown11,size:26"` + SogaHairFile string `eq2:"soga_hair_file,type:str16"` + SogaHairTypeColor types.Color `eq2:"soga_hair_type_color"` + SogaHairTypeHighlightColor types.Color `eq2:"soga_hair_type_highlight_color"` + SogaFaceFile string `eq2:"soga_face_file,type:str16"` + SogaHairFaceColor types.Color `eq2:"soga_hair_face_color"` + SogaHairFaceHighlightColor types.Color `eq2:"soga_hair_face_highlight_color"` + SogaWingFile string `eq2:"soga_wing_file,type:str16"` + SogaWingColor1 types.Color `eq2:"soga_wing_color1"` + SogaWingColor2 types.Color `eq2:"soga_wing_color2"` + SogaChestFile string `eq2:"soga_chest_file,type:str16"` + SogaShirtColor types.Color `eq2:"soga_shirt_color"` + SogaUnknownChestColor types.Color `eq2:"soga_unknown_chest_color"` + SogaLegsFile string `eq2:"soga_legs_file,type:str16"` + SogaPantsColor types.Color `eq2:"soga_pants_color"` + SogaUnknownLegsColor types.Color `eq2:"soga_unknown_legs_color"` + SogaUnknown12 types.Color `eq2:"soga_unknown12"` + SogaEyes2 [3]float32 `eq2:"soga_eyes2,size:3"` + SogaEars [3]float32 `eq2:"soga_ears,size:3"` + SogaEyeBrows [3]float32 `eq2:"soga_eye_brows,size:3"` + SogaCheeks [3]float32 `eq2:"soga_cheeks,size:3"` + SogaLips [3]float32 `eq2:"soga_lips,size:3"` + SogaChin [3]float32 `eq2:"soga_chin,size:3"` + SogaNose [3]float32 `eq2:"soga_nose,size:3"` + SogaBodySize float32 `eq2:"soga_body_size"` + SogaBodyAge float32 `eq2:"soga_body_age"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacterV57080) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Unknown0 + dest[offset] = byte(p.Unknown0) + offset++ + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 + dest[offset] = byte(p.Unknown3) + offset++ + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + dest[offset] = byte(p.StartingZone) + offset++ + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write Unknown10 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown10)) + offset += 2 + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor.ToUint32()) + offset += 4 + + // Write EyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.EyeColor.ToUint32()) + offset += 4 + + // Write UnknownSkinColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownSkinColor2.ToUint32()) + offset += 4 + + // Write HairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor1.ToUint32()) + offset += 4 + + // Write HairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor2.ToUint32()) + offset += 4 + + // Write HairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.HairHighlight.ToUint32()) + offset += 4 + + // Write Unknown8 array + for i := 0; i < 26; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeColor.ToUint32()) + offset += 4 + + // Write HairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceColor.ToUint32()) + offset += 4 + + // Write HairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write WingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.WingFile))) + offset += 2 + copy(dest[offset:], []byte(p.WingFile)) + offset += uint32(len(p.WingFile)) + + // Write WingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor1.ToUint32()) + offset += 4 + + // Write WingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor2.ToUint32()) + offset += 4 + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.ShirtColor.ToUint32()) + offset += 4 + + // Write UnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownChestColor.ToUint32()) + offset += 4 + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.PantsColor.ToUint32()) + offset += 4 + + // Write UnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownLegsColor.ToUint32()) + offset += 4 + + // Write Unknown9 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown9.ToUint32()) + offset += 4 + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + // Write SogaVersion + dest[offset] = byte(p.SogaVersion) + offset++ + + // Write SogaRaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaRaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaRaceFile)) + offset += uint32(len(p.SogaRaceFile)) + + // Write SogaSkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaSkinColor.ToUint32()) + offset += 4 + + // Write SogaEyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaEyeColor.ToUint32()) + offset += 4 + + // Write SogaHairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor1.ToUint32()) + offset += 4 + + // Write SogaHairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor2.ToUint32()) + offset += 4 + + // Write SogaHairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairHighlight.ToUint32()) + offset += 4 + + // Write SogaUnknownColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownColor.ToUint32()) + offset += 4 + + // Write SogaUnknown11 array + for i := 0; i < 26; i++ { + dest[offset] = p.SogaUnknown11[i] + offset++ + } + + // Write SogaHairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaHairFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaHairFile)) + offset += uint32(len(p.SogaHairFile)) + + // Write SogaHairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeColor.ToUint32()) + offset += 4 + + // Write SogaHairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write SogaFaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaFaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaFaceFile)) + offset += uint32(len(p.SogaFaceFile)) + + // Write SogaHairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write SogaWingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaWingFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaWingFile)) + offset += uint32(len(p.SogaWingFile)) + + // Write SogaWingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor1.ToUint32()) + offset += 4 + + // Write SogaWingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor2.ToUint32()) + offset += 4 + + // Write SogaChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaChestFile)) + offset += uint32(len(p.SogaChestFile)) + + // Write SogaShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaShirtColor.ToUint32()) + offset += 4 + + // Write SogaUnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownChestColor.ToUint32()) + offset += 4 + + // Write SogaLegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaLegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaLegsFile)) + offset += uint32(len(p.SogaLegsFile)) + + // Write SogaPantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaPantsColor.ToUint32()) + offset += 4 + + // Write SogaUnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownLegsColor.ToUint32()) + offset += 4 + + // Write SogaUnknown12 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknown12.ToUint32()) + offset += 4 + + // Write SogaEyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyes2[i])) + offset += 4 + } + + // Write SogaEars array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEars[i])) + offset += 4 + } + + // Write SogaEyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyeBrows[i])) + offset += 4 + } + + // Write SogaCheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaCheeks[i])) + offset += 4 + } + + // Write SogaLips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaLips[i])) + offset += 4 + } + + // Write SogaChin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaChin[i])) + offset += 4 + } + + // Write SogaNose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaNose[i])) + offset += 4 + } + + // Write SogaBodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodySize)) + offset += 4 + + // Write SogaBodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodyAge)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacterV57080) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 4 + + size += 4 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 2 + + size += 2 + uint32(len(p.RaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 26 + + size += 2 + uint32(len(p.HairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.WingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.SogaRaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 26 + + size += 2 + uint32(len(p.SogaHairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaFaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaWingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaLegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + return size +} + +// CreateCharacterV60085 represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacterV60085 struct { + Unknown0 uint8 `eq2:"unknown0"` // TODO: Identify purpose + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 uint8 `eq2:"unknown3"` // TODO: Identify purpose + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint8 `eq2:"starting_zone"` + Version uint8 `eq2:"version"` + Unknown10 uint16 `eq2:"unknown10"` // TODO: Identify purpose + RaceFile string `eq2:"race_file,type:str16"` + SkinColor types.Color `eq2:"skin_color"` + EyeColor types.Color `eq2:"eye_color"` + UnknownSkinColor2 types.Color `eq2:"unknown_skin_color2"` // TODO: Identify purpose + HairColor1 types.Color `eq2:"hair_color1"` + HairColor2 types.Color `eq2:"hair_color2"` + HairHighlight types.Color `eq2:"hair_highlight"` + Unknown8 [26]uint8 `eq2:"unknown8,size:26"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor types.Color `eq2:"hair_type_color"` + HairTypeHighlightColor types.Color `eq2:"hair_type_highlight_color"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor types.Color `eq2:"hair_face_color"` + HairFaceHighlightColor types.Color `eq2:"hair_face_highlight_color"` + WingFile string `eq2:"wing_file,type:str16"` + WingColor1 types.Color `eq2:"wing_color1"` + WingColor2 types.Color `eq2:"wing_color2"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor types.Color `eq2:"shirt_color"` + UnknownChestColor types.Color `eq2:"unknown_chest_color"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor types.Color `eq2:"pants_color"` + UnknownLegsColor types.Color `eq2:"unknown_legs_color"` // TODO: Identify purpose + Unknown9 types.Color `eq2:"unknown9"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` + SogaVersion uint8 `eq2:"soga_version"` + SogaRaceFile string `eq2:"soga_race_file,type:str16"` + SogaSkinColor types.Color `eq2:"soga_skin_color"` + SogaEyeColor types.Color `eq2:"soga_eye_color"` + SogaHairColor1 types.Color `eq2:"soga_hair_color1"` + SogaHairColor2 types.Color `eq2:"soga_hair_color2"` + SogaHairHighlight types.Color `eq2:"soga_hair_highlight"` + SogaUnknownColor types.Color `eq2:"soga_unknown_color"` + SogaUnknown11 [26]uint8 `eq2:"soga_unknown11,size:26"` + SogaHairFile string `eq2:"soga_hair_file,type:str16"` + SogaHairTypeColor types.Color `eq2:"soga_hair_type_color"` + SogaHairTypeHighlightColor types.Color `eq2:"soga_hair_type_highlight_color"` + SogaFaceFile string `eq2:"soga_face_file,type:str16"` + SogaHairFaceColor types.Color `eq2:"soga_hair_face_color"` + SogaHairFaceHighlightColor types.Color `eq2:"soga_hair_face_highlight_color"` + SogaWingFile string `eq2:"soga_wing_file,type:str16"` + SogaWingColor1 types.Color `eq2:"soga_wing_color1"` + SogaWingColor2 types.Color `eq2:"soga_wing_color2"` + SogaChestFile string `eq2:"soga_chest_file,type:str16"` + SogaShirtColor types.Color `eq2:"soga_shirt_color"` + SogaUnknownChestColor types.Color `eq2:"soga_unknown_chest_color"` + SogaLegsFile string `eq2:"soga_legs_file,type:str16"` + SogaPantsColor types.Color `eq2:"soga_pants_color"` + SogaUnknownLegsColor types.Color `eq2:"soga_unknown_legs_color"` + SogaUnknown12 types.Color `eq2:"soga_unknown12"` + SogaEyes2 [3]float32 `eq2:"soga_eyes2,size:3"` + SogaEars [3]float32 `eq2:"soga_ears,size:3"` + SogaEyeBrows [3]float32 `eq2:"soga_eye_brows,size:3"` + SogaCheeks [3]float32 `eq2:"soga_cheeks,size:3"` + SogaLips [3]float32 `eq2:"soga_lips,size:3"` + SogaChin [3]float32 `eq2:"soga_chin,size:3"` + SogaNose [3]float32 `eq2:"soga_nose,size:3"` + SogaBodySize float32 `eq2:"soga_body_size"` + SogaBodyAge float32 `eq2:"soga_body_age"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacterV60085) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Unknown0 + dest[offset] = byte(p.Unknown0) + offset++ + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 + dest[offset] = byte(p.Unknown3) + offset++ + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + dest[offset] = byte(p.StartingZone) + offset++ + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write Unknown10 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown10)) + offset += 2 + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor.ToUint32()) + offset += 4 + + // Write EyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.EyeColor.ToUint32()) + offset += 4 + + // Write UnknownSkinColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownSkinColor2.ToUint32()) + offset += 4 + + // Write HairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor1.ToUint32()) + offset += 4 + + // Write HairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor2.ToUint32()) + offset += 4 + + // Write HairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.HairHighlight.ToUint32()) + offset += 4 + + // Write Unknown8 array + for i := 0; i < 26; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeColor.ToUint32()) + offset += 4 + + // Write HairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceColor.ToUint32()) + offset += 4 + + // Write HairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write WingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.WingFile))) + offset += 2 + copy(dest[offset:], []byte(p.WingFile)) + offset += uint32(len(p.WingFile)) + + // Write WingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor1.ToUint32()) + offset += 4 + + // Write WingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor2.ToUint32()) + offset += 4 + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.ShirtColor.ToUint32()) + offset += 4 + + // Write UnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownChestColor.ToUint32()) + offset += 4 + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.PantsColor.ToUint32()) + offset += 4 + + // Write UnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownLegsColor.ToUint32()) + offset += 4 + + // Write Unknown9 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown9.ToUint32()) + offset += 4 + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + // Write SogaVersion + dest[offset] = byte(p.SogaVersion) + offset++ + + // Write SogaRaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaRaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaRaceFile)) + offset += uint32(len(p.SogaRaceFile)) + + // Write SogaSkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaSkinColor.ToUint32()) + offset += 4 + + // Write SogaEyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaEyeColor.ToUint32()) + offset += 4 + + // Write SogaHairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor1.ToUint32()) + offset += 4 + + // Write SogaHairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor2.ToUint32()) + offset += 4 + + // Write SogaHairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairHighlight.ToUint32()) + offset += 4 + + // Write SogaUnknownColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownColor.ToUint32()) + offset += 4 + + // Write SogaUnknown11 array + for i := 0; i < 26; i++ { + dest[offset] = p.SogaUnknown11[i] + offset++ + } + + // Write SogaHairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaHairFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaHairFile)) + offset += uint32(len(p.SogaHairFile)) + + // Write SogaHairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeColor.ToUint32()) + offset += 4 + + // Write SogaHairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write SogaFaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaFaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaFaceFile)) + offset += uint32(len(p.SogaFaceFile)) + + // Write SogaHairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write SogaWingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaWingFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaWingFile)) + offset += uint32(len(p.SogaWingFile)) + + // Write SogaWingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor1.ToUint32()) + offset += 4 + + // Write SogaWingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor2.ToUint32()) + offset += 4 + + // Write SogaChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaChestFile)) + offset += uint32(len(p.SogaChestFile)) + + // Write SogaShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaShirtColor.ToUint32()) + offset += 4 + + // Write SogaUnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownChestColor.ToUint32()) + offset += 4 + + // Write SogaLegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaLegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaLegsFile)) + offset += uint32(len(p.SogaLegsFile)) + + // Write SogaPantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaPantsColor.ToUint32()) + offset += 4 + + // Write SogaUnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownLegsColor.ToUint32()) + offset += 4 + + // Write SogaUnknown12 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknown12.ToUint32()) + offset += 4 + + // Write SogaEyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyes2[i])) + offset += 4 + } + + // Write SogaEars array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEars[i])) + offset += 4 + } + + // Write SogaEyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyeBrows[i])) + offset += 4 + } + + // Write SogaCheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaCheeks[i])) + offset += 4 + } + + // Write SogaLips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaLips[i])) + offset += 4 + } + + // Write SogaChin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaChin[i])) + offset += 4 + } + + // Write SogaNose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaNose[i])) + offset += 4 + } + + // Write SogaBodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodySize)) + offset += 4 + + // Write SogaBodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodyAge)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacterV60085) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 4 + + size += 4 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 2 + + size += 2 + uint32(len(p.RaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 26 + + size += 2 + uint32(len(p.HairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.WingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.SogaRaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 26 + + size += 2 + uint32(len(p.SogaHairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaFaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaWingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaLegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + return size +} + +// CreateCharacterV64659 represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacterV64659 struct { + Unknown0 uint8 `eq2:"unknown0"` // TODO: Identify purpose + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 uint8 `eq2:"unknown3"` // TODO: Identify purpose + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint32 `eq2:"starting_zone"` + Version uint8 `eq2:"version"` + RaceFile string `eq2:"race_file,type:str16"` + SkinColor types.Color `eq2:"skin_color"` + SkinColor2 types.Color `eq2:"skin_color2"` + EyeColor types.Color `eq2:"eye_color"` + HairColor1 types.Color `eq2:"hair_color1"` + HairColor2 types.Color `eq2:"hair_color2"` + Unknown8 [38]uint8 `eq2:"unknown8,size:38"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor types.Color `eq2:"hair_type_color"` + HairTypeHighlightColor types.Color `eq2:"hair_type_highlight_color"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor types.Color `eq2:"hair_face_color"` + HairFaceHighlightColor types.Color `eq2:"hair_face_highlight_color"` + WingFile string `eq2:"wing_file,type:str16"` + WingColor1 types.Color `eq2:"wing_color1"` + WingColor2 types.Color `eq2:"wing_color2"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor types.Color `eq2:"shirt_color"` + UnknownChestColor types.Color `eq2:"unknown_chest_color"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor types.Color `eq2:"pants_color"` + UnknownLegsColor types.Color `eq2:"unknown_legs_color"` // TODO: Identify purpose + Unknown9 types.Color `eq2:"unknown9"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` + SogaVersion uint8 `eq2:"soga_version"` + SogaRaceFile string `eq2:"soga_race_file,type:str16"` + SogaSkinColor types.Color `eq2:"soga_skin_color"` + SogaEyeColor types.Color `eq2:"soga_eye_color"` + SogaHairColor1 types.Color `eq2:"soga_hair_color1"` + SogaHairColor2 types.Color `eq2:"soga_hair_color2"` + SogaHairHighlight types.Color `eq2:"soga_hair_highlight"` + SogaUnknown11 [38]uint8 `eq2:"soga_unknown11,size:38"` + SogaHairFile string `eq2:"soga_hair_file,type:str16"` + SogaHairTypeColor types.Color `eq2:"soga_hair_type_color"` + SogaHairTypeHighlightColor types.Color `eq2:"soga_hair_type_highlight_color"` + SogaFaceFile string `eq2:"soga_face_file,type:str16"` + SogaHairFaceColor types.Color `eq2:"soga_hair_face_color"` + SogaHairFaceHighlightColor types.Color `eq2:"soga_hair_face_highlight_color"` + SogaWingFile string `eq2:"soga_wing_file,type:str16"` + SogaWingColor1 types.Color `eq2:"soga_wing_color1"` + SogaWingColor2 types.Color `eq2:"soga_wing_color2"` + SogaChestFile string `eq2:"soga_chest_file,type:str16"` + SogaShirtColor types.Color `eq2:"soga_shirt_color"` + SogaUnknownChestColor types.Color `eq2:"soga_unknown_chest_color"` + SogaLegsFile string `eq2:"soga_legs_file,type:str16"` + SogaPantsColor types.Color `eq2:"soga_pants_color"` + SogaUnknownLegsColor types.Color `eq2:"soga_unknown_legs_color"` + SogaUnknown12 types.Color `eq2:"soga_unknown12"` + SogaEyes2 [3]float32 `eq2:"soga_eyes2,size:3"` + SogaEars [3]float32 `eq2:"soga_ears,size:3"` + SogaEyeBrows [3]float32 `eq2:"soga_eye_brows,size:3"` + SogaCheeks [3]float32 `eq2:"soga_cheeks,size:3"` + SogaLips [3]float32 `eq2:"soga_lips,size:3"` + SogaChin [3]float32 `eq2:"soga_chin,size:3"` + SogaNose [3]float32 `eq2:"soga_nose,size:3"` + SogaBodySize float32 `eq2:"soga_body_size"` + SogaBodyAge float32 `eq2:"soga_body_age"` + Unknown13 [2]uint8 `eq2:"unknown13,size:2"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacterV64659) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Unknown0 + dest[offset] = byte(p.Unknown0) + offset++ + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 + dest[offset] = byte(p.Unknown3) + offset++ + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.StartingZone)) + offset += 4 + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor.ToUint32()) + offset += 4 + + // Write SkinColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor2.ToUint32()) + offset += 4 + + // Write EyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.EyeColor.ToUint32()) + offset += 4 + + // Write HairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor1.ToUint32()) + offset += 4 + + // Write HairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor2.ToUint32()) + offset += 4 + + // Write Unknown8 array + for i := 0; i < 38; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeColor.ToUint32()) + offset += 4 + + // Write HairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceColor.ToUint32()) + offset += 4 + + // Write HairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write WingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.WingFile))) + offset += 2 + copy(dest[offset:], []byte(p.WingFile)) + offset += uint32(len(p.WingFile)) + + // Write WingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor1.ToUint32()) + offset += 4 + + // Write WingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor2.ToUint32()) + offset += 4 + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.ShirtColor.ToUint32()) + offset += 4 + + // Write UnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownChestColor.ToUint32()) + offset += 4 + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.PantsColor.ToUint32()) + offset += 4 + + // Write UnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownLegsColor.ToUint32()) + offset += 4 + + // Write Unknown9 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown9.ToUint32()) + offset += 4 + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + // Write SogaVersion + dest[offset] = byte(p.SogaVersion) + offset++ + + // Write SogaRaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaRaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaRaceFile)) + offset += uint32(len(p.SogaRaceFile)) + + // Write SogaSkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaSkinColor.ToUint32()) + offset += 4 + + // Write SogaEyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaEyeColor.ToUint32()) + offset += 4 + + // Write SogaHairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor1.ToUint32()) + offset += 4 + + // Write SogaHairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor2.ToUint32()) + offset += 4 + + // Write SogaHairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairHighlight.ToUint32()) + offset += 4 + + // Write SogaUnknown11 array + for i := 0; i < 38; i++ { + dest[offset] = p.SogaUnknown11[i] + offset++ + } + + // Write SogaHairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaHairFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaHairFile)) + offset += uint32(len(p.SogaHairFile)) + + // Write SogaHairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeColor.ToUint32()) + offset += 4 + + // Write SogaHairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write SogaFaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaFaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaFaceFile)) + offset += uint32(len(p.SogaFaceFile)) + + // Write SogaHairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write SogaWingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaWingFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaWingFile)) + offset += uint32(len(p.SogaWingFile)) + + // Write SogaWingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor1.ToUint32()) + offset += 4 + + // Write SogaWingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor2.ToUint32()) + offset += 4 + + // Write SogaChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaChestFile)) + offset += uint32(len(p.SogaChestFile)) + + // Write SogaShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaShirtColor.ToUint32()) + offset += 4 + + // Write SogaUnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownChestColor.ToUint32()) + offset += 4 + + // Write SogaLegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaLegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaLegsFile)) + offset += uint32(len(p.SogaLegsFile)) + + // Write SogaPantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaPantsColor.ToUint32()) + offset += 4 + + // Write SogaUnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownLegsColor.ToUint32()) + offset += 4 + + // Write SogaUnknown12 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknown12.ToUint32()) + offset += 4 + + // Write SogaEyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyes2[i])) + offset += 4 + } + + // Write SogaEars array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEars[i])) + offset += 4 + } + + // Write SogaEyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyeBrows[i])) + offset += 4 + } + + // Write SogaCheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaCheeks[i])) + offset += 4 + } + + // Write SogaLips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaLips[i])) + offset += 4 + } + + // Write SogaChin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaChin[i])) + offset += 4 + } + + // Write SogaNose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaNose[i])) + offset += 4 + } + + // Write SogaBodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodySize)) + offset += 4 + + // Write SogaBodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodyAge)) + offset += 4 + + // Write Unknown13 array + for i := 0; i < 2; i++ { + dest[offset] = p.Unknown13[i] + offset++ + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacterV64659) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 4 + + size += 4 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.RaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 38 + + size += 2 + uint32(len(p.HairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.WingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.SogaRaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 38 + + size += 2 + uint32(len(p.SogaHairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaFaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaWingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaLegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + size += 2 + + return size +} + +// CreateCharacterV65534 represents packet structure for OP_CreateCharacterRequestMsg +type CreateCharacterV65534 struct { + Unknown0 uint8 `eq2:"unknown0"` // TODO: Identify purpose + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 uint8 `eq2:"unknown3"` // TODO: Identify purpose + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Gender uint8 `eq2:"gender"` + Deity uint8 `eq2:"deity"` + Class uint8 `eq2:"class"` + Level uint8 `eq2:"level"` + StartingZone uint32 `eq2:"starting_zone"` + Version uint8 `eq2:"version"` + RaceFile string `eq2:"race_file,type:str16"` + SkinColor types.Color `eq2:"skin_color"` + SkinColor2 types.Color `eq2:"skin_color2"` + EyeColor types.Color `eq2:"eye_color"` + HairColor1 types.Color `eq2:"hair_color1"` + HairColor2 types.Color `eq2:"hair_color2"` + Unknown8 [38]uint8 `eq2:"unknown8,size:38"` // TODO: Identify purpose + HairFile string `eq2:"hair_file,type:str16"` + HairTypeColor types.Color `eq2:"hair_type_color"` + HairTypeHighlightColor types.Color `eq2:"hair_type_highlight_color"` + FaceFile string `eq2:"face_file,type:str16"` + HairFaceColor types.Color `eq2:"hair_face_color"` + HairFaceHighlightColor types.Color `eq2:"hair_face_highlight_color"` + WingFile string `eq2:"wing_file,type:str16"` + WingColor1 types.Color `eq2:"wing_color1"` + WingColor2 types.Color `eq2:"wing_color2"` + ChestFile string `eq2:"chest_file,type:str16"` + ShirtColor types.Color `eq2:"shirt_color"` + UnknownChestColor types.Color `eq2:"unknown_chest_color"` // TODO: Identify purpose + LegsFile string `eq2:"legs_file,type:str16"` + PantsColor types.Color `eq2:"pants_color"` + UnknownLegsColor types.Color `eq2:"unknown_legs_color"` // TODO: Identify purpose + Unknown9 types.Color `eq2:"unknown9"` // TODO: Identify purpose + Eyes2 [3]float32 `eq2:"eyes2,size:3"` + Ears [3]float32 `eq2:"ears,size:3"` + EyeBrows [3]float32 `eq2:"eye_brows,size:3"` + Cheeks [3]float32 `eq2:"cheeks,size:3"` + Lips [3]float32 `eq2:"lips,size:3"` + Chin [3]float32 `eq2:"chin,size:3"` + Nose [3]float32 `eq2:"nose,size:3"` + BodySize float32 `eq2:"body_size"` + BodyAge float32 `eq2:"body_age"` + SogaVersion uint8 `eq2:"soga_version"` + SogaRaceFile string `eq2:"soga_race_file,type:str16"` + SogaSkinColor types.Color `eq2:"soga_skin_color"` + SogaEyeColor types.Color `eq2:"soga_eye_color"` + SogaHairColor1 types.Color `eq2:"soga_hair_color1"` + SogaHairColor2 types.Color `eq2:"soga_hair_color2"` + SogaHairHighlight types.Color `eq2:"soga_hair_highlight"` + SogaUnknown11 [38]uint8 `eq2:"soga_unknown11,size:38"` + SogaHairFile string `eq2:"soga_hair_file,type:str16"` + SogaHairTypeColor types.Color `eq2:"soga_hair_type_color"` + SogaHairTypeHighlightColor types.Color `eq2:"soga_hair_type_highlight_color"` + SogaFaceFile string `eq2:"soga_face_file,type:str16"` + SogaHairFaceColor types.Color `eq2:"soga_hair_face_color"` + SogaHairFaceHighlightColor types.Color `eq2:"soga_hair_face_highlight_color"` + SogaWingFile string `eq2:"soga_wing_file,type:str16"` + SogaWingColor1 types.Color `eq2:"soga_wing_color1"` + SogaWingColor2 types.Color `eq2:"soga_wing_color2"` + SogaChestFile string `eq2:"soga_chest_file,type:str16"` + SogaShirtColor types.Color `eq2:"soga_shirt_color"` + SogaUnknownChestColor types.Color `eq2:"soga_unknown_chest_color"` + SogaLegsFile string `eq2:"soga_legs_file,type:str16"` + SogaPantsColor types.Color `eq2:"soga_pants_color"` + SogaUnknownLegsColor types.Color `eq2:"soga_unknown_legs_color"` + SogaUnknown12 types.Color `eq2:"soga_unknown12"` + SogaEyes2 [3]float32 `eq2:"soga_eyes2,size:3"` + SogaEars [3]float32 `eq2:"soga_ears,size:3"` + SogaEyeBrows [3]float32 `eq2:"soga_eye_brows,size:3"` + SogaCheeks [3]float32 `eq2:"soga_cheeks,size:3"` + SogaLips [3]float32 `eq2:"soga_lips,size:3"` + SogaChin [3]float32 `eq2:"soga_chin,size:3"` + SogaNose [3]float32 `eq2:"soga_nose,size:3"` + SogaBodySize float32 `eq2:"soga_body_size"` + SogaBodyAge float32 `eq2:"soga_body_age"` + Unknown13 [2]uint8 `eq2:"unknown13,size:2"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *CreateCharacterV65534) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Unknown0 + dest[offset] = byte(p.Unknown0) + offset++ + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 + dest[offset] = byte(p.Unknown3) + offset++ + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Deity + dest[offset] = byte(p.Deity) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + dest[offset] = byte(p.Level) + offset++ + + // Write StartingZone + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.StartingZone)) + offset += 4 + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write RaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.RaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.RaceFile)) + offset += uint32(len(p.RaceFile)) + + // Write SkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor.ToUint32()) + offset += 4 + + // Write SkinColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor2.ToUint32()) + offset += 4 + + // Write EyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.EyeColor.ToUint32()) + offset += 4 + + // Write HairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor1.ToUint32()) + offset += 4 + + // Write HairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor2.ToUint32()) + offset += 4 + + // Write Unknown8 array + for i := 0; i < 38; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write HairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.HairFile))) + offset += 2 + copy(dest[offset:], []byte(p.HairFile)) + offset += uint32(len(p.HairFile)) + + // Write HairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeColor.ToUint32()) + offset += 4 + + // Write HairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write FaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.FaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.FaceFile)) + offset += uint32(len(p.FaceFile)) + + // Write HairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceColor.ToUint32()) + offset += 4 + + // Write HairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write WingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.WingFile))) + offset += 2 + copy(dest[offset:], []byte(p.WingFile)) + offset += uint32(len(p.WingFile)) + + // Write WingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor1.ToUint32()) + offset += 4 + + // Write WingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor2.ToUint32()) + offset += 4 + + // Write ChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.ChestFile)) + offset += uint32(len(p.ChestFile)) + + // Write ShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.ShirtColor.ToUint32()) + offset += 4 + + // Write UnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownChestColor.ToUint32()) + offset += 4 + + // Write LegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.LegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.LegsFile)) + offset += uint32(len(p.LegsFile)) + + // Write PantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.PantsColor.ToUint32()) + offset += 4 + + // Write UnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownLegsColor.ToUint32()) + offset += 4 + + // Write Unknown9 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown9.ToUint32()) + offset += 4 + + // Write Eyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Eyes2[i])) + offset += 4 + } + + // Write Ears array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Ears[i])) + offset += 4 + } + + // Write EyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.EyeBrows[i])) + offset += 4 + } + + // Write Cheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Cheeks[i])) + offset += 4 + } + + // Write Lips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Lips[i])) + offset += 4 + } + + // Write Chin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Chin[i])) + offset += 4 + } + + // Write Nose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.Nose[i])) + offset += 4 + } + + // Write BodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodySize)) + offset += 4 + + // Write BodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.BodyAge)) + offset += 4 + + // Write SogaVersion + dest[offset] = byte(p.SogaVersion) + offset++ + + // Write SogaRaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaRaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaRaceFile)) + offset += uint32(len(p.SogaRaceFile)) + + // Write SogaSkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaSkinColor.ToUint32()) + offset += 4 + + // Write SogaEyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaEyeColor.ToUint32()) + offset += 4 + + // Write SogaHairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor1.ToUint32()) + offset += 4 + + // Write SogaHairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor2.ToUint32()) + offset += 4 + + // Write SogaHairHighlight + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairHighlight.ToUint32()) + offset += 4 + + // Write SogaUnknown11 array + for i := 0; i < 38; i++ { + dest[offset] = p.SogaUnknown11[i] + offset++ + } + + // Write SogaHairFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaHairFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaHairFile)) + offset += uint32(len(p.SogaHairFile)) + + // Write SogaHairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeColor.ToUint32()) + offset += 4 + + // Write SogaHairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write SogaFaceFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaFaceFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaFaceFile)) + offset += uint32(len(p.SogaFaceFile)) + + // Write SogaHairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write SogaWingFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaWingFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaWingFile)) + offset += uint32(len(p.SogaWingFile)) + + // Write SogaWingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor1.ToUint32()) + offset += 4 + + // Write SogaWingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaWingColor2.ToUint32()) + offset += 4 + + // Write SogaChestFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaChestFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaChestFile)) + offset += uint32(len(p.SogaChestFile)) + + // Write SogaShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaShirtColor.ToUint32()) + offset += 4 + + // Write SogaUnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownChestColor.ToUint32()) + offset += 4 + + // Write SogaLegsFile as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SogaLegsFile))) + offset += 2 + copy(dest[offset:], []byte(p.SogaLegsFile)) + offset += uint32(len(p.SogaLegsFile)) + + // Write SogaPantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaPantsColor.ToUint32()) + offset += 4 + + // Write SogaUnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknownLegsColor.ToUint32()) + offset += 4 + + // Write SogaUnknown12 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaUnknown12.ToUint32()) + offset += 4 + + // Write SogaEyes2 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyes2[i])) + offset += 4 + } + + // Write SogaEars array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEars[i])) + offset += 4 + } + + // Write SogaEyeBrows array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaEyeBrows[i])) + offset += 4 + } + + // Write SogaCheeks array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaCheeks[i])) + offset += 4 + } + + // Write SogaLips array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaLips[i])) + offset += 4 + } + + // Write SogaChin array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaChin[i])) + offset += 4 + } + + // Write SogaNose array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaNose[i])) + offset += 4 + } + + // Write SogaBodySize + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodySize)) + offset += 4 + + // Write SogaBodyAge + binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(p.SogaBodyAge)) + offset += 4 + + // Write Unknown13 array + for i := 0; i < 2; i++ { + dest[offset] = p.Unknown13[i] + offset++ + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *CreateCharacterV65534) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 4 + + size += 4 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.RaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 38 + + size += 2 + uint32(len(p.HairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.FaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.WingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.ChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.LegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.SogaRaceFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 38 + + size += 2 + uint32(len(p.SogaHairFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaFaceFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaWingFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaChestFile)) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.SogaLegsFile)) + + size += 4 + + size += 4 + + size += 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 3 * 4 + + size += 4 + + size += 4 + + size += 2 + + return size +} + +// BadLanguageFilter represents packet structure for OP_BadLanguageFilter +type BadLanguageFilter struct { + NumWords uint16 `eq2:"num_words"` + WordsArray []struct { + Word string `eq2:"word,type:str16"` + } `eq2:"words_array,sizeVar:num_words"` +} + +// Serialize writes the packet data to the provided buffer +func (p *BadLanguageFilter) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write NumWords + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.NumWords)) + offset += 2 + + // Write WordsArray array (dynamic size) + for _, elem := range p.WordsArray { + // Write Word string field + dest[offset] = byte(len(elem.Word)) + offset++ + copy(dest[offset:], []byte(elem.Word)) + offset += uint32(len(elem.Word)) + + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *BadLanguageFilter) Size() uint32 { + size := uint32(0) + + size += 2 + + // Dynamic array: WordsArray + for _, elem := range p.WordsArray { + _ = elem // Avoid unused variable warning + size += 1 + uint32(len(elem.Word)) + + } + + return size +} + + + + + + + + + diff --git a/defs/generated/login.go b/defs/generated/login.go new file mode 100644 index 0000000..8c68607 --- /dev/null +++ b/defs/generated/login.go @@ -0,0 +1,7722 @@ +// Code generated by codegen. DO NOT EDIT. +// Source: login.xml + +package generated + +import ( + "encoding/binary" + "git.sharkk.net/EQ2/Protocol/types" +) + + +// LSCreateCharacterReply represents packet structure for OP_CreateCharacterReplyMsg +type LSCreateCharacterReply struct { + AccountId uint32 `eq2:"account_id"` + Response uint8 `eq2:"response"` + Name string `eq2:"name,type:str16"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSCreateCharacterReply) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Response + dest[offset] = byte(p.Response) + offset++ + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSCreateCharacterReply) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.Name)) + + return size +} + +// LSCreateCharacterReplyV1189 represents packet structure for OP_CreateCharacterReplyMsg +type LSCreateCharacterReplyV1189 struct { + AccountId uint32 `eq2:"account_id"` + Unknown uint32 `eq2:"unknown"` // TODO: Identify purpose + Response uint8 `eq2:"response"` + Name string `eq2:"name,type:str16"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSCreateCharacterReplyV1189) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown)) + offset += 4 + + // Write Response + dest[offset] = byte(p.Response) + offset++ + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSCreateCharacterReplyV1189) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.Name)) + + return size +} + +// LSCreateCharacterReplyV60085 represents packet structure for OP_CreateCharacterReplyMsg +type LSCreateCharacterReplyV60085 struct { + AccountId uint32 `eq2:"account_id"` + Unknown uint32 `eq2:"unknown"` // TODO: Identify purpose + Response uint8 `eq2:"response"` + Name string `eq2:"name,type:str16"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSCreateCharacterReplyV60085) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown)) + offset += 4 + + // Write Response + dest[offset] = byte(p.Response) + offset++ + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSCreateCharacterReplyV60085) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 1 + + size += 2 + uint32(len(p.Name)) + + return size +} + +// LSDeleteCharacterRequest represents packet structure for OP_DeleteCharacterRequestMsg +type LSDeleteCharacterRequest struct { + CharId uint32 `eq2:"char_id"` + ServerId uint32 `eq2:"server_id"` + Unknown uint32 `eq2:"unknown"` // TODO: Identify purpose + Name string `eq2:"name,type:str16"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSDeleteCharacterRequest) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write CharId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CharId)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Unknown + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSDeleteCharacterRequest) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + return size +} + +// LSDeleteCharacterResponse represents packet structure for OP_DeleteCharacterReplyMsg +type LSDeleteCharacterResponse struct { + Response uint8 `eq2:"response"` + ServerId uint32 `eq2:"server_id"` + CharId uint32 `eq2:"char_id"` + AccountId uint32 `eq2:"account_id"` + Name string `eq2:"name,type:str16"` + MaxCharacters uint32 `eq2:"max_characters"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSDeleteCharacterResponse) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Response + dest[offset] = byte(p.Response) + offset++ + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write CharId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CharId)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write MaxCharacters + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.MaxCharacters)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSDeleteCharacterResponse) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 4 + + return size +} + +// LSLoginRequest represents packet structure for OP_LoginRequestMsg +type LSLoginRequest struct { + SessionID string `eq2:"sessionID,type:str16"` + SessionRecycleToken string `eq2:"sessionRecycleToken,type:str16"` + Username string `eq2:"username,type:str16"` + Password string `eq2:"password,type:str16"` + AcctNum uint32 `eq2:"acctNum"` + PassCode uint32 `eq2:"passCode"` + Version uint16 `eq2:"version"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginRequest) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write SessionID as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SessionID))) + offset += 2 + copy(dest[offset:], []byte(p.SessionID)) + offset += uint32(len(p.SessionID)) + + // Write SessionRecycleToken as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.SessionRecycleToken))) + offset += 2 + copy(dest[offset:], []byte(p.SessionRecycleToken)) + offset += uint32(len(p.SessionRecycleToken)) + + // Write Username as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Username))) + offset += 2 + copy(dest[offset:], []byte(p.Username)) + offset += uint32(len(p.Username)) + + // Write Password as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Password))) + offset += 2 + copy(dest[offset:], []byte(p.Password)) + offset += uint32(len(p.Password)) + + // Write AcctNum + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AcctNum)) + offset += 4 + + // Write PassCode + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.PassCode)) + offset += 4 + + // Write Version + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Version)) + offset += 2 + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginRequest) Size() uint32 { + size := uint32(0) + + size += 2 + uint32(len(p.SessionID)) + + size += 2 + uint32(len(p.SessionRecycleToken)) + + size += 2 + uint32(len(p.Username)) + + size += 2 + uint32(len(p.Password)) + + size += 4 + + size += 4 + + size += 2 + + return size +} + +// LSLoginRequestV562 represents packet structure for OP_LoginRequestMsg +type LSLoginRequestV562 struct { + Accesscode string `eq2:"accesscode,type:str16"` + Unknown1 string `eq2:"unknown1,type:str16"` // TODO: Identify purpose + Username string `eq2:"username,type:str16"` + Password string `eq2:"password,type:str16"` + Unknown2 [8]uint8 `eq2:"unknown2,size:8"` // TODO: Identify purpose + Unknown3 [2]uint8 `eq2:"unknown3,size:2"` // TODO: Identify purpose + Version uint32 `eq2:"version"` + Unknown4 uint16 `eq2:"unknown4"` // TODO: Identify purpose + Unknown5 uint32 `eq2:"unknown5"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginRequestV562) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Accesscode as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Accesscode))) + offset += 2 + copy(dest[offset:], []byte(p.Accesscode)) + offset += uint32(len(p.Accesscode)) + + // Write Unknown1 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown1))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown1)) + offset += uint32(len(p.Unknown1)) + + // Write Username as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Username))) + offset += 2 + copy(dest[offset:], []byte(p.Username)) + offset += uint32(len(p.Username)) + + // Write Password as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Password))) + offset += 2 + copy(dest[offset:], []byte(p.Password)) + offset += uint32(len(p.Password)) + + // Write Unknown2 array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write Unknown3 array + for i := 0; i < 2; i++ { + dest[offset] = p.Unknown3[i] + offset++ + } + + // Write Version + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Version)) + offset += 4 + + // Write Unknown4 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown4)) + offset += 2 + + // Write Unknown5 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown5)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginRequestV562) Size() uint32 { + size := uint32(0) + + size += 2 + uint32(len(p.Accesscode)) + + size += 2 + uint32(len(p.Unknown1)) + + size += 2 + uint32(len(p.Username)) + + size += 2 + uint32(len(p.Password)) + + size += 8 + + size += 2 + + size += 4 + + size += 2 + + size += 4 + + return size +} + +// LSLoginRequestV1208 represents packet structure for OP_LoginRequestMsg +type LSLoginRequestV1208 struct { + Accesscode string `eq2:"accesscode,type:str16"` + Unknown1 string `eq2:"unknown1,type:str16"` // TODO: Identify purpose + Username string `eq2:"username,type:str16"` + Password string `eq2:"password,type:str16"` + Unknown2 [8]uint8 `eq2:"unknown2,size:8"` // TODO: Identify purpose + Unknown3 [2]uint8 `eq2:"unknown3,size:2"` // TODO: Identify purpose + Version uint16 `eq2:"version"` + Unknown4 uint8 `eq2:"unknown4"` // TODO: Identify purpose + Unknown5 [3]uint32 `eq2:"unknown5,size:3"` // TODO: Identify purpose + Unknown6 uint16 `eq2:"unknown6"` // TODO: Identify purpose + Unknown7 string `eq2:"unknown7,type:str16"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginRequestV1208) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Accesscode as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Accesscode))) + offset += 2 + copy(dest[offset:], []byte(p.Accesscode)) + offset += uint32(len(p.Accesscode)) + + // Write Unknown1 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown1))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown1)) + offset += uint32(len(p.Unknown1)) + + // Write Username as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Username))) + offset += 2 + copy(dest[offset:], []byte(p.Username)) + offset += uint32(len(p.Username)) + + // Write Password as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Password))) + offset += 2 + copy(dest[offset:], []byte(p.Password)) + offset += uint32(len(p.Password)) + + // Write Unknown2 array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write Unknown3 array + for i := 0; i < 2; i++ { + dest[offset] = p.Unknown3[i] + offset++ + } + + // Write Version + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Version)) + offset += 2 + + // Write Unknown4 + dest[offset] = byte(p.Unknown4) + offset++ + + // Write Unknown5 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown5[i])) + offset += 4 + } + + // Write Unknown6 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown6)) + offset += 2 + + // Write Unknown7 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown7))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown7)) + offset += uint32(len(p.Unknown7)) + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginRequestV1208) Size() uint32 { + size := uint32(0) + + size += 2 + uint32(len(p.Accesscode)) + + size += 2 + uint32(len(p.Unknown1)) + + size += 2 + uint32(len(p.Username)) + + size += 2 + uint32(len(p.Password)) + + size += 8 + + size += 2 + + size += 2 + + size += 1 + + size += 3 * 4 + + size += 2 + + size += 2 + uint32(len(p.Unknown7)) + + return size +} + +// LSWorldList represents packet structure for OP_WorldListMsg +type LSWorldList struct { + NumWorlds uint8 `eq2:"num_worlds"` + WorldList []struct { + Id uint32 `eq2:"id"` + Name string `eq2:"name,type:str16"` + Online uint8 `eq2:"online"` + Locked uint8 `eq2:"locked"` + Unknown2 uint8 `eq2:"unknown2"` + Unknown3 uint8 `eq2:"unknown3"` + Load uint8 `eq2:"load"` + } `eq2:"world_list,sizeVar:num_worlds"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSWorldList) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write NumWorlds + dest[offset] = byte(p.NumWorlds) + offset++ + + // Write WorldList array (dynamic size) + for _, elem := range p.WorldList { + binary.LittleEndian.PutUint32(dest[offset:], elem.Id) + offset += 4 + // Write Name string field + dest[offset] = byte(len(elem.Name)) + offset++ + copy(dest[offset:], []byte(elem.Name)) + offset += uint32(len(elem.Name)) + dest[offset] = elem.Online + offset++ + dest[offset] = elem.Locked + offset++ + dest[offset] = elem.Unknown2 + offset++ + dest[offset] = elem.Unknown3 + offset++ + dest[offset] = elem.Load + offset++ + + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSWorldList) Size() uint32 { + size := uint32(0) + + size += 1 + + // Dynamic array: WorldList + for _, elem := range p.WorldList { + _ = elem // Avoid unused variable warning + size += 4 + size += 1 + uint32(len(elem.Name)) + size += 1 + size += 1 + size += 1 + size += 1 + size += 1 + + } + + return size +} + +// LSWorldListV373 represents packet structure for OP_WorldListMsg +type LSWorldListV373 struct { + NumWorlds uint8 `eq2:"num_worlds"` + WorldList []struct { + Id uint32 `eq2:"id"` + Name string `eq2:"name,type:str16"` + Tag uint8 `eq2:"tag"` + Locked uint8 `eq2:"locked"` + Hidden uint8 `eq2:"hidden"` + Unknown uint8 `eq2:"unknown"` + NumPlayers uint16 `eq2:"num_players"` + Load uint8 `eq2:"load"` + NumberOnlineFlag uint8 `eq2:"number_online_flag"` + AllowedRaces uint32 `eq2:"allowed_races"` + } `eq2:"world_list,sizeVar:num_worlds"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSWorldListV373) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write NumWorlds + dest[offset] = byte(p.NumWorlds) + offset++ + + // Write WorldList array (dynamic size) + for _, elem := range p.WorldList { + binary.LittleEndian.PutUint32(dest[offset:], elem.Id) + offset += 4 + // Write Name string field + dest[offset] = byte(len(elem.Name)) + offset++ + copy(dest[offset:], []byte(elem.Name)) + offset += uint32(len(elem.Name)) + dest[offset] = elem.Tag + offset++ + dest[offset] = elem.Locked + offset++ + dest[offset] = elem.Hidden + offset++ + dest[offset] = elem.Unknown + offset++ + binary.LittleEndian.PutUint16(dest[offset:], elem.NumPlayers) + offset += 2 + dest[offset] = elem.Load + offset++ + dest[offset] = elem.NumberOnlineFlag + offset++ + binary.LittleEndian.PutUint32(dest[offset:], elem.AllowedRaces) + offset += 4 + + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSWorldListV373) Size() uint32 { + size := uint32(0) + + size += 1 + + // Dynamic array: WorldList + for _, elem := range p.WorldList { + _ = elem // Avoid unused variable warning + size += 4 + size += 1 + uint32(len(elem.Name)) + size += 1 + size += 1 + size += 1 + size += 1 + size += 2 + size += 1 + size += 1 + size += 4 + + } + + return size +} + +// LSWorldListV546 represents packet structure for OP_WorldListMsg +type LSWorldListV546 struct { + NumWorlds uint8 `eq2:"num_worlds"` + WorldList []struct { + Id uint32 `eq2:"id"` + Name string `eq2:"name,type:str16"` + Name2 string `eq2:"name2,type:str16"` + Tag uint8 `eq2:"tag"` + Locked uint8 `eq2:"locked"` + Hidden uint8 `eq2:"hidden"` + Unknown uint8 `eq2:"unknown"` + NumPlayers uint16 `eq2:"num_players"` + Load uint8 `eq2:"load"` + NumberOnlineFlag uint8 `eq2:"number_online_flag"` + Unknown2 uint8 `eq2:"unknown2"` + AllowedRaces uint32 `eq2:"allowed_races"` + } `eq2:"world_list,sizeVar:num_worlds"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSWorldListV546) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write NumWorlds + dest[offset] = byte(p.NumWorlds) + offset++ + + // Write WorldList array (dynamic size) + for _, elem := range p.WorldList { + binary.LittleEndian.PutUint32(dest[offset:], elem.Id) + offset += 4 + // Write Name string field + dest[offset] = byte(len(elem.Name)) + offset++ + copy(dest[offset:], []byte(elem.Name)) + offset += uint32(len(elem.Name)) + // Write Name2 string field + dest[offset] = byte(len(elem.Name2)) + offset++ + copy(dest[offset:], []byte(elem.Name2)) + offset += uint32(len(elem.Name2)) + dest[offset] = elem.Tag + offset++ + dest[offset] = elem.Locked + offset++ + dest[offset] = elem.Hidden + offset++ + dest[offset] = elem.Unknown + offset++ + binary.LittleEndian.PutUint16(dest[offset:], elem.NumPlayers) + offset += 2 + dest[offset] = elem.Load + offset++ + dest[offset] = elem.NumberOnlineFlag + offset++ + dest[offset] = elem.Unknown2 + offset++ + binary.LittleEndian.PutUint32(dest[offset:], elem.AllowedRaces) + offset += 4 + + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSWorldListV546) Size() uint32 { + size := uint32(0) + + size += 1 + + // Dynamic array: WorldList + for _, elem := range p.WorldList { + _ = elem // Avoid unused variable warning + size += 4 + size += 1 + uint32(len(elem.Name)) + size += 1 + uint32(len(elem.Name2)) + size += 1 + size += 1 + size += 1 + size += 1 + size += 2 + size += 1 + size += 1 + size += 1 + size += 4 + + } + + return size +} + +// LSWorldListV562 represents packet structure for OP_WorldListMsg +type LSWorldListV562 struct { + NumWorlds uint8 `eq2:"num_worlds"` + WorldList []struct { + Id uint32 `eq2:"id"` + Name string `eq2:"name,type:str16"` + Name2 string `eq2:"name2,type:str16"` + Tag uint8 `eq2:"tag"` + Locked uint8 `eq2:"locked"` + Hidden uint8 `eq2:"hidden"` + Unknown uint8 `eq2:"unknown"` + NumPlayers uint16 `eq2:"num_players"` + Load uint8 `eq2:"load"` + NumberOnlineFlag uint8 `eq2:"number_online_flag"` + FeatureSet [2]uint8 `eq2:"feature_set,size:2"` + AllowedRaces uint32 `eq2:"allowed_races"` + } `eq2:"world_list,sizeVar:num_worlds"` + Unknown2 uint8 `eq2:"unknown2"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSWorldListV562) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write NumWorlds + dest[offset] = byte(p.NumWorlds) + offset++ + + // Write WorldList array (dynamic size) + for _, elem := range p.WorldList { + binary.LittleEndian.PutUint32(dest[offset:], elem.Id) + offset += 4 + // Write Name string field + dest[offset] = byte(len(elem.Name)) + offset++ + copy(dest[offset:], []byte(elem.Name)) + offset += uint32(len(elem.Name)) + // Write Name2 string field + dest[offset] = byte(len(elem.Name2)) + offset++ + copy(dest[offset:], []byte(elem.Name2)) + offset += uint32(len(elem.Name2)) + dest[offset] = elem.Tag + offset++ + dest[offset] = elem.Locked + offset++ + dest[offset] = elem.Hidden + offset++ + dest[offset] = elem.Unknown + offset++ + binary.LittleEndian.PutUint16(dest[offset:], elem.NumPlayers) + offset += 2 + dest[offset] = elem.Load + offset++ + dest[offset] = elem.NumberOnlineFlag + offset++ + // Write FeatureSet array field + for i := 0; i < 2; i++ { + dest[offset] = byte(elem.FeatureSet[i]) + offset++ + } + binary.LittleEndian.PutUint32(dest[offset:], elem.AllowedRaces) + offset += 4 + + } + + // Write Unknown2 + dest[offset] = byte(p.Unknown2) + offset++ + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSWorldListV562) Size() uint32 { + size := uint32(0) + + size += 1 + + // Dynamic array: WorldList + for _, elem := range p.WorldList { + _ = elem // Avoid unused variable warning + size += 4 + size += 1 + uint32(len(elem.Name)) + size += 1 + uint32(len(elem.Name2)) + size += 1 + size += 1 + size += 1 + size += 1 + size += 2 + size += 1 + size += 1 + size += 2 + size += 4 + + } + + size += 1 + + return size +} + +// LSWorldListV60114 represents packet structure for OP_WorldListMsg +type LSWorldListV60114 struct { + NumWorlds uint8 `eq2:"num_worlds"` + WorldList []struct { + Id uint32 `eq2:"id"` + Name string `eq2:"name,type:str16"` + Name2 string `eq2:"name2,type:str16"` + Tag uint8 `eq2:"tag"` + Locked uint8 `eq2:"locked"` + Hidden uint8 `eq2:"hidden"` + Unknown uint8 `eq2:"unknown"` + NumPlayers uint16 `eq2:"num_players"` + Load uint8 `eq2:"load"` + NumberOnlineFlag uint8 `eq2:"number_online_flag"` + FeatureSet [2]uint8 `eq2:"feature_set,size:2"` + AllowedRaces uint32 `eq2:"allowed_races"` + } `eq2:"world_list,sizeVar:num_worlds"` + Unknown2 uint8 `eq2:"unknown2"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSWorldListV60114) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write NumWorlds + dest[offset] = byte(p.NumWorlds) + offset++ + + // Write WorldList array (dynamic size) + for _, elem := range p.WorldList { + binary.LittleEndian.PutUint32(dest[offset:], elem.Id) + offset += 4 + // Write Name string field + dest[offset] = byte(len(elem.Name)) + offset++ + copy(dest[offset:], []byte(elem.Name)) + offset += uint32(len(elem.Name)) + // Write Name2 string field + dest[offset] = byte(len(elem.Name2)) + offset++ + copy(dest[offset:], []byte(elem.Name2)) + offset += uint32(len(elem.Name2)) + dest[offset] = elem.Tag + offset++ + dest[offset] = elem.Locked + offset++ + dest[offset] = elem.Hidden + offset++ + dest[offset] = elem.Unknown + offset++ + binary.LittleEndian.PutUint16(dest[offset:], elem.NumPlayers) + offset += 2 + dest[offset] = elem.Load + offset++ + dest[offset] = elem.NumberOnlineFlag + offset++ + // Write FeatureSet array field + for i := 0; i < 2; i++ { + dest[offset] = byte(elem.FeatureSet[i]) + offset++ + } + binary.LittleEndian.PutUint32(dest[offset:], elem.AllowedRaces) + offset += 4 + + } + + // Write Unknown2 + dest[offset] = byte(p.Unknown2) + offset++ + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSWorldListV60114) Size() uint32 { + size := uint32(0) + + size += 1 + + // Dynamic array: WorldList + for _, elem := range p.WorldList { + _ = elem // Avoid unused variable warning + size += 4 + size += 1 + uint32(len(elem.Name)) + size += 1 + uint32(len(elem.Name2)) + size += 1 + size += 1 + size += 1 + size += 1 + size += 2 + size += 1 + size += 1 + size += 2 + size += 4 + + } + + size += 1 + + return size +} + +// LSWorldListV65534 represents packet structure for OP_WorldListMsg +type LSWorldListV65534 struct { + NumWorlds uint8 `eq2:"num_worlds"` + WorldList []struct { + Id uint32 `eq2:"id"` + Name string `eq2:"name,type:str16"` + Name2 string `eq2:"name2,type:str16"` + Tag uint8 `eq2:"tag"` + Locked uint8 `eq2:"locked"` + Hidden uint8 `eq2:"hidden"` + Unknown uint8 `eq2:"unknown"` + NumPlayers uint16 `eq2:"num_players"` + Load uint8 `eq2:"load"` + NumberOnlineFlag uint8 `eq2:"number_online_flag"` + FeatureSet [3]uint8 `eq2:"feature_set,size:3"` + AllowedRaces uint32 `eq2:"allowed_races"` + } `eq2:"world_list,sizeVar:num_worlds"` + Unknown2 uint8 `eq2:"unknown2"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSWorldListV65534) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write NumWorlds + dest[offset] = byte(p.NumWorlds) + offset++ + + // Write WorldList array (dynamic size) + for _, elem := range p.WorldList { + binary.LittleEndian.PutUint32(dest[offset:], elem.Id) + offset += 4 + // Write Name string field + dest[offset] = byte(len(elem.Name)) + offset++ + copy(dest[offset:], []byte(elem.Name)) + offset += uint32(len(elem.Name)) + // Write Name2 string field + dest[offset] = byte(len(elem.Name2)) + offset++ + copy(dest[offset:], []byte(elem.Name2)) + offset += uint32(len(elem.Name2)) + dest[offset] = elem.Tag + offset++ + dest[offset] = elem.Locked + offset++ + dest[offset] = elem.Hidden + offset++ + dest[offset] = elem.Unknown + offset++ + binary.LittleEndian.PutUint16(dest[offset:], elem.NumPlayers) + offset += 2 + dest[offset] = elem.Load + offset++ + dest[offset] = elem.NumberOnlineFlag + offset++ + // Write FeatureSet array field + for i := 0; i < 3; i++ { + dest[offset] = byte(elem.FeatureSet[i]) + offset++ + } + binary.LittleEndian.PutUint32(dest[offset:], elem.AllowedRaces) + offset += 4 + + } + + // Write Unknown2 + dest[offset] = byte(p.Unknown2) + offset++ + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSWorldListV65534) Size() uint32 { + size := uint32(0) + + size += 1 + + // Dynamic array: WorldList + for _, elem := range p.WorldList { + _ = elem // Avoid unused variable warning + size += 4 + size += 1 + uint32(len(elem.Name)) + size += 1 + uint32(len(elem.Name2)) + size += 1 + size += 1 + size += 1 + size += 1 + size += 2 + size += 1 + size += 1 + size += 3 + size += 4 + + } + + size += 1 + + return size +} + +// LSWorldUpdate represents packet structure for OP_WorldStatusChangeMsg +type LSWorldUpdate struct { + ServerId uint32 `eq2:"server_id"` + Up uint8 `eq2:"up"` + Locked uint8 `eq2:"locked"` + Unknown1 uint8 `eq2:"unknown1"` // TODO: Identify purpose + Unknown2 uint8 `eq2:"unknown2"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSWorldUpdate) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Up + dest[offset] = byte(p.Up) + offset++ + + // Write Locked + dest[offset] = byte(p.Locked) + offset++ + + // Write Unknown1 + dest[offset] = byte(p.Unknown1) + offset++ + + // Write Unknown2 + dest[offset] = byte(p.Unknown2) + offset++ + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSWorldUpdate) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + return size +} + +// LSPlayRequest represents packet structure for OP_PlayCharacterRequestMsg +type LSPlayRequest struct { + CharId uint32 `eq2:"char_id"` + Name string `eq2:"name,type:str16"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSPlayRequest) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write CharId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CharId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSPlayRequest) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 2 + uint32(len(p.Name)) + + return size +} + +// LSPlayRequestV284 represents packet structure for OP_PlayCharacterRequestMsg +type LSPlayRequestV284 struct { + CharId uint32 `eq2:"char_id"` + ServerId uint32 `eq2:"server_id"` + Unknown [3]uint8 `eq2:"unknown,size:3"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSPlayRequestV284) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write CharId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CharId)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Unknown array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown[i] + offset++ + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSPlayRequestV284) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 3 + + return size +} + +// LSPlayResponse represents packet structure for OP_PlayCharacterReplyMsg +type LSPlayResponse struct { + Response uint8 `eq2:"response"` + Server string `eq2:"server,type:str8"` + Port uint16 `eq2:"port"` + AccountId uint32 `eq2:"account_id"` + AccessCode uint32 `eq2:"access_code"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSPlayResponse) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Response + dest[offset] = byte(p.Response) + offset++ + + // Write Server as 8-bit length-prefixed string + dest[offset] = byte(len(p.Server)) + offset++ + copy(dest[offset:], []byte(p.Server)) + offset += uint32(len(p.Server)) + + // Write Port + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Port)) + offset += 2 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write AccessCode + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccessCode)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSPlayResponse) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 1 + uint32(len(p.Server)) + + size += 2 + + size += 4 + + size += 4 + + return size +} + +// LSPlayResponseV1096 represents packet structure for OP_PlayCharacterReplyMsg +type LSPlayResponseV1096 struct { + Response uint8 `eq2:"response"` + Unknown1 uint16 `eq2:"unknown1"` // TODO: Identify purpose + Server string `eq2:"server,type:str8"` + Port uint16 `eq2:"port"` + AccountId uint32 `eq2:"account_id"` + AccessCode uint32 `eq2:"access_code"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSPlayResponseV1096) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Response + dest[offset] = byte(p.Response) + offset++ + + // Write Unknown1 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown1)) + offset += 2 + + // Write Server as 8-bit length-prefixed string + dest[offset] = byte(len(p.Server)) + offset++ + copy(dest[offset:], []byte(p.Server)) + offset += uint32(len(p.Server)) + + // Write Port + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Port)) + offset += 2 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write AccessCode + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccessCode)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSPlayResponseV1096) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + + size += 1 + uint32(len(p.Server)) + + size += 2 + + size += 4 + + size += 4 + + return size +} + +// LSPlayResponseV60085 represents packet structure for OP_PlayCharacterReplyMsg +type LSPlayResponseV60085 struct { + Response uint8 `eq2:"response"` + Unknown1 [3]uint16 `eq2:"unknown1,size:3"` // TODO: Identify purpose + Server string `eq2:"server,type:str8"` + Port uint16 `eq2:"port"` + AccountId uint32 `eq2:"account_id"` + AccessCode uint32 `eq2:"access_code"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSPlayResponseV60085) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Response + dest[offset] = byte(p.Response) + offset++ + + // Write Unknown1 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown1[i])) + offset += 2 + } + + // Write Server as 8-bit length-prefixed string + dest[offset] = byte(len(p.Server)) + offset++ + copy(dest[offset:], []byte(p.Server)) + offset += uint32(len(p.Server)) + + // Write Port + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Port)) + offset += 2 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write AccessCode + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccessCode)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSPlayResponseV60085) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 3 * 2 + + size += 1 + uint32(len(p.Server)) + + size += 2 + + size += 4 + + size += 4 + + return size +} + +// LSPlayResponseV60099 represents packet structure for OP_PlayCharacterReplyMsg +type LSPlayResponseV60099 struct { + Response uint8 `eq2:"response"` + Unknown1 [3]uint16 `eq2:"unknown1,size:3"` // TODO: Identify purpose + Server string `eq2:"server,type:str8"` + Port uint16 `eq2:"port"` + AccountId uint32 `eq2:"account_id"` + AccessCode uint32 `eq2:"access_code"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSPlayResponseV60099) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Response + dest[offset] = byte(p.Response) + offset++ + + // Write Unknown1 array + for i := 0; i < 3; i++ { + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown1[i])) + offset += 2 + } + + // Write Server as 8-bit length-prefixed string + dest[offset] = byte(len(p.Server)) + offset++ + copy(dest[offset:], []byte(p.Server)) + offset += uint32(len(p.Server)) + + // Write Port + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Port)) + offset += 2 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write AccessCode + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccessCode)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSPlayResponseV60099) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 3 * 2 + + size += 1 + uint32(len(p.Server)) + + size += 2 + + size += 4 + + size += 4 + + return size +} + +// CharSelectProfile represents packet structure for client version 1 +type CharSelectProfile struct { + Charid uint32 `eq2:"charid"` + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Class uint8 `eq2:"class"` + Level uint32 `eq2:"level"` + Zone string `eq2:"zone,type:str16"` + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + Unknown2 uint32 `eq2:"unknown2"` // TODO: Identify purpose + CreatedDate uint32 `eq2:"created_date"` + LastPlayed uint32 `eq2:"last_played"` + Unknown3 uint32 `eq2:"unknown3"` // TODO: Identify purpose + Unknown4 uint32 `eq2:"unknown4"` // TODO: Identify purpose + Zonename2 string `eq2:"zonename2,type:str16"` + Zonedesc string `eq2:"zonedesc,type:str16"` + Version uint8 `eq2:"version"` + RaceType uint16 `eq2:"race_type"` + SkinColor [3]int8 `eq2:"skin_color,size:3"` + EyeColor [3]int8 `eq2:"eye_color,size:3"` + Equip [21]types.EquipmentItem `eq2:"equip,size:21"` + HairType uint16 `eq2:"hair_type"` + HairTypeColor [3]int8 `eq2:"hair_type_color,size:3"` + HairTypeHighlightColor [3]int8 `eq2:"hair_type_highlight_color,size:3"` + HairFaceType uint16 `eq2:"hair_face_type"` + HairFaceColor [3]int8 `eq2:"hair_face_color,size:3"` + HairFaceHighlightColor [3]int8 `eq2:"hair_face_highlight_color,size:3"` + ChestType uint16 `eq2:"chest_type"` + ShirtColor [3]int8 `eq2:"shirt_color,size:3"` + UnknownChestColor [3]int8 `eq2:"unknown_chest_color,size:3"` // TODO: Identify purpose + LegsType uint16 `eq2:"legs_type"` + PantsColor [3]int8 `eq2:"pants_color,size:3"` + UnknownLegsColor [3]int8 `eq2:"unknown_legs_color,size:3"` // TODO: Identify purpose + Unknown9 [3]int8 `eq2:"unknown9,size:3"` // TODO: Identify purpose + EyeType [3]int8 `eq2:"eye_type,size:3"` + EarType [3]int8 `eq2:"ear_type,size:3"` + EyeBrowType [3]int8 `eq2:"eye_brow_type,size:3"` + CheekType [3]int8 `eq2:"cheek_type,size:3"` + LipType [3]int8 `eq2:"lip_type,size:3"` + ChinType [3]int8 `eq2:"chin_type,size:3"` + NoseType [3]int8 `eq2:"nose_type,size:3"` + BodySize int8 `eq2:"body_size"` + BumpScale int8 `eq2:"bump_scale"` + Mount uint16 `eq2:"mount"` + MountColor1 [3]int8 `eq2:"mount_color1,size:3"` + MountColor2 [3]int8 `eq2:"mount_color2,size:3"` + HairColor1 [3]int8 `eq2:"hair_color1,size:3"` + HairColor2 [3]int8 `eq2:"hair_color2,size:3"` + HairColor3 [3]int8 `eq2:"hair_color3,size:3"` + Flags uint8 `eq2:"flags"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CharSelectProfile) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Charid + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Charid)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Level)) + offset += 4 + + // Write Zone as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zone))) + offset += 2 + copy(dest[offset:], []byte(p.Zone)) + offset += uint32(len(p.Zone)) + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write Unknown2 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown2)) + offset += 4 + + // Write CreatedDate + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CreatedDate)) + offset += 4 + + // Write LastPlayed + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.LastPlayed)) + offset += 4 + + // Write Unknown3 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown3)) + offset += 4 + + // Write Unknown4 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown4)) + offset += 4 + + // Write Zonename2 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonename2))) + offset += 2 + copy(dest[offset:], []byte(p.Zonename2)) + offset += uint32(len(p.Zonename2)) + + // Write Zonedesc as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonedesc))) + offset += 2 + copy(dest[offset:], []byte(p.Zonedesc)) + offset += uint32(len(p.Zonedesc)) + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write RaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.RaceType)) + offset += 2 + + // Write SkinColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SkinColor[i]) + offset++ + } + + // Write EyeColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeColor[i]) + offset++ + } + + // Write Equip array + for i := 0; i < 21; i++ { + binary.LittleEndian.PutUint16(dest[offset:], p.Equip[i].Type) + offset += 2 + binary.LittleEndian.PutUint32(dest[offset:], p.Equip[i].Color.ToUint32()) + offset += 4 + } + + // Write HairType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairType)) + offset += 2 + + // Write HairTypeColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairTypeColor[i]) + offset++ + } + + // Write HairTypeHighlightColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairTypeHighlightColor[i]) + offset++ + } + + // Write HairFaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairFaceType)) + offset += 2 + + // Write HairFaceColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairFaceColor[i]) + offset++ + } + + // Write HairFaceHighlightColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairFaceHighlightColor[i]) + offset++ + } + + // Write ChestType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.ChestType)) + offset += 2 + + // Write ShirtColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.ShirtColor[i]) + offset++ + } + + // Write UnknownChestColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.UnknownChestColor[i]) + offset++ + } + + // Write LegsType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.LegsType)) + offset += 2 + + // Write PantsColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.PantsColor[i]) + offset++ + } + + // Write UnknownLegsColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.UnknownLegsColor[i]) + offset++ + } + + // Write Unknown9 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.Unknown9[i]) + offset++ + } + + // Write EyeType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeType[i]) + offset++ + } + + // Write EarType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EarType[i]) + offset++ + } + + // Write EyeBrowType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeBrowType[i]) + offset++ + } + + // Write CheekType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.CheekType[i]) + offset++ + } + + // Write LipType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.LipType[i]) + offset++ + } + + // Write ChinType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.ChinType[i]) + offset++ + } + + // Write NoseType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.NoseType[i]) + offset++ + } + + // Write BodySize + dest[offset] = byte(p.BodySize) + offset++ + + // Write BumpScale + dest[offset] = byte(p.BumpScale) + offset++ + + // Write Mount + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Mount)) + offset += 2 + + // Write MountColor1 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.MountColor1[i]) + offset++ + } + + // Write MountColor2 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.MountColor2[i]) + offset++ + } + + // Write HairColor1 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairColor1[i]) + offset++ + } + + // Write HairColor2 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairColor2[i]) + offset++ + } + + // Write HairColor3 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairColor3[i]) + offset++ + } + + // Write Flags + dest[offset] = byte(p.Flags) + offset++ + + return offset +} + +// Size returns the serialized size of the packet +func (p *CharSelectProfile) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Zone)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Zonename2)) + + size += 2 + uint32(len(p.Zonedesc)) + + size += 1 + + size += 2 + + size += 3 + + size += 3 + + size += 21 * 6 + + size += 2 + + size += 3 + + size += 3 + + size += 2 + + size += 3 + + size += 3 + + size += 2 + + size += 3 + + size += 3 + + size += 2 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 1 + + size += 1 + + size += 2 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 1 + + return size +} + +// CharSelectProfileV373 represents packet structure for client version 373 +type CharSelectProfileV373 struct { + Charid uint32 `eq2:"charid"` + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Class uint8 `eq2:"class"` + Level uint32 `eq2:"level"` + Zone string `eq2:"zone,type:str16"` + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + Unknown2 uint32 `eq2:"unknown2"` // TODO: Identify purpose + CreatedDate uint32 `eq2:"created_date"` + LastPlayed uint32 `eq2:"last_played"` + Unknown3 uint32 `eq2:"unknown3"` // TODO: Identify purpose + Unknown4 uint32 `eq2:"unknown4"` // TODO: Identify purpose + Zonename2 string `eq2:"zonename2,type:str16"` + Zonedesc string `eq2:"zonedesc,type:str16"` + Version uint8 `eq2:"version"` + RaceType uint16 `eq2:"race_type"` + SkinColor [3]int8 `eq2:"skin_color,size:3"` + EyeColor [3]int8 `eq2:"eye_color,size:3"` + Equip [21]types.EquipmentItem `eq2:"equip,size:21"` + HairType uint16 `eq2:"hair_type"` + HairTypeColor [3]int8 `eq2:"hair_type_color,size:3"` + HairTypeHighlightColor [3]int8 `eq2:"hair_type_highlight_color,size:3"` + HairFaceType uint16 `eq2:"hair_face_type"` + HairFaceColor [3]int8 `eq2:"hair_face_color,size:3"` + HairFaceHighlightColor [3]int8 `eq2:"hair_face_highlight_color,size:3"` + ChestType uint16 `eq2:"chest_type"` + ShirtColor [3]int8 `eq2:"shirt_color,size:3"` + UnknownChestColor [3]int8 `eq2:"unknown_chest_color,size:3"` // TODO: Identify purpose + LegsType uint16 `eq2:"legs_type"` + PantsColor [3]int8 `eq2:"pants_color,size:3"` + UnknownLegsColor [3]int8 `eq2:"unknown_legs_color,size:3"` // TODO: Identify purpose + Unknown9 [3]int8 `eq2:"unknown9,size:3"` // TODO: Identify purpose + EyeType [3]int8 `eq2:"eye_type,size:3"` + EarType [3]int8 `eq2:"ear_type,size:3"` + EyeBrowType [3]int8 `eq2:"eye_brow_type,size:3"` + CheekType [3]int8 `eq2:"cheek_type,size:3"` + LipType [3]int8 `eq2:"lip_type,size:3"` + ChinType [3]int8 `eq2:"chin_type,size:3"` + NoseType [3]int8 `eq2:"nose_type,size:3"` + BodySize int8 `eq2:"body_size"` + BumpScale int8 `eq2:"bump_scale"` + Mount uint16 `eq2:"mount"` + MountColor1 [3]int8 `eq2:"mount_color1,size:3"` + MountColor2 [3]int8 `eq2:"mount_color2,size:3"` + HairColor1 [3]int8 `eq2:"hair_color1,size:3"` + HairColor2 [3]int8 `eq2:"hair_color2,size:3"` + HairColor3 [3]int8 `eq2:"hair_color3,size:3"` + Flags uint8 `eq2:"flags"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CharSelectProfileV373) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Charid + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Charid)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Level + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Level)) + offset += 4 + + // Write Zone as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zone))) + offset += 2 + copy(dest[offset:], []byte(p.Zone)) + offset += uint32(len(p.Zone)) + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write Unknown2 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown2)) + offset += 4 + + // Write CreatedDate + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CreatedDate)) + offset += 4 + + // Write LastPlayed + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.LastPlayed)) + offset += 4 + + // Write Unknown3 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown3)) + offset += 4 + + // Write Unknown4 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown4)) + offset += 4 + + // Write Zonename2 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonename2))) + offset += 2 + copy(dest[offset:], []byte(p.Zonename2)) + offset += uint32(len(p.Zonename2)) + + // Write Zonedesc as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonedesc))) + offset += 2 + copy(dest[offset:], []byte(p.Zonedesc)) + offset += uint32(len(p.Zonedesc)) + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write RaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.RaceType)) + offset += 2 + + // Write SkinColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SkinColor[i]) + offset++ + } + + // Write EyeColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeColor[i]) + offset++ + } + + // Write Equip array + for i := 0; i < 21; i++ { + binary.LittleEndian.PutUint16(dest[offset:], p.Equip[i].Type) + offset += 2 + binary.LittleEndian.PutUint32(dest[offset:], p.Equip[i].Color.ToUint32()) + offset += 4 + } + + // Write HairType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairType)) + offset += 2 + + // Write HairTypeColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairTypeColor[i]) + offset++ + } + + // Write HairTypeHighlightColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairTypeHighlightColor[i]) + offset++ + } + + // Write HairFaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairFaceType)) + offset += 2 + + // Write HairFaceColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairFaceColor[i]) + offset++ + } + + // Write HairFaceHighlightColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairFaceHighlightColor[i]) + offset++ + } + + // Write ChestType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.ChestType)) + offset += 2 + + // Write ShirtColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.ShirtColor[i]) + offset++ + } + + // Write UnknownChestColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.UnknownChestColor[i]) + offset++ + } + + // Write LegsType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.LegsType)) + offset += 2 + + // Write PantsColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.PantsColor[i]) + offset++ + } + + // Write UnknownLegsColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.UnknownLegsColor[i]) + offset++ + } + + // Write Unknown9 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.Unknown9[i]) + offset++ + } + + // Write EyeType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeType[i]) + offset++ + } + + // Write EarType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EarType[i]) + offset++ + } + + // Write EyeBrowType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeBrowType[i]) + offset++ + } + + // Write CheekType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.CheekType[i]) + offset++ + } + + // Write LipType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.LipType[i]) + offset++ + } + + // Write ChinType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.ChinType[i]) + offset++ + } + + // Write NoseType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.NoseType[i]) + offset++ + } + + // Write BodySize + dest[offset] = byte(p.BodySize) + offset++ + + // Write BumpScale + dest[offset] = byte(p.BumpScale) + offset++ + + // Write Mount + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Mount)) + offset += 2 + + // Write MountColor1 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.MountColor1[i]) + offset++ + } + + // Write MountColor2 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.MountColor2[i]) + offset++ + } + + // Write HairColor1 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairColor1[i]) + offset++ + } + + // Write HairColor2 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairColor2[i]) + offset++ + } + + // Write HairColor3 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairColor3[i]) + offset++ + } + + // Write Flags + dest[offset] = byte(p.Flags) + offset++ + + return offset +} + +// Size returns the serialized size of the packet +func (p *CharSelectProfileV373) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Zone)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Zonename2)) + + size += 2 + uint32(len(p.Zonedesc)) + + size += 1 + + size += 2 + + size += 3 + + size += 3 + + size += 21 * 6 + + size += 2 + + size += 3 + + size += 3 + + size += 2 + + size += 3 + + size += 3 + + size += 2 + + size += 3 + + size += 3 + + size += 2 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 1 + + size += 1 + + size += 2 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 1 + + return size +} + +// CharSelectProfileV546 represents packet structure for client version 546 +type CharSelectProfileV546 struct { + Charid uint32 `eq2:"charid"` + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Race uint8 `eq2:"race"` + Class uint8 `eq2:"class"` + Gender uint8 `eq2:"gender"` + Level uint32 `eq2:"level"` + Zone string `eq2:"zone,type:str16"` + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + Unknown2 uint32 `eq2:"unknown2"` // TODO: Identify purpose + CreatedDate uint32 `eq2:"created_date"` + LastPlayed uint32 `eq2:"last_played"` + Unknown3 uint32 `eq2:"unknown3"` // TODO: Identify purpose + Unknown4 uint32 `eq2:"unknown4"` // TODO: Identify purpose + Zonename2 string `eq2:"zonename2,type:str16"` + Zonedesc string `eq2:"zonedesc,type:str16"` + Unknown5 uint32 `eq2:"unknown5"` // TODO: Identify purpose + Version uint8 `eq2:"version"` + RaceType uint16 `eq2:"race_type"` + SkinColor [3]int8 `eq2:"skin_color,size:3"` + EyeColor [3]int8 `eq2:"eye_color,size:3"` + Equip [23]types.EquipmentItem `eq2:"equip,size:23"` + HairType uint16 `eq2:"hair_type"` + HairTypeColor [3]int8 `eq2:"hair_type_color,size:3"` + HairTypeHighlightColor [3]int8 `eq2:"hair_type_highlight_color,size:3"` + HairFaceType uint16 `eq2:"hair_face_type"` + HairFaceColor [3]int8 `eq2:"hair_face_color,size:3"` + HairFaceHighlightColor [3]int8 `eq2:"hair_face_highlight_color,size:3"` + ChestType uint16 `eq2:"chest_type"` + ShirtColor [3]int8 `eq2:"shirt_color,size:3"` + UnknownChestColor [3]int8 `eq2:"unknown_chest_color,size:3"` // TODO: Identify purpose + LegsType uint16 `eq2:"legs_type"` + PantsColor [3]int8 `eq2:"pants_color,size:3"` + UnknownLegsColor [3]int8 `eq2:"unknown_legs_color,size:3"` // TODO: Identify purpose + Unknown9 [3]int8 `eq2:"unknown9,size:3"` // TODO: Identify purpose + EyeType [3]int8 `eq2:"eye_type,size:3"` + EarType [3]int8 `eq2:"ear_type,size:3"` + EyeBrowType [3]int8 `eq2:"eye_brow_type,size:3"` + CheekType [3]int8 `eq2:"cheek_type,size:3"` + LipType [3]int8 `eq2:"lip_type,size:3"` + ChinType [3]int8 `eq2:"chin_type,size:3"` + NoseType [3]int8 `eq2:"nose_type,size:3"` + BodySize int8 `eq2:"body_size"` + BumpScale int8 `eq2:"bump_scale"` + Mount uint16 `eq2:"mount"` + MountColor1 [3]int8 `eq2:"mount_color1,size:3"` + MountColor2 [3]int8 `eq2:"mount_color2,size:3"` + HairColor1 [3]int8 `eq2:"hair_color1,size:3"` + HairColor2 [3]int8 `eq2:"hair_color2,size:3"` + HairColor3 [3]int8 `eq2:"hair_color3,size:3"` + Unknown11 [10]uint8 `eq2:"unknown11,size:10"` // TODO: Identify purpose + SogaRaceType uint16 `eq2:"soga_race_type"` + SogaSkinColorx types.Color `eq2:"soga_skin_colorx"` + SogaEyeColor types.Color `eq2:"soga_eye_color"` + Unknown12 [3]uint8 `eq2:"Unknown12,size:3"` // TODO: Identify purpose + SogaEyeType [3]int8 `eq2:"soga_eye_type,size:3"` + SogaEarType [3]int8 `eq2:"soga_ear_type,size:3"` + SogaEyeBrowType [3]int8 `eq2:"soga_eye_brow_type,size:3"` + SogaCheekType [3]int8 `eq2:"soga_cheek_type,size:3"` + SogaLipType [3]int8 `eq2:"soga_lip_type,size:3"` + SogaChinType [3]int8 `eq2:"soga_chin_type,size:3"` + SogaNoseType [3]int8 `eq2:"soga_nose_type,size:3"` + SogaHairColor1 types.Color `eq2:"soga_hair_color1"` + SogaChestType uint16 `eq2:"soga_chest_type"` + SogaHairColor2 types.Color `eq2:"soga_hair_color2"` + SogaHairColor3 types.Color `eq2:"soga_hair_color3"` + SogaHairType uint16 `eq2:"soga_hair_type"` + SogaHairTypeColor types.Color `eq2:"soga_hair_type_color"` + SogaHairTypeHighlightColor types.Color `eq2:"soga_hair_type_highlight_color"` + SogaHairFaceType uint16 `eq2:"soga_hair_face_type"` + SogaHairFaceColor types.Color `eq2:"soga_hair_face_color"` + SogaHairFaceHighlightColor types.Color `eq2:"soga_hair_face_highlight_color"` +} + +// Serialize writes the packet data to the provided buffer +func (p *CharSelectProfileV546) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Charid + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Charid)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Level + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Level)) + offset += 4 + + // Write Zone as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zone))) + offset += 2 + copy(dest[offset:], []byte(p.Zone)) + offset += uint32(len(p.Zone)) + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write Unknown2 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown2)) + offset += 4 + + // Write CreatedDate + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CreatedDate)) + offset += 4 + + // Write LastPlayed + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.LastPlayed)) + offset += 4 + + // Write Unknown3 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown3)) + offset += 4 + + // Write Unknown4 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown4)) + offset += 4 + + // Write Zonename2 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonename2))) + offset += 2 + copy(dest[offset:], []byte(p.Zonename2)) + offset += uint32(len(p.Zonename2)) + + // Write Zonedesc as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonedesc))) + offset += 2 + copy(dest[offset:], []byte(p.Zonedesc)) + offset += uint32(len(p.Zonedesc)) + + // Write Unknown5 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown5)) + offset += 4 + + // Write Version + dest[offset] = byte(p.Version) + offset++ + + // Write RaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.RaceType)) + offset += 2 + + // Write SkinColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SkinColor[i]) + offset++ + } + + // Write EyeColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeColor[i]) + offset++ + } + + // Write Equip array + for i := 0; i < 23; i++ { + binary.LittleEndian.PutUint16(dest[offset:], p.Equip[i].Type) + offset += 2 + binary.LittleEndian.PutUint32(dest[offset:], p.Equip[i].Color.ToUint32()) + offset += 4 + } + + // Write HairType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairType)) + offset += 2 + + // Write HairTypeColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairTypeColor[i]) + offset++ + } + + // Write HairTypeHighlightColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairTypeHighlightColor[i]) + offset++ + } + + // Write HairFaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairFaceType)) + offset += 2 + + // Write HairFaceColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairFaceColor[i]) + offset++ + } + + // Write HairFaceHighlightColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairFaceHighlightColor[i]) + offset++ + } + + // Write ChestType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.ChestType)) + offset += 2 + + // Write ShirtColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.ShirtColor[i]) + offset++ + } + + // Write UnknownChestColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.UnknownChestColor[i]) + offset++ + } + + // Write LegsType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.LegsType)) + offset += 2 + + // Write PantsColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.PantsColor[i]) + offset++ + } + + // Write UnknownLegsColor array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.UnknownLegsColor[i]) + offset++ + } + + // Write Unknown9 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.Unknown9[i]) + offset++ + } + + // Write EyeType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeType[i]) + offset++ + } + + // Write EarType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EarType[i]) + offset++ + } + + // Write EyeBrowType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeBrowType[i]) + offset++ + } + + // Write CheekType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.CheekType[i]) + offset++ + } + + // Write LipType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.LipType[i]) + offset++ + } + + // Write ChinType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.ChinType[i]) + offset++ + } + + // Write NoseType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.NoseType[i]) + offset++ + } + + // Write BodySize + dest[offset] = byte(p.BodySize) + offset++ + + // Write BumpScale + dest[offset] = byte(p.BumpScale) + offset++ + + // Write Mount + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Mount)) + offset += 2 + + // Write MountColor1 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.MountColor1[i]) + offset++ + } + + // Write MountColor2 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.MountColor2[i]) + offset++ + } + + // Write HairColor1 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairColor1[i]) + offset++ + } + + // Write HairColor2 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairColor2[i]) + offset++ + } + + // Write HairColor3 array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.HairColor3[i]) + offset++ + } + + // Write Unknown11 array + for i := 0; i < 10; i++ { + dest[offset] = p.Unknown11[i] + offset++ + } + + // Write SogaRaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.SogaRaceType)) + offset += 2 + + // Write SogaSkinColorx + binary.LittleEndian.PutUint32(dest[offset:], p.SogaSkinColorx.ToUint32()) + offset += 4 + + // Write SogaEyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaEyeColor.ToUint32()) + offset += 4 + + // Write Unknown12 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown12[i] + offset++ + } + + // Write SogaEyeType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaEyeType[i]) + offset++ + } + + // Write SogaEarType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaEarType[i]) + offset++ + } + + // Write SogaEyeBrowType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaEyeBrowType[i]) + offset++ + } + + // Write SogaCheekType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaCheekType[i]) + offset++ + } + + // Write SogaLipType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaLipType[i]) + offset++ + } + + // Write SogaChinType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaChinType[i]) + offset++ + } + + // Write SogaNoseType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaNoseType[i]) + offset++ + } + + // Write SogaHairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor1.ToUint32()) + offset += 4 + + // Write SogaChestType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.SogaChestType)) + offset += 2 + + // Write SogaHairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor2.ToUint32()) + offset += 4 + + // Write SogaHairColor3 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor3.ToUint32()) + offset += 4 + + // Write SogaHairType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.SogaHairType)) + offset += 2 + + // Write SogaHairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeColor.ToUint32()) + offset += 4 + + // Write SogaHairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.SogaHairFaceType)) + offset += 2 + + // Write SogaHairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceHighlightColor.ToUint32()) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *CharSelectProfileV546) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Zone)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Zonename2)) + + size += 2 + uint32(len(p.Zonedesc)) + + size += 4 + + size += 1 + + size += 2 + + size += 3 + + size += 3 + + size += 23 * 6 + + size += 2 + + size += 3 + + size += 3 + + size += 2 + + size += 3 + + size += 3 + + size += 2 + + size += 3 + + size += 3 + + size += 2 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 1 + + size += 1 + + size += 2 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 10 + + size += 2 + + size += 4 + + size += 4 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + return size +} + +// CharSelectProfileV562 represents packet structure for client version 562 +type CharSelectProfileV562 struct { + Version uint32 `eq2:"version"` + Charid uint32 `eq2:"charid"` + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Unknown uint8 `eq2:"unknown"` // TODO: Identify purpose + Race uint8 `eq2:"race"` + Class uint8 `eq2:"class"` + Gender uint8 `eq2:"gender"` + Level uint32 `eq2:"level"` + Zone string `eq2:"zone,type:str16"` + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + Unknown2 uint32 `eq2:"unknown2"` // TODO: Identify purpose + CreatedDate uint32 `eq2:"created_date"` + LastPlayed uint32 `eq2:"last_played"` + Unknown3 uint32 `eq2:"unknown3"` // TODO: Identify purpose + Unknown4 uint32 `eq2:"unknown4"` // TODO: Identify purpose + Zonename2 string `eq2:"zonename2,type:str16"` + Zonedesc string `eq2:"zonedesc,type:str16"` + Unknown5 uint32 `eq2:"unknown5"` // TODO: Identify purpose + ServerName string `eq2:"server_name,type:str16"` + AccountId uint32 `eq2:"account_id"` + Unknown6 [2]uint8 `eq2:"unknown6,size:2"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + Unknown8 uint8 `eq2:"unknown8"` // TODO: Identify purpose + RaceType uint16 `eq2:"race_type"` + SkinColor types.Color `eq2:"skin_color"` + EyeColor types.Color `eq2:"eye_color"` + Equip [25]types.EquipmentItem `eq2:"equip,size:25"` + HairType uint16 `eq2:"hair_type"` + HairTypeColor types.Color `eq2:"hair_type_color"` + HairTypeHighlightColor types.Color `eq2:"hair_type_highlight_color"` + HairFaceType uint16 `eq2:"hair_face_type"` + HairFaceColor types.Color `eq2:"hair_face_color"` + HairFaceHighlightColor types.Color `eq2:"hair_face_highlight_color"` + ChestType uint16 `eq2:"chest_type"` + ShirtColor types.Color `eq2:"shirt_color"` + UnknownChestColor types.Color `eq2:"unknown_chest_color"` // TODO: Identify purpose + LegsType uint16 `eq2:"legs_type"` + PantsColor types.Color `eq2:"pants_color"` + UnknownLegsColor types.Color `eq2:"unknown_legs_color"` // TODO: Identify purpose + Unknown9 types.Color `eq2:"unknown9"` // TODO: Identify purpose + EyeType [3]int8 `eq2:"eye_type,size:3"` + EarType [3]int8 `eq2:"ear_type,size:3"` + EyeBrowType [3]int8 `eq2:"eye_brow_type,size:3"` + CheekType [3]int8 `eq2:"cheek_type,size:3"` + LipType [3]int8 `eq2:"lip_type,size:3"` + ChinType [3]int8 `eq2:"chin_type,size:3"` + NoseType [3]int8 `eq2:"nose_type,size:3"` + BodySize int8 `eq2:"body_size"` + Unknown10 [9]uint8 `eq2:"unknown10,size:9"` // TODO: Identify purpose + HairColor1 types.Color `eq2:"hair_color1"` + HairColor2 types.Color `eq2:"hair_color2"` + Unknown11 [13]uint8 `eq2:"unknown11,size:13"` // TODO: Identify purpose + Unknown15 [7]uint8 `eq2:"unknown15,size:7"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *CharSelectProfileV562) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Version + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Version)) + offset += 4 + + // Write Charid + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Charid)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Unknown + dest[offset] = byte(p.Unknown) + offset++ + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Level + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Level)) + offset += 4 + + // Write Zone as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zone))) + offset += 2 + copy(dest[offset:], []byte(p.Zone)) + offset += uint32(len(p.Zone)) + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write Unknown2 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown2)) + offset += 4 + + // Write CreatedDate + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CreatedDate)) + offset += 4 + + // Write LastPlayed + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.LastPlayed)) + offset += 4 + + // Write Unknown3 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown3)) + offset += 4 + + // Write Unknown4 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown4)) + offset += 4 + + // Write Zonename2 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonename2))) + offset += 2 + copy(dest[offset:], []byte(p.Zonename2)) + offset += uint32(len(p.Zonename2)) + + // Write Zonedesc as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonedesc))) + offset += 2 + copy(dest[offset:], []byte(p.Zonedesc)) + offset += uint32(len(p.Zonedesc)) + + // Write Unknown5 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown5)) + offset += 4 + + // Write ServerName as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ServerName))) + offset += 2 + copy(dest[offset:], []byte(p.ServerName)) + offset += uint32(len(p.ServerName)) + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown6 array + for i := 0; i < 2; i++ { + dest[offset] = p.Unknown6[i] + offset++ + } + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write Unknown8 + dest[offset] = byte(p.Unknown8) + offset++ + + // Write RaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.RaceType)) + offset += 2 + + // Write SkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor.ToUint32()) + offset += 4 + + // Write EyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.EyeColor.ToUint32()) + offset += 4 + + // Write Equip array + for i := 0; i < 25; i++ { + binary.LittleEndian.PutUint16(dest[offset:], p.Equip[i].Type) + offset += 2 + binary.LittleEndian.PutUint32(dest[offset:], p.Equip[i].Color.ToUint32()) + offset += 4 + } + + // Write HairType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairType)) + offset += 2 + + // Write HairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeColor.ToUint32()) + offset += 4 + + // Write HairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write HairFaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairFaceType)) + offset += 2 + + // Write HairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceColor.ToUint32()) + offset += 4 + + // Write HairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write ChestType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.ChestType)) + offset += 2 + + // Write ShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.ShirtColor.ToUint32()) + offset += 4 + + // Write UnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownChestColor.ToUint32()) + offset += 4 + + // Write LegsType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.LegsType)) + offset += 2 + + // Write PantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.PantsColor.ToUint32()) + offset += 4 + + // Write UnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownLegsColor.ToUint32()) + offset += 4 + + // Write Unknown9 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown9.ToUint32()) + offset += 4 + + // Write EyeType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeType[i]) + offset++ + } + + // Write EarType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EarType[i]) + offset++ + } + + // Write EyeBrowType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeBrowType[i]) + offset++ + } + + // Write CheekType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.CheekType[i]) + offset++ + } + + // Write LipType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.LipType[i]) + offset++ + } + + // Write ChinType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.ChinType[i]) + offset++ + } + + // Write NoseType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.NoseType[i]) + offset++ + } + + // Write BodySize + dest[offset] = byte(p.BodySize) + offset++ + + // Write Unknown10 array + for i := 0; i < 9; i++ { + dest[offset] = p.Unknown10[i] + offset++ + } + + // Write HairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor1.ToUint32()) + offset += 4 + + // Write HairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor2.ToUint32()) + offset += 4 + + // Write Unknown11 array + for i := 0; i < 13; i++ { + dest[offset] = p.Unknown11[i] + offset++ + } + + // Write Unknown15 array + for i := 0; i < 7; i++ { + dest[offset] = p.Unknown15[i] + offset++ + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *CharSelectProfileV562) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Zone)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Zonename2)) + + size += 2 + uint32(len(p.Zonedesc)) + + size += 4 + + size += 2 + uint32(len(p.ServerName)) + + size += 4 + + size += 2 + + size += 4 + + size += 1 + + size += 2 + + size += 4 + + size += 4 + + size += 25 * 6 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 4 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 1 + + size += 9 + + size += 4 + + size += 4 + + size += 13 + + size += 7 + + return size +} + +// CharSelectProfileV887 represents packet structure for client version 887 +type CharSelectProfileV887 struct { + Version uint32 `eq2:"version"` + Charid uint32 `eq2:"charid"` + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Unknown uint8 `eq2:"unknown"` // TODO: Identify purpose + Race uint8 `eq2:"race"` + Class uint8 `eq2:"class"` + Gender uint8 `eq2:"gender"` + Level uint32 `eq2:"level"` + Zone string `eq2:"zone,type:str16"` + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + Unknown2 uint32 `eq2:"unknown2"` // TODO: Identify purpose + CreatedDate uint32 `eq2:"created_date"` + LastPlayed uint32 `eq2:"last_played"` + Unknown3 uint32 `eq2:"unknown3"` // TODO: Identify purpose + Unknown4 uint32 `eq2:"unknown4"` // TODO: Identify purpose + Zonename2 string `eq2:"zonename2,type:str16"` + Zonedesc string `eq2:"zonedesc,type:str16"` + Unknown5 uint32 `eq2:"unknown5"` // TODO: Identify purpose + ServerName string `eq2:"server_name,type:str16"` + AccountId uint32 `eq2:"account_id"` + Unknown6 [2]uint8 `eq2:"unknown6,size:2"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + TradeskillClass uint8 `eq2:"tradeskill_class"` + TradeskillLevel uint32 `eq2:"tradeskill_level"` + Unknown8 uint8 `eq2:"unknown8"` // TODO: Identify purpose + RaceType uint16 `eq2:"race_type"` + SkinColor types.Color `eq2:"skin_color"` + EyeColor types.Color `eq2:"eye_color"` + Equip [25]types.EquipmentItem `eq2:"equip,size:25"` + HairType uint16 `eq2:"hair_type"` + HairTypeColor types.Color `eq2:"hair_type_color"` + HairTypeHighlightColor types.Color `eq2:"hair_type_highlight_color"` + HairFaceType uint16 `eq2:"hair_face_type"` + HairFaceColor types.Color `eq2:"hair_face_color"` + HairFaceHighlightColor types.Color `eq2:"hair_face_highlight_color"` + WingType uint16 `eq2:"wing_type"` + WingColor1 types.Color `eq2:"wing_color1"` + WingColor2 types.Color `eq2:"wing_color2"` + ChestType uint16 `eq2:"chest_type"` + ShirtColor types.Color `eq2:"shirt_color"` + UnknownChestColor types.Color `eq2:"unknown_chest_color"` // TODO: Identify purpose + LegsType uint16 `eq2:"legs_type"` + PantsColor types.Color `eq2:"pants_color"` + UnknownLegsColor types.Color `eq2:"unknown_legs_color"` // TODO: Identify purpose + Unknown9 types.Color `eq2:"unknown9"` // TODO: Identify purpose + EyeType [3]int8 `eq2:"eye_type,size:3"` + EarType [3]int8 `eq2:"ear_type,size:3"` + EyeBrowType [3]int8 `eq2:"eye_brow_type,size:3"` + CheekType [3]int8 `eq2:"cheek_type,size:3"` + LipType [3]int8 `eq2:"lip_type,size:3"` + ChinType [3]int8 `eq2:"chin_type,size:3"` + NoseType [3]int8 `eq2:"nose_type,size:3"` + BodySize int8 `eq2:"body_size"` + Unknown10 [9]uint8 `eq2:"unknown10,size:9"` // TODO: Identify purpose + HairColor1 types.Color `eq2:"hair_color1"` + HairColor2 types.Color `eq2:"hair_color2"` + Unknown11 [13]uint8 `eq2:"unknown11,size:13"` // TODO: Identify purpose + SogaRaceType uint16 `eq2:"soga_race_type"` + SogaSkinColor types.Color `eq2:"soga_skin_color"` + SogaEyeColor types.Color `eq2:"soga_eye_color"` + Unknown12 [3]uint8 `eq2:"Unknown12,size:3"` // TODO: Identify purpose + SogaEyeType [3]int8 `eq2:"soga_eye_type,size:3"` + SogaEarType [3]int8 `eq2:"soga_ear_type,size:3"` + SogaEyeBrowType [3]int8 `eq2:"soga_eye_brow_type,size:3"` + SogaCheekType [3]int8 `eq2:"soga_cheek_type,size:3"` + SogaLipType [3]int8 `eq2:"soga_lip_type,size:3"` + SogaChinType [3]int8 `eq2:"soga_chin_type,size:3"` + SogaNoseType [3]int8 `eq2:"soga_nose_type,size:3"` + Unknown13 uint16 `eq2:"unknown13"` // TODO: Identify purpose + SogaHairColor1 types.Color `eq2:"soga_hair_color1"` + SogaHairColor2 types.Color `eq2:"soga_hair_color2"` + Unknown14 types.Color `eq2:"unknown14"` // TODO: Identify purpose + SogaHairType uint16 `eq2:"soga_hair_type"` + SogaHairTypeColor types.Color `eq2:"soga_hair_type_color"` + SogaHairTypeHighlightColor types.Color `eq2:"soga_hair_type_highlight_color"` + SogaHairFaceType uint16 `eq2:"soga_hair_face_type"` + SogaHairFaceColor types.Color `eq2:"soga_hair_face_color"` + SogaHairFaceHighlightColor types.Color `eq2:"soga_hair_face_highlight_color"` + Unknown15 [7]uint8 `eq2:"unknown15,size:7"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *CharSelectProfileV887) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Version + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Version)) + offset += 4 + + // Write Charid + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Charid)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Unknown + dest[offset] = byte(p.Unknown) + offset++ + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Level + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Level)) + offset += 4 + + // Write Zone as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zone))) + offset += 2 + copy(dest[offset:], []byte(p.Zone)) + offset += uint32(len(p.Zone)) + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write Unknown2 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown2)) + offset += 4 + + // Write CreatedDate + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CreatedDate)) + offset += 4 + + // Write LastPlayed + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.LastPlayed)) + offset += 4 + + // Write Unknown3 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown3)) + offset += 4 + + // Write Unknown4 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown4)) + offset += 4 + + // Write Zonename2 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonename2))) + offset += 2 + copy(dest[offset:], []byte(p.Zonename2)) + offset += uint32(len(p.Zonename2)) + + // Write Zonedesc as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonedesc))) + offset += 2 + copy(dest[offset:], []byte(p.Zonedesc)) + offset += uint32(len(p.Zonedesc)) + + // Write Unknown5 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown5)) + offset += 4 + + // Write ServerName as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ServerName))) + offset += 2 + copy(dest[offset:], []byte(p.ServerName)) + offset += uint32(len(p.ServerName)) + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown6 array + for i := 0; i < 2; i++ { + dest[offset] = p.Unknown6[i] + offset++ + } + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write TradeskillClass + dest[offset] = byte(p.TradeskillClass) + offset++ + + // Write TradeskillLevel + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.TradeskillLevel)) + offset += 4 + + // Write Unknown8 + dest[offset] = byte(p.Unknown8) + offset++ + + // Write RaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.RaceType)) + offset += 2 + + // Write SkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor.ToUint32()) + offset += 4 + + // Write EyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.EyeColor.ToUint32()) + offset += 4 + + // Write Equip array + for i := 0; i < 25; i++ { + binary.LittleEndian.PutUint16(dest[offset:], p.Equip[i].Type) + offset += 2 + binary.LittleEndian.PutUint32(dest[offset:], p.Equip[i].Color.ToUint32()) + offset += 4 + } + + // Write HairType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairType)) + offset += 2 + + // Write HairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeColor.ToUint32()) + offset += 4 + + // Write HairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write HairFaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairFaceType)) + offset += 2 + + // Write HairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceColor.ToUint32()) + offset += 4 + + // Write HairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write WingType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.WingType)) + offset += 2 + + // Write WingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor1.ToUint32()) + offset += 4 + + // Write WingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor2.ToUint32()) + offset += 4 + + // Write ChestType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.ChestType)) + offset += 2 + + // Write ShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.ShirtColor.ToUint32()) + offset += 4 + + // Write UnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownChestColor.ToUint32()) + offset += 4 + + // Write LegsType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.LegsType)) + offset += 2 + + // Write PantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.PantsColor.ToUint32()) + offset += 4 + + // Write UnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownLegsColor.ToUint32()) + offset += 4 + + // Write Unknown9 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown9.ToUint32()) + offset += 4 + + // Write EyeType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeType[i]) + offset++ + } + + // Write EarType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EarType[i]) + offset++ + } + + // Write EyeBrowType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeBrowType[i]) + offset++ + } + + // Write CheekType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.CheekType[i]) + offset++ + } + + // Write LipType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.LipType[i]) + offset++ + } + + // Write ChinType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.ChinType[i]) + offset++ + } + + // Write NoseType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.NoseType[i]) + offset++ + } + + // Write BodySize + dest[offset] = byte(p.BodySize) + offset++ + + // Write Unknown10 array + for i := 0; i < 9; i++ { + dest[offset] = p.Unknown10[i] + offset++ + } + + // Write HairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor1.ToUint32()) + offset += 4 + + // Write HairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor2.ToUint32()) + offset += 4 + + // Write Unknown11 array + for i := 0; i < 13; i++ { + dest[offset] = p.Unknown11[i] + offset++ + } + + // Write SogaRaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.SogaRaceType)) + offset += 2 + + // Write SogaSkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaSkinColor.ToUint32()) + offset += 4 + + // Write SogaEyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaEyeColor.ToUint32()) + offset += 4 + + // Write Unknown12 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown12[i] + offset++ + } + + // Write SogaEyeType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaEyeType[i]) + offset++ + } + + // Write SogaEarType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaEarType[i]) + offset++ + } + + // Write SogaEyeBrowType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaEyeBrowType[i]) + offset++ + } + + // Write SogaCheekType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaCheekType[i]) + offset++ + } + + // Write SogaLipType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaLipType[i]) + offset++ + } + + // Write SogaChinType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaChinType[i]) + offset++ + } + + // Write SogaNoseType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaNoseType[i]) + offset++ + } + + // Write Unknown13 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown13)) + offset += 2 + + // Write SogaHairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor1.ToUint32()) + offset += 4 + + // Write SogaHairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor2.ToUint32()) + offset += 4 + + // Write Unknown14 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown14.ToUint32()) + offset += 4 + + // Write SogaHairType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.SogaHairType)) + offset += 2 + + // Write SogaHairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeColor.ToUint32()) + offset += 4 + + // Write SogaHairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.SogaHairFaceType)) + offset += 2 + + // Write SogaHairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write Unknown15 array + for i := 0; i < 7; i++ { + dest[offset] = p.Unknown15[i] + offset++ + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *CharSelectProfileV887) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Zone)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Zonename2)) + + size += 2 + uint32(len(p.Zonedesc)) + + size += 4 + + size += 2 + uint32(len(p.ServerName)) + + size += 4 + + size += 2 + + size += 4 + + size += 1 + + size += 4 + + size += 1 + + size += 2 + + size += 4 + + size += 4 + + size += 25 * 6 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 4 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 1 + + size += 9 + + size += 4 + + size += 4 + + size += 13 + + size += 2 + + size += 4 + + size += 4 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 2 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 7 + + return size +} + +// CharSelectProfileV60085 represents packet structure for client version 60085 +type CharSelectProfileV60085 struct { + Version uint32 `eq2:"version"` + Charid uint32 `eq2:"charid"` + ServerId uint32 `eq2:"server_id"` + Name string `eq2:"name,type:str16"` + Unknown uint8 `eq2:"unknown"` // TODO: Identify purpose + Race uint8 `eq2:"race"` + Class uint8 `eq2:"class"` + Gender uint8 `eq2:"gender"` + Level uint32 `eq2:"level"` + Zone string `eq2:"zone,type:str16"` + Unknown1 uint32 `eq2:"unknown1"` // TODO: Identify purpose + Unknown2 uint32 `eq2:"unknown2"` // TODO: Identify purpose + CreatedDate uint32 `eq2:"created_date"` + LastPlayed uint32 `eq2:"last_played"` + Unknown3 uint32 `eq2:"unknown3"` // TODO: Identify purpose + Unknown4 uint32 `eq2:"unknown4"` // TODO: Identify purpose + Zonename2 string `eq2:"zonename2,type:str16"` + Zonedesc string `eq2:"zonedesc,type:str16"` + Unknown5 uint32 `eq2:"unknown5"` // TODO: Identify purpose + ServerName string `eq2:"server_name,type:str16"` + AccountId uint32 `eq2:"account_id"` + Unknown6 [2]uint8 `eq2:"unknown6,size:2"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + TradeskillClass uint8 `eq2:"tradeskill_class"` + TradeskillLevel uint32 `eq2:"tradeskill_level"` + Unknown8 uint8 `eq2:"unknown8"` // TODO: Identify purpose + RaceType uint16 `eq2:"race_type"` + SkinColor types.Color `eq2:"skin_color"` + EyeColor types.Color `eq2:"eye_color"` + Equip [25]types.EquipmentItem `eq2:"equip,size:25"` + HairType uint16 `eq2:"hair_type"` + HairTypeColor types.Color `eq2:"hair_type_color"` + HairTypeHighlightColor types.Color `eq2:"hair_type_highlight_color"` + HairFaceType uint16 `eq2:"hair_face_type"` + HairFaceColor types.Color `eq2:"hair_face_color"` + HairFaceHighlightColor types.Color `eq2:"hair_face_highlight_color"` + WingType uint16 `eq2:"wing_type"` + WingColor1 types.Color `eq2:"wing_color1"` + WingColor2 types.Color `eq2:"wing_color2"` + ChestType uint16 `eq2:"chest_type"` + ShirtColor types.Color `eq2:"shirt_color"` + UnknownChestColor types.Color `eq2:"unknown_chest_color"` // TODO: Identify purpose + LegsType uint16 `eq2:"legs_type"` + PantsColor types.Color `eq2:"pants_color"` + UnknownLegsColor types.Color `eq2:"unknown_legs_color"` // TODO: Identify purpose + Unknown9 types.Color `eq2:"unknown9"` // TODO: Identify purpose + EyeType [3]int8 `eq2:"eye_type,size:3"` + EarType [3]int8 `eq2:"ear_type,size:3"` + EyeBrowType [3]int8 `eq2:"eye_brow_type,size:3"` + CheekType [3]int8 `eq2:"cheek_type,size:3"` + LipType [3]int8 `eq2:"lip_type,size:3"` + ChinType [3]int8 `eq2:"chin_type,size:3"` + NoseType [3]int8 `eq2:"nose_type,size:3"` + BodySize int8 `eq2:"body_size"` + Unknown10 [9]uint8 `eq2:"unknown10,size:9"` // TODO: Identify purpose + HairColor1 types.Color `eq2:"hair_color1"` + HairColor2 types.Color `eq2:"hair_color2"` + Unknown11 [13]uint8 `eq2:"unknown11,size:13"` // TODO: Identify purpose + SogaRaceType uint16 `eq2:"soga_race_type"` + SogaSkinColor types.Color `eq2:"soga_skin_color"` + SogaEyeColor types.Color `eq2:"soga_eye_color"` + Unknown12 [3]uint8 `eq2:"Unknown12,size:3"` // TODO: Identify purpose + SogaEyeType [3]int8 `eq2:"soga_eye_type,size:3"` + SogaEarType [3]int8 `eq2:"soga_ear_type,size:3"` + SogaEyeBrowType [3]int8 `eq2:"soga_eye_brow_type,size:3"` + SogaCheekType [3]int8 `eq2:"soga_cheek_type,size:3"` + SogaLipType [3]int8 `eq2:"soga_lip_type,size:3"` + SogaChinType [3]int8 `eq2:"soga_chin_type,size:3"` + SogaNoseType [3]int8 `eq2:"soga_nose_type,size:3"` + Unknown13 uint16 `eq2:"unknown13"` // TODO: Identify purpose + SogaHairColor1 types.Color `eq2:"soga_hair_color1"` + SogaHairColor2 types.Color `eq2:"soga_hair_color2"` + Unknown14 types.Color `eq2:"unknown14"` // TODO: Identify purpose + SogaHairType uint16 `eq2:"soga_hair_type"` + SogaHairTypeColor types.Color `eq2:"soga_hair_type_color"` + SogaHairTypeHighlightColor types.Color `eq2:"soga_hair_type_highlight_color"` + SogaHairFaceType uint16 `eq2:"soga_hair_face_type"` + SogaHairFaceColor types.Color `eq2:"soga_hair_face_color"` + SogaHairFaceHighlightColor types.Color `eq2:"soga_hair_face_highlight_color"` + Unknown15 [7]uint8 `eq2:"unknown15,size:7"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *CharSelectProfileV60085) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write Version + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Version)) + offset += 4 + + // Write Charid + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Charid)) + offset += 4 + + // Write ServerId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ServerId)) + offset += 4 + + // Write Name as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Name))) + offset += 2 + copy(dest[offset:], []byte(p.Name)) + offset += uint32(len(p.Name)) + + // Write Unknown + dest[offset] = byte(p.Unknown) + offset++ + + // Write Race + dest[offset] = byte(p.Race) + offset++ + + // Write Class + dest[offset] = byte(p.Class) + offset++ + + // Write Gender + dest[offset] = byte(p.Gender) + offset++ + + // Write Level + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Level)) + offset += 4 + + // Write Zone as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zone))) + offset += 2 + copy(dest[offset:], []byte(p.Zone)) + offset += uint32(len(p.Zone)) + + // Write Unknown1 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown1)) + offset += 4 + + // Write Unknown2 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown2)) + offset += 4 + + // Write CreatedDate + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CreatedDate)) + offset += 4 + + // Write LastPlayed + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.LastPlayed)) + offset += 4 + + // Write Unknown3 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown3)) + offset += 4 + + // Write Unknown4 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown4)) + offset += 4 + + // Write Zonename2 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonename2))) + offset += 2 + copy(dest[offset:], []byte(p.Zonename2)) + offset += uint32(len(p.Zonename2)) + + // Write Zonedesc as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Zonedesc))) + offset += 2 + copy(dest[offset:], []byte(p.Zonedesc)) + offset += uint32(len(p.Zonedesc)) + + // Write Unknown5 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown5)) + offset += 4 + + // Write ServerName as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.ServerName))) + offset += 2 + copy(dest[offset:], []byte(p.ServerName)) + offset += uint32(len(p.ServerName)) + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown6 array + for i := 0; i < 2; i++ { + dest[offset] = p.Unknown6[i] + offset++ + } + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write TradeskillClass + dest[offset] = byte(p.TradeskillClass) + offset++ + + // Write TradeskillLevel + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.TradeskillLevel)) + offset += 4 + + // Write Unknown8 + dest[offset] = byte(p.Unknown8) + offset++ + + // Write RaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.RaceType)) + offset += 2 + + // Write SkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SkinColor.ToUint32()) + offset += 4 + + // Write EyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.EyeColor.ToUint32()) + offset += 4 + + // Write Equip array + for i := 0; i < 25; i++ { + binary.LittleEndian.PutUint16(dest[offset:], p.Equip[i].Type) + offset += 2 + binary.LittleEndian.PutUint32(dest[offset:], p.Equip[i].Color.ToUint32()) + offset += 4 + } + + // Write HairType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairType)) + offset += 2 + + // Write HairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeColor.ToUint32()) + offset += 4 + + // Write HairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write HairFaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.HairFaceType)) + offset += 2 + + // Write HairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceColor.ToUint32()) + offset += 4 + + // Write HairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.HairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write WingType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.WingType)) + offset += 2 + + // Write WingColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor1.ToUint32()) + offset += 4 + + // Write WingColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.WingColor2.ToUint32()) + offset += 4 + + // Write ChestType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.ChestType)) + offset += 2 + + // Write ShirtColor + binary.LittleEndian.PutUint32(dest[offset:], p.ShirtColor.ToUint32()) + offset += 4 + + // Write UnknownChestColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownChestColor.ToUint32()) + offset += 4 + + // Write LegsType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.LegsType)) + offset += 2 + + // Write PantsColor + binary.LittleEndian.PutUint32(dest[offset:], p.PantsColor.ToUint32()) + offset += 4 + + // Write UnknownLegsColor + binary.LittleEndian.PutUint32(dest[offset:], p.UnknownLegsColor.ToUint32()) + offset += 4 + + // Write Unknown9 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown9.ToUint32()) + offset += 4 + + // Write EyeType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeType[i]) + offset++ + } + + // Write EarType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EarType[i]) + offset++ + } + + // Write EyeBrowType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.EyeBrowType[i]) + offset++ + } + + // Write CheekType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.CheekType[i]) + offset++ + } + + // Write LipType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.LipType[i]) + offset++ + } + + // Write ChinType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.ChinType[i]) + offset++ + } + + // Write NoseType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.NoseType[i]) + offset++ + } + + // Write BodySize + dest[offset] = byte(p.BodySize) + offset++ + + // Write Unknown10 array + for i := 0; i < 9; i++ { + dest[offset] = p.Unknown10[i] + offset++ + } + + // Write HairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor1.ToUint32()) + offset += 4 + + // Write HairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.HairColor2.ToUint32()) + offset += 4 + + // Write Unknown11 array + for i := 0; i < 13; i++ { + dest[offset] = p.Unknown11[i] + offset++ + } + + // Write SogaRaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.SogaRaceType)) + offset += 2 + + // Write SogaSkinColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaSkinColor.ToUint32()) + offset += 4 + + // Write SogaEyeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaEyeColor.ToUint32()) + offset += 4 + + // Write Unknown12 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown12[i] + offset++ + } + + // Write SogaEyeType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaEyeType[i]) + offset++ + } + + // Write SogaEarType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaEarType[i]) + offset++ + } + + // Write SogaEyeBrowType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaEyeBrowType[i]) + offset++ + } + + // Write SogaCheekType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaCheekType[i]) + offset++ + } + + // Write SogaLipType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaLipType[i]) + offset++ + } + + // Write SogaChinType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaChinType[i]) + offset++ + } + + // Write SogaNoseType array + for i := 0; i < 3; i++ { + dest[offset] = byte(p.SogaNoseType[i]) + offset++ + } + + // Write Unknown13 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown13)) + offset += 2 + + // Write SogaHairColor1 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor1.ToUint32()) + offset += 4 + + // Write SogaHairColor2 + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairColor2.ToUint32()) + offset += 4 + + // Write Unknown14 + binary.LittleEndian.PutUint32(dest[offset:], p.Unknown14.ToUint32()) + offset += 4 + + // Write SogaHairType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.SogaHairType)) + offset += 2 + + // Write SogaHairTypeColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeColor.ToUint32()) + offset += 4 + + // Write SogaHairTypeHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairTypeHighlightColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceType + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.SogaHairFaceType)) + offset += 2 + + // Write SogaHairFaceColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceColor.ToUint32()) + offset += 4 + + // Write SogaHairFaceHighlightColor + binary.LittleEndian.PutUint32(dest[offset:], p.SogaHairFaceHighlightColor.ToUint32()) + offset += 4 + + // Write Unknown15 array + for i := 0; i < 7; i++ { + dest[offset] = p.Unknown15[i] + offset++ + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *CharSelectProfileV60085) Size() uint32 { + size := uint32(0) + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Name)) + + size += 1 + + size += 1 + + size += 1 + + size += 1 + + size += 4 + + size += 2 + uint32(len(p.Zone)) + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Zonename2)) + + size += 2 + uint32(len(p.Zonedesc)) + + size += 4 + + size += 2 + uint32(len(p.ServerName)) + + size += 4 + + size += 2 + + size += 4 + + size += 1 + + size += 4 + + size += 1 + + size += 2 + + size += 4 + + size += 4 + + size += 25 * 6 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 4 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 1 + + size += 9 + + size += 4 + + size += 4 + + size += 13 + + size += 2 + + size += 4 + + size += 4 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 3 + + size += 2 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 2 + + size += 4 + + size += 4 + + size += 7 + + return size +} + +// LSLoginReplyMsg represents packet structure for OP_LoginReplyMsg +type LSLoginReplyMsg struct { + LoginResponse uint8 `eq2:"login_response"` + WorldName string `eq2:"worldName,type:str16"` + ParentalControlFlag uint8 `eq2:"parental_control_flag"` + ParentalControlTimer [2]uint32 `eq2:"parental_control_timer,size:2"` + ParentalControlNext uint32 `eq2:"parental_control_next"` + AccountId uint32 `eq2:"account_id"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginReplyMsg) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write LoginResponse + dest[offset] = byte(p.LoginResponse) + offset++ + + // Write WorldName as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.WorldName))) + offset += 2 + copy(dest[offset:], []byte(p.WorldName)) + offset += uint32(len(p.WorldName)) + + // Write ParentalControlFlag + dest[offset] = byte(p.ParentalControlFlag) + offset++ + + // Write ParentalControlTimer array + for i := 0; i < 2; i++ { + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ParentalControlTimer[i])) + offset += 4 + } + + // Write ParentalControlNext + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ParentalControlNext)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginReplyMsg) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + uint32(len(p.WorldName)) + + size += 1 + + size += 2 * 4 + + size += 4 + + size += 4 + + return size +} + +// LSLoginReplyMsgV284 represents packet structure for OP_LoginReplyMsg +type LSLoginReplyMsgV284 struct { + LoginResponse uint8 `eq2:"login_response"` + Unknown string `eq2:"unknown,type:str16"` // TODO: Identify purpose + ParentalControlFlag uint8 `eq2:"parental_control_flag"` + ParentalControlTimer uint32 `eq2:"parental_control_timer"` + Unknown2 [8]uint8 `eq2:"unknown2,size:8"` // TODO: Identify purpose + CacheSettingAccountId uint32 `eq2:"cache_setting_account_id"` + Unknown3 string `eq2:"unknown3,type:str16"` // TODO: Identify purpose + ResetAppearance uint8 `eq2:"reset_appearance"` + DoNotForceSoga uint8 `eq2:"do_not_force_soga"` + Unknown5 uint16 `eq2:"unknown5"` // TODO: Identify purpose + Unknown6 uint8 `eq2:"unknown6"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + Unknown8 [2]uint8 `eq2:"unknown8,size:2"` // TODO: Identify purpose + Unknown10 uint8 `eq2:"unknown10"` // TODO: Identify purpose + NumClassItems uint8 `eq2:"num_class_items,ifSet:unknown10"` + ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint16 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"class_items,sizeVar:num_class_items,ifSet:unknown10"` + UnknownArray2Size uint8 `eq2:"unknown_array2_size"` // TODO: Identify purpose + UnknownArray2 []struct { + Array2Unknown uint32 `eq2:"array2_unknown"` + } `eq2:"unknown_array2,sizeVar:unknown_array2_size"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginReplyMsgV284) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write LoginResponse + dest[offset] = byte(p.LoginResponse) + offset++ + + // Write Unknown as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown)) + offset += uint32(len(p.Unknown)) + + // Write ParentalControlFlag + dest[offset] = byte(p.ParentalControlFlag) + offset++ + + // Write ParentalControlTimer + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ParentalControlTimer)) + offset += 4 + + // Write Unknown2 array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write CacheSettingAccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.CacheSettingAccountId)) + offset += 4 + + // Write Unknown3 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown3))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown3)) + offset += uint32(len(p.Unknown3)) + + // Write ResetAppearance + dest[offset] = byte(p.ResetAppearance) + offset++ + + // Write DoNotForceSoga + dest[offset] = byte(p.DoNotForceSoga) + offset++ + + // Write Unknown5 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown5)) + offset += 2 + + // Write Unknown6 + dest[offset] = byte(p.Unknown6) + offset++ + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write Unknown8 array + for i := 0; i < 2; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write Unknown10 + dest[offset] = byte(p.Unknown10) + offset++ + + // Write NumClassItems + dest[offset] = byte(p.NumClassItems) + offset++ + + // Write ClassItems array (dynamic size) + for _, elem := range p.ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint16(dest[offset:], nestedElem.ModelId) + offset += 2 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write UnknownArray2Size + dest[offset] = byte(p.UnknownArray2Size) + offset++ + + // Write UnknownArray2 array (dynamic size) + for _, elem := range p.UnknownArray2 { + binary.LittleEndian.PutUint32(dest[offset:], elem.Array2Unknown) + offset += 4 + + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginReplyMsgV284) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + uint32(len(p.Unknown)) + + size += 1 + + size += 4 + + size += 8 + + size += 4 + + size += 2 + uint32(len(p.Unknown3)) + + size += 1 + + size += 1 + + size += 2 + + size += 1 + + size += 4 + + size += 2 + + size += 1 + + size += 1 + + // Dynamic array: ClassItems + for _, elem := range p.ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 2 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + // Dynamic array: UnknownArray2 + for _, elem := range p.UnknownArray2 { + _ = elem // Avoid unused variable warning + size += 4 + + } + + return size +} + +// LSLoginReplyMsgV843 represents packet structure for OP_LoginReplyMsg +type LSLoginReplyMsgV843 struct { + LoginResponse uint8 `eq2:"login_response"` + Unknown string `eq2:"unknown,type:str16"` // TODO: Identify purpose + ParentalControlFlag uint8 `eq2:"parental_control_flag"` + ParentalControlTimer uint32 `eq2:"parental_control_timer"` + Unknown2 [8]uint8 `eq2:"unknown2,size:8"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 string `eq2:"unknown3,type:str16"` // TODO: Identify purpose + ResetAppearance uint8 `eq2:"reset_appearance"` + DoNotForceSoga uint8 `eq2:"do_not_force_soga"` + Unknown4 uint8 `eq2:"unknown4"` // TODO: Identify purpose + Unknown5 uint16 `eq2:"unknown5"` // TODO: Identify purpose + Unknown6 uint8 `eq2:"unknown6"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + RaceUnknown uint8 `eq2:"race_unknown"` + Unknown8 [3]uint8 `eq2:"unknown8,size:3"` // TODO: Identify purpose + Unknown9 uint8 `eq2:"unknown9"` // TODO: Identify purpose + Unknown10 uint8 `eq2:"unknown10"` // TODO: Identify purpose + NumClassItems uint8 `eq2:"num_class_items,ifSet:unknown10"` + ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint16 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"class_items,sizeVar:num_class_items,ifSet:unknown10"` + UnknownArray2Size uint8 `eq2:"unknown_array2_size"` // TODO: Identify purpose + UnknownArray2 []struct { + Array2Unknown uint32 `eq2:"array2_unknown"` + } `eq2:"unknown_array2,sizeVar:unknown_array2_size"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginReplyMsgV843) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write LoginResponse + dest[offset] = byte(p.LoginResponse) + offset++ + + // Write Unknown as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown)) + offset += uint32(len(p.Unknown)) + + // Write ParentalControlFlag + dest[offset] = byte(p.ParentalControlFlag) + offset++ + + // Write ParentalControlTimer + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ParentalControlTimer)) + offset += 4 + + // Write Unknown2 array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown3))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown3)) + offset += uint32(len(p.Unknown3)) + + // Write ResetAppearance + dest[offset] = byte(p.ResetAppearance) + offset++ + + // Write DoNotForceSoga + dest[offset] = byte(p.DoNotForceSoga) + offset++ + + // Write Unknown4 + dest[offset] = byte(p.Unknown4) + offset++ + + // Write Unknown5 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown5)) + offset += 2 + + // Write Unknown6 + dest[offset] = byte(p.Unknown6) + offset++ + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write RaceUnknown + dest[offset] = byte(p.RaceUnknown) + offset++ + + // Write Unknown8 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write Unknown9 + dest[offset] = byte(p.Unknown9) + offset++ + + // Write Unknown10 + dest[offset] = byte(p.Unknown10) + offset++ + + // Write NumClassItems + dest[offset] = byte(p.NumClassItems) + offset++ + + // Write ClassItems array (dynamic size) + for _, elem := range p.ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint16(dest[offset:], nestedElem.ModelId) + offset += 2 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write UnknownArray2Size + dest[offset] = byte(p.UnknownArray2Size) + offset++ + + // Write UnknownArray2 array (dynamic size) + for _, elem := range p.UnknownArray2 { + binary.LittleEndian.PutUint32(dest[offset:], elem.Array2Unknown) + offset += 4 + + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginReplyMsgV843) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + uint32(len(p.Unknown)) + + size += 1 + + size += 4 + + size += 8 + + size += 4 + + size += 2 + uint32(len(p.Unknown3)) + + size += 1 + + size += 1 + + size += 1 + + size += 2 + + size += 1 + + size += 4 + + size += 1 + + size += 3 + + size += 1 + + size += 1 + + size += 1 + + // Dynamic array: ClassItems + for _, elem := range p.ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 2 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + // Dynamic array: UnknownArray2 + for _, elem := range p.UnknownArray2 { + _ = elem // Avoid unused variable warning + size += 4 + + } + + return size +} + +// LSLoginReplyMsgV1096 represents packet structure for OP_LoginReplyMsg +type LSLoginReplyMsgV1096 struct { + LoginResponse uint8 `eq2:"login_response"` + Unknown string `eq2:"unknown,type:str16"` // TODO: Identify purpose + ParentalControlFlag uint8 `eq2:"parental_control_flag"` + ParentalControlTimer uint32 `eq2:"parental_control_timer"` + Unknown2 [8]uint8 `eq2:"unknown2,size:8"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 string `eq2:"unknown3,type:str16"` // TODO: Identify purpose + ResetAppearance uint8 `eq2:"reset_appearance"` + DoNotForceSoga uint8 `eq2:"do_not_force_soga"` + Unknown4 uint8 `eq2:"unknown4"` // TODO: Identify purpose + Unknown5 uint16 `eq2:"unknown5"` // TODO: Identify purpose + Unknown6 [5]uint8 `eq2:"unknown6,size:5"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + RaceUnknown uint8 `eq2:"race_unknown"` + Unknown8 [3]uint8 `eq2:"unknown8,size:3"` // TODO: Identify purpose + Unknown9 uint8 `eq2:"unknown9"` // TODO: Identify purpose + Unknown10 uint8 `eq2:"unknown10"` // TODO: Identify purpose + NumClassItems uint8 `eq2:"num_class_items,ifSet:unknown10"` + ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint16 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"class_items,sizeVar:num_class_items,ifSet:unknown10"` + UnknownArray2Size uint8 `eq2:"unknown_array2_size"` // TODO: Identify purpose + UnknownArray2 []struct { + Array2Unknown uint32 `eq2:"array2_unknown"` + } `eq2:"unknown_array2,sizeVar:unknown_array2_size"` + Unknown11 uint32 `eq2:"unknown11"` // TODO: Identify purpose + SubLevel uint32 `eq2:"sub_level"` + RaceFlag uint32 `eq2:"race_flag"` + ClassFlag uint32 `eq2:"class_flag"` + Password string `eq2:"password,type:str16"` + Username string `eq2:"username,type:str16"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginReplyMsgV1096) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write LoginResponse + dest[offset] = byte(p.LoginResponse) + offset++ + + // Write Unknown as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown)) + offset += uint32(len(p.Unknown)) + + // Write ParentalControlFlag + dest[offset] = byte(p.ParentalControlFlag) + offset++ + + // Write ParentalControlTimer + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ParentalControlTimer)) + offset += 4 + + // Write Unknown2 array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown3))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown3)) + offset += uint32(len(p.Unknown3)) + + // Write ResetAppearance + dest[offset] = byte(p.ResetAppearance) + offset++ + + // Write DoNotForceSoga + dest[offset] = byte(p.DoNotForceSoga) + offset++ + + // Write Unknown4 + dest[offset] = byte(p.Unknown4) + offset++ + + // Write Unknown5 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown5)) + offset += 2 + + // Write Unknown6 array + for i := 0; i < 5; i++ { + dest[offset] = p.Unknown6[i] + offset++ + } + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write RaceUnknown + dest[offset] = byte(p.RaceUnknown) + offset++ + + // Write Unknown8 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write Unknown9 + dest[offset] = byte(p.Unknown9) + offset++ + + // Write Unknown10 + dest[offset] = byte(p.Unknown10) + offset++ + + // Write NumClassItems + dest[offset] = byte(p.NumClassItems) + offset++ + + // Write ClassItems array (dynamic size) + for _, elem := range p.ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint16(dest[offset:], nestedElem.ModelId) + offset += 2 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write UnknownArray2Size + dest[offset] = byte(p.UnknownArray2Size) + offset++ + + // Write UnknownArray2 array (dynamic size) + for _, elem := range p.UnknownArray2 { + binary.LittleEndian.PutUint32(dest[offset:], elem.Array2Unknown) + offset += 4 + + } + + // Write Unknown11 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown11)) + offset += 4 + + // Write SubLevel + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.SubLevel)) + offset += 4 + + // Write RaceFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.RaceFlag)) + offset += 4 + + // Write ClassFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ClassFlag)) + offset += 4 + + // Write Password as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Password))) + offset += 2 + copy(dest[offset:], []byte(p.Password)) + offset += uint32(len(p.Password)) + + // Write Username as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Username))) + offset += 2 + copy(dest[offset:], []byte(p.Username)) + offset += uint32(len(p.Username)) + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginReplyMsgV1096) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + uint32(len(p.Unknown)) + + size += 1 + + size += 4 + + size += 8 + + size += 4 + + size += 2 + uint32(len(p.Unknown3)) + + size += 1 + + size += 1 + + size += 1 + + size += 2 + + size += 5 + + size += 4 + + size += 1 + + size += 3 + + size += 1 + + size += 1 + + size += 1 + + // Dynamic array: ClassItems + for _, elem := range p.ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 2 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + // Dynamic array: UnknownArray2 + for _, elem := range p.UnknownArray2 { + _ = elem // Avoid unused variable warning + size += 4 + + } + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Password)) + + size += 2 + uint32(len(p.Username)) + + return size +} + +// LSLoginReplyMsgV1142 represents packet structure for OP_LoginReplyMsg +type LSLoginReplyMsgV1142 struct { + LoginResponse uint8 `eq2:"login_response"` + Unknown string `eq2:"unknown,type:str16"` // TODO: Identify purpose + ParentalControlFlag uint8 `eq2:"parental_control_flag"` + ParentalControlTimer uint32 `eq2:"parental_control_timer"` + Unknown2 [8]uint8 `eq2:"unknown2,size:8"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 string `eq2:"unknown3,type:str16"` // TODO: Identify purpose + ResetAppearance uint8 `eq2:"reset_appearance"` + DoNotForceSoga uint8 `eq2:"do_not_force_soga"` + Unknown4 uint8 `eq2:"unknown4"` // TODO: Identify purpose + Unknown5 uint16 `eq2:"unknown5"` // TODO: Identify purpose + Unknown6 [5]uint8 `eq2:"unknown6,size:5"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + Unknown7a uint32 `eq2:"unknown7a"` // TODO: Identify purpose + RaceUnknown uint8 `eq2:"race_unknown"` + Unknown8 [3]uint8 `eq2:"unknown8,size:3"` // TODO: Identify purpose + Unknown9 uint8 `eq2:"unknown9"` // TODO: Identify purpose + Unknown10 uint8 `eq2:"unknown10"` // TODO: Identify purpose + NumClassItems uint8 `eq2:"num_class_items,ifSet:unknown10"` + ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint16 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"class_items,sizeVar:num_class_items,ifSet:unknown10"` + UnknownArray2Size uint8 `eq2:"unknown_array2_size"` // TODO: Identify purpose + UnknownArray2 []struct { + Array2Unknown uint32 `eq2:"array2_unknown"` + } `eq2:"unknown_array2,sizeVar:unknown_array2_size"` + Unknown11 uint32 `eq2:"unknown11"` // TODO: Identify purpose + SubLevel uint32 `eq2:"sub_level"` + RaceFlag uint32 `eq2:"race_flag"` + ClassFlag uint32 `eq2:"class_flag"` + Password string `eq2:"password,type:str16"` + Username string `eq2:"username,type:str16"` +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginReplyMsgV1142) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write LoginResponse + dest[offset] = byte(p.LoginResponse) + offset++ + + // Write Unknown as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown)) + offset += uint32(len(p.Unknown)) + + // Write ParentalControlFlag + dest[offset] = byte(p.ParentalControlFlag) + offset++ + + // Write ParentalControlTimer + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ParentalControlTimer)) + offset += 4 + + // Write Unknown2 array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown3))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown3)) + offset += uint32(len(p.Unknown3)) + + // Write ResetAppearance + dest[offset] = byte(p.ResetAppearance) + offset++ + + // Write DoNotForceSoga + dest[offset] = byte(p.DoNotForceSoga) + offset++ + + // Write Unknown4 + dest[offset] = byte(p.Unknown4) + offset++ + + // Write Unknown5 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown5)) + offset += 2 + + // Write Unknown6 array + for i := 0; i < 5; i++ { + dest[offset] = p.Unknown6[i] + offset++ + } + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write Unknown7a + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7a)) + offset += 4 + + // Write RaceUnknown + dest[offset] = byte(p.RaceUnknown) + offset++ + + // Write Unknown8 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write Unknown9 + dest[offset] = byte(p.Unknown9) + offset++ + + // Write Unknown10 + dest[offset] = byte(p.Unknown10) + offset++ + + // Write NumClassItems + dest[offset] = byte(p.NumClassItems) + offset++ + + // Write ClassItems array (dynamic size) + for _, elem := range p.ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint16(dest[offset:], nestedElem.ModelId) + offset += 2 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write UnknownArray2Size + dest[offset] = byte(p.UnknownArray2Size) + offset++ + + // Write UnknownArray2 array (dynamic size) + for _, elem := range p.UnknownArray2 { + binary.LittleEndian.PutUint32(dest[offset:], elem.Array2Unknown) + offset += 4 + + } + + // Write Unknown11 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown11)) + offset += 4 + + // Write SubLevel + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.SubLevel)) + offset += 4 + + // Write RaceFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.RaceFlag)) + offset += 4 + + // Write ClassFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ClassFlag)) + offset += 4 + + // Write Password as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Password))) + offset += 2 + copy(dest[offset:], []byte(p.Password)) + offset += uint32(len(p.Password)) + + // Write Username as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Username))) + offset += 2 + copy(dest[offset:], []byte(p.Username)) + offset += uint32(len(p.Username)) + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginReplyMsgV1142) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + uint32(len(p.Unknown)) + + size += 1 + + size += 4 + + size += 8 + + size += 4 + + size += 2 + uint32(len(p.Unknown3)) + + size += 1 + + size += 1 + + size += 1 + + size += 2 + + size += 5 + + size += 4 + + size += 4 + + size += 1 + + size += 3 + + size += 1 + + size += 1 + + size += 1 + + // Dynamic array: ClassItems + for _, elem := range p.ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 2 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + // Dynamic array: UnknownArray2 + for _, elem := range p.UnknownArray2 { + _ = elem // Avoid unused variable warning + size += 4 + + } + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Password)) + + size += 2 + uint32(len(p.Username)) + + return size +} + +// LSLoginReplyMsgV1188 represents packet structure for OP_LoginReplyMsg +type LSLoginReplyMsgV1188 struct { + LoginResponse uint8 `eq2:"login_response"` + Unknown string `eq2:"unknown,type:str16"` // TODO: Identify purpose + ParentalControlFlag uint8 `eq2:"parental_control_flag"` + ParentalControlTimer uint32 `eq2:"parental_control_timer"` + Unknown2 [8]uint8 `eq2:"unknown2,size:8"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 string `eq2:"unknown3,type:str16"` // TODO: Identify purpose + ResetAppearance uint8 `eq2:"reset_appearance"` + DoNotForceSoga uint8 `eq2:"do_not_force_soga"` + Unknown4 uint8 `eq2:"unknown4"` // TODO: Identify purpose + Unknown5 uint16 `eq2:"unknown5"` // TODO: Identify purpose + Unknown6 [5]uint8 `eq2:"unknown6,size:5"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + Unknown7a uint32 `eq2:"unknown7a"` // TODO: Identify purpose + RaceUnknown uint8 `eq2:"race_unknown"` + Unknown8 [3]uint8 `eq2:"unknown8,size:3"` // TODO: Identify purpose + Unknown9 uint8 `eq2:"unknown9"` // TODO: Identify purpose + Unknown10 uint8 `eq2:"unknown10"` // TODO: Identify purpose + NumClassItems uint8 `eq2:"num_class_items,ifSet:unknown10"` + ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint16 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"class_items,sizeVar:num_class_items,ifSet:unknown10"` + UnknownArray2Size uint8 `eq2:"unknown_array2_size"` // TODO: Identify purpose + UnknownArray2 []struct { + Array2Unknown uint32 `eq2:"array2_unknown"` + } `eq2:"unknown_array2,sizeVar:unknown_array2_size"` + Unknown11 uint32 `eq2:"unknown11"` // TODO: Identify purpose + SubLevel uint32 `eq2:"sub_level"` + RaceFlag uint32 `eq2:"race_flag"` + ClassFlag uint32 `eq2:"class_flag"` + Password string `eq2:"password,type:str16"` + Username string `eq2:"username,type:str16"` + Unknown12 string `eq2:"unknown12,type:str16"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginReplyMsgV1188) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write LoginResponse + dest[offset] = byte(p.LoginResponse) + offset++ + + // Write Unknown as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown)) + offset += uint32(len(p.Unknown)) + + // Write ParentalControlFlag + dest[offset] = byte(p.ParentalControlFlag) + offset++ + + // Write ParentalControlTimer + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ParentalControlTimer)) + offset += 4 + + // Write Unknown2 array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown3))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown3)) + offset += uint32(len(p.Unknown3)) + + // Write ResetAppearance + dest[offset] = byte(p.ResetAppearance) + offset++ + + // Write DoNotForceSoga + dest[offset] = byte(p.DoNotForceSoga) + offset++ + + // Write Unknown4 + dest[offset] = byte(p.Unknown4) + offset++ + + // Write Unknown5 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown5)) + offset += 2 + + // Write Unknown6 array + for i := 0; i < 5; i++ { + dest[offset] = p.Unknown6[i] + offset++ + } + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write Unknown7a + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7a)) + offset += 4 + + // Write RaceUnknown + dest[offset] = byte(p.RaceUnknown) + offset++ + + // Write Unknown8 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write Unknown9 + dest[offset] = byte(p.Unknown9) + offset++ + + // Write Unknown10 + dest[offset] = byte(p.Unknown10) + offset++ + + // Write NumClassItems + dest[offset] = byte(p.NumClassItems) + offset++ + + // Write ClassItems array (dynamic size) + for _, elem := range p.ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint16(dest[offset:], nestedElem.ModelId) + offset += 2 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write UnknownArray2Size + dest[offset] = byte(p.UnknownArray2Size) + offset++ + + // Write UnknownArray2 array (dynamic size) + for _, elem := range p.UnknownArray2 { + binary.LittleEndian.PutUint32(dest[offset:], elem.Array2Unknown) + offset += 4 + + } + + // Write Unknown11 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown11)) + offset += 4 + + // Write SubLevel + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.SubLevel)) + offset += 4 + + // Write RaceFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.RaceFlag)) + offset += 4 + + // Write ClassFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ClassFlag)) + offset += 4 + + // Write Password as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Password))) + offset += 2 + copy(dest[offset:], []byte(p.Password)) + offset += uint32(len(p.Password)) + + // Write Username as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Username))) + offset += 2 + copy(dest[offset:], []byte(p.Username)) + offset += uint32(len(p.Username)) + + // Write Unknown12 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown12))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown12)) + offset += uint32(len(p.Unknown12)) + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginReplyMsgV1188) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + uint32(len(p.Unknown)) + + size += 1 + + size += 4 + + size += 8 + + size += 4 + + size += 2 + uint32(len(p.Unknown3)) + + size += 1 + + size += 1 + + size += 1 + + size += 2 + + size += 5 + + size += 4 + + size += 4 + + size += 1 + + size += 3 + + size += 1 + + size += 1 + + size += 1 + + // Dynamic array: ClassItems + for _, elem := range p.ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 2 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + // Dynamic array: UnknownArray2 + for _, elem := range p.UnknownArray2 { + _ = elem // Avoid unused variable warning + size += 4 + + } + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Password)) + + size += 2 + uint32(len(p.Username)) + + size += 2 + uint32(len(p.Unknown12)) + + return size +} + +// LSLoginReplyMsgV57080 represents packet structure for OP_LoginReplyMsg +type LSLoginReplyMsgV57080 struct { + LoginResponse uint8 `eq2:"login_response"` + Unknown string `eq2:"unknown,type:str16"` // TODO: Identify purpose + ParentalControlFlag uint8 `eq2:"parental_control_flag"` + ParentalControlTimer uint32 `eq2:"parental_control_timer"` + Unknown2 [8]uint8 `eq2:"unknown2,size:8"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 string `eq2:"unknown3,type:str16"` // TODO: Identify purpose + ResetAppearance uint8 `eq2:"reset_appearance"` + DoNotForceSoga uint8 `eq2:"do_not_force_soga"` + Unknown4 uint8 `eq2:"unknown4"` // TODO: Identify purpose + Unknown5 uint16 `eq2:"unknown5"` // TODO: Identify purpose + Unknown6 [5]uint8 `eq2:"unknown6,size:5"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + Unknown7a uint32 `eq2:"unknown7a"` // TODO: Identify purpose + RaceUnknown uint8 `eq2:"race_unknown"` + Unknown8 [3]uint8 `eq2:"unknown8,size:3"` // TODO: Identify purpose + Unknown9 uint8 `eq2:"unknown9"` // TODO: Identify purpose + Unknown10 uint8 `eq2:"unknown10"` // TODO: Identify purpose + NumClassItems uint8 `eq2:"num_class_items,ifSet:unknown10"` + ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"class_items,sizeVar:num_class_items,ifSet:unknown10"` + UnknownArray2Size uint8 `eq2:"unknown_array2_size"` // TODO: Identify purpose + UnknownArray2 []struct { + Array2Unknown uint32 `eq2:"array2_unknown"` + } `eq2:"unknown_array2,sizeVar:unknown_array2_size"` + Unknown11 uint32 `eq2:"unknown11"` // TODO: Identify purpose + SubLevel uint32 `eq2:"sub_level"` + RaceFlag uint32 `eq2:"race_flag"` + ClassFlag uint32 `eq2:"class_flag"` + Password string `eq2:"password,type:str16"` + Username string `eq2:"username,type:str16"` + Service string `eq2:"service,type:str16"` + Web1 string `eq2:"web1,type:str16"` + Web2 string `eq2:"web2,type:str16"` + Web3 string `eq2:"web3,type:str16"` + Web4 string `eq2:"web4,type:str16"` + Web5 string `eq2:"web5,type:str16"` + Web6 string `eq2:"web6,type:str16"` + Web7 string `eq2:"web7,type:str16"` + Web8 string `eq2:"web8,type:str16"` + Web9 string `eq2:"web9,type:str16"` + Unknown12 uint8 `eq2:"unknown12"` // TODO: Identify purpose + Lvl90NumClassItems uint8 `eq2:"lvl90_num_class_items,ifSet:unknown10"` + Lvl90ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"lvl90_class_items,sizeVar:lvl90_num_class_items,ifSet:unknown10"` + Unknown13 [5]uint8 `eq2:"unknown13,size:5"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginReplyMsgV57080) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write LoginResponse + dest[offset] = byte(p.LoginResponse) + offset++ + + // Write Unknown as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown)) + offset += uint32(len(p.Unknown)) + + // Write ParentalControlFlag + dest[offset] = byte(p.ParentalControlFlag) + offset++ + + // Write ParentalControlTimer + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ParentalControlTimer)) + offset += 4 + + // Write Unknown2 array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown3))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown3)) + offset += uint32(len(p.Unknown3)) + + // Write ResetAppearance + dest[offset] = byte(p.ResetAppearance) + offset++ + + // Write DoNotForceSoga + dest[offset] = byte(p.DoNotForceSoga) + offset++ + + // Write Unknown4 + dest[offset] = byte(p.Unknown4) + offset++ + + // Write Unknown5 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown5)) + offset += 2 + + // Write Unknown6 array + for i := 0; i < 5; i++ { + dest[offset] = p.Unknown6[i] + offset++ + } + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write Unknown7a + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7a)) + offset += 4 + + // Write RaceUnknown + dest[offset] = byte(p.RaceUnknown) + offset++ + + // Write Unknown8 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write Unknown9 + dest[offset] = byte(p.Unknown9) + offset++ + + // Write Unknown10 + dest[offset] = byte(p.Unknown10) + offset++ + + // Write NumClassItems + dest[offset] = byte(p.NumClassItems) + offset++ + + // Write ClassItems array (dynamic size) + for _, elem := range p.ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write UnknownArray2Size + dest[offset] = byte(p.UnknownArray2Size) + offset++ + + // Write UnknownArray2 array (dynamic size) + for _, elem := range p.UnknownArray2 { + binary.LittleEndian.PutUint32(dest[offset:], elem.Array2Unknown) + offset += 4 + + } + + // Write Unknown11 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown11)) + offset += 4 + + // Write SubLevel + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.SubLevel)) + offset += 4 + + // Write RaceFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.RaceFlag)) + offset += 4 + + // Write ClassFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ClassFlag)) + offset += 4 + + // Write Password as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Password))) + offset += 2 + copy(dest[offset:], []byte(p.Password)) + offset += uint32(len(p.Password)) + + // Write Username as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Username))) + offset += 2 + copy(dest[offset:], []byte(p.Username)) + offset += uint32(len(p.Username)) + + // Write Service as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Service))) + offset += 2 + copy(dest[offset:], []byte(p.Service)) + offset += uint32(len(p.Service)) + + // Write Web1 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Web1))) + offset += 2 + copy(dest[offset:], []byte(p.Web1)) + offset += uint32(len(p.Web1)) + + // Write Web2 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Web2))) + offset += 2 + copy(dest[offset:], []byte(p.Web2)) + offset += uint32(len(p.Web2)) + + // Write Web3 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Web3))) + offset += 2 + copy(dest[offset:], []byte(p.Web3)) + offset += uint32(len(p.Web3)) + + // Write Web4 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Web4))) + offset += 2 + copy(dest[offset:], []byte(p.Web4)) + offset += uint32(len(p.Web4)) + + // Write Web5 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Web5))) + offset += 2 + copy(dest[offset:], []byte(p.Web5)) + offset += uint32(len(p.Web5)) + + // Write Web6 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Web6))) + offset += 2 + copy(dest[offset:], []byte(p.Web6)) + offset += uint32(len(p.Web6)) + + // Write Web7 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Web7))) + offset += 2 + copy(dest[offset:], []byte(p.Web7)) + offset += uint32(len(p.Web7)) + + // Write Web8 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Web8))) + offset += 2 + copy(dest[offset:], []byte(p.Web8)) + offset += uint32(len(p.Web8)) + + // Write Web9 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Web9))) + offset += 2 + copy(dest[offset:], []byte(p.Web9)) + offset += uint32(len(p.Web9)) + + // Write Unknown12 + dest[offset] = byte(p.Unknown12) + offset++ + + // Write Lvl90NumClassItems + dest[offset] = byte(p.Lvl90NumClassItems) + offset++ + + // Write Lvl90ClassItems array (dynamic size) + for _, elem := range p.Lvl90ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write Unknown13 array + for i := 0; i < 5; i++ { + dest[offset] = p.Unknown13[i] + offset++ + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginReplyMsgV57080) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + uint32(len(p.Unknown)) + + size += 1 + + size += 4 + + size += 8 + + size += 4 + + size += 2 + uint32(len(p.Unknown3)) + + size += 1 + + size += 1 + + size += 1 + + size += 2 + + size += 5 + + size += 4 + + size += 4 + + size += 1 + + size += 3 + + size += 1 + + size += 1 + + size += 1 + + // Dynamic array: ClassItems + for _, elem := range p.ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + // Dynamic array: UnknownArray2 + for _, elem := range p.UnknownArray2 { + _ = elem // Avoid unused variable warning + size += 4 + + } + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Password)) + + size += 2 + uint32(len(p.Username)) + + size += 2 + uint32(len(p.Service)) + + size += 2 + uint32(len(p.Web1)) + + size += 2 + uint32(len(p.Web2)) + + size += 2 + uint32(len(p.Web3)) + + size += 2 + uint32(len(p.Web4)) + + size += 2 + uint32(len(p.Web5)) + + size += 2 + uint32(len(p.Web6)) + + size += 2 + uint32(len(p.Web7)) + + size += 2 + uint32(len(p.Web8)) + + size += 2 + uint32(len(p.Web9)) + + size += 1 + + size += 1 + + // Dynamic array: Lvl90ClassItems + for _, elem := range p.Lvl90ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 5 + + return size +} + +// LSLoginReplyMsgV60100 represents packet structure for OP_LoginReplyMsg +type LSLoginReplyMsgV60100 struct { + LoginResponse uint8 `eq2:"login_response"` + Unknown string `eq2:"unknown,type:str16"` // TODO: Identify purpose + ParentalControlFlag uint8 `eq2:"parental_control_flag"` + ParentalControlTimer uint32 `eq2:"parental_control_timer"` + Unknown2 [8]uint8 `eq2:"unknown2,size:8"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 string `eq2:"unknown3,type:str16"` // TODO: Identify purpose + ResetAppearance uint8 `eq2:"reset_appearance"` + DoNotForceSoga uint8 `eq2:"do_not_force_soga"` + Unknown5 int64 `eq2:"unknown5"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + Unknown7a uint16 `eq2:"unknown7a"` // TODO: Identify purpose + RaceUnknown uint8 `eq2:"race_unknown"` + Unknown8 [3]uint8 `eq2:"unknown8,size:3"` // TODO: Identify purpose + Unknown9 [3]uint8 `eq2:"unknown9,size:3"` // TODO: Identify purpose + Unknown10 uint8 `eq2:"unknown10"` // TODO: Identify purpose + NumClassItems uint8 `eq2:"num_class_items,ifSet:unknown10"` + ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"class_items,sizeVar:num_class_items,ifSet:unknown10"` + UnknownArray2Size uint8 `eq2:"unknown_array2_size"` // TODO: Identify purpose + UnknownArray2 []struct { + Array2Unknown uint32 `eq2:"array2_unknown"` + } `eq2:"unknown_array2,sizeVar:unknown_array2_size"` + Unknown11 uint32 `eq2:"unknown11"` // TODO: Identify purpose + SubLevel uint32 `eq2:"sub_level"` + RaceFlag uint32 `eq2:"race_flag"` + ClassFlag uint32 `eq2:"class_flag"` + Password string `eq2:"password,type:str16"` + Username string `eq2:"username,type:str16"` + Service string `eq2:"service,type:str16"` + Unknown12 uint8 `eq2:"unknown12"` // TODO: Identify purpose + Lvl90NumClassItems uint8 `eq2:"lvl90_num_class_items,ifSet:unknown12"` + Lvl90ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"lvl90_class_items,sizeVar:lvl90_num_class_items,ifSet:unknown12"` + Unknown13 uint8 `eq2:"unknown13"` // TODO: Identify purpose + TimeLockedNumClassItems uint8 `eq2:"time_locked_num_class_items,ifSet:unknown13"` + TimeLockedClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"time_locked_class_items,sizeVar:time_locked_num_class_items,ifSet:unknown13"` + Unknown14 [13]uint8 `eq2:"unknown14,size:13"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginReplyMsgV60100) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write LoginResponse + dest[offset] = byte(p.LoginResponse) + offset++ + + // Write Unknown as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown)) + offset += uint32(len(p.Unknown)) + + // Write ParentalControlFlag + dest[offset] = byte(p.ParentalControlFlag) + offset++ + + // Write ParentalControlTimer + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ParentalControlTimer)) + offset += 4 + + // Write Unknown2 array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown3))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown3)) + offset += uint32(len(p.Unknown3)) + + // Write ResetAppearance + dest[offset] = byte(p.ResetAppearance) + offset++ + + // Write DoNotForceSoga + dest[offset] = byte(p.DoNotForceSoga) + offset++ + + // Write Unknown5 + binary.LittleEndian.PutUint64(dest[offset:], uint64(p.Unknown5)) + offset += 8 + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write Unknown7a + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown7a)) + offset += 2 + + // Write RaceUnknown + dest[offset] = byte(p.RaceUnknown) + offset++ + + // Write Unknown8 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write Unknown9 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown9[i] + offset++ + } + + // Write Unknown10 + dest[offset] = byte(p.Unknown10) + offset++ + + // Write NumClassItems + dest[offset] = byte(p.NumClassItems) + offset++ + + // Write ClassItems array (dynamic size) + for _, elem := range p.ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write UnknownArray2Size + dest[offset] = byte(p.UnknownArray2Size) + offset++ + + // Write UnknownArray2 array (dynamic size) + for _, elem := range p.UnknownArray2 { + binary.LittleEndian.PutUint32(dest[offset:], elem.Array2Unknown) + offset += 4 + + } + + // Write Unknown11 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown11)) + offset += 4 + + // Write SubLevel + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.SubLevel)) + offset += 4 + + // Write RaceFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.RaceFlag)) + offset += 4 + + // Write ClassFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ClassFlag)) + offset += 4 + + // Write Password as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Password))) + offset += 2 + copy(dest[offset:], []byte(p.Password)) + offset += uint32(len(p.Password)) + + // Write Username as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Username))) + offset += 2 + copy(dest[offset:], []byte(p.Username)) + offset += uint32(len(p.Username)) + + // Write Service as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Service))) + offset += 2 + copy(dest[offset:], []byte(p.Service)) + offset += uint32(len(p.Service)) + + // Write Unknown12 + dest[offset] = byte(p.Unknown12) + offset++ + + // Write Lvl90NumClassItems + dest[offset] = byte(p.Lvl90NumClassItems) + offset++ + + // Write Lvl90ClassItems array (dynamic size) + for _, elem := range p.Lvl90ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write Unknown13 + dest[offset] = byte(p.Unknown13) + offset++ + + // Write TimeLockedNumClassItems + dest[offset] = byte(p.TimeLockedNumClassItems) + offset++ + + // Write TimeLockedClassItems array (dynamic size) + for _, elem := range p.TimeLockedClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write Unknown14 array + for i := 0; i < 13; i++ { + dest[offset] = p.Unknown14[i] + offset++ + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginReplyMsgV60100) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + uint32(len(p.Unknown)) + + size += 1 + + size += 4 + + size += 8 + + size += 4 + + size += 2 + uint32(len(p.Unknown3)) + + size += 1 + + size += 1 + + size += 8 + + size += 4 + + size += 2 + + size += 1 + + size += 3 + + size += 3 + + size += 1 + + size += 1 + + // Dynamic array: ClassItems + for _, elem := range p.ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + // Dynamic array: UnknownArray2 + for _, elem := range p.UnknownArray2 { + _ = elem // Avoid unused variable warning + size += 4 + + } + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Password)) + + size += 2 + uint32(len(p.Username)) + + size += 2 + uint32(len(p.Service)) + + size += 1 + + size += 1 + + // Dynamic array: Lvl90ClassItems + for _, elem := range p.Lvl90ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + size += 1 + + // Dynamic array: TimeLockedClassItems + for _, elem := range p.TimeLockedClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 13 + + return size +} + +// LSLoginReplyMsgV63181 represents packet structure for OP_LoginReplyMsg +type LSLoginReplyMsgV63181 struct { + LoginResponse uint8 `eq2:"login_response"` + Unknown string `eq2:"unknown,type:str16"` // TODO: Identify purpose + ParentalControlFlag uint8 `eq2:"parental_control_flag"` + ParentalControlTimer uint32 `eq2:"parental_control_timer"` + Unknown2 [8]uint8 `eq2:"unknown2,size:8"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 string `eq2:"unknown3,type:str16"` // TODO: Identify purpose + ResetAppearance uint8 `eq2:"reset_appearance"` + DoNotForceSoga uint8 `eq2:"do_not_force_soga"` + Unknown4 uint8 `eq2:"unknown4"` // TODO: Identify purpose + Unknown5 uint16 `eq2:"unknown5"` // TODO: Identify purpose + Unknown6 [5]uint8 `eq2:"unknown6,size:5"` // TODO: Identify purpose + Unknown6a [8]uint8 `eq2:"unknown6a,size:8"` // TODO: Identify purpose + Unknown7 uint32 `eq2:"unknown7"` // TODO: Identify purpose + Unknown7a uint16 `eq2:"unknown7a"` // TODO: Identify purpose + RaceUnknown uint8 `eq2:"race_unknown"` + Unknown8 [3]uint8 `eq2:"unknown8,size:3"` // TODO: Identify purpose + Unknown9 [3]uint8 `eq2:"unknown9,size:3"` // TODO: Identify purpose + Unknown10 uint8 `eq2:"unknown10"` // TODO: Identify purpose + NumClassItems uint8 `eq2:"num_class_items,ifSet:unknown10"` + ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"class_items,sizeVar:num_class_items,ifSet:unknown10"` + UnknownArray2Size uint8 `eq2:"unknown_array2_size"` // TODO: Identify purpose + UnknownArray2 []struct { + Array2Unknown uint32 `eq2:"array2_unknown"` + } `eq2:"unknown_array2,sizeVar:unknown_array2_size"` + Unknown11 uint32 `eq2:"unknown11"` // TODO: Identify purpose + SubLevel uint32 `eq2:"sub_level"` + RaceFlag uint32 `eq2:"race_flag"` + ClassFlag uint32 `eq2:"class_flag"` + Password string `eq2:"password,type:str16"` + Username string `eq2:"username,type:str16"` + Service string `eq2:"service,type:str16"` + Unknown12 uint8 `eq2:"unknown12"` // TODO: Identify purpose + Lvl90NumClassItems uint8 `eq2:"lvl90_num_class_items,ifSet:unknown12"` + Lvl90ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"lvl90_class_items,sizeVar:lvl90_num_class_items,ifSet:unknown12"` + Unknown13 uint8 `eq2:"unknown13"` // TODO: Identify purpose + TimeLockedNumClassItems uint8 `eq2:"time_locked_num_class_items,ifSet:unknown13"` + TimeLockedClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"time_locked_class_items,sizeVar:time_locked_num_class_items,ifSet:unknown13"` + Unknown14 [9]uint8 `eq2:"unknown14,size:9"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginReplyMsgV63181) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write LoginResponse + dest[offset] = byte(p.LoginResponse) + offset++ + + // Write Unknown as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown)) + offset += uint32(len(p.Unknown)) + + // Write ParentalControlFlag + dest[offset] = byte(p.ParentalControlFlag) + offset++ + + // Write ParentalControlTimer + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ParentalControlTimer)) + offset += 4 + + // Write Unknown2 array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown2[i] + offset++ + } + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown3))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown3)) + offset += uint32(len(p.Unknown3)) + + // Write ResetAppearance + dest[offset] = byte(p.ResetAppearance) + offset++ + + // Write DoNotForceSoga + dest[offset] = byte(p.DoNotForceSoga) + offset++ + + // Write Unknown4 + dest[offset] = byte(p.Unknown4) + offset++ + + // Write Unknown5 + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown5)) + offset += 2 + + // Write Unknown6 array + for i := 0; i < 5; i++ { + dest[offset] = p.Unknown6[i] + offset++ + } + + // Write Unknown6a array + for i := 0; i < 8; i++ { + dest[offset] = p.Unknown6a[i] + offset++ + } + + // Write Unknown7 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown7)) + offset += 4 + + // Write Unknown7a + binary.LittleEndian.PutUint16(dest[offset:], uint16(p.Unknown7a)) + offset += 2 + + // Write RaceUnknown + dest[offset] = byte(p.RaceUnknown) + offset++ + + // Write Unknown8 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown8[i] + offset++ + } + + // Write Unknown9 array + for i := 0; i < 3; i++ { + dest[offset] = p.Unknown9[i] + offset++ + } + + // Write Unknown10 + dest[offset] = byte(p.Unknown10) + offset++ + + // Write NumClassItems + dest[offset] = byte(p.NumClassItems) + offset++ + + // Write ClassItems array (dynamic size) + for _, elem := range p.ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write UnknownArray2Size + dest[offset] = byte(p.UnknownArray2Size) + offset++ + + // Write UnknownArray2 array (dynamic size) + for _, elem := range p.UnknownArray2 { + binary.LittleEndian.PutUint32(dest[offset:], elem.Array2Unknown) + offset += 4 + + } + + // Write Unknown11 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown11)) + offset += 4 + + // Write SubLevel + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.SubLevel)) + offset += 4 + + // Write RaceFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.RaceFlag)) + offset += 4 + + // Write ClassFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ClassFlag)) + offset += 4 + + // Write Password as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Password))) + offset += 2 + copy(dest[offset:], []byte(p.Password)) + offset += uint32(len(p.Password)) + + // Write Username as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Username))) + offset += 2 + copy(dest[offset:], []byte(p.Username)) + offset += uint32(len(p.Username)) + + // Write Service as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Service))) + offset += 2 + copy(dest[offset:], []byte(p.Service)) + offset += uint32(len(p.Service)) + + // Write Unknown12 + dest[offset] = byte(p.Unknown12) + offset++ + + // Write Lvl90NumClassItems + dest[offset] = byte(p.Lvl90NumClassItems) + offset++ + + // Write Lvl90ClassItems array (dynamic size) + for _, elem := range p.Lvl90ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write Unknown13 + dest[offset] = byte(p.Unknown13) + offset++ + + // Write TimeLockedNumClassItems + dest[offset] = byte(p.TimeLockedNumClassItems) + offset++ + + // Write TimeLockedClassItems array (dynamic size) + for _, elem := range p.TimeLockedClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write Unknown14 array + for i := 0; i < 9; i++ { + dest[offset] = p.Unknown14[i] + offset++ + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginReplyMsgV63181) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + uint32(len(p.Unknown)) + + size += 1 + + size += 4 + + size += 8 + + size += 4 + + size += 2 + uint32(len(p.Unknown3)) + + size += 1 + + size += 1 + + size += 1 + + size += 2 + + size += 5 + + size += 8 + + size += 4 + + size += 2 + + size += 1 + + size += 3 + + size += 3 + + size += 1 + + size += 1 + + // Dynamic array: ClassItems + for _, elem := range p.ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + // Dynamic array: UnknownArray2 + for _, elem := range p.UnknownArray2 { + _ = elem // Avoid unused variable warning + size += 4 + + } + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Password)) + + size += 2 + uint32(len(p.Username)) + + size += 2 + uint32(len(p.Service)) + + size += 1 + + size += 1 + + // Dynamic array: Lvl90ClassItems + for _, elem := range p.Lvl90ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + size += 1 + + // Dynamic array: TimeLockedClassItems + for _, elem := range p.TimeLockedClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 9 + + return size +} + +// LSLoginReplyMsgV65534 represents packet structure for OP_LoginReplyMsg +type LSLoginReplyMsgV65534 struct { + LoginResponse uint8 `eq2:"login_response"` + WorldName string `eq2:"world_name,type:str16"` + ParentalControlFlag uint8 `eq2:"parental_control_flag"` + ParentalControlTimer int64 `eq2:"parental_control_timer"` + Unknown2 uint32 `eq2:"unknown2"` // TODO: Identify purpose + AccountId uint32 `eq2:"account_id"` + Unknown3 string `eq2:"unknown3,type:str16"` // TODO: Identify purpose + ResetAppearance uint8 `eq2:"reset_appearance"` + DoNotForceSoga uint8 `eq2:"do_not_force_soga"` + Unknown4 string `eq2:"unknown4,type:EQ2_32Bit_String"` // TODO: Identify purpose + Unknown7 string `eq2:"unknown7,type:EQ2_32Bit_String"` // TODO: Identify purpose + RaceUnknown uint32 `eq2:"race_unknown"` + Unknown8 uint8 `eq2:"unknown8"` // TODO: Identify purpose + Unknown10 uint8 `eq2:"unknown10"` // TODO: Identify purpose + NumClassItems uint8 `eq2:"num_class_items,ifSet:unknown10"` + ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"class_items,sizeVar:num_class_items,ifSet:unknown10"` + UnknownArray2Size uint8 `eq2:"unknown_array2_size"` // TODO: Identify purpose + UnknownArray2 []struct { + Array2Unknown uint32 `eq2:"array2_unknown"` + } `eq2:"unknown_array2,sizeVar:unknown_array2_size,ifSet:unknown_array2_size"` + Unknown11 uint32 `eq2:"unknown11"` // TODO: Identify purpose + SubLevel uint32 `eq2:"sub_level"` + RaceFlag uint32 `eq2:"race_flag"` + ClassFlag uint32 `eq2:"class_flag"` + Password string `eq2:"password,type:str16"` + Username string `eq2:"username,type:str16"` + Service string `eq2:"service,type:str16"` + Unknown12 uint8 `eq2:"unknown12"` // TODO: Identify purpose + Lvl90NumClassItems uint8 `eq2:"lvl90_num_class_items,ifSet:unknown12"` + Lvl90ClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"lvl90_class_items,sizeVar:lvl90_num_class_items,ifSet:unknown12"` + Unknown13 uint8 `eq2:"unknown13"` // TODO: Identify purpose + TimeLockedNumClassItems uint8 `eq2:"time_locked_num_class_items,ifSet:unknown13"` + TimeLockedClassItems []struct { + ClassId uint8 `eq2:"class_id"` + NumItems uint8 `eq2:"num_items"` + StartingItems []struct { + ModelId uint32 `eq2:"model_id"` + SlotId uint8 `eq2:"slot_id"` + UseColor uint8 `eq2:"use_color"` + UseHighlightColor uint8 `eq2:"use_highlight_color"` + ModelColor types.Color `eq2:"model_color"` + ModelHighlightColor types.Color `eq2:"model_highlight_color"` + } `eq2:"starting_items"` + } `eq2:"time_locked_class_items,sizeVar:time_locked_num_class_items,ifSet:unknown13"` + Unknown14 [13]uint8 `eq2:"unknown14,size:13"` // TODO: Identify purpose +} + +// Serialize writes the packet data to the provided buffer +func (p *LSLoginReplyMsgV65534) Serialize(dest []byte) uint32 { + offset := uint32(0) + + // Write LoginResponse + dest[offset] = byte(p.LoginResponse) + offset++ + + // Write WorldName as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.WorldName))) + offset += 2 + copy(dest[offset:], []byte(p.WorldName)) + offset += uint32(len(p.WorldName)) + + // Write ParentalControlFlag + dest[offset] = byte(p.ParentalControlFlag) + offset++ + + // Write ParentalControlTimer + binary.LittleEndian.PutUint64(dest[offset:], uint64(p.ParentalControlTimer)) + offset += 8 + + // Write Unknown2 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown2)) + offset += 4 + + // Write AccountId + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.AccountId)) + offset += 4 + + // Write Unknown3 as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Unknown3))) + offset += 2 + copy(dest[offset:], []byte(p.Unknown3)) + offset += uint32(len(p.Unknown3)) + + // Write ResetAppearance + dest[offset] = byte(p.ResetAppearance) + offset++ + + // Write DoNotForceSoga + dest[offset] = byte(p.DoNotForceSoga) + offset++ + + // Write Unknown4 as 32-bit length-prefixed string + binary.LittleEndian.PutUint32(dest[offset:], uint32(len(p.Unknown4))) + offset += 4 + copy(dest[offset:], []byte(p.Unknown4)) + offset += uint32(len(p.Unknown4)) + + // Write Unknown7 as 32-bit length-prefixed string + binary.LittleEndian.PutUint32(dest[offset:], uint32(len(p.Unknown7))) + offset += 4 + copy(dest[offset:], []byte(p.Unknown7)) + offset += uint32(len(p.Unknown7)) + + // Write RaceUnknown + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.RaceUnknown)) + offset += 4 + + // Write Unknown8 + dest[offset] = byte(p.Unknown8) + offset++ + + // Write Unknown10 + dest[offset] = byte(p.Unknown10) + offset++ + + // Write NumClassItems + dest[offset] = byte(p.NumClassItems) + offset++ + + // Write ClassItems array (dynamic size) + for _, elem := range p.ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write UnknownArray2Size + dest[offset] = byte(p.UnknownArray2Size) + offset++ + + // Write UnknownArray2 array (dynamic size) + for _, elem := range p.UnknownArray2 { + binary.LittleEndian.PutUint32(dest[offset:], elem.Array2Unknown) + offset += 4 + + } + + // Write Unknown11 + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.Unknown11)) + offset += 4 + + // Write SubLevel + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.SubLevel)) + offset += 4 + + // Write RaceFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.RaceFlag)) + offset += 4 + + // Write ClassFlag + binary.LittleEndian.PutUint32(dest[offset:], uint32(p.ClassFlag)) + offset += 4 + + // Write Password as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Password))) + offset += 2 + copy(dest[offset:], []byte(p.Password)) + offset += uint32(len(p.Password)) + + // Write Username as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Username))) + offset += 2 + copy(dest[offset:], []byte(p.Username)) + offset += uint32(len(p.Username)) + + // Write Service as 16-bit length-prefixed string + binary.LittleEndian.PutUint16(dest[offset:], uint16(len(p.Service))) + offset += 2 + copy(dest[offset:], []byte(p.Service)) + offset += uint32(len(p.Service)) + + // Write Unknown12 + dest[offset] = byte(p.Unknown12) + offset++ + + // Write Lvl90NumClassItems + dest[offset] = byte(p.Lvl90NumClassItems) + offset++ + + // Write Lvl90ClassItems array (dynamic size) + for _, elem := range p.Lvl90ClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write Unknown13 + dest[offset] = byte(p.Unknown13) + offset++ + + // Write TimeLockedNumClassItems + dest[offset] = byte(p.TimeLockedNumClassItems) + offset++ + + // Write TimeLockedClassItems array (dynamic size) + for _, elem := range p.TimeLockedClassItems { + dest[offset] = elem.ClassId + offset++ + dest[offset] = elem.NumItems + offset++ + // Write nested StartingItems array + for _, nestedElem := range elem.StartingItems { + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelId) + offset += 4 + dest[offset] = nestedElem.SlotId + offset++ + dest[offset] = nestedElem.UseColor + offset++ + dest[offset] = nestedElem.UseHighlightColor + offset++ + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelColor.ToUint32()) + offset += 4 + binary.LittleEndian.PutUint32(dest[offset:], nestedElem.ModelHighlightColor.ToUint32()) + offset += 4 + + } + + } + + // Write Unknown14 array + for i := 0; i < 13; i++ { + dest[offset] = p.Unknown14[i] + offset++ + } + + return offset +} + +// Size returns the serialized size of the packet +func (p *LSLoginReplyMsgV65534) Size() uint32 { + size := uint32(0) + + size += 1 + + size += 2 + uint32(len(p.WorldName)) + + size += 1 + + size += 8 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Unknown3)) + + size += 1 + + size += 1 + + size += 4 + uint32(len(p.Unknown4)) + + size += 4 + uint32(len(p.Unknown7)) + + size += 4 + + size += 1 + + size += 1 + + size += 1 + + // Dynamic array: ClassItems + for _, elem := range p.ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + // Dynamic array: UnknownArray2 + for _, elem := range p.UnknownArray2 { + _ = elem // Avoid unused variable warning + size += 4 + + } + + size += 4 + + size += 4 + + size += 4 + + size += 4 + + size += 2 + uint32(len(p.Password)) + + size += 2 + uint32(len(p.Username)) + + size += 2 + uint32(len(p.Service)) + + size += 1 + + size += 1 + + // Dynamic array: Lvl90ClassItems + for _, elem := range p.Lvl90ClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 1 + + size += 1 + + // Dynamic array: TimeLockedClassItems + for _, elem := range p.TimeLockedClassItems { + _ = elem // Avoid unused variable warning + size += 1 + size += 1 + // Nested array: StartingItems + for _, nestedElem := range elem.StartingItems { + _ = nestedElem // Avoid unused variable + size += 4 + size += 1 + size += 1 + size += 1 + size += 4 + size += 4 + + } + + } + + size += 13 + + return size +} + + + + + + + + + diff --git a/defs/xml/common.xml b/defs/xml/common.xml index 6ab28aa..3ce92a3 100644 --- a/defs/xml/common.xml +++ b/defs/xml/common.xml @@ -1,21 +1,21 @@ - - + + - - - - - - - + + + + + + + - + @@ -41,24 +41,24 @@ - - - + + + - - - - - - - + + + + + + + - + @@ -84,26 +84,26 @@ - - - - + + + + - - - - - - - - + + + + + + + + - + @@ -129,25 +129,25 @@ - - - - + + + + - - - - - - - + + + + + + + - + @@ -173,26 +173,26 @@ - - - - - + + + + + - - - - - - - + + + + + + + - + @@ -218,14 +218,14 @@ - + - + @@ -254,19 +254,19 @@ - - - - - + + + + + - - - - - - - + + + + + + + @@ -274,7 +274,7 @@ - + @@ -300,7 +300,7 @@ - + @@ -308,7 +308,7 @@ - + @@ -337,19 +337,19 @@ - - - - - + + + + + - - - - - - - + + + + + + + @@ -357,7 +357,7 @@ - + @@ -385,7 +385,7 @@ - + @@ -393,7 +393,7 @@ - + @@ -422,20 +422,20 @@ - - - - - + + + + + - - - - - - - - + + + + + + + + @@ -443,7 +443,7 @@ - + @@ -471,7 +471,7 @@ - + @@ -479,7 +479,7 @@ - + @@ -508,20 +508,20 @@ - - - - - + + + + + - - - - - - - - + + + + + + + + @@ -529,7 +529,7 @@ - + @@ -557,7 +557,7 @@ - + @@ -565,7 +565,7 @@ - + @@ -594,26 +594,26 @@ - - - - - + + + + + - - - - - - - + + + + + + + - + @@ -639,14 +639,14 @@ - + - + @@ -672,30 +672,30 @@ - + - - - - - + + + + + - - - - - - - + + + + + + + - + @@ -721,14 +721,14 @@ - + - + @@ -754,11 +754,11 @@ - + - + diff --git a/defs/xml/eq2.xml b/defs/xml/eq2.xml deleted file mode 100644 index 6e7c019..0000000 --- a/defs/xml/eq2.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/defs/xml/login.xml b/defs/xml/login.xml index 60f5418..3a50cfd 100644 --- a/defs/xml/login.xml +++ b/defs/xml/login.xml @@ -52,8 +52,8 @@ - - + + diff --git a/types/color.go b/types/color.go new file mode 100644 index 0000000..2d45560 --- /dev/null +++ b/types/color.go @@ -0,0 +1,85 @@ +package types + +import ( + "encoding/binary" + "io" +) + +// Color represents an RGBA color value +type Color struct { + R uint8 + G uint8 + B uint8 + A uint8 +} + +// NewColor creates a new Color from RGBA values +func NewColor(r, g, b, a uint8) Color { + return Color{R: r, G: g, B: b, A: a} +} + +// NewColorFromUint32 creates a Color from a packed uint32 (0xAARRGGBB) +func NewColorFromUint32(packed uint32) Color { + return Color{ + R: uint8((packed >> 16) & 0xFF), + G: uint8((packed >> 8) & 0xFF), + B: uint8(packed & 0xFF), + A: uint8((packed >> 24) & 0xFF), + } +} + +// ToUint32 converts the color to a packed uint32 (0xAARRGGBB) +func (c Color) ToUint32() uint32 { + return uint32(c.A)<<24 | uint32(c.R)<<16 | uint32(c.G)<<8 | uint32(c.B) +} + +// Serialize writes the color as a uint32 to a writer +func (c Color) Serialize(w io.Writer) error { + return binary.Write(w, binary.LittleEndian, c.ToUint32()) +} + +// SerializeToBytes writes the color to a byte slice at the given offset +func (c Color) SerializeToBytes(dest []byte, offset *uint32) { + binary.LittleEndian.PutUint32(dest[*offset:], c.ToUint32()) + *offset += 4 +} + +// Size returns the serialized size of the color (always 4 bytes) +func (c Color) Size() uint32 { + return 4 +} + +// Deserialize reads a color from a reader +func (c *Color) Deserialize(r io.Reader) error { + var packed uint32 + if err := binary.Read(r, binary.LittleEndian, &packed); err != nil { + return err + } + *c = NewColorFromUint32(packed) + return nil +} + +// EQ2Color is an alias for Color specifically for EQ2 packets +// EQ2 sometimes uses different color formats, this allows for customization +type EQ2Color Color + +// Serialize writes the EQ2 color as a uint32 to a writer +func (c EQ2Color) Serialize(w io.Writer) error { + return Color(c).Serialize(w) +} + +// SerializeToBytes writes the EQ2 color to a byte slice +func (c EQ2Color) SerializeToBytes(dest []byte, offset *uint32) { + Color(c).SerializeToBytes(dest, offset) +} + +// Size returns the serialized size (always 4 bytes) +func (c EQ2Color) Size() uint32 { + return 4 +} + +// Deserialize reads an EQ2 color from a reader +func (c *EQ2Color) Deserialize(r io.Reader) error { + color := (*Color)(c) + return color.Deserialize(r) +} \ No newline at end of file diff --git a/types/equipment.go b/types/equipment.go new file mode 100644 index 0000000..a5a8606 --- /dev/null +++ b/types/equipment.go @@ -0,0 +1,40 @@ +package types + +import ( + "encoding/binary" + "io" +) + +// EquipmentItem represents an equipment item with model and color information +type EquipmentItem struct { + Type uint16 // Model/item type ID + Color Color // RGB color for the item +} + +// Serialize writes the equipment item to a writer +func (e *EquipmentItem) Serialize(w io.Writer) error { + if err := binary.Write(w, binary.LittleEndian, e.Type); err != nil { + return err + } + return e.Color.Serialize(w) +} + +// SerializeToBytes writes the equipment item to a byte slice at the given offset +func (e *EquipmentItem) SerializeToBytes(dest []byte, offset *uint32) { + binary.LittleEndian.PutUint16(dest[*offset:], e.Type) + *offset += 2 + e.Color.SerializeToBytes(dest, offset) +} + +// Size returns the serialized size of the equipment item +func (e *EquipmentItem) Size() uint32 { + return 2 + e.Color.Size() // 2 bytes for type + color size +} + +// Deserialize reads an equipment item from a reader +func (e *EquipmentItem) Deserialize(r io.Reader) error { + if err := binary.Read(r, binary.LittleEndian, &e.Type); err != nil { + return err + } + return e.Color.Deserialize(r) +} \ No newline at end of file diff --git a/types/fixed.go b/types/fixed.go new file mode 100644 index 0000000..30031ff --- /dev/null +++ b/types/fixed.go @@ -0,0 +1,71 @@ +package types + +import ( + "io" +) + +// FixedString represents a fixed-length string field +type FixedString struct { + Data []byte + Size int +} + +// NewFixedString creates a new fixed string with the specified size +func NewFixedString(size int) *FixedString { + return &FixedString{ + Data: make([]byte, size), + Size: size, + } +} + +// SetString sets the string value, truncating or padding as needed +func (f *FixedString) SetString(s string) { + copy(f.Data, []byte(s)) + // Pad with zeros if string is shorter than fixed size + for i := len(s); i < f.Size; i++ { + f.Data[i] = 0 + } +} + +// String returns the string value, trimming null bytes +func (f *FixedString) String() string { + // Find first null byte + for i, b := range f.Data { + if b == 0 { + return string(f.Data[:i]) + } + } + return string(f.Data) +} + +// Serialize writes the fixed string to a writer +func (f *FixedString) Serialize(w io.Writer) error { + _, err := w.Write(f.Data) + return err +} + +// SerializeToBytes writes the fixed string to a byte slice +func (f *FixedString) SerializeToBytes(dest []byte, offset *uint32) { + copy(dest[*offset:], f.Data) + *offset += uint32(f.Size) +} + +// Deserialize reads a fixed string from a reader +func (f *FixedString) Deserialize(r io.Reader) error { + _, err := io.ReadFull(r, f.Data) + return err +} + +// FixedArray represents a fixed-size array of primitive types +type FixedArray[T any] struct { + Data []T + Size int +} + +// NewFixedArray creates a new fixed array with the specified size +func NewFixedArray[T any](size int) *FixedArray[T] { + return &FixedArray[T]{ + Data: make([]T, size), + Size: size, + } +} diff --git a/types/packet.go b/types/packet.go new file mode 100644 index 0000000..3a5ba3a --- /dev/null +++ b/types/packet.go @@ -0,0 +1,219 @@ +package types + +import ( + "bytes" + "encoding/binary" + "io" +) + +// Packet represents a basic EQ2 packet interface +type Packet interface { + Serialize(dest []byte) uint32 + Size() uint32 +} + +// PacketWriter helps with writing packet data +type PacketWriter struct { + buffer *bytes.Buffer + offset uint32 +} + +// NewPacketWriter creates a new packet writer +func NewPacketWriter() *PacketWriter { + return &PacketWriter{ + buffer: new(bytes.Buffer), + offset: 0, + } +} + +// WriteUint8 writes a uint8 value +func (pw *PacketWriter) WriteUint8(v uint8) error { + return binary.Write(pw.buffer, binary.LittleEndian, v) +} + +// WriteUint16 writes a uint16 value +func (pw *PacketWriter) WriteUint16(v uint16) error { + return binary.Write(pw.buffer, binary.LittleEndian, v) +} + +// WriteUint32 writes a uint32 value +func (pw *PacketWriter) WriteUint32(v uint32) error { + return binary.Write(pw.buffer, binary.LittleEndian, v) +} + +// WriteUint64 writes a uint64 value +func (pw *PacketWriter) WriteUint64(v uint64) error { + return binary.Write(pw.buffer, binary.LittleEndian, v) +} + +// WriteString8 writes a string with 8-bit length prefix +func (pw *PacketWriter) WriteString8(s string) error { + str := EQ2String8(s) + return str.Serialize(pw.buffer) +} + +// WriteString16 writes a string with 16-bit length prefix +func (pw *PacketWriter) WriteString16(s string) error { + str := EQ2String16(s) + return str.Serialize(pw.buffer) +} + +// WriteString32 writes a string with 32-bit length prefix +func (pw *PacketWriter) WriteString32(s string) error { + str := EQ2String32(s) + return str.Serialize(pw.buffer) +} + +// WriteColor writes a color value +func (pw *PacketWriter) WriteColor(c Color) error { + return c.Serialize(pw.buffer) +} + +// WriteFloat32 writes a float32 value +func (pw *PacketWriter) WriteFloat32(v float32) error { + f := Float32(v) + return f.Serialize(pw.buffer) +} + +// WriteFloat64 writes a float64 value +func (pw *PacketWriter) WriteFloat64(v float64) error { + f := Float64(v) + return f.Serialize(pw.buffer) +} + +// Bytes returns the written bytes +func (pw *PacketWriter) Bytes() []byte { + return pw.buffer.Bytes() +} + +// Size returns the current size of written data +func (pw *PacketWriter) Size() uint32 { + return uint32(pw.buffer.Len()) +} + +// PacketReader helps with reading packet data +type PacketReader struct { + reader io.Reader + offset uint32 +} + +// NewPacketReader creates a new packet reader +func NewPacketReader(data []byte) *PacketReader { + return &PacketReader{ + reader: bytes.NewReader(data), + offset: 0, + } +} + +// NewPacketReaderFromReader creates a packet reader from an io.Reader +func NewPacketReaderFromReader(r io.Reader) *PacketReader { + return &PacketReader{ + reader: r, + offset: 0, + } +} + +// ReadUint8 reads a uint8 value +func (pr *PacketReader) ReadUint8() (uint8, error) { + var v uint8 + err := binary.Read(pr.reader, binary.LittleEndian, &v) + if err == nil { + pr.offset++ + } + return v, err +} + +// ReadUint16 reads a uint16 value +func (pr *PacketReader) ReadUint16() (uint16, error) { + var v uint16 + err := binary.Read(pr.reader, binary.LittleEndian, &v) + if err == nil { + pr.offset += 2 + } + return v, err +} + +// ReadUint32 reads a uint32 value +func (pr *PacketReader) ReadUint32() (uint32, error) { + var v uint32 + err := binary.Read(pr.reader, binary.LittleEndian, &v) + if err == nil { + pr.offset += 4 + } + return v, err +} + +// ReadUint64 reads a uint64 value +func (pr *PacketReader) ReadUint64() (uint64, error) { + var v uint64 + err := binary.Read(pr.reader, binary.LittleEndian, &v) + if err == nil { + pr.offset += 8 + } + return v, err +} + +// ReadString8 reads a string with 8-bit length prefix +func (pr *PacketReader) ReadString8() (string, error) { + var s EQ2String8 + err := s.Deserialize(pr.reader) + if err == nil { + pr.offset += s.Size() + } + return string(s), err +} + +// ReadString16 reads a string with 16-bit length prefix +func (pr *PacketReader) ReadString16() (string, error) { + var s EQ2String16 + err := s.Deserialize(pr.reader) + if err == nil { + pr.offset += s.Size() + } + return string(s), err +} + +// ReadString32 reads a string with 32-bit length prefix +func (pr *PacketReader) ReadString32() (string, error) { + var s EQ2String32 + err := s.Deserialize(pr.reader) + if err == nil { + pr.offset += s.Size() + } + return string(s), err +} + +// ReadColor reads a color value +func (pr *PacketReader) ReadColor() (Color, error) { + var c Color + err := c.Deserialize(pr.reader) + if err == nil { + pr.offset += 4 + } + return c, err +} + +// ReadFloat32 reads a float32 value +func (pr *PacketReader) ReadFloat32() (float32, error) { + var f Float32 + err := f.Deserialize(pr.reader) + if err == nil { + pr.offset += 4 + } + return float32(f), err +} + +// ReadFloat64 reads a float64 value +func (pr *PacketReader) ReadFloat64() (float64, error) { + var f Float64 + err := f.Deserialize(pr.reader) + if err == nil { + pr.offset += 8 + } + return float64(f), err +} + +// Offset returns the current read offset +func (pr *PacketReader) Offset() uint32 { + return pr.offset +} \ No newline at end of file diff --git a/types/primitives.go b/types/primitives.go new file mode 100644 index 0000000..95fad45 --- /dev/null +++ b/types/primitives.go @@ -0,0 +1,81 @@ +package types + +import ( + "encoding/binary" + "io" + "math" +) + +// Float32 provides serialization methods for float32 +type Float32 float32 + +func (f Float32) Serialize(w io.Writer) error { + return binary.Write(w, binary.LittleEndian, math.Float32bits(float32(f))) +} + +func (f Float32) SerializeToBytes(dest []byte, offset *uint32) { + binary.LittleEndian.PutUint32(dest[*offset:], math.Float32bits(float32(f))) + *offset += 4 +} + +func (f Float32) Size() uint32 { + return 4 +} + +func (f *Float32) Deserialize(r io.Reader) error { + var bits uint32 + if err := binary.Read(r, binary.LittleEndian, &bits); err != nil { + return err + } + *f = Float32(math.Float32frombits(bits)) + return nil +} + +// Float64 provides serialization methods for float64 +type Float64 float64 + +func (f Float64) Serialize(w io.Writer) error { + return binary.Write(w, binary.LittleEndian, math.Float64bits(float64(f))) +} + +func (f Float64) SerializeToBytes(dest []byte, offset *uint32) { + binary.LittleEndian.PutUint64(dest[*offset:], math.Float64bits(float64(f))) + *offset += 8 +} + +func (f Float64) Size() uint32 { + return 8 +} + +func (f *Float64) Deserialize(r io.Reader) error { + var bits uint64 + if err := binary.Read(r, binary.LittleEndian, &bits); err != nil { + return err + } + *f = Float64(math.Float64frombits(bits)) + return nil +} + +// GetTypeSize returns the size in bytes for common EQ2 types +func GetTypeSize(typeName string) uint32 { + switch typeName { + case "int8", "uint8", "byte", "char": + return 1 + case "int16", "uint16": + return 2 + case "int32", "uint32", "float", "float32", "color": + return 4 + case "int64", "uint64", "double", "float64": + return 8 + default: + return 0 + } +} + +// Serializable interface for types that can be serialized +type Serializable interface { + Serialize(w io.Writer) error + SerializeToBytes(dest []byte, offset *uint32) + Size() uint32 + Deserialize(r io.Reader) error +} \ No newline at end of file diff --git a/types/strings.go b/types/strings.go new file mode 100644 index 0000000..e07f7df --- /dev/null +++ b/types/strings.go @@ -0,0 +1,151 @@ +package types + +import ( + "encoding/binary" + "io" +) + +// EQ2String8 represents a string with an 8-bit length prefix +type EQ2String8 string + +// Serialize writes the string with 8-bit length prefix +func (s EQ2String8) Serialize(w io.Writer) error { + if len(s) > 255 { + return io.ErrShortWrite + } + + // Write length byte + if err := binary.Write(w, binary.LittleEndian, uint8(len(s))); err != nil { + return err + } + + // Write string data + _, err := w.Write([]byte(s)) + return err +} + +// SerializeToBytes writes the string to a byte slice at the given offset +func (s EQ2String8) SerializeToBytes(dest []byte, offset *uint32) { + dest[*offset] = uint8(len(s)) + *offset++ + copy(dest[*offset:], []byte(s)) + *offset += uint32(len(s)) +} + +// Size returns the serialized size (1 byte length + string data) +func (s EQ2String8) Size() uint32 { + return 1 + uint32(len(s)) +} + +// Deserialize reads a string with 8-bit length prefix +func (s *EQ2String8) Deserialize(r io.Reader) error { + var length uint8 + if err := binary.Read(r, binary.LittleEndian, &length); err != nil { + return err + } + + data := make([]byte, length) + if _, err := io.ReadFull(r, data); err != nil { + return err + } + + *s = EQ2String8(data) + return nil +} + +// EQ2String16 represents a string with a 16-bit length prefix +type EQ2String16 string + +// Serialize writes the string with 16-bit length prefix +func (s EQ2String16) Serialize(w io.Writer) error { + if len(s) > 65535 { + return io.ErrShortWrite + } + + // Write length as uint16 + if err := binary.Write(w, binary.LittleEndian, uint16(len(s))); err != nil { + return err + } + + // Write string data + _, err := w.Write([]byte(s)) + return err +} + +// SerializeToBytes writes the string to a byte slice at the given offset +func (s EQ2String16) SerializeToBytes(dest []byte, offset *uint32) { + binary.LittleEndian.PutUint16(dest[*offset:], uint16(len(s))) + *offset += 2 + copy(dest[*offset:], []byte(s)) + *offset += uint32(len(s)) +} + +// Size returns the serialized size (2 bytes length + string data) +func (s EQ2String16) Size() uint32 { + return 2 + uint32(len(s)) +} + +// Deserialize reads a string with 16-bit length prefix +func (s *EQ2String16) Deserialize(r io.Reader) error { + var length uint16 + if err := binary.Read(r, binary.LittleEndian, &length); err != nil { + return err + } + + data := make([]byte, length) + if _, err := io.ReadFull(r, data); err != nil { + return err + } + + *s = EQ2String16(data) + return nil +} + +// EQ2String32 represents a string with a 32-bit length prefix +type EQ2String32 string + +// Serialize writes the string with 32-bit length prefix +func (s EQ2String32) Serialize(w io.Writer) error { + // Write length as uint32 + if err := binary.Write(w, binary.LittleEndian, uint32(len(s))); err != nil { + return err + } + + // Write string data + _, err := w.Write([]byte(s)) + return err +} + +// SerializeToBytes writes the string to a byte slice at the given offset +func (s EQ2String32) SerializeToBytes(dest []byte, offset *uint32) { + binary.LittleEndian.PutUint32(dest[*offset:], uint32(len(s))) + *offset += 4 + copy(dest[*offset:], []byte(s)) + *offset += uint32(len(s)) +} + +// Size returns the serialized size (4 bytes length + string data) +func (s EQ2String32) Size() uint32 { + return 4 + uint32(len(s)) +} + +// Deserialize reads a string with 32-bit length prefix +func (s *EQ2String32) Deserialize(r io.Reader) error { + var length uint32 + if err := binary.Read(r, binary.LittleEndian, &length); err != nil { + return err + } + + // Sanity check to prevent huge allocations + if length > 1024*1024 { // 1MB limit + return io.ErrUnexpectedEOF + } + + data := make([]byte, length) + if _, err := io.ReadFull(r, data); err != nil { + return err + } + + *s = EQ2String32(data) + return nil +} \ No newline at end of file