diff --git a/include/Engine/Core/EntityFileParser.h b/include/Engine/Core/EntityFileParser.h index d8e51a8b..c4c8c221 100644 --- a/include/Engine/Core/EntityFileParser.h +++ b/include/Engine/Core/EntityFileParser.h @@ -1,3 +1,6 @@ +#ifndef EntityFileParser_h__ +#define EntityFileParser_h__ + #include "EntityFile.h" #include "World.h" @@ -20,4 +23,6 @@ private: void onStartComponent(EntityID entity, std::string component); void onStartComponentField(EntityID entity, std::string componentType, std::string fieldName, std::map attributes); void onFieldData(EntityID entity, std::string componentType, std::string fieldName, const char* fieldData); -}; \ No newline at end of file +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Core/EntityFilePreprocessor.h b/include/Engine/Core/EntityFilePreprocessor.h index b21edf7f..3c3998b1 100644 --- a/include/Engine/Core/EntityFilePreprocessor.h +++ b/include/Engine/Core/EntityFilePreprocessor.h @@ -1,3 +1,6 @@ +#ifndef EntityFilePreprocessor_h__ +#define EntityFilePreprocessor_h__ + #include #include #include @@ -28,4 +31,6 @@ private: void onStartComponent(EntityID entity, std::string type); void parseComponentInfo(); void parseDefaults(); -}; \ No newline at end of file +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Core/EntityFileWriter.h b/include/Engine/Core/EntityFileWriter.h new file mode 100644 index 00000000..ba4035e4 --- /dev/null +++ b/include/Engine/Core/EntityFileWriter.h @@ -0,0 +1,38 @@ +#ifndef EntityFileWriter_h__ +#define EntityFileWriter_h__ + +#include +#include +#include +#include +#include + +#include "Util/XercesString.h" +#include "EntityFile.h" +#include "World.h" + +class EntityFileWriter +{ +public: + EntityFileWriter(boost::filesystem::path file) + : m_FilePath(file) + { + using namespace xercesc; + m_DOMImplementation = DOMImplementationRegistry::getDOMImplementation(XS::ToXMLCh("LS")); + m_DOMLSSerializer = static_cast(m_DOMImplementation)->createLSSerializer(); + m_DOMLSSerializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTDiscardDefaultContent, true); + m_DOMLSSerializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true); + } + + void WriteWorld(World* world); + +private: + boost::filesystem::path m_FilePath; + xercesc::DOMImplementation* m_DOMImplementation; + xercesc::DOMLSSerializer* m_DOMLSSerializer; + + void appendEntityChildren(xercesc::DOMElement* parentElement, const World* world, EntityID entity); + void appentEntityComponents(xercesc::DOMElement* parentElemetn, const World* world, EntityID entity); +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Core/World.h b/include/Engine/Core/World.h index 92378816..b3209ea7 100644 --- a/include/Engine/Core/World.h +++ b/include/Engine/Core/World.h @@ -22,7 +22,7 @@ public: // Attach a component to an entity and fill it with default values ComponentWrapper AttachComponent(EntityID entity, std::string componentType); // Check if an entity has a component - bool HasComponent(EntityID entity, std::string componentType); + bool HasComponent(EntityID entity, std::string componentType) const; // Get a component of an entity ComponentWrapper GetComponent(EntityID entity, std::string componentType); // Delete a component off an entity diff --git a/src/Engine/Core/EntityFileWriter.cpp b/src/Engine/Core/EntityFileWriter.cpp new file mode 100644 index 00000000..8207fbe3 --- /dev/null +++ b/src/Engine/Core/EntityFileWriter.cpp @@ -0,0 +1,121 @@ +#include "Core/EntityFileWriter.h" + +#define X(str) XS::ToXMLCh(str) + +void EntityFileWriter::WriteWorld(World* world) +{ + using namespace xercesc; + DOMDocument* doc = m_DOMImplementation->createDocument(nullptr, X("Entity"), nullptr); + DOMElement* root = doc->getDocumentElement(); + root->setAttribute(X("xmlns:xsi"), X("http://www.w3.org/2001/XMLSchema-instance")); + root->setAttribute(X("xsi:noNamespaceSchemaLocation"), X("../Types/Entity.xsd")); + root->setAttribute(X("xmlns:c"), X("components")); + + DOMElement* componentsElement = doc->createElement(X("Components")); + root->appendChild(componentsElement); + appentEntityComponents(componentsElement, world, 0); + + DOMElement* childrenElement = doc->createElement(X("Children")); + root->appendChild(childrenElement); + appendEntityChildren(childrenElement, world, 0); + + XMLFormatTarget* target = new StdOutFormatTarget(); + DOMLSOutput* output = static_cast(m_DOMImplementation)->createLSOutput(); + output->setByteStream(target); + m_DOMLSSerializer->write(doc, output); +} + +void EntityFileWriter::appendEntityChildren(xercesc::DOMElement* parentElement, const World* world, EntityID entity) +{ + using namespace xercesc; + DOMDocument* doc = parentElement->getOwnerDocument(); + + auto childrenRange = world->GetEntityChildren().equal_range(entity); + for (auto it = childrenRange.first; it != childrenRange.second; ++it) { + EntityID childEntity = it->second; + + DOMElement* entityElement = doc->createElement(X("Entity")); + parentElement->appendChild(entityElement); + + DOMElement* componentsElement = doc->createElement(X("Components")); + entityElement->appendChild(componentsElement); + appentEntityComponents(componentsElement, world, childEntity); + + DOMElement* childrenElement = doc->createElement(X("Children")); + entityElement->appendChild(childrenElement); + appendEntityChildren(childrenElement, world, childEntity); + } +} + +void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement, const World* world, EntityID entity) +{ + using namespace xercesc; + DOMDocument* doc = parentElement->getOwnerDocument(); + auto& componentPools = world->GetComponentPools(); + + // Step through all component pools to get an entity's components + // HACK: This is sloooow. + for (auto& kv : componentPools) { + const std::string& componentName = kv.first; + if (!world->HasComponent(entity, componentName)) { + continue; + } + std::string qualifiedComponentName = "c:" + componentName; + DOMElement* componentElement = doc->createElement(X(qualifiedComponentName)); + parentElement->appendChild(componentElement); + ComponentWrapper c = kv.second->GetByEntity(entity); + for (auto& kv : c.Info.FieldTypes) { + std::string fieldName = kv.first; + std::string fieldType = kv.second; + std::size_t fieldOffset = c.Info.FieldOffsets.at(fieldName); + + // Ignore fields that are equal to the default + // HACK: This is probably sloooooow, but it's okay. + if (memcmp(c.Data + fieldOffset, c.Info.Defaults.get() + fieldOffset, EntityFile::GetTypeStride(fieldType)) == 0) { + continue; + } + + DOMElement* fieldElement = doc->createElement(X(fieldName)); + componentElement->appendChild(fieldElement); + + if (fieldType == "Vector") { + const glm::vec3& vec = c[fieldName]; + fieldElement->setAttribute(X("X"), X(boost::lexical_cast(vec.x))); + fieldElement->setAttribute(X("Y"), X(boost::lexical_cast(vec.y))); + fieldElement->setAttribute(X("Z"), X(boost::lexical_cast(vec.z))); + } else if (fieldType == "Color") { + const glm::vec4& vec = c[fieldName]; + fieldElement->setAttribute(X("R"), X(boost::lexical_cast(vec.r))); + fieldElement->setAttribute(X("G"), X(boost::lexical_cast(vec.g))); + fieldElement->setAttribute(X("B"), X(boost::lexical_cast(vec.b))); + fieldElement->setAttribute(X("A"), X(boost::lexical_cast(vec.a))); + } else if (fieldType == "Quaternion") { + const glm::quat& q = c[fieldName]; + fieldElement->setAttribute(X("X"), X(boost::lexical_cast(q.x))); + fieldElement->setAttribute(X("Y"), X(boost::lexical_cast(q.y))); + fieldElement->setAttribute(X("Z"), X(boost::lexical_cast(q.z))); + fieldElement->setAttribute(X("W"), X(boost::lexical_cast(q.w))); + } else if (fieldType == "int") { + const int& value = c[fieldName]; + fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast(value)))); + } else if (fieldType == "float") { + const float& value = c[fieldName]; + fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast(value)))); + } else if (fieldType == "double") { + const double& value = c[fieldName]; + fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast(value)))); + } else if (fieldType == "bool") { + const bool& value = c[fieldName]; + if (value) { + fieldElement->appendChild(doc->createTextNode(X("true"))); + } else { + fieldElement->appendChild(doc->createTextNode(X("false"))); + } + } else if (fieldType == "string") { + const std::string& value = c[fieldName]; + fieldElement->appendChild(doc->createTextNode(X(value))); + } + } + } +} + diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 9957e0ec..4c45d0d5 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -68,7 +68,7 @@ ComponentWrapper World::AttachComponent(EntityID entity, std::string componentTy } -bool World::HasComponent(EntityID entity, std::string componentType) +bool World::HasComponent(EntityID entity, std::string componentType) const { ComponentPool* pool = m_ComponentPools.at(componentType); return pool->KnowsEntity(entity); diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 1e9e15aa..c6f2286e 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -2,6 +2,7 @@ #include "Collision/TriggerSystem.h" #include "Collision/CollisionSystem.h" #include "Game/HealthSystem.h" +#include "Core/EntityFileWriter.h" Game::Game(int argc, char* argv[]) { @@ -53,6 +54,9 @@ Game::Game(int argc, char* argv[]) fpp.RegisterComponents(m_World); EntityFileParser fp(file); fp.MergeEntities(m_World); + + EntityFileWriter writer("Testasdasdasd.xml"); + writer.WriteWorld(m_World); } // Create system pipeline