Enforce Content:CloneAssetFile() running on the main thread, to avoid a bug that occurs when a particle emitter is created from one of the templates due to the creation coming from the content thread.
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
#include "Engine/Engine/EngineService.h"
|
#include "Engine/Engine/EngineService.h"
|
||||||
#include "Engine/Platform/FileSystem.h"
|
#include "Engine/Platform/FileSystem.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
|
#include "Engine/Threading/MainThreadTask.h"
|
||||||
#include "Engine/Graphics/Graphics.h"
|
#include "Engine/Graphics/Graphics.h"
|
||||||
#include "Engine/Engine/Time.h"
|
#include "Engine/Engine/Time.h"
|
||||||
#include "Engine/Engine/Globals.h"
|
#include "Engine/Engine/Globals.h"
|
||||||
@@ -688,101 +689,135 @@ bool Content::FastTmpAssetClone(const StringView& path, String& resultPath)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Content::CloneAssetFile(const StringView& dstPath, const StringView& srcPath, const Guid& dstId)
|
class CloneAssetFileTask : public MainThreadTask
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
public:
|
||||||
ASSERT(FileSystem::AreFilePathsEqual(srcPath, dstPath) == false && dstId.IsValid());
|
StringView dstPath;
|
||||||
|
StringView srcPath;
|
||||||
|
Guid dstId;
|
||||||
|
bool* output;
|
||||||
|
|
||||||
LOG(Info, "Cloning asset \'{0}\' to \'{1}\'({2}).", srcPath, dstPath, dstId);
|
protected:
|
||||||
|
bool Run() override
|
||||||
// Check source file
|
|
||||||
if (!FileSystem::FileExists(srcPath))
|
|
||||||
{
|
{
|
||||||
LOG(Warning, "Missing source file.");
|
*output = Content::CloneAssetFile(dstPath, srcPath, dstId);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case for json resources
|
|
||||||
if (JsonStorageProxy::IsValidExtension(FileSystem::GetExtension(srcPath).ToLower()))
|
|
||||||
{
|
|
||||||
if (FileSystem::CopyFile(dstPath, srcPath))
|
|
||||||
{
|
|
||||||
LOG(Warning, "Cannot copy file to destination.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (JsonStorageProxy::ChangeId(dstPath, dstId))
|
|
||||||
{
|
|
||||||
LOG(Warning, "Cannot change asset ID.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Check if destination file is missing
|
bool Content::CloneAssetFile(const StringView& dstPath, const StringView& srcPath, const Guid& dstId)
|
||||||
if (!FileSystem::FileExists(dstPath))
|
{
|
||||||
|
// Best to run this on the main thread to avoid clone conflicts.
|
||||||
|
if (IsInMainThread())
|
||||||
{
|
{
|
||||||
// Use quick file copy
|
PROFILE_CPU();
|
||||||
if (FileSystem::CopyFile(dstPath, srcPath))
|
ASSERT(FileSystem::AreFilePathsEqual(srcPath, dstPath) == false && dstId.IsValid());
|
||||||
|
|
||||||
|
LOG(Info, "Cloning asset \'{0}\' to \'{1}\'({2}).", srcPath, dstPath, dstId);
|
||||||
|
|
||||||
|
// Check source file
|
||||||
|
if (!FileSystem::FileExists(srcPath))
|
||||||
{
|
{
|
||||||
LOG(Warning, "Cannot copy file to destination.");
|
LOG(Warning, "Missing source file.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change ID
|
// Special case for json resources
|
||||||
auto storage = ContentStorageManager::GetStorage(dstPath);
|
if (JsonStorageProxy::IsValidExtension(FileSystem::GetExtension(srcPath).ToLower()))
|
||||||
FlaxStorage::Entry e;
|
|
||||||
storage->GetEntry(0, e);
|
|
||||||
if (storage == nullptr || storage->ChangeAssetID(e, dstId))
|
|
||||||
{
|
{
|
||||||
LOG(Warning, "Cannot change asset ID.");
|
if (FileSystem::CopyFile(dstPath, srcPath))
|
||||||
return true;
|
{
|
||||||
|
LOG(Warning, "Cannot copy file to destination.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (JsonStorageProxy::ChangeId(dstPath, dstId))
|
||||||
|
{
|
||||||
|
LOG(Warning, "Cannot change asset ID.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if destination file is missing
|
||||||
|
if (!FileSystem::FileExists(dstPath))
|
||||||
|
{
|
||||||
|
// Use quick file copy
|
||||||
|
if (FileSystem::CopyFile(dstPath, srcPath))
|
||||||
|
{
|
||||||
|
LOG(Warning, "Cannot copy file to destination.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change ID
|
||||||
|
auto storage = ContentStorageManager::GetStorage(dstPath);
|
||||||
|
FlaxStorage::Entry e;
|
||||||
|
storage->GetEntry(0, e);
|
||||||
|
if (storage == nullptr || storage->ChangeAssetID(e, dstId))
|
||||||
|
{
|
||||||
|
LOG(Warning, "Cannot change asset ID.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use temporary file
|
||||||
|
String tmpPath = Globals::TemporaryFolder / Guid::New().ToString(Guid::FormatType::D);
|
||||||
|
if (FileSystem::CopyFile(tmpPath, srcPath))
|
||||||
|
{
|
||||||
|
LOG(Warning, "Cannot copy file.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change asset ID
|
||||||
|
{
|
||||||
|
auto storage = ContentStorageManager::GetStorage(tmpPath);
|
||||||
|
if (!storage)
|
||||||
|
{
|
||||||
|
LOG(Warning, "Cannot change asset ID.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
FlaxStorage::Entry e;
|
||||||
|
storage->GetEntry(0, e);
|
||||||
|
if (storage->ChangeAssetID(e, dstId))
|
||||||
|
{
|
||||||
|
LOG(Warning, "Cannot change asset ID.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock destination file
|
||||||
|
ContentStorageManager::EnsureAccess(dstPath);
|
||||||
|
|
||||||
|
// Copy temp file to the destination
|
||||||
|
if (FileSystem::CopyFile(dstPath, tmpPath))
|
||||||
|
{
|
||||||
|
LOG(Warning, "Cannot copy file to destination.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
FileSystem::DeleteFile(tmpPath);
|
||||||
|
|
||||||
|
// Reload storage
|
||||||
|
if (auto storage = ContentStorageManager::GetStorage(dstPath))
|
||||||
|
{
|
||||||
|
storage->Reload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Use temporary file
|
CloneAssetFileTask* task = New<CloneAssetFileTask>();
|
||||||
String tmpPath = Globals::TemporaryFolder / Guid::New().ToString(Guid::FormatType::D);
|
task->dstId = dstId;
|
||||||
if (FileSystem::CopyFile(tmpPath, srcPath))
|
task->dstPath = dstPath;
|
||||||
{
|
task->srcPath = srcPath;
|
||||||
LOG(Warning, "Cannot copy file.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change asset ID
|
bool result = false;
|
||||||
{
|
task->output = &result;
|
||||||
auto storage = ContentStorageManager::GetStorage(tmpPath);
|
task->Start();
|
||||||
if (!storage)
|
task->Wait();
|
||||||
{
|
|
||||||
LOG(Warning, "Cannot change asset ID.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
FlaxStorage::Entry e;
|
|
||||||
storage->GetEntry(0, e);
|
|
||||||
if (storage->ChangeAssetID(e, dstId))
|
|
||||||
{
|
|
||||||
LOG(Warning, "Cannot change asset ID.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlock destination file
|
return result;
|
||||||
ContentStorageManager::EnsureAccess(dstPath);
|
|
||||||
|
|
||||||
// Copy temp file to the destination
|
|
||||||
if (FileSystem::CopyFile(dstPath, tmpPath))
|
|
||||||
{
|
|
||||||
LOG(Warning, "Cannot copy file to destination.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
FileSystem::DeleteFile(tmpPath);
|
|
||||||
|
|
||||||
// Reload storage
|
|
||||||
if (auto storage = ContentStorageManager::GetStorage(dstPath))
|
|
||||||
{
|
|
||||||
storage->Reload();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user