|
|
|
|
@ -9,15 +9,20 @@
|
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
|
#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)
|
|
|
|
|
: mpProject(nullptr), mNextID(0)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
@ -43,49 +48,265 @@ namespace lunarium { namespace editor
|
|
|
|
|
|
|
|
|
|
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_document doc;
|
|
|
|
|
pugi::xml_node proj_node = doc.append_child("Contents");
|
|
|
|
|
if (!doc.save_file(mContentFile.string().c_str()))
|
|
|
|
|
// 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 content = proj_node.child("Content");
|
|
|
|
|
|
|
|
|
|
if (!content)
|
|
|
|
|
{
|
|
|
|
|
return OpRes::Fail("content_meta.xml missing Content node");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Iterate through content
|
|
|
|
|
for (pugi::xml_node asset = content.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("ContentManager could not save file: %s", mContentFile.string().c_str());
|
|
|
|
|
return OpRes::Fail("Asset ID collision, ID: %llu, File: %s",
|
|
|
|
|
pAsset->GetID(), pAsset->GetFileLocation().filename().string().c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OpRes::OK();
|
|
|
|
|
mAssets[pAsset->mID] = pAsset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OpRes::Fail("ContentManager::Load not implemented");
|
|
|
|
|
return OpRes::OK();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OpRes ContentManager::Save()
|
|
|
|
|
{
|
|
|
|
|
return OpRes::Fail("ContentManager::Save not implemented");
|
|
|
|
|
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;
|
|
|
|
|
mAssets.clear();
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OpRes ContentManager::ImportFile(std::filesystem::path file, AssetType type)
|
|
|
|
|
void ContentManager::RemoveAsset(uint64_t asset_id)
|
|
|
|
|
{
|
|
|
|
|
return OpRes::Fail("ContentManager::ImportFile not implemented");
|
|
|
|
|
auto iter = mAssets.find(asset_id);
|
|
|
|
|
if (iter == mAssets.end())
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete iter->second;
|
|
|
|
|
mAssets.erase(iter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ContentManager::MoveAsset(EditorAsset* asset, std::filesystem::path to)
|
|
|
|
|
bool ContentManager::IsValidAsset(pugi::xml_node& node)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (!node.child("ID")) { return false; }
|
|
|
|
|
if (!node.child("Type")) { return false; }
|
|
|
|
|
if (!node.child("Location")) { return false; }
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ContentManager::RenameAsset(EditorAsset* asset, std::string name)
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}}
|