ButterNet Multiplayer Voxel
Installation & Setup
- Requirements
- Install the plugin
- Iris replication
- Concepts
- Quick start
- Volume definition
- Generators
- Material set & authorizer
- Editing at runtime
- Replication
- Persistence
- Terrain mode
- Editor tools
- Project settings
- Performance tuning
- Troubleshooting
- Limitations
Requirements
Unreal Engine 5.8. Blueprint or C++ project. The plugin contains three modules and needs nothing else: ButterNetRuntimeVoxels (volumes, editing, meshing, replication, persistence, debris), ButterNetVoxelsLandscape (terrain host for landscapes), and ButterNetVoxelsEditor (the Voxel Sculpt editor mode).
Install the plugin
- Copy the plugin
Copy the
ButterNetVoxelsfolder into your project'sPluginsdirectory (create it next to the.uprojectif it does not exist). - Enable in the editor
Open the project.
Edit → Plugins → ButterNet Voxelsshould be enabled; enable it and restart if not. No compile step is required.
Optional: Iris replication
The plugin supports both network drivers. To run on Iris add to [SystemSettings] in Config/DefaultEngine.ini:
net.Iris.UseIrisReplication=1 net.SubObjects.DefaultUseSubObjectReplicationList=1
Iris refuses actors that replicate subobjects the legacy way, so the second line is required. Remove both lines to return to the legacy driver.
Concepts
| Term | Meaning |
|---|---|
| Volume | An AVoxelVolumeActor placed in a level or spawned at runtime. It owns a box of chunks. |
| Chunk | 32 × 32 × 32 voxels. Unedited chunks regenerate from the generator on demand and cost no memory; edited chunks hold 64 KB. |
| Voxel size | Edge length of one voxel in centimetres, per definition. 50 cm suits terrain; 20 cm suits detailed structures. |
| Definition | A VoxelVolumeDefinition data asset holding every setting. Several volumes can share one. |
| Density | A signed distance stored per voxel. Negative is solid. Surfaces are smooth because the mesh interpolates between voxels. |
| Material index | One byte per voxel, 0 = air. It reaches your material as red vertex colour × 255. |
| Mode | Blob volumes are free-standing shapes from a generator. Terrain volumes take their ground from a host (a landscape) and only render where players have dug. |
| Edit op | A quantised brush application. Ops are integers end to end, so every machine that applies the same op gets the same voxels. |
Quick start
A diggable blob in five steps:
- Create a definition
Content Browser → Add → Miscellaneous → Data Asset → VoxelVolumeDefinition. Name it
DA_Ground. - Configure the generator
Set Generator to Voxel Generator Noise, add one Height Layer (Wavelength 128, Amplitude 20) and set Render Material to any material.
- Place a volume
Drag
VoxelVolumeActorfrom Place Actors into the level and set its Definition toDA_Ground. The terrain appears in the viewport. - Create brush presets
Create a
VoxelBrushPresetnamedDA_Dig(Mode Subtract, Radius 150) and anotherDA_Fill(Mode Add). - Wire input
In your PlayerController, on a key press call
Get World Subsystem (ButterNetVoxelSubsystem) → Request Edit From ViewwithController = Self,Brush = DA_Dig,Reach = 600,Push Outward = false. For fill useDA_Fillwith Push Outward = true so the sphere sits on the surface rather than inside it.
Play. Digging works in standalone, listen server and client sessions without further work; the subsystem routes client requests through a replicated player component that the plugin attaches at login.
Volume definition
All settings live on the VoxelVolumeDefinition asset unless stated otherwise.
| Setting | Meaning |
|---|---|
| Volume | |
| Mode | Blob (free-standing) or Terrain (ground from a host). |
| Voxel Size Cm | Edge length of one voxel. Smaller = more detail, more memory and meshing time (cost grows with the cube). |
| Bounds Min/Max Chunk | Inclusive chunk coordinates the volume covers. 32 voxels per chunk, so at 50 cm a chunk is 16 m. |
| Generator | Baseline shape for Blob volumes. See Generators. |
| Material Set | Optional VoxelMaterialSet asset. See Material set & authorizer. |
| Rendering | |
| Render Material | Applied to every chunk mesh. |
| Meshing Mode | Surface Nets (smooth) or Dual Contouring (sharp edges; best with static-mesh generators). |
| Replication | |
| Replicate | Off makes the volume local to each machine. |
| Max Edit Range Cm | Server rejects edits further than this from the player. 0 disables. |
| Max Ops Per Second Per Player | Server-side rate limit. |
| Snapshot Bytes Per Second | Bandwidth cap for a client catching up from snapshots. |
| Persistence | |
| Persist | Load on start, save on change. Needs a key. |
| Persistence Key | Identifies the saved state. A placed actor can override it. |
| Auto Save Debounce Seconds | Quiet time after the last edit before a save. |
| Performance & LOD | |
| Enable LOD | Distant chunks mesh at 2× and 4× cell size on clients and standalone. |
| Far Distance Cm | Beyond this, chunks batch per region into one mesh. |
| Server Meshes Collision Only | Dedicated servers skip render data entirely. |
| Debris | |
| Enable Debris | Disconnected pieces break off as physics actors after a dig. |
| Max Debris Voxels | Largest piece per axis that can break off; bigger pieces stay attached. |
On the placed actor: Definition, optional Persistence Key Override, Terrain Host Actor for Terrain volumes, Preview In Editor, and buttons to refresh preview or clear authored state.
Generators
Set on the definition's Generator. All generators are deterministic: the same settings give the same voxels on every machine. Untouched chunks regenerate from the generator; edited chunks are baseline plus replayed ops.
Voxel Generator Noise
Height-map terrain from layered gradient noise, with optional caves.
| Setting | Meaning |
|---|---|
| Base Height Voxels | Ground level before noise, in voxels from the volume origin. |
| Height Layers | Layers summed into the height map: wavelength, amplitude, octaves, persistence, seed. A long wavelength for hills plus a short one for detail is a good start. |
| Surface Material | Material index of the top layer. |
| Surface Depth Voxels | Voxels below the surface that use the surface material before switching to subsurface. |
| Subsurface Material | Material index below the surface layer. |
| Caves | |
| Cave Mode | None; Noise (3D noise tunnels); Random (discrete pockets per cell). |
| Cave Threshold | Noise mode: how much rock becomes air. Lower = more caves. |
| Cave Min Depth Voxels | Caves never open closer to the surface than this. |
The volume exposes placed pockets through Get Caves, Get Cave Count and Find Nearest Cave for spawning loot or enemies.
Voxel Generator Primitive
One sphere or box by centre, radius or half extents, and material. Useful for tests and for a floor under a sculpted volume.
Voxel Generator Static Mesh
Voxelises a closed static mesh at runtime.
| Setting | Meaning |
|---|---|
| Mesh | Closed static mesh to voxelise. In cooked builds it needs Allow CPU Access. |
| Mesh Transform | Placement of the mesh inside the volume, in centimetres. |
| Material | Material index written into solid voxels. |
| Narrow Band Voxels | Distance from the surface over which exact signed distances are computed. |
Surface normals are kept, so Dual Contouring reproduces edges and corners to within a few percent of a voxel. Walls thinner than two voxels vanish at that voxel size. The volume's bounds must contain the mesh; a warning is logged with the exact chunk range when they do not.
Material set & authorizer
Voxels store a compact material index (one byte, 0 = air). A VoxelMaterialSet data asset is an optional lookup table that gives those indices names, tool/yield ids and a gameplay tag for your Blueprint or C++ logic. Generators, terrain layers and brush presets still use raw indices; the set is how your game interprets them.
The material set does not affect rendering. Visuals come from Render Material on the definition and the index in the red vertex colour channel (index × 255). The set is for loot, effects, tool rules and anything else your game reads after an edit or query.
Creating a material set
- Create the asset
Content Browser → Add → Miscellaneous → Data Asset → VoxelMaterialSet. Name it (for example
DA_VoxelMaterials). - Fill the entries
Array slot N describes material index N. Leave index 0 as an air placeholder. Match the indices your generator and brushes use (surface material 1, subsurface 2, and so on).
- Assign on the definition
Set Material Set on the
VoxelVolumeDefinition. Several volumes can share one set.
| Entry field | Meaning |
|---|---|
| Name | Lookup string for Find Material. Not shown in the world. |
| Hardness | Multiplier on how much effort an edit needs. Your authorizer or yield logic reads this; the plugin does not enforce it. |
| Required Tool Id | FName id the player's equipped tool must match before an edit is allowed. Checked in your authorizer, not by the plugin. |
| Yield Id | FName id for what removing this material produces — inventory, loot tables, crafting. Read from edit events. |
| Tag | Gameplay tag for effect or sound when this material is hit or removed. Read from edit events; works with GameplayCues and tag-based systems. |
Query entries at runtime with Get Material Entry (Index) on the volume actor, or Get Material / Find Material on the set asset. Edit events (On Voxels Removed, On Voxels Added) and the edit result struct include Removed and Added arrays of { Material, Count } — loop those, resolve each index through the set, then grant loot from Yield Id or play FX from Tag.
Edit authorizer
Before the server applies any edit, it calls an object implementing VoxelEditAuthorizer. Implement Authorize Voxel Edit (Volume, Instigator, Brush, Location) and return false to refuse the edit. By default the GameMode is consulted when it implements this interface; override with Set Edit Authorizer on the subsystem to point at any other object (a subsystem, player state, or dedicated rules actor).
The authorizer runs only on the authority. Clients still predict dig and fill locally; if the server rejects the edit, affected chunks roll back to the confirmed state.
Common uses: require a pickaxe id before digging rock (Required Tool Id from the material set), block edits outside a claimed zone, enforce ownership, or scale brush strength from Hardness. A typical tool check: Query Voxel or Line Trace Voxels at the edit location, Get Material Entry on the hit material index, compare Required Tool Id against the equipped tool id on the instigator, return false when it does not match.
Plugin vs game logic
Hardness, tool ids, yield ids and the gameplay tag are metadata for your game. The plugin stores indices, replicates edits and reports per-material counts; your authorizer and event handlers enforce the rules and drive gameplay.
Editing at runtime
Everything goes through the ButterNetVoxelSubsystem (a world subsystem) or the volume actor.
| Function | Notes |
|---|---|
| ButterNetVoxelSubsystem | |
| Request Edit | Apply a brush at a point. On an authority it applies directly; on a client it predicts dig and fill locally and sends the request to the server. |
| Request Edit From View | Trace from the player's view and edit where the voxels are hit. The usual dig/fill input. |
| Query Voxel | Solid or air, material, signed distance. |
| Line Trace Voxels | First solid voxel along a ray, with location, normal and volume. |
| Find Volumes At / Get Volumes | Discover volumes in the world. |
| Spawn Volume / Spawn Persistent Volume | Create volumes at runtime. |
| Set Edit Authorizer | Object implementing VoxelEditAuthorizer. See Material set & authorizer. |
| AVoxelVolumeActor | |
| Apply Brush | Authority only. |
| Get Material Entry | Name, ids and tag from the definition's material set for a material index. False when none is set. |
| Export / Import Volume State | Serialise or replace the whole edited state as bytes. |
| Events | On Voxels Removed and On Voxels Added include per-material counts. Also On Initial Mesh Complete, On Snapshot Complete, On State Loaded / Saved, On Debris Spawned. |
Brush presets (VoxelBrushPreset) describe one tool: shape (sphere or box), mode (Subtract, Add, Paint, Smooth), radius, strength, falloff, material and cooldown. Brushes are quantised to quarter voxels.
Replication
The server applies edits and appends them to a replicated ring of ops; clients apply the same ops in order. Steady-state cost is about 60 bytes per edit.
Clients predict dig and fill immediately; if the server rejects an edit (authorizer, range, rate), the affected chunks roll back to the confirmed state. A client that joins late or falls behind the op history requests chunk snapshots: compressed deltas against the generator baseline, about 1.8 KB per edited chunk, paced by snapshot bandwidth settings. On Snapshot Complete fires when the client is caught up.
Debris pieces are replicated actors with movement replication; the server's physics corrects the clients. Dedicated servers keep full-resolution collision meshes and skip render data.
Persistence
A persistence provider is any object implementing VoxelPersistenceProvider: load bytes for a key, save bytes (with an urgent flag on shutdown), delete a key. The subsystem creates one provider per world from Project Settings → Plugins → ButterNet Voxels → Persistence Provider Class, or you hand it one at runtime with Set Persistence Provider.
The default local file provider writes Saved/<Local Save Directory>/<key>.bnv, one file per key. To turn persistence on, set Persist and a Persistence Key on the definition (or override per actor). The volume loads on BeginPlay (authority only) and saves after the debounce quiet period, on demand, and when the world ends if configured.
You can also use Export Volume State and Import Volume State to move bytes through your own SaveGame or RPC without a provider. The format is versioned and compressed (Oodle); untouched chunks are never stored.
Terrain mode and landscapes
A Terrain volume takes its ground from a terrain host. Place a VoxelVolumeActor over a landscape, give it a definition whose Mode is Terrain, and it samples the landscape heights on start. Nothing renders until the first dig; from then on each edited column renders as voxels, and the landscape is hidden and its collision lowered under that column.
- Create a terrain definition
Set surface and subsurface materials and the Render Material for the voxel ground.
- Choose a hide mode
Material Mask (default) uses
MF_VoxelHoleMaskin the landscape material — see below. Hide Landscape Components hides whole components on first dig with no material changes. None leaves the landscape visible and only adjusts collision. - Align and size
Place the volume on a multiple of the voxel size so column edges line up with the hole mask. Size chunk bounds to the height range players can reach.
MF_VoxelHoleMask (Material Mask mode)
When Terrain Hide Mode is Material Mask, the landscape host writes a runtime hole texture per dug column. Your landscape material must read it through the plugin's material function:
- Open the function
In the Content Browser:
Plugins → ButterNet Voxels Content → Materials → MF_VoxelHoleMask. - Add it to the landscape material
Drop
MF_VoxelHoleMaskinto the landscape material graph and connect its output to Opacity Mask. - Set blend mode
On the landscape material, set Blend Mode to Masked so clipped pixels are discarded rather than blended.
- Combine with an existing visibility mask
If the material already uses a Landscape Visibility Mask, multiply the two masks together before Opacity Mask. Either order works; both must be 1 for the surface to show.
The function expects two texture parameters the host fills at runtime: VoxelHoleMask (the hole texture) and VoxelHoleMaskRect (world-space origin and UV scale). You do not assign these yourself — the landscape host creates dynamic material instances on the landscape and pushes updated values as players dig.
Mask resolution comes from Project Settings → Plugins → ButterNet Voxels → Hole Mask Texel Cm (default 100 cm per texel). Smaller texels give sharper hole edges and a larger texture. The ground is hidden only once the column's voxel meshes exist, so nothing shows through on a fresh dig.
The voxel mesh cannot use a landscape material directly. Put the ground appearance (triplanar textures, colour, roughness) in one material function and use it from both the landscape material and the voxel Render Material. The voxel material reads the material index from the red vertex colour channel.
Landscape grass and foliage
Grass and foliage are not removed over holes. Listen for On Voxels Removed and clear them in the game.
Editor tools
Voxel Sculpt mode sculpts placed blob volumes directly in the level viewport:
- Enable preview
Make sure the volume has Preview In Editor on so its mesh is visible.
- Select the mode
Open the Modes dropdown in the level editor toolbar and pick Voxel Sculpt.
- Sculpt
Hover for the brush outline (red dig, green fill, yellow paint). Drag to sculpt. Hold Shift to swap dig and fill, Ctrl to paint. Each stroke is one undo step and is saved with the level.
Terrain volumes show nothing in the editor and cannot be sculpted there; they are edited in play. Console: bnv.DebugDraw 1 chunk states, 2 LOD bands, 3 terrain columns, 0 off. stat ButterNetVoxels shows edit, meshing and upload timings.
Project settings
Project Settings → Plugins → ButterNet Voxels
| Setting | Meaning |
|---|---|
| Persistence Provider Class | Object that loads and saves volumes. Default: the local file provider. |
| Local Save Directory | Folder under Saved used by the local provider. |
| Save On End Play | Save dirty volumes when the world ends. |
| Hole Mask Texel Cm | Resolution of the landscape hole mask texture. |
| Carve Depth Margin Cm | How far below the volume's bottom the landscape collision is pushed under dug columns. |
Performance tuning
Voxel Size Cm is the biggest lever: halving it costs eight times the voxels. Keep Max Concurrent Mesh Jobs near your worker count and Max Chunk Uploads Per Frame at 2–4 for smooth frames. Turn Cast Shadows off on underground volumes. Use several medium volumes with World Partition instead of one enormous one.
Measured on a desktop CPU: dig ~0.05 ms; one chunk meshed ~0.3 ms on a worker; 1,024 chunks fully meshed in ~320 ms; a breaking cut ~0.3 ms.
Troubleshooting
Ground looks wrong or missing after a reload
The generator (or landscape) changed since the save, so the saved deltas decode against a different baseline. Delete the .bnv file or the key.
Iris requires replicated actors to use registered subobject lists
Add net.SubObjects.DefaultUseSubObjectReplicationList=1 under [SystemSettings].
A static-mesh volume shows only part of the mesh
The bounds are smaller than the mesh; the log names the chunk range needed.
Client cannot dig
The player must have logged in (the voxel player component is attached at login) and the volume's Replicate must be on.
Nothing happens when editing in the viewport
Select the Voxel Sculpt mode, not Select mode, and make sure the volume is a blob with Preview In Editor on.
Limitations
Landscape grass and foliage are not cleared over holes. The sculpt editor mode works on blob volumes only. Debris uses one convex hull per piece. Static-mesh features thinner than two voxels disappear at that voxel size. Saved state and snapshots assume the generator and its seed are unchanged.
Questions, bug reports and integration help — use the contact form on the main site.