| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- #include "BsProjectLibrary.h"
- #include "BsEditorApplication.h"
- #include "CmPath.h"
- #include "CmFileSystem.h"
- #include "CmException.h"
- #include "CmResources.h"
- #include "CmResourceManifest.h"
- #include "CmImporter.h"
- #include "BsResourceMeta.h"
- #include "CmResources.h"
- #include "CmImporter.h"
- #include "CmImportOptions.h"
- #include "CmFileSerializer.h"
- using namespace CamelotFramework;
- using namespace BansheeEngine;
- namespace BansheeEditor
- {
- const WString ProjectLibrary::INTERNAL_RESOURCES_DIR = L"Internal/Resources";
- enum class LibraryEntryType
- {
- File,
- Directory
- };
- struct ProjectLibrary::LibraryEntry
- {
- LibraryEntryType type;
- WPath path;
- DirectoryEntry* parent;
- };
- struct ProjectLibrary::ResourceEntry : public ProjectLibrary::LibraryEntry
- {
- ResourceMetaPtr meta;
- std::time_t lastUpdateTime;
- };
- struct ProjectLibrary::DirectoryEntry : public ProjectLibrary::LibraryEntry
- {
- Vector<LibraryEntry*>::type mChildren;
- };
- ProjectLibrary::ProjectLibrary()
- :mRootEntry(nullptr)
- {
- }
- ProjectLibrary::~ProjectLibrary()
- {
- if(mRootEntry != nullptr)
- deleteDirectory(mRootEntry);
- }
- void ProjectLibrary::checkForModifications(const CM::WString& folder)
- {
- if(!PathUtil::includes(folder, EditorApplication::instance().getResourcesFolderPath()))
- return; // Folder not part of our resources path, so no modifications
- if(mRootEntry == nullptr)
- {
- mRootEntry = cm_new<DirectoryEntry>();
- mRootEntry->path = toPath(EditorApplication::instance().getResourcesFolderPath());
- }
- DirectoryEntry* directoryEntry = findDirectoryEntry(folder);
- if(directoryEntry == nullptr)
- {
- CM_EXCEPT(InternalErrorException, "Attempting to check for modifications on a folder that is not yet part " \
- "of the project library. Maybe check for modifications on the parent folder first? Folder: \"" + toString(folder) + "\"");
- }
- Stack<DirectoryEntry*>::type todo;
- todo.push(directoryEntry);
- Vector<WPath>::type childFiles;
- Vector<WPath>::type childDirectories;
- Vector<bool>::type existingEntries;
- Vector<LibraryEntry*>::type toDelete;
- while(!todo.empty())
- {
- DirectoryEntry* currentDir = todo.top();
- todo.pop();
- existingEntries.clear();
- existingEntries.resize(currentDir->mChildren.size());
- for(UINT32 i = 0; i < (UINT32)currentDir->mChildren.size(); i++)
- existingEntries[i] = false;
- childFiles.clear();
- childDirectories.clear();
- FileSystem::getChildren(currentDir->path, childFiles, childDirectories);
-
- for(auto& filePath : childFiles)
- {
- ResourceEntry* existingEntry = nullptr;
- UINT32 idx = 0;
- for(auto& child : currentDir->mChildren)
- {
- if(child->type == LibraryEntryType::File && child->path == filePath)
- {
- existingEntries[idx] = true;
- existingEntry = static_cast<ResourceEntry*>(child);
- break;
- }
- idx++;
- }
- if(existingEntry != nullptr)
- {
- reimportResource(existingEntry);
- }
- else
- {
- addResource(currentDir, filePath);
- }
- }
- for(auto& dirPath : childDirectories)
- {
- DirectoryEntry* existingEntry = nullptr;
- UINT32 idx = 0;
- for(auto& child : currentDir->mChildren)
- {
- if(child->type == LibraryEntryType::Directory && child->path == dirPath)
- {
- existingEntries[idx] = true;
- existingEntry = static_cast<DirectoryEntry*>(child);
- break;
- }
- idx++;
- }
- if(existingEntry == nullptr)
- {
- DirectoryEntry* newEntry = cm_new<DirectoryEntry>();
- newEntry->path = dirPath;
- newEntry->type = LibraryEntryType::Directory;
- newEntry->parent = currentDir;
- currentDir->mChildren.push_back(newEntry);
- }
- }
- {
- UINT32 idx = 0;
- toDelete.clear();
- for(auto& child : currentDir->mChildren)
- {
- if(existingEntries[idx])
- continue;
- toDelete.push_back(child);
- idx++;
- }
- for(auto& child : toDelete)
- {
- if(child->type == LibraryEntryType::Directory)
- deleteDirectory(static_cast<DirectoryEntry*>(child));
- else if(child->type == LibraryEntryType::File)
- deleteResource(static_cast<ResourceEntry*>(child));
- }
- }
- for(auto& child : currentDir->mChildren)
- {
- if(child->type == LibraryEntryType::Directory)
- todo.push(static_cast<DirectoryEntry*>(child));
- }
- }
- }
- void ProjectLibrary::addResource(DirectoryEntry* parent, const CM::WPath& filePath)
- {
- ResourceEntry* newResource = cm_new<ResourceEntry>();
- newResource->type = LibraryEntryType::File;
- newResource->path = filePath;
- newResource->parent = parent;
- parent->mChildren.push_back(newResource);
- reimportResource(newResource);
- }
- void ProjectLibrary::reimportResource(ResourceEntry* resource)
- {
- WString ext = toWString(PathUtil::getExtension(resource->path));
- WPath metaPath = resource->path;
- PathUtil::replaceExtension(metaPath, ext + L".meta");
- ext = ext.substr(1, ext.size() - 1); // Remove the .
- if(!Importer::instance().supportsFileType(ext))
- return;
- if(resource->meta == nullptr)
- {
- FileSerializer fs;
- if(FileSystem::isFile(metaPath))
- {
- std::shared_ptr<IReflectable> loadedMeta = fs.decode(toWString(metaPath));
- if(loadedMeta != nullptr && loadedMeta->isDerivedFrom(ResourceMeta::getRTTIStatic()))
- {
- ResourceMetaPtr resourceMeta = std::static_pointer_cast<ResourceMeta>(loadedMeta);
- resource->meta = resourceMeta;
- }
- }
- }
- if(!isUpToDate(resource))
- {
- ImportOptionsPtr importOptions = nullptr;
-
- if(resource->meta != nullptr)
- importOptions = resource->meta->getImportOptions();
- else
- importOptions = Importer::instance().createImportOptions(toWString(resource->path));
- HResource importedResource = Importer::instance().import(toWString(resource->path), importOptions);
- if(resource->meta == nullptr)
- {
- resource->meta = ResourceMeta::create(importedResource.getUUID(), importOptions);
- FileSerializer fs;
- fs.encode(resource->meta.get(), toWString(metaPath)); // TODO - Make it accept WPath
- }
- WPath internalResourcesPath = toPath(EditorApplication::instance().getActiveProjectPath()) / toPath(INTERNAL_RESOURCES_DIR);
- if(!FileSystem::isDirectory(internalResourcesPath))
- FileSystem::createDir(internalResourcesPath);
- internalResourcesPath /= toPath(toWString(importedResource.getUUID()) + L".asset");
- gResources().save(importedResource, toWString(internalResourcesPath), true);
- resource->lastUpdateTime = std::time(nullptr);
- }
- }
- void ProjectLibrary::deleteResource(ResourceEntry* resource)
- {
- ResourceManifestPtr manifest = gResources().getResourceManifest();
- if(resource->meta != nullptr)
- {
- if(manifest->uuidExists(resource->meta->getUUID()))
- {
- const WString& path = manifest->uuidToFilePath(resource->meta->getUUID());
- if(FileSystem::isFile(path))
- FileSystem::remove(path);
- }
- WString ext = toWString(PathUtil::getExtension(resource->path));
- WPath metaPath = resource->path;
- PathUtil::replaceExtension(metaPath, ext + L".meta");
- if(FileSystem::isFile(metaPath))
- FileSystem::remove(metaPath);
- }
- DirectoryEntry* parent = resource->parent;
- auto findIter = std::find_if(parent->mChildren.begin(), parent->mChildren.end(),
- [&] (const LibraryEntry* entry) { return entry == resource; });
- parent->mChildren.erase(findIter);
- cm_delete(resource);
- }
- void ProjectLibrary::deleteDirectory(DirectoryEntry* directory)
- {
- if(directory == mRootEntry)
- mRootEntry = nullptr;
- for(auto& child : directory->mChildren)
- {
- if(child->type == LibraryEntryType::Directory)
- deleteDirectory(static_cast<DirectoryEntry*>(child));
- else
- deleteResource(static_cast<ResourceEntry*>(child));
- }
- DirectoryEntry* parent = directory->parent;
- auto findIter = std::find_if(parent->mChildren.begin(), parent->mChildren.end(),
- [&] (const LibraryEntry* entry) { return entry == directory; });
- parent->mChildren.erase(findIter);
- cm_delete(directory);
- }
- bool ProjectLibrary::isUpToDate(ResourceEntry* resource) const
- {
- if(resource->meta == nullptr)
- return false;
- ResourceManifestPtr manifest = gResources().getResourceManifest();
- if(!manifest->uuidExists(resource->meta->getUUID()))
- return false;
- const WString& path = manifest->uuidToFilePath(resource->meta->getUUID());
- if(!FileSystem::isFile(path))
- return false;
- std::time_t lastModifiedTime = FileSystem::getLastModifiedTime(path);
- return lastModifiedTime <= resource->lastUpdateTime;
- }
- ProjectLibrary::DirectoryEntry* ProjectLibrary::findDirectoryEntry(const CM::WString& folder) const
- {
- WPath pathToSearch = toPath(folder);
- Stack<DirectoryEntry*>::type todo;
- todo.push(mRootEntry);
- while(!todo.empty())
- {
- DirectoryEntry* currentDir = todo.top();
- todo.pop();
- for(auto& child : currentDir->mChildren)
- {
- if(child->type == LibraryEntryType::Directory)
- {
- if(pathToSearch == child->path)
- return static_cast<DirectoryEntry*>(child);
- todo.push(static_cast<DirectoryEntry*>(child));
- }
- }
- }
- return nullptr;
- }
- }
|