From 44eefefe67a4a5f514faa4594370346fd1b54996 Mon Sep 17 00:00:00 2001 From: Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> Date: Thu, 21 Sep 2023 19:26:40 +0300 Subject: organize packets and classes (#9) --- README.md | 18 ++- pkg/classes/cmdInfo.go | 63 ----------- pkg/classes/consoleCmd.go | 19 ++++ pkg/classes/customData.go | 30 +++++ pkg/classes/dataTables.go | 245 +++++++++++++++++++++++++++++++++++++++++ pkg/classes/packet.go | 90 +++++++++++++++ pkg/classes/sendTable.go | 194 -------------------------------- pkg/classes/serverClassInfo.go | 33 ------ pkg/classes/signOn.go | 52 +++++++++ pkg/classes/stop.go | 17 +++ pkg/classes/stringTable.go | 93 ---------------- pkg/classes/stringTables.go | 100 +++++++++++++++++ pkg/classes/syncTick.go | 5 + pkg/classes/userCmd.go | 231 ++++++++++++++++++++++++++++++++++++++ pkg/classes/userCmdInfo.go | 87 --------------- pkg/messages/messages.go | 2 +- pkg/packets/packets.go | 125 ++++----------------- pkg/packets/types.go | 53 --------- 18 files changed, 824 insertions(+), 633 deletions(-) delete mode 100644 pkg/classes/cmdInfo.go create mode 100644 pkg/classes/consoleCmd.go create mode 100644 pkg/classes/customData.go create mode 100644 pkg/classes/dataTables.go create mode 100644 pkg/classes/packet.go delete mode 100644 pkg/classes/sendTable.go delete mode 100644 pkg/classes/serverClassInfo.go create mode 100644 pkg/classes/signOn.go create mode 100644 pkg/classes/stop.go delete mode 100644 pkg/classes/stringTable.go create mode 100644 pkg/classes/stringTables.go create mode 100644 pkg/classes/syncTick.go create mode 100644 pkg/classes/userCmd.go delete mode 100644 pkg/classes/userCmdInfo.go delete mode 100644 pkg/packets/types.go diff --git a/README.md b/README.md index e446603..b916ac1 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,28 @@ Work-In-Progress demo parser for Portal 2 written in Golang. -Usage: +## Couldn't Do This Without Them + +- [@UncraftedName](https://github.com/UncraftedName): For [UntitledParser](https://github.com/UncraftedName/UntitledParser) +- [@NeKzor](https://github.com/NeKzor): For [nekz.me/dem](https://nekz.me/dem) + +## Usage ```bash $ ./parser demo.dem ``` -Currently supports: +## Currently Supports - File or folder input using the CLI. - Basic parsing of demo headers each message type. - Basic parsing of packet classes. - Custom injected SAR data parsing. -TODO: +## TODO + +- StringTableEntry parsing. ([#8][i8]) +- In-depth packet class parsing for each class. ([#7][i7]) -- StringTableEntry parsing. -- In-depth packet class parsing for each class. +[i8]: https://github.com/pektezol/DemoParser/issues/8 +[i7]: https://github.com/pektezol/DemoParser/issues/7 \ No newline at end of file diff --git a/pkg/classes/cmdInfo.go b/pkg/classes/cmdInfo.go deleted file mode 100644 index eccfe99..0000000 --- a/pkg/classes/cmdInfo.go +++ /dev/null @@ -1,63 +0,0 @@ -package classes - -import ( - "fmt" - - "github.com/pektezol/bitreader" - "github.com/pektezol/demoparser/pkg/writer" -) - -type CmdInfo struct { - Flags string - ViewOrigin []float32 - ViewAngles []float32 - LocalViewAngles []float32 - ViewOrigin2 []float32 - ViewAngles2 []float32 - LocalViewAngles2 []float32 -} - -type CmdInfoFlags int - -const ( - ECmdInfoFlagsNone = 0 - ECmdInfoFlagsUseOrigin2 = 1 - ECmdInfoFlagsUserAngles2 = 1 << 1 - ECmdInfoFlagsNoInterp = 1 << 2 -) - -func (cmdInfoFlags CmdInfoFlags) String() string { - switch cmdInfoFlags { - case ECmdInfoFlagsNone: - return "None" - case ECmdInfoFlagsUseOrigin2: - return "UseOrigin2" - case ECmdInfoFlagsUserAngles2: - return "UserAngles2" - case ECmdInfoFlagsNoInterp: - return "NoInterp" - default: - return fmt.Sprintf("%d", int(cmdInfoFlags)) - } -} - -func ParseCmdInfo(reader *bitreader.Reader) CmdInfo { - cmdInfo := CmdInfo{ - Flags: CmdInfoFlags(reader.TryReadUInt32()).String(), - ViewOrigin: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()}, - ViewAngles: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()}, - LocalViewAngles: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()}, - ViewOrigin2: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()}, - ViewAngles2: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()}, - LocalViewAngles2: []float32{reader.TryReadFloat32(), reader.TryReadFloat32(), reader.TryReadFloat32()}, - } - writer.AppendLine("\tFlags: %s", cmdInfo.Flags) - writer.AppendLine("\tView Origin: %v", cmdInfo.ViewOrigin) - writer.AppendLine("\tView Angles: %v", cmdInfo.ViewAngles) - writer.AppendLine("\tLocal View Angles: %v", cmdInfo.LocalViewAngles) - writer.AppendLine("\tView Origin 2: %v", cmdInfo.ViewOrigin2) - writer.AppendLine("\tView Angles 2: %v", cmdInfo.ViewAngles2) - writer.AppendLine("\tLocal View Angles 2: %v", cmdInfo.LocalViewAngles2) - writer.AppendLine("") - return cmdInfo -} diff --git a/pkg/classes/consoleCmd.go b/pkg/classes/consoleCmd.go new file mode 100644 index 0000000..75a56eb --- /dev/null +++ b/pkg/classes/consoleCmd.go @@ -0,0 +1,19 @@ +package classes + +import ( + "strings" + + "github.com/pektezol/bitreader" + "github.com/pektezol/demoparser/pkg/writer" +) + +type ConsoleCmd struct { + Size int32 + Data string +} + +func (consoleCmd *ConsoleCmd) ParseConsoleCmd(reader *bitreader.Reader) { + consoleCmd.Size = reader.TryReadSInt32() + consoleCmd.Data = reader.TryReadStringLength(uint64(consoleCmd.Size)) + writer.AppendLine("\t%s", strings.TrimSpace(consoleCmd.Data)) +} diff --git a/pkg/classes/customData.go b/pkg/classes/customData.go new file mode 100644 index 0000000..2dadde4 --- /dev/null +++ b/pkg/classes/customData.go @@ -0,0 +1,30 @@ +package classes + +import ( + "github.com/pektezol/bitreader" + "github.com/pektezol/demoparser/pkg/writer" +) + +type CustomData struct { + Type int32 + Size int32 + Data string +} + +func (customData *CustomData) ParseCustomData(reader *bitreader.Reader, tickNumber int32, packetType uint8) { + customData.Type = reader.TryReadSInt32() + customData.Size = reader.TryReadSInt32() + if customData.Type != 0 || customData.Size == 8 { + // Not SAR data + writer.AppendLine("[%d] %s (%d):", tickNumber, "CUSTOMDATA", packetType) + customData.Data = string(reader.TryReadBytesToSlice(uint64(customData.Size))) + writer.AppendLine("\t%s", customData.Data) + return + } + // SAR data + writer.AppendLine("[%d] %s (%d):", tickNumber, "SARDATA", packetType) + sarData := SarData{} + data := reader.TryReadBytesToSlice(uint64(customData.Size)) + sarReader := bitreader.NewReaderFromBytes(data, true) + sarData.ParseSarData(sarReader) +} diff --git a/pkg/classes/dataTables.go b/pkg/classes/dataTables.go new file mode 100644 index 0000000..27ab9e4 --- /dev/null +++ b/pkg/classes/dataTables.go @@ -0,0 +1,245 @@ +package classes + +import ( + "fmt" + + "github.com/pektezol/bitreader" + "github.com/pektezol/demoparser/pkg/writer" +) + +type DataTables struct { + Size int32 + SendTable []SendTable + ServerClassInfo []ServerClassInfo +} + +type SendTable struct { + NeedsDecoder bool + NetTableName string + NumOfProps int16 + Props []prop +} + +type ServerClassInfo struct { + ClassId uint16 + ClassName string + DataTableName string +} + +type prop struct { + SendPropType sendPropType + SendPropName string + SendPropFlags uint32 + Priority uint8 + ExcludeDtName string + LowValue float32 + HighValue float32 + NumBits int32 + NumElements int32 +} + +func (dataTables *DataTables) ParseDataTables(reader *bitreader.Reader) { + dataTables.Size = int32(reader.TryReadSInt32()) + dataTableReader := bitreader.NewReaderFromBytes(reader.TryReadBytesToSlice(uint64(dataTables.Size)), true) + count := 0 + for dataTableReader.TryReadBool() { + count++ + dataTables.SendTable = append(dataTables.SendTable, ParseSendTable(dataTableReader)) + } + writer.AppendLine("\t%d Send Tables:", count) + writer.AppendOutputFromTemp() + numOfClasses := dataTableReader.TryReadBits(16) + for count = 0; count < int(numOfClasses); count++ { + dataTables.ServerClassInfo = append(dataTables.ServerClassInfo, ParseServerClassInfo(dataTableReader, count, int(numOfClasses))) + } + writer.AppendLine("\t%d Classes:", count) + writer.AppendOutputFromTemp() +} + +func ParseSendTable(reader *bitreader.Reader) SendTable { + sendTable := SendTable{ + NeedsDecoder: reader.TryReadBool(), + NetTableName: reader.TryReadString(), + NumOfProps: int16(reader.TryReadBits(10)), + } + if sendTable.NumOfProps < 0 { + return sendTable + } + writer.TempAppendLine("\t\t%s (%d Props):", sendTable.NetTableName, sendTable.NumOfProps) + for count := 0; count < int(sendTable.NumOfProps); count++ { + propType := int8(reader.TryReadBits(5)) + if propType >= int8(7) { + return sendTable + } + prop := prop{ + SendPropType: sendPropType(propType), + SendPropName: reader.TryReadString(), + SendPropFlags: uint32(reader.TryReadBits(19)), + Priority: reader.TryReadUInt8(), + } + writer.TempAppend("\t\t\t%s\t", prop.SendPropType) + if propType == int8(ESendPropTypeDataTable) || checkBit(prop.SendPropFlags, 6) { + prop.ExcludeDtName = reader.TryReadString() + writer.TempAppend(":\t%s\t", prop.ExcludeDtName) + } else { + switch propType { + case int8(ESendPropTypeString), int8(ESendPropTypeInt), int8(ESendPropTypeFloat), int8(ESendPropTypeVector3), int8(ESendPropTypeVector2): + prop.LowValue = reader.TryReadFloat32() + prop.HighValue = reader.TryReadFloat32() + prop.NumBits = int32(reader.TryReadBits(7)) + writer.TempAppend("Low: %f\tHigh: %f\t%d bits\t", prop.LowValue, prop.HighValue, prop.NumBits) + case int8(ESendPropTypeArray): + prop.NumElements = int32(reader.TryReadBits(10)) + writer.TempAppend("Elements: %d\t", prop.NumElements) + default: + writer.TempAppend("Unknown Prop Type: %v\t", propType) + return sendTable + } + } + writer.TempAppend("Flags: %v\tPriority: %d\n", prop.GetFlags(), prop.Priority) + sendTable.Props = append(sendTable.Props, prop) + } + return sendTable +} + +func ParseServerClassInfo(reader *bitreader.Reader, count int, numOfClasses int) ServerClassInfo { + serverClassInfo := ServerClassInfo{ + ClassId: reader.TryReadUInt16(), + ClassName: reader.TryReadString(), + DataTableName: reader.TryReadString(), + } + writer.TempAppendLine("\t\t\t[%d] %s (%s)", serverClassInfo.ClassId, serverClassInfo.ClassName, serverClassInfo.DataTableName) + return serverClassInfo +} + +// func serverClassBits(numOfClasses int) int { +// return highestBitIndex(uint(numOfClasses)) + 1 +// } + +// func highestBitIndex(i uint) int { +// var j int +// for j = 31; j >= 0 && (i&(1<= int8(7) { - return sendTable - } - prop := prop{ - SendPropType: sendPropType(propType), - SendPropName: reader.TryReadString(), - SendPropFlags: uint32(reader.TryReadBits(19)), - Priority: reader.TryReadUInt8(), - } - writer.TempAppend("\t\t\t%s\t", prop.SendPropType) - if propType == int8(ESendPropTypeDataTable) || checkBit(prop.SendPropFlags, 6) { - prop.ExcludeDtName = reader.TryReadString() - writer.TempAppend(":\t%s\t", prop.ExcludeDtName) - } else { - switch propType { - case int8(ESendPropTypeString), int8(ESendPropTypeInt), int8(ESendPropTypeFloat), int8(ESendPropTypeVector3), int8(ESendPropTypeVector2): - prop.LowValue = reader.TryReadFloat32() - prop.HighValue = reader.TryReadFloat32() - prop.NumBits = int32(reader.TryReadBits(7)) - writer.TempAppend("Low: %f\tHigh: %f\t%d bits\t", prop.LowValue, prop.HighValue, prop.NumBits) - case int8(ESendPropTypeArray): - prop.NumElements = int32(reader.TryReadBits(10)) - writer.TempAppend("Elements: %d\t", prop.NumElements) - default: - writer.TempAppend("Unknown Prop Type: %v\t", propType) - return sendTable - } - } - writer.TempAppend("Flags: %v\tPriority: %d\n", prop.GetFlags(), prop.Priority) - sendTable.Props = append(sendTable.Props, prop) - } - return sendTable -} - -func checkBit(val uint32, bit int) bool { - return (val & (uint32(1) << bit)) != 0 -} diff --git a/pkg/classes/serverClassInfo.go b/pkg/classes/serverClassInfo.go deleted file mode 100644 index c0d2a2a..0000000 --- a/pkg/classes/serverClassInfo.go +++ /dev/null @@ -1,33 +0,0 @@ -package classes - -import ( - "github.com/pektezol/bitreader" - "github.com/pektezol/demoparser/pkg/writer" -) - -type ServerClassInfo struct { - ClassId uint16 - ClassName string - DataTableName string -} - -func ParseServerClassInfo(reader *bitreader.Reader, count int, numOfClasses int) ServerClassInfo { - serverClassInfo := ServerClassInfo{ - ClassId: reader.TryReadUInt16(), - ClassName: reader.TryReadString(), - DataTableName: reader.TryReadString(), - } - writer.TempAppendLine("\t\t\t[%d] %s (%s)", serverClassInfo.ClassId, serverClassInfo.ClassName, serverClassInfo.DataTableName) - return serverClassInfo -} - -// func serverClassBits(numOfClasses int) int { -// return highestBitIndex(uint(numOfClasses)) + 1 -// } - -// func highestBitIndex(i uint) int { -// var j int -// for j = 31; j >= 0 && (i&(1<