package main import ( "go/ast" "go/token" "slices" "strconv" "github.com/admin-else/strom/proto_generator/protodef" "github.com/admin-else/strom/util" "github.com/go-viper/mapstructure/v2" ) func DefaultDecoder(_ *Generator, varToSet ast.Expr, _ any, _ string) (s []ast.Stmt, err error) { s = Stmts( Assign( Exprs(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 protodef.Container 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 := util.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("proto_base", "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 protodef.Array lName := "l" + util.CamelCase(name) err = mapstructure.Decode(dataRaw, &data) if err != nil { return } var s2 []ast.Stmt countType, err := g.VisitNameAndData("varint", nil) if data.CountType != nil { countType, err = g.VisitType(data.CountType) if err != nil { return } s2, err = g.VisitDecoder(Ident(lName), data.CountType, name) if err != nil { return } } else { var n int n, err = strconv.Atoi(data.Count) var e ast.Expr if err == nil { e = NumLit(n) } else { e, _, err = g.ParseCompareTo(data.Count) } s2 = append(s2, Assign121(Ident(lName), e)) } 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 protodef.TypeForward if err = mapstructure.Decode(dataRaw, &data); err != nil { return } return g.VisitDecoder(varToSet, data.Type, name) } var BooleanValues = []string{"true", "false"} // CaseExprType This exists to fix this // "switch", // // { // "compareTo": "itemCount", // "fields": { // "0": "void", // "false": "void" // }, // "default": [ // // Protodef is best!!! // they are also inconsistent with bool compare to sometimes they use false sometimes they use numbers // that's why this bullshit exists type CaseExprType int const ( CaseExprTypeUnset CaseExprType = iota CaseExprTypeNumber CaseExprTypeBool CaseExprTypeString // CaseExprTypeOnlyNumber CaseExprTypeOnlyBool CaseExprTypeStringOnly These are special overwrite values retuned by // the compare to for the case of being certain that it's the right type. CaseExprTypeOnlyNumber CaseExprTypeOnlyBool CaseExprTypeStringOnly ) 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(BooleanValues, s) { e = Ident(s) ct = CaseExprTypeBool } else { e = StrLit(s) ct = CaseExprTypeString } if *t == CaseExprTypeUnset { *t = ct return } if *t == ct { return } if ct == CaseExprTypeNumber && *t == CaseExprTypeOnlyBool { if s == "0" { e = Ident("false") } else { e = Ident("true") } return } e = nil return } func SwitchDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) { var data protodef.Switch err = mapstructure.Decode(dataRaw, &data) if err != nil { return } compareToExpr, cet, err := g.ParseCompareTo(data.CompareTo) if err != nil { return } for _, fName := range util.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 + util.CamelCase(fName) + "Tmp" s1 := VarStmt(tName, tType) s3 := Assign121(varToSet, Ident(tName)) var caseDecodeValueStmts []ast.Stmt caseDecodeValueStmts, err = g.VisitDecoder(Ident(tName), fType, tName) 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("proto_base", "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 protodef.Mapper err = mapstructure.Decode(dataRaw, &data) if err != nil { return } kName := util.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 util.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("proto_base", "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 protodef.Buffer err = mapstructure.Decode(dataRaw, &data) if err != nil { return } // rawString, err := io.ReadAll(io.LimitReader(r, int64(l))) if data.CountType != nil { lName := "l" + util.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 protodef.BitField err = mapstructure.Decode(dataRaw, &data) if err != nil { return } totalSize := 0 for _, field := range data { totalSize += field.Size } packedTypeProtodef, err := BitSizeToProtodef(totalSize, false) if err != nil { return } t, err := g.VisitType(packedTypeProtodef) if err != nil { return } packed := name + "Packed" packedVarStmt := VarStmt(packed, t) stmts, err := g.VisitDecoder(Ident(packed), packedTypeProtodef, name) if err != nil { return } s = append(s, packedVarStmt) s = append(s, stmts...) lShiftBy := 0 for _, field := range data { var fieldTypeProtodef string fieldTypeProtodef, err = BitSizeToProtodef(field.Size, field.Signed) if err != nil { return } var fieldType ast.Expr fieldType, err = g.VisitType(fieldTypeProtodef) if err != nil { return } rShiftBy := totalSize - field.Size fieldToSet := SelectorExprAndStr(varToSet, util.CamelCase(field.Name)) var getDataExpr ast.Expr getDataExpr = RightShift( LeftShift( Ident(packed), NumLit(lShiftBy)), NumLit(rShiftBy), ) if fieldTypeProtodef == "bool" { getDataExpr = Equals(getDataExpr, NumLit(1)) } else if fieldTypeProtodef != packedTypeProtodef { getDataExpr = Call(fieldType, getDataExpr) } s = append(s, Assign121(fieldToSet, getDataExpr)) if field.Signed { s = append(s, If( GreaterThanOrEqual( fieldToSet, LeftShift(NumLit(1), NumLit(field.Size-1)), ), NewBlockEllipsis( SubAssign( fieldToSet, LeftShift(NumLit(1), NumLit(field.Size)), ), ), )) } lShiftBy += field.Size } return } func RegistryEntryHolderSetDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) { var data protodef.RegistryEntryHolderSet 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" + util.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 protodef.EntryHolderSet err = mapstructure.Decode(dataRaw, &data) if err != nil { return } idName := name + "Id" varIntType, err := g.VisitNameAndData("varint", nil) if err != nil { return } IdVar := VarStmt(idName, varIntType) idDecodeStatements, err := g.VisitDecoder(Ident(idName), "varint", name) if err != nil { return } otherwiseType, err := g.VisitType(data.Otherwise.Type) if err != nil { return } resName := name + "Result" resNameIdent := Ident(resName) var otherwisePath []ast.Stmt otherwisePath = append(otherwisePath, VarStmt(resName, otherwiseType)) otherwiseDecodeStatements, err := g.VisitDecoder(resNameIdent, data.Otherwise.Type, name+"Otherwise") if err != nil { return } otherwisePath = append(otherwisePath, otherwiseDecodeStatements...) otherwisePath = append(otherwisePath, Assign121(varToSet, resNameIdent)) idPath := IfElse(NotEquals(Ident(idName), NumLit(0)), NewBlockEllipsis(Assign121(varToSet, Ident(idName))), NewBlock(otherwisePath)) s = append(s, IdVar) s = append(s, idDecodeStatements...) s = append(s, idPath) return } func VarIntDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) { s = Stmts(Assign(Exprs(varToSet, Ident("err")), Exprs(Call(Selector("proto_base", "DecodeVarInt"), Ident("r")))), IfErrNil()) return } func VarLongDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) { s = Stmts(Assign(Exprs(varToSet, Ident("err")), Exprs(Call(Selector("proto_base", "DecodeVarLong"), Ident("r")))), IfErrNil()) return } func VoidDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) { return } func EntityMetadataLoopDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) { var data protodef.EntityMetadataLoop err = mapstructure.Decode(dataRaw, &data) if err != nil { return } innerType, err := g.VisitType(data.Type) if err != nil { return } assignVts := Assign121(varToSet, Call(Ident("make"), MapType(Ident("uint8"), innerType))) idVar := VarStmt("id", Ident("uint8")) decodeIdStatements, err := g.VisitDecoder(Ident("id"), "u8", name) endCheck := If(Equals(Ident("id"), NumLit(data.EndVal)), NewBlockEllipsis(Break())) declEntry := VarStmt("entry", innerType) decodingEntryStmts, err := g.VisitDecoder(Ident("entry"), data.Type, name+"Inner") if err != nil { return } assignEntry := Assign121(Index(varToSet, Ident("id")), Ident("entry")) var loopStmts []ast.Stmt loopStmts = append(loopStmts, decodeIdStatements...) loopStmts = append(loopStmts, endCheck) loopStmts = append(loopStmts, declEntry) loopStmts = append(loopStmts, decodingEntryStmts...) loopStmts = append(loopStmts, assignEntry) s = Stmts(assignVts, idVar, ForStmt(nil, nil, nil, NewBlock(loopStmts))) /* vts = make(map[uint8]{{data.type}}) var id uint8 for { err = binary.Read(r, binary.BigEndian, &id) if err != nil { return } if id == {{data.EndId}} { return } var data {{type(data.type)}} {{unpack(data.type)}} vts[id] = data } */ 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": VoidDecoder, "varint": VarIntDecoder, "varlong": VarLongDecoder, "anonymousNbt": DefaultDecoder, "anonOptionalNbt": DefaultDecoder, // I have no idea what the difference is between these two "lpVec3": ToDoDecoder, "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": ToDoDecoder, // RegistryEntryHolderSetDecoder "entityMetadataLoop": EntityMetadataLoopDecoder, "topBitSetTerminatedArray": ToDoDecoder, "todo": ToDoDecoder, } }