Compare commits
2 Commits
678d653932
...
7a2bfc13f8
Author | SHA1 | Date | |
---|---|---|---|
7a2bfc13f8 | |||
ca43e4637d |
10
.claude/settings.local.json
Normal file
10
.claude/settings.local.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(go run:*)",
|
||||||
|
"Bash(grep:*)"
|
||||||
|
],
|
||||||
|
"deny": [],
|
||||||
|
"ask": []
|
||||||
|
}
|
||||||
|
}
|
108
defs/gen/main.go
108
defs/gen/main.go
@ -443,8 +443,14 @@ func (p *{{.Name}}) Serialize(dest []byte) uint32 {
|
|||||||
{{- else if eq (baseType .Type) "types.EquipmentItem"}}
|
{{- else if eq (baseType .Type) "types.EquipmentItem"}}
|
||||||
binary.LittleEndian.PutUint16(dest[offset:], p.{{.GoName}}[i].Type)
|
binary.LittleEndian.PutUint16(dest[offset:], p.{{.GoName}}[i].Type)
|
||||||
offset += 2
|
offset += 2
|
||||||
binary.LittleEndian.PutUint32(dest[offset:], p.{{.GoName}}[i].Color.ToUint32())
|
dest[offset] = p.{{.GoName}}[i].Color.R
|
||||||
offset += 4
|
dest[offset+1] = p.{{.GoName}}[i].Color.G
|
||||||
|
dest[offset+2] = p.{{.GoName}}[i].Color.B
|
||||||
|
offset += 3
|
||||||
|
dest[offset] = p.{{.GoName}}[i].Highlight.R
|
||||||
|
dest[offset+1] = p.{{.GoName}}[i].Highlight.G
|
||||||
|
dest[offset+2] = p.{{.GoName}}[i].Highlight.B
|
||||||
|
offset += 3
|
||||||
{{- end}}
|
{{- end}}
|
||||||
}
|
}
|
||||||
{{- else}}
|
{{- else}}
|
||||||
@ -462,8 +468,10 @@ func (p *{{.Name}}) Serialize(dest []byte) uint32 {
|
|||||||
binary.LittleEndian.PutUint16(dest[offset:], uint16(p.{{.GoName}}))
|
binary.LittleEndian.PutUint16(dest[offset:], uint16(p.{{.GoName}}))
|
||||||
offset += 2
|
offset += 2
|
||||||
{{- else if eq .Type "types.Color"}}
|
{{- else if eq .Type "types.Color"}}
|
||||||
binary.LittleEndian.PutUint32(dest[offset:], p.{{.GoName}}.ToUint32())
|
dest[offset] = p.{{.GoName}}.R
|
||||||
offset += 4
|
dest[offset+1] = p.{{.GoName}}.G
|
||||||
|
dest[offset+2] = p.{{.GoName}}.B
|
||||||
|
offset += 3
|
||||||
{{- else if or (eq .Type "int32") (eq .Type "uint32")}}
|
{{- else if or (eq .Type "int32") (eq .Type "uint32")}}
|
||||||
binary.LittleEndian.PutUint32(dest[offset:], uint32(p.{{.GoName}}))
|
binary.LittleEndian.PutUint32(dest[offset:], uint32(p.{{.GoName}}))
|
||||||
offset += 4
|
offset += 4
|
||||||
@ -478,34 +486,7 @@ func (p *{{.Name}}) Serialize(dest []byte) uint32 {
|
|||||||
|
|
||||||
// Size returns the serialized size of the packet
|
// Size returns the serialized size of the packet
|
||||||
func (p *{{.Name}}) Size() uint32 {
|
func (p *{{.Name}}) Size() uint32 {
|
||||||
size := uint32(0)
|
return types.CalculateSize(p)
|
||||||
{{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}}
|
{{end}}
|
||||||
|
|
||||||
@ -543,8 +524,10 @@ func (p *{{.Name}}) Size() uint32 {
|
|||||||
binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(elem.{{.GoName}}))
|
binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(elem.{{.GoName}}))
|
||||||
offset += 4
|
offset += 4
|
||||||
{{- else if eq .Type "types.Color"}}
|
{{- else if eq .Type "types.Color"}}
|
||||||
binary.LittleEndian.PutUint32(dest[offset:], elem.{{.GoName}}.ToUint32())
|
dest[offset] = elem.{{.GoName}}.R
|
||||||
offset += 4
|
dest[offset+1] = elem.{{.GoName}}.G
|
||||||
|
dest[offset+2] = elem.{{.GoName}}.B
|
||||||
|
offset += 3
|
||||||
{{- else if eq .Type "uint32"}}
|
{{- else if eq .Type "uint32"}}
|
||||||
binary.LittleEndian.PutUint32(dest[offset:], elem.{{.GoName}})
|
binary.LittleEndian.PutUint32(dest[offset:], elem.{{.GoName}})
|
||||||
offset += 4
|
offset += 4
|
||||||
@ -570,28 +553,6 @@ func (p *{{.Name}}) Size() uint32 {
|
|||||||
{{- end}}
|
{{- 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"}}
|
{{define "serializeNestedFields"}}
|
||||||
{{- range .}}
|
{{- range .}}
|
||||||
{{- if .IsDynamicArray}}
|
{{- if .IsDynamicArray}}
|
||||||
@ -627,8 +588,10 @@ func (p *{{.Name}}) Size() uint32 {
|
|||||||
binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(nestedElem.{{.GoName}}))
|
binary.LittleEndian.PutUint32(dest[offset:], math.Float32bits(nestedElem.{{.GoName}}))
|
||||||
offset += 4
|
offset += 4
|
||||||
{{- else if eq .Type "types.Color"}}
|
{{- else if eq .Type "types.Color"}}
|
||||||
binary.LittleEndian.PutUint32(dest[offset:], nestedElem.{{.GoName}}.ToUint32())
|
dest[offset] = nestedElem.{{.GoName}}.R
|
||||||
offset += 4
|
dest[offset+1] = nestedElem.{{.GoName}}.G
|
||||||
|
dest[offset+2] = nestedElem.{{.GoName}}.B
|
||||||
|
offset += 3
|
||||||
{{- else if eq .Type "uint32"}}
|
{{- else if eq .Type "uint32"}}
|
||||||
binary.LittleEndian.PutUint32(dest[offset:], nestedElem.{{.GoName}})
|
binary.LittleEndian.PutUint32(dest[offset:], nestedElem.{{.GoName}})
|
||||||
offset += 4
|
offset += 4
|
||||||
@ -653,29 +616,6 @@ func (p *{{.Name}}) Size() uint32 {
|
|||||||
{{- end}}
|
{{- end}}
|
||||||
{{- end}}
|
{{- 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 {
|
func contains(s, substr string) bool {
|
||||||
@ -700,12 +640,14 @@ func sizeOf(typeName string) int {
|
|||||||
return 1
|
return 1
|
||||||
case "int16", "uint16":
|
case "int16", "uint16":
|
||||||
return 2
|
return 2
|
||||||
case "int32", "uint32", "float32", "types.Color":
|
case "types.Color":
|
||||||
|
return 3 // RGB: 3 bytes
|
||||||
|
case "int32", "uint32", "float32":
|
||||||
return 4
|
return 4
|
||||||
case "int64", "uint64", "float64":
|
case "int64", "uint64", "float64":
|
||||||
return 8
|
return 8
|
||||||
case "types.EquipmentItem":
|
case "types.EquipmentItem":
|
||||||
return 6
|
return 8 // 2 bytes type + 3 bytes color + 3 bytes highlight
|
||||||
default:
|
default:
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,58 +5,65 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Color represents an RGBA color value
|
// Color represents an RGB color value (3 bytes) matching EQ2's format
|
||||||
type Color struct {
|
type Color struct {
|
||||||
R uint8
|
R uint8
|
||||||
G uint8
|
G uint8
|
||||||
B uint8
|
B uint8
|
||||||
A uint8
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewColor creates a new Color from RGBA values
|
// NewColor creates a new Color from RGB values
|
||||||
func NewColor(r, g, b, a uint8) Color {
|
func NewColor(r, g, b uint8) Color {
|
||||||
return Color{R: r, G: g, B: b, A: a}
|
return Color{R: r, G: g, B: b}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewColorFromUint32 creates a Color from a packed uint32 (0xAARRGGBB)
|
// NewColorFromUint32 creates a Color from a packed uint32 (ignores alpha, uses 0x00RRGGBB)
|
||||||
func NewColorFromUint32(packed uint32) Color {
|
func NewColorFromUint32(packed uint32) Color {
|
||||||
return Color{
|
return Color{
|
||||||
R: uint8((packed >> 16) & 0xFF),
|
R: uint8((packed >> 16) & 0xFF),
|
||||||
G: uint8((packed >> 8) & 0xFF),
|
G: uint8((packed >> 8) & 0xFF),
|
||||||
B: uint8(packed & 0xFF),
|
B: uint8(packed & 0xFF),
|
||||||
A: uint8((packed >> 24) & 0xFF),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToUint32 converts the color to a packed uint32 (0xAARRGGBB)
|
// ToUint32 converts the color to a packed uint32 (0x00RRGGBB for compatibility)
|
||||||
func (c Color) ToUint32() uint32 {
|
func (c Color) ToUint32() uint32 {
|
||||||
return uint32(c.A)<<24 | uint32(c.R)<<16 | uint32(c.G)<<8 | uint32(c.B)
|
return uint32(c.R)<<16 | uint32(c.G)<<8 | uint32(c.B)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize writes the color as a uint32 to a writer
|
// Serialize writes the color as 3 bytes (RGB) to a writer
|
||||||
func (c Color) Serialize(w io.Writer) error {
|
func (c Color) Serialize(w io.Writer) error {
|
||||||
return binary.Write(w, binary.LittleEndian, c.ToUint32())
|
if err := binary.Write(w, binary.LittleEndian, c.R); err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
return err
|
||||||
}
|
}
|
||||||
*c = NewColorFromUint32(packed)
|
if err := binary.Write(w, binary.LittleEndian, c.G); err != nil {
|
||||||
return nil
|
return err
|
||||||
|
}
|
||||||
|
return binary.Write(w, binary.LittleEndian, c.B)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SerializeToBytes writes the color as 3 bytes to a byte slice at the given offset
|
||||||
|
func (c Color) SerializeToBytes(dest []byte, offset *uint32) {
|
||||||
|
dest[*offset] = c.R
|
||||||
|
dest[*offset+1] = c.G
|
||||||
|
dest[*offset+2] = c.B
|
||||||
|
*offset += 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the serialized size of the color (always 3 bytes)
|
||||||
|
func (c Color) Size() uint32 {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialize reads a color (3 bytes) from a reader
|
||||||
|
func (c *Color) Deserialize(r io.Reader) error {
|
||||||
|
if err := binary.Read(r, binary.LittleEndian, &c.R); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(r, binary.LittleEndian, &c.G); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return binary.Read(r, binary.LittleEndian, &c.B)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EQ2Color is an alias for Color specifically for EQ2 packets
|
// EQ2Color is an alias for Color specifically for EQ2 packets
|
||||||
|
@ -6,9 +6,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// EquipmentItem represents an equipment item with model and color information
|
// EquipmentItem represents an equipment item with model and color information
|
||||||
|
// Matches EQ2_EquipmentItem from C++ code
|
||||||
type EquipmentItem struct {
|
type EquipmentItem struct {
|
||||||
Type uint16 // Model/item type ID
|
Type uint16 // Model/item type ID
|
||||||
Color Color // RGB color for the item
|
Color Color // RGB color for the item (3 bytes)
|
||||||
|
Highlight Color // RGB highlight color for the item (3 bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize writes the equipment item to a writer
|
// Serialize writes the equipment item to a writer
|
||||||
@ -16,7 +18,10 @@ func (e *EquipmentItem) Serialize(w io.Writer) error {
|
|||||||
if err := binary.Write(w, binary.LittleEndian, e.Type); err != nil {
|
if err := binary.Write(w, binary.LittleEndian, e.Type); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return e.Color.Serialize(w)
|
if err := e.Color.Serialize(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.Highlight.Serialize(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SerializeToBytes writes the equipment item to a byte slice at the given offset
|
// SerializeToBytes writes the equipment item to a byte slice at the given offset
|
||||||
@ -24,11 +29,12 @@ func (e *EquipmentItem) SerializeToBytes(dest []byte, offset *uint32) {
|
|||||||
binary.LittleEndian.PutUint16(dest[*offset:], e.Type)
|
binary.LittleEndian.PutUint16(dest[*offset:], e.Type)
|
||||||
*offset += 2
|
*offset += 2
|
||||||
e.Color.SerializeToBytes(dest, offset)
|
e.Color.SerializeToBytes(dest, offset)
|
||||||
|
e.Highlight.SerializeToBytes(dest, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the serialized size of the equipment item
|
// Size returns the serialized size of the equipment item
|
||||||
func (e *EquipmentItem) Size() uint32 {
|
func (e *EquipmentItem) Size() uint32 {
|
||||||
return 2 + e.Color.Size() // 2 bytes for type + color size
|
return 2 + e.Color.Size() + e.Highlight.Size() // 2 bytes for type + 3 bytes color + 3 bytes highlight = 8 bytes total
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deserialize reads an equipment item from a reader
|
// Deserialize reads an equipment item from a reader
|
||||||
@ -36,5 +42,8 @@ func (e *EquipmentItem) Deserialize(r io.Reader) error {
|
|||||||
if err := binary.Read(r, binary.LittleEndian, &e.Type); err != nil {
|
if err := binary.Read(r, binary.LittleEndian, &e.Type); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return e.Color.Deserialize(r)
|
if err := e.Color.Deserialize(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return e.Highlight.Deserialize(r)
|
||||||
}
|
}
|
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