diff --git a/include/Engine/Core/ComponentInfo.h b/include/Engine/Core/ComponentInfo.h index d9799059..3383f297 100644 --- a/include/Engine/Core/ComponentInfo.h +++ b/include/Engine/Core/ComponentInfo.h @@ -27,6 +27,7 @@ struct ComponentInfo std::string Name; std::unordered_map Fields; std::vector FieldsInOrder; + std::vector StringFields; unsigned int Stride = 0; std::shared_ptr Defaults = nullptr; std::shared_ptr Meta = nullptr; diff --git a/include/Engine/Core/ComponentPool.h b/include/Engine/Core/ComponentPool.h index 957b8756..aedfd06b 100644 --- a/include/Engine/Core/ComponentPool.h +++ b/include/Engine/Core/ComponentPool.h @@ -1,6 +1,7 @@ #ifndef ComponentPool_h__ #define ComponentPool_h__ +#include #include "MemoryPool.h" #include "ComponentInfo.h" #include "ComponentWrapper.h" @@ -45,7 +46,8 @@ public: : m_ComponentInfo(ci) , m_Pool(ci.Meta->Allocation, sizeof(EntityID) + ci.Stride) { } - ComponentPool(const ComponentPool& other) = delete; + ~ComponentPool(); + ComponentPool(const ComponentPool& other); ComponentPool(const ComponentPool&& other) = delete; const ::ComponentInfo& ComponentInfo() const { return m_ComponentInfo; } diff --git a/include/Engine/Core/ComponentWrapper.h b/include/Engine/Core/ComponentWrapper.h index 0b9f7357..3ebad94a 100644 --- a/include/Engine/Core/ComponentWrapper.h +++ b/include/Engine/Core/ComponentWrapper.h @@ -7,6 +7,23 @@ #include "ComponentInfo.h" #include "Util/Any.h" +template +struct ComponentField { }; + +template +struct ComponentField::value>::type> +{ + static T& Get(const ComponentInfo::Field_t& info, char* data) { return *reinterpret_cast(data); } + static void Set(const ComponentInfo::Field_t& info, char* data, const T& value) { Get(data) = value; } +}; + +template <> +struct ComponentField +{ + static std::string& Get(const ComponentInfo::Field_t& info, char* data) { return **reinterpret_cast(data); } + static void Set(const ComponentInfo::Field_t& info, char* data, const std::string& value) { Get(info, data) = value; } +}; + struct ComponentWrapper { ComponentWrapper(const ComponentInfo& componentInfo, char* data) @@ -47,7 +64,20 @@ struct ComponentWrapper void Copy(ComponentWrapper& destination) { - memcpy(destination.Data, this->Data, Info.Stride); + // Copy trivial data + memcpy(destination.Data, Data, Info.Stride); + // Duplicate strings + SolidifyStrings(destination); + } + + // When component data has been copied, strings need to be reconstructed or they'll refer to the same data! + static void SolidifyStrings(ComponentWrapper& component) + { + for (auto& name : component.Info.StringFields) { + std::size_t offset = component.Info.Fields.at(name).Offset; + auto& value = *reinterpret_cast(component.Data + offset); + new (component.Data + offset) std::string(value); + } } struct SubscriptProxy @@ -94,44 +124,4 @@ private: boost::shared_array m_DataReference; }; -// TODO: Move this to Tests once entity importing is finished -class ComponentWrapperFactory -{ -public: - ComponentWrapperFactory() = default; - ComponentWrapperFactory(std::string componentTypeName, unsigned int allocation = 0) - { - m_ComponentInfo.Name = componentTypeName; - m_ComponentInfo.Meta->Allocation = allocation; - } - - template - void AddProperty(std::string fieldName, T defaultValue) - { - m_DefaultValues.push_back(defaultValue); - m_ComponentInfo.Fields[fieldName].Type = typeid(T).name(); - m_ComponentInfo.Fields[fieldName].Offset = m_ComponentInfo.Stride; - m_ComponentInfo.Fields[fieldName].Stride = sizeof(T); - m_ComponentInfo.Stride += sizeof(T); - } - - ComponentInfo& Finalize() - { - m_ComponentInfo.Defaults = std::shared_ptr(new char[m_ComponentInfo.Stride]); - std::size_t offset = 0; - for (auto& val : m_DefaultValues) { - memcpy(m_ComponentInfo.Defaults.get() + offset, val.Data.get(), val.Size); - offset += val.Size; - } - - return m_ComponentInfo; - } - - operator ComponentInfo&() { return Finalize(); } - -private: - ComponentInfo m_ComponentInfo; - std::vector m_DefaultValues; -}; - #endif diff --git a/include/Engine/Core/MemoryPool.h b/include/Engine/Core/MemoryPool.h index f4073294..0cf7b6bf 100644 --- a/include/Engine/Core/MemoryPool.h +++ b/include/Engine/Core/MemoryPool.h @@ -66,9 +66,24 @@ public: , m_LowestAllocatedSlot(m_NumSlots) { } - //We may get problems with memory being released - //prematurely, etc. if we allow copies. - MemoryPool(const MemoryPool& other) = delete; + MemoryPool(const MemoryPool& other) + : m_StartAddress(new char[other.m_NumSlots*other.m_Stride]) + , m_SlotIsAllocated(other.m_NumSlots, false) + , m_NumSlots(other.m_NumSlots) + , m_Stride(other.m_Stride) + , m_NumAllocatedSlots(0) + , m_CurrentAllocSlot(0) + , m_LowestAllocatedSlot(m_NumSlots) + { + // Copy statically allocated pool + memcpy(m_StartAddress, other.m_StartAddress, m_NumSlots*m_Stride); + // Copy dynamically allocated memory + for (char* otherAddr : other.m_ExtraMemory) { + char* addr = (char*)malloc(m_Stride); + memcpy(addr, otherAddr, m_Stride); + m_ExtraMemory.push_back(addr); + } + } MemoryPool(const MemoryPool&& other) = delete; //Free all memory that has been allocated. diff --git a/src/Engine/Core/ComponentPool.cpp b/src/Engine/Core/ComponentPool.cpp index 7b465fbc..bc4aab7e 100644 --- a/src/Engine/Core/ComponentPool.cpp +++ b/src/Engine/Core/ComponentPool.cpp @@ -1,7 +1,5 @@ #include "Core/ComponentPool.h" - - ComponentWrapper ComponentPoolForwardIterator::operator*() const { char* data = &(*m_MemoryPoolIterator); @@ -32,6 +30,28 @@ ComponentPoolForwardIterator& ComponentPoolForwardIterator::operator++() return *this; } +ComponentPool::ComponentPool(const ComponentPool& other) + : m_ComponentInfo(other.m_ComponentInfo) + , m_Pool(other.m_Pool) +{ + // Duplicate strings + for (auto& name : m_ComponentInfo.StringFields) { + for (auto& c : *this) { + ComponentWrapper::SolidifyStrings(c); + } + } +} + +ComponentPool::~ComponentPool() +{ + // Call std::string destructors + for (auto& name : m_ComponentInfo.StringFields) { + for (auto& c : *this) { + c.Field(name).~basic_string(); + } + } +} + //const ::ComponentInfo& ComponentPool::ComponentInfo() const //{ // return m_ComponentInfo; @@ -39,10 +59,19 @@ ComponentPoolForwardIterator& ComponentPoolForwardIterator::operator++() ComponentWrapper ComponentPool::Allocate(EntityID entity) { + // Allocate pool data char* data = m_Pool.Allocate(); + // Copy EntityID memcpy(data, &entity, sizeof(EntityID)); + m_EntityToComponent[entity] = data; - return ComponentWrapper(m_ComponentInfo, data); + ComponentWrapper component(m_ComponentInfo, data); + + // Copy defaults + memcpy(component.Data, m_ComponentInfo.Defaults.get(), m_ComponentInfo.Stride); + ComponentWrapper::SolidifyStrings(component); + + return component; } ComponentWrapper ComponentPool::GetByEntity(EntityID ent) diff --git a/src/Engine/Core/EntityFilePreprocessor.cpp b/src/Engine/Core/EntityFilePreprocessor.cpp index a1370dd2..c3a90c29 100644 --- a/src/Engine/Core/EntityFilePreprocessor.cpp +++ b/src/Engine/Core/EntityFilePreprocessor.cpp @@ -185,6 +185,9 @@ void EntityFilePreprocessor::parseComponentInfo() field.Offset = fieldOffset; field.Stride = stride; compInfo.FieldsInOrder.push_back(name); + if (field.Type == "string") { + compInfo.StringFields.push_back(name); + } fieldOffset += stride; } diff --git a/src/Engine/Core/World.cpp b/src/Engine/Core/World.cpp index 69c25f61..79f210ea 100644 --- a/src/Engine/Core/World.cpp +++ b/src/Engine/Core/World.cpp @@ -48,6 +48,7 @@ ComponentWrapper World::AttachComponent(EntityID entity, const std::string& comp ComponentWrapper c = pool->Allocate(entity); // Write default values memcpy(c.Data, ci.Defaults.get(), ci.Stride); + ComponentWrapper::SolidifyStrings(c); return c; }