refactor print_replay to improve unprocessable packet test creation

This commit is contained in:
adman
2026-05-10 17:29:52 +02:00
parent c483bf9553
commit c56898e787
5 changed files with 77 additions and 24 deletions
+4 -4
View File
@@ -4,15 +4,15 @@ import (
"bytes" "bytes"
"testing" "testing"
"github.com/admin-else/strom/proto_generated/v1_21_8" generated "github.com/admin-else/strom/proto_generated/%v"
) )
// Error: %v // Error: %v
func TestFailedPacket%10X(t *testing.T) { func TestFailedPacket%10X(t *testing.T) {
p := v1_21_8.Play%vPacket{} p := &generated.%v{}
b := bytes.NewBuffer(%#v) b := bytes.NewBuffer(%#v)
err := p.Decode(b) err := p.Decode(b)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
+40 -12
View File
@@ -5,13 +5,16 @@ import (
"crypto/sha256" "crypto/sha256"
_ "embed" _ "embed"
"encoding/binary" "encoding/binary"
"errors"
"flag" "flag"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
"os" "os"
"reflect" "reflect"
"strings"
"github.com/admin-else/strom/data"
"github.com/admin-else/strom/proto" "github.com/admin-else/strom/proto"
"github.com/admin-else/strom/proto_base" "github.com/admin-else/strom/proto_base"
) )
@@ -20,13 +23,13 @@ var (
cmd = flag.NewFlagSet("print-replay", flag.ContinueOnError) cmd = flag.NewFlagSet("print-replay", flag.ContinueOnError)
FileFlag = cmd.String("file", "", "The tmcpr file to print") FileFlag = cmd.String("file", "", "The tmcpr file to print")
ProtocolVersion = cmd.Int("protocol", -1, "The protocol version") ProtocolVersion = cmd.Int("protocol", -1, "The protocol version")
CreateTestsPath = cmd.String("create-tests", "", "The path to create tests from failed packets, if empty no tests will be created") CreateTestsPath = cmd.String("create-tests", "", "")
) )
//go:embed failed_packet.go.tmpl //go:embed failed_packet.go.tmpl
var TestSrcF string var TestSrcF string
func SaveUnCodeAbleAsTest(d proto_base.Direction, packet *proto.UnCodablePacket) { func SaveUnCodeAbleAsTest(packet *proto.UnCodablePacket) {
hUntrimmed := sha256.Sum256(packet.Data) hUntrimmed := sha256.Sum256(packet.Data)
h := hUntrimmed[:8] h := hUntrimmed[:8]
f, err := os.Create(fmt.Sprintf(*CreateTestsPath+"/%v_%10x_test.go", len(packet.Data), h)) f, err := os.Create(fmt.Sprintf(*CreateTestsPath+"/%v_%10x_test.go", len(packet.Data), h))
@@ -34,9 +37,15 @@ func SaveUnCodeAbleAsTest(d proto_base.Direction, packet *proto.UnCodablePacket)
panic(err) panic(err)
} }
ret, err := data.LookUpVersionByProtocolVersion(packet.Info.ProtocolVersion)
if err != nil {
panic(err)
}
goPackage := "v" + strings.ReplaceAll(ret.MinecraftVersion, ".", "_")
//goland:noinspection GoUnhandledErrorResult //goland:noinspection GoUnhandledErrorResult
defer f.Close() defer f.Close()
_, err = fmt.Fprintf(f, TestSrcF, packet.Err, h, d.Opposite(), packet.Data) _, err = fmt.Fprintf(f, TestSrcF, goPackage, packet.Err, h, reflect.TypeOf(packet.Info.Type).Elem().Name(), packet.Data)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -55,26 +64,35 @@ func UnpackPacket(r io.Reader) (packet proto_base.EncodeDecodeAble, err error) {
if err != nil { if err != nil {
return return
} }
b := bytes.NewBuffer(nil)
_, err = io.CopyN(b, r, int64(length)) // Read the packet data into a byte slice
packetData := make([]byte, length)
_, err = io.ReadFull(r, packetData)
if err != nil { if err != nil {
return return
} }
// Use bytes.Reader instead of bytes.Buffer
b := bytes.NewReader(packetData)
packetId, err := proto_base.DecodeVarInt(b) packetId, err := proto_base.DecodeVarInt(b)
if err != nil { if err != nil {
return return
} }
// Calculate position after reading the packet ID
// indexafterid represents how many bytes we've read so far
indexafterid := int(b.Size()) - int(b.Len())
i, ok := proto.LookUpTypeByPacketInfo(proto_base.ToClient, state, packetId, int32(*ProtocolVersion)) i, ok := proto.LookUpTypeByPacketInfo(proto_base.ToClient, state, packetId, int32(*ProtocolVersion))
if !ok { if !ok {
packet = &proto.UnCodablePacket{Err: proto.BadPacketIdErr, Data: b.Bytes(), Direction: proto_base.ToClient} packet = &proto.UnCodablePacket{Err: proto.BadPacketIdErr, Data: packetData, Info: i}
return return
} }
packet = reflect.New(reflect.TypeOf(i.Type).Elem()).Interface().(proto_base.EncodeDecodeAble) packet = reflect.New(reflect.TypeOf(i.Type).Elem()).Interface().(proto_base.EncodeDecodeAble)
err = packet.Decode(b) err = packet.Decode(b)
if err != nil { if err != nil {
packet = &proto.UnCodablePacket{Err: err, Data: b.Bytes(), Direction: proto_base.ToClient} packet = &proto.UnCodablePacket{Err: err, Data: packetData[indexafterid:], Info: i}
return return
} }
switch i.Name { switch i.Name {
@@ -85,7 +103,6 @@ func UnpackPacket(r io.Reader) (packet proto_base.EncodeDecodeAble, err error) {
} }
return return
} }
func Run(args []string) (err error) { func Run(args []string) (err error) {
err = cmd.Parse(args) err = cmd.Parse(args)
if err != nil { if err != nil {
@@ -103,17 +120,28 @@ func Run(args []string) (err error) {
} }
defer f.Close() defer f.Close()
var totalPackets, failedPackets int
for { for {
var packet proto_base.EncodeDecodeAble var packet proto_base.EncodeDecodeAble
packet, err = UnpackPacket(f) packet, err = UnpackPacket(f)
unCodablePacket, ok := packet.(*proto.UnCodablePacket) unCodablePacket, ok := packet.(*proto.UnCodablePacket)
if ok && *CreateTestsPath != "" { if ok {
SaveUnCodeAbleAsTest(proto_base.ToClient, unCodablePacket) if *CreateTestsPath != "" {
SaveUnCodeAbleAsTest(unCodablePacket)
}
failedPackets++
} }
if err != nil { if err != nil {
return fmt.Println(err)
} else {
fmt.Printf("Packet: %#v\n", packet)
} }
fmt.Printf("Packet: %#v\n", packet) if errors.Is(err, io.EOF) {
break
}
totalPackets++
} }
fmt.Printf("Total packets: %d, failed packets: %d, %%failed: %.2f%%\n", totalPackets, failedPackets, float64(failedPackets)/float64(totalPackets)*100)
return
} }
+7 -7
View File
@@ -41,9 +41,9 @@ var EarliestVersion = proto_generated.SupportedVersions[0]
// UnCodablePacket represents a packet that could not be decoded. // UnCodablePacket represents a packet that could not be decoded.
type UnCodablePacket struct { type UnCodablePacket struct {
Err error Err error
Data []byte Data []byte
Direction proto_base.Direction Info proto_base.PacketInfo
} }
func (u *UnCodablePacket) Encode(w io.Writer) (err error) { func (u *UnCodablePacket) Encode(w io.Writer) (err error) {
@@ -242,7 +242,7 @@ func (c *Conn) Receive() (packet proto_base.EncodeDecodeAble, err error) {
i, ok := LookUpTypeByPacketInfo(c.Actor.ReceiveDirection(), c.State(), id, c.ProtocolVersion) i, ok := LookUpTypeByPacketInfo(c.Actor.ReceiveDirection(), c.State(), id, c.ProtocolVersion)
if !ok { if !ok {
packet = &UnCodablePacket{Err: BadPacketIdErr, Data: packetBytes, Direction: c.Actor.ReceiveDirection()} packet = &UnCodablePacket{Err: BadPacketIdErr, Data: packetBytes, Info: i}
return return
} }
packet = reflect.New(reflect.TypeOf(i.Type).Elem()).Interface().(proto_base.EncodeDecodeAble) packet = reflect.New(reflect.TypeOf(i.Type).Elem()).Interface().(proto_base.EncodeDecodeAble)
@@ -250,18 +250,18 @@ func (c *Conn) Receive() (packet proto_base.EncodeDecodeAble, err error) {
slices.ContainsFunc(c.DebugPrintPackets, func(s string) bool { return strings.Contains(i.Name, s) }) slices.ContainsFunc(c.DebugPrintPackets, func(s string) bool { return strings.Contains(i.Name, s) })
isListenerRegistered := c.IsTypeRegistered(reflect.TypeOf(packet)) isListenerRegistered := c.IsTypeRegistered(reflect.TypeOf(packet))
if !isListenerRegistered && !debugPrint { if !isListenerRegistered && !debugPrint {
packet = &UnCodablePacket{Err: NoHandlerRegisteredErr, Data: packetBytes, Direction: c.Actor.ReceiveDirection()} packet = &UnCodablePacket{Err: NoHandlerRegisteredErr, Data: packetBytes, Info: i}
return return
} }
err = packet.Decode(b) err = packet.Decode(b)
if err != nil { if err != nil {
packet = &UnCodablePacket{Err: err, Data: packetBytes, Direction: c.Actor.ReceiveDirection()} packet = &UnCodablePacket{Err: err, Data: packetBytes, Info: i}
err = nil err = nil
return return
} }
if b.Len() != 0 { if b.Len() != 0 {
err = nil err = nil
packet = &UnCodablePacket{Err: PacketNotFullyDecodedErr, Data: packetBytes, Direction: c.Actor.ReceiveDirection()} packet = &UnCodablePacket{Err: PacketNotFullyDecodedErr, Data: packetBytes, Info: i}
return return
} }
if debugPrint { if debugPrint {
+9 -1
View File
@@ -25,6 +25,14 @@ func init() {
func LookUpTypeByPacketInfo(direction proto_base.Direction, state proto_base.State, pid, version int32) (p proto_base.PacketInfo, ok bool) { func LookUpTypeByPacketInfo(direction proto_base.Direction, state proto_base.State, pid, version int32) (p proto_base.PacketInfo, ok bool) {
pP, ok := pidMap[PidEtc{direction, state, pid, version}] pP, ok := pidMap[PidEtc{direction, state, pid, version}]
if !ok { if !ok {
p = proto_base.PacketInfo{
Type: nil,
Name: "",
Direction: direction,
State: state,
PacketId: pid,
ProtocolVersion: version,
}
return return
} }
p = *pP p = *pP
@@ -43,7 +51,7 @@ func LookUpTypeByPacketInfoAndCopyType(direction proto_base.Direction, state pro
func LookupPacketInfoByType(packet proto_base.EncodeDecodeAble) (p proto_base.PacketInfo, ok bool) { func LookupPacketInfoByType(packet proto_base.EncodeDecodeAble) (p proto_base.PacketInfo, ok bool) {
undecodedPacket, isUndecoable := packet.(*UnCodablePacket) undecodedPacket, isUndecoable := packet.(*UnCodablePacket)
if isUndecoable { if isUndecoable {
p = proto_base.PacketInfo{Type: &UnCodablePacket{}, Name: "un_codable", Direction: undecodedPacket.Direction, State: proto_base.Handshaking, PacketId: -1, ProtocolVersion: -1} p = undecodedPacket.Info
ok = true ok = true
return return
} }
+17
View File
@@ -42,6 +42,23 @@ const (
Play Play
) )
func (s State) String() string {
switch s {
case Handshaking:
return "Handshaking"
case Status:
return "Status"
case Login:
return "Login"
case Configuration:
return "Configuration"
case Play:
return "Play"
default:
return "Unknown"
}
}
type Actor int type Actor int
const ( const (