public static MatchData GetMatchData(RocketLeagueReplayParser.Replay repObj) { string MatchId = (string)repObj.Properties["Id"].Value; int TeamSize = (int)repObj.Properties["TeamSize"].Value; int Team0Score = 0; if (repObj.Properties.ContainsKey("Team0Score")) { Team0Score = (int)repObj.Properties["Team0Score"].Value; } int Team1Score = 0; if (repObj.Properties.ContainsKey("Team1Score")) { Team1Score = (int)repObj.Properties["Team1Score"].Value; } string MatchType = (string)repObj.Properties["MatchType"].Value; string MapName = (string)repObj.Properties["MapName"].Value; DateTime Date = DateTime.ParseExact((string)repObj.Properties["Date"].Value, "yyyy-MM-dd HH-mm-ss", null); Console.WriteLine(Date); MatchData header = new MatchData(MatchId, Date, TeamSize, Team0Score, Team1Score, MatchType, MapName); return(header); }
public static Dictionary <long, uint> CarLookup(RocketLeagueReplayParser.Replay rep, List <long> ids) { Dictionary <long, uint> CarIds = new Dictionary <long, uint>(); long tmpId = 0; for (int i = 0; i < rep.Frames[0].ActorStates.Count; i++) { foreach (UInt32 key in rep.Frames[0].ActorStates[i].Properties.Keys) { if (rep.Frames[0].ActorStates[i].Properties[key].PropertyName == "Engine.PlayerReplicationInfo:UniqueId") { dynamic uniqueTest = rep.Frames[0].ActorStates[i].Properties[key].Data; Int64 steamId = uniqueTest.SteamID64; if (!ids.Contains((long)steamId) || CarIds.ContainsKey(steamId)) { break; } tmpId = steamId; } if (rep.Frames[0].ActorStates[i].Properties[key].PropertyName == "TAGame.PRI_TA:ClientLoadouts") { dynamic loadout = rep.Frames[0].ActorStates[i].Properties[key].Data; uint carType = loadout.Loadout1.BodyProductId; CarIds.Add(tmpId, carType); } } } return(CarIds); }
public static Dictionary <long, int> PlatformIdActorId(RocketLeagueReplayParser.Replay rep, List <long> ids) { Dictionary <long, int> PlatformIdActorId = new Dictionary <long, int>(); long tmpId = 0; for (int i = 0; i < rep.Frames[0].ActorStates.Count; i++) { foreach (UInt32 key in rep.Frames[0].ActorStates[i].Properties.Keys) { if (rep.Frames[0].ActorStates[i].Properties[key].PropertyName == "Engine.PlayerReplicationInfo:UniqueId") { dynamic uniqueTest = rep.Frames[0].ActorStates[i].Properties[key].Data; Int64 steamId = uniqueTest.SteamID64; if (!ids.Contains((long)steamId) || PlatformIdActorId.ContainsKey(steamId)) { break; } tmpId = steamId; } if (rep.Frames[0].ActorStates[i].Properties[key].PropertyName == "TAGame.PRI_TA:PersistentCamera") { dynamic id = rep.Frames[0].ActorStates[i].Properties[key].Data; int ActorId = id.ActorId; if (!PlatformIdActorId.ContainsValue(ActorId)) { PlatformIdActorId.Add(tmpId, ActorId); } } } } return(PlatformIdActorId); }
public static void ParseAndStore(string filepath) { string conStr = @"Data Source=PSML65609\SQLEXPRESS;Initial Catalog=rlstat;Integrated Security=True"; RocketLeagueReplayParser.Replay replay = GetReplay(filepath); Tuple <List <MatchStats>, MatchData> parse = ExtractReplayData(replay); List <MatchStats> stats = parse.Item1; MatchData data = parse.Item2; ProcessMatchData(data, conStr); int i = 0; foreach (MatchStats entry in stats) { dynamic tmp = replay.Properties["PlayerStats"]; string platformName = tmp[i]["Platform"].Value.Value; string username = tmp[i]["Name"].Value; Player tmpPlayer = new Player(entry.PlatformId, platformName, username); ProcessPlayer(tmpPlayer, conStr); ProcessMatchStats(entry, conStr); i++; } }
public static Tuple <List <MatchStats>, MatchData> ExtractReplayData(RocketLeagueReplayParser.Replay repObj) { dynamic PlayerStats = repObj.Properties["PlayerStats"].Value; MatchData data = GetMatchData(repObj); List <long> IDS = new List <long>(); for (int i = 0; i < PlayerStats.Count; i++) { long OnlineID = PlayerStats[i]["OnlineID"].Value; IDS.Add(OnlineID); } Dictionary <long, uint> CarIds = CarLookup(repObj, IDS); Dictionary <long, List <float> > CameraSettings = CameraLookup(repObj, IDS); List <MatchStats> PlayerStatList = GetMatchStats(PlayerStats, CarIds, CameraSettings, data); return(Tuple.Create(PlayerStatList, data)); }
public static Dictionary <int, List <float> > ActorIdCamera(RocketLeagueReplayParser.Replay rep) { Dictionary <int, List <float> > ActorIdCamera = new Dictionary <int, List <float> >(); dynamic tmp = rep.Properties["PlayerStats"].Value; for (int i = 0; i < rep.Frames.Count; i++) { for (int j = 0; j < rep.Frames[i].ActorStates.Count; j++) { foreach (UInt32 key in rep.Frames[i].ActorStates[j].Properties.Keys) { if (rep.Frames[i].ActorStates[j].Properties[key].PropertyName == "TAGame.CameraSettingsActor_TA:ProfileSettings") { List <float> CameraSettings = new List <float>(); dynamic settings = rep.Frames[i].ActorStates[j].Properties[key].Data; CameraSettings.Add(settings.FieldOfView); CameraSettings.Add(settings.Height); CameraSettings.Add(settings.Pitch); CameraSettings.Add(settings.Distance); CameraSettings.Add(settings.Stiffness); CameraSettings.Add(settings.SwivelSpeed); CameraSettings.Add(settings.TransitionSpeed); if (!ActorIdCamera.ContainsKey((int)rep.Frames[i].ActorStates[j].Id)) { ActorIdCamera.Add((int)rep.Frames[i].ActorStates[j].Id, CameraSettings); } break; } } } if (ActorIdCamera.Count == tmp.Count) { break; } } return(ActorIdCamera); }
public static Dictionary <long, List <float> > CameraLookup(RocketLeagueReplayParser.Replay rep, List <long> ids) { Dictionary <long, int> PlatformActor = PlatformIdActorId(rep, ids); Dictionary <int, List <float> > ActorCamera = ActorIdCamera(rep); List <long> BadPlatform = new List <long>(); List <List <float> > BadCamera = new List <List <float> >(); dynamic tmp = rep.Properties["PlayerStats"].Value; Dictionary <long, List <float> > PlatformCamera = new Dictionary <long, List <float> >(); foreach (long key in PlatformActor.Keys) { if (ActorCamera.ContainsKey(PlatformActor[key])) { PlatformCamera.Add(key, ActorCamera[PlatformActor[key]]); } else { BadPlatform.Add(PlatformActor[key]); } } foreach (int key in ActorCamera.Keys) { if (!PlatformActor.ContainsValue(key)) { BadCamera.Add(ActorCamera[key]); } } if (PlatformCamera.Count != tmp.Count) { if (BadCamera.Count == 1 && BadPlatform.Count == 1) { PlatformCamera.Add(BadPlatform[0], BadCamera[0]); } } return(PlatformCamera); }
public static Replay DeserializeHeader(BinaryReader br) { var replay = new Replay(); replay.Part1Length = br.ReadInt32(); replay.Part1Crc = br.ReadUInt32(); replay.VersionMajor = br.ReadUInt32(); replay.VersionMinor = br.ReadUInt32(); replay.Unknown5 = br.ReadString2(); replay.Properties = PropertyDictionary.Deserialize(br); return replay; }
public static Replay Deserialize(BinaryReader br) { var replay = new Replay(); try { replay.Part1Length = br.ReadInt32(); replay.Part1Crc = br.ReadUInt32(); replay.VersionMajor = br.ReadUInt32(); replay.VersionMinor = br.ReadUInt32(); replay.Unknown5 = br.ReadString2(); var s = br.BaseStream.Position; replay.Properties = new List <Property>(); Property prop; do { prop = Property.Deserialize(br); replay.Properties.Add(prop); }while (prop.Name != "None"); replay.Part2Length = br.ReadInt32(); replay.Part2Crc = br.ReadUInt32(); replay.LevelLength = br.ReadInt32(); // looks like sfx data, not level data. shrug replay.Levels = new List <Level>(); for (int i = 0; i < replay.LevelLength; i++) { replay.Levels.Add(Level.Deserialize(br)); } replay.KeyFrameLength = br.ReadInt32(); replay.KeyFrames = new List <KeyFrame>(); for (int i = 0; i < replay.KeyFrameLength; i++) { replay.KeyFrames.Add(KeyFrame.Deserialize(br)); } replay.NetworkStreamLength = br.ReadInt32(); replay.NetworkStream = new List <byte>(); for (int i = 0; i < replay.NetworkStreamLength; ++i) { replay.NetworkStream.Add(br.ReadByte()); } replay.DebugStringLength = br.ReadInt32(); replay.DebugStrings = new List <DebugString>(); for (int i = 0; i < replay.DebugStringLength; i++) { replay.DebugStrings.Add(DebugString.Deserialize(br)); } replay.TickMarkLength = br.ReadInt32(); replay.TickMarks = new List <TickMark>(); for (int i = 0; i < replay.TickMarkLength; i++) { replay.TickMarks.Add(TickMark.Deserialize(br)); } replay.PackagesLength = br.ReadInt32(); replay.Packages = new List <string>(); for (int i = 0; i < replay.PackagesLength; i++) { replay.Packages.Add(br.ReadString2()); } replay.ObjectLength = br.ReadInt32(); replay.Objects = new string[replay.ObjectLength]; for (int i = 0; i < replay.ObjectLength; i++) { replay.Objects[i] = br.ReadString2(); } replay.NamesLength = br.ReadInt32(); replay.Names = new string[replay.NamesLength]; for (int i = 0; i < replay.NamesLength; i++) { replay.Names[i] = br.ReadString2(); } replay.ClassIndexLength = br.ReadInt32(); replay.ClassIndexes = new List <ClassIndex>(); for (int i = 0; i < replay.ClassIndexLength; i++) { replay.ClassIndexes.Add(ClassIndex.Deserialize(br)); } replay.ClassNetCacheLength = br.ReadInt32(); replay.ClassNetCaches = new ClassNetCache[replay.ClassNetCacheLength]; for (int i = 0; i < replay.ClassNetCacheLength; i++) { var classNetCache = ClassNetCache.Deserialize(br); replay.ClassNetCaches[i] = classNetCache; for (int j = i - 1; j >= 0; --j) { if (classNetCache.ParentId == replay.ClassNetCaches[j].Id) { classNetCache.Parent = replay.ClassNetCaches[j]; replay.ClassNetCaches[j].Children.Add(classNetCache); break; } } if (replay.ClassNetCaches[i].Parent == null) { replay.ClassNetCaches[i].Root = true; } } // 2016/02/10 patch replays have TAGame.PRI_TA classes with no parent. // Deserialization may have failed somehow, but for now manually fix it up. replay.FixClassParent("ProjectX.PRI_X", "Engine.PlayerReplicationInfo"); replay.FixClassParent("TAGame.PRI_TA", "ProjectX.PRI_X"); // A lot of replays have messed up class hierarchies, commonly giving // both Engine.TeamInfo, TAGame.CarComponent_TA, and others the same id. // Some ambiguities may have become more common since the 2016-06-20 patch, // but there have always been issues. // // For example, from E8B66F8A4561A2DAACC61FA9FBB710CD: // Index 26(TAGame.CarComponent_TA) ParentId 21 Id 24 // Index 28(TAGame.CarComponent_Dodge_TA) ParentId 24 Id 25 // Index 188(TAGame.CarComponent_Jump_TA) ParentId 24 Id 24 // Index 190(TAGame.CarComponent_DoubleJump_TA) ParentId 24 Id 24 // Index 30(Engine.Info) ParentId 21 Id 21 // Index 31(Engine.ReplicationInfo) ParentId 21 Id 21 // Index 195(Engine.TeamInfo) ParentId 21 Id 24 // Index 214(TAGame.CarComponent_Boost_TA) ParentId 24 Id 31 // Index 237(TAGame.CarComponent_FlipCar_TA) ParentId 24 Id 26 // Problems: // TAGame.CarComponent_Jump_TA's parent id and id are both 24 (happens to work fine in this case) // TAGame.CarComponent_DoubleJump_TA's parent id and id are both 24 (incorrectly picks CarComponent_Jump_TA as parent) // Engine.TeamInfo's ID is 24, even though there are 3 other classes with that id // TAGame.CarComponent_Boost_TA's parent is 24 (Incorrectly picks Engine.TeamInfo, since it's ambiguous) // TAGame.CarComponent_FlipCar_TA's parent is 24 (Incorrectly picks Engine.TeamInfo, since it's ambiguous) // Engine.ReplicationInfo and Engine.Info have the same parent id and id (no ill effects so far) // // Note: The heirarchy problems do not always cause parsing errors! But they can if you're unlucky. replay.FixClassParent("TAGame.CarComponent_Boost_TA", "TAGame.CarComponent_TA"); replay.FixClassParent("TAGame.CarComponent_FlipCar_TA", "TAGame.CarComponent_TA"); replay.FixClassParent("TAGame.CarComponent_Jump_TA", "TAGame.CarComponent_TA"); replay.FixClassParent("TAGame.CarComponent_Dodge_TA", "TAGame.CarComponent_TA"); replay.FixClassParent("TAGame.CarComponent_DoubleJump_TA", "TAGame.CarComponent_TA"); replay.FixClassParent("TAGame.GameEvent_TA", "Engine.Actor"); replay.FixClassParent("TAGame.SpecialPickup_TA", "TAGame.CarComponent_TA"); replay.FixClassParent("TAGame.SpecialPickup_BallVelcro_TA", "TAGame.SpecialPickup_TA"); replay.FixClassParent("TAGame.SpecialPickup_Targeted_TA", "TAGame.SpecialPickup_TA"); replay.FixClassParent("TAGame.SpecialPickup_Spring_TA", "TAGame.SpecialPickup_Targeted_TA"); replay.FixClassParent("TAGame.SpecialPickup_BallLasso_TA", "TAGame.SpecialPickup_Spring_TA"); replay.FixClassParent("TAGame.SpecialPickup_BoostOverride_TA", "TAGame.SpecialPickup_Targeted_TA"); replay.FixClassParent("TAGame.SpecialPickup_BallCarSpring_TA", "TAGame.SpecialPickup_Spring_TA"); replay.FixClassParent("TAGame.SpecialPickup_BallFreeze_TA", "TAGame.SpecialPickup_Targeted_TA"); replay.FixClassParent("TAGame.SpecialPickup_Swapper_TA", "TAGame.SpecialPickup_Targeted_TA"); replay.FixClassParent("TAGame.SpecialPickup_GrapplingHook_TA", "TAGame.SpecialPickup_Targeted_TA"); replay.FixClassParent("TAGame.SpecialPickup_BallGravity_TA", "TAGame.SpecialPickup_TA"); replay.FixClassParent("TAGame.SpecialPickup_HitForce_TA", "TAGame.SpecialPickup_TA"); replay.FixClassParent("TAGame.SpecialPickup_Tornado_TA", "TAGame.SpecialPickup_TA"); // Havent had problems with these yet. They (among others) can be ambiguous, // but I havent found a replay yet where my parent choosing algorithm // (which picks the matching class that was most recently read) picks the wrong class. // Just a safeguard for now. replay.FixClassParent("Engine.TeamInfo", "Engine.ReplicationInfo"); replay.FixClassParent("TAGame.Team_TA", "Engine.TeamInfo"); replay.Frames = ExtractFrames(replay.MaxChannels(), replay.NetworkStream, replay.KeyFrames.Select(x => x.FilePosition), replay.Objects, replay.ClassNetCaches, replay.VersionMajor, replay.VersionMinor); if (br.BaseStream.Position != br.BaseStream.Length) { throw new Exception("Extra data somewhere!"); } return(replay); } catch (Exception) { #if DEBUG return(replay); #else throw; #endif } }
public static Replay Deserialize(BinaryReader br, out string log) { var logSb = new StringBuilder(); var replay = new Replay(); replay.Unknown1 = br.ReadInt32(); replay.Unknown2 = br.ReadInt32(); replay.Unknown3 = br.ReadInt32(); replay.Unknown4 = br.ReadInt32(); // This looks almost like an ArrayProperty, but without type and the unknown ints replay.Unknown5 = br.ReadAsciiString(); replay.Properties = new List<Property>(); Property prop; do { prop = Property.Deserialize(br); replay.Properties.Add(prop); } while (prop.Name != "None"); replay.LengthOfRemainingData = br.ReadInt32(); replay.Unknown7 = br.ReadInt32(); replay.LevelLength = br.ReadInt32(); // looks like sfx data, not level data. shrug replay.Levels = new List<Level>(); for (int i = 0; i < replay.LevelLength; i++ ) { replay.Levels.Add(Level.Deserialize(br)); } replay.KeyFrameLength = br.ReadInt32(); replay.KeyFrames = new List<KeyFrame>(); for (int i = 0; i < replay.KeyFrameLength; i++) { replay.KeyFrames.Add(KeyFrame.Deserialize(br)); } replay.NetworkStreamLength = br.ReadInt32(); replay.NetworkStream = new List<byte>(); for (int i = 0; i < replay.NetworkStreamLength; ++i) { replay.NetworkStream.Add(br.ReadByte()); } replay.DebugStringLength = br.ReadInt32(); replay.DebugStrings = new List<string>(); for (int i = 0; i < replay.DebugStringLength; i++) { replay.DebugStrings.Add(br.ReadAsciiString()); } replay.TickMarkLength = br.ReadInt32(); replay.TickMarks = new List<TickMark>(); for (int i = 0; i < replay.TickMarkLength; i++) { replay.TickMarks.Add(TickMark.Deserialize(br)); } replay.PackagesLength = br.ReadInt32(); replay.Packages = new List<string>(); for (int i = 0; i < replay.PackagesLength; i++) { replay.Packages.Add(br.ReadAsciiString()); } replay.ObjectLength = br.ReadInt32(); replay.Objects = new string[replay.ObjectLength]; for (int i = 0; i < replay.ObjectLength; i++) { replay.Objects[i] = br.ReadAsciiString(); } //replay.Unknown9 = br.ReadInt32(); replay.NamesLength = br.ReadInt32(); replay.Names = new List<string>(); for (int i = 0; i < replay.NamesLength; i++) { replay.Names.Add(br.ReadAsciiString()); } replay.ClassIndexLength = br.ReadInt32(); replay.ClassIndexes = new List<ClassIndex>(); for (int i = 0; i < replay.ClassIndexLength; i++) { replay.ClassIndexes.Add(ClassIndex.Deserialize(br)); } replay.ClassNetCacheLength = br.ReadInt32(); replay.ClassNetCaches = new ClassNetCache[replay.ClassNetCacheLength]; for (int i = 0; i < replay.ClassNetCacheLength; i++) { replay.ClassNetCaches[i] = ClassNetCache.Deserialize(br); int j = 0; for(j = i-1; j >=0; --j) { if ( replay.ClassNetCaches[i].ParentId == replay.ClassNetCaches[j].Id) { replay.ClassNetCaches[i].Parent = replay.ClassNetCaches[j]; replay.ClassNetCaches[j].Children.Add(replay.ClassNetCaches[i]); break; } } if ( j < 0 ) { replay.ClassNetCaches[i].Root = true; } } // break into frames, using best guesses var objectIndexToName = Enumerable.Range(0, replay.Objects.Length).ToDictionary(i => i, i => replay.Objects[i]); replay.Frames = ExtractFrames(replay.NetworkStream, replay.KeyFrames.Select(x => x.FilePosition), objectIndexToName, replay.ClassNetCaches, logSb); //var minSize = replay.Frames.Where(x => !x.Complete /*&& x.BitLength != 163*/ && x.ActorStates.Count > 0 && !string.IsNullOrWhiteSpace(x.ActorStates[0].TypeName)).Min(x => x.BitLength); foreach (var f in replay.Frames.Where(x => !x.Complete))// x.Failed) )//Complete && x.BitLength == minSize)) { //if ( f.ActorStates.Count >= 1 && f.ActorStates.First().State == "New") //{ logSb.AppendLine(f.ToDebugString(replay.Objects)); //} } //logSb.AppendLine(replay.Frames.First().ToDebugString(replay.Objects)); if ( br.BaseStream.Position != br.BaseStream.Length ) { throw new Exception("Extra data somewhere!"); } log = logSb.ToString(); //Console.WriteLine(log); return replay; }