Skip to content

Commit

Permalink
Merge pull request #90 from koliva8245/battlelobby-update
Browse files Browse the repository at this point in the history
Updated battlelobby with more accurate parsing
  • Loading branch information
barrett777 authored Jan 20, 2020
2 parents 91c6892 + fd6285c commit 16218b0
Showing 1 changed file with 80 additions and 82 deletions.
162 changes: 80 additions & 82 deletions Heroes.ReplayParser/MPQFiles/ReplayServerBattlelobby.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,71 +30,62 @@ public static void Parse(Replay replay, byte[] buffer)
return;
}

int s2mArrayLength = bitReader.ReadByte();
int stringLength = bitReader.ReadByte();

bitReader.ReadString(stringLength);

for (var i = 1; i < s2mArrayLength; i++)
{
bitReader.Read(16);
bitReader.ReadString(stringLength);
}

if (bitReader.ReadByte() != s2mArrayLength)
throw new Exception("s2ArrayLength not equal");

for (var i = 0; i < s2mArrayLength; i++)
uint dependenciesLength = bitReader.Read(6);
for (int i = 0; i < dependenciesLength; i++)
{
bitReader.ReadString(4); // s2m
bitReader.ReadBytes(2); // 0x00 0x00
bitReader.ReadString(2); // Realm
bitReader.ReadBytes(32);
bitReader.ReadBlobPrecededWithLength(10);
}

if (replay.ReplayBuild < 55929)
// s2ma cache handles
uint s2maCacheHandlesLength = bitReader.Read(6);
for (int i = 0; i < s2maCacheHandlesLength; i++)
{
bitReader.stream.Position = bitReader.stream.Position + 2632;
bitReader.AlignToByte();
if (bitReader.ReadString(4) != "s2ma")
throw new DetailedParsedException($"s2ma cache");

if (bitReader.ReadString(8) != "HumnComp")
throw new DetailedParsedException("Not HumnComp");
bitReader.ReadBytes(36);
}

DetailedParse(bitReader, replay, s2mArrayLength);
DetailedParse(bitReader, replay, s2maCacheHandlesLength);
}
}

private static void DetailedParse(BitReader bitReader, Replay replay, int s2mArrayLength)
private static void DetailedParse(BitReader bitReader, Replay replay, uint s2maCacheHandlesLength)
{
bitReader.AlignToByte();
for (; ; )
{
// we're just going to skip all the way down to the s2mh
if (bitReader.ReadString(4) == "s2mh")
{
bitReader.stream.Position = bitReader.stream.Position - 4;
bitReader.stream.Position -= 4;
break;
}
else
bitReader.stream.Position = bitReader.stream.Position - 3;
bitReader.stream.Position -= 3;
}

for (var i = 0; i < s2mArrayLength; i++)
// bitReader.Read(???); // this depends on previous data (not byte aligned)

// s2mh cache handles
// uint s2mhCacheHandlesLength = bitReader.Read(6);
// for (int i = 0; i < s2mhCacheHandlesLength; i++)
for (var i = 0; i < s2maCacheHandlesLength; i++)
{
bitReader.ReadString(4); // s2mh
bitReader.ReadBytes(2); // 0x00 0x00
bitReader.ReadString(2); // Realm
bitReader.ReadBytes(32);
bitReader.AlignToByte();
if (bitReader.ReadString(4) != "s2mh")
throw new Exception($"s2mh cache");

bitReader.ReadBytes(36);
}

// Player collections - starting with HOTS 2.0 (live build 52860)
// strings gone starting with build (ptr) 55929
// --------------------------------------------------------------
var playerCollection = new List<string>();

var collectionSize = 0;

collectionSize = replay.ReplayBuild >= 48027 ? bitReader.ReadInt16() : bitReader.ReadInt32();
int collectionSize = replay.ReplayBuild >= 48027 ? bitReader.ReadInt16() : bitReader.ReadInt32();

if (collectionSize > 8000)
throw new DetailedParsedException("collectionSize is an unusually large number");
Expand Down Expand Up @@ -150,68 +141,77 @@ private static void DetailedParse(BitReader bitReader, Replay replay, int s2mArr
else
bitReader.ReadInt32();

bitReader.ReadBytes(32);
bitReader.ReadInt32(); // 0x19
bitReader.ReadBytes(4);

if (replay.ReplayBuild <= 47479 || replay.ReplayBuild == 47903)
{
ExtendedBattleTagParsingOld(replay, bitReader);
return;
}

for (var player = 0; player < replay.ClientListByUserID.Length; player++)
uint playerListLength = bitReader.Read(5);

for (uint i = 0; i < playerListLength; i++)
{
if (replay.ClientListByUserID[player] == null)
break;
bitReader.Read(3);
bitReader.ReadBytes(24);
bitReader.Read(24);
bitReader.Read(16);
bitReader.Read(10);

int idLength = (int)bitReader.Read(7);

bitReader.AlignToByte();
if (bitReader.ReadString(2) != "T:")
throw new Exception("Not T:");

replay.ClientListByUserID[i].BattleNetTId = bitReader.ReadString(idLength);

if (player == 0)
bitReader.ReadBytes(4);

if (replay.ReplayBuild <= 47479)
{
var offset = bitReader.ReadByte();
bitReader.ReadString(2); // T:
replay.ClientListByUserID[player].BattleNetTId = bitReader.ReadString(12 + offset); // TId
bitReader.ReadBytes(5);
bitReader.Read(5);

idLength = (int)bitReader.Read(7);
if (bitReader.ReadString(2) != "T:")
throw new Exception(" Not T: (duplicate)");

if (replay.ClientListByUserID[i].BattleNetTId != bitReader.ReadString(idLength))
throw new Exception($"Duplicate TID does not match");
}
else
{
ReadByte0x00(bitReader);
ReadByte0x00(bitReader);
ReadByte0x00(bitReader);
bitReader.Read(6);

// get XXXXXXXX#YYY
replay.ClientListByUserID[player].BattleNetTId = Encoding.UTF8.GetString(ReadSpecialBlob(bitReader, 8)); // TId
bitReader.ReadBytes(25);
}

// next 30 bytes
bitReader.ReadBytes(4); // same for all players
bitReader.ReadBytes(25);
// bitReader.ReadBytes(8); ai games have 8 more bytes somewhere around here

bitReader.Read(7);

if (!bitReader.ReadBoolean())
{
// repeat of the collection section above
if (replay.ReplayBuild >= 51609)
if (replay.ReplayBuild >= 51609 || replay.ReplayBuild == 47903 || replay.ReplayBuild == 47479)
{
var size = (int)bitReader.Read(12); // 3 bytes
if (size == collectionSize)
{
var bytesSize = collectionSize / 8;
var bitsSize = collectionSize % 8;
uint size = bitReader.Read(12);

bitReader.ReadBytes(bytesSize);
bitReader.Read(bitsSize);
int bytesSize = (int)(size / 8);
int bitsSize = (int)(size % 8);

bitReader.ReadBoolean();
}
// else if not equal, then data isn't available, most likely an observer
bitReader.ReadBytes(bytesSize);
bitReader.Read(bitsSize);

bitReader.ReadBoolean();
}
else
{
if (replay.ReplayBuild >= 48027)
bitReader.ReadInt16();
else
bitReader.ReadInt32();
bitReader.Read(1);
uint size = bitReader.Read(15);

// each byte has a max value of 0x7F (127)
bitReader.stream.Position = bitReader.stream.Position + (collectionSize * 2);
bitReader.ReadBytes((int)size * 2);
}
}

Expand All @@ -227,31 +227,29 @@ private static void DetailedParse(BitReader bitReader, Replay replay, int s2mArr
bitReader.ReadBoolean(); // m_isBlizzardStaff

if (bitReader.ReadBoolean()) // is player in party
replay.ClientListByUserID[player].PartyValue = bitReader.ReadInt32() + bitReader.ReadInt32(); // players in same party will have the same exact 8 bytes of data
replay.ClientListByUserID[i].PartyValue = bitReader.ReadInt32() + bitReader.ReadInt32(); // players in same party will have the same exact 8 bytes of data

bitReader.ReadBoolean();
bitReader.ReadBoolean(); // has battletag?

var battleTag = Encoding.UTF8.GetString(bitReader.ReadBlobPrecededWithLength(7)).Split('#'); // battleTag <name>#xxxxx

if (battleTag.Length != 2 || battleTag[0] != replay.ClientListByUserID[player].Name)
if (battleTag.Length != 2 || battleTag[0] != replay.ClientListByUserID[i].Name)
throw new DetailedParsedException("Couldn't find BattleTag");

replay.ClientListByUserID[player].BattleTag = int.Parse(battleTag[1]);
replay.ClientListByUserID[i].BattleTag = int.Parse(battleTag[1]);

if (replay.ReplayBuild >= 52860 || (replay.ReplayVersionMajor == 2 && replay.ReplayBuild >= 51978))
replay.ClientListByUserID[player].AccountLevel = bitReader.ReadInt32(); // player's account level, not available in custom games
replay.ClientListByUserID[i].AccountLevel = (int)bitReader.Read(32); // in custom games, this is a 0

if (replay.ReplayBuild >= 69947)
{
bitReader.ReadBoolean(); // m_hasActiveBoost
bitReader.Read(7);
bitReader.Read(2);
}
else
{
bitReader.ReadByte(); // 0x00
bitReader.Read(3);
}

bitReader.ReadBytes(26); // these similar bytes don't occur for last player
}

// some more data after this
Expand Down Expand Up @@ -290,7 +288,7 @@ private static void ExtendedBattleTagParsingOld(Replay replay, BitReader bitRead
TId_2 = Encoding.UTF8.GetString(ReadSpecialBlob(bitReader, 8));

if (TId != TId_2)
throw new Exception("TID dup not equal");
throw new DetailedParsedException("TID dup not equal");
}
}
else
Expand All @@ -315,7 +313,7 @@ private static void ExtendedBattleTagParsingOld(Replay replay, BitReader bitRead
TId_2 = Encoding.UTF8.GetString(ReadSpecialBlob(bitReader, 8));

if (TId != TId_2)
throw new Exception("TID dup not equal");
throw new DetailedParsedException("TID dup not equal");
}
}
replay.ClientListByUserID[i].BattleNetTId = TId;
Expand Down Expand Up @@ -366,7 +364,7 @@ private static void ExtendedBattleTagParsingOld(Replay replay, BitReader bitRead
var battleTag = Encoding.UTF8.GetString(bitReader.ReadBlobPrecededWithLength(7)).Split('#'); // battleTag <name>#xxxxx

if (battleTag.Length != 2 || battleTag[0] != replay.ClientListByUserID[i].Name)
throw new Exception("Couldn't find BattleTag");
throw new DetailedParsedException("Couldn't find BattleTag");

replay.ClientListByUserID[i].BattleTag = int.Parse(battleTag[1]);

Expand Down

0 comments on commit 16218b0

Please sign in to comment.