diff --git a/Source/Editor/Managed/ManagedEditor.Internal.cpp b/Source/Editor/Managed/ManagedEditor.Internal.cpp index b2867c2df..31295253f 100644 --- a/Source/Editor/Managed/ManagedEditor.Internal.cpp +++ b/Source/Editor/Managed/ManagedEditor.Internal.cpp @@ -602,3 +602,13 @@ bool ManagedEditor::CreateAsset(const String& tag, String outputPath) FileSystem::NormalizePath(outputPath); return AssetsImportingManager::Create(tag, outputPath); } + +Array ManagedEditor::GetAssetReferences(const Guid& assetId) +{ + Array result; + if (auto* asset = Content::Load(assetId)) + { + asset->GetReferences(result); + } + return result; +} diff --git a/Source/Editor/Managed/ManagedEditor.h b/Source/Editor/Managed/ManagedEditor.h index 5c7907d17..eb1cceef8 100644 --- a/Source/Editor/Managed/ManagedEditor.h +++ b/Source/Editor/Managed/ManagedEditor.h @@ -218,6 +218,13 @@ public: /// Output asset path. API_FUNCTION() static bool CreateAsset(const String& tag, String outputPath); + /// + /// Gets a list of asset references of a given asset. + /// + /// The asset ID. + /// List of referenced assets. + API_FUNCTION() static Array GetAssetReferences(const Guid& assetId); + public: API_STRUCT(Internal, NoDefault) struct VisualScriptStackFrame { diff --git a/Source/Editor/SceneGraph/Actors/TerrainNode.cs b/Source/Editor/SceneGraph/Actors/TerrainNode.cs index 1f95981bd..099dd5347 100644 --- a/Source/Editor/SceneGraph/Actors/TerrainNode.cs +++ b/Source/Editor/SceneGraph/Actors/TerrainNode.cs @@ -1,5 +1,9 @@ // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; using FlaxEngine; namespace FlaxEditor.SceneGraph.Actors @@ -10,6 +14,15 @@ namespace FlaxEditor.SceneGraph.Actors [HideInEditor] public sealed class TerrainNode : ActorNode { + private struct RemovedTerrain + { + public Guid SceneId; + public Guid TerrainId; + public string[] Files; + } + + private static List _cleanupFiles; + /// public TerrainNode(Actor actor) : base(actor) @@ -18,5 +31,68 @@ namespace FlaxEditor.SceneGraph.Actors /// public override bool AffectsNavigation => true; + + /// + public override void Delete() + { + // Schedule terrain data files for automatic cleanup + if (_cleanupFiles == null) + { + _cleanupFiles = new List(); + Engine.RequestingExit += OnRequestingExit; + } + if (Actor is Terrain terrain) + { + var removed = new RemovedTerrain + { + SceneId = terrain.Scene?.ID ?? Guid.Empty, + TerrainId = terrain.ID, + Files = new string[4], + }; + for (int i = 0; i < terrain.PatchesCount; i++) + { + var patch = terrain.GetPatch(i); + if (patch.Heightmap) + removed.Files[0] = patch.Heightmap.Path; + if (patch.Heightfield) + removed.Files[1] = patch.Heightfield.Path; + if (patch.GetSplatmap(0)) + removed.Files[2] = patch.GetSplatmap(0).Path; + if (patch.GetSplatmap(1)) + removed.Files[3] = patch.GetSplatmap(1).Path; + } + _cleanupFiles.Add(removed); + } + + base.Delete(); + } + + void OnRequestingExit() + { + foreach (var e in _cleanupFiles) + { + try + { + // Skip removing this terrain file sif it's still referenced + var sceneReferences = Editor.GetAssetReferences(e.SceneId); + if (sceneReferences != null && sceneReferences.Contains(e.TerrainId)) + continue; + + // Delete files + foreach (var file in e.Files) + { + if (file != null && File.Exists(file)) + File.Delete(file); + } + } + catch (Exception ex) + { + Editor.LogWarning(ex); + } + } + _cleanupFiles.Clear(); + _cleanupFiles = null; + Engine.RequestingExit -= OnRequestingExit; + } } } diff --git a/Source/Engine/Terrain/TerrainPatch.cpp b/Source/Engine/Terrain/TerrainPatch.cpp index 10ce5ba6a..592c2e7f9 100644 --- a/Source/Engine/Terrain/TerrainPatch.cpp +++ b/Source/Engine/Terrain/TerrainPatch.cpp @@ -113,6 +113,11 @@ TerrainPatch::~TerrainPatch() #endif } +RawDataAsset* TerrainPatch::GetHeightfield() const +{ + return _heightfield.Get(); +} + void TerrainPatch::RemoveLightmap() { for (auto& chunk : Chunks) diff --git a/Source/Engine/Terrain/TerrainPatch.h b/Source/Engine/Terrain/TerrainPatch.h index 295f37144..05a7693fe 100644 --- a/Source/Engine/Terrain/TerrainPatch.h +++ b/Source/Engine/Terrain/TerrainPatch.h @@ -149,6 +149,12 @@ public: return GetChunk(z * Terrain::ChunksCountEdge + x); } + /// + /// Gets the heightfield collision data asset. + /// + /// The heightfield data asset. + API_PROPERTY() RawDataAsset* GetHeightfield() const; + /// /// Gets the splatmap assigned to this patch. ///