#ifndef URDE_PROJECT_RESOURCE_FACTORY_BASE_HPP #define URDE_PROJECT_RESOURCE_FACTORY_BASE_HPP #include "hecl/ClientProcess.hpp" #include "hecl/Database.hpp" #include "Runtime/IFactory.hpp" #include "Runtime/CFactoryMgr.hpp" #include "Runtime/CResFactory.hpp" #include "optional.hpp" #include <thread> #include <mutex> namespace urde { class ProjectResourceFactoryBase : public IFactory { friend class ProjectResourcePool; hecl::ClientProcess& m_clientProc; public: struct AsyncTask { ProjectResourceFactoryBase& m_parent; SObjectTag x0_tag; //IDvdRequest* x8_dvdReq = nullptr; std::unique_ptr<u8[]>* xc_targetDataPtr = nullptr; u8* xc_targetDataRawPtr = nullptr; IObj** xc_targetObjPtr = nullptr; std::unique_ptr<u8[]> x10_loadBuffer; u32 x14_resSize = UINT32_MAX; u32 x14_resOffset = 0; CVParamTransfer x18_cvXfer; CObjectReference* m_selfRef = nullptr; hecl::ProjectPath m_workingPath; hecl::ProjectPath m_cookedPath; std::shared_ptr<const hecl::ClientProcess::CookTransaction> m_cookTransaction; std::shared_ptr<const hecl::ClientProcess::BufferTransaction> m_bufTransaction; bool m_failed = false; bool m_complete = false; AsyncTask(ProjectResourceFactoryBase& parent, const SObjectTag& tag, std::unique_ptr<u8[]>& ptr) : m_parent(parent), x0_tag(tag), xc_targetDataPtr(&ptr) {} AsyncTask(ProjectResourceFactoryBase& parent, const SObjectTag& tag, std::unique_ptr<u8[]>& ptr, u32 size, u32 off) : m_parent(parent), x0_tag(tag), xc_targetDataPtr(&ptr), x14_resSize(size), x14_resOffset(off) {} AsyncTask(ProjectResourceFactoryBase& parent, const SObjectTag& tag, u8* ptr, u32 size, u32 off) : m_parent(parent), x0_tag(tag), xc_targetDataRawPtr(ptr), x14_resSize(size), x14_resOffset(off) {} AsyncTask(ProjectResourceFactoryBase& parent, const SObjectTag& tag, IObj** ptr, const CVParamTransfer& xfer, CObjectReference* selfRef) : m_parent(parent), x0_tag(tag), xc_targetObjPtr(ptr), x18_cvXfer(xfer), m_selfRef(selfRef) {} void EnsurePath(const urde::SObjectTag& tag, const hecl::ProjectPath& path); void CookComplete(); bool AsyncPump(); void WaitForComplete(); }; protected: std::unordered_map<urde::SObjectTag, hecl::ProjectPath> m_tagToPath; std::unordered_map<hecl::Hash, urde::SObjectTag> m_pathToTag; std::unordered_map<std::string, urde::SObjectTag> m_catalogNameToTag; void Clear(); const hecl::Database::Project* m_proj = nullptr; const hecl::Database::DataSpecEntry* m_origSpec = nullptr; const hecl::Database::DataSpecEntry* m_pcSpec = nullptr; /* Used to resolve cooked paths */ std::unique_ptr<hecl::Database::IDataSpec> m_cookSpec; urde::CFactoryMgr m_factoryMgr; hecl::BlenderToken m_backgroundBlender; std::thread m_backgroundIndexTh; std::mutex m_backgroundIndexMutex; bool m_backgroundRunning = false; std::unordered_map<SObjectTag, std::shared_ptr<AsyncTask>> m_asyncLoadList; bool WaitForTagReady(const urde::SObjectTag& tag, const hecl::ProjectPath*& pathOut); bool PrepForReadSync(const SObjectTag& tag, const hecl::ProjectPath& path, std::experimental::optional<athena::io::FileReader>& fr); SObjectTag TagFromPath(const hecl::ProjectPath& path, hecl::BlenderToken& btok) const; SObjectTag BuildTagFromPath(const hecl::ProjectPath& path, hecl::BlenderToken& btok) const { return static_cast<DataSpec::SpecBase&>(*m_cookSpec).BuildTagFromPath(path, btok); } void ReadCatalog(const hecl::ProjectPath& catalogPath, athena::io::YAMLDocWriter& nameWriter); bool AddFileToIndex(const hecl::ProjectPath& path, athena::io::YAMLDocWriter& cacheWriter); void BackgroundIndexRecursiveProc(const hecl::ProjectPath& path, athena::io::YAMLDocWriter& cacheWriter, athena::io::YAMLDocWriter& nameWriter, int level); void BackgroundIndexRecursiveCatalogs(const hecl::ProjectPath& path, athena::io::YAMLDocWriter& nameWriter, int level); void BackgroundIndexProc(); void CancelBackgroundIndex(); void BeginBackgroundIndex(hecl::Database::Project& proj, const hecl::Database::DataSpecEntry& origSpec, const hecl::Database::DataSpecEntry& pcSpec); hecl::ProjectPath GetCookedPath(const hecl::ProjectPath& working, bool pcTarget) const; bool SyncCook(const hecl::ProjectPath& working); CFactoryFnReturn BuildSync(const SObjectTag& tag, const hecl::ProjectPath& path, const CVParamTransfer& paramXfer, CObjectReference* selfRef); public: ProjectResourceFactoryBase(hecl::ClientProcess& clientProc) : m_clientProc(clientProc) {} std::unique_ptr<urde::IObj> Build(const urde::SObjectTag&, const urde::CVParamTransfer&, CObjectReference* selfRef); void BuildAsync(const urde::SObjectTag&, const urde::CVParamTransfer&, urde::IObj**, CObjectReference* selfRef); std::shared_ptr<AsyncTask> BuildAsyncInternal(const urde::SObjectTag&, const urde::CVParamTransfer&, urde::IObj**, CObjectReference* selfRef); void CancelBuild(const urde::SObjectTag&); bool CanBuild(const urde::SObjectTag&); const urde::SObjectTag* GetResourceIdByName(const char*) const; FourCC GetResourceTypeById(ResId id) const; void EnumerateResources(const std::function<bool(const SObjectTag&)>& lambda) const; void EnumerateNamedResources(const std::function<bool(const std::string&, const SObjectTag&)>& lambda) const; u32 ResourceSize(const SObjectTag& tag); std::shared_ptr<AsyncTask> LoadResourceAsync(const urde::SObjectTag& tag, std::unique_ptr<u8[]>& target); std::shared_ptr<AsyncTask> LoadResourcePartAsync(const urde::SObjectTag& tag, u32 size, u32 off, std::unique_ptr<u8[]>& target); std::shared_ptr<AsyncTask> LoadResourcePartAsync(const urde::SObjectTag& tag, u32 size, u32 off, u8* target); std::unique_ptr<u8[]> LoadResourceSync(const urde::SObjectTag& tag); std::unique_ptr<u8[]> LoadResourcePartSync(const urde::SObjectTag& tag, u32 size, u32 off); bool AsyncPumpTask(std::unordered_map<SObjectTag, std::shared_ptr<AsyncTask>>::iterator& it); void AsyncIdle(); void Shutdown() {CancelBackgroundIndex();} SObjectTag TagFromPath(const hecl::SystemChar* path) const { return TagFromPath(hecl::ProjectPath(*(hecl::Database::Project*)m_proj, path), hecl::SharedBlenderToken); } ~ProjectResourceFactoryBase() {Shutdown();} }; } #endif // URDE_PROJECT_RESOURCE_FACTORY_BASE_HPP