Added enum support to entity file format, see "Team" component for an example. Use ComponentInfo::Enum to convert enum string keys to its corresponding integer representation at runtime.

This commit is contained in:
2016-01-16 22:48:08 +01:00
parent f65ac65e30
commit 9ec32464bc
17 changed files with 383 additions and 222 deletions
+4 -2
View File
@@ -9,7 +9,8 @@ struct ComponentInfo
{ {
std::string Annotation; std::string Annotation;
unsigned int Allocation = 0; unsigned int Allocation = 0;
unsigned int Stride = 0; std::map<std::string, std::string> FieldAnnotations;
std::map<std::string, std::map<std::string, int>> FieldEnumDefinitions;
}; };
struct Field_t struct Field_t
@@ -23,8 +24,9 @@ struct ComponentInfo
std::string Name; std::string Name;
std::unordered_map<std::string, Field_t> Fields; std::unordered_map<std::string, Field_t> Fields;
std::vector<std::string> FieldsInOrder; std::vector<std::string> FieldsInOrder;
Meta_t Meta; unsigned int Stride = 0;
std::shared_ptr<char> Defaults = nullptr; std::shared_ptr<char> Defaults = nullptr;
std::shared_ptr<Meta_t> Meta = nullptr;
}; };
template<> template<>
+1 -1
View File
@@ -43,7 +43,7 @@ public:
ComponentPool(const ::ComponentInfo& ci) ComponentPool(const ::ComponentInfo& ci)
: m_ComponentInfo(ci) : m_ComponentInfo(ci)
, m_Pool(ci.Meta.Allocation, sizeof(EntityID) + ci.Meta.Stride) , m_Pool(ci.Meta->Allocation, sizeof(EntityID) + ci.Stride)
{ } { }
ComponentPool(const ComponentPool& other) = delete; ComponentPool(const ComponentPool& other) = delete;
ComponentPool(const ComponentPool&& other) = delete; ComponentPool(const ComponentPool&& other) = delete;
+14 -5
View File
@@ -6,6 +6,7 @@
#include "ComponentInfo.h" #include "ComponentInfo.h"
#include "Util/Any.h" #include "Util/Any.h"
// TODO: Change all instances "Property" to "Field" to remain consistent with ComponentInfo
struct ComponentWrapper struct ComponentWrapper
{ {
ComponentWrapper(const ComponentInfo& componentInfo, char* data) ComponentWrapper(const ComponentInfo& componentInfo, char* data)
@@ -18,6 +19,11 @@ struct ComponentWrapper
const ::EntityID EntityID; const ::EntityID EntityID;
char* Data; char* Data;
int Enum(const char* fieldName, const char* enumKey)
{
return Info.Meta->FieldEnumDefinitions.at(fieldName).at(enumKey);
}
template <typename T> template <typename T>
T& Property(std::string name) T& Property(std::string name)
{ {
@@ -33,7 +39,7 @@ struct ComponentWrapper
// Specialization for string literals // Specialization for string literals
template <std::size_t N> template <std::size_t N>
void SetProperty(std::string name, const char(&value)[N]) { Property<std::string>(name) = std::string(value); } void SetProperty(std::string name, const char(&value)[N]) { Property<std::string>(name) = std::string(value); }
struct SubscriptProxy struct SubscriptProxy
{ {
friend struct ComponentWrapper; friend struct ComponentWrapper;
@@ -47,6 +53,9 @@ struct ComponentWrapper
std::string m_PropertyName; std::string m_PropertyName;
public: public:
// Return the integer value of an enum type key for this field
int Enum(const char* enumKey) { return m_Component->Enum(m_PropertyName.c_str(), enumKey); }
template <typename T> template <typename T>
operator T&() { return m_Component->Property<T>(m_PropertyName); } operator T&() { return m_Component->Property<T>(m_PropertyName); }
@@ -71,7 +80,7 @@ public:
ComponentWrapperFactory(std::string componentTypeName, std::size_t allocation = 0) ComponentWrapperFactory(std::string componentTypeName, std::size_t allocation = 0)
{ {
m_ComponentInfo.Name = componentTypeName; m_ComponentInfo.Name = componentTypeName;
m_ComponentInfo.Meta.Allocation = allocation; m_ComponentInfo.Meta->Allocation = allocation;
} }
template <typename T> template <typename T>
@@ -79,14 +88,14 @@ public:
{ {
m_DefaultValues.push_back(defaultValue); m_DefaultValues.push_back(defaultValue);
m_ComponentInfo.Fields[fieldName].Name = typeid(T).name(); m_ComponentInfo.Fields[fieldName].Name = typeid(T).name();
m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Meta.Stride; m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Stride;
m_ComponentInfo.Fields[fieldName].Stride = sizeof(T); m_ComponentInfo.Fields[fieldName].Stride = sizeof(T);
m_ComponentInfo.Meta.Stride += sizeof(T); m_ComponentInfo.Stride += sizeof(T);
} }
ComponentInfo& Finalize() ComponentInfo& Finalize()
{ {
m_ComponentInfo.Defaults = std::shared_ptr<char>(new char[m_ComponentInfo.Meta.Stride]); m_ComponentInfo.Defaults = std::shared_ptr<char>(new char[m_ComponentInfo.Stride]);
std::size_t offset = 0; std::size_t offset = 0;
for (auto& val : m_DefaultValues) { for (auto& val : m_DefaultValues) {
memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size); memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size);
+8 -8
View File
@@ -285,7 +285,7 @@ private:
XSValue::Status status; XSValue::Status status;
XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status); XSValue* val = XSValue::getActualValue(child->getNodeValue(), XSValue::dt_integer, status);
compInfo.Meta.Allocation += val->fData.fValue.f_int; compInfo.Meta->Allocation += val->fData.fValue.f_int;
} }
// Save documentation string // Save documentation string
@@ -293,11 +293,11 @@ private:
if (documentationTags->getLength() != 0) { if (documentationTags->getLength() != 0) {
auto child = documentationTags->item(0)->getFirstChild(); auto child = documentationTags->item(0)->getFirstChild();
if (child != nullptr) { if (child != nullptr) {
compInfo.Meta.Annotation = XSTR(child->getNodeValue()); compInfo.Meta->Annotation = XSTR(child->getNodeValue());
} }
} }
// TODO: Parse annotation string XML // TODO: Parse annotation string XML
// compInfo.Meta.Allocation = ... // compInfo.Meta->Allocation = ...
} else { } else {
std::cout << "Warning: Component is missing an annotation!" << std::endl; std::cout << "Warning: Component is missing an annotation!" << std::endl;
} }
@@ -344,7 +344,7 @@ private:
fieldOffset += getTypeStride(type); fieldOffset += getTypeStride(type);
} }
compInfo.Meta.Stride = fieldOffset; compInfo.Stride = fieldOffset;
m_ComponentInfo[compInfo.Name] = compInfo; m_ComponentInfo[compInfo.Name] = compInfo;
} }
} }
@@ -367,14 +367,14 @@ private:
std::string componentName = XSTR(component->getLocalName()); std::string componentName = XSTR(component->getLocalName());
auto& compInfo = m_ComponentInfo.at(componentName); auto& compInfo = m_ComponentInfo.at(componentName);
compInfo.Meta.Allocation += 1; compInfo.Meta->Allocation += 1;
} }
std::cout << "COMPONENT INFO" << std::endl; std::cout << "COMPONENT INFO" << std::endl;
for (auto& pair : m_ComponentInfo) { for (auto& pair : m_ComponentInfo) {
ComponentInfo& ci = pair.second; ComponentInfo& ci = pair.second;
std::cout << "Component: " << ci.Name << " (" << ci.Meta.Annotation << ")" << std::endl; std::cout << "Component: " << ci.Name << " (" << ci.Meta->Annotation << ")" << std::endl;
std::cout << " Allocation: " << ci.Meta.Allocation << std::endl; std::cout << " Allocation: " << ci.Meta->Allocation << std::endl;
std::cout << " Fields:" << std::endl; std::cout << " Fields:" << std::endl;
// Calculate component size // Calculate component size
@@ -393,7 +393,7 @@ private:
cs.ComponentName = ci.Name; cs.ComponentName = ci.Name;
cs.Stride = stride; cs.Stride = stride;
cs.Info = ci; cs.Info = ci;
cs.Data = new char[stride*ci.Meta.Allocation]; cs.Data = new char[stride*ci.Meta->Allocation];
m_ComponentStore[cs.ComponentName] = cs; m_ComponentStore[cs.ComponentName] = cs;
} }
} }
+18 -147
View File
@@ -73,88 +73,15 @@ public:
ComponentField ComponentField
}; };
EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader);
: m_Handler(handler)
, m_Reader(reader)
{
// 0 is imaginary base parent
m_EntityStack.push(0);
m_StateStack.push(State::Unknown);
}
void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override void startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs) override;
{ void characters(const XMLCh* const chars, const XMLSize_t length) override;
std::string name = XS::ToString(_localName); void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override;
if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) { void warning(const xercesc::SAXParseException& e);
if (name == "Entity") { void error(const xercesc::SAXParseException& e);
m_StateStack.push(State::Entity); void fatalError(const xercesc::SAXParseException& e);
onStartEntity(attrs);
return;
}
if (name == "EntityRef") {
onStartEntityRef(attrs);
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Entity) {
if (uri == "components") {
m_StateStack.push(State::Component);
onStartComponent(name);
return;
}
}
if (m_StateStack.top() == State::Component) {
m_StateStack.push(State::ComponentField);
onStartComponentField(name, attrs);
return;
}
}
void characters(const XMLCh* const chars, const XMLSize_t length) override
{
if (m_StateStack.top() == State::ComponentField) {
char* transcoded = xercesc::XMLString::transcode(chars);
onFieldData(transcoded);
}
}
void endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname) override
{
std::string name = XS::ToString(_localName);
if (m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.pop();
onEndEntity();
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Component) {
//if (uri == "components") {
m_StateStack.pop();
onEndComponent(name);
return;
//}
}
if (m_StateStack.top() == State::ComponentField) {
m_StateStack.pop();
onEndComponentField(name);
return;
}
}
void fatalError(const xercesc::SAXParseException& e)
{
XS::ToString s(e.getMessage());
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
//throw e;
}
private: private:
const EntityFileHandler* m_Handler; const EntityFileHandler* m_Handler;
@@ -168,73 +95,14 @@ private:
std::string m_CurrentField; std::string m_CurrentField;
std::map<std::string, std::string> m_CurrentAttributes; std::map<std::string, std::string> m_CurrentAttributes;
void onStartEntity(const xercesc::Attributes& attrs) void onStartEntity(const xercesc::Attributes& attrs);
{ void onEndEntity();
EntityID parent = m_EntityStack.top(); void onStartEntityRef(const xercesc::Attributes& attrs);
void onStartComponent(const std::string& name);
if (m_Handler->m_OnStartEntityCallback) { void onEndComponent(const std::string& name);
std::string name; void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs);
auto xName = attrs.getValue(XS::ToXMLCh("name")); void onEndComponentField(const std::string& field);
if (xName != nullptr) { void onFieldData(char* data);
name = XS::ToString(xName);
}
m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name);
}
m_EntityStack.push(m_NextEntityID);
m_NextEntityID++;
}
void onEndEntity()
{
m_EntityStack.pop();
}
void onStartEntityRef(const xercesc::Attributes& attrs)
{
std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file")));
xercesc::SAX2XMLReader* parser = xercesc::XMLReaderFactory::createXMLReader();
parser->setContentHandler(this);
parser->setErrorHandler(this);
parser->parse(path.c_str());
delete parser;
}
void onStartComponent(const std::string& name)
{
//LOG_DEBUG(" Component: %s", name.c_str());
m_CurrentComponent = name;
if (m_Handler->m_OnStartComponentCallback) {
m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name);
}
}
void onEndComponent(const std::string& name) { }
void onStartComponentField(const std::string& field, const xercesc::Attributes& attrs)
{
//LOG_DEBUG(" Field: %s", field.c_str());
m_CurrentField = field;
m_CurrentAttributes.clear();
for (int i = 0; i < attrs.getLength(); i++) {
auto name = attrs.getQName(i);
auto value = attrs.getValue(name);
//LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value));
m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string();
}
if (m_Handler->m_OnStartFieldCallback) {
m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes);
}
}
void onEndComponentField(const std::string& field) { }
void onFieldData(char* data)
{
//LOG_DEBUG(" Data: %s", data);
if (m_Handler->m_OnStartFieldDataCallback) {
m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data);
}
xercesc::XMLString::release(&data);
}
}; };
class EntityFileXMLErrorHandler : public xercesc::ErrorHandler class EntityFileXMLErrorHandler : public xercesc::ErrorHandler
@@ -269,6 +137,7 @@ private:
class EntityFile : public Resource class EntityFile : public Resource
{ {
friend class ResourceManager; friend class ResourceManager;
friend class EntityFileSAXHandler;
private: private:
EntityFile(boost::filesystem::path path); EntityFile(boost::filesystem::path path);
~EntityFile(); ~EntityFile();
@@ -288,6 +157,8 @@ private:
xercesc::SAX2XMLReader* m_SAX2XMLReader; xercesc::SAX2XMLReader* m_SAX2XMLReader;
//std::map<std::string, ::ComponentInfo> m_ComponentInfo; //std::map<std::string, ::ComponentInfo> m_ComponentInfo;
//std::vector<std::string> m_EntityReferences; //std::vector<std::string> m_EntityReferences;
static void setReaderFeatures(xercesc::SAX2XMLReader* reader);
}; };
#endif #endif
@@ -5,6 +5,7 @@
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp> #include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
#include <xercesc/framework/psvi/XSParticle.hpp> #include <xercesc/framework/psvi/XSParticle.hpp>
#include <xercesc/framework/psvi/XSModelGroup.hpp> #include <xercesc/framework/psvi/XSModelGroup.hpp>
#include <xercesc/framework/psvi/XSModelGroupDefinition.hpp>
#include <xercesc/framework/psvi/XSAnnotation.hpp> #include <xercesc/framework/psvi/XSAnnotation.hpp>
#include <xercesc/framework/psvi/XSValue.hpp> #include <xercesc/framework/psvi/XSValue.hpp>
#include <xercesc/framework/MemBufFormatTarget.hpp> #include <xercesc/framework/MemBufFormatTarget.hpp>
@@ -31,6 +32,7 @@ private:
void onStartComponent(EntityID entity, std::string type); void onStartComponent(EntityID entity, std::string type);
void parseComponentInfo(); void parseComponentInfo();
void parseDefaults(); void parseDefaults();
std::string parseAnnotationXML(const XMLCh* xml);
}; };
#endif #endif
+1
View File
@@ -18,4 +18,5 @@
<xs:include schemaLocation="Components/Spawner.xsd"/> <xs:include schemaLocation="Components/Spawner.xsd"/>
<xs:include schemaLocation="Components/SpawnPoint.xsd"/> <xs:include schemaLocation="Components/SpawnPoint.xsd"/>
<xs:include schemaLocation="Components/PlayerSpawn.xsd"/> <xs:include schemaLocation="Components/PlayerSpawn.xsd"/>
<xs:include schemaLocation="Components/Team.xsd"/>
</xs:schema> </xs:schema>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Team xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Team.xsd">
<Team><Spectator/></Team>
</Team>
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:complexType name="TeamEnum" mixed="true">
<xs:complexContent>
<xs:extension base="t:enum">
<xs:choice>
<xs:element name="Spectator" type="xs:integer" fixed="1" minOccurs="0"/>
<xs:element name="Red" type="xs:integer" fixed="2" minOccurs="0"/>
<xs:element name="Blue" type="xs:integer" fixed="3" minOccurs="0"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="Team">
<xs:annotation>
<xs:documentation>Represents entity team affiliation</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:all>
<xs:element name="Team" type="TeamEnum" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
+3
View File
@@ -4,6 +4,9 @@
<xs:include schemaLocation="Types/Quaternion.xsd"/> <xs:include schemaLocation="Types/Quaternion.xsd"/>
<xs:include schemaLocation="Types/Vector.xsd"/> <xs:include schemaLocation="Types/Vector.xsd"/>
<xs:include schemaLocation="Types/Color.xsd"/> <xs:include schemaLocation="Types/Color.xsd"/>
<xs:complexType name="enum" mixed="true">
<xs:choice></xs:choice>
</xs:complexType>
<xs:simpleType name="bool"> <xs:simpleType name="bool">
<xs:restriction base="xs:boolean"></xs:restriction> <xs:restriction base="xs:boolean"></xs:restriction>
</xs:simpleType> </xs:simpleType>
+1
View File
@@ -27,6 +27,7 @@
<xs:element ref="c:Spawner" minOccurs="0"/> <xs:element ref="c:Spawner" minOccurs="0"/>
<xs:element ref="c:SpawnPoint" minOccurs="0"/> <xs:element ref="c:SpawnPoint" minOccurs="0"/>
<xs:element ref="c:PlayerSpawn" minOccurs="0"/> <xs:element ref="c:PlayerSpawn" minOccurs="0"/>
<xs:element ref="c:Team" minOccurs="0"/>
</xs:all> </xs:all>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
+182 -5
View File
@@ -21,16 +21,24 @@ void EntityFile::Parse(const EntityFileHandler* handler) const
using namespace xercesc; using namespace xercesc;
EntityFileSAXHandler saxHandler(handler, nullptr); EntityFileSAXHandler saxHandler(handler, nullptr);
m_SAX2XMLReader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true); setReaderFeatures(m_SAX2XMLReader);
m_SAX2XMLReader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
m_SAX2XMLReader->setFeature(XMLUni::fgXercesSchema, true);
m_SAX2XMLReader->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
m_SAX2XMLReader->setContentHandler(&saxHandler); m_SAX2XMLReader->setContentHandler(&saxHandler);
m_SAX2XMLReader->setErrorHandler(&saxHandler); m_SAX2XMLReader->setErrorHandler(&saxHandler);
m_SAX2XMLReader->setDeclarationHandler(&saxHandler); m_SAX2XMLReader->setDeclarationHandler(&saxHandler);
m_SAX2XMLReader->parse(m_FilePath.string().c_str()); m_SAX2XMLReader->parse(m_FilePath.string().c_str());
} }
void EntityFile::setReaderFeatures(xercesc::SAX2XMLReader* reader)
{
using namespace xercesc;
reader->setFeature(XMLUni::fgXercesCacheGrammarFromParse, true);
reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
reader->setFeature(XMLUni::fgSAX2CoreValidation, true);
reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
reader->setFeature(XMLUni::fgXercesSchema, true);
reader->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
}
std::size_t EntityFile::GetTypeStride(std::string typeName) std::size_t EntityFile::GetTypeStride(std::string typeName)
{ {
std::map<std::string, size_t> typeStrides{ std::map<std::string, size_t> typeStrides{
@@ -39,6 +47,7 @@ std::size_t EntityFile::GetTypeStride(std::string typeName)
{ "float", sizeof(float) }, { "float", sizeof(float) },
{ "double", sizeof(double) }, { "double", sizeof(double) },
{ "string", sizeof(std::string) }, { "string", sizeof(std::string) },
{ "enum", sizeof(int) },
{ "Vector", sizeof(glm::vec3) }, { "Vector", sizeof(glm::vec3) },
{ "Quaternion", sizeof(glm::quat) }, { "Quaternion", sizeof(glm::quat) },
{ "Color", sizeof(glm::vec4) } { "Color", sizeof(glm::vec4) }
@@ -77,7 +86,7 @@ void EntityFile::WriteAttributeData(char* outData, const ComponentInfo::Field_t&
void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData) void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& field, const char* valueData)
{ {
if (field.Type == "int") { if (field.Type == "int" || field.Type == "enum") {
int value = boost::lexical_cast<int>(valueData); int value = boost::lexical_cast<int>(valueData);
memcpy(outData, reinterpret_cast<char*>(&value), field.Stride); memcpy(outData, reinterpret_cast<char*>(&value), field.Stride);
} else if (field.Type == "float") { } else if (field.Type == "float") {
@@ -95,3 +104,171 @@ void EntityFile::WriteValueData(char* outData, const ComponentInfo::Field_t& fie
LOG_WARNING("Unknown value data type: %s", field.Type.c_str()); LOG_WARNING("Unknown value data type: %s", field.Type.c_str());
} }
} }
EntityFileSAXHandler::EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader) : m_Handler(handler)
, m_Reader(reader)
{
// 0 is imaginary base parent
m_EntityStack.push(0);
m_StateStack.push(State::Unknown);
}
void EntityFileSAXHandler::startElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname, const xercesc::Attributes& attrs)
{
std::string name = XS::ToString(_localName);
if (m_StateStack.top() == State::Unknown || m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.push(State::Entity);
onStartEntity(attrs);
return;
}
if (name == "EntityRef") {
onStartEntityRef(attrs);
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Entity) {
if (uri == "components") {
m_StateStack.push(State::Component);
onStartComponent(name);
return;
}
}
if (m_StateStack.top() == State::Component) {
m_StateStack.push(State::ComponentField);
onStartComponentField(name, attrs);
return;
}
}
void EntityFileSAXHandler::endElement(const XMLCh* const _uri, const XMLCh* const _localName, const XMLCh* const _qname)
{
std::string name = XS::ToString(_localName);
if (m_StateStack.top() == State::Entity) {
if (name == "Entity") {
m_StateStack.pop();
onEndEntity();
return;
}
}
std::string uri = XS::ToString(_uri);
if (m_StateStack.top() == State::Component) {
//if (uri == "components") {
m_StateStack.pop();
onEndComponent(name);
return;
//}
}
if (m_StateStack.top() == State::ComponentField) {
m_StateStack.pop();
onEndComponentField(name);
return;
}
}
void EntityFileSAXHandler::characters(const XMLCh* const chars, const XMLSize_t length)
{
if (m_StateStack.top() == State::ComponentField) {
char* transcoded = xercesc::XMLString::transcode(chars);
onFieldData(transcoded);
}
}
void EntityFileSAXHandler::fatalError(const xercesc::SAXParseException& e)
{
XS::ToString s(e.getMessage());
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
//throw e;
}
void EntityFileSAXHandler::error(const xercesc::SAXParseException& e)
{
XS::ToString s(e.getMessage());
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
}
void EntityFileSAXHandler::warning(const xercesc::SAXParseException& e)
{
XS::ToString s(e.getMessage());
LOG_ERROR("SAXParseException: %s", ((std::string)s).c_str());
}
void EntityFileSAXHandler::onStartEntity(const xercesc::Attributes& attrs)
{
EntityID parent = m_EntityStack.top();
if (m_Handler->m_OnStartEntityCallback) {
std::string name;
auto xName = attrs.getValue(XS::ToXMLCh("name"));
if (xName != nullptr) {
name = XS::ToString(xName);
}
m_Handler->m_OnStartEntityCallback(m_NextEntityID, parent, name);
}
m_EntityStack.push(m_NextEntityID);
m_NextEntityID++;
}
void EntityFileSAXHandler::onEndEntity()
{
m_EntityStack.pop();
}
void EntityFileSAXHandler::onStartEntityRef(const xercesc::Attributes& attrs)
{
std::string path = XS::ToString(attrs.getValue(XS::ToXMLCh("file")));
xercesc::SAX2XMLReader* reader = xercesc::XMLReaderFactory::createXMLReader();
EntityFile::setReaderFeatures(reader);
reader->setContentHandler(this);
reader->setErrorHandler(this);
reader->parse(path.c_str());
delete reader;
}
void EntityFileSAXHandler::onStartComponentField(const std::string& field, const xercesc::Attributes& attrs)
{
//LOG_DEBUG(" Field: %s", field.c_str());
m_CurrentField = field;
m_CurrentAttributes.clear();
for (int i = 0; i < attrs.getLength(); i++) {
auto name = attrs.getQName(i);
auto value = attrs.getValue(name);
//LOG_DEBUG(" %s = %s", (char*)XS::ToString(name), (char*)XS::ToString(value));
m_CurrentAttributes[XS::ToString(name).operator std::string()] = XS::ToString(value).operator std::string();
}
if (m_Handler->m_OnStartFieldCallback) {
m_Handler->m_OnStartFieldCallback(m_EntityStack.top(), m_CurrentComponent, field, m_CurrentAttributes);
}
}
void EntityFileSAXHandler::onEndComponent(const std::string& name) { }
void EntityFileSAXHandler::onStartComponent(const std::string& name)
{
//LOG_DEBUG(" Component: %s", name.c_str());
m_CurrentComponent = name;
if (m_Handler->m_OnStartComponentCallback) {
m_Handler->m_OnStartComponentCallback(m_EntityStack.top(), name);
}
}
void EntityFileSAXHandler::onEndComponentField(const std::string& field) { }
void EntityFileSAXHandler::onFieldData(char* data)
{
//LOG_DEBUG(" Data: %s", data);
if (m_Handler->m_OnStartFieldDataCallback) {
m_Handler->m_OnStartFieldDataCallback(m_EntityStack.top(), m_CurrentComponent, m_CurrentField, data);
}
xercesc::XMLString::release(&data);
}
+91 -48
View File
@@ -16,12 +16,12 @@ EntityFilePreprocessor::EntityFilePreprocessor(const EntityFile* entityFile)
for (auto& kv : m_ComponentInfo) { for (auto& kv : m_ComponentInfo) {
auto& info = kv.second; auto& info = kv.second;
LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta.Annotation.c_str()); LOG_DEBUG("Component: %s (%s)", info.Name.c_str(), info.Meta->Annotation.c_str());
LOG_DEBUG("Stride: %i", info.Meta.Stride); LOG_DEBUG("Stride: %i", info.Stride);
LOG_DEBUG("Allocation: %i", info.Meta.Allocation); LOG_DEBUG("Allocation: %i", info.Meta->Allocation);
for (auto& kv : info.Fields) { for (auto& kv : info.Fields) {
auto& field = kv.second; auto& field = kv.second;
LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type, kv.first.c_str()); LOG_DEBUG("\t%i\t%s %s", field.Offset, field.Type.c_str(), kv.first.c_str());
} }
} }
@@ -62,46 +62,16 @@ void EntityFilePreprocessor::parseComponentInfo()
} }
ComponentInfo compInfo; ComponentInfo compInfo;
compInfo.Meta = std::make_shared<ComponentInfo::Meta_t>();
// Name // Name
compInfo.Name = XS::ToString(element->getName()); compInfo.Name = XS::ToString(element->getName());
// Known allocation // Known allocation
compInfo.Meta.Allocation = m_ComponentCounts[compInfo.Name]; compInfo.Meta->Allocation = m_ComponentCounts[compInfo.Name];
// Annotation // Annotation
auto componentAnnotation = element->getAnnotation(); auto componentAnnotation = element->getAnnotation();
if (componentAnnotation != nullptr) { if (componentAnnotation != nullptr) {
// Parse annotation XML compInfo.Meta->Annotation = parseAnnotationXML(componentAnnotation->getAnnotationString());
char* annotationString = XMLString::transcode(componentAnnotation->getAnnotationString());
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(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<DOMElement*>(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 { } else {
LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str()); LOG_WARNING("Component \"%s\" is missing an annotation!", compInfo.Name.c_str());
} }
@@ -140,24 +110,58 @@ void EntityFilePreprocessor::parseComponentInfo()
std::string name = XS::ToString(elementDeclaration->getName()); std::string name = XS::ToString(elementDeclaration->getName());
std::string type = XS::ToString(elementDeclaration->getTypeDefinition()->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;
size_t stride = EntityFile::GetTypeStride(type); size_t stride = EntityFile::GetTypeStride(type);
if (stride == 0) { if (stride == 0) {
LOG_WARNING("Field \"%s\" in component \"%s\" uses unexpected field type \"%s\". Skipping.", name.c_str(), compInfo.Name.c_str(), type.c_str()); stride = EntityFile::GetTypeStride(baseType);
continue; 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<XSComplexTypeDefinition*>(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<int>(enumValue);
LOG_DEBUG("ENUM %s = %s", enumName.c_str(), enumValue.c_str());
}
}
} }
auto& field = compInfo.Fields[name]; auto& field = compInfo.Fields[name];
field.Name = name; field.Name = name;
field.Type = type; field.Type = effectiveType;
field.Offset = fieldOffset; field.Offset = fieldOffset;
field.Stride = stride; field.Stride = stride;
compInfo.FieldsInOrder.push_back(name); compInfo.FieldsInOrder.push_back(name);
fieldOffset += stride; fieldOffset += stride;
} }
compInfo.Meta.Stride = fieldOffset; compInfo.Stride = fieldOffset;
m_ComponentInfo[compInfo.Name] = compInfo; m_ComponentInfo[compInfo.Name] = compInfo;
} }
} }
@@ -170,8 +174,10 @@ void EntityFilePreprocessor::parseDefaults()
for (auto& ci : m_ComponentInfo) { for (auto& ci : m_ComponentInfo) {
// Allocate memory for default values // Allocate memory for default values
ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Meta.Stride]); ci.second.Defaults = std::shared_ptr<char>(new char[ci.second.Stride]);
memset(ci.second.Defaults.get(), 0, ci.second.Meta.Stride); memset(ci.second.Defaults.get(), 0, ci.second.Stride);
std::string componentName = ci.first;
XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager); XercesDOMParser parser(nullptr, XMLPlatformUtils::fgMemoryManager);
parser.setDoSchema(true); parser.setDoSchema(true);
@@ -179,8 +185,11 @@ void EntityFilePreprocessor::parseDefaults()
parser.setErrorHandler(&errorHandler); parser.setErrorHandler(&errorHandler);
parser.setValidationScheme(XercesDOMParser::Val_Always); parser.setValidationScheme(XercesDOMParser::Val_Always);
parser.setValidationSchemaFullChecking(true); parser.setValidationSchemaFullChecking(true);
//parser.setDoNamespaces(true);
//boost::filesystem::path schemaLocation = "Schema/Components/" + componentName + ".xsd";
//std::string namespaceSchema = schemaLocation.string();
//parser.setExternalNoNamespaceSchemaLocation("Teamasdasdasdasd.xsd");
std::string componentName = ci.first;
LOG_DEBUG("Parsing defaults for component %s", componentName.c_str()); LOG_DEBUG("Parsing defaults for component %s", componentName.c_str());
boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml"; boost::filesystem::path defaultsFile = "Schema/Components/" + componentName + ".xml";
@@ -192,7 +201,7 @@ void EntityFilePreprocessor::parseDefaults()
} }
// Find the node in the components namespace matching the component name // Find the node in the components namespace matching the component name
std::string tagName = "c:" + componentName; std::string tagName = componentName;
auto rootNodes = doc->getElementsByTagName(XS::ToXMLCh(tagName)); auto rootNodes = doc->getElementsByTagName(XS::ToXMLCh(tagName));
if (rootNodes->getLength() == 0) { if (rootNodes->getLength() == 0) {
LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str()); LOG_ERROR("Couldn't find defaults for component \"%s\"! Skipping.", componentName.c_str());
@@ -225,9 +234,19 @@ void EntityFilePreprocessor::parseDefaults()
EntityFile::WriteAttributeData(data, field, attributes); EntityFile::WriteAttributeData(data, field, attributes);
} }
// Handle potential field values
auto childNode = fieldElement->getFirstChild(); auto childNode = fieldElement->getFirstChild();
if (childNode != nullptr && childNode->getNodeType() == DOMNode::TEXT_NODE) { 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()); char* cstrValue = XMLString::transcode(childNode->getNodeValue());
EntityFile::WriteValueData(data, field, cstrValue); EntityFile::WriteValueData(data, field, cstrValue);
XMLString::release(&cstrValue); XMLString::release(&cstrValue);
@@ -236,3 +255,27 @@ void EntityFilePreprocessor::parseDefaults()
} }
} }
std::string EntityFilePreprocessor::parseAnnotationXML(const XMLCh* xml)
{
using namespace xercesc;
// Parse annotation XML
char* annotationString = XMLString::transcode(xml);
MemBufInputSource annotationInput(reinterpret_cast<const XMLByte*>(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();
}
+1 -1
View File
@@ -114,7 +114,7 @@ void EntityFileWriter::appentEntityComponents(xercesc::DOMElement* parentElement
fieldElement->setAttribute(X("Y"), X(boost::lexical_cast<std::string>(q.y))); fieldElement->setAttribute(X("Y"), X(boost::lexical_cast<std::string>(q.y)));
fieldElement->setAttribute(X("Z"), X(boost::lexical_cast<std::string>(q.z))); fieldElement->setAttribute(X("Z"), X(boost::lexical_cast<std::string>(q.z)));
fieldElement->setAttribute(X("W"), X(boost::lexical_cast<std::string>(q.w))); fieldElement->setAttribute(X("W"), X(boost::lexical_cast<std::string>(q.w)));
} else if (field.Type == "int") { } else if (field.Type == "int" || field.Type == "enum") {
const int& value = c[fieldName]; const int& value = c[fieldName];
fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value)))); fieldElement->appendChild(doc->createTextNode(X(boost::lexical_cast<std::string>(value))));
} else if (field.Type == "float") { } else if (field.Type == "float") {
+1 -1
View File
@@ -75,7 +75,7 @@ ComponentWrapper World::AttachComponent(EntityID entity, const std::string& comp
// Allocate space for the component // Allocate space for the component
ComponentWrapper c = pool->Allocate(entity); ComponentWrapper c = pool->Allocate(entity);
// Write default values // Write default values
memcpy(c.Data, ci.Defaults.get(), ci.Meta.Stride); memcpy(c.Data, ci.Defaults.get(), ci.Stride);
return c; return c;
} }
+22 -2
View File
@@ -484,8 +484,8 @@ void EditorSystem::drawUI(World* world, double dt)
} }
if (ImGui::CollapsingHeader(componentType.c_str())) { if (ImGui::CollapsingHeader(componentType.c_str())) {
if (!ci.Meta.Annotation.empty()) { if (!ci.Meta->Annotation.empty()) {
ImGui::Text(ci.Meta.Annotation.c_str()); ImGui::Text(ci.Meta->Annotation.c_str());
} }
auto& component = world->GetComponent(m_Selection, componentType); auto& component = world->GetComponent(m_Selection, componentType);
@@ -529,6 +529,26 @@ void EditorSystem::drawUI(World* world, double dt)
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) { if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
component.SetProperty(fieldName, static_cast<double>(tempVal)); component.SetProperty(fieldName, static_cast<double>(tempVal));
} }
} else if (field.Type == "int") {
int val = component.Property<int>(fieldName);
ImGui::InputInt("", &val);
} else if (field.Type == "enum") {
int currentValue = component.Property<int>(fieldName);
int item = -1;
std::stringstream enumKeys;
std::vector<int> enumValues;
int i = 0;
for (auto& kv : ci.Meta->FieldEnumDefinitions.at(fieldName)) {
enumKeys << kv.first << " (" << kv.second << ")" << '\0';
enumValues.push_back(kv.second);
if (currentValue == kv.second) {
item = i;
}
i++;
}
if (ImGui::Combo("", &item, enumKeys.str().c_str())) {
component.SetProperty(fieldName, enumValues.at(item));
}
} else if (field.Type == "bool") { } else if (field.Type == "bool") {
auto& val = component.Property<bool>(fieldName); auto& val = component.Property<bool>(fieldName);
ImGui::Checkbox("", &val); ImGui::Checkbox("", &val);
+2 -2
View File
@@ -10,8 +10,8 @@ BOOST_AUTO_TEST_CASE(ComponentPoolTest)
//ci.Name = "Test"; //ci.Name = "Test";
//ci.FieldTypes["Field"] = "int"; //ci.FieldTypes["Field"] = "int";
//ci.FieldOffsets["Field"] = 0; //ci.FieldOffsets["Field"] = 0;
//ci.Meta.Allocation = 3; //ci.Meta->Allocation = 3;
//ci.Meta.Stride = sizeof(EntityID) + sizeof(int); //ci.Stride = sizeof(EntityID) + sizeof(int);
//std::vector<ComponentWrapper> wrappers; //std::vector<ComponentWrapper> wrappers;
//ComponentPool pool(ci); //ComponentPool pool(ci);