#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.Stride); // LOG_DEBUG("Allocation: %i", info.Meta->Allocation); // for (auto& kv : info.Fields) { // auto& field = kv.second; // LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type.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 // 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; compInfo.Meta = std::make_shared(); // Name compInfo.Name = XS::ToString(element->getName()); bool brk = compInfo.Name == "HiddenForLocalPlayer"; // Known allocation compInfo.Meta->Allocation = m_ComponentCounts[compInfo.Name]; // Annotation auto componentAnnotation = element->getAnnotation(); if (componentAnnotation != nullptr) { compInfo.Meta->Annotation = parseAnnotationXML(componentAnnotation->getAnnotationString()); } else { //LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str()); } // auto typeDefinition = element->getTypeDefinition(); // Allow empty components if (typeDefinition == nullptr) { continue; } if (typeDefinition->getTypeCategory() != XSTypeDefinition::COMPLEX_TYPE) { LOG_ERROR("Failed to parse component definition for \"%s\": Type definition wasn't COMPLEX_TYPE!", compInfo.Name.c_str()); continue; } auto complexTypeDefinition = dynamic_cast(typeDefinition); // auto modelGroupParticle = complexTypeDefinition->getParticle(); if (modelGroupParticle == nullptr || modelGroupParticle->getTermType() != XSParticle::TERM_MODELGROUP) { LOG_ERROR("Failed to parse component definition for \"%s\": Model group particle was null or wasn't TERM_MODELGROUP!", compInfo.Name.c_str()); 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("Failed to parse a field definition in component \"%s\": Particle wasn't TERM_ELEMENT! Skipping.", compInfo.Name.c_str()); continue; } auto elementDeclaration = particle->getElementTerm(); std::string name = XS::ToString(elementDeclaration->getName()); std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->getName()); std::string typeNamespace = XS::ToString(elementDeclaration->getTypeDefinition()->getNamespace()); std::string baseType = XS::ToString(elementDeclaration->getTypeDefinition()->getBaseType()->getName()); std::string effectiveType = type; unsigned int stride = EntityFile::GetTypeStride(type); if (stride == 0) { stride = EntityFile::GetTypeStride(baseType); if (stride == 0) { LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\" with base type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str(), baseType.c_str()); continue; } effectiveType = baseType; } // Annotation auto fieldAnnotation = elementDeclaration->getAnnotation(); if (fieldAnnotation != nullptr) { compInfo.Meta->FieldAnnotations[name] = parseAnnotationXML(fieldAnnotation->getAnnotationString()); } else { //LOG_WARNING("Component field \"%s.%s\" is missing an annotation!", compInfo.Name.c_str(), name.c_str()); } if (effectiveType == "enum") { // Parse potential enum type definition for field type if (compInfo.Meta->FieldEnumDefinitions.count(name) == 0) { auto enumTypeDefinition = xsModel->getTypeDefinition(XS::ToXMLCh(type), XS::ToXMLCh("components")); auto xsComplexType = dynamic_cast(enumTypeDefinition); auto xsComplexContent = xsComplexType->getParticle(); auto xsExtension = xsComplexContent->getModelGroupTerm(); auto xsExtensionParticles = xsExtension->getParticles(); auto xsChoice = xsExtensionParticles->elementAt(0)->getModelGroupTerm(); auto xsChoiceParticles = xsChoice->getParticles(); for (int i = 0; i < xsChoiceParticles->size(); ++i) { auto enumElement = xsChoiceParticles->elementAt(i)->getElementTerm(); std::string enumName = XS::ToString(enumElement->getName()); std::string enumValue = XS::ToString(enumElement->getConstraintValue()); compInfo.Meta->FieldEnumDefinitions[name][enumName] = boost::lexical_cast(enumValue); //LOG_DEBUG("ENUM %s = %s", enumName.c_str(), enumValue.c_str()); } } } auto& field = compInfo.Fields[name]; field.Name = name; field.Type = effectiveType; field.Offset = fieldOffset; field.Stride = stride; compInfo.FieldsInOrder.push_back(name); fieldOffset += stride; } compInfo.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.Stride]); memset(ci.second.Defaults.get(), 0, ci.second.Stride); std::string componentName = ci.first; XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); parser.setDoSchema(true); parser.setDoNamespaces(true); parser.setErrorHandler(&errorHandler); parser.setValidationScheme(XercesDOMParser::Val_Always); parser.setValidationSchemaFullChecking(true); //parser.setDoNamespaces(true); //boost::filesystem::path schemaLocation = "Schema/Components/" + componentName + ".xsd"; //std::string namespaceSchema = schemaLocation.string(); //parser.setExternalNoNamespaceSchemaLocation("Teamasdasdasdasd.xsd"); //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 = 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& kv : ci.second.Fields) { std::string fieldName = kv.first; auto& field = kv.second; 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); char* data = ci.second.Defaults.get() + field.Offset; // 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, field, attributes); } auto childNode = fieldElement->getFirstChild(); if (childNode == nullptr) { continue; } // An enum will either have an element node with a text node inside, // or contain a text node directly. if (childNode->getNodeType() == DOMNode::ELEMENT_NODE) { childNode = childNode->getFirstChild(); } // Handle potential field values if (childNode->getNodeType() == DOMNode::TEXT_NODE) { char* cstrValue = XMLString::transcode(childNode->getNodeValue()); EntityFile::WriteValueData(data, field, cstrValue); XMLString::release(&cstrValue); } } } } std::string EntityFilePreprocessor::parseAnnotationXML(const XMLCh* xml) { using namespace xercesc; // Parse annotation XML char* annotationString = XMLString::transcode(xml); MemBufInputSource annotationInput(reinterpret_cast(annotationString), strlen(annotationString), "MemBuf: Annotation String"); XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); //parser.setErrorHandler(&errorHandler); parser.parse(annotationInput); XMLString::release(&annotationString); auto doc = parser.getDocument(); // Save documentation string auto documentationTags = doc->getElementsByTagName(XS::ToXMLCh("xs:documentation")); if (documentationTags->getLength() != 0) { auto child = documentationTags->item(0)->getFirstChild(); if (child != nullptr) { return XS::ToString(child->getNodeValue()); } } return std::string(); }