# Path of Valheiman — public API 1.1.0 The supported way for other Valheim mods to work with Path of Valheiman (PoV): read the character's progression and stats, show PoV's equipment and items in your own interface, keep PoV's cells in your own inventory, give tree or profession XP for your own activities, keep your skills out of PoV's skill freeze, and leave your creatures alone. Everything is in the namespace `Valheiman.Api` inside `PathOfValheiman.dll`. Web version: https://valheiman.com/api **Availability:** API 1.0.0 since Path of Valheiman 5.0.8, 1.1.0 since 5.0.9. Check `Pov.Has(...)` at runtime and your mod keeps working with older PoV versions. ## Rules in one screen - **Versioning.** [Semantic versioning](https://semver.org). Within major version 1 nothing is removed and nothing changes meaning; minor versions only add. Check `Pov.AtLeast(1, minor)` and `Pov.Has("feature")`. - **Only `Valheiman.Api` is a promise.** Everything else in the DLL (the `PassiveTree.*` namespaces) is PoV's inside and changes without notice. Do not reflect into it; ask for what you need instead. - **Soft dependency.** Your mod must load without PoV. Keep PoV calls in a class of their own, touched only when PoV is installed (see Quick start). - **Main thread.** Call everything from Unity's main thread. - **Never throws for missing state.** Without a local player or world, calls return empty values: 0, null, false, empty lists. - **Local vs world.** Character data (progression, equipment, XP) is the local player's, kept on their client. Creature data lives in the creature's ZDO: readable on every peer; PoV writes it only on the ZDO owner. World settings belong to the host. Calls that must run on every machine say so. - **Hosting.** Several parts of PoV's interface can be handed to your mod (`...Host(yourGuid)`): PoV keeps the logic and data and stops drawing that part. `null` gives it back. The last host wins. ## Quick start 1. Reference the API: download `PathOfValheiman.ref.dll` (a small reference assembly with the public types only) from https://valheiman.com/api-assets/PathOfValheiman.ref.dll, or reference the real `PathOfValheiman.dll`. Set `Private=false` so it is not copied into your package. ```xml libs\PathOfValheiman.ref.dll false ``` 2. Declare a soft dependency and keep the calls behind a check: ```csharp [BepInPlugin("my.mod", "My Mod", "1.0.0")] [BepInDependency("treextr.pathofvalheiman", BepInDependency.DependencyFlags.SoftDependency)] public class MyMod : BaseUnityPlugin { public static bool Pov => Chainloader.PluginInfos.ContainsKey("treextr.pathofvalheiman"); void Update() { if (Pov) PovBridge.Tick(); } } // Only this class mentions PoV types: it is never loaded when PoV is absent. static class PovBridge { public static void Tick() { if (!Valheiman.Api.Pov.Has("progress")) return; int points = Valheiman.Api.Progression.FreePoints; } } ``` 3. Listen instead of polling where you can: `Pov.Changed` and the `Events` class. ## Features `Pov.Has(name)` is true for each feature this PoV provides. | Feature | What it gives | |---|---| | `progress`, `stats` | level, XP, points, tree nodes; stat values by name | | `events` | character loaded, level up, node taken/removed, stats changed, loot rolled | | `grant` | give tree XP or profession XP from your mod | | `crafting` | the craft tree (professions) | | `build` | the character's path, ascendancy class and masteries | | `skills.exempt` | keep your mod's skills out of PoV's skill freeze | | `equipment`, `equipment.cells`, `equipment.keys` | equipment cells, their items, hotkeys | | `equipment.host` | your mod draws the equipment | | `equipment.off` | your mod turns PoV's equipment system off | | `storage` | your inventory mod keeps PoV's storage cells | | `purse` | coins kept in their own cells | | `looks`, `looks.portrait` | transmog; a turning character portrait for your window | | `trinkets` | extra trinket seats | | `rows`, `rows.host` | extra backpack rows from the tree; your mod sizes the inventory | | `rarity`, `rarity.host`, `tooltip` | item rarity and colours, tooltip affix rows; your mod draws rarity frames | | `items.details` | affixes with ids, tiers and roll ranges; implicits; corrupted, identified, item level; sockets and sigils; influences | | `chests` | crafting from nearby chests | | `quickstack`, `quickstack.host` | bag tidying; your mod provides the buttons | | `shield` | the energy shield | | `hud`, `hud.claim` | PoV's HUD pieces; your mod places them | | `creatures`, `creatures.leave-alone` | creature rarity, stars, modifiers, levels; opt your creatures out | | `difficulty` | the world's PoV preset and Valheim combat modifier | | `text` | PoV's texts in the player's language | ## Pov ```csharp Pov.Guid // "treextr.pathofvalheiman" Pov.Version // "1.1.0" - the API's version, not the mod's Pov.AtLeast(1, 0) // this API is 1.0 or newer within major 1 Pov.Has("storage") Pov.Changed += areas => { /* "equipment", "keys", "purse", "looks", "progress", "host" */ }; ``` `Pov.Changed` fires on the main thread at most once per frame with the areas that changed. ## Progression and stats ```csharp Progression.Level; Progression.Xp; Progression.XpToNextLevel; Progression.FreePoints; Progression.SpentPoints; Progression.HasNode("node-id"); Progression.Nodes; // taken node ids Progression.TreeOpen; // the tree window is open Stats.Get("XpGainPct"); Stats.Has("TidyPack"); Stats.Names; // unknown names read 0 Shield.Enabled; Shield.Current; Shield.Max; Shield.Regenerating; Build.Path; // dreng, skitalets, koldun, ratnik, trickster, warden - or null Build.PathTitle; // in the player's language Build.AscendancyClass; // or null Build.Masteries; // category -> chosen options ``` ## Events ```csharp Events.CharacterLoaded += player => { }; Events.LevelUp += level => { }; Events.NodeTaken += nodeId => { }; Events.NodeRemoved += nodeId => { }; Events.StatsChanged += () => { }; // read Stats again Events.LootRolled += items => { }; // PoV rolled kill loot for the local player (rarity and affixes set) ``` A listener that throws is logged and does not stop the others. ## Grant XP from your mod ```csharp Grant.TreeXp(120f, XpKind.Kills, "my.mod"); // counted like PoV's own XP of that kind Grant.ProfessionXp("smith", 40); // one craft-tree profession Crafting.Professions; // miner, smith, armorer, woodcutter, builder, shipwright, sailor, hunter, herder, cook, // brewer, beekeeper, farmer, forager, fisher, pathfinder, delver Crafting.TotalXp; Crafting.HasNode("craft-node-id"); ``` - `XpKind`: `Combat`, `Kills`, `Crafting`, `Gathering`, `Mining`, `Building`, `Travel`, `Map`. Each kind has its own world multiplier. Peaceful kinds (`Crafting`, `Gathering`, `Mining`, `Building`) go to the craft tree, as PoV's own do. - At most `Grant.MaxPerCall` (5000) per call. Local player only: call it on the client whose player did the thing. - Typical use: an enchanting table, a new gathering activity, a quest reward. ## Skills: keep yours out of the freeze PoV replaces skill levels with its tree: with the world setting on, every skill is frozen. A skill mod can keep its own skills working as without PoV: ```csharp // In Awake, on every machine: SkillFreeze.Exempt(mySkillType); // true; false for a Valheim skill (those stay PoV's) SkillFreeze.Frozen; // the freeze is on in this world SkillFreeze.IsExempt(type); ``` An exempt skill gains experience and reports its real level. It also keeps its level on death (PoV skips the vanilla death loss while the freeze is on). ## Equipment PoV keeps equipment in cells. By default they are hidden rows of the player's own inventory, under the backpack. **Never compute where they are**: the first row is remembered per character, other mods change the inventory height, and an inventory mod may keep the cells itself (see Storage). Use the API. Cell ids (stable): `helmet`, `chest`, `legs`, `cape`, `belt`, `quiver`, `trinket`, `utility`, `utility.wisp`, `utility.wishbone`, `trinket.1`, `trinket.2`, `trinket.hand` (the extra trinket seats talents open; worn seats like `trinket`, not storage), `food.0..2`, `potion.0..2`, `arrow.0..2`, `tool.0..7`, `purse.0..7`, `key.0..7`. Later minor versions may add cells; treat unknown ids gracefully. ```csharp Equipment.On; // the system is on Equipment.TurnedOffFor; // the other equipment mod that keeps the slots instead, or null foreach (CellInfo c in Equipment.Cells) { c.Id; c.Kind; c.Index; c.Title; c.Worn; } Equipment.ItemIn(player, "food.0"); Equipment.IsOpen(player, "potion.2"); // food/potion/arrow cells depend on the belt and quiver worn Equipment.Accepts("tool.3", item); Equipment.Put(player, "food.1", item); // worn cells: wears the item; false if refused Equipment.TakeOut(player, "helmet"); Equipment.GridPosition(player, "key.0"); // where the cell's item lies; (-1,-1) if none Equipment.IsCellPosition(player, pos); // sorters and stackers: leave these positions alone Equipment.BackpackRows(player); Equipment.FoodCells(player); Equipment.PotionCells(player); Equipment.ArrowCells(player); Equipment.KeyLabel("tool.0"); // "Alt+1" Purse.Open(player); Purse.Coins(player); Purse.Empty(player); Trinkets.Seats; Trinkets.OrdinarySeats; Trinkets.Worn(player); ``` **Turn it off.** `Equipment.TurnOff("my.guid")` in Awake: PoV's equipment system is off as if the player switched it off (rows, window, tool bar and purse stay away; cells a save still holds go back to the backpack). `TurnOff(null)` gives it back from the next character load. If you only want to keep the items yourself, `Storage.Register` is better: PoV's rules and effects then keep working. **Draw it yourself.** `Equipment.Host("my.guid")`: PoV keeps the cells and rules, removes its window and HUD bars and stops hiding its rows in the backpack grid. `Equipment.Host(null)` gives it back. ## Storage: keep PoV's cells in your inventory mod For inventory mods that manage slots themselves. Your mod keeps where the items lie and draws them; PoV keeps every rule and effect: what a cell accepts, how many food/potion/arrow cells are open, the hotkeys, the utility items' effects, the purse's death and weight rules, transmog, the tree's extra rows. ```csharp class MyStorage : IStorageProvider { public string Id => "my.guid"; public int Contract => Storage.Contract; // 1 public ItemDrop.ItemData ItemIn(Player p, string cell) { ... } // never moves anything public bool Put(Player p, string cell, ItemDrop.ItemData item) { ... } // move it, or change nothing public bool TakeOut(Player p, string cell) { ... } // into the backpack; false if no room } string refused = Storage.Register(new MyStorage()); // in Awake, before a character loads; null = accepted Storage.Changed("food.0"); // once after every committed change ``` - `Storage.Cells` lists the cells you keep: `food.*`, `potion.*`, `arrow.*`, `tool.*`, `purse.*`, `key.*`, `utility`, `utility.wisp`, `utility.wishbone`. Armour, belt, quiver and trinket stay the game's own equipment. - Items stay real items of the player's own inventory. Return those very items, not copies. - Check `Equipment.Accepts(cell, item)` and `Equipment.IsOpen(player, cell)` before placing. Your own slot counts and filters do not override PoV's rules: an item a cell does not accept is ignored there (PoV reads the cell as empty). - The choice is made when the character loads and holds for the session. With a provider active, PoV never attaches its rows, never reads item positions as cells, and hands you `Rows.Host` and `Equipment.Host`. Size the backpack with `Storage.ExtraRows`. - Death and weight: PoV keeps purse items out of the grave and removes their weight itself, through `ItemIn`. Read `Storage.KeptOnDeath` and `Storage.Weightless` to show it, but do not apply it again. - Coins and keys picked up are not sorted into their cells by PoV; place them yourself if you like. - If your provider throws, PoV logs it and pauses the cells for the session (`Storage.Suspended`). It never falls back to its own rows mid-session. - `Unregister` takes effect from the next character load. Nothing is converted: PoV rows in an old save are not moved into your slots. - Local player only, never on a dedicated server. ## Looks (transmog) ```csharp Looks.CanChange(item); Looks.Choices(item); Looks.IsOpen(look); Looks.Current(player, item); Looks.SameLook(a, b); Looks.HiddenLook; Looks.WhyNot(player, item, look, canHide); // null when allowed, else a translated reason string refused = Looks.Apply(player, list); // (item, look, canHide) tuples; one Rune of Guise each Looks.Reset(player, item); Looks.Runes(player); Looks.RuneIcon; using var portrait = Looks.CreatePortrait(rawImage); // Tick(player) each frame, Turn(deg), ShowBackground, TryOn ``` ## Items and tooltips ```csharp Rarity r = Items.RarityOf(item); // Common, Magic, Rare, Unique, Legendary Items.RarityTitle(r); Items.RarityNameColor(r); Items.RarityFrameColor(r); Items.Signature(item); // changes when anything PoV keeps on the item changes: redraw then string type = Tooltip.Describe(item, out var rows); // AffixRow: Name, Effect, Tint, Socket, EmptySocket, Warning Items.HostRarityFrames("my.guid"); // you draw rarity frames on inventory cells; PoV stops ``` Everything PoV keeps on an item, as data (feature `items.details`): ```csharp Items.IsCorrupted(item); Items.IsIdentified(item); Items.ItemLevel(item); Items.IsJewel(item); foreach (AffixInfo a in Items.Affixes(item)) // empty while the item is unidentified { a.Id; // stable affix id from the loot catalogue, or the unique line's mechanic id a.Place; // Prefix, Suffix or Unique (unique items and jewels) a.Tier; // "T1", "T2" ... or "" a.Value; // the rolled number, as the tooltip shows it a.Min; a.Max; // the tier's roll range, already scaled for the item's slot a.Text; // the tooltip line in the player's language a.Local; // works on the item itself (weapon damage, armour) instead of the character foreach (AffixStat st in a.Stats) { st.Stat; st.Form; st.Value; st.Subjects; } // PoV stat names, see Stats.Names } foreach (ImplicitInfo i in Items.Implicits(item)) { i.Id; i.Value; i.Min; i.Max; i.Text; } // e.g. belt food/potion slots foreach (SocketInfo s in Items.Sockets(item)) { s.Kind; s.Sigil; } // "runic" / "corrupted" / "divine", sigil prefab or null Items.Influences(item); // influence ids ``` ## Inventory and conveniences ```csharp Rows.Extra; // extra backpack rows the tree gives Rows.Host("my.guid"); // you size the inventory; PoV stops changing its height Conveniences.CraftFromChests; Conveniences.ChestReach(station); Conveniences.ChestCircleShown = true; QuickStack.Available; QuickStack.StackKey; QuickStack.SortKey; QuickStack.HostButtons("my.guid"); // you show the buttons; PoV's hotkeys keep working ``` ## HUD ```csharp foreach (HudPiece p in HudPieces.Pieces()) { p.Id; p.Title; p.Rect; p.ClaimedBy; } HudPieces.Claim("level", "my.guid"); // PoV stops moving and fading it; null gives it back ``` Piece ids: `level`, `buffs`, `monolith`, `shield`, `gauges`, `craft-queue`, `tasks` (more may come). ## Creatures ```csharp Creatures.RarityOf(c); // Magic, Rare, Unique from stars; Common when PoV's creature rarity is off Creatures.Stars(c); Creatures.ModifiersOf(c); // ids: swift, furious, armored, warded, burning, ... Creatures.Modifiers; // every modifier: Id, Title, About Creatures.Level(c); Creatures.BiomeLevel(Heightmap.Biome.Swamp); Creatures.IsPovBoss(c); // PoV's own monolith bosses Creatures.DamageFactor(c); // how much PoV multiplies its damage ``` **Leave your creatures alone.** A boss overhaul or elite-creature mod that designs its creatures itself: ```csharp // In Awake, on every machine (server and clients): Creatures.LeaveAlone("Bonemass", "my.guid"); ``` PoV then gives that prefab no rarity, stars or modifiers and does not scale its health or damage. `Creatures.LeftAloneBy(prefab)` tells who asked. ## Difficulty ```csharp Difficulty.Preset; // 0 vanilla creatures, 1 easy, 2 normal, 3 hard, 4 merciless Difficulty.PresetTitle; Difficulty.VanillaCombat; // Valheim's Combat modifier: 0 very easy ... 4 very hard, 5 none of these Difficulty.MonsterPower(c); // altar monster power for this creature (1 = none) ``` ## Texts `Texts.Get(key, englishFallback)`: a PoV text in the player's language. ## Recipes - **A skill mod (new skills):** `SkillFreeze.Exempt(yourSkill)` in Awake. Optionally also `Grant.TreeXp` for the activity, so it feeds the tree too. - **A boss or elite-creature overhaul:** `Creatures.LeaveAlone(prefab, guid)` for each creature you design. - **An inventory/equipment UI mod:** either draw PoV's cells (`Equipment.Host` + `Equipment.*`) or keep them yourself (`Storage.Register`). Use `Equipment.IsCellPosition` in sorting and stacking. - **A HUD mod:** `HudPieces.Pieces()` and `HudPieces.Claim`, then place the rects as you like. - **A loot mod:** read `Items.RarityOf`, `Tooltip.Describe`, `Creatures.RarityOf` / `ModifiersOf` for drop chances; `Events.LootRolled` to react to PoV's drops. - **A crafting station or profession mod:** `Grant.ProfessionXp(profession, xp)`. ## Missing something? Ask on the PoV Discord (https://discord.gg/XZsYRF2YtQ) with what you need. New members come in minor versions. ## Changelog - **1.1.0**: trinket seat cells `trinket.1`, `trinket.2`, `trinket.hand`. Known issue in PoV 5.0.9: `Pov.AtLeast(1, 1)` returns false there (`Pov.Version` says "1.1.0"); to detect the trinket cells, check `Equipment.Cell("trinket.1") != null`. Fixed in the next update. - **1.0.0**: first release.