@astefanski/storm-parser 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index.d.mts +134 -10
- package/dist/index.d.ts +134 -10
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
A tool for parsing Heroes of the Storm (`.StormReplay`) replay files. Extract valuable match data including players, heroes, builds, match results, and more.
|
|
4
4
|
|
|
5
|
+
[GitHub Repository](https://github.com/astefanski1/storm-parser)
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
This is a private scoped package. Ensure you have access and are authenticated with npm, then install it via:
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,121 @@
|
|
|
1
|
+
interface MPQFileHeader {
|
|
2
|
+
magic: string;
|
|
3
|
+
headerSize: number;
|
|
4
|
+
archiveSize: number;
|
|
5
|
+
formatVersion: number;
|
|
6
|
+
sectorSizeShift: number;
|
|
7
|
+
hashTableOffset: number;
|
|
8
|
+
blockTableOffset: number;
|
|
9
|
+
hashTableEntries: number;
|
|
10
|
+
blockTableEntries: number;
|
|
11
|
+
offset?: number;
|
|
12
|
+
userDataHeader?: MPQUserDataHeader;
|
|
13
|
+
extendedBlockTableOffset?: number;
|
|
14
|
+
hashTableOffsetHigh?: number;
|
|
15
|
+
blockTableOffsetHigh?: number;
|
|
16
|
+
}
|
|
17
|
+
interface MPQUserDataHeader {
|
|
18
|
+
magic: string;
|
|
19
|
+
userDataSize: number;
|
|
20
|
+
mpqHeaderOffset: number;
|
|
21
|
+
userDataHeaderSize: number;
|
|
22
|
+
content?: Buffer;
|
|
23
|
+
}
|
|
24
|
+
interface MPQHashTableEntry {
|
|
25
|
+
hashA: number;
|
|
26
|
+
hashB: number;
|
|
27
|
+
locale: number;
|
|
28
|
+
platform: number;
|
|
29
|
+
blockTableIndex: number;
|
|
30
|
+
}
|
|
31
|
+
interface MPQBlockTableEntry {
|
|
32
|
+
offset: number;
|
|
33
|
+
archivedSize: number;
|
|
34
|
+
size: number;
|
|
35
|
+
flags: number;
|
|
36
|
+
}
|
|
37
|
+
declare class MpqReader {
|
|
38
|
+
file: Buffer;
|
|
39
|
+
header: MPQFileHeader;
|
|
40
|
+
hashTable: MPQHashTableEntry[];
|
|
41
|
+
blockTable: MPQBlockTableEntry[];
|
|
42
|
+
files: string[] | null;
|
|
43
|
+
constructor(filenameOrData: string | Buffer, readListfile?: boolean);
|
|
44
|
+
private readHeader;
|
|
45
|
+
private readMPQHeader;
|
|
46
|
+
private readMPQUserDataHeader;
|
|
47
|
+
private readTable;
|
|
48
|
+
getHashTableEntry(filename: string): MPQHashTableEntry | undefined;
|
|
49
|
+
readFile(filename: string, forceDecompress?: boolean): Buffer | null;
|
|
50
|
+
private hash;
|
|
51
|
+
private decrypt;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
declare class BitPackedBuffer {
|
|
55
|
+
private _data;
|
|
56
|
+
private _used;
|
|
57
|
+
private _next;
|
|
58
|
+
private _nextbits;
|
|
59
|
+
private _bigendian;
|
|
60
|
+
constructor(contents: Buffer, endian?: "big" | "little");
|
|
61
|
+
done(): boolean;
|
|
62
|
+
used_bits(): number;
|
|
63
|
+
byte_align(): void;
|
|
64
|
+
read_aligned_bytes(bytes: number): Buffer;
|
|
65
|
+
read_bits(bits: number): number;
|
|
66
|
+
read_bits_bigint(bits: number): bigint;
|
|
67
|
+
read_unaligned_bytes(bytes: number): Buffer;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
type DecodedData = string | number | boolean | bigint | null | Buffer | DecodedData[] | {
|
|
71
|
+
[key: string]: DecodedData;
|
|
72
|
+
};
|
|
73
|
+
declare class BitPackedDecoder {
|
|
74
|
+
protected _buffer: BitPackedBuffer;
|
|
75
|
+
protected _typeinfos: TypeInfo[];
|
|
76
|
+
constructor(contents: Buffer, typeinfos: TypeInfo[]);
|
|
77
|
+
instance(typeid: number): DecodedData;
|
|
78
|
+
byte_align(): void;
|
|
79
|
+
done(): boolean;
|
|
80
|
+
used_bits(): number;
|
|
81
|
+
protected _array(bounds: [number, number], typeid: number): DecodedData[];
|
|
82
|
+
protected _bitarray(bounds: [number, number]): [number, number];
|
|
83
|
+
protected _blob(bounds: [number, number]): Buffer;
|
|
84
|
+
protected _bool(): boolean;
|
|
85
|
+
protected _choice(_bounds: [number, number], fields: Record<string, [string, number]>): Record<string, DecodedData>;
|
|
86
|
+
protected _fourcc(): string;
|
|
87
|
+
protected _int(bounds: [number, number]): number;
|
|
88
|
+
protected _null(): null;
|
|
89
|
+
protected _optional(typeid: number): DecodedData | null;
|
|
90
|
+
protected _real32(): number;
|
|
91
|
+
protected _real64(): number;
|
|
92
|
+
protected _struct(fields: [string, number][]): Record<string, DecodedData>;
|
|
93
|
+
}
|
|
94
|
+
declare class VersionedDecoder {
|
|
95
|
+
protected _buffer: BitPackedBuffer;
|
|
96
|
+
protected _typeinfos: TypeInfo[];
|
|
97
|
+
constructor(contents: Buffer, typeinfos: TypeInfo[]);
|
|
98
|
+
instance(typeid: number): DecodedData;
|
|
99
|
+
byte_align(): void;
|
|
100
|
+
done(): boolean;
|
|
101
|
+
used_bits(): number;
|
|
102
|
+
protected _expect_skip(expected: number): void;
|
|
103
|
+
protected _vint(): number | bigint;
|
|
104
|
+
protected _array(_bounds: [number, number], typeid: number): DecodedData[];
|
|
105
|
+
protected _bitarray(_bounds: [number, number]): [number, Buffer];
|
|
106
|
+
protected _blob(_bounds: [number, number]): Buffer;
|
|
107
|
+
protected _bool(): boolean;
|
|
108
|
+
protected _choice(_bounds: [number, number], fields: Record<string, [string, number]>): Record<string, DecodedData>;
|
|
109
|
+
protected _fourcc(): Buffer;
|
|
110
|
+
protected _int(_bounds: [number, number]): number;
|
|
111
|
+
protected _null(): null;
|
|
112
|
+
protected _optional(typeid: number): DecodedData | null;
|
|
113
|
+
protected _real32(): number;
|
|
114
|
+
protected _real64(): number;
|
|
115
|
+
protected _struct(fields: [string, number, number?][]): Record<string, DecodedData>;
|
|
116
|
+
protected _skip_instance(): void;
|
|
117
|
+
}
|
|
118
|
+
|
|
1
119
|
interface ReplayVersion {
|
|
2
120
|
m_flags: number;
|
|
3
121
|
m_major: number;
|
|
@@ -486,25 +604,31 @@ interface ReplayEvent {
|
|
|
486
604
|
[key: string]: unknown;
|
|
487
605
|
}
|
|
488
606
|
declare class ReplayParser {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
constructor(filenameOrData
|
|
607
|
+
protected mpq: MpqReader;
|
|
608
|
+
protected header: RawHeader | undefined;
|
|
609
|
+
protected build: number;
|
|
610
|
+
protected protocol?: Protocol;
|
|
611
|
+
protected baseProtocol?: Protocol;
|
|
612
|
+
constructor(filenameOrData?: string | Buffer);
|
|
495
613
|
init(): void;
|
|
496
|
-
|
|
497
|
-
|
|
614
|
+
protected loadProtocolForBuild(build: number): Protocol;
|
|
615
|
+
protected decodeEventStream(decoder: BitPackedDecoder | VersionedDecoder, eventidTypeid: number, eventTypes: Record<number, [number, string]>, decodeUserId: boolean): IterableIterator<ReplayEvent>;
|
|
498
616
|
getDetails(): RawDetails | null;
|
|
499
617
|
getInitData(): RawInitData | null;
|
|
500
618
|
getTrackerEvents(): ReplayEvent[];
|
|
501
619
|
getGameEvents(): ReplayEvent[];
|
|
502
|
-
getAttributeEvents():
|
|
620
|
+
getAttributeEvents(): unknown;
|
|
503
621
|
extractFile(filename: string): Buffer | null;
|
|
504
622
|
getHeader(): RawHeader | undefined;
|
|
505
623
|
getBuild(): number;
|
|
506
624
|
}
|
|
507
625
|
|
|
626
|
+
declare class LiveStreamParser extends ReplayParser {
|
|
627
|
+
constructor(build?: number);
|
|
628
|
+
parseTracker(buffer: Buffer): ReplayEvent[];
|
|
629
|
+
parseGame(buffer: Buffer): ReplayEvent[];
|
|
630
|
+
}
|
|
631
|
+
|
|
508
632
|
declare class ReplayAnalyzer {
|
|
509
633
|
static analyze(filePath: string): Promise<AnalysisResult>;
|
|
510
634
|
private static emptyTeam;
|
|
@@ -515,4 +639,4 @@ declare class ReplayAnalyzer {
|
|
|
515
639
|
private static fileTimeToDate;
|
|
516
640
|
}
|
|
517
641
|
|
|
518
|
-
export { type AnalysisResult, type BanEntry, type KillParticipant, type LevelAdvSegment, type LevelTime, type MatchStat, type MercCapture, type MercUnit, type MercUnitLocation, type MercsData, type ObjectiveData, type ObjectiveEvent, type PickData, type PlayerStat, type PlayerUnit, type Protocol, ReplayAnalyzer, type ReplayEvent, ReplayParser, type ReplayVersion, type StructureInfo, type StructureStats, type TakedownEvent, type TalentChoices, type TeamObjective, type TeamStat, type TeamStats, type TeamTotals, type UnitLife, type UnitPosition, type UptimeEntry, type XPBreakdownEntry, type XPValues };
|
|
642
|
+
export { type AnalysisResult, type BanEntry, type KillParticipant, type LevelAdvSegment, type LevelTime, LiveStreamParser, type MatchStat, type MercCapture, type MercUnit, type MercUnitLocation, type MercsData, type ObjectiveData, type ObjectiveEvent, type PickData, type PlayerStat, type PlayerUnit, type Protocol, ReplayAnalyzer, type ReplayEvent, ReplayParser, type ReplayVersion, type StructureInfo, type StructureStats, type TakedownEvent, type TalentChoices, type TeamObjective, type TeamStat, type TeamStats, type TeamTotals, type UnitLife, type UnitPosition, type UptimeEntry, type XPBreakdownEntry, type XPValues };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,121 @@
|
|
|
1
|
+
interface MPQFileHeader {
|
|
2
|
+
magic: string;
|
|
3
|
+
headerSize: number;
|
|
4
|
+
archiveSize: number;
|
|
5
|
+
formatVersion: number;
|
|
6
|
+
sectorSizeShift: number;
|
|
7
|
+
hashTableOffset: number;
|
|
8
|
+
blockTableOffset: number;
|
|
9
|
+
hashTableEntries: number;
|
|
10
|
+
blockTableEntries: number;
|
|
11
|
+
offset?: number;
|
|
12
|
+
userDataHeader?: MPQUserDataHeader;
|
|
13
|
+
extendedBlockTableOffset?: number;
|
|
14
|
+
hashTableOffsetHigh?: number;
|
|
15
|
+
blockTableOffsetHigh?: number;
|
|
16
|
+
}
|
|
17
|
+
interface MPQUserDataHeader {
|
|
18
|
+
magic: string;
|
|
19
|
+
userDataSize: number;
|
|
20
|
+
mpqHeaderOffset: number;
|
|
21
|
+
userDataHeaderSize: number;
|
|
22
|
+
content?: Buffer;
|
|
23
|
+
}
|
|
24
|
+
interface MPQHashTableEntry {
|
|
25
|
+
hashA: number;
|
|
26
|
+
hashB: number;
|
|
27
|
+
locale: number;
|
|
28
|
+
platform: number;
|
|
29
|
+
blockTableIndex: number;
|
|
30
|
+
}
|
|
31
|
+
interface MPQBlockTableEntry {
|
|
32
|
+
offset: number;
|
|
33
|
+
archivedSize: number;
|
|
34
|
+
size: number;
|
|
35
|
+
flags: number;
|
|
36
|
+
}
|
|
37
|
+
declare class MpqReader {
|
|
38
|
+
file: Buffer;
|
|
39
|
+
header: MPQFileHeader;
|
|
40
|
+
hashTable: MPQHashTableEntry[];
|
|
41
|
+
blockTable: MPQBlockTableEntry[];
|
|
42
|
+
files: string[] | null;
|
|
43
|
+
constructor(filenameOrData: string | Buffer, readListfile?: boolean);
|
|
44
|
+
private readHeader;
|
|
45
|
+
private readMPQHeader;
|
|
46
|
+
private readMPQUserDataHeader;
|
|
47
|
+
private readTable;
|
|
48
|
+
getHashTableEntry(filename: string): MPQHashTableEntry | undefined;
|
|
49
|
+
readFile(filename: string, forceDecompress?: boolean): Buffer | null;
|
|
50
|
+
private hash;
|
|
51
|
+
private decrypt;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
declare class BitPackedBuffer {
|
|
55
|
+
private _data;
|
|
56
|
+
private _used;
|
|
57
|
+
private _next;
|
|
58
|
+
private _nextbits;
|
|
59
|
+
private _bigendian;
|
|
60
|
+
constructor(contents: Buffer, endian?: "big" | "little");
|
|
61
|
+
done(): boolean;
|
|
62
|
+
used_bits(): number;
|
|
63
|
+
byte_align(): void;
|
|
64
|
+
read_aligned_bytes(bytes: number): Buffer;
|
|
65
|
+
read_bits(bits: number): number;
|
|
66
|
+
read_bits_bigint(bits: number): bigint;
|
|
67
|
+
read_unaligned_bytes(bytes: number): Buffer;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
type DecodedData = string | number | boolean | bigint | null | Buffer | DecodedData[] | {
|
|
71
|
+
[key: string]: DecodedData;
|
|
72
|
+
};
|
|
73
|
+
declare class BitPackedDecoder {
|
|
74
|
+
protected _buffer: BitPackedBuffer;
|
|
75
|
+
protected _typeinfos: TypeInfo[];
|
|
76
|
+
constructor(contents: Buffer, typeinfos: TypeInfo[]);
|
|
77
|
+
instance(typeid: number): DecodedData;
|
|
78
|
+
byte_align(): void;
|
|
79
|
+
done(): boolean;
|
|
80
|
+
used_bits(): number;
|
|
81
|
+
protected _array(bounds: [number, number], typeid: number): DecodedData[];
|
|
82
|
+
protected _bitarray(bounds: [number, number]): [number, number];
|
|
83
|
+
protected _blob(bounds: [number, number]): Buffer;
|
|
84
|
+
protected _bool(): boolean;
|
|
85
|
+
protected _choice(_bounds: [number, number], fields: Record<string, [string, number]>): Record<string, DecodedData>;
|
|
86
|
+
protected _fourcc(): string;
|
|
87
|
+
protected _int(bounds: [number, number]): number;
|
|
88
|
+
protected _null(): null;
|
|
89
|
+
protected _optional(typeid: number): DecodedData | null;
|
|
90
|
+
protected _real32(): number;
|
|
91
|
+
protected _real64(): number;
|
|
92
|
+
protected _struct(fields: [string, number][]): Record<string, DecodedData>;
|
|
93
|
+
}
|
|
94
|
+
declare class VersionedDecoder {
|
|
95
|
+
protected _buffer: BitPackedBuffer;
|
|
96
|
+
protected _typeinfos: TypeInfo[];
|
|
97
|
+
constructor(contents: Buffer, typeinfos: TypeInfo[]);
|
|
98
|
+
instance(typeid: number): DecodedData;
|
|
99
|
+
byte_align(): void;
|
|
100
|
+
done(): boolean;
|
|
101
|
+
used_bits(): number;
|
|
102
|
+
protected _expect_skip(expected: number): void;
|
|
103
|
+
protected _vint(): number | bigint;
|
|
104
|
+
protected _array(_bounds: [number, number], typeid: number): DecodedData[];
|
|
105
|
+
protected _bitarray(_bounds: [number, number]): [number, Buffer];
|
|
106
|
+
protected _blob(_bounds: [number, number]): Buffer;
|
|
107
|
+
protected _bool(): boolean;
|
|
108
|
+
protected _choice(_bounds: [number, number], fields: Record<string, [string, number]>): Record<string, DecodedData>;
|
|
109
|
+
protected _fourcc(): Buffer;
|
|
110
|
+
protected _int(_bounds: [number, number]): number;
|
|
111
|
+
protected _null(): null;
|
|
112
|
+
protected _optional(typeid: number): DecodedData | null;
|
|
113
|
+
protected _real32(): number;
|
|
114
|
+
protected _real64(): number;
|
|
115
|
+
protected _struct(fields: [string, number, number?][]): Record<string, DecodedData>;
|
|
116
|
+
protected _skip_instance(): void;
|
|
117
|
+
}
|
|
118
|
+
|
|
1
119
|
interface ReplayVersion {
|
|
2
120
|
m_flags: number;
|
|
3
121
|
m_major: number;
|
|
@@ -486,25 +604,31 @@ interface ReplayEvent {
|
|
|
486
604
|
[key: string]: unknown;
|
|
487
605
|
}
|
|
488
606
|
declare class ReplayParser {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
constructor(filenameOrData
|
|
607
|
+
protected mpq: MpqReader;
|
|
608
|
+
protected header: RawHeader | undefined;
|
|
609
|
+
protected build: number;
|
|
610
|
+
protected protocol?: Protocol;
|
|
611
|
+
protected baseProtocol?: Protocol;
|
|
612
|
+
constructor(filenameOrData?: string | Buffer);
|
|
495
613
|
init(): void;
|
|
496
|
-
|
|
497
|
-
|
|
614
|
+
protected loadProtocolForBuild(build: number): Protocol;
|
|
615
|
+
protected decodeEventStream(decoder: BitPackedDecoder | VersionedDecoder, eventidTypeid: number, eventTypes: Record<number, [number, string]>, decodeUserId: boolean): IterableIterator<ReplayEvent>;
|
|
498
616
|
getDetails(): RawDetails | null;
|
|
499
617
|
getInitData(): RawInitData | null;
|
|
500
618
|
getTrackerEvents(): ReplayEvent[];
|
|
501
619
|
getGameEvents(): ReplayEvent[];
|
|
502
|
-
getAttributeEvents():
|
|
620
|
+
getAttributeEvents(): unknown;
|
|
503
621
|
extractFile(filename: string): Buffer | null;
|
|
504
622
|
getHeader(): RawHeader | undefined;
|
|
505
623
|
getBuild(): number;
|
|
506
624
|
}
|
|
507
625
|
|
|
626
|
+
declare class LiveStreamParser extends ReplayParser {
|
|
627
|
+
constructor(build?: number);
|
|
628
|
+
parseTracker(buffer: Buffer): ReplayEvent[];
|
|
629
|
+
parseGame(buffer: Buffer): ReplayEvent[];
|
|
630
|
+
}
|
|
631
|
+
|
|
508
632
|
declare class ReplayAnalyzer {
|
|
509
633
|
static analyze(filePath: string): Promise<AnalysisResult>;
|
|
510
634
|
private static emptyTeam;
|
|
@@ -515,4 +639,4 @@ declare class ReplayAnalyzer {
|
|
|
515
639
|
private static fileTimeToDate;
|
|
516
640
|
}
|
|
517
641
|
|
|
518
|
-
export { type AnalysisResult, type BanEntry, type KillParticipant, type LevelAdvSegment, type LevelTime, type MatchStat, type MercCapture, type MercUnit, type MercUnitLocation, type MercsData, type ObjectiveData, type ObjectiveEvent, type PickData, type PlayerStat, type PlayerUnit, type Protocol, ReplayAnalyzer, type ReplayEvent, ReplayParser, type ReplayVersion, type StructureInfo, type StructureStats, type TakedownEvent, type TalentChoices, type TeamObjective, type TeamStat, type TeamStats, type TeamTotals, type UnitLife, type UnitPosition, type UptimeEntry, type XPBreakdownEntry, type XPValues };
|
|
642
|
+
export { type AnalysisResult, type BanEntry, type KillParticipant, type LevelAdvSegment, type LevelTime, LiveStreamParser, type MatchStat, type MercCapture, type MercUnit, type MercUnitLocation, type MercsData, type ObjectiveData, type ObjectiveEvent, type PickData, type PlayerStat, type PlayerUnit, type Protocol, ReplayAnalyzer, type ReplayEvent, ReplayParser, type ReplayVersion, type StructureInfo, type StructureStats, type TakedownEvent, type TalentChoices, type TeamObjective, type TeamStat, type TeamStats, type TeamTotals, type UnitLife, type UnitPosition, type UptimeEntry, type XPBreakdownEntry, type XPValues };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";var Ne=Object.create;var Y=Object.defineProperty;var Fe=Object.getOwnPropertyDescriptor;var Xe=Object.getOwnPropertyNames;var Ge=Object.getPrototypeOf,Ke=Object.prototype.hasOwnProperty;var G=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),je=(t,e)=>{for(var r in e)Y(t,r,{get:e[r],enumerable:!0})},ue=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Xe(e))!Ke.call(t,i)&&i!==r&&Y(t,i,{get:()=>e[i],enumerable:!(n=Fe(e,i))||n.enumerable});return t};var J=(t,e,r)=>(r=t!=null?Ne(Ge(t)):{},ue(e||!t||!t.__esModule?Y(r,"default",{value:t,enumerable:!0}):r,t)),Qe=t=>ue(Y({},"__esModule",{value:!0}),t);var pe=G((Bt,be)=>{"use strict";var me=[0,1,3,7,15,31,63,127,255],K=function(t){this.stream=t,this.bitOffset=0,this.curByte=0,this.hasByte=!1};K.prototype._ensureByte=function(){this.hasByte||(this.curByte=this.stream.readByte(),this.hasByte=!0)};K.prototype.read=function(t){for(var e=0;t>0;){this._ensureByte();var r=8-this.bitOffset;if(t>=r)e<<=r,e|=me[r]&this.curByte,this.hasByte=!1,this.bitOffset=0,t-=r;else{e<<=t;var n=r-t;e|=(this.curByte&me[t]<<n)>>n,this.bitOffset+=t,t=0}}return e};K.prototype.seek=function(t){var e=t%8,r=(t-e)/8;this.bitOffset=e,this.stream.seek(r),this.hasByte=!1};K.prototype.pi=function(){var t=new Buffer(6),e;for(e=0;e<t.length;e++)t[e]=this.read(8);return t.toString("hex")};be.exports=K});var _e=G((Ct,he)=>{"use strict";var H=function(){};H.prototype.readByte=function(){throw new Error("abstract method readByte() not implemented")};H.prototype.read=function(t,e,r){for(var n=0;n<r;){var i=this.readByte();if(i<0)return n===0?-1:n;t[e++]=i,n++}return n};H.prototype.seek=function(t){throw new Error("abstract method seek() not implemented")};H.prototype.writeByte=function(t){throw new Error("abstract method readByte() not implemented")};H.prototype.write=function(t,e,r){var n;for(n=0;n<r;n++)this.writeByte(t[e++]);return r};H.prototype.flush=function(){};he.exports=H});var ye=G((It,ge)=>{"use strict";ge.exports=(function(){var t=new Uint32Array([0,79764919,159529838,222504665,319059676,398814059,445009330,507990021,638119352,583659535,797628118,726387553,890018660,835552979,1015980042,944750013,1276238704,1221641927,1167319070,1095957929,1595256236,1540665371,1452775106,1381403509,1780037320,1859660671,1671105958,1733955601,2031960084,2111593891,1889500026,1952343757,2552477408,2632100695,2443283854,2506133561,2334638140,2414271883,2191915858,2254759653,3190512472,3135915759,3081330742,3009969537,2905550212,2850959411,2762807018,2691435357,3560074640,3505614887,3719321342,3648080713,3342211916,3287746299,3467911202,3396681109,4063920168,4143685023,4223187782,4286162673,3779000052,3858754371,3904687514,3967668269,881225847,809987520,1023691545,969234094,662832811,591600412,771767749,717299826,311336399,374308984,453813921,533576470,25881363,88864420,134795389,214552010,2023205639,2086057648,1897238633,1976864222,1804852699,1867694188,1645340341,1724971778,1587496639,1516133128,1461550545,1406951526,1302016099,1230646740,1142491917,1087903418,2896545431,2825181984,2770861561,2716262478,3215044683,3143675388,3055782693,3001194130,2326604591,2389456536,2200899649,2280525302,2578013683,2640855108,2418763421,2498394922,3769900519,3832873040,3912640137,3992402750,4088425275,4151408268,4197601365,4277358050,3334271071,3263032808,3476998961,3422541446,3585640067,3514407732,3694837229,3640369242,1762451694,1842216281,1619975040,1682949687,2047383090,2127137669,1938468188,2001449195,1325665622,1271206113,1183200824,1111960463,1543535498,1489069629,1434599652,1363369299,622672798,568075817,748617968,677256519,907627842,853037301,1067152940,995781531,51762726,131386257,177728840,240578815,269590778,349224269,429104020,491947555,4046411278,4126034873,4172115296,4234965207,3794477266,3874110821,3953728444,4016571915,3609705398,3555108353,3735388376,3664026991,3290680682,3236090077,3449943556,3378572211,3174993278,3120533705,3032266256,2961025959,2923101090,2868635157,2813903052,2742672763,2604032198,2683796849,2461293480,2524268063,2284983834,2364738477,2175806836,2238787779,1569362073,1498123566,1409854455,1355396672,1317987909,1246755826,1192025387,1137557660,2072149281,2135122070,1912620623,1992383480,1753615357,1816598090,1627664531,1707420964,295390185,358241886,404320391,483945776,43990325,106832002,186451547,266083308,932423249,861060070,1041341759,986742920,613929101,542559546,756411363,701822548,3316196985,3244833742,3425377559,3370778784,3601682597,3530312978,3744426955,3689838204,3819031489,3881883254,3928223919,4007849240,4037393693,4100235434,4180117107,4259748804,2310601993,2373574846,2151335527,2231098320,2596047829,2659030626,2470359227,2550115596,2947551409,2876312838,2788305887,2733848168,3165939309,3094707162,3040238851,2985771188]),e=function(){var r=4294967295;this.getCRC=function(){return~r>>>0},this.updateCRC=function(n){r=r<<8^t[(r>>>24^n)&255]},this.updateCRCRun=function(n,i){for(;i-- >0;)r=r<<8^t[(r>>>24^n)&255]}};return e})()});var xe=G((At,Ve)=>{Ve.exports={name:"seek-bzip",version:"2.0.0",contributors:["C. Scott Ananian (http://cscott.net)","Eli Skeggs","Kevin Kwok","Rob Landley (http://landley.net)"],description:"a pure-JavaScript Node.JS module for random-access decoding bzip2 data",main:"./lib/index.js",repository:{type:"git",url:"https://github.com/cscott/seek-bzip.git"},license:"MIT",bin:{"seek-bunzip":"./bin/seek-bunzip","seek-table":"./bin/seek-bzip-table"},directories:{test:"test"},dependencies:{commander:"^6.0.0"},devDependencies:{fibers:"^5.0.0",mocha:"^8.1.0"},scripts:{test:"mocha"}}});var De=G((Mt,Pe)=>{"use strict";var We=pe(),j=_e(),Se=ye(),we=xe(),ee=20,ve=258,Te=0,$e=1,qe=2,Ze=6,Ye=50,Je="314159265359",et="177245385090",ke=function(t,e){var r=t[e],n;for(n=e;n>0;n--)t[n]=t[n-1];return t[0]=r,r},g={OK:0,LAST_BLOCK:-1,NOT_BZIP_DATA:-2,UNEXPECTED_INPUT_EOF:-3,UNEXPECTED_OUTPUT_EOF:-4,DATA_ERROR:-5,OUT_OF_MEMORY:-6,OBSOLETE_INPUT:-7,END_OF_BLOCK:-8},C={};C[g.LAST_BLOCK]="Bad file checksum";C[g.NOT_BZIP_DATA]="Not bzip data";C[g.UNEXPECTED_INPUT_EOF]="Unexpected input EOF";C[g.UNEXPECTED_OUTPUT_EOF]="Unexpected output EOF";C[g.DATA_ERROR]="Data error";C[g.OUT_OF_MEMORY]="Out of memory";C[g.OBSOLETE_INPUT]="Obsolete (pre 0.9.5) bzip format not supported.";var T=function(t,e){var r=C[t]||"unknown error";e&&(r+=": "+e);var n=new TypeError(r);throw n.errorCode=t,n},S=function(t,e){this.writePos=this.writeCurrent=this.writeCount=0,this._start_bunzip(t,e)};S.prototype._init_block=function(){var t=this._get_next_block();return t?(this.blockCRC=new Se,!0):(this.writeCount=-1,!1)};S.prototype._start_bunzip=function(t,e){var r=new Buffer(4);(t.read(r,0,4)!==4||String.fromCharCode(r[0],r[1],r[2])!=="BZh")&&T(g.NOT_BZIP_DATA,"bad magic");var n=r[3]-48;(n<1||n>9)&&T(g.NOT_BZIP_DATA,"level out of range"),this.reader=new We(t),this.dbufSize=1e5*n,this.nextoutput=0,this.outputStream=e,this.streamCRC=0};S.prototype._get_next_block=function(){var t,e,r,n=this.reader,i=n.pi();if(i===et)return!1;i!==Je&&T(g.NOT_BZIP_DATA),this.targetBlockCRC=n.read(32)>>>0,this.streamCRC=(this.targetBlockCRC^(this.streamCRC<<1|this.streamCRC>>>31))>>>0,n.read(1)&&T(g.OBSOLETE_INPUT);var a=n.read(24);a>this.dbufSize&&T(g.DATA_ERROR,"initial position out of bounds");var s=n.read(16),o=new Buffer(256),l=0;for(t=0;t<16;t++)if(s&1<<15-t){var c=t*16;for(r=n.read(16),e=0;e<16;e++)r&1<<15-e&&(o[l++]=c+e)}var f=n.read(3);(f<qe||f>Ze)&&T(g.DATA_ERROR);var u=n.read(15);u===0&&T(g.DATA_ERROR);var m=new Buffer(256);for(t=0;t<f;t++)m[t]=t;var p=new Buffer(u);for(t=0;t<u;t++){for(e=0;n.read(1);e++)e>=f&&T(g.DATA_ERROR);p[t]=ke(m,e)}var d=l+2,h=[],b;for(e=0;e<f;e++){var _=new Buffer(d),y=new Uint16Array(ee+1);for(s=n.read(5),t=0;t<d;t++){for(;(s<1||s>ee)&&T(g.DATA_ERROR),!!n.read(1);)n.read(1)?s--:s++;_[t]=s}var x,P;for(x=P=_[0],t=1;t<d;t++)_[t]>P?P=_[t]:_[t]<x&&(x=_[t]);b={},h.push(b),b.permute=new Uint16Array(ve),b.limit=new Uint32Array(ee+2),b.base=new Uint32Array(ee+1),b.minLen=x,b.maxLen=P;var A=0;for(t=x;t<=P;t++)for(y[t]=b.limit[t]=0,s=0;s<d;s++)_[s]===t&&(b.permute[A++]=s);for(t=0;t<d;t++)y[_[t]]++;for(A=s=0,t=x;t<P;t++)A+=y[t],b.limit[t]=A-1,A<<=1,s+=y[t],b.base[t+1]=A-s;b.limit[P+1]=Number.MAX_VALUE,b.limit[P]=A+y[P]-1,b.base[x]=0}var U=new Uint32Array(256);for(t=0;t<256;t++)m[t]=t;var M=0,B=0,ce=0,E,F=this.dbuf=new Uint32Array(this.dbufSize);for(d=0;;){for(d--||(d=Ye-1,ce>=u&&T(g.DATA_ERROR),b=h[p[ce++]]),t=b.minLen,e=n.read(t);t>b.maxLen&&T(g.DATA_ERROR),!(e<=b.limit[t]);t++)e=e<<1|n.read(1);e-=b.base[t],(e<0||e>=ve)&&T(g.DATA_ERROR);var X=b.permute[e];if(X===Te||X===$e){M||(M=1,s=0),X===Te?s+=M:s+=2*M,M<<=1;continue}if(M)for(M=0,B+s>this.dbufSize&&T(g.DATA_ERROR),E=o[m[0]],U[E]+=s;s--;)F[B++]=E;if(X>l)break;B>=this.dbufSize&&T(g.DATA_ERROR),t=X-1,E=ke(m,t),E=o[E],U[E]++,F[B++]=E}for((a<0||a>=B)&&T(g.DATA_ERROR),e=0,t=0;t<256;t++)r=e+U[t],U[t]=e,e=r;for(t=0;t<B;t++)E=F[t]&255,F[U[E]]|=t<<8,U[E]++;var Z=0,fe=0,de=0;return B&&(Z=F[a],fe=Z&255,Z>>=8,de=-1),this.writePos=Z,this.writeCurrent=fe,this.writeCount=B,this.writeRun=de,!0};S.prototype._read_bunzip=function(t,e){var r,n,i;if(this.writeCount<0)return 0;for(var a=0,s=this.dbuf,o=this.writePos,l=this.writeCurrent,c=this.writeCount,f=this.outputsize,u=this.writeRun;c;){for(c--,n=l,o=s[o],l=o&255,o>>=8,u++===3?(r=l,i=n,l=-1):(r=1,i=l),this.blockCRC.updateCRCRun(i,r);r--;)this.outputStream.writeByte(i),this.nextoutput++;l!=n&&(u=0)}return this.writeCount=c,this.blockCRC.getCRC()!==this.targetBlockCRC&&T(g.DATA_ERROR,"Bad block CRC (got "+this.blockCRC.getCRC().toString(16)+" expected "+this.targetBlockCRC.toString(16)+")"),this.nextoutput};var ae=function(t){if("readByte"in t)return t;var e=new j;return e.pos=0,e.readByte=function(){return t[this.pos++]},e.seek=function(r){this.pos=r},e.eof=function(){return this.pos>=t.length},e},Ee=function(t){var e=new j,r=!0;if(t)if(typeof t=="number")e.buffer=new Buffer(t),r=!1;else{if("writeByte"in t)return t;e.buffer=t,r=!1}else e.buffer=new Buffer(16384);return e.pos=0,e.writeByte=function(n){if(r&&this.pos>=this.buffer.length){var i=new Buffer(this.buffer.length*2);this.buffer.copy(i),this.buffer=i}this.buffer[this.pos++]=n},e.getBuffer=function(){if(this.pos!==this.buffer.length){if(!r)throw new TypeError("outputsize does not match decoded input");var n=new Buffer(this.pos);this.buffer.copy(n,0,0,this.pos),this.buffer=n}return this.buffer},e._coerced=!0,e};S.Err=g;S.decode=function(t,e,r){for(var n=ae(t),i=Ee(e),a=new S(n,i);!("eof"in n&&n.eof());)if(a._init_block())a._read_bunzip();else{var s=a.reader.read(32)>>>0;if(s!==a.streamCRC&&T(g.DATA_ERROR,"Bad stream CRC (got "+a.streamCRC.toString(16)+" expected "+s.toString(16)+")"),r&&"eof"in n&&!n.eof())a._start_bunzip(n,i);else break}if("getBuffer"in i)return i.getBuffer()};S.decodeBlock=function(t,e,r){var n=ae(t),i=Ee(r),a=new S(n,i);a.reader.seek(e);var s=a._get_next_block();if(s&&(a.blockCRC=new Se,a.writeCopies=0,a._read_bunzip()),"getBuffer"in i)return i.getBuffer()};S.table=function(t,e,r){var n=new j;n.delegate=ae(t),n.pos=0,n.readByte=function(){return this.pos++,this.delegate.readByte()},n.delegate.eof&&(n.eof=n.delegate.eof.bind(n.delegate));var i=new j;i.pos=0,i.writeByte=function(){this.pos++};for(var a=new S(n,i),s=a.dbufSize;!("eof"in n&&n.eof());){var o=n.pos*8+a.reader.bitOffset;if(a.reader.hasByte&&(o-=8),a._init_block()){var l=i.pos;a._read_bunzip(),e(o,i.pos-l)}else{var c=a.reader.read(32);if(r&&"eof"in n&&!n.eof())a._start_bunzip(n,i),console.assert(a.dbufSize===s,"shouldn't change block size within multistream file");else break}}};S.Stream=j;S.version=we.version;S.license=we.license;Pe.exports=S});var Dt={};je(Dt,{ReplayAnalyzer:()=>ie,ReplayParser:()=>N});module.exports=Qe(Dt);var Ce=J(require("fs")),Q=J(require("zlib")),tt=De(),Re=512,rt=65536,nt=16777216,it=67108864,at=2147483648,st={TABLE_OFFSET:0,HASH_A:1,HASH_B:2,TABLE:3};function ot(){let t=1048577,e=new Uint32Array(256*5);for(let r=0;r<256;r++){let n=r;for(let i=0;i<5;i++){t=(t*125+3)%2796203;let a=(t&65535)<<16;t=(t*125+3)%2796203;let s=t&65535;e[n]=(a|s)>>>0,n+=256}}return e}var Be=ot(),te=class{file;header;hashTable;blockTable;files;constructor(e,r=!0){if(Buffer.isBuffer(e)?this.file=e:this.file=Ce.readFileSync(e),this.header=this.readHeader(),this.hashTable=this.readTable("hash"),this.blockTable=this.readTable("block"),r){let n=this.readFile("(listfile)");n?this.files=n.toString("utf8").trim().split(`\r
|
|
2
|
-
`):this.files=null}else this.files=null}readHeader(){let e=this.file.toString("utf8",0,4),r;if(e==="MPQ")r=this.readMPQHeader(),r.offset=0;else if(e==="MPQ\x1B"){let n=this.readMPQUserDataHeader();r=this.readMPQHeader(n.mpqHeaderOffset),r.offset=n.mpqHeaderOffset,r.userDataHeader=n}else throw new Error("Invalid MPQ file header");return r}readMPQHeader(e=0){let r=this.file.subarray(e,e+32),n={magic:r.toString("utf8",0,4),headerSize:r.readUInt32LE(4),archiveSize:r.readUInt32LE(8),formatVersion:r.readUInt16LE(12),sectorSizeShift:r.readUInt16LE(14),hashTableOffset:r.readUInt32LE(16),blockTableOffset:r.readUInt32LE(20),hashTableEntries:r.readUInt32LE(24),blockTableEntries:r.readUInt32LE(28)};if(n.formatVersion===1){let i=this.file.subarray(e+32,e+32+12);n.extendedBlockTableOffset=i.readUInt32LE(0)+i.readUInt32LE(4)*4294967296,n.hashTableOffsetHigh=i.readInt8(8),n.blockTableOffsetHigh=i.readInt8(10)}return n}readMPQUserDataHeader(){let e=this.file.subarray(0,16),r={magic:e.toString("utf8",0,4),userDataSize:e.readUInt32LE(4),mpqHeaderOffset:e.readUInt32LE(8),userDataHeaderSize:e.readUInt32LE(12)};return r.content=this.file.subarray(16,16+r.userDataHeaderSize),r}readTable(e){let r=e==="hash"?"hashTableOffset":"blockTableOffset",n=e==="hash"?"hashTableEntries":"blockTableEntries",i=this.header[r],a=this.header[n];if(i==null||a==null)throw new Error("Missing "+e+" offset or entries");let s=this.hash("("+e+" table)","TABLE"),o=this.file.subarray(i+(this.header.offset||0),i+(this.header.offset||0)+a*16);o=this.decrypt(o,s);let
|
|
3
|
-
Searched: `+t.join(", "))}var se=new Map,oe=null;function Ie(){return oe||(oe=lt()),oe}function re(t){if(se.has(t))return se.get(t);let e=Ie(),r=I.default.join(e,`protocol${t}.json`);if(!z.default.existsSync(r))return null;let n=JSON.parse(z.default.readFileSync(r,"utf-8"));return se.set(t,n),n}function Ae(){let t=Ie();return z.default.readdirSync(t).filter(e=>/^protocol\d+\.json$/.test(e)).map(e=>parseInt(e.match(/\d+/)[0],10)).sort((e,r)=>e-r)}var N=class{mpq;header;build=0;protocol;baseProtocol;constructor(e){this.mpq=new te(e,!1)}init(){let e=re(29406);if(!e)throw new Error("Base protocol29406 not found. Did postinstall run? Try: npx tsx node_modules/@astefanski/storm-parser/scripts/postinstall.ts");this.baseProtocol=e;let r=this.mpq.header.userDataHeader;if(!r||!r.content)throw new Error("Replay does not have a user data header");let n=new O(r.content,this.baseProtocol.typeinfos);this.header=n.instance(this.baseProtocol.replay_header_typeid),this.build=this.header.m_version.m_baseBuild,this.protocol=this.loadProtocolForBuild(this.build)}loadProtocolForBuild(e){let r=re(e);if(!r){let n=Ae(),i=n[0];for(let a of n)a<=e&&a>i&&(i=a);r=re(i)}if(!r)throw new Error(`No protocol found for build ${e}`);return r}*decodeEventStream(e,r,n,i){if(!this.protocol)throw new Error("Protocol not loaded");let a=0;for(;!e.done();){let s=e.used_bits(),o=e.instance(this.protocol.svaruint32_typeid),l=Object.keys(o)[0],c=o[l];a+=c;let f=i?e.instance(this.protocol.replay_userid_typeid):void 0,u=Number(e.instance(r)),m=n[u];if(!m)throw new Error(`Unknown eventid(${u})`);let p=m[0],d=m[1],h=e.instance(p);h._event=d,h._eventid=u,h._gameloop=a,i&&(h._userid=f),e.byte_align(),h._bits=e.used_bits()-s,yield h}}getDetails(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.details");return e?new O(e,this.protocol.typeinfos).instance(this.protocol.game_details_typeid):null}getInitData(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.initData");return e?new $(e,this.protocol.typeinfos).instance(this.protocol.replay_initdata_typeid):null}getTrackerEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.tracker.events");if(!e)return[];let r=new O(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(r,this.protocol.tracker_eventid_typeid,this.protocol.tracker_event_types,!1))}getGameEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.game.events");if(!e)return[];let r=new $(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(r,this.protocol.game_eventid_typeid,this.protocol.game_event_types,!0))}getAttributeEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.attributes.events");return e?new O(e,this.protocol.typeinfos).instance(this.protocol.replay_attributes_events_typeid):null}extractFile(e){return this.mpq.readFile(e)}getHeader(){return this.header}getBuild(){return this.build}};var Me=["Abathur","Alarak","Alexstrasza","Ana","Anduin","Anubarak","Artanis","Arthas","Auriel","Azmodan","Blaze","Brightwing","Cassia","Chen","Cho","Chromie","Deathwing","Deckard","Dehaka","Diablo","DVa","ETC","Falstad","Fenix","Gall","Garrosh","Gazlowe","Genji","Greymane","Guldan","Hanzo","Hogger","Illidan","Imperius","Jaina","Johanna","Junkrat","Kaelthas","KelThuzad","Kerrigan","Kharazim","Leoric","LiLi","LiMing","LtMorales","Lunara","Maiev","Malfurion","MalGanis","Malthael","Medivh","Mei","Mephisto","Muradin","Murky","Nazeebo","Nova","Orphea","Probius","Qhira","Ragnaros","Raynor","Rehgar","Rexxar","Samuro","SgtHammer","Sonya","Stitches","Stukov","Sylvanas","Tassadar","TheButcher","TheLostVikings","Thrall","Tracer","Tychus","Tyrael","Tyrande","Uther","Valeera","Valla","Varian","Whitemane","Xul","Yrel","Zagara","Zarya","Zeratul","Zuljin"],He={FaerieDragon:"Brightwing",Amazon:"Cassia",Barbarian:"Sonya",Crusader:"Johanna",DemonHunter:"Valla",WitchDoctor:"Nazeebo",Monk:"Kharazim",Wizard:"LiMing",Tinker:"Gazlowe",Medic:"LtMorales",L90ETC:"ETC",Butcher:"TheButcher",LostVikings:"TheLostVikings",Necromancer:"Xul",Dryad:"Lunara",Shapeshifter:"Greymane",ChoGall:"Cho"};function q(t){if(!t)return null;if(Me.includes(t))return t;if(He[t])return He[t];let e=t.replace(/[^a-zA-Z0-9]/g,"").toLowerCase(),r=Me.find(n=>n.toLowerCase()===e);return r||null}var Le={TownCannonTowerL2:"Fort Tower",TownCannonTowerL3:"Keep Tower",TownTownHallL2:"Fort",TownTownHallL3:"Keep",TownMoonwellL2:"Fort Well",TownMoonwellL3:"Keep Well"},ct={MercLanerMeleeKnight:"Bruiser Camp",MercLanerRangedMage:"Bruiser Camp",MercLanerSiegeGiant:"Siege Camp",MercLanerRangedMinion:"Siege Camp"};function R(t){return Buffer.isBuffer(t)?t.toString("utf8"):typeof t=="string"?t:String(t??"")}function v(t,e){if(!t)return;let r=t.find(n=>R(n.m_key)===e);return r!==void 0?r.m_value:void 0}function ne(t,e){if(!t)return;let r=t.find(n=>R(n.m_key)===e);return r!==void 0?R(r.m_value):void 0}function w(t,e){if(!t)return;let r=t.find(n=>R(n.m_key)===e);return r!==void 0?r.m_value:void 0}function le(t,e){return`${t}-${e}`}function D(t,e){return(t-e)/16}function Oe(t,e,r){let n={playerIDMap:{},loopGameStart:0,loopGameEnd:0,unitIndex:{},heroUnits:{},heroLives:{}};r.bans||(r.bans={0:[],1:[]}),r.levelTimes={0:{},1:{}},r.takedowns=[],r.structures={},r.XPBreakdown=[],r.mercs={captures:[],units:{}},r.objective={0:{count:0,events:[]},1:{count:0,events:[]},type:r.map||""};for(let i of t)switch(n.loopGameEnd=Math.max(n.loopGameEnd,i._gameloop),i._event){case"NNet.Replay.Tracker.SStatGameEvent":ft(i,n,e,r);break;case"NNet.Replay.Tracker.SHeroBannedEvent":if(i.m_hero){let a=R(i.m_hero),s=q(a);if(!s)break;let o=i.m_controllingTeam===2?1:0;if(r.bans&&r.bans[o]){let l=r.bans[o].length+1,c=r.bans[0].length+r.bans[1].length+1;r.bans[o].push({hero:s,order:l,absolute:c})}}break;case"NNet.Replay.Tracker.SUnitBornEvent":mt(i,n,r);break;case"NNet.Replay.Tracker.SUnitDiedEvent":bt(i,n,r);break;case"NNet.Replay.Tracker.SUnitOwnerChangeEvent":pt(i,n);break}return r.loopGameStart=n.loopGameStart,r.loopLength=n.loopGameEnd,r.length=(n.loopGameEnd-n.loopGameStart)/16,ht(n,e),{playerIDMap:n.playerIDMap}}function ft(t,e,r,n){let i=R(t.m_eventName),a=t.m_intData,s=t.m_stringData,o=t.m_fixedData;switch(i){case"PlayerInit":{let l=v(a,"PlayerID"),c=ne(s,"ToonHandle");l!==void 0&&c&&r[c]&&(e.playerIDMap[l]=c);break}case"GatesOpen":e.loopGameStart=t._gameloop;break;case"LevelUp":{let l=v(a,"PlayerID"),c=v(a,"Level");if(l===void 0||c===void 0)break;let f;if(l>=1&&l<=5)f="0";else if(l>=6&&l<=10)f="1";else break;n.levelTimes[f][String(c)]||(n.levelTimes[f][String(c)]={loop:t._gameloop,level:c,team:f,time:D(t._gameloop,e.loopGameStart)});break}case"TalentChosen":{let l=v(a,"PlayerID"),c=ne(s,"PurchaseName");if(l===void 0||!c||c==="Win"||c==="Loss"||c.startsWith("Hero"))break;let f=n.map?.replace(/\s+/g,"")||"";if(c===f)break;let u=e.playerIDMap[l];if(!u||!r[u])break;let m=["Tier1Choice","Tier2Choice","Tier3Choice","Tier4Choice","Tier5Choice","Tier6Choice","Tier7Choice"];for(let p of m)if(!r[u].talents[p]){r[u].talents[p]=c;break}break}case"PlayerDeath":{let l=v(a,"PlayerID"),c=v(a,"KillingPlayer"),f=w(o,"PositionX")??0,u=w(o,"PositionY")??0;if(l===void 0)break;let m=e.playerIDMap[l];if(!m)break;let p={player:m,hero:r[m]?.hero||""},d=[],h=r[m]?.team;if(c&&c>0){let _=e.playerIDMap[c];_&&r[_]&&d.push({player:_,hero:r[_].hero})}for(let[_,y]of Object.entries(e.playerIDMap)){let x=r[y];!x||x.team===h||parseInt(_)===c||d.push({player:y,hero:x.hero})}let b={loop:t._gameloop,time:D(t._gameloop,e.loopGameStart),x:f,y:u,killers:d,victim:p};n.takedowns.push(b),r[m]&&r[m].deaths.push(b);for(let _ of d)r[_.player]&&r[_.player].takedowns.push(b);break}case"PeriodicXPBreakdown":{let l=v(a,"Team");if(l===void 0)break;let c={GameTime:v(a,"GameTime")??0,PreviousGameTime:v(a,"PreviousGameTime")??0,MinionXP:w(o,"MinionXP")??0,CreepXP:w(o,"CreepXP")??0,StructureXP:w(o,"StructureXP")??0,HeroXP:w(o,"HeroXP")??0,TrickleXP:w(o,"TrickleXP")??0};n.XPBreakdown.push({loop:t._gameloop,time:D(t._gameloop,e.loopGameStart),team:l,teamLevel:v(a,"TeamLevel")??0,breakdown:c,theoreticalMinionXP:v(a,"TheoreticalMinionXP")??0});break}case"EndOfGameXPBreakdown":{let l=v(a,"Team");if(l===void 0)break;n.XPBreakdown.push({loop:t._gameloop,time:D(t._gameloop,e.loopGameStart),team:l,theoreticalMinionXP:v(a,"TheoreticalMinionXP")??0,breakdown:{GameTime:0,PreviousGameTime:0,MinionXP:w(o,"MinionXP")??0,CreepXP:w(o,"CreepXP")??0,StructureXP:w(o,"StructureXP")??0,HeroXP:w(o,"HeroXP")??0,TrickleXP:w(o,"TrickleXP")??0}});break}case"JungleCampCapture":{let l=v(a,"CampTeam")??v(a,"Team")??0;n.mercs.captures.push({loop:t._gameloop,type:ne(s,"CampType")??ne(s,"Result")??"Unknown Camp",team:l,time:D(t._gameloop,e.loopGameStart)});break}case"EndOfGameTalentChoices":{let l=v(a,"PlayerID");if(l===void 0)break;let c=e.playerIDMap[l];if(!c||!r[c])break;let f={};if(s)for(let u of s){let m=R(u.m_key),p=R(u.m_value);m==="Tier 1 Choice"&&p?f.Tier1Choice=p:m==="Tier 2 Choice"&&p?f.Tier2Choice=p:m==="Tier 3 Choice"&&p?f.Tier3Choice=p:m==="Tier 4 Choice"&&p?f.Tier4Choice=p:m==="Tier 5 Choice"&&p?f.Tier5Choice=p:m==="Tier 6 Choice"&&p?f.Tier6Choice=p:m==="Tier 7 Choice"&&p&&(f.Tier7Choice=p)}r[c].talents=f;break}default:ut(i,t,e,n,a,o);break}}var dt=new Set(["SoulEatersSpawned","TributeCollected","RavenCurseActivated","AltarCaptured","SkyTempleShotsFired","DragonKnightActivated","GardenTerrorActivated","InfernalShrineCaptured","PunisherKilled","VolskayaVehicleCapture","BraxisWaveStart","ImmortalDefeated","NukeExploded","PayloadDelivered","AlteracCavalryCharge","AlteracCavalry"]);function ut(t,e,r,n,i,a){if(!dt.has(t)||!i)return;let s=v(i,"Team")??v(i,"Event")??0,o=s===0||s===1?s:0,l={team:s,loop:e._gameloop,time:D(e._gameloop,r.loopGameStart),score:v(i,"Score"),duration:w(a,"Duration")};n.objective[o].events.push(l),n.objective[o].count=n.objective[o].events.length}function mt(t,e,r){let n=R(t.m_unitTypeName),i=t.m_unitTagIndex,a=t.m_unitTagRecycle,s=le(i,a),o=t.m_controlPlayerId??t.m_upkeepPlayerId,l=t.m_x??0,c=t.m_y??0,f;if(o>=1&&o<=5?f=0:o>=6&&o<=10?f=1:o===11?f=0:o===12?f=1:f=o<=5?0:1,e.unitIndex[s]={type:n,playerId:o,team:f,x:l,y:c,bornLoop:t._gameloop},n.startsWith("Town")&&Le[n]&&(r.structures[s]={type:n,name:Le[n],tag:i,rtag:a,x:l,y:c,team:f}),n.startsWith("Hero")&&o>=1&&o<=10){e.heroUnits[s]=o,e.heroLives[o]||(e.heroLives[o]=[]);let u=D(t._gameloop,e.loopGameStart);e.heroLives[o].push({born:u,locations:[{x:l,y:c,time:u}],duration:0})}if(ct[n]){let m=r.mercs.captures[r.mercs.captures.length-1]?.loop??t._gameloop;r.mercs.units[s]={loop:m,team:f,type:n,locations:[{x:l,y:c}],time:D(m,e.loopGameStart),duration:0}}}function bt(t,e,r){let n=le(t.m_unitTagIndex,t.m_unitTagRecycle),i=D(t._gameloop,e.loopGameStart);r.structures[n]&&(r.structures[n].destroyedLoop=t._gameloop,r.structures[n].destroyed=i),r.mercs.units[n]&&(r.mercs.units[n].duration=i-r.mercs.units[n].time);let a=e.heroUnits[n];if(a!==void 0&&e.heroLives[a]){let s=e.heroLives[a],o=s[s.length-1];o&&o.died===void 0&&(o.died=i,o.duration=i-o.born)}}function pt(t,e){let r=le(t.m_unitTagIndex,t.m_unitTagRecycle),n=t.m_controlPlayerId??t.m_upkeepPlayerId;e.unitIndex[r]&&(e.unitIndex[r].playerId=n,n>=1&&n<=5?e.unitIndex[r].team=0:n>=6&&n<=10&&(e.unitIndex[r].team=1))}function ht(t,e){for(let[r,n]of Object.entries(t.heroLives)){let i=parseInt(r,10),a=t.playerIDMap[i];if(!a||!e[a])continue;for(let o of n)if(o.died===void 0){let l=o.locations[o.locations.length-1];o.duration=l?l.time-o.born:0}let s="";for(let[o,l]of Object.entries(t.heroUnits))if(l===i){s=o;break}s&&(e[a].units[s]={lives:n})}}var _t=["DamageTaken","CreepDamage","Healing","HeroDamage","MinionDamage","SelfHealing","SiegeDamage","ProtectionGivenToAllies","TeamfightDamageTaken","TeamfightHealingDone","TeamfightHeroDamage","TimeCCdEnemyHeroes","TimeRootingEnemyHeroes","TimeSpentDead","TimeStunningEnemyHeroes","TimeSilencingEnemyHeroes"];function gt(){return{DamageTaken:0,CreepDamage:0,Healing:0,HeroDamage:0,MinionDamage:0,SelfHealing:0,SiegeDamage:0,ProtectionGivenToAllies:0,TeamfightDamageTaken:0,TeamfightHealingDone:0,TeamfightHeroDamage:0,TimeCCdEnemyHeroes:0,TimeRootingEnemyHeroes:0,TimeSpentDead:0,TimeStunningEnemyHeroes:0,TimeSilencingEnemyHeroes:0,avgTimeSpentDead:0,timeDeadPct:0}}function yt(){return{mercCaptures:0,mercUptime:0,mercUptimePercent:0,structures:{},KDA:0,PPK:0,timeTo10:0,totals:gt(),levelAdvTime:0,maxLevelAdv:0,avgLevelAdv:0,levelAdvPct:0,uptime:[],uptimeHistogram:{},wipes:0,avgHeroesAlive:0,aces:0,timeWithHeroAdv:0,pctWithHeroAdv:0,passiveXPRate:0,passiveXPDiff:0,passiveXPGain:0}}function ze(t,e){kt(t),xt(t,e),Tt(t,e),St(t),wt(t,e),Pt(t)}function xt(t,e){for(let r of["0","1"]){let n=t.teams[r];if(!n)continue;n.names=[],n.heroes=[],n.tags=[],n.stats=yt();for(let u of n.ids){let m=e[u];m&&(n.names.push(m.name),n.heroes.push(m.hero),n.tags.push(m.tag))}for(let u of n.ids){let m=e[u];if(m)for(let p of _t){let d=m.gameStats[p];typeof d=="number"&&(n.stats.totals[p]+=d)}}let i=n.ids.reduce((u,m)=>u+(e[m]?.gameStats.Deaths??0),0);i>0&&(n.stats.totals.avgTimeSpentDead=n.stats.totals.TimeSpentDead/i),t.length>0&&(n.stats.totals.timeDeadPct=n.stats.totals.TimeSpentDead/(t.length*n.ids.length));let a=n.takedowns,s=i;n.stats.KDA=s>0?a/s:a,n.stats.PPK=a>0?t.takedowns.filter(u=>n.ids.includes(u.killers[0]?.player)).reduce((u,m)=>u+m.killers.length,0)/a:0;let o=t.levelTimes[r];o?.["10"]&&(n.stats.timeTo10=o[10].time);let l=parseInt(r,10),c=t.mercs.captures.filter(u=>u.team===l);n.stats.mercCaptures=c.length;let f=0;for(let u of Object.values(t.mercs.units))u.team===l&&u.duration>0&&(f+=u.duration);n.stats.mercUptime=f,n.stats.mercUptimePercent=t.length>0?f/t.length:0,vt(t,n,r)}}function vt(t,e,r){let n=parseInt(r,10),i=n===0?1:0,a={};for(let s of Object.values(t.structures)){let o=s.name;a[o]||(a[o]={lost:0,destroyed:0,first:t.length}),s.team===i&&s.destroyed!==void 0&&(a[o].destroyed++,a[o].first=Math.min(a[o].first,s.destroyed)),s.team===n&&s.destroyed!==void 0&&a[o].lost++}e.stats.structures=a}function Tt(t,e){let r=t.length/60;for(let n of Object.values(e)){let i=n.gameStats,a=i.Deaths??0,s=i.TeamTakedowns??0;r>0&&(i.DPM=(i.HeroDamage??0)/r,i.HPM=((i.Healing??0)+(i.SelfHealing??0))/r,i.XPM=(i.ExperienceContribution??0)/r),i.KDA=a>0?(i.Takedowns??0)/a:i.Takedowns??0,i.KillParticipation=s>0?(i.Takedowns??0)/s:0,i.damageDonePerDeath=a>0?(i.HeroDamage??0)/a:i.HeroDamage??0,i.damageTakenPerDeath=a>0?(i.DamageTaken??0)/a:i.DamageTaken??0,i.healingDonePerDeath=a>0?((i.Healing??0)+(i.SelfHealing??0))/a:(i.Healing??0)+(i.SelfHealing??0),i.length=t.length}}function kt(t){let e=0,r=0,n=new Set(t.teams[0]?.ids||[]);for(let i of t.takedowns)n.has(i.victim.player)?r++:e++;t.team0Takedowns=e,t.team1Takedowns=r,t.teams[0]&&(t.teams[0].takedowns=e),t.teams[1]&&(t.teams[1].takedowns=r)}function St(t){let e=t.levelTimes[0]||{},r=t.levelTimes[1]||{},n=[];for(let c of Object.values(e))n.push({time:c.time,team:0,level:c.level});for(let c of Object.values(r))n.push({time:c.time,team:1,level:c.level});if(n.sort((c,f)=>c.time-f.time),n.length===0){t.levelAdvTimeline=[];return}let i=[],a=0,s=0,o=n[0].time;for(let c of n){let f=a-s;c.time>o&&i.push({start:o,end:c.time,levelDiff:f,length:c.time-o}),c.team===0?a=c.level:s=c.level,o=c.time}let l=a-s;t.length>o&&i.push({start:o,end:t.length,levelDiff:l,length:t.length-o}),t.levelAdvTimeline=i;for(let c of["0","1"]){let f=t.teams[c];if(!f)continue;let u=c==="0"?1:-1,m=0,p=0,d=0,h=0;for(let b of i){let _=b.levelDiff*u;_>0&&(m+=b.length),p=Math.max(p,_),d+=_*b.length,h+=b.length}f.stats.levelAdvTime=m,f.stats.maxLevelAdv=p,f.stats.avgLevelAdv=h>0?d/h:0,f.stats.levelAdvPct=t.length>0?m/t.length:0}}function wt(t,e){for(let a of["0","1"]){let s=t.teams[a];if(!s)continue;let o=[];for(let b of s.ids){let _=e[b];if(_)for(let y of _.deaths){o.push({time:y.time,delta:-1});let x=y.time+Et(_.gameStats.Level??1,y.time,t.length);x<t.length&&o.push({time:x,delta:1})}}o.sort((b,_)=>b.time-_.time);let l=[{time:0,heroes:s.ids.length}],c=s.ids.length;for(let b of o)c+=b.delta,c=Math.max(0,Math.min(s.ids.length,c)),l.push({time:b.time,heroes:c});s.stats.uptime=l;let f={};for(let b=0;b<l.length;b++){let y=(b<l.length-1?l[b+1].time:t.length)-l[b].time,x=String(l[b].heroes);f[x]=(f[x]||0)+y}s.stats.uptimeHistogram=f;let u=0,m=0;for(let b=0;b<l.length;b++){let y=(b<l.length-1?l[b+1].time:t.length)-l[b].time;u+=l[b].heroes*y,m+=y}s.stats.avgHeroesAlive=m>0?u/m:s.ids.length,s.stats.wipes=l.filter(b=>b.heroes===0).length,s.stats.aces=0;let p=a==="0"?"1":"0",d=t.teams[p];d?.stats?.uptime&&(s.stats.aces=d.stats.uptime.filter(b=>b.heroes===0).length);let h=t.XPBreakdown.filter(b=>b.team===parseInt(a,10));if(h.length>0){let _=h[h.length-1].breakdown.TrickleXP;s.stats.passiveXPGain=_,s.stats.passiveXPRate=t.length>0?_/(t.length/60):0}}for(let a of["0","1"]){let s=t.teams[a],o=a==="0"?"1":"0",l=t.teams[o];if(!s||!l)continue;let c=s.stats.uptime,f=l.stats.uptime;if(!c.length||!f.length)continue;let u=new Set;for(let d of c)u.add(d.time);for(let d of f)u.add(d.time);let m=Array.from(u).sort((d,h)=>d-h),p=0;for(let d=0;d<m.length;d++){let h=m[d],_=(d<m.length-1?m[d+1]:t.length)-h,y=Ue(c,h),x=Ue(f,h);y>x&&(p+=_)}s.stats.timeWithHeroAdv=p,s.stats.pctWithHeroAdv=t.length>0?p/t.length:0}let r=t.teams[0]?.stats.passiveXPRate??0,n=t.teams[1]?.stats.passiveXPRate??0,i=(r+n)/2;t.teams[0]&&(t.teams[0].stats.passiveXPDiff=i>0?r/i:0),t.teams[1]&&(t.teams[1].stats.passiveXPDiff=i>0?n/i:0)}function Ue(t,e){let r=0;for(let n of t)if(n.time<=e)r=n.heroes;else break;return r}function Et(t,e,r){return t<=1?15:t<=5?15+(t-1)*2:t<=10?23+(t-5)*3:t<=15?38+(t-10)*4:58+(t-15)*5}function Pt(t){let e=1/0,r=-1,n=1/0,i=-1;for(let s of Object.values(t.structures))s.destroyed!==void 0&&(s.name==="Fort"&&s.destroyed<e&&(e=s.destroyed,r=s.team===0?1:0),s.name==="Keep"&&s.destroyed<n&&(n=s.destroyed,i=s.team===0?1:0));r>=0&&(t.firstFort=r,t.firstFortWin=r===t.winner),i>=0&&(t.firstKeep=i,t.firstKeepWin=i===t.winner);let a=[...t.objective[0].events.map(s=>({...s,assignedTeam:0})),...t.objective[1].events.map(s=>({...s,assignedTeam:1}))].sort((s,o)=>s.loop-o.loop);a.length>0&&(t.firstObjective=a[0].assignedTeam,t.firstObjectiveWin=a[0].assignedTeam===t.winner),t.firstPickWin=t.picks.first===t.winner}function k(t){return Buffer.isBuffer(t)?t.toString("utf8"):typeof t=="string"?t:String(t??"")}var ie=class{static async analyze(e){try{let r=new N(e);await r.init();let n=r.getDetails();if(!n)throw new Error("Missing replay.details from parsed MPQ archive");let i=r.getTrackerEvents(),a=r.getInitData(),o=r.getHeader()?.m_version??{},l={m_flags:o.m_flags??0,m_major:o.m_major??0,m_minor:o.m_minor??0,m_revision:o.m_revision??0,m_build:o.m_baseBuild??r.getBuild(),m_baseBuild:o.m_baseBuild??r.getBuild()},c=n.m_playerList.find(p=>p?.m_toon)?.m_toon,f={version:l,map:k(n.m_title),isBlizzardMap:n.m_isBlizzardMap,timeLocalOffset:Number(n.m_timeLocalOffset),gameSpeed:n.m_gameSpeed,date:this.fileTimeToDate(n.m_timeUTC).toISOString(),rawDate:Number(n.m_timeUTC),length:0,winner:-1,region:c?.m_region,playerIDs:[],heroes:[],levelTimes:{0:{},1:{}},bans:{0:[],1:[]},picks:{0:[],1:[],first:0},XPBreakdown:[],takedowns:[],mercs:{captures:[],units:{}},team0Takedowns:0,team1Takedowns:0,structures:{},objective:{0:{count:0,events:[]},1:{count:0,events:[]},type:""},teams:{0:this.emptyTeam(),1:this.emptyTeam()},winningPlayers:[],levelAdvTimeline:[],firstPickWin:!1};f.objective.type=f.map||"";let u={};for(let p of n.m_playerList){if(!p?.m_toon)continue;let d=p.m_toon,h=k(d.m_programId),b=`${d.m_region}-${h}-${d.m_realm}-${d.m_id}`,_=k(p.m_hero),y=q(_)||_;u[b]={hero:y,name:k(p.m_name),uuid:d.m_id,region:d.m_region,realm:d.m_realm,ToonHandle:b,tag:0,team:p.m_teamId,win:p.m_result===1,skin:"",mount:"",banner:"",spray:"",clanTag:"",highestLeague:0,combinedRaceLevels:0,randomSeed:0,announcer:"",silenced:!1,voiceSilenced:!1,gameStats:{},awards:[],talents:{},takedowns:[],deaths:[],units:{}},f.playerIDs.push(b),f.heroes.push(y)}this.extractBattleTags(r,n,u),this.extractDraft(a,f,n),this.extractCosmetics(a,n,u);let{playerIDMap:m}=Oe(i,u,f);this.processScoreEvents(i,m,u);for(let[p,d]of Object.entries(u)){d.win&&(f.winner=d.team,f.winningPlayers.push(p));let h=f.teams[d.team.toString()];h&&(h.level=Math.max(h.level,d.gameStats.Level||0),h.ids.push(p))}return ze(f,u),{status:1,match:f,players:u}}catch(r){return console.error("ReplayAnalyzer Error:",r),{status:-2,error:String(r)}}}static emptyTeam(){return{level:0,takedowns:0,ids:[],names:[],heroes:[],tags:[],stats:{mercCaptures:0,mercUptime:0,mercUptimePercent:0,structures:{},KDA:0,PPK:0,timeTo10:0,totals:{DamageTaken:0,CreepDamage:0,Healing:0,HeroDamage:0,MinionDamage:0,SelfHealing:0,SiegeDamage:0,ProtectionGivenToAllies:0,TeamfightDamageTaken:0,TeamfightHealingDone:0,TeamfightHeroDamage:0,TimeCCdEnemyHeroes:0,TimeRootingEnemyHeroes:0,TimeSpentDead:0,TimeStunningEnemyHeroes:0,TimeSilencingEnemyHeroes:0,avgTimeSpentDead:0,timeDeadPct:0},levelAdvTime:0,maxLevelAdv:0,avgLevelAdv:0,levelAdvPct:0,uptime:[],uptimeHistogram:{},wipes:0,avgHeroesAlive:0,aces:0,timeWithHeroAdv:0,pctWithHeroAdv:0,passiveXPRate:0,passiveXPDiff:0,passiveXPGain:0}}}static extractBattleTags(e,r,n){let i=e.extractFile("replay.server.battlelobby");if(i)try{let a=new RegExp("([\\p{L}\\d]{3,24}#\\d{4,10})[z\xD8]?","gu"),s=i.toString("utf8").match(a);if(!s)return;let o=0;for(let l of r.m_playerList){if(!l?.m_toon)continue;let c=k(l.m_name);for(;o<s.length;){let u=s[o].split("#"),m=u[0],p=u[1].replace(/[zØ]/g,"");if(o++,m===c){let d=l.m_toon,h=`${d.m_region}-${k(d.m_programId)}-${d.m_realm}-${d.m_id}`;n[h]&&(n[h].tag=parseInt(p,10)||0);break}}}}catch(a){console.error("BattleTag regex error:",a)}}static extractDraft(e,r,n){if(e)try{let i=e.m_syncLobbyState;if(!i)return;let a=i.m_lobbyState,s=i.m_gameDescription;if(!a)return;s&&(r.randomValue=s.m_randomValue,r.gameOptions=s.m_gameOptions);let o=[],l=[];for(let d of n.m_playerList){if(!d?.m_toon)continue;let h=k(d.m_hero),b=q(h)||h;d.m_teamId===0?o.push(b):d.m_teamId===1&&l.push(b)}r.picks={0:o,1:l,first:0};let c,f=s?.m_gameOptions;if(f&&typeof f.m_ammId=="number"){let d=f.m_ammId;d===50001?c="Quick Match":d===50031?c="ARAM":d===50041?c="Unranked Draft":d===50051?c="Custom":d===50061?c="Hero League":d===50071?c="Team League":d===50091&&(c="Storm League")}if(!c&&typeof a.m_gameMode=="number"){let d=a.m_gameMode;d===3?c="Quick Match":d===4?c="Custom":d===5?c="Hero League":d===6?c="Team League":d===7?c="Unranked Draft":d===8&&(c="ARAM")}if(r.mode=c,typeof a.m_gameType=="number"&&(r.type=a.m_gameType),!a.m_slots)return;let m=a.m_pickedMapTag,p=0;m!==void 0&&(p=a.m_firstPickTeam??0,r.picks.first=p)}catch{}}static extractCosmetics(e,r,n){if(e)try{let i=e.m_syncLobbyState;if(!i)return;let a=i.m_lobbyState;if(!a)return;let s=a.m_slots,o=i.m_userInitialData;if(!s)return;let l=0;for(let c of r.m_playerList){if(!c?.m_toon)continue;let f=c.m_toon,u=`${f.m_region}-${k(f.m_programId)}-${f.m_realm}-${f.m_id}`,m=n[u];for(;l<s.length;){let p=s[l];l++;let d=p.m_hero;if(!(!d||Buffer.isBuffer(d)&&d.length===0)){if(m&&(m.skin=k(p.m_skin)||"",m.mount=k(p.m_mount)||"",m.announcer=k(p.m_announcerPack)||"",m.banner=k(p.m_banner)||"",m.spray=k(p.m_spray)||"",m.silenced=!!p.m_hasSilencePenalty,m.voiceSilenced=!!p.m_hasVoiceSilencePenalty,o)){let h=o.find(b=>k(b.m_name)===m.name);h&&(m.clanTag=k(h.m_clanTag),m.highestLeague=h.m_highestLeague,m.combinedRaceLevels=h.m_combinedRaceLevels,m.randomSeed=h.m_randomSeed)}break}}}}catch{}}static processScoreEvents(e,r,n){for(let i of e){if(i._event!=="NNet.Replay.Tracker.SScoreResultEvent")continue;let a=i.m_instanceList;for(let s of a){let o=k(s.m_name),l=s.m_values,c=o.startsWith("EndOfMatchAward"),f=0;for(let u of l)if(u&&u.length>0&&u[0]!==void 0){let m=f+1,p=r[m];if(p&&n[p]){let d=typeof u[0]=="object"&&u[0]!==null&&"m_value"in u[0]?u[0].m_value:u[0];d!=null&&(c?d===1&&n[p].awards.push(o):n[p].gameStats[o]=d)}f++}else u&&u.length===0&&f++}}}static fileTimeToDate(e){return new Date(Number(e)/1e4-116444736e5)}};0&&(module.exports={ReplayAnalyzer,ReplayParser});
|
|
1
|
+
"use strict";var Fe=Object.create;var Y=Object.defineProperty;var Xe=Object.getOwnPropertyDescriptor;var Ge=Object.getOwnPropertyNames;var Ke=Object.getPrototypeOf,je=Object.prototype.hasOwnProperty;var K=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),Qe=(t,e)=>{for(var r in e)Y(t,r,{get:e[r],enumerable:!0})},pe=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ge(e))!je.call(t,i)&&i!==r&&Y(t,i,{get:()=>e[i],enumerable:!(n=Xe(e,i))||n.enumerable});return t};var J=(t,e,r)=>(r=t!=null?Fe(Ke(t)):{},pe(e||!t||!t.__esModule?Y(r,"default",{value:t,enumerable:!0}):r,t)),Ve=t=>pe(Y({},"__esModule",{value:!0}),t);var _e=K((Ct,he)=>{"use strict";var be=[0,1,3,7,15,31,63,127,255],j=function(t){this.stream=t,this.bitOffset=0,this.curByte=0,this.hasByte=!1};j.prototype._ensureByte=function(){this.hasByte||(this.curByte=this.stream.readByte(),this.hasByte=!0)};j.prototype.read=function(t){for(var e=0;t>0;){this._ensureByte();var r=8-this.bitOffset;if(t>=r)e<<=r,e|=be[r]&this.curByte,this.hasByte=!1,this.bitOffset=0,t-=r;else{e<<=t;var n=r-t;e|=(this.curByte&be[t]<<n)>>n,this.bitOffset+=t,t=0}}return e};j.prototype.seek=function(t){var e=t%8,r=(t-e)/8;this.bitOffset=e,this.stream.seek(r),this.hasByte=!1};j.prototype.pi=function(){var t=new Buffer(6),e;for(e=0;e<t.length;e++)t[e]=this.read(8);return t.toString("hex")};he.exports=j});var ye=K((It,ge)=>{"use strict";var O=function(){};O.prototype.readByte=function(){throw new Error("abstract method readByte() not implemented")};O.prototype.read=function(t,e,r){for(var n=0;n<r;){var i=this.readByte();if(i<0)return n===0?-1:n;t[e++]=i,n++}return n};O.prototype.seek=function(t){throw new Error("abstract method seek() not implemented")};O.prototype.writeByte=function(t){throw new Error("abstract method readByte() not implemented")};O.prototype.write=function(t,e,r){var n;for(n=0;n<r;n++)this.writeByte(t[e++]);return r};O.prototype.flush=function(){};ge.exports=O});var ve=K((At,xe)=>{"use strict";xe.exports=(function(){var t=new Uint32Array([0,79764919,159529838,222504665,319059676,398814059,445009330,507990021,638119352,583659535,797628118,726387553,890018660,835552979,1015980042,944750013,1276238704,1221641927,1167319070,1095957929,1595256236,1540665371,1452775106,1381403509,1780037320,1859660671,1671105958,1733955601,2031960084,2111593891,1889500026,1952343757,2552477408,2632100695,2443283854,2506133561,2334638140,2414271883,2191915858,2254759653,3190512472,3135915759,3081330742,3009969537,2905550212,2850959411,2762807018,2691435357,3560074640,3505614887,3719321342,3648080713,3342211916,3287746299,3467911202,3396681109,4063920168,4143685023,4223187782,4286162673,3779000052,3858754371,3904687514,3967668269,881225847,809987520,1023691545,969234094,662832811,591600412,771767749,717299826,311336399,374308984,453813921,533576470,25881363,88864420,134795389,214552010,2023205639,2086057648,1897238633,1976864222,1804852699,1867694188,1645340341,1724971778,1587496639,1516133128,1461550545,1406951526,1302016099,1230646740,1142491917,1087903418,2896545431,2825181984,2770861561,2716262478,3215044683,3143675388,3055782693,3001194130,2326604591,2389456536,2200899649,2280525302,2578013683,2640855108,2418763421,2498394922,3769900519,3832873040,3912640137,3992402750,4088425275,4151408268,4197601365,4277358050,3334271071,3263032808,3476998961,3422541446,3585640067,3514407732,3694837229,3640369242,1762451694,1842216281,1619975040,1682949687,2047383090,2127137669,1938468188,2001449195,1325665622,1271206113,1183200824,1111960463,1543535498,1489069629,1434599652,1363369299,622672798,568075817,748617968,677256519,907627842,853037301,1067152940,995781531,51762726,131386257,177728840,240578815,269590778,349224269,429104020,491947555,4046411278,4126034873,4172115296,4234965207,3794477266,3874110821,3953728444,4016571915,3609705398,3555108353,3735388376,3664026991,3290680682,3236090077,3449943556,3378572211,3174993278,3120533705,3032266256,2961025959,2923101090,2868635157,2813903052,2742672763,2604032198,2683796849,2461293480,2524268063,2284983834,2364738477,2175806836,2238787779,1569362073,1498123566,1409854455,1355396672,1317987909,1246755826,1192025387,1137557660,2072149281,2135122070,1912620623,1992383480,1753615357,1816598090,1627664531,1707420964,295390185,358241886,404320391,483945776,43990325,106832002,186451547,266083308,932423249,861060070,1041341759,986742920,613929101,542559546,756411363,701822548,3316196985,3244833742,3425377559,3370778784,3601682597,3530312978,3744426955,3689838204,3819031489,3881883254,3928223919,4007849240,4037393693,4100235434,4180117107,4259748804,2310601993,2373574846,2151335527,2231098320,2596047829,2659030626,2470359227,2550115596,2947551409,2876312838,2788305887,2733848168,3165939309,3094707162,3040238851,2985771188]),e=function(){var r=4294967295;this.getCRC=function(){return~r>>>0},this.updateCRC=function(n){r=r<<8^t[(r>>>24^n)&255]},this.updateCRCRun=function(n,i){for(;i-- >0;)r=r<<8^t[(r>>>24^n)&255]}};return e})()});var Te=K((Mt,We)=>{We.exports={name:"seek-bzip",version:"2.0.0",contributors:["C. Scott Ananian (http://cscott.net)","Eli Skeggs","Kevin Kwok","Rob Landley (http://landley.net)"],description:"a pure-JavaScript Node.JS module for random-access decoding bzip2 data",main:"./lib/index.js",repository:{type:"git",url:"https://github.com/cscott/seek-bzip.git"},license:"MIT",bin:{"seek-bunzip":"./bin/seek-bunzip","seek-table":"./bin/seek-bzip-table"},directories:{test:"test"},dependencies:{commander:"^6.0.0"},devDependencies:{fibers:"^5.0.0",mocha:"^8.1.0"},scripts:{test:"mocha"}}});var Be=K((Ht,Re)=>{"use strict";var $e=_e(),Q=ye(),Ee=ve(),Pe=Te(),ee=20,ke=258,Se=0,qe=1,Ze=2,Ye=6,Je=50,et="314159265359",tt="177245385090",we=function(t,e){var r=t[e],n;for(n=e;n>0;n--)t[n]=t[n-1];return t[0]=r,r},g={OK:0,LAST_BLOCK:-1,NOT_BZIP_DATA:-2,UNEXPECTED_INPUT_EOF:-3,UNEXPECTED_OUTPUT_EOF:-4,DATA_ERROR:-5,OUT_OF_MEMORY:-6,OBSOLETE_INPUT:-7,END_OF_BLOCK:-8},I={};I[g.LAST_BLOCK]="Bad file checksum";I[g.NOT_BZIP_DATA]="Not bzip data";I[g.UNEXPECTED_INPUT_EOF]="Unexpected input EOF";I[g.UNEXPECTED_OUTPUT_EOF]="Unexpected output EOF";I[g.DATA_ERROR]="Data error";I[g.OUT_OF_MEMORY]="Out of memory";I[g.OBSOLETE_INPUT]="Obsolete (pre 0.9.5) bzip format not supported.";var T=function(t,e){var r=I[t]||"unknown error";e&&(r+=": "+e);var n=new TypeError(r);throw n.errorCode=t,n},S=function(t,e){this.writePos=this.writeCurrent=this.writeCount=0,this._start_bunzip(t,e)};S.prototype._init_block=function(){var t=this._get_next_block();return t?(this.blockCRC=new Ee,!0):(this.writeCount=-1,!1)};S.prototype._start_bunzip=function(t,e){var r=new Buffer(4);(t.read(r,0,4)!==4||String.fromCharCode(r[0],r[1],r[2])!=="BZh")&&T(g.NOT_BZIP_DATA,"bad magic");var n=r[3]-48;(n<1||n>9)&&T(g.NOT_BZIP_DATA,"level out of range"),this.reader=new $e(t),this.dbufSize=1e5*n,this.nextoutput=0,this.outputStream=e,this.streamCRC=0};S.prototype._get_next_block=function(){var t,e,r,n=this.reader,i=n.pi();if(i===tt)return!1;i!==et&&T(g.NOT_BZIP_DATA),this.targetBlockCRC=n.read(32)>>>0,this.streamCRC=(this.targetBlockCRC^(this.streamCRC<<1|this.streamCRC>>>31))>>>0,n.read(1)&&T(g.OBSOLETE_INPUT);var a=n.read(24);a>this.dbufSize&&T(g.DATA_ERROR,"initial position out of bounds");var s=n.read(16),o=new Buffer(256),c=0;for(t=0;t<16;t++)if(s&1<<15-t){var l=t*16;for(r=n.read(16),e=0;e<16;e++)r&1<<15-e&&(o[c++]=l+e)}var f=n.read(3);(f<Ze||f>Ye)&&T(g.DATA_ERROR);var u=n.read(15);u===0&&T(g.DATA_ERROR);var m=new Buffer(256);for(t=0;t<f;t++)m[t]=t;var b=new Buffer(u);for(t=0;t<u;t++){for(e=0;n.read(1);e++)e>=f&&T(g.DATA_ERROR);b[t]=we(m,e)}var d=c+2,h=[],p;for(e=0;e<f;e++){var _=new Buffer(d),y=new Uint16Array(ee+1);for(s=n.read(5),t=0;t<d;t++){for(;(s<1||s>ee)&&T(g.DATA_ERROR),!!n.read(1);)n.read(1)?s--:s++;_[t]=s}var x,P;for(x=P=_[0],t=1;t<d;t++)_[t]>P?P=_[t]:_[t]<x&&(x=_[t]);p={},h.push(p),p.permute=new Uint16Array(ke),p.limit=new Uint32Array(ee+2),p.base=new Uint32Array(ee+1),p.minLen=x,p.maxLen=P;var H=0;for(t=x;t<=P;t++)for(y[t]=p.limit[t]=0,s=0;s<d;s++)_[s]===t&&(p.permute[H++]=s);for(t=0;t<d;t++)y[_[t]]++;for(H=s=0,t=x;t<P;t++)H+=y[t],p.limit[t]=H-1,H<<=1,s+=y[t],p.base[t+1]=H-s;p.limit[P+1]=Number.MAX_VALUE,p.limit[P]=H+y[P]-1,p.base[x]=0}var N=new Uint32Array(256);for(t=0;t<256;t++)m[t]=t;var L=0,C=0,de=0,E,X=this.dbuf=new Uint32Array(this.dbufSize);for(d=0;;){for(d--||(d=Je-1,de>=u&&T(g.DATA_ERROR),p=h[b[de++]]),t=p.minLen,e=n.read(t);t>p.maxLen&&T(g.DATA_ERROR),!(e<=p.limit[t]);t++)e=e<<1|n.read(1);e-=p.base[t],(e<0||e>=ke)&&T(g.DATA_ERROR);var G=p.permute[e];if(G===Se||G===qe){L||(L=1,s=0),G===Se?s+=L:s+=2*L,L<<=1;continue}if(L)for(L=0,C+s>this.dbufSize&&T(g.DATA_ERROR),E=o[m[0]],N[E]+=s;s--;)X[C++]=E;if(G>c)break;C>=this.dbufSize&&T(g.DATA_ERROR),t=G-1,E=we(m,t),E=o[E],N[E]++,X[C++]=E}for((a<0||a>=C)&&T(g.DATA_ERROR),e=0,t=0;t<256;t++)r=e+N[t],N[t]=e,e=r;for(t=0;t<C;t++)E=X[t]&255,X[N[E]]|=t<<8,N[E]++;var Z=0,ue=0,me=0;return C&&(Z=X[a],ue=Z&255,Z>>=8,me=-1),this.writePos=Z,this.writeCurrent=ue,this.writeCount=C,this.writeRun=me,!0};S.prototype._read_bunzip=function(t,e){var r,n,i;if(this.writeCount<0)return 0;for(var a=0,s=this.dbuf,o=this.writePos,c=this.writeCurrent,l=this.writeCount,f=this.outputsize,u=this.writeRun;l;){for(l--,n=c,o=s[o],c=o&255,o>>=8,u++===3?(r=c,i=n,c=-1):(r=1,i=c),this.blockCRC.updateCRCRun(i,r);r--;)this.outputStream.writeByte(i),this.nextoutput++;c!=n&&(u=0)}return this.writeCount=l,this.blockCRC.getCRC()!==this.targetBlockCRC&&T(g.DATA_ERROR,"Bad block CRC (got "+this.blockCRC.getCRC().toString(16)+" expected "+this.targetBlockCRC.toString(16)+")"),this.nextoutput};var oe=function(t){if("readByte"in t)return t;var e=new Q;return e.pos=0,e.readByte=function(){return t[this.pos++]},e.seek=function(r){this.pos=r},e.eof=function(){return this.pos>=t.length},e},De=function(t){var e=new Q,r=!0;if(t)if(typeof t=="number")e.buffer=new Buffer(t),r=!1;else{if("writeByte"in t)return t;e.buffer=t,r=!1}else e.buffer=new Buffer(16384);return e.pos=0,e.writeByte=function(n){if(r&&this.pos>=this.buffer.length){var i=new Buffer(this.buffer.length*2);this.buffer.copy(i),this.buffer=i}this.buffer[this.pos++]=n},e.getBuffer=function(){if(this.pos!==this.buffer.length){if(!r)throw new TypeError("outputsize does not match decoded input");var n=new Buffer(this.pos);this.buffer.copy(n,0,0,this.pos),this.buffer=n}return this.buffer},e._coerced=!0,e};S.Err=g;S.decode=function(t,e,r){for(var n=oe(t),i=De(e),a=new S(n,i);!("eof"in n&&n.eof());)if(a._init_block())a._read_bunzip();else{var s=a.reader.read(32)>>>0;if(s!==a.streamCRC&&T(g.DATA_ERROR,"Bad stream CRC (got "+a.streamCRC.toString(16)+" expected "+s.toString(16)+")"),r&&"eof"in n&&!n.eof())a._start_bunzip(n,i);else break}if("getBuffer"in i)return i.getBuffer()};S.decodeBlock=function(t,e,r){var n=oe(t),i=De(r),a=new S(n,i);a.reader.seek(e);var s=a._get_next_block();if(s&&(a.blockCRC=new Ee,a.writeCopies=0,a._read_bunzip()),"getBuffer"in i)return i.getBuffer()};S.table=function(t,e,r){var n=new Q;n.delegate=oe(t),n.pos=0,n.readByte=function(){return this.pos++,this.delegate.readByte()},n.delegate.eof&&(n.eof=n.delegate.eof.bind(n.delegate));var i=new Q;i.pos=0,i.writeByte=function(){this.pos++};for(var a=new S(n,i),s=a.dbufSize;!("eof"in n&&n.eof());){var o=n.pos*8+a.reader.bitOffset;if(a.reader.hasByte&&(o-=8),a._init_block()){var c=i.pos;a._read_bunzip(),e(o,i.pos-c)}else{var l=a.reader.read(32);if(r&&"eof"in n&&!n.eof())a._start_bunzip(n,i),console.assert(a.dbufSize===s,"shouldn't change block size within multistream file");else break}}};S.Stream=Q;S.version=Pe.version;S.license=Pe.license;Re.exports=S});var Rt={};Qe(Rt,{LiveStreamParser:()=>ie,ReplayAnalyzer:()=>se,ReplayParser:()=>M});module.exports=Ve(Rt);var Ae=J(require("fs")),V=J(require("zlib")),rt=Be(),Ce=512,nt=65536,it=16777216,at=67108864,st=2147483648,ot={TABLE_OFFSET:0,HASH_A:1,HASH_B:2,TABLE:3};function ct(){let t=1048577,e=new Uint32Array(256*5);for(let r=0;r<256;r++){let n=r;for(let i=0;i<5;i++){t=(t*125+3)%2796203;let a=(t&65535)<<16;t=(t*125+3)%2796203;let s=t&65535;e[n]=(a|s)>>>0,n+=256}}return e}var Ie=ct(),te=class{file;header;hashTable;blockTable;files;constructor(e,r=!0){if(Buffer.isBuffer(e)?this.file=e:this.file=Ae.readFileSync(e),this.header=this.readHeader(),this.hashTable=this.readTable("hash"),this.blockTable=this.readTable("block"),r){let n=this.readFile("(listfile)");n?this.files=n.toString("utf8").trim().split(`\r
|
|
2
|
+
`):this.files=null}else this.files=null}readHeader(){let e=this.file.toString("utf8",0,4),r;if(e==="MPQ")r=this.readMPQHeader(),r.offset=0;else if(e==="MPQ\x1B"){let n=this.readMPQUserDataHeader();r=this.readMPQHeader(n.mpqHeaderOffset),r.offset=n.mpqHeaderOffset,r.userDataHeader=n}else throw new Error("Invalid MPQ file header");return r}readMPQHeader(e=0){let r=this.file.subarray(e,e+32),n={magic:r.toString("utf8",0,4),headerSize:r.readUInt32LE(4),archiveSize:r.readUInt32LE(8),formatVersion:r.readUInt16LE(12),sectorSizeShift:r.readUInt16LE(14),hashTableOffset:r.readUInt32LE(16),blockTableOffset:r.readUInt32LE(20),hashTableEntries:r.readUInt32LE(24),blockTableEntries:r.readUInt32LE(28)};if(n.formatVersion===1){let i=this.file.subarray(e+32,e+32+12);n.extendedBlockTableOffset=i.readUInt32LE(0)+i.readUInt32LE(4)*4294967296,n.hashTableOffsetHigh=i.readInt8(8),n.blockTableOffsetHigh=i.readInt8(10)}return n}readMPQUserDataHeader(){let e=this.file.subarray(0,16),r={magic:e.toString("utf8",0,4),userDataSize:e.readUInt32LE(4),mpqHeaderOffset:e.readUInt32LE(8),userDataHeaderSize:e.readUInt32LE(12)};return r.content=this.file.subarray(16,16+r.userDataHeaderSize),r}readTable(e){let r=e==="hash"?"hashTableOffset":"blockTableOffset",n=e==="hash"?"hashTableEntries":"blockTableEntries",i=this.header[r],a=this.header[n];if(i==null||a==null)throw new Error("Missing "+e+" offset or entries");let s=this.hash("("+e+" table)","TABLE"),o=this.file.subarray(i+(this.header.offset||0),i+(this.header.offset||0)+a*16);o=this.decrypt(o,s);let c=[];for(let l=0;l<a;l++){let f=o.subarray(l*16,l*16+16);e==="hash"?c.push({hashA:f.readUInt32LE(0),hashB:f.readUInt32LE(4),locale:f.readUInt16LE(8),platform:f.readUInt16LE(10),blockTableIndex:f.readUInt32LE(12)}):c.push({offset:f.readUInt32LE(0),archivedSize:f.readUInt32LE(4),size:f.readUInt32LE(8),flags:f.readUInt32LE(12)})}return c}getHashTableEntry(e){let r=this.hash(e,"HASH_A"),n=this.hash(e,"HASH_B");for(let i of this.hashTable)if(i.hashA===r&&i.hashB===n)return i}readFile(e,r=!1){function n(c){let l=c[0];if(l===0)return c;if(l===2)return V.inflateSync(c.subarray(1));if(l===16)return rt.decode(c.subarray(1));try{return V.inflateSync(c.subarray(1))}catch{return V.inflateRawSync(c.subarray(1))}}let i=this.getHashTableEntry(e);if(!i)return null;let a=this.blockTable[i.blockTableIndex];if(!a||!(a.flags&st))return null;if(a.archivedSize===0)return Buffer.alloc(0);let s=a.offset+(this.header.offset||0),o=this.file.subarray(s,s+a.archivedSize);if(a.flags&nt)throw new Error("Encryption is not supported");if(a.flags&it)a.flags&Ce&&(r||a.size>a.archivedSize)&&(o=n(o));else{let c=512<<this.header.sectorSizeShift,l=Math.trunc(a.size/c)+1,f=!1;a.flags&at&&(f=!0,l+=1);let u=[];for(let h=0;h<l+1;h++)u.push(o.readUInt32LE(4*h));let m=u.length-(f?2:1),b=[],d=a.size;for(let h=0;h<m;h++){let p=o.subarray(u[h],u[h+1]);a.flags&Ce&&(r||d>p.length)&&(p=n(p)),d-=p.length,b.push(p)}o=Buffer.concat(b)}return o}hash(e,r){let n=2146271213,i=4008636142;for(let a=0;a<e.length;a++){let s=e.toUpperCase().charCodeAt(a);n=(Ie[(ot[r]<<8)+s]^n+i)>>>0,i=s+n+i+(i<<5)+3>>>0}return n}decrypt(e,r){let n=r>>>0,i=4008636142,a=Buffer.alloc(e.length),s=e.length/4;for(let o=0;o<s;o++){i=i+Ie[1024+(n&255)]>>>0;let c=e.readUInt32LE(o*4);c=(c^n+i)>>>0,n=((~n<<21)+286331153|n>>>11)>>>0,i=c+i+(i<<5)+3>>>0,a.writeUInt32LE(c,o*4)}return a}};var W=class extends Error{constructor(e="Truncated Buffer"){super(e),this.name="TruncatedError"}},U=class extends Error{constructor(e="Corrupted Buffer"){super(e),this.name="CorruptedError"}},$=class{_data;_used;_next;_nextbits;_bigendian;constructor(e,r="big"){this._data=e,this._used=0,this._next=0,this._nextbits=0,this._bigendian=r==="big"}done(){return this._nextbits===0&&this._used>=this._data.length}used_bits(){return this._used*8-this._nextbits}byte_align(){this._nextbits=0}read_aligned_bytes(e){if(this.byte_align(),this._used+e>this._data.length)throw new W;let r=this._data.subarray(this._used,this._used+e);return this._used+=e,r}read_bits(e){let r=0,n=0;for(;n!==e;){if(this._nextbits===0){if(this.done())throw new W;this._next=this._data[this._used],this._used+=1,this._nextbits=8}let i=Math.min(e-n,this._nextbits),a=this._next&(1<<i)-1;this._bigendian?r+=a*Math.pow(2,e-n-i):r+=a*Math.pow(2,n),this._next>>=i,this._nextbits-=i,n+=i}return r}read_bits_bigint(e){let r=0n,n=0;for(;n!==e;){if(this._nextbits===0){if(this.done())throw new W;this._next=this._data[this._used],this._used+=1,this._nextbits=8}let i=Math.min(e-n,this._nextbits),a=BigInt(this._next&(1<<i)-1);this._bigendian?r|=a<<BigInt(e-n-i):r|=a<<BigInt(n),this._next>>=i,this._nextbits-=i,n+=i}return r}read_unaligned_bytes(e){let r=Buffer.alloc(e);for(let n=0;n<e;n++)r[n]=this.read_bits(8);return r}};var z=class{_buffer;_typeinfos;constructor(e,r){this._buffer=new $(e),this._typeinfos=r}instance(e){if(e>=this._typeinfos.length)throw new U(`Invalid typeid ${e}`);let r=this._typeinfos[e],n=r[0],i=r[1]||[],a=this[n];if(typeof a!="function")throw new Error(`Decoder method ${n} not implemented`);return a.apply(this,i)}byte_align(){this._buffer.byte_align()}done(){return this._buffer.done()}used_bits(){return this._buffer.used_bits()}_array(e,r){let n=this._int(e),i=new Array(n);for(let a=0;a<n;a++)i[a]=this.instance(r);return i}_bitarray(e){let r=this._int(e);return[r,this._buffer.read_bits(r)]}_blob(e){let r=this._int(e);return this._buffer.read_aligned_bytes(r)}_bool(){return this._int([0,1])!==0}_choice(e,r){let n=this._int(e);if(!(n in r))throw new U(`Choice tag ${n} not found`);let i=r[n];return{[i[0]]:this.instance(i[1])}}_fourcc(){let e=this._buffer.read_bits(32),r=Buffer.alloc(4);return r.writeUInt32BE(e,0),r.toString("ascii")}_int(e){return e[0]+this._buffer.read_bits(e[1])}_null(){return null}_optional(e){return this._bool()?this.instance(e):null}_real32(){return this._buffer.read_unaligned_bytes(4).readFloatBE(0)}_real64(){return this._buffer.read_unaligned_bytes(8).readDoubleBE(0)}_struct(e){let r={};for(let n of e)if(n[0]==="__parent"){let i=this.instance(n[1]);if(typeof i=="object"&&i!==null&&!Array.isArray(i)&&!Buffer.isBuffer(i))r={...r,...i};else{if(e.length===1)return i;r[n[0]]=i}}else r[n[0]]=this.instance(n[1]);return r}},D=class{_buffer;_typeinfos;constructor(e,r){this._buffer=new $(e),this._typeinfos=r}instance(e){if(e>=this._typeinfos.length)throw new U(`Invalid typeid ${e}`);let r=this._typeinfos[e],n=r[0],i=r[1]||[],a=this[n];if(typeof a!="function")throw new Error(`Decoder method ${n} not implemented`);return a.apply(this,i)}byte_align(){this._buffer.byte_align()}done(){return this._buffer.done()}used_bits(){return this._buffer.used_bits()}_expect_skip(e){if(this._buffer.read_bits(8)!==e)throw new U(`Expected skip ${e}`)}_vint(){let e=this._buffer.read_bits(8),r=(e&1)!==0,n=BigInt(e>>1&63),i=6n;for(;(e&128)!==0;)e=this._buffer.read_bits(8),n|=BigInt(e&127)<<i,i+=7n;let a=r?-n:n;return a>=BigInt(Number.MIN_SAFE_INTEGER)&&a<=BigInt(Number.MAX_SAFE_INTEGER)?Number(a):a}_array(e,r){this._expect_skip(0);let n=Number(this._vint()),i=new Array(n);for(let a=0;a<n;a++)i[a]=this.instance(r);return i}_bitarray(e){this._expect_skip(1);let r=Number(this._vint());return[r,this._buffer.read_aligned_bytes(Math.floor((r+7)/8))]}_blob(e){this._expect_skip(2);let r=Number(this._vint());return this._buffer.read_aligned_bytes(r)}_bool(){return this._expect_skip(6),this._buffer.read_bits(8)!==0}_choice(e,r){this._expect_skip(3);let n=Number(this._vint());if(!(n in r))return this._skip_instance(),{};let i=r[n];return{[i[0]]:this.instance(i[1])}}_fourcc(){return this._expect_skip(7),this._buffer.read_aligned_bytes(4)}_int(e){return this._expect_skip(9),Number(this._vint())}_null(){return null}_optional(e){return this._expect_skip(4),this._buffer.read_bits(8)!==0?this.instance(e):null}_real32(){return this._expect_skip(7),this._buffer.read_aligned_bytes(4).readFloatBE(0)}_real64(){return this._expect_skip(8),this._buffer.read_aligned_bytes(8).readDoubleBE(0)}_struct(e){this._expect_skip(5);let r={},n=Number(this._vint());for(let i=0;i<n;i++){let a=Number(this._vint()),s=e.find(o=>o[2]===a);if(s)if(s[0]==="__parent"){let o=this.instance(s[1]);typeof o=="object"&&o!==null&&!Array.isArray(o)&&!Buffer.isBuffer(o)?r={...r,...o}:e.length===1?r=o:r[s[0]]=o}else r[s[0]]=this.instance(s[1]);else this._skip_instance()}return r}_skip_instance(){let e=this._buffer.read_bits(8);if(e===0){let r=Number(this._vint());for(let n=0;n<r;n++)this._skip_instance()}else if(e===1){let r=Number(this._vint());this._buffer.read_aligned_bytes(Math.floor((r+7)/8))}else if(e===2){let r=Number(this._vint());this._buffer.read_aligned_bytes(r)}else if(e===3)this._vint(),this._skip_instance();else if(e===4)this._buffer.read_bits(8)!==0&&this._skip_instance();else if(e===5){let r=Number(this._vint());for(let n=0;n<r;n++)this._vint(),this._skip_instance()}else e===6?this._buffer.read_aligned_bytes(1):e===7?this._buffer.read_aligned_bytes(4):e===8?this._buffer.read_aligned_bytes(8):e===9&&this._vint()}};var F=J(require("fs")),A=J(require("path"));function lt(){let t=[];try{t.push(A.default.resolve(__dirname,"..","protocols")),t.push(A.default.resolve(__dirname,"..","..","protocols"))}catch{}t.push(A.default.resolve(process.cwd(),"protocols"));let e=process.cwd();for(;e!==A.default.dirname(e);){let r=A.default.join(e,"node_modules","@astefanski","storm-parser","protocols");t.push(r),e=A.default.dirname(e)}for(let r of t)if(F.default.existsSync(r)&&F.default.readdirSync(r).some(n=>n.endsWith(".json")))return r;throw new Error(`@astefanski/storm-parser: Protocols directory not found. Did postinstall run? Try: npx tsx node_modules/@astefanski/storm-parser/scripts/postinstall.ts
|
|
3
|
+
Searched: `+t.join(", "))}var ce=new Map,le=null;function Me(){return le||(le=lt()),le}function re(t){if(ce.has(t))return ce.get(t);let e=Me(),r=A.default.join(e,`protocol${t}.json`);if(!F.default.existsSync(r))return null;let n=JSON.parse(F.default.readFileSync(r,"utf-8"));return ce.set(t,n),n}function ne(){let t=Me();return F.default.readdirSync(t).filter(e=>/^protocol\d+\.json$/.test(e)).map(e=>parseInt(e.match(/\d+/)[0],10)).sort((e,r)=>e-r)}var M=class{mpq;header;build=0;protocol;baseProtocol;constructor(e){e&&(this.mpq=new te(e,!1))}init(){let e=re(29406);if(!e)throw new Error("Base protocol29406 not found. Did postinstall run? Try: npx tsx node_modules/@astefanski/storm-parser/scripts/postinstall.ts");this.baseProtocol=e;let r=this.mpq.header.userDataHeader;if(!r||!r.content)throw new Error("Replay does not have a user data header");let n=new D(r.content,this.baseProtocol.typeinfos);this.header=n.instance(this.baseProtocol.replay_header_typeid),this.build=this.header.m_version.m_baseBuild,this.protocol=this.loadProtocolForBuild(this.build)}loadProtocolForBuild(e){let r=re(e);if(!r){let n=ne(),i=n[0];for(let a of n)a<=e&&a>i&&(i=a);r=re(i)}if(!r)throw new Error(`No protocol found for build ${e}`);return r}*decodeEventStream(e,r,n,i){if(!this.protocol)throw new Error("Protocol not loaded");let a=0;for(;!e.done();){let s=e.used_bits(),o=e.instance(this.protocol.svaruint32_typeid),c=Object.keys(o)[0],l=o[c];a+=l;let f=i?e.instance(this.protocol.replay_userid_typeid):void 0,u=Number(e.instance(r)),m=n[u];if(!m)throw new Error(`Unknown eventid(${u})`);let b=m[0],d=m[1],h=e.instance(b);h._event=d,h._eventid=u,h._gameloop=a,i&&(h._userid=f),e.byte_align(),h._bits=e.used_bits()-s,yield h}}getDetails(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.details");return e?new D(e,this.protocol.typeinfos).instance(this.protocol.game_details_typeid):null}getInitData(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.initData");return e?new z(e,this.protocol.typeinfos).instance(this.protocol.replay_initdata_typeid):null}getTrackerEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.tracker.events");if(!e)return[];let r=new D(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(r,this.protocol.tracker_eventid_typeid,this.protocol.tracker_event_types,!1))}getGameEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.game.events");if(!e)return[];let r=new z(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(r,this.protocol.game_eventid_typeid,this.protocol.game_event_types,!0))}getAttributeEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.attributes.events");return e?new D(e,this.protocol.typeinfos).instance(this.protocol.replay_attributes_events_typeid):null}extractFile(e){return this.mpq.readFile(e)}getHeader(){return this.header}getBuild(){return this.build}};var ie=class extends M{constructor(e){super();let r=e;if(!r){let n=ne();r=n[n.length-1]}this.protocol=this.loadProtocolForBuild(r)}parseTracker(e){if(!this.protocol)return[];try{let r=new D(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(r,this.protocol.tracker_eventid_typeid,this.protocol.tracker_event_types,!1))}catch(r){return console.error("[LiveStreamParser] Failed to parse tracker events",r),[]}}parseGame(e){if(!this.protocol)return[];try{let r=new z(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(r,this.protocol.game_eventid_typeid,this.protocol.game_event_types,!0))}catch(r){return console.error("[LiveStreamParser] Failed to parse game events",r),[]}}};var He=["Abathur","Alarak","Alexstrasza","Ana","Anduin","Anubarak","Artanis","Arthas","Auriel","Azmodan","Blaze","Brightwing","Cassia","Chen","Cho","Chromie","Deathwing","Deckard","Dehaka","Diablo","DVa","ETC","Falstad","Fenix","Gall","Garrosh","Gazlowe","Genji","Greymane","Guldan","Hanzo","Hogger","Illidan","Imperius","Jaina","Johanna","Junkrat","Kaelthas","KelThuzad","Kerrigan","Kharazim","Leoric","LiLi","LiMing","LtMorales","Lunara","Maiev","Malfurion","MalGanis","Malthael","Medivh","Mei","Mephisto","Muradin","Murky","Nazeebo","Nova","Orphea","Probius","Qhira","Ragnaros","Raynor","Rehgar","Rexxar","Samuro","SgtHammer","Sonya","Stitches","Stukov","Sylvanas","Tassadar","TheButcher","TheLostVikings","Thrall","Tracer","Tychus","Tyrael","Tyrande","Uther","Valeera","Valla","Varian","Whitemane","Xul","Yrel","Zagara","Zarya","Zeratul","Zuljin"],Le={FaerieDragon:"Brightwing",Amazon:"Cassia",Barbarian:"Sonya",Crusader:"Johanna",DemonHunter:"Valla",WitchDoctor:"Nazeebo",Monk:"Kharazim",Wizard:"LiMing",Tinker:"Gazlowe",Medic:"LtMorales",L90ETC:"ETC",Butcher:"TheButcher",LostVikings:"TheLostVikings",Necromancer:"Xul",Dryad:"Lunara",Shapeshifter:"Greymane",ChoGall:"Cho"};function q(t){if(!t)return null;if(He.includes(t))return t;if(Le[t])return Le[t];let e=t.replace(/[^a-zA-Z0-9]/g,"").toLowerCase(),r=He.find(n=>n.toLowerCase()===e);return r||null}var Oe={TownCannonTowerL2:"Fort Tower",TownCannonTowerL3:"Keep Tower",TownTownHallL2:"Fort",TownTownHallL3:"Keep",TownMoonwellL2:"Fort Well",TownMoonwellL3:"Keep Well"},ft={MercLanerMeleeKnight:"Bruiser Camp",MercLanerRangedMage:"Bruiser Camp",MercLanerSiegeGiant:"Siege Camp",MercLanerRangedMinion:"Siege Camp"};function B(t){return Buffer.isBuffer(t)?t.toString("utf8"):typeof t=="string"?t:String(t??"")}function v(t,e){if(!t)return;let r=t.find(n=>B(n.m_key)===e);return r!==void 0?r.m_value:void 0}function ae(t,e){if(!t)return;let r=t.find(n=>B(n.m_key)===e);return r!==void 0?B(r.m_value):void 0}function w(t,e){if(!t)return;let r=t.find(n=>B(n.m_key)===e);return r!==void 0?r.m_value:void 0}function fe(t,e){return`${t}-${e}`}function R(t,e){return(t-e)/16}function Ue(t,e,r){let n={playerIDMap:{},loopGameStart:0,loopGameEnd:0,unitIndex:{},heroUnits:{},heroLives:{}};r.bans||(r.bans={0:[],1:[]}),r.levelTimes={0:{},1:{}},r.takedowns=[],r.structures={},r.XPBreakdown=[],r.mercs={captures:[],units:{}},r.objective={0:{count:0,events:[]},1:{count:0,events:[]},type:r.map||""};for(let i of t)switch(n.loopGameEnd=Math.max(n.loopGameEnd,i._gameloop),i._event){case"NNet.Replay.Tracker.SStatGameEvent":dt(i,n,e,r);break;case"NNet.Replay.Tracker.SHeroBannedEvent":if(i.m_hero){let a=B(i.m_hero),s=q(a);if(!s)break;let o=i.m_controllingTeam===2?1:0;if(r.bans&&r.bans[o]){let c=r.bans[o].length+1,l=r.bans[0].length+r.bans[1].length+1;r.bans[o].push({hero:s,order:c,absolute:l})}}break;case"NNet.Replay.Tracker.SUnitBornEvent":pt(i,n,r);break;case"NNet.Replay.Tracker.SUnitDiedEvent":bt(i,n,r);break;case"NNet.Replay.Tracker.SUnitOwnerChangeEvent":ht(i,n);break}return r.loopGameStart=n.loopGameStart,r.loopLength=n.loopGameEnd,r.length=(n.loopGameEnd-n.loopGameStart)/16,_t(n,e),{playerIDMap:n.playerIDMap}}function dt(t,e,r,n){let i=B(t.m_eventName),a=t.m_intData,s=t.m_stringData,o=t.m_fixedData;switch(i){case"PlayerInit":{let c=v(a,"PlayerID"),l=ae(s,"ToonHandle");c!==void 0&&l&&r[l]&&(e.playerIDMap[c]=l);break}case"GatesOpen":e.loopGameStart=t._gameloop;break;case"LevelUp":{let c=v(a,"PlayerID"),l=v(a,"Level");if(c===void 0||l===void 0)break;let f;if(c>=1&&c<=5)f="0";else if(c>=6&&c<=10)f="1";else break;n.levelTimes[f][String(l)]||(n.levelTimes[f][String(l)]={loop:t._gameloop,level:l,team:f,time:R(t._gameloop,e.loopGameStart)});break}case"TalentChosen":{let c=v(a,"PlayerID"),l=ae(s,"PurchaseName");if(c===void 0||!l||l==="Win"||l==="Loss"||l.startsWith("Hero"))break;let f=n.map?.replace(/\s+/g,"")||"";if(l===f)break;let u=e.playerIDMap[c];if(!u||!r[u])break;let m=["Tier1Choice","Tier2Choice","Tier3Choice","Tier4Choice","Tier5Choice","Tier6Choice","Tier7Choice"];for(let b of m)if(!r[u].talents[b]){r[u].talents[b]=l;break}break}case"PlayerDeath":{let c=v(a,"PlayerID"),l=v(a,"KillingPlayer"),f=w(o,"PositionX")??0,u=w(o,"PositionY")??0;if(c===void 0)break;let m=e.playerIDMap[c];if(!m)break;let b={player:m,hero:r[m]?.hero||""},d=[],h=r[m]?.team;if(l&&l>0){let _=e.playerIDMap[l];_&&r[_]&&d.push({player:_,hero:r[_].hero})}for(let[_,y]of Object.entries(e.playerIDMap)){let x=r[y];!x||x.team===h||parseInt(_)===l||d.push({player:y,hero:x.hero})}let p={loop:t._gameloop,time:R(t._gameloop,e.loopGameStart),x:f,y:u,killers:d,victim:b};n.takedowns.push(p),r[m]&&r[m].deaths.push(p);for(let _ of d)r[_.player]&&r[_.player].takedowns.push(p);break}case"PeriodicXPBreakdown":{let c=v(a,"Team");if(c===void 0)break;let l={GameTime:v(a,"GameTime")??0,PreviousGameTime:v(a,"PreviousGameTime")??0,MinionXP:w(o,"MinionXP")??0,CreepXP:w(o,"CreepXP")??0,StructureXP:w(o,"StructureXP")??0,HeroXP:w(o,"HeroXP")??0,TrickleXP:w(o,"TrickleXP")??0};n.XPBreakdown.push({loop:t._gameloop,time:R(t._gameloop,e.loopGameStart),team:c,teamLevel:v(a,"TeamLevel")??0,breakdown:l,theoreticalMinionXP:v(a,"TheoreticalMinionXP")??0});break}case"EndOfGameXPBreakdown":{let c=v(a,"Team");if(c===void 0)break;n.XPBreakdown.push({loop:t._gameloop,time:R(t._gameloop,e.loopGameStart),team:c,theoreticalMinionXP:v(a,"TheoreticalMinionXP")??0,breakdown:{GameTime:0,PreviousGameTime:0,MinionXP:w(o,"MinionXP")??0,CreepXP:w(o,"CreepXP")??0,StructureXP:w(o,"StructureXP")??0,HeroXP:w(o,"HeroXP")??0,TrickleXP:w(o,"TrickleXP")??0}});break}case"JungleCampCapture":{let c=v(a,"CampTeam")??v(a,"Team")??0;n.mercs.captures.push({loop:t._gameloop,type:ae(s,"CampType")??ae(s,"Result")??"Unknown Camp",team:c,time:R(t._gameloop,e.loopGameStart)});break}case"EndOfGameTalentChoices":{let c=v(a,"PlayerID");if(c===void 0)break;let l=e.playerIDMap[c];if(!l||!r[l])break;let f={};if(s)for(let u of s){let m=B(u.m_key),b=B(u.m_value);m==="Tier 1 Choice"&&b?f.Tier1Choice=b:m==="Tier 2 Choice"&&b?f.Tier2Choice=b:m==="Tier 3 Choice"&&b?f.Tier3Choice=b:m==="Tier 4 Choice"&&b?f.Tier4Choice=b:m==="Tier 5 Choice"&&b?f.Tier5Choice=b:m==="Tier 6 Choice"&&b?f.Tier6Choice=b:m==="Tier 7 Choice"&&b&&(f.Tier7Choice=b)}r[l].talents=f;break}default:mt(i,t,e,n,a,o);break}}var ut=new Set(["SoulEatersSpawned","TributeCollected","RavenCurseActivated","AltarCaptured","SkyTempleShotsFired","DragonKnightActivated","GardenTerrorActivated","InfernalShrineCaptured","PunisherKilled","VolskayaVehicleCapture","BraxisWaveStart","ImmortalDefeated","NukeExploded","PayloadDelivered","AlteracCavalryCharge","AlteracCavalry"]);function mt(t,e,r,n,i,a){if(!ut.has(t)||!i)return;let s=v(i,"Team")??v(i,"Event")??0,o=s===0||s===1?s:0,c={team:s,loop:e._gameloop,time:R(e._gameloop,r.loopGameStart),score:v(i,"Score"),duration:w(a,"Duration")};n.objective[o].events.push(c),n.objective[o].count=n.objective[o].events.length}function pt(t,e,r){let n=B(t.m_unitTypeName),i=t.m_unitTagIndex,a=t.m_unitTagRecycle,s=fe(i,a),o=t.m_controlPlayerId??t.m_upkeepPlayerId,c=t.m_x??0,l=t.m_y??0,f;if(o>=1&&o<=5?f=0:o>=6&&o<=10?f=1:o===11?f=0:o===12?f=1:f=o<=5?0:1,e.unitIndex[s]={type:n,playerId:o,team:f,x:c,y:l,bornLoop:t._gameloop},n.startsWith("Town")&&Oe[n]&&(r.structures[s]={type:n,name:Oe[n],tag:i,rtag:a,x:c,y:l,team:f}),n.startsWith("Hero")&&o>=1&&o<=10){e.heroUnits[s]=o,e.heroLives[o]||(e.heroLives[o]=[]);let u=R(t._gameloop,e.loopGameStart);e.heroLives[o].push({born:u,locations:[{x:c,y:l,time:u}],duration:0})}if(ft[n]){let m=r.mercs.captures[r.mercs.captures.length-1]?.loop??t._gameloop;r.mercs.units[s]={loop:m,team:f,type:n,locations:[{x:c,y:l}],time:R(m,e.loopGameStart),duration:0}}}function bt(t,e,r){let n=fe(t.m_unitTagIndex,t.m_unitTagRecycle),i=R(t._gameloop,e.loopGameStart);r.structures[n]&&(r.structures[n].destroyedLoop=t._gameloop,r.structures[n].destroyed=i),r.mercs.units[n]&&(r.mercs.units[n].duration=i-r.mercs.units[n].time);let a=e.heroUnits[n];if(a!==void 0&&e.heroLives[a]){let s=e.heroLives[a],o=s[s.length-1];o&&o.died===void 0&&(o.died=i,o.duration=i-o.born)}}function ht(t,e){let r=fe(t.m_unitTagIndex,t.m_unitTagRecycle),n=t.m_controlPlayerId??t.m_upkeepPlayerId;e.unitIndex[r]&&(e.unitIndex[r].playerId=n,n>=1&&n<=5?e.unitIndex[r].team=0:n>=6&&n<=10&&(e.unitIndex[r].team=1))}function _t(t,e){for(let[r,n]of Object.entries(t.heroLives)){let i=parseInt(r,10),a=t.playerIDMap[i];if(!a||!e[a])continue;for(let o of n)if(o.died===void 0){let c=o.locations[o.locations.length-1];o.duration=c?c.time-o.born:0}let s="";for(let[o,c]of Object.entries(t.heroUnits))if(c===i){s=o;break}s&&(e[a].units[s]={lives:n})}}var gt=["DamageTaken","CreepDamage","Healing","HeroDamage","MinionDamage","SelfHealing","SiegeDamage","ProtectionGivenToAllies","TeamfightDamageTaken","TeamfightHealingDone","TeamfightHeroDamage","TimeCCdEnemyHeroes","TimeRootingEnemyHeroes","TimeSpentDead","TimeStunningEnemyHeroes","TimeSilencingEnemyHeroes"];function yt(){return{DamageTaken:0,CreepDamage:0,Healing:0,HeroDamage:0,MinionDamage:0,SelfHealing:0,SiegeDamage:0,ProtectionGivenToAllies:0,TeamfightDamageTaken:0,TeamfightHealingDone:0,TeamfightHeroDamage:0,TimeCCdEnemyHeroes:0,TimeRootingEnemyHeroes:0,TimeSpentDead:0,TimeStunningEnemyHeroes:0,TimeSilencingEnemyHeroes:0,avgTimeSpentDead:0,timeDeadPct:0}}function xt(){return{mercCaptures:0,mercUptime:0,mercUptimePercent:0,structures:{},KDA:0,PPK:0,timeTo10:0,totals:yt(),levelAdvTime:0,maxLevelAdv:0,avgLevelAdv:0,levelAdvPct:0,uptime:[],uptimeHistogram:{},wipes:0,avgHeroesAlive:0,aces:0,timeWithHeroAdv:0,pctWithHeroAdv:0,passiveXPRate:0,passiveXPDiff:0,passiveXPGain:0}}function Ne(t,e){St(t),vt(t,e),kt(t,e),wt(t),Et(t,e),Dt(t)}function vt(t,e){for(let r of["0","1"]){let n=t.teams[r];if(!n)continue;n.names=[],n.heroes=[],n.tags=[],n.stats=xt();for(let u of n.ids){let m=e[u];m&&(n.names.push(m.name),n.heroes.push(m.hero),n.tags.push(m.tag))}for(let u of n.ids){let m=e[u];if(m)for(let b of gt){let d=m.gameStats[b];typeof d=="number"&&(n.stats.totals[b]+=d)}}let i=n.ids.reduce((u,m)=>u+(e[m]?.gameStats.Deaths??0),0);i>0&&(n.stats.totals.avgTimeSpentDead=n.stats.totals.TimeSpentDead/i),t.length>0&&(n.stats.totals.timeDeadPct=n.stats.totals.TimeSpentDead/(t.length*n.ids.length));let a=n.takedowns,s=i;n.stats.KDA=s>0?a/s:a,n.stats.PPK=a>0?t.takedowns.filter(u=>n.ids.includes(u.killers[0]?.player)).reduce((u,m)=>u+m.killers.length,0)/a:0;let o=t.levelTimes[r];o?.["10"]&&(n.stats.timeTo10=o[10].time);let c=parseInt(r,10),l=t.mercs.captures.filter(u=>u.team===c);n.stats.mercCaptures=l.length;let f=0;for(let u of Object.values(t.mercs.units))u.team===c&&u.duration>0&&(f+=u.duration);n.stats.mercUptime=f,n.stats.mercUptimePercent=t.length>0?f/t.length:0,Tt(t,n,r)}}function Tt(t,e,r){let n=parseInt(r,10),i=n===0?1:0,a={};for(let s of Object.values(t.structures)){let o=s.name;a[o]||(a[o]={lost:0,destroyed:0,first:t.length}),s.team===i&&s.destroyed!==void 0&&(a[o].destroyed++,a[o].first=Math.min(a[o].first,s.destroyed)),s.team===n&&s.destroyed!==void 0&&a[o].lost++}e.stats.structures=a}function kt(t,e){let r=t.length/60;for(let n of Object.values(e)){let i=n.gameStats,a=i.Deaths??0,s=i.TeamTakedowns??0;r>0&&(i.DPM=(i.HeroDamage??0)/r,i.HPM=((i.Healing??0)+(i.SelfHealing??0))/r,i.XPM=(i.ExperienceContribution??0)/r),i.KDA=a>0?(i.Takedowns??0)/a:i.Takedowns??0,i.KillParticipation=s>0?(i.Takedowns??0)/s:0,i.damageDonePerDeath=a>0?(i.HeroDamage??0)/a:i.HeroDamage??0,i.damageTakenPerDeath=a>0?(i.DamageTaken??0)/a:i.DamageTaken??0,i.healingDonePerDeath=a>0?((i.Healing??0)+(i.SelfHealing??0))/a:(i.Healing??0)+(i.SelfHealing??0),i.length=t.length}}function St(t){let e=0,r=0,n=new Set(t.teams[0]?.ids||[]);for(let i of t.takedowns)n.has(i.victim.player)?r++:e++;t.team0Takedowns=e,t.team1Takedowns=r,t.teams[0]&&(t.teams[0].takedowns=e),t.teams[1]&&(t.teams[1].takedowns=r)}function wt(t){let e=t.levelTimes[0]||{},r=t.levelTimes[1]||{},n=[];for(let l of Object.values(e))n.push({time:l.time,team:0,level:l.level});for(let l of Object.values(r))n.push({time:l.time,team:1,level:l.level});if(n.sort((l,f)=>l.time-f.time),n.length===0){t.levelAdvTimeline=[];return}let i=[],a=0,s=0,o=n[0].time;for(let l of n){let f=a-s;l.time>o&&i.push({start:o,end:l.time,levelDiff:f,length:l.time-o}),l.team===0?a=l.level:s=l.level,o=l.time}let c=a-s;t.length>o&&i.push({start:o,end:t.length,levelDiff:c,length:t.length-o}),t.levelAdvTimeline=i;for(let l of["0","1"]){let f=t.teams[l];if(!f)continue;let u=l==="0"?1:-1,m=0,b=0,d=0,h=0;for(let p of i){let _=p.levelDiff*u;_>0&&(m+=p.length),b=Math.max(b,_),d+=_*p.length,h+=p.length}f.stats.levelAdvTime=m,f.stats.maxLevelAdv=b,f.stats.avgLevelAdv=h>0?d/h:0,f.stats.levelAdvPct=t.length>0?m/t.length:0}}function Et(t,e){for(let a of["0","1"]){let s=t.teams[a];if(!s)continue;let o=[];for(let p of s.ids){let _=e[p];if(_)for(let y of _.deaths){o.push({time:y.time,delta:-1});let x=y.time+Pt(_.gameStats.Level??1);x<t.length&&o.push({time:x,delta:1})}}o.sort((p,_)=>p.time-_.time);let c=[{time:0,heroes:s.ids.length}],l=s.ids.length;for(let p of o)l+=p.delta,l=Math.max(0,Math.min(s.ids.length,l)),c.push({time:p.time,heroes:l});s.stats.uptime=c;let f={};for(let p=0;p<c.length;p++){let y=(p<c.length-1?c[p+1].time:t.length)-c[p].time,x=String(c[p].heroes);f[x]=(f[x]||0)+y}s.stats.uptimeHistogram=f;let u=0,m=0;for(let p=0;p<c.length;p++){let y=(p<c.length-1?c[p+1].time:t.length)-c[p].time;u+=c[p].heroes*y,m+=y}s.stats.avgHeroesAlive=m>0?u/m:s.ids.length,s.stats.wipes=c.filter(p=>p.heroes===0).length,s.stats.aces=0;let b=a==="0"?"1":"0",d=t.teams[b];d?.stats?.uptime&&(s.stats.aces=d.stats.uptime.filter(p=>p.heroes===0).length);let h=t.XPBreakdown.filter(p=>p.team===parseInt(a,10));if(h.length>0){let _=h[h.length-1].breakdown.TrickleXP;s.stats.passiveXPGain=_,s.stats.passiveXPRate=t.length>0?_/(t.length/60):0}}for(let a of["0","1"]){let s=t.teams[a],o=a==="0"?"1":"0",c=t.teams[o];if(!s||!c)continue;let l=s.stats.uptime,f=c.stats.uptime;if(!l.length||!f.length)continue;let u=new Set;for(let d of l)u.add(d.time);for(let d of f)u.add(d.time);let m=Array.from(u).sort((d,h)=>d-h),b=0;for(let d=0;d<m.length;d++){let h=m[d],_=(d<m.length-1?m[d+1]:t.length)-h,y=ze(l,h),x=ze(f,h);y>x&&(b+=_)}s.stats.timeWithHeroAdv=b,s.stats.pctWithHeroAdv=t.length>0?b/t.length:0}let r=t.teams[0]?.stats.passiveXPRate??0,n=t.teams[1]?.stats.passiveXPRate??0,i=(r+n)/2;t.teams[0]&&(t.teams[0].stats.passiveXPDiff=i>0?r/i:0),t.teams[1]&&(t.teams[1].stats.passiveXPDiff=i>0?n/i:0)}function ze(t,e){let r=0;for(let n of t)if(n.time<=e)r=n.heroes;else break;return r}function Pt(t){return t<=1?15:t<=5?15+(t-1)*2:t<=10?23+(t-5)*3:t<=15?38+(t-10)*4:58+(t-15)*5}function Dt(t){let e=1/0,r=-1,n=1/0,i=-1;for(let s of Object.values(t.structures))s.destroyed!==void 0&&(s.name==="Fort"&&s.destroyed<e&&(e=s.destroyed,r=s.team===0?1:0),s.name==="Keep"&&s.destroyed<n&&(n=s.destroyed,i=s.team===0?1:0));r>=0&&(t.firstFort=r,t.firstFortWin=r===t.winner),i>=0&&(t.firstKeep=i,t.firstKeepWin=i===t.winner);let a=[...t.objective[0].events.map(s=>({...s,assignedTeam:0})),...t.objective[1].events.map(s=>({...s,assignedTeam:1}))].sort((s,o)=>s.loop-o.loop);a.length>0&&(t.firstObjective=a[0].assignedTeam,t.firstObjectiveWin=a[0].assignedTeam===t.winner),t.firstPickWin=t.picks.first===t.winner}function k(t){return Buffer.isBuffer(t)?t.toString("utf8"):typeof t=="string"?t:String(t??"")}var se=class{static async analyze(e){try{let r=new M(e);await r.init();let n=r.getDetails();if(!n)throw new Error("Missing replay.details from parsed MPQ archive");let i=r.getTrackerEvents(),a=r.getInitData(),o=r.getHeader()?.m_version??{},c={m_flags:o.m_flags??0,m_major:o.m_major??0,m_minor:o.m_minor??0,m_revision:o.m_revision??0,m_build:o.m_baseBuild??r.getBuild(),m_baseBuild:o.m_baseBuild??r.getBuild()},l=n.m_playerList.find(b=>b?.m_toon)?.m_toon,f={version:c,map:k(n.m_title),isBlizzardMap:n.m_isBlizzardMap,timeLocalOffset:Number(n.m_timeLocalOffset),gameSpeed:n.m_gameSpeed,date:this.fileTimeToDate(n.m_timeUTC).toISOString(),rawDate:Number(n.m_timeUTC),length:0,winner:-1,region:l?.m_region,playerIDs:[],heroes:[],levelTimes:{0:{},1:{}},bans:{0:[],1:[]},picks:{0:[],1:[],first:0},XPBreakdown:[],takedowns:[],mercs:{captures:[],units:{}},team0Takedowns:0,team1Takedowns:0,structures:{},objective:{0:{count:0,events:[]},1:{count:0,events:[]},type:""},teams:{0:this.emptyTeam(),1:this.emptyTeam()},winningPlayers:[],levelAdvTimeline:[],firstPickWin:!1};f.objective.type=f.map||"";let u={};for(let b of n.m_playerList){if(!b?.m_toon)continue;let d=b.m_toon,h=k(d.m_programId),p=`${d.m_region}-${h}-${d.m_realm}-${d.m_id}`,_=k(b.m_hero),y=q(_)||_;u[p]={hero:y,name:k(b.m_name),uuid:d.m_id,region:d.m_region,realm:d.m_realm,ToonHandle:p,tag:0,team:b.m_teamId,win:b.m_result===1,skin:"",mount:"",banner:"",spray:"",clanTag:"",highestLeague:0,combinedRaceLevels:0,randomSeed:0,announcer:"",silenced:!1,voiceSilenced:!1,gameStats:{},awards:[],talents:{},takedowns:[],deaths:[],units:{}},f.playerIDs.push(p),f.heroes.push(y)}this.extractBattleTags(r,n,u),this.extractDraft(a,f,n),this.extractCosmetics(a,n,u);let{playerIDMap:m}=Ue(i,u,f);this.processScoreEvents(i,m,u);for(let[b,d]of Object.entries(u)){d.win&&(f.winner=d.team,f.winningPlayers.push(b));let h=f.teams[d.team.toString()];h&&(h.level=Math.max(h.level,d.gameStats.Level||0),h.ids.push(b))}return Ne(f,u),{status:1,match:f,players:u}}catch(r){return console.error("ReplayAnalyzer Error:",r),{status:-2,error:String(r)}}}static emptyTeam(){return{level:0,takedowns:0,ids:[],names:[],heroes:[],tags:[],stats:{mercCaptures:0,mercUptime:0,mercUptimePercent:0,structures:{},KDA:0,PPK:0,timeTo10:0,totals:{DamageTaken:0,CreepDamage:0,Healing:0,HeroDamage:0,MinionDamage:0,SelfHealing:0,SiegeDamage:0,ProtectionGivenToAllies:0,TeamfightDamageTaken:0,TeamfightHealingDone:0,TeamfightHeroDamage:0,TimeCCdEnemyHeroes:0,TimeRootingEnemyHeroes:0,TimeSpentDead:0,TimeStunningEnemyHeroes:0,TimeSilencingEnemyHeroes:0,avgTimeSpentDead:0,timeDeadPct:0},levelAdvTime:0,maxLevelAdv:0,avgLevelAdv:0,levelAdvPct:0,uptime:[],uptimeHistogram:{},wipes:0,avgHeroesAlive:0,aces:0,timeWithHeroAdv:0,pctWithHeroAdv:0,passiveXPRate:0,passiveXPDiff:0,passiveXPGain:0}}}static extractBattleTags(e,r,n){let i=e.extractFile("replay.server.battlelobby");if(i)try{let a=new RegExp("([\\p{L}\\d]{3,24}#\\d{4,10})[z\xD8]?","gu"),s=i.toString("utf8").match(a);if(!s)return;let o=0;for(let c of r.m_playerList){if(!c?.m_toon)continue;let l=k(c.m_name);for(;o<s.length;){let u=s[o].split("#"),m=u[0],b=u[1].replace(/[zØ]/g,"");if(o++,m===l){let d=c.m_toon,h=`${d.m_region}-${k(d.m_programId)}-${d.m_realm}-${d.m_id}`;n[h]&&(n[h].tag=parseInt(b,10)||0);break}}}}catch(a){console.error("BattleTag regex error:",a)}}static extractDraft(e,r,n){if(e)try{let i=e.m_syncLobbyState;if(!i)return;let a=i.m_lobbyState,s=i.m_gameDescription;if(!a)return;s&&(r.randomValue=s.m_randomValue,r.gameOptions=s.m_gameOptions);let o=[],c=[];for(let d of n.m_playerList){if(!d?.m_toon)continue;let h=k(d.m_hero),p=q(h)||h;d.m_teamId===0?o.push(p):d.m_teamId===1&&c.push(p)}r.picks={0:o,1:c,first:0};let l,f=s?.m_gameOptions;if(f&&typeof f.m_ammId=="number"){let d=f.m_ammId;d===50001?l="Quick Match":d===50031?l="ARAM":d===50041?l="Unranked Draft":d===50051?l="Custom":d===50061?l="Hero League":d===50071?l="Team League":d===50091&&(l="Storm League")}if(!l&&typeof a.m_gameMode=="number"){let d=a.m_gameMode;d===3?l="Quick Match":d===4?l="Custom":d===5?l="Hero League":d===6?l="Team League":d===7?l="Unranked Draft":d===8&&(l="ARAM")}if(r.mode=l,typeof a.m_gameType=="number"&&(r.type=a.m_gameType),!a.m_slots)return;let m=a.m_pickedMapTag,b=0;m!==void 0&&(b=a.m_firstPickTeam??0,r.picks.first=b)}catch{}}static extractCosmetics(e,r,n){if(e)try{let i=e.m_syncLobbyState;if(!i)return;let a=i.m_lobbyState;if(!a)return;let s=a.m_slots,o=i.m_userInitialData;if(!s)return;let c=0;for(let l of r.m_playerList){if(!l?.m_toon)continue;let f=l.m_toon,u=`${f.m_region}-${k(f.m_programId)}-${f.m_realm}-${f.m_id}`,m=n[u];for(;c<s.length;){let b=s[c];c++;let d=b.m_hero;if(!(!d||Buffer.isBuffer(d)&&d.length===0)){if(m&&(m.skin=k(b.m_skin)||"",m.mount=k(b.m_mount)||"",m.announcer=k(b.m_announcerPack)||"",m.banner=k(b.m_banner)||"",m.spray=k(b.m_spray)||"",m.silenced=!!b.m_hasSilencePenalty,m.voiceSilenced=!!b.m_hasVoiceSilencePenalty,o)){let h=o.find(p=>k(p.m_name)===m.name);h&&(m.clanTag=k(h.m_clanTag),m.highestLeague=h.m_highestLeague,m.combinedRaceLevels=h.m_combinedRaceLevels,m.randomSeed=h.m_randomSeed)}break}}}}catch{}}static processScoreEvents(e,r,n){for(let i of e){if(i._event!=="NNet.Replay.Tracker.SScoreResultEvent")continue;let a=i.m_instanceList;for(let s of a){let o=k(s.m_name),c=s.m_values,l=o.startsWith("EndOfMatchAward"),f=0;for(let u of c)if(u&&u.length>0&&u[0]!==void 0){let m=f+1,b=r[m];if(b&&n[b]){let d=typeof u[0]=="object"&&u[0]!==null&&"m_value"in u[0]?u[0].m_value:u[0];d!=null&&(l?d===1&&n[b].awards.push(o):n[b].gameStats[o]=d)}f++}else u&&u.length===0&&f++}}}static fileTimeToDate(e){return new Date(Number(e)/1e4-116444736e5)}};0&&(module.exports={LiveStreamParser,ReplayAnalyzer,ReplayParser});
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var F=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var ue=F((yt,de)=>{"use strict";var fe=[0,1,3,7,15,31,63,127,255],X=function(t){this.stream=t,this.bitOffset=0,this.curByte=0,this.hasByte=!1};X.prototype._ensureByte=function(){this.hasByte||(this.curByte=this.stream.readByte(),this.hasByte=!0)};X.prototype.read=function(t){for(var e=0;t>0;){this._ensureByte();var r=8-this.bitOffset;if(t>=r)e<<=r,e|=fe[r]&this.curByte,this.hasByte=!1,this.bitOffset=0,t-=r;else{e<<=t;var n=r-t;e|=(this.curByte&fe[t]<<n)>>n,this.bitOffset+=t,t=0}}return e};X.prototype.seek=function(t){var e=t%8,r=(t-e)/8;this.bitOffset=e,this.stream.seek(r),this.hasByte=!1};X.prototype.pi=function(){var t=new Buffer(6),e;for(e=0;e<t.length;e++)t[e]=this.read(8);return t.toString("hex")};de.exports=X});var be=F((xt,me)=>{"use strict";var M=function(){};M.prototype.readByte=function(){throw new Error("abstract method readByte() not implemented")};M.prototype.read=function(t,e,r){for(var n=0;n<r;){var i=this.readByte();if(i<0)return n===0?-1:n;t[e++]=i,n++}return n};M.prototype.seek=function(t){throw new Error("abstract method seek() not implemented")};M.prototype.writeByte=function(t){throw new Error("abstract method readByte() not implemented")};M.prototype.write=function(t,e,r){var n;for(n=0;n<r;n++)this.writeByte(t[e++]);return r};M.prototype.flush=function(){};me.exports=M});var he=F((vt,pe)=>{"use strict";pe.exports=(function(){var t=new Uint32Array([0,79764919,159529838,222504665,319059676,398814059,445009330,507990021,638119352,583659535,797628118,726387553,890018660,835552979,1015980042,944750013,1276238704,1221641927,1167319070,1095957929,1595256236,1540665371,1452775106,1381403509,1780037320,1859660671,1671105958,1733955601,2031960084,2111593891,1889500026,1952343757,2552477408,2632100695,2443283854,2506133561,2334638140,2414271883,2191915858,2254759653,3190512472,3135915759,3081330742,3009969537,2905550212,2850959411,2762807018,2691435357,3560074640,3505614887,3719321342,3648080713,3342211916,3287746299,3467911202,3396681109,4063920168,4143685023,4223187782,4286162673,3779000052,3858754371,3904687514,3967668269,881225847,809987520,1023691545,969234094,662832811,591600412,771767749,717299826,311336399,374308984,453813921,533576470,25881363,88864420,134795389,214552010,2023205639,2086057648,1897238633,1976864222,1804852699,1867694188,1645340341,1724971778,1587496639,1516133128,1461550545,1406951526,1302016099,1230646740,1142491917,1087903418,2896545431,2825181984,2770861561,2716262478,3215044683,3143675388,3055782693,3001194130,2326604591,2389456536,2200899649,2280525302,2578013683,2640855108,2418763421,2498394922,3769900519,3832873040,3912640137,3992402750,4088425275,4151408268,4197601365,4277358050,3334271071,3263032808,3476998961,3422541446,3585640067,3514407732,3694837229,3640369242,1762451694,1842216281,1619975040,1682949687,2047383090,2127137669,1938468188,2001449195,1325665622,1271206113,1183200824,1111960463,1543535498,1489069629,1434599652,1363369299,622672798,568075817,748617968,677256519,907627842,853037301,1067152940,995781531,51762726,131386257,177728840,240578815,269590778,349224269,429104020,491947555,4046411278,4126034873,4172115296,4234965207,3794477266,3874110821,3953728444,4016571915,3609705398,3555108353,3735388376,3664026991,3290680682,3236090077,3449943556,3378572211,3174993278,3120533705,3032266256,2961025959,2923101090,2868635157,2813903052,2742672763,2604032198,2683796849,2461293480,2524268063,2284983834,2364738477,2175806836,2238787779,1569362073,1498123566,1409854455,1355396672,1317987909,1246755826,1192025387,1137557660,2072149281,2135122070,1912620623,1992383480,1753615357,1816598090,1627664531,1707420964,295390185,358241886,404320391,483945776,43990325,106832002,186451547,266083308,932423249,861060070,1041341759,986742920,613929101,542559546,756411363,701822548,3316196985,3244833742,3425377559,3370778784,3601682597,3530312978,3744426955,3689838204,3819031489,3881883254,3928223919,4007849240,4037393693,4100235434,4180117107,4259748804,2310601993,2373574846,2151335527,2231098320,2596047829,2659030626,2470359227,2550115596,2947551409,2876312838,2788305887,2733848168,3165939309,3094707162,3040238851,2985771188]),e=function(){var r=4294967295;this.getCRC=function(){return~r>>>0},this.updateCRC=function(n){r=r<<8^t[(r>>>24^n)&255]},this.updateCRCRun=function(n,i){for(;i-- >0;)r=r<<8^t[(r>>>24^n)&255]}};return e})()});var _e=F((Tt,Oe)=>{Oe.exports={name:"seek-bzip",version:"2.0.0",contributors:["C. Scott Ananian (http://cscott.net)","Eli Skeggs","Kevin Kwok","Rob Landley (http://landley.net)"],description:"a pure-JavaScript Node.JS module for random-access decoding bzip2 data",main:"./lib/index.js",repository:{type:"git",url:"https://github.com/cscott/seek-bzip.git"},license:"MIT",bin:{"seek-bunzip":"./bin/seek-bunzip","seek-table":"./bin/seek-bzip-table"},directories:{test:"test"},dependencies:{commander:"^6.0.0"},devDependencies:{fibers:"^5.0.0",mocha:"^8.1.0"},scripts:{test:"mocha"}}});var we=F((kt,Se)=>{"use strict";var Ue=ue(),G=be(),ve=he(),Te=_e(),Y=20,ge=258,ye=0,ze=1,Ne=2,Fe=6,Xe=50,Ge="314159265359",Ke="177245385090",xe=function(t,e){var r=t[e],n;for(n=e;n>0;n--)t[n]=t[n-1];return t[0]=r,r},g={OK:0,LAST_BLOCK:-1,NOT_BZIP_DATA:-2,UNEXPECTED_INPUT_EOF:-3,UNEXPECTED_OUTPUT_EOF:-4,DATA_ERROR:-5,OUT_OF_MEMORY:-6,OBSOLETE_INPUT:-7,END_OF_BLOCK:-8},C={};C[g.LAST_BLOCK]="Bad file checksum";C[g.NOT_BZIP_DATA]="Not bzip data";C[g.UNEXPECTED_INPUT_EOF]="Unexpected input EOF";C[g.UNEXPECTED_OUTPUT_EOF]="Unexpected output EOF";C[g.DATA_ERROR]="Data error";C[g.OUT_OF_MEMORY]="Out of memory";C[g.OBSOLETE_INPUT]="Obsolete (pre 0.9.5) bzip format not supported.";var T=function(t,e){var r=C[t]||"unknown error";e&&(r+=": "+e);var n=new TypeError(r);throw n.errorCode=t,n},S=function(t,e){this.writePos=this.writeCurrent=this.writeCount=0,this._start_bunzip(t,e)};S.prototype._init_block=function(){var t=this._get_next_block();return t?(this.blockCRC=new ve,!0):(this.writeCount=-1,!1)};S.prototype._start_bunzip=function(t,e){var r=new Buffer(4);(t.read(r,0,4)!==4||String.fromCharCode(r[0],r[1],r[2])!=="BZh")&&T(g.NOT_BZIP_DATA,"bad magic");var n=r[3]-48;(n<1||n>9)&&T(g.NOT_BZIP_DATA,"level out of range"),this.reader=new Ue(t),this.dbufSize=1e5*n,this.nextoutput=0,this.outputStream=e,this.streamCRC=0};S.prototype._get_next_block=function(){var t,e,r,n=this.reader,i=n.pi();if(i===Ke)return!1;i!==Ge&&T(g.NOT_BZIP_DATA),this.targetBlockCRC=n.read(32)>>>0,this.streamCRC=(this.targetBlockCRC^(this.streamCRC<<1|this.streamCRC>>>31))>>>0,n.read(1)&&T(g.OBSOLETE_INPUT);var a=n.read(24);a>this.dbufSize&&T(g.DATA_ERROR,"initial position out of bounds");var s=n.read(16),o=new Buffer(256),l=0;for(t=0;t<16;t++)if(s&1<<15-t){var c=t*16;for(r=n.read(16),e=0;e<16;e++)r&1<<15-e&&(o[l++]=c+e)}var f=n.read(3);(f<Ne||f>Fe)&&T(g.DATA_ERROR);var u=n.read(15);u===0&&T(g.DATA_ERROR);var m=new Buffer(256);for(t=0;t<f;t++)m[t]=t;var p=new Buffer(u);for(t=0;t<u;t++){for(e=0;n.read(1);e++)e>=f&&T(g.DATA_ERROR);p[t]=xe(m,e)}var d=l+2,h=[],b;for(e=0;e<f;e++){var _=new Buffer(d),y=new Uint16Array(Y+1);for(s=n.read(5),t=0;t<d;t++){for(;(s<1||s>Y)&&T(g.DATA_ERROR),!!n.read(1);)n.read(1)?s--:s++;_[t]=s}var x,P;for(x=P=_[0],t=1;t<d;t++)_[t]>P?P=_[t]:_[t]<x&&(x=_[t]);b={},h.push(b),b.permute=new Uint16Array(ge),b.limit=new Uint32Array(Y+2),b.base=new Uint32Array(Y+1),b.minLen=x,b.maxLen=P;var I=0;for(t=x;t<=P;t++)for(y[t]=b.limit[t]=0,s=0;s<d;s++)_[s]===t&&(b.permute[I++]=s);for(t=0;t<d;t++)y[_[t]]++;for(I=s=0,t=x;t<P;t++)I+=y[t],b.limit[t]=I-1,I<<=1,s+=y[t],b.base[t+1]=I-s;b.limit[P+1]=Number.MAX_VALUE,b.limit[P]=I+y[P]-1,b.base[x]=0}var U=new Uint32Array(256);for(t=0;t<256;t++)m[t]=t;var A=0,B=0,oe=0,E,z=this.dbuf=new Uint32Array(this.dbufSize);for(d=0;;){for(d--||(d=Xe-1,oe>=u&&T(g.DATA_ERROR),b=h[p[oe++]]),t=b.minLen,e=n.read(t);t>b.maxLen&&T(g.DATA_ERROR),!(e<=b.limit[t]);t++)e=e<<1|n.read(1);e-=b.base[t],(e<0||e>=ge)&&T(g.DATA_ERROR);var N=b.permute[e];if(N===ye||N===ze){A||(A=1,s=0),N===ye?s+=A:s+=2*A,A<<=1;continue}if(A)for(A=0,B+s>this.dbufSize&&T(g.DATA_ERROR),E=o[m[0]],U[E]+=s;s--;)z[B++]=E;if(N>l)break;B>=this.dbufSize&&T(g.DATA_ERROR),t=N-1,E=xe(m,t),E=o[E],U[E]++,z[B++]=E}for((a<0||a>=B)&&T(g.DATA_ERROR),e=0,t=0;t<256;t++)r=e+U[t],U[t]=e,e=r;for(t=0;t<B;t++)E=z[t]&255,z[U[E]]|=t<<8,U[E]++;var Z=0,le=0,ce=0;return B&&(Z=z[a],le=Z&255,Z>>=8,ce=-1),this.writePos=Z,this.writeCurrent=le,this.writeCount=B,this.writeRun=ce,!0};S.prototype._read_bunzip=function(t,e){var r,n,i;if(this.writeCount<0)return 0;for(var a=0,s=this.dbuf,o=this.writePos,l=this.writeCurrent,c=this.writeCount,f=this.outputsize,u=this.writeRun;c;){for(c--,n=l,o=s[o],l=o&255,o>>=8,u++===3?(r=l,i=n,l=-1):(r=1,i=l),this.blockCRC.updateCRCRun(i,r);r--;)this.outputStream.writeByte(i),this.nextoutput++;l!=n&&(u=0)}return this.writeCount=c,this.blockCRC.getCRC()!==this.targetBlockCRC&&T(g.DATA_ERROR,"Bad block CRC (got "+this.blockCRC.getCRC().toString(16)+" expected "+this.targetBlockCRC.toString(16)+")"),this.nextoutput};var re=function(t){if("readByte"in t)return t;var e=new G;return e.pos=0,e.readByte=function(){return t[this.pos++]},e.seek=function(r){this.pos=r},e.eof=function(){return this.pos>=t.length},e},ke=function(t){var e=new G,r=!0;if(t)if(typeof t=="number")e.buffer=new Buffer(t),r=!1;else{if("writeByte"in t)return t;e.buffer=t,r=!1}else e.buffer=new Buffer(16384);return e.pos=0,e.writeByte=function(n){if(r&&this.pos>=this.buffer.length){var i=new Buffer(this.buffer.length*2);this.buffer.copy(i),this.buffer=i}this.buffer[this.pos++]=n},e.getBuffer=function(){if(this.pos!==this.buffer.length){if(!r)throw new TypeError("outputsize does not match decoded input");var n=new Buffer(this.pos);this.buffer.copy(n,0,0,this.pos),this.buffer=n}return this.buffer},e._coerced=!0,e};S.Err=g;S.decode=function(t,e,r){for(var n=re(t),i=ke(e),a=new S(n,i);!("eof"in n&&n.eof());)if(a._init_block())a._read_bunzip();else{var s=a.reader.read(32)>>>0;if(s!==a.streamCRC&&T(g.DATA_ERROR,"Bad stream CRC (got "+a.streamCRC.toString(16)+" expected "+s.toString(16)+")"),r&&"eof"in n&&!n.eof())a._start_bunzip(n,i);else break}if("getBuffer"in i)return i.getBuffer()};S.decodeBlock=function(t,e,r){var n=re(t),i=ke(r),a=new S(n,i);a.reader.seek(e);var s=a._get_next_block();if(s&&(a.blockCRC=new ve,a.writeCopies=0,a._read_bunzip()),"getBuffer"in i)return i.getBuffer()};S.table=function(t,e,r){var n=new G;n.delegate=re(t),n.pos=0,n.readByte=function(){return this.pos++,this.delegate.readByte()},n.delegate.eof&&(n.eof=n.delegate.eof.bind(n.delegate));var i=new G;i.pos=0,i.writeByte=function(){this.pos++};for(var a=new S(n,i),s=a.dbufSize;!("eof"in n&&n.eof());){var o=n.pos*8+a.reader.bitOffset;if(a.reader.hasByte&&(o-=8),a._init_block()){var l=i.pos;a._read_bunzip(),e(o,i.pos-l)}else{var c=a.reader.read(32);if(r&&"eof"in n&&!n.eof())a._start_bunzip(n,i),console.assert(a.dbufSize===s,"shouldn't change block size within multistream file");else break}}};S.Stream=G;S.version=Te.version;S.license=Te.license;Se.exports=S});import*as De from"fs";import*as K from"zlib";var je=we(),Ee=512,Qe=65536,Ve=16777216,We=67108864,$e=2147483648,qe={TABLE_OFFSET:0,HASH_A:1,HASH_B:2,TABLE:3};function Ze(){let t=1048577,e=new Uint32Array(256*5);for(let r=0;r<256;r++){let n=r;for(let i=0;i<5;i++){t=(t*125+3)%2796203;let a=(t&65535)<<16;t=(t*125+3)%2796203;let s=t&65535;e[n]=(a|s)>>>0,n+=256}}return e}var Pe=Ze(),J=class{file;header;hashTable;blockTable;files;constructor(e,r=!0){if(Buffer.isBuffer(e)?this.file=e:this.file=De.readFileSync(e),this.header=this.readHeader(),this.hashTable=this.readTable("hash"),this.blockTable=this.readTable("block"),r){let n=this.readFile("(listfile)");n?this.files=n.toString("utf8").trim().split(`\r
|
|
2
|
-
`):this.files=null}else this.files=null}readHeader(){let e=this.file.toString("utf8",0,4),
|
|
3
|
-
Searched: `+t.join(", "))}var ne=new Map,ie=null;function Re(){return ie||(ie=Ye()),ie}function ee(t){if(ne.has(t))return ne.get(t);let e=Re(),r=O.join(e,`protocol${t}.json`);if(!W.existsSync(r))return null;let n=JSON.parse(W.readFileSync(r,"utf-8"));return ne.set(t,n),n}function Be(){let t=Re();return W.readdirSync(t).filter(e=>/^protocol\d+\.json$/.test(e)).map(e=>parseInt(e.match(/\d+/)[0],10)).sort((e,r)=>e-r)}var $=class{mpq;header;build=0;protocol;baseProtocol;constructor(e){this.mpq=new J(e,!1)}init(){let e=ee(29406);if(!e)throw new Error("Base protocol29406 not found. Did postinstall run? Try: npx tsx node_modules/@astefanski/storm-parser/scripts/postinstall.ts");this.baseProtocol=e;let r=this.mpq.header.userDataHeader;if(!r||!r.content)throw new Error("Replay does not have a user data header");let n=new L(r.content,this.baseProtocol.typeinfos);this.header=n.instance(this.baseProtocol.replay_header_typeid),this.build=this.header.m_version.m_baseBuild,this.protocol=this.loadProtocolForBuild(this.build)}loadProtocolForBuild(e){let r=ee(e);if(!r){let n=Be(),i=n[0];for(let a of n)a<=e&&a>i&&(i=a);r=ee(i)}if(!r)throw new Error(`No protocol found for build ${e}`);return r}*decodeEventStream(e,r,n,i){if(!this.protocol)throw new Error("Protocol not loaded");let a=0;for(;!e.done();){let s=e.used_bits(),o=e.instance(this.protocol.svaruint32_typeid),l=Object.keys(o)[0],c=o[l];a+=c;let f=i?e.instance(this.protocol.replay_userid_typeid):void 0,u=Number(e.instance(r)),m=n[u];if(!m)throw new Error(`Unknown eventid(${u})`);let p=m[0],d=m[1],h=e.instance(p);h._event=d,h._eventid=u,h._gameloop=a,i&&(h._userid=f),e.byte_align(),h._bits=e.used_bits()-s,yield h}}getDetails(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.details");return e?new L(e,this.protocol.typeinfos).instance(this.protocol.game_details_typeid):null}getInitData(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.initData");return e?new V(e,this.protocol.typeinfos).instance(this.protocol.replay_initdata_typeid):null}getTrackerEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.tracker.events");if(!e)return[];let r=new L(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(r,this.protocol.tracker_eventid_typeid,this.protocol.tracker_event_types,!1))}getGameEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.game.events");if(!e)return[];let r=new V(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(r,this.protocol.game_eventid_typeid,this.protocol.game_event_types,!0))}getAttributeEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.attributes.events");return e?new L(e,this.protocol.typeinfos).instance(this.protocol.replay_attributes_events_typeid):null}extractFile(e){return this.mpq.readFile(e)}getHeader(){return this.header}getBuild(){return this.build}};var Ce=["Abathur","Alarak","Alexstrasza","Ana","Anduin","Anubarak","Artanis","Arthas","Auriel","Azmodan","Blaze","Brightwing","Cassia","Chen","Cho","Chromie","Deathwing","Deckard","Dehaka","Diablo","DVa","ETC","Falstad","Fenix","Gall","Garrosh","Gazlowe","Genji","Greymane","Guldan","Hanzo","Hogger","Illidan","Imperius","Jaina","Johanna","Junkrat","Kaelthas","KelThuzad","Kerrigan","Kharazim","Leoric","LiLi","LiMing","LtMorales","Lunara","Maiev","Malfurion","MalGanis","Malthael","Medivh","Mei","Mephisto","Muradin","Murky","Nazeebo","Nova","Orphea","Probius","Qhira","Ragnaros","Raynor","Rehgar","Rexxar","Samuro","SgtHammer","Sonya","Stitches","Stukov","Sylvanas","Tassadar","TheButcher","TheLostVikings","Thrall","Tracer","Tychus","Tyrael","Tyrande","Uther","Valeera","Valla","Varian","Whitemane","Xul","Yrel","Zagara","Zarya","Zeratul","Zuljin"],Ie={FaerieDragon:"Brightwing",Amazon:"Cassia",Barbarian:"Sonya",Crusader:"Johanna",DemonHunter:"Valla",WitchDoctor:"Nazeebo",Monk:"Kharazim",Wizard:"LiMing",Tinker:"Gazlowe",Medic:"LtMorales",L90ETC:"ETC",Butcher:"TheButcher",LostVikings:"TheLostVikings",Necromancer:"Xul",Dryad:"Lunara",Shapeshifter:"Greymane",ChoGall:"Cho"};function q(t){if(!t)return null;if(Ce.includes(t))return t;if(Ie[t])return Ie[t];let e=t.replace(/[^a-zA-Z0-9]/g,"").toLowerCase(),r=Ce.find(n=>n.toLowerCase()===e);return r||null}var Ae={TownCannonTowerL2:"Fort Tower",TownCannonTowerL3:"Keep Tower",TownTownHallL2:"Fort",TownTownHallL3:"Keep",TownMoonwellL2:"Fort Well",TownMoonwellL3:"Keep Well"},Je={MercLanerMeleeKnight:"Bruiser Camp",MercLanerRangedMage:"Bruiser Camp",MercLanerSiegeGiant:"Siege Camp",MercLanerRangedMinion:"Siege Camp"};function R(t){return Buffer.isBuffer(t)?t.toString("utf8"):typeof t=="string"?t:String(t??"")}function v(t,e){if(!t)return;let r=t.find(n=>R(n.m_key)===e);return r!==void 0?r.m_value:void 0}function te(t,e){if(!t)return;let r=t.find(n=>R(n.m_key)===e);return r!==void 0?R(r.m_value):void 0}function w(t,e){if(!t)return;let r=t.find(n=>R(n.m_key)===e);return r!==void 0?r.m_value:void 0}function ae(t,e){return`${t}-${e}`}function D(t,e){return(t-e)/16}function Me(t,e,r){let n={playerIDMap:{},loopGameStart:0,loopGameEnd:0,unitIndex:{},heroUnits:{},heroLives:{}};r.bans||(r.bans={0:[],1:[]}),r.levelTimes={0:{},1:{}},r.takedowns=[],r.structures={},r.XPBreakdown=[],r.mercs={captures:[],units:{}},r.objective={0:{count:0,events:[]},1:{count:0,events:[]},type:r.map||""};for(let i of t)switch(n.loopGameEnd=Math.max(n.loopGameEnd,i._gameloop),i._event){case"NNet.Replay.Tracker.SStatGameEvent":et(i,n,e,r);break;case"NNet.Replay.Tracker.SHeroBannedEvent":if(i.m_hero){let a=R(i.m_hero),s=q(a);if(!s)break;let o=i.m_controllingTeam===2?1:0;if(r.bans&&r.bans[o]){let l=r.bans[o].length+1,c=r.bans[0].length+r.bans[1].length+1;r.bans[o].push({hero:s,order:l,absolute:c})}}break;case"NNet.Replay.Tracker.SUnitBornEvent":nt(i,n,r);break;case"NNet.Replay.Tracker.SUnitDiedEvent":it(i,n,r);break;case"NNet.Replay.Tracker.SUnitOwnerChangeEvent":at(i,n);break}return r.loopGameStart=n.loopGameStart,r.loopLength=n.loopGameEnd,r.length=(n.loopGameEnd-n.loopGameStart)/16,st(n,e),{playerIDMap:n.playerIDMap}}function et(t,e,r,n){let i=R(t.m_eventName),a=t.m_intData,s=t.m_stringData,o=t.m_fixedData;switch(i){case"PlayerInit":{let l=v(a,"PlayerID"),c=te(s,"ToonHandle");l!==void 0&&c&&r[c]&&(e.playerIDMap[l]=c);break}case"GatesOpen":e.loopGameStart=t._gameloop;break;case"LevelUp":{let l=v(a,"PlayerID"),c=v(a,"Level");if(l===void 0||c===void 0)break;let f;if(l>=1&&l<=5)f="0";else if(l>=6&&l<=10)f="1";else break;n.levelTimes[f][String(c)]||(n.levelTimes[f][String(c)]={loop:t._gameloop,level:c,team:f,time:D(t._gameloop,e.loopGameStart)});break}case"TalentChosen":{let l=v(a,"PlayerID"),c=te(s,"PurchaseName");if(l===void 0||!c||c==="Win"||c==="Loss"||c.startsWith("Hero"))break;let f=n.map?.replace(/\s+/g,"")||"";if(c===f)break;let u=e.playerIDMap[l];if(!u||!r[u])break;let m=["Tier1Choice","Tier2Choice","Tier3Choice","Tier4Choice","Tier5Choice","Tier6Choice","Tier7Choice"];for(let p of m)if(!r[u].talents[p]){r[u].talents[p]=c;break}break}case"PlayerDeath":{let l=v(a,"PlayerID"),c=v(a,"KillingPlayer"),f=w(o,"PositionX")??0,u=w(o,"PositionY")??0;if(l===void 0)break;let m=e.playerIDMap[l];if(!m)break;let p={player:m,hero:r[m]?.hero||""},d=[],h=r[m]?.team;if(c&&c>0){let _=e.playerIDMap[c];_&&r[_]&&d.push({player:_,hero:r[_].hero})}for(let[_,y]of Object.entries(e.playerIDMap)){let x=r[y];!x||x.team===h||parseInt(_)===c||d.push({player:y,hero:x.hero})}let b={loop:t._gameloop,time:D(t._gameloop,e.loopGameStart),x:f,y:u,killers:d,victim:p};n.takedowns.push(b),r[m]&&r[m].deaths.push(b);for(let _ of d)r[_.player]&&r[_.player].takedowns.push(b);break}case"PeriodicXPBreakdown":{let l=v(a,"Team");if(l===void 0)break;let c={GameTime:v(a,"GameTime")??0,PreviousGameTime:v(a,"PreviousGameTime")??0,MinionXP:w(o,"MinionXP")??0,CreepXP:w(o,"CreepXP")??0,StructureXP:w(o,"StructureXP")??0,HeroXP:w(o,"HeroXP")??0,TrickleXP:w(o,"TrickleXP")??0};n.XPBreakdown.push({loop:t._gameloop,time:D(t._gameloop,e.loopGameStart),team:l,teamLevel:v(a,"TeamLevel")??0,breakdown:c,theoreticalMinionXP:v(a,"TheoreticalMinionXP")??0});break}case"EndOfGameXPBreakdown":{let l=v(a,"Team");if(l===void 0)break;n.XPBreakdown.push({loop:t._gameloop,time:D(t._gameloop,e.loopGameStart),team:l,theoreticalMinionXP:v(a,"TheoreticalMinionXP")??0,breakdown:{GameTime:0,PreviousGameTime:0,MinionXP:w(o,"MinionXP")??0,CreepXP:w(o,"CreepXP")??0,StructureXP:w(o,"StructureXP")??0,HeroXP:w(o,"HeroXP")??0,TrickleXP:w(o,"TrickleXP")??0}});break}case"JungleCampCapture":{let l=v(a,"CampTeam")??v(a,"Team")??0;n.mercs.captures.push({loop:t._gameloop,type:te(s,"CampType")??te(s,"Result")??"Unknown Camp",team:l,time:D(t._gameloop,e.loopGameStart)});break}case"EndOfGameTalentChoices":{let l=v(a,"PlayerID");if(l===void 0)break;let c=e.playerIDMap[l];if(!c||!r[c])break;let f={};if(s)for(let u of s){let m=R(u.m_key),p=R(u.m_value);m==="Tier 1 Choice"&&p?f.Tier1Choice=p:m==="Tier 2 Choice"&&p?f.Tier2Choice=p:m==="Tier 3 Choice"&&p?f.Tier3Choice=p:m==="Tier 4 Choice"&&p?f.Tier4Choice=p:m==="Tier 5 Choice"&&p?f.Tier5Choice=p:m==="Tier 6 Choice"&&p?f.Tier6Choice=p:m==="Tier 7 Choice"&&p&&(f.Tier7Choice=p)}r[c].talents=f;break}default:rt(i,t,e,n,a,o);break}}var tt=new Set(["SoulEatersSpawned","TributeCollected","RavenCurseActivated","AltarCaptured","SkyTempleShotsFired","DragonKnightActivated","GardenTerrorActivated","InfernalShrineCaptured","PunisherKilled","VolskayaVehicleCapture","BraxisWaveStart","ImmortalDefeated","NukeExploded","PayloadDelivered","AlteracCavalryCharge","AlteracCavalry"]);function rt(t,e,r,n,i,a){if(!tt.has(t)||!i)return;let s=v(i,"Team")??v(i,"Event")??0,o=s===0||s===1?s:0,l={team:s,loop:e._gameloop,time:D(e._gameloop,r.loopGameStart),score:v(i,"Score"),duration:w(a,"Duration")};n.objective[o].events.push(l),n.objective[o].count=n.objective[o].events.length}function nt(t,e,r){let n=R(t.m_unitTypeName),i=t.m_unitTagIndex,a=t.m_unitTagRecycle,s=ae(i,a),o=t.m_controlPlayerId??t.m_upkeepPlayerId,l=t.m_x??0,c=t.m_y??0,f;if(o>=1&&o<=5?f=0:o>=6&&o<=10?f=1:o===11?f=0:o===12?f=1:f=o<=5?0:1,e.unitIndex[s]={type:n,playerId:o,team:f,x:l,y:c,bornLoop:t._gameloop},n.startsWith("Town")&&Ae[n]&&(r.structures[s]={type:n,name:Ae[n],tag:i,rtag:a,x:l,y:c,team:f}),n.startsWith("Hero")&&o>=1&&o<=10){e.heroUnits[s]=o,e.heroLives[o]||(e.heroLives[o]=[]);let u=D(t._gameloop,e.loopGameStart);e.heroLives[o].push({born:u,locations:[{x:l,y:c,time:u}],duration:0})}if(Je[n]){let m=r.mercs.captures[r.mercs.captures.length-1]?.loop??t._gameloop;r.mercs.units[s]={loop:m,team:f,type:n,locations:[{x:l,y:c}],time:D(m,e.loopGameStart),duration:0}}}function it(t,e,r){let n=ae(t.m_unitTagIndex,t.m_unitTagRecycle),i=D(t._gameloop,e.loopGameStart);r.structures[n]&&(r.structures[n].destroyedLoop=t._gameloop,r.structures[n].destroyed=i),r.mercs.units[n]&&(r.mercs.units[n].duration=i-r.mercs.units[n].time);let a=e.heroUnits[n];if(a!==void 0&&e.heroLives[a]){let s=e.heroLives[a],o=s[s.length-1];o&&o.died===void 0&&(o.died=i,o.duration=i-o.born)}}function at(t,e){let r=ae(t.m_unitTagIndex,t.m_unitTagRecycle),n=t.m_controlPlayerId??t.m_upkeepPlayerId;e.unitIndex[r]&&(e.unitIndex[r].playerId=n,n>=1&&n<=5?e.unitIndex[r].team=0:n>=6&&n<=10&&(e.unitIndex[r].team=1))}function st(t,e){for(let[r,n]of Object.entries(t.heroLives)){let i=parseInt(r,10),a=t.playerIDMap[i];if(!a||!e[a])continue;for(let o of n)if(o.died===void 0){let l=o.locations[o.locations.length-1];o.duration=l?l.time-o.born:0}let s="";for(let[o,l]of Object.entries(t.heroUnits))if(l===i){s=o;break}s&&(e[a].units[s]={lives:n})}}var ot=["DamageTaken","CreepDamage","Healing","HeroDamage","MinionDamage","SelfHealing","SiegeDamage","ProtectionGivenToAllies","TeamfightDamageTaken","TeamfightHealingDone","TeamfightHeroDamage","TimeCCdEnemyHeroes","TimeRootingEnemyHeroes","TimeSpentDead","TimeStunningEnemyHeroes","TimeSilencingEnemyHeroes"];function lt(){return{DamageTaken:0,CreepDamage:0,Healing:0,HeroDamage:0,MinionDamage:0,SelfHealing:0,SiegeDamage:0,ProtectionGivenToAllies:0,TeamfightDamageTaken:0,TeamfightHealingDone:0,TeamfightHeroDamage:0,TimeCCdEnemyHeroes:0,TimeRootingEnemyHeroes:0,TimeSpentDead:0,TimeStunningEnemyHeroes:0,TimeSilencingEnemyHeroes:0,avgTimeSpentDead:0,timeDeadPct:0}}function ct(){return{mercCaptures:0,mercUptime:0,mercUptimePercent:0,structures:{},KDA:0,PPK:0,timeTo10:0,totals:lt(),levelAdvTime:0,maxLevelAdv:0,avgLevelAdv:0,levelAdvPct:0,uptime:[],uptimeHistogram:{},wipes:0,avgHeroesAlive:0,aces:0,timeWithHeroAdv:0,pctWithHeroAdv:0,passiveXPRate:0,passiveXPDiff:0,passiveXPGain:0}}function Le(t,e){mt(t),ft(t,e),ut(t,e),bt(t),pt(t,e),_t(t)}function ft(t,e){for(let r of["0","1"]){let n=t.teams[r];if(!n)continue;n.names=[],n.heroes=[],n.tags=[],n.stats=ct();for(let u of n.ids){let m=e[u];m&&(n.names.push(m.name),n.heroes.push(m.hero),n.tags.push(m.tag))}for(let u of n.ids){let m=e[u];if(m)for(let p of ot){let d=m.gameStats[p];typeof d=="number"&&(n.stats.totals[p]+=d)}}let i=n.ids.reduce((u,m)=>u+(e[m]?.gameStats.Deaths??0),0);i>0&&(n.stats.totals.avgTimeSpentDead=n.stats.totals.TimeSpentDead/i),t.length>0&&(n.stats.totals.timeDeadPct=n.stats.totals.TimeSpentDead/(t.length*n.ids.length));let a=n.takedowns,s=i;n.stats.KDA=s>0?a/s:a,n.stats.PPK=a>0?t.takedowns.filter(u=>n.ids.includes(u.killers[0]?.player)).reduce((u,m)=>u+m.killers.length,0)/a:0;let o=t.levelTimes[r];o?.["10"]&&(n.stats.timeTo10=o[10].time);let l=parseInt(r,10),c=t.mercs.captures.filter(u=>u.team===l);n.stats.mercCaptures=c.length;let f=0;for(let u of Object.values(t.mercs.units))u.team===l&&u.duration>0&&(f+=u.duration);n.stats.mercUptime=f,n.stats.mercUptimePercent=t.length>0?f/t.length:0,dt(t,n,r)}}function dt(t,e,r){let n=parseInt(r,10),i=n===0?1:0,a={};for(let s of Object.values(t.structures)){let o=s.name;a[o]||(a[o]={lost:0,destroyed:0,first:t.length}),s.team===i&&s.destroyed!==void 0&&(a[o].destroyed++,a[o].first=Math.min(a[o].first,s.destroyed)),s.team===n&&s.destroyed!==void 0&&a[o].lost++}e.stats.structures=a}function ut(t,e){let r=t.length/60;for(let n of Object.values(e)){let i=n.gameStats,a=i.Deaths??0,s=i.TeamTakedowns??0;r>0&&(i.DPM=(i.HeroDamage??0)/r,i.HPM=((i.Healing??0)+(i.SelfHealing??0))/r,i.XPM=(i.ExperienceContribution??0)/r),i.KDA=a>0?(i.Takedowns??0)/a:i.Takedowns??0,i.KillParticipation=s>0?(i.Takedowns??0)/s:0,i.damageDonePerDeath=a>0?(i.HeroDamage??0)/a:i.HeroDamage??0,i.damageTakenPerDeath=a>0?(i.DamageTaken??0)/a:i.DamageTaken??0,i.healingDonePerDeath=a>0?((i.Healing??0)+(i.SelfHealing??0))/a:(i.Healing??0)+(i.SelfHealing??0),i.length=t.length}}function mt(t){let e=0,r=0,n=new Set(t.teams[0]?.ids||[]);for(let i of t.takedowns)n.has(i.victim.player)?r++:e++;t.team0Takedowns=e,t.team1Takedowns=r,t.teams[0]&&(t.teams[0].takedowns=e),t.teams[1]&&(t.teams[1].takedowns=r)}function bt(t){let e=t.levelTimes[0]||{},r=t.levelTimes[1]||{},n=[];for(let c of Object.values(e))n.push({time:c.time,team:0,level:c.level});for(let c of Object.values(r))n.push({time:c.time,team:1,level:c.level});if(n.sort((c,f)=>c.time-f.time),n.length===0){t.levelAdvTimeline=[];return}let i=[],a=0,s=0,o=n[0].time;for(let c of n){let f=a-s;c.time>o&&i.push({start:o,end:c.time,levelDiff:f,length:c.time-o}),c.team===0?a=c.level:s=c.level,o=c.time}let l=a-s;t.length>o&&i.push({start:o,end:t.length,levelDiff:l,length:t.length-o}),t.levelAdvTimeline=i;for(let c of["0","1"]){let f=t.teams[c];if(!f)continue;let u=c==="0"?1:-1,m=0,p=0,d=0,h=0;for(let b of i){let _=b.levelDiff*u;_>0&&(m+=b.length),p=Math.max(p,_),d+=_*b.length,h+=b.length}f.stats.levelAdvTime=m,f.stats.maxLevelAdv=p,f.stats.avgLevelAdv=h>0?d/h:0,f.stats.levelAdvPct=t.length>0?m/t.length:0}}function pt(t,e){for(let a of["0","1"]){let s=t.teams[a];if(!s)continue;let o=[];for(let b of s.ids){let _=e[b];if(_)for(let y of _.deaths){o.push({time:y.time,delta:-1});let x=y.time+ht(_.gameStats.Level??1,y.time,t.length);x<t.length&&o.push({time:x,delta:1})}}o.sort((b,_)=>b.time-_.time);let l=[{time:0,heroes:s.ids.length}],c=s.ids.length;for(let b of o)c+=b.delta,c=Math.max(0,Math.min(s.ids.length,c)),l.push({time:b.time,heroes:c});s.stats.uptime=l;let f={};for(let b=0;b<l.length;b++){let y=(b<l.length-1?l[b+1].time:t.length)-l[b].time,x=String(l[b].heroes);f[x]=(f[x]||0)+y}s.stats.uptimeHistogram=f;let u=0,m=0;for(let b=0;b<l.length;b++){let y=(b<l.length-1?l[b+1].time:t.length)-l[b].time;u+=l[b].heroes*y,m+=y}s.stats.avgHeroesAlive=m>0?u/m:s.ids.length,s.stats.wipes=l.filter(b=>b.heroes===0).length,s.stats.aces=0;let p=a==="0"?"1":"0",d=t.teams[p];d?.stats?.uptime&&(s.stats.aces=d.stats.uptime.filter(b=>b.heroes===0).length);let h=t.XPBreakdown.filter(b=>b.team===parseInt(a,10));if(h.length>0){let _=h[h.length-1].breakdown.TrickleXP;s.stats.passiveXPGain=_,s.stats.passiveXPRate=t.length>0?_/(t.length/60):0}}for(let a of["0","1"]){let s=t.teams[a],o=a==="0"?"1":"0",l=t.teams[o];if(!s||!l)continue;let c=s.stats.uptime,f=l.stats.uptime;if(!c.length||!f.length)continue;let u=new Set;for(let d of c)u.add(d.time);for(let d of f)u.add(d.time);let m=Array.from(u).sort((d,h)=>d-h),p=0;for(let d=0;d<m.length;d++){let h=m[d],_=(d<m.length-1?m[d+1]:t.length)-h,y=He(c,h),x=He(f,h);y>x&&(p+=_)}s.stats.timeWithHeroAdv=p,s.stats.pctWithHeroAdv=t.length>0?p/t.length:0}let r=t.teams[0]?.stats.passiveXPRate??0,n=t.teams[1]?.stats.passiveXPRate??0,i=(r+n)/2;t.teams[0]&&(t.teams[0].stats.passiveXPDiff=i>0?r/i:0),t.teams[1]&&(t.teams[1].stats.passiveXPDiff=i>0?n/i:0)}function He(t,e){let r=0;for(let n of t)if(n.time<=e)r=n.heroes;else break;return r}function ht(t,e,r){return t<=1?15:t<=5?15+(t-1)*2:t<=10?23+(t-5)*3:t<=15?38+(t-10)*4:58+(t-15)*5}function _t(t){let e=1/0,r=-1,n=1/0,i=-1;for(let s of Object.values(t.structures))s.destroyed!==void 0&&(s.name==="Fort"&&s.destroyed<e&&(e=s.destroyed,r=s.team===0?1:0),s.name==="Keep"&&s.destroyed<n&&(n=s.destroyed,i=s.team===0?1:0));r>=0&&(t.firstFort=r,t.firstFortWin=r===t.winner),i>=0&&(t.firstKeep=i,t.firstKeepWin=i===t.winner);let a=[...t.objective[0].events.map(s=>({...s,assignedTeam:0})),...t.objective[1].events.map(s=>({...s,assignedTeam:1}))].sort((s,o)=>s.loop-o.loop);a.length>0&&(t.firstObjective=a[0].assignedTeam,t.firstObjectiveWin=a[0].assignedTeam===t.winner),t.firstPickWin=t.picks.first===t.winner}function k(t){return Buffer.isBuffer(t)?t.toString("utf8"):typeof t=="string"?t:String(t??"")}var se=class{static async analyze(e){try{let r=new $(e);await r.init();let n=r.getDetails();if(!n)throw new Error("Missing replay.details from parsed MPQ archive");let i=r.getTrackerEvents(),a=r.getInitData(),o=r.getHeader()?.m_version??{},l={m_flags:o.m_flags??0,m_major:o.m_major??0,m_minor:o.m_minor??0,m_revision:o.m_revision??0,m_build:o.m_baseBuild??r.getBuild(),m_baseBuild:o.m_baseBuild??r.getBuild()},c=n.m_playerList.find(p=>p?.m_toon)?.m_toon,f={version:l,map:k(n.m_title),isBlizzardMap:n.m_isBlizzardMap,timeLocalOffset:Number(n.m_timeLocalOffset),gameSpeed:n.m_gameSpeed,date:this.fileTimeToDate(n.m_timeUTC).toISOString(),rawDate:Number(n.m_timeUTC),length:0,winner:-1,region:c?.m_region,playerIDs:[],heroes:[],levelTimes:{0:{},1:{}},bans:{0:[],1:[]},picks:{0:[],1:[],first:0},XPBreakdown:[],takedowns:[],mercs:{captures:[],units:{}},team0Takedowns:0,team1Takedowns:0,structures:{},objective:{0:{count:0,events:[]},1:{count:0,events:[]},type:""},teams:{0:this.emptyTeam(),1:this.emptyTeam()},winningPlayers:[],levelAdvTimeline:[],firstPickWin:!1};f.objective.type=f.map||"";let u={};for(let p of n.m_playerList){if(!p?.m_toon)continue;let d=p.m_toon,h=k(d.m_programId),b=`${d.m_region}-${h}-${d.m_realm}-${d.m_id}`,_=k(p.m_hero),y=q(_)||_;u[b]={hero:y,name:k(p.m_name),uuid:d.m_id,region:d.m_region,realm:d.m_realm,ToonHandle:b,tag:0,team:p.m_teamId,win:p.m_result===1,skin:"",mount:"",banner:"",spray:"",clanTag:"",highestLeague:0,combinedRaceLevels:0,randomSeed:0,announcer:"",silenced:!1,voiceSilenced:!1,gameStats:{},awards:[],talents:{},takedowns:[],deaths:[],units:{}},f.playerIDs.push(b),f.heroes.push(y)}this.extractBattleTags(r,n,u),this.extractDraft(a,f,n),this.extractCosmetics(a,n,u);let{playerIDMap:m}=Me(i,u,f);this.processScoreEvents(i,m,u);for(let[p,d]of Object.entries(u)){d.win&&(f.winner=d.team,f.winningPlayers.push(p));let h=f.teams[d.team.toString()];h&&(h.level=Math.max(h.level,d.gameStats.Level||0),h.ids.push(p))}return Le(f,u),{status:1,match:f,players:u}}catch(r){return console.error("ReplayAnalyzer Error:",r),{status:-2,error:String(r)}}}static emptyTeam(){return{level:0,takedowns:0,ids:[],names:[],heroes:[],tags:[],stats:{mercCaptures:0,mercUptime:0,mercUptimePercent:0,structures:{},KDA:0,PPK:0,timeTo10:0,totals:{DamageTaken:0,CreepDamage:0,Healing:0,HeroDamage:0,MinionDamage:0,SelfHealing:0,SiegeDamage:0,ProtectionGivenToAllies:0,TeamfightDamageTaken:0,TeamfightHealingDone:0,TeamfightHeroDamage:0,TimeCCdEnemyHeroes:0,TimeRootingEnemyHeroes:0,TimeSpentDead:0,TimeStunningEnemyHeroes:0,TimeSilencingEnemyHeroes:0,avgTimeSpentDead:0,timeDeadPct:0},levelAdvTime:0,maxLevelAdv:0,avgLevelAdv:0,levelAdvPct:0,uptime:[],uptimeHistogram:{},wipes:0,avgHeroesAlive:0,aces:0,timeWithHeroAdv:0,pctWithHeroAdv:0,passiveXPRate:0,passiveXPDiff:0,passiveXPGain:0}}}static extractBattleTags(e,r,n){let i=e.extractFile("replay.server.battlelobby");if(i)try{let a=new RegExp("([\\p{L}\\d]{3,24}#\\d{4,10})[z\xD8]?","gu"),s=i.toString("utf8").match(a);if(!s)return;let o=0;for(let l of r.m_playerList){if(!l?.m_toon)continue;let c=k(l.m_name);for(;o<s.length;){let u=s[o].split("#"),m=u[0],p=u[1].replace(/[zØ]/g,"");if(o++,m===c){let d=l.m_toon,h=`${d.m_region}-${k(d.m_programId)}-${d.m_realm}-${d.m_id}`;n[h]&&(n[h].tag=parseInt(p,10)||0);break}}}}catch(a){console.error("BattleTag regex error:",a)}}static extractDraft(e,r,n){if(e)try{let i=e.m_syncLobbyState;if(!i)return;let a=i.m_lobbyState,s=i.m_gameDescription;if(!a)return;s&&(r.randomValue=s.m_randomValue,r.gameOptions=s.m_gameOptions);let o=[],l=[];for(let d of n.m_playerList){if(!d?.m_toon)continue;let h=k(d.m_hero),b=q(h)||h;d.m_teamId===0?o.push(b):d.m_teamId===1&&l.push(b)}r.picks={0:o,1:l,first:0};let c,f=s?.m_gameOptions;if(f&&typeof f.m_ammId=="number"){let d=f.m_ammId;d===50001?c="Quick Match":d===50031?c="ARAM":d===50041?c="Unranked Draft":d===50051?c="Custom":d===50061?c="Hero League":d===50071?c="Team League":d===50091&&(c="Storm League")}if(!c&&typeof a.m_gameMode=="number"){let d=a.m_gameMode;d===3?c="Quick Match":d===4?c="Custom":d===5?c="Hero League":d===6?c="Team League":d===7?c="Unranked Draft":d===8&&(c="ARAM")}if(r.mode=c,typeof a.m_gameType=="number"&&(r.type=a.m_gameType),!a.m_slots)return;let m=a.m_pickedMapTag,p=0;m!==void 0&&(p=a.m_firstPickTeam??0,r.picks.first=p)}catch{}}static extractCosmetics(e,r,n){if(e)try{let i=e.m_syncLobbyState;if(!i)return;let a=i.m_lobbyState;if(!a)return;let s=a.m_slots,o=i.m_userInitialData;if(!s)return;let l=0;for(let c of r.m_playerList){if(!c?.m_toon)continue;let f=c.m_toon,u=`${f.m_region}-${k(f.m_programId)}-${f.m_realm}-${f.m_id}`,m=n[u];for(;l<s.length;){let p=s[l];l++;let d=p.m_hero;if(!(!d||Buffer.isBuffer(d)&&d.length===0)){if(m&&(m.skin=k(p.m_skin)||"",m.mount=k(p.m_mount)||"",m.announcer=k(p.m_announcerPack)||"",m.banner=k(p.m_banner)||"",m.spray=k(p.m_spray)||"",m.silenced=!!p.m_hasSilencePenalty,m.voiceSilenced=!!p.m_hasVoiceSilencePenalty,o)){let h=o.find(b=>k(b.m_name)===m.name);h&&(m.clanTag=k(h.m_clanTag),m.highestLeague=h.m_highestLeague,m.combinedRaceLevels=h.m_combinedRaceLevels,m.randomSeed=h.m_randomSeed)}break}}}}catch{}}static processScoreEvents(e,r,n){for(let i of e){if(i._event!=="NNet.Replay.Tracker.SScoreResultEvent")continue;let a=i.m_instanceList;for(let s of a){let o=k(s.m_name),l=s.m_values,c=o.startsWith("EndOfMatchAward"),f=0;for(let u of l)if(u&&u.length>0&&u[0]!==void 0){let m=f+1,p=r[m];if(p&&n[p]){let d=typeof u[0]=="object"&&u[0]!==null&&"m_value"in u[0]?u[0].m_value:u[0];d!=null&&(c?d===1&&n[p].awards.push(o):n[p].gameStats[o]=d)}f++}else u&&u.length===0&&f++}}}static fileTimeToDate(e){return new Date(Number(e)/1e4-116444736e5)}};export{se as ReplayAnalyzer,$ as ReplayParser};
|
|
1
|
+
var G=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports);var pe=G((xt,me)=>{"use strict";var ue=[0,1,3,7,15,31,63,127,255],K=function(r){this.stream=r,this.bitOffset=0,this.curByte=0,this.hasByte=!1};K.prototype._ensureByte=function(){this.hasByte||(this.curByte=this.stream.readByte(),this.hasByte=!0)};K.prototype.read=function(r){for(var e=0;r>0;){this._ensureByte();var t=8-this.bitOffset;if(r>=t)e<<=t,e|=ue[t]&this.curByte,this.hasByte=!1,this.bitOffset=0,r-=t;else{e<<=r;var n=t-r;e|=(this.curByte&ue[r]<<n)>>n,this.bitOffset+=r,r=0}}return e};K.prototype.seek=function(r){var e=r%8,t=(r-e)/8;this.bitOffset=e,this.stream.seek(t),this.hasByte=!1};K.prototype.pi=function(){var r=new Buffer(6),e;for(e=0;e<r.length;e++)r[e]=this.read(8);return r.toString("hex")};me.exports=K});var he=G((vt,be)=>{"use strict";var H=function(){};H.prototype.readByte=function(){throw new Error("abstract method readByte() not implemented")};H.prototype.read=function(r,e,t){for(var n=0;n<t;){var i=this.readByte();if(i<0)return n===0?-1:n;r[e++]=i,n++}return n};H.prototype.seek=function(r){throw new Error("abstract method seek() not implemented")};H.prototype.writeByte=function(r){throw new Error("abstract method readByte() not implemented")};H.prototype.write=function(r,e,t){var n;for(n=0;n<t;n++)this.writeByte(r[e++]);return t};H.prototype.flush=function(){};be.exports=H});var ge=G((Tt,_e)=>{"use strict";_e.exports=(function(){var r=new Uint32Array([0,79764919,159529838,222504665,319059676,398814059,445009330,507990021,638119352,583659535,797628118,726387553,890018660,835552979,1015980042,944750013,1276238704,1221641927,1167319070,1095957929,1595256236,1540665371,1452775106,1381403509,1780037320,1859660671,1671105958,1733955601,2031960084,2111593891,1889500026,1952343757,2552477408,2632100695,2443283854,2506133561,2334638140,2414271883,2191915858,2254759653,3190512472,3135915759,3081330742,3009969537,2905550212,2850959411,2762807018,2691435357,3560074640,3505614887,3719321342,3648080713,3342211916,3287746299,3467911202,3396681109,4063920168,4143685023,4223187782,4286162673,3779000052,3858754371,3904687514,3967668269,881225847,809987520,1023691545,969234094,662832811,591600412,771767749,717299826,311336399,374308984,453813921,533576470,25881363,88864420,134795389,214552010,2023205639,2086057648,1897238633,1976864222,1804852699,1867694188,1645340341,1724971778,1587496639,1516133128,1461550545,1406951526,1302016099,1230646740,1142491917,1087903418,2896545431,2825181984,2770861561,2716262478,3215044683,3143675388,3055782693,3001194130,2326604591,2389456536,2200899649,2280525302,2578013683,2640855108,2418763421,2498394922,3769900519,3832873040,3912640137,3992402750,4088425275,4151408268,4197601365,4277358050,3334271071,3263032808,3476998961,3422541446,3585640067,3514407732,3694837229,3640369242,1762451694,1842216281,1619975040,1682949687,2047383090,2127137669,1938468188,2001449195,1325665622,1271206113,1183200824,1111960463,1543535498,1489069629,1434599652,1363369299,622672798,568075817,748617968,677256519,907627842,853037301,1067152940,995781531,51762726,131386257,177728840,240578815,269590778,349224269,429104020,491947555,4046411278,4126034873,4172115296,4234965207,3794477266,3874110821,3953728444,4016571915,3609705398,3555108353,3735388376,3664026991,3290680682,3236090077,3449943556,3378572211,3174993278,3120533705,3032266256,2961025959,2923101090,2868635157,2813903052,2742672763,2604032198,2683796849,2461293480,2524268063,2284983834,2364738477,2175806836,2238787779,1569362073,1498123566,1409854455,1355396672,1317987909,1246755826,1192025387,1137557660,2072149281,2135122070,1912620623,1992383480,1753615357,1816598090,1627664531,1707420964,295390185,358241886,404320391,483945776,43990325,106832002,186451547,266083308,932423249,861060070,1041341759,986742920,613929101,542559546,756411363,701822548,3316196985,3244833742,3425377559,3370778784,3601682597,3530312978,3744426955,3689838204,3819031489,3881883254,3928223919,4007849240,4037393693,4100235434,4180117107,4259748804,2310601993,2373574846,2151335527,2231098320,2596047829,2659030626,2470359227,2550115596,2947551409,2876312838,2788305887,2733848168,3165939309,3094707162,3040238851,2985771188]),e=function(){var t=4294967295;this.getCRC=function(){return~t>>>0},this.updateCRC=function(n){t=t<<8^r[(t>>>24^n)&255]},this.updateCRCRun=function(n,i){for(;i-- >0;)t=t<<8^r[(t>>>24^n)&255]}};return e})()});var ye=G((kt,Ue)=>{Ue.exports={name:"seek-bzip",version:"2.0.0",contributors:["C. Scott Ananian (http://cscott.net)","Eli Skeggs","Kevin Kwok","Rob Landley (http://landley.net)"],description:"a pure-JavaScript Node.JS module for random-access decoding bzip2 data",main:"./lib/index.js",repository:{type:"git",url:"https://github.com/cscott/seek-bzip.git"},license:"MIT",bin:{"seek-bunzip":"./bin/seek-bunzip","seek-table":"./bin/seek-bzip-table"},directories:{test:"test"},dependencies:{commander:"^6.0.0"},devDependencies:{fibers:"^5.0.0",mocha:"^8.1.0"},scripts:{test:"mocha"}}});var Pe=G((St,Ee)=>{"use strict";var ze=pe(),j=he(),ke=ge(),Se=ye(),Y=20,xe=258,ve=0,Ne=1,Fe=2,Xe=6,Ge=50,Ke="314159265359",je="177245385090",Te=function(r,e){var t=r[e],n;for(n=e;n>0;n--)r[n]=r[n-1];return r[0]=t,t},g={OK:0,LAST_BLOCK:-1,NOT_BZIP_DATA:-2,UNEXPECTED_INPUT_EOF:-3,UNEXPECTED_OUTPUT_EOF:-4,DATA_ERROR:-5,OUT_OF_MEMORY:-6,OBSOLETE_INPUT:-7,END_OF_BLOCK:-8},I={};I[g.LAST_BLOCK]="Bad file checksum";I[g.NOT_BZIP_DATA]="Not bzip data";I[g.UNEXPECTED_INPUT_EOF]="Unexpected input EOF";I[g.UNEXPECTED_OUTPUT_EOF]="Unexpected output EOF";I[g.DATA_ERROR]="Data error";I[g.OUT_OF_MEMORY]="Out of memory";I[g.OBSOLETE_INPUT]="Obsolete (pre 0.9.5) bzip format not supported.";var T=function(r,e){var t=I[r]||"unknown error";e&&(t+=": "+e);var n=new TypeError(t);throw n.errorCode=r,n},S=function(r,e){this.writePos=this.writeCurrent=this.writeCount=0,this._start_bunzip(r,e)};S.prototype._init_block=function(){var r=this._get_next_block();return r?(this.blockCRC=new ke,!0):(this.writeCount=-1,!1)};S.prototype._start_bunzip=function(r,e){var t=new Buffer(4);(r.read(t,0,4)!==4||String.fromCharCode(t[0],t[1],t[2])!=="BZh")&&T(g.NOT_BZIP_DATA,"bad magic");var n=t[3]-48;(n<1||n>9)&&T(g.NOT_BZIP_DATA,"level out of range"),this.reader=new ze(r),this.dbufSize=1e5*n,this.nextoutput=0,this.outputStream=e,this.streamCRC=0};S.prototype._get_next_block=function(){var r,e,t,n=this.reader,i=n.pi();if(i===je)return!1;i!==Ke&&T(g.NOT_BZIP_DATA),this.targetBlockCRC=n.read(32)>>>0,this.streamCRC=(this.targetBlockCRC^(this.streamCRC<<1|this.streamCRC>>>31))>>>0,n.read(1)&&T(g.OBSOLETE_INPUT);var a=n.read(24);a>this.dbufSize&&T(g.DATA_ERROR,"initial position out of bounds");var s=n.read(16),o=new Buffer(256),c=0;for(r=0;r<16;r++)if(s&1<<15-r){var l=r*16;for(t=n.read(16),e=0;e<16;e++)t&1<<15-e&&(o[c++]=l+e)}var f=n.read(3);(f<Fe||f>Xe)&&T(g.DATA_ERROR);var u=n.read(15);u===0&&T(g.DATA_ERROR);var m=new Buffer(256);for(r=0;r<f;r++)m[r]=r;var b=new Buffer(u);for(r=0;r<u;r++){for(e=0;n.read(1);e++)e>=f&&T(g.DATA_ERROR);b[r]=Te(m,e)}var d=c+2,h=[],p;for(e=0;e<f;e++){var _=new Buffer(d),y=new Uint16Array(Y+1);for(s=n.read(5),r=0;r<d;r++){for(;(s<1||s>Y)&&T(g.DATA_ERROR),!!n.read(1);)n.read(1)?s--:s++;_[r]=s}var x,P;for(x=P=_[0],r=1;r<d;r++)_[r]>P?P=_[r]:_[r]<x&&(x=_[r]);p={},h.push(p),p.permute=new Uint16Array(xe),p.limit=new Uint32Array(Y+2),p.base=new Uint32Array(Y+1),p.minLen=x,p.maxLen=P;var A=0;for(r=x;r<=P;r++)for(y[r]=p.limit[r]=0,s=0;s<d;s++)_[s]===r&&(p.permute[A++]=s);for(r=0;r<d;r++)y[_[r]]++;for(A=s=0,r=x;r<P;r++)A+=y[r],p.limit[r]=A-1,A<<=1,s+=y[r],p.base[r+1]=A-s;p.limit[P+1]=Number.MAX_VALUE,p.limit[P]=A+y[P]-1,p.base[x]=0}var N=new Uint32Array(256);for(r=0;r<256;r++)m[r]=r;var M=0,C=0,le=0,E,F=this.dbuf=new Uint32Array(this.dbufSize);for(d=0;;){for(d--||(d=Ge-1,le>=u&&T(g.DATA_ERROR),p=h[b[le++]]),r=p.minLen,e=n.read(r);r>p.maxLen&&T(g.DATA_ERROR),!(e<=p.limit[r]);r++)e=e<<1|n.read(1);e-=p.base[r],(e<0||e>=xe)&&T(g.DATA_ERROR);var X=p.permute[e];if(X===ve||X===Ne){M||(M=1,s=0),X===ve?s+=M:s+=2*M,M<<=1;continue}if(M)for(M=0,C+s>this.dbufSize&&T(g.DATA_ERROR),E=o[m[0]],N[E]+=s;s--;)F[C++]=E;if(X>c)break;C>=this.dbufSize&&T(g.DATA_ERROR),r=X-1,E=Te(m,r),E=o[E],N[E]++,F[C++]=E}for((a<0||a>=C)&&T(g.DATA_ERROR),e=0,r=0;r<256;r++)t=e+N[r],N[r]=e,e=t;for(r=0;r<C;r++)E=F[r]&255,F[N[E]]|=r<<8,N[E]++;var Z=0,fe=0,de=0;return C&&(Z=F[a],fe=Z&255,Z>>=8,de=-1),this.writePos=Z,this.writeCurrent=fe,this.writeCount=C,this.writeRun=de,!0};S.prototype._read_bunzip=function(r,e){var t,n,i;if(this.writeCount<0)return 0;for(var a=0,s=this.dbuf,o=this.writePos,c=this.writeCurrent,l=this.writeCount,f=this.outputsize,u=this.writeRun;l;){for(l--,n=c,o=s[o],c=o&255,o>>=8,u++===3?(t=c,i=n,c=-1):(t=1,i=c),this.blockCRC.updateCRCRun(i,t);t--;)this.outputStream.writeByte(i),this.nextoutput++;c!=n&&(u=0)}return this.writeCount=l,this.blockCRC.getCRC()!==this.targetBlockCRC&&T(g.DATA_ERROR,"Bad block CRC (got "+this.blockCRC.getCRC().toString(16)+" expected "+this.targetBlockCRC.toString(16)+")"),this.nextoutput};var ne=function(r){if("readByte"in r)return r;var e=new j;return e.pos=0,e.readByte=function(){return r[this.pos++]},e.seek=function(t){this.pos=t},e.eof=function(){return this.pos>=r.length},e},we=function(r){var e=new j,t=!0;if(r)if(typeof r=="number")e.buffer=new Buffer(r),t=!1;else{if("writeByte"in r)return r;e.buffer=r,t=!1}else e.buffer=new Buffer(16384);return e.pos=0,e.writeByte=function(n){if(t&&this.pos>=this.buffer.length){var i=new Buffer(this.buffer.length*2);this.buffer.copy(i),this.buffer=i}this.buffer[this.pos++]=n},e.getBuffer=function(){if(this.pos!==this.buffer.length){if(!t)throw new TypeError("outputsize does not match decoded input");var n=new Buffer(this.pos);this.buffer.copy(n,0,0,this.pos),this.buffer=n}return this.buffer},e._coerced=!0,e};S.Err=g;S.decode=function(r,e,t){for(var n=ne(r),i=we(e),a=new S(n,i);!("eof"in n&&n.eof());)if(a._init_block())a._read_bunzip();else{var s=a.reader.read(32)>>>0;if(s!==a.streamCRC&&T(g.DATA_ERROR,"Bad stream CRC (got "+a.streamCRC.toString(16)+" expected "+s.toString(16)+")"),t&&"eof"in n&&!n.eof())a._start_bunzip(n,i);else break}if("getBuffer"in i)return i.getBuffer()};S.decodeBlock=function(r,e,t){var n=ne(r),i=we(t),a=new S(n,i);a.reader.seek(e);var s=a._get_next_block();if(s&&(a.blockCRC=new ke,a.writeCopies=0,a._read_bunzip()),"getBuffer"in i)return i.getBuffer()};S.table=function(r,e,t){var n=new j;n.delegate=ne(r),n.pos=0,n.readByte=function(){return this.pos++,this.delegate.readByte()},n.delegate.eof&&(n.eof=n.delegate.eof.bind(n.delegate));var i=new j;i.pos=0,i.writeByte=function(){this.pos++};for(var a=new S(n,i),s=a.dbufSize;!("eof"in n&&n.eof());){var o=n.pos*8+a.reader.bitOffset;if(a.reader.hasByte&&(o-=8),a._init_block()){var c=i.pos;a._read_bunzip(),e(o,i.pos-c)}else{var l=a.reader.read(32);if(t&&"eof"in n&&!n.eof())a._start_bunzip(n,i),console.assert(a.dbufSize===s,"shouldn't change block size within multistream file");else break}}};S.Stream=j;S.version=Se.version;S.license=Se.license;Ee.exports=S});import*as Be from"fs";import*as Q from"zlib";var Qe=Pe(),De=512,Ve=65536,We=16777216,$e=67108864,qe=2147483648,Ze={TABLE_OFFSET:0,HASH_A:1,HASH_B:2,TABLE:3};function Ye(){let r=1048577,e=new Uint32Array(256*5);for(let t=0;t<256;t++){let n=t;for(let i=0;i<5;i++){r=(r*125+3)%2796203;let a=(r&65535)<<16;r=(r*125+3)%2796203;let s=r&65535;e[n]=(a|s)>>>0,n+=256}}return e}var Re=Ye(),J=class{file;header;hashTable;blockTable;files;constructor(e,t=!0){if(Buffer.isBuffer(e)?this.file=e:this.file=Be.readFileSync(e),this.header=this.readHeader(),this.hashTable=this.readTable("hash"),this.blockTable=this.readTable("block"),t){let n=this.readFile("(listfile)");n?this.files=n.toString("utf8").trim().split(`\r
|
|
2
|
+
`):this.files=null}else this.files=null}readHeader(){let e=this.file.toString("utf8",0,4),t;if(e==="MPQ")t=this.readMPQHeader(),t.offset=0;else if(e==="MPQ\x1B"){let n=this.readMPQUserDataHeader();t=this.readMPQHeader(n.mpqHeaderOffset),t.offset=n.mpqHeaderOffset,t.userDataHeader=n}else throw new Error("Invalid MPQ file header");return t}readMPQHeader(e=0){let t=this.file.subarray(e,e+32),n={magic:t.toString("utf8",0,4),headerSize:t.readUInt32LE(4),archiveSize:t.readUInt32LE(8),formatVersion:t.readUInt16LE(12),sectorSizeShift:t.readUInt16LE(14),hashTableOffset:t.readUInt32LE(16),blockTableOffset:t.readUInt32LE(20),hashTableEntries:t.readUInt32LE(24),blockTableEntries:t.readUInt32LE(28)};if(n.formatVersion===1){let i=this.file.subarray(e+32,e+32+12);n.extendedBlockTableOffset=i.readUInt32LE(0)+i.readUInt32LE(4)*4294967296,n.hashTableOffsetHigh=i.readInt8(8),n.blockTableOffsetHigh=i.readInt8(10)}return n}readMPQUserDataHeader(){let e=this.file.subarray(0,16),t={magic:e.toString("utf8",0,4),userDataSize:e.readUInt32LE(4),mpqHeaderOffset:e.readUInt32LE(8),userDataHeaderSize:e.readUInt32LE(12)};return t.content=this.file.subarray(16,16+t.userDataHeaderSize),t}readTable(e){let t=e==="hash"?"hashTableOffset":"blockTableOffset",n=e==="hash"?"hashTableEntries":"blockTableEntries",i=this.header[t],a=this.header[n];if(i==null||a==null)throw new Error("Missing "+e+" offset or entries");let s=this.hash("("+e+" table)","TABLE"),o=this.file.subarray(i+(this.header.offset||0),i+(this.header.offset||0)+a*16);o=this.decrypt(o,s);let c=[];for(let l=0;l<a;l++){let f=o.subarray(l*16,l*16+16);e==="hash"?c.push({hashA:f.readUInt32LE(0),hashB:f.readUInt32LE(4),locale:f.readUInt16LE(8),platform:f.readUInt16LE(10),blockTableIndex:f.readUInt32LE(12)}):c.push({offset:f.readUInt32LE(0),archivedSize:f.readUInt32LE(4),size:f.readUInt32LE(8),flags:f.readUInt32LE(12)})}return c}getHashTableEntry(e){let t=this.hash(e,"HASH_A"),n=this.hash(e,"HASH_B");for(let i of this.hashTable)if(i.hashA===t&&i.hashB===n)return i}readFile(e,t=!1){function n(c){let l=c[0];if(l===0)return c;if(l===2)return Q.inflateSync(c.subarray(1));if(l===16)return Qe.decode(c.subarray(1));try{return Q.inflateSync(c.subarray(1))}catch{return Q.inflateRawSync(c.subarray(1))}}let i=this.getHashTableEntry(e);if(!i)return null;let a=this.blockTable[i.blockTableIndex];if(!a||!(a.flags&qe))return null;if(a.archivedSize===0)return Buffer.alloc(0);let s=a.offset+(this.header.offset||0),o=this.file.subarray(s,s+a.archivedSize);if(a.flags&Ve)throw new Error("Encryption is not supported");if(a.flags&We)a.flags&De&&(t||a.size>a.archivedSize)&&(o=n(o));else{let c=512<<this.header.sectorSizeShift,l=Math.trunc(a.size/c)+1,f=!1;a.flags&$e&&(f=!0,l+=1);let u=[];for(let h=0;h<l+1;h++)u.push(o.readUInt32LE(4*h));let m=u.length-(f?2:1),b=[],d=a.size;for(let h=0;h<m;h++){let p=o.subarray(u[h],u[h+1]);a.flags&De&&(t||d>p.length)&&(p=n(p)),d-=p.length,b.push(p)}o=Buffer.concat(b)}return o}hash(e,t){let n=2146271213,i=4008636142;for(let a=0;a<e.length;a++){let s=e.toUpperCase().charCodeAt(a);n=(Re[(Ze[t]<<8)+s]^n+i)>>>0,i=s+n+i+(i<<5)+3>>>0}return n}decrypt(e,t){let n=t>>>0,i=4008636142,a=Buffer.alloc(e.length),s=e.length/4;for(let o=0;o<s;o++){i=i+Re[1024+(n&255)]>>>0;let c=e.readUInt32LE(o*4);c=(c^n+i)>>>0,n=((~n<<21)+286331153|n>>>11)>>>0,i=c+i+(i<<5)+3>>>0,a.writeUInt32LE(c,o*4)}return a}};var V=class extends Error{constructor(e="Truncated Buffer"){super(e),this.name="TruncatedError"}},L=class extends Error{constructor(e="Corrupted Buffer"){super(e),this.name="CorruptedError"}},W=class{_data;_used;_next;_nextbits;_bigendian;constructor(e,t="big"){this._data=e,this._used=0,this._next=0,this._nextbits=0,this._bigendian=t==="big"}done(){return this._nextbits===0&&this._used>=this._data.length}used_bits(){return this._used*8-this._nextbits}byte_align(){this._nextbits=0}read_aligned_bytes(e){if(this.byte_align(),this._used+e>this._data.length)throw new V;let t=this._data.subarray(this._used,this._used+e);return this._used+=e,t}read_bits(e){let t=0,n=0;for(;n!==e;){if(this._nextbits===0){if(this.done())throw new V;this._next=this._data[this._used],this._used+=1,this._nextbits=8}let i=Math.min(e-n,this._nextbits),a=this._next&(1<<i)-1;this._bigendian?t+=a*Math.pow(2,e-n-i):t+=a*Math.pow(2,n),this._next>>=i,this._nextbits-=i,n+=i}return t}read_bits_bigint(e){let t=0n,n=0;for(;n!==e;){if(this._nextbits===0){if(this.done())throw new V;this._next=this._data[this._used],this._used+=1,this._nextbits=8}let i=Math.min(e-n,this._nextbits),a=BigInt(this._next&(1<<i)-1);this._bigendian?t|=a<<BigInt(e-n-i):t|=a<<BigInt(n),this._next>>=i,this._nextbits-=i,n+=i}return t}read_unaligned_bytes(e){let t=Buffer.alloc(e);for(let n=0;n<e;n++)t[n]=this.read_bits(8);return t}};var O=class{_buffer;_typeinfos;constructor(e,t){this._buffer=new W(e),this._typeinfos=t}instance(e){if(e>=this._typeinfos.length)throw new L(`Invalid typeid ${e}`);let t=this._typeinfos[e],n=t[0],i=t[1]||[],a=this[n];if(typeof a!="function")throw new Error(`Decoder method ${n} not implemented`);return a.apply(this,i)}byte_align(){this._buffer.byte_align()}done(){return this._buffer.done()}used_bits(){return this._buffer.used_bits()}_array(e,t){let n=this._int(e),i=new Array(n);for(let a=0;a<n;a++)i[a]=this.instance(t);return i}_bitarray(e){let t=this._int(e);return[t,this._buffer.read_bits(t)]}_blob(e){let t=this._int(e);return this._buffer.read_aligned_bytes(t)}_bool(){return this._int([0,1])!==0}_choice(e,t){let n=this._int(e);if(!(n in t))throw new L(`Choice tag ${n} not found`);let i=t[n];return{[i[0]]:this.instance(i[1])}}_fourcc(){let e=this._buffer.read_bits(32),t=Buffer.alloc(4);return t.writeUInt32BE(e,0),t.toString("ascii")}_int(e){return e[0]+this._buffer.read_bits(e[1])}_null(){return null}_optional(e){return this._bool()?this.instance(e):null}_real32(){return this._buffer.read_unaligned_bytes(4).readFloatBE(0)}_real64(){return this._buffer.read_unaligned_bytes(8).readDoubleBE(0)}_struct(e){let t={};for(let n of e)if(n[0]==="__parent"){let i=this.instance(n[1]);if(typeof i=="object"&&i!==null&&!Array.isArray(i)&&!Buffer.isBuffer(i))t={...t,...i};else{if(e.length===1)return i;t[n[0]]=i}}else t[n[0]]=this.instance(n[1]);return t}},D=class{_buffer;_typeinfos;constructor(e,t){this._buffer=new W(e),this._typeinfos=t}instance(e){if(e>=this._typeinfos.length)throw new L(`Invalid typeid ${e}`);let t=this._typeinfos[e],n=t[0],i=t[1]||[],a=this[n];if(typeof a!="function")throw new Error(`Decoder method ${n} not implemented`);return a.apply(this,i)}byte_align(){this._buffer.byte_align()}done(){return this._buffer.done()}used_bits(){return this._buffer.used_bits()}_expect_skip(e){if(this._buffer.read_bits(8)!==e)throw new L(`Expected skip ${e}`)}_vint(){let e=this._buffer.read_bits(8),t=(e&1)!==0,n=BigInt(e>>1&63),i=6n;for(;(e&128)!==0;)e=this._buffer.read_bits(8),n|=BigInt(e&127)<<i,i+=7n;let a=t?-n:n;return a>=BigInt(Number.MIN_SAFE_INTEGER)&&a<=BigInt(Number.MAX_SAFE_INTEGER)?Number(a):a}_array(e,t){this._expect_skip(0);let n=Number(this._vint()),i=new Array(n);for(let a=0;a<n;a++)i[a]=this.instance(t);return i}_bitarray(e){this._expect_skip(1);let t=Number(this._vint());return[t,this._buffer.read_aligned_bytes(Math.floor((t+7)/8))]}_blob(e){this._expect_skip(2);let t=Number(this._vint());return this._buffer.read_aligned_bytes(t)}_bool(){return this._expect_skip(6),this._buffer.read_bits(8)!==0}_choice(e,t){this._expect_skip(3);let n=Number(this._vint());if(!(n in t))return this._skip_instance(),{};let i=t[n];return{[i[0]]:this.instance(i[1])}}_fourcc(){return this._expect_skip(7),this._buffer.read_aligned_bytes(4)}_int(e){return this._expect_skip(9),Number(this._vint())}_null(){return null}_optional(e){return this._expect_skip(4),this._buffer.read_bits(8)!==0?this.instance(e):null}_real32(){return this._expect_skip(7),this._buffer.read_aligned_bytes(4).readFloatBE(0)}_real64(){return this._expect_skip(8),this._buffer.read_aligned_bytes(8).readDoubleBE(0)}_struct(e){this._expect_skip(5);let t={},n=Number(this._vint());for(let i=0;i<n;i++){let a=Number(this._vint()),s=e.find(o=>o[2]===a);if(s)if(s[0]==="__parent"){let o=this.instance(s[1]);typeof o=="object"&&o!==null&&!Array.isArray(o)&&!Buffer.isBuffer(o)?t={...t,...o}:e.length===1?t=o:t[s[0]]=o}else t[s[0]]=this.instance(s[1]);else this._skip_instance()}return t}_skip_instance(){let e=this._buffer.read_bits(8);if(e===0){let t=Number(this._vint());for(let n=0;n<t;n++)this._skip_instance()}else if(e===1){let t=Number(this._vint());this._buffer.read_aligned_bytes(Math.floor((t+7)/8))}else if(e===2){let t=Number(this._vint());this._buffer.read_aligned_bytes(t)}else if(e===3)this._vint(),this._skip_instance();else if(e===4)this._buffer.read_bits(8)!==0&&this._skip_instance();else if(e===5){let t=Number(this._vint());for(let n=0;n<t;n++)this._vint(),this._skip_instance()}else e===6?this._buffer.read_aligned_bytes(1):e===7?this._buffer.read_aligned_bytes(4):e===8?this._buffer.read_aligned_bytes(8):e===9&&this._vint()}};import $ from"fs";import U from"path";function Je(){let r=[];try{r.push(U.resolve(__dirname,"..","protocols")),r.push(U.resolve(__dirname,"..","..","protocols"))}catch{}r.push(U.resolve(process.cwd(),"protocols"));let e=process.cwd();for(;e!==U.dirname(e);){let t=U.join(e,"node_modules","@astefanski","storm-parser","protocols");r.push(t),e=U.dirname(e)}for(let t of r)if($.existsSync(t)&&$.readdirSync(t).some(n=>n.endsWith(".json")))return t;throw new Error(`@astefanski/storm-parser: Protocols directory not found. Did postinstall run? Try: npx tsx node_modules/@astefanski/storm-parser/scripts/postinstall.ts
|
|
3
|
+
Searched: `+r.join(", "))}var ie=new Map,ae=null;function Ce(){return ae||(ae=Je()),ae}function ee(r){if(ie.has(r))return ie.get(r);let e=Ce(),t=U.join(e,`protocol${r}.json`);if(!$.existsSync(t))return null;let n=JSON.parse($.readFileSync(t,"utf-8"));return ie.set(r,n),n}function te(){let r=Ce();return $.readdirSync(r).filter(e=>/^protocol\d+\.json$/.test(e)).map(e=>parseInt(e.match(/\d+/)[0],10)).sort((e,t)=>e-t)}var z=class{mpq;header;build=0;protocol;baseProtocol;constructor(e){e&&(this.mpq=new J(e,!1))}init(){let e=ee(29406);if(!e)throw new Error("Base protocol29406 not found. Did postinstall run? Try: npx tsx node_modules/@astefanski/storm-parser/scripts/postinstall.ts");this.baseProtocol=e;let t=this.mpq.header.userDataHeader;if(!t||!t.content)throw new Error("Replay does not have a user data header");let n=new D(t.content,this.baseProtocol.typeinfos);this.header=n.instance(this.baseProtocol.replay_header_typeid),this.build=this.header.m_version.m_baseBuild,this.protocol=this.loadProtocolForBuild(this.build)}loadProtocolForBuild(e){let t=ee(e);if(!t){let n=te(),i=n[0];for(let a of n)a<=e&&a>i&&(i=a);t=ee(i)}if(!t)throw new Error(`No protocol found for build ${e}`);return t}*decodeEventStream(e,t,n,i){if(!this.protocol)throw new Error("Protocol not loaded");let a=0;for(;!e.done();){let s=e.used_bits(),o=e.instance(this.protocol.svaruint32_typeid),c=Object.keys(o)[0],l=o[c];a+=l;let f=i?e.instance(this.protocol.replay_userid_typeid):void 0,u=Number(e.instance(t)),m=n[u];if(!m)throw new Error(`Unknown eventid(${u})`);let b=m[0],d=m[1],h=e.instance(b);h._event=d,h._eventid=u,h._gameloop=a,i&&(h._userid=f),e.byte_align(),h._bits=e.used_bits()-s,yield h}}getDetails(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.details");return e?new D(e,this.protocol.typeinfos).instance(this.protocol.game_details_typeid):null}getInitData(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.initData");return e?new O(e,this.protocol.typeinfos).instance(this.protocol.replay_initdata_typeid):null}getTrackerEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.tracker.events");if(!e)return[];let t=new D(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(t,this.protocol.tracker_eventid_typeid,this.protocol.tracker_event_types,!1))}getGameEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.game.events");if(!e)return[];let t=new O(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(t,this.protocol.game_eventid_typeid,this.protocol.game_event_types,!0))}getAttributeEvents(){if(!this.protocol)throw new Error("Protocol not loaded");let e=this.mpq.readFile("replay.attributes.events");return e?new D(e,this.protocol.typeinfos).instance(this.protocol.replay_attributes_events_typeid):null}extractFile(e){return this.mpq.readFile(e)}getHeader(){return this.header}getBuild(){return this.build}};var se=class extends z{constructor(e){super();let t=e;if(!t){let n=te();t=n[n.length-1]}this.protocol=this.loadProtocolForBuild(t)}parseTracker(e){if(!this.protocol)return[];try{let t=new D(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(t,this.protocol.tracker_eventid_typeid,this.protocol.tracker_event_types,!1))}catch(t){return console.error("[LiveStreamParser] Failed to parse tracker events",t),[]}}parseGame(e){if(!this.protocol)return[];try{let t=new O(e,this.protocol.typeinfos);return Array.from(this.decodeEventStream(t,this.protocol.game_eventid_typeid,this.protocol.game_event_types,!0))}catch(t){return console.error("[LiveStreamParser] Failed to parse game events",t),[]}}};var Ie=["Abathur","Alarak","Alexstrasza","Ana","Anduin","Anubarak","Artanis","Arthas","Auriel","Azmodan","Blaze","Brightwing","Cassia","Chen","Cho","Chromie","Deathwing","Deckard","Dehaka","Diablo","DVa","ETC","Falstad","Fenix","Gall","Garrosh","Gazlowe","Genji","Greymane","Guldan","Hanzo","Hogger","Illidan","Imperius","Jaina","Johanna","Junkrat","Kaelthas","KelThuzad","Kerrigan","Kharazim","Leoric","LiLi","LiMing","LtMorales","Lunara","Maiev","Malfurion","MalGanis","Malthael","Medivh","Mei","Mephisto","Muradin","Murky","Nazeebo","Nova","Orphea","Probius","Qhira","Ragnaros","Raynor","Rehgar","Rexxar","Samuro","SgtHammer","Sonya","Stitches","Stukov","Sylvanas","Tassadar","TheButcher","TheLostVikings","Thrall","Tracer","Tychus","Tyrael","Tyrande","Uther","Valeera","Valla","Varian","Whitemane","Xul","Yrel","Zagara","Zarya","Zeratul","Zuljin"],Ae={FaerieDragon:"Brightwing",Amazon:"Cassia",Barbarian:"Sonya",Crusader:"Johanna",DemonHunter:"Valla",WitchDoctor:"Nazeebo",Monk:"Kharazim",Wizard:"LiMing",Tinker:"Gazlowe",Medic:"LtMorales",L90ETC:"ETC",Butcher:"TheButcher",LostVikings:"TheLostVikings",Necromancer:"Xul",Dryad:"Lunara",Shapeshifter:"Greymane",ChoGall:"Cho"};function q(r){if(!r)return null;if(Ie.includes(r))return r;if(Ae[r])return Ae[r];let e=r.replace(/[^a-zA-Z0-9]/g,"").toLowerCase(),t=Ie.find(n=>n.toLowerCase()===e);return t||null}var Me={TownCannonTowerL2:"Fort Tower",TownCannonTowerL3:"Keep Tower",TownTownHallL2:"Fort",TownTownHallL3:"Keep",TownMoonwellL2:"Fort Well",TownMoonwellL3:"Keep Well"},et={MercLanerMeleeKnight:"Bruiser Camp",MercLanerRangedMage:"Bruiser Camp",MercLanerSiegeGiant:"Siege Camp",MercLanerRangedMinion:"Siege Camp"};function B(r){return Buffer.isBuffer(r)?r.toString("utf8"):typeof r=="string"?r:String(r??"")}function v(r,e){if(!r)return;let t=r.find(n=>B(n.m_key)===e);return t!==void 0?t.m_value:void 0}function re(r,e){if(!r)return;let t=r.find(n=>B(n.m_key)===e);return t!==void 0?B(t.m_value):void 0}function w(r,e){if(!r)return;let t=r.find(n=>B(n.m_key)===e);return t!==void 0?t.m_value:void 0}function oe(r,e){return`${r}-${e}`}function R(r,e){return(r-e)/16}function He(r,e,t){let n={playerIDMap:{},loopGameStart:0,loopGameEnd:0,unitIndex:{},heroUnits:{},heroLives:{}};t.bans||(t.bans={0:[],1:[]}),t.levelTimes={0:{},1:{}},t.takedowns=[],t.structures={},t.XPBreakdown=[],t.mercs={captures:[],units:{}},t.objective={0:{count:0,events:[]},1:{count:0,events:[]},type:t.map||""};for(let i of r)switch(n.loopGameEnd=Math.max(n.loopGameEnd,i._gameloop),i._event){case"NNet.Replay.Tracker.SStatGameEvent":tt(i,n,e,t);break;case"NNet.Replay.Tracker.SHeroBannedEvent":if(i.m_hero){let a=B(i.m_hero),s=q(a);if(!s)break;let o=i.m_controllingTeam===2?1:0;if(t.bans&&t.bans[o]){let c=t.bans[o].length+1,l=t.bans[0].length+t.bans[1].length+1;t.bans[o].push({hero:s,order:c,absolute:l})}}break;case"NNet.Replay.Tracker.SUnitBornEvent":it(i,n,t);break;case"NNet.Replay.Tracker.SUnitDiedEvent":at(i,n,t);break;case"NNet.Replay.Tracker.SUnitOwnerChangeEvent":st(i,n);break}return t.loopGameStart=n.loopGameStart,t.loopLength=n.loopGameEnd,t.length=(n.loopGameEnd-n.loopGameStart)/16,ot(n,e),{playerIDMap:n.playerIDMap}}function tt(r,e,t,n){let i=B(r.m_eventName),a=r.m_intData,s=r.m_stringData,o=r.m_fixedData;switch(i){case"PlayerInit":{let c=v(a,"PlayerID"),l=re(s,"ToonHandle");c!==void 0&&l&&t[l]&&(e.playerIDMap[c]=l);break}case"GatesOpen":e.loopGameStart=r._gameloop;break;case"LevelUp":{let c=v(a,"PlayerID"),l=v(a,"Level");if(c===void 0||l===void 0)break;let f;if(c>=1&&c<=5)f="0";else if(c>=6&&c<=10)f="1";else break;n.levelTimes[f][String(l)]||(n.levelTimes[f][String(l)]={loop:r._gameloop,level:l,team:f,time:R(r._gameloop,e.loopGameStart)});break}case"TalentChosen":{let c=v(a,"PlayerID"),l=re(s,"PurchaseName");if(c===void 0||!l||l==="Win"||l==="Loss"||l.startsWith("Hero"))break;let f=n.map?.replace(/\s+/g,"")||"";if(l===f)break;let u=e.playerIDMap[c];if(!u||!t[u])break;let m=["Tier1Choice","Tier2Choice","Tier3Choice","Tier4Choice","Tier5Choice","Tier6Choice","Tier7Choice"];for(let b of m)if(!t[u].talents[b]){t[u].talents[b]=l;break}break}case"PlayerDeath":{let c=v(a,"PlayerID"),l=v(a,"KillingPlayer"),f=w(o,"PositionX")??0,u=w(o,"PositionY")??0;if(c===void 0)break;let m=e.playerIDMap[c];if(!m)break;let b={player:m,hero:t[m]?.hero||""},d=[],h=t[m]?.team;if(l&&l>0){let _=e.playerIDMap[l];_&&t[_]&&d.push({player:_,hero:t[_].hero})}for(let[_,y]of Object.entries(e.playerIDMap)){let x=t[y];!x||x.team===h||parseInt(_)===l||d.push({player:y,hero:x.hero})}let p={loop:r._gameloop,time:R(r._gameloop,e.loopGameStart),x:f,y:u,killers:d,victim:b};n.takedowns.push(p),t[m]&&t[m].deaths.push(p);for(let _ of d)t[_.player]&&t[_.player].takedowns.push(p);break}case"PeriodicXPBreakdown":{let c=v(a,"Team");if(c===void 0)break;let l={GameTime:v(a,"GameTime")??0,PreviousGameTime:v(a,"PreviousGameTime")??0,MinionXP:w(o,"MinionXP")??0,CreepXP:w(o,"CreepXP")??0,StructureXP:w(o,"StructureXP")??0,HeroXP:w(o,"HeroXP")??0,TrickleXP:w(o,"TrickleXP")??0};n.XPBreakdown.push({loop:r._gameloop,time:R(r._gameloop,e.loopGameStart),team:c,teamLevel:v(a,"TeamLevel")??0,breakdown:l,theoreticalMinionXP:v(a,"TheoreticalMinionXP")??0});break}case"EndOfGameXPBreakdown":{let c=v(a,"Team");if(c===void 0)break;n.XPBreakdown.push({loop:r._gameloop,time:R(r._gameloop,e.loopGameStart),team:c,theoreticalMinionXP:v(a,"TheoreticalMinionXP")??0,breakdown:{GameTime:0,PreviousGameTime:0,MinionXP:w(o,"MinionXP")??0,CreepXP:w(o,"CreepXP")??0,StructureXP:w(o,"StructureXP")??0,HeroXP:w(o,"HeroXP")??0,TrickleXP:w(o,"TrickleXP")??0}});break}case"JungleCampCapture":{let c=v(a,"CampTeam")??v(a,"Team")??0;n.mercs.captures.push({loop:r._gameloop,type:re(s,"CampType")??re(s,"Result")??"Unknown Camp",team:c,time:R(r._gameloop,e.loopGameStart)});break}case"EndOfGameTalentChoices":{let c=v(a,"PlayerID");if(c===void 0)break;let l=e.playerIDMap[c];if(!l||!t[l])break;let f={};if(s)for(let u of s){let m=B(u.m_key),b=B(u.m_value);m==="Tier 1 Choice"&&b?f.Tier1Choice=b:m==="Tier 2 Choice"&&b?f.Tier2Choice=b:m==="Tier 3 Choice"&&b?f.Tier3Choice=b:m==="Tier 4 Choice"&&b?f.Tier4Choice=b:m==="Tier 5 Choice"&&b?f.Tier5Choice=b:m==="Tier 6 Choice"&&b?f.Tier6Choice=b:m==="Tier 7 Choice"&&b&&(f.Tier7Choice=b)}t[l].talents=f;break}default:nt(i,r,e,n,a,o);break}}var rt=new Set(["SoulEatersSpawned","TributeCollected","RavenCurseActivated","AltarCaptured","SkyTempleShotsFired","DragonKnightActivated","GardenTerrorActivated","InfernalShrineCaptured","PunisherKilled","VolskayaVehicleCapture","BraxisWaveStart","ImmortalDefeated","NukeExploded","PayloadDelivered","AlteracCavalryCharge","AlteracCavalry"]);function nt(r,e,t,n,i,a){if(!rt.has(r)||!i)return;let s=v(i,"Team")??v(i,"Event")??0,o=s===0||s===1?s:0,c={team:s,loop:e._gameloop,time:R(e._gameloop,t.loopGameStart),score:v(i,"Score"),duration:w(a,"Duration")};n.objective[o].events.push(c),n.objective[o].count=n.objective[o].events.length}function it(r,e,t){let n=B(r.m_unitTypeName),i=r.m_unitTagIndex,a=r.m_unitTagRecycle,s=oe(i,a),o=r.m_controlPlayerId??r.m_upkeepPlayerId,c=r.m_x??0,l=r.m_y??0,f;if(o>=1&&o<=5?f=0:o>=6&&o<=10?f=1:o===11?f=0:o===12?f=1:f=o<=5?0:1,e.unitIndex[s]={type:n,playerId:o,team:f,x:c,y:l,bornLoop:r._gameloop},n.startsWith("Town")&&Me[n]&&(t.structures[s]={type:n,name:Me[n],tag:i,rtag:a,x:c,y:l,team:f}),n.startsWith("Hero")&&o>=1&&o<=10){e.heroUnits[s]=o,e.heroLives[o]||(e.heroLives[o]=[]);let u=R(r._gameloop,e.loopGameStart);e.heroLives[o].push({born:u,locations:[{x:c,y:l,time:u}],duration:0})}if(et[n]){let m=t.mercs.captures[t.mercs.captures.length-1]?.loop??r._gameloop;t.mercs.units[s]={loop:m,team:f,type:n,locations:[{x:c,y:l}],time:R(m,e.loopGameStart),duration:0}}}function at(r,e,t){let n=oe(r.m_unitTagIndex,r.m_unitTagRecycle),i=R(r._gameloop,e.loopGameStart);t.structures[n]&&(t.structures[n].destroyedLoop=r._gameloop,t.structures[n].destroyed=i),t.mercs.units[n]&&(t.mercs.units[n].duration=i-t.mercs.units[n].time);let a=e.heroUnits[n];if(a!==void 0&&e.heroLives[a]){let s=e.heroLives[a],o=s[s.length-1];o&&o.died===void 0&&(o.died=i,o.duration=i-o.born)}}function st(r,e){let t=oe(r.m_unitTagIndex,r.m_unitTagRecycle),n=r.m_controlPlayerId??r.m_upkeepPlayerId;e.unitIndex[t]&&(e.unitIndex[t].playerId=n,n>=1&&n<=5?e.unitIndex[t].team=0:n>=6&&n<=10&&(e.unitIndex[t].team=1))}function ot(r,e){for(let[t,n]of Object.entries(r.heroLives)){let i=parseInt(t,10),a=r.playerIDMap[i];if(!a||!e[a])continue;for(let o of n)if(o.died===void 0){let c=o.locations[o.locations.length-1];o.duration=c?c.time-o.born:0}let s="";for(let[o,c]of Object.entries(r.heroUnits))if(c===i){s=o;break}s&&(e[a].units[s]={lives:n})}}var ct=["DamageTaken","CreepDamage","Healing","HeroDamage","MinionDamage","SelfHealing","SiegeDamage","ProtectionGivenToAllies","TeamfightDamageTaken","TeamfightHealingDone","TeamfightHeroDamage","TimeCCdEnemyHeroes","TimeRootingEnemyHeroes","TimeSpentDead","TimeStunningEnemyHeroes","TimeSilencingEnemyHeroes"];function lt(){return{DamageTaken:0,CreepDamage:0,Healing:0,HeroDamage:0,MinionDamage:0,SelfHealing:0,SiegeDamage:0,ProtectionGivenToAllies:0,TeamfightDamageTaken:0,TeamfightHealingDone:0,TeamfightHeroDamage:0,TimeCCdEnemyHeroes:0,TimeRootingEnemyHeroes:0,TimeSpentDead:0,TimeStunningEnemyHeroes:0,TimeSilencingEnemyHeroes:0,avgTimeSpentDead:0,timeDeadPct:0}}function ft(){return{mercCaptures:0,mercUptime:0,mercUptimePercent:0,structures:{},KDA:0,PPK:0,timeTo10:0,totals:lt(),levelAdvTime:0,maxLevelAdv:0,avgLevelAdv:0,levelAdvPct:0,uptime:[],uptimeHistogram:{},wipes:0,avgHeroesAlive:0,aces:0,timeWithHeroAdv:0,pctWithHeroAdv:0,passiveXPRate:0,passiveXPDiff:0,passiveXPGain:0}}function Oe(r,e){pt(r),dt(r,e),mt(r,e),bt(r),ht(r,e),gt(r)}function dt(r,e){for(let t of["0","1"]){let n=r.teams[t];if(!n)continue;n.names=[],n.heroes=[],n.tags=[],n.stats=ft();for(let u of n.ids){let m=e[u];m&&(n.names.push(m.name),n.heroes.push(m.hero),n.tags.push(m.tag))}for(let u of n.ids){let m=e[u];if(m)for(let b of ct){let d=m.gameStats[b];typeof d=="number"&&(n.stats.totals[b]+=d)}}let i=n.ids.reduce((u,m)=>u+(e[m]?.gameStats.Deaths??0),0);i>0&&(n.stats.totals.avgTimeSpentDead=n.stats.totals.TimeSpentDead/i),r.length>0&&(n.stats.totals.timeDeadPct=n.stats.totals.TimeSpentDead/(r.length*n.ids.length));let a=n.takedowns,s=i;n.stats.KDA=s>0?a/s:a,n.stats.PPK=a>0?r.takedowns.filter(u=>n.ids.includes(u.killers[0]?.player)).reduce((u,m)=>u+m.killers.length,0)/a:0;let o=r.levelTimes[t];o?.["10"]&&(n.stats.timeTo10=o[10].time);let c=parseInt(t,10),l=r.mercs.captures.filter(u=>u.team===c);n.stats.mercCaptures=l.length;let f=0;for(let u of Object.values(r.mercs.units))u.team===c&&u.duration>0&&(f+=u.duration);n.stats.mercUptime=f,n.stats.mercUptimePercent=r.length>0?f/r.length:0,ut(r,n,t)}}function ut(r,e,t){let n=parseInt(t,10),i=n===0?1:0,a={};for(let s of Object.values(r.structures)){let o=s.name;a[o]||(a[o]={lost:0,destroyed:0,first:r.length}),s.team===i&&s.destroyed!==void 0&&(a[o].destroyed++,a[o].first=Math.min(a[o].first,s.destroyed)),s.team===n&&s.destroyed!==void 0&&a[o].lost++}e.stats.structures=a}function mt(r,e){let t=r.length/60;for(let n of Object.values(e)){let i=n.gameStats,a=i.Deaths??0,s=i.TeamTakedowns??0;t>0&&(i.DPM=(i.HeroDamage??0)/t,i.HPM=((i.Healing??0)+(i.SelfHealing??0))/t,i.XPM=(i.ExperienceContribution??0)/t),i.KDA=a>0?(i.Takedowns??0)/a:i.Takedowns??0,i.KillParticipation=s>0?(i.Takedowns??0)/s:0,i.damageDonePerDeath=a>0?(i.HeroDamage??0)/a:i.HeroDamage??0,i.damageTakenPerDeath=a>0?(i.DamageTaken??0)/a:i.DamageTaken??0,i.healingDonePerDeath=a>0?((i.Healing??0)+(i.SelfHealing??0))/a:(i.Healing??0)+(i.SelfHealing??0),i.length=r.length}}function pt(r){let e=0,t=0,n=new Set(r.teams[0]?.ids||[]);for(let i of r.takedowns)n.has(i.victim.player)?t++:e++;r.team0Takedowns=e,r.team1Takedowns=t,r.teams[0]&&(r.teams[0].takedowns=e),r.teams[1]&&(r.teams[1].takedowns=t)}function bt(r){let e=r.levelTimes[0]||{},t=r.levelTimes[1]||{},n=[];for(let l of Object.values(e))n.push({time:l.time,team:0,level:l.level});for(let l of Object.values(t))n.push({time:l.time,team:1,level:l.level});if(n.sort((l,f)=>l.time-f.time),n.length===0){r.levelAdvTimeline=[];return}let i=[],a=0,s=0,o=n[0].time;for(let l of n){let f=a-s;l.time>o&&i.push({start:o,end:l.time,levelDiff:f,length:l.time-o}),l.team===0?a=l.level:s=l.level,o=l.time}let c=a-s;r.length>o&&i.push({start:o,end:r.length,levelDiff:c,length:r.length-o}),r.levelAdvTimeline=i;for(let l of["0","1"]){let f=r.teams[l];if(!f)continue;let u=l==="0"?1:-1,m=0,b=0,d=0,h=0;for(let p of i){let _=p.levelDiff*u;_>0&&(m+=p.length),b=Math.max(b,_),d+=_*p.length,h+=p.length}f.stats.levelAdvTime=m,f.stats.maxLevelAdv=b,f.stats.avgLevelAdv=h>0?d/h:0,f.stats.levelAdvPct=r.length>0?m/r.length:0}}function ht(r,e){for(let a of["0","1"]){let s=r.teams[a];if(!s)continue;let o=[];for(let p of s.ids){let _=e[p];if(_)for(let y of _.deaths){o.push({time:y.time,delta:-1});let x=y.time+_t(_.gameStats.Level??1);x<r.length&&o.push({time:x,delta:1})}}o.sort((p,_)=>p.time-_.time);let c=[{time:0,heroes:s.ids.length}],l=s.ids.length;for(let p of o)l+=p.delta,l=Math.max(0,Math.min(s.ids.length,l)),c.push({time:p.time,heroes:l});s.stats.uptime=c;let f={};for(let p=0;p<c.length;p++){let y=(p<c.length-1?c[p+1].time:r.length)-c[p].time,x=String(c[p].heroes);f[x]=(f[x]||0)+y}s.stats.uptimeHistogram=f;let u=0,m=0;for(let p=0;p<c.length;p++){let y=(p<c.length-1?c[p+1].time:r.length)-c[p].time;u+=c[p].heroes*y,m+=y}s.stats.avgHeroesAlive=m>0?u/m:s.ids.length,s.stats.wipes=c.filter(p=>p.heroes===0).length,s.stats.aces=0;let b=a==="0"?"1":"0",d=r.teams[b];d?.stats?.uptime&&(s.stats.aces=d.stats.uptime.filter(p=>p.heroes===0).length);let h=r.XPBreakdown.filter(p=>p.team===parseInt(a,10));if(h.length>0){let _=h[h.length-1].breakdown.TrickleXP;s.stats.passiveXPGain=_,s.stats.passiveXPRate=r.length>0?_/(r.length/60):0}}for(let a of["0","1"]){let s=r.teams[a],o=a==="0"?"1":"0",c=r.teams[o];if(!s||!c)continue;let l=s.stats.uptime,f=c.stats.uptime;if(!l.length||!f.length)continue;let u=new Set;for(let d of l)u.add(d.time);for(let d of f)u.add(d.time);let m=Array.from(u).sort((d,h)=>d-h),b=0;for(let d=0;d<m.length;d++){let h=m[d],_=(d<m.length-1?m[d+1]:r.length)-h,y=Le(l,h),x=Le(f,h);y>x&&(b+=_)}s.stats.timeWithHeroAdv=b,s.stats.pctWithHeroAdv=r.length>0?b/r.length:0}let t=r.teams[0]?.stats.passiveXPRate??0,n=r.teams[1]?.stats.passiveXPRate??0,i=(t+n)/2;r.teams[0]&&(r.teams[0].stats.passiveXPDiff=i>0?t/i:0),r.teams[1]&&(r.teams[1].stats.passiveXPDiff=i>0?n/i:0)}function Le(r,e){let t=0;for(let n of r)if(n.time<=e)t=n.heroes;else break;return t}function _t(r){return r<=1?15:r<=5?15+(r-1)*2:r<=10?23+(r-5)*3:r<=15?38+(r-10)*4:58+(r-15)*5}function gt(r){let e=1/0,t=-1,n=1/0,i=-1;for(let s of Object.values(r.structures))s.destroyed!==void 0&&(s.name==="Fort"&&s.destroyed<e&&(e=s.destroyed,t=s.team===0?1:0),s.name==="Keep"&&s.destroyed<n&&(n=s.destroyed,i=s.team===0?1:0));t>=0&&(r.firstFort=t,r.firstFortWin=t===r.winner),i>=0&&(r.firstKeep=i,r.firstKeepWin=i===r.winner);let a=[...r.objective[0].events.map(s=>({...s,assignedTeam:0})),...r.objective[1].events.map(s=>({...s,assignedTeam:1}))].sort((s,o)=>s.loop-o.loop);a.length>0&&(r.firstObjective=a[0].assignedTeam,r.firstObjectiveWin=a[0].assignedTeam===r.winner),r.firstPickWin=r.picks.first===r.winner}function k(r){return Buffer.isBuffer(r)?r.toString("utf8"):typeof r=="string"?r:String(r??"")}var ce=class{static async analyze(e){try{let t=new z(e);await t.init();let n=t.getDetails();if(!n)throw new Error("Missing replay.details from parsed MPQ archive");let i=t.getTrackerEvents(),a=t.getInitData(),o=t.getHeader()?.m_version??{},c={m_flags:o.m_flags??0,m_major:o.m_major??0,m_minor:o.m_minor??0,m_revision:o.m_revision??0,m_build:o.m_baseBuild??t.getBuild(),m_baseBuild:o.m_baseBuild??t.getBuild()},l=n.m_playerList.find(b=>b?.m_toon)?.m_toon,f={version:c,map:k(n.m_title),isBlizzardMap:n.m_isBlizzardMap,timeLocalOffset:Number(n.m_timeLocalOffset),gameSpeed:n.m_gameSpeed,date:this.fileTimeToDate(n.m_timeUTC).toISOString(),rawDate:Number(n.m_timeUTC),length:0,winner:-1,region:l?.m_region,playerIDs:[],heroes:[],levelTimes:{0:{},1:{}},bans:{0:[],1:[]},picks:{0:[],1:[],first:0},XPBreakdown:[],takedowns:[],mercs:{captures:[],units:{}},team0Takedowns:0,team1Takedowns:0,structures:{},objective:{0:{count:0,events:[]},1:{count:0,events:[]},type:""},teams:{0:this.emptyTeam(),1:this.emptyTeam()},winningPlayers:[],levelAdvTimeline:[],firstPickWin:!1};f.objective.type=f.map||"";let u={};for(let b of n.m_playerList){if(!b?.m_toon)continue;let d=b.m_toon,h=k(d.m_programId),p=`${d.m_region}-${h}-${d.m_realm}-${d.m_id}`,_=k(b.m_hero),y=q(_)||_;u[p]={hero:y,name:k(b.m_name),uuid:d.m_id,region:d.m_region,realm:d.m_realm,ToonHandle:p,tag:0,team:b.m_teamId,win:b.m_result===1,skin:"",mount:"",banner:"",spray:"",clanTag:"",highestLeague:0,combinedRaceLevels:0,randomSeed:0,announcer:"",silenced:!1,voiceSilenced:!1,gameStats:{},awards:[],talents:{},takedowns:[],deaths:[],units:{}},f.playerIDs.push(p),f.heroes.push(y)}this.extractBattleTags(t,n,u),this.extractDraft(a,f,n),this.extractCosmetics(a,n,u);let{playerIDMap:m}=He(i,u,f);this.processScoreEvents(i,m,u);for(let[b,d]of Object.entries(u)){d.win&&(f.winner=d.team,f.winningPlayers.push(b));let h=f.teams[d.team.toString()];h&&(h.level=Math.max(h.level,d.gameStats.Level||0),h.ids.push(b))}return Oe(f,u),{status:1,match:f,players:u}}catch(t){return console.error("ReplayAnalyzer Error:",t),{status:-2,error:String(t)}}}static emptyTeam(){return{level:0,takedowns:0,ids:[],names:[],heroes:[],tags:[],stats:{mercCaptures:0,mercUptime:0,mercUptimePercent:0,structures:{},KDA:0,PPK:0,timeTo10:0,totals:{DamageTaken:0,CreepDamage:0,Healing:0,HeroDamage:0,MinionDamage:0,SelfHealing:0,SiegeDamage:0,ProtectionGivenToAllies:0,TeamfightDamageTaken:0,TeamfightHealingDone:0,TeamfightHeroDamage:0,TimeCCdEnemyHeroes:0,TimeRootingEnemyHeroes:0,TimeSpentDead:0,TimeStunningEnemyHeroes:0,TimeSilencingEnemyHeroes:0,avgTimeSpentDead:0,timeDeadPct:0},levelAdvTime:0,maxLevelAdv:0,avgLevelAdv:0,levelAdvPct:0,uptime:[],uptimeHistogram:{},wipes:0,avgHeroesAlive:0,aces:0,timeWithHeroAdv:0,pctWithHeroAdv:0,passiveXPRate:0,passiveXPDiff:0,passiveXPGain:0}}}static extractBattleTags(e,t,n){let i=e.extractFile("replay.server.battlelobby");if(i)try{let a=new RegExp("([\\p{L}\\d]{3,24}#\\d{4,10})[z\xD8]?","gu"),s=i.toString("utf8").match(a);if(!s)return;let o=0;for(let c of t.m_playerList){if(!c?.m_toon)continue;let l=k(c.m_name);for(;o<s.length;){let u=s[o].split("#"),m=u[0],b=u[1].replace(/[zØ]/g,"");if(o++,m===l){let d=c.m_toon,h=`${d.m_region}-${k(d.m_programId)}-${d.m_realm}-${d.m_id}`;n[h]&&(n[h].tag=parseInt(b,10)||0);break}}}}catch(a){console.error("BattleTag regex error:",a)}}static extractDraft(e,t,n){if(e)try{let i=e.m_syncLobbyState;if(!i)return;let a=i.m_lobbyState,s=i.m_gameDescription;if(!a)return;s&&(t.randomValue=s.m_randomValue,t.gameOptions=s.m_gameOptions);let o=[],c=[];for(let d of n.m_playerList){if(!d?.m_toon)continue;let h=k(d.m_hero),p=q(h)||h;d.m_teamId===0?o.push(p):d.m_teamId===1&&c.push(p)}t.picks={0:o,1:c,first:0};let l,f=s?.m_gameOptions;if(f&&typeof f.m_ammId=="number"){let d=f.m_ammId;d===50001?l="Quick Match":d===50031?l="ARAM":d===50041?l="Unranked Draft":d===50051?l="Custom":d===50061?l="Hero League":d===50071?l="Team League":d===50091&&(l="Storm League")}if(!l&&typeof a.m_gameMode=="number"){let d=a.m_gameMode;d===3?l="Quick Match":d===4?l="Custom":d===5?l="Hero League":d===6?l="Team League":d===7?l="Unranked Draft":d===8&&(l="ARAM")}if(t.mode=l,typeof a.m_gameType=="number"&&(t.type=a.m_gameType),!a.m_slots)return;let m=a.m_pickedMapTag,b=0;m!==void 0&&(b=a.m_firstPickTeam??0,t.picks.first=b)}catch{}}static extractCosmetics(e,t,n){if(e)try{let i=e.m_syncLobbyState;if(!i)return;let a=i.m_lobbyState;if(!a)return;let s=a.m_slots,o=i.m_userInitialData;if(!s)return;let c=0;for(let l of t.m_playerList){if(!l?.m_toon)continue;let f=l.m_toon,u=`${f.m_region}-${k(f.m_programId)}-${f.m_realm}-${f.m_id}`,m=n[u];for(;c<s.length;){let b=s[c];c++;let d=b.m_hero;if(!(!d||Buffer.isBuffer(d)&&d.length===0)){if(m&&(m.skin=k(b.m_skin)||"",m.mount=k(b.m_mount)||"",m.announcer=k(b.m_announcerPack)||"",m.banner=k(b.m_banner)||"",m.spray=k(b.m_spray)||"",m.silenced=!!b.m_hasSilencePenalty,m.voiceSilenced=!!b.m_hasVoiceSilencePenalty,o)){let h=o.find(p=>k(p.m_name)===m.name);h&&(m.clanTag=k(h.m_clanTag),m.highestLeague=h.m_highestLeague,m.combinedRaceLevels=h.m_combinedRaceLevels,m.randomSeed=h.m_randomSeed)}break}}}}catch{}}static processScoreEvents(e,t,n){for(let i of e){if(i._event!=="NNet.Replay.Tracker.SScoreResultEvent")continue;let a=i.m_instanceList;for(let s of a){let o=k(s.m_name),c=s.m_values,l=o.startsWith("EndOfMatchAward"),f=0;for(let u of c)if(u&&u.length>0&&u[0]!==void 0){let m=f+1,b=t[m];if(b&&n[b]){let d=typeof u[0]=="object"&&u[0]!==null&&"m_value"in u[0]?u[0].m_value:u[0];d!=null&&(l?d===1&&n[b].awards.push(o):n[b].gameStats[o]=d)}f++}else u&&u.length===0&&f++}}}static fileTimeToDate(e){return new Date(Number(e)/1e4-116444736e5)}};export{se as LiveStreamParser,ce as ReplayAnalyzer,z as ReplayParser};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astefanski/storm-parser",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "Storm Parser is a tool for parsing Heroes of the Storm replays.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -24,19 +24,22 @@
|
|
|
24
24
|
"publishConfig": {
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/astefanski1/storm-parser.git"
|
|
30
|
+
},
|
|
27
31
|
"scripts": {
|
|
28
32
|
"test": "vitest run",
|
|
29
33
|
"test:watch": "vitest",
|
|
30
|
-
"lint": "eslint .
|
|
31
|
-
"lint:fix": "eslint . --fix
|
|
34
|
+
"lint": "eslint .",
|
|
35
|
+
"lint:fix": "eslint . --fix",
|
|
32
36
|
"build": "tsup",
|
|
33
37
|
"postinstall": "tsx scripts/postinstall.ts",
|
|
34
38
|
"generate:protocols": "tsx scripts/postinstall.ts"
|
|
35
39
|
},
|
|
36
40
|
"keywords": [],
|
|
37
41
|
"author": {
|
|
38
|
-
"name": "Aleksander Stefański"
|
|
39
|
-
"email": "aleksander.stefanski@outlook.com"
|
|
42
|
+
"name": "Aleksander Stefański"
|
|
40
43
|
},
|
|
41
44
|
"license": "ISC",
|
|
42
45
|
"packageManager": "pnpm@10.28.2",
|