#include "SampleManager.h" #include "ExecutionTime.h" #include "Misc/AronaConfig.h" FArchive& operator<<(FArchive& Ar, FSamplePathNode* In) { return *In << Ar; } FSamplePathNode* FSamplePathNode::Create(const FString& Path) { if (!FPaths::DirectoryExists(Path)) return nullptr; FSamplePathNode* Root = new FSamplePathNode(); Root->Value = Path; Root->NodeType = Type::Directory; Root->Parent = nullptr; class FSamplePathVisitor : public IPlatformFile::FDirectoryStatVisitor { public: FSamplePathVisitor(FSamplePathNode* InRoot) : Root(InRoot) { } virtual bool Visit(const TCHAR* FilenameOrDirectory, const FFileStatData& StatData) override { if (!StatData.bIsDirectory) { const FString& FilePath = FPaths::GetPath(FilenameOrDirectory); auto* PathNode = Root->GetNodeByPath(FilePath); if (!PathNode) { PathNode = Root->CreateNodeByPath(FilePath); } FSamplePathNode* SamplePathNode = PathNode->AddChild(); SamplePathNode->NodeType = Type::File; SamplePathNode->Value = FPaths::GetCleanFilename(FilenameOrDirectory); return true; } Root->CreateNodeByPath(FilenameOrDirectory); return true; } FSamplePathNode* Root; } Visitor(Root); IPlatformFile::GetPlatformPhysical().IterateDirectoryStatRecursively(*Path, Visitor); return Root; } FSamplePathNode* FSamplePathNode::AddChild() { FSamplePathNode* ChildNode = new FSamplePathNode(); ChildNode->Parent = this; Child.Add(ChildNode); return ChildNode; } FSamplePathNode* FSamplePathNode::GetNodeByPath(const FString& Path) { if (FPaths::IsSamePath(Path, GetFullPath())) return this; if (FSamplePathNode** Node = GetRootNode()->ChildMap.Find(Path)) return *Node; return nullptr; } FSamplePathNode* FSamplePathNode::CreateNodeByPath(FString Path) { const FString& FullPath = GetFullPath(); if (FullPath == Path) return this; TArray Paths; FString Leaf; do { FString Temp = FPaths::GetPathLeaf(Path); if (Temp == Leaf) break; Leaf = Temp; Paths.Add(Path); Path = FPaths::GetPath(Path); if (Path == FullPath) break; } while (true); Algo::Reverse(Paths); return CreateNodeByPathInternal(Paths); } FSamplePathNode* FSamplePathNode::CreateNodeByPathInternal(const TArray& Paths) { FSamplePathNode* RootNode = GetRootNode(); for (auto Str : Paths) { FSamplePathNode* PathNode = GetNodeByPath(Str); if (!PathNode) { PathNode = AddChild(); PathNode->Value = FPaths::GetPathLeaf(Str); PathNode->NodeType = Directory; RootNode->ChildMap.Add(Str, PathNode); } } return GetNodeByPath(Paths[0]); } bool FSampleDirectoryCache::NeedRefresh() { if (!FPaths::FileExists(*GetCachePath())) return true; TArray PathsStr; FAronaConfig::GetValueArray("Sample", "Path", PathsStr); if (PathsStr.Num() != SamplePathNodes.Num()) return true; // TODO: 比较路径是否相同 return false; } void FSampleDirectoryCache::Init() { Reload(); if (NeedRefresh()) { Refresh(); } } void FSampleDirectoryCache::Reload() { Clear(); TArray Data; if (!FFileHelper::LoadFileToArray(Data, *GetCachePath())) return; FMemoryReader MemoryReader(Data); Serialize(MemoryReader); Save(); } void FSampleDirectoryCache::Refresh() { if (Loading || !NeedRefresh()) return; Async(EAsyncExecution::Thread, [this]() { Loading = true; RegenCache(); Loading = false; }); } void FSampleDirectoryCache::RegenCache() { DeleteCache(); FAronaConfig::GetValueArray("Sample", "Path", SamplePaths); for (auto Str : SamplePaths) { if (FSamplePathNode* SamplePathNode = FSamplePathNode::Create(Str)) SamplePathNodes.Add(SamplePathNode); } Save(); } bool FSampleDirectoryCache::Save() { TArray Data; FMemoryWriter MemoryWriter(Data); Serialize(MemoryWriter); return FFileHelper::SaveArrayToFile(Data, *GetCachePath()); } void FSampleDirectoryCache::Clear() { for (const auto PathNode : SamplePathNodes) { delete PathNode; } SamplePathNodes.Empty(); } void FSampleManager::Init() { Cache.Init(); } void FSampleManager::Refresh() { Cache.Refresh(); } void FSampleDirectoryCache::DeleteCache() { IPlatformFile::GetPlatformPhysical().DeleteFile(*GetCachePath()); } FString FSampleDirectoryCache::GetCachePath() { return FPaths::ProjectSavedDir() / TEXT("SampleCache"); }