From 23e78c4947b85e3c48949ae0f88229eb26c24812 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 7 Jan 2016 14:43:54 +0100 Subject: [PATCH] Cleaned up code --- include/Engine/Core/EntityFile.h | 68 +-- include/Engine/Core/EntityFileParser.h | 65 +-- include/Engine/Core/EntityFilePreprocessor.h | 229 +--------- include/Engine/Core/EntityXMLFile.h | 141 ------ include/Game/Game.h | 1 - src/Engine/Core/EntityFile.cpp | 50 +- src/Engine/Core/EntityFileParser.cpp | 58 +++ src/Engine/Core/EntityFilePreprocessor.cpp | 225 +++++++++ src/Engine/Core/EntityXMLFile.cpp | 451 ------------------- src/Game/Game.cpp | 3 +- 10 files changed, 352 insertions(+), 939 deletions(-) delete mode 100644 include/Engine/Core/EntityXMLFile.h create mode 100644 src/Engine/Core/EntityFileParser.cpp create mode 100644 src/Engine/Core/EntityFilePreprocessor.cpp delete mode 100644 src/Engine/Core/EntityXMLFile.cpp diff --git a/include/Engine/Core/EntityFile.h b/include/Engine/Core/EntityFile.h index 42a3891d..3bee9a5b 100644 --- a/include/Engine/Core/EntityFile.h +++ b/include/Engine/Core/EntityFile.h @@ -275,79 +275,19 @@ private: public: static std::size_t GetTypeStride(std::string typeName); - - static void WriteAttributeData(char* outData, const std::string fieldType, const std::map& attributes) - { - if (fieldType == "Vector") { - glm::vec3 vec; - vec.x = boost::lexical_cast(attributes.at("X")); - vec.y = boost::lexical_cast(attributes.at("Y")); - vec.z = boost::lexical_cast(attributes.at("Z")); - memcpy(outData, reinterpret_cast(&vec), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "Color") { - glm::vec4 vec; - vec.r = boost::lexical_cast(attributes.at("R")); - vec.g = boost::lexical_cast(attributes.at("G")); - vec.b = boost::lexical_cast(attributes.at("B")); - vec.a = boost::lexical_cast(attributes.at("A")); - memcpy(outData, reinterpret_cast(&vec), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "Quaternion") { - glm::quat q; - q.x = boost::lexical_cast(attributes.at("X")); - q.y = boost::lexical_cast(attributes.at("Y")); - q.z = boost::lexical_cast(attributes.at("Z")); - q.w = boost::lexical_cast(attributes.at("W")); - memcpy(outData, reinterpret_cast(&q), EntityFile::GetTypeStride(fieldType)); - } else if (!attributes.empty()) { - LOG_WARNING("%i attributes not handled by any type conversion!", attributes.size()); - } - } - - static void WriteValueData(char* outData, const std::string fieldType, const char* valueData) - { - if (fieldType == "int") { - int value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "float") { - float value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "double") { - double value = boost::lexical_cast(valueData); - memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "bool") { - bool value = (valueData[0] == 't'); // Lazy bool evaluation - memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); - } else if (fieldType == "string") { - new (outData) std::string(valueData); - } else { - LOG_WARNING("Unknown value data type: %s", fieldType.c_str()); - } - } - - void Parse(const EntityFileHandler* handler); - //const std::map& ComponentInfo() const { return m_ComponentInfo; } - //const std::vector& EntityReferences() const { return m_EntityReferences; } + static void WriteAttributeData(char* outData, const std::string fieldType, const std::map& attributes); + static void WriteValueData(char* outData, const std::string fieldType, const char* valueData); xercesc::XMLGrammarPool* GrammarPool() const { return m_GrammarPool; } + void Parse(const EntityFileHandler* handler) const; + private: boost::filesystem::path m_FilePath; xercesc::XMLGrammarPool* m_GrammarPool; xercesc::SAX2XMLReader* m_SAX2XMLReader; //std::map m_ComponentInfo; //std::vector m_EntityReferences; -static float getFloatAttribute(const xercesc::DOMElement* element, const char* attribute) -{ - using namespace xercesc; - XSValue::Status status; - XSValue* val = XSValue::getActualValue(element->getAttribute(XS::ToXMLCh(attribute)), xercesc::XSValue::DataType::dt_double, status); - if (val == nullptr) { - LOG_ERROR("Element \"%s\" doesn't have an \"%s\" attribute!", ((std::string)XS::ToString(element->getTagName())).c_str(), attribute); - return 0.f; - } else { - return static_cast(val->fData.fValue.f_double); - } -} }; #endif \ No newline at end of file diff --git a/include/Engine/Core/EntityFileParser.h b/include/Engine/Core/EntityFileParser.h index 4a989719..d8e51a8b 100644 --- a/include/Engine/Core/EntityFileParser.h +++ b/include/Engine/Core/EntityFileParser.h @@ -4,67 +4,20 @@ class EntityFileParser { public: - EntityFileParser(EntityFile* entityFile) - : m_EntityFile(entityFile) - { - m_Handler.SetStartEntityCallback(std::bind(&EntityFileParser::onStartEntity, this, std::placeholders::_1, std::placeholders::_2)); - m_Handler.SetStartComponentCallback(std::bind(&EntityFileParser::onStartComponent, this, std::placeholders::_1, std::placeholders::_2)); - m_Handler.SetStartFieldCallback(std::bind(&EntityFileParser::onStartComponentField, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); - m_Handler.SetStartFieldDataCallback(std::bind(&EntityFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); - } + EntityFileParser(const EntityFile* entityFile); - void MergeEntities(World* world) - { - m_World = world; - m_EntityIDMapper[0] = 0; - m_EntityFile->Parse(&m_Handler); - } + void MergeEntities(World* world); private: - EntityFile* m_EntityFile; + const EntityFile* m_EntityFile; EntityFileHandler m_Handler; World* m_World = nullptr; - // Maps EntityIDs local to the file to real IDs in the world + // Maps EntityIDs local to the file to real IDs in the world after they've been + // created in order to resolve parent-child relationships. std::map m_EntityIDMapper; - void onStartEntity(EntityID entity, EntityID parent) - { - EntityID realParent = m_EntityIDMapper.at(parent); - EntityID realEntity = m_World->CreateEntity(realParent); - m_EntityIDMapper[entity] = realEntity; - LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent); - } - - void onStartComponent(EntityID entity, std::string component) - { - EntityID realEntity = m_EntityIDMapper.at(entity); - m_World->AttachComponent(entity, component); - LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity); - } - - void onStartComponentField(EntityID entity, std::string componentType, std::string fieldName, std::map attributes) - { - EntityID realEntity = m_EntityIDMapper.at(entity); - ComponentWrapper component = m_World->GetComponent(realEntity, componentType); - std::string fieldType = component.Info.FieldTypes.at(fieldName); - - LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), fieldType.c_str()); - LOG_DEBUG("Attributes:"); - for (auto& kv : attributes) { - LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str()); - } - - char* data = component.Data + component.Info.FieldOffsets.at(fieldName); - EntityFile::WriteAttributeData(data, fieldType, attributes); - } - - void onFieldData(EntityID entity, std::string componentType, std::string fieldName, const char* fieldData) - { - EntityID realEntity = m_EntityIDMapper.at(entity); - ComponentWrapper component = m_World->GetComponent(realEntity, componentType); - std::string fieldType = component.Info.FieldTypes.at(fieldName); - - char* data = component.Data + component.Info.FieldOffsets.at(fieldName); - EntityFile::WriteValueData(data, fieldType, fieldData); - } + void onStartEntity(EntityID entity, EntityID parent); + 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 diff --git a/include/Engine/Core/EntityFilePreprocessor.h b/include/Engine/Core/EntityFilePreprocessor.h index 6bee4636..b21edf7f 100644 --- a/include/Engine/Core/EntityFilePreprocessor.h +++ b/include/Engine/Core/EntityFilePreprocessor.h @@ -16,233 +16,16 @@ class EntityFilePreprocessor { public: - EntityFilePreprocessor(std::string path) - : m_FilePath(path) - { - m_EntityFile = ResourceManager::Load(path); - EntityFileHandler handler; - handler.SetStartComponentCallback(std::bind(&EntityFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2)); - m_EntityFile->Parse(&handler); + EntityFilePreprocessor(const EntityFile* entityFile); - LOG_DEBUG("___ COMPONENT DEFINITIONS ___"); - for (auto& kv : m_ComponentCounts) { - LOG_DEBUG("%s: %i", kv.first.c_str(), kv.second); - } - - parseComponentInfo(); - - for (auto& kv : m_ComponentInfo) { - auto& info = kv.second; - LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta.Annotation.c_str()); - LOG_DEBUG("Stride: %i", info.Meta.Stride); - LOG_DEBUG("Allocation: %i", info.Meta.Allocation); - for (auto& kv : info.FieldTypes) { - LOG_DEBUG("\t%i\t%s %s", info.FieldOffsets[kv.first], kv.second.c_str(), kv.first.c_str()); - } - } - - parseDefaults(); - } - - void RegisterComponents(World* world) - { - for (auto& kv : m_ComponentInfo) { - world->RegisterComponent(kv.second); - } - } + void RegisterComponents(World* world); private: - std::string m_FilePath; - EntityFile* m_EntityFile; + const EntityFile* m_EntityFile; std::map m_ComponentCounts; std::map m_ComponentInfo; - void onStartComponent(EntityID entity, std::string type) - { - //LOG_DEBUG("Component: %s", type.c_str()); - m_ComponentCounts[type]++; - } - - void parseComponentInfo() - { - using namespace xercesc; - EntityFileXMLErrorHandler errorHandler; - auto grammarPool = m_EntityFile->GrammarPool(); - bool whateverTheFuckThisIs; - auto xsModel = grammarPool->getXSModel(whateverTheFuckThisIs); - - // Find component xsd element declarations - std::cout << "Enumerating components..." << std::endl; - // - auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION); - for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) { - auto element = static_cast(topLevelElements->item(i)); - - std::string nameSpace = XS::ToString(element->getNamespace()); - if (nameSpace != "components") { - continue; - } - - ComponentInfo compInfo; - - // Name - compInfo.Name = XS::ToString(element->getName()); - // Known allocation - compInfo.Meta.Allocation = m_ComponentCounts[compInfo.Name]; - // Annotation - auto componentAnnotation = element->getAnnotation(); - if (componentAnnotation != nullptr) { - // Parse annotation XML - char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString()); - MemBufInputSource annotationInput(reinterpret_cast(annotationString), strlen(annotationString), "MemBuf: Annotation String"); - XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, grammarPool); - parser.setErrorHandler(&errorHandler); - parser.parse(annotationInput); - XMLString::release(&annotationString); - auto doc = parser.getDocument(); - - // TODO: Add allocation estimations from external file on map-to-map basis - // Add allocation estimation(s) - //auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation")); - //for (int i = 0; i < allocationTags->getLength(); ++i) { - // auto allocation = dynamic_cast(allocationTags->item(i)); - // auto child = allocation->getFirstChild(); - // if (child == nullptr) { - // continue; - // } - - // XSValue::Status status; - // XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status); - // compInfo.Meta.Allocation += val->fData.fValue.f_int; - //} - - // Save documentation string - auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation")); - if (documentationTags->getLength() != 0) { - auto child = documentationTags->item(0)->getFirstChild(); - if (child != nullptr) { - compInfo.Meta.Annotation = XS::ToString(child->getNodeValue()); - } - } - } else { - LOG_WARNING("Component is missing an annotation!"); - } - - // - auto typeDefinition = element->getTypeDefinition(); - if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) { - LOG_ERROR("Type definition wasn't COMPLEX_TYPE! Skipping."); - continue; - } - auto complexTypeDefinition = dynamic_cast(typeDefinition); - - // - auto modelGroupParticle = complexTypeDefinition->getParticle(); - if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { - LOG_ERROR("Model group particle wasn't TERM_MODELGROUP! Skipping."); - continue; - } - auto modelGroup = modelGroupParticle->getModelGroupTerm(); - - // getParticles(); - for (unsigned int i = 0; i < particles->size(); ++i) { - auto particle = particles->elementAt(i); - if (particle->getTermType() != XSParticle::TERM_ELEMENT) { - LOG_ERROR("Particle wasn't TERM_ELEMENT! Skipping."); - continue; - } - auto elementDeclaration = particle->getElementTerm(); - - std::string name = XS::ToString(elementDeclaration->getName()); - std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->getName()); - - size_t stride = EntityFile::GetTypeStride(type); - if (stride == 0) { - std::cout << "Warning: Field \"" << name << "\" in component \"" << compInfo.Name << "\" uses unexpected field type \"" << type << "\". Skipping." << std::endl; - continue; - } - - compInfo.FieldTypes[name] = type; - compInfo.FieldOffsets[name] = fieldOffset; - fieldOffset += stride; - } - - compInfo.Meta.Stride = fieldOffset; - m_ComponentInfo[compInfo.Name] = compInfo; - } - } - - void parseDefaults() - { - using namespace xercesc; - - EntityFileXMLErrorHandler errorHandler; - - for (auto& ci : m_ComponentInfo) { - // Allocate memory for default values - ci.second.Defaults = std::shared_ptr(new char[ci.second.Meta.Stride]); - memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride); - - XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); - parser.setErrorHandler(&errorHandler); - - std::string componentName = ci.first; - LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); - boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml"; - - parser.parse(defaultsFile.string().c_str()); - auto doc = parser.getDocument(); - if (doc == nullptr) { - LOG_ERROR("%s not found! Skipping.", defaultsFile.string().c_str()); - continue; - } - - // Find the node in the components namespace matching the component name - std::string tagName = "c:" + componentName; - auto rootNodes = doc->getElementsByTagName(XS::ToXMLCh(tagName)); - if (rootNodes->getLength() == 0) { - LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str()); - continue; - } - auto componentElement = dynamic_cast(rootNodes->item(0)); - - // Fill the default value buffer with values - for (auto& field : ci.second.FieldOffsets) { - std::string fieldName = field.first; - auto fieldNodes = componentElement->getElementsByTagName(XS::ToXMLCh(fieldName)); - auto fieldNode = fieldNodes->item(0); - if (fieldNode == nullptr) { - LOG_ERROR("Defaults for component \"%s\" is missing field \"%s\"!", componentName.c_str(), fieldName.c_str()); - continue; - } - auto fieldElement = dynamic_cast(fieldNode); - - std::string fieldType = ci.second.FieldTypes.at(fieldName); - unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName); - char* data = ci.second.Defaults.get() + fieldOffset; - - // Handle potential field attributes - if (fieldElement->hasAttributes()) { - std::map attributes; - auto attributeMap = fieldElement->getAttributes(); - for (int i = 0; i < attributeMap->getLength(); ++i) { - auto attribItem = attributeMap->item(i); - attributes[XS::ToString(attribItem->getNodeName())] = XS::ToString(attribItem->getNodeValue()); - } - EntityFile::WriteAttributeData(data, fieldType, attributes); - } - - // Handle potential field values - auto childNode = fieldElement->getFirstChild(); - if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) { - char* cstrValue = XMLString::transcode(childNode->getNodeValue()); - EntityFile::WriteValueData(data, fieldType, cstrValue); - XMLString::release(&cstrValue); - } - } - } - } + void onStartComponent(EntityID entity, std::string type); + void parseComponentInfo(); + void parseDefaults(); }; \ No newline at end of file diff --git a/include/Engine/Core/EntityXMLFile.h b/include/Engine/Core/EntityXMLFile.h deleted file mode 100644 index 6fa71dad..00000000 --- a/include/Engine/Core/EntityXMLFile.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef EntityXMLFile_h__ -#define EntityXMLFile_h__ - -#include - -#include "../Common.h" -#include "../GLM.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ResourceManager.h" -#include "Entity.h" -#include "ComponentInfo.h" -class World; - -class EntityPreprocessorXMLErrorHandler : public xercesc::DOMErrorHandler -{ -public: - bool handleError(const xercesc::DOMError &e) override - { - char* message = xercesc::XMLString::transcode(e.getMessage()); - std::cerr << "Preprocessor DOMError: " << message << std::endl; - xercesc::XMLString::release(&message); - return false; - } -}; - -class EntityParserXMLErrorHandler : public xercesc::ErrorHandler -{ -public: - void warning(const xercesc::SAXParseException& e) override - { - reportParseException("Warning", e); - } - void error(const xercesc::SAXParseException& e) override - { - reportParseException("Error", e); - } - void fatalError(const xercesc::SAXParseException& e) override - { - reportParseException("FATAL ERROR", e); - } - void resetErrors() override { } - -private: - void reportParseException(std::string type, const xercesc::SAXParseException& e) - { - char* message = xercesc::XMLString::transcode(e.getMessage()); - char* systemID = xercesc::XMLString::transcode(e.getSystemId()); - std::cerr << systemID << ":" << e.getLineNumber() << ":" << e.getColumnNumber() << std::endl; - std::cerr << type << ": " << message << std::endl; - xercesc::XMLString::release(&systemID); - xercesc::XMLString::release(&message); - } -}; - -class XSTR -{ -public: - XSTR(const XMLCh* const xmlString) - { - m_AsChar = xercesc::XMLString::transcode(xmlString); - } - - XSTR(const char* normalString) - { - m_AsXMLCh = xercesc::XMLString::transcode(normalString); - } - - ~XSTR() - { - if (m_AsChar != nullptr) { - xercesc::XMLString::release(&m_AsChar); - } - if (m_AsXMLCh != nullptr) { - xercesc::XMLString::release(&m_AsXMLCh); - } - } - - operator const char*() const { return m_AsChar; } - operator const XMLCh*() const { return m_AsXMLCh; } - -private: - char* m_AsChar = nullptr; - XMLCh* m_AsXMLCh = nullptr; -}; - -class EntityXMLFile : public Resource -{ - friend class ResourceManager; - -private: - EntityXMLFile(std::string path); - -public: - ~EntityXMLFile(); - - void PopulateWorld(World* world); - -private: - static unsigned int InstanceCount; - - std::string m_EntityFile; - xercesc::XMLGrammarPool* m_GrammarPool = nullptr; - EntityParserXMLErrorHandler* m_ErrorHandler = nullptr; - xercesc::XercesDOMParser* m_DOMParser = nullptr; - xercesc::DOMDocument* m_DOMDocument = nullptr; - std::map m_ComponentInfo; - - // Preprocesses the entity file to insert include-by-copy child entities - // TODO: Make this work in memory instead of saving to file - void preprocess(std::string inPath, std::string outPath); - - void parseComponentInfo(); - void parseDefaults(); - void predictComponentAllocation(); - void parseEntityGraph(World* world, xercesc::DOMElement* parent, EntityID parentEntity); - std::size_t getTypeStride(std::string typeName); - float getFloatAttribute(const xercesc::DOMElement* element, const char* attribute) const; - void writeData(const xercesc::DOMElement* element, std::string typeName, char* outData); -}; - -#endif \ No newline at end of file diff --git a/include/Game/Game.h b/include/Game/Game.h index e82369e0..1c19aac2 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -13,7 +13,6 @@ #include "Input/KeyboardInputHandler.h" #include "Input/MouseInputHandler.h" #include "Core/EKeyDown.h" -#include "Core/EntityXMLFile.h" #include "Core/EntityFilePreprocessor.h" #include "Core/SystemPipeline.h" #include "RaptorCopterSystem.h" diff --git a/src/Engine/Core/EntityFile.cpp b/src/Engine/Core/EntityFile.cpp index 672d3e84..b05c9e48 100644 --- a/src/Engine/Core/EntityFile.cpp +++ b/src/Engine/Core/EntityFile.cpp @@ -16,7 +16,7 @@ EntityFile::~EntityFile() xercesc::XMLPlatformUtils::Terminate(); } -void EntityFile::Parse(const EntityFileHandler* handler) +void EntityFile::Parse(const EntityFileHandler* handler) const { using namespace xercesc; @@ -45,3 +45,51 @@ std::size_t EntityFile::GetTypeStride(std::string typeName) auto it = typeStrides.find(typeName); return (it != typeStrides.end()) ? it->second : 0; } + +void EntityFile::WriteAttributeData(char* outData, const std::string fieldType, const std::map& attributes) +{ + if (fieldType == "Vector") { + glm::vec3 vec; + vec.x = boost::lexical_cast(attributes.at("X")); + vec.y = boost::lexical_cast(attributes.at("Y")); + vec.z = boost::lexical_cast(attributes.at("Z")); + memcpy(outData, reinterpret_cast(&vec), EntityFile::GetTypeStride(fieldType)); + } else if (fieldType == "Color") { + glm::vec4 vec; + vec.r = boost::lexical_cast(attributes.at("R")); + vec.g = boost::lexical_cast(attributes.at("G")); + vec.b = boost::lexical_cast(attributes.at("B")); + vec.a = boost::lexical_cast(attributes.at("A")); + memcpy(outData, reinterpret_cast(&vec), EntityFile::GetTypeStride(fieldType)); + } else if (fieldType == "Quaternion") { + glm::quat q; + q.x = boost::lexical_cast(attributes.at("X")); + q.y = boost::lexical_cast(attributes.at("Y")); + q.z = boost::lexical_cast(attributes.at("Z")); + q.w = boost::lexical_cast(attributes.at("W")); + memcpy(outData, reinterpret_cast(&q), EntityFile::GetTypeStride(fieldType)); + } else if (!attributes.empty()) { + LOG_WARNING("%i attributes not handled by any type conversion!", attributes.size()); + } +} + +void EntityFile::WriteValueData(char* outData, const std::string fieldType, const char* valueData) +{ + if (fieldType == "int") { + int value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); + } else if (fieldType == "float") { + float value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); + } else if (fieldType == "double") { + double value = boost::lexical_cast(valueData); + memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); + } else if (fieldType == "bool") { + bool value = (valueData[0] == 't'); // Lazy bool evaluation + memcpy(outData, reinterpret_cast(&value), EntityFile::GetTypeStride(fieldType)); + } else if (fieldType == "string") { + new (outData) std::string(valueData); + } else { + LOG_WARNING("Unknown value data type: %s", fieldType.c_str()); + } +} diff --git a/src/Engine/Core/EntityFileParser.cpp b/src/Engine/Core/EntityFileParser.cpp new file mode 100644 index 00000000..e14e5508 --- /dev/null +++ b/src/Engine/Core/EntityFileParser.cpp @@ -0,0 +1,58 @@ +#include "Core/EntityFileParser.h" + +EntityFileParser::EntityFileParser(const EntityFile* entityFile) + : m_EntityFile(entityFile) +{ + m_Handler.SetStartEntityCallback(std::bind(&EntityFileParser::onStartEntity, this, std::placeholders::_1, std::placeholders::_2)); + m_Handler.SetStartComponentCallback(std::bind(&EntityFileParser::onStartComponent, this, std::placeholders::_1, std::placeholders::_2)); + m_Handler.SetStartFieldCallback(std::bind(&EntityFileParser::onStartComponentField, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); + m_Handler.SetStartFieldDataCallback(std::bind(&EntityFileParser::onFieldData, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); +} + +void EntityFileParser::MergeEntities(World* world) +{ + m_World = world; + m_EntityIDMapper[0] = 0; + m_EntityFile->Parse(&m_Handler); +} + +void EntityFileParser::onStartEntity(EntityID entity, EntityID parent) +{ + EntityID realParent = m_EntityIDMapper.at(parent); + EntityID realEntity = m_World->CreateEntity(realParent); + m_EntityIDMapper[entity] = realEntity; + LOG_DEBUG("Created entity #%i (%i) with parent %i (%i)", entity, realEntity, parent, realParent); +} + +void EntityFileParser::onStartComponent(EntityID entity, std::string component) +{ + EntityID realEntity = m_EntityIDMapper.at(entity); + m_World->AttachComponent(entity, component); + LOG_DEBUG("Attached component of type \"%s\" to entity #%i (%i)", component.c_str(), entity, realEntity); +} + +void EntityFileParser::onStartComponentField(EntityID entity, std::string componentType, std::string fieldName, std::map attributes) +{ + EntityID realEntity = m_EntityIDMapper.at(entity); + ComponentWrapper component = m_World->GetComponent(realEntity, componentType); + std::string fieldType = component.Info.FieldTypes.at(fieldName); + + LOG_DEBUG("Field \"%s\" type \"%s\"", fieldName.c_str(), fieldType.c_str()); + LOG_DEBUG("Attributes:"); + for (auto& kv : attributes) { + LOG_DEBUG("\t%s = %s", kv.first.c_str(), kv.second.c_str()); + } + + char* data = component.Data + component.Info.FieldOffsets.at(fieldName); + EntityFile::WriteAttributeData(data, fieldType, attributes); +} + +void EntityFileParser::onFieldData(EntityID entity, std::string componentType, std::string fieldName, const char* fieldData) +{ + EntityID realEntity = m_EntityIDMapper.at(entity); + ComponentWrapper component = m_World->GetComponent(realEntity, componentType); + std::string fieldType = component.Info.FieldTypes.at(fieldName); + + char* data = component.Data + component.Info.FieldOffsets.at(fieldName); + EntityFile::WriteValueData(data, fieldType, fieldData); +} diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityFilePreprocessor.cpp new file mode 100644 index 00000000..1f6b36f1 --- /dev/null +++ b/src/Engine/Core/EntityFilePreprocessor.cpp @@ -0,0 +1,225 @@ +#include "Core/EntityFilePreprocessor.h" + +EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile) + : m_EntityFile(entityFile) +{ + EntityFileHandler handler; + handler.SetStartComponentCallback(std::bind(&EntityFilePreprocessor::onStartComponent, this, std::placeholders::_1, std::placeholders::_2)); + m_EntityFile->Parse(&handler); + + LOG_DEBUG("___ COMPONENT DEFINITIONS ___"); + for (auto& kv : m_ComponentCounts) { + LOG_DEBUG("%s: %i", kv.first.c_str(), kv.second); + } + + parseComponentInfo(); + + for (auto& kv : m_ComponentInfo) { + auto& info = kv.second; + LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta.Annotation.c_str()); + LOG_DEBUG("Stride: %i", info.Meta.Stride); + LOG_DEBUG("Allocation: %i", info.Meta.Allocation); + for (auto& kv : info.FieldTypes) { + LOG_DEBUG("\t%i\t%s %s", info.FieldOffsets[kv.first], kv.second.c_str(), kv.first.c_str()); + } + } + + parseDefaults(); +} + +void EntityFilePreprocessor::RegisterComponents(World* world) +{ + for (auto& kv : m_ComponentInfo) { + world->RegisterComponent(kv.second); + } +} + +void EntityFilePreprocessor::onStartComponent(EntityID entity, std::string type) +{ + //LOG_DEBUG("Component: %s", type.c_str()); + m_ComponentCounts[type]++; +} + +void EntityFilePreprocessor::parseComponentInfo() +{ + using namespace xercesc; + EntityFileXMLErrorHandler errorHandler; + auto grammarPool = m_EntityFile->GrammarPool(); + bool whateverTheFuckThisIs; + auto xsModel = grammarPool->getXSModel(whateverTheFuckThisIs); + + // Find component xsd element declarations + std::cout << "Enumerating components..." << std::endl; + // + auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION); + for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) { + auto element = static_cast(topLevelElements->item(i)); + + std::string nameSpace = XS::ToString(element->getNamespace()); + if (nameSpace != "components") { + continue; + } + + ComponentInfo compInfo; + + // Name + compInfo.Name = XS::ToString(element->getName()); + // Known allocation + compInfo.Meta.Allocation = m_ComponentCounts[compInfo.Name]; + // Annotation + auto componentAnnotation = element->getAnnotation(); + if (componentAnnotation != nullptr) { + // Parse annotation XML + char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString()); + MemBufInputSource annotationInput(reinterpret_cast(annotationString), strlen(annotationString), "MemBuf: Annotation String"); + XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, grammarPool); + parser.setErrorHandler(&errorHandler); + parser.parse(annotationInput); + XMLString::release(&annotationString); + auto doc = parser.getDocument(); + + // TODO: Add allocation estimations from external file on map-to-map basis + // Add allocation estimation(s) + //auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation")); + //for (int i = 0; i < allocationTags->getLength(); ++i) { + // auto allocation = dynamic_cast(allocationTags->item(i)); + // auto child = allocation->getFirstChild(); + // if (child == nullptr) { + // continue; + // } + + // XSValue::Status status; + // XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status); + // compInfo.Meta.Allocation += val->fData.fValue.f_int; + //} + + // Save documentation string + auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation")); + if (documentationTags->getLength() != 0) { + auto child = documentationTags->item(0)->getFirstChild(); + if (child != nullptr) { + compInfo.Meta.Annotation = XS::ToString(child->getNodeValue()); + } + } + } else { + LOG_WARNING("Component is missing an annotation!"); + } + + // + auto typeDefinition = element->getTypeDefinition(); + if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) { + LOG_ERROR("Type definition wasn't COMPLEX_TYPE! Skipping."); + continue; + } + auto complexTypeDefinition = dynamic_cast(typeDefinition); + + // + auto modelGroupParticle = complexTypeDefinition->getParticle(); + if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { + LOG_ERROR("Model group particle wasn't TERM_MODELGROUP! Skipping."); + continue; + } + auto modelGroup = modelGroupParticle->getModelGroupTerm(); + + // getParticles(); + for (unsigned int i = 0; i < particles->size(); ++i) { + auto particle = particles->elementAt(i); + if (particle->getTermType() != XSParticle::TERM_ELEMENT) { + LOG_ERROR("Particle wasn't TERM_ELEMENT! Skipping."); + continue; + } + auto elementDeclaration = particle->getElementTerm(); + + std::string name = XS::ToString(elementDeclaration->getName()); + std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->getName()); + + size_t stride = EntityFile::GetTypeStride(type); + if (stride == 0) { + std::cout << "Warning: Field \"" << name << "\" in component \"" << compInfo.Name << "\" uses unexpected field type \"" << type << "\". Skipping." << std::endl; + continue; + } + + compInfo.FieldTypes[name] = type; + compInfo.FieldOffsets[name] = fieldOffset; + fieldOffset += stride; + } + + compInfo.Meta.Stride = fieldOffset; + m_ComponentInfo[compInfo.Name] = compInfo; + } +} + +void EntityFilePreprocessor::parseDefaults() +{ + using namespace xercesc; + + EntityFileXMLErrorHandler errorHandler; + + for (auto& ci : m_ComponentInfo) { + // Allocate memory for default values + ci.second.Defaults = std::shared_ptr(new char[ci.second.Meta.Stride]); + memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride); + + XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); + parser.setErrorHandler(&errorHandler); + + std::string componentName = ci.first; + LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); + boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml"; + + parser.parse(defaultsFile.string().c_str()); + auto doc = parser.getDocument(); + if (doc == nullptr) { + LOG_ERROR("%s not found! Skipping.", defaultsFile.string().c_str()); + continue; + } + + // Find the node in the components namespace matching the component name + std::string tagName = "c:" + componentName; + auto rootNodes = doc->getElementsByTagName(XS::ToXMLCh(tagName)); + if (rootNodes->getLength() == 0) { + LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str()); + continue; + } + auto componentElement = dynamic_cast(rootNodes->item(0)); + + // Fill the default value buffer with values + for (auto& field : ci.second.FieldOffsets) { + std::string fieldName = field.first; + auto fieldNodes = componentElement->getElementsByTagName(XS::ToXMLCh(fieldName)); + auto fieldNode = fieldNodes->item(0); + if (fieldNode == nullptr) { + LOG_ERROR("Defaults for component \"%s\" is missing field \"%s\"!", componentName.c_str(), fieldName.c_str()); + continue; + } + auto fieldElement = dynamic_cast(fieldNode); + + std::string fieldType = ci.second.FieldTypes.at(fieldName); + unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName); + char* data = ci.second.Defaults.get() + fieldOffset; + + // Handle potential field attributes + if (fieldElement->hasAttributes()) { + std::map attributes; + auto attributeMap = fieldElement->getAttributes(); + for (int i = 0; i < attributeMap->getLength(); ++i) { + auto attribItem = attributeMap->item(i); + attributes[XS::ToString(attribItem->getNodeName())] = XS::ToString(attribItem->getNodeValue()); + } + EntityFile::WriteAttributeData(data, fieldType, attributes); + } + + // Handle potential field values + auto childNode = fieldElement->getFirstChild(); + if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) { + char* cstrValue = XMLString::transcode(childNode->getNodeValue()); + EntityFile::WriteValueData(data, fieldType, cstrValue); + XMLString::release(&cstrValue); + } + } + } +} + diff --git a/src/Engine/Core/EntityXMLFile.cpp b/src/Engine/Core/EntityXMLFile.cpp deleted file mode 100644 index 58957347..00000000 --- a/src/Engine/Core/EntityXMLFile.cpp +++ /dev/null @@ -1,451 +0,0 @@ -#include "Core/EntityXMLFile.h" -#include "Core/World.h" - -unsigned int EntityXMLFile::InstanceCount = 0; - -EntityXMLFile::EntityXMLFile(std::string path) - : m_EntityFile(path) -{ - using namespace xercesc; - - if (InstanceCount == 0) { - XMLPlatformUtils::Initialize(); - } - InstanceCount++; - - m_GrammarPool = new XMLGrammarPoolImpl(); - m_ErrorHandler = new EntityParserXMLErrorHandler(); - m_DOMParser = new XercesDOMParser(nullptr, XMLPlatformUtils::fgMemoryManager, m_GrammarPool); - m_DOMParser->setErrorHandler(m_ErrorHandler); - m_DOMParser->setDoNamespaces(true); - m_DOMParser->setDoXInclude(true); - m_DOMParser->setDoSchema(true); - m_DOMParser->setValidationSchemaFullChecking(true); - m_DOMParser->setValidationScheme(xercesc::XercesDOMParser::Val_Auto); - m_DOMParser->setValidationSchemaFullChecking(true); - m_DOMParser->setValidationConstraintFatal(false); - m_DOMParser->setIncludeIgnorableWhitespace(false); - // Make sure schema grammar is kept after validation - m_DOMParser->cacheGrammarFromParse(true); - - // HACK: Use Sax2 parser instead so the entire DOM doesn't have to reside in memory - m_DOMParser->parse(m_EntityFile.c_str()); - m_DOMDocument = m_DOMParser->getDocument(); - - // 1. Fill in ComponentInfo name, fields, default values and metadata from PSVI - parseComponentInfo(); - // 2. Parse default value files for those components - parseDefaults(); - // 3. Allocate component structures - predictComponentAllocation(); -} - -EntityXMLFile::~EntityXMLFile() -{ - using namespace xercesc; - - if (m_DOMParser != nullptr) { - delete m_DOMParser; - } - if (m_ErrorHandler != nullptr) { - delete m_ErrorHandler; - } - if (m_GrammarPool != nullptr) { - delete m_GrammarPool; - } - - InstanceCount--; - if (InstanceCount == 0) { - XMLPlatformUtils::Terminate(); - } -} - -void EntityXMLFile::PopulateWorld(World* world) -{ - for (auto& pair : m_ComponentInfo) { - world->RegisterComponent(pair.second); - } - - // 4. Parse entity hierarchy - auto root = m_DOMDocument->getDocumentElement(); - parseEntityGraph(world, root, 0); -} - -void EntityXMLFile::preprocess(std::string inPath, std::string outPath) -{ - using namespace xercesc; - - static const XMLCh gLS[] = { 'L', 'S', '\0' }; - DOMImplementationLS* di = static_cast(DOMImplementationRegistry::getDOMImplementation(gLS)); - - // Parse the file - DOMLSParser* parser = di->createLSParser(DOMImplementationLS::MODE_SYNCHRONOUS, nullptr); - DOMConfiguration* config = parser->getDomConfig(); - config->setParameter(XMLUni::fgDOMNamespaces, true); - config->setParameter(XMLUni::fgXercesSchema, true); - config->setParameter(XMLUni::fgXercesHandleMultipleImports, true); - config->setParameter(XMLUni::fgXercesSchemaFullChecking, true); - config->setParameter(XMLUni::fgXercesDoXInclude, true); - auto errHandler = new EntityPreprocessorXMLErrorHandler(); - config->setParameter(XMLUni::fgDOMErrorHandler, errHandler); - - auto source = new LocalFileInputSource(XSTR(inPath.c_str())); - Wrapper4InputSource* domSourceWrapper = new Wrapper4InputSource(source); - DOMDocument* doc = parser->parse(dynamic_cast(domSourceWrapper)); - - // Serialize and output the new XML - DOMLSSerializer* writer = di->createLSSerializer(); - DOMLSOutput* output = di->createLSOutput(); - XMLFormatTarget* formatTarget = new LocalFileFormatTarget(outPath.c_str()); - // TODO: MemBufFormatTarget* formatTarget = new MemBufFormatTarget() - output->setByteStream(formatTarget); - writer->write(doc, output); - - delete formatTarget; - output->release(); - writer->release(); - parser->release(); -} - -void EntityXMLFile::parseComponentInfo() -{ - using namespace xercesc; - bool wasChanged; - XSModel* xsModel = m_GrammarPool->getXSModel(wasChanged); - - // Find component xsd element declarations - std::cout << "Enumerating components..." << std::endl; - // - auto topLevelElements = xsModel->getComponents(XSConstants::ELEMENT_DECLARATION); - for (unsigned int i = 0; i < topLevelElements->getLength(); ++i) { - auto element = static_cast(topLevelElements->item(i)); - - std::string nameSpace = XSTR(element->getNamespace()); - if (nameSpace != "components") { - continue; - } - - ComponentInfo compInfo; - - // Name - compInfo.Name = (std::string)XSTR(element->getName()); - // Annotation - auto componentAnnotation = element->getAnnotation(); - if (componentAnnotation != nullptr) { - // Parse annotation XML - char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString()); - MemBufInputSource annotationInput(reinterpret_cast(annotationString), strlen(annotationString), "MemBuf: Annotation String"); - XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager, m_GrammarPool); - parser.setErrorHandler(m_ErrorHandler); - parser.parse(annotationInput); - XMLString::release(&annotationString); - auto doc = parser.getDocument(); - - // Add allocation estimation(s) - auto allocationTags = doc->getElementsByTagName(XSTR("meta:allocation")); - for (int i = 0; i < allocationTags->getLength(); ++i) { - auto allocation = dynamic_cast(allocationTags->item(i)); - auto child = allocation->getFirstChild(); - if (child == nullptr) { - continue; - } - - XSValue::Status status; - XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status); - compInfo.Meta.Allocation += val->fData.fValue.f_int; - } - - // Save documentation string - auto documentationTags = doc->getElementsByTagName(XSTR("xs:documentation")); - if (documentationTags->getLength() != 0) { - auto child = documentationTags->item(0)->getFirstChild(); - if (child != nullptr) { - compInfo.Meta.Annotation = XSTR(child->getNodeValue()); - } - } - // TODO: Parse annotation string XML - // compInfo.Meta.Allocation = ... - } else { - std::cout << "Warning: Component is missing an annotation!" << std::endl; - } - - // - auto typeDefinition = element->getTypeDefinition(); - if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) { - std::cerr << "Error: Type definition wasn't COMPLEX_TYPE! Skipping." << std::endl; - continue; - } - auto complexTypeDefinition = dynamic_cast(typeDefinition); - - // - auto modelGroupParticle = complexTypeDefinition->getParticle(); - if (modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { - std::cerr << "Error: Model group particle wasn't TERM_MODELGROUP! Skipping." << std::endl; - continue; - } - auto modelGroup = modelGroupParticle->getModelGroupTerm(); - - // getParticles(); - for (unsigned int i = 0; i < particles->size(); ++i) { - auto particle = particles->elementAt(i); - if (particle->getTermType() != XSParticle::TERM_ELEMENT) { - std::cerr << "Error: Particle wasn't TERM_ELEMENT! Skipping." << std::endl; - continue; - } - auto elementDeclaration = particle->getElementTerm(); - - std::string name = XSTR(elementDeclaration->getName()); - std::string type = XSTR(elementDeclaration->getTypeDefinition()->getName()); - - size_t stride = getTypeStride(type); - if (stride == 0) { - std::cout << "Warning: Field \"" << name << "\" in component \"" << compInfo.Name << "\" uses unexpected field type \"" << type << "\". Skipping." << std::endl; - continue; - } - - compInfo.FieldTypes[name] = type; - compInfo.FieldOffsets[name] = fieldOffset; - fieldOffset += getTypeStride(type); - } - - compInfo.Meta.Stride = fieldOffset; - m_ComponentInfo[compInfo.Name] = compInfo; - } -} - -void EntityXMLFile::parseDefaults() -{ - using namespace xercesc; - - for (auto& ci : m_ComponentInfo) { - // Allocate memory for default values - ci.second.Defaults = std::shared_ptr(new char[ci.second.Meta.Stride]); - memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride); - - XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); - parser.setErrorHandler(m_ErrorHandler); - - std::string componentName = ci.first; - LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); - boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml"; - - parser.parse(defaultsFile.string().c_str()); - auto doc = parser.getDocument(); - if (doc == nullptr) { - LOG_ERROR("%s not found! Skipping.", defaultsFile.string().c_str()); - continue; - } - - // Find the node in the components namespace matching the component name - std::string tagName = "c:" + componentName; - auto rootNodes = doc->getElementsByTagName(XSTR(tagName.c_str())); - if (rootNodes->getLength() == 0) { - LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str()); - continue; - } - auto componentElement = dynamic_cast(rootNodes->item(0)); - - // Fill the default value buffer with values - for (auto& field : ci.second.FieldOffsets) { - std::string fieldName = field.first; - auto fieldNodes = componentElement->getElementsByTagName(XSTR(fieldName.c_str())); - auto fieldNode = fieldNodes->item(0); - if (fieldNode == nullptr) { - LOG_ERROR("Defaults for component \"%s\" is missing field \"%s\"!", componentName.c_str(), fieldName.c_str()); - continue; - } - auto fieldElement = dynamic_cast(fieldNode); - - std::string fieldType = ci.second.FieldTypes.at(fieldName); - unsigned int fieldOffset = ci.second.FieldOffsets.at(fieldName); - writeData(fieldElement, fieldType, ci.second.Defaults.get() + fieldOffset); - } - } -} - -void EntityXMLFile::predictComponentAllocation() -{ - using namespace xercesc; - - auto root = m_DOMDocument->getDocumentElement(); - - // Count static instances of components present in entity hierarchy - auto components = m_DOMDocument->getElementsByTagNameNS(XSTR("components"), XSTR("*")); - for (int i = 0; i < components->getLength(); ++i) { - auto component = dynamic_cast(components->item(i)); - - std::string componentName = XSTR(component->getLocalName()); - auto& compInfo = m_ComponentInfo.at(componentName); - compInfo.Meta.Allocation += 1; - } - - std::cout << "COMPONENT INFO" << std::endl; - for (auto& pair : m_ComponentInfo) { - ComponentInfo& ci = pair.second; - std::cout << "Component: " << ci.Name << " (" << ci.Meta.Annotation << ")" << std::endl; - std::cout << " Allocation: " << ci.Meta.Allocation << std::endl; - std::cout << " Fields:" << std::endl; - - // Calculate component size - std::size_t stride = 0; - // Add size of fields - for (auto& field : ci.FieldTypes) { - std::cout << " " << field.second << " " << field.first << " (" << getTypeStride(field.second) << " byte)" << std::endl; - stride += getTypeStride(field.second); - } - std::cout << " Stride: " << ci.Meta.Stride << std::endl; - } -} - -void EntityXMLFile::parseEntityGraph(World* world, xercesc::DOMElement* element, EntityID parentEntity) -{ - using namespace xercesc; - - // Create entity - EntityID entity = world->CreateEntity(parentEntity); - LOG_DEBUG("Created entity %i, parent %i", entity, parentEntity); - - // Add components - auto components = m_DOMDocument->evaluate(XSTR("Components/*"), element, nullptr, DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, nullptr); - for (int i = 0; i < components->getSnapshotLength(); i++) { - components->snapshotItem(i); - auto componentElement = dynamic_cast(components->getNodeValue()); - std::string componentName = XSTR(componentElement->getLocalName()); - auto& ci = m_ComponentInfo.at(componentName); - - // Attach the component - auto c = world->AttachComponent(entity, componentName); - LOG_DEBUG("Attached %s component", componentName.c_str()); - - // Write field data - auto fields = componentElement->getChildNodes(); - for (int j = 0; j < fields->getLength(); ++j) { - auto fieldNode = fields->item(j); - auto nodeType = fieldNode->getNodeType(); - if (nodeType != DOMNode::ELEMENT_NODE) { - continue; - } - auto field = dynamic_cast(fields->item(j)); - //const XMLCh* value = fields->item(j)->getTextContent(); - std::string fieldName(XSTR(field->getLocalName())); - if (ci.FieldTypes.find(fieldName) == ci.FieldTypes.end()) { - std::cout << "Warning: Component \"" << componentName << "\" contains invalid field \"" << fieldName << "\". Skipping." << std::endl; - continue; - } - - std::string fieldType = ci.FieldTypes.at(fieldName); - unsigned int fieldOffset = ci.FieldOffsets.at(fieldName); - std::string fieldValue(XSTR(field->getTextContent())); - LOG_DEBUG(" %s %s = %s", fieldType.c_str(), fieldName.c_str(), fieldValue.c_str()); - writeData(field, fieldType, c.Data + fieldOffset); - } - } - - // Recurse children entities - auto children = m_DOMDocument->evaluate(XSTR("Children/Entity"), element, nullptr, DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, nullptr); - for (int i = 0; i < children->getSnapshotLength(); i++) { - children->snapshotItem(i); - parseEntityGraph(world, dynamic_cast(children->getNodeValue()), entity); - } - - // Recurse children entity references - auto refs = m_DOMDocument->evaluate(XSTR("Children/EntityRef"), element, nullptr, DOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE, nullptr); - for (int i = 0; i < refs->getSnapshotLength(); i++) { - refs->snapshotItem(i); - auto entityRefElement = dynamic_cast(refs->getNodeValue()); - auto attribute = entityRefElement->getAttribute(XSTR("file")); - if (attribute == nullptr) { - continue; - } - - std::string file((const char*)XSTR(attribute)); - boost::filesystem::path absolutePath = boost::filesystem::path(m_EntityFile).parent_path() / file; - ResourceManager::Load(absolutePath.string())->PopulateWorld(world); - } -} - -std::size_t EntityXMLFile::getTypeStride(std::string typeName) -{ - std::map typeStrides{ - { "bool", sizeof(bool) }, - { "int", sizeof(int) }, - { "float", sizeof(float) }, - { "double", sizeof(double) }, - { "string", sizeof(std::string) }, - { "Vector", sizeof(glm::vec3) }, - { "Quaternion", sizeof(glm::quat) }, - { "Color", sizeof(glm::vec4) } - }; - - auto it = typeStrides.find(typeName); - return (it != typeStrides.end()) ? it->second : 0; -} - -float EntityXMLFile::getFloatAttribute(const xercesc::DOMElement* element, const char* attribute) const -{ - using namespace xercesc; - XSValue::Status status; - XSValue* val = XSValue::getActualValue(element->getAttribute(XSTR(attribute)), xercesc::XSValue::DataType::dt_double, status); - if (val == nullptr) { - LOG_ERROR("Element \"%s\" doesn't have an \"%s\" attribute!", XSTR(element->getTagName()), attribute); - return 0.f; - } else { - return static_cast(val->fData.fValue.f_double); - } -} - -void EntityXMLFile::writeData(const xercesc::DOMElement* element, std::string typeName, char* outData) -{ - using namespace xercesc; - - if (typeName == "Vector") { - glm::vec3 vec; - vec.x = getFloatAttribute(element, "X"); - vec.y = getFloatAttribute(element, "Y"); - vec.z = getFloatAttribute(element, "Z"); - memcpy(outData, reinterpret_cast(&vec), getTypeStride(typeName)); - } else if (typeName == "Color") { - glm::vec4 vec; - vec.r = getFloatAttribute(element, "R"); - vec.g = getFloatAttribute(element, "G"); - vec.b = getFloatAttribute(element, "B"); - vec.a = getFloatAttribute(element, "A"); - memcpy(outData, reinterpret_cast(&vec), getTypeStride(typeName)); - } else if (typeName == "Quaternion") { - glm::quat q; - q.x = getFloatAttribute(element, "X"); - q.y = getFloatAttribute(element, "Y"); - q.z = getFloatAttribute(element, "Z"); - q.w = getFloatAttribute(element, "W"); - memcpy(outData, reinterpret_cast(&q), getTypeStride(typeName)); - } else if (typeName == "float") { - XSValue::Status status; - XSValue* val = XSValue::getActualValue(element->getTextContent(), xercesc::XSValue::DataType::dt_float, status); - memcpy(outData, reinterpret_cast(&val->fData.fValue.f_float), getTypeStride(typeName)); - } else if (typeName == "double") { - XSValue::Status status; - XSValue* val = XSValue::getActualValue(element->getTextContent(), xercesc::XSValue::DataType::dt_double, status); - memcpy(outData, reinterpret_cast(&val->fData.fValue.f_double), getTypeStride(typeName)); - } else if (typeName == "bool") { - XSValue::Status status; - XSValue* val = XSValue::getActualValue(element->getTextContent(), xercesc::XSValue::DataType::dt_boolean, status); - memcpy(outData, reinterpret_cast(&val->fData.fValue.f_bool), getTypeStride(typeName)); - } else { - XSValue::DataType dataType = XSValue::getDataType(XSTR(typeName.c_str())); - if (dataType == XSValue::DataType::dt_string) { - char* str = XMLString::transcode(element->getTextContent()); - std::string standardString(str); - new (outData) std::string(str); - XMLString::release(&str); - //memcpy(outData, reinterpret_cast(&standardString), getTypeStride(typeName)); - } else { - //XSValue::Status status; - //XSValue* val = XSValue::getActualValue(element->getTextContent(), dataType, status); - //memcpy(outData, reinterpret_cast(&val->fData.fValue), getTypeStride(typeName)); - LOG_WARNING("Unknown native data type: %s", typeName.c_str()); - } - } -} \ No newline at end of file diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index c2957d02..1e9e15aa 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -8,7 +8,6 @@ Game::Game(int argc, char* argv[]) ResourceManager::RegisterType("ConfigFile"); ResourceManager::RegisterType("Model"); ResourceManager::RegisterType("Texture"); - ResourceManager::RegisterType("EntityXMLFile"); ResourceManager::RegisterType("ShaderProgram"); ResourceManager::RegisterType("EntityFile"); @@ -50,7 +49,7 @@ Game::Game(int argc, char* argv[]) std::string mapToLoad = m_Config->Get("Debug.LoadMap", ""); if (!mapToLoad.empty()) { auto file = ResourceManager::Load(mapToLoad); - EntityFilePreprocessor fpp(mapToLoad); + EntityFilePreprocessor fpp(file); fpp.RegisterComponents(m_World); EntityFileParser fp(file); fp.MergeEntities(m_World);