# TerraVox Diggable, replicated and persistent voxel volumes for Unreal Engine 5.6, 5.7 and 5.8 (Windows and Linux). Players dig and build with a key press; every client sees the same result; edits survive restarts. Voxels are smooth: each one stores how much of it is rock, so walls, slopes and dig marks follow the real shape instead of stepping one voxel at a time. Five kinds of volume: | Actor | What it is | Typical use | |---|---|---| | **TV Interior Volume** | A private closed space of rock the player is teleported into. | Burrows, personal mines, pocket dimensions. | | **TV Voxel Block** | A solid box or ellipsoid placed in the world (or spawned), dug from outside or inside. | Rocks, walls, mounds, breakable obstacles. | | **TV Voxel Terrain** | Diggable ground from a preset (hills, mountains, canyon, island, flat) or an imported heightmap. | Diggable landscapes, arenas, islands. | | **TV Voxel Mesh** | Any static mesh turned into diggable voxels. | Statues, ruins, custom rocks. | | **TV Surface Patch** | Makes an area of an existing Landscape (or static mesh ground) diggable. | Dig into your own level's terrain. | **Contents:** [Quick start](#quick-start) · [Try the example first](#try-the-example-first) · [Blueprint only](#blueprint-only) · [Voxel materials](#voxel-materials) · [Editing in the editor](#editing-in-the-editor) · [AI navigation](#ai-navigation) · [Sculpting](#sculpting) · [Stamps](#stamps) · [Undo and redo](#undo-and-redo) · [Dig effects](#dig-effects) · [Explosions](#explosions) · [Building](#building) · [The digger component](#the-digger-component) · [Settings shared by every volume](#settings-shared-by-every-volume) · [Interior volumes](#interior-volumes) · [Voxel blocks](#voxel-blocks) · [Voxel terrain](#voxel-terrain) · [Voxel meshes](#voxel-meshes) · [Foliage](#foliage) · [Surface patches (dig into a Landscape)](#surface-patches-dig-into-a-landscape) · [Reacting to changes (Blueprint)](#reacting-to-changes-blueprint) · [Saving](#saving) · [Console](#console) · [Performance](#performance) · [Networking](#networking) · [Troubleshooting](#troubleshooting) · [Limitations](#limitations) · [Tests](#tests) ## Quick start 1. Enable the **TerraVox** plugin (it enables Procedural Mesh Component and Enhanced Input). 2. Add a **TV Digger Component** to your character. 3. On it set **Dig Action** (an Input Action, Digital/bool), **Build Action** if players build, and, for interiors, **Enter Exit Action**. If those actions aren't in your own mapping context, also set **Input Mapping Context** to one that maps them to keys. The plugin's own will do: pick `IA_Dig`, `IA_Build`, `IA_EnterExit`... and `IMC_TerraVoxDigger` from *TerraVox Content / Example / Input* (enable *Show Plugin Content* in the picker); it maps every action the component has (dig, build, paint, sculpt, undo, redo, next material, next brush, enter/exit). The component binds itself when the pawn is possessed. **Dig Pitch Offset** (10°) lifts the aim for a camera above and behind the pawn; set it to 0 for a first-person camera, or digs land above the crosshair. Also for first person, tick **Dig At Aim**: digs land where the crosshair meets the ground (within reach) instead of starting at the pawn's body. 4. Drag a **TV Voxel Block** or **TV Voxel Terrain** into your level (it shows in the editor viewport), press Play and dig. For interiors, press your Enter Exit key (or run `TV.EnterExitInterior`): you are moved into your own interior 2 km above you. Press it again to come back. The component digs or builds in whichever volume is in front of the pawn: the one it stands in, or a block / terrain within reach. A new terrain looks like grass over dirt over stone out of the box (the plugin's procedural sample materials); blocks, interiors and voxelized meshes are filled with their **Fill Material** (0, grass, unless you set 1 for dirt or 2 for stone). Give them your own look with a **Palette** (see *Voxel materials*). Nothing happens when you press dig? See *Troubleshooting*. ## Try the example first Open **TerraVox Content / Example / Maps / TerraVoxExample** (enable *Show Plugin Content* in the Content Browser) and press Play. Left mouse digs, right mouse builds, F paints, hold R to sculpt, G / T pick the material / brush, B throws a grenade, V drops a boulder, M switches the supply mode, Z / X undo and redo, K takes you to your own underground room, F3 shows debug info (frame time, the volume aimed at, its dug chunks, meshes, queued work and predictions, and `TV.Voxel.Debug`'s bounds and dig shape). The keys are on screen. Everything there is ordinary content you can copy into your project: | Asset | What it shows | |---|---| | `BP_TerraVoxExampleCharacter` | A first-person character with a TV Digger Component, every action set in its Details panel. Its Event Graph prints the gold a dig yields (the component's **On Dug** event, when there's gold), and B / V / M call Throw, Drop Boulder and Switch Supply Mode. It allows undo to show it off: undo and redo are reported through On Built / On Dug, so a game that pays in On Dug must also charge in On Built, or turn **Allow Undo** off. | | `BP_TerraVoxExampleInterior` | The underground room K takes you to: a TV Interior Volume child with its own size, cavity and a gold vein (the character's digger component points at it). | | `BP_TerraVoxExampleGrenade` | A grenade whose Event Graph is the whole recipe: **Delay**, then (on the server) **Explode** where it lies, then **Destroy Actor**. | | `BP_TerraVoxExampleBoulder` | V drops it: its Event Graph **Stamp Shape**s a stone rock where it lands, with the boulder as **Author** (its thrower's rules apply, it never buries anyone, and the rock is reported to the thrower through On Built). In Dig To Build a boulder costs a build's supply. | | `SM_TerraVoxExampleGrass`, `M_TerraVoxExampleGrass` | The terrain's **Foliage**: grass on the grass layer only, gone where the ground is dug. | | `BP_TerraVoxExampleGameMode` | Picks that character; its HUD prints the keys, the build material, the brush and the supply. | | `Input/IA_*`, `IMC_TerraVoxExample`, `IMC_TerraVoxDigger` | Enhanced Input actions and the two mapping contexts (moving; digging). | | `PA_TerraVoxExample` | A voxel palette: grass, dirt, stone and gold, each with its textured look, hardness and sounds. | | `Maps/TerraVoxExample` | A terrain with layers, a gold vein, caves and grass, a voxel block and a voxelized mesh. M switches the digger between **Free** and **Dig To Build** (digging earns the supply building spends; the HUD shows it). | | `Maps/TerraVoxExample_SurfacePatch` | Ordinary level ground made diggable in one area by a surface patch (a Landscape works the same). Its ground is a plain colour so you can see where the patch takes over; in your level, give the patch's top material the look of your ground. | **Multiplayer**: in the Play menu set *Number of Players* to 2 and *Net Mode* to *Play As Listen Server* (or Client); dig in one window and watch the other. `Net PktLag=200` in the console shows client prediction at work. **Saving**: digs are saved on their own (every **Autosave Interval**, and when play ends); stop and play again and the holes are still there. Delete `Saved/SaveGames/TerraVox_*.sav` to start fresh. Your underground room (K) is the exception in PIE: it's saved under the player's online id (Steam, EOS...), which PIE doesn't have, so it starts new each time there. ## Blueprint only No C++ is needed. In a Blueprint project: 1. Add a **TV Digger Component** to your character Blueprint and fill its **Input** fields (or leave them empty and call **Request Dig**, **Request Build**, **Request Paint**, **Request Sculpt**, **Request Undo / Redo** and **Request Enter Exit** from your own input events). 2. For your UI, read **Get Supply**, **Selected Material** (set it, or call **Select Material By Name**) and **Sculpt Mode**, and bind **On Supply Changed**. 3. Volumes are placed like any actor (Place Actors has a **TerraVox** tab); you can subclass them in Blueprint. Dig shape, reach, effects and level-of-detail settings can be changed at runtime; layout settings are read-only once playing. **Dig Extent** belongs to the volume, so it's the same for everyone digging in it (change it on the server and the clients, which predict with it). For one player's bigger tool, call **Stamp Shape** (Add off) with their pawn as **Author**: their rules apply and what it digs is reported to them like a dig. **Save To Storage** / **Load From Storage** save at a checkpoint (server). Bind **On Voxels Edited** (see *Reacting to changes*) to react to digging, and use **Line Trace With Voxels** for shots that should see dug tunnels and hit the rock exactly. **Find Dig Target** / **Find Build Target** / **Find Sculpt Target** (pawn + the component's **Get Dig Direction**) return the volume the player is aiming at, e.g. for a HUD showing **Get Material Name** of it. Recipes (Event Graph): - **A grenade** (`BP_TerraVoxExampleGrenade` is this): an actor Blueprint spawned with **Spawn Actor from Class** (Instigator = the thrower's pawn); on **Event Hit** (or after a **Delay**): **Explode** (Location = **Get Actor Location**, Radius 300, Power 1, Base Damage as you like, Damage Causer = **Self**), then **Destroy Actor**. It digs a crater in every volume it reaches and throws the loose rock as debris; call it on the server (**Has Authority**). - **Paying for what was dug**: select the TV Digger Component and add its **On Dug** event (Details → Events, the green +): **Voxels By Material** holds how many voxels of each material were dug; **Get** index 3 (gold in the example palette) and add it to your inventory. **On Built** is its counterpart (take the material a build used). Both fire on the server, for everything the player does: digs, builds, paints, sculpt strokes, their grenades and stamps (an Author or a projectile they threw), and undo / redo (undoing a dig reports the rock it puts back through On Built). Pay in one and charge in the other and no sequence of edits makes something from nothing. The **TV Digger** interface (Class Settings → Interfaces) gives the same **Event On Dug** / **Event On Built** plus rules (**Can Dig In**, **Can Build In**); once added, those two return false until you open each and tick its Return Value (or put your rule there), or nothing can be dug or built. - **Reacting to any change** (a quest, AI, decals): on a volume, **Bind Event to On Voxels Edited**; the event gives the author, the world box that changed and how many voxels. The example character is a Blueprint of a small C++ class (walking, looking, the throw RPC); the keys B, V, M and the gold message are in its Event Graph. A plain `Character` Blueprint with the component works the same. ## Voxel materials Every voxel has a material id: an index into the volume's **Voxel Materials** array (any Unreal material; use world-aligned / triplanar ones, no UVs are generated). Surfaces are split into one mesh section per material, with a hard edge where two materials meet. By default it holds the four procedural samples: grass (0), dirt (1), stone (2), gold (3). **Palette** (recommended): a **TV Voxel Palette** data asset (Content Browser > Miscellaneous > Data Asset) lists each material once for the whole game: **Name**, **Material**, **Hardness** and **Sounds**. Set it on each volume's **Palette** and it replaces that volume's Voxel Materials, Material Hardness and Material Sounds. Blueprints then use names: **Find Material Id** ("Gold" → id), **Get Material Name**, **Get Num Materials**, and the digger component's **Select Material By Name**; the editor brush lists them by name. Volumes also expose **Get Voxel Size**, **Get Bounds Extent**, **Get Grid Size**, **Get Num Chunks** (changed chunks) and **Get Palette** to Blueprints. - **Fill Material**: the starting rock (blocks, interiors; on terrain, what lies below its layers). - **Ground Layers** (terrain): bands from the ground down, e.g. grass 50 cm, dirt 3 m, then Fill Material. - **Veins**: ore or other pockets in the starting rock, placed by 3D noise (same on every machine): material, size, rarity (roughly the share of rock it takes) and, on terrain, a minimum depth. - **Paint**: the component's **Paint Action** / `RequestPaint` repaints the rock being aimed at with its **Selected Material**, without changing its shape. - **Build** places new rock of the **Selected Material**. - **Dig** reports what it mined: the digger component's **On Dug** event (or `OnDug` on the pawn's TV Digger interface), or `GetLastDugByMaterial()` on the volume: count per material id, e.g. to give the player ore. Builds, paints, sculpt strokes and undo / redo are reported the same way (**On Built** for rock added or repainted). **Ready-made look** (plugin content, Materials/Samples): `M_TerraVoxTriplanar` projects textures from the three world axes (voxel surfaces have no UVs) with Tint, Tile Size, Roughness Scale and Metallic; instances for grass, dirt, stone and gold use CC0 textures by [ambientCG](https://ambientcg.com) (Grass001, Ground037, Rock030). `M_TerraVoxProcedural` is a texture-free alternative (world-space noise). **Blended edges** (**Blend Material** = `M_TerraVoxTriplanarBlend`): neighbouring materials fade into each other instead of meeting in a voxel-sized zigzag. Each surface piece draws its four most used voxel materials as layers of one material, weighted per vertex; the layers' looks are read from the Voxel Materials (instances of `M_TerraVoxTriplanar`). Without it, each material is its own section with hard edges, and any materials work. Falling debris keeps hard edges. **Hardness** (**Material Hardness**, by material id like Voxel Materials): how many digs a material takes to open, each one wearing it down (1 = one dig, 3 = three). 0 = unbreakable: never dug, painted over or built with, and it holds up what rests on it (bedrock, vault walls). A hit that only wears rock down still counts as a hit (effects, montage) but hands out nothing: `OnDug` reports voxels once they open. ## Editing in the editor Pick **TerraVox** in the level editor's mode selector and click-drag on any voxel volume: **Dig**, **Build**, **Paint** (with **Material**), **Smooth**, **Flatten**, **Raise** or **Lower**, within **Radius** at **Strength**. Hold Shift while clicking for the opposite (Dig ↔ Build, Raise ↔ Lower); `[` and `]` resize the brush. Each stroke becomes part of the volume's starting layout, saved with the level (every machine starts from it; player saves made before the edit no longer match and start fresh), and is one Ctrl+Z. **Clear Editor Edits** on the volume removes them all. Changing the volume's size or voxel size drops the edits (a warning says so). The brush aims through the voxels, so the whole volume can be edited, not only the detailed part near the camera; two circles show its reach and its strong middle. **Clear Edits Of Volume Under Brush** (in the tool's panel) removes a volume's editor edits (undoable). ## AI navigation Full-detail surface meshes affect navigation, and each one tells the navigation system when its collision changes (after it finishes cooking), so the navmesh follows digs and builds. For that the project must regenerate navigation at runtime: **Project Settings > Navigation Mesh > Runtime Generation = Dynamic** (TerraVox logs a warning if it isn't), with a **Nav Mesh Bounds Volume** over the area (or navigation invokers). Coarse far-away pieces (see level of detail) have no collision and no navmesh; every pawn, AI included, keeps full detail around itself. ## Sculpting `Sculpt(Sculptor, Direction, Mode, Strength)` / `SculptAt(Location, Normal, Mode, Strength)` (server) and the digger component's `RequestSculpt` (with **Sculpt Mode** and **Sculpt Strength**, predicted on clients like digs) shape the surface within **Sculpt Radius**, strongest in the middle: **Smooth** evens bumps out, **Flatten** pulls the surface onto the plane it was aimed at (floors, walls), **Raise** / **Lower** add or remove rock. Hard rock changes slower, unbreakable rock not at all, and rock is never added into a pawn. Allowed wherever the pawn may both dig and build. A stroke is reported like a dig and a build: what it opened through **On Dug**, what it filled through **On Built** (per material), so a game that pays for ore and charges for builds covers sculpting too. ## Stamps `StampMesh(WorldContext, Mesh, Transform, bAdd, Material)` (server) presses any closed static mesh, moved, turned and scaled by Transform, into every volume it reaches: carve a prefab room or a curved tunnel, or add a ramp or a pillar in rock of Material. `StampShape(WorldContext, Box | Ellipsoid, Transform, HalfSize, bAdd, Material, Author)` does the same with a plain shape (added rock must touch existing rock, like a build). Unbreakable rock stays. With an **Author** (a pawn, or a projectile whose Instigator is one) the stamp is that player's: their rules apply (Can Dig In / Can Build In, an interior only its owner may change), it never buries a pawn, it's theirs to undo, and it's reported to their digger component (On Built for the rock it adds, On Dug for what it carves). Without one it's the game's own and goes as asked. Stamping a mesh at runtime in a packaged game needs **Allow CPU Access** on it; each mesh is voxelized once and reused. ## Undo and redo Each volume keeps its last **Max Undo Steps** edits (32; digs, builds, paints, sculpts, explosions, stamps), every changed voxel before and after. `UndoEdit(WorldContext, Author)` / `RedoEdit` (server) undo or redo Author's latest edit (anyone's, with no Author), exactly. Refused if the voxels aren't what the edit left any more (a later edit, or an earlier one undone since: undo that one first) or if the rock it puts back would trap a pawn. With a digger component on Author, what an undo or redo takes away is reported through **On Dug** and what it puts back through **On Built**: a game that pays in On Dug and charges in On Built stays even. The component's supply isn't touched, so undo is refused in Dig To Build mode, and switching modes drops the pawn's history (**Forget Edits** does it on demand). Players: the digger component's `RequestUndo` / `RequestRedo`, only with **Allow Undo** (off by default). History isn't saved: it's gone after a restart. ## Dig effects Every dig throws **Dig Chip Count** small pieces (**Dig Chip Mesh**, a cube by default) drawn in the dug voxel material: they fly back out of the hole, bounce, shrink and vanish after **Dig Chip Lifetime**. Explosions throw four times as many, twice as fast. Chips are local and cheap (no physics bodies, one trace per chip per frame); 0 turns them off. **Sounds**: **Material Sounds** (by voxel material id) gives each material its own dig and build sounds, one picked at random per hit; materials without any use **Dig Sound** / **Build Sound**. The plugin ships 25 in Sounds/ (S_Grass, S_Dirt, S_Stone, S_Gold, S_Build, five variations each), CC0 by [Kenney](https://kenney.nl) ("Impact Sounds"), and S_Explosion (the default **Explosion Sound**), made from a CC0 firework recording by rubberduck ([OpenGameArt](https://opengameart.org/content/25-cc0-bang-firework-sfx)). For your own effects (Niagara, decals, camera shake), bind the volume's **On Dig Effects** / **On Build Effects** / **On Explosion Effects** events (from the level Blueprint, a volume subclass or any actor, in BeginPlay so every machine binds them): they fire on every machine with the voxel material id, so each material can have its own. ## Explosions `ATVVoxelVolume::Explode(WorldContext, Location, Radius, Power, BaseDamage, DamageCauser)` (Blueprint: **Explode**, server only) blows a sphere out of every volume it reaches. **Power** is how many digs it counts as against hard rock. Pieces cut loose fall as debris thrown away from the blast (**Explosion Debris Speed**); **Explosion Sound** and the **On Explosion Effects** event play on every machine. BaseDamage > 0 also applies Unreal's radial damage (voxel walls shelter what's behind them). ## Building **Build** adds material in the same shape and place a dig would remove it (the dig shape in front of the body). It fills dug holes and adds rock anywhere inside the volume's grid (e.g. mounds on terrain, walls in an interior). Three rules: it never fills a pawn (nobody gets stuck), it must touch existing rock (nothing floats), and it stays inside the grid (a box block's grid is the box, so blocks are built back, not grown past their size). ## The digger component - **Dig Action** / **Build Action** / **Paint Action** / **Enter Exit Action** / **Sculpt Action** (held) / **Undo Action** / **Redo Action** / **Next Material Action** / **Next Sculpt Mode Action** / **Input Mapping Context**, or call `RequestDig` / `RequestBuild` / `RequestPaint` / `RequestEnterExit` / `RequestSculpt` / `RequestUndo` / `RequestRedo` / `SelectNextMaterial` / `SelectNextSculptMode` from your own input. - **Selected Material**: the voxel material builds and paints use (set it from your UI). - **Interior Volume Class**: the interior Enter Exit takes the player to (a Blueprint child of TV Interior Volume). - **Dig At Aim**: digs land where the aim meets the surface instead of against the body (first-person games). **Dig Interval** (server-enforced, shared by digs and builds), **Dig Pitch Offset** (aim correction for third-person cameras; 0 in first person), **Dig Montage**. - The client only sends a direction; the server finds the target and places the dig against the pawn's body. - **Predict Edits** (on by default): a client's own digs, builds and paints show at once instead of a round trip later. They live in an overlay over the replicated voxels (which stay exactly the server's) until the server answers: a refused edit is undone, an applied one gives way to the server's voxels when they arrive. The server stays in charge; a client that pressed inside **Dig Interval** doesn't send (the server would refuse and the edit would flicker). **Supply Mode** (on the component): - **Free** (default): dig and build without limits. - **Dig To Build**: each dig earns **Supply Per Dig**, each build needs and spends **Supply Per Build**; no supply, no build. **Starting Supply** and **Max Supply** (0 = no limit) set the pool. `GetSupply()` and the **On Supply Changed** event (server and owning client) drive your UI; `SetSupply` / `SetSupplyMode` change it at runtime (server). Implement **TV Digger** (interface) on your pawn to plug in your rules: `CanDigIn` / `CanBuildIn` (stamina, material, alive, team...) and `OnDug(Volume, Voxels, VoxelsByMaterial)` / `OnBuilt(Volume, Voxels, Material)`. Voxels is how many voxels turned from rock into air or back: hand it out as dug material and charge it for building. Without the interface, digging and building are free. **Server rules** (on the component, checked by the server: a modified client can send any request whether or not your game binds a key to it). Turn off what your game doesn't use: - **Allow Build**, **Allow Paint**, **Allow Sculpt** (a stroke needs the pawn's dig and build rules), **Allow Interiors** (leaving one always works). - **Allowed Build Materials**: material ids builds and paints may use; empty = any the volume allows. In a game that pays for digging ore, leave the ore out, or players paint rock into ore and dig it. - **Allow Undo** is refused in Dig To Build mode (undo puts the rock back but not the supply); leave it off too if `OnDug` pays rewards. - Even at **Dig Interval** 0 the server paces each pawn at 20 edits a second (bursts of 3 pass). - A player's explosion (`Explode` with a Damage Causer spawned with the player's pawn as Instigator, e.g. their grenade) obeys the same owner rule as their digs. An owned interior is sent only to its owner and to players inside it. ## Settings shared by every volume - **Extent / Voxel Size**: size of the grid and dig resolution. Smaller voxels = smoother walls, more memory per dug volume. - **Dig Shape / Dig Extent / Dig Offset**: what one dig removes (X forward, Y width, Z height). - **Floor Smoothing / Wall Smoothing / Floor Smoothing Radius**: after each dig, bumps and pits are evened out so tunnels stay walkable. - **Max Floating Island Voxels**: rock cut loose from its anchor falls away (collapses) if it's at most this big. - **Spawn Debris** / **Debris Lifetime**: a piece that collapses falls as a physics object with its own shape and materials, then disappears after the lifetime (default 6 s). Cosmetic: every machine simulates its own copy from the same shape, it doesn't push pawns, and dedicated servers don't spawn it. - **Dig Sound** / **Build Sound** and the **On Dig Effects** / **On Build Effects** Blueprint events: cosmetic feedback on every client (spawn particles there, any FX system). - **Storage Class / Save Id / Autosave Interval**: see Saving. Layout settings (size, shape, preset, seed, heightmap) are sent once, with the actor, and every machine builds the volume from them: set them per instance on actors **placed in a level**, or on the **Spawn Actor** node (they're exposed on spawn) for actors spawned at runtime. They can't change after spawning. ## Interior volumes - Solid rock bounded by **Shape** / **Extent**, with a starting cavity (**Initial Cavity Center / Shape / Extent**) where players arrive. - **Get Or Create For Player** (Pawn, Class, Location; server; the digger component's Enter Exit calls it for you) finds the player's interior of that class or spawns one at a free spot (straight above `Location`) and loads their saved digs. The owner is identified by the PlayerState's unique net id (Steam, EOS...); call `SetVolumeOwner` to use your own ids. - **Only Owner Digs** (default on) and **Allowed Visitor Classes** (who else may `Enter`). - `Enter` remembers where the pawn stood; `Exit` sends it back. Both fire the pawn's digger component **On Interior Teleport** (Blueprint) and `ATVInteriorVolume::OnPawnTeleported` (C++, every pawn) on the server: tell your anti-cheat there so the jump isn't flagged. - A black shell outside the walls hides the sky if the camera clips through. ## Voxel blocks A solid **Box** or **Ellipsoid** of **Extent**. Its bottom layer holds it up: cut a block in two and the loose part falls away. ## Voxel terrain - **Extent** X/Y is half the terrain's width/depth, Z half its height; the actor sits at the terrain's centre. The bottom layer never breaks; the sides show as cliffs. - **Preset**: Flat, Rolling Hills, Mountains, Canyon, Island, or Heightmap. **Seed** changes the generated shapes (same seed, same ground on every machine). **Base Level** = ground level before relief, **Relief Height** = how much of the height the relief uses, **Feature Size** = size of the landforms. - **Turn a Landscape into a diggable terrain**: place a Voxel Terrain (unrotated), pick your Landscape (or any actor with ground collision) as **Ground Source** and click **Copy Ground**. The terrain moves over the Landscape's area, takes its height range (plus Build Headroom) and stores its heights (up to 4097 samples a side; one per voxel on smaller ones), so its ground lands where the Landscape's was (measured within 2 cm). Then hide or delete the Landscape and set the terrain's materials. A World Partition Landscape: load its whole area in the editor first (only loaded parts are copied); a progress bar shows (and can cancel) a long copy. To keep the Landscape and dig holes in part of it instead, use a surface patch (below). - **Heightmap import**: pick **Heightmap File** (grayscale PNG, 8 or 16 bit, or RAW/R16 16-bit square) and click **Import Heightmap** in the details panel. The heights are saved with the actor. At runtime, `SetHeightmap` before the terrain begins play (deferred spawn); runtime heightmaps don't reach clients unless they set them too. - **Spawned from Blueprint**: the layout settings (Preset, Seed, levels, caves, Extent, Voxel Size) show as pins on **Spawn Actor from Class**; they can't change once the terrain plays (every machine builds the same layout from them). **Caves** (**Caves** on the terrain): winding tunnels through the ground, the same on every machine for the same Seed. **Cave Scale** = how far a tunnel runs before it bends, **Cave Radius** = its rough width, **Cave Min Depth** = none shallower than this (0 = tunnels open at the surface). Ore veins show on their walls. Tunnels add surface to build: a 120 m terrain takes about twice the work to start (still spread over frames). ## Voxel meshes - Set **Source Mesh** (and **Mesh Scale**; the actor itself stays unscaled). The actor sits at the mesh's bounds centre and its box follows the mesh; **Voxel Size** sets the detail. - The mesh must be closed (watertight): inside and outside are found by counting surface crossings. - Placed in a level, the mesh is voxelized in the editor and saved with the level: no runtime cost. Spawned at runtime (`SpawnActorDeferred`, `SetSourceMesh`, `FinishSpawning`), it's voxelized on spawn on every machine, which in a packaged game needs **Allow CPU Access** on the mesh. - **Anchor Bottom** (on): the lowest layer holds the shape up. - The whole shape uses **Fill Material**. ## Foliage **Foliage** (any volume): meshes scattered over the rendered surface, each type with a **Density** (per m²), the voxel material it grows on (**On Material**, e.g. grass but not the dirt a dig exposes), **Max Slope**, scale range, upright or **Align To Surface**, **Sink Depth**, **Cull Distance**, **Collision** (trees, boulders) and the coarsest level of detail it's placed on. Placement follows the surface (the same on every machine, **Foliage Seed**) and is redone with it, so foliage vanishes where the ground is dug away. Dedicated servers only place the types with collision. ## Surface patches (dig into a Landscape) A runtime Landscape can't be changed, so a patch copies an area of it into voxels and stands in for it there. 1. Place a **TV Surface Patch** over the area (unrotated) and set **Surface Source** to the Landscape (or a ground actor with static mesh collision). **Extent** Z must cover the ground's height range inside the patch. 2. In the source's material: add the function **MF_TerraVoxSurfaceMask** (plugin content, Materials), plug its output into **Opacity Mask**, and set **Blend Mode** to **Masked**. `M_TerraVoxExampleGround` is an example. Without this the ground still works but the source's surface keeps drawing over dug holes. 3. Play. The patch starts once the source's collision exists, traces its height column by column and only draws what differs (holes, builds, paint). Pawns inside the patch walk on the voxel copy instead of the source. - **Edge Margin** (150 cm): a band along the sides that can't be dug, where pawns switch between the two grounds. - Spawning a patch at runtime: `SpawnActorDeferred`, `SetSurfaceSource`, then `FinishSpawning`. - Physics debris is off by default on patches: the pieces would land on the source's collision still spanning the hole. ## Reacting to changes (Blueprint) **On Voxels Edited** (server) fires after every edit that changed voxels — digs, builds, paints, sculpts, explosions, stamps, undo and redo — with the volume, who made it (empty for the game's own stamps and explosions), the world box it touched and how many voxels changed: bind it to update quests, AI, decals or anything that depends on the ground. **Is Solid At** tells whether a point is inside rock right now and which material (clients too). ## Saving Digs are saved 60 s after a dig (**Autosave Interval**), when an interior's owner exits, and when the volume is destroyed or the server stops. The autosave (and an interior's exit) encodes on a worker thread: the game thread only copies the packed chunks (measured on a 1 km terrain: 11 ms with 1.5k dug chunks, 40 ms with 50k, against 56 ms and 2.4 s done on the game thread). **Save In Background** does the same from Blueprint; **Save To Storage** writes at once (a checkpoint), and a background save that finishes after it is dropped. Keys: an interior saves under owner id + class; blocks and terrain under **Save Id**, or their actor path when empty (stable for level-placed actors; set Save Id on spawned ones). A save made before Extent or Voxel Size changed is ignored with a warning. Interiors without an owner id (e.g. PIE with no Steam/EOS) aren't saved. A save that doesn't fit is never overwritten silently: one made for another layout is kept under key `<key>.rejected`; one with some unreadable chunks loads without them and is kept there too; a save slot the default storage can't read at all (the game stopped mid-write) is copied to `<slot>_unreadable`. Keep a palette's order when you add materials (add new ones at the end): saves store material ids. In World Partition or Level Instance maps set **Save Id** on level-placed volumes too, so the key doesn't depend on how the actor was loaded. Custom backend: subclass **TV Voxel Storage** (C++ or Blueprint), implement `SaveVolume(Key, Payload)` / `LoadVolume(Key)`, and set it as the volume's **Storage Class**. `SaveToString` / `LoadFromString` are also public. ## Console | Command | | |---|---| | `TV.EnterExitInterior` | Enter/leave your interior (not in Shipping). Works on remote clients. | | `TV.Voxel.Debug 1` | Shows volume bounds and the dig shape where it will land; logs every dig request and why the server refuses one. | | `TV.Voxel.Stats` | Logs each volume's dug chunks, chunk meshes, chunks still to build and predicted voxels. | | `TV.Voxel.StressDig [Count] [Seed]` | Server: digs Count random holes in every volume, to try joining, bandwidth and saves with a lot dug. | | `TV.Net.ChunkBytesPerSecond` | Voxel data sent to each client per second at most (default 60000). | | `TV.MaxEditVoxels` | Largest box of voxels one edit may cover (default 16M: a box about 250 voxels across, 50 m at 20 cm voxels); bigger stamps and blasts are refused with a warning. | ## Performance Measured with the included benchmark (`TerraVoxPerf.Benchmark`, 150 digs, 15 cm voxels, 40 × 40 × 10 m interior): ~2.5 ms per dig on the server, ~1 ms of game-thread remesh per dig on every machine (the rest runs on worker threads), ~1.7 KB of replication per dig (chunks are sent compressed). Dig cost grows with how much is dug, not with the volume's size. Starting surface: a volume spends **Startup Build Seconds** (0.25 s) of its first frame building the ground under the players (pawns, player starts), with collision, then builds the rest over the next frames within **Chunk Build Budget Ms** (3 ms per frame): the ground around every pawn first, then the whole horizon in coarse pieces, then finer detail. A terrain's heights are computed where they're needed, not for its whole area up front. Default terrain settings, 25 cm voxels, level of detail on: | Terrain | Start (first frame) | Rest built | Pieces | Triangles | |---|---|---|---|---| | 240 × 240 m | 0.26 s | ~0.6 s | 1 023 | 0.7 M | | 1 × 1 km | 0.27 s | ~0.8 s | 1 611 | 1.2 M | | 2 × 2 km | 0.28 s | ~0.8 s | 1 922 | 1.4 M | | 8 × 8 km | 0.73 s | ~1.3 s | 2 501 | 1.9 M | Coarse pieces over untouched ground are sampled on worker threads (identical surfaces to the game thread's; `TV.Voxel.SampleOnWorkers 0` turns it off), so the game thread only applies meshes. **C++ subclasses of the voxel terrain** inherit this: their `GetInitialSolid`, `GetBaseMaterial` and `IsOutsideSolid` must only read settings (no shared caches, no world queries), or return false from `CanSampleInitialOffGameThread`. Rendered (1280 × 720, flying a player over the terrain): a 4 km terrain is fully drawn within the first second; flying over it at 30 m/s runs at ~195 fps (game thread ~2.3 ms, render ~5 ms, GPU ~4 ms). A dedicated server with the same 8 km terrain uses the memory of an empty one. **Level of detail** (**Enable Lod**, on): full detail and collision within **Lod Distance** (40 m) of any player (pawns with a player's PlayerState, and cameras) and within **Other Pawn Detail Distance** (10 m) of other pawns (AI, vehicles, collision interests), so hundreds of AI stay cheap; beyond it the surface is drawn in coarser pieces, half the detail each time the distance doubles, up to **Max Lod Level** (8 = 1/256, only used kilometres away), without collision. Pieces follow the players as they move, and a strip hanging from each coarse piece's border hides the cracks where levels meet. With a player in the middle, 25 cm voxels: | Terrain | Without LOD | With LOD | |---|---|---| | 240 × 240 m | 2.5 M triangles, 4742 meshes | 0.66 M triangles, 992 meshes | | 480 × 480 m | — | 0.9 M triangles, 1262 meshes | **Lod Fade Seconds** (off by default): detail changes cross-fade (the new piece dithers in where the old one dithers out) instead of popping. It needs materials that read it: **MF_TerraVoxLodFade** in the **Opacity Mask** (clip 0.5) of a **Masked** material. The sample materials have it wired but stay Opaque (masked costs rendering for nothing when nothing fades); use their **_Fade** instances (Masked override: MI_Textured_*_Fade, MI_Procedural_*_Fade, MI_TerraVoxTriplanarBlend_Fade) with it. Plain opaque materials: leave it off. Off on surface patches. **Dedicated servers** draw nothing: they build only full-detail collision within Lod Distance of every pawn (players and AI; under a pawn that appears it's built at once), so a 1 km terrain costs the server what's around its pawns (measured: idle, ~700 pieces around the start) instead of all ~250 000 surface pieces. Far from every pawn there's no collision, on clients and servers alike. For that: - **Long-range shots**: **Line Trace With Voxels** (a normal trace on your channel plus a trace through the voxels, nearer hit wins) or **Line Trace Voxels** (voxels only, with the rock's material) hit the ground at any distance, where the drawn surface is, and see digs at once. Open air is skipped a chunk at a time: a 900 m shot fired down from 100 m up costs ~0.03 ms; a shot grazing the ground the whole way ~0.7 ms per 800 m. - **Physics objects and non-pawn vehicles** far from players: **Add Collision Interest** (actor) gives them full-detail collision around themselves like a pawn; **Remove Collision Interest** when they no longer need it. A pawn that spawns (a respawn, an AI) or is taken in or out of an interior gets the ground under it at once. After teleporting a player yourself, call **Refresh Around Pawns** so it doesn't wait for the next update. `TV.Voxel.CollisionOnly 1` makes any machine build like a server. **Big edits** (explosions, stamps) are redrawn within **Edit Build Budget Ms** a frame (6 ms): a 12 m explosion next to the player measured a 63 ms frame drawn all at once, and 14 ms at worst spread over five frames. 0 draws everything in one frame. ## Networking The server owns the voxels. Each client gets them from its own `ATVVoxelStreamer` (spawned by the plugin for every remote player): the chunks that differ from the starting layout, nearest the player first, in small batches at up to `TV.Net.ChunkBytesPerSecond`. A player joining a well-dug world gets the ground around them first and the rest in the following seconds (587 dug chunks: ~5 s). The volume actor itself only carries dig effects and debris. Layout settings are sent only with the actor (a volume spawned at runtime with its own Seed or size gets them on every client); every machine then builds the starting layout itself. A client whose layout still differs from the server's (a setting changed on the server only after spawning) logs an error saying so. A client has a volume only within **Net Relevancy Distance** (300 m) of its box: far terrain and other players' interiors cost it nothing; what changes meanwhile arrives when it comes near. Distance is measured from the player's pawn (or the view target the server set), not from the camera position the client reports, which a modified client could fake. An edit sends the whole changed chunks (a few hundred bytes to about 1.5 KB each, packed), not the voxels that changed: a 12 m explosion is about 100 chunks, some 150 KB per nearby client, a couple of seconds at the default `TV.Net.ChunkBytesPerSecond` (60 KB/s; the digger's own prediction shows it at once). Raise it on a server with bandwidth to spare, or keep explosions smaller in games with many players. A client gets every dug chunk of each volume near it, not only those near its player: a joiner in a map with 50 000 dug chunks waits some 15 minutes at the default rate for the far ones (the ground around them comes first). Chunks dug while a client catches up are sent in turn. Interiors trust the player's online id (Steam, EOS...): with a subsystem that doesn't authenticate it on the server (Null), a client could claim someone else's id. An interior whose owner has left the game and that nobody is inside is saved and removed (it comes back from the save when they return). ## Troubleshooting - **Pressing dig does nothing.** Run `TV.Voxel.Debug 1`: a line shows where the dig goes and the log says why one is refused. Usual causes: the pawn's **TV Digger** interface answers **Can Dig In** with false (tick its Return Value); the input mapping context isn't added (set **Input Mapping Context** on the component); the pawn isn't possessed; the aim misses the volume (first person: **Dig Pitch Offset** 0 and **Dig At Aim** on); an interior only its owner may dig. - **The ground is a grey checkerboard.** A material slot is empty or its material lacks *Used with Instanced Static Meshes* (dig chips) - use the samples or a Palette. - **Holes close again on a client after a moment.** The server refused the dig (rules above) and the client's prediction was undone; `TV.Voxel.Debug 1` on the server logs the reason. - **Saved digs don't come back.** Look for "save was made for another starting layout" in the log: a setting that shapes the ground changed. The old save is kept as `<key>.rejected`. ## Limitations - Windows x64 and Linux on 5.6, 5.7 and 5.8, Windows ARM64 on 5.7 and 5.8: the runtime compiles and ships on each (checked with Development and Shipping builds, Epic's Linux toolchain for Linux, no warnings); the editor tools are tested on Windows x64. - A volume must not move or scale after BeginPlay. - Up to four surface patches per Landscape (or mesh ground), one per slot of MF_TerraVoxSurfaceMask; a fifth logs an error and shows no holes. Make patches bigger rather than more. - Walls are runtime Static meshes: they don't receive baked lighting. Light them dynamically. - Surface patches: the source's own collision stays under holes for everything except pawns (traces for aiming ignore it too). Other physics objects dropped into a hole rest on the original surface. - Very large loose pieces (over Max Floating Island Voxels) stay up, to bound the cost per dig. - The example (`TerraVoxExample` module and `Example` content) is compiled into your game like the rest; delete `Source/TerraVoxExample` and the `Example` folder (and its entry in TerraVox.uplugin) if you don't want it shipped. Nothing else needs them (the tests that look at the example skip). ## Tests Automation tests under `TerraVox.*` (Session Frontend → Automation, or `UnrealEditor-Cmd <project> -ExecCmds="Automation RunTests TerraVox.; Quit" -unattended -nullrhi`). Changing the plugin itself? `ARCHITECTURE.md` explains where things live and the rules the code relies on (level of detail, mesh versions, worker sampling, cross-fades). `TerraVoxPerf.*` (kept out of that run) are measurements, not checks: they log costs (a terrain from 240 m to 8 km, many pawns, a teleport, saves and big edits) and never fail. The tests write a few save slots under `Saved/` and delete them when they finish.