You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lunarium_OLD/src/run_modes/editor/contents/content_manager.cpp

312 lines
9.4 KiB
C++

/******************************************************************************
* File - content_manager.cpp
* Author - Joey Pollack
* Date - 2022/02/22 (y/m/d)
* Mod Date - 2022/02/22 (y/m/d)
* Description - Keeps track of all resource files in the project.
* Reads/Writes meta-data to the contents_meta.xml file.
* Also manages the physical location of each asset file.
******************************************************************************/
#include "content_manager.h"
#include <editor/editor.h>
#include "../project.h"
#include <pugixml.hpp>
#include "editor_asset.h"
// Asset types
#include "tile_set.h"
namespace lunarium { namespace editor
{
ContentManager* ContentManager::mpInstance = nullptr;
ContentManager::ContentManager()
: mpProject(nullptr), mNextID(0)
{
}
ContentManager& ContentManager::GetInstance()
{
if (!mpInstance)
{
mpInstance = new ContentManager();
}
return *mpInstance;
}
void ContentManager::FreeInstance()
{
if (mpInstance)
{
delete mpInstance;
mpInstance = nullptr;
}
}
OpRes ContentManager::Load(Project* project)
{
Unload();
mpProject = project;
std::filesystem::path root = mpProject->GetRootDirectory();
mContentFile = root / "contents/content_meta.xml";
// If this is a new project being generated just create a base contents file
if (!std::filesystem::exists(mContentFile))
{
// pugi::xml_node proj_node = doc.append_child("Project");
// proj_node.append_attribute("Name").set_value(mpProject->GetName().c_str());
// mNextID = 0;
// proj_node.append_child("NextID").append_attribute("ID").set_value(mNextID);
// // pugi::xml_node proj_node = doc.append_child("Contents");
// proj_node.append_child("Contents");
// if (!doc.save_file(mContentFile.string().c_str()))
// {
// return OpRes::Fail("ContentManager could not save file: %s", mContentFile.string().c_str());
// }
return Save();
}
// Load the file
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(mContentFile.string().c_str());
if (result.status != pugi::xml_parse_status::status_ok)
{
return OpRes::Fail("Could not open contents file: %s, %s", mContentFile.string().c_str(), result.description());
}
pugi::xml_node proj_node = doc.child("Project");
if (!proj_node)
{
return OpRes::Fail("content_meta.xml missing Project root node");
}
// Get ID
pugi::xml_node ID = proj_node.child("NextID");
if (!ID)
{
return OpRes::Fail("content_meta.xml missing NextID node");
}
mNextID = ID.attribute("ID").as_ullong();
pugi::xml_node contents = proj_node.child("Contents");
if (!contents)
{
return OpRes::Fail("content_meta.xml missing Contents node");
}
// Iterate through content
for (pugi::xml_node asset = contents.child("Asset"); asset; asset = asset.next_sibling("Asset"))
{
if (!IsValidAsset(asset))
{
return OpRes::Fail("Invalid asset node in content_meta.xml");
}
// Load Type
AssetType type = (AssetType)asset.attribute("Type").as_int();
EditorAsset* pAsset = CreateAsset(type);
if (!pAsset)
{
return OpRes::Fail("Could not create Editor Asset. Unknown type: %n", (int)type);
}
// Load ID
pAsset->mID = (uint64_t)asset.attribute("ID").as_ullong();
// Load Location
pAsset->mLocation = std::filesystem::path(asset.attribute("Location").as_string());
// Load type specific data
if (Failed(pAsset->LoadFromXML(asset).LogIfFailed(Editor::LogCat)))
{
return OpRes::Fail("Could not load asset type specific data for asset with ID: %llu, File: %s",
pAsset->GetID(), pAsset->GetFileLocation().filename().string().c_str());
}
// Store asset
if (mAssets.find(pAsset->mID) != mAssets.end())
{
return OpRes::Fail("Asset ID collision, ID: %llu, File: %s",
pAsset->GetID(), pAsset->GetFileLocation().filename().string().c_str());
}
mAssets[pAsset->mID] = pAsset;
}
return OpRes::OK();
}
OpRes ContentManager::Save()
{
if (!mpProject)
{
return OpRes::Fail("ConentManager::Save failed: no project set");
}
// Save header info
pugi::xml_document doc;
pugi::xml_node proj_node = doc.append_child("Project");
proj_node.append_attribute("Name").set_value(mpProject->GetName().c_str());
proj_node.append_child("NextID").append_attribute("ID").set_value(mNextID);
// pugi::xml_node proj_node = doc.append_child("Contents");
// Save all assets
pugi::xml_node contents = proj_node.append_child("Contents");
for (auto iter = mAssets.begin(); iter != mAssets.end(); iter++)
{
EditorAsset* pAsset = iter->second;
pugi::xml_node asset = contents.append_child("Asset");
asset.append_attribute("Type").set_value((int)pAsset->GetType());
asset.append_attribute("ID").set_value(pAsset->GetID());
asset.append_attribute("Location").set_value(pAsset->GetFileLocation().string().c_str());
if (Failed(pAsset->SaveToXML(asset).LogIfFailed(Editor::LogCat)))
{
return OpRes::Fail("Could not save asset meta data for file: %s", pAsset->GetFileLocation().string().c_str());
}
}
if (!doc.save_file(mContentFile.string().c_str()))
{
return OpRes::Fail("ContentManager could not save file: %s", mContentFile.string().c_str());
}
return OpRes::OK();
}
void ContentManager::Unload()
{
mpProject = nullptr;
FreeAssets();
mContentFile = "";
mNextID = 0;
}
void ContentManager::GetAllAssetIDs(std::vector<uint64_t>& container) const
{
container.clear();
for (auto iter = mAssets.begin(); iter != mAssets.end(); iter++)
{
container.push_back(iter->first);
}
}
void ContentManager::GetAllAssetsByType(std::vector<EditorAsset*>& container, AssetType type) const
{
container.clear();
for (auto iter = mAssets.begin(); iter != mAssets.end(); iter++)
{
if (iter->second->GetType() == type)
{
container.push_back(iter->second);
}
}
}
EditorAsset* ContentManager::GetAsset(uint64_t id)
{
auto iter = mAssets.find(id);
if (iter == mAssets.end())
{
return nullptr;
}
return iter->second;
}
OpRes ContentManager::AddGeneratedAsset(EditorAsset* asset, uint64_t& id)
{
if (mAssets.find(mNextID) != mAssets.end())
{
return OpRes::Fail("Could not import asset, ID collision. ID: %llu", mNextID);
}
asset->mID = mNextID;
mNextID++;
mAssets[asset->mID] = asset;
id = asset->mID;
return OpRes::OK();
}
OpRes ContentManager::ImportFile(std::filesystem::path file, std::filesystem::path to_location, AssetType type, uint64_t& id)
{
if (mAssets.find(mNextID) != mAssets.end())
{
return OpRes::Fail("Could not import asset, ID collision. ID: %llu", mNextID);
}
if (!std::filesystem::copy_file(file, to_location))
{
return OpRes::Fail("Could not copy asset file from: %s to: %s", file.string().c_str(), to_location.string().c_str());
}
EditorAsset* pAsset = CreateAsset(type);
pAsset->mID = mNextID;
mNextID++;
pAsset->mLocation = to_location;
if (Failed(pAsset->LoadRawFile().LogIfFailed(Editor::LogCat)))
{
delete pAsset;
return OpRes::Fail("Could not load asset data from raw file: %s", file.string().c_str());
}
mAssets[pAsset->mID] = pAsset;
id = pAsset->mID;
return OpRes::OK();
}
void ContentManager::RemoveAsset(uint64_t asset_id)
{
auto iter = mAssets.find(asset_id);
if (iter == mAssets.end())
{
return;
}
delete iter->second;
mAssets.erase(iter);
}
bool ContentManager::IsValidAsset(pugi::xml_node& node)
{
if (!node.attribute("ID")) { return false; }
if (!node.attribute("Type")) { return false; }
if (!node.attribute("Location")) { return false; }
return true;
}
EditorAsset* ContentManager::CreateAsset(AssetType type)
{
switch (type)
{
case AssetType::EATYPE_TILE_SET: return new TileSet();
default: return nullptr;
}
}
void ContentManager::FreeAssets()
{
for (auto iter = mAssets.begin(); iter != mAssets.end(); iter++)
{
delete iter->second;
}
mAssets.clear();
}
}}