Holy Shroom!

Modding Guide

Build your own forests, creatures, characters and rules, then publish them on the Steam Workshop. No C++ required.

What a mod can add

Four kinds of content, all of them made in the Unreal Editor, none of them needing a line of C++.

Terrains

Your own forest, swamp or trench, added to the map list in the base.

Characters

An extra pick in the character select, or a replacement for one of ours.

Creatures

A monster with working AI from a single data asset, or your own brain on top.

Mechanics

Your own rules: react to a picked mushroom, a sold basket, nightfall, a death.

The game's own data

Prices, species, contracts, emotes. Add a row, or replace one of ours.

A mod is not limited to adding things next to the game. Hand it a table with the same row type as ours and a row whose key the game already has, and your value wins: that is how a mod doubles what a bolete sells for, makes a contract pay differently, or puts a new species in the forest. Details in step 2.

Everything your mod contains lives under its own name, so two mods can both have a creature called Wolf without ever colliding. Your assets are mounted at /YourModName/.

Before you start

Three things, and the third one is the part most people miss.

WhatWhy
Unreal Engine 5.8The game is built on 5.8. An older engine cannot open the SDK project.
Holy Shroom! Mod SDKThe project you open in the editor. 4 MB, and it carries the mod API, the packaging tools and a working example.
The game on SteamYou test the mod in the real game, and the Workshop upload goes through your Steam account.
Download the Mod SDK (4 MB)
The game's tables are open to mods: a mod can change what a mushroom is worth, what the shop sells and which contracts show up, on top of adding creatures, characters and terrains.

Unzip it anywhere and open HolyShroomModSDK.uproject. The plugins come compiled, so you do not need Visual Studio and there is nothing to build.

The SDK does not contain the game. No game source, no game assets. It carries the mod API (the same plugin the shipped game runs), the packaging tools, a snapshot of the released game to cook against, and two worked examples: Rotcap, a creature built from data alone, and Hunger, a mechanic written entirely in a Blueprint graph. Both are on the Workshop, so you can read the files and play the result side by side. When a new version of Holy Shroom! ships, take the new SDK: an old snapshot cooks mods against an old game.
Questions and broken mods: the Holy Shroom! Discord. That is also the place to show what you are building.

A mod is a content-only Unreal plugin that sits in the Mods folder of the SDK project:

HolyShroom/ Mods/ MyCoolMod/ MyCoolMod.uplugin who you are, what you need Content/ ModManifest.uasset what the mod adds ...your assets... meshes, maps, blueprints
Two files decide everything: the descriptor and the manifest.
The RotcapMod folder in Windows Explorer: a Content folder and a .uplugin file
What it looks like on disk. This is Rotcap, the first published mod: one folder, one descriptor.

1Create the mod

One menu entry. It writes the descriptor, the folder and the manifest for you.

  1. Open the Mod SDK project in Unreal Editor 5.8.
  2. Go to Tools → Ultimate Mod Kit → New Mod…
  3. Type a name, your author name and one sentence about what the mod does.

The Content Browser now shows /MyCoolMod/ and you can start dropping assets in. You never need the Python console for any of this: the same menu packages the mod and publishes it.

Content Browser showing the mod's manifest and creature profile
The two assets of a creature mod in the Content Browser: the manifest and the creature profile, both of them data assets. (Editor shown in Polish, the layout is the same in any language.)
Read this once and you will save yourself an evening. A mod is never mounted automatically in the editor. After every editor restart, open it again with Tools → Ultimate Mod Kit → Open Mod For Editing and pick your mod from the list. If its folder is in the Content Browser, it is open.

The whole menu

Tools → Ultimate Mod KitWhat it does
New Mod…Creates the mod: descriptor, Content folder, manifest, placeholder preview image.
Open Mod For EditingRe-opens a mod after an editor restart.
Package ModCooks it into the archive players download.
Upload Mod To Steam WorkshopPublishes it, or updates your item.

If you would rather script it, the same four things are on unreal.GrzybiarzModTools in the Python console — but nothing in this guide requires it.

2Fill in the manifest

The manifest is the game asking: so what exactly did you bring?

Open /MyCoolMod/ModManifest. Every field is a list you add to.

FieldWhat it does
MapsAdds terrains to the pick-a-forest list in the base.
CharactersExtra cards in character select, or a replacement for one of ours.
CreaturesOne entry per creature profile.
MechanicsYour components, injected into the player or into creatures. Target says which.
TablesThe game's own data: prices, species, contracts, emotes.
RequiresModsYour mod refuses to start without these.

Characters: body and animations

A character here is not a pawn class - it is a row of data (body, stat bars, voice) that the shared player body uses. Two fields decide how it moves:

FieldWhat it does
MeshThe body. Janusz_Skeleton ships with the SDK, so import your mesh onto it (or mark your skeleton compatible with it) and every animation and montage in the game plays on your character for free.
AnimClassYour own Anim Blueprint, for a body on a skeleton of your own. Empty = the game's animations.
Our montages live on our skeleton. Picking, punching, getting up and the emote dances are animations on Janusz_Skeleton and will not play on a foreign one. Your own Anim Blueprint gives your character walking, running and idling; those gestures stay missing until you rebuild them yourself. For most characters the easy road is the right one: build the body on our skeleton and leave AnimClass empty.

Mechanics: where your component goes

A mechanic is a Blueprint deriving from Grzybiarz Mod Mechanic Component, listed under Mechanics with your blueprint in ComponentClass. Target picks who gets it:

TargetWho gets the component
PlayerThe picker. Use this for anything that happens to the person playing.
CreatureCreatures from any mod.
Custom classA class you ship yourself, named in TargetClass.
Leave it on Player unless you know otherwise. The SDK carries no game code, so the player class is not in your class list and you cannot point at it by hand - the game supplies it when your mod runs. Mods/HungerMod in the SDK is exactly this: one component on the player, all the logic in a Blueprint graph, no C++.

Tables: changing the rules, not just adding to them

Make a Data Table with the same row type as ours, and list it under Tables with the name of the table it joins:

TableIdJoinsWhat you can do
Mushroomsmushroom speciesadd a species, or change a price, freshness or trip effect
Shopthe shopadd an item, or change what one of ours costs
Missionscontractswrite your own, or change a reward
Emotesthe emote wheeladd a dance
Creaturesthe bestiaryadd an entry
Terrains, Charactersforests and pickerssame as the fields above

Two rules decide everything:

The row type must match. A table with the wrong row type is skipped with a message in the log, rather than being read as garbage. Open one of the game's tables once to see the columns you fill in.

Set bMayOverrideBaseRows to false if your mod should only ever add things; the game then leaves its own rows alone and tells you in the log when your table collides with one. Changing prices makes your mod gameplay-affecting, so everyone in a co-op session needs it. That happens by itself.

The manifest must keep its name. It lives in the root of your Content folder and it is called ModManifest, exactly. A mod without one still mounts its assets, it just adds nothing by itself.

3Example: a creature in ten minutes

The shortest useful mod there is. One data asset, and the game gives it a working brain: idle, wander, chase, attack, flee, die.

Right click in your mod folder and create a Grzybiarz Mod Creature Profile, or make it from the console:

unreal.GrzybiarzModTools.create_mod_data_asset(
    "MyCoolMod", "DA_MyCreature", unreal.GrzybiarzModCreatureProfile)
The creature profile asset open in the editor, with its categories
The profile has everything in one place: looks, classes, stats, AI, spawning, sound, animation. Open it and fill in the categories from top to bottom.

Then fill it in. These are the numbers from Rotcap, the first published mod, so you can copy them and change one thing at a time:

FieldValueWhat it means in play
Mesh + AnimClassskeletal mesh + its anim blueprintLeave AnimClass empty and your creature stands there like a statue.
Health70Dies to a handful of hits.
Damage10A player has 100 health, so ten hits.
RunSpeed460Slower than a sprinting picker. They can get away.
SightRadius180018 metres. Centimetres everywhere, this is Unreal.
bRequiresLineOfSightfalseIt smells you through the trees. Turn it on for a creature that hunts by sight.
FleeHealthFraction0.25Runs away once it is down to a quarter. 0 means it never runs.
TimeOfDay10 anytime, 1 night only, 2 day only.
MaxAlive4How many of them can be in the forest at once.
ThinkInterval0.3How often it makes a decision. This is a timer, not a tick.
Always set Attenuation on the sounds. Without it every player hears your creature growling across the whole forest, all the time, and your mod gets uninstalled in four minutes.

Want more than the built-in brain?

Last step: add the profile to Creatures in the manifest. A creature nobody lists is a creature nobody sees.

4Test it in the editor

Two tests, and they answer different questions. The SDK has no game in it, so the game itself is where a mod is finally proven.

In the SDK: does the game accept the mod at all

  1. Mount the mod (see step 1).
  2. Watch the Output Log, category LogGrzybiarzMods. Mounting the mod and loading its manifest both report there, and so does every table it changes: doklada do tabeli 'Mushrooms': 20 wierszy.
  3. If the manifest has a mistake, it is named here: a table entry without an id, a creature profile that would not load, a table the game does not know.

In the game: does it actually do something

  1. Package the mod (step 5).
  2. Copy the packaged mod folder into Mods next to the installed game, so that you end up with HolyShroom/Mods/YourMod/YourMod.uplugin and HolyShroom/Mods/YourMod/Content/Paks/Windows/.
  3. Start the game, open MODS, tick your mod, press APPLY.
  4. The row tells you what the game took from it, for example 2 tables or 1 creature. If it says Assets only., your manifest declared nothing.

This second test is the one that matters. A mod can look perfect in the editor, where its assets are loose files on disk, and still arrive empty in a packaged game, where everything lives inside an archive. Do not skip it, and do not announce a mod you have only seen in the editor.

5Package it

In the editor, raw asset files work. In the real game they do not, and this is where most first mods die.

The packaged game reads cooked content, a .pak inside your mod's Content/Paks/<Platform>, for example Content/Paks/Windows. You never build that by hand:

Two things the scaffold does not make for you, and both are easy to notice only after your mod is already on the Workshop looking unfinished:
  • preview.png in the mod folder, under 1 MB. Without it your item has no thumbnail, and an item with no thumbnail is one nobody clicks. preview.jpg or Resources/Icon128.png work too.
  • "UMKTags": ["Creature"] in your .uplugin. Without it the upload sends no tags at all and nobody filtering the Workshop will find you.
Also: save your assets before packaging. The cooker reads files from disk, so an unsaved manifest is a mod packaged without the thing you just made.

Tools → Ultimate Mod Kit → Package Mod → your mod. Package Mod and Upload are submenus: they list every mod the kit can see, and you pick yours.

The Ultimate Mod Kit entries in the editor's Tools menu
Five entries live under Tools, here filtered by typing "Mod" into the menu's search box, which is why Create Base Game Release is not on the screenshot. That is the fastest way to reach them.
Your mod .uasset files Package Mod cooks it as DLC Upload to the Workshop Subscriber ticks it in MODS
Four steps from your folder to somebody else's game.

Your mod is cooked on top of a snapshot of the shipped game. Anything you re-use from the base game, a mesh, an animation blueprint, a sound, stays out of your .pak and costs you nothing. That is why a good creature mod can weigh a few kilobytes.

"No base game release" in the menu? It means the snapshot has not been made for the build you are on. The kit says so plainly: "No base game release named '1.0' was found", and tells you to run Create Base Game Release first. If you are modding a released build and that entry fails for you, say so on Discord, because then it is on us.

6Upload to the Steam Workshop

Tools → Ultimate Mod Kit → Upload Mod To Steam Workshop → your mod

Your mod is not in the list? The kit only lists mods from the folder the project points it at. If yours sits somewhere else it will not show up, even though it is a perfectly good mod. Keep mods in Mods/.

What ends up on your Workshop page is taken from files you already have:

On the pageComes from
TitleFriendlyName in your .uplugin
DescriptionDescription in your .uplugin
TagsUMKTags in your .uplugin
Preview imagepreview.png, preview.jpg or Resources/Icon128.png in your mod folder

Make the preview a square, somewhere around 512 by 512, and keep it under 1 MB: that is Steam's limit for a Workshop preview image. A 4K screenshot dropped in as preview.png is the most common reason an upload comes back with an error that explains nothing.

The first time you upload anything to a Workshop, Steam asks you to accept the Steam Workshop Terms of Service. Until you do, uploads from any tool fail.

Do not delete workshop.json. It sits next to your mod and remembers the Workshop item id. Lose it, and your next upload creates a second item instead of updating the first one.
Never upload the staging folder the cooker leaves behind. It has no .uplugin in its root, so it looks perfectly fine on your machine and is rejected on every subscriber's machine. Upload what the kit builds for you and nothing else.

Bump VersionName on every release. Players paste their mod list into bug reports, and the version is what tells you which build they were on.

7Your item page on Steam

Most of your item page is written by your mod, not by you clicking around on Steam.

The title, the description and the tags come from your .uplugin (FriendlyName, Description, UMKTags) and are sent again on every upload. Fix a typo in the descriptor, upload, and the page follows. The flip side: if you rewrite that text by hand on Steam, your next upload overwrites it. To keep the page yours, put "SyncDescription": false into the mod's workshop.json and the uploader stops touching it.

Visibility is also set by the upload, so a new item does not sit there private waiting for you to find the switch. It comes from "Visibility" in workshop.json, and when that field is absent, from the game's own default, which is public:

{
    "ItemId": "3826200138",
    "Mod": "RotcapMod",
    "Visibility": "public"
}

public is listed and searchable, unlisted works by direct link and can still be subscribed to, friends is your Steam friends only, and private is you alone. Set it here rather than on the Steam page: a change made on the page is undone by your next upload.

What is still yours to do on Steam:

  1. Open Workshop → Your Files → Your Workshop Files, or go straight to the item by its id, the number the kit writes into workshop.json.
  2. Add screenshots. Three or four from inside the game, showing the thing your mod adds. The uploader does not send these, and they are what decides whether anyone subscribes.
Your mod files .uplugin: name, text, tags workshop.json: visibility Upload Mod sends all of it, every time SyncDescription: false to stop Live on the Workshop people can subscribe you add screenshots
The page is built from your mod's own files. Screenshots are the part you add on Steam.

Check it like a player would

  1. Subscribe to your own item.
  2. Start Holy Shroom!
  3. Open MODS. Your mod is in the list, with the name and description from the .uplugin.
  4. Tick it, press APPLY, play.
It is in the list but it does nothing. Nine times out of ten you uploaded a mod that was never packaged, so the game has your descriptor and no cooked content. Go back to step 5, package it, upload again.

8Updating your mod

Same two clicks, one number.

  1. Change whatever you are changing in the editor.
  2. Bump VersionName in the .uplugin.
  3. Package Mod again.
  4. Upload Mod To Steam Workshop again. Thanks to workshop.json this updates your existing item instead of making a second one.
  5. On the item page, write a short change note. Subscribers get your update automatically and a note is the only way they learn what moved.
In co-op, everybody needs the same version. A gameplay mod builds a fingerprint from its version, so a host on 1.2 and a friend on 1.1 will not match. Tell people in the change note when an update breaks older sessions.

When something breaks

The mod list in the game says all of this out loud. Here is what each line means.

What you seeWhat to do
The .uplugin file is missing ExplicitlyLoaded Add "ExplicitlyLoaded": true and "CanContainContent": true to the json. Both are required: without them the game cannot mount your mod while it runs.
The mod's content could not be mounted There is no Content folder, or CanContainContent is missing.
Made for mod API N Your GrzybiarzModApiVersion does not match this build of the game. Update the mod.
This mod interrupted the previous launch The game crashed while your mod was starting, so it was parked to let the game boot. Fix it, then tick it again.
Your creature stands still AnimClass is empty, or the anim blueprint does not match the mesh skeleton.
Your creature is sunk into the ground The mesh pivot is not at its feet. Raise it with MeshZOffset.
Nothing of yours appears in the packaged game You shipped raw assets instead of a packaged mod. Go back to step 5.
The upload worked, nobody can find the mod Check "Visibility" in the mod's workshop.json. If it says private or friends, change it and upload again. Steam also takes a few minutes to index a brand new item.
The upload fails and says nothing useful Two usual causes: your preview image is over 1 MB, or you have never accepted the Steam Workshop Terms of Service on this account.
Your second upload made a second item workshop.json next to the mod was deleted or moved. Delete the duplicate item and keep that file from now on.

Co-op rules

Holy Shroom! is played together, and that puts three rules on your mod.

Money and progress live in the profile of the machine you are on, not in the world: in co-op everybody has their own wallet.