aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2024-06-06 22:24:34 +0300
committerArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2024-06-06 22:24:34 +0300
commiteead3c2bd90fa428dca616bc56fcd85f362f4040 (patch)
treeadcf19686e86c2ce91cff67190d258c186e2bd5b
parentchange project name, update to go1.22 (diff)
downloadsdp.go-eead3c2bd90fa428dca616bc56fcd85f362f4040.tar.gz
sdp.go-eead3c2bd90fa428dca616bc56fcd85f362f4040.tar.bz2
sdp.go-eead3c2bd90fa428dca616bc56fcd85f362f4040.zip
change project name, decouple main and parsing entrance
this will make it more like a library, where another project can create Parser struct and call ParseDemos to get all relevant information, and if anyone wants to use executable from this project, the main function works exactly the same
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}