fix: resolve parameterized $compareTo types and fix array count type

- VisitNameAndData: return any instead of named struct when mergeCompareTo
  resolves $compareTo, fixing field type mismatches for switch/container types
- ContainerCompareTo: traverse anon/bitfield fields for compareTo resolution,
  fixes entityMetadata 'field not found' errors
- Array.Count: change from string to any to handle numeric count values
- ArrayEncoder: fix nil check to correctly write length prefix for arrays
- ArrayDecoder: use fmt.Sprint for safe Count conversion
This commit is contained in:
OpenCode
2026-08-05 18:33:39 +02:00
parent fa70ea36c6
commit eb83786f9a
14 changed files with 2138 additions and 101 deletions
+86
View File
@@ -7,6 +7,7 @@ import (
"go/ast"
"go/token"
"io"
"maps"
"os"
"runtime/debug"
"slices"
@@ -56,6 +57,7 @@ type Generator struct {
EncoderNatives map[string]FunctionGeneratorFunc
CompareToNatives map[string]CompareToGeneratorFunc
Protocol Protocol
RawTypes map[string]map[string]any
File *ast.File
// These persist in the current GenerateType call
@@ -129,6 +131,11 @@ func (g *Generator) VisitNameAndData(tName string, tData any) (e ast.Expr, err e
}
t, found := g.Protocol.Types.Types[tName]
if t != "native" && found {
if tData != nil {
if _, ok := g.mergeCompareTo(tName, t, tData); ok {
return Ident("any"), nil
}
}
return Ident(util2.CamelCase(tName)), nil
}
t, found = g.CurrentlyGeneratingTypes.Types[tName]
@@ -152,6 +159,14 @@ func (g *Generator) VisitDecoder(varToSet ast.Expr, data any, name string) (e []
if found {
return d(g, varToSet, tData, name)
}
if tData != nil {
if merged, ok := g.mergeCompareTo(tName, g.Protocol.Types.Types[tName], tData); ok {
s, found := g.DecoderNatives[merged.tName]
if found {
return s(g, varToSet, merged.data, name)
}
}
}
t, found := g.Protocol.Types.Types[tName]
if t == "native" {
err = fmt.Errorf("decoder native not implemented %v", tName)
@@ -160,6 +175,55 @@ func (g *Generator) VisitDecoder(varToSet ast.Expr, data any, name string) (e []
return DefaultDecoder(g, varToSet, tData, name)
}
type mergedType struct {
tName string
data any
}
func (g *Generator) mergeCompareTo(tName string, t any, overrideData any) (mergedType, bool) {
overrideMap, ok := overrideData.(map[string]any)
if !ok {
return mergedType{}, false
}
overrideCompareTo, hasOverride := overrideMap["compareTo"]
if !hasOverride {
return mergedType{}, false
}
if s, ok := overrideCompareTo.(string); ok && strings.HasPrefix(s, "$") {
return mergedType{}, false
}
var typeMap map[string]any
var nativeName string
if m, ok := t.(map[string]any); ok {
typeMap = m
nativeName = "container"
} else if a, ok := t.([]any); ok && len(a) >= 2 {
if m, ok := a[1].(map[string]any); ok {
typeMap = m
}
if s, ok := a[0].(string); ok {
nativeName = s
}
} else {
m, ok := g.RawTypes[tName]
if !ok {
return mergedType{}, false
}
typeMap = m
nativeName = "switch"
}
typeCompareTo, hasType := typeMap["compareTo"]
if !hasType {
return mergedType{}, false
}
if s, ok := typeCompareTo.(string); !ok || !strings.HasPrefix(s, "$") {
return mergedType{}, false
}
merged := maps.Clone(typeMap)
merged["compareTo"] = overrideCompareTo
return mergedType{tName: nativeName, data: merged}, true
}
func (g *Generator) VisitEncoder(varToSet ast.Expr, data any, name string) (e []ast.Stmt, err error) {
g.Depth += 1
defer func() { g.Depth -= 1 }()
@@ -172,6 +236,14 @@ func (g *Generator) VisitEncoder(varToSet ast.Expr, data any, name string) (e []
if found {
return d(g, varToSet, tData, name)
}
if tData != nil {
if merged, ok := g.mergeCompareTo(tName, g.Protocol.Types.Types[tName], tData); ok {
s, found := g.EncoderNatives[merged.tName]
if found {
return s(g, varToSet, merged.data, name)
}
}
}
t, found := g.Protocol.Types.Types[tName]
if t == "native" {
err = fmt.Errorf("encoder native not implemented %v", tName)
@@ -357,6 +429,20 @@ func Generate(version string, w io.Writer, sourceHash string) (packetInfos []Pac
g := &Generator{Protocol: protocol}
g.RawTypes = make(map[string]map[string]any)
for k, v := range protocol.Types.Types {
if m, ok := v.(map[string]any); ok {
g.RawTypes[k] = m
}
if a, ok := v.([]any); ok && len(a) == 2 {
if m, ok := a[1].(map[string]any); ok {
if _, has := m["fields"]; has {
g.RawTypes[k] = m
}
}
}
}
g.File = NewFile("v" + strings.ReplaceAll(version, ".", "_"))
// Add file header comment for IDE recognition and reproducibility