diff options
| author | Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> | 2023-09-16 20:39:02 +0300 |
|---|---|---|
| committer | Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> | 2023-09-16 21:39:43 +0300 |
| commit | 81f365e99636104ff81151370048a51e8ae8027a (patch) | |
| tree | 0bd2781ad73fdc982abdcb70f9f44c551ac76bcf /pkg/classes/sarData.go | |
| parent | update CI workflow for go 1.21.0 (diff) | |
| download | sdp.go-81f365e99636104ff81151370048a51e8ae8027a.tar.gz sdp.go-81f365e99636104ff81151370048a51e8ae8027a.tar.bz2 sdp.go-81f365e99636104ff81151370048a51e8ae8027a.zip | |
feat: parsing sar custom data (#4)
Diffstat (limited to 'pkg/classes/sarData.go')
| -rw-r--r-- | pkg/classes/sarData.go | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/pkg/classes/sarData.go b/pkg/classes/sarData.go new file mode 100644 index 0000000..133b67a --- /dev/null +++ b/pkg/classes/sarData.go | |||
| @@ -0,0 +1,378 @@ | |||
| 1 | package classes | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "errors" | ||
| 5 | "fmt" | ||
| 6 | |||
| 7 | "github.com/pektezol/bitreader" | ||
| 8 | ) | ||
| 9 | |||
| 10 | type SarDataType uint8 | ||
| 11 | |||
| 12 | const ( | ||
| 13 | ESarDataTimescaleCheat SarDataType = 0x01 | ||
| 14 | ESarDataInitialCVar SarDataType = 0x02 | ||
| 15 | ESarDataEntityInput SarDataType = 0x03 | ||
| 16 | ESarDataEntityInputSlot SarDataType = 0x04 | ||
| 17 | ESarDataPortalPlacement SarDataType = 0x05 | ||
| 18 | ESarDataChallengeFlags SarDataType = 0x06 | ||
| 19 | ESarDataCrouchFly SarDataType = 0x07 | ||
| 20 | ESarDataPause SarDataType = 0x08 | ||
| 21 | ESarDataWaitRun SarDataType = 0x09 | ||
| 22 | ESarDataSpeedrunTime SarDataType = 0x0A | ||
| 23 | ESarDataTimestamp SarDataType = 0x0B | ||
| 24 | ESarDataFileChecksum SarDataType = 0x0C | ||
| 25 | ESarDataHWaitRun SarDataType = 0x0D | ||
| 26 | ESarDataChecksum SarDataType = 0xFF | ||
| 27 | ESarDataChecksumV2 SarDataType = 0xFE | ||
| 28 | ESarDataInvalid SarDataType = iota | ||
| 29 | ) | ||
| 30 | |||
| 31 | func (t SarDataType) String() string { | ||
| 32 | switch t { | ||
| 33 | case ESarDataTimescaleCheat: | ||
| 34 | return "SarDataTimescaleCheat" | ||
| 35 | case ESarDataInitialCVar: | ||
| 36 | return "SarDataInitialCVar" | ||
| 37 | case ESarDataEntityInput: | ||
| 38 | return "SarDataEntityInput" | ||
| 39 | case ESarDataEntityInputSlot: | ||
| 40 | return "SarDataEntityInputSlot" | ||
| 41 | case ESarDataPortalPlacement: | ||
| 42 | return "SarDataPortalPlacement" | ||
| 43 | case ESarDataChallengeFlags: | ||
| 44 | return "SarDataChallengeFlags" | ||
| 45 | case ESarDataCrouchFly: | ||
| 46 | return "SarDataCrouchFly" | ||
| 47 | case ESarDataPause: | ||
| 48 | return "SarDataPause" | ||
| 49 | case ESarDataWaitRun: | ||
| 50 | return "SarDataWaitRun" | ||
| 51 | case ESarDataSpeedrunTime: | ||
| 52 | return "SarDataSpeedrunTime" | ||
| 53 | case ESarDataTimestamp: | ||
| 54 | return "SarDataTimestamp" | ||
| 55 | case ESarDataFileChecksum: | ||
| 56 | return "SarDataFileChecksum" | ||
| 57 | case ESarDataHWaitRun: | ||
| 58 | return "SarDataHWaitRun" | ||
| 59 | case ESarDataChecksum: | ||
| 60 | return "SarDataChecksum" | ||
| 61 | case ESarDataChecksumV2: | ||
| 62 | return "SarDataChecksumV2" | ||
| 63 | case ESarDataInvalid: | ||
| 64 | return "SarDataInvalid" | ||
| 65 | default: | ||
| 66 | return fmt.Sprintf("%d", int(t)) | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | type SarData struct { | ||
| 71 | Type SarDataType | ||
| 72 | Slot int | ||
| 73 | Data any | ||
| 74 | } | ||
| 75 | |||
| 76 | type SarDataTimescaleCheat struct { | ||
| 77 | Timescale float32 | ||
| 78 | } | ||
| 79 | |||
| 80 | type SarDataInitialCVar struct { | ||
| 81 | CVar string | ||
| 82 | Val string | ||
| 83 | } | ||
| 84 | |||
| 85 | type SarDataChecksum struct { | ||
| 86 | DemoSum uint32 | ||
| 87 | SarSum uint32 | ||
| 88 | } | ||
| 89 | |||
| 90 | type SarDataChecksumV2 struct { | ||
| 91 | SarSum uint32 | ||
| 92 | Signature [64]byte | ||
| 93 | } | ||
| 94 | |||
| 95 | type SarDataEntityInput struct { | ||
| 96 | TargetName string | ||
| 97 | ClassName string | ||
| 98 | InputName string | ||
| 99 | Parameter string | ||
| 100 | } | ||
| 101 | |||
| 102 | type SarDataPortalPlacement struct { | ||
| 103 | Orange bool | ||
| 104 | X float32 | ||
| 105 | Y float32 | ||
| 106 | Z float32 | ||
| 107 | } | ||
| 108 | |||
| 109 | type SarDataPause struct { | ||
| 110 | PauseTicks uint32 | ||
| 111 | } | ||
| 112 | |||
| 113 | type SarDataWaitRun struct { | ||
| 114 | Ticks int | ||
| 115 | Cmd string | ||
| 116 | } | ||
| 117 | |||
| 118 | type SarDataHWaitRun struct { | ||
| 119 | Ticks int | ||
| 120 | Cmd string | ||
| 121 | } | ||
| 122 | |||
| 123 | type SarDataSpeedrunTime struct { | ||
| 124 | NSplits uint32 | ||
| 125 | Splits []SarDataSpeedrunTimeSplits | ||
| 126 | } | ||
| 127 | |||
| 128 | type SarDataSpeedrunTimeSegs struct { | ||
| 129 | Name string | ||
| 130 | Ticks uint32 | ||
| 131 | } | ||
| 132 | |||
| 133 | type SarDataSpeedrunTimeSplits struct { | ||
| 134 | Name string | ||
| 135 | NSegs uint32 | ||
| 136 | Segs []SarDataSpeedrunTimeSegs | ||
| 137 | } | ||
| 138 | |||
| 139 | type SarDataTimestamp struct { | ||
| 140 | Year uint16 | ||
| 141 | Mon uint8 | ||
| 142 | Day uint8 | ||
| 143 | Hour uint8 | ||
| 144 | Min uint8 | ||
| 145 | Sec uint8 | ||
| 146 | } | ||
| 147 | |||
| 148 | type SarDataFileChecksum struct { | ||
| 149 | Sum uint32 | ||
| 150 | Path string | ||
| 151 | } | ||
| 152 | |||
| 153 | func (sarData *SarData) ParseSarData(reader *bitreader.Reader) (err error) { | ||
| 154 | reader.SkipBytes(8) | ||
| 155 | len := reader.TryReadRemainingBits() / 8 | ||
| 156 | if len == 0 { | ||
| 157 | sarData.Type = ESarDataInvalid | ||
| 158 | err = errors.New("sar data invalid") | ||
| 159 | return err | ||
| 160 | } | ||
| 161 | sarData.Type = SarDataType(reader.TryReadBytes(1)) | ||
| 162 | if sarData.Type == ESarDataChecksum && len == 5 { | ||
| 163 | len = 9 | ||
| 164 | } | ||
| 165 | dataReader := bitreader.NewReaderFromBytes(reader.TryReadBytesToSlice(len-1), true) | ||
| 166 | switch sarData.Type { | ||
| 167 | case ESarDataTimescaleCheat: | ||
| 168 | sarData.Data, err = parseTimescaleCheatData(dataReader, len) | ||
| 169 | if err != nil { | ||
| 170 | sarData.Data = nil | ||
| 171 | } | ||
| 172 | case ESarDataInitialCVar: | ||
| 173 | sarData.Data = parseInitialCVarData(dataReader) | ||
| 174 | case ESarDataEntityInputSlot: | ||
| 175 | sarData.Slot = int(dataReader.TryReadBytes(1)) | ||
| 176 | case ESarDataEntityInput: | ||
| 177 | sarData.Data = parseEntityInputData(dataReader) | ||
| 178 | case ESarDataChecksum: | ||
| 179 | sarData.Data, err = parseChecksumData(dataReader, len) | ||
| 180 | if err != nil { | ||
| 181 | sarData.Data = nil | ||
| 182 | } | ||
| 183 | case ESarDataChecksumV2: | ||
| 184 | sarData.Data, err = parseChecksumV2Data(dataReader, len) | ||
| 185 | if err != nil { | ||
| 186 | sarData.Data = nil | ||
| 187 | } | ||
| 188 | case ESarDataPortalPlacement: | ||
| 189 | data, slot, err := parsePortalPlacementData(dataReader, len) | ||
| 190 | if err != nil { | ||
| 191 | sarData.Data = nil | ||
| 192 | } else { | ||
| 193 | sarData.Data = data | ||
| 194 | sarData.Slot = slot | ||
| 195 | } | ||
| 196 | case ESarDataChallengeFlags, ESarDataCrouchFly: | ||
| 197 | sarData.Slot, err = parseChallengeFlagsCrouchFlyData(dataReader, len) | ||
| 198 | if err != nil { | ||
| 199 | sarData.Data = nil | ||
| 200 | } | ||
| 201 | case ESarDataPause: | ||
| 202 | sarData.Data, err = parsePauseData(dataReader, len) | ||
| 203 | if err != nil { | ||
| 204 | sarData.Data = nil | ||
| 205 | } | ||
| 206 | case ESarDataWaitRun: | ||
| 207 | sarData.Data, err = parseWaitRunData(dataReader, len) | ||
| 208 | if err != nil { | ||
| 209 | sarData.Data = nil | ||
| 210 | } | ||
| 211 | case ESarDataHWaitRun: | ||
| 212 | sarData.Data, err = parseHWaitRunData(dataReader, len) | ||
| 213 | if err != nil { | ||
| 214 | sarData.Data = nil | ||
| 215 | } | ||
| 216 | case ESarDataSpeedrunTime: | ||
| 217 | sarData.Data, err = parseSpeedrunTimeData(dataReader, len) | ||
| 218 | if err != nil { | ||
| 219 | sarData.Data = nil | ||
| 220 | } | ||
| 221 | case ESarDataTimestamp: | ||
| 222 | sarData.Data, err = parseTimestampData(dataReader, len) | ||
| 223 | if err != nil { | ||
| 224 | sarData.Data = nil | ||
| 225 | } | ||
| 226 | case ESarDataFileChecksum: | ||
| 227 | sarData.Data, err = parseFileChecksumData(dataReader, len) | ||
| 228 | if err != nil { | ||
| 229 | sarData.Data = nil | ||
| 230 | } | ||
| 231 | default: | ||
| 232 | err = errors.New("unsupported SAR data type") | ||
| 233 | return err | ||
| 234 | } | ||
| 235 | return nil | ||
| 236 | } | ||
| 237 | |||
| 238 | func parseTimescaleCheatData(reader *bitreader.Reader, length uint64) (SarDataTimescaleCheat, error) { | ||
| 239 | if length != 5 { | ||
| 240 | return SarDataTimescaleCheat{}, errors.New("sar data invalid") | ||
| 241 | } | ||
| 242 | return SarDataTimescaleCheat{ | ||
| 243 | Timescale: reader.TryReadFloat32(), | ||
| 244 | }, nil | ||
| 245 | } | ||
| 246 | |||
| 247 | func parseInitialCVarData(reader *bitreader.Reader) SarDataInitialCVar { | ||
| 248 | return SarDataInitialCVar{ | ||
| 249 | CVar: reader.TryReadString(), | ||
| 250 | Val: reader.TryReadString(), | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | func parseEntityInputData(reader *bitreader.Reader) SarDataEntityInput { | ||
| 255 | return SarDataEntityInput{ | ||
| 256 | TargetName: reader.TryReadString(), | ||
| 257 | ClassName: reader.TryReadString(), | ||
| 258 | InputName: reader.TryReadString(), | ||
| 259 | Parameter: reader.TryReadString(), | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | func parseChecksumData(reader *bitreader.Reader, length uint64) (SarDataChecksum, error) { | ||
| 264 | if length != 9 { | ||
| 265 | return SarDataChecksum{}, errors.New("sar data invalid") | ||
| 266 | } | ||
| 267 | return SarDataChecksum{ | ||
| 268 | DemoSum: reader.TryReadUInt32(), | ||
| 269 | SarSum: reader.TryReadUInt32(), | ||
| 270 | }, nil | ||
| 271 | } | ||
| 272 | |||
| 273 | func parseChecksumV2Data(reader *bitreader.Reader, length uint64) (SarDataChecksumV2, error) { | ||
| 274 | if length != 69 { | ||
| 275 | return SarDataChecksumV2{}, errors.New("sar data invalid") | ||
| 276 | } | ||
| 277 | return SarDataChecksumV2{ | ||
| 278 | SarSum: reader.TryReadUInt32(), | ||
| 279 | Signature: [64]byte(reader.TryReadBytesToSlice(60)), | ||
| 280 | }, nil | ||
| 281 | } | ||
| 282 | |||
| 283 | func parsePortalPlacementData(reader *bitreader.Reader, length uint64) (SarDataPortalPlacement, int, error) { | ||
| 284 | if length != 15 { | ||
| 285 | return SarDataPortalPlacement{}, 0, errors.New("sar data invalid") | ||
| 286 | } | ||
| 287 | slot := int(reader.TryReadBytes(1)) | ||
| 288 | orange := reader.TryReadBool() | ||
| 289 | reader.SkipBits(7) | ||
| 290 | return SarDataPortalPlacement{ | ||
| 291 | Orange: orange, | ||
| 292 | X: reader.TryReadFloat32(), | ||
| 293 | Y: reader.TryReadFloat32(), | ||
| 294 | Z: reader.TryReadFloat32(), | ||
| 295 | }, slot, nil | ||
| 296 | } | ||
| 297 | |||
| 298 | func parseChallengeFlagsCrouchFlyData(reader *bitreader.Reader, length uint64) (int, error) { | ||
| 299 | if length != 2 { | ||
| 300 | return 0, errors.New("sar data invalid") | ||
| 301 | } | ||
| 302 | return int(reader.TryReadBytes(1)), nil | ||
| 303 | } | ||
| 304 | |||
| 305 | func parsePauseData(reader *bitreader.Reader, length uint64) (SarDataPause, error) { | ||
| 306 | if length != 5 { | ||
| 307 | return SarDataPause{}, errors.New("sar data invalid") | ||
| 308 | } | ||
| 309 | return SarDataPause{ | ||
| 310 | PauseTicks: reader.TryReadUInt32(), | ||
| 311 | }, nil | ||
| 312 | } | ||
| 313 | |||
| 314 | func parseWaitRunData(reader *bitreader.Reader, length uint64) (SarDataWaitRun, error) { | ||
| 315 | if length < 6 { | ||
| 316 | return SarDataWaitRun{}, errors.New("sar data invalid") | ||
| 317 | } | ||
| 318 | return SarDataWaitRun{ | ||
| 319 | Ticks: int(reader.TryReadUInt32()), | ||
| 320 | Cmd: reader.TryReadString(), | ||
| 321 | }, nil | ||
| 322 | } | ||
| 323 | |||
| 324 | func parseHWaitRunData(reader *bitreader.Reader, length uint64) (SarDataHWaitRun, error) { | ||
| 325 | if length < 6 { | ||
| 326 | return SarDataHWaitRun{}, errors.New("sar data invalid") | ||
| 327 | } | ||
| 328 | return SarDataHWaitRun{ | ||
| 329 | Ticks: int(reader.TryReadUInt32()), | ||
| 330 | Cmd: reader.TryReadString(), | ||
| 331 | }, nil | ||
| 332 | } | ||
| 333 | |||
| 334 | func parseSpeedrunTimeData(reader *bitreader.Reader, length uint64) (SarDataSpeedrunTime, error) { | ||
| 335 | if length < 5 { | ||
| 336 | return SarDataSpeedrunTime{}, errors.New("sar data invalid") | ||
| 337 | } | ||
| 338 | numberOfSplits := reader.TryReadUInt32() | ||
| 339 | splits := make([]SarDataSpeedrunTimeSplits, numberOfSplits) | ||
| 340 | for splitCount := 0; splitCount < int(numberOfSplits); splitCount++ { | ||
| 341 | splits[splitCount].Name = reader.TryReadString() | ||
| 342 | splits[splitCount].NSegs = reader.TryReadUInt32() | ||
| 343 | splits[splitCount].Segs = make([]SarDataSpeedrunTimeSegs, splits[splitCount].NSegs) | ||
| 344 | for segCount := 0; segCount < int(splits[splitCount].NSegs); segCount++ { | ||
| 345 | splits[splitCount].Segs[segCount].Name = reader.TryReadString() | ||
| 346 | splits[splitCount].Segs[segCount].Ticks = reader.TryReadUInt32() | ||
| 347 | } | ||
| 348 | } | ||
| 349 | return SarDataSpeedrunTime{ | ||
| 350 | NSplits: numberOfSplits, | ||
| 351 | Splits: splits, | ||
| 352 | }, nil | ||
| 353 | } | ||
| 354 | |||
| 355 | func parseTimestampData(reader *bitreader.Reader, length uint64) (SarDataTimestamp, error) { | ||
| 356 | if length != 8 { | ||
| 357 | return SarDataTimestamp{}, errors.New("sar data invalid") | ||
| 358 | } | ||
| 359 | timestamp := reader.TryReadBytesToSlice(7) | ||
| 360 | return SarDataTimestamp{ | ||
| 361 | Year: uint16(timestamp[0]) | uint16(timestamp[1])<<8, | ||
| 362 | Mon: timestamp[2] + 1, | ||
| 363 | Day: timestamp[3], | ||
| 364 | Hour: timestamp[4], | ||
| 365 | Min: timestamp[5], | ||
| 366 | Sec: timestamp[6], | ||
| 367 | }, nil | ||
| 368 | } | ||
| 369 | |||
| 370 | func parseFileChecksumData(reader *bitreader.Reader, length uint64) (SarDataFileChecksum, error) { | ||
| 371 | if length < 6 { | ||
| 372 | return SarDataFileChecksum{}, errors.New("sar data invalid") | ||
| 373 | } | ||
| 374 | return SarDataFileChecksum{ | ||
| 375 | Sum: reader.TryReadUInt32(), | ||
| 376 | Path: reader.TryReadString(), | ||
| 377 | }, nil | ||
| 378 | } | ||