Skip to content

About

Library to parse items in the simc profile format into functional objects.

Topics

Resources

Stars

6 stars

Watchers

1 watching

Forks

Repository files navigation

Simc Profile Parser

Build & Run Tests Publish to nuget

A library to parse items in the simc import format into functional objects.

PLEASE NOTE: This library is still a work in progress and is being created to support another project. Please raise an issue if something isn't working as you would expect or throws a NotYetImplemented exception and it may be prioritised.

Requires .NET 10. See the changelog for release notes and upgrade steps between major versions.

Usage

The examples below assume these namespaces are imported:

using SimcProfileParser;                  // SimcGenerationService, AddSimcProfileParser()
using SimcProfileParser.Interfaces;       // ISimcGenerationService
using SimcProfileParser.Model.Generated;  // SimcItemOptions, SimcSpellOptions and the generated models
using SimcProfileParser.Model.RawData;    // ItemQuality, InventoryType enums

Initialising

Instance Creation

A new instance can be manually created.

ISimcGenerationService sgs = new SimcGenerationService();

To provide logging to the new instance and its children, supply an ILoggerFactory:

ISimcGenerationService sgs = new SimcGenerationService(myLoggerFactory);

Using Dependency Injection

To implement this using Dependency Injection register it alongside your other services configuration using the AddSimcProfileParser() extension method when configuring your DI services:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSimcProfileParser();
}

Then you request an instance of ISimcGenerationService through DI in your class constructors:

class MyClass
{
    private readonly ISimcGenerationService _simcGenerationService;

    public MyClass(ISimcGenerationService simcGenerationService)
    {
        _simcGenerationService = simcGenerationService;
    }
}

Examples

Parsing profile files/strings

Generating a profile object from a simc import file named import.simc:

ISimcGenerationService sgs = new SimcGenerationService();

// Using async
var profile = await sgs.GenerateProfileAsync(File.ReadAllText("import.simc"));

// Output some details about the profile
Console.WriteLine($"Profile: {profile.ParsedProfile.Name} - Level {profile.ParsedProfile.Level}");
Console.WriteLine($"Items loaded: {profile.GeneratedItems.Count}");
Console.WriteLine($"Talents loaded: {profile.Talents.Count}");

var json = JsonSerializer.Serialize(profile, new JsonSerializerOptions() { WriteIndented = true });
await File.WriteAllTextAsync("profile.json", json);

You can also generate a profile object from individual lines of an import file:

ISimcGenerationService sgs = new SimcGenerationService();

var lines = new List<string>()
{
    "level=90",
    "main_hand=,id=237728,bonus_id=6652/10356/13446/1540/10255"
};

var profile = await sgs.GenerateProfileAsync(lines);

// Access parsed data
Console.WriteLine($"Profile object created for a level {profile.ParsedProfile.Level}");

// Access enriched items with full stats
var firstItem = profile.GeneratedItems.FirstOrDefault();
Console.WriteLine($"Wielding {firstItem.Name} with {firstItem.Mods.Count} stats");

var json = JsonSerializer.Serialize(profile, new JsonSerializerOptions() { WriteIndented = true });
await File.WriteAllTextAsync("profile.json", json);

Understanding Profile Output:

  • ParsedProfile - Raw parsed character data (name, class, spec, level, etc.)
  • GeneratedItems - Fully enriched items with calculated stats, gems, enchants, sockets, and effects
  • Talents - Talent details including spell IDs, names, and ranks

Creating a single item

There are some basic options to manually create an item using ISimcGenerationService.GenerateItemAsync.

ISimcGenerationService sgs = new SimcGenerationService();

var itemOptions = new SimcItemOptions()
{
    ItemId = 242392,
    Quality = ItemQuality.ITEM_QUALITY_EPIC,
    ItemLevel = 730
};

var item = await sgs.GenerateItemAsync(itemOptions);

Console.WriteLine($"Item: {item.Name} (iLevel {item.ItemLevel})");
Console.WriteLine($"Stats: {item.Mods.Count}, Sockets: {item.Sockets.Count}, Effects: {item.Effects.Count}");

var json = JsonSerializer.Serialize(item, new JsonSerializerOptions() { WriteIndented = true });
await File.WriteAllTextAsync("item.json", json);

Available item options:

public uint ItemId { get; set; }                    // Required: The game item ID
public int ItemLevel { get; set; }                  // Override the base item level (Midnight item level bonuses can still change it)
public IList<int> BonusIds { get; set; }            // Bonus IDs that modify stats, sockets, or item level
public IList<int> GemIds { get; set; }              // Gem item IDs to socket into the item
public IList<int> CraftedStatIds { get; set; }      // Stat IDs for player-crafted items
public ItemQuality Quality { get; set; }            // Override item quality
public int DropLevel { get; set; }                  // Character level when item dropped (affects scaling)
public int ContentTuningId { get; set; }            // content_tuning= from a simc profile (affects scaling)
public uint RedirectedBaseStatsItemId { get; set; } // redirected_base_stats= from a simc profile, for catalysed items
public int EnchantId { get; set; }                  // Permanent enchant (enchant_id=)
public int PlayerLevel { get; set; }                // Player level to scale gems and enchants to (default: max level)

Item Generation Details:

  • Bonus IDs: Modify items by adding stats, sockets, changing item level, or quality
  • Gems: Add secondary stats when socketed into items with sockets
  • Enchants: SimcItem.Enchant lists the stats a permanent enchant adds, kept separate from the item's own stats in Mods, and the IDs of any spells it applies (procs, equip and use effects)
  • Drop Level: Affects item level scaling for items with dynamic scaling curves
  • Crafted Stats: Specify which secondary stats player-crafted gear should have
  • Explicit ItemLevel: If set, overrides any item level modifications from bonus IDs

Creating a single spell

There are some basic options to manually create a spell using ISimcGenerationService.GenerateSpellAsync.

There are two types of spell scaling:

Item Scaling - For spells that scale with item level (trinkets, enchants, weapon procs):

ISimcGenerationService sgs = new SimcGenerationService();

var spellOptions = new SimcSpellOptions()
{
    SpellId = 1238697,
    ItemLevel = 730,
    ItemQuality = ItemQuality.ITEM_QUALITY_EPIC,
    ItemInventoryType = InventoryType.INVTYPE_TRINKET
};

var spell = await sgs.GenerateSpellAsync(spellOptions);

// Calculate scaled effect values
var effect = spell.Effects.FirstOrDefault();
var scaledValue = effect.BaseValue + (effect.Coefficient * effect.ScaleBudget);
Console.WriteLine($"Spell: {spell.Name}, Scaled Value: {scaledValue}");

var json = JsonSerializer.Serialize(spell, new JsonSerializerOptions() { WriteIndented = true });
await File.WriteAllTextAsync("spell.json", json);

Player Scaling - For spells that scale with player level (racials, class abilities):

ISimcGenerationService sgs = new SimcGenerationService();

var spellOptions = new SimcSpellOptions()
{
    SpellId = 274740,
    PlayerLevel = 90
};

var spell = await sgs.GenerateSpellAsync(spellOptions);

// The effect's value at level 90, as simc's allspells.txt shows it
var effect = spell.Effects.FirstOrDefault();
Console.WriteLine($"Spell: {spell.Name}, Scaled Value: {effect.ScaledValue}");

var json = JsonSerializer.Serialize(spell, new JsonSerializerOptions() { WriteIndented = true });
await File.WriteAllTextAsync("spell.json", json);

Each spell effect has a ScaleBudget property that should be multiplied with the effect's coefficient to get the final scaled value. For simple cases, the BaseValue property contains the unscaled value.

For player spells, SimcSpellEffect.ScaledValue is the effect's value at the player level, matching "Scaled Value" in simc's allspells.txt:

  • Effects with a coefficient: Coefficient × ScaleBudget
  • Effects with points per level: BaseValue + PointsPerLevel for each level from the spell's level up to the player level (capped at the spell's max level, if it has one). For example, effect #4 of the Holy Priest aura (137031) has BaseValue 0 and PointsPerLevel 1, so its ScaledValue is 90 at level 90.
  • Anything else: BaseValue

Where simc shows a range (effects with a Delta), ScaledValue is the midpoint. For item spells, ScaledValue is always BaseValue; use Coefficient × ScaleBudget as above.

Spell relationships - Generated spells also list which spells modify each other, matching the "Affected Spells" / "Affecting Spells" output in simc's allspells.txt:

  • SimcSpell.AffectedBySpellIds - IDs of spells with an effect that modifies this spell (talents, class auras, set bonuses, etc.)
  • SimcSpellEffect.AffectedSpellIds - IDs of spells this effect modifies

Relationships are matched three ways, and each list contains every spell ID once:

  • Class family flags: e.g. Add Flat/Percent Modifier effects (subtypes 107/108).
  • Spell category: cooldown and charge modifiers. The category is the effect's MiscValue1.
  • Spell label: e.g. Apply Flat/Percent Modifier w/ Label effects (subtypes 219/218), which modify every spell carrying a label. The label is the effect's MiscValue2 (or MiscValue1 for other label effects, such as cooldown recharge rate).

Broad labels such as "Class Spells" (16) or "Priest Spells" (18) are matched like any other label, so an effect targeting them lists every spell with that label. simc's dump shows only the label name in that case.

The raw data is also available so you can do your own matching:

  • SimcSpell.Labels: the spell's label IDs
  • SimcSpellEffect.MiscValue1 / MiscValue2: for spell modifiers, MiscValue1 is the property modified (e.g. damage, duration, cooldown)

Talent rank values - For talents whose effect values change per rank, each effect lists the values for every rank, matching the "Talent Entry" line (Effect#1 [op=set, values=(10, 20)]) in simc's allspells.txt:

  • SimcSpellEffect.RankOperation: Set (the rank value replaces BaseValue) or Multiply (the rank value multiplies BaseValue), or null if the effect has no per-rank values
  • SimcSpellEffect.RankValues: the raw value for each rank, normally index 0 = rank 1

BaseValue is always the unmodified spell data value. For example, Light of the Naaru (196985) has BaseValue 10, RankOperation Set and RankValues [10, 20], so its effect is 20 at rank 2. Critical Mass (117216) has RankOperation Multiply and RankValues [1, 2], so its effect is BaseValue × 2 at rank 2.

Working with Talents

ISimcGenerationService sgs = new SimcGenerationService();

// Get all available talents for a class/spec
// Example: Holy Priest (classId: 5, specId: 257)
var talents = await sgs.GetAvailableTalentsAsync(classId: 5, specId: 257);

Console.WriteLine($"Found {talents.Count} talents for Holy Priest");

Base character stats

Base attributes, racial modifiers, base mana and combat rating conversions come from simc's data, using the same branch and PTR settings as everything else.

ISimcGenerationService sgs = new SimcGenerationService();

// Class base attributes at a level, before racial modifiers. Priest (5) at level 90: 360 / 515 / 4600 / 620
var classStats = await sgs.GetClassBaseStatsAsync(classId: 5, level: 90);

// Racial modifiers, by the same race ID SimcParsedProfile.RaceId returns. Gnome (7): -3 / +1 / -1 / +3
var raceStats = await sgs.GetRaceBaseStatsAsync(raceId: 7);

// Base mana. Priest at level 90: 250,000
var baseMana = await sgs.GetBaseManaAsync(classId: 5, level: 90);

// Rating needed for 1% at a level, e.g. 46 crit rating per 1% crit at level 90
var ratings = await sgs.GetCombatRatingsAsync(level: 90);

Console.WriteLine($"Intellect: {classStats.Intellect + raceStats.Intellect}, crit rating per 1%: {ratings.CritSpell}");
  • GetClassBaseStatsAsync returns null for levels simc has no data for, e.g. above the current max level.
  • GetRaceBaseStatsAsync uses simc's race IDs (util::race_id), which match SimcParsedProfile.RaceId but differ from the game's race IDs for some races, e.g. Dark Iron Dwarf is 12 rather than 34.
  • Combat ratings are before any class or specialization multiplier, such as a specialization's mastery coefficient.

Configuration

Switching Game Data Versions

The library automatically downloads game data from SimulationCraft's GitHub repository. You can control which version of the data to use:

var service = new SimcGenerationService();

// Use PTR (Public Test Realm) data instead of live game data
service.UsePtrData = true;

// Switch between expansions
service.UseBranchName = "midnight";        // Midnight expansion (WoW 12.x) - default
// service.UseBranchName = "thewarwithin"; // The War Within (WoW 11.x)
// service.UseBranchName = "dragonflight"; // Dragonflight (WoW 10.x)

// Check which game version the data is from
var version = await service.GetGameDataVersionAsync();
Console.WriteLine($"Using game data from WoW version: {version}");

Note: Changing UsePtrData or UseBranchName will clear all cached data to prevent mixing incompatible game versions.

Data Caching

Game data files are automatically downloaded and cached in your system's temp directory for performance. The library handles:

  • Automatic downloading when data is first needed
  • ETag-based cache validation to check for updates
  • Efficient memory caching of parsed data

Cache location: Path.GetTempPath() + "SimcProfileParserData"

Important Notes

Supported Game Data

  • Item data: Base stats, sockets, item levels, bonus IDs, gems, enchants
  • Spell data: Effects, scaling, cooldowns, durations, proc rates (RPPM)
  • Talent data: Talent trees, spell IDs, ranks, requirements
  • Scaling data: Combat rating multipliers, stamina multipliers, spell scaling by level
  • Character data: Class base attributes, racial modifiers, base mana and combat ratings by level

Limitations

  • Some newer bonus ID types may not be fully implemented
  • Complex talent prerequisites and choice nodes are not validated
  • Covenant/Soulbind data is parsed but may not be enriched (legacy content)

Error Handling

The library throws exceptions for invalid inputs:

  • ArgumentNullException - When required parameters are null or empty
  • ArgumentOutOfRangeException - When item/spell IDs are not found in the game data
  • NotImplementedException - When encountering unsupported game features

Always wrap API calls in try-catch blocks when dealing with user input.

Support

For bugs please search issues then create a new issue if needed.

For help using this library, please check the wiki or visit discord.

About

Library to parse items in the simc profile format into functional objects.

Topics

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages