Cafu Engine
CompBase.hpp
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
6 
7 #ifndef CAFU_GAMESYS_COMPONENT_BASE_HPP_INCLUDED
8 #define CAFU_GAMESYS_COMPONENT_BASE_HPP_INCLUDED
9 
10 #include "Variables.hpp"
11 #include "Math3D/BoundingBox.hpp"
12 #include "Templates/Pointer.hpp"
13 
14 // This macro is introduced by some header (gtk?) under Linux...
15 #undef CurrentTime
16 
17 
18 namespace cf { namespace ClipSys { class ClipModelT; } }
19 namespace cf { namespace TypeSys { class TypeInfoT; } }
20 namespace cf { namespace TypeSys { class CreateParamsT; } }
21 namespace cf { namespace TypeSys { class MethsDocT; } }
22 namespace cf { namespace TypeSys { class VarsDocT; } }
23 
24 struct CaKeyboardEventT;
25 struct CaMouseEventT;
26 struct lua_State;
27 struct luaL_Reg;
28 
29 
30 namespace cf
31 {
32  namespace GameSys
33  {
34  class ApproxBaseT;
35  class EntityT;
36 
37  /// This is the base class for the components that an entity is composed/aggregated of.
38  ///
39  /// Components are the basic building blocks of an entity: their composition defines
40  /// the properties, the behaviour, and thus virtually every aspect of the entity.
41  ///
42  /// Components can exist in two invariants:
43  /// - Stand-alone, independent and not a part of any entity.
44  /// - Normally, as an active part of a entity.
45  ///
46  /// Stand-alone components typically occur when they're newly instantiated, for example
47  /// when they are loaded from disk, when they are instantiated in scripts, or when they
48  /// are kept in the clipboard or managed in the Undo/Redo system of the Map Editor.
49  /// Newly created, copied or cloned components are initially stand-alone.
50  ///
51  /// A component becomes a part of an entity via the EntityT::AddComponent() method.
52  /// The entity then knows the component, because it hosts it, and reversely, the
53  /// component then knows the parent entity that it is a component of.
54  class ComponentBaseT : public RefCountedT
55  {
56  public:
57 
58  /// The constructor.
59  /// The newly created component is initially not a part of any entity.
61 
62  /// The copy constructor.
63  /// The newly copied component is initially not a part of any entity, even if the source component was.
64  /// @param Comp The component to create a copy of.
65  ComponentBaseT(const ComponentBaseT& Comp);
66 
67  /// The virtual copy constructor.
68  /// Callers can use this method to create a copy of this component without knowing its concrete type.
69  /// Overrides in derived classes use a covariant return type to facilitate use when the concrete type is known.
70  /// The newly cloned component is initially not a part of any entity, even if the source component was.
71  virtual ComponentBaseT* Clone() const;
72 
73  /// The virtual destructor.
74  virtual ~ComponentBaseT();
75 
76 
77  /// Returns the name of this component.
78  virtual const char* GetName() const { return "Base"; }
79 
80  /// Returns the parent entity that contains this component,
81  /// or `NULL` if this component is currently not a part of any entity.
82  EntityT* GetEntity() const { return m_Entity; }
83 
84  /// Returns the variable manager that keeps generic references to our member variables,
85  /// providing a simple kind of "reflection" or "type introspection" feature.
86  TypeSys::VarManT& GetMemberVars() { return m_MemberVars; }
87 
88  /// Sets the member variable with the given name to the given value.
89  /// The purpose of this method is to allow C++ code an easier access to the `m_MemberVars`,
90  /// especially when initializing newly created components (e.g. in the Map Editor).
91  /// (Alternatively, most derived classes had to provide some `SetXY()` methods on their own,
92  /// and thereby clutter their own public interfaces with quasi unimportant methods,
93  /// or the user code had to deal cumbersomely with the TypeSys::VarManT instance itself.)
94  template<class T> void SetMember(const char* Name, const T& Value)
95  {
96  TypeSys::VarT<T>* v = dynamic_cast<TypeSys::VarT<T>*>(m_MemberVars.Find(Name));
97  assert(v);
98  v->Set(Value);
99  }
100 
101  /// Returns the interpolators that have been registered with this component.
102  ArrayT<ApproxBaseT*>& GetInterpolators() { return m_ClientApprox; }
103 
104  /// Registers the member variable with the given name for interpolation over client
105  /// frames in order to bridge the larger intervals between server frames.
106  /// This method only works with variables whose related type is `float`, `double`,
107  /// `Vector2fT`, `Vector3fT` or `Vector3dT`.
108  bool InitClientApprox(const char* VarName);
109 
110  /// Writes the current state of this component into the given stream.
111  /// This method is called to send the state of the component over the network, to save it to disk,
112  /// or to store it in the clipboard.
113  /// The implementation calls DoSerialize() that derived classes can override to add their own data.
114  ///
115  /// @param Stream
116  /// The stream to write the state data to.
117  void Serialize(cf::Network::OutStreamT& Stream) const;
118 
119  /// Reads the state of this component from the given stream, and updates the component accordingly.
120  /// This method is called after the state of the component has been received over the network,
121  /// has been loaded from disk, has been read from the clipboard, or must be "reset" for the purpose
122  /// of (re-)prediction.
123  /// The implementation calls DoDeserialize() that derived classes can override to read their own data,
124  /// or to run any post-deserialization code.
125  ///
126  /// @param Stream
127  /// The stream to read the state data from.
128  ///
129  /// @param IsIniting
130  /// Used to indicate that the call is part of the construction / first-time initialization of the component.
131  /// The implementation will use this to not wrongly process the event counters, interpolation, etc.
132  void Deserialize(cf::Network::InStreamT& Stream, bool IsIniting);
133 
134  /// Calls the given Lua method of this component.
135  /// This method is analogous to UniScriptStateT::CallMethod(), see there for details.
136  /// @param MethodName The name of the Lua method to call.
137  /// @param NumExtraArgs The number of extra arguments that have been pushed on the stack.
138  /// @param Signature See UniScriptStateT::Call() for details.
139  bool CallLuaMethod(const char* MethodName, int NumExtraArgs, const char* Signature="", ...);
140 
141 
142  /// This method is called whenever something "external" to this component has changed:
143  /// - if the parent entity has changed, because this component was added to or removed from it,
144  /// - if other components in the parent entity have changed.
145  /// The component can use the opportunity to search the entity for "sibling" components
146  /// that it depends on, and store direct pointers to them.
147  /// Note however that dependencies among components must not be cyclic, or else the deletion
148  /// of an entity will leave a memory leak.
149  /// @param Entity The parent entity that contains this component, or `NULL` to indicate that this component is removed from the entity that it used to be a part of.
150  virtual void UpdateDependencies(EntityT* Entity);
151 
152  /// Returns a color that the Map Editor can use to render the representation of this component's entity.
153  /// The Map Editor may use the color of an entity's first component as returned by this method to render
154  /// the visual representation of the entity.
155  virtual unsigned int GetEditorColor() const { return 0xDC1EDC; } // (220, 30, 220)
156 
157  /// Returns a bounding-box that the Map Editor can use to render the representation of this component's
158  /// entity and for related hit tests in the 2D and 3D views after mouse clicks.
159  /// The Map Editor may use the bounding-box of an entity's first component as returned by this method to
160  /// render the visual representation of the entity.
161  ///
162  /// Note that the returned bounding-box is often *smaller* than the bounding-box returned by
163  /// GetCullingBB(), e.g. for light sources (whose radius and thus their indirect effects on other objects
164  /// it may not cover), for trees (whose trunk it usually covers, but maybe not their crown), or for models
165  /// (that, when animated, may break the limits of the static bounding-box).
166  ///
167  /// On the other hand, the returned bounding-box may also be *larger* than the bounding-box returned by
168  /// GetCullingBB(), e.g. for models that are not initialized. Such models would be "invisible" in the 2D
169  /// and 3D views of the Map Editor if we didn't return "dummy" bounding-boxes for them so that users can
170  /// see and work with them.
171  ///
172  /// The returned bounding-box is in local entity space and is always initialized (`IsInited() == true`).
173  virtual BoundingBox3fT GetEditorBB() const { return BoundingBox3fT(Vector3fT(-8, -8, -8), Vector3fT(8, 8, 8)); }
174 
175  /// This method returns a bounding-box that encloses the visual representation of this component.
176  /// It is used to determine if the entity is in the view-frustum of a camera, how large a region must be
177  /// updated in the 2D views of a Map Editor, if the entity is in the potentially-visibility-set (PVS) of
178  /// another entity, and similar purposes.
179  ///
180  /// The returned bounding-box is in local space, i.e. typically centered around the origin (0, 0, 0).
181  /// If the component doesn't have a visual representation, the returned bounding-box may be uninitialized
182  /// (`!IsInited()`). Also see EntityT::GetCullingBB() for additional details.
183  virtual BoundingBox3fT GetCullingBB() const { return BoundingBox3fT(); }
184 
185  /// This method returns the clip model of this component, if any.
186  virtual const cf::ClipSys::ClipModelT* GetClipModel() { return NULL; }
187 
188  /// Initializes any resources that may be needed on the client or server ahead of time.
189  /// The goal is to avoid in-game disruptions on frame-rate caused by lazily loaded assets.
190  virtual void PreCache() { }
191 
192  /// This method implements the graphical output of this component.
193  /// @param FirstPersonView If the world is rendered from the perspective of this component's entity.
194  /// @param LodDist The distance of the viewer entity to this component's entity.
195  /// @returns `true` if "something" was rendered, `false` otherwise (in this case the Map Editor may choose
196  /// to render another visual representation of this component's entity).
197  virtual bool Render(bool FirstPersonView, float LodDist) const { return false; }
198 
199  /// This method provides an opportunity for another render pass.
200  virtual void PostRender(bool FirstPersonView) { }
201 
202  /// This method is called after all entities and their components have been loaded.
203  ///
204  /// It is called only once when the static part of world initializatzion is complete, i.e. after the initial
205  /// values of all entities and their components have been set.
206  /// Components can override this method in order act / do something / add custom behaviour at that time.
207  ///
208  /// For example, a choice component can use it to set the associated text component to the initial
209  /// selection, a script component can forward it to the script by calling a related script function,
210  /// a component that for backwards-compatibility supports reading old variables can convert to new ones, etc.
211  ///
212  /// @param OnlyStatic `true` if only the loading of static data is desired, e.g.
213  /// when the world is instantiated in the Map Editor, `false` if also
214  /// user-defined scripts with custom, initial behaviour should be loaded.
215  /// Also see WorldT::InitFlagsT::InitFlag_OnlyStatic for related information.
216  virtual void OnPostLoad(bool OnlyStatic) { }
217 
218  /// This method handles keyboard input events.
219  /// @param KE Keyboard event instance.
220  /// @returns Whether the component handled ("consumed") the event.
221  virtual bool OnInputEvent(const CaKeyboardEventT& KE) { return false; }
222 
223  /// This method handles mouse input events.
224  /// @param ME Mouse event instance.
225  /// @param PosX x-coordinate of the mouse cursor position.
226  /// @param PosY y-coordinate of the mouse cursor position.
227  /// @returns Whether the component handled ("consumed") the event.
228  virtual bool OnInputEvent(const CaMouseEventT& ME, float PosX, float PosY) { return false; }
229 
230  /// Advances the component one frame (one "clock-tick") on the server.
231  /// It typically updates all game-relevant state that is sync'ed over the network to all
232  /// connected game clients.
233  ///
234  /// Note that the implementation calls DoServerFrame() that derived classes can override to
235  /// implement their own custom behaviour.
236  ///
237  /// @param t The time in seconds since the last server frame.
238  void OnServerFrame(float t);
239 
240  /// Advances the component one frame (one "clock-tick") on the client.
241  /// It typically updates eye-candy that is *not* sync'ed over the network.
242  /// (State that is sync'ed over the network must be updated in OnServerFrame() instead.)
243  ///
244  /// Note that the implementation calls DoClientFrame() that derived classes can override to
245  /// implement their own custom behaviour.
246  ///
247  /// @param t The time in seconds since the last client frame.
248  void OnClientFrame(float t);
249 
250 
251  // The TypeSys related declarations for this class.
252  virtual const cf::TypeSys::TypeInfoT* GetType() const { return &TypeInfo; }
253  static void* CreateInstance(const cf::TypeSys::CreateParamsT& Params);
254  static const cf::TypeSys::TypeInfoT TypeInfo;
255 
256 
257  protected:
258 
259  // The Lua API methods of this class.
260  static int Get(lua_State* LuaState);
261  static int Set(lua_State* LuaState);
262  static int GetExtraMessage(lua_State* LuaState);
263  static int Interpolate(lua_State* LuaState);
264  static int GetEntity(lua_State* LuaState);
265  static int InitClientApprox(lua_State* LuaState);
266  static int toString(lua_State* LuaState);
267 
268  static const luaL_Reg MethodsList[]; ///< The list of Lua methods for this class.
269  static const char* DocClass;
270  static const cf::TypeSys::MethsDocT DocMethods[];
271  static const cf::TypeSys::MethsDocT DocCallbacks[];
272 
273 
274  private:
275 
276  /// A helper structure for interpolations.
277  struct InterpolationT
278  {
279  cf::TypeSys::VarBaseT* Var; ///< The variable whose value is being interpolated.
280  unsigned int Suffix; ///< If the variable is composed of several values, this is the index of the one being interpolated.
281  float StartValue; ///< Start value of the interpolation.
282  float EndValue; ///< End value of the interpolation.
283  float CurrentTime; ///< Current time between 0 and TotalTime.
284  float TotalTime; ///< Duration of the interpolation.
285 
286  float GetCurrentValue() const { return StartValue + (EndValue-StartValue)*CurrentTime/TotalTime; }
287  };
288 
289 
290  /// Use of the Assignment Operator is not allowed (the method is declared, but left undefined).
291  void operator = (const ComponentBaseT&);
292 
293  /// Derived classes override this method in order to write additional state data into the given stream.
294  /// The method itself is automatically called from Serialize(), see Serialize() for more details.
295  ///
296  /// (This follows the "Non-Virtual Interface Idiom" as described by Scott Meyers in
297  /// "Effective C++, 3rd Edition", item 35 ("Consider alternatives to virtual functions.").)
298  virtual void DoSerialize(cf::Network::OutStreamT& Stream) const { }
299 
300  /// Derived classes override this method in order to read additional state data from the given stream,
301  /// or to run any post-deserialization code.
302  /// The method itself is automatically called from Deserialize(), see Deserialize() for more details.
303  ///
304  /// (This follows the "Non-Virtual Interface Idiom" as described by Scott Meyers in
305  /// "Effective C++, 3rd Edition", item 35 ("Consider alternatives to virtual functions.").)
306  virtual void DoDeserialize(cf::Network::InStreamT& Stream, bool IsIniting) { }
307 
308  /// Derived classes override this method in order to implement the real work proposed by OnServerFrame(),
309  /// which explicitly calls this method for this purpose.
310  ///
311  /// (This follows the "Non-Virtual Interface Idiom" as described by Scott Meyers in
312  /// "Effective C++, 3rd Edition", item 35 ("Consider alternatives to virtual functions.").)
313  virtual void DoServerFrame(float t) { }
314 
315  /// Derived classes override this method in order to implement the real work proposed by OnClientFrame(),
316  /// which explicitly calls this method for this purpose.
317  ///
318  /// (This follows the "Non-Virtual Interface Idiom" as described by Scott Meyers in
319  /// "Effective C++, 3rd Edition", item 35 ("Consider alternatives to virtual functions.").)
320  virtual void DoClientFrame(float t) { }
321 
322 
323  EntityT* m_Entity; ///< The parent entity that contains this component, or `NULL` if this component is currently not a part of any entity.
324  TypeSys::VarManT m_MemberVars; ///< The variable manager that keeps generic references to our member variables.
325  ArrayT<InterpolationT*> m_PendingInterp; ///< The currently pending interpolations. These are usually set by scripts, in order to e.g. transfer a lift from A to B.
326  ArrayT<ApproxBaseT*> m_ClientApprox; ///< The interpolators that advance values over client frames in order to bridge the larger intervals between server frames.
327  };
328  }
329 }
330 
331 #endif
virtual BoundingBox3fT GetEditorBB() const
Returns a bounding-box that the Map Editor can use to render the representation of this component's e...
Definition: CompBase.hpp:173
This class is a simple container for pointers to VarBaseTs.
Definition: Variables.hpp:326
virtual bool OnInputEvent(const CaMouseEventT &ME, float PosX, float PosY)
This method handles mouse input events.
Definition: CompBase.hpp:228
virtual unsigned int GetEditorColor() const
Returns a color that the Map Editor can use to render the representation of this component's entity...
Definition: CompBase.hpp:155
A clip model represents an object in the world against which clipping queries can be performed...
Definition: ClipModel.hpp:31
virtual bool OnInputEvent(const CaKeyboardEventT &KE)
This method handles keyboard input events.
Definition: CompBase.hpp:221
bool CallLuaMethod(const char *MethodName, int NumExtraArgs, const char *Signature="",...)
Calls the given Lua method of this component.
Definition: CompBase.cpp:133
void OnServerFrame(float t)
Advances the component one frame (one "clock-tick") on the server.
Definition: CompBase.cpp:151
TypeSys::VarManT & GetMemberVars()
Returns the variable manager that keeps generic references to our member variables, providing a simple kind of "reflection" or "type introspection" feature.
Definition: CompBase.hpp:86
void Deserialize(cf::Network::InStreamT &Stream, bool IsIniting)
Reads the state of this component from the given stream, and updates the component accordingly...
Definition: CompBase.cpp:116
void Serialize(cf::Network::OutStreamT &Stream) const
Writes the current state of this component into the given stream.
Definition: CompBase.cpp:98
This struct describes a mouse event.
Definition: OpenGLWindow.hpp:185
virtual void OnPostLoad(bool OnlyStatic)
This method is called after all entities and their components have been loaded.
Definition: CompBase.hpp:216
This class represents game entities, which are the basic elements of a world.
Definition: Entity.hpp:53
This is a "wrapper" around a normal C++ variable.
Definition: SetCompVar.hpp:15
bool InitClientApprox(const char *VarName)
Registers the member variable with the given name for interpolation over client frames in order to br...
Definition: CompBase.cpp:71
virtual void PreCache()
Initializes any resources that may be needed on the client or server ahead of time.
Definition: CompBase.hpp:190
virtual ComponentBaseT * Clone() const
The virtual copy constructor.
Definition: CompBase.cpp:50
This class is used for reading data from a StateT instance (deserialization).
Definition: State.hpp:207
EntityT * GetEntity() const
Returns the parent entity that contains this component, or NULL if this component is currently not a ...
Definition: CompBase.hpp:82
ArrayT< ApproxBaseT * > & GetInterpolators()
Returns the interpolators that have been registered with this component.
Definition: CompBase.hpp:102
This class is used for writing data into a StateT instance (serialization).
Definition: State.hpp:81
This struct describes a keyboard event.
Definition: OpenGLWindow.hpp:20
void SetMember(const char *Name, const T &Value)
Sets the member variable with the given name to the given value.
Definition: CompBase.hpp:94
virtual ~ComponentBaseT()
The virtual destructor.
Definition: CompBase.cpp:56
virtual BoundingBox3fT GetCullingBB() const
This method returns a bounding-box that encloses the visual representation of this component...
Definition: CompBase.hpp:183
ComponentBaseT()
The constructor.
Definition: CompBase.cpp:32
virtual void PostRender(bool FirstPersonView)
This method provides an opportunity for another render pass.
Definition: CompBase.hpp:200
This is the common base class for the VarT classes.
Definition: Variables.hpp:113
virtual bool Render(bool FirstPersonView, float LodDist) const
This method implements the graphical output of this component.
Definition: CompBase.hpp:197
virtual void Set(const T &v)
Sets the value of this variable to the given value v.
Definition: Variables.hpp:189
void OnClientFrame(float t)
Advances the component one frame (one "clock-tick") on the client.
Definition: CompBase.cpp:194
virtual void UpdateDependencies(EntityT *Entity)
This method is called whenever something "external" to this component has changed: ...
Definition: CompBase.cpp:145
static const luaL_Reg MethodsList[]
The list of Lua methods for this class.
Definition: CompBase.hpp:268
virtual const char * GetName() const
Returns the name of this component.
Definition: CompBase.hpp:78
virtual const cf::ClipSys::ClipModelT * GetClipModel()
This method returns the clip model of this component, if any.
Definition: CompBase.hpp:186
Definition: Renderer.hpp:16
Definition: TypeSys.hpp:52
Definition: TypeSys.hpp:57
This class keeps type information (about an entity class that occurs in the game).
Definition: TypeSys.hpp:79
A base class for objects that are reference-counted with IntrusivePtrTs.
Definition: Pointer.hpp:13
This is the base class for the components that an entity is composed/aggregated of.
Definition: CompBase.hpp:54