simDatablock.h
Engine/source/console/simDatablock.h
Classes:
class
Root DataBlock class.
class
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