Pioneer
BodyComponent.h
Go to the documentation of this file.
1 // Copyright © 2008-2023 Pioneer Developers. See AUTHORS.txt for details
2 // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3 
4 #pragma once
5 
6 #include "JsonFwd.h"
7 #include "core/TypeId.h"
8 
9 #include <cassert>
10 #include <cstddef>
11 #include <map>
12 #include <vector>
13 
14 class Body;
15 class Space;
16 
17 // Macro to handle registering components at startup
18 #define REGISTER_COMPONENT_TYPE(type) \
19  namespace type##RegisterComponent \
20  { \
21  void Register(); \
22  bool type##Registered = BodyComponentDB::AddComponentRegistrar(&Register); \
23  } \
24  void type##RegisterComponent::Register()
25 
26 /*
27  BodyComponentDB provides a simple interface to support dynamic composition
28  of game objects. It is intended to be an interim solution to assist in
29  transitioning Pioneer's inheritance hierarchy to a simpler composition
30  model.
31 */
33 public:
34  static void Init();
35  static void Uninit();
36 
37  // Add a registrar to create and register a component pool using the REGISTER_COMPONENT_TYPE macro
38  static bool AddComponentRegistrar(void (*registrar)());
39 
40  // Polymorphic interface to support generic serialization operations
41  // This functionality is separated to facilitate components that do not wish
42  // to be serialized.
43  struct SerializerBase {
45  virtual ~SerializerBase() {}
46 
47  virtual void toJson(const Body *body, Json &obj, Space *space) = 0;
48  virtual void fromJson(Body *body, const Json &obj, Space *space) = 0;
49  };
50 
51  // Polymorphic interface to support pushing type-erased components to Lua
52  // This functionality is separated to facilitate components that do not wish
53  // to be accessed from Lua.
56  virtual ~LuaInterfaceBase() {}
57 
58  virtual void PushToLua(const Body *body) = 0;
59  virtual void DeregisterComponent(const Body *body) = 0;
60  };
61 
62  // Primary polymorphic interface to component storage. PoolBase contains all
63  // functionality for operating on specific components in a type-erased manner.
64  struct PoolBase {
65  PoolBase(size_t index, size_t type) :
66  componentIndex(index),
67  componentType(type) {}
68  virtual ~PoolBase();
69 
70  size_t componentIndex = 0;
71  size_t componentType = 0;
72 
73  // Pointer to an optional type-erased serializer instance.
74  // The serializer will persist for the lifetime of the program.
76 
77  // Pointer to an optional type-erased lua interface helper.
78  // The lua interface will be deleted by the pool's destructor.
80 
81  // Primary name of the component type for serialization purposes.
82  std::string typeName;
83 
84  virtual void deleteComponent(Body *body) = 0;
85  };
86 
87  // Forward-declared to allow access to specializations of the Pool struct.
88  template <typename T>
89  struct Serializer;
90 
91  // Intentionally left undefined, implemented in lua/LuaBodyComponent.h
92  template <typename T>
93  struct LuaInterface;
94 
95  // Type-specific component pool; uses std::map as a backing store.
96  // This is not meant to be particularly performant, merely to transition API usage.
97  // Future optimization may include use of a custom sparse-set or hash-table for
98  // faster lookup times.
99  template <typename T>
100  struct Pool final : public PoolBase {
101  using PoolBase::PoolBase;
102 
103  // Delete the component and delegate removing it from lua if necessary
104  virtual void deleteComponent(Body *body) override
105  {
106  if (luaInterface)
108 
109  m_components.erase(body);
110  }
111 
112  // Create a new component, or return the existing one.
113  T *newComponent(const Body *body) { return &m_components[body]; }
114  // Assert that a component exists for this body and return it
115  T *get(const Body *body) { return &m_components.at(body); }
116 
117  private:
118  template <typename U>
120  template <typename U>
122 
123  std::map<const Body *, T> m_components;
124  };
125 
126  // Type-specific serialization implementation. Delegates to the type's
127  // internal serialization methods and provides the needed glue code.
128  //
129  // The Component::LoadFromJson method will be called after the component
130  // is constructed and added to the body, and may potentially have defaults
131  // set by the owning Body before it is deserialized.
132  template <typename T>
133  struct Serializer final : public SerializerBase {
135  pool(pool)
136  {}
138 
139  virtual void toJson(const Body *body, Json &obj, Space *space) override
140  {
141  pool->get(body)->SaveToJson(obj, space);
142  }
143 
144  virtual void fromJson(Body *body, const Json &obj, Space *space) override
145  {
146  auto *component = pool->newComponent(body);
147  component->LoadFromJson(obj, space);
148  }
149  };
150 
151  // Returns (and creates) a type-specific pool.
152  template <typename T>
154  {
155  auto iter = m_componentPools.find(TypeId<T>::Get());
156  if (iter == m_componentPools.end()) {
157  return nullptr;
158  }
159 
160  return static_cast<Pool<T> *>(iter->second.get());
161  }
162 
163  // Returns (if present) the polymorphic interface to component associated with the given index
164  // This differs from the type-ID and is volatile between program restarts
165  static PoolBase *GetComponentType(size_t componentIndex)
166  {
167  assert(componentIndex < m_componentTypes.size());
168  return m_componentTypes[componentIndex];
169  }
170 
171  // Returns (if present) the polymorphic interface to the component type associated with the given name
172  // This name can be used for serialization or to interface with Lua
173  static PoolBase *GetComponentType(const std::string &typeName)
174  {
175  auto iter = m_componentNames.find(typeName);
176  if (iter != m_componentNames.end())
177  return iter->second;
178 
179  return nullptr;
180  }
181 
182  // Explicitly create and register a component pool. This function should be called during startup
183  // for all component types used at runtime.
184  template <typename T>
185  static void RegisterComponent(std::string typeName)
186  {
187  // We cannot have more components registered than fit in the Body bitset
188  assert(m_componentIdx < 64);
189  assert(m_componentPools.find(TypeId<T>::Get()) == m_componentPools.end());
190 
191  auto *pool = new Pool<T>(m_componentIdx++, TypeId<T>::Get());
192  pool->typeName = typeName;
193  m_componentPools.emplace(TypeId<T>::Get(), pool);
194  m_componentNames.emplace(typeName, pool);
195  m_componentTypes.push_back(pool);
196  }
197 
198  // Register a component type to be queryable from Lua with body:GetComponent()
199  template <typename T>
200  static bool RegisterLuaInterface()
201  {
202  Pool<T> *pool = GetComponentType<T>();
203  if (pool->luaInterface)
204  return false;
205 
206  pool->luaInterface = new LuaInterface<T>(pool);
207  return true;
208  }
209 
210  // Register a serializer for the given type.
211  // Multiple serializers can be registered for the given type and used while
212  // loading for backwards compatibility, however only the last-registered
213  // serializer will be used when serializing to JSON
214  template <typename T>
215  static bool RegisterSerializer(std::string typeName = {})
216  {
217  Pool<T> *pool = GetComponentType<T>();
218  if (typeName.empty())
219  typeName = pool->typeName;
220 
221  assert(!m_componentSerializers.count(typeName));
222 
223  SerializerBase *serial = new Serializer<T>(pool);
224  pool->serializer = serial;
225 
226  m_componentSerializers.emplace(typeName, serial);
227  m_componentNames.emplace(typeName, pool);
228  return true;
229  }
230 
231  // Returns a pointer to the registered Serializer instance for a type identified by the given name, or nullptr.
232  // To retrieve the serializer instance for a given type index, use GetComponentType(idx)->serializer
233  // or GetComponentType<T>()->serializer.
234  static SerializerBase *GetSerializer(const std::string &typeName)
235  {
236  auto iter = m_componentSerializers.find(typeName);
237  if (iter != m_componentSerializers.end())
238  return iter->second.get();
239 
240  return nullptr;
241  }
242 
243 private:
244  static std::map<size_t, std::unique_ptr<PoolBase>> m_componentPools;
245  static std::map<std::string, std::unique_ptr<SerializerBase>> m_componentSerializers;
246  static std::map<std::string, PoolBase *> m_componentNames;
247  static std::vector<PoolBase *> m_componentTypes;
248  static size_t m_componentIdx;
249 };
nlohmann::json Json
Definition: Json.h:8
Definition: BodyComponent.h:32
static void Uninit()
Definition: BodyComponent.cpp:23
static void Init()
Definition: BodyComponent.cpp:16
static bool RegisterSerializer(std::string typeName={})
Definition: BodyComponent.h:215
static Pool< T > * GetComponentType()
Definition: BodyComponent.h:153
static PoolBase * GetComponentType(size_t componentIndex)
Definition: BodyComponent.h:165
static bool AddComponentRegistrar(void(*registrar)())
Definition: BodyComponent.cpp:33
static void RegisterComponent(std::string typeName)
Definition: BodyComponent.h:185
static SerializerBase * GetSerializer(const std::string &typeName)
Definition: BodyComponent.h:234
static bool RegisterLuaInterface()
Definition: BodyComponent.h:200
static PoolBase * GetComponentType(const std::string &typeName)
Definition: BodyComponent.h:173
Definition: Body.h:57
Definition: Space.h:19
Definition: TypeId.h:22
Definition: GeomTree.h:9
Definition: BodyComponent.h:54
virtual void PushToLua(const Body *body)=0
virtual ~LuaInterfaceBase()
Definition: BodyComponent.h:56
LuaInterfaceBase()
Definition: BodyComponent.h:55
virtual void DeregisterComponent(const Body *body)=0
Definition: LuaBodyComponent.h:18
Definition: BodyComponent.h:64
LuaInterfaceBase * luaInterface
Definition: BodyComponent.h:79
std::string typeName
Definition: BodyComponent.h:82
size_t componentType
Definition: BodyComponent.h:71
virtual void deleteComponent(Body *body)=0
virtual ~PoolBase()
Definition: BodyComponent.cpp:39
SerializerBase * serializer
Definition: BodyComponent.h:75
PoolBase(size_t index, size_t type)
Definition: BodyComponent.h:65
size_t componentIndex
Definition: BodyComponent.h:70
Definition: BodyComponent.h:100
virtual void deleteComponent(Body *body) override
Definition: BodyComponent.h:104
T * get(const Body *body)
Definition: BodyComponent.h:115
T * newComponent(const Body *body)
Definition: BodyComponent.h:113
Definition: BodyComponent.h:43
SerializerBase()
Definition: BodyComponent.h:44
virtual void fromJson(Body *body, const Json &obj, Space *space)=0
virtual void toJson(const Body *body, Json &obj, Space *space)=0
virtual ~SerializerBase()
Definition: BodyComponent.h:45
Definition: BodyComponent.h:133
virtual void toJson(const Body *body, Json &obj, Space *space) override
Definition: BodyComponent.h:139
Pool< T > * pool
Definition: BodyComponent.h:137
Serializer(Pool< T > *pool)
Definition: BodyComponent.h:134
virtual void fromJson(Body *body, const Json &obj, Space *space) override
Definition: BodyComponent.h:144