Add VarLong encoder/decoder and integrate into generation pipeline

This commit is contained in:
adman
2025-12-24 12:35:14 +01:00
parent dd41115ca2
commit db091d17df
7 changed files with 52 additions and 21 deletions
+2 -1
View File
@@ -1,3 +1,4 @@
.devres/ .devres/
.idea/ .idea/
.failed_packets/ .failed_packets/
proto_generated/*
-18
View File
@@ -6,11 +6,7 @@ import (
"testing" "testing"
"github.com/admin-else/strom/nbt"
"github.com/admin-else/strom/proto_base"
"github.com/admin-else/strom/proto_generated/v1_21_8" "github.com/admin-else/strom/proto_generated/v1_21_8"
"github.com/google/uuid"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
) )
@@ -22,20 +18,6 @@ var nanIgnorer64 = cmp.Comparer(func(x, y float64) bool {
return (math.IsNaN(x) && math.IsNaN(y)) || x == y return (math.IsNaN(x) && math.IsNaN(y)) || x == y
}) })
func TestChat(t *testing.T) {
//p := v1_21_8.PlayToServerPacketChatMessage{Message: "dfs", Timestamp: 1764153707364, Salt: -5634100397920314628, Signature: (*[256]uint8)(nil), Offset: 0, Acknowledged: [3]uint8{0x0, 0x0, 0x0}, Checksum: 0x1}
p := v1_21_8.PlayToClientPacketPlayerChat{GlobalIndex: 0, SenderUuid: uuid.UUID{0x1d, 0xc5, 0x57, 0x82, 0x3c, 0x0, 0x3e, 0xd4, 0xbf, 0x8b, 0x76, 0xd4, 0xc6, 0xd9, 0xcc, 0x47}, Index: 0, Signature: (*[256]uint8)(nil), PlainMessage: "csdf", Timestamp: 1764153823132, Salt: 0, PreviousMessages: v1_21_8.PreviousMessages{Val: []struct {
Id int32
Signature interface{}
}{}}, UnsignedChatContent: (*nbt.Anon)(nil), FilterType: 0, FilterTypeMask: proto_base.Void{}, Type: v1_21_8.PlayToClientChatTypesHolder{Val: 1}, NetworkName: nbt.Anon{Value: map[string]interface{}{"click_event": map[string]interface{}{"action": "suggest_command", "command": "/tell Player659 "}, "hover_event": map[string]interface{}{"action": "show_entity", "id": "minecraft:player", "name": "Player659", "uuid": []int32{499472258, 1006649044, -1081379116, -958804921}}, "insertion": "Player659", "text": "Player659"}}, NetworkTargetName: (*nbt.Anon)(nil)}
b := bytes.NewBuffer(nil)
err := p.Encode(b)
if err != nil {
t.Fatal(err)
}
t.Logf("%q", b.Bytes())
}
func FuzzPlayPackets(f *testing.F) { func FuzzPlayPackets(f *testing.F) {
f.Fuzz(func(t *testing.T, b []byte) { f.Fuzz(func(t *testing.T, b []byte) {
t.Logf("Fuzz data %q\n", b) t.Logf("Fuzz data %q\n", b)
+36 -1
View File
@@ -144,7 +144,7 @@ func EncodeVarInt(w io.Writer, v int32) (err error) {
if uv != 0 { if uv != 0 {
b |= 0x80 b |= 0x80
} }
err := binary.Write(w, binary.BigEndian, b) err = binary.Write(w, binary.BigEndian, b)
if err != nil { if err != nil {
return err return err
} }
@@ -171,6 +171,41 @@ func DecodeVarInt(r io.Reader) (ret int32, err error) {
return return
} }
func EncodeVarLong(w io.Writer, v int64) (err error) {
uv := uint64(v)
for {
b := uint8(uv & 0x7F)
uv >>= 7
if uv != 0 {
b |= 0x80
}
err = binary.Write(w, binary.BigEndian, b)
if err != nil {
return err
}
if uv == 0 {
break
}
}
return nil
}
func DecodeVarLong(r io.Reader) (ret int64, err error) {
for i := range 10 { // ceil(64/7)
var b uint8
err = binary.Read(r, binary.BigEndian, &b)
if err != nil {
return
}
ret |= int64(uint64(b&0x7F) << (7 * uint64(i)))
if b&0x80 == 0 {
return
}
}
err = errors.New("VarInt too long")
return
}
func ErroringIndex[K comparable, V any, M map[K]V](m M, i K) (v V, err error) { func ErroringIndex[K comparable, V any, M map[K]V](m M, i K) (v V, err error) {
var ok bool var ok bool
v, ok = m[i] v, ok = m[i]
+1 -1
View File
@@ -301,7 +301,7 @@ func Generate(version string, w io.Writer) (err error) {
g := &Generator{Protocol: protocol} g := &Generator{Protocol: protocol}
// These have annoying edge cases that would require me to implement a whole new compareTo parser // 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.Settings.ReplaceWithTodoNames = []string{}
g.File = NewFile("v" + strings.ReplaceAll(version, ".", "_")) g.File = NewFile("v" + strings.ReplaceAll(version, ".", "_"))
AppendDecl(g.File, Import("encoding/binary", "io", "github.com/admin-else/strom/proto_base", "github.com/admin-else/strom/nbt", "github.com/google/uuid")) AppendDecl(g.File, Import("encoding/binary", "io", "github.com/admin-else/strom/proto_base", "github.com/admin-else/strom/nbt", "github.com/google/uuid"))
+6
View File
@@ -507,6 +507,11 @@ func VarIntDecoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s
return 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 (g *Generator) RegisterDecoderNatives() { func (g *Generator) RegisterDecoderNatives() {
g.DecoderNatives = map[string]FunctionGeneratorFunc{ g.DecoderNatives = map[string]FunctionGeneratorFunc{
"container": ContainerDecoder, "container": ContainerDecoder,
@@ -521,6 +526,7 @@ func (g *Generator) RegisterDecoderNatives() {
"void": DefaultDecoder, "void": DefaultDecoder,
"varint": VarIntDecoder, "varint": VarIntDecoder,
"varlong": VarLongDecoder,
"anonymousNbt": DefaultDecoder, "anonymousNbt": DefaultDecoder,
"anonOptionalNbt": DefaultDecoder, // I have no idea what the difference is between these two "anonOptionalNbt": DefaultDecoder, // I have no idea what the difference is between these two
"UUID": UUIDDecoder, "UUID": UUIDDecoder,
+6
View File
@@ -320,6 +320,11 @@ func VarIntEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s
return return
} }
func VarLongEncoder(g *Generator, varToSet ast.Expr, dataRaw any, name string) (s []ast.Stmt, err error) {
s = Stmts(Assign121(Ident("err"), Call(Selector("proto_base", "EncodeVarLong"), Ident("w"), varToSet)), IfErrNil())
return
}
func (g *Generator) RegisterEncoderNatives() { func (g *Generator) RegisterEncoderNatives() {
g.EncoderNatives = map[string]FunctionGeneratorFunc{ g.EncoderNatives = map[string]FunctionGeneratorFunc{
"container": ContainerEncoder, "container": ContainerEncoder,
@@ -333,6 +338,7 @@ func (g *Generator) RegisterEncoderNatives() {
"void": DefaultEncoder, "void": DefaultEncoder,
"varint": VarIntEncoder, "varint": VarIntEncoder,
"varlong": VarLongEncoder,
"anonymousNbt": DefaultEncoder, "anonymousNbt": DefaultEncoder,
"anonOptionalNbt": DefaultEncoder, // I have no idea what the difference is between these two "anonOptionalNbt": DefaultEncoder, // I have no idea what the difference is between these two
"UUID": UUIDEncoder, "UUID": UUIDEncoder,
+1
View File
@@ -158,6 +158,7 @@ func (g *Generator) RegisterNatives() {
"container": VisitContainerType, "container": VisitContainerType,
"buffer": VisitBufferType, "buffer": VisitBufferType,
"varint": MakeIdentVisitor("int32"), "varint": MakeIdentVisitor("int32"),
"varlong": MakeIdentVisitor("int64"),
"array": VisitArrayTypeVisitorType, "array": VisitArrayTypeVisitorType,
"mapper": MakeIdentVisitor("string"), "mapper": MakeIdentVisitor("string"),
"native": VisitDontGenerateType, "native": VisitDontGenerateType,