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
+7
View File
@@ -59,6 +59,13 @@ func ContainerCompareTo(g *Generator, parts []string, inExpr ast.Expr, dataRaw a
if field.Name == name {
return g.VisitCompareTo(parts, SelectorExprAndStr(inExpr, util2.CamelCase(field.Name)), field.Type)
}
if field.Anon {
anonParts := append([]string{name}, parts...)
e, cet, err2 := g.VisitCompareTo(anonParts, SelectorExprAndStr(inExpr, "Anon"), field.Type)
if err2 == nil {
return e, cet, nil
}
}
}
err = errors.New("field not found")
return
+4 -2
View File
@@ -1,6 +1,7 @@
package main
import (
"fmt"
"go/ast"
"go/token"
"slices"
@@ -124,13 +125,14 @@ func ArrayDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s
return
}
} else {
countStr := fmt.Sprint(data.Count)
var n int
n, err = strconv.Atoi(data.Count)
n, err = strconv.Atoi(countStr)
var e ast.Expr
if err == nil {
e = NumLit(n)
} else {
e, _, err = g.ParseCompareTo(data.Count)
e, _, err = g.ParseCompareTo(countStr)
}
s2 = append(s2, Assign121(Ident(lName), e))
}
+1 -1
View File
@@ -79,7 +79,7 @@ func ArrayEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s
iName := "i" + name
//s, err = g.VisitEncoder(varToSet, data.Type, name)
var s1 []ast.Stmt
if data.Count == "" {
if data.Count == nil {
s1, err = g.VisitEncoder(Call(ct, Call(Ident("len"), varToSet)), data.CountType, name)
if err != nil {
return
+1 -1
View File
@@ -35,7 +35,7 @@ type (
Array struct {
CountType any
Count string
Count any
Type any
}