Radium Engine  1.5.20
Loading...
Searching...
No Matches
ComponentMessenger.hpp
1#pragma once
2
3#include <Core/Utils/Singleton.hpp>
4#include <Core/Utils/StdUtils.hpp>
5#include <Engine/RaEngine.hpp>
6#include <Engine/Scene/Component.hpp>
7
8#include <functional>
9#include <iostream>
10#include <memory>
11#include <typeindex>
12#include <unordered_map>
13#include <vector>
14
15namespace Ra {
16namespace Engine {
17namespace Scene {
18
19class Entity;
20class Component;
21
39class RA_ENGINE_API ComponentMessenger
40{
41 RA_SINGLETON_INTERFACE( ComponentMessenger );
42
43 public:
45 template <typename T>
48 using Getter = std::function<const T*( void )>;
50 using Setter = std::function<void( const T* )>;
51
53 using ReadWrite = std::function<T*( void )>;
54
56 static const T& getHelper( const Getter& g ) { return *( g() ); }
57 };
58
59 template <typename T>
60 struct CallbackTypes<std::shared_ptr<T>> {
61 using Getter = std::function<std::shared_ptr<const T>( void )>;
62 using Setter = std::function<void( std::shared_ptr<const T> )>;
63 using ReadWrite = std::function<std::shared_ptr<T>( void )>;
64
65 static const std::shared_ptr<const T>& getHelper( const Getter& g ) { return ( g() ); }
66 };
67
68 private:
71
72 // Unfortunately there is no standard hash functions for std::pair.
73 // so we have to provide one (which justs xors the two hashes)
74 // We could use a proper hash combination function like this one :
75 // http://www.boost.org/doc/libs/1_46_1/doc/html/hash/reference.html#boost.hash_combine
76
78 struct HashFunc {
79 inline std::size_t operator()( const Key& k ) const;
80 };
81
83 struct CallbackBase {};
84 template <typename T>
85 struct GetterCallback : public CallbackBase {
86 typename CallbackTypes<T>::Getter m_cb;
87 };
88 template <typename T>
89 struct SetterCallback : public CallbackBase {
90 typename CallbackTypes<T>::Setter m_cb;
91 };
92 template <typename T>
93 struct RwCallback : public CallbackBase {
94 typename CallbackTypes<T>::ReadWrite m_cb;
95 };
96
98 using CallbackMap = std::unordered_map<Key, std::unique_ptr<CallbackBase>, HashFunc>;
99
100 public:
101 ComponentMessenger() = default;
102
103 //
104 // Direct access to function pointers
105 //
106
107 template <typename ReturnType>
108 inline typename CallbackTypes<ReturnType>::Getter getterCallback( const Entity* entity,
109 const std::string& id );
110
111 template <typename ReturnType>
112 inline typename CallbackTypes<ReturnType>::ReadWrite rwCallback( const Entity* entity,
113 const std::string& id );
114
115 template <typename ReturnType>
116 inline typename CallbackTypes<ReturnType>::Setter setterCallback( const Entity* entity,
117 const std::string& id );
118
119 //
120 // Access the exported data.
121 //
122
123 // Note : all functions assert when the data is not available.
124 // e.g. get() assert if canGet() is false.
125
126 template <typename ReturnType>
127 inline const ReturnType& get( const Entity* entity, const std::string& id );
128
129 //
130 // Query if a given key has registered data.
131 //
132
133 template <typename ReturnType>
134 inline bool canGet( const Entity* entity, const std::string& id );
135
136 template <typename ReturnType>
137 inline bool canSet( const Entity* entity, const std::string& id );
138
139 template <typename ReturnType>
140 inline bool canRw( const Entity* entity, const std::string& id );
141
142 //
143 // Register callbacks
144 //
145
146 template <typename ReturnType>
147 inline void registerOutput( const Entity* entity,
148 Component* comp,
149 const std::string& id,
150 const typename CallbackTypes<ReturnType>::Getter& cb );
151
152 template <typename ReturnType>
153 inline void registerReadWrite( const Entity* entity,
154 Component* comp,
155 const std::string& id,
156 const typename CallbackTypes<ReturnType>::ReadWrite& cb );
157
158 template <typename ReturnType>
159 inline void registerInput( const Entity* entity,
160 Component* comp,
161 const std::string& id,
162 const typename CallbackTypes<ReturnType>::Setter& cb );
163
165 void unregisterAll( const Entity* entity, Component* component );
166
167 private:
169 EntityMap m_entityGetLists;
170 EntityMap m_entitySetLists;
171 EntityMap m_entityRwLists;
172};
173
174inline std::size_t ComponentMessenger::HashFunc::operator()( const Key& k ) const {
175 return Core::Utils::hash( k );
176}
177
178template <typename ReturnType>
180ComponentMessenger::getterCallback( const Entity* entity, const std::string& id ) {
181 CORE_ASSERT( canGet<ReturnType>( entity, id ), "Unregistered callback" );
182 return static_cast<GetterCallback<ReturnType>*>(
183 m_entityGetLists[entity][Key( id, std::type_index( typeid( ReturnType ) ) )].get() )
184 ->m_cb;
185}
186
187template <typename ReturnType>
189ComponentMessenger::rwCallback( const Entity* entity, const std::string& id ) {
190 CORE_ASSERT( canRw<ReturnType>( entity, id ), "Unregistered callback" );
191 return static_cast<RwCallback<ReturnType>*>(
192 m_entityRwLists[entity][Key( id, std::type_index( typeid( ReturnType ) ) )].get() )
193 ->m_cb;
194}
195
196template <typename ReturnType>
198ComponentMessenger::setterCallback( const Entity* entity, const std::string& id ) {
199 CORE_ASSERT( canSet<ReturnType>( entity, id ), "Unregistered callback" );
200 return static_cast<SetterCallback<ReturnType>*>(
201 m_entitySetLists[entity][Key( id, std::type_index( typeid( ReturnType ) ) )].get() )
202 ->m_cb;
203}
204
205template <typename ReturnType>
206inline const ReturnType& ComponentMessenger::get( const Entity* entity, const std::string& id ) {
207 return CallbackTypes<ReturnType>::getHelper( getterCallback<ReturnType>( entity, id ) );
208}
209/*
210 template<typename ReturnType>
211 inline void ComponentMessenger::set(const Entity* entity, const std::string& id, const
212 ReturnType& x)
213 {
214 return setterCallback<ReturnType>(entity, id)(x);
215 }
216*/
217template <typename ReturnType>
218inline bool ComponentMessenger::canGet( const Entity* entity, const std::string& id ) {
219 // Attempt to find the given entity list.
220 const auto& entityListPos = m_entityGetLists.find( entity );
221 if ( entityListPos == m_entityGetLists.end() )
222 return false; // Entity has no registered component
223
224 Key key( id, std::type_index( typeid( ReturnType ) ) );
225 const CallbackMap& entityList = entityListPos->second;
226
227 // Check if there are components exporting the given type,
228 // so let's try to find if there is one with the requested id.
229 const auto& callbackEntry = entityList.find( key );
230 const bool found = ( callbackEntry != entityList.end() );
231 return found;
232}
233
234template <typename ReturnType>
235inline bool ComponentMessenger::canSet( const Entity* entity, const std::string& id ) {
236 // Attempt to find the given entity list.
237 auto entityListPos = m_entitySetLists.find( entity );
238 if ( entityListPos == m_entitySetLists.end() )
239 return false; // Entity has no registered component
240
241 Key key( id, std::type_index( typeid( ReturnType ) ) );
242 const CallbackMap& entityList = entityListPos->second;
243
244 // Check if there are components exporting the given type,
245 // so let's try to find if there is one with the requested id.
246 const auto& callbackEntry = entityList.find( key );
247 const bool found = ( callbackEntry != entityList.end() );
248 return found;
249}
250
251template <typename ReturnType>
252inline bool ComponentMessenger::canRw( const Entity* entity, const std::string& id ) {
253 // Attempt to find the given entity list.
254 const auto& entityListPos = m_entityRwLists.find( entity );
255 if ( entityListPos == m_entityRwLists.end() )
256 return false; // Entity has no registered component
257
258 Key key( id, std::type_index( typeid( ReturnType ) ) );
259 const CallbackMap& entityList = entityListPos->second;
260
261 // Check if there are components exporting the given type,
262 // so let's try to find if there is one with the requested id.
263 const auto& callbackEntry = entityList.find( key );
264 const bool found = ( callbackEntry != entityList.end() );
265 return found;
266}
267
268template <typename ReturnType>
269inline void
270ComponentMessenger::registerOutput( const Entity* entity,
271 Component* comp,
272 const std::string& id,
273 const typename CallbackTypes<ReturnType>::Getter& cb ) {
274 CORE_ASSERT( entity && comp->getEntity() == entity, "Component not added to entity" );
275 CORE_UNUSED( comp );
276 // Will insert a new entity entry if it doesn't exist.
277 CallbackMap& entityList = m_entityGetLists[entity];
278
279 Key key( id, std::type_index( typeid( ReturnType ) ) );
280 CORE_ASSERT( entityList.find( key ) == entityList.end(),
281 "Output function already registered for " + id );
282
283 GetterCallback<ReturnType>* getter = new GetterCallback<ReturnType>();
284 getter->m_cb = cb;
285 entityList[key].reset( getter );
286}
287
288template <typename ReturnType>
289inline void
290ComponentMessenger::registerReadWrite( const Entity* entity,
291 Component* comp,
292 const std::string& id,
293 const typename CallbackTypes<ReturnType>::ReadWrite& cb ) {
294 CORE_ASSERT( entity && comp->getEntity() == entity, "Component not added to entity" );
295 CORE_UNUSED( comp );
296 // Will insert a new entity entry if it doesn't exist.
297 CallbackMap& entityList = m_entityRwLists[entity];
298
299 Key key( id, std::type_index( typeid( ReturnType ) ) );
300 CORE_ASSERT( entityList.find( key ) == entityList.end(),
301 "Rw function already registered for " + id );
302
303 RwCallback<ReturnType>* rw = new RwCallback<ReturnType>();
304 rw->m_cb = cb;
305 entityList[key].reset( rw );
306}
307
308template <typename ReturnType>
309inline void
310ComponentMessenger::registerInput( const Entity* entity,
311 Component* comp,
312 const std::string& id,
313 const typename CallbackTypes<ReturnType>::Setter& cb ) {
314 CORE_ASSERT( entity && comp->getEntity() == entity, "Component not added to entity" );
315 CORE_UNUSED( comp );
316 // Will insert a new entity entry if it doesn't exist.
317 CallbackMap& entityList = m_entitySetLists[entity];
318
319 Key key( id, std::type_index( typeid( ReturnType ) ) );
320 CORE_ASSERT( entityList.find( key ) == entityList.end(),
321 "Input function already registered for " + id );
322
323 SetterCallback<ReturnType>* setter = new SetterCallback<ReturnType>();
324 setter->m_cb = cb;
325 entityList[key].reset( setter );
326}
327
328} // namespace Scene
329} // namespace Engine
330} // namespace Ra
T end(T... args)
T find(T... args)
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
STL namespace.
This describes the function pointers accepted for each type.
std::function< void(const T *)> Setter
Function pointer for a setter function.
std::function< T *(void)> ReadWrite
Function pointer for a read/write getter.
std::function< const T *(void)> Getter
Function pointer for a getter function.
static const T & getHelper(const Getter &g)
Calls the callback and retrieves the object.