gameBase.h

Engine/source/T3D/gameBase/gameBase.h

More...

Classes:

class

Base class for game objects which use datablocks, networking, are editable, and need to process ticks.

class

Scriptable, demo-able datablock.

Public Defines

Public Functions

bool
PACK_DB_ID(BitStream * stream, U32 id)
bool
PRELOAD_DB(U32 & id, SimDataBlock ** data, bool server, const char * clientMissing, const char * serverMissing)
bool
UNPACK_DB_ID(BitStream * stream, U32 & id)

Detailed Description

Public Defines

__SCENEMANAGER_H__() 

Public Functions

PACK_DB_ID(BitStream * stream, U32 id)

PRELOAD_DB(U32 & id, SimDataBlock ** data, bool server, const char * clientMissing, const char * serverMissing)

UNPACK_DB_ID(BitStream * stream, U32 & id)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#ifndef _GAMEBASE_H_
 25#define _GAMEBASE_H_
 26
 27#ifndef _SCENEOBJECT_H_
 28#include "scene/sceneObject.h"
 29#endif
 30#ifndef _PROCESSLIST_H_
 31#include "T3D/gameBase/processList.h"
 32#endif
 33#ifndef _TICKCACHE_H_
 34#include "T3D/gameBase/tickCache.h"
 35#endif
 36#ifndef _DYNAMIC_CONSOLETYPES_H_
 37#include "console/dynamicTypes.h"
 38#endif
 39#ifndef __SCENEMANAGER_H__  
 40#include "scene/sceneManager.h"    
 41#define __SCENEMANAGER_H__  
 42#endif
 43#ifndef _IDISPLAYDEVICE_H_
 44#include "platform/output/IDisplayDevice.h"
 45#endif
 46
 47class NetConnection;
 48class ProcessList;
 49class GameBase;
 50struct Move;
 51
 52//----------------------------------------------------------------------------
 53//----------------------------------------------------------------------------
 54
 55/// Scriptable, demo-able datablock.
 56///
 57/// This variant of SimDataBlock performs these additional tasks:
 58///   - Linking datablock's namepsaces to the namespace of their C++ class, so
 59///     that datablocks can expose script functionality.
 60///   - Linking datablocks to a user defined scripting namespace, by setting the
 61///     'class' field at datablock definition time.
 62///   - Adds a category field; this is used by the world creator in the editor to
 63///     classify creatable shapes. Creatable shapes are placed under the Shapes
 64///     node in the treeview for this; additional levels are created, named after
 65///     the category fields.
 66///   - Adds support for demo stream recording. This support takes the form
 67///     of the member variable packed. When a demo is being recorded by a client,
 68///     data is unpacked, then packed again to the data stream, then, in the case
 69///     of datablocks, preload() is called to process the data. It is occasionally
 70///     the case that certain references in the datablock stream cannot be resolved
 71///     until preload is called, in which case a raw ID field is stored in the variable
 72///     which will eventually be used to store a pointer to the object. However, if
 73///     packData() is called before we resolve this ID, trying to call getID() on the
 74///     objecct ID would be a fatal error. Therefore, in these cases, we test packed;
 75///     if it is true, then we know we have to write the raw data, instead of trying
 76///     to resolve an ID.
 77///
 78/// @see SimDataBlock for further details about datablocks.
 79/// @see http://hosted.tribalwar.com/t2faq/datablocks.shtml for an excellent
 80///      explanation of the basics of datablocks from a scripting perspective.
 81/// @nosubgrouping
 82struct GameBaseData : public SimDataBlock 
 83{
 84private:
 85
 86   typedef SimDataBlock Parent;
 87
 88public:
 89
 90   bool packed;
 91   StringTableEntry category;
 92
 93   // Signal triggered when this datablock is modified.
 94   // GameBase objects referencing this datablock notify with this signal.
 95   Signal<void(void)> mReloadSignal;
 96
 97   // Triggers the reload signal.
 98   void inspectPostApply();
 99
100   bool onAdd();   
101
102   // The derived class should provide the following:
103   DECLARE_CONOBJECT(GameBaseData);
104   GameBaseData();
105   static void initPersistFields();
106   bool preload(bool server, String &errorStr);
107   void unpackData(BitStream* stream);
108
109   /// @name Callbacks
110   /// @{
111   DECLARE_CALLBACK( void, onAdd, ( GameBase* obj ) );
112   DECLARE_CALLBACK( void, onRemove, ( GameBase* obj ) );
113   DECLARE_CALLBACK( void, onNewDataBlock, ( GameBase* obj ) );
114   DECLARE_CALLBACK( void, onMount, ( SceneObject* obj, SceneObject* mountObj, S32 node ) );
115   DECLARE_CALLBACK( void, onUnmount, ( SceneObject* obj, SceneObject* mountObj, S32 node ) );
116   /// @}
117};
118
119//----------------------------------------------------------------------------
120// A few utility methods for sending datablocks over the net
121//----------------------------------------------------------------------------
122
123bool UNPACK_DB_ID(BitStream *, U32 & id);
124bool PACK_DB_ID(BitStream *, U32 id);
125bool PRELOAD_DB(U32 & id, SimDataBlock **, bool server, const char * clientMissing = NULL, const char * serverMissing = NULL);
126
127//----------------------------------------------------------------------------
128class GameConnection;
129class WaterObject;
130class MoveList;
131
132// For truly it is written: "The wise man extends GameBase for his purposes,
133// while the fool has the ability to eject shell casings from the belly of his
134// dragon." -- KillerBunny
135
136/// Base class for game objects which use datablocks, networking, are editable,
137/// and need to process ticks.
138///
139/// @section GameBase_process GameBase and ProcessList
140///
141/// GameBase adds two kinds of time-based updates. Torque works off of a concept
142/// of ticks. Ticks are slices of time 32 milliseconds in length. There are three
143/// methods which are used to update GameBase objects that are registered with
144/// the ProcessLists:
145///      - processTick(Move*) is called on each object once for every tick, regardless
146///        of the "real" framerate.
147///      - interpolateTick(float) is called on client objects when they need to interpolate
148///        to match the next tick.
149///      - advanceTime(float) is called on client objects so they can do time-based behaviour,
150///        like updating animations.
151///
152/// Torque maintains a server and a client processing list; in a local game, both
153/// are populated, while in multiplayer situations, either one or the other is
154/// populated.
155///
156/// You can control whether an object is considered for ticking by means of the
157/// setProcessTick() method.
158///
159/// @section GameBase_datablock GameBase and Datablocks
160///
161/// GameBase adds support for datablocks. Datablocks are secondary classes which store
162/// static data for types of game elements. For instance, this means that all "light human
163/// male armor" type Players share the same datablock. Datablocks typically store not only
164/// raw data, but perform precalculations, like finding nodes in the game model, or
165/// validating movement parameters.
166///
167/// There are three parts to the datablock interface implemented in GameBase:
168///      - <b>getDataBlock()</b>, which gets a pointer to the current datablock. This is
169///        mostly for external use; for in-class use, it's better to directly access the
170///        mDataBlock member.
171///      - <b>setDataBlock()</b>, which sets mDataBlock to point to a new datablock; it
172///        uses the next part of the interface to inform subclasses of this.
173///      - <b>onNewDataBlock()</b> is called whenever a new datablock is assigned to a GameBase.
174///
175/// Datablocks are also usable through the scripting language.
176///
177/// @see SimDataBlock for more details.
178///
179/// @section GameBase_networking GameBase and Networking
180///
181/// writePacketData() and readPacketData() are called to transfer information needed for client
182/// side prediction. They are usually used when updating a client of its control object state.
183///
184/// Subclasses of GameBase usually transmit positional and basic status data in the packUpdate()
185/// functions, while giving velocity, momentum, and similar state information in the writePacketData().
186///
187/// writePacketData()/readPacketData() are called <i>in addition</i> to packUpdate/unpackUpdate().
188///
189/// @nosubgrouping
190class GameBase : public SceneObject
191{      
192   typedef SceneObject Parent;
193
194   /// @name Datablock
195   /// @{
196
197   GameBaseData*     mDataBlock;
198
199   /// @}
200
201   TickCache mTickCache;
202   
203   // Control interface
204   GameConnection* mControllingClient;
205
206public:
207
208   static bool gShowBoundingBox;    ///< Should we render bounding boxes?
209  
210protected:
211
212   F32 mCameraFov;
213
214   /// The WaterObject we are currently within.
215   WaterObject *mCurrentWaterObject;
216   
217   static bool setDataBlockProperty( void *object, const char *index, const char *data );
218
219#ifdef TORQUE_DEBUG_NET_MOVES
220   U32 mLastMoveId;
221   U32 mTicksSinceLastMove;
222   bool mIsAiControlled;
223#endif   
224
225public:
226
227   GameBase();
228   ~GameBase();
229
230   enum GameBaseMasks {      
231      DataBlockMask     = Parent::NextFreeMask << 0,
232      ExtendedInfoMask  = Parent::NextFreeMask << 1,
233      NextFreeMask      = Parent::NextFreeMask << 2
234   };
235
236   // net flags added by game base
237   enum
238   {
239      NetOrdered        = BIT(Parent::MaxNetFlagBit+1), /// Process in same order on client and server.
240      NetNearbyAdded    = BIT(Parent::MaxNetFlagBit+2), /// Is set during client catchup when neighbors have been checked.
241      GhostUpdated      = BIT(Parent::MaxNetFlagBit+3), /// Is set whenever ghost updated (and reset) on the client, for hifi objects.
242      TickLast          = BIT(Parent::MaxNetFlagBit+4), /// Tick this object after all others.
243      NewGhost          = BIT(Parent::MaxNetFlagBit+5), /// This ghost was just added during the last update.
244      HiFiPassive       = BIT(Parent::MaxNetFlagBit+6), /// Do not interact with other hifi passive objects.
245      MaxNetFlagBit     = Parent::MaxNetFlagBit+6
246   };
247
248   /// @name Inherited Functionality.
249   /// @{
250
251   bool onAdd();
252   void onRemove();
253   void inspectPostApply();
254   static void initPersistFields();
255   static void consoleInit();
256
257   /// @}
258
259   ///@name Datablock
260   ///@{
261
262   /// Assigns this object a datablock and loads attributes with onNewDataBlock.
263   ///
264   /// @see onNewDataBlock
265   /// @param   dptr   Datablock
266   bool          setDataBlock( GameBaseData *dptr );
267
268   /// Returns the datablock for this object.
269   GameBaseData* getDataBlock()  { return mDataBlock; }
270
271   /// Called when a new datablock is set. This allows subclasses to
272   /// appropriately handle new datablocks.
273   ///
274   /// @see    setDataBlock()
275   /// @param  dptr     New datablock
276   /// @param  reload   Is this a new datablock or are we reloading one
277   ///                  we already had.
278   virtual bool onNewDataBlock( GameBaseData *dptr, bool reload );   
279   ///@}
280
281   /// @name Script
282   /// The scriptOnXX methods are invoked by the leaf classes
283   /// @{
284
285   /// Executes the 'onAdd' script function for this object.
286   /// @note This must be called after everything is ready
287   void scriptOnAdd();
288
289   /// Executes the 'onNewDataBlock' script function for this object.
290   ///
291   /// @note This must be called after everything is loaded.
292   void scriptOnNewDataBlock();
293
294   /// Executes the 'onRemove' script function for this object.
295   /// @note This must be called while the object is still valid
296   void scriptOnRemove();
297
298   /// @}
299
300   // ProcessObject override
301   void processTick( const Move *move ); 
302
303   /// @name GameBase NetFlags & Hifi-Net Interface   
304   /// @{
305   
306   /// Set or clear the GhostUpdated bit in our NetFlags.
307   /// @see GhostUpdated
308   void setGhostUpdated( bool b ) { if (b) mNetFlags.set(GhostUpdated); else mNetFlags.clear(GhostUpdated); }
309
310   /// Returns true if the GhostUpdated bit in our NetFlags is set.
311   /// @see GhostUpdated
312   bool isGhostUpdated() const { return mNetFlags.test(GhostUpdated); }
313
314   /// Set or clear the NewGhost bit in our NetFlags.
315   /// @see NewGhost
316   void setNewGhost( bool n ) { if (n) mNetFlags.set(NewGhost); else mNetFlags.clear(NewGhost); }
317
318   /// Returns true if the NewGhost bit in out NetFlags is set.
319   /// @see NewGhost
320   bool isNewGhost() const { return mNetFlags.test(NewGhost); }
321
322   /// Set or clear the NetNearbyAdded bit in our NetFlags.
323   /// @see NetNearbyAdded
324   void setNetNearbyAdded( bool b ) { if (b) mNetFlags.set(NetNearbyAdded); else mNetFlags.clear(NetNearbyAdded); }
325
326   /// Returns true if the NetNearby bit in our NetFlags is set.
327   /// @see NetNearbyAdded
328   bool isNetNearbyAdded() const { return mNetFlags.test(NetNearbyAdded); }
329
330   /// Returns true if the HiFiPassive bit in our NetFlags is set.
331   /// @see HiFiPassive
332   bool isHifiPassive() const { return mNetFlags.test(HiFiPassive); }
333
334   /// Returns true if the TickLast bit in our NetFlags is set.
335   /// @see TickLast
336   bool isTickLast() const { return mNetFlags.test(TickLast); }
337
338   /// Returns true if the NetOrdered bit in our NetFlags is set.
339   /// @see NetOrdered
340   bool isNetOrdered() const { return mNetFlags.test(NetOrdered); }
341   
342   /// Called during client catchup under the hifi-net model.
343   virtual void computeNetSmooth( F32 backDelta ) {}
344
345   /// Returns TickCache used under the hifi-net model.
346   TickCache& getTickCache() { return mTickCache; }
347   /// @}
348
349   /// @name Network
350   /// @see NetObject, NetConnection
351   /// @{
352
353   F32  getUpdatePriority( CameraScopeQuery *focusObject, U32 updateMask, S32 updateSkips );
354   U32  packUpdate  ( NetConnection *conn, U32 mask, BitStream *stream );
355   void unpackUpdate( NetConnection *conn,           BitStream *stream );
356
357   /// Write state information necessary to perform client side prediction of an object.
358   ///
359   /// This information is sent only to the controlling object. For example, if you are a client
360   /// controlling a Player, the server uses writePacketData() instead of packUpdate() to
361   /// generate the data you receive.
362   ///
363   /// @param   conn     Connection for which we're generating this data.
364   /// @param   stream   Bitstream for output.
365   virtual void writePacketData( GameConnection *conn, BitStream *stream );
366
367   /// Read data written with writePacketData() and update the object state.
368   ///
369   /// @param   conn    Connection for which we're generating this data.
370   /// @param   stream  Bitstream to read.
371   virtual void readPacketData( GameConnection *conn, BitStream *stream );
372
373   /// Gets the checksum for packet data.
374   ///
375   /// Basically writes a packet, does a CRC check on it, and returns
376   /// that CRC.
377   ///
378   /// @see writePacketData
379   /// @param   conn   Game connection
380   virtual U32 getPacketDataChecksum( GameConnection *conn );
381   ///@}
382
383
384   /// @name Mounted objects ( overrides )
385   /// @{
386
387public:
388
389   virtual void onMount( SceneObject *obj, S32 node );   
390   virtual void onUnmount( SceneObject *obj,S32 node ); 
391
392   /// @}
393
394   /// @name User control
395   /// @{
396
397   /// Returns the client controlling this object
398   GameConnection *getControllingClient() { return mControllingClient; }
399   const GameConnection *getControllingClient() const { return mControllingClient; }
400
401   /// Returns the MoveList of the client controlling this object.
402   /// If there is no client it returns NULL;
403   MoveList* getMoveList();
404
405   /// Sets the client controlling this object
406   /// @param  client   Client that is now controlling this object
407   virtual void setControllingClient( GameConnection *client );
408
409   virtual GameBase * getControllingObject() { return NULL; }
410   virtual GameBase * getControlObject() { return NULL; }
411   virtual void setControlObject( GameBase * ) { }
412   /// @}
413
414   virtual F32 getDefaultCameraFov() { return 90.f; }
415   virtual F32 getCameraFov() { return 90.f; }
416   virtual void setCameraFov( F32 fov )   { }
417   virtual bool isValidCameraFov( F32 fov ) { return true; }
418   virtual bool useObjsEyePoint() const { return false; }
419   virtual bool onlyFirstPerson() const { return false; }
420   virtual F32 getDamageFlash() const { return 0.0f; }
421   virtual F32 getWhiteOut() const { return 0.0f; }
422   
423   // Not implemented here, but should return the Camera to world transformation matrix
424   virtual void getCameraTransform (F32 *pos, MatrixF *mat ) { *mat = MatrixF::Identity; }
425   virtual void getEyeCameraTransform ( IDisplayDevice *device, U32 eyeId, MatrixF *mat ) { *mat = MatrixF::Identity; }
426
427   /// Returns the water object we are colliding with, it is up to derived
428   /// classes to actually set this object.
429   virtual WaterObject* getCurrentWaterObject() { return mCurrentWaterObject; }
430   
431   #ifdef TORQUE_DEBUG_NET_MOVES
432   bool isAIControlled() const { return mIsAiControlled; }
433   #endif
434
435   DECLARE_CONOBJECT (GameBase );
436
437   /// @name Callbacks
438   /// @{
439   DECLARE_CALLBACK( void, setControl, ( bool controlled ) );
440   /// @}
441
442private:
443
444   /// This is called by the reload signal in our datablock when it is 
445   /// modified in the editor.
446   ///
447   /// This method is private and is not virtual. To handle a datablock-modified
448   /// even in a child-class specific way you should override onNewDatablock
449   /// and handle the reload( true ) case.   
450   ///
451   /// Warning: For local-client, editor situations only.
452   ///
453   /// Warning: Do not attempt to call .remove or .notify on mDataBlock->mReloadSignal
454   /// within this callback.
455   ///   
456   void _onDatablockModified();
457};
458
459
460#endif // _GAMEBASE_H_
461