switch struct size calc to reflection
This commit is contained in:
parent
ca43e4637d
commit
7a2bfc13f8
@ -486,34 +486,7 @@ func (p *{{.Name}}) Serialize(dest []byte) uint32 {
|
||||
|
||||
// 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}} * 8
|
||||
{{- else if eq (sizeOf (baseType .Type)) 1}}
|
||||
size += {{.Size}}
|
||||
{{- else}}
|
||||
size += {{.Size}} * {{sizeOf (baseType .Type)}}
|
||||
{{- end}}
|
||||
{{- else}}
|
||||
size += {{sizeOf .Type}}
|
||||
{{- end}}
|
||||
{{end}}
|
||||
return size
|
||||
return types.CalculateSize(p)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
@ -580,28 +553,6 @@ func (p *{{.Name}}) Size() uint32 {
|
||||
{{- 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}}
|
||||
@ -665,29 +616,6 @@ func (p *{{.Name}}) Size() uint32 {
|
||||
{{- 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 {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
181
types/reflect_size.go
Normal file
181
types/reflect_size.go
Normal file
@ -0,0 +1,181 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CalculateSize uses reflection to calculate the serialized size of a struct
|
||||
func CalculateSize(v interface{}) uint32 {
|
||||
return calculateSizeValue(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
func calculateSizeValue(v reflect.Value) uint32 {
|
||||
// Dereference pointers
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return 0
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
return calculateStructSize(v)
|
||||
case reflect.Slice:
|
||||
return calculateSliceSize(v)
|
||||
case reflect.Array:
|
||||
return calculateArraySize(v)
|
||||
case reflect.String:
|
||||
// Default to 16-bit length prefix if not specified
|
||||
return 2 + uint32(v.Len())
|
||||
case reflect.Uint8, reflect.Int8:
|
||||
return 1
|
||||
case reflect.Uint16, reflect.Int16:
|
||||
return 2
|
||||
case reflect.Uint32, reflect.Int32, reflect.Float32:
|
||||
return 4
|
||||
case reflect.Uint64, reflect.Int64, reflect.Float64:
|
||||
return 8
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func calculateStructSize(v reflect.Value) uint32 {
|
||||
var size uint32
|
||||
t := v.Type()
|
||||
|
||||
// Handle known types
|
||||
switch t.Name() {
|
||||
case "Color", "EQ2Color":
|
||||
return 3 // RGB: 3 bytes
|
||||
case "EquipmentItem":
|
||||
return 8 // 2 bytes type + 3 bytes color + 3 bytes highlight
|
||||
}
|
||||
|
||||
// Calculate size for each field
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
field := v.Field(i)
|
||||
fieldType := t.Field(i)
|
||||
|
||||
// Skip unexported fields
|
||||
if !field.CanInterface() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse struct tags for size hints
|
||||
tag := fieldType.Tag.Get("eq2")
|
||||
tagParts := parseTag(tag)
|
||||
|
||||
// Handle string types with specific encoding
|
||||
if field.Kind() == reflect.String {
|
||||
strLen := uint32(field.Len())
|
||||
if strType, ok := tagParts["type"]; ok {
|
||||
switch strType {
|
||||
case "str8", "EQ2_8Bit_String":
|
||||
size += 1 + strLen
|
||||
case "str16", "EQ2_16Bit_String":
|
||||
size += 2 + strLen
|
||||
case "str32", "EQ2_32Bit_String":
|
||||
size += 4 + strLen
|
||||
default:
|
||||
size += 2 + strLen // Default to 16-bit
|
||||
}
|
||||
} else {
|
||||
size += 2 + strLen // Default to 16-bit
|
||||
}
|
||||
} else if field.Kind() == reflect.Array {
|
||||
// Fixed-size array
|
||||
elemSize := getElementSize(field.Type().Elem())
|
||||
size += uint32(field.Len()) * elemSize
|
||||
} else if field.Kind() == reflect.Slice {
|
||||
// Dynamic array - calculate size of all elements
|
||||
for j := 0; j < field.Len(); j++ {
|
||||
size += calculateSizeValue(field.Index(j))
|
||||
}
|
||||
} else {
|
||||
// Regular field
|
||||
size += calculateSizeValue(field)
|
||||
}
|
||||
}
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
func calculateSliceSize(v reflect.Value) uint32 {
|
||||
var size uint32
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
size += calculateSizeValue(v.Index(i))
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
func calculateArraySize(v reflect.Value) uint32 {
|
||||
if v.Len() == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
elemSize := getElementSize(v.Type().Elem())
|
||||
return uint32(v.Len()) * elemSize
|
||||
}
|
||||
|
||||
func getElementSize(t reflect.Type) uint32 {
|
||||
switch t.Kind() {
|
||||
case reflect.Uint8, reflect.Int8:
|
||||
return 1
|
||||
case reflect.Uint16, reflect.Int16:
|
||||
return 2
|
||||
case reflect.Uint32, reflect.Int32, reflect.Float32:
|
||||
return 4
|
||||
case reflect.Uint64, reflect.Int64, reflect.Float64:
|
||||
return 8
|
||||
case reflect.Struct:
|
||||
// Handle known struct types
|
||||
switch t.Name() {
|
||||
case "Color", "EQ2Color":
|
||||
return 3
|
||||
case "EquipmentItem":
|
||||
return 8
|
||||
default:
|
||||
// For unknown structs, create a zero value and calculate
|
||||
return calculateSizeValue(reflect.Zero(t))
|
||||
}
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func parseTag(tag string) map[string]string {
|
||||
result := make(map[string]string)
|
||||
if tag == "" {
|
||||
return result
|
||||
}
|
||||
|
||||
parts := strings.Split(tag, ",")
|
||||
if len(parts) > 0 {
|
||||
result["name"] = parts[0]
|
||||
}
|
||||
|
||||
for i := 1; i < len(parts); i++ {
|
||||
kv := strings.Split(parts[i], ":")
|
||||
if len(kv) == 2 {
|
||||
result[kv[0]] = kv[1]
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// SizeCalculator interface for types that can calculate their own size
|
||||
type SizeCalculator interface {
|
||||
Size() uint32
|
||||
}
|
||||
|
||||
// CalculateSizeOptimized uses the Size() method if available, otherwise uses reflection
|
||||
func CalculateSizeOptimized(v interface{}) uint32 {
|
||||
if sc, ok := v.(SizeCalculator); ok {
|
||||
return sc.Size()
|
||||
}
|
||||
return CalculateSize(v)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user