/
ientity.h
348 lines (302 loc) · 11 KB
/
ientity.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#pragma once
#include "inode.h"
#include "ipath.h"
#include "imodule.h"
#include "irender.h"
#include "inameobserver.h"
#include <functional>
class IEntityClass;
typedef std::shared_ptr<IEntityClass> IEntityClassPtr;
typedef std::shared_ptr<const IEntityClass> IEntityClassConstPtr;
// Observes a single entity key value and gets notified on change
class KeyObserver
{
public:
virtual ~KeyObserver() {}
/**
* This event gets called when the observed keyvalue changes.
* The new value is passed as argument, which can be an empty string.
*/
virtual void onKeyValueChanged(const std::string& newValue) = 0;
};
class EntityKeyValue :
public NameObserver
{
public:
virtual ~EntityKeyValue() {}
/** greebo: Retrieves the actual value of this key
*/
virtual const std::string& get() const = 0;
/** greebo: Sets the value of this key
*/
virtual void assign(const std::string& other) = 0;
/** greebo: Attaches/detaches a callback to get notified about
* the key change.
*/
virtual void attach(KeyObserver& observer) = 0;
virtual void detach(KeyObserver& observer) = 0;
};
typedef std::shared_ptr<EntityKeyValue> EntityKeyValuePtr;
/**
* Interface for a map entity. The Entity is the main building block of a
* map, and the uppermost layer in the scenegraph under the root node. Each
* entity contains a arbitrary dictionary of strings ("properties" or
* "spawnargs") containing information about this entity which is used by the
* game engine to modify its behaviour, and may additionally contain child
* primitives (brushes and patches) depending on its type.
*
* At the minimum, each Entity must contain three properties: "name" which
* contains a map-unique string identifier, "classname" which identifies the
* entity class to the game, and "origin" which stores the location of the
* entity in 3-dimensional world space.
*
* A valid <b>Id Tech 4</b> map must contain at least one entity: the
* "worldspawn" which is the parent of all map geometry primitives.
*
* greebo: Note that keys are treated case-insensitively in Doom 3, so
* the Entity class will return the same result for "MYKeY" as for "mykey".
*/
class Entity
{
public:
// A container with key => value pairs
typedef std::vector< std::pair<std::string, std::string> > KeyValuePairs;
/**
* \brief
* Abstract base class for entity observers.
*
* An entity observer receives notifications when keyvalues are inserted or
* deleted on the entity it is observing.
*/
class Observer
{
public:
virtual ~Observer() {}
/**
* \brief
* Notification that a new key value has been inserted on the entity.
*/
virtual void onKeyInsert(const std::string& key, EntityKeyValue& value)
{ }
/**
* \brief
* Notification that a key value has changed on the entity.
*/
virtual void onKeyChange(const std::string& key, const std::string& val)
{ }
/**
* \brief
* Notification that a key value has been removed from the entity.
*/
virtual void onKeyErase(const std::string& key, EntityKeyValue& value)
{ }
};
// Function typedef to visit keyvalues
typedef std::function<void(const std::string& key, const std::string& value)> KeyValueVisitFunctor;
// Function typedef to visit actual EntityKeyValue objects, not just the string values
typedef std::function<void(const std::string& key, EntityKeyValue& value)> EntityKeyValueVisitFunctor;
virtual ~Entity() {}
/**
* Return the entity class object for this entity.
*/
virtual IEntityClassPtr getEntityClass() const = 0;
/**
* Enumerate key values on this entity using a function object taking
* key and value as string arguments.
*/
virtual void forEachKeyValue(const KeyValueVisitFunctor& visitor) const = 0;
// Similar to above, visiting the EntityKeyValue objects itself, not just the string value.
virtual void forEachEntityKeyValue(const EntityKeyValueVisitFunctor& visitor) = 0;
/** Set a key value on this entity. Setting the value to "" will
* remove the key.
*
* @param key
* The key to set.
*
* @param value
* Value to give the key, or the empty string to remove the key.
*/
virtual void setKeyValue(const std::string& key,
const std::string& value) = 0;
/* Retrieve a key value from the entity.
*
* @param key
* The key to retrieve.
*
* @returns
* The current value for this key, or the empty string if it does not
* exist.
*/
virtual std::string getKeyValue(const std::string& key) const = 0;
/**
* greebo: Checks whether the given key is inherited or not.
*
* @returns: TRUE if the value is inherited,
* FALSE when it is not or when the key doesn't exist at all.
*/
virtual bool isInherited(const std::string& key) const = 0;
/**
* Return the list of Key/Value pairs matching the given prefix, case ignored.
*
* This method performs a search for all spawnargs whose key
* matches the given prefix, with a suffix consisting of zero or more
* arbitrary characters. For example, if "target" were specified as the
* prefix, the list would include "target", "target0", "target127" etc.
*
* This operation may not have high performance, due to the need to scan
* for matching names, therefore should not be used in performance-critical
* code.
*
* @param prefix
* The prefix to search for, interpreted case-insensitively.
*
* @return
* A list of KeyValue pairs matching the provided prefix. This
* list will be empty if there were no matches.
*/
virtual KeyValuePairs getKeyValuePairs(const std::string& prefix) const = 0;
/** greebo: Returns true if the entity is a model. For Doom3, this is
* usually true when the classname == "func_static" and
* the non-empty spawnarg "model" != "name".
*/
virtual bool isModel() const = 0;
/**
* Returns true if this entity is the worldspawn, which can be game-specific,
* but is usually true if this entity's classname equals "worldspawn"
*/
virtual bool isWorldspawn() const = 0;
virtual bool isContainer() const = 0;
/**
* \brief
* Attach an Entity::Observer to this Entity.
*/
virtual void attachObserver(Observer* observer) = 0;
/**
* \brief
* Detach an Entity::Observer from this Entity.
*/
virtual void detachObserver(Observer* observer) = 0;
/**
* Returns true if this entity is of type or inherits from the
* given entity class name. className is treated case-sensitively.
*/
virtual bool isOfType(const std::string& className) = 0;
};
/// Interface for a INode subclass that contains an Entity
class IEntityNode :
public virtual IRenderEntity,
public virtual scene::INode
{
public:
virtual ~IEntityNode() {}
/// Get a modifiable reference to the contained Entity
virtual Entity& getEntity() = 0;
/**
* greebo: Tells the entity to reload the child model. This usually
* includes removal of the child model node and triggering
* a "skin changed" event.
*/
virtual void refreshModel() = 0;
};
typedef std::shared_ptr<IEntityNode> IEntityNodePtr;
inline Entity* Node_getEntity(const scene::INodePtr& node)
{
IEntityNodePtr entityNode = std::dynamic_pointer_cast<IEntityNode>(node);
if (entityNode != NULL) {
return &(entityNode->getEntity());
}
return NULL;
}
inline bool Node_isEntity(const scene::INodePtr& node)
{
//assert(!((std::dynamic_pointer_cast<IEntityNode>(node) != nullptr) ^ (node->getNodeType() == scene::INode::Type::Entity)));
return node->getNodeType() == scene::INode::Type::Entity;
}
/**
* greebo: This is an abstract representation of a target.
* In Doom3 maps, a Target can be any entity node, that's
* why this object encapsulates a reference to an actual
* scene::INode.
*
* Note: Such a Target object can be empty. That's the case for
* entities referring to non-existing entities in their
* "target" spawnarg.
*
* All ITargetableObjects are owned by the TargetManager class.
*/
class ITargetableObject
{
public:
virtual ~ITargetableObject() {}
// Returns the scene node behind this target. If the named target
// cannot be resolved in the current scene, an empty pointer is returned.
virtual const scene::INode* getNode() const = 0;
// Use this method to check whether the node can be resolved
virtual bool isEmpty() const = 0;
};
typedef std::shared_ptr<ITargetableObject> ITargetableObjectPtr;
/**
* greebo: The TargetManager keeps track of all ITargetableObjects
* in the current scene/map. A TargetManager instance is owned
* by the RootNode. TargetManager instances can be acquired through
* the EntityCreator interface.
*
* Clients acquire a named ITargetableObjectPtr by calling getTarget(). This
* always succeeds - if the named ITargetableObject is not found,
* a new, empty one is created.
*
* ITargetableObject object (can be empty)
* ________
* / \
* Entity | |
* TargetKey ----->>| -------->> holds scene::INodePtr (==NULL, if empty)
* | |
* \________/
*/
class ITargetManager
{
public:
/**
* Returns the Target with the given name.
* This never returns NULL, an ITargetableObject is created if it doesn't exist yet.
*/
virtual ITargetableObjectPtr getTarget(const std::string name) = 0;
/**
* greebo: Associates the named Target with the given scene::INode.
* The Target will be created if it doesn't exist yet.
*/
virtual void associateTarget(const std::string& name, const scene::INode& node) = 0;
/**
* greebo: Disassociates the Target from the given name. The node
* must also be passed to allow the manager to check the request.
* Otherwise it would be possible for cloned nodes to dissociate
* the target from their source node.
*/
virtual void clearTarget(const std::string& name, const scene::INode& node) = 0;
};
typedef std::shared_ptr<ITargetManager> ITargetManagerPtr;
const char* const MODULE_ENTITYCREATOR("Doom3EntityCreator");
/**
* \brief
* Interface for the entity creator module.
*/
class EntityCreator :
public RegisterableModule
{
public:
virtual ~EntityCreator() {}
/// Create an entity node with the given entity class.
virtual IEntityNodePtr createEntity(const IEntityClassPtr& eclass) = 0;
// Constructs a new targetmanager instance (used by root nodes)
virtual ITargetManagerPtr createTargetManager() = 0;
};
inline EntityCreator& GlobalEntityCreator()
{
// Cache the reference locally
static EntityCreator& _entityCreator(
*std::static_pointer_cast<EntityCreator>(
module::GlobalModuleRegistry().getModule(MODULE_ENTITYCREATOR)
)
);
return _entityCreator;
}