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