GregOrigin - Instant Organic Caves: Lightweight Procedural Runtime Structure Generator

IOC 0.1 in action (Youtube).

Read the docs.

đź“– Overview

Instant Organic Caves (IOC) is a small plugin designed to generate massive, seamless, and organic cave and/or rock systems procedurally at runtime. Unlike traditional marketplace assets that rely on static meshes or Blueprint construction scripts, IOC utilizes a "Metal C++" approach.

It builds geometry directly using Unreal's `FDynamicMesh3` core math libraries, bypassing overhead from the Blueprint VM and intermediate wrapper libraries. The result is a system that can generate infinite, seamless, Nanite-enabled environments suitable for high-fidelity production.

✨ Key Features

*Pure C++ Architecture:** No dependency on Blueprint logic, PCG Graphs, or external assets. The geometry is calculated mathematically from scratch.

*Direct Dynamic Mesh Manipulation:** Operates directly on `UE::Geometry::FDynamicMesh3` for maximum performance.

*Infinite World Generation:** Supports seamless chunk tiling using world-space Perlin Noise.

*Organic Smoothing:** Implements custom, stable Laplacian Smoothing to convert blocky voxel grids into smooth, eroded cavern walls.

*Welded Topology:** Custom meshing algorithm ensures watertight geometry with no internal faces, preventing shading artifacts and mesh tearing.

*Nanite & Lumen Ready:** programmatically enables Nanite support on generated meshes.

🚀 Quick Start

Single Chunk Generation

1. In a New Scene, open the Place Actors panel.

2. Search for `IOCProceduralActor` in Plugins.

3. Drag it into the viewport.

4. A cave chunk will generate immediately. Use the Details Panel to adjust settings like `Seed`, `Roughness`, and `Cave Size`.

  1. Use LeftAlt+LMB to duplicate the generated chunk in any direction. Chunks can be seamlessly merged. More sophisticated options to extend the structures will come in the next version.

Infinite World Generation (WIP, coming soon)

1. Search for `IOCWorldGenerator` in the Class list.

2. Drag it into the level.

3. In the Details Panel:

Set *Chunk Class** to `IOCProceduralActor`.

Set *Render Distance** (e.g., `2` for a 5x5 grid).

Set *Update Interval** (e.g., `0.5` seconds).

4. Press Play. As the camera moves, new cave chunks will form ahead of you seamlessly.

Please note: the plugin needs the PCG and GeometryScripting modules enabled.

Hi all. I am looking into the possibilities of merging this plugin with another one of mine, TerraDyne: I think it would make great sense since both are essentially runtime procedural systems to generate or manipulate organic structures in a level.
However, such a merge would result in a deeply complex unified plugin with a higher margin of error (and a book-length manual really).
If you have any comments or requests on this, please share it here or in email, thanks.

[0.3.0] - 2026-06-20 update :camping:

Added :plus: :newspaper:

    🎨 Pure Math Material: Developed M_IOC_MathRock , a zero-footprint master material that uses World Position and 3D Simplex Noise to generate organic rock strata without relying on texture memory.

    :rock: Hybrid PBR Pipeline: Upgraded the Master Material with a Use PBR Texture switch, instantly swapping between Pure Math and traditional Textures.
    :gem_stone: Seamless Biome Textures: Packaged three new 4K tileable rock textures directly into the plugin: Obsidian Flow, Limestone Crawl, and Alien Hive. (More to come later.)
    :world_map: Triplanar Projection: Implemented automatic Box Mapping to prevent texture stretching on generated vertical cave walls.
    :books: Vector Documentation: Overhauled the shipped Manual. Replaced static screenshots with clean, responsive SVG vector illustrations and added comprehensive guides for the new Hybrid Texture workflow.

  • Readiness Guard: Showcase flythrough camera now intelligently defers its start until all asynchronous procedural caves have completed generating (or up to a 30s fallback timeout).
  • Flythrough Looping: Added bLoopShowcase property to AIOCShowcaseLauncher, giving users control over whether the showcase flythrough loops continuously or halts after one pass.
  • Dedicated Tools Menu: Added Tools > Instant Organic Caves with one-click access to the setup wizard, validation, documentation, demo spawns, showcase launch, and showcase cleanup.
  • Launcher Quick Actions: AIOCShowcaseLauncher now exposes clearer Call In Editor actions for standard showcase start, capture showcase start, and showcase cleanup, with friendlier property labels and tooltips.
  • Wizard Quick Start UX: The setup wizard now exposes a welcome-page project snapshot, quick-start actions, clickable step navigation, and preset-to-custom workflow shortcuts.

Changed :coral:

  • Showcase Robustness: Refactored the showcase spawn pipeline into resilient conditional blocks. If a specific section's actor fails to spawn, the system gracefully skips it without crashing or desyncing the camera.
  • Concurrency Safety: Added a strict bIsActive lock to ShowcaseState with hardened reset logic to prevent overlapping showcases, memory pollution, and hot-reload errors.
  • Python Drift Prevention: Fully deprecated IOC_CreateShowcaseMap.py via runtime warnings and comments, establishing the C++ Setup Wizard as the single source of truth for starter map configuration.
  • Shipping Build Compatibility: Wrapped editor-only setup wizard capture functionality inside #if WITH_EDITOR blocks, completely resolving compilation errors in Game/Runtime/Shipping targets.
  • Typed Showcase/Demo API: Wizard and launcher flows now call a shared native module API instead of relying on string-built GEngine->Exec commands.
  • Validation Feedback: Installation validation now also shows editor notifications while still writing the full report to the Output Log.
  • Documentation Access: Wizard and editor menu actions now share a single documentation opener that prefers the local shipped docs and falls back to the website.
  • Wizard Practicality: Review now links directly to starter assets, preview-side workload visibility is stronger, and safer-first-pass actions surface earlier in the flow.
  • Standalone Packaging: Fixed Win64 game-target packaging by restoring the runtime material-domain include used by fallback cave materials.
  • Native Setup Flow: The setup wizard no longer depends on Python execution for starter assets or showcase-map creation; both workflows now use built-in editor APIs with explicit success/failure handling.
  • Validation Messaging: Installation checks now treat Python automation as optional and correctly describe starter assets as shipped plugin content.

This really needs at least 2 new videos to showcase new features and instruct on usage. Please bear with me.

0.3.5 update, 2026-07-18 :volcano:

Added

  • Authoritative runtime carving: Reflected carve records now replicate to late joiners, serialize through SaveGame, validate radius/input, and obey a bounded FIFO history.
  • Persistent streamed carving: AIOCStreamingManager owns a saveable carve history, routes excavation to affected chunks, and restores it after unload/reload.
  • Production resource budgets: Hard voxel, triangle, and scatter caps reject unsafe work while preserving the last valid generated mesh.
  • Multiplayer streaming controls: Authority tracks all player pawns, unions their desired chunks, caps retention, throttles loads, and releases chunks after the last player leaves.
  • Seam-safe streamed density: Voxel/LOD-aligned chunk dimensions, a one-voxel neighbor halo, stable global seeding, and locked smoothing boundaries prevent artificial interface caps.
  • World-aligned generated UVs: World-space chunks now project generated UVs from world coordinates so UV-driven materials do not restart at every chunk origin.
  • :artist_palette: Pure Math Material (updated): Developed M_IOC_MathRock, a zero-footprint master material that uses World Position and 3D Simplex Noise to generate organic rock strata without relying on texture memory.
  • :rock: Hybrid PBR Pipeline (updated): Upgraded the Master Material with a Use PBR Texture switch, instantly swapping between Pure Math and traditional Textures.
  • :gem_stone: Seamless Biome Textures (updated): Packaged three new 4K tileable rock textures directly into the plugin: Obsidian Flow, Limestone Crawl, and Alien Hive.
  • :world_map: Triplanar Projection (updated): Implemented automatic Box Mapping to prevent texture stretching on generated vertical cave walls.
  • Readiness Guard: Showcase flythrough camera now intelligently defers its start until all asynchronous procedural caves have completed generating (or up to a 30s fallback timeout).
  • Flythrough Looping: Added bLoopShowcase property to AIOCShowcaseLauncher, giving users control over whether the showcase flythrough loops continuously or halts after one pass.
  • Production bake controls: Stable unique naming, material override, lightmap UV/tangent generation, optional generated LOD, optional Nanite, and selectable collision mode.
  • Runtime status: Blueprint-visible success, failure reason, timing, voxel, triangle, LOD, and scatter metrics.
  • Regression coverage: Added runtime-contract, generation-budget, streamed-seam, and streamed-carve-persistence automation tests.

Changed

  • Cave transforms now participate correctly in world-space noise, biome, and carve sampling.
  • Generation cancellation is lifecycle-safe and checks cancellation during expensive parallel voxel/carve work.
  • LOD distance uses generated mesh bounds and never switches to an invalid LOD.
  • Player coupling is opt-in and disabled for network games unless explicitly allowed.
  • Demo/showcase commands are non-shipping cheat commands; the showcase launcher is inert in Shipping.

Fixed

  • Removed global debug-line flushing that could erase unrelated project visualization.
  • Removed module delegate leakage during shutdown.
  • Removed plugin-owned UE 5.7 deprecation warnings for networking and Nanite access.
  • Fixed Shipping compilation of the showcase launcher.
  • Fixed world-space generation seeds being ignored and per-chunk seeds breaking density continuity.

[0.4.0] update, 2026-09-09 :brown_mushroom: :camping:

At a glance:

  • Support for UE5.5, 5.6, 5.7, 5.8.x
  • An original scatter library
  • 10x performance boost
  • All content re-authored on UE5.5 to ensure compatibility
  • New demo map and offline / online tutorial
  • Redesigned Setup Wizard
  • Major rehauling of cave materials
  • Carving and instrumentation upgrade
  • Network update: delta-replicate
  • Many fixes

A long overdue major update. Carving, content and onboarding. Every shipped asset was re-authored on the 5.5 floor, the plugin gained its own scatter library, the Setup Wizard was rebuilt, and a demo map and tutorial now give two routes in that need no setup.

A deeply technical changelog follows, aimed mainly at enthusiasts. The online manual and setup tutorial may be an easier read otherwise. Please remember that the open-source version is also advanced, updated and supported.

Verified on UE 5.5, 5.6, 5.7 and 5.8. Automation suite 21/21 green on the 5.5 floor, up from 14 tests, and every assertion added this cycle was negative-tested: deliberately broken, observed to fail, then restored.

:high_voltage: Performance — carve latency 200 ms to 118 ms (1.7x)

Measured on an 80^3 cave (3200 uu bounds, 40 uu voxels, non-tunnel, one sphere carve).
New per-stage instrumentation, logged when bLogPresetDebug is set, drove all of it:

stage before after
noise fill 23 ms 0 ms (replayed)
carve 0.3 ms 0.3 ms
face extract 10.5 ms 10 ms
Laplacian smooth 73 ms 7.2 ms
mesh build 58 ms 64 ms
overlays 35 ms 35 ms
worker total 200 ms 118 ms
  • Laplacian smoothing was allocating a TSet<int32> per vertex to hold adjacency – one
    hash set per mesh vertex, which made allocator traffic the single largest cost in the whole
    generator (36% of generation time). Replaced with compressed-sparse-row adjacency built in
    two linear passes, with per-slice sort-and-unique reproducing TSet’s unique-neighbour
    semantics. The per-vertex update has no cross-vertex dependency, so it now also runs through
    ParallelFor. 10x faster on that stage.
  • Added FIOCVoxelCache: the post-noise, pre-carve voxel field is cached and replayed, so
    a carve no longer re-evaluates the noise. Keyed by a signature covering every input to the
    fill (seed, noise parameters, tunnel geometry, biome overrides, spline segments, actor
    transform, bounds) plus voxel size and grid dimensions – change any generation parameter and
    the signature stops matching, so a stale field cannot be served and there is no invalidation
    call to forget. Stored as one bit per voxel (a 2M-voxel streamed chunk costs ~250 KB); only
    caves that actually carry carves populate a cache. Toggleable in Project Settings.
  • The carve pass is restricted to the union bounding box of the carves’ influence. Outside
    it the field is identical to the filled or replayed result. The remaining ~110 ms is entirely mesh build (64 ms) and attribute overlays (35 ms), both bound
    by single-threaded FDynamicMesh3 append APIs.

:collision: Breaking

  • AIOCProceduralActor::RuntimeCarves changed type from TArray<FIOCCarvingCapture> to
    FIOCCarveHistory. C++ that iterated it should use RuntimeCarves.Items or the new
    GetRuntimeCarves(); Blueprint should use GetRuntimeCarves(). The SaveGame layout for
    carve history changed
    – previously saved carve histories will not load.
  • OnRep_RuntimeCarves is gone; the FastArray notifies through its own hook.

:moai: Content — everything re-authored on the 5.5 floor

  • All shipped assets are now fully compatible with the declared 5.5 floor.
    Forward compatibility runs one way only — there is no downgrade path and
    no descriptor setting that helps. Every asset was rebuilt natively on 5.5 by dumping its
    semantic content on a newer engine and replaying it through the editor API, then re-dumping
    the rebuild on 5.5 and diffing: 279 values compared, one difference, and that one is an
    engine limitation carrying no data.
  • Packaging.ContentEngineFloor now scans every shipped .uasset and .umap and fails on
    anything saved above the floor, so this cannot recur silently.

:adhesive_bandage: Fixed — cave materials

  • Three base materials were one-sided. A cave is a shell – TunnelRadius of air inside WallThickness of rock – and the player stands inside it, so the bore’s
    surfaces are backfaces and were being culled. All three are now two-sided,
    which also fixes shading, since Unreal flips the vertex normal on
    backfaces for two-sided materials.
  • Both flags are set by Resources/SetMaterialRenderFlags.py and guarded by the
    Content.MaterialRenderFlags automation test.
  • :artist_palette: M_IOC_SmartCave ignored vertex colours. VertexColor was wired to nothing
    and both LinearInterpolate alpha pins sat at const_alpha = 0.5, so the material rendered a
    fixed 50/50 blend. The authoring script wired outputs named "Green"/"Blue"; the outputs
    are R/G/B/A.
  • :artist_palette: M_IOC_MathRock ran its noise at default world scale. The Noise position input was
    unconnected and WorldPosition → Multiply(x0.002) dangled — the script targeted a pin named
    "Position", which is actually "World Position".
  • :puzzle_piece: IOC_Fn_ScatterCrystals computed a density it discarded — NormalToDensity_0.Out went
    nowhere. It now feeds DensityFilter_0.In.
  • ConnectMaterialExpressions returns false on an unknown pin or
    output name and changes nothing. Every authoring
    script now routes through a helper that raises on rejection.

:rock: Added — an original scatter library

  • Eight meshes generated with GeometryScripting and shipped in
    /InstantOrganicCaves/InstantOrganicCaves/Geometry/: three rocks from boulder to gravel, two
    crystals, a geode, a stalactite and a stalagmite. Each has two LODs, simple collision, and a
    pivot placed for how it is used — the stalactite hangs from its top, the rest sit on their
    base — so instances neither float nor sink when aligned to a surface.
  • Content.ScatterMeshLibrary checks all eight for material slots, LOD count and reduction,
    triangle budget, collision, real-world scale and pivot placement. All eight gates have now
    been proven able to fail.

:compass: Added — two routes in that need no setup

  • :world_map: A demo map ships: /InstantOrganicCaves/Maps/IOC_DemoMap, reachable from
    Tools → Instant Organic Caves → Open Demo Map. It holds one launcher and a PlayerStart
    and nothing else — every cave is built at runtime on Play, so there is no baked lighting to
    rebuild, nothing to rot, and no content references beyond a native class.
  • :open_book: A tutorial ships: Resources/Docs/Tutorial.html. The manual documents every property
    and teaches nothing, which left no guided path for a new user. The tutorial
    covers demo, wizard, presets, sizing, the six parameters that matter, scatter and
    troubleshooting, with a preset explorer that draws each cave’s cross-section to scale from
    the real preset values and a voxel budget calculator running the wizard’s own arithmetic.
  • :broom: IOC.ClearAllDemos removes everything any demo command added, including the playtest
    character, so the commands leave no residue in a customer’s level.

:magic_wand: Changed — the Setup Wizard

  • Every SWrapBox had always been wrapping at 100px. SWrapBox defaults to
    PreferredSize = 100 with UseAllottedSize = false, and all twelve instances set neither —
    so button rows stacked vertically regardless of available width.
  • The wizard opens on a first run with a working route forward. IOC.OpenSetupWizard opens it without the menu.

:globe_with_meridians: Network

  • RuntimeCarves now delta-replicates. It was a plain TArray<FIOCCarvingCapture>, so
    every carve resent the whole array – roughly 25 KB to each relevant client against a
    256-entry history. It is now FIOCCarveHistory, a FFastArraySerializer. The common case
    (append) marks one item and sends one small delta; only FIFO eviction degrades to a full
    array update, because a removal invalidates the replication keys after it.
  • Client-side rebuilds are driven by PostReplicatedReceive, which fires once per received
    update, rather than by the per-element add/change/remove hooks.

:sparkles: Added — carving and instrumentation

  • InstantOrganicCaves.Cave.CarveFieldCacheParity – proves a replayed field produces geometry
    identical to a recomputed one, that two consecutive cached generations agree, and that
    changing the seed invalidates the cache rather than serving the stale field.
  • Production.RuntimeContract now asserts the carve history carries
    STRUCT_NetDeltaSerializeNative. Omitting the type trait still compiles and still
    replicates, just as a whole array – this is the only check that distinguishes the two.
  • Per-stage generation timings behind bLogPresetDebug.

:test_tube: Verification

  • Suite grown from 14 tests to 21. Seven are new: Content.ScatterMeshLibrary,
    Content.MaterialRenderFlags, Content.WizardStyleAssets, Demo.DemoMap,
    Demo.ShowcaseLifecycle, SetupWizard.ButtonSweep and SetupWizard.Layout. The
    fourteenth, Packaging.ContentEngineFloor, existed and was the one failure — it passes now
    that the content is authored on the floor.
  • Every new assertion was negative-tested. Two proved worth the effort by exposing tests
    that could not have failed: a mesh-breaking helper reported success while doing nothing,
    because the editor library it called is a silent no-op outside a real editor session; and an
    early layout test emitted four confident failures.

:brick: Structure

  • Split out an InstantOrganicCavesEditor module (Type: Editor).
  • The showcase still runs in PIE and packaged builds, so it stayed in the Runtime module; its level-viewport control is inverted through FIOCShowcaseViewportHooks, which the editor module binds on startup. The Runtime module no longer depends on LevelEditor, ToolMenus or ApplicationCore at all.
  • FInstantOrganicCavesModule::ValidateInstallation / OpenDocumentation moved to FInstantOrganicCavesEditorModule. API break for any C++ that called them.
  • Editor logging goes to a separate LogIOCEditor category.

:sparkles: Also added

  • Project Settings page (UIOCSettings, Project Settings > Plugins > Instant Organic Caves): fallback cave material as a FSoftObjectPath, max grid cells per axis, max spline samples, and the vertex welding toggle.
  • Blueprint-assignable generation events. OnGenerationStartedEvent and OnGenerationFinishedEvent are BlueprintAssignable; generation is asynchronous and can take seconds, and Blueprints previously had to poll bIsGeneratingDisplay on tick to know when a cave was ready. The native C++ delegates are unchanged and still broadcast.
  • GenerateCave and RequestRegeneration are now BlueprintCallable.
  • Vertical chunk streaming. AIOCStreamingManager keys chunks by FIntVector and gained VerticalStreamRadius. It defaults to 0, which reproduces the previous single-layer behaviour exactly; raising it streams cave systems deeper than one chunk. Note the chunk count scales by (2 * VerticalStreamRadius + 1), so MaxLoadedChunks needs raising to match.
  • InstantOrganicCaves.Cave.VertexWelding regression test: asserts welding preserves every triangle while sharing vertices, and logs the measured saving.

:wrench: Additional changes

  • Generated meshes weld their vertices. The generator emitted four unshared vertices per quad because FDynamicMesh3 rejects triangles that would create a non-manifold edge – something diagonal-touching voxels produce constantly. It now shares a vertex per grid corner and falls back to duplicated vertices for only the individual triangles that actually fail, so the manifold guarantee holds and no triangle is lost. Measured 2.93x fewer vertices (5504 → 1881 for 2752 triangles) on the test cave, with the same reduction carried into cooked collision. Revertible via the project setting.
  • The PCG node has a version-gated output path. UPCGBasePointData (structure-of-arrays) does not exist on 5.5, so 5.5 keeps UPCGPointData + TArray<FPCGPoint> while 5.6+ uses FPCGContext::NewPointData_AnyThread with the SoA value ranges – which also picks up UPCGPointArrayData where a project has enabled it. The solid-voxel scan was restructured into a count-then-fill pass so both back-ends write output in parallel with no per-point reallocation.
  • TObjectPtr for all UPROPERTY object references on the cave actor, streaming manager and character.
  • Editor UI strings converted from INVTEXT to LOCTEXT in the menus and validation notifications.

:adhesive_bandage: Additional fixes

  • PCG element allocated UObjects off the game thread. FIOCVoxelCoreElement::ExecuteInternal called NewObject<UPCGPointData>() directly; PCG elements run on worker threads (IPCGElement::CanExecuteOnlyOnMainThread defaults to false), so this raced the garbage collector. Now uses FPCGContext::NewObject_AnyThread.
  • Cellular Automata seeding produced a lattice, not noise. The initial fill used a single LCG step, which leaves consecutive cells a fixed stride apart and yields regular banding. Replaced with a MurmurHash3-finalised, coordinate-keyed hash that is also stable across grid resizes.
  • Streaming manager held raw UObject* chunk pointers in a non-UPROPERTY map, invisible to the GC and left dangling when a chunk was destroyed outside UnloadChunk. Now TWeakObjectPtr, with an explicit prune pass.
  • Clients overwrote replicated generation settings. BeginPlay re-expanded the cave preset on every peer, clobbering the replicated recipe and producing client geometry (and collision) the server did not have. Preset expansion is now authority-only.
  • The legacy preset migration could hijack runtime actors. ShouldAutoPreset() is a value-match heuristic over user-editable fields; it no longer runs at BeginPlay, only in a genuine editor world, so a streamed chunk whose settings coincide with the defaults is not silently converted into a tunnel.
  • Generation bounds were silently truncated. The working grid is capped per axis; exceeding it shrank the cave with no diagnostic. The cap is raised to 2048 cells per axis and clamping now logs a warning.
  • Splines were chorded, not followed. Tunnel generation read only GetLocationAtSplinePoint, so a two-point spline with tangents produced a straight tunnel and curves were clipped by bounds derived from the same chords. Splines are now sampled by arc length, backed by a new uniform segment grid so the extra segments do not turn the nearest-segment query into an O(voxels x segments) scan.
  • World-space noise tiled. FMath::PerlinNoise3D masks its lattice with & 255, repeating roughly every 512 m at the default frequency and folding large seed offsets back onto the same lattice. Replaced with a hash-lattice gradient noise of matching range and distribution, so existing thresholds still apply. Regenerating an existing cave will change its shape.
  • Collision was re-cooked on every mesh edit. Complex-as-simple collision updates are now deferred and cooked once per completed generation.
  • The demo and showcase commands changed the user’s level. They took the first DirectionalLight / SkyLight / Fog / PostProcessVolume found in the level, overwrote its settings and renamed it. Environment dressing is now plugin-owned, tagged, transient in editor worlds, and removed by IOC.ClearShowcase.
  • IOC.CaptureWizardPreset — an authoring screenshot tool that spawns actors into the open level, moves the viewport and can quit the editor — is now registered only when the editor is launched with -IOCDevTools, and its retry ticker is removed on module shutdown.
  • Setup wizard rollback snapshot held bare UObject* references on a Slate widget. SIOCSetupWizard is now an FGCObject and reports them; the referenced fields use TObjectPtr.
  • Authoring Python scripts shipped with absolute paths from the author’s machine (including a user-profile path). Paths are now relative or environment-driven, logging goes to the Output Log.
  • AIOCCharacter no longer teleports to an arbitrary cave on BeginPlay: the snap is an exposed, documented option, picks the nearest cave, honours spline mode, and runs on the authority only. Input modifiers use CreateDefaultSubobject instead of NewObject during construction.
  • Property edits that cannot affect geometry (bake options, debug toggles, LOD switch distance, runtime-carve limits) no longer trigger a full regeneration.
  • Runtime carves within a frame are coalesced into a single rebuild instead of one full revoxelisation each.
  • bShowDebugViz gizmos persist while the box is ticked. They were issued once from OnConstruction into the transient line batcher, which expires them after about a second.
  • UIOCVoxelCoreSettings exposes MaxVoxelCount instead of a hard-coded 15M ceiling.

[0.4.1] update, 2026-09-23 :volcano:

:glowing_star: At a glance

  • :counterclockwise_arrows_button: Cave meshes face into the cave. Collision, scatter and lighting now match the surface you see.
  • :world_map: Interactive tour: six feature zones on one walkable route, then a portal to an endless
    streamed tunnel. Ships as a map.
  • :pick: Player carving: AIOCCharacter can carve the cave under its crosshair (opt-in).
  • :fog: Biome blending: AIOCBiomeVolume::BlendDistance eases a volume’s overrides in rather
    than switching them at its face.
  • :bug: Fixes: capsule carves, spline bends, carve falloff, runtime biome volumes,
    biome ledges, streaming placement and stalactites.
  • :blue_book: Illustrated demo guide: Resources/Docs/DemoGuide.html, with a frame from every zone.
  • :test_tube: 35 automation tests, up from 22.

:white_check_mark: Verified: automation suite 35/35 green on UE 5.8 and on the 5.5 floor, 0 ensures; every
new test negative-tested. BuildPlugin unity and strict passes succeed with zero warnings on 5.5,
5.6, 5.7 and 5.8, and all packages pass the isolated-build validator. The shipped tour map (262 m in 53 s) starts cleanly in a standalone -game run.

:collision: Upgrading from 0.4.0 — behaviour changes

  • :counterclockwise_arrows_button: Every cave looks and behaves differently. Surfaces face into the cave, so lighting,
    collision from inside a cave and scatter placement all change.
  • :tooth: Stalactites now grow along +Z from their base. Scatter layers that place SM_IOC_Stalactite
    need Align To Normal on; with it off, stalactites now point up.
  • :pill: Capsule carving components carve a capsule. They used to carve everything within the
    capsule’s length inside the carve pass’s bounds: a box on their own, and the whole region when
    beside a larger carve. Caves that use capsule carves change shape.
  • :pick: A carve never puts rock back. Where carve falloffs overlap, the strongest carve now wins,
    so caves with overlapping falloffs come out slightly more open.
  • :thread: Spline tunnels are sealed on the outside of every bend. Tunnels whose bends showed slits
    to the outside are now closed.
  • :round_pushpin: AIOCStreamingManager builds where it is placed. It always used the world origin; a
    manager placed elsewhere now builds its caves around its own location.

:counterclockwise_arrows_button: Fixed

  • Vertex normals now agree with the winding. They pointed at the air while the winding did not,
    and two-sided shading flips the normal on back faces, so surfaces were lit from behind.
  • The smart-material ceiling mask was inverted. SmoothStep(-0.6, -0.85, Up) has its bounds
    reversed and returned 1 for every surface above -0.6, so M_IOC_SmartCave painted the ceiling
    colour on floors and walls. It now mirrors the floor test.

:world_map: Added — the interactive tour

  • Six zones, one route, ~264 m. The Mouth (a drop-in cave actor on a preset), The Winding Run
    (a spline tunnel that a biome volume flares open), Crystal Gallery (a carved hall dressed by
    scatter layers), Alien Hive (domain warp), Strata Canyon (terraces switched on by a second
    biome volume) and The Forge (a hall shaped by sphere, box and capsule carving components, and the
    one cave the player may carve). A glowing crystal by the Forge’s far wall leads to Infinite
    Depths
    , where an AIOCStreamingManager builds cave around the walking player.
  • Built from four cave actors: two tunnels and two solid-block chambers whose rooms are carved,
    joined tunnel to chamber through carved passages sized from the tunnel mouths measured after they
    generate. Walkable about a second after spawning; no window to the outside anywhere along the
    route except the entrance.
  • A caption per zone on first entry (what the feature is, how to use it, live generation
    numbers), and a “Generating caves…” caption while it builds.
  • Carve the Forge yourself: left mouse / right trigger with the crosshair on the rock.
  • Ships as a map: /InstantOrganicCaves/Maps/IOC_InteractiveDemo (authored on UE 5.5; a launcher
    in Interactive mode and a PlayerStart), opened from Tools > Instant Organic Caves > Open
    Interactive Demo
    or the Setup Wizard’s Open Interactive Demo button. Also
    FInstantOrganicCavesModule::SpawnInteractiveTour, the console command IOC.SpawnInteractiveTour
    and a Spawn Interactive Tour menu entry.
  • AIOCShowcaseLauncher Interactive Demo mode (bInteractiveMode, Start Interactive Demo)
    runs the tour at the launcher’s location instead of the flythrough.
  • IOC.TourAutopilot walks the tour on its own – the route, a carve in the Forge, the portal and
    the depths – for recording and kiosks (-IOCTourAutopilot, -IOCTourAutopilotQuit,
    -IOCTourNoCaptions). Zone entries log their engine frame, for timing titles on a frame dump.
  • The caption overlay is shared by the showcase and the tour, and no longer takes mouse input.

:bug: Fixed

  • Biome volumes left a ledge. Overrides switched at the volume’s face, leaving a step in a tunnel
    floor wherever the radius changed – 186 cm in the test case. BlendDistance eases them in; 45 cm
    with a 10 m blend. The default, 0, keeps the old switch.
  • Capsule carves cut a slab. The capsule distance took the closest axis point as
    (x, y, clamped z), dropping the radial term, so everything within the capsule’s length read as
    inside. The carve pass visits the union of all carves’ bounds, so a capsule beside any larger carve
    hollowed out that whole region – the showcase’s Carved Chamber included, which now has its proper
    shape.
  • Spline tunnels had slits on the outside of every bend. A voxel beyond the end of one spline
    segment and before the start of the next counted as “past the tunnel’s open end” and was dropped,
    cutting a wedge through the wall wherever the spline turned. Only a spline’s true first and last
    segments are open now. Measured on the tour’s tunnel: 228 rays escaped around one bend before, 0 after.
  • Adding a carve could add rock. In a falloff band the carve probability came from the nearest
    carve rather than the strongest, so a new carve’s weak outer band could undo a stronger carve’s
    work. A click in the Forge grew a wall 1.7 m in front of where the player aimed. The pass now takes
    the strongest carve, so carving only ever removes rock.
  • Scattered stalactites grew into the ceiling. See Content below.
  • The walking lane is checked, not assumed. The demo traces the floor every metre (highest rock
    under each 1 m x 2.1 m footprint), sweeps the character’s capsule along the lane, carves a corridor
    with CarveAtLocation wherever rock intrudes, removes scatter props reaching into it (they have no
    collision), then lays one-metre slabs that follow the floor. The same lane runs through every cave
    of the tour and through IOC.SpawnSpectacular.
  • The freeze while the cave generates now holds. Possess() runs Restart(), which reset the
    movement mode and undid the freeze. Possession now happens first.
  • IOC.SpawnSpectacular got a lighting pass: staged warm-key / cool-fill / violet-rim lighting
    in physical units, a SkyAtmosphere for the real-time SkyLight, and limestone / alien-rock surfaces.
  • AIOCCharacter forces an Enhanced Input component, so it works in host projects still configured
    for the legacy input component.

:sparkles: Added — API

  • :pick: AIOCCharacter carving, opt-in: bEnableCaveCarving (off by default),
    SetCaveCarvingEnabled, CarveAtAim, CarveRadius, CarveReach, and PlayerCarvableTag
    (IOC_PlayerCarvable). Only caves with that tag accept the player’s carves. The carve keys live in
    their own mapping context, installed only while carving is on, so a project’s own use of the left
    mouse button is untouched.
  • :fog: AIOCBiomeVolume: BlendDistance, bUseBoxExtent, BoxExtent.
  • :world_map: FInstantOrganicCavesModule: SpawnInteractiveTour(World, Origin), and
    GetShownCaptionTitle for tests and tools.
  • :keyboard: Console: IOC.SpawnInteractiveTour, IOC.TourAutopilot.

:rock: Content

  • SM_IOC_Stalactite re-authored to grow from its base along +Z, like SM_IOC_Stalagmite.
    Scatter aligns +Z to the surface normal, which points into the cave – down, on a ceiling – so the
    normal is what hangs it. Authored tip-down with its pivot on top, it only suited the inside-out
    mesh; with correct normals every stalactite on a ceiling pointed up into the rock and vanished.
    Regenerated on UE 5.5 from its seed; the other seven meshes are unchanged.
  • New map IOC_InteractiveDemo, authored on UE 5.5.
  • Poisson spacing packs a surface. Worth knowing when tuning scatter: with
    PoissonMinSeparation set, the scatter throws 30x the candidates and keeps every one far enough
    apart, so the result approaches the spacing limit whatever Density says. The tour uses density
    alone.

:books: Documentation

  • :blue_book: New Resources/Docs/DemoGuide.html, replacing IOC_DEMO_GUIDE.md: the tour zone by zone,
    illustrated with frames from the game, plus its controls, console commands, how to record it and a
    presenter’s script. Its images are inlined, so it works opened from disk.
  • :graduation_cap: Tutorial: the two demo levels, the tour’s zones and controls, IOC.SpawnInteractiveTour,
    biome blending, player carving, stalactite pivots and Poisson spacing, and two new
    troubleshooting entries.
  • :open_book: Manual: supported engines 5.5-5.8, the Tools menu, the wizard’s and launcher’s interactive
    entries, streaming placement, the new biome properties, carve falloff, a Player Carving section,
    decoration pivots and spacing, the new console commands and API.
  • All three pages link to each other.

:test_tube: Tests — 35, up from 22

  • Mesh orientation: Cave.NormalOrientation – from inside a tunnel, the floor faces up, the
    ceiling faces down, physics hits the floor the mesh shows, vertex normals agree with the winding,
    and floors and ceilings carry the right smart-colour masks. Against the inside-out mesh all three
    facing checks fail.
  • Generator defects: Carving.CapsuleShape, Carving.NeverAddsRock, Cave.SplineBendSealed,
    Cave.BiomeBlend, Cave.BiomeVolumeBox, Content.ScatterFacesIntoCave, and a placement check in
    Production.StreamingCarvePersistence.
  • The tour: Demo.InteractiveLaneInBore (the walkway on the cave floor at 12 stations across
    all six zones, a route of at least 200 m, nothing left behind by IOC.ClearAllDemos),
    Demo.InteractiveRouteSealed (from head height over the walkway, no ray sideways or upward reaches
    the void except out of the entrance), Demo.InteractiveCarving (a click at a Forge wall carves the
    Forge only and digs into the wall; a click in Tunnel B carves nothing), Demo.InteractiveStreaming
    (the portal puts the player on a streamed floor, inside the tunnel, able to walk) and
    Demo.InteractiveBudget (walkable within 4 s; measured 0.7 s).
  • Real input: Demo.InteractiveInput sends a real key event through Slate into the focused game
    viewport in PIE (one layer down under -NullRHI, where the viewport has no size and drops keys),
    walks the whole tour and requires every zone caption in route order.
  • Coverage: Demo.DemoMap covers both shipped maps; SetupWizard.SafetyAndValidation and
    ButtonSweep cover the new command, map and button. Demo.ShowcaseLifecycle no longer fails inside
    a level with its own IOC_-labelled actors.
  • Every new test was negative-tested: broken on purpose, observed to fail, then restored.

:warning: Known

  • AIOCCharacter has no mesh: the third-person camera follows an invisible capsule. For now, this is intentional.
  • Runtime carving still re-meshes the whole actor per carve (unchanged from 0.4.0).
  • SetupWizard.Layout still checks how the wrap boxes are built, not their laid-out width (see 0.4.0).

Basic procedural walkthrough of the 0.4.1 interactive demo:

Another interactive 0.4.1 demo:

A comprehensive tutorial video is now available:

[0.4.5] update, 2026-10-01 :mount_fuji:

:candle: A dark level, in its own rock — and every surface rebuilt at 2K. The Warren is a second
playable demo: 346 m of tight, organic burrow walked by flashlight, with scripted moments, a rock plug
you carve through, and a hollow beyond it open to the daylight. Each of its six beats wears its own
rock, drawn by a new world-aligned material you can put on any cave. Around it, every texture and prop
in the plugin was rebuilt: ten 2048² rock sets drawn world-aligned, and thirteen props modelled and
baked in Blender with real UVs. The setup wizard lost seven rough edges on the way. The release after
0.4.1 is numbered 0.4.5; there was no public 0.4.2 to 0.4.4.

:glowing_star: At a glance

  • :candle: The Warren — six beats, ~346 m, lit only by the character’s flashlight. Ships as
    /InstantOrganicCaves/Maps/IOC_DarkDemo.
  • :rock: Six rock sets, one per beat — flesh-rock, mycelium, rusted shale, calcified bone,
    weeping stone and fractured basalt.
  • :brick: M_IOC_WarrenRock — a world-aligned rock material: no UV streaks, real surface relief
    under a torch, usable on any cave.
  • :hole: Organic Warren preset — a tight, heavily warped bore: a burrow rather than a bore hole.
  • :bone: Five new props — roots, a fungal shelf, an egg sac, a bone pile and a membrane, plus a wet
    organic material and a glowing fungus one.
  • :pick: Carve to continue — the level dead-ends in rock; carve through it and walk on into the
    Hollow.
  • :clapper_board: IOC.WarrenAutopilot — walks the whole level by itself, for recording and kiosks.
  • :framed_picture: 2K rock, world-aligned — obsidian, limestone, alien, cave floor and the six Warren sets are
    2048², and the default cave skin (MI_IOC_CaveWalls) now draws them world-aligned too: no UV
    streaks, real relief in the normal map, glowing veins on the alien set.
  • :rock: Thirteen props, rebuilt in Blender — sculpted, UV-unwrapped, baked onto three 2048² atlases
    (rock, crystal, organic), two LODs and convex collision each.
  • :mage: A better-mannered setup wizard — it keeps the lights already in your level, stays in front
    of the editor, says “Setup Complete” without contradicting itself, shows every preset name in
    full, and keeps its banner’s title at any window size.
  • :mobile_phone: Platforms: Win64, Linux and Android. The modules’ PlatformAllowList is now
    [Win64, Linux, Android] (it was [Win64, Mac, Linux]), and all three are compiled for every
    supported engine before release.
  • :test_tube: 49 automation tests, up from 35.

:white_check_mark: Verified: automation suite 49/49 green on UE 5.5, 5.6, 5.7 and 5.8, each built from a clean
copy of the plugin in a content-free host (PluginTestMatrix), and 0 ensures in the 5.8 and 5.5-floor
runs of the dev project. The
Warren’s tests and the four new wizard tests were negative-tested, as was the budget-message check;
SetupWizard.OwnedByEditor and SetupWizard.LiveLayout were run in a rendering editor, where a
headless suite skips them. The
Warren’s own autopilot walks it end to end — through the carved plug and across the Hollow — in a
standalone -game run. All new and rebuilt content is authored on UE 5.5.

:collision: Upgrading from 0.4.1

  • :artist_palette: Caves using the default material look different. MI_IOC_CaveWalls (parent
    M_IOC_MathRock) is now world-aligned, so the cave’s UVs and TextureTiling no longer place its
    texture: use the material’s TileSize (world cm per repeat) instead. CaveStyleTexture and the
    Use PBR Texture switch keep their names; set CaveStyleNormal to the style’s _N map when you
    change styles.
  • :artist_palette: M_IOC_SmartCave is textured. Color_Wall, Color_Floor and Color_Ceiling are now tints
    over the wall and floor textures (neutral by default) rather than flat colours, Roughness multiplies
    the maps, and it blends by world normal, so it no longer needs bGenerateSmartColors. Instances that
    set strong colours will tint the rock rather than replace it.
  • :rock: The thirteen props were replaced in place — same names and paths, so scatter layers, PCG graphs
    and placed actors keep working, but the geometry is new and each mesh has one material slot. If you
    overrode a prop’s material, check it still lands where you want.
  • :mage: The wizard’s Set up lighting no longer duplicates your lights. It adds only the directional
    light, sky light, height fog and unbound post-process volume the level lacks.
  • :desktop_computer: Mac is no longer listed. The modules’ PlatformAllowList is [Win64, Linux, Android], so the
    plugin does not load in a Mac editor or build for Mac.
  • :package: The package is larger: plugin content grows from about 27 MB to about 209 MB, almost all of it
    the 2048² textures (normal maps are stored uncompressed-quality BC5 at 9–13 MB each).

:candle: Added — the Warren, the dark demo level

  • :compass: Six beats, one descent, ~346 m. The Gullet (a tight warped crawl with membranes strung
    across it), The Nest (five overlapping sphere carves — pods, not a room — with egg sacs, roots
    and a glowing fungus cluster), The Throat (tighter and steeper; the roof comes down behind you),
    The Bone Garden (a low hall of columns and bone piles, with a light that dies as you approach),
    The Weep (the narrowest run, where an alcove opens behind you) and The Hollow (reached only by
    carving through a rock plug, ending at a crack of daylight).
  • :building_construction: Built from six cave actors: three tight spline tunnels and three solid blocks whose rooms
    are carve components, joined tunnel to block through passages sized from the tunnels’ measured
    mouths — the same join recipe as the interactive tour.
  • :flashlight: Lit by the flashlight. The level places four lights in 346 m: the fungus, the dying lamp,
    a rim on the Hollow’s far wall and the daylight crack. Sun and sky are turned down to almost
    nothing.
  • :performing_arts: Scripted moments, no creature. A collapse that drops rubble behind you with a stutter of
    the flashlight, a light that goes out as you close on it, and a side alcove that opens in rock
    you have already walked past. Each is a carve or a prop, placed against its own trigger point, so
    nothing can land in front of you.
  • :pick: Carve to continue. The level ends in solid rock, and only that cave accepts your carves.
    Carve through the plug and a walkway is laid beyond it, joined to the one you arrived on, into the
    Hollow and on towards the daylight.
  • :world_map: Ships as a map: /InstantOrganicCaves/Maps/IOC_DarkDemo (authored on UE 5.5), opened
    from Tools ▸ Instant Organic Caves ▸ Open Dark Demo or the Setup Wizard’s Open Dark Demo
    button. Also FInstantOrganicCavesModule::SpawnDarkWarren, the console command
    IOC.SpawnDarkWarren, a Spawn Dark Warren menu entry, and AIOCShowcaseLauncher’s new
    Dark Warren mode.
  • :clapper_board: IOC.WarrenAutopilot walks the level on its own — the route, the scripted moments,
    carving the plug and out across the Hollow (-IOCWarrenAutopilot, -IOCWarrenAutopilotQuit,
    -IOCWarrenNoCaptions). Beats and events log their engine frame, for timing a recording.

:rock: Added — the Warren’s own rock

Each beat wears a rock of its own, so every stretch of the descent looks like a different place:

  • :anatomical_heart: Gullet — wet, folded, flesh-toned rock, glossy in the creases.
  • :mushroom: Nest — dark stone laced with pale fungal threads and flecked with spores.
  • :brown_circle: Throat — cracked shale with rust weeping from the cracks.
  • :bone: Bone Garden — pale, pitted, calcified stone the colour of old bone.
  • :droplet: Weep — dark wet stone with teal and white mineral seeps that glisten under the torch.
  • :volcano: Hollow — fractured basalt, with lichen where the daylight reaches.
  • :artist_palette: Each set is a colour map with roughness in its alpha plus a normal map, 2048², in
    Textures/Warren/ (T_Warren_<Beat>_D / _N). They are generated from fixed seeds, so they tile
    without seams.
  • :brick: M_IOC_WarrenRock draws them world-aligned (triplanar): colour, roughness and normals
    are projected in world space, ignoring the cave’s UVs, so nothing smears where the UV projection
    changes and the torch finds real relief in the rock. Parameters: RockColour, RockNormal,
    TileSize (world cm per repeat), RoughnessScale, FloorWetness (below 1, up-facing surfaces
    read wetter) and NormalStrength.
  • :repeat_button: Use it on your own caves: set CaveMaterial to an instance of it with any of the six sets
    (see the Manual’s Warren Rock). The Warren falls back to the shared rock textures if the set is
    missing, so it never renders untextured.

:sparkles: Added — preset and API

  • :hole: EIOCCavePreset::Warren (“Organic Warren”): TunnelRadius 350, WallThickness 70,
    NoiseFrequency 0.009, VoxelSize 25, DomainWarpIntensity 260. Like Tight Crawlspace it is a
    shape, not a promise a character fits; the demo opens its own tunnels up for walking.
  • :electric_plug: FInstantOrganicCavesModule::SpawnDarkWarren(World, Origin), and GetDarkWarrenPlug for
    tests and tools.
  • :rocket: AIOCShowcaseLauncher::bDarkWarrenMode / StartDarkWarren().

:package: Content

  • :bone: Five new generated props, seeded and reproducible like the other eight:
    SM_IOC_Root_A, SM_IOC_FungalShelf, SM_IOC_EggSac, SM_IOC_BonePile, SM_IOC_Membrane.
    Thirteen props ship now.
  • :green_circle: M_IOC_Organic with BaseColor, Roughness and EmissiveColor parameters — the first
    shipped material to expose emissive — plus MI_IOC_Organic (wet) and MI_IOC_Fungus (glowing).
  • :rock: Twelve rock textures and M_IOC_WarrenRock (above).
  • :ice: Both new base materials are two-sided and flagged for instanced static meshes, like every
    other shipped material.
  • :white_check_mark: All new and rebuilt assets, the map included, were authored on the UE 5.5 floor. 61 content
    assets ship (46 in 0.4.1’s count plus the 2K rework below).

:framed_picture: Changed — every texture and prop, rebuilt at 2K

  • :rock: Four shared rock sets at 2048²: T_RockObsidian, T_RockLimestone, T_RockAlien and
    T_CaveFloor, each a colour map with roughness in alpha plus a _N normal map. Obsidian is glassy
    scalloped fracture with knife-edge ridges, limestone pale water-worn stone, alien dark bioporous
    stone with veins, and the floor packed grit and pebbles. The six Warren sets are 2048² as well.
  • :brick: M_IOC_MathRock is world-aligned. The default cave skin (MI_IOC_CaveWalls) projects its
    texture in world space like M_IOC_WarrenRock, so it never streaks where the generator’s UV
    projection changes axis, and it finally has a normal map. New parameters: CaveStyleNormal,
    TileSize, ProjectionContrast, NormalStrength, RoughnessScale, Tint, VeinGlow and
    VeinGlowColour (the alien set’s veins glow). With Use PBR Texture off it is still the
    zero-texture rock, now with a gentler bump that no longer tips whole patches away from the light.
  • :puzzle_piece: M_IOC_SmartCave is textured: a wall set and a floor set blended by world normal, tinted by
    its three colours (see Upgrading).
  • :rock: Thirteen props, modelled in Blender. Each prop is a fixed-seed sculpt, decimated to a game
    mesh with real UVs, with a lighter LOD1 and convex collision. The props bake onto three shared
    2048² atlases — rock, crystal, organic — with colour, roughness, normal and emissive, drawn by one
    new master, Materials/M_IOC_Prop (Tint, RoughnessScale, EmissiveColour,
    EmissiveStrength, RimGlow). MI_IOC_PropRock is new; MI_IOC_Crystal, MI_IOC_Organic and
    MI_IOC_Fungus now derive from it. Crystals glow at their rims and the fungus shelves glow.
  • :repeat_button: Regenerable from source: the textures come from Resources/GenerateRockTextures.py and the
    props from Resources/Blender/GenerateScatterProps.py (Blender 5.2) plus
    Resources/ImportScatterProps.py. None of these scripts ship.

:mage: Fixed — the setup wizard

  • :light_bulb: It no longer puts a second sun in a lit level. Set up lighting always spawned a
    directional light, sky light, height fog and post-process volume, and the UE Basic template already
    has the first three. The first Generate in a new level left two suns fighting over the sky (UE
    prints a warning over the viewport) and doubled the fog. It now adds only what the level lacks and
    logs what it kept.
  • :window: It stays in front of the editor. It was an unowned window, so the moment the editor took
    focus it drew over the wizard, and Generate Cave focuses the editor by selecting the new cave. The
    Finish page, with Undo Added Actors, vanished behind the level editor exactly when it was
    needed. The wizard is now owned by the editor’s main window.
  • :white_check_mark: The Finish page says what happened. A successful setup read “Setup Complete” over “No cave was
    generated yet”, above the new cave’s statistics.
  • :label: Preset names are no longer cut off. At the wizard’s default size every style card clipped
    its name (“[A] Larg”), its description and its spec line: an empty spacer took half of each title
    row, and the description wrapped at a fixed 250 px on a card about 170 px wide. Everything on a
    card now wraps to the card.
  • :framed_picture: The banner keeps its title when the wizard is widened. Its art was cropped into a fixed
    196 px box, so a wider window scaled the art up and cropped the title away. The banner’s height now
    follows its width, showing the same slice of the art at any size.
  • :chequered_flag: After Undo Added Actors, the Finish page stops describing the undone setup. Its “Spawned new
    cave actor” and “LOD generated” badges stayed under “Setup Not Run”; they now show only while a
    setup is running or done.
  • :snake: The validation report no longer mentions Python helpers that don’t ship. It said Python was
    “enabled for optional Resources/*.py automation helpers”; those are authoring scripts excluded from
    the package, and the plugin needs no Python.
  • :broom: “Reconfigure an existing cave actor” is no longer restored from an earlier session. It names
    an entry in that session’s cave list, so restored it made Generate fail with “the selected cave
    actor is no longer available”. And the automation tests no longer save their own wizard settings
    over yours.

:bug: Fixed — generation errors

  • :speech_balloon: LastGenerationError names the budget that stopped a cave. A generation refused by
    MaxVoxelCount or MaxGeneratedTriangles reported the generic “Generation produced no surface…”;
    it now carries the same message the log does (“Voxel grid budget exceeded (…)”).

:bug: Fixed

  • :bullseye: A scripted event could fire where the player stands rather than where it belongs. The
    collapse placed its rubble relative to the player’s position at the moment it triggered, so a
    player who covered ground in one step — a teleport, a hitch — could have it land in front of
    them, or on them. Events now place themselves against their own trigger point.
  • :ladder: Carves that sank below a chamber’s floor left steps nobody could climb. Sphere and capsule
    carves centred less than their own radius above the floor scoop pits through it; the walkway
    followed them down and back up, leaving a 96 cm step — a character climbs 45 cm. Every round
    carve in the level now sits tangent to its floor, and Demo.WarrenLaneInBore measures the
    tallest step on the walkway.

:wrench: Changed

  • :link: The interactive tour and the Warren now share their cave-building helpers
    (IOCDemo::MakeRockMaterial, AddScatterLayer, AddCarveComponent, SplinePointAt,
    MeasureFloorBelow) rather than keeping two copies.

:books: Documentation

  • :blue_book: The demo guide covers both levels: a new The Warren, beat by beat section with a frame
    from each beat, and the new commands in its command table.
  • :graduation_cap: Tutorial: a third demo card, the Organic Warren preset in the preset explorer with its real
    values, and IOC.SpawnDarkWarren in the console list.
  • :open_book: Manual: the preset table, the new console commands, the wizard’s new button, and a
    Warren Rock (world-aligned) section on using the new material. The material pipeline is rewritten
    for the world-aligned M_IOC_MathRock and the textured M_IOC_SmartCave, the scatter section lists
    all thirteen props and their atlases, and the wizard’s Environment step says it keeps your lights.
  • :graduation_cap: Tutorial: the scatter section lists the organic props as well as the mineral ones.

:test_tube: Tests — 49, up from 35

  • :railway_track: Demo.WarrenLaneInBore — six beats tile a route of at least 280 m, the walkway lies on the
    cave floor at twelve stations, no step along it is taller than a character can climb, and
    IOC.ClearAllDemos leaves nothing behind.
  • :locked: Demo.WarrenRouteSealed — from head height over the walkway, no ray reaches the void except
    out of the entrance.
  • :performing_arts: Demo.WarrenBeats — each scripted moment fires once, in route order; the way forward is as
    clear after the collapse as before it; the dying light ends at zero; the alcove opens behind its
    trigger.
  • :pick: Demo.WarrenPlug (PIE) — a click at the plug carves the Hollow, carving through opens a
    character-sized way on, no other cave in the level accepts a carve, and a character walks
    from the end of the walkway through the carved plug and 5 m beyond, with real movement input.
  • :new_moon: Demo.WarrenDarkness — at most four placed lights, none of them a key light, sun and sky
    turned down, and the character’s flashlight lit.
  • :rock: Demo.WarrenRock — each of the six caves renders its own rock set through M_IOC_WarrenRock;
    colour maps are sRGB with roughness in alpha, normal maps are linear normal maps.
  • :stopwatch: Demo.WarrenBudget — walkable within 3 s (measured 0.6 s).
  • :hole: Cave.PresetWarren — the preset is tighter and more warped than the wide default, with a
    voxel fine enough to resolve it.
  • :rock: Content.RockStyles — every shared rock style is a 2048² pair (sRGB colour that keeps its
    roughness alpha, and a normal map that is not sRGB); both cave materials take world-space normals
    and expose their style parameters; MI_IOC_CaveWalls wears obsidian with its normal map; and a
    style swap moves the normal map with the colour.
  • :world_map: Content.PropAtlases — the three prop atlases are 2048² with the same colour/normal rules, and
    every prop is UV-mapped into its atlas and wears an M_IOC_Prop instance sampling its family’s maps.
  • :light_bulb: SetupWizard.KeepsLevelLighting — in a lit level, Set up lighting adds no second directional
    light, sky light or fog, and a test run leaves your saved wizard settings untouched.
  • :window: SetupWizard.OwnedByEditor — the wizard window is a child of the editor’s main window (needs a
    rendering editor; skipped in a headless run).
  • :white_check_mark: SetupWizard.FinishMessage — after setup the Finish page does not also say no cave was generated,
    and with no setup done (never run, or undone) no badge describes one.
  • :triangular_ruler: SetupWizard.LiveLayout — opens the real wizard window and measures what the editor drew: at the
    default size no text on a style card is narrower than it needs, and widened, the banner keeps its
    height-to-width ratio (needs a rendering editor; skipped in a headless run).
  • :plus: Extended: Production.GenerationBudget checks that the refusal names the voxel budget;
    Demo.DemoMap covers three shipped maps, Content.ScatterMeshLibrary thirteen
    props, Content.MaterialRenderFlags both new materials, Content.ShippedDocumentation the
    guide’s new section, and the wizard’s sweeps the new command, map and button.