/// <summary> /// Check a line for the SimC Addon version string, and set it on result if present /// </summary> private void TryApplySimcVersion(SimcParsedProfile result, string valueString) { var versionPrefix = "SimC Addon "; if (valueString.Length > versionPrefix.Length && valueString.Substring(0, versionPrefix.Length) == versionPrefix) { var version = valueString[versionPrefix.Length..];
public void SimcParsedProfile_Collections_Not_Null() { // Arrange var spp = new SimcParsedProfile(); // Assert Assert.IsNotNull(spp.Soulbinds); Assert.IsNotNull(spp.Conduits); Assert.IsNotNull(spp.Professions); Assert.IsNotNull(spp.Items); }
private void TryApplyClass(SimcParsedProfile profile, string classValue) { profile.Class = classValue; var classId = (classValue) switch { "priest" => Class.Priest, "paladin" => Class.Paladin, "monk" => Class.Monk, "shaman" => Class.Shaman, "druid" => Class.Druid, "rogue" => Class.Rogue, "mage" => Class.Mage, "deathknight" => Class.DeathKnight, "demonhunter" => Class.DemonHunter, "hunter" => Class.Hunter, "warlock" => Class.Warlock, "warrior" => Class.Warrior, _ => Class.None }; profile.ClassId = (int)classId; }
private void TryApplyRace(SimcParsedProfile profile, SimcParsedLine line) { // Set Race and RaceId profile.Race = line.Value.Trim(); var raceId = (profile.Race.ToLower()) switch { "human" => Race.Human, "orc" => Race.Orc, "dwarf" => Race.Dwarf, "night_elf" => Race.NightElf, "undead" => Race.Undead, "tauren" => Race.Tauren, "gnome" => Race.Gnome, "troll" => Race.Troll, "goblin" => Race.Goblin, "blood_elf" => Race.BloodElf, "draenei" => Race.Draenei, "dark_iron_dwarf" => Race.DarkIronDwarf, "vulpera" => Race.Vulpera, "maghar_orc" => Race.MagharOrc, "mechagnome" => Race.Mechagnome, "worgen" => Race.Worgen, "pandaren" => Race.Pandaren, "pandaren_alliance" => Race.PandarenAlliance, "pandaren_horde" => Race.PandarenHorde, "nightborne" => Race.Nightborne, "highmountain_tauren" => Race.HighmountainTauren, "void_elf" => Race.VoidElf, "lightforged_draenei" => Race.LightforgedDraenei, "zandalari_troll" => Race.ZandalariTroll, "kul_tiran" => Race.KulTiran, _ => Race.NoRace, }; profile.RaceId = (int)raceId; }
public async Task InitOnce() { // Configure Logging Log.Logger = new LoggerConfiguration() .MinimumLevel.Verbose() .Enrich.FromLogContext() .WriteTo.File("logs" + Path.DirectorySeparatorChar + "SimcProfileParser.log", rollingInterval: RollingInterval.Day) .CreateLogger(); // Load a data file var testFile = @"RawData" + Path.DirectorySeparatorChar + "Hierophant.simc"; var testFileContents = await File.ReadAllLinesAsync(testFile); var testFileString = new List <string>(testFileContents); // Create a new profile service using var loggerFactory = LoggerFactory.Create(builder => builder .AddSerilog() .AddFilter(level => level >= LogLevel.Trace)); var logger = loggerFactory.CreateLogger <SimcParserService>(); var simcParser = new SimcParserService(logger); ParsedProfile = simcParser.ParseProfileAsync(testFileString); }
private void TryApplySpecId(SimcParsedProfile profile) { var specId = Specialisation.SPEC_NONE; // from specialization_string in sc_const_data.cpp switch ((Class)profile.ClassId) { case Class.Priest: if (profile.Spec == "discipline") { specId = Specialisation.PRIEST_DISCIPLINE; } if (profile.Spec == "holy") { specId = Specialisation.PRIEST_HOLY; } if (profile.Spec == "shadow") { specId = Specialisation.PRIEST_SHADOW; } break; case Class.Warrior: if (profile.Spec == "arms") { specId = Specialisation.WARRIOR_ARMS; } if (profile.Spec == "fury") { specId = Specialisation.WARRIOR_FURY; } if (profile.Spec == "protection") { specId = Specialisation.WARRIOR_PROTECTION; } break; case Class.Paladin: if (profile.Spec == "holy") { specId = Specialisation.PALADIN_HOLY; } if (profile.Spec == "protection") { specId = Specialisation.PALADIN_PROTECTION; } if (profile.Spec == "retribution") { specId = Specialisation.PALADIN_RETRIBUTION; } break; case Class.Hunter: if (profile.Spec == "beast_mastery") { specId = Specialisation.HUNTER_BEAST_MASTERY; } if (profile.Spec == "marksmanship") { specId = Specialisation.HUNTER_MARKSMANSHIP; } if (profile.Spec == "survival") { specId = Specialisation.HUNTER_SURVIVAL; } break; case Class.Rogue: if (profile.Spec == "assassination") { specId = Specialisation.ROGUE_ASSASSINATION; } if (profile.Spec == "outlaw") { specId = Specialisation.ROGUE_OUTLAW; } if (profile.Spec == "subtlety") { specId = Specialisation.ROGUE_SUBTLETY; } break; case Class.DeathKnight: if (profile.Spec == "blood") { specId = Specialisation.DEATH_KNIGHT_BLOOD; } if (profile.Spec == "frost") { specId = Specialisation.DEATH_KNIGHT_FROST; } if (profile.Spec == "unholy") { specId = Specialisation.DEATH_KNIGHT_UNHOLY; } break; case Class.Shaman: if (profile.Spec == "elemental") { specId = Specialisation.SHAMAN_ELEMENTAL; } if (profile.Spec == "enhancement") { specId = Specialisation.SHAMAN_ENHANCEMENT; } if (profile.Spec == "restoration") { specId = Specialisation.SHAMAN_RESTORATION; } break; case Class.Mage: if (profile.Spec == "arcane") { specId = Specialisation.MAGE_ARCANE; } if (profile.Spec == "fire") { specId = Specialisation.MAGE_FIRE; } if (profile.Spec == "frost") { specId = Specialisation.MAGE_FROST; } break; case Class.Warlock: if (profile.Spec == "affliction") { specId = Specialisation.WARLOCK_AFFLICTION; } if (profile.Spec == "demonology") { specId = Specialisation.WARLOCK_DEMONOLOGY; } if (profile.Spec == "destruction") { specId = Specialisation.WARLOCK_DESTRUCTION; } break; case Class.Monk: if (profile.Spec == "brewmaster") { specId = Specialisation.MONK_BREWMASTER; } if (profile.Spec == "mistweaver") { specId = Specialisation.MONK_MISTWEAVER; } if (profile.Spec == "windwalker") { specId = Specialisation.MONK_WINDWALKER; } break; case Class.Druid: if (profile.Spec == "balance") { specId = Specialisation.DRUID_BALANCE; } if (profile.Spec == "feral") { specId = Specialisation.DRUID_FERAL; } if (profile.Spec == "guardian") { specId = Specialisation.DRUID_GUARDIAN; } if (profile.Spec == "restoration") { specId = Specialisation.DRUID_RESTORATION; } break; case Class.DemonHunter: if (profile.Spec == "havoc") { specId = Specialisation.DEMON_HUNTER_HAVOC; } if (profile.Spec == "vengeance") { specId = Specialisation.DEMON_HUNTER_VENGEANCE; } break; case Class.None: default: break; } profile.SpecId = (int)specId; }
public SimcParsedProfile ParseProfileAsync(List <string> profileLines) { _logger?.LogInformation($"Parsing a profileString with {profileLines.Count} lines."); var runtime = Stopwatch.StartNew(); var profile = new SimcParsedProfile(); // Loop through each of the lines and parse them on their own merit. List <SimcParsedLine> validLines = new List <SimcParsedLine>(); foreach (var rawLine in profileLines) { // Lines either start with the identifier=value combo or are commented, then identifier or comment. // e.g.: # shoulder=,id=173247,bonus_id=6716/1487/6977/6649/6647 // TODO: pull the datetime/simc version from here var currentLine = rawLine; // Remove the comment # if (!string.IsNullOrEmpty(rawLine) && rawLine[0] == '#') { currentLine = currentLine.Trim('#').Trim(); } TryApplySimcVersion(profile, currentLine); TryApplyProfileDate(profile, currentLine); // Check if there is an identifier if (string.IsNullOrEmpty(rawLine) || !rawLine.Contains('=')) { continue; } _logger?.LogDebug($"New raw line: {currentLine}"); var kvp = currentLine.Split('='); var identifier = kvp.FirstOrDefault(); var valueString = string.Join("=", kvp.Skip(1)); // All but the identifier var parsedLine = new SimcParsedLine() { RawLine = rawLine, CleanLine = currentLine, Identifier = identifier, Value = valueString }; validLines.Add(parsedLine); } _logger?.LogInformation($"Found {validLines.Count} valid lines"); if (validLines.Count == 0) { return(profile); } profile.ProfileLines = validLines; foreach (var line in validLines) { _logger?.LogTrace($"Processing line: {line.CleanLine} " + $"Identifier: ({line.Identifier}) Value: {line.Value}"); switch (line.Identifier) { // Items case "head": case "neck": case "shoulder": case "back": case "chest": case "wrist": case "hands": case "waist": case "legs": case "feet": case "finger1": case "finger2": case "trinket1": case "trinket2": case "main_hand": case "off_hand": _logger?.LogDebug($"Trying to parse item for slot: ({line.Identifier}) with values: {line.Value}"); TryApplyItem(profile, line); break; // TODO: Add the remaining specs case "priest": case "paladin": case "monk": case "shaman": case "druid": case "rogue": case "mage": case "deathknight": case "demonhunter": case "hunter": case "warlock": case "warrior": _logger?.LogDebug($"Setting player name for class ({line.Identifier}) with value: {line.Value}"); profile.Name = line.Value.Trim().Trim('"'); TryApplyClass(profile, line.Identifier.Trim()); break; case "level": _logger?.LogDebug($"Trying to set level ({line.Identifier}) with value: {line.Value}"); TryApplyLevel(profile, line.Value.Trim()); break; case "race": _logger?.LogDebug($"Trying to set race ({line.Identifier}) with value: {line.Value}"); TryApplyRace(profile, line); break; case "region": _logger?.LogDebug($"Trying to set region ({line.Identifier}) with value: {line.Value}"); profile.Region = line.Value.Trim(); break; case "server": _logger?.LogDebug($"Trying to set server ({line.Identifier}) with value: {line.Value}"); profile.Server = line.Value.Trim(); break; case "role": _logger?.LogDebug($"Trying to set role ({line.Identifier}) with value: {line.Value}"); profile.Role = line.Value.Trim(); break; case "professions": _logger?.LogDebug($"Trying to parse profession ({line.Identifier}) with value: {line.Value}"); TryApplyProfessions(profile, line); break; case "talents": _logger?.LogDebug($"Trying to parse talents ({line.Identifier}) with value: {line.Value}"); TryApplyTalents(profile, line.Value); break; case "spec": _logger?.LogDebug($"Trying to set spec ({line.Identifier}) with value: {line.Value}"); profile.Spec = line.Value.Trim(); break; case "covenant": _logger?.LogDebug($"Trying to parse covenant ({line.Identifier}) with value: {line.Value}"); profile.Covenant = line.Value.Trim(); break; case "soulbind": _logger?.LogDebug($"Trying to parse soulbind ({line.Identifier}) with value: {line.Value}"); TryApplySoulbind(profile, line); break; case "conduits_available": _logger?.LogDebug($"Trying to parse conduits_available ({line.Identifier}) with value: {line.Value}"); TryApplyConduitData(profile, line.Value); break; case "renown": _logger?.LogDebug($"Trying to parse renown ({line.Identifier}) with value: {line.Value}"); if (int.TryParse(line.Value.Trim(), out int renown)) { profile.Renown = renown; } else { _logger?.LogWarning($"Invalid renown value: {line.Value}"); } break; default: _logger?.LogWarning($"Unrecognised identifier found: {line.Identifier}"); break; } } // Call this last in case the class line is after the spec line. TryApplySpecId(profile); runtime.Stop(); _logger?.LogInformation($"Done processing profile in {runtime.ElapsedMilliseconds}ms"); return(profile); }