simDatablock.h 8.1 KB

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