This commit is contained in:
adman
2025-12-15 22:07:37 +01:00
parent 01bf2a575c
commit 6108534a12
1118 changed files with 13788358 additions and 331 deletions
+178
View File
@@ -0,0 +1,178 @@
func TypeToPacketIdentifier(d queser.Direction, s queser.State, t any) (i string) {
switch d {
case queser.ToServer:
switch s {
case queser.Handshaking:
i = HandshakingToServerTypeToPacketIdentifier(t)
case queser.Status:
i = StatusToServerTypeToPacketIdentifier(t)
case queser.Login:
i = LoginToServerTypeToPacketIdentifier(t)
case queser.Configuration:
i = ConfigurationToServerTypeToPacketIdentifier(t)
case queser.Play:
i = PlayToServerTypeToPacketIdentifier(t)
}
case queser.ToClient:
switch s {
case queser.Handshaking:
i = HandshakingToClientTypeToPacketIdentifier(t)
case queser.Status:
i = StatusToClientTypeToPacketIdentifier(t)
case queser.Login:
i = LoginToClientTypeToPacketIdentifier(t)
case queser.Configuration:
i = ConfigurationToClientTypeToPacketIdentifier(t)
case queser.Play:
i = PlayToClientTypeToPacketIdentifier(t)
}
}
return
}
func PacketIdentifierToType(d queser.Direction, s queser.State, i string) (t any) {
switch d {
case queser.ToServer:
switch s {
case queser.Handshaking:
t = HandshakingToServerPacketIdentifierToType(i)
case queser.Status:
t = StatusToServerPacketIdentifierToType(i)
case queser.Login:
t = LoginToServerPacketIdentifierToType(i)
case queser.Configuration:
t = ConfigurationToServerPacketIdentifierToType(i)
case queser.Play:
t = PlayToServerPacketIdentifierToType(i)
}
case queser.ToClient:
switch s {
case queser.Handshaking:
t = HandshakingToClientPacketIdentifierToType(i)
case queser.Status:
t = StatusToClientPacketIdentifierToType(i)
case queser.Login:
t = LoginToClientPacketIdentifierToType(i)
case queser.Configuration:
t = ConfigurationToClientPacketIdentifierToType(i)
case queser.Play:
t = PlayToClientPacketIdentifierToType(i)
}
}
return
}
func DecodePacket(d queser.Direction, s queser.State, r io.Reader) (params any, err error) {
switch d {
case queser.ToServer:
switch s {
case queser.Handshaking:
var packet HandshakingToServerPacket
packet, err = HandshakingToServerPacket{}.Decode(r)
if err != nil {
return
}
params = packet.Params
case queser.Status:
var packet StatusToServerPacket
packet, err = StatusToServerPacket{}.Decode(r)
if err != nil {
return
}
params = packet.Params
case queser.Login:
var packet LoginToServerPacket
packet, err = LoginToServerPacket{}.Decode(r)
if err != nil {
return
}
params = packet.Params
case queser.Configuration:
var packet ConfigurationToServerPacket
packet, err = ConfigurationToServerPacket{}.Decode(r)
if err != nil {
return
}
params = packet.Params
case queser.Play:
var packet PlayToServerPacket
packet, err = PlayToServerPacket{}.Decode(r)
if err != nil {
return
}
params = packet.Params
}
case queser.ToClient:
switch s {
case queser.Handshaking:
var packet HandshakingToClientPacket
packet, err = HandshakingToClientPacket{}.Decode(r)
if err != nil {
return
}
params = packet.Params
case queser.Status:
var packet StatusToClientPacket
packet, err = StatusToClientPacket{}.Decode(r)
if err != nil {
return
}
params = packet.Params
case queser.Login:
var packet LoginToClientPacket
packet, err = LoginToClientPacket{}.Decode(r)
if err != nil {
return
}
params = packet.Params
case queser.Configuration:
var packet ConfigurationToClientPacket
packet, err = ConfigurationToClientPacket{}.Decode(r)
if err != nil {
return
}
params = packet.Params
case queser.Play:
var packet PlayToClientPacket
packet, err = PlayToClientPacket{}.Decode(r)
if err != nil {
return
}
params = packet.Params
}
}
return
}
func EncodePacket(d queser.Direction, s queser.State, i string, p any, w io.Writer) (err error) {
switch d {
case queser.ToServer:
switch s {
case queser.Handshaking:
err = HandshakingToServerPacket{i, p}.Encode(w)
case queser.Status:
err = StatusToServerPacket{i, p}.Encode(w)
case queser.Login:
err = LoginToServerPacket{i, p}.Encode(w)
case queser.Configuration:
err = ConfigurationToServerPacket{i, p}.Encode(w)
case queser.Play:
err = PlayToServerPacket{i, p}.Encode(w)
}
case queser.ToClient:
switch s {
case queser.Handshaking:
err = HandshakingToClientPacket{i, p}.Encode(w)
case queser.Status:
err = StatusToClientPacket{i, p}.Encode(w)
case queser.Login:
err = LoginToClientPacket{i, p}.Encode(w)
case queser.Configuration:
err = ConfigurationToClientPacket{i, p}.Encode(w)
case queser.Play:
err = PlayToClientPacket{i, p}.Encode(w)
}
}
return
}
+129
View File
@@ -0,0 +1,129 @@
package main
import (
"go/ast"
"io"
"strings"
_ "embed"
"github.com/admin-else/queser/data"
)
//go:embed helper_append.txt
var helperAppend string
func GenerateHelperTypes(t Types, prefix string, f *ast.File) (err error) {
for k, v := range t.Types {
if k != "packet" {
continue
}
v := v.([]any)[1].([]any)[1].(map[string]any)["type"].([]any)[1].(map[string]any)["fields"].(map[string]any)
m := make(map[string]string)
for k2, v2 := range v {
v2 := v2.(string)
if strings.HasPrefix(v2, "packet_common") {
m[k2] = CamelCase(v2)
} else if v2 == "void" {
m[k2] = "queser.Void"
} else {
m[k2] = prefix + CamelCase(v2)
}
}
err = PacketIdentifierToTypeGenerator(prefix, f, m)
if err != nil {
return
}
m = ReverseMap(m)
err = TypeToPacketIdentifierGenerator(prefix, f, m)
if err != nil {
return
}
}
return
}
func GenerateHelperState(s State, prefix string, f *ast.File) (err error) {
err = GenerateHelperTypes(s.ToServer, prefix+"ToServer", f)
if err != nil {
return
}
return GenerateHelperTypes(s.ToClient, prefix+"ToClient", f)
}
func GenerateHelperProtocol(p Protocol, f *ast.File) (err error) {
err = GenerateHelperState(p.Handshaking, "Handshaking", f)
if err != nil {
return
}
err = GenerateHelperState(p.Status, "Status", f)
if err != nil {
return
}
err = GenerateHelperState(p.Login, "Login", f)
if err != nil {
return
}
err = GenerateHelperState(p.Configuration, "Configuration", f)
if err != nil {
return
}
err = GenerateHelperState(p.Play, "Play", f)
if err != nil {
return
}
return
}
// PacketIdentifierToTypeGenerator func PacketIdentifierToType(s string) any {
// switch s {
// case "abilities":
// return PlayToClientPacketAbilities{}
// default:
// return nil
// }
// }
func PacketIdentifierToTypeGenerator(funcNamePrefix string, f *ast.File, m map[string]string) (err error) {
var s []ast.Stmt
for _, k := range OrderedKeys(m) {
v := m[k]
s = append(s, Case(Exprs(StrLit(k)), Stmts(Assign121(Ident("t"), CompLit(Ident(v), nil)))))
}
s = append(s, Case(nil, Stmts(Assign121(Ident("t"), Nil()))))
fn := NewFunc(funcNamePrefix+"PacketIdentifierToType", []NameAndType{{"s", Ident("string")}}, []NameAndType{{"t", Ident("any")}})
fn.Body = NewBlockEllipsis(SwitchStmt(Ident("s"), NewBlock(s)), Return())
AppendDecl(f, fn)
return
}
func TypeToPacketIdentifierGenerator(funcNamePrefix string, f *ast.File, m map[string]string) (err error) {
var s []ast.Stmt
for _, k := range OrderedKeys(m) {
v := m[k]
s = append(s, Case(Exprs(Ident(k)), Stmts(Assign121(Ident("s"), StrLit(v)))))
}
fn := NewFunc(funcNamePrefix+"TypeToPacketIdentifier", []NameAndType{{"t", Ident("any")}}, []NameAndType{{"s", Ident("string")}})
fn.Body = NewBlockEllipsis(TypeSwitch(ExprStmt(TypeAssert(Ident("t"), Ident("type"))), NewBlock(s)), Return())
AppendDecl(f, fn)
return
}
func GenerateHelpers(version string, w io.Writer) (err error) {
protocol := Protocol{}
err = data.LoadVersionedJson(version, "protocol", &protocol)
if err != nil {
return
}
f := NewFile("v" + strings.ReplaceAll(version, ".", "_"))
AppendDecl(f, Import("io", "github.com/admin-else/queser"))
err = GenerateHelperProtocol(protocol, f)
if err != nil {
return
}
err = PrintToFile(f, w)
if err != nil {
return
}
_, err = w.Write([]byte(helperAppend))
return
}
+372
View File
@@ -0,0 +1,372 @@
package main
import (
"errors"
"fmt"
"go/ast"
"go/token"
"io"
"os"
"slices"
"strings"
"github.com/admin-else/queser/data"
)
var ToDoError = errors.New("to do")
type Types struct {
Types map[string]any
}
type State struct {
ToClient, ToServer Types
}
type Protocol struct {
Types
Handshaking, Status, Login, Configuration, Play State
}
type Settings struct {
ReplaceWithTodoNames []string
}
type ContainerStackEntry struct {
Data []struct {
Name string
Type any
Anon bool
}
VarToSet ast.Expr
}
type Generator struct {
// These persist the entire generate-call
Settings Settings
Natives map[string]ExprGeneratorFunc
DecoderNatives map[string]FunctionGeneratorFunc
EncoderNatives map[string]FunctionGeneratorFunc
CompareToNatives map[string]CompareToGeneratorFunc
Protocol Protocol
File *ast.File
// These persist in the current GenerateType call
CurrentlyGeneratingTypes Types
// These persist 1 type generation
CurrentlyGeneratingTypesPrefix string
CurrentlyGeneratingTypeName string
// Change during type generation
Depth int
Declared []string
ContainerStack []ContainerStackEntry
VtsStack []ast.Expr
}
func (g *Generator) Decl(name string, t token.Token, e ast.Expr) {
if slices.Contains(g.Declared, name) {
return
}
g.Declared = append(g.Declared, name)
AppendDecl(g.File, &ast.GenDecl{
Tok: t,
Specs: []ast.Spec{
&ast.ValueSpec{
Names: []*ast.Ident{
Ident(name),
},
Values: []ast.Expr{e},
},
},
})
}
func ParseType(t any) (tName string, tData any, err error) {
switch t := t.(type) {
case string:
tName = t
return
case []any:
if len(t) != 2 {
err = fmt.Errorf("unable to parse type %v", t)
return
}
var ok bool
tName, ok = t[0].(string)
if !ok {
err = fmt.Errorf("unable to parse type %v", t)
return
}
tData = t[1]
return
}
err = fmt.Errorf("unable to parse type %v", t)
return
}
type ExprGeneratorFunc func(g *Generator, data any) (ast.Expr, error)
type CompareToGeneratorFunc func(g *Generator, parts []string, inExpr ast.Expr, data any) (ast.Expr, error)
type FunctionGeneratorFunc func(g *Generator, varToSet ast.Expr, data any, name string) ([]ast.Stmt, error)
func (g *Generator) VisitType(data any) (e ast.Expr, err error) {
tName, tData, err := ParseType(data)
if err != nil {
return
}
return g.VisitNameAndData(tName, tData)
}
func (g *Generator) VisitNameAndData(tName string, tData any) (e ast.Expr, err error) {
g.Depth += 1
defer func() { g.Depth -= 1 }()
n, found := g.Natives[tName]
if found {
return n(g, tData)
}
t, found := g.Protocol.Types.Types[tName]
if t != "native" && found {
return Ident(CamelCase(tName)), nil
}
t, found = g.CurrentlyGeneratingTypes.Types[tName]
if found {
return Ident(g.CurrentlyGeneratingTypesPrefix + CamelCase(tName)), nil
}
err = fmt.Errorf("unknown type %s", tName)
return
}
func (g *Generator) VisitDecoder(varToSet ast.Expr, data any, name string) (e []ast.Stmt, err error) {
g.Depth += 1
defer func() { g.Depth -= 1 }()
tName, tData, err := ParseType(data)
if err != nil {
return
}
d, found := g.DecoderNatives[tName]
if found {
return d(g, varToSet, tData, name)
}
t, found := g.Protocol.Types.Types[tName]
if t == "native" {
err = fmt.Errorf("decoder native not implemented %v", tName)
return
}
return DefaultDecoder(g, varToSet, tData, name)
}
func (g *Generator) VisitEncoder(varToSet ast.Expr, data any, name string) (e []ast.Stmt, err error) {
g.Depth += 1
defer func() { g.Depth -= 1 }()
tName, tData, err := ParseType(data)
if err != nil {
return
}
d, found := g.EncoderNatives[tName]
if found {
return d(g, varToSet, tData, name)
}
t, found := g.Protocol.Types.Types[tName]
if t == "native" {
err = fmt.Errorf("encoder native not implemented %v", tName)
return
}
return DefaultEncoder(g, varToSet, tData, name)
}
// FixPointerReceivers
// We cannot declare a function on a ptr type as described by https://go.dev/ref/spec#Method_declarations.
// So we wrap them in a struct.
func FixPointerReceivers(e ast.Expr) (td ast.Expr, ret ast.Expr) {
_, isStruct := e.(*ast.StructType)
ret = Ident("ret")
if isStruct {
td = e
return
}
ret = Selector("ret", "Val")
s := NewStruct()
AddFieldToStruct(s, "Val", e)
td = s
return
}
func (g *Generator) GenerateTypes(prefix string, types Types) error {
g.CurrentlyGeneratingTypes = types
g.CurrentlyGeneratingTypesPrefix = prefix
for _, k := range OrderedKeys(types.Types) {
v := types.Types[k]
if slices.Contains(g.Settings.ReplaceWithTodoNames, k) {
v = "todo"
}
g.Depth = 0
e, err := g.VisitType(v)
if errors.Is(err, ToDoError) {
e = Selector("queser", "ToDo")
err = nil
}
if err != nil {
return err
}
if e == nil { // This is for types we implement ourselves
continue
}
tName := prefix + CamelCase(k)
g.CurrentlyGeneratingTypeName = tName
e, retExpr := FixPointerReceivers(e)
AppendDecl(g.File, TypeDecl(tName, e))
args := []NameAndType{{"r", Ident("io.Reader")}}
rets := []NameAndType{{"ret", Ident(tName)}, {"err", Ident("error")}}
decodeFunction := NewFuncWithReceiver("Decode", "_", tName, args, rets)
g.Depth = 0
s, err := g.VisitDecoder(retExpr, v, tName)
if err != nil {
s = ToDoStmts
if !errors.Is(err, ToDoError) {
fmt.Println("failed to make decoder for", k, err)
}
}
decodeFunction.Body = NewBlock(append(s, Return()))
AppendDecl(g.File, decodeFunction)
args = []NameAndType{{"w", Ident("io.Writer")}}
rets = []NameAndType{{"err", Ident("error")}}
encodeFunction := NewFuncWithReceiver("Encode", "ret", tName, args, rets)
g.Depth = 0
s, err = g.VisitEncoder(retExpr, v, tName)
if err != nil {
s = ToDoStmts
if !errors.Is(err, ToDoError) {
fmt.Println("failed to make encoder for", k, err)
}
}
encodeFunction.Body = NewBlock(append(s, Return()))
AppendDecl(g.File, encodeFunction)
}
return nil
}
func (g *Generator) GenerateState(prefix string, state State) (err error) {
err = g.GenerateTypes(prefix+"ToServer", state.ToServer)
if err != nil {
return
}
err = g.GenerateTypes(prefix+"ToClient", state.ToClient)
return
}
func (g *Generator) GenerateProtocol(protocol Protocol) (err error) {
err = g.GenerateTypes("", protocol.Types)
if err != nil {
return
}
err = g.GenerateState("Handshaking", protocol.Handshaking)
if err != nil {
return
}
err = g.GenerateState("Status", protocol.Status)
if err != nil {
return
}
err = g.GenerateState("Login", protocol.Login)
if err != nil {
return
}
err = g.GenerateState("Configuration", protocol.Configuration)
if err != nil {
return
}
err = g.GenerateState("Play", protocol.Play)
return
}
func Generate(version string, w io.Writer) (err error) {
protocol := Protocol{}
err = data.LoadVersionedJson(version, "protocol", &protocol)
if err != nil {
return
}
g := &Generator{Protocol: protocol}
// These have annoying edge cases that would require me to implement a whole new compareTo parser
g.Settings.ReplaceWithTodoNames = []string{"packet_scoreboard_score", "packet_advancements"}
g.File = NewFile("v" + strings.ReplaceAll(version, ".", "_"))
AppendDecl(g.File, Import("encoding/binary", "io", "github.com/admin-else/queser", "github.com/admin-else/queser/nbt", "github.com/google/uuid"))
g.RegisterNatives()
g.RegisterDecoderNatives()
g.RegisterEncoderNatives()
g.RegisterCompareToNatives()
err = g.GenerateProtocol(protocol)
if err != nil {
return
}
return PrintToFile(g.File, w)
}
func generateVersion(v string) (err error) {
vUnderscore := strings.ReplaceAll(v, ".", "_")
err = os.MkdirAll("generated/v"+vUnderscore, 0755)
if err != nil {
return
}
f, err := os.Create("generated/v" + vUnderscore + "/proto.go")
if err != nil {
return
}
defer f.Close()
err = Generate(v, f)
if err != nil {
return
}
helperF, err := os.Create("generated/v" + vUnderscore + "/helpers.go")
if err != nil {
return
}
defer f.Close()
err = GenerateHelpers(v, helperF)
return
}
func GenerateVersions(versions []string) (err error) {
err = os.RemoveAll("generated/")
if err != nil {
return
}
err = os.MkdirAll("generated/", 0755)
if err != nil {
return
}
f, err := os.Create("generated/version_switcher.go")
if err != nil {
return
}
defer f.Close()
err = GenerateVersionSwitcher(versions, f)
for _, version := range versions {
fmt.Println("generating", version)
err = generateVersion(version)
if err != nil {
return
}
}
return
}
func main() {
err := GenerateVersions([]string{"1.21.8"})
if err != nil {
panic(err)
}
}
+108
View File
@@ -0,0 +1,108 @@
package main
import (
"errors"
"fmt"
"go/ast"
"strings"
"github.com/go-viper/mapstructure/v2"
)
func ParseCompareTo(g *Generator, compareTo string) (e ast.Expr, err error) {
parts := strings.Split(compareTo, "/")
downPrefixCount := 0
for _, part := range parts {
if part == ".." {
downPrefixCount++
}
}
parts = parts[downPrefixCount:]
startingPoint := g.ContainerStack[len(g.ContainerStack)-downPrefixCount-1]
e, err = g.VisitCompareTo(parts, startingPoint.VarToSet, CombineNamAndData("container", startingPoint.Data))
// return ParseCompareToLegacy(compareTo, varToSet)
return
}
func (g *Generator) VisitCompareTo(parts []string, inExpr ast.Expr, data any) (e ast.Expr, err error) {
tName, tData, err := ParseType(data)
if err != nil {
return
}
d, found := g.CompareToNatives[tName]
if found {
return d(g, parts, inExpr, tData)
}
err = fmt.Errorf("native compare to not implemented for %v", tName)
return
}
func ContainerCompareTo(g *Generator, parts []string, inExpr ast.Expr, dataRaw any) (e ast.Expr, err error) {
var data []struct {
Name string
Type any
Anon bool
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
name, parts, ok := PopFront(parts)
if !ok {
err = errors.New("expected name part")
return
}
for _, field := range data {
if field.Name == name {
return g.VisitCompareTo(parts, SelectorExprAndStr(inExpr, CamelCase(field.Name)), field.Type)
}
}
err = errors.New("field not found")
return
}
func ReturnInputCompareTo(_ *Generator, _ []string, inExpr ast.Expr, _ any) (e ast.Expr, err error) {
return inExpr, nil
}
func BitflagsCompareTo(_ *Generator, parts []string, inExpr ast.Expr, dataRaw any) (e ast.Expr, err error) {
var data struct {
Flags []string
Type any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
name, parts, ok := PopFront(parts)
if !ok {
err = errors.New("expected name part")
return
}
for i, flag := range data.Flags {
if flag != name {
continue
}
e = NotEquals(BinAnd(inExpr, NumLitHex(1<<i)), NumLit(0))
return
}
err = errors.New("flag not found")
return
}
func (g *Generator) RegisterCompareToNatives() {
g.CompareToNatives = map[string]CompareToGeneratorFunc{
"container": ContainerCompareTo,
"bool": ReturnInputCompareTo,
"mapper": ReturnInputCompareTo,
"varint": ReturnInputCompareTo,
"bitfield": ReturnInputCompareTo,
"u8": ReturnInputCompareTo,
"i8": ReturnInputCompareTo,
"bitflags": BitflagsCompareTo,
"switch": ReturnInputCompareTo,
"varlong": ReturnInputCompareTo,
}
}
+523
View File
@@ -0,0 +1,523 @@
package main
import (
"go/ast"
"go/token"
"slices"
"strconv"
"github.com/go-viper/mapstructure/v2"
)
func DefaultDecoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign(
Exprs(varToSet, Ident("err")),
Exprs(Call(SelectorExprAndStr(varToSet, "Decode"), Ident("r"))),
),
IfErrNil(),
)
return
}
func UUIDDecoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
//_, err = io.ReadFull(r, U[:])
s = Stmts(
Assign(Exprs(Ident("_"), Ident("err")), Exprs(Call(Selector("io", "ReadFull"), Ident("r"), MultiIndex(varToSet, nil, nil, nil)))),
IfErrNil(),
)
return
}
func ContainerDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data []struct {
Name string
Type any
Anon bool
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
g.ContainerStack = append(g.ContainerStack, ContainerStackEntry{
Data: data,
VarToSet: varToSet,
})
defer func() { g.ContainerStack = g.ContainerStack[:len(g.ContainerStack)-1] }()
for _, field := range data {
var statements []ast.Stmt
cName := CamelCase(field.Name)
if field.Anon {
cName = "Anon"
}
statements, err = g.VisitDecoder(SelectorExprAndStr(varToSet, cName), field.Type, name+cName)
if err != nil {
return
}
s = append(s, statements...)
}
return
}
func SimpleTypeDecoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign(
Exprs(Ident("err")),
Exprs(Call(Selector("binary", "Read"), Ident("r"), Selector("binary", "BigEndian"), AddrOf(varToSet))),
),
IfErrNil(),
)
return
}
func StringDecoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign(Exprs(varToSet, Ident("err")), Exprs(Call(Selector("queser", "DecodeString"), Ident("r")))),
IfErrNil(),
)
return
}
func OptionDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
pVarName := name + "Present"
tVarName := name + "PresentValue"
boolStmts, err := g.VisitDecoder(Ident(pVarName), "bool", name)
if err != nil {
return
}
t, err := g.VisitType(dataRaw)
if err != nil {
return
}
tStmts1 := Stmts(VarStmt(tVarName, t))
tStmts2, err := g.VisitDecoder(Ident(tVarName), dataRaw, name)
if err != nil {
return
}
// This looks so shit
tStmts := append(tStmts1, tStmts2...)
tStmts = append(tStmts, Assign121(varToSet, AddrOf(Ident(tVarName))))
s = append(s, VarStmt(pVarName, Ident("bool")))
s = append(s, boolStmts...)
s = append(s, If(Ident(pVarName), NewBlock(tStmts)))
return
}
func ArrayDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
CountType any
Type any
}
lName := "l" + CamelCase(name)
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
countType, err := g.VisitType(data.CountType)
if err != nil {
return
}
s2, err := g.VisitDecoder(Ident(lName), data.CountType, name)
if err != nil {
return
}
normalType, err := g.VisitType(data.Type)
if err != nil {
return
}
arrayType, err := g.VisitNameAndData("array", dataRaw)
if err != nil {
return
}
tName := name + "Element"
rangeStatements := Stmts(VarStmt(tName, normalType))
s5, err := g.VisitDecoder(Ident(tName), data.Type, tName)
rangeStatements = append(rangeStatements, s5...)
rangeStatements = append(rangeStatements, Assign121(varToSet, Call(Ident("append"), varToSet, Ident(tName))))
if err != nil {
return
}
s1 := VarStmt(lName, countType)
s3 := Assign121(varToSet, CompLit(arrayType, Exprs()))
s4 := ForRange(nil, Ident(lName), NewBlock(rangeStatements))
s = append(s, s1)
s = append(s, s2...)
s = append(s, s3)
s = append(s, s4)
return
}
func TypeForwardDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
Type string
}
if err = mapstructure.Decode(dataRaw, &data); err != nil {
return
}
return g.VisitDecoder(varToSet, data.Type, name)
}
var DontStringify = []string{"true", "false"}
// CaseExprType This exists to fix this
// "switch",
//
// {
// "compareTo": "itemCount",
// "fields": {
// "0": "void",
// "false": "void"
// },
// "default": [
//
// Protodef is best!!!
type CaseExprType int
const (
CaseExprTypeUnset CaseExprType = iota
CaseExprTypeNumber
CaseExprTypeSpecial
CaseExprTypeString
)
func MultiTypeFix(s string, t *CaseExprType) (e ast.Expr) {
n, err := strconv.Atoi(s)
ct := CaseExprTypeUnset
if err == nil {
err = nil
e = NumLit(n)
ct = CaseExprTypeNumber
} else if slices.Contains(DontStringify, s) {
e = Ident(s)
ct = CaseExprTypeSpecial
} else {
e = StrLit(s)
ct = CaseExprTypeString
}
if *t == CaseExprTypeUnset {
*t = ct
return
}
if *t != ct {
e = nil
}
return
}
func SwitchDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
CompareTo string
Fields map[string]any
Default any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
compareToExpr, err := ParseCompareTo(g, data.CompareTo)
if err != nil {
return
}
cet := CaseExprTypeUnset
for _, fName := range OrderedKeys(data.Fields) {
fType := data.Fields[fName]
e := MultiTypeFix(fName, &cet)
if e == nil {
continue
}
var tType ast.Expr
tType, err = g.VisitType(fType)
if err != nil {
return
}
tName := name + "Tmp"
s1 := VarStmt(tName, tType)
s3 := Assign121(varToSet, Ident(tName))
var caseDecodeValueStmts []ast.Stmt
caseDecodeValueStmts, err = g.VisitDecoder(Ident(tName), fType, name)
if err != nil {
return
}
var caseStmts []ast.Stmt
caseStmts = append(caseStmts, s1)
caseStmts = append(caseStmts, caseDecodeValueStmts...)
caseStmts = append(caseStmts, s3)
s = append(s, Case(Exprs(e), caseStmts))
}
if data.Default != nil {
var tType ast.Expr
tType, err = g.VisitType(data.Default)
tName := name + "Tmp"
s1 := VarStmt(tName, tType)
s3 := Assign121(varToSet, Ident(tName))
var caseDecodeValueStmts []ast.Stmt
caseDecodeValueStmts, err = g.VisitDecoder(Ident(tName), data.Default, name)
if err != nil {
return
}
var caseStmts []ast.Stmt
caseStmts = append(caseStmts, s1)
caseStmts = append(caseStmts, caseDecodeValueStmts...)
caseStmts = append(caseStmts, s3)
s = append(s, Case(nil, caseStmts))
}
if len(s) != 0 {
s = Stmts(SwitchStmt(compareToExpr, NewBlock(s)))
}
return
}
var ToDoStmts = Stmts(Assign121(Ident("err"), Selector("queser", "ToDoError")))
func ToDoDecoder(_ *Generator, _ ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
err = ToDoError
return
}
func MapperDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
Mappings map[string]string
Type any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
kName := CamelCase(name) + "Key"
kType, err := g.VisitType(data.Type)
if err != nil {
return
}
s1 := VarStmt(kName, kType)
s2, err := g.VisitDecoder(Ident(kName), data.Type, name)
if err != nil {
return
}
mName := name + "Map"
expressions := Exprs()
for _, k := range OrderedKeys(data.Mappings) {
v := data.Mappings[k]
expressions = append(expressions, KeyValueExpr(NumLitStr(k), StrLit(v)))
}
g.Decl(mName, token.VAR, CompLit(MapType(kType, Ident("string")), expressions))
s3 := Assign(Exprs(varToSet, Ident("err")), Exprs(Call(Selector("queser", "ErroringIndex"), Ident(mName), Ident(kName))))
s = append(s, s1)
s = append(s, s2...)
s = append(s, s3)
s = append(s, IfErrNil())
return
}
func BufferDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
Count int
CountType any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
// rawString, err := io.ReadAll(io.LimitReader(r, int64(l)))
if data.CountType != nil {
lName := "l" + CamelCase(name)
var countType ast.Expr
countType, err = g.VisitType(data.CountType)
if err != nil {
return
}
var s2 []ast.Stmt
s2, err = g.VisitDecoder(Ident(lName), data.CountType, name)
if err != nil {
return
}
s1 := VarStmt(lName, countType)
s3 := Assign(Exprs(varToSet, Ident("err")), Exprs(Call(Selector("io", "ReadAll"), Call(Selector("io", "LimitReader"), Ident("r"), Call(Ident("int64"), Ident(lName))))))
s = append(s, s1)
s = append(s, s2...)
s = append(s, s3)
} else {
s = Stmts(Assign(Exprs(Ident("_"), Ident("err")), Exprs(Call(Selector("r", "Read"), MultiIndex(varToSet, nil, nil, nil)))))
}
s = append(s, IfErrNil())
return
}
func BitFieldDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data []struct {
Name string
Singed bool
Size int
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
totalSize := 0
for _, field := range data {
totalSize += field.Size
}
p, err := TotalBitfieldSizeToProtodefName(totalSize)
if err != nil {
return
}
return g.VisitDecoder(varToSet, p, name)
}
func RegistryEntryHolderSetDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
Base struct {
Name string
Type any
}
Otherwise struct {
Name string
Type any
}
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
var countType ast.Expr
countType, err = g.VisitType("varint")
if err != nil {
return
}
baseType, err := g.VisitType(data.Base.Type)
if err != nil {
return
}
otherwiseArrayType, err := g.VisitNameAndData("array", map[string]any{"type": data.Otherwise.Type})
if err != nil {
return
}
otherwiseType, err := g.VisitType(data.Otherwise.Type)
if err != nil {
return
}
lName := "l" + CamelCase(name)
s1 := VarStmt(lName, countType)
s2, err := g.VisitDecoder(Ident(lName), "varint", name)
if err != nil {
return
}
s3 := Assign121(Ident(lName), Sub(Ident(lName), NumLit(1)))
resultName := name + "Result"
b1s1 := VarStmt(resultName, baseType)
b1s2, err := g.VisitDecoder(Ident(resultName), data.Base.Type, resultName)
b1s3 := Assign121(varToSet, Ident(resultName))
b1s4 := Return()
var b1 []ast.Stmt
b1 = append(b1, b1s1)
b1 = append(b1, b1s2...)
b1 = append(b1, b1s3)
b1 = append(b1, b1s4)
tName := name + "Element"
rangeStatements := Stmts(VarStmt(tName, otherwiseType))
rangeStatementsDecode, err := g.VisitDecoder(Ident(tName), data.Otherwise.Type, tName)
rangeStatements = append(rangeStatements, rangeStatementsDecode...)
rangeStatements = append(rangeStatements, Assign121(Ident(resultName), Call(Ident("append"), Ident(resultName), Ident(tName))))
s5 := If(Equals(Ident(lName), NumLit(-1)), NewBlock(b1))
s6 := VarStmt(resultName, otherwiseArrayType)
s7 := ForRange(nil, Ident(lName), NewBlock(rangeStatements))
s = append(s, s1)
s = append(s, s2...)
s = append(s, s3)
s = append(s, s5)
s = append(s, s6)
s = append(s, s7)
return
}
func RegistryEntryHolderDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data EntryHolderSet
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
idName := name + "Id"
IdVar := VarStmt(idName, Selector("queser", "VarInt"))
idDecodeStatements, err := g.VisitDecoder(Ident(idName), "varint", name)
if err != nil {
return
}
idPath := If(NotEquals(Ident(idName), NumLit(0)), NewBlockEllipsis(Assign121(varToSet, Ident(idName)), Return()))
otherwiseType, err := g.VisitType(data.Otherwise.Type)
if err != nil {
return
}
resName := name + "Result"
resNameIdent := Ident(resName)
resultVar := VarStmt(resName, otherwiseType)
otherwiseDecodeStatements, err := g.VisitDecoder(resNameIdent, data.Otherwise.Type, name+"Otherwise")
if err != nil {
return
}
resultAssign := Assign121(varToSet, resNameIdent)
s = append(s, IdVar)
s = append(s, idDecodeStatements...)
s = append(s, idPath)
s = append(s, resultVar)
s = append(s, otherwiseDecodeStatements...)
s = append(s, resultAssign)
return
}
func (g *Generator) RegisterDecoderNatives() {
g.DecoderNatives = map[string]FunctionGeneratorFunc{
"container": ContainerDecoder,
"array": ArrayDecoder,
"option": OptionDecoder,
"bitflags": TypeForwardDecoder,
"switch": SwitchDecoder,
"mapper": MapperDecoder,
"buffer": BufferDecoder,
"bitfield": BitFieldDecoder,
"string": StringDecoder,
"void": DefaultDecoder,
"varint": DefaultDecoder,
"anonymousNbt": DefaultDecoder,
"anonOptionalNbt": DefaultDecoder, // I have no idea what the difference is between these two
"UUID": UUIDDecoder,
"restBuffer": DefaultDecoder,
"f32": SimpleTypeDecoder,
"f64": SimpleTypeDecoder,
"i8": SimpleTypeDecoder,
"i16": SimpleTypeDecoder,
"i32": SimpleTypeDecoder,
"i64": SimpleTypeDecoder,
"u8": SimpleTypeDecoder,
"u16": SimpleTypeDecoder,
"u32": SimpleTypeDecoder,
"u64": SimpleTypeDecoder,
"bool": SimpleTypeDecoder,
"registryEntryHolder": RegistryEntryHolderDecoder,
"registryEntryHolderSet": RegistryEntryHolderSetDecoder,
"entityMetadataLoop": ToDoDecoder,
"topBitSetTerminatedArray": ToDoDecoder,
"todo": ToDoDecoder,
}
}
+356
View File
@@ -0,0 +1,356 @@
package main
import (
"errors"
"go/ast"
"go/token"
"github.com/go-viper/mapstructure/v2"
)
func DefaultEncoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign121(
Ident("err"),
Call(SelectorExprAndStr(varToSet, "Encode"), Ident("w")),
),
IfErrNil(),
)
return
}
func ContainerEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data []struct {
Name string
Type any
Anon bool
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
g.ContainerStack = append(g.ContainerStack, ContainerStackEntry{
Data: data,
VarToSet: varToSet,
})
defer func() { g.ContainerStack = g.ContainerStack[:len(g.ContainerStack)-1] }()
for _, field := range data {
var statements []ast.Stmt
cName := CamelCase(field.Name)
if field.Anon {
cName = "Anon"
}
statements, err = g.VisitEncoder(SelectorExprAndStr(varToSet, cName), field.Type, name+CamelCase(cName))
if err != nil {
return
}
s = append(s, statements...)
}
return
}
func SimpleTypeEncoder(_ *Generator, data ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign121(
Ident("err"),
Call(Selector("binary", "Write"), Ident("w"), Selector("binary", "BigEndian"), data),
),
IfErrNil(),
)
return
}
func ArrayEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
CountType any
Type any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
ct, err := g.VisitType(data.CountType)
if err != nil {
return
}
_, ok := ct.(*ast.Ident)
if !ok {
err = errors.New("array count type must be simple type otherwise wtf")
}
iName := "i" + name
s, err = g.VisitEncoder(varToSet, data.Type, name)
s1, err := g.VisitEncoder(Call(ct, Call(Ident("len"), varToSet)), data.CountType, name)
if err != nil {
return
}
s2, err := g.VisitEncoder(Index(varToSet, Ident(iName)), data.Type, name+"Inner")
if err != nil {
}
s2 = Stmts(ForRange(Ident(iName), Call(Ident("len"), varToSet), NewBlock(s2)))
s = append(s1, s2...)
return
}
func ToDoEncoder(_ *Generator, _ ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
err = ToDoError
return
}
func OptionEncoder(g *Generator, data ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
cond := NotEquals(data, Nil())
s1, err := g.VisitEncoder(cond, "bool", name)
if err != nil {
return
}
s2, err := g.VisitEncoder(DeRef(data), dataRaw, name)
if err != nil {
return
}
s = append(s1, If(cond, NewBlock(s2)))
return
}
func BufferEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
Count int
CountType any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
if data.CountType != nil {
var countType ast.Expr
countType, err = g.VisitType(data.CountType)
if err != nil {
return
}
var s2 []ast.Stmt
s2, err = g.VisitEncoder(Call(countType, Call(Ident("len"), varToSet)), data.CountType, name)
if err != nil {
return
}
s = append(s, s2...)
} else {
s = append(s, Define121(Ident("arr"), varToSet))
varToSet = MultiIndex(Ident("arr"), nil, nil, nil)
}
s = append(s, Assign(Exprs(Ident("_"), Ident("err")), Exprs(Call(Selector("w", "Write"), varToSet))))
s = append(s, IfErrNil())
return
}
func BitFieldEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data []struct {
Name string
Singed bool
Size int
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
totalSize := 0
for _, field := range data {
totalSize += field.Size
}
p, err := TotalBitfieldSizeToProtodefName(totalSize)
if err != nil {
return
}
return g.VisitEncoder(varToSet, p, name)
}
func SwitchEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
CompareTo string
Fields map[string]any
Default any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
compareToExpr, err := ParseCompareTo(g, data.CompareTo)
if err != nil {
return
}
cet := CaseExprTypeUnset
for _, fName := range OrderedKeys(data.Fields) {
fType := data.Fields[fName]
e := MultiTypeFix(fName, &cet)
if e == nil {
continue
}
var tType ast.Expr
tType, err = g.VisitType(fType)
if err != nil {
return
}
s1 := Define(Exprs(Ident(name), Ident("ok")), Exprs(TypeAssert(varToSet, tType)))
s2 := If(Not(Ident("ok")), NewBlockEllipsis(Assign121(Ident("err"), Selector("queser", "BadTypeError")), Return()))
var caseDecodeValueStmts []ast.Stmt
caseDecodeValueStmts, err = g.VisitEncoder(Ident(name), fType, name)
if err != nil {
return
}
var caseStmts []ast.Stmt
caseStmts = append(caseStmts, s1)
caseStmts = append(caseStmts, s2)
caseStmts = append(caseStmts, caseDecodeValueStmts...)
s = append(s, Case(Exprs(e), caseStmts))
}
if data.Default != nil {
var tType ast.Expr
tType, err = g.VisitType(data.Default)
if err != nil {
return
}
s1 := Define(Exprs(Ident("_"), Ident("ok")), Exprs(TypeAssert(varToSet, tType)))
s2 := If(Not(Ident("ok")), NewBlockEllipsis(Assign121(Ident("err"), Selector("queser", "BadTypeError")), Return()))
defaultStmts := []ast.Stmt{s1, s2}
var defaultEncodingStmts []ast.Stmt
defaultEncodingStmts, err = g.VisitEncoder(TypeAssert(varToSet, tType), data.Default, name)
if err != nil {
return
}
defaultStmts = append(defaultStmts, defaultEncodingStmts...)
s = append(s, Case(nil, defaultStmts))
}
if len(s) != 0 {
s = Stmts(SwitchStmt(compareToExpr, NewBlock(s)))
}
return
}
func TypeForwardEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
Type string
}
if err = mapstructure.Decode(dataRaw, &data); err != nil {
return
}
return g.VisitEncoder(varToSet, data.Type, name)
}
func MapperEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data struct {
Mappings map[string]string
Type any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
kType, err := g.VisitType(data.Type)
if err != nil {
return
}
mName := name + "ReverseMap"
exprs := Exprs()
for _, k := range OrderedKeys(data.Mappings) {
v := data.Mappings[k]
exprs = append(exprs, KeyValueExpr(StrLit(v), NumLitStr(k)))
}
g.Decl(mName, token.VAR, CompLit(MapType(Ident("string"), kType), exprs))
vName := "v" + name
s1 := VarStmt(vName, kType)
s2 := Assign(Exprs(Ident(vName), Ident("err")), Exprs(Call(Selector("queser", "ErroringIndex"), Ident(mName), varToSet)))
s3 := IfErrNil()
s4, err := g.VisitEncoder(Ident(vName), data.Type, name)
if err != nil {
return
}
s = append(s, s1)
s = append(s, s2)
s = append(s, s3)
s = append(s, s4...)
return
}
func StringEncoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(
Assign121(Ident("err"), Call(Selector("queser", "EncodeString"), Ident("w"), varToSet)), IfErrNil())
return
}
func UUIDEncoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) {
s = Stmts(Assign(Exprs(Ident("_"), Ident("err")), Exprs(Call(Selector("w", "Write"), MultiIndex(varToSet, nil, nil, nil)))), IfErrNil())
return
}
func RegistryEntryHolderEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
var data EntryHolderSet
err = mapstructure.Decode(dataRaw, &data)
otherwiseType, err := g.VisitType(data.Otherwise.Type)
if err != nil {
return
}
knownTypeName := name + "KnownType"
otherwiseEncodeStatements, err := g.VisitEncoder(Ident(knownTypeName), data.Otherwise.Type, name+"Otherwise")
if err != nil {
return
}
baseType, err := g.VisitType("varint")
if err != nil {
return
}
baseEncodeStatements, err := g.VisitEncoder(Ident(knownTypeName), "varint", name)
if err != nil {
return
}
statements := Stmts()
statements = append(statements, Case(Exprs(baseType), baseEncodeStatements))
statements = append(statements, Case(Exprs(otherwiseType), otherwiseEncodeStatements))
statements = append(statements, Case(nil, Stmts(Assign121(Ident("err"), Selector("queser", "BadTypeError")))))
s = Stmts(TypeSwitch(Define121(Ident(knownTypeName), TypeAssert(varToSet, Ident("type"))), NewBlock(statements)))
return
}
func (g *Generator) RegisterEncoderNatives() {
g.EncoderNatives = map[string]FunctionGeneratorFunc{
"container": ContainerEncoder,
"array": ArrayEncoder,
"option": OptionEncoder,
"bitflags": TypeForwardEncoder,
"switch": SwitchEncoder,
"mapper": MapperEncoder,
"buffer": BufferEncoder,
"bitfield": BitFieldEncoder,
"void": DefaultEncoder,
"varint": DefaultEncoder,
"anonymousNbt": DefaultEncoder,
"anonOptionalNbt": DefaultEncoder, // I have no idea what the difference is between these two
"UUID": UUIDEncoder,
"restBuffer": DefaultEncoder,
"string": StringEncoder,
"f32": SimpleTypeEncoder,
"f64": SimpleTypeEncoder,
"i8": SimpleTypeEncoder,
"i16": SimpleTypeEncoder,
"i32": SimpleTypeEncoder,
"i64": SimpleTypeEncoder,
"u8": SimpleTypeEncoder,
"u16": SimpleTypeEncoder,
"u32": SimpleTypeEncoder,
"u64": SimpleTypeEncoder,
"bool": SimpleTypeEncoder,
"registryEntryHolder": RegistryEntryHolderEncoder,
"registryEntryHolderSet": ToDoEncoder,
"entityMetadataLoop": ToDoEncoder,
"topBitSetTerminatedArray": ToDoEncoder,
"todo": ToDoEncoder,
}
}
+192
View File
@@ -0,0 +1,192 @@
package main
import (
"errors"
"fmt"
"go/ast"
"github.com/go-viper/mapstructure/v2"
)
func VisitContainerType(g *Generator, dataRaw any) (ast.Expr, error) {
var data []struct {
Name string
Type any
Anon bool
}
err := mapstructure.Decode(dataRaw, &data)
if err != nil {
return nil, err
}
g.ContainerStack = append(g.ContainerStack, ContainerStackEntry{
Data: data,
VarToSet: nil,
})
defer func() { g.ContainerStack = g.ContainerStack[:len(g.ContainerStack)-1] }()
s := NewStruct()
for _, field := range data {
t, err := g.VisitType(field.Type)
if err != nil {
return nil, err
}
if field.Anon {
field.Name = "Anon" // lol
}
AddFieldToStruct(s, CamelCase(field.Name), t)
}
return s, nil
}
func VisitBufferType(_ *Generator, dataRaw any) (e ast.Expr, err error) {
var data struct {
CountType any
Count int
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
if data.CountType != nil {
if data.CountType == "varint" {
e = Slice(Ident("byte"))
return
}
return nil, fmt.Errorf("unsupported count type: %v", data.CountType) // TODO: old versions use uint16 as count type
}
e = Array(Ident("byte"), data.Count)
return
}
func VisitArrayTypeVisitorType(g *Generator, dataRaw any) (ast.Expr, error) {
var data struct {
CountType any
Type any
}
must(mapstructure.Decode(dataRaw, &data))
e, err := g.VisitType(data.Type)
if err != nil {
return nil, err
}
return Slice(e), nil
}
func VisitDontGenerateType(_ *Generator, _ any) (ast.Expr, error) {
return nil, nil
}
func VisitToDoType(_ *Generator, _ any) (e ast.Expr, err error) {
err = ToDoError
return
}
func VisitOptionType(g *Generator, dataRaw any) (e ast.Expr, err error) {
e, err = g.VisitType(dataRaw)
if err != nil {
return
}
e = Pointer(e)
return
}
func TotalBitfieldSizeToProtodefName(totalSize int) (e string, err error) {
if totalSize <= 8 {
e = "u8"
} else if totalSize <= 16 {
e = "u16"
} else if totalSize <= 32 {
e = "u32"
} else if totalSize <= 64 {
e = "u64"
} else {
err = errors.New("bitfield size too large")
}
return
}
func VisitBitFieldType(g *Generator, dataRaw any) (e ast.Expr, err error) {
var data []struct {
Name string
Singed bool
Size int
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
totalSize := 0
for _, field := range data {
totalSize += field.Size
}
// TODO: we will want to generate Methods and other stuff
p, err := TotalBitfieldSizeToProtodefName(totalSize)
if err != nil {
return
}
return g.VisitType(p)
}
func VisitBitFlagsType(g *Generator, dataRaw any) (e ast.Expr, err error) {
var data struct {
Flags []string
Type any
}
err = mapstructure.Decode(dataRaw, &data)
if err != nil {
return
}
return g.VisitType(data.Type)
}
func MakeIdentVisitor(name string) func(g *Generator, dataRaw any) (e ast.Expr, err error) {
return func(g *Generator, dataRaw any) (e ast.Expr, err error) {
e = Ident(name)
return
}
}
func MakeSelectorVisitor(x, sel string) func(g *Generator, dataRaw any) (e ast.Expr, err error) {
return func(g *Generator, dataRaw any) (e ast.Expr, err error) {
e = Selector(x, sel)
return
}
}
func (g *Generator) RegisterNatives() {
g.Natives = map[string]ExprGeneratorFunc{
"container": VisitContainerType,
"buffer": VisitBufferType,
"varint": MakeSelectorVisitor("queser", "VarInt"),
"array": VisitArrayTypeVisitorType,
"mapper": MakeIdentVisitor("string"),
"native": VisitDontGenerateType,
"anonymousNbt": MakeSelectorVisitor("nbt", "Anon"),
"anonOptionalNbt": MakeSelectorVisitor("nbt", "Anon"), // I have no idea what the difference is between these two
"void": MakeSelectorVisitor("queser", "Void"),
"bool": MakeIdentVisitor("bool"),
"u8": MakeIdentVisitor("uint8"),
"u16": MakeIdentVisitor("uint16"),
"u32": MakeIdentVisitor("uint32"),
"u64": MakeIdentVisitor("uint64"),
"i8": MakeIdentVisitor("int8"),
"i16": MakeIdentVisitor("int16"),
"i32": MakeIdentVisitor("int32"),
"i64": MakeIdentVisitor("int64"),
"f32": MakeIdentVisitor("float32"),
"f64": MakeIdentVisitor("float64"),
"registryEntryHolder": MakeIdentVisitor("any"), // Go really fucking needs good tagged unions
"registryEntryHolderSet": MakeIdentVisitor("any"),
"entityMetadataLoop": VisitToDoType,
"option": VisitOptionType,
"switch": MakeIdentVisitor("any"),
"UUID": MakeSelectorVisitor("uuid", "UUID"),
"bitfield": VisitBitFieldType,
"pstring": VisitDontGenerateType,
"string": MakeIdentVisitor("string"),
"restBuffer": MakeSelectorVisitor("queser", "RestBuffer"),
"bitflags": VisitBitFlagsType,
"topBitSetTerminatedArray": VisitToDoType,
"todo": VisitToDoType,
}
}
+462
View File
@@ -0,0 +1,462 @@
package main
import (
"fmt"
"go/ast"
"go/format"
"go/token"
"io"
)
func NewStruct() *ast.StructType {
return &ast.StructType{
Fields: &ast.FieldList{
List: []*ast.Field{},
},
}
}
func AddFieldToStruct(s *ast.StructType, fieldName string, t ast.Expr) {
s.Fields.List = append(s.Fields.List, &ast.Field{
Names: []*ast.Ident{
{
Name: fieldName,
},
},
Type: t,
})
}
//func AddAnonFieldToStruct(s *ast.StructType, t ast.Expr) {
// s.Fields.List = append(s.Fields.List, &ast.Field{
// Names: []*ast.Ident{},
// Type: t,
// })
//}
func Import(path ...string) ast.Decl {
specs := make([]ast.Spec, len(path))
for i, p := range path {
specs[i] = &ast.ImportSpec{
Path: StrLit(p),
}
}
return &ast.GenDecl{
Tok: token.IMPORT,
Specs: specs,
}
}
func Ident(name string) *ast.Ident {
return ast.NewIdent(name)
}
func VarStmt(name string, t ast.Expr) *ast.DeclStmt {
return &ast.DeclStmt{Decl: Var(name, t)}
}
func Var(name string, t ast.Expr) ast.Decl {
return &ast.GenDecl{
Tok: token.VAR,
Specs: []ast.Spec{
&ast.ValueSpec{
Names: []*ast.Ident{
{
Name: name,
},
},
Type: t,
},
},
}
}
func Slice(elementType ast.Expr) ast.Expr {
return &ast.ArrayType{
Len: nil, // nil Length means it's a slice, not an array
Elt: elementType,
}
}
func NumLit(n int) *ast.BasicLit {
return NumLitStr(fmt.Sprint(n))
}
func NumLitHex(n int) *ast.BasicLit {
return NumLitStr(fmt.Sprintf("%X", n))
}
func NumLitStr(n string) *ast.BasicLit {
return &ast.BasicLit{
ValuePos: 0,
Kind: token.INT,
Value: n,
}
}
func Array(elementType ast.Expr, len int) ast.Expr {
return &ast.ArrayType{
Len: NumLit(len),
Elt: elementType,
}
}
func TypeDecl(name string, t ast.Expr) ast.Decl {
return &ast.GenDecl{
Tok: token.TYPE,
Specs: []ast.Spec{
&ast.TypeSpec{
Name: &ast.Ident{
Name: name,
},
Type: t,
},
},
}
}
func Selector(x, sel string) ast.Expr {
return &ast.SelectorExpr{
X: Ident(x),
Sel: Ident(sel),
}
}
func SelectorExprAndStr(x ast.Expr, sel string) ast.Expr {
return &ast.SelectorExpr{
X: x,
Sel: Ident(sel),
}
}
func Pointer(elementType ast.Expr) ast.Expr {
return &ast.StarExpr{
X: elementType,
}
}
func Call(fn ast.Expr, args ...ast.Expr) *ast.CallExpr {
return &ast.CallExpr{
Fun: fn,
Args: args,
}
}
func Assign121(lhs, rhs ast.Expr) *ast.AssignStmt {
return &ast.AssignStmt{
Lhs: []ast.Expr{lhs},
Tok: token.ASSIGN,
Rhs: []ast.Expr{rhs},
}
}
func Assign(lhs, rhs []ast.Expr) *ast.AssignStmt {
return &ast.AssignStmt{
Lhs: lhs,
Tok: token.ASSIGN,
Rhs: rhs,
}
}
func Define(lhs, rhs []ast.Expr) *ast.AssignStmt {
return &ast.AssignStmt{
Lhs: lhs,
Tok: token.DEFINE,
Rhs: rhs,
}
}
func Define121(lhs, rhs ast.Expr) *ast.AssignStmt {
return &ast.AssignStmt{
Lhs: []ast.Expr{lhs},
Tok: token.DEFINE,
Rhs: []ast.Expr{rhs},
}
}
func Exprs(exprs ...ast.Expr) []ast.Expr {
return exprs
}
func Stmts(stmts ...ast.Stmt) []ast.Stmt {
return stmts
}
func ExprStmt(expr ast.Expr) *ast.ExprStmt {
return &ast.ExprStmt{
X: expr,
}
}
func If(cond ast.Expr, body *ast.BlockStmt) *ast.IfStmt {
return &ast.IfStmt{
Cond: cond,
Body: body,
}
}
func NotEquals(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.NEQ,
Y: rhs,
}
}
func Equals(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.EQL,
Y: rhs,
}
}
func Nil() ast.Expr {
return Ident("nil")
}
func NewFile(name string) *ast.File {
return &ast.File{
Name: &ast.Ident{
Name: name,
},
Decls: []ast.Decl{},
}
}
type NameAndType struct {
Name string
Type ast.Expr
}
func NewFunc(name string, arguments []NameAndType, returns []NameAndType) *ast.FuncDecl {
params := &ast.FieldList{
List: make([]*ast.Field, len(arguments)),
}
for i, arg := range arguments {
params.List[i] = &ast.Field{
Names: []*ast.Ident{Ident(arg.Name)},
Type: arg.Type,
}
}
results := &ast.FieldList{
List: make([]*ast.Field, len(returns)),
}
for i, ret := range returns {
results.List[i] = &ast.Field{
Names: []*ast.Ident{{Name: ret.Name}},
Type: ret.Type,
}
}
return &ast.FuncDecl{
Name: Ident(name),
Type: &ast.FuncType{
Params: params,
Results: results,
},
Body: &ast.BlockStmt{},
}
}
func NewFuncWithReceiver(name, receiverName, receiver string, arguments []NameAndType, returns []NameAndType) *ast.FuncDecl {
f := NewFunc(name, arguments, returns)
f.Recv = &ast.FieldList{
List: []*ast.Field{
{
Names: []*ast.Ident{{Name: receiverName}},
Type: &ast.Ident{Name: receiver},
},
},
}
return f
}
func NewBlock(statements []ast.Stmt) *ast.BlockStmt {
return &ast.BlockStmt{
List: statements,
}
}
func NewBlockEllipsis(statements ...ast.Stmt) *ast.BlockStmt {
return &ast.BlockStmt{
List: statements,
}
}
//func MergeBlocks(blocks ...*ast.BlockStmt) *ast.BlockStmt {
// list := make([]ast.Stmt, 0)
// for _, block := range blocks {
// if block != nil {
// list = append(list, block.List...)
// }
// }
// return &ast.BlockStmt{
// List: list,
// }
//}
func Return(exprs ...ast.Expr) *ast.ReturnStmt {
return &ast.ReturnStmt{
Results: exprs,
}
}
func AppendDecl(file *ast.File, decl ast.Decl) {
file.Decls = append(file.Decls, decl)
}
func PrintToFile(f *ast.File, w io.Writer) error {
return format.Node(w, token.NewFileSet(), f)
}
func IfErrNil() *ast.IfStmt {
return If(
NotEquals(Ident("err"), Nil()), NewBlockEllipsis(Return()),
)
}
func AddrOf(e ast.Expr) *ast.UnaryExpr {
return &ast.UnaryExpr{
Op: token.AND,
X: e,
}
}
func DeRef(e ast.Expr) *ast.StarExpr {
return &ast.StarExpr{
X: e,
}
}
func ForRange(K, X ast.Expr, block *ast.BlockStmt) *ast.RangeStmt {
return &ast.RangeStmt{
Key: K, // The loop variable "i"
Value: nil, // No second variable (common for index-only range loops)
X: X, // The collection being ranged over "l"
Tok: token.DEFINE, // ":=" token
Body: block,
}
}
func Index(X, I ast.Expr) *ast.IndexExpr {
return &ast.IndexExpr{
X: X,
Index: I,
}
}
func MultiIndex(X ast.Expr, Low, High, Max ast.Expr) *ast.SliceExpr {
return &ast.SliceExpr{
X: X,
Low: Low,
High: High,
Max: Max,
Slice3: Max != nil,
}
}
func SwitchStmt(Tag ast.Expr, block *ast.BlockStmt) *ast.SwitchStmt {
return &ast.SwitchStmt{
Tag: Tag,
Body: block,
}
}
//func SwitchStmtInit(init ast.Stmt, block *ast.BlockStmt) *ast.SwitchStmt {
// return &ast.SwitchStmt{
// Init: init,
// Body: block,
// }
//}
func StrLit(s string) *ast.BasicLit {
return &ast.BasicLit{
Kind: token.STRING,
Value: `"` + s + `"`,
}
}
func Case(exprs []ast.Expr, stmts []ast.Stmt) *ast.CaseClause {
return &ast.CaseClause{
List: exprs,
Body: stmts,
}
}
func MapType(key, value ast.Expr) ast.Expr {
return &ast.MapType{
Key: key,
Value: value,
}
}
func CompLit(t ast.Expr, elts []ast.Expr) *ast.CompositeLit {
return &ast.CompositeLit{
Type: t,
Elts: elts,
}
}
//func VarAssign(name string, value ast.Expr) *ast.GenDecl {
// return &ast.GenDecl{
// Tok: token.VAR,
// Specs: []ast.Spec{
// &ast.ValueSpec{
// Names: []*ast.Ident{
// {
// Name: name,
// },
// },
// Values: []ast.Expr{value},
// },
// },
// }
//}
func KeyValueExpr(key, value ast.Expr) *ast.KeyValueExpr {
return &ast.KeyValueExpr{
Key: key,
Value: value,
}
}
func TypeAssert(x, t ast.Expr) *ast.TypeAssertExpr {
return &ast.TypeAssertExpr{
X: x,
Type: t,
}
}
func TypeSwitch(x ast.Stmt, block *ast.BlockStmt) *ast.TypeSwitchStmt {
return &ast.TypeSwitchStmt{
Assign: x,
Body: block,
}
}
func Not(x ast.Expr) *ast.UnaryExpr {
return &ast.UnaryExpr{
Op: token.NOT,
X: x,
}
}
func Sub(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.SUB,
Y: rhs,
}
}
func BinAnd(lhs, rhs ast.Expr) *ast.BinaryExpr {
return &ast.BinaryExpr{
X: lhs,
Op: token.AND,
Y: rhs,
}
}
+9
View File
@@ -0,0 +1,9 @@
package main
type EntryHolderSet struct {
BaseName string
Otherwise struct {
Name string
Type any
}
}
+58
View File
@@ -0,0 +1,58 @@
package main
import (
"cmp"
"maps"
"slices"
"unicode"
)
var boundaries = []rune{' ', '_', '-', '.', ',', ';', ':', '(', ')', '[', ']', '{', '}'}
func CamelCase(s string) (ret string) {
atWordBoundary := true
for _, c := range s {
if slices.Contains(boundaries, c) {
atWordBoundary = true
continue
}
if atWordBoundary && unicode.IsLower(c) {
c = unicode.ToUpper(c)
}
atWordBoundary = false
ret += string(c)
}
return
}
func OrderedKeys[Map map[K]V, K cmp.Ordered, V any](m Map) []K {
keysIter := maps.Keys(m)
keys := slices.Collect(keysIter)
slices.Sort(keys)
return keys
}
func ReverseMap[M map[K]V, K cmp.Ordered, V cmp.Ordered](m M) (ret map[V]K) {
ret = map[V]K{}
for k, v := range m {
ret[v] = k
}
return
}
func must(err error) {
if err != nil {
panic(err)
}
}
func PopFront[T any](s []T) (front T, rest []T, ok bool) {
if len(s) == 0 {
return front, s, false
}
return s[0], s[1:], true
}
func CombineNamAndData(name string, data any) []any {
return []any{name, data}
}
+25
View File
@@ -0,0 +1,25 @@
package main
import "testing"
func TestCamelCase(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"hello world", "HelloWorld"},
{"test_case", "TestCase"},
{"simple-test", "SimpleTest"},
{"already.Camel", "AlreadyCamel"},
{"UPPER_CASE", "UPPERCASE"},
{"mixed_Case_string", "MixedCaseString"},
{"", ""},
}
for _, test := range tests {
result := CamelCase(test.input)
if result != test.expected {
t.Errorf("CamelCase(%q) = %q; expected %q", test.input, result, test.expected)
}
}
}
+142
View File
@@ -0,0 +1,142 @@
package main
import (
"go/ast"
"io"
"strings"
)
func GeneratePacketIdentifierToType(versions []string) (decl ast.Decl) {
var s []ast.Stmt
for _, version := range versions {
s = append(s, Case(Exprs(StrLit(version)), Stmts(
Assign121(Ident("t"), Call(SelectorExprAndStr(Ident("v"+strings.ReplaceAll(version, ".", "_")), "PacketIdentifierToType"), Ident("d"), Ident("s"), Ident("i"))),
)))
}
s = append(s, Case(nil, Stmts()))
fn := NewFunc("PacketIdentifierToType", []NameAndType{
{"v", Ident("string")},
{"d", Ident("queser.Direction")},
{"s", Ident("queser.State")},
{"i", Ident("string")},
}, []NameAndType{
{"t", Ident("any")},
})
fn.Body = NewBlockEllipsis(SwitchStmt(Ident("v"), NewBlock(s)), Return())
decl = fn
return
}
/*
func PacketIdentifierToType(v string, d queser.Direction, s queser.State, i string) (t any) {
switch v {
case "1.21.8":
t = v1_21_8.PacketIdentifierToType(d, s, i)
default:
}
return
}
func TypeToPacketIdentifier(v string, d queser.Direction, s queser.State, t any) (i string) {
switch v {
case "1.21.8":
i = v1_21_8.TypeToPacketIdentifier(d, s, t)
}
return
}
func DecodePacket(v string, d queser.Direction, s queser.State, r io.Reader) (packet any, err error) {
switch v {
case "1.21.8":
packet, err = v1_21_8.DecodePacket(d, s, r)
}
return
}
func EncodePacket(v string, d queser.Direction, s queser.State, i string, p any, w io.Writer) (err error) {
switch v {
case "1.21.8":
err = v1_21_8.EncodePacket(d, s, i, p, w)
}
return
}
*/
func GenerateTypeToPacketIdentifier(versions []string) (decl ast.Decl) {
var s []ast.Stmt
for _, version := range versions {
s = append(s, Case(Exprs(StrLit(version)), Stmts(
Assign121(Ident("i"), Call(SelectorExprAndStr(Ident("v"+strings.ReplaceAll(version, ".", "_")), "TypeToPacketIdentifier"), Ident("d"), Ident("s"), Ident("t"))),
)))
}
fn := NewFunc("TypeToPacketIdentifier", []NameAndType{
{"v", Ident("string")},
{"d", Ident("queser.Direction")},
{"s", Ident("queser.State")},
{"t", Ident("any")},
}, []NameAndType{
{"i", Ident("string")},
})
fn.Body = NewBlockEllipsis(SwitchStmt(Ident("v"), NewBlock(s)), Return())
decl = fn
return
}
func GenerateDecodePacket(versions []string) (decl ast.Decl) {
var s []ast.Stmt
for _, version := range versions {
s = append(s, Case(Exprs(StrLit(version)), Stmts(
Assign([]ast.Expr{Ident("packet"), Ident("err")}, []ast.Expr{Call(SelectorExprAndStr(Ident("v"+strings.ReplaceAll(version, ".", "_")), "DecodePacket"), Ident("d"), Ident("s"), Ident("r"))}),
)))
}
fn := NewFunc("DecodePacket", []NameAndType{
{"v", Ident("string")},
{"d", Ident("queser.Direction")},
{"s", Ident("queser.State")},
{"r", Ident("io.Reader")},
}, []NameAndType{
{"packet", Ident("any")},
{"err", Ident("error")},
})
fn.Body = NewBlockEllipsis(SwitchStmt(Ident("v"), NewBlock(s)), Return())
decl = fn
return
}
func GenerateEncodePacket(versions []string) (decl ast.Decl) {
var s []ast.Stmt
for _, version := range versions {
s = append(s, Case(Exprs(StrLit(version)), Stmts(
Assign121(Ident("err"), Call(SelectorExprAndStr(Ident("v"+strings.ReplaceAll(version, ".", "_")), "EncodePacket"), Ident("d"), Ident("s"), Ident("i"), Ident("p"), Ident("w"))),
)))
}
fn := NewFunc("EncodePacket", []NameAndType{
{"v", Ident("string")},
{"d", Ident("queser.Direction")},
{"s", Ident("queser.State")},
{"i", Ident("string")},
{"p", Ident("any")},
{"w", Ident("io.Writer")},
}, []NameAndType{
{"err", Ident("error")},
})
fn.Body = NewBlockEllipsis(SwitchStmt(Ident("v"), NewBlock(s)), Return())
decl = fn
return
}
func GenerateVersionSwitcher(versions []string, printTo io.Writer) (err error) {
f := NewFile("generated")
AppendDecl(f, Import(
"io",
"github.com/admin-else/queser",
"github.com/admin-else/queser/generated/v1_21_8"))
AppendDecl(f, GeneratePacketIdentifierToType(versions))
AppendDecl(f, GenerateTypeToPacketIdentifier(versions))
AppendDecl(f, GenerateDecodePacket(versions))
AppendDecl(f, GenerateEncodePacket(versions))
return PrintToFile(f, printTo)
}