Merge remote-tracking branch 'origin/master' into Sound
# Conflicts: # README.md # resources/Schema/Components.xsd # resources/Schema/Types/Entity.xsd
This commit is contained in:
@@ -12,9 +12,16 @@ struct ComponentInfo
|
||||
unsigned int Stride = 0;
|
||||
};
|
||||
|
||||
struct Field_t
|
||||
{
|
||||
std::string Type;
|
||||
unsigned int Offset;
|
||||
unsigned int Stride;
|
||||
};
|
||||
|
||||
std::string Name;
|
||||
std::unordered_map<std::string, std::string> FieldTypes;
|
||||
std::unordered_map<std::string, unsigned int> FieldOffsets;
|
||||
std::unordered_map<std::string, Field_t> Fields;
|
||||
std::vector<const Field_t*> FieldsInOrder;
|
||||
Meta_t Meta;
|
||||
std::shared_ptr<char> Defaults = nullptr;
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ struct ComponentWrapper
|
||||
template <typename T>
|
||||
T& Property(std::string name)
|
||||
{
|
||||
unsigned int offset = Info.FieldOffsets.at(name);
|
||||
unsigned int offset = Info.Fields.at(name).Offset;
|
||||
return *reinterpret_cast<T*>(&Data[offset]);
|
||||
}
|
||||
|
||||
@@ -78,8 +78,9 @@ public:
|
||||
void AddProperty(std::string fieldName, T defaultValue)
|
||||
{
|
||||
m_DefaultValues.push_back(defaultValue);
|
||||
m_ComponentInfo.FieldTypes[fieldName] = typeid(T).name();
|
||||
m_ComponentInfo.FieldOffsets[fieldName] = m_ComponentInfo.Meta.Stride;
|
||||
m_ComponentInfo.Fields[fieldName].Name = typeid(T).name();
|
||||
m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Meta.Stride;
|
||||
m_ComponentInfo.Fields[fieldName].Stride = sizeof(T);
|
||||
m_ComponentInfo.Meta.Stride += sizeof(T);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef EPlayerDamage_h__
|
||||
#define EPlayerDamage_h__
|
||||
|
||||
#include "EventBroker.h"
|
||||
#include "../Core/Entity.h"
|
||||
|
||||
namespace Events
|
||||
{
|
||||
|
||||
struct PlayerDamage : Event
|
||||
{
|
||||
double DamageAmount;
|
||||
EntityID PlayerDamagedID;
|
||||
//optional TypeOfDamage
|
||||
std::string TypeOfDamage;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef EPlayerDeath_h__
|
||||
#define EPlayerDeath_h__
|
||||
|
||||
#include "EventBroker.h"
|
||||
#include "../Core/Entity.h"
|
||||
|
||||
namespace Events
|
||||
{
|
||||
|
||||
struct PlayerDeath : Event
|
||||
{
|
||||
//KilledBy,KilledByWhat is optional for now. It might be used later in the playerlog-system
|
||||
EntityID KilledBy;
|
||||
EntityID PlayerID;
|
||||
std::string KilledByWhat;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef EPlayerHealthPickup_h__
|
||||
#define EPlayerHealthPickup_h__
|
||||
|
||||
#include "EventBroker.h"
|
||||
#include "../Core/Entity.h"
|
||||
|
||||
namespace Events
|
||||
{
|
||||
|
||||
struct PlayerHealthPickup : Event
|
||||
{
|
||||
double HealthAmount;
|
||||
EntityID PlayerHealedID;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,5 +2,6 @@
|
||||
#define Entity_h__
|
||||
|
||||
typedef unsigned int EntityID;
|
||||
const static unsigned int EntityID_Invalid = -1;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,293 @@
|
||||
#ifndef EntityFile_h__
|
||||
#define EntityFile_h__
|
||||
|
||||
#include <stack>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <xercesc/util/XercesDefs.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
#include <xercesc/sax2/SAX2XMLReader.hpp>
|
||||
#include <xercesc/sax2/XMLReaderFactory.hpp>
|
||||
#include <xercesc/sax2/DefaultHandler.hpp>
|
||||
#include <xercesc/sax2/Attributes.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/XMLChar.hpp>
|
||||
#include <xercesc/sax2/DefaultHandler.hpp>
|
||||
#include <xercesc/framework/XMLDocumentHandler.hpp>
|
||||
#include <xercesc/framework/psvi/XSElementDeclaration.hpp>
|
||||
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
|
||||
#include <xercesc/framework/psvi/XSParticle.hpp>
|
||||
#include <xercesc/framework/psvi/XSModelGroup.hpp>
|
||||
#include <xercesc/framework/psvi/XSAnnotation.hpp>
|
||||
#include <xercesc/framework/psvi/XSValue.hpp>
|
||||
#include <xercesc/framework/XMLGrammarPoolImpl.hpp>
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/dom/DOMLSInput.hpp>
|
||||
#include <xercesc/dom/DOMElement.hpp>
|
||||
|
||||
#include "../GLM.h"
|
||||
#include "Util/XercesString.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "Entity.h"
|
||||
#include "ComponentInfo.h"
|
||||
|
||||
class EntityFileHandler
|
||||
{
|
||||
friend class EntityFileSAXHandler;
|
||||
public:
|
||||
// @param EntityID The entity found
|
||||
// @param EntityID The parent of the entity
|
||||
typedef std::function<void(EntityID, EntityID, const std::string&)> OnStartEntityCallback;
|
||||
void SetStartEntityCallback(OnStartEntityCallback c) { m_OnStartEntityCallback = c; }
|
||||
// @param EntityID The entity the component corresponds to
|
||||
// @param std::string Type name of the component
|
||||
typedef std::function<void(EntityID, const std::string&)> OnStartComponentCallback;
|
||||
void SetStartComponentCallback(OnStartComponentCallback c) { m_OnStartComponentCallback = c; }
|
||||
// @param EntityID Entity
|
||||
// @param std::string Component name
|
||||
// @param std::string Field name
|
||||
// @param std::map<std::string, std::string> Field attribute names and values
|
||||
typedef std::function<void(EntityID, const std::string&, const std::string&, const std::map<std::string, std::string>&)> OnStartFieldCallback;
|
||||
void SetStartFieldCallback(OnStartFieldCallback c) { m_OnStartFieldCallback = c; }
|
||||
// @param EntityID Entity
|
||||
// @param std::string Component name
|
||||
// @param std::string Field name
|
||||
// @param char* Field data
|
||||
typedef std::function<void(EntityID, const std::string&, const std::string&, const char*)> OnStartFieldDataCallback;
|
||||
void SetStartFieldDataCallback(OnStartFieldDataCallback c) { m_OnStartFieldDataCallback = c; }
|
||||
|
||||
private:
|
||||
OnStartEntityCallback m_OnStartEntityCallback = nullptr;
|
||||
OnStartComponentCallback m_OnStartComponentCallback = nullptr;
|
||||
OnStartFieldCallback m_OnStartFieldCallback = nullptr;
|
||||
OnStartFieldDataCallback m_OnStartFieldDataCallback = nullptr;
|
||||
};
|
||||
|
||||
class EntityFileSAXHandler : public xercesc::DefaultHandler
|
||||
{
|
||||
public:
|
||||
enum class State
|
||||
{
|
||||
Unknown,
|
||||
Entity,
|
||||
Component,
|
||||
ComponentField
|
||||
};
|
||||
|
||||
EntityFileSAXHandler(const EntityFileHandler* handler, xercesc::SAX2XMLReader* reader)
|
||||
: m_Handler(handler)
|
||||
, m_Reader(reader)
|
||||
{
|
||||
// 0 is imaginary world entity
|
||||
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
|
||||
{
|
||||
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 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:
|
||||
const EntityFileHandler* m_Handler;
|
||||
xercesc::XMLGrammarPool* m_GrammarPool;
|
||||
xercesc::SAX2XMLReader* m_Reader;
|
||||
//State m_CurrentScope = State::Unknown;
|
||||
std::stack<State> m_StateStack;
|
||||
unsigned int m_NextEntityID = 0;
|
||||
std::stack<EntityID> m_EntityStack;
|
||||
std::string m_CurrentComponent;
|
||||
std::string m_CurrentField;
|
||||
std::map<std::string, std::string> m_CurrentAttributes;
|
||||
|
||||
void 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 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
|
||||
{
|
||||
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 EntityFile : public Resource
|
||||
{
|
||||
friend class ResourceManager;
|
||||
private:
|
||||
EntityFile(boost::filesystem::path path);
|
||||
~EntityFile();
|
||||
|
||||
public:
|
||||
static std::size_t GetTypeStride(std::string typeName);
|
||||
static void WriteAttributeData(char* outData, const ComponentInfo::Field_t& field, const std::map<std::string, std::string>& attributes);
|
||||
static void WriteValueData(char* outData, const ComponentInfo::Field_t& field, 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<std::string, ::ComponentInfo> m_ComponentInfo;
|
||||
//std::vector<std::string> m_EntityReferences;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef EntityFileParser_h__
|
||||
#define EntityFileParser_h__
|
||||
|
||||
#include "EntityFile.h"
|
||||
#include "World.h"
|
||||
|
||||
class EntityFileParser
|
||||
{
|
||||
public:
|
||||
EntityFileParser(const EntityFile* entityFile);
|
||||
|
||||
void MergeEntities(World* world);
|
||||
|
||||
private:
|
||||
const EntityFile* m_EntityFile;
|
||||
EntityFileHandler m_Handler;
|
||||
World* m_World = nullptr;
|
||||
// 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<EntityID, EntityID> m_EntityIDMapper;
|
||||
|
||||
void onStartEntity(EntityID entity, EntityID parent, const std::string& name);
|
||||
void onStartComponent(EntityID entity, const std::string& component);
|
||||
void onStartComponentField(EntityID entity, const std::string& componentType, const std::string& fieldName, const std::map<std::string, std::string>& attributes);
|
||||
void onFieldData(EntityID entity, const std::string& componentType, const std::string& fieldName, const char* fieldData);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef EntityFilePreprocessor_h__
|
||||
#define EntityFilePreprocessor_h__
|
||||
|
||||
#include <xercesc/framework/psvi/XSElementDeclaration.hpp>
|
||||
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
|
||||
#include <xercesc/framework/psvi/XSParticle.hpp>
|
||||
#include <xercesc/framework/psvi/XSModelGroup.hpp>
|
||||
#include <xercesc/framework/psvi/XSAnnotation.hpp>
|
||||
#include <xercesc/framework/psvi/XSValue.hpp>
|
||||
#include <xercesc/framework/MemBufFormatTarget.hpp>
|
||||
#include <xercesc/framework/MemBufInputSource.hpp>
|
||||
#include <xercesc/parsers/XercesDOMParser.hpp>
|
||||
|
||||
#include "Util/XercesString.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "World.h"
|
||||
#include "EntityFile.h"
|
||||
|
||||
class EntityFilePreprocessor
|
||||
{
|
||||
public:
|
||||
EntityFilePreprocessor(const EntityFile* entityFile);
|
||||
|
||||
void RegisterComponents(World* world);
|
||||
|
||||
private:
|
||||
const EntityFile* m_EntityFile;
|
||||
std::map<std::string, unsigned int> m_ComponentCounts;
|
||||
std::map<std::string, ComponentInfo> m_ComponentInfo;
|
||||
|
||||
void onStartComponent(EntityID entity, std::string type);
|
||||
void parseComponentInfo();
|
||||
void parseDefaults();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef EntityFileWriter_h__
|
||||
#define EntityFileWriter_h__
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
||||
|
||||
#include "Util/XercesString.h"
|
||||
#include "EntityFile.h"
|
||||
#include "World.h"
|
||||
|
||||
class EntityFileWriter
|
||||
{
|
||||
public:
|
||||
EntityFileWriter(boost::filesystem::path file)
|
||||
: m_FilePath(file)
|
||||
{
|
||||
using namespace xercesc;
|
||||
m_DOMImplementation = DOMImplementationRegistry::getDOMImplementation(XS::ToXMLCh("LS"));
|
||||
m_DOMLSSerializer = static_cast<DOMImplementationLS*>(m_DOMImplementation)->createLSSerializer();
|
||||
m_DOMLSSerializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTDiscardDefaultContent, true);
|
||||
m_DOMLSSerializer->getDomConfig()->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
|
||||
}
|
||||
|
||||
void WriteWorld(World* world);
|
||||
void WriteEntity(World* world, EntityID entity);
|
||||
|
||||
private:
|
||||
boost::filesystem::path m_FilePath;
|
||||
xercesc::DOMImplementation* m_DOMImplementation;
|
||||
xercesc::DOMLSSerializer* m_DOMLSSerializer;
|
||||
|
||||
void appendEntityChildren(xercesc::DOMElement* parentElement, const World* world, EntityID entity);
|
||||
void appentEntityComponents(xercesc::DOMElement* parentElemetn, const World* world, EntityID entity);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,141 +0,0 @@
|
||||
#ifndef EntityXMLFile_h__
|
||||
#define EntityXMLFile_h__
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "../Common.h"
|
||||
#include "../GLM.h"
|
||||
#include <xercesc/dom/DOM.hpp>
|
||||
#include <xercesc/dom/DOMLSInput.hpp>
|
||||
#include <xercesc/dom/DOMElement.hpp>
|
||||
#include <xercesc/framework/Wrapper4InputSource.hpp>
|
||||
#include <xercesc/framework/LocalFileInputSource.hpp>
|
||||
#include <xercesc/framework/LocalFileFormatTarget.hpp>
|
||||
#include <xercesc/framework/MemBufFormatTarget.hpp>
|
||||
#include <xercesc/framework/MemBufInputSource.hpp>
|
||||
#include <xercesc/sax/HandlerBase.hpp>
|
||||
#include <xercesc/util/PlatformUtils.hpp>
|
||||
#include <xercesc/util/XMLFloat.hpp>
|
||||
#include <xercesc/framework/XMLGrammarPoolImpl.hpp>
|
||||
#include <xercesc/parsers/XercesDOMParser.hpp>
|
||||
#include <xercesc/framework/psvi/XSElementDeclaration.hpp>
|
||||
#include <xercesc/framework/psvi/XSComplexTypeDefinition.hpp>
|
||||
#include <xercesc/framework/psvi/XSParticle.hpp>
|
||||
#include <xercesc/framework/psvi/XSModelGroup.hpp>
|
||||
#include <xercesc/framework/psvi/XSAnnotation.hpp>
|
||||
#include <xercesc/framework/psvi/XSValue.hpp>
|
||||
#include <xercesc/framework/XMLValidator.hpp>
|
||||
|
||||
#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<std::string, ComponentInfo> 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
|
||||
@@ -14,21 +14,28 @@ public:
|
||||
{ }
|
||||
~SystemPipeline()
|
||||
{
|
||||
for (auto& pair : m_Systems) {
|
||||
delete pair.second;
|
||||
for (UnorderedSystems& group : m_OrderedSystemGroups) {
|
||||
for (auto& pair : group.Systems) {
|
||||
delete pair.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename... Arguments>
|
||||
void AddSystem(Arguments... args)
|
||||
//All systems with orderlevel 0 will be updated first, then 1, 2, etc.
|
||||
void AddSystem(int updateOrderLevel, Arguments... args)
|
||||
{
|
||||
if (updateOrderLevel + 1 > m_OrderedSystemGroups.size()) {
|
||||
m_OrderedSystemGroups.resize(updateOrderLevel + 1);
|
||||
}
|
||||
UnorderedSystems& group = m_OrderedSystemGroups[updateOrderLevel];
|
||||
System* system = new T(m_EventBroker, args...);
|
||||
m_Systems[typeid(T).name()] = system;
|
||||
group.Systems[typeid(T).name()] = system;
|
||||
|
||||
if (std::is_base_of<PureSystem, T>::value) {
|
||||
PureSystem* pureSystem = static_cast<PureSystem*>(system);
|
||||
if (!pureSystem->m_ComponentType.empty()) {
|
||||
m_PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
|
||||
group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
|
||||
} else {
|
||||
LOG_ERROR("Failed to add pure system \"%s\": Missing component type!", typeid(T).name());
|
||||
}
|
||||
@@ -36,41 +43,47 @@ public:
|
||||
|
||||
if (std::is_base_of<ImpureSystem, T>::value) {
|
||||
ImpureSystem* impureSystem = static_cast<ImpureSystem*>(system);
|
||||
m_ImpureSystems.push_back(impureSystem);
|
||||
group.ImpureSystems.push_back(impureSystem);
|
||||
}
|
||||
}
|
||||
|
||||
void Update(World* world, double dt)
|
||||
{
|
||||
// Process events
|
||||
for (auto& pair : m_Systems) {
|
||||
m_EventBroker->Process(pair.first);
|
||||
}
|
||||
|
||||
// Update
|
||||
for (auto& pair : m_PureSystems) {
|
||||
const std::string& componentName = pair.first;
|
||||
auto& systems = pair.second;
|
||||
const ComponentPool* pool = world->GetComponents(componentName);
|
||||
if (pool == nullptr) {
|
||||
continue;
|
||||
for (UnorderedSystems& group : m_OrderedSystemGroups) {
|
||||
// Process events
|
||||
for (auto& pair : group.Systems) {
|
||||
m_EventBroker->Process(pair.first);
|
||||
}
|
||||
for (auto& component : *pool) {
|
||||
for (auto& system : systems) {
|
||||
system->UpdateComponent(world, component, dt);
|
||||
|
||||
// Update
|
||||
for (auto& pair : group.PureSystems) {
|
||||
const std::string& componentName = pair.first;
|
||||
auto& systems = pair.second;
|
||||
const ComponentPool* pool = world->GetComponents(componentName);
|
||||
if (pool == nullptr) {
|
||||
continue;
|
||||
}
|
||||
for (auto& component : *pool) {
|
||||
for (auto& system : systems) {
|
||||
system->UpdateComponent(world, component, dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto& system : m_ImpureSystems) {
|
||||
system->Update(world, dt);
|
||||
for (auto& system : group.ImpureSystems) {
|
||||
system->Update(world, dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EventBroker* m_EventBroker;
|
||||
std::map<std::string, System*> m_Systems;
|
||||
std::map<std::string, std::vector<PureSystem*>> m_PureSystems;
|
||||
std::vector<ImpureSystem*> m_ImpureSystems;
|
||||
struct UnorderedSystems
|
||||
{
|
||||
std::map<std::string, System*> Systems;
|
||||
std::map<std::string, std::vector<PureSystem*>> PureSystems;
|
||||
std::vector<ImpureSystem*> ImpureSystems;
|
||||
};
|
||||
std::vector<UnorderedSystems> m_OrderedSystemGroups;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef Util_XercesString_h__
|
||||
#define Util_XercesString_h__
|
||||
|
||||
#include <string>
|
||||
#include <xercesc/util/XercesDefs.hpp>
|
||||
#include <xercesc/util/XMLString.hpp>
|
||||
|
||||
namespace XS
|
||||
{
|
||||
|
||||
class ToString
|
||||
{
|
||||
public:
|
||||
ToString(const XMLCh* const str) { m_AsChar = xercesc::XMLString::transcode(str); }
|
||||
~ToString()
|
||||
{
|
||||
if (m_AsChar != nullptr) {
|
||||
xercesc::XMLString::release(&m_AsChar);
|
||||
}
|
||||
}
|
||||
|
||||
operator std::string() const { return std::string(m_AsChar); }
|
||||
private:
|
||||
char* m_AsChar = nullptr;
|
||||
};
|
||||
|
||||
class ToXMLCh
|
||||
{
|
||||
public:
|
||||
ToXMLCh(const std::string str) { m_Transcoded = xercesc::XMLString::transcode(str.c_str()); }
|
||||
ToXMLCh(const char* str) { m_Transcoded = xercesc::XMLString::transcode(str); }
|
||||
~ToXMLCh()
|
||||
{
|
||||
if (m_Transcoded != nullptr) {
|
||||
xercesc::XMLString::release(&m_Transcoded);
|
||||
}
|
||||
}
|
||||
|
||||
operator const XMLCh*() const { return m_Transcoded; }
|
||||
private:
|
||||
XMLCh* m_Transcoded = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -16,13 +16,14 @@ public:
|
||||
EntityID CreateEntity(EntityID parent = 0);
|
||||
// Delete entity and all components within
|
||||
void DeleteEntity(EntityID entity);
|
||||
|
||||
// Check if an entity exists
|
||||
bool ValidEntity(EntityID entity) const;
|
||||
// Register a component type and allocate space for it
|
||||
void RegisterComponent(ComponentInfo& ci);
|
||||
// Attach a component to an entity and fill it with default values
|
||||
ComponentWrapper AttachComponent(EntityID entity, std::string componentType);
|
||||
// Check if an entity has a component
|
||||
bool HasComponent(EntityID entity, std::string componentType);
|
||||
bool HasComponent(EntityID entity, std::string componentType) const;
|
||||
// Get a component of an entity
|
||||
ComponentWrapper GetComponent(EntityID entity, std::string componentType);
|
||||
// Delete a component off an entity
|
||||
@@ -37,14 +38,19 @@ public:
|
||||
const std::unordered_map<std::string, ComponentPool*>& GetComponentPools() const { return m_ComponentPools; }
|
||||
// Get the entity children map
|
||||
const std::unordered_multimap<EntityID, EntityID>& GetEntityChildren() const { return m_EntityChildren; }
|
||||
// Set the textual name of an entity
|
||||
void SetName(EntityID entity, const std::string& name);
|
||||
// Get the textual name of an entity
|
||||
std::string GetName(EntityID entity) const;
|
||||
|
||||
private:
|
||||
EntityID m_CurrentEntityID = 1;
|
||||
EntityID m_CurrentEntityID = 0;
|
||||
|
||||
std::unordered_map<EntityID, EntityID> m_EntityParents;
|
||||
// TODO: This should be a more effective structure
|
||||
std::unordered_multimap<EntityID, EntityID> m_EntityChildren;
|
||||
std::unordered_map<std::string, ComponentPool*> m_ComponentPools;
|
||||
std::unordered_map<EntityID, std::string> m_EntityNames;
|
||||
|
||||
EntityID generateEntityID();
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <imgui/imgui.h>
|
||||
#include <glm/gtx/common.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <nativefiledialog/nfd.h>
|
||||
#include "../Core/System.h"
|
||||
#include "../Core/EMousePress.h"
|
||||
#include "../Core/EMouseRelease.h"
|
||||
@@ -11,6 +12,9 @@
|
||||
#include "../Rendering/EPicking.h"
|
||||
#include "../Core/EFileDropped.h"
|
||||
#include "../Rendering/RenderQueueFactory.h"
|
||||
#include "../Core/EntityFilePreprocessor.h"
|
||||
#include "../Core/EntityFileParser.h"
|
||||
#include "../Core/EntityFileWriter.h"
|
||||
|
||||
class EditorSystem : public ImpureSystem
|
||||
{
|
||||
@@ -25,6 +29,8 @@ private:
|
||||
|
||||
bool m_Enabled;
|
||||
bool m_Visible;
|
||||
boost::filesystem::path m_DefaultEntityDir;
|
||||
boost::filesystem::path m_CurrentFile;
|
||||
std::vector<glm::vec2> m_PickingQueue;
|
||||
|
||||
enum class WidgetMode
|
||||
@@ -41,22 +47,26 @@ private:
|
||||
Global
|
||||
} m_WidgetSpace = WidgetSpace::Global;
|
||||
|
||||
EntityID m_Widget = 0;
|
||||
EntityID m_WidgetX = 0;
|
||||
EntityID m_WidgetPlaneX = 0;
|
||||
EntityID m_WidgetY = 0;
|
||||
EntityID m_WidgetPlaneY = 0;
|
||||
EntityID m_WidgetZ = 0;
|
||||
EntityID m_WidgetPlaneZ = 0;
|
||||
EntityID m_WidgetOrigin = 0;
|
||||
EntityID m_Widget = EntityID_Invalid;
|
||||
EntityID m_WidgetX = EntityID_Invalid;
|
||||
EntityID m_WidgetPlaneX = EntityID_Invalid;
|
||||
EntityID m_WidgetY = EntityID_Invalid;
|
||||
EntityID m_WidgetPlaneY = EntityID_Invalid;
|
||||
EntityID m_WidgetZ = EntityID_Invalid;
|
||||
EntityID m_WidgetPlaneZ = EntityID_Invalid;
|
||||
EntityID m_WidgetOrigin = EntityID_Invalid;
|
||||
glm::vec3 m_WidgetCurrentAxis;
|
||||
float m_WidgetPickingDepth = 0.f;
|
||||
|
||||
EntityID m_Selection = 0;
|
||||
EntityID m_LastSelection = 0;
|
||||
EntityID m_Selection = EntityID_Invalid;
|
||||
EntityID m_LastSelection = EntityID_Invalid;
|
||||
EntityID m_UIDraggingEntity = EntityID_Invalid;
|
||||
glm::vec3 m_Position;
|
||||
std::string m_LastDroppedFile;
|
||||
|
||||
static boost::filesystem::path openDialog(boost::filesystem::path defaultPath);
|
||||
static boost::filesystem::path saveDialog(boost::filesystem::path defaultPath);
|
||||
|
||||
EventRelay<EditorSystem, Events::InputCommand> m_EInputCommand;
|
||||
bool OnInputCommand(const Events::InputCommand& e);
|
||||
EventRelay<EditorSystem, Events::MouseRelease> m_EMouseRelease;
|
||||
@@ -70,10 +80,15 @@ private:
|
||||
EventRelay<EditorSystem, Events::FileDropped> m_EFileDropped;
|
||||
bool OnFileDropped(const Events::FileDropped& e);
|
||||
|
||||
void createWidget();
|
||||
void updateWidget();
|
||||
void setWidgetMode(WidgetMode newMode);
|
||||
void setWidgetSpace(WidgetSpace space);
|
||||
void drawUI(World* world, double dt);
|
||||
bool createDeleteButton(std::string componentType);
|
||||
bool createEntityNode(World* world, EntityID entity);
|
||||
void changeParent(EntityID entity, EntityID newParent);
|
||||
void fileImport(World* world);
|
||||
void fileSave(World* world);
|
||||
void fileSaveAs(World* world);
|
||||
};
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
if (it != PickingColorsToEntity->end()) {
|
||||
pickData.Entity = it->second;
|
||||
} else {
|
||||
pickData.Entity = 0;
|
||||
pickData.Entity = EntityID_Invalid;
|
||||
}
|
||||
pickData.Position = ScreenCoords::ToWorldPos(screenCoord.x, screenCoord.y, data.Depth, Resolution, ProjectionMatrix, ViewMatrix);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user