Tech Tree API

API reference

Every public type and member in TechTree.Api, flat and anchored.

Namespace: TechTree.Api. Assembly: TechTree.dll. Nothing outside this namespace is public - the rest of the mod is internal on purpose, so there is exactly one door.

No member here takes or returns a Sprite, a Color, a GameObject or any Il2Cpp* type. You never need Il2CppInterop to use the API.

TechTreeApi

public static class TechTreeApi

MemberDescription
const string ModGuid Always "TechTree". Use it in [BepInDependency].
static readonly int ApiVersion Contract version of the installed dll. readonly, never const - see Versioning. Currently 1.
TechTreeModule ForPlugin(string pluginGuid, string tabName) Creates or renames your sub-tab and returns your module. Call once, keep the result. Never returns null.
int GetLevel(string nodeId) Owned levels, clamped to that node's MaxLevel. 0 for an unknown id. Dictionary lookup - cheap enough for a hot patch.
bool IsRegistered(string nodeId) Whether the id is currently in the tree.
void RefreshUi() Ask an open tree window to repaint. No-op when nothing is open.
event Action<string,int> LevelChanged (nodeId, newLevel), after a buy or a sell-back. All nodes, including built-ins.
event Action Apply About every 2 s, after Tech Tree's own effects. Not a per-frame hook.
event Action<int> SaveLoaded (slotIndex), once levels for that slot have been read.

TechTreeModule

public sealed class TechTreeModule - obtained from ForPlugin, never constructed directly.

MemberDescription
string PluginGuid { get; }The guid you passed in.
string TabName { get; }Your sub-tab label after trimming to 18 characters.
UpgradeHandle Register(UpgradeDefinition definition) Adds one upgrade line. Never throws; check .Success.
bool Unregister(string nodeId) Removes one of your nodes. The player's level is kept in the save.
void AddTranslations(string locale, IDictionary<string,string> values) UI strings for one locale. Tech Tree's own keys are skipped. Details

UpgradeDefinition

public sealed class UpgradeDefinition - a plain object with public fields. Full explanations on Node definition.

FieldTypeDefault
Id requiredstring-
DisplayNamestringnull
NameKeystringnull (auto: <id>.name)
MaxLevelint1
BaseCostfloat1000
CostMultiplierfloat1.8
CostForLevelFunc<int,int>null
SellBackRate 1.3.1float?null (60%)
IconUpgradeIconnull
DescribeLevel requiredFunc<int,string>-
IsUnlockedFunc<bool>null
LockedReasonFunc<string>null
ComingSoonboolfalse
SortOrderint0
LegacyIds 1.3.1string[]null
OnLevelChangedAction<int>null
OnApplyActionnull

There is no category field. Every registered node lives in the Mods tab, in your sub-tab. Why

UpgradeIcon

public sealed class UpgradeIcon - built through factory methods.

MemberDescription
static UpgradeIcon Builtin(string name) One of the 14 built-in icons. Unknown names fall back to a generic one. List
static UpgradeIcon FromPng(byte[] data, bool whiteSilhouette = false) Your own PNG, under 512 KB. Ship white artwork with alpha, or pass whiteSilhouette: true.

UpgradeHandle

public sealed class UpgradeHandle - what Register returns. Always non-null.

MemberDescription
string NodeId { get; }The id you registered.
string OwnerGuid { get; }The plugin guid that owns it.
RegisterResult Result { get; }Why it succeeded or failed.
bool Success { get; }Shorthand for Result.Success.
int Level { get; }Current owned level. Same as TechTreeApi.GetLevel(NodeId).
bool Unregister()Removes the node; the level stays in the save.

RegisterResult

public sealed class RegisterResult

MemberDescription
bool Success { get; }True for Ok and Replaced.
RegisterStatus Status { get; }Machine-readable outcome.
string Message { get; }The same text that went to the log.
string ToString()"Status: message".

RegisterStatus

public enum RegisterStatus

ValueMeaning
OkAdded.
ReplacedSame plugin re-registered the id; level kept.
MissingFieldNull definition, or no DescribeLevel / no name.
InvalidIdNot prefix.name, or bad characters.
ReservedIdStarts with techtree. or tt.
OwnedByAnotherAnother plugin owns the id.
InvalidLevelsMaxLevel outside 1..20.
InvalidCostNo positive BaseCost and no CostForLevel.
InvalidModuleEmpty plugin guid.

Built-in node ids

Stable, and none of them contains a dot - which is exactly why your ids must. Useful for gating.

IdNameLevels
cashier_speedFaster Till5
restocker_speedFaster Restocker5
staff_speedFaster Support5
customer_speedFaster Shoppers4
more_customersMore Customers5
smart_self_checkoutSmart Self-Checkout5
player_moveFast Feet5
player_sprintSprinter3
player_reachLong Reach3
quick_handsQuick Hands5

Limits at a glance

LimitValue
Nodes per plugin64
Levels per node1 - 20
Id length3 - 64 characters
Sub-tab label18 characters
Icon PNG512 KB
Kept lines per save slot4096
IsUnlocked cache0.25 s
Sell-back rate60% by default; a registered node can declare 0..1 via SellBackRate