Pioneer
Loading...
Searching...
No Matches
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
14class Body;
15class 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*/
33public:
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.
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>
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
243private:
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 PoolBase * GetComponentType(size_t componentIndex)
Definition BodyComponent.h:165
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 SerializerBase * GetSerializer(const std::string &typeName)
Definition BodyComponent.h:234
static bool AddComponentRegistrar(void(*registrar)())
Definition BodyComponent.cpp:33
static Pool< T > * GetComponentType()
Definition BodyComponent.h:153
static void RegisterComponent(std::string typeName)
Definition BodyComponent.h:185
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 * newComponent(const Body *body)
Definition BodyComponent.h:113
T * get(const Body *body)
Definition BodyComponent.h:115
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