aboutsummaryrefslogtreecommitdiff
path: root/pkg/classes/sarData.go
diff options
context:
space:
mode:
authorArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2023-09-16 20:39:02 +0300
committerArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2023-09-16 21:39:43 +0300
commit81f365e99636104ff81151370048a51e8ae8027a (patch)
tree0bd2781ad73fdc982abdcb70f9f44c551ac76bcf /pkg/classes/sarData.go
parentupdate CI workflow for go 1.21.0 (diff)
downloadsdp.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.go378
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 @@
1package classes
2
3import (
4 "errors"
5 "fmt"
6
7 "github.com/pektezol/bitreader"
8)
9
10type SarDataType uint8
11
12const (
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
31func (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
70type SarData struct {
71 Type SarDataType
72 Slot int
73 Data any
74}
75
76type SarDataTimescaleCheat struct {
77 Timescale float32
78}
79
80type SarDataInitialCVar struct {
81 CVar string
82 Val string
83}
84
85type SarDataChecksum struct {
86 DemoSum uint32
87 SarSum uint32
88}
89
90type SarDataChecksumV2 struct {
91 SarSum uint32
92 Signature [64]byte
93}
94
95type SarDataEntityInput struct {
96 TargetName string
97 ClassName string
98 InputName string
99 Parameter string
100}
101
102type SarDataPortalPlacement struct {
103 Orange bool
104 X float32
105 Y float32
106 Z float32
107}
108
109type SarDataPause struct {
110 PauseTicks uint32
111}
112
113type SarDataWaitRun struct {
114 Ticks int
115 Cmd string
116}
117
118type SarDataHWaitRun struct {
119 Ticks int
120 Cmd string
121}
122
123type SarDataSpeedrunTime struct {
124 NSplits uint32
125 Splits []SarDataSpeedrunTimeSplits
126}
127
128type SarDataSpeedrunTimeSegs struct {
129 Name string
130 Ticks uint32
131}
132
133type SarDataSpeedrunTimeSplits struct {
134 Name string
135 NSegs uint32
136 Segs []SarDataSpeedrunTimeSegs
137}
138
139type SarDataTimestamp struct {
140 Year uint16
141 Mon uint8
142 Day uint8
143 Hour uint8
144 Min uint8
145 Sec uint8
146}
147
148type SarDataFileChecksum struct {
149 Sum uint32
150 Path string
151}
152
153func (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
238func 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
247func parseInitialCVarData(reader *bitreader.Reader) SarDataInitialCVar {
248 return SarDataInitialCVar{
249 CVar: reader.TryReadString(),
250 Val: reader.TryReadString(),
251 }
252}
253
254func 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
263func 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
273func 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
283func 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
298func 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
305func 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
314func 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
324func 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
334func 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
355func 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
370func 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}