Skip to content

Commit

Permalink
Merge pull request #89 from BryanRMorgan/master
Browse files Browse the repository at this point in the history
Misc cleanup
  • Loading branch information
barrett777 authored Jan 19, 2020
2 parents 2d29bf2 + 2c44e1c commit 91c6892
Show file tree
Hide file tree
Showing 16 changed files with 170 additions and 183 deletions.
15 changes: 6 additions & 9 deletions Heroes.ReplayParser.ConsoleApplication/Program.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using System.IO;
using System;
using System.Collections.Generic;
using System;
using System.IO;
using System.Linq;
using Heroes.ReplayParser;

namespace ConsoleApplication1
namespace ConsoleApplication
{
class Program
{
Expand All @@ -15,13 +14,11 @@ static void Main(string[] args)

// Attempt to parse the replay
// Ignore errors can be set to true if you want to attempt to parse currently unsupported replays, such as 'VS AI' or 'PTR Region' replays
var replayParseResult = DataParser.ParseReplay(randomReplayFileName, ignoreErrors: false, deleteFile: false);
var (replayParseResult, replay) = DataParser.ParseReplay(randomReplayFileName, ignoreErrors: false, deleteFile: false);

// If successful, the Replay object now has all currently available information
if (replayParseResult.Item1 == DataParser.ReplayParseResult.Success)
if (replayParseResult == DataParser.ReplayParseResult.Success)
{
var replay = replayParseResult.Item2;

Console.WriteLine("Replay Build: " + replay.ReplayBuild);
Console.WriteLine("Map: " + replay.Map);
foreach (var player in replay.Players.OrderByDescending(i => i.IsWinner))
Expand All @@ -30,7 +27,7 @@ static void Main(string[] args)
Console.WriteLine("Press Any Key to Close");
}
else
Console.WriteLine("Failed to Parse Replay: " + replayParseResult.Item1);
Console.WriteLine("Failed to Parse Replay: " + replayParseResult);

Console.Read();
}
Expand Down
18 changes: 6 additions & 12 deletions Heroes.ReplayParser/BitReader.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
namespace Heroes.ReplayParser.Streams
{
using System;
using System.IO;
using System.Text;
using System;
using System.IO;
using System.Text;

namespace Heroes.ReplayParser
{
/// <summary>
/// A basic little-endian bitstream reader.
/// </summary>
Expand Down Expand Up @@ -31,13 +31,7 @@ public BitReader(Stream stream)
/// <summary>
/// Gets a value indicating whether the end of stream has been reached.
/// </summary>
public bool EndOfStream
{
get
{
return (this.Cursor >> 3) == this.stream.Length;
}
}
public bool EndOfStream => (this.Cursor >> 3) == this.stream.Length;

/// <summary>
/// Reads up to 32 bits from the stream, returning them as a uint.
Expand Down
2 changes: 2 additions & 0 deletions Heroes.ReplayParser/DataParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Heroes.ReplayParser.MPQFiles;
using MpqHeader = Heroes.ReplayParser.MPQFiles.MpqHeader;

namespace Heroes.ReplayParser
{
Expand Down
11 changes: 6 additions & 5 deletions Heroes.ReplayParser/MPQFiles/MpqHeader.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
namespace Heroes.ReplayParser
{
using System;
using System.IO;
using System;
using System.IO;

namespace Heroes.ReplayParser.MPQFiles
{
/// <summary> Parses the header at the beginning of the MPQ file structure. </summary>
public static class MpqHeader
{
Expand Down Expand Up @@ -37,7 +37,8 @@ private static void ParseHeader(Replay replay, BinaryReader reader)

// [0] = Blob, "Heroes of the Storm replay 11" - Strange backward arrow before 11 as well. I don't think the '11' will change, as I believe it was also always '11' in Starcraft 2 replays.

replay.ReplayVersion = string.Format("{0}.{1}.{2}.{3}", headerStructure.dictionary[1].dictionary[1].vInt.Value, headerStructure.dictionary[1].dictionary[2].vInt.Value, headerStructure.dictionary[1].dictionary[3].vInt.Value, headerStructure.dictionary[1].dictionary[4].vInt.Value);
replay.ReplayVersion =
$"{headerStructure.dictionary[1].dictionary[1].vInt.Value}.{headerStructure.dictionary[1].dictionary[2].vInt.Value}.{headerStructure.dictionary[1].dictionary[3].vInt.Value}.{headerStructure.dictionary[1].dictionary[4].vInt.Value}";

replay.ReplayBuild = (int)headerStructure.dictionary[1].dictionary[4].vInt.Value;

Expand Down
29 changes: 17 additions & 12 deletions Heroes.ReplayParser/MPQFiles/ReplayAttributeEvents.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Heroes.ReplayParser
namespace Heroes.ReplayParser.MPQFiles
{
using System.Collections.Generic;

public static class ReplayAttributeEvents
{
public const string FileName = "replay.attributes.events";
Expand All @@ -16,7 +15,7 @@ public static void Parse(Replay replay, byte[] buffer)

var attributes = new ReplayAttribute[BitConverter.ToInt32(buffer, headerSize)];

var initialOffset = 4 + headerSize;
const int initialOffset = 4 + headerSize;

for (var i = 0; i < attributes.Length; i++)
{
Expand Down Expand Up @@ -68,15 +67,21 @@ private static void ApplyAttributes(Replay replay, ReplayAttribute[] Attributes)
if (type == "comp" || type == "humn")
replay.PlayersWithOpenSlots[attribute.PlayerId - 1] = replay.Players[attribute.PlayerId - replayPlayersWithOpenSlotsIndex];

if (type == "comp")
replay.PlayersWithOpenSlots[attribute.PlayerId - 1].PlayerType = PlayerType.Computer;
else if (type == "humn")
replay.PlayersWithOpenSlots[attribute.PlayerId - 1].PlayerType = PlayerType.Human;
else if (type == "open")
switch (type)
{
case "comp":
replay.PlayersWithOpenSlots[attribute.PlayerId - 1].PlayerType = PlayerType.Computer;
break;
case "humn":
replay.PlayersWithOpenSlots[attribute.PlayerId - 1].PlayerType = PlayerType.Human;
break;
// Less than 10 players in a Custom game
replayPlayersWithOpenSlotsIndex++;
else
throw new Exception("Unexpected value for PlayerType");
case "open":
replayPlayersWithOpenSlotsIndex++;
break;
default:
throw new Exception("Unexpected value for PlayerType");
}

break;
}
Expand Down
28 changes: 16 additions & 12 deletions Heroes.ReplayParser/MPQFiles/ReplayDetails.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using System.Linq;
using System;
using System.IO;
using System.Linq;

namespace Heroes.ReplayParser
namespace Heroes.ReplayParser.MPQFiles
{
using System;
using System.IO;

public static class ReplayDetails
{
public const string FileName = "replay.details";
Expand Down Expand Up @@ -51,13 +50,18 @@ public static void Parse(Replay replay, byte[] buffer, bool ignoreErrors = false

replay.Timestamp = DateTime.FromFileTimeUtc(replayDetailsStructure.dictionary[5].vInt.Value); // m_timeUTC

// There was a bug during the below builds where timestamps were buggy for the Mac build of Heroes of the Storm
// The replay, as well as viewing these replays in the game client, showed years such as 1970, 1999, etc
// I couldn't find a way to get the correct timestamp, so I am just estimating based on when these builds were live
if (replay.ReplayBuild == 34053 && replay.Timestamp < new DateTime(2015, 2, 8))
replay.Timestamp = new DateTime(2015, 2, 13);
else if (replay.ReplayBuild == 34190 && replay.Timestamp < new DateTime(2015, 2, 15))
replay.Timestamp = new DateTime(2015, 2, 20);
switch (replay.ReplayBuild)
{
// There was a bug during the below builds where timestamps were buggy for the Mac build of Heroes of the Storm
// The replay, as well as viewing these replays in the game client, showed years such as 1970, 1999, etc
// I couldn't find a way to get the correct timestamp, so I am just estimating based on when these builds were live
case 34053 when replay.Timestamp < new DateTime(2015, 2, 8):
replay.Timestamp = new DateTime(2015, 2, 13);
break;
case 34190 when replay.Timestamp < new DateTime(2015, 2, 15):
replay.Timestamp = new DateTime(2015, 2, 20);
break;
}

// [6] - m_timeLocalOffset - For Windows replays, this is Utc offset. For Mac replays, this is actually the entire Local Timestamp
// [7] - m_description - Empty String
Expand Down
23 changes: 9 additions & 14 deletions Heroes.ReplayParser/MPQFiles/ReplayGameEvents.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using System.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Heroes.ReplayParser
namespace Heroes.ReplayParser.MPQFiles
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

public class ReplayGameEvents
{
public const string FileName = "replay.game.events";
Expand All @@ -20,7 +18,7 @@ public static List<GameEvent> Parse(byte[] buffer, Player[] clientList, int repl
var ticksElapsed = 0;
using (var stream = new MemoryStream(buffer))
{
var bitReader = new Streams.BitReader(stream);
var bitReader = new BitReader(stream);
while (!bitReader.EndOfStream)
{
var gameEvent = new GameEvent();
Expand Down Expand Up @@ -453,10 +451,7 @@ public static List<GameEvent> Parse(byte[] buffer, Player[] clientList, int repl
break;
case GameEventType.CGameUserLeaveEvent:
// m_leaveReason
if(replayBuild >= 55929)
bitReader.Read(5);
else
bitReader.Read(4);
bitReader.Read(replayBuild >= 55929 ? 5 : 4);
break;
case GameEventType.CGameUserJoinEvent:
gameEvent.data = new TrackerEventStructure { array = new TrackerEventStructure[5] };
Expand Down Expand Up @@ -527,12 +522,12 @@ public class GameEvent
public Player player = null;
public bool isGlobal = false;
public int ticksElapsed;
public TimeSpan TimeSpan { get { return new TimeSpan(0, 0, (int)(ticksElapsed / 16.0)); } }
public TimeSpan TimeSpan => new TimeSpan(0, 0, (int)(ticksElapsed / 16.0));
public TrackerEventStructure data = null;

public override string ToString()
{
return data != null ? data.ToString() : null;
return data?.ToString();
}
}

Expand Down
36 changes: 15 additions & 21 deletions Heroes.ReplayParser/MPQFiles/ReplayInitData.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace Heroes.ReplayParser
using System;
using System.IO;
using System.Linq;
using System.Text;

namespace Heroes.ReplayParser.MPQFiles
{
using Heroes.ReplayParser.Streams;
using System;
using System.IO;
using System.Linq;
using System.Text;
/// <summary> Parses the replay.Initdata file in the replay file. </summary>
public class ReplayInitData
{
Expand Down Expand Up @@ -142,10 +142,7 @@ public static void Parse(Replay replay, byte[] buffer)
reader.Read(8); // + 1 = Max Races

// Max Controls
if (replay.ReplayBuild < 59279)
reader.Read(8);
else
reader.Read(4);
reader.Read(replay.ReplayBuild < 59279 ? 8 : 4);

replay.MapSize = new Point { X = (int)reader.Read(8), Y = (int)reader.Read(8) };
if (replay.MapSize.Y == 1)
Expand All @@ -171,10 +168,7 @@ public static void Parse(Replay replay, byte[] buffer)
reader.ReadBitArray(reader.Read(6)); // m_allowedDifficulty

// m_allowedControls
if (replay.ReplayBuild < 59279)
reader.ReadBitArray(reader.Read(8));
else
reader.ReadBitArray(reader.Read(4));
reader.ReadBitArray(replay.ReplayBuild < 59279 ? reader.Read(8) : reader.Read(4));

reader.ReadBitArray(reader.Read(2)); // m_allowedObserveTypes
reader.ReadBitArray(reader.Read(7)); // m_allowedAIBuilds
Expand Down Expand Up @@ -222,7 +216,7 @@ public static void Parse(Replay replay, byte[] buffer)

reader.Read(32); // m_logoIndex

string heroId = Encoding.ASCII.GetString(reader.ReadBlobPrecededWithLength(9)); // m_hero
var heroId = Encoding.ASCII.GetString(reader.ReadBlobPrecededWithLength(9)); // m_hero

var skinAndSkinTint = Encoding.ASCII.GetString(reader.ReadBlobPrecededWithLength(9)); // m_skin
if (skinAndSkinTint == "")
Expand Down Expand Up @@ -296,19 +290,19 @@ public static void Parse(Replay replay, byte[] buffer)

if (replay.ReplayVersionMajor >= 2)
{
string banner = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_banner
var banner = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_banner
if (!string.IsNullOrEmpty(banner) && userID.HasValue)
replay.ClientListByUserID[userID.Value].Banner = banner;

string spray = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_spray
var spray = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_spray
if (!string.IsNullOrEmpty(spray) && userID.HasValue)
replay.ClientListByUserID[userID.Value].Spray = spray;

string announcer = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_announcerPack
var announcer = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_announcerPack
if (!string.IsNullOrEmpty(announcer) && userID.HasValue)
replay.ClientListByUserID[userID.Value].AnnouncerPack = announcer;

string voiceLine = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_voiceLine
var voiceLine = Encoding.UTF8.GetString(reader.ReadBlobPrecededWithLength(9)); // m_voiceLine
if (!string.IsNullOrEmpty(voiceLine) && userID.HasValue)
replay.ClientListByUserID[userID.Value].VoiceLine = voiceLine;

Expand All @@ -318,8 +312,8 @@ public static void Parse(Replay replay, byte[] buffer)
var heroMasteryTiersLength = reader.Read(10);
for (var j = 0; j < heroMasteryTiersLength; j++)
{
string heroAttributeName = new string(BitConverter.GetBytes(reader.Read(32)).Select(k => (char)k).Reverse().ToArray()); // m_hero
int tier = (int)reader.Read(8); // m_tier
var heroAttributeName = new string(BitConverter.GetBytes(reader.Read(32)).Select(k => (char)k).Reverse().ToArray()); // m_hero
var tier = (int)reader.Read(8); // m_tier

if (userID.HasValue)
{
Expand Down
Loading

0 comments on commit 91c6892

Please sign in to comment.