ButterNet Multiplayer Voxel

Installation & Setup

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

  1. Copy the plugin

    Copy the ButterNetVoxels folder into your project's Plugins directory (create it next to the .uproject if it does not exist).

  2. Enable in the editor

    Open the project. Edit → Plugins → ButterNet Voxels should 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

TermMeaning
VolumeAn AVoxelVolumeActor placed in a level or spawned at runtime. It owns a box of chunks.
Chunk32 × 32 × 32 voxels. Unedited chunks regenerate from the generator on demand and cost no memory; edited chunks hold 64 KB.
Voxel sizeEdge length of one voxel in centimetres, per definition. 50 cm suits terrain; 20 cm suits detailed structures.
DefinitionA VoxelVolumeDefinition data asset holding every setting. Several volumes can share one.
DensityA signed distance stored per voxel. Negative is solid. Surfaces are smooth because the mesh interpolates between voxels.
Material indexOne byte per voxel, 0 = air. It reaches your material as red vertex colour × 255.
ModeBlob 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 opA 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:

  1. Create a definition

    Content Browser → Add → Miscellaneous → Data Asset → VoxelVolumeDefinition. Name it DA_Ground.

  2. Configure the generator

    Set Generator to Voxel Generator Noise, add one Height Layer (Wavelength 128, Amplitude 20) and set Render Material to any material.

  3. Place a volume

    Drag VoxelVolumeActor from Place Actors into the level and set its Definition to DA_Ground. The terrain appears in the viewport.

  4. Create brush presets

    Create a VoxelBrushPreset named DA_Dig (Mode Subtract, Radius 150) and another DA_Fill (Mode Add).

  5. Wire input

    In your PlayerController, on a key press call Get World Subsystem (ButterNetVoxelSubsystem) → Request Edit From View with Controller = Self, Brush = DA_Dig, Reach = 600, Push Outward = false. For fill use DA_Fill with 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.

SettingMeaning
Volume
ModeBlob (free-standing) or Terrain (ground from a host).
Voxel Size CmEdge length of one voxel. Smaller = more detail, more memory and meshing time (cost grows with the cube).
Bounds Min/Max ChunkInclusive chunk coordinates the volume covers. 32 voxels per chunk, so at 50 cm a chunk is 16 m.
GeneratorBaseline shape for Blob volumes. See Generators.
Material SetOptional VoxelMaterialSet asset. See Material set & authorizer.
Rendering
Render MaterialApplied to every chunk mesh.
Meshing ModeSurface Nets (smooth) or Dual Contouring (sharp edges; best with static-mesh generators).
Replication
ReplicateOff makes the volume local to each machine.
Max Edit Range CmServer rejects edits further than this from the player. 0 disables.
Max Ops Per Second Per PlayerServer-side rate limit.
Snapshot Bytes Per SecondBandwidth cap for a client catching up from snapshots.
Persistence
PersistLoad on start, save on change. Needs a key.
Persistence KeyIdentifies the saved state. A placed actor can override it.
Auto Save Debounce SecondsQuiet time after the last edit before a save.
Performance & LOD
Enable LODDistant chunks mesh at 2× and 4× cell size on clients and standalone.
Far Distance CmBeyond this, chunks batch per region into one mesh.
Server Meshes Collision OnlyDedicated servers skip render data entirely.
Debris
Enable DebrisDisconnected pieces break off as physics actors after a dig.
Max Debris VoxelsLargest 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.

SettingMeaning
Base Height VoxelsGround level before noise, in voxels from the volume origin.
Height LayersLayers 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 MaterialMaterial index of the top layer.
Surface Depth VoxelsVoxels below the surface that use the surface material before switching to subsurface.
Subsurface MaterialMaterial index below the surface layer.
Caves
Cave ModeNone; Noise (3D noise tunnels); Random (discrete pockets per cell).
Cave ThresholdNoise mode: how much rock becomes air. Lower = more caves.
Cave Min Depth VoxelsCaves 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.

SettingMeaning
MeshClosed static mesh to voxelise. In cooked builds it needs Allow CPU Access.
Mesh TransformPlacement of the mesh inside the volume, in centimetres.
MaterialMaterial index written into solid voxels.
Narrow Band VoxelsDistance 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

  1. Create the asset

    Content Browser → Add → Miscellaneous → Data Asset → VoxelMaterialSet. Name it (for example DA_VoxelMaterials).

  2. 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).

  3. Assign on the definition

    Set Material Set on the VoxelVolumeDefinition. Several volumes can share one set.

Entry fieldMeaning
NameLookup string for Find Material. Not shown in the world.
HardnessMultiplier on how much effort an edit needs. Your authorizer or yield logic reads this; the plugin does not enforce it.
Required Tool IdFName id the player's equipped tool must match before an edit is allowed. Checked in your authorizer, not by the plugin.
Yield IdFName id for what removing this material produces — inventory, loot tables, crafting. Read from edit events.
TagGameplay 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.

FunctionNotes
ButterNetVoxelSubsystem
Request EditApply 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 ViewTrace from the player's view and edit where the voxels are hit. The usual dig/fill input.
Query VoxelSolid or air, material, signed distance.
Line Trace VoxelsFirst solid voxel along a ray, with location, normal and volume.
Find Volumes At / Get VolumesDiscover volumes in the world.
Spawn Volume / Spawn Persistent VolumeCreate volumes at runtime.
Set Edit AuthorizerObject implementing VoxelEditAuthorizer. See Material set & authorizer.
AVoxelVolumeActor
Apply BrushAuthority only.
Get Material EntryName, ids and tag from the definition's material set for a material index. False when none is set.
Export / Import Volume StateSerialise or replace the whole edited state as bytes.
EventsOn 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.

  1. Create a terrain definition

    Set surface and subsurface materials and the Render Material for the voxel ground.

  2. Choose a hide mode

    Material Mask (default) uses MF_VoxelHoleMask in 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.

  3. 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:

  1. Open the function

    In the Content Browser: Plugins → ButterNet Voxels Content → Materials → MF_VoxelHoleMask.

  2. Add it to the landscape material

    Drop MF_VoxelHoleMask into the landscape material graph and connect its output to Opacity Mask.

  3. Set blend mode

    On the landscape material, set Blend Mode to Masked so clipped pixels are discarded rather than blended.

  4. 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:

  1. Enable preview

    Make sure the volume has Preview In Editor on so its mesh is visible.

  2. Select the mode

    Open the Modes dropdown in the level editor toolbar and pick Voxel Sculpt.

  3. 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

SettingMeaning
Persistence Provider ClassObject that loads and saves volumes. Default: the local file provider.
Local Save DirectoryFolder under Saved used by the local provider.
Save On End PlaySave dirty volumes when the world ends.
Hole Mask Texel CmResolution of the landscape hole mask texture.
Carve Depth Margin CmHow 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.

Support

Questions, bug reports and integration help — use the contact form on the main site.

← Back to overview