Mega Tree API

Icons

The fourteen built-in icons, and how to ship your own PNG so it does not come out the wrong colour.

Built-in icons

Cheapest option, and it keeps your node visually consistent with the rest of the tree. Pass the name; an unknown name silently falls back to git-branch.

csharp
Icon = UpgradeIcon.Builtin("package"),

These are the exact images the mod draws, rendered here from the same files:

chevrons-right chevrons-right
footprints footprints
gauge gauge
git-branch git-branch
hand hand
monitor monitor
package package
scan-barcode scan-barcode
shopping-cart shopping-cart
timer timer
truck truck
user-plus user-plus
users users
zap zap

Icons by Lucide, ISC License.

The same fourteen names as Tech Tree

Mega Tree ships the identical icon set, under the identical names. A registration copied from a Supermarket mod keeps the same picture without you checking anything.

Your own PNG

csharp
Icon = UpgradeIcon.FromPng(MyIcons.Capacity),

// ...and if your art is coloured, let Mega Tree flatten it:
Icon = UpgradeIcon.FromPng(MyIcons.Capacity, whiteSilhouette: true),
RequirementValue
FormatPNG with an alpha channel
ColourWhite artwork on a transparent background
SizeSquare. 128×128 is what the built-ins use and is plenty
File sizeKeep it under 512 KB
White with alpha, not colour

Mega Tree tints the icon through Image.color to show state - grey when locked, dim when unaffordable, branch colour when bought. Tinting multiplies, so a green icon tinted violet comes out near black, and a dark icon comes out invisible. White is the only colour that survives every state.

If you cannot re-export your art, pass whiteSilhouette: true and every opaque pixel is flattened to white for you, keeping the alpha. You lose the internal shading, so it works for flat symbols and not for detailed pictures.

Embedding the bytes

Never ask the player to drop a loose png next to your dll: a missing file means a broken node and a bug report you cannot reproduce. Put the bytes in your assembly.

As an embedded resource

xml
<ItemGroup>
  <EmbeddedResource Include="assets\capacity.png">
    <LogicalName>BigBoxes.capacity.png</LogicalName>
  </EmbeddedResource>
</ItemGroup>
csharp
private static byte[] Load(string name)
{
    using (var s = typeof(Plugin).Assembly.GetManifestResourceStream(name))
    {
        if (s == null) return null;
        using (var ms = new MemoryStream())
        {
            s.CopyTo(ms);
            return ms.ToArray();
        }
    }
}

// Icon = UpgradeIcon.FromPng(Load("BigBoxes.capacity.png")),
The MSBuild culture trap

MSBuild treats a file named icon.en.png as an English satellite resource and moves it into a separate assembly, where GetManifestResourceStream will never find it. If a filename has a dot-separated segment that looks like a culture code, set <WithCulture>false</WithCulture> alongside LogicalName.

As base64

No resource plumbing, at the cost of a large string literal. This is what the example mod does.

csharp
internal static class MyIcons
{
    private static byte[] _capacity;
    public static byte[] Capacity => _capacity ?? (_capacity = Convert.FromBase64String(CapacityB64));

    private const string CapacityB64 =
        "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAB9klEQVR42u3cUW7DMAwE0azR" +
        "...";
}

Generate the string from a file:

powershell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("icon.png")) | clip

When the decoding happens

Your bytes are kept as bytes at registration and only turned into a texture the first time a node using them is drawn. This is not laziness for its own sake: a Texture2D can only be created on Unity's main thread once the engine is up, and your plugin's Awake() runs long before any scene exists. Decoding at registration would crash the game.

Consequences worth knowing:

Choosing well