aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2023-09-12 20:53:09 +0300
committerArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2023-09-16 21:39:42 +0300
commit82871ba1bac1d62f69e1933b66659e62d2e5e063 (patch)
treea906310fba89b670bcfda9625a6d776553d482f6 /pkg
parentnet/svc messages finally getting parsed correctly (diff)
downloadsdp.go-82871ba1bac1d62f69e1933b66659e62d2e5e063.tar.gz
sdp.go-82871ba1bac1d62f69e1933b66659e62d2e5e063.tar.bz2
sdp.go-82871ba1bac1d62f69e1933b66659e62d2e5e063.zip
another rewrite, v1.0.0
Diffstat (limited to 'pkg')
-rw-r--r--pkg/classes/cmdInfo.go27
-rw-r--r--pkg/classes/sendTable.go106
-rw-r--r--pkg/classes/serverClassInfo.go30
-rw-r--r--pkg/classes/stringTable.go82
-rw-r--r--pkg/classes/userCmdInfo.go72
-rw-r--r--pkg/messages/messages.go87
-rw-r--r--pkg/messages/types/netDisconnect.go13
-rw-r--r--pkg/messages/types/netFile.go17
-rw-r--r--pkg/messages/types/netNop.go9
-rw-r--r--pkg/messages/types/netSetConVar.go29
-rw-r--r--pkg/messages/types/netSignOnState.go26
-rw-r--r--pkg/messages/types/netSplitScreenUser.go13
-rw-r--r--pkg/messages/types/netStringCmd.go13
-rw-r--r--pkg/messages/types/netTick.go17
-rw-r--r--pkg/messages/types/svcBspDecal.go61
-rw-r--r--pkg/messages/types/svcClassInfo.go40
-rw-r--r--pkg/messages/types/svcCmdKeyValues.go16
-rw-r--r--pkg/messages/types/svcCreateStringTable.go36
-rw-r--r--pkg/messages/types/svcCrosshairAngle.go13
-rw-r--r--pkg/messages/types/svcEntityMessage.go20
-rw-r--r--pkg/messages/types/svcFixAngle.go15
-rw-r--r--pkg/messages/types/svcGameEvent.go16
-rw-r--r--pkg/messages/types/svcGameEventList.go21
-rw-r--r--pkg/messages/types/svcGetCvarValue.go16
-rw-r--r--pkg/messages/types/svcMenu.go18
-rw-r--r--pkg/messages/types/svcPacketEntities.go30
-rw-r--r--pkg/messages/types/svcPaintmapData.go16
-rw-r--r--pkg/messages/types/svcPrefetch.go13
-rw-r--r--pkg/messages/types/svcPrint.go13
-rw-r--r--pkg/messages/types/svcSendTable.go17
-rw-r--r--pkg/messages/types/svcServerInfo.go43
-rw-r--r--pkg/messages/types/svcSetPause.go13
-rw-r--r--pkg/messages/types/svcSetView.go13
-rw-r--r--pkg/messages/types/svcSounds.go25
-rw-r--r--pkg/messages/types/svcSplitScreen.go18
-rw-r--r--pkg/messages/types/svcTempEntities.go18
-rw-r--r--pkg/messages/types/svcUpdateStringTable.go22
-rw-r--r--pkg/messages/types/svcUserMessage.go18
-rw-r--r--pkg/messages/types/svcVoiceData.go20
-rw-r--r--pkg/messages/types/svcVoiceInit.go20
-rw-r--r--pkg/packets/headers.go48
-rw-r--r--pkg/packets/packets.go125
-rw-r--r--pkg/packets/types.go53
43 files changed, 1338 insertions, 0 deletions
diff --git a/pkg/classes/cmdInfo.go b/pkg/classes/cmdInfo.go
new file mode 100644
index 0000000..6e56c41
--- /dev/null
+++ b/pkg/classes/cmdInfo.go
@@ -0,0 +1,27 @@
1package classes
2
3import (
4 "github.com/pektezol/bitreader"
5)
6
7type CmdInfo struct {
8 Flags int32
9 ViewOrigin []float32
10 ViewAngles []float32
11 LocalViewAngles []float32
12 ViewOrigin2 []float32
13 ViewAngles2 []float32
14 LocalViewAngles2 []float32
15}
16
17func ParseCmdInfo(reader *bitreader.ReaderType) CmdInfo {
18 return CmdInfo{
19 Flags: int32(reader.TryReadBits(32)),
20 ViewOrigin: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()},
21 ViewAngles: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()},
22 LocalViewAngles: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()},
23 ViewOrigin2: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()},
24 ViewAngles2: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()},
25 LocalViewAngles2: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()},
26 }
27}
diff --git a/pkg/classes/sendTable.go b/pkg/classes/sendTable.go
new file mode 100644
index 0000000..4521464
--- /dev/null
+++ b/pkg/classes/sendTable.go
@@ -0,0 +1,106 @@
1package classes
2
3import (
4 "github.com/pektezol/bitreader"
5)
6
7type SendTable struct {
8 NeedsDecoder bool
9 NetTableName string
10 NumOfProps int16
11 Props []prop
12}
13
14type prop struct {
15 SendPropType int8
16 SendPropName string
17 SendPropFlags int32
18 Priority int8
19 ExcludeDtName string
20 LowValue float32
21 HighValue float32
22 NumBits int32
23 NumElements int32
24}
25
26type sendPropFlag int
27
28const (
29 Unsigned sendPropFlag = iota
30 Coord
31 NoScale
32 RoundDown
33 RoundUp
34 Normal
35 Exclude
36 Xyze
37 InsideArray
38 ProxyAlwaysYes
39 IsVectorElem
40 Collapsible
41 CoordMp
42 CoordMpLp // low precision
43 CoordMpInt
44 CellCoord
45 CellCoordLp
46 CellCoordInt
47 ChangesOften
48)
49
50type sendPropType int
51
52const (
53 Int sendPropType = iota
54 Float
55 Vector3
56 Vector2
57 String
58 Array
59 DataTable
60)
61
62func ParseSendTable(reader *bitreader.ReaderType) SendTable {
63 sendTable := SendTable{
64 NeedsDecoder: reader.TryReadBool(),
65 NetTableName: reader.TryReadString(),
66 NumOfProps: int16(reader.TryReadBits(10)),
67 // SendPropType: int8(reader.TryReadBits(5)),
68 // SendPropName: reader.TryReadString(),
69 // SendPropFlags: int16(reader.TryReadBits(16)),
70 }
71 if sendTable.NumOfProps < 0 {
72 return sendTable
73 }
74 for count := 0; count < int(sendTable.NumOfProps); count++ {
75 propType := int8(reader.TryReadBits(5))
76 if propType >= int8(7) {
77 return sendTable
78 }
79 prop := prop{
80 SendPropType: propType,
81 SendPropName: reader.TryReadString(),
82 SendPropFlags: int32(reader.TryReadBits(19)),
83 Priority: int8(reader.TryReadBits(8)),
84 }
85 if propType == int8(DataTable) || CheckBit(int64(prop.SendPropFlags), int(Exclude)) {
86 prop.ExcludeDtName = reader.TryReadString()
87 } else {
88 switch propType {
89 case int8(String), int8(Int), int8(Float), int8(Vector3), int8(Vector2):
90 prop.LowValue = reader.TryReadFloat32()
91 prop.HighValue = reader.TryReadFloat32()
92 prop.NumBits = int32(reader.TryReadBits(7))
93 case int8(Array):
94 prop.NumElements = int32(reader.TryReadBits(10))
95 default:
96 return sendTable
97 }
98 }
99 sendTable.Props = append(sendTable.Props, prop)
100 }
101 return sendTable
102}
103
104func CheckBit(val int64, bit int) bool {
105 return (val & (int64(1) << bit)) != 0
106}
diff --git a/pkg/classes/serverClassInfo.go b/pkg/classes/serverClassInfo.go
new file mode 100644
index 0000000..c60dad1
--- /dev/null
+++ b/pkg/classes/serverClassInfo.go
@@ -0,0 +1,30 @@
1package classes
2
3import (
4 "github.com/pektezol/bitreader"
5)
6
7type ServerClassInfo struct {
8 ClassId int16
9 ClassName string
10 DataTableName string
11}
12
13func ParseServerClassInfo(reader *bitreader.ReaderType, count int, numOfClasses int) ServerClassInfo {
14 return ServerClassInfo{
15 ClassId: int16(reader.TryReadBits(16)),
16 ClassName: reader.TryReadString(),
17 DataTableName: reader.TryReadString(),
18 }
19}
20
21// func serverClassBits(numOfClasses int) int {
22// return highestBitIndex(uint(numOfClasses)) + 1
23// }
24
25// func highestBitIndex(i uint) int {
26// var j int
27// for j = 31; j >= 0 && (i&(1<<j)) == 0; j-- {
28// }
29// return j
30// }
diff --git a/pkg/classes/stringTable.go b/pkg/classes/stringTable.go
new file mode 100644
index 0000000..c6709f5
--- /dev/null
+++ b/pkg/classes/stringTable.go
@@ -0,0 +1,82 @@
1package classes
2
3import (
4 "bytes"
5
6 "github.com/pektezol/bitreader"
7)
8
9type StringTable struct {
10 Name string
11 TableEntries []StringTableEntry
12 Classes []StringTableClass
13}
14
15type StringTableEntry struct {
16 Name string
17 EntryData StringTableEntryData
18}
19
20type StringTableEntryData struct {
21 // TODO: Parse StringTableEntry
22}
23
24type StringTableClass struct {
25 Name string
26 Data string
27}
28
29func ParseStringTables(reader *bitreader.ReaderType) []StringTable {
30 tableCount := reader.TryReadBits(8)
31 stringTables := make([]StringTable, tableCount)
32 for i := 0; i < int(tableCount); i++ {
33 var table StringTable
34 table.ParseStream(reader)
35 stringTables[i] = table
36 }
37 return stringTables
38}
39
40func (stringTable *StringTable) ParseStream(reader *bitreader.ReaderType) {
41 stringTable.Name = reader.TryReadString()
42 entryCount := reader.TryReadBits(16)
43 stringTable.TableEntries = make([]StringTableEntry, entryCount)
44
45 for i := 0; i < int(entryCount); i++ {
46 var entry StringTableEntry
47 entry.Parse(reader)
48 stringTable.TableEntries[i] = entry
49 }
50
51 if reader.TryReadBool() {
52 classCount := reader.TryReadBits(16)
53 stringTable.Classes = make([]StringTableClass, classCount)
54
55 for i := 0; i < int(classCount); i++ {
56 var class StringTableClass
57 class.Parse(reader)
58 stringTable.Classes[i] = class
59 }
60 }
61}
62
63func (stringTableEntry *StringTableEntry) Parse(reader *bitreader.ReaderType) {
64 stringTableEntry.Name = reader.TryReadString()
65 if reader.TryReadBool() {
66 byteLen, err := reader.ReadBits(16)
67 if err != nil {
68 return
69 }
70 dataBsr := reader.TryReadBytesToSlice(int(byteLen))
71 _ = bitreader.Reader(bytes.NewReader(dataBsr), true) // TODO: Parse StringTableEntry
72 // stringTableEntry.EntryData.ParseStream(entryReader)
73 }
74}
75
76func (stringTableClass *StringTableClass) Parse(reader *bitreader.ReaderType) {
77 stringTableClass.Name = reader.TryReadString()
78 if reader.TryReadBool() {
79 dataLen := reader.TryReadBits(16)
80 stringTableClass.Data = reader.TryReadStringLen(int(dataLen))
81 }
82}
diff --git a/pkg/classes/userCmdInfo.go b/pkg/classes/userCmdInfo.go
new file mode 100644
index 0000000..a6d9091
--- /dev/null
+++ b/pkg/classes/userCmdInfo.go
@@ -0,0 +1,72 @@
1package classes
2
3import (
4 "bytes"
5
6 "github.com/pektezol/bitreader"
7)
8
9type UserCmdInfo struct {
10 CommandNumber int32
11 TickCount int32
12 ViewAnglesX float32
13 ViewAnglesY float32
14 ViewAnglesZ float32
15 ForwardMove float32
16 SideMove float32
17 UpMove float32
18 Buttons int32
19 Impulse int8
20 WeaponSelect int16
21 WeaponSubType int8
22 MouseDx int16
23 MouseDy int16
24}
25
26func ParseUserCmdInfo(data []byte) UserCmdInfo {
27 reader := bitreader.Reader(bytes.NewReader(data), true)
28 userCmdInfo := UserCmdInfo{}
29 if reader.TryReadBool() {
30 userCmdInfo.CommandNumber = int32(reader.TryReadBits(32))
31 }
32 if reader.TryReadBool() {
33 userCmdInfo.TickCount = int32(reader.TryReadBits(32))
34 }
35 if reader.TryReadBool() {
36 userCmdInfo.ViewAnglesX = reader.TryReadFloat32()
37 }
38 if reader.TryReadBool() {
39 userCmdInfo.ViewAnglesY = reader.TryReadFloat32()
40 }
41 if reader.TryReadBool() {
42 userCmdInfo.ViewAnglesZ = reader.TryReadFloat32()
43 }
44 if reader.TryReadBool() {
45 userCmdInfo.ForwardMove = reader.TryReadFloat32()
46 }
47 if reader.TryReadBool() {
48 userCmdInfo.SideMove = reader.TryReadFloat32()
49 }
50 if reader.TryReadBool() {
51 userCmdInfo.UpMove = reader.TryReadFloat32()
52 }
53 if reader.TryReadBool() {
54 userCmdInfo.Buttons = int32(reader.TryReadBits(32))
55 }
56 if reader.TryReadBool() {
57 userCmdInfo.Impulse = int8(reader.TryReadBits(8))
58 }
59 if reader.TryReadBool() {
60 userCmdInfo.WeaponSelect = int16(reader.TryReadBits(11))
61 if reader.TryReadBool() {
62 userCmdInfo.WeaponSubType = int8(reader.TryReadBits(6))
63 }
64 }
65 if reader.TryReadBool() {
66 userCmdInfo.MouseDx = int16(reader.TryReadBits(16))
67 }
68 if reader.TryReadBool() {
69 userCmdInfo.MouseDy = int16(reader.TryReadBits(16))
70 }
71 return userCmdInfo
72}
diff --git a/pkg/messages/messages.go b/pkg/messages/messages.go
new file mode 100644
index 0000000..39f89e9
--- /dev/null
+++ b/pkg/messages/messages.go
@@ -0,0 +1,87 @@
1package messages
2
3import (
4 "fmt"
5 "reflect"
6
7 "github.com/pektezol/bitreader"
8 messages "github.com/pektezol/demoparser/pkg/messages/types"
9)
10
11func ParseMessages(messageType int, reader *bitreader.ReaderType) any {
12 var messageData any
13 switch messageType {
14 case 0:
15 messageData = messages.ParseNetNop(reader)
16 case 1:
17 messageData = messages.ParseNetDisconnect(reader)
18 case 2:
19 messageData = messages.ParseNetFile(reader)
20 case 3:
21 messageData = messages.ParseNetSplitScreenUser(reader)
22 case 4:
23 messageData = messages.ParseNetTick(reader)
24 case 5:
25 messageData = messages.ParseNetStringCmd(reader)
26 case 6:
27 messageData = messages.ParseNetSetConVar(reader)
28 case 7:
29 messageData = messages.ParseNetSignOnState(reader)
30 case 8:
31 messageData = messages.ParseSvcServerInfo(reader)
32 case 9:
33 messageData = messages.ParseSvcSendTable(reader)
34 case 10:
35 messageData = messages.ParseSvcClassInfo(reader)
36 case 11:
37 messageData = messages.ParseSvcSetPause(reader)
38 case 12:
39 messageData = messages.ParseSvcCreateStringTable(reader)
40 case 13:
41 messageData = messages.ParseSvcUpdateStringTable(reader)
42 case 14:
43 messageData = messages.ParseSvcVoiceInit(reader)
44 case 15:
45 messageData = messages.ParseSvcVoiceData(reader)
46 case 16:
47 messageData = messages.ParseSvcPrint(reader)
48 case 17:
49 messageData = messages.ParseSvcSounds(reader)
50 case 18:
51 messageData = messages.ParseSvcSetView(reader)
52 case 19:
53 messageData = messages.ParseSvcFixAngle(reader)
54 case 20:
55 messageData = messages.ParseSvcCrosshairAngle(reader)
56 case 21:
57 messageData = messages.ParseSvcBspDecal(reader)
58 case 22:
59 messageData = messages.ParseSvcSplitScreen(reader)
60 case 23:
61 messageData = messages.ParseSvcUserMessage(reader)
62 case 24:
63 messageData = messages.ParseSvcEntityMessage(reader)
64 case 25:
65 messageData = messages.ParseSvcGameEvent(reader)
66 case 26:
67 messageData = messages.ParseSvcPacketEntities(reader)
68 case 27:
69 messageData = messages.ParseSvcTempEntities(reader)
70 case 28:
71 messageData = messages.ParseSvcPrefetch(reader)
72 case 29:
73 messageData = messages.ParseSvcMenu(reader)
74 case 30:
75 messageData = messages.ParseSvcGameEventList(reader)
76 case 31:
77 messageData = messages.ParseSvcGetCvarValue(reader)
78 case 32:
79 messageData = messages.ParseSvcCmdKeyValues(reader)
80 case 33:
81 messageData = messages.ParseSvcPaintmapData(reader)
82 default:
83 return nil
84 }
85 fmt.Printf("\t\t(%d) %s:\n\t\t\t%+v\n", messageType, reflect.ValueOf(messageData).Type(), messageData)
86 return messageData
87}
diff --git a/pkg/messages/types/netDisconnect.go b/pkg/messages/types/netDisconnect.go
new file mode 100644
index 0000000..69d4a67
--- /dev/null
+++ b/pkg/messages/types/netDisconnect.go
@@ -0,0 +1,13 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type NetDisconnect struct {
6 Text string
7}
8
9func ParseNetDisconnect(reader *bitreader.ReaderType) NetDisconnect {
10 return NetDisconnect{
11 Text: reader.TryReadString(),
12 }
13}
diff --git a/pkg/messages/types/netFile.go b/pkg/messages/types/netFile.go
new file mode 100644
index 0000000..a41a0cf
--- /dev/null
+++ b/pkg/messages/types/netFile.go
@@ -0,0 +1,17 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type NetFile struct {
6 TransferId int32
7 FileName string
8 FileRequested bool
9}
10
11func ParseNetFile(reader *bitreader.ReaderType) NetFile {
12 return NetFile{
13 TransferId: int32(reader.TryReadBits(32)),
14 FileName: reader.TryReadString(),
15 FileRequested: reader.TryReadBool(),
16 }
17}
diff --git a/pkg/messages/types/netNop.go b/pkg/messages/types/netNop.go
new file mode 100644
index 0000000..33f8e25
--- /dev/null
+++ b/pkg/messages/types/netNop.go
@@ -0,0 +1,9 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type NetNop struct{}
6
7func ParseNetNop(reader *bitreader.ReaderType) NetNop {
8 return NetNop{}
9}
diff --git a/pkg/messages/types/netSetConVar.go b/pkg/messages/types/netSetConVar.go
new file mode 100644
index 0000000..08042ae
--- /dev/null
+++ b/pkg/messages/types/netSetConVar.go
@@ -0,0 +1,29 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type NetSetConVar struct {
6 Length int8
7 ConVars []conVar
8}
9
10type conVar struct {
11 Name string
12 Value string
13}
14
15func ParseNetSetConVar(reader *bitreader.ReaderType) NetSetConVar {
16 length := reader.TryReadBits(8)
17 convars := []conVar{}
18 for count := 0; count < int(length); count++ {
19 convar := conVar{
20 Name: reader.TryReadString(),
21 Value: reader.TryReadString(),
22 }
23 convars = append(convars, convar)
24 }
25 return NetSetConVar{
26 Length: int8(length),
27 ConVars: convars,
28 }
29}
diff --git a/pkg/messages/types/netSignOnState.go b/pkg/messages/types/netSignOnState.go
new file mode 100644
index 0000000..4609ff2
--- /dev/null
+++ b/pkg/messages/types/netSignOnState.go
@@ -0,0 +1,26 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type NetSignOnState struct {
6 SignOnState int8
7 SpawnCount int32
8 NumServerPlayers int32
9 IdsLength int32
10 PlayersNetworksIds []byte
11 MapNameLength int32
12 MapName string
13}
14
15func ParseNetSignOnState(reader *bitreader.ReaderType) NetSignOnState {
16 netSignOnState := NetSignOnState{
17 SignOnState: int8(reader.TryReadBits(8)),
18 SpawnCount: int32(reader.TryReadBits(32)),
19 NumServerPlayers: int32(reader.TryReadBits(32)),
20 IdsLength: int32(reader.TryReadBits(32)),
21 }
22 netSignOnState.PlayersNetworksIds = reader.TryReadBytesToSlice(int(netSignOnState.IdsLength))
23 netSignOnState.MapNameLength = int32(reader.TryReadBits(32))
24 netSignOnState.MapName = reader.TryReadStringLen(int(netSignOnState.MapNameLength))
25 return netSignOnState
26}
diff --git a/pkg/messages/types/netSplitScreenUser.go b/pkg/messages/types/netSplitScreenUser.go
new file mode 100644
index 0000000..65e85f3
--- /dev/null
+++ b/pkg/messages/types/netSplitScreenUser.go
@@ -0,0 +1,13 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type NetSplitScreenUser struct {
6 Unknown bool
7}
8
9func ParseNetSplitScreenUser(reader *bitreader.ReaderType) NetSplitScreenUser {
10 return NetSplitScreenUser{
11 Unknown: reader.TryReadBool(),
12 }
13}
diff --git a/pkg/messages/types/netStringCmd.go b/pkg/messages/types/netStringCmd.go
new file mode 100644
index 0000000..158658e
--- /dev/null
+++ b/pkg/messages/types/netStringCmd.go
@@ -0,0 +1,13 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type NetStringCmd struct {
6 Command string
7}
8
9func ParseNetStringCmd(reader *bitreader.ReaderType) NetStringCmd {
10 return NetStringCmd{
11 Command: reader.TryReadString(),
12 }
13}
diff --git a/pkg/messages/types/netTick.go b/pkg/messages/types/netTick.go
new file mode 100644
index 0000000..e14f259
--- /dev/null
+++ b/pkg/messages/types/netTick.go
@@ -0,0 +1,17 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type NetTick struct {
6 Tick int32
7 HostFrameTime int16
8 HostFrameTimeStdDeviation int16
9}
10
11func ParseNetTick(reader *bitreader.ReaderType) NetTick {
12 return NetTick{
13 Tick: int32(reader.TryReadBits(32)),
14 HostFrameTime: int16(reader.TryReadBits(16) / 10e5),
15 HostFrameTimeStdDeviation: int16(reader.TryReadBits(16) / 10e5),
16 }
17}
diff --git a/pkg/messages/types/svcBspDecal.go b/pkg/messages/types/svcBspDecal.go
new file mode 100644
index 0000000..484497f
--- /dev/null
+++ b/pkg/messages/types/svcBspDecal.go
@@ -0,0 +1,61 @@
1package messages
2
3import (
4 "github.com/pektezol/bitreader"
5)
6
7type SvcBspDecal struct {
8 Pos []vectorCoord
9 DecalTextureIndex int16
10 EntityIndex int16
11 ModelIndex int16
12 LowPriority int8
13}
14
15type vectorCoord struct {
16 Value float32
17 Valid bool
18}
19
20func ParseSvcBspDecal(reader *bitreader.ReaderType) SvcBspDecal {
21 svcBspDecal := SvcBspDecal{
22 Pos: readVectorCoords(reader),
23 DecalTextureIndex: int16(reader.TryReadBits(9)),
24 }
25 if reader.TryReadBool() {
26 svcBspDecal.EntityIndex = int16(reader.TryReadBits(11))
27 svcBspDecal.ModelIndex = int16(reader.TryReadBits(11))
28 }
29 svcBspDecal.LowPriority = int8(reader.TryReadBits(1))
30 return svcBspDecal
31}
32
33func readVectorCoords(reader *bitreader.ReaderType) []vectorCoord {
34 const COORD_INTEGER_BITS uint8 = 14
35 const COORD_FRACTIONAL_BITS uint8 = 5
36 const COORD_DENOMINATOR uint8 = 1 << COORD_FRACTIONAL_BITS
37 const COORD_RESOLUTION float32 = 1.0 / float32(COORD_DENOMINATOR)
38 readVectorCoord := func() float32 {
39 value := float32(0)
40 integer := reader.TryReadBits(1)
41 fraction := reader.TryReadBits(1)
42 if integer != 0 || fraction != 0 {
43 sign := reader.TryReadBits(1)
44 if integer != 0 {
45 integer = reader.TryReadBits(int(COORD_INTEGER_BITS)) + 1
46 }
47 if fraction != 0 {
48 fraction = reader.TryReadBits(int(COORD_FRACTIONAL_BITS))
49 }
50 value = float32(integer) + float32(fraction)*COORD_RESOLUTION
51 if sign != 0 {
52 value = -value
53 }
54 }
55 return value
56 }
57 x := reader.TryReadBits(1)
58 y := reader.TryReadBits(1)
59 z := reader.TryReadBits(1)
60 return []vectorCoord{{Value: readVectorCoord(), Valid: x != 0}, {Value: readVectorCoord(), Valid: y != 0}, {Value: readVectorCoord(), Valid: z != 0}}
61}
diff --git a/pkg/messages/types/svcClassInfo.go b/pkg/messages/types/svcClassInfo.go
new file mode 100644
index 0000000..9f367d3
--- /dev/null
+++ b/pkg/messages/types/svcClassInfo.go
@@ -0,0 +1,40 @@
1package messages
2
3import (
4 "fmt"
5 "math"
6
7 "github.com/pektezol/bitreader"
8)
9
10type SvcClassInfo struct {
11 Length int16
12 CreateOnClient bool
13 ServerClasses []serverClass
14}
15
16type serverClass struct {
17 ClassId int16
18 ClassName string
19 DataTableName string
20}
21
22func ParseSvcClassInfo(reader *bitreader.ReaderType) SvcClassInfo {
23 svcClassInfo := SvcClassInfo{
24 Length: int16(reader.TryReadBits(16)),
25 CreateOnClient: reader.TryReadBool(),
26 }
27 classes := []serverClass{}
28 if !svcClassInfo.CreateOnClient {
29 for count := 0; count < int(svcClassInfo.Length); count++ {
30 fmt.Println(classes)
31 classes = append(classes, serverClass{
32 ClassId: int16(reader.TryReadBits(int(math.Log2(float64(svcClassInfo.Length)) + 1))),
33 ClassName: reader.TryReadString(),
34 DataTableName: reader.TryReadString(),
35 })
36 }
37 }
38 svcClassInfo.ServerClasses = classes
39 return svcClassInfo
40}
diff --git a/pkg/messages/types/svcCmdKeyValues.go b/pkg/messages/types/svcCmdKeyValues.go
new file mode 100644
index 0000000..1c4d819
--- /dev/null
+++ b/pkg/messages/types/svcCmdKeyValues.go
@@ -0,0 +1,16 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcCmdKeyValues struct {
6 Length int32
7 Data []byte
8}
9
10func ParseSvcCmdKeyValues(reader *bitreader.ReaderType) SvcCmdKeyValues {
11 svcCmdKeyValues := SvcCmdKeyValues{
12 Length: int32(reader.TryReadBits(32)),
13 }
14 svcCmdKeyValues.Data = reader.TryReadBytesToSlice(int(svcCmdKeyValues.Length))
15 return svcCmdKeyValues
16}
diff --git a/pkg/messages/types/svcCreateStringTable.go b/pkg/messages/types/svcCreateStringTable.go
new file mode 100644
index 0000000..ed9e477
--- /dev/null
+++ b/pkg/messages/types/svcCreateStringTable.go
@@ -0,0 +1,36 @@
1package messages
2
3import (
4 "math"
5
6 "github.com/pektezol/bitreader"
7)
8
9type SvcCreateStringTable struct {
10 Name string
11 MaxEntries int16
12 NumEntries int8
13 Length int32
14 UserDataFixedSize bool
15 UserDataSize int16
16 UserDataSizeBits int8
17 Flags int8
18 StringData int
19}
20
21func ParseSvcCreateStringTable(reader *bitreader.ReaderType) SvcCreateStringTable {
22 svcCreateStringTable := SvcCreateStringTable{
23 Name: reader.TryReadString(),
24 MaxEntries: int16(reader.TryReadBits(16)),
25 }
26 svcCreateStringTable.NumEntries = int8(reader.TryReadBits(int(math.Log2(float64(svcCreateStringTable.MaxEntries))) + 1))
27 svcCreateStringTable.Length = int32(reader.TryReadBits(20))
28 svcCreateStringTable.UserDataFixedSize = reader.TryReadBool()
29 if svcCreateStringTable.UserDataFixedSize {
30 svcCreateStringTable.UserDataSize = int16(reader.TryReadBits(12))
31 svcCreateStringTable.UserDataSizeBits = int8(reader.TryReadBits(4))
32 }
33 svcCreateStringTable.Flags = int8(reader.TryReadBits(2))
34 reader.SkipBits(int(svcCreateStringTable.Length)) // TODO: StringTable parsing
35 return svcCreateStringTable
36}
diff --git a/pkg/messages/types/svcCrosshairAngle.go b/pkg/messages/types/svcCrosshairAngle.go
new file mode 100644
index 0000000..cf18212
--- /dev/null
+++ b/pkg/messages/types/svcCrosshairAngle.go
@@ -0,0 +1,13 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcCrosshairAngle struct {
6 Angle []int16
7}
8
9func ParseSvcCrosshairAngle(reader *bitreader.ReaderType) SvcCrosshairAngle {
10 return SvcCrosshairAngle{
11 Angle: []int16{int16(reader.TryReadBits(16)), int16(reader.TryReadBits(16)), int16(reader.TryReadBits(16))},
12 }
13}
diff --git a/pkg/messages/types/svcEntityMessage.go b/pkg/messages/types/svcEntityMessage.go
new file mode 100644
index 0000000..9726ced
--- /dev/null
+++ b/pkg/messages/types/svcEntityMessage.go
@@ -0,0 +1,20 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcEntityMessage struct {
6 EntityIndex int16
7 ClassId int16
8 Length int16
9 Data []byte
10}
11
12func ParseSvcEntityMessage(reader *bitreader.ReaderType) SvcEntityMessage {
13 svcEntityMessage := SvcEntityMessage{
14 EntityIndex: int16(reader.TryReadBits(11)),
15 ClassId: int16(reader.TryReadBits(9)),
16 Length: int16(reader.TryReadBits(11)),
17 }
18 svcEntityMessage.Data = reader.TryReadBitsToSlice(int(svcEntityMessage.Length))
19 return svcEntityMessage
20}
diff --git a/pkg/messages/types/svcFixAngle.go b/pkg/messages/types/svcFixAngle.go
new file mode 100644
index 0000000..56acf04
--- /dev/null
+++ b/pkg/messages/types/svcFixAngle.go
@@ -0,0 +1,15 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcFixAngle struct {
6 Relative bool
7 Angle []int16
8}
9
10func ParseSvcFixAngle(reader *bitreader.ReaderType) SvcFixAngle {
11 return SvcFixAngle{
12 Relative: reader.TryReadBool(),
13 Angle: []int16{int16(reader.TryReadBits(16)), int16(reader.TryReadBits(16)), int16(reader.TryReadBits(16))},
14 }
15}
diff --git a/pkg/messages/types/svcGameEvent.go b/pkg/messages/types/svcGameEvent.go
new file mode 100644
index 0000000..6ee4d01
--- /dev/null
+++ b/pkg/messages/types/svcGameEvent.go
@@ -0,0 +1,16 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcGameEvent struct {
6 Length int16
7 Data []byte // TODO: GameEvent[]
8}
9
10func ParseSvcGameEvent(reader *bitreader.ReaderType) SvcGameEvent {
11 svcGameEvent := SvcGameEvent{
12 Length: int16(reader.TryReadBits(11)),
13 }
14 svcGameEvent.Data = reader.TryReadBitsToSlice(int(svcGameEvent.Length))
15 return svcGameEvent
16}
diff --git a/pkg/messages/types/svcGameEventList.go b/pkg/messages/types/svcGameEventList.go
new file mode 100644
index 0000000..b99ce28
--- /dev/null
+++ b/pkg/messages/types/svcGameEventList.go
@@ -0,0 +1,21 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcGameEventList struct {
6 Events int16
7 Length int32
8 GameEventDescriptor []gameEventDescriptor
9}
10
11type gameEventDescriptor struct {
12}
13
14func ParseSvcGameEventList(reader *bitreader.ReaderType) SvcGameEventList {
15 svcGameEventList := SvcGameEventList{
16 Events: int16(reader.TryReadBits(9)),
17 Length: int32(reader.TryReadBits(20)),
18 }
19 reader.TryReadBitsToSlice(int(svcGameEventList.Length))
20 return svcGameEventList
21}
diff --git a/pkg/messages/types/svcGetCvarValue.go b/pkg/messages/types/svcGetCvarValue.go
new file mode 100644
index 0000000..aef5c8e
--- /dev/null
+++ b/pkg/messages/types/svcGetCvarValue.go
@@ -0,0 +1,16 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcGetCvarValue struct {
6 Cookie string
7 CvarName string
8}
9
10func ParseSvcGetCvarValue(reader *bitreader.ReaderType) SvcGetCvarValue {
11 svcGetCvarValue := SvcGetCvarValue{
12 Cookie: reader.TryReadStringLen(4),
13 CvarName: reader.TryReadString(),
14 }
15 return svcGetCvarValue
16}
diff --git a/pkg/messages/types/svcMenu.go b/pkg/messages/types/svcMenu.go
new file mode 100644
index 0000000..d89f52c
--- /dev/null
+++ b/pkg/messages/types/svcMenu.go
@@ -0,0 +1,18 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcMenu struct {
6 MenuType int16
7 Length int32
8 Data []byte
9}
10
11func ParseSvcMenu(reader *bitreader.ReaderType) SvcMenu {
12 svcMenu := SvcMenu{
13 MenuType: int16(reader.TryReadBits(16)),
14 Length: int32(reader.TryReadBits(32)),
15 }
16 svcMenu.Data = reader.TryReadBitsToSlice(int(svcMenu.Length))
17 return svcMenu
18}
diff --git a/pkg/messages/types/svcPacketEntities.go b/pkg/messages/types/svcPacketEntities.go
new file mode 100644
index 0000000..b1c23e5
--- /dev/null
+++ b/pkg/messages/types/svcPacketEntities.go
@@ -0,0 +1,30 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcPacketEntities struct {
6 MaxEntries int16
7 IsDelta bool
8 DeltaFrom int32
9 BaseLine bool
10 UpdatedEntries int16
11 Length int32
12 UpdatedBaseline bool
13 Data []byte
14}
15
16func ParseSvcPacketEntities(reader *bitreader.ReaderType) SvcPacketEntities {
17 svcPacketEntities := SvcPacketEntities{
18 MaxEntries: int16(reader.TryReadBits(11)),
19 IsDelta: reader.TryReadBool(),
20 }
21 if svcPacketEntities.IsDelta {
22 svcPacketEntities.DeltaFrom = int32(reader.TryReadBits(32))
23 }
24 svcPacketEntities.BaseLine = reader.TryReadBool()
25 svcPacketEntities.UpdatedEntries = int16(reader.TryReadBits(11))
26 svcPacketEntities.Length = int32(reader.TryReadBits(20))
27 svcPacketEntities.UpdatedBaseline = reader.TryReadBool()
28 svcPacketEntities.Data = reader.TryReadBitsToSlice(int(svcPacketEntities.Length))
29 return svcPacketEntities
30}
diff --git a/pkg/messages/types/svcPaintmapData.go b/pkg/messages/types/svcPaintmapData.go
new file mode 100644
index 0000000..6b041da
--- /dev/null
+++ b/pkg/messages/types/svcPaintmapData.go
@@ -0,0 +1,16 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcPaintmapData struct {
6 Length int32
7 Data []byte
8}
9
10func ParseSvcPaintmapData(reader *bitreader.ReaderType) SvcPaintmapData {
11 svcPaintmapData := SvcPaintmapData{
12 Length: int32(reader.TryReadBits(32)),
13 }
14 svcPaintmapData.Data = reader.TryReadBitsToSlice(int(svcPaintmapData.Length))
15 return svcPaintmapData
16}
diff --git a/pkg/messages/types/svcPrefetch.go b/pkg/messages/types/svcPrefetch.go
new file mode 100644
index 0000000..549f926
--- /dev/null
+++ b/pkg/messages/types/svcPrefetch.go
@@ -0,0 +1,13 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcPrefetch struct {
6 SoundIndex int16
7}
8
9func ParseSvcPrefetch(reader *bitreader.ReaderType) SvcPrefetch {
10 return SvcPrefetch{
11 SoundIndex: int16(reader.TryReadBits(13)),
12 }
13}
diff --git a/pkg/messages/types/svcPrint.go b/pkg/messages/types/svcPrint.go
new file mode 100644
index 0000000..8aff927
--- /dev/null
+++ b/pkg/messages/types/svcPrint.go
@@ -0,0 +1,13 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcPrint struct {
6 Message string
7}
8
9func ParseSvcPrint(reader *bitreader.ReaderType) SvcPrint {
10 return SvcPrint{
11 Message: reader.TryReadString(),
12 }
13}
diff --git a/pkg/messages/types/svcSendTable.go b/pkg/messages/types/svcSendTable.go
new file mode 100644
index 0000000..ae8960b
--- /dev/null
+++ b/pkg/messages/types/svcSendTable.go
@@ -0,0 +1,17 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcSendTable struct {
6 NeedsDecoder int8
7 Length int8
8 Props int32
9}
10
11func ParseSvcSendTable(reader *bitreader.ReaderType) SvcSendTable {
12 return SvcSendTable{
13 NeedsDecoder: int8(reader.TryReadBits(8)),
14 Length: int8(reader.TryReadBits(8)),
15 Props: int32(reader.TryReadBits(32)),
16 }
17}
diff --git a/pkg/messages/types/svcServerInfo.go b/pkg/messages/types/svcServerInfo.go
new file mode 100644
index 0000000..b8bb308
--- /dev/null
+++ b/pkg/messages/types/svcServerInfo.go
@@ -0,0 +1,43 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcServerInfo struct {
6 Protocol int16
7 ServerCount int32
8 IsHltv bool
9 IsDedicated bool
10 ClientCrc int32
11 MaxClasses int16
12 MapCrc int32
13 PlayerSlot int8
14 MaxClients int8
15 Unk int32
16 TickInterval int32
17 COs int8
18 GameDir string
19 MapName string
20 SkyName string
21 HostName string
22}
23
24func ParseSvcServerInfo(reader *bitreader.ReaderType) SvcServerInfo {
25 return SvcServerInfo{
26 Protocol: int16(reader.TryReadBits(16)),
27 ServerCount: int32(reader.TryReadBits(32)),
28 IsHltv: reader.TryReadBool(),
29 IsDedicated: reader.TryReadBool(),
30 ClientCrc: int32(reader.TryReadBits(32)),
31 MaxClasses: int16(reader.TryReadBits(16)),
32 MapCrc: int32(reader.TryReadBits(32)),
33 PlayerSlot: int8(reader.TryReadBits(8)),
34 MaxClients: int8(reader.TryReadBits(8)),
35 Unk: int32(reader.TryReadBits(32)),
36 TickInterval: int32(reader.TryReadBits(32)),
37 COs: int8(reader.TryReadBits(8)),
38 GameDir: reader.TryReadString(),
39 MapName: reader.TryReadString(),
40 SkyName: reader.TryReadString(),
41 HostName: reader.TryReadString(),
42 }
43}
diff --git a/pkg/messages/types/svcSetPause.go b/pkg/messages/types/svcSetPause.go
new file mode 100644
index 0000000..94303b7
--- /dev/null
+++ b/pkg/messages/types/svcSetPause.go
@@ -0,0 +1,13 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcSetPause struct {
6 Paused bool
7}
8
9func ParseSvcSetPause(reader *bitreader.ReaderType) SvcSetPause {
10 return SvcSetPause{
11 Paused: reader.TryReadBool(),
12 }
13}
diff --git a/pkg/messages/types/svcSetView.go b/pkg/messages/types/svcSetView.go
new file mode 100644
index 0000000..70d1e2b
--- /dev/null
+++ b/pkg/messages/types/svcSetView.go
@@ -0,0 +1,13 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcSetView struct {
6 EntityIndex int16
7}
8
9func ParseSvcSetView(reader *bitreader.ReaderType) SvcSetView {
10 return SvcSetView{
11 EntityIndex: int16(reader.TryReadBits(11)),
12 }
13}
diff --git a/pkg/messages/types/svcSounds.go b/pkg/messages/types/svcSounds.go
new file mode 100644
index 0000000..e87d584
--- /dev/null
+++ b/pkg/messages/types/svcSounds.go
@@ -0,0 +1,25 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcSounds struct {
6 ReliableSound bool
7 Size int8
8 Length int16
9 Data []byte
10}
11
12func ParseSvcSounds(reader *bitreader.ReaderType) SvcSounds {
13 svcSounds := SvcSounds{
14 ReliableSound: reader.TryReadBool(),
15 }
16 if svcSounds.ReliableSound {
17 svcSounds.Size = 1
18 svcSounds.Length = int16(reader.TryReadBits(8))
19 } else {
20 svcSounds.Size = int8(reader.TryReadBits(8))
21 svcSounds.Length = int16(reader.TryReadBits(16))
22 }
23 svcSounds.Data = reader.TryReadBitsToSlice(int(svcSounds.Length))
24 return svcSounds
25}
diff --git a/pkg/messages/types/svcSplitScreen.go b/pkg/messages/types/svcSplitScreen.go
new file mode 100644
index 0000000..9c808bc
--- /dev/null
+++ b/pkg/messages/types/svcSplitScreen.go
@@ -0,0 +1,18 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcSplitScreen struct {
6 Unk bool
7 Length int16
8 Data []byte
9}
10
11func ParseSvcSplitScreen(reader *bitreader.ReaderType) SvcSplitScreen {
12 svcSplitScreen := SvcSplitScreen{
13 Unk: reader.TryReadBool(),
14 Length: int16(reader.TryReadBits(11)),
15 }
16 svcSplitScreen.Data = reader.TryReadBitsToSlice(int(svcSplitScreen.Length))
17 return svcSplitScreen
18}
diff --git a/pkg/messages/types/svcTempEntities.go b/pkg/messages/types/svcTempEntities.go
new file mode 100644
index 0000000..d22423d
--- /dev/null
+++ b/pkg/messages/types/svcTempEntities.go
@@ -0,0 +1,18 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcTempEntities struct {
6 NumEntries int8
7 Length int32
8 Data []byte
9}
10
11func ParseSvcTempEntities(reader *bitreader.ReaderType) SvcTempEntities {
12 svcTempEntities := SvcTempEntities{
13 NumEntries: int8(reader.TryReadBits(8)),
14 Length: int32(reader.TryReadBits(17)),
15 }
16 svcTempEntities.Data = reader.TryReadBitsToSlice(int(svcTempEntities.Length))
17 return svcTempEntities
18}
diff --git a/pkg/messages/types/svcUpdateStringTable.go b/pkg/messages/types/svcUpdateStringTable.go
new file mode 100644
index 0000000..2840482
--- /dev/null
+++ b/pkg/messages/types/svcUpdateStringTable.go
@@ -0,0 +1,22 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcUpdateStringTable struct {
6 TableId int8
7 NumChangedEntries int16
8 Length int32
9 Data []byte
10}
11
12func ParseSvcUpdateStringTable(reader *bitreader.ReaderType) SvcUpdateStringTable {
13 svcUpdateStringTable := SvcUpdateStringTable{
14 TableId: int8(reader.TryReadBits(5)),
15 }
16 if reader.TryReadBool() {
17 svcUpdateStringTable.NumChangedEntries = int16(reader.TryReadBits(16))
18 }
19 svcUpdateStringTable.Length = int32(reader.TryReadBits(20))
20 svcUpdateStringTable.Data = reader.TryReadBitsToSlice(int(svcUpdateStringTable.Length))
21 return svcUpdateStringTable
22}
diff --git a/pkg/messages/types/svcUserMessage.go b/pkg/messages/types/svcUserMessage.go
new file mode 100644
index 0000000..b53c7c0
--- /dev/null
+++ b/pkg/messages/types/svcUserMessage.go
@@ -0,0 +1,18 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcUserMessage struct {
6 MsgType int8
7 Length int16
8 Data []byte
9}
10
11func ParseSvcUserMessage(reader *bitreader.ReaderType) SvcUserMessage {
12 svcUserMessage := SvcUserMessage{
13 MsgType: int8(reader.TryReadBits(8)),
14 Length: int16(reader.TryReadBits(12)),
15 }
16 svcUserMessage.Data = reader.TryReadBitsToSlice(int(svcUserMessage.Length))
17 return svcUserMessage
18}
diff --git a/pkg/messages/types/svcVoiceData.go b/pkg/messages/types/svcVoiceData.go
new file mode 100644
index 0000000..b6c81d4
--- /dev/null
+++ b/pkg/messages/types/svcVoiceData.go
@@ -0,0 +1,20 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcVoiceData struct {
6 Client int8
7 Proximity int8
8 Length int16
9 Data []byte
10}
11
12func ParseSvcVoiceData(reader *bitreader.ReaderType) SvcVoiceData {
13 svcVoiceData := SvcVoiceData{
14 Client: int8(reader.TryReadBits(8)),
15 Proximity: int8(reader.TryReadBits(8)),
16 Length: int16(reader.TryReadBits(16)),
17 }
18 svcVoiceData.Data = reader.TryReadBitsToSlice(int(svcVoiceData.Length))
19 return svcVoiceData
20}
diff --git a/pkg/messages/types/svcVoiceInit.go b/pkg/messages/types/svcVoiceInit.go
new file mode 100644
index 0000000..4c95aab
--- /dev/null
+++ b/pkg/messages/types/svcVoiceInit.go
@@ -0,0 +1,20 @@
1package messages
2
3import "github.com/pektezol/bitreader"
4
5type SvcVoiceInit struct {
6 Codec string
7 Quality uint8
8 Unk float32
9}
10
11func ParseSvcVoiceInit(reader *bitreader.ReaderType) SvcVoiceInit {
12 svcVoiceInit := SvcVoiceInit{
13 Codec: reader.TryReadString(),
14 Quality: uint8(reader.TryReadBits(8)),
15 }
16 if svcVoiceInit.Quality == 0b11111111 {
17 svcVoiceInit.Unk = reader.TryReadFloat32()
18 }
19 return svcVoiceInit
20}
diff --git a/pkg/packets/headers.go b/pkg/packets/headers.go
new file mode 100644
index 0000000..543476b
--- /dev/null
+++ b/pkg/packets/headers.go
@@ -0,0 +1,48 @@
1package packets
2
3import (
4 "fmt"
5
6 "github.com/pektezol/bitreader"
7)
8
9type Headers struct {
10 DemoFileStamp string
11 DemoProtocol int32
12 NetworkProtocol int32
13 ServerName string
14 ClientName string
15 MapName string
16 GameDirectory string
17 PlaybackTime float32
18 PlaybackTicks int32
19 PlaybackFrames int32
20 SignOnLength int32
21}
22
23func ParseHeaders(reader *bitreader.ReaderType) Headers {
24 headers := Headers{
25 DemoFileStamp: reader.TryReadString(),
26 DemoProtocol: int32(reader.TryReadInt32()),
27 NetworkProtocol: int32(reader.TryReadInt32()),
28 ServerName: reader.TryReadStringLen(260),
29 ClientName: reader.TryReadStringLen(260),
30 MapName: reader.TryReadStringLen(260),
31 GameDirectory: reader.TryReadStringLen(260),
32 PlaybackTime: reader.TryReadFloat32(),
33 PlaybackTicks: int32(reader.TryReadInt32()),
34 PlaybackFrames: int32(reader.TryReadInt32()),
35 SignOnLength: int32(reader.TryReadInt32()),
36 }
37 if headers.DemoFileStamp != "HL2DEMO" {
38 panic("invalid demo file stamp")
39 }
40 if headers.DemoProtocol != 4 {
41 panic("this parser only supports demos from new engine")
42 }
43 if headers.NetworkProtocol != 2001 {
44 panic("this parser only supports demos from portal 2")
45 }
46 fmt.Printf("Headers: %+v\n", headers)
47 return headers
48}
diff --git a/pkg/packets/packets.go b/pkg/packets/packets.go
new file mode 100644
index 0000000..a84da21
--- /dev/null
+++ b/pkg/packets/packets.go
@@ -0,0 +1,125 @@
1package packets
2
3import (
4 "bytes"
5
6 "github.com/pektezol/bitreader"
7 "github.com/pektezol/demoparser/pkg/classes"
8 "github.com/pektezol/demoparser/pkg/messages"
9)
10
11type PacketMessageInfo struct {
12 PacketType int8
13 TickNumber int32
14 SlotNumber int8
15 Data any
16}
17
18const MSSC = 2
19
20func ParsePackets(reader *bitreader.ReaderType) PacketMessageInfo {
21 packetType := reader.TryReadBits(8)
22 tickNumber := reader.TryReadBits(32)
23 slotNumber := reader.TryReadBits(8)
24 var packetData any
25 switch packetType {
26 case 1: // SignOn
27 signOn := SignOn{}
28 for count := 0; count < MSSC; count++ {
29 signOn.PacketInfo = append(signOn.PacketInfo, classes.ParseCmdInfo(reader))
30 }
31 signOn.InSequence = int32(reader.TryReadBits(32))
32 signOn.OutSequence = int32(reader.TryReadBits(32))
33 signOn.Size = int32(reader.TryReadInt32())
34 data := reader.TryReadBytesToSlice(int(signOn.Size))
35 packetReader := bitreader.Reader(bytes.NewReader(data), true)
36 for {
37 messageType, err := packetReader.ReadBits(6)
38 if err != nil {
39 break
40 }
41 signOn.Data = append(signOn.Data, messages.ParseMessages(int(messageType), packetReader))
42 }
43 packetData = signOn
44 case 2: // Packet
45 packet := Packet{}
46 for count := 0; count < MSSC; count++ {
47 packet.PacketInfo = append(packet.PacketInfo, classes.ParseCmdInfo(reader))
48 }
49 packet.InSequence = int32(reader.TryReadBits(32))
50 packet.OutSequence = int32(reader.TryReadBits(32))
51 packet.Size = int32(reader.TryReadInt32())
52 data := reader.TryReadBytesToSlice(int(packet.Size))
53 packetReader := bitreader.Reader(bytes.NewReader(data), true)
54 for {
55 messageType, err := packetReader.ReadBits(6)
56 if err != nil {
57 break
58 }
59 packet.Data = append(packet.Data, messages.ParseMessages(int(messageType), packetReader))
60 }
61 packetData = packet
62 case 3: // SyncTick
63 syncTick := SyncTick{}
64 packetData = syncTick
65 case 4: // ConsoleCmd
66 size := reader.TryReadInt32()
67 consoleCmd := ConsoleCmd{
68 Size: int32(size),
69 Data: reader.TryReadStringLen(int(size)),
70 }
71 packetData = consoleCmd
72 case 5: // UserCmd
73 userCmd := UserCmd{}
74 userCmd.Cmd = int32(reader.TryReadInt32())
75 userCmd.Size = int32(reader.TryReadInt32())
76 data := reader.TryReadBytesToSlice(int(userCmd.Size))
77 userCmd.Data = classes.ParseUserCmdInfo(data)
78 packetData = userCmd
79 case 6: // DataTables
80 dataTables := DataTables{}
81 dataTables.Size = int32(reader.TryReadInt32())
82 data := reader.TryReadBytesToSlice(int(dataTables.Size))
83 dataTableReader := bitreader.Reader(bytes.NewReader(data), true)
84 count := 0
85 for dataTableReader.TryReadBool() {
86 count++
87 dataTables.SendTable = append(dataTables.SendTable, classes.ParseSendTable(dataTableReader))
88 }
89 numOfClasses := dataTableReader.TryReadBits(16)
90 for count = 0; count < int(numOfClasses); count++ {
91 dataTables.ServerClassInfo = append(dataTables.ServerClassInfo, classes.ParseServerClassInfo(dataTableReader, count, int(numOfClasses)))
92 }
93 packetData = dataTables
94 case 7: // Stop
95 stop := Stop{}
96 if reader.TryReadBool() {
97 // read remaining data
98 stop.RemainingData = []byte{}
99 }
100 packetData = stop
101 case 8: // CustomData
102 customData := CustomData{
103 Unknown: int32(reader.TryReadBits(32)),
104 Size: int32(reader.TryReadBits(32)),
105 }
106 customData.Data = string(reader.TryReadBytesToSlice(int(customData.Size)))
107 packetData = customData
108 case 9: // StringTables
109 stringTables := StringTables{
110 Size: int32(reader.TryReadInt32()),
111 }
112 data := reader.TryReadBytesToSlice(int(stringTables.Size))
113 stringTableReader := bitreader.Reader(bytes.NewReader(data), true)
114 stringTables.Data = classes.ParseStringTables(stringTableReader)
115 packetData = stringTables
116 default: // invalid
117 panic("invalid packet type")
118 }
119 return PacketMessageInfo{
120 PacketType: int8(packetType),
121 TickNumber: int32(tickNumber),
122 SlotNumber: int8(slotNumber),
123 Data: packetData,
124 }
125}
diff --git a/pkg/packets/types.go b/pkg/packets/types.go
new file mode 100644
index 0000000..6297b01
--- /dev/null
+++ b/pkg/packets/types.go
@@ -0,0 +1,53 @@
1package packets
2
3import "github.com/pektezol/demoparser/pkg/classes"
4
5type SignOn struct {
6 PacketInfo []classes.CmdInfo
7 InSequence int32
8 OutSequence int32
9 Size int32
10 Data []any
11}
12
13type Packet struct {
14 PacketInfo []classes.CmdInfo
15 InSequence int32
16 OutSequence int32
17 Size int32
18 Data []any
19}
20
21type SyncTick struct{}
22
23type ConsoleCmd struct {
24 Size int32
25 Data string
26}
27
28type UserCmd struct {
29 Cmd int32
30 Size int32
31 Data classes.UserCmdInfo
32}
33
34type DataTables struct {
35 Size int32
36 SendTable []classes.SendTable
37 ServerClassInfo []classes.ServerClassInfo
38}
39
40type Stop struct {
41 RemainingData []byte
42}
43
44type CustomData struct {
45 Unknown int32
46 Size int32
47 Data string
48}
49
50type StringTables struct {
51 Size int32
52 Data []classes.StringTable
53}