diff options
Diffstat (limited to 'backend/parser')
| -rw-r--r-- | backend/parser/parser.go | 196 |
1 files changed, 180 insertions, 16 deletions
diff --git a/backend/parser/parser.go b/backend/parser/parser.go index 1a80d4a..4605600 100644 --- a/backend/parser/parser.go +++ b/backend/parser/parser.go | |||
| @@ -4,30 +4,52 @@ import ( | |||
| 4 | "errors" | 4 | "errors" |
| 5 | "math" | 5 | "math" |
| 6 | "os" | 6 | "os" |
| 7 | "regexp" | ||
| 8 | "strconv" | ||
| 9 | "strings" | ||
| 7 | 10 | ||
| 8 | "github.com/pektezol/bitreader" | 11 | "github.com/pektezol/bitreader" |
| 9 | ) | 12 | ) |
| 10 | 13 | ||
| 14 | type Result struct { | ||
| 15 | MapID int | ||
| 16 | ServerNumber int | ||
| 17 | PortalCount int | ||
| 18 | TickCount int | ||
| 19 | HostSteamID string | ||
| 20 | PartnerSteamID string | ||
| 21 | IsHost bool | ||
| 22 | } | ||
| 23 | |||
| 11 | // Don't try to understand it, feel it. | 24 | // Don't try to understand it, feel it. |
| 12 | func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID string, partnerSteamID string, err error) { | 25 | func ProcessDemo(filePath string) (Result, error) { |
| 26 | var result Result | ||
| 13 | file, err := os.Open(filePath) | 27 | file, err := os.Open(filePath) |
| 14 | if err != nil { | 28 | if err != nil { |
| 15 | return 0, 0, "", "", err | 29 | return Result{}, err |
| 16 | } | 30 | } |
| 17 | reader := bitreader.NewReader(file, true) | 31 | reader := bitreader.NewReader(file, true) |
| 18 | demoFileStamp := reader.TryReadString() | 32 | demoFileStamp := reader.TryReadString() |
| 19 | demoProtocol := reader.TryReadSInt32() | 33 | demoProtocol := reader.TryReadSInt32() |
| 20 | networkProtocol := reader.TryReadSInt32() | 34 | networkProtocol := reader.TryReadSInt32() |
| 21 | reader.SkipBytes(1056) | 35 | serverName := reader.TryReadStringLength(260) |
| 36 | // clientName := reader.TryReadStringLength(260) | ||
| 37 | reader.SkipBytes(260) | ||
| 38 | mapName := reader.TryReadStringLength(260) | ||
| 39 | reader.SkipBytes(276) | ||
| 22 | if demoFileStamp != "HL2DEMO" { | 40 | if demoFileStamp != "HL2DEMO" { |
| 23 | return 0, 0, "", "", errors.New("invalid demo file stamp") | 41 | return Result{}, errors.New("invalid demo file stamp") |
| 24 | } | 42 | } |
| 25 | if demoProtocol != 4 { | 43 | if demoProtocol != 4 { |
| 26 | return 0, 0, "", "", errors.New("this parser only supports demos from new engine") | 44 | return Result{}, errors.New("this parser only supports demos from new engine") |
| 27 | } | 45 | } |
| 28 | if networkProtocol != 2001 { | 46 | if networkProtocol != 2001 { |
| 29 | return 0, 0, "", "", errors.New("this parser only supports demos from portal 2") | 47 | return Result{}, errors.New("this parser only supports demos from portal 2") |
| 48 | } | ||
| 49 | if mapDict[mapName] == 0 { | ||
| 50 | return Result{}, errors.New("demo recorded on an invalid map") | ||
| 30 | } | 51 | } |
| 52 | result.MapID = mapDict[mapName] | ||
| 31 | for { | 53 | for { |
| 32 | packetType := reader.TryReadUInt8() | 54 | packetType := reader.TryReadUInt8() |
| 33 | reader.SkipBits(40) | 55 | reader.SkipBits(40) |
| @@ -119,7 +141,17 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 119 | packetReader.SkipBytes(2) | 141 | packetReader.SkipBytes(2) |
| 120 | packetReader.SkipBits(uint64(packetReader.TryReadUInt16())) | 142 | packetReader.SkipBits(uint64(packetReader.TryReadUInt16())) |
| 121 | case 16: | 143 | case 16: |
| 122 | packetReader.TryReadString() | 144 | print := packetReader.TryReadString() |
| 145 | re := regexp.MustCompile(`Server Number: (\d+)`) | ||
| 146 | match := re.FindStringSubmatch(print) | ||
| 147 | if len(match) >= 1 { | ||
| 148 | serverNumber := match[1] | ||
| 149 | n, err := strconv.Atoi(serverNumber) | ||
| 150 | if err != nil { | ||
| 151 | return Result{}, err | ||
| 152 | } | ||
| 153 | result.ServerNumber = n | ||
| 154 | } | ||
| 123 | case 17: | 155 | case 17: |
| 124 | var length uint16 | 156 | var length uint16 |
| 125 | if packetReader.TryReadBool() { | 157 | if packetReader.TryReadBool() { |
| @@ -180,8 +212,8 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 180 | NumPortals: userMessageReader.TryReadSInt32(), | 212 | NumPortals: userMessageReader.TryReadSInt32(), |
| 181 | TimeTaken: userMessageReader.TryReadSInt32(), | 213 | TimeTaken: userMessageReader.TryReadSInt32(), |
| 182 | } | 214 | } |
| 183 | portalCount = int(scoreboardTempUpdate.NumPortals) | 215 | result.PortalCount = int(scoreboardTempUpdate.NumPortals) |
| 184 | tickCount = int(math.Round(float64((float32(scoreboardTempUpdate.TimeTaken) / 100.0) / float32(1.0/60.0)))) | 216 | result.TickCount = int(math.Round(float64((float32(scoreboardTempUpdate.TimeTaken) / 100.0) / float32(1.0/60.0)))) |
| 185 | } | 217 | } |
| 186 | case 24: | 218 | case 24: |
| 187 | packetReader.SkipBits(20) | 219 | packetReader.SkipBits(20) |
| @@ -216,8 +248,8 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 216 | packetReader.SkipBytes(packetReader.TryReadBits(32)) | 248 | packetReader.SkipBytes(packetReader.TryReadBits(32)) |
| 217 | case 33: | 249 | case 33: |
| 218 | packetReader.SkipBits(packetReader.TryReadBits(32)) | 250 | packetReader.SkipBits(packetReader.TryReadBits(32)) |
| 219 | default: | 251 | // default: |
| 220 | return 0, 0, "", "", errors.New("unknown msg type") | 252 | // return Result{}, errors.New(fmt.Sprintf("unknown msg type %d", messageType)) |
| 221 | } | 253 | } |
| 222 | } | 254 | } |
| 223 | case 3, 7: | 255 | case 3, 7: |
| @@ -252,7 +284,7 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 252 | if stringTableReader.TryReadBool() { | 284 | if stringTableReader.TryReadBool() { |
| 253 | byteLen, err := stringTableReader.ReadBits(16) | 285 | byteLen, err := stringTableReader.ReadBits(16) |
| 254 | if err != nil { | 286 | if err != nil { |
| 255 | return 0, 0, "", "", errors.New("error on reading entry length") | 287 | return Result{}, errors.New("error on reading entry length") |
| 256 | } | 288 | } |
| 257 | stringTableEntryReader := bitreader.NewReaderFromBytes(stringTableReader.TryReadBytesToSlice(byteLen), true) | 289 | stringTableEntryReader := bitreader.NewReaderFromBytes(stringTableReader.TryReadBytesToSlice(byteLen), true) |
| 258 | if tableName == "userinfo" { | 290 | if tableName == "userinfo" { |
| @@ -285,10 +317,14 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 285 | userInfo.FilesDownloaded = stringTableEntryReader.TryReadUInt8() | 317 | userInfo.FilesDownloaded = stringTableEntryReader.TryReadUInt8() |
| 286 | stringTableEntryReader.SkipBytes(3) | 318 | stringTableEntryReader.SkipBytes(3) |
| 287 | if guidCount == 0 { | 319 | if guidCount == 0 { |
| 288 | hostSteamID = userInfo.GUID | 320 | result.HostSteamID = userInfo.GUID |
| 321 | if strings.Contains(serverName, "localhost") { | ||
| 322 | result.IsHost = true | ||
| 323 | } | ||
| 289 | } else if guidCount == 1 { | 324 | } else if guidCount == 1 { |
| 290 | partnerSteamID = userInfo.GUID | 325 | result.PartnerSteamID = userInfo.GUID |
| 291 | } | 326 | } |
| 327 | guidCount++ | ||
| 292 | } | 328 | } |
| 293 | } | 329 | } |
| 294 | } | 330 | } |
| @@ -303,11 +339,139 @@ func ProcessDemo(filePath string) (portalCount int, tickCount int, hostSteamID s | |||
| 303 | } | 339 | } |
| 304 | } | 340 | } |
| 305 | default: | 341 | default: |
| 306 | return 0, 0, "", "", errors.New("invalid packet type") | 342 | return Result{}, errors.New("invalid packet type") |
| 307 | } | 343 | } |
| 308 | if packetType == 7 { | 344 | if packetType == 7 { |
| 309 | break | 345 | break |
| 310 | } | 346 | } |
| 311 | } | 347 | } |
| 312 | return portalCount, tickCount, hostSteamID, partnerSteamID, nil | 348 | return result, nil |
| 349 | } | ||
| 350 | |||
| 351 | var mapDict = map[string]int{ | ||
| 352 | "sp_a1_intro1": 1, | ||
| 353 | "sp_a1_intro2": 2, | ||
| 354 | "sp_a1_intro3": 3, | ||
| 355 | "sp_a1_intro4": 4, | ||
| 356 | "sp_a1_intro5": 5, | ||
| 357 | "sp_a1_intro6": 6, | ||
| 358 | "sp_a1_intro7": 7, | ||
| 359 | "sp_a1_wakeup": 8, | ||
| 360 | "sp_a2_intro": 9, | ||
| 361 | |||
| 362 | "sp_a2_laser_intro": 10, | ||
| 363 | "sp_a2_laser_stairs": 11, | ||
| 364 | "sp_a2_dual_lasers": 12, | ||
| 365 | "sp_a2_laser_over_goo": 13, | ||
| 366 | "sp_a2_catapult_intro": 14, | ||
| 367 | "sp_a2_trust_fling": 15, | ||
| 368 | "sp_a2_pit_flings": 16, | ||
| 369 | "sp_a2_fizzler_intro": 17, | ||
| 370 | |||
| 371 | "sp_a2_sphere_peek": 18, | ||
| 372 | "sp_a2_ricochet": 19, | ||
| 373 | "sp_a2_bridge_intro": 20, | ||
| 374 | "sp_a2_bridge_the_gap": 21, | ||
| 375 | "sp_a2_turret_intro": 22, | ||
| 376 | "sp_a2_laser_relays": 23, | ||
| 377 | "sp_a2_turret_blocker": 24, | ||
| 378 | "sp_a2_laser_vs_turret": 25, | ||
| 379 | "sp_a2_pull_the_rug": 26, | ||
| 380 | |||
| 381 | "sp_a2_column_blocker": 27, | ||
| 382 | "sp_a2_laser_chaining": 28, | ||
| 383 | "sp_a2_triple_laser": 29, | ||
| 384 | "sp_a2_bts1": 30, | ||
| 385 | "sp_a2_bts2": 31, | ||
| 386 | |||
| 387 | "sp_a2_bts3": 32, | ||
| 388 | "sp_a2_bts4": 33, | ||
| 389 | "sp_a2_bts5": 34, | ||
| 390 | "sp_a2_core": 35, | ||
| 391 | |||
| 392 | "sp_a3_01": 36, | ||
| 393 | "sp_a3_03": 37, | ||
| 394 | "sp_a3_jump_intro": 38, | ||
| 395 | "sp_a3_bomb_flings": 39, | ||
| 396 | "sp_a3_crazy_box": 40, | ||
| 397 | "sp_a3_transition01": 41, | ||
| 398 | |||
| 399 | "sp_a3_speed_ramp": 42, | ||
| 400 | "sp_a3_speed_flings": 43, | ||
| 401 | "sp_a3_portal_intro": 44, | ||
| 402 | "sp_a3_end": 45, | ||
| 403 | |||
| 404 | "sp_a4_intro": 46, | ||
| 405 | "sp_a4_tb_intro": 47, | ||
| 406 | "sp_a4_tb_trust_drop": 48, | ||
| 407 | "sp_a4_tb_wall_button": 49, | ||
| 408 | "sp_a4_tb_polarity": 50, | ||
| 409 | "sp_a4_tb_catch": 51, | ||
| 410 | "sp_a4_stop_the_box": 52, | ||
| 411 | "sp_a4_laser_catapult": 53, | ||
| 412 | "sp_a4_laser_platform": 54, | ||
| 413 | "sp_a4_speed_catch": 55, | ||
| 414 | "sp_a4_jump_polarity": 56, | ||
| 415 | |||
| 416 | "sp_a4_finale1": 57, | ||
| 417 | "sp_a4_finale2": 58, | ||
| 418 | "sp_a4_finale3": 59, | ||
| 419 | "sp_a4_finale4": 60, | ||
| 420 | |||
| 421 | "mp_coop_start": 61, | ||
| 422 | "mp_coop_lobby_2": 62, | ||
| 423 | |||
| 424 | "mp_coop_doors": 63, | ||
| 425 | "mp_coop_race_2": 64, | ||
| 426 | "mp_coop_laser_2": 65, | ||
| 427 | "mp_coop_rat_maze": 66, | ||
| 428 | "mp_coop_laser_crusher": 67, | ||
| 429 | "mp_coop_teambts": 68, | ||
| 430 | |||
| 431 | "mp_coop_fling_3": 69, | ||
| 432 | "mp_coop_infinifling_train": 70, | ||
| 433 | "mp_coop_come_along": 71, | ||
| 434 | "mp_coop_fling_1": 72, | ||
| 435 | "mp_coop_catapult_1": 73, | ||
| 436 | "mp_coop_multifling_1": 74, | ||
| 437 | "mp_coop_fling_crushers": 75, | ||
| 438 | "mp_coop_fan": 76, | ||
| 439 | |||
| 440 | "mp_coop_wall_intro": 77, | ||
| 441 | "mp_coop_wall_2": 78, | ||
| 442 | "mp_coop_catapult_wall_intro": 79, | ||
| 443 | "mp_coop_wall_block": 80, | ||
| 444 | "mp_coop_catapult_2": 81, | ||
| 445 | "mp_coop_turret_walls": 82, | ||
| 446 | "mp_coop_turret_ball": 83, | ||
| 447 | "mp_coop_wall_5": 84, | ||
| 448 | |||
| 449 | "mp_coop_tbeam_redirect": 85, | ||
| 450 | "mp_coop_tbeam_drill": 86, | ||
| 451 | "mp_coop_tbeam_catch_grind_1": 87, | ||
| 452 | "mp_coop_tbeam_laser_1": 88, | ||
| 453 | "mp_coop_tbeam_polarity": 89, | ||
| 454 | "mp_coop_tbeam_polarity2": 90, | ||
| 455 | "mp_coop_tbeam_polarity3": 91, | ||
| 456 | "mp_coop_tbeam_maze": 92, | ||
| 457 | "mp_coop_tbeam_end": 93, | ||
| 458 | |||
| 459 | "mp_coop_paint_come_along": 94, | ||
| 460 | "mp_coop_paint_redirect": 95, | ||
| 461 | "mp_coop_paint_bridge": 96, | ||
| 462 | "mp_coop_paint_walljumps": 97, | ||
| 463 | "mp_coop_paint_speed_flings": 98, | ||
| 464 | "mp_coop_paint_red_racer": 99, | ||
| 465 | "mp_coop_paint_speed_catch": 100, | ||
| 466 | "mp_coop_paint_longjump_intro": 101, | ||
| 467 | |||
| 468 | "mp_coop_seperation_1": 102, | ||
| 469 | "mp_coop_tripleaxis": 103, | ||
| 470 | "mp_coop_catapult_catch": 104, | ||
| 471 | "mp_coop_2paints_1bridge": 105, | ||
| 472 | "mp_coop_paint_conversion": 106, | ||
| 473 | "mp_coop_bridge_catch": 107, | ||
| 474 | "mp_coop_laser_tbeam": 108, | ||
| 475 | "mp_coop_paint_rat_maze": 109, | ||
| 476 | "mp_coop_paint_crazy_box": 110, | ||
| 313 | } | 477 | } |