Hoedin
Compatibility port of MagicMike's MyDirtyHoe for current Valheim. All credit to MagicMike. Temporary - it will be removed the moment the original is updated.
About this mod Author’s original text
Hoedin
This is MagicMike's mod. Hoedin is nothing more than a compatibility port of
MyDirtyHoe 2.0.2
so it runs on current Valheim. Every tool, every piece, every bit of design in
here is MagicMike's work — the only thing added was the plumbing needed to make
it load again.
It is meant to be temporary. The moment MagicMike updates MyDirtyHoe, install
his and delete this; this package will be taken down. If MagicMike would like it
removed sooner, say the word and it goes immediately.
Sorry about 1.1.0
1.1.0 (14 Sep 2026) broke every hoe operation on the client — the piece placed,
the effect played, and the ground never moved, with a stack trace in the log per
click. That was a typo-class mistake in the radius fix, not anything in
MagicMike's mod, and it was live for about two hours before 1.1.1 replaced it.
If you played in that window and thought the mod was dead, it was: update and
it works. Apologies for the wasted evening.
Why it exists
MyDirtyHoe 2.0.2 was published in June 2025 and still installs cleanly today —
which is exactly the problem. On current Valheim the hammer menu fills in, the
pieces place, the effects play, and the ground never moves. No error, no
crash, nothing in the log that looks wrong. It just silently does nothing.
Three separate changes cause it:
- TerrainComp was sealed. m_initialized, m_width, m_modifiedHeight,
m_levelDelta, m_smoothDelta, m_modifiedPaint, m_paintMask, m_nview
and Save() all became private; the mod read and wrote them directly.
- Signatures changed. Heightmap.Poke(bool) became
Poke(int delayed = 0, bool paintOnly = false), Piece.SetCreator gained a
PlatformUserID, and Terminal.ConsoleCommand's constructor gained an
argument before the options fetcher.
- Terrain operations stopped carrying their settings over the wire. The game
now sends only a prefab hash and resolves it against a registry built from the
shipped ObjectDB. A modded piece is not in that list, so the server logs
"Failed to deserialize TerrainOp settings … cancelling TerrainOp" and returns
null — the piece still places, and the terrain is never touched. This one
breaks every mod that adds terrain pieces, not just this one.
Note that none of the first two is a missing name, which is why a name-only
compatibility check calls the mod healthy. It is not.
What changed
- Every now-private TerrainComp member goes through Harmony FieldRefAccess
delegates, built once at load. This runs per terrain vertex across a radius, so
reflection on every access would have been felt.
- Call sites were fixed against the game's own usage rather than guesswork —
Poke(1) because the game itself calls the delayed form that way, and
SetCreator(id, PlatformManager.DistributionPlatform.LocalUser.PlatformUserID)
copied from Player.
- A Harmony prefix on ObjectDB.UpdateRegisters adds the bundle's terrain-op
prefabs to m_terrainOps before the game rebuilds its hash table, which fixes
point 3 above. A prefix rather than a postfix so the game does its own hashing —
a postfix would have to duplicate that and would rot when it changes.
- The scroll-wheel radius works again (1.1.1). MyDirtyHoe changes the radius
by adjusting the placed piece's settings, and before 1.0.7 those settings
travelled with the terrain operation. Now only the prefab hash does, so the
server applied the default size every time while the preview happily scaled —
a feature that looked like it worked and did nothing. Hoedin appends the
radius change to the operation itself and reads it back on the receiving side.
An unscrolled placement is byte-for-byte vanilla, and a sender or receiver
without this build is simply applied at the default size.
If Ctrl+scroll grew the preview but the ground always came out the same
size, 1.1.1 should fix it (1.1.0 tried and broke every hoe operation on the
client instead — do not run it). If it still does not on a 1.1.1 server, send
the server owner your BepInEx/LogOutput.log.
- Its own plugin GUID (org.zrikzinc.
Install & use Install: BepInEx plugin
- The archive from playbuff is the mod itself — usually a BepInEx plugin (a .dll or a plugin folder once unzipped).
- Recommended: use a community mod manager (such as r2modman) — pick this game, import the mod, and the manager sets up BepInEx and its dependencies for you.
- Manual route: install the BepInEx loader in the game folder, then drop the unzipped .dll or plugin folder into BepInEx/plugins/.
- Launch the game — the BepInEx console logs every plugin it loads; seeing this mod in the log means it is installed.
Mods with listed dependencies need those installed too, or they will not load. Options are usually changed in-game or in the plugin's config file. In multiplayer, the host and every client need the same mods installed.
Install these first, or the mod will not work: