private bool UseLogEntry( CombatLogEntry entry ) { return entry.SourceId.Value == this.sourceId || entry.TargetId.Value == this.sourceId; }
public void ParseLine( string line ) { try { if( string.IsNullOrEmpty( line ) ) return; if( line.Trim() == string.Empty ) return; // Regex expressions are slow, so we parse the // old-fashioned way. It's about 4x faster. string timeStampText = line.Substring( 0, 8 ); DateTime timeStamp = DateTime.ParseExact( timeStampText, "HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture ); // If timestamp wraps around, increase day number if( timeStamp < previousTimestamp ) { this.dayBump++; } this.previousTimestamp = timeStamp; timeStamp = timeStamp.AddDays( dayBump ); // Delineate the events between "Combat Begin" and "Combat End" // as "encounters." Within each encounter, we list all participants. // Not perfect, but not sure how else to do it. if( line.EndsWith( "Combat Begin" ) ) { this.currentEncounter = new CombatEncounter(); this.currentEncounter.TimeStamp = timeStamp; this.encounters.Add( this.currentEncounter ); } else if( line.EndsWith( "Combat End" ) ) { if( this.currentEncounter != null ) { // Analyze the encounter foreach( CombatTarget target in currentEncounter.Entities ) target.Analyzer.Calculate(); if( this.EncounterEnded != null ) this.EncounterEnded( this, new EncounterEndedArgs() { Encounter = currentEncounter } ); } this.currentEncounter = null; } // First split the line into parts, breaking on commas. string[] parts = line.Split( ',' ); if( parts.Length != 10 ) { // Should only be special cases "Combat Begin" or "Combat End" return; } // We now have an array that looks something like this: // [0] 00:37:43: ( 5 // [1] T=N#R=O#9223372041015909532 // [2] T=N#R=O#9223372041015909532 // [3] T=X#R=X#0 // [4] T=X#R=X#0 // [5] Corrupted Knight // [6] Corrupted Knight // [7] 0 // [8] 458094657 // [9] Soul Sickness ) Corrupted Knight's Soul Sickness heals Corrupted Knight for 0. // Sub-parse the first and last parts string categoryText = parts[0].Substring( 11 ).Trim(); int parenIndex = parts[9].IndexOf( ')' ); string abilityName = parts[9].Substring( 0, parenIndex - 1 ).Trim(); string logMessage = parts[9].Substring( parenIndex + 1 ).Trim(); // Fill in a log entry object CombatLogEntry entry = new CombatLogEntry(); entry.TimeStamp = timeStamp; entry.Category = int.Parse( categoryText ); entry.SourceId = new CombatId( parts[1].Trim() ); entry.TargetId = new CombatId( parts[2].Trim() ); entry.SourceParentId = new CombatId( parts[3].Trim() ); entry.TargetParentId = new CombatId( parts[4].Trim() ); entry.SourceName = parts[5].Trim(); entry.TargetName = parts[6].Trim(); entry.Damage = int.Parse( parts[7].Trim() ); // We don't do anything with the ability ID (parts[8]) entry.AbilityName = abilityName; entry.Message = logMessage; // Skip resurrects "Ekosan's Soul Walk heals Ekosan for 410." if( entry.IsHeal && entry.AbilityName == "Soul Walk" ) return; // Skip 'Weathered' whatever that is - "Smashy's Weathered heals Smashy for 558. (17 overheal)" if( entry.IsHeal && entry.AbilityName == "Weathered" ) return; if( entry.SourceName == string.Empty || entry.SourceName == "Unknown" ) return; if( entry.TargetName == string.Empty || entry.TargetName == "Unknown" ) return; if( logMessage.IndexOf( "Physical damage" ) >= 0 ) entry.DamageType = "Physical"; else if( logMessage.IndexOf( "Air damage" ) >= 0 ) entry.DamageType = "Air"; else if( logMessage.IndexOf( "Water damage" ) >= 0 ) entry.DamageType = "Water"; else if( logMessage.IndexOf( "Fire damage" ) >= 0 ) entry.DamageType = "Fire"; else if( logMessage.IndexOf( "Death damage" ) >= 0 ) entry.DamageType = "Death"; else if( logMessage.IndexOf( "Life damage" ) >= 0 ) entry.DamageType = "Life"; else if( logMessage.IndexOf( "Earth damage" ) >= 0 ) entry.DamageType = "Earth"; //if( entry.IsInformation ) return; Match m; // Collect information from the log message itself. // Test for existence of keywords before doing the regex. // It's much, much faster. if( logMessage.IndexOf( "absorbed)" ) >= 0 ) { m = Regex.Match( logMessage, @"\((\d+) absorbed\)" ); if( m.Success ) entry.Absorbed = int.Parse( m.Groups[1].Value ); } if( logMessage.IndexOf( "blocked)" ) >= 0 ) { m = Regex.Match( logMessage, @"\((\d+) blocked\)" ); if( m.Success ) entry.Blocked = int.Parse( m.Groups[1].Value ); } if( logMessage.IndexOf( "overkill)" ) >= 0 ) { m = Regex.Match( logMessage, @"\((\d+) overkill\)" ); if( m.Success ) entry.Overkill = int.Parse( m.Groups[1].Value ); } if( logMessage.IndexOf( "overheal)" ) >= 0 ) { m = Regex.Match( logMessage, @"\((\d+) overheal\)" ); if( m.Success ) entry.Overheal = int.Parse( m.Groups[1].Value ); } // Record the source and target entities. if( this.currentEncounter != null ) { // Add this log message into the current encounter. this.currentEncounter.Log.Add( entry ); this.allEncounter.Log.Add( entry ); } CombatEntity sourceEntity = this.CountEntity( entry.SourceId, entry.SourceName, entry.SourceParentId ); if( sourceEntity != null ) { if( sourceEntity.Class == null ) sourceEntity.Class = entry.SourceClass; if( entry.IsHit ) sourceEntity.TotalDamage += entry.Damage; if( entry.IsHeal ) sourceEntity.TotalHealing += entry.Damage; sourceEntity.Analyzer.Log.Add( entry ); if( this.currentEncounter != null ) { // Record source as a participant in current encounter if( !this.currentEncounter.ContainsEntity( sourceEntity ) ) this.currentEncounter.AddEntity( sourceEntity ); if( !this.allEncounter.ContainsEntity( sourceEntity ) ) this.allEncounter.AddEntity( sourceEntity ); } } if( entry.TargetId != entry.SourceId ) { CombatEntity targetEntity = this.CountEntity( entry.TargetId, entry.TargetName, entry.TargetParentId ); if( sourceEntity != null && targetEntity != null ) { targetEntity.Analyzer.Log.Add( entry ); CombatTarget target1 = sourceEntity.AddTarget( targetEntity ); if( target1 != null ) target1.Analyzer.Log.Add( entry ); CombatTarget target2 = targetEntity.AddTarget( sourceEntity ); if( target2 != null ) target2.Analyzer.Log.Add( entry ); } if( this.currentEncounter != null ) { // Record target as a participant in current encounter if( !this.currentEncounter.ContainsEntity( targetEntity ) ) this.currentEncounter.AddEntity( targetEntity ); if( !this.allEncounter.ContainsEntity( targetEntity ) ) this.allEncounter.AddEntity( targetEntity ); } } } catch( Exception ex ) { Console.WriteLine( line ); throw; } }