1#include "DynamicComponentSystem.h"
5#include "Foundation/Logging/Logger.h"
8#include "MemoryContext.h"
10#include "EntityStore.h"
11#include "EntityDefinition.h"
24 typedef void UserDataMessageCallback(
int messageId,
void * userData,
const void * data);
28 if (component->userData && component->messageCallback) {
29 ((UserDataMessageCallback *)component->messageCallback)((int)messageId, component->userData, data);
30 }
else if (component->messageCallback) {
31 ((MessageCallback *)component->messageCallback)((int)messageId, data);
33 LOG_ERROR(logger,
"Dispatcher callback not registered.");
39 template<
typename... Args>
40 void * getDispatcherArg(Args... args)
42 std::tuple<Args...> store(args...);
44 if constexpr (std::tuple_size<std::tuple<Args...>>::value != 1) {
45 LOG_WARNING(logger,
"Tried passing multiple arguments to single value dispatcher. Additional arguments discarded.");
48 return std::get<0>(store);
51 void * getDispatcherArg()
56 template<
typename Collection,
typename... Args>
57 void dispatch(
const Collection& receivers,
size_t messageId, Args... args)
59 dispatchRef(receivers, messageId, std::forward<Args>(args)...);
62 template<
typename Collection,
typename... Args>
63 void dispatchRef(
const Collection& receivers,
size_t messageId, Args... args)
65 for (
auto & r : receivers) {
66 auto component = r.component.resolve();
68 if (component->getGeneration() != r.component.generation) {
72 if (r.typeInfo->dispatcher) {
73 r.method->call(r.typeInfo->dispatcher, component, messageId, getDispatcherArg(args...));
75 r.method->call(component, args...);
85 dynamicTypes.reserve(kMaxDynamicTypes);
87 initializeMessage = registerMessage(
"initialize");
88 updateMessage = registerMessage(
"update");
89 postUpdateMessage = registerMessage(
"postUpdate");
90 cleanupMessage = registerMessage(
"cleanup");
100 for (
auto & p : pools) {
101 Memory::destroy(p.second, context->
memory->baseAllocator);
107 dispatch(messageHandlers[initializeMessage], initializeMessage, context);
109 messageHandlers[initializeMessage].clear();
114 dispatch(messageHandlers[updateMessage], updateMessage);
119 dispatch(messageHandlers[postUpdateMessage], postUpdateMessage);
121 for (
auto & update : messageHandlers[updateMessage]) {
122 auto component = update.component.resolve();
124 component->resetFieldsChanged();
130 this->context = context;
136 if (dynamicTypes.size() == kMaxDynamicTypes) {
137 LOG_ERROR(logger,
"Max number of dynamic types exceeded.");
141 dynamicTypes.emplace_back();
142 auto typeInfo = &dynamicTypes.back();
144 typeInfo->pool = pool;
145 typeInfo->methods.resize(kMaxDynamicMethods);
147 for (
size_t i = 0; i < messages.size(); ++i) {
148 auto messageMethod = type.
getMethod(messages[i].name);
151 typeInfo->messageMask |= 1 << i;
152 typeInfo->methods[i] = messageMethod;
156 const size_t typeInfoIndex = dynamicTypes.size() - 1;
158 ComponentCreator creator = [
this, typeInfoIndex]()
160 auto component = createComponent(&dynamicTypes[typeInfoIndex]);
162 component.resolveComponent<DynamicComponent>()->dynamicTypeInfoIndex = typeInfoIndex;
167 ComponentDestroyer destroyer = [
this, typeInfoIndex](
ComponentHandle component)
169 destroyComponent(&dynamicTypes[typeInfoIndex], component);
175void Cogs::Core::DynamicComponentSystem::registerType(Context * context,
const StringView & name,
size_t dispatchMask)
179 sizeof(DynamicComponent),
180 &Reflection::Construction::createInstance<DynamicComponent>,
181 &Reflection::Construction::destroyInstance<DynamicComponent>,
182 &Reflection::Construction::constructInstance<DynamicComponent>,
183 &Reflection::Construction::destructInstance<DynamicComponent>,
186 std::vector<Reflection::Method> methods;
188 for (
size_t i = 0; i < messages.size(); ++i) {
189 if (dispatchMask & (1 << i)) {
190 methods.emplace_back(Reflection::Method(messages[i].name, &MessageDispatcher::dispatch));
194 newType.setBase<DynamicComponent>().setMethods(methods.data(), methods.size());
196 registerType(context, newType);
198 auto & typeInfo = dynamicTypes.back();
200 typeInfo.dispatcher = &dispatcher;
203Cogs::Core::MessageId Cogs::Core::DynamicComponentSystem::registerMessage(
const StringView & messageName)
205 MessageInfo info = {};
206 info.name = messageName.to_string();
208 messages.emplace_back(info);
209 messageHandlers.resize(messages.size());
211 return messages.size() - 1;
214Cogs::Core::MessageId Cogs::Core::DynamicComponentSystem::getMessageId(
const StringView & messageName)
const
216 for (
auto & m : messages) {
217 if (messageName == m.name)
return std::distance(messages.data(), &m);
223void Cogs::Core::DynamicComponentSystem::sendMessage(
Entity * entity, MessageId messageId)
225 sendMessage(entity, messageId,
nullptr);
228void Cogs::Core::DynamicComponentSystem::sendMessage(
Entity * entity, MessageId messageId,
void * arg)
230 std::vector<DispatchInfo> dispatchers;
232 for (
auto & d : messageHandlers[messageId]) {
233 if (d.component.resolve()->getContainer() == entity) {
234 dispatchers.push_back(d);
239 dispatchRef(dispatchers, messageId, arg);
241 dispatchRef(dispatchers, messageId);
247 auto component = typeInfo->pool->allocateComponent();
250 for (
size_t i = 0; i < messages.size(); ++i) {
251 if (typeInfo->messageMask & (1 << i)) {
252 messageHandlers[i].push_back(DispatchInfo{ component, typeInfo->methods[i], typeInfo });
259void Cogs::Core::DynamicComponentSystem::destroyComponent(DynamicTypeInfo * typeInfo, ComponentModel::ComponentHandle handle)
261 auto component = handle.resolve();
263 if (typeInfo->messageMask & (1 << cleanupMessage)) {
265 if (typeInfo->dispatcher) {
266 dispatcher.dispatch(
static_cast<DynamicComponent *
>(component), cleanupMessage,
nullptr);
268 typeInfo->methods[cleanupMessage]->call(component, context);
272 for (
size_t i = 0; i < messages.size(); ++i) {
273 if (typeInfo->messageMask & (1 << i)) {
274 auto & handler = messageHandlers[i];
276 auto it = std::remove_if(handler.begin(), handler.end(), [&](
const DispatchInfo & u)
278 return u.component == handle;
281 if (it != handler.end()) {
288 typeInfo->pool->deallocateComponent(handle);
293 auto pIt = pools.find(typeId);
295 if (pIt == pools.end()) {
296 assert(typeId !=
Reflection::NoType &&
"Cannot create component pool without valid type.");
298 auto pool = Memory::create<ComponentModel::ComponentPoolBase>(context->memory->baseAllocator, typeId, 128, context->memory->componentAllocator, MemBlockType::Component);
301 pools[typeId] = pool;
Untyped Component pool base.
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
Container for components, providing composition of dynamic entities.
Base class for component systems.
void postUpdate()
Perform post update logic in the system.
virtual void initialize(Context *context)
Initialize the system.
void update()
Updates the system state to that of the current frame.
void preUpdate()
Run the pre-update method of the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
class EntityStore * store
Entity store.
std::unique_ptr< struct MemoryContext > memory
Memory and allocation info.
virtual ComponentHandle createComponent()
Create a new component instance.
void cleanup(Context *context) override
Provided for custom cleanup logic in derived systems.
void initialize(Context *context) override
Initialize the system.
Base class for components implementing dynamic behavior.
void addSystem(const Reflection::TypeId typeId, ComponentCreator creator, ComponentDestroyer destroyer)
Adds the given creator and destroyer functions for handling components of the given typeId.
Log implementation class.
static Type & createType(bool isAbstract=false)
Create a new Type from the provided template type.
Represents a discrete type definition, describing a native type class.
const Method * getMethod(const Name &name) const
Get a pointer to the method with the given name.
constexpr TypeId getTypeId() const
Get the unique Reflection::TypeId of this instance.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
uint16_t TypeId
Built in type used to uniquely identify a single type instance.
constexpr TypeId NoType
Definition of no type.
Contains all Cogs related functionality.
@ Changed
The components data has changed.
Handle to a Component instance.
COGSFOUNDATION_API class Component * resolve() const
Resolve the handle, returning a pointer to the held Component instance.
@ AllowGrow
Allows the component pool to grow on demand.