无
重现步骤
我需要使用python脚本在unreal项目下删除某个文件夹和下面的资源文件,目前的做法是先找到所有的资源先删除,然后再删除空目录。
但是这种方法可能会导致unreal奔溃,请问这是为什么,以及是否有安全的删除文件夹的方法。
备注:在手动删除的时候,如果打开目录下的关卡会提示错误;所以我在运行脚本的时候已经确保当前打开的关卡不是该目录下的,但是还是会奔溃
备注1:以下是代码
[Image Removed]
备注2:以下是奔溃截图
[Image Removed]
您好,我试了一下您的代码,并没有出现您所说的问题。
看代码也没有什么问题,注意到您是在5.5上测试的,是否有升级5.6的计划,或者测试看一下
[Image Removed]
我重新测试了代码,发现可能是unreal认为该文件夹下的关卡还打开的原因;
虽然我在其他地方已经切换了关卡,但是可能存在延时,导致实际上在删除的时候并没有;
所以我在删除之前强制加上了切换的代码就正常了。
另外建议框架在处理这个问题的时候优化一下,给出相应的异常提示,而不是奔溃
[Image Removed]
您好,我试了一下在关卡打开情况下确实是有这个问题。
如果您的工程包含代码,可以在Module Startup的时候添加一个 FEditorDelegates::OnAssetsCanDelete,在里面调用ContainsWorldInUse
这样就会在删除前进行检测
这份代码会导致内存爆满,机器卡死,而且最终还没有删除成功,不知道是不是使用的问题,以下是我的代码;
我想达到的目的是删除文件夹和下面的资源,而不只是让unreal不奔溃。。
bool ContainsWorldInUse(const TArray< UObject* >& ObjectsToDelete)
{
TArray<const UWorld*> WorldsToDelete;
for (const UObject* ObjectToDelete : ObjectsToDelete)
{
if (const UWorld\* World \= Cast\<UWorld\>(ObjectToDelete))
{
WorldsToDelete.AddUnique(World);
}
}
if (WorldsToDelete.Num() == 0)
{
return false;
}
auto GetCombinedWorldNames = (const TArray<const UWorld*>& Worlds) -> FString
{
return FString::JoinBy(Worlds, TEXT(", "),
\[](const UWorld\* World) \-\> FString
{
return World\-\>GetPathName();
});
};
//UE_LOG(LogAssetAnalyzer, Log, TEXT(“Deleting %d worlds: %s”), WorldsToDelete.Num(), *GetCombinedWorldNames(WorldsToDelete));
TArray<const UWorld*> ActiveWorlds;
for (const FWorldContext& WorldContext : GEditor->GetWorldContexts())
{
if (const UWorld\* World \= WorldContext.World())
{
ActiveWorlds.AddUnique(World);
for (const ULevelStreaming\* StreamingLevel : World\-\>GetStreamingLevels())
{
if (StreamingLevel \&\& StreamingLevel\-\>GetLoadedLevel() \&\& StreamingLevel\-\>GetLoadedLevel()\-\>GetOuter())
{
if (const UWorld\* StreamingWorld \= Cast\<UWorld\>(StreamingLevel\-\>GetLoadedLevel()\-\>GetOuter()))
{
ActiveWorlds.AddUnique(StreamingWorld);
}
}
}
}
}
//UE_LOG(LogAssetAnalyzer, Log, TEXT(“Currently %d active worlds: %s”), ActiveWorlds.Num(), *GetCombinedWorldNames(ActiveWorlds));
for (const UWorld* World : WorldsToDelete)
{
if (ActiveWorlds.Contains(World))
{
return true;
}
}
return false;
}
void FAssetAnalyzerModule::OnAssetsCanDelete(const TArray<UObject*>& Assets /*InObjectToDelete*/, FCanDeleteAssetResult& result)
{
// 保证 CanDelete 长度和 Assets 一致
for (int32 i = 0; i < Assets.Num(); ++i)
{
bool bInUse \= false;
if (const UWorld\* World \= Cast\<UWorld\>(Assets\[i]))
{
bInUse \= ContainsWorldInUse({ Assets\[i] });
result.Set(!bInUse);
}
}
}
void FAssetAnalyzerModule::StartupModule()
{
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
FEditorDelegates::OnAssetPostImport.AddRaw(this, &FAssetAnalyzerModule::OnAssetPostImport);
FEditorDelegates::OnAssetsCanDelete.AddRaw(this, &FAssetAnalyzerModule::OnAssetsCanDelete);
}
这个函数改成这样,我这边是正常的
void FAssetAnalyzerModule::OnAssetsCanDelete(const TArray<UObject*>& Assets, FCanDeleteAssetResult& result)
{
result.Set(!ContainsWorldInUse(Assets));
}
其实您前面的脚本里已经做了切换一个地图的操作,已经可以实现这个需求了
其实代码里是有处理 【删除正在使用的地图】的一些相关逻辑代码的,但是目前失效了,我给相关的同事提一下
跟了一下代码,ShownObjectsToDelete里面的对象在打开临时地图的时候已经被GC了,所以出错了
如果你们使用的是源码版本引擎可以按照下面修改一下,这个问题应该要等到5.8才能修复
否则只能先通过OnAssetsCanDelete先跳过
[Image Removed]
好的,我先用切换关卡的办法处理这个问题,不在C++里修改了。
感谢耐心解答。