simDatablock.h

Engine/source/console/simDatablock.h

More...

Classes:

Detailed Description

  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#ifndef _SIMDATABLOCK_H_
 29#define _SIMDATABLOCK_H_
 30
 31#ifndef _SIMBASE_H_
 32#include "console/simBase.h"
 33#endif
 34
 35// Forward Refs
 36class BitStream;
 37
 38/// Root DataBlock class.
 39///
 40/// @section SimDataBlock_intro Introduction
 41///
 42/// Another powerful aspect of Torque's networking is the datablock. Datablocks
 43/// are used to provide relatively static information about entities; for instance,
 44/// what model a weapon should use to display itself, or how heavy a player class is.
 45///
 46/// This gives significant gains in network efficiency, because it means that all
 47/// the datablocks on a server can be transferred over the network at client
 48/// connect time, instead of being intertwined with the update code for NetObjects.
 49///
 50/// This makes the network code much simpler overall, as one-time initialization
 51/// code is segregated from the standard object update code, as well as providing
 52/// several powerful features, which we will discuss momentarily.
 53///
 54/// @section SimDataBlock_preload preload() and File Downloading
 55///
 56/// Because datablocks are sent over the wire, using SimDataBlockEvent, before
 57/// gameplay starts in earnest, we gain in several areas. First, we don't have to
 58/// try to keep up with the game state while working with incomplete information.
 59/// Second, we can provide the user with a nice loading screen, instead of the more
 60/// traditional "Connecting..." message. Finally, and most usefully, we can request
 61/// missing files from the server as we become aware of them, since we are under
 62/// no obligation to render anything for the user.
 63///
 64/// The mechanism for this is fairly basic. After a datablock is unpacked, the
 65/// preload() method is called. If it returns false and sets an error, then the
 66/// network code checks to see if a file (or files) failed to be located by the
 67/// ResManager; if so, then it requests those files from the server. If preload
 68/// returns true, then the datablock is considered loaded. If preload returns
 69/// false and sets no error, then the connection is aborted.
 70///
 71/// Once the file(s) is downloaded, the datablock's preload() method is called again.
 72/// If it fails with the same error, the connection is aborted. If a new error is
 73/// returned, then the download-retry process is repeated until the preload works.
 74///
 75/// @section SimDataBlock_guide Guide To Datablock Code
 76///
 77/// To make a datablock subclass, you need to extend three functions:
 78///      - preload()
 79///      - packData()
 80///      - unpackData()
 81///
 82/// packData() and unpackData() simply read or write data to a network stream. If you
 83/// add any fields, you need to add appropriate calls to read or write. Make sure that
 84/// the order of reads and writes is the same in both functions. Make sure to call
 85/// the Parent's version of these methods in every subclass.
 86///
 87/// preload() is a bit more complex; it is responsible for taking the raw data read by
 88/// unpackData() and processing it into a form useful by the datablock's owning object. For
 89/// instance, the Player class' datablock, PlayerData, gets handles to commonly used
 90/// nodes in the player model, as well as resolving handles to textures and other
 91/// resources. <b>Any</b> code which loads files or performs other actions beyond simply
 92/// reading the data from the packet, such as validation, must reside in preload().
 93///
 94/// To write your own preload() methods, see any of the existing methods in the codebase; for instance,
 95/// PlayerData::preload() is an excellent example of error-reporting, data validation, and so forth.
 96///
 97/// @note A useful trick, which is used in several places in the engine, is that of temporarily
 98///       storing SimObjectIds in the variable which will eventually hold the "real" handle. ShapeImage
 99///       uses this trick in several pllaces; so do the vehicle classes. See GameBaseData for more on
100///       using this trick.
101///
102/// @see GameBaseData for some more information on the datablocks used throughout
103///      most of the engine.
104/// @see http://hosted.tribalwar.com/t2faq/datablocks.shtml for an excellent
105///      explanation of the basics of datablocks from script. Note that these comments
106///      mostly apply to GameBaseData and its children.
107/// @nosubgrouping
108class SimDataBlock: public SimObject
109{
110   typedef SimObject Parent;
111public:
112
113   SimDataBlock();
114   DECLARE_CONOBJECT(SimDataBlock);
115   
116   /// @name Datablock Internals
117   /// @{
118
119protected:
120   S32  modifiedKey;
121
122public:
123   static SimObjectId sNextObjectId;
124   static S32         sNextModifiedKey;
125
126   /// Assign a new modified key.
127   ///
128   /// Datablocks are assigned a modified key which is updated every time
129   /// a static field of the datablock is changed. These are gotten from
130   /// a global store.
131   static S32 getNextModifiedKey() { return sNextModifiedKey; }
132
133   /// Returns true if this is a client side only datablock (in
134   /// other words a datablock allocated with 'new' instead of 
135   /// the 'datablock' keyword).
136   bool isClientOnly() const { return getId() < DataBlockObjectIdFirst || getId() > DataBlockObjectIdLast; }
137
138   /// Get the modified key for this particular datablock.
139   S32 getModifiedKey() const { return modifiedKey; }
140
141   bool onAdd();
142   virtual void onStaticModified(const char* slotName, const char*newValue = NULL);
143   //void setLastError(const char*);
144   void assignId();
145
146   /// @}
147
148   /// @name Datablock Interface
149   /// @{
150
151   ///
152   virtual void packData(BitStream* stream);
153   virtual void unpackData(BitStream* stream);
154
155   /// Called to prepare the datablock for use, after it has been unpacked.
156   ///
157   /// @param  server      Set if we're running on the server (and therefore don't need to load
158   ///                     things like textures or sounds).
159   /// @param  errorStr    If an error occurs in loading, this is set to a short string describing
160   ///                     the error.
161   /// @returns True if all went well; false if something failed.
162   ///
163   /// @see @ref SimDataBlock_preload
164   virtual bool preload(bool server, String &errorStr);
165   /// @}
166
167   /// Output the TorqueScript to recreate this object.
168   ///
169   /// This calls writeFields internally.
170   /// @param   stream  Stream to output to.
171   /// @param   tabStop Indentation level for this object.
172   /// @param   flags   If SelectedOnly is passed here, then
173   ///                  only objects marked as selected (using setSelected)
174   ///                  will output themselves.
175   virtual void write(Stream &stream, U32 tabStop, U32 flags = 0);
176
177   /// Used by the console system to automatically tell datablock classes apart
178   /// from non-datablock classes.
179   static const bool __smIsDatablock = true;
180protected:
181   struct SubstitutionStatement
182   {
183      StringTableEntry  mSlot;
184      S32               mIdx;
185      char*             mValue;
186      SubstitutionStatement(StringTableEntry slot, S32 idx, const char* value);
187      ~SubstitutionStatement();
188      void replaceValue(const char* value);
189   };
190   Vector<SubstitutionStatement*> substitutions;
191   void    clear_substitutions();
192public:
193   /*C*/  SimDataBlock(const SimDataBlock&, bool = false);
194   /*D*/  ~SimDataBlock();
195
196   void   addSubstitution(StringTableEntry field, S32 idx, const char* subst);
197   const char* getSubstitution(StringTableEntry field, S32 idx);
198   S32    getSubstitutionCount() { return substitutions.size(); }
199   void   performSubstitutions(SimDataBlock*, const SimObject*, S32 index=0);
200   void   copySubstitutionsFrom(SimDataBlock* other);
201   void   printSubstitutions();
202   bool   fieldHasSubstitution(StringTableEntry slot);
203   virtual void onAddSubstitution(StringTableEntry, S32 idx, const char* subst) { }
204   virtual void onRemoveSubstitution(StringTableEntry, S32 idx) { }
205   virtual void onPerformSubstitutions() { }
206};
207
208//---------------------------------------------------------------------------
209
210class SimDataBlockGroup : public SimGroup
211{
212private:
213   S32 mLastModifiedKey;
214
215public:
216   static S32 QSORT_CALLBACK compareModifiedKey(const void* a,const void* b);
217   void sort();
218   SimDataBlockGroup();
219};
220
221#endif // _SIMDATABLOCK_H_
222