aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--cmd/parser.go107
-rw-r--r--pkg/packets/packets.go104
2 files changed, 151 insertions, 60 deletions
diff --git a/cmd/parser.go b/cmd/parser.go
index b4cbba4..f21d91f 100644
--- a/cmd/parser.go
+++ b/cmd/parser.go
@@ -1,53 +1,106 @@
1package main 1package main
2 2
3import ( 3import (
4 "errors"
4 "fmt" 5 "fmt"
5 "os" 6 "os"
7 "strings"
6 8
7 "github.com/pektezol/bitreader" 9 "github.com/pektezol/bitreader"
8 "github.com/pektezol/demoparser/pkg/packets" 10 "github.com/pektezol/sdp.go/pkg/packets"
9 "github.com/pektezol/demoparser/pkg/writer" 11 "github.com/pektezol/sdp.go/pkg/writer"
10) 12)
11 13
14type Demo struct {
15 Headers packets.Headers `json:"headers"`
16 Messages []packets.Message `json:"messages"`
17}
18
19type Parser struct {
20 DemoPath string
21 writer strings.Builder
22}
23
24func NewParser(demoPath string) *Parser {
25 return &Parser{
26 DemoPath: demoPath,
27 }
28}
29
12const littleEndian bool = true 30const littleEndian bool = true
13 31
14func main() { 32func main() {
15 if len(os.Args) != 2 { 33 if len(os.Args) != 2 {
16 panic("specify file in command line arguments") 34 fmt.Println("specify file in command line arguments")
35 os.Exit(1)
17 } 36 }
18 writer.AppendLine("Generated By: github.com/pektezol/demoparser") 37 parser := NewParser(os.Args[1])
19 files, err := os.ReadDir(os.Args[1]) 38 _, err := parser.ParseDemos()
20 if err != nil { // If it's not a directory 39 if err != nil {
21 file, err := os.Open(os.Args[1]) 40 fmt.Println(err.Error())
22 if err != nil { 41 os.Exit(1)
23 panic(err)
24 }
25 writer.AppendLine("\nFile Name: %s", file.Name())
26 reader := bitreader.NewReader(file, littleEndian)
27 demoParserHandler(reader)
28 defer file.Close()
29 fmt.Println(writer.GetString())
30 return
31 } 42 }
32 for _, fileinfo := range files { // If it is a directory 43 fmt.Println(parser.GetOutput())
33 file, err := os.Open(os.Args[1] + fileinfo.Name()) 44}
45
46func (p *Parser) GetOutput() string {
47 return p.writer.String()
48}
49
50func (p *Parser) ParseDemos() ([]Demo, error) {
51 writer.AppendLine("Generated By: github.com/pektezol/sdp.go")
52 files, err := os.ReadDir(p.DemoPath)
53 if err != nil {
54 // not a directory
55 file, err := os.Open(p.DemoPath)
34 if err != nil { 56 if err != nil {
35 panic(err) 57 return []Demo{}, err
36 } 58 }
37 writer.AppendLine("\nFile Name: %s", file.Name())
38 reader := bitreader.NewReader(file, littleEndian)
39 demoParserHandler(reader)
40 defer file.Close() 59 defer file.Close()
60 reader := bitreader.NewReader(file, littleEndian)
61 demo := demoParserHandler(reader, file.Name())
62 p.writer = writer.GetWriter()
63 return []Demo{demo}, nil
64 } else {
65 demos := []Demo{}
66 // directory
67 for _, fileinfo := range files {
68 if len(fileinfo.Name()) > 4 && fileinfo.Name()[len(fileinfo.Name())-4:] == ".dem" {
69 file, err := os.Open(p.DemoPath + fileinfo.Name())
70 if err != nil {
71 return []Demo{}, err
72 }
73 defer file.Close()
74 reader := bitreader.NewReader(file, littleEndian)
75 demo := demoParserHandler(reader, file.Name())
76 demos = append(demos, demo)
77 }
78 }
79 p.writer = writer.GetWriter()
80 if len(demos) == 0 {
81 return demos, errors.New("no demo found in given directory")
82 }
83 return demos, nil
41 } 84 }
42 fmt.Println(writer.GetString())
43} 85}
44 86
45func demoParserHandler(reader *bitreader.Reader) { 87func demoParserHandler(reader *bitreader.Reader, filename string) Demo {
46 packets.ParseHeaders(reader) 88 demo := Demo{}
89 writer.AppendLine("\nFile Name: %s", filename)
90 // this is for recovering after a panic inside parse headers and packet.
91 // this approach was taken since error handling bitreader functions would take a long time.
92 defer func() {
93 if err := recover(); err != nil {
94 writer.AppendLine("failed to parse demo: %v", err)
95 }
96 }()
97 demo.Headers = packets.ParseHeaders(reader)
47 for { 98 for {
48 packet := packets.ParsePackets(reader) 99 message := packets.ParseMessage(reader)
49 if packet.PacketType == 7 { 100 demo.Messages = append(demo.Messages, message)
101 if message.PacketType == 7 {
50 break 102 break
51 } 103 }
52 } 104 }
105 return demo
53} 106}
diff --git a/pkg/packets/packets.go b/pkg/packets/packets.go
index b1d6a40..1bf3f57 100644
--- a/pkg/packets/packets.go
+++ b/pkg/packets/packets.go
@@ -2,63 +2,101 @@ package packets
2 2
3import ( 3import (
4 "github.com/pektezol/bitreader" 4 "github.com/pektezol/bitreader"
5 "github.com/pektezol/demoparser/pkg/classes" 5 "github.com/pektezol/sdp.go/pkg/classes"
6 "github.com/pektezol/demoparser/pkg/writer" 6 "github.com/pektezol/sdp.go/pkg/writer"
7) 7)
8 8
9type PacketMessageInfo struct { 9type MessageType uint8
10 PacketType uint8 10
11const (
12 SignOn MessageType = iota + 1
13 Packet
14 SyncTick
15 ConsoleCmd
16 UserCmd
17 DataTables
18 Stop
19 CustomData
20 StringTables
21)
22
23type Message struct {
24 PacketType MessageType
11 TickNumber int32 25 TickNumber int32
12 SlotNumber uint8 26 SlotNumber uint8
27 Data any
13} 28}
14 29
15func ParsePackets(reader *bitreader.Reader) PacketMessageInfo { 30func ParseMessage(reader *bitreader.Reader) Message {
16 packetType := reader.TryReadUInt8() 31 message := Message{
17 tickNumber := reader.TryReadSInt32() 32 PacketType: MessageType(reader.TryReadUInt8()),
18 slotNumber := reader.TryReadUInt8() 33 TickNumber: reader.TryReadSInt32(),
19 switch packetType { 34 SlotNumber: reader.TryReadUInt8(),
20 case 1: // SignOn 35 }
21 writer.AppendLine("[%d] %s (%d):", tickNumber, "SIGNON", packetType) 36 writer.AppendLine("[%d] %s (%d):", message.TickNumber, message.PacketType.String(), message.PacketType)
37 switch message.PacketType {
38 case SignOn:
22 signOn := classes.SignOn{} 39 signOn := classes.SignOn{}
23 signOn.ParseSignOn(reader) 40 signOn.ParseSignOn(reader)
24 case 2: // Packet 41 message.Data = signOn
25 writer.AppendLine("[%d] %s (%d):", tickNumber, "PACKET", packetType) 42 case Packet:
26 packet := classes.Packet{} 43 packet := classes.Packet{}
27 packet.ParsePacket(reader) 44 packet.ParsePacket(reader)
28 case 3: // SyncTick 45 message.Data = packet
29 writer.AppendLine("[%d] %s (%d):", tickNumber, "SYNCTICK", packetType) 46 case SyncTick:
30 syncTick := classes.SyncTick{} 47 syncTick := classes.SyncTick{}
31 syncTick.ParseSyncTick() 48 syncTick.ParseSyncTick()
32 case 4: // ConsoleCmd 49 message.Data = syncTick
33 writer.AppendLine("[%d] %s (%d):", tickNumber, "CONSOLECMD", packetType) 50 case ConsoleCmd:
34 consoleCmd := classes.ConsoleCmd{} 51 consoleCmd := classes.ConsoleCmd{}
35 consoleCmd.ParseConsoleCmd(reader) 52 consoleCmd.ParseConsoleCmd(reader)
36 case 5: // UserCmd 53 message.Data = consoleCmd
37 writer.AppendLine("[%d] %s (%d):", tickNumber, "USERCMD", packetType) 54 case UserCmd:
38 userCmd := classes.UserCmd{} 55 userCmd := classes.UserCmd{}
39 userCmd.ParseUserCmd(reader) 56 userCmd.ParseUserCmd(reader)
40 case 6: // DataTables 57 message.Data = userCmd
41 writer.AppendLine("[%d] %s (%d):", tickNumber, "DATATABLES", packetType) 58 case DataTables:
42 dataTables := classes.DataTables{} 59 dataTables := classes.DataTables{}
43 dataTables.ParseDataTables(reader) 60 dataTables.ParseDataTables(reader)
44 case 7: // Stop 61 message.Data = dataTables
45 writer.AppendLine("[%d] %s (%d):", tickNumber, "STOP", packetType) 62 case Stop:
46 stop := classes.Stop{} 63 stop := classes.Stop{}
47 stop.ParseStop(reader) 64 stop.ParseStop(reader)
48 case 8: // CustomData TODO: not sar data 65 message.Data = stop
66 case CustomData: // TODO: not sar data
49 customData := classes.CustomData{} 67 customData := classes.CustomData{}
50 customData.ParseCustomData(reader, tickNumber, packetType) 68 customData.ParseCustomData(reader, message.TickNumber, uint8(message.PacketType))
51 case 9: // StringTables TODO: parsing string table data 69 message.Data = customData
52 writer.AppendLine("[%d] %s (%d):", tickNumber, "STRINGTABLES", packetType) 70 case StringTables: // TODO: parsing string table data
53 stringTables := classes.StringTables{} 71 stringTables := classes.StringTables{}
54 stringTables.ParseStringTables(reader) 72 stringTables.ParseStringTables(reader)
55 default: // Invalid 73 message.Data = stringTables
56 writer.AppendLine("[%d] %s (%d):", tickNumber, "INVALID", packetType) 74 default:
57 panic("invalid packet type") 75 panic("invalid packet type")
58 } 76 }
59 return PacketMessageInfo{ 77 return message
60 PacketType: packetType, 78}
61 TickNumber: tickNumber, 79
62 SlotNumber: slotNumber, 80func (t MessageType) String() string {
81 switch t {
82 case SignOn:
83 return "SIGNON"
84 case Packet:
85 return "PACKET"
86 case SyncTick:
87 return "SYNCTICK"
88 case ConsoleCmd:
89 return "CONSOLECMD"
90 case UserCmd:
91 return "USERCMD"
92 case DataTables:
93 return "DATATABLES"
94 case Stop:
95 return "STOP"
96 case CustomData:
97 return "CUSTOMDATA"
98 case StringTables:
99 return "STRINGTABLES"
63 } 100 }
101 return "INVALID"
64} 102}