/// <summary> /// This does an asynchronous demo parse. /// </summary> /// <param name="filepath"></param> /// <returns></returns> /// <summary> /// Parses a demo file from any engine /// </summary> /// <param name="filename">Path to the file</param> /// <returns></returns> public static CrossParseResult Parse(string filename) { var cpr = new CrossParseResult(); switch (CheckDemoType(filename)) { case Parseresult.GoldSource: cpr.Type = Parseresult.GoldSource; cpr.GsDemoInfo = GoldSourceParser.ReadGoldSourceDemo(filename); break; case Parseresult.UnsupportedFile: cpr.Type = Parseresult.UnsupportedFile; //Main.//Log("Demotype check resulted in an unsupported file."); break; case Parseresult.Source: cpr.Type = Parseresult.Source; var a = new SourceParser(new MemoryStream(File.ReadAllBytes(filename))); cpr.Sdi = a.Info; if (cpr.Sdi.GameDirectory == "portal") { cpr.Type = Parseresult.Portal; var lp = new L4D2BranchParser(); cpr.L4D2BranchInfo = lp.Parse(filename); } break; case Parseresult.Hlsooe: cpr.Type = Parseresult.Hlsooe; cpr.HlsooeDemoInfo = GoldSourceParser.ParseDemoHlsooe(filename); break; case Parseresult.L4D2Branch: cpr.Type = Parseresult.L4D2Branch; var l = new L4D2BranchParser(); cpr.L4D2BranchInfo = l.Parse(filename); break; default: cpr.Type = Parseresult.UnsupportedFile; break; } cpr.DisplayData = GetDemoDataTuples(cpr); return(cpr); }
/// <summary> /// This returns a nice string which can be assigned to the richtexbox only call it if you /// are extremely sure the demo is not corrupt. /// </summary> /// <param name="demo"></param> /// <returns></returns> public static List <Tuple <string, string> > GetDemoDataTuples(CrossParseResult demo) { //Maybe enum as 3rd tuple item? var result = new List <Tuple <string, string> >(); #region Print switch (demo.Type) { case Parseresult.UnsupportedFile: result.Add(new Tuple <string, string>("Unsupported file!", "")); break; case Parseresult.GoldSource: result = new List <Tuple <string, string> >(); try { result.Add( new Tuple <string, string>( $"Analyzed GoldSource engine demo file ({demo.GsDemoInfo.Header.GameDir}):", "")); result.Add(new Tuple <string, string>("Demo protocol", $"{demo.GsDemoInfo.Header.DemoProtocol}")); result.Add(new Tuple <string, string>("Net protocol", $"{demo.GsDemoInfo.Header.NetProtocol}")); result.Add(new Tuple <string, string>("Directory Offset", $"{demo.GsDemoInfo.Header.DirectoryOffset}")); result.Add(new Tuple <string, string>("MapCRC", $"{demo.GsDemoInfo.Header.MapCrc}")); result.Add(new Tuple <string, string>("Map name", $"{demo.GsDemoInfo.Header.MapName}")); result.Add(new Tuple <string, string>("Game directory", $"{demo.GsDemoInfo.Header.GameDir}")); result.Add(new Tuple <string, string>("Length in seconds", $"{demo.GsDemoInfo.DirectoryEntries.Sum(x => x.TrackTime).ToString("n3")}s")); result.Add(new Tuple <string, string>("Directory entries", $"{demo.GsDemoInfo.DirectoryEntries.Count}")); for (var i = 0; i < demo.GsDemoInfo.DirectoryEntries.Count; i++) { try { result.Add(new Tuple <string, string>("---------------------", "---------------------")); } catch { } try { result.Add(new Tuple <string, string>("[Directory entry ", $"{i}]")); } catch { } try { result.Add(new Tuple <string, string>("Length ", $"{demo.GsDemoInfo.DirectoryEntries[i].FileLength}")); } catch { } try { result.Add(new Tuple <string, string>("Description ", $"{demo.GsDemoInfo.DirectoryEntries[i].Description}")); } catch { } try { result.Add(new Tuple <string, string>("Frames ", $"{demo.GsDemoInfo.DirectoryEntries[i].FrameCount}")); } catch { } try { result.Add(new Tuple <string, string>("Type ", $"{demo.GsDemoInfo.DirectoryEntries[i].Type}")); } catch { } try { result.Add(new Tuple <string, string>("---------------------", "---------------------")); } catch { } } result.Add(new Tuple <string, string>("Frame count", $"{demo.GsDemoInfo.DirectoryEntries.Sum(x => x.FrameCount)}")); result.Add(new Tuple <string, string>("Highest FPS", $"{(1 / demo.GsDemoInfo.AditionalStats.FrametimeMin).ToString("N2")}")); result.Add(new Tuple <string, string>("Lowest FPS", $"{(1 / demo.GsDemoInfo.AditionalStats.FrametimeMax).ToString("N2")}")); result.Add(new Tuple <string, string>("Average FPS", $"{(demo.GsDemoInfo.AditionalStats.Count / demo.GsDemoInfo.AditionalStats.FrametimeSum).ToString("N2")}")); result.Add(new Tuple <string, string>("Lowest msec", $"{(1000.0 / demo.GsDemoInfo.AditionalStats.MsecMin).ToString("N2")} FPS")); result.Add(new Tuple <string, string>("Highest msec", $"{(1000.0 / demo.GsDemoInfo.AditionalStats.MsecMax).ToString("N2")} FPS")); result.Add(new Tuple <string, string>("Frame count", $"{demo.GsDemoInfo.DirectoryEntries.Sum(x => x.FrameCount)}")); result.Add(new Tuple <string, string>("Average msec", $"{(1000.0 / (demo.GsDemoInfo.AditionalStats.MsecSum / (double) demo.GsDemoInfo.AditionalStats.Count)).ToString("N2")} FPS")); } catch { } break; case Parseresult.Hlsooe: result = new List <Tuple <string, string> > { new Tuple <string, string>("Demo protocol", $"{demo.HlsooeDemoInfo.Header.DemoProtocol}"), new Tuple <string, string>("Net protocol", $"{demo.HlsooeDemoInfo.Header.NetProtocol}"), new Tuple <string, string>("Directory offset", $"{demo.HlsooeDemoInfo.Header.DirectoryOffset}"), new Tuple <string, string>("Map name", $"{demo.HlsooeDemoInfo.Header.MapName}"), new Tuple <string, string>("Game directory", $"{demo.HlsooeDemoInfo.Header.GameDir}"), new Tuple <string, string>("Length in seconds", $"{demo.HlsooeDemoInfo.DirectoryEntries.SkipWhile(x => x.FrameCount < 1).Max(x => x.Frames.Max(y => y.Key.Index)) * 0.015}s [{demo.HlsooeDemoInfo.DirectoryEntries.SkipWhile(x => x.FrameCount < 1).Max(x => x.Frames.Max(y => y.Key.Index))}ticks]"), new Tuple <string, string>("Save flag:", $"{demo.HlsooeDemoInfo.DirectoryEntries.SkipWhile(x => x.FrameCount < 1).Max(x => x.Frames.Where(y => y.Key.Type == Hlsooe.DemoFrameType.ConsoleCommand).FirstOrDefault(z => ((Hlsooe.ConsoleCommandFrame) z.Value).Command.Contains("#SAVE#")).Key.Index) * 0.015} [{demo.HlsooeDemoInfo.DirectoryEntries.SkipWhile(x => x.FrameCount < 1).Max(x => x.Frames.Where(y => y.Key.Type == Hlsooe.DemoFrameType.ConsoleCommand).FirstOrDefault(z => ((Hlsooe.ConsoleCommandFrame) z.Value).Command.Contains("#SAVE#")).Key.Index)}ticks]") }; break; case Parseresult.Source: result = new List <Tuple <string, string> > { new Tuple <string, string>("Demo protocol", $"{demo.Sdi.DemoProtocol}"), new Tuple <string, string>("Net protocol", $"{demo.Sdi.NetProtocol}"), new Tuple <string, string>("Server name", $"{demo.Sdi.ServerName}"), new Tuple <string, string>("Client name", $"{demo.Sdi.ClientName}"), new Tuple <string, string>("Map name", $"{demo.Sdi.MapName}"), new Tuple <string, string>("Playback seconds", $"{demo.Sdi.Seconds.ToString("n3")}s"), new Tuple <string, string>("Playback tick count", $"{demo.Sdi.TickCount}"), new Tuple <string, string>("Event count", $"{demo.Sdi.EventCount}"), new Tuple <string, string>("Length", $"{(demo.Sdi.Messages.SkipWhile(x => x.Type != SourceParser.MessageType.SyncTick).Max(x => x.Tick) * 0.015).ToString("n3")}s"), new Tuple <string, string>("Ticks", $"{demo.Sdi.Messages.SkipWhile(x => x.Type != SourceParser.MessageType.SyncTick).Max(x => x.Tick)}") }; break; case Parseresult.Portal: case Parseresult.L4D2Branch: result = new List <Tuple <string, string> > { new Tuple <string, string>("Demo protocol", $"{demo.L4D2BranchInfo.Header.Protocol}"), new Tuple <string, string>("Net protocol", $"{demo.L4D2BranchInfo.Header.NetworkProtocol}"), new Tuple <string, string>("Server name", $"{demo.L4D2BranchInfo.Header.ServerName}"), new Tuple <string, string>("Client name", $"{demo.L4D2BranchInfo.Header.ClientName}"), new Tuple <string, string>("Mapname", $"{demo.L4D2BranchInfo.Header.MapName}"), new Tuple <string, string>("GameDir", $"{demo.L4D2BranchInfo.Header.GameDirectory}"), new Tuple <string, string>("Playback seconds", $"{demo.L4D2BranchInfo.Header.PlaybackTime.ToString("n3")}s"), new Tuple <string, string>("Playback tick count", $"{demo.L4D2BranchInfo.Header.PlaybackTicks}"), new Tuple <string, string>("Event count", $"{demo.L4D2BranchInfo.Header.EventCount}"), new Tuple <string, string>("Signon Length", $"{demo.L4D2BranchInfo.Header.SignonLength}"), new Tuple <string, string>("Tickrate", $"{demo.L4D2BranchInfo.Header.Tickrate}"), new Tuple <string, string>("Start tick", $"{demo.L4D2BranchInfo.PortalDemoInfo?.StartAdjustmentTick}"), new Tuple <string, string>("Type", $"{demo.L4D2BranchInfo.PortalDemoInfo?.StartAdjustmentType}"), new Tuple <string, string>("End tick", $"{demo.L4D2BranchInfo.PortalDemoInfo?.EndAdjustmentTick}"), new Tuple <string, string>("Type", $"{demo.L4D2BranchInfo.PortalDemoInfo?.EndAdjustmentType}"), new Tuple <string, string>("Adjusted time", $"{demo.L4D2BranchInfo.PortalDemoInfo?.AdjustTime(demo.L4D2BranchInfo.Header.TicksPerSecond).ToString("n3")}s"), new Tuple <string, string>("Adjusted ticks", $"{demo.L4D2BranchInfo.PortalDemoInfo?.AdjustedTicks}") }; break; } #endregion return(FormatTuples(result)); }