simDatablock.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  23. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  24. // Copyright (C) 2015 Faust Logic, Inc.
  25. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  26. #ifndef _SIMDATABLOCK_H_
  27. #define _SIMDATABLOCK_H_
  28. #ifndef _SIMBASE_H_
  29. #include "console/simBase.h"
  30. #endif
  31. // Forward Refs
  32. class BitStream;
  33. /// Root DataBlock class.
  34. ///
  35. /// @section SimDataBlock_intro Introduction
  36. ///
  37. /// Another powerful aspect of Torque's networking is the datablock. Datablocks
  38. /// are used to provide relatively static information about entities; for instance,
  39. /// what model a weapon should use to display itself, or how heavy a player class is.
  40. ///
  41. /// This gives significant gains in network efficiency, because it means that all
  42. /// the datablocks on a server can be transferred over the network at client
  43. /// connect time, instead of being intertwined with the update code for NetObjects.
  44. ///
  45. /// This makes the network code much simpler overall, as one-time initialization
  46. /// code is segregated from the standard object update code, as well as providing
  47. /// several powerful features, which we will discuss momentarily.
  48. ///
  49. /// @section SimDataBlock_preload preload() and File Downloading
  50. ///
  51. /// Because datablocks are sent over the wire, using SimDataBlockEvent, before
  52. /// gameplay starts in earnest, we gain in several areas. First, we don't have to
  53. /// try to keep up with the game state while working with incomplete information.
  54. /// Second, we can provide the user with a nice loading screen, instead of the more
  55. /// traditional "Connecting..." message. Finally, and most usefully, we can request
  56. /// missing files from the server as we become aware of them, since we are under
  57. /// no obligation to render anything for the user.
  58. ///
  59. /// The mechanism for this is fairly basic. After a datablock is unpacked, the
  60. /// preload() method is called. If it returns false and sets an error, then the
  61. /// network code checks to see if a file (or files) failed to be located by the
  62. /// ResManager; if so, then it requests those files from the server. If preload
  63. /// returns true, then the datablock is considered loaded. If preload returns
  64. /// false and sets no error, then the connection is aborted.
  65. ///
  66. /// Once the file(s) is downloaded, the datablock's preload() method is called again.
  67. /// If it fails with the same error, the connection is aborted. If a new error is
  68. /// returned, then the download-retry process is repeated until the preload works.
  69. ///
  70. /// @section SimDataBlock_guide Guide To Datablock Code
  71. ///
  72. /// To make a datablock subclass, you need to extend three functions:
  73. /// - preload()
  74. /// - packData()
  75. /// - unpackData()
  76. ///
  77. /// packData() and unpackData() simply read or write data to a network stream. If you
  78. /// add any fields, you need to add appropriate calls to read or write. Make sure that
  79. /// the order of reads and writes is the same in both functions. Make sure to call
  80. /// the Parent's version of these methods in every subclass.
  81. ///
  82. /// preload() is a bit more complex; it is responsible for taking the raw data read by
  83. /// unpackData() and processing it into a form useful by the datablock's owning object. For
  84. /// instance, the Player class' datablock, PlayerData, gets handles to commonly used
  85. /// nodes in the player model, as well as resolving handles to textures and other
  86. /// resources. <b>Any</b> code which loads files or performs other actions beyond simply
  87. /// reading the data from the packet, such as validation, must reside in preload().
  88. ///
  89. /// To write your own preload() methods, see any of the existing methods in the codebase; for instance,
  90. /// PlayerData::preload() is an excellent example of error-reporting, data validation, and so forth.
  91. ///
  92. /// @note A useful trick, which is used in several places in the engine, is that of temporarily
  93. /// storing SimObjectIds in the variable which will eventually hold the "real" handle. ShapeImage
  94. /// uses this trick in several pllaces; so do the vehicle classes. See GameBaseData for more on
  95. /// using this trick.
  96. ///
  97. /// @see GameBaseData for some more information on the datablocks used throughout
  98. /// most of the engine.
  99. /// @see http://hosted.tribalwar.com/t2faq/datablocks.shtml for an excellent
  100. /// explanation of the basics of datablocks from script. Note that these comments
  101. /// mostly apply to GameBaseData and its children.
  102. /// @nosubgrouping
  103. class SimDataBlock: public SimObject
  104. {
  105. typedef SimObject Parent;
  106. public:
  107. SimDataBlock();
  108. DECLARE_CONOBJECT(SimDataBlock);
  109. /// @name Datablock Internals
  110. /// @{
  111. protected:
  112. S32 modifiedKey;
  113. public:
  114. static SimObjectId sNextObjectId;
  115. static S32 sNextModifiedKey;
  116. /// Assign a new modified key.
  117. ///
  118. /// Datablocks are assigned a modified key which is updated every time
  119. /// a static field of the datablock is changed. These are gotten from
  120. /// a global store.
  121. static S32 getNextModifiedKey() { return sNextModifiedKey; }
  122. /// Returns true if this is a client side only datablock (in
  123. /// other words a datablock allocated with 'new' instead of
  124. /// the 'datablock' keyword).
  125. bool isClientOnly() const { return getId() < DataBlockObjectIdFirst || getId() > DataBlockObjectIdLast; }
  126. /// Get the modified key for this particular datablock.
  127. S32 getModifiedKey() const { return modifiedKey; }
  128. bool onAdd();
  129. virtual void onStaticModified(const char* slotName, const char*newValue = NULL);
  130. //void setLastError(const char*);
  131. void assignId();
  132. /// @}
  133. /// @name Datablock Interface
  134. /// @{
  135. ///
  136. virtual void packData(BitStream* stream);
  137. virtual void unpackData(BitStream* stream);
  138. /// Called to prepare the datablock for use, after it has been unpacked.
  139. ///
  140. /// @param server Set if we're running on the server (and therefore don't need to load
  141. /// things like textures or sounds).
  142. /// @param errorStr If an error occurs in loading, this is set to a short string describing
  143. /// the error.
  144. /// @returns True if all went well; false if something failed.
  145. ///
  146. /// @see @ref SimDataBlock_preload
  147. virtual bool preload(bool server, String &errorStr);
  148. /// @}
  149. /// Output the TorqueScript to recreate this object.
  150. ///
  151. /// This calls writeFields internally.
  152. /// @param stream Stream to output to.
  153. /// @param tabStop Indentation level for this object.
  154. /// @param flags If SelectedOnly is passed here, then
  155. /// only objects marked as selected (using setSelected)
  156. /// will output themselves.
  157. virtual void write(Stream &stream, U32 tabStop, U32 flags = 0);
  158. /// Used by the console system to automatically tell datablock classes apart
  159. /// from non-datablock classes.
  160. static const bool __smIsDatablock = true;
  161. protected:
  162. struct SubstitutionStatement
  163. {
  164. StringTableEntry mSlot;
  165. S32 mIdx;
  166. char* mValue;
  167. SubstitutionStatement(StringTableEntry slot, S32 idx, const char* value);
  168. ~SubstitutionStatement();
  169. void replaceValue(const char* value);
  170. };
  171. Vector<SubstitutionStatement*> substitutions;
  172. void clear_substitutions();
  173. public:
  174. /*C*/ SimDataBlock(const SimDataBlock&, bool = false);
  175. /*D*/ ~SimDataBlock();
  176. void addSubstitution(StringTableEntry field, S32 idx, const char* subst);
  177. const char* getSubstitution(StringTableEntry field, S32 idx);
  178. S32 getSubstitutionCount() { return substitutions.size(); }
  179. void performSubstitutions(SimDataBlock*, const SimObject*, S32 index=0);
  180. void copySubstitutionsFrom(SimDataBlock* other);
  181. void printSubstitutions();
  182. bool fieldHasSubstitution(StringTableEntry slot);
  183. virtual void onAddSubstitution(StringTableEntry, S32 idx, const char* subst) { }
  184. virtual void onRemoveSubstitution(StringTableEntry, S32 idx) { }
  185. virtual void onPerformSubstitutions() { }
  186. };
  187. //---------------------------------------------------------------------------
  188. class SimDataBlockGroup : public SimGroup
  189. {
  190. private:
  191. S32 mLastModifiedKey;
  192. public:
  193. static S32 QSORT_CALLBACK compareModifiedKey(const void* a,const void* b);
  194. void sort();
  195. SimDataBlockGroup();
  196. };
  197. #endif // _SIMDATABLOCK_H_