TerraDyne is a landscape plugin that unifies Runtime Terrain Sculpting with Real-Time Physics using a modern, unified architecture that moves away from legacy methods.
It started as an unassuming GitHub repo, and slowly built from there, with some help from the great OSS community. The 0.1 open-source version is still available there with 3 separate branches, but it only contains up to 15% of the present Fab version's functionality, which is being regularly updated.
UE 5.7 version is recommended over older versions: it's the version I develop on and the first to get updates.
TerraDyne currently features the following:
1. True Runtime Plasticity:
Unlike standard Unreal Landscapes, TerraDyne allows for real-time structural changes (sculpting, craters, tectonic shifts) during gameplay.
It successfully integrates a hybrid CPU/GPU pipeline, using Compute Shaders/Render Targets (HeightRT, SculptRT) for fast deformation and UDynamicMeshComponent for rendering.
2. "Live Takeover" Workflow:
The system can sample existing Landscape actors into its own data structures (16-bit precision), allowing developers to design in the editor and convert to TerraDyne for runtime interactivity without data loss.
3. Visual & Physical Parity:
It solves the complex problem of aligning visual meshes with physics collision at runtime.
4. Integrated Tooling:
It provides a standalone Runtime GUI (Slate-based STerraDynePanel) with GPU telemetry, proving it works as a "game-ready" tool, not just an editor plugin.
Includes a "Zero-Configuration" wizard (TerraDyneSceneSetup) for instant usability.
Root cause: single render target couldn't be read and written in the same Canvas draw pass
Added HeightRT_Swap for ping-pong rendering — material reads PrevHeight from current RT, draws to swap RT, pointers are swapped after each stroke
Added self-validation on startup: uploads CPU height data to RT, reads it back, spot-checks 16 samples (tolerance 0.01). Falls back to CPU automatically if validation fails or M_HeightBrush material is missing
Fixed RT upload to copy row-by-row respecting GPU row pitch (Stride from LockTexture2D), preventing corruption on GPUs with padded row alignment
Added FlushRenderingCommands() after RT upload in LoadFromData() to prevent stale pointer if chunk is immediately streamed out
Initialized HeightRT_Swap = nullptr in constructor for consistency
Was a non-functional stub that always returned true
Now performs grid-based triangle lookup: computes cell from mesh bounds and resolution, checks MaterialID on both triangles at that cell (non-zero = hole = not traceable)
Added mesh layout safety check: validates triangle count matches expected grid before using computed indices
Fixed const qualifier on GetMaterialID() return (const mesh in ProcessMesh lambda)
Was using GetFirstPlayerController() only — single player drove all chunk streaming
Tick() now iterates all player controllers via GetPlayerControllerIterator() to gather positions
UpdateStreaming() accepts TArray<FVector> and computes the union of all player load regions (diamond-shaped per player)
Chunks unload only when outside ALL players' unload radius (prevents one player unloading another's nearby chunks)
ProcessStreamingQueues() sorts by minimum Manhattan distance to nearest player (loads nearest first, unloads farthest first)
LOD updates use nearest player per chunk instead of first player globally
Replaced LastStreamingCenter (single FIntPoint) with LastStreamingHash (uint32 hash of all player chunk coords) for movement detection
Additional Defects Fixed
bMaterialsLoaded dead code (Manager.h/cpp): field was declared but never set. Now guards LoadMaterials() with early return and set to true at end, preventing redundant material loading on hot-reload
LODTimer first-frame fire (Manager.h): was initialized to 0.0f, causing streaming update with zero position on frame 1. Now initialized to 0.25f
GetWeightDataFast signature (Baker.cpp): was passing TArray<uint8> by value instead of pointer — would not compile
March 7 — Settings & Showcase Polish
Settings Expansion (TerraDyneSettings.h/cpp)
Corrected MasterMaterialPath default: removed VHFM/ subdirectory prefix from path
Added GrassDebounceTime setting (0.05s min, 0.5s default) — delay before regenerating grass after sculpt/paint edits
Added Streaming settings category:
ChunkLoadRadius (1-20, default 5) — diamond-shaped load region in chunk units
MaxChunkOpsPerTick (1-8, default 2) — throttles chunk spawn/teardown per tick
GridExtent (1-50, default 10) — half-width of world grid (-N..+N)
ChunkSaveDir (default TerraDyne/ChunkCache) — subdirectory for per-chunk cache files
Added Undo/Redo settings:
MaxUndoHistory (1-100, default 20) — max undo entries per player
Added Multiplayer settings:
MaxBrushRPCsPerSecond (1-120, default 30) — server-side rate limit per player
MaxBrushRadius (100+, default 10000) — max accepted brush radius
MaxBrushStrength (0+, default 5000) — max accepted brush strength
Grass Demo Fix (TerraDyneOrchestrator.cpp)
Removed MaterialOverride assignment from MWAM grass varieties in UpdateGrassDemo()
MWAM grass meshes (SMMWAM_GrassA-D) have their own embedded green materials — applying MTL_MWAMPlantsGrass as override was redundant and could conflict
Notification System: New UTerraDyneSubsystem::ShowNotification() with Info/Warning/Error severities, Slate toasts in editor, on-screen messages at runtime, and a bShowRuntimeNotifications setting for users to opt out at runtime.
Brush Preview Decal:ATerraDyneEditController now projects a live decal at the cursor showing the brush radius and tool mode (blue for sculpt, orange for paint).
Chunk Debug Overlay: New bShowDebugOverlay on the manager, color-coded by chunk state (green=loaded, yellow=loading, red=unloading, cyan=imported), wired to a toggle button on STerraDynePanel.
Marketplace Documentation:Docs/QuickStart.md, Docs/API.md, and Docs/ExampleBlueprints.md now ship with the plugin.
Asset Automation Scripts:Content/Scripts/CreateBrushPreviewMaterial.py, CreateDemoMap.py, and CreateExampleBlueprints.py create the supporting assets without manual editor work.
Changed
Error Reporting: Critical failure points (material load, chunk spawn, save/load, landscape import, cache write, buffer mismatch) now surface to the user via ShowNotification instead of log-only.
Input Validation:ATerraDyneEditController validates the TerraDyneClick input action at startup and shows an actionable error toast if missing.
Logging Hygiene: All LogTemp calls replaced with LogTerraDyne (runtime) or LogTerraDyneEditor (editor) — zero LogTemp references remain in plugin source.
Settings Tooltips: Every UTerraDyneSettings property in the Asset Paths and Defaults categories now exposes a tooltip in the project settings details panel.
Setup Wizard:Initialize World now dismisses its tab on success so it can’t be re-clicked indefinitely.
Platform Support:.uplugin runtime module now lists Linux and Mac alongside Win64 (editor module remains Win64-only).
Fixed
Setup Wizard:Initialize World button now dismisses the wizard tab on success — previously it could be re-clicked indefinitely.
Runtime Grass Blade Mesh: Material slot is now registered before BuildFromStaticMeshDescriptions, fixing a UVChannelData.bInitialized ensure() that fired during showcase startup.
Verified
Automation:Automation RunTests TerraDyne passes with 21/21 TerraDyne tests.
[0.2.0] - 2026-04-05
Added
Authored World Conversion: GitHub now includes the verified landscape migration path with paint layer capture, placed foliage transfer, and actor foliage transfer.
Persistent Runtime World: Terrain save/load, replicated chunk sync, persistent runtime actors, destruction state, harvest/regrowth flow, and runtime placement are part of the public release.
Procedural Extension: Seeded outskirts, biome overlays, runtime spawn rules, optional edge growth, and PCG-ready point export are now included.
Gameplay Hooks: Blueprint-callable biome queries, AI spawn zones, build-permission checks, navmesh dirtying, and terrain/foliage/population change events are exposed from the manager.
Designer Workflow: World presets, scene templates, showcase automation, and packaged docs now ship with the plugin.
Changed
Public Positioning: TerraDyne 0.3 is now presented as a persistent runtime world framework for survival, sandbox, and open-world games built on Unreal Landscapes.
Play Mode Tool UI Switch: Added Enable Play Mode Tool UI on ATerraDyneEditController so gameplay maps can disable the TerraDyne runtime widget safely.
Changed
Edit Controller Safety: Disabling the play mode tool UI now removes the TerraDyne widget, restores GameOnly input, hides the cursor and brush decal, and blocks sculpt/undo/redo and related edit RPC paths so invisible edit mode cannot remain active during play.
Fixed
Landscape Conversion Coverage: Authored World Conversion now resolves the full landscape through ULandscapeInfo and imports all loaded landscape components instead of only the selected ALandscapeProxy, which fixes partial or empty imports on partitioned landscapes and streaming-proxy setups.
Landscape Import Diagnostics: Conversion now surfaces explicit user-facing errors when the selected landscape has no loaded components or when no TerraDyne chunks were created from the import.
Landscape Material Adoption Safety:Adopt Landscape Material As Master Material now refuses landscape materials that use landscape-only material expressions and keeps the existing TerraDyne chunk material instead of applying an incompatible graph.
Source Landscape Hiding:Hide Source Landscape now hides the full landscape proxy hierarchy instead of only the selected source actor.
Fab Startup Crash: TerraDyne now verifies the plugin shader directory before registering /Plugin/TerraDyne, preventing the RenderCore DirectoryExists assertion when a packaged install is missing Shaders/.
Marketplace Packaging Gate: Added a release validator and automation coverage for Shaders/TerraDyneSimulation.usf so the required RDG shader payload cannot be omitted silently.
Play Mode Tool UI Switch: Added Enable Play Mode Tool UI on ATerraDyneEditController so gameplay maps can disable the TerraDyne runtime widget safely.
PIE Controller Automation: Added a dedicated PIE automation harness that boots a real ATerraDyneEditController with bEnablePlayModeToolUI=false and asserts the no-UI branch end to end.
External QA Landscape Import Prep: Added repo-root tools/ImportFreeLandscape.ps1, tools/import_free_landscape.py, and tools/ImportFreeLandscape.md to fetch the latest public-domain USGS 3DEP 1/3-arc-second DEM for a curated profile, crop it, resample it to a UE-friendly resolution, export a 16-bit heightmap, and emit a manifest with exact Landscape import scales and source traceability.
Versioned Real-Map Fixture Output: External landscape prep now writes a reproducible package under Saved/ExternalLandscapes/... containing the cached source GeoTIFF, a preview image, the processed heightmap, raw TNMAccess metadata, and the Unreal import manifest so authored-world conversion QA can use real terrain without shipping source maps in the plugin payload.
Changed
Edit Controller Safety: Disabling the play mode tool UI now removes the TerraDyne widget, restores GameOnly input, hides the cursor and brush decal, and blocks sculpt/undo/redo and related edit RPC paths so invisible edit mode cannot remain active during play.
Chunk Material Initialization:ATerraDyneManager now assigns BrushMaterialBase when registering chunks and when applying materials to active chunks, allowing chunks created before manager material initialization to participate in the GPU brush path once compatible materials are available.
External Import Source Selection: The free-landscape import tool now selects only TNMAccess products that fully contain the configured crop bounds, retries transient Windows file-lock failures when finalizing downloads, and records the exact USGS tile revision used for each generated fixture.
Fixed
Disabled-UI Input Leak:ATerraDyneEditController no longer validates or binds TerraDyne edit input actions when play mode tool UI is disabled, so gameplay-mode PIE sessions do not emit false missing-input errors.
Showcase Population Mobility: TerraDyne now normalizes persistent/runtime-placed actors to Movable before transform and mesh assignment, eliminating live showcase mobility warnings and SetStaticMesh-while-static warnings during runtime validation.
Population Mesh Binding Duplication: Removed the redundant SetStaticMesh application in the persistent population spawn path.
UE 5.7 GPU Terrain Startup:ATerraDyneChunk no longer seeds the height render target by writing render-target memory directly. Height data is now uploaded through a transient PF_FloatRGBA texture and blitted into the render target through UCanvas, matching UE 5.7 render-target lifecycle expectations and restoring the GPU-backed chunk path.
GPU Validation Readback: Height render-target validation now uses float readback plus vertical-orientation detection, preventing false GPU fallback caused by readback ordering differences during startup validation.
Transient Texture Naming Noise: Height-upload and weightmap helper textures now use unique transient object names, removing generic overwrite warnings during repeated editor/runtime validation.
Landscape Conversion Coverage: Authored World Conversion now resolves the full landscape through ULandscapeInfo and imports all loaded landscape components instead of only the selected ALandscapeProxy, which fixes partial or empty imports on partitioned landscapes and streaming-proxy setups.
Landscape Import Diagnostics: Conversion now surfaces explicit user-facing errors when the selected landscape has no loaded components or when no TerraDyne chunks were created from the import.
Landscape Material Adoption Safety:Adopt Landscape Material As Master Material now refuses landscape materials that use landscape-only material expressions and keeps the existing TerraDyne chunk material instead of applying an incompatible graph.
Source Landscape Hiding:Hide Source Landscape now hides the full landscape proxy hierarchy instead of only the selected source actor.
Verified
Automation Coverage:Automation RunTests TerraDyne passes with 23/23 TerraDyne tests on UE 5.7 after the runtime warning cleanup and GPU terrain-path fixes.
Render Path Validation:TerraDyne.Rendering.MaterialBindings now reaches Chunk [0,0]: Ready (GPU: YES) instead of disabling GPU after render-target validation.
Live Showcase Smoke:/TerraDyne/Maps/DemoMap_Showcase now completes live smoke validation with zero render-target validation warnings, zero mobility warnings, and zero static-mesh mobility warnings while streamed chunks initialize on the GPU path.
Real-Map Fixture Generation: The external import tool successfully generated a Crater Lake package from USGS 1/3 Arc Second n43w123 20260202, including a 2017x2017 Unreal-ready heightmap and exact recommended import scales of X=886.9353, Y=881.6758, Z=229.7515 centimeters.
Packaged First-Run Samples: Added self-contained TerraDyne sample content under /TerraDyne/Samples, including M_TerraDyne_GrassSample, SM_TerraDyne_GrassA/B/C, DA_TerraDyne_ShowcaseGrass, and DA_TerraDyne_ShowcaseWorld.
Survival Integration Example: Added ATerraDyneSurvivalIntegrationExample plus /TerraDyne/Examples/BP_TerraDyne_SurvivalSetup to show a small game-facing setup path that finds or spawns a manager, applies the packaged world preset and grass profile, enables streaming/procedural defaults, and exposes a Blueprint event when the world is ready.
PCG Integration Example: Added ATerraDynePCGIntegrationExample plus /TerraDyne/Examples/BP_TerraDyne_PCGExporter to demonstrate chunk seed-point export for PCG graphs and Blueprint consumers.
Replication Integration Example: Added ATerraDyneReplicationIntegrationExample plus /TerraDyne/Examples/BP_TerraDyne_ReplicationBridge to demonstrate authoritative terrain edit routing, undo-stroke wrapping, multicast brush application, and full terrain sync requests for owned multiplayer actors.
Example Blueprint Automation:Content/Scripts/CreateExampleBlueprints.py now creates or preserves the three first-run example Blueprints under /TerraDyne/Examples and reruns cleanly without reparenting noise.
Showcase Sample Automation: Added sample-asset generation for the packaged grass meshes, grass material, showcase grass profile, and showcase world preset so the demo no longer depends on missing or project-local placeholder assets.
Changed
First-Run Wizard Defaults: The setup wizard now opens on Survival Framework (Recommended First Run), lists it first, and explains that it applies packaged sample presets, grass profiles, biome overlays, AI zones, build zones, streaming defaults, lighting, manager, and orchestrator setup.
Scene Setup Defaults:ATerraDyneSceneSetup now defaults to SurvivalFramework and applies /TerraDyne/Samples/Presets/DA_TerraDyne_ShowcaseWorld and /TerraDyne/Samples/Profiles/DA_TerraDyne_ShowcaseGrass when no project-specific preset or grass profile has been assigned.
Demo Map Self-Containment:CreateDemoMap.py and ATerraDyneOrchestrator now prefer packaged TerraDyne sample presets, profiles, grass meshes, and materials, with legacy project assets used only as fallback.
Showcase Messaging: Scene setup logging now distinguishes the cinematic Full Feature Showcase from general first-run world initialization, avoiding misleading “showcase ready” messaging for non-showcase templates.
Fixed
Missing Sample Meshes: Added back packaged grass mesh assets and bound them through the sample grass profile so first-run maps and the showcase can spawn foliage without missing-asset warnings.
Demo Map Warning Baseline:/TerraDyne/Maps/DemoMap_Showcase now loads with the packaged profile, preset, and sample meshes and stays clear of TerraDyne/map diagnostics during live validation.
Blueprint Example Regeneration: Re-running the example Blueprint creation script no longer emits warnings for already-existing example assets.
Disabled-UI Input Leak:ATerraDyneEditController no longer validates or binds TerraDyne edit input actions when play mode tool UI is disabled, so gameplay-mode PIE sessions do not emit false missing-input errors.
Showcase Population Mobility: TerraDyne now normalizes persistent/runtime-placed actors to Movable before transform and mesh assignment, eliminating live showcase mobility warnings and SetStaticMesh-while-static warnings during runtime validation.
Verified
Automation Coverage:Automation RunTests TerraDyne passes with 23/23 TerraDyne tests on UE 5.7 after the runtime warning cleanup, GPU terrain-path fixes, sample asset checks, first-run default checks, and integration example class checks.
Blueprint Asset Generation:CreateExampleBlueprints.py completes with 0 error(s), 0 warning(s) after the survival, PCG, and replication examples are present.
Runtime Authored-World Asset Set: Added UTerraDyneLandscapeAssetSet, a packaged-build-safe authored-world payload that stores migration metadata, an optional adopted master material, and the baked TerraDyne tile set for a converted Landscape.
Runtime Bootstrap API: Added ATerraDyneManager::InitializeFromBakedLandscapeAssetSet() so Blueprint and C++ callers can initialize TerraDyne directly from baked authored-world data without any editor-only Landscape import path.
Tile Runtime Payload Reconstruction:UTerraDyneTileData now exposes BuildChunkData() and persists the foliage/runtime payload required to reconstruct transferred static and actor foliage when booting from baked authored-world assets.
Async Mesh Apply Budget Controls: Added MaxMeshBuildAppliesPerFrame and MaxCollisionUpdatesPerFrame to UTerraDyneSettings so teams can tune how aggressively chunk mesh and collision work is applied back onto the game thread.
Setup Wizard Runtime Data Controls: The setup wizard now exposes a baked Landscape asset-set picker, baked-output folder selection, and an explicit live-import fallback toggle for authored-world conversion.
Changed
Unified Authored Conversion Workflow: The setup wizard is now the only authored-world conversion entry point. It bakes runtime-safe authored-world data and initializes TerraDyne from that same payload instead of maintaining a separate conversion panel or tile-only bake workflow.
Packaged Runtime Initialization:ATerraDyneSceneSetup now prefers baked authored-world data by default through AuthoredWorldAssetSet and bPreferBakedLandscapeData, allowing authored-world conversion to work in packaged builds instead of relying on WITH_EDITOR-only initialization.
Landscape Baking Pipeline:UTerraDyneBaker::BakeLandscapeToAssetSet() now resolves the full Landscape group, captures migration metadata, layer mappings, adopted-material compatibility, and transferred foliage payload, and saves a runtime-safe asset set plus normalized TerraDyne tile assets.
Chunk Rebuild Scheduling: Height edits and chunk loads now stage mesh-surface computation off-thread and throttle how many mesh/collision applies can land on the game thread per frame, reducing the worst terrain-edit hitch path.
Documentation:docs/QuickStart.md now describes the baked authored-world workflow as the primary path and position live Landscape import as an editor-only fallback.
Fixed
GPU Brush Simulation Gap:Shaders/TerraDyneSimulation.usf is no longer a pass-through writeback. The compute path now performs raise, lower, flatten, and smooth brush operations and writes the modified height result into the swap render target.
Authored-World Runtime Init Gap: TerraDyne no longer depends on the editor wizard/live Landscape import path to bootstrap authored worlds at runtime; baked asset sets can now initialize managers in packaged builds.
Game-Thread Rebuild Bottleneck: Chunk mesh and collision rebuilds no longer force the full terrain-surface recompute path synchronously on the game thread during normal deformation/load flow.
Landscape Height Bake Scaling: Baked Landscape Z scale is now captured using the correct full-height conversion, preventing authored-world imports from using the older under-scaled height interpretation.
Conversion UX Failure Cases: Authored-world conversion now hard-fails with explicit notifications when no valid source Landscape is available for live import or when baking the runtime asset set fails.
Removed
Obsolete Conversion UI: Removed the legacy STerraDyneTools conversion panel and the redundant TerraDyne Conversion Wizard menu/tab path.
Retired Tile-Only Bake API: Removed the deprecated UTerraDyneBaker::BakeLandscapeToAssets() compatibility workflow so the baked asset-set path is now the single authored-world bake surface.
Dead Editor Wiring: Removed unused editor-module members, unused setup-wizard initial-template plumbing, stale editor-only includes, and the extra WorkspaceMenuStructure dependency that no longer served the unified workflow.
I am working on showcase videos that finally do justice to what this plugin is capable of.
A tutorial video is also a must.
Added
UE 5.8 support
Reusable Replication Component: Added UTerraDyneReplicationComponent, which can be attached to any project PlayerController and no longer requires replacing the project’s controller with ATerraDyneEditController.
Bounded State Transport: Chunk state is now validated, Zlib-compressed, CRC-protected, split into configurable fragments capped at 48 KiB, throttled per connection, reassembled with timeouts, and bounded by compressed/uncompressed/in-flight byte limits.
Project-Owned Persistence API: Added GetActiveChunkCoordinates, ExportChunkStatePacket, and ImportChunkStatePacket so database-backed games can store TerraDyne state without using local SaveGame/cache ownership.
Gameplay Authorization API: Added ApplyAuthorizedBrush as the server-owned integration surface for craters, digging, construction, and other gameplay-approved deformation.
Production Settings: Added configurable replication radius, transfer budgets, request rates, collision profile/object channel, GPU enablement, async cache writes, and navigation dirty-area coalescing.
Explicit Client/Server Demo Targets: Added TerraDyneClient.Target.cs and TerraDyneServer.Target.cs for source-distribution validation where the installed engine includes those target types.
Production Automation: Added codec round-trip, integrity/limit, and safe-default tests under TerraDyne.Production.
Changed
Safe Multiplayer Defaults: The manager is no longer always relevant by default. Brush events and authoritative corrections are routed through relevant connection-owned components. Remote terrain editing is opt-in on the built-in controller and has a Blueprint authorization hook.
Server RPC Validation: Remote brushes now enforce finite values, enum/layer validity, request rate, maximum radius/strength, owner distance, affected-chunk budget, stroke ordering, and flatten-height delta.
Dedicated-Server Runtime: Removed the unused VirtualHeightfieldMesh dependency. Headless runtimes no longer allocate weight textures, height render targets, upload textures, lighting, or material instances; CPU height/collision remains available.
Persistence: Dirty chunk cache files now use a versioned/CRC-checked format, atomic replacement, asynchronous compression/write, in-memory state until success, retry scheduling, and transparent legacy-cache migration. SaveWorld now uses Unreal’s asynchronous save API and serializes an explicit schema version.
Navigation: Overlapping dirty areas are coalesced and debounced instead of submitting one full chunk navigation update per brush event.
Collision: Generated chunks use project-configurable collision profile and object channel rather than hard-coded WorldStatic/BlockAll behavior.
Authored Baking: Component heights are read through FLandscapeEditDataInterface, respecting shared heightmap atlas subregions. Asset-set tiles now use one canonical four-channel layer mapping.
Integration Example: Client RPCs in the replication example are disabled by default, ignore client-supplied controller references, enforce owner distance/cooldown, use ApplyAuthorizedBrush, and support any controller carrying the replication component.
Fixed
Oversized Chunk RPCs: Removed internal use of full FTerraDyneChunkData RPC parameters, which exceeded Unreal’s default 64 KiB constructed-bunch limit at normal resolution.
Global Edit Broadcast: Removed high-frequency NetMulticast terrain edits from the always-relevant manager path.
Unvalidated Terrain Editing: The built-in controller no longer accepts unrestricted client terrain writes.
Cache Corruption Detection: New cache/network packets reject unsupported versions, inconsistent arrays, invalid sizes, coordinate mismatches, decompression failures, and CRC mismatches.
Landscape Atlas Bake: Baking no longer treats an entire shared heightmap texture as one component.
Per-Component Paint Remapping: RGBA meanings no longer change when component layer allocation order differs.
Visibility-Hole Data Loss: Authored conversion now stops with a clear error when Landscape visibility holes are present instead of silently filling them.
NullRHI Startup: Shader source mapping remains available to commandlets while chunk GPU resource creation stays disabled on headless runtimes.
Breaking / Migration Notes
Multicast_ApplyBrush and Multicast_SyncChunkState retain their names for source/Blueprint compatibility but are no longer NetMulticast RPCs; they route through UTerraDyneReplicationComponent.
Projects using a custom PlayerController must add a replicated UTerraDyneReplicationComponent to receive TerraDyne edits/state.
ATerraDyneEditController::bAllowRemoteTerrainEditing defaults to false. Explicitly enable it only on an authorized controller subclass and preferably override IsRemoteTerrainEditAuthorized.
Cache files are migrated on read. World SaveGame objects carry format version 2 while legacy version-zero saves remain loadable.
Landscape visibility holes remain unsupported topology in 0.6; conversion now fails safely by default.
Verified
The full suite passes 30/30 tests under UnrealEditor-Cmd -NullRHI (27 clean and 3 with expected diagnostic warnings).
The full render-capable suite passes 31/31 tests under D3D12 SM6 on an NVIDIA GeForce RTX 5060 Ti, including GPU brush synchronization and material bindings.
A fix & augmentation pass that follows the major 0.5.0 update.
Fixed
Substrate Rendering & Paint Alignment: Generated materials now connect the automatically created Substrate converter, and terrain state textures use chunk-normalized UVs so paint appears at the brush location.
Demo Lighting & Camera: Demo generation now sets the sun rotation with named Python fields and adds a movable skylight. Showcase camera moves also update the player controller’s view rotation.
Showcase Undo/Redo & UI: The default-controller editing fallback now records complete strokes and only edits authoritative terrain hits. The native panel and showcase use the current plugin version and no longer probe a missing fallback widget asset.
Redundant Grass Rebuilds: Unchanged showcase grass profiles no longer force every nearby chunk to rebuild foliage between phases; changed profile settings still refresh affected chunks.
Grass Placement: Grass instances are now added in batches with collision and navigation disabled. Async varieties arriving out of order retain their own meshes.
Chunk Initialization: Direct initialization and BeginPlay now allocate all height and paint buffers, initialize rendering resources when available, and schedule mesh/collision updates. Reinitialization clears previous edits.
Async Mesh Ownership: Results now return to the exact requesting actor through a weak reference. Standalone chunks no longer stall without a manager, and streamed replacement chunks cannot receive a previous actor’s mesh result.
Height Texture Import: Import now resamples differing mip dimensions after buffer initialization and preserves authored values instead of overwriting them with procedural noise.
Paint Data: Paint textures now use linear RGBA data; loading legacy saves without paint data clears previous paint.
Save/Network Validation: Decoders validate array and nested string lengths before allocation, including legacy caches. Legacy trailing data, non-finite foliage offsets, invalid transforms, and inconsistent foliage definitions are rejected. Failed encoding clears the output packet.
State Transfers: Transfers reject impossible fragment counts, conflicting duplicates, and partial transfers exceeding their declared byte budget. Sender fragment sizes are independent of receiver configuration. New state removes older pending snapshots before application.
Asset Compatibility: Rebuilt ten new material/texture assets in UE 5.5, using plugin-local references and a reproducible asset generator. Existing valid materials are preserved when generators rerun.
Demo Asset Selection: Demo generation now selects the runtime master and brush materials and resolves Engine classes without probing nonexistent plugin classes.
Authored Landscape Height Scale: Baked tiles and editor live import now use the exact Landscape height range (65535 / 128 per unit of Z scale) instead of 512. The previous value raised converted terrain by up to ScaleZ / 128 cm; the validation fixture measured 0.31 cm at scale Z 75.
Baked Foliage Cooking: Baked tiles now record soft cook dependencies for transferred foliage meshes, override materials, and actor classes. Cooking only the baked asset directory previously omitted project-owned foliage assets, so packaged games could not restore them.
Changed
Packaging: Consolidated packaging: no source descriptor mutations, source-owned release metadata, explicit UE 5.8 selection, recursive file filters, and generated-cache exclusion.
Added
Regression Coverage: Added checks for direct initialization, source-height resampling, legacy paint reset, malformed current/legacy packets, Unicode foliage paths, output contracts, partial-transfer budgets, and out-of-order fragment assembly.
Grass Batch Regression: Added coverage for 1,024 world-space transforms, out-of-order mesh selection, replacement/empty batches, and decorative grass collision/navigation settings.
Development Guide: Added development and asset-generation instructions in Docs/Development.md.
Verified
UE 5.5.4, 5.6.1, 5.7.4, 5.8.2 Win64: The final Development Editor build and D3D12 automation suite pass 39/39 tests, with zero failures or incomplete tests. Four tests emit expected diagnostic warnings. All on MSVC 14.44.
Live Showcase: Native Play completes all 14 stages in the editor, including saving and restoring 83 chunks in the final run.
Mouse Editing: Native sculpt/paint strokes and Undo/Redo pass checks across 1,089 sampled terrain points. Undo/Redo restores sampled heights and weights exactly.
Save/Load Precision: Loading the 61-chunk manual edit save restores sampled heights exactly; maximum paint error is 0.001524, within the 8-bit storage tolerance.
Material Persistence: The corrected material graph survives an editor restart with no dirty content packages.