Add automatic heightmap files removal on Editor shutdown for deleted terrains

#1902
This commit is contained in:
Wojtek Figat
2024-08-22 23:29:42 +02:00
parent b8cb1a828a
commit fc66738dca
5 changed files with 104 additions and 0 deletions

View File

@@ -602,3 +602,13 @@ bool ManagedEditor::CreateAsset(const String& tag, String outputPath)
FileSystem::NormalizePath(outputPath);
return AssetsImportingManager::Create(tag, outputPath);
}
Array<Guid> ManagedEditor::GetAssetReferences(const Guid& assetId)
{
Array<Guid> result;
if (auto* asset = Content::Load<Asset>(assetId))
{
asset->GetReferences(result);
}
return result;
}

View File

@@ -218,6 +218,13 @@ public:
/// <param name="outputPath">Output asset path.</param>
API_FUNCTION() static bool CreateAsset(const String& tag, String outputPath);
/// <summary>
/// Gets a list of asset references of a given asset.
/// </summary>
/// <param name="assetId">The asset ID.</param>
/// <returns>List of referenced assets.</returns>
API_FUNCTION() static Array<Guid> GetAssetReferences(const Guid& assetId);
public:
API_STRUCT(Internal, NoDefault) struct VisualScriptStackFrame
{

View File

@@ -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<RemovedTerrain> _cleanupFiles;
/// <inheritdoc />
public TerrainNode(Actor actor)
: base(actor)
@@ -18,5 +31,68 @@ namespace FlaxEditor.SceneGraph.Actors
/// <inheritdoc />
public override bool AffectsNavigation => true;
/// <inheritdoc />
public override void Delete()
{
// Schedule terrain data files for automatic cleanup
if (_cleanupFiles == null)
{
_cleanupFiles = new List<RemovedTerrain>();
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;
}
}
}

View File

@@ -113,6 +113,11 @@ TerrainPatch::~TerrainPatch()
#endif
}
RawDataAsset* TerrainPatch::GetHeightfield() const
{
return _heightfield.Get();
}
void TerrainPatch::RemoveLightmap()
{
for (auto& chunk : Chunks)

View File

@@ -149,6 +149,12 @@ public:
return GetChunk(z * Terrain::ChunksCountEdge + x);
}
/// <summary>
/// Gets the heightfield collision data asset.
/// </summary>
/// <returns>The heightfield data asset.</returns>
API_PROPERTY() RawDataAsset* GetHeightfield() const;
/// <summary>
/// Gets the splatmap assigned to this patch.
/// </summary>