00001 /* 00002 * typeinst.h 00003 * 00004 * Copyright (C) 2008,2009 Thomas A. Vaughan 00005 * All rights reserved. 00006 * 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions are met: 00010 * * Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * * Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * * Neither the name of the <organization> nor the 00016 * names of its contributors may be used to endorse or promote products 00017 * derived from this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY 00020 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00022 * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY 00023 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00026 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 * 00030 * Root header for generic types and instances. 00031 */ 00032 00033 #ifndef AESOP_TYPEINST_H__ 00034 #define AESOP_TYPEINST_H__ 00035 00036 // includes -------------------------------------------------------------------- 00037 #include "aesop-base/aesop-base.h" 00038 00039 #include "datahash/datahash.h" 00040 #include "datahash/datahash_util.h" 00041 #include "geometry/placement.h" 00042 #include "story/story.h" 00043 00044 00045 namespace aesop { 00046 00047 00048 //////////////////////////////////////////////////////////////////////////////// 00049 /// 00050 /// \ingroup aesop_core 00051 /// \defgroup typeinst AESOP Types and Instances 00052 /// 00053 /// \n 00054 /// The Type/Instance library is the key to AESOP extensibility. If you want 00055 /// to extend the framework to add your own graphics/AI/physics/etc., then 00056 /// you should understand how these work. World designers will also need to 00057 /// know how these objects are used. When you place objects in your world, 00058 /// you'll be creating instances, and this framework gives you the ability to 00059 /// customize each instance to some degree, beyond the default behavior of the 00060 /// type. 00061 /// 00062 /// \n 00063 /// A type is any sort of thing that can appear in a map. This includes: 00064 /// - landscapes (terrain) and skyboxes 00065 /// - buildings 00066 /// - trees 00067 /// - walls 00068 /// - special effects (lighting, particles, etc.) 00069 /// - creatures 00070 /// - people 00071 /// 00072 /// A type has an arbitrary number of named properties (called "components"). 00073 /// Some examples of type components are: 00074 /// - \b physics This describes the collision shape to be used for physics 00075 /// calculations on the server. 00076 /// - \b model This describes the 3D model to be used for rendering on 00077 /// the client. 00078 /// - \b ai This describes the Artificial Intelligence module to use to 00079 /// determine how this type behaves. Many types (buildings, landscapes, 00080 /// trees, etc.) have no AI at all. 00081 /// 00082 /// The whole purpose of the type/instance library is that although the type 00083 /// can have arbitrary components bound to it, the type doesn't know how they 00084 /// are implemented. This way, the codebase can use Type/Instance objects to 00085 /// keep track of what is in the world, without being bound to how things are 00086 /// actualy implemented. 00087 /// 00088 /// Different applications will care about 00089 /// different components. For instance, the server won't care about the visual 00090 /// (3D rendering) component at all. The server will mostly care about the 00091 /// physics and AI. The client is the reverse: it will need to render, but 00092 /// won't use the AI. (The client may use the physics for predictive 00093 /// purposes). 00094 /// 00095 /// The application binding occurs in the main.cpp file (or something similar). 00096 /// During initialization, the application writer provides TypeComponentLoader 00097 /// objects for the components they think the application will need. Most 00098 /// applications are pretty simple: pick the core AESOP libraries you need, 00099 /// register whatever component loaders seem appropriate, and then let the core 00100 /// libraries start execution. The component loaders will be called as needed. 00101 /// 00102 /// The type/instance library uses a very decoupled model, so that the server 00103 /// can pick up the components of a type that it cares about, without any 00104 /// dependencies on the components it doesn't care about. And similarly for 00105 /// the client. Furthermore, other parts of the codebase only use components 00106 /// through general interfaces, so in most cases you should be able to swap 00107 /// out components (different AI system, different graphics engine, etc.) 00108 /// with minimal impact. 00109 /// 00110 /// \n 00111 /// An "instance" is a concrete instance of a type. For example, you could 00112 /// declare a type with ID "chicken", and then populate your map with hundreds 00113 /// of instances of chicken types. And so on. 00114 /// 00115 /// Every instance has three properties: 00116 /// - ID (ID of the specific instance -- non-unique, can be empty!) 00117 /// - typeId (ID of the type of which this is an instance) 00118 /// - placement (position and orientation) 00119 /// 00120 /// In addition, every instance has "component data". This component data is 00121 /// purposely left general, because this core piece of the framework doesn't 00122 /// know what components will be added. All that the Instance knows is that 00123 /// there are ComponentData objects attached to it, each with a name. Some 00124 /// common examples are: 00125 /// - <b>physics</b> This component is most likely a physics model or a base 00126 /// object used to create physics models specific to this type and 00127 /// instance. 00128 /// - <b>model</b> This component is a 3D model used to render this type and 00129 /// instance. 00130 /// - <b>ai</b> This component contains Artificial Intelligence data and 00131 /// logic for this instance. 00132 /// - <b>game</b> The game logic may need additional data attached to 00133 /// instances, beyond what the framework provides. 00134 /// 00135 /// In all of these cases, the component owner will provide rich objects that 00136 /// inherit from the ComponentData base class. If you have an instance, you 00137 /// will need to upcast to the appropriate object as necessary. 00138 /// \n 00139 /// 00140 //////////////////////////////////////////////////////////////////////////////// 00141 /*@{*/ 00142 00143 00144 /// a base class that components can use to provide rich implementations 00145 class ComponentData { 00146 public: 00147 // virtual destructor -------------------------------------------------- 00148 virtual ~ComponentData(void) throw(); 00149 00150 // aesop::ComponentData class interface data --------------------------- 00151 00152 /// for debugging -- called by Instance::dump() 00153 virtual void dump(IN const char * txt) const throw(); 00154 }; 00155 00156 00157 00158 /// A concrete instantiation of an object at a given place. 00159 /// Usually, callers are interested in one of two things (or both!): 00160 /// - where this instance is located (placement data) 00161 /// - a particular component of the instance (physics model, 3d model, etc.) 00162 /// 00163 /// When an Instance is created (using the static methods of this class), the 00164 /// framework creates a simple empty Instance object (with just the IDs and 00165 /// placement information), and then invokes all registered TypeComponenLoader 00166 /// objects to load any and all component data. Users of the Instance object 00167 /// can retrieve this component data by calling getComponentData(). 00168 /// 00169 /// This object is threadsafe, except for placement_t access. At the moment 00170 /// readers and writers can collide. If this turns into an issue (at the 00171 /// moment it is unlikely to cause more than occasional slight mistakes in 00172 /// coordinates, if anything) placement access can be made threadsafe. 00173 class Instance { 00174 public: 00175 // virtual destructor -------------------------------------------------- 00176 virtual ~Instance(void) throw(); 00177 00178 // aesop::Instance class interface methods ----------------------------- 00179 00180 /// ID of this particular instance (can be non-unique, can be null!) 00181 virtual const char * getInstanceId(void) const throw() = 0; 00182 00183 /// ID of the instance type 00184 virtual const char * getTypeId(void) const throw() = 0; 00185 00186 /// raw read/write access to placement 00187 virtual placement_t& getPlacement(void) throw() = 0; 00188 00189 /// provide component data (physics model, 3d model, ai, etc.). 00190 /// set to null to clear component data 00191 virtual void setComponentData(IN const char * componentName, 00192 IN smart_ptr<ComponentData>& data) = 0; 00193 00194 /// retrieve component data (physics model, 3d model, ai, etc.) 00195 virtual smart_ptr<ComponentData> getComponentData( 00196 IN const char * componentName) = 0; 00197 00198 /// retrieve raw component data from type 00199 virtual const Datahash * getTypeComponentData( 00200 IN const char * componentName) = 0; 00201 00202 /// Set raw instance data for the given named component. 00203 /// Set to null toclear out instance data for that named comonent. 00204 virtual void setInstanceData(IN const char * componentName, 00205 IN smart_ptr<Datahash>& data) = 0; 00206 00207 /// Retrieve raw instance data for the given named component. Returns 00208 /// null if no data was set for the given component name. 00209 /// This is typically used by TypeComponentLoader objects. Everyone 00210 /// else should use component data from getComponentData(). 00211 virtual smart_ptr<Datahash> getInstanceData( 00212 IN const char * componentName) = 0; 00213 00214 /// for debugging 00215 virtual void dump(IN const char * txt) throw() = 0; 00216 00217 // static factory methods ---------------------------------------------- 00218 static smart_ptr<Instance> parse(IO std::istream& stream); 00219 static smart_ptr<Instance> create(IN const char * instanceId, 00220 IN const char * typeId); 00221 }; 00222 00223 00224 00225 /// vector of instances 00226 typedef std::vector<smart_ptr<Instance> > vec_instance_t; 00227 00228 00229 /// a typedef to support iteration of instances. 00230 typedef void (*instance_iteration_fn)(IN smart_ptr<Instance>& instance, 00231 IN void * context); 00232 00233 00234 00235 /// Clients of this library need to provide component loaders for anything 00236 /// that they want loaded. For instance, servers will need to provide loaders 00237 /// for physics and ai components, and clients will need to provide loaders for 00238 /// visual components. 00239 /// 00240 /// Think of TypeComponentLoader objects as factories. They are capable of 00241 /// creating rich component data for a specific instance of a type. 00242 /// 00243 /// <b>Every method must be threadsafe!</b> Can be called on multiple 00244 /// background threads during loading etc. 00245 class TypeComponentLoader { 00246 public: 00247 // virtual destructor -------------------------------------------------- 00248 virtual ~TypeComponentLoader(void) throw(); 00249 00250 // aesop::TypeComponentLoader class interface methods ----------------- 00251 00252 /// what type of component does this load? "physics", "model", "ai" ... 00253 virtual const char * getComponentName(void) const throw() = 0; 00254 00255 /// what is the name of this loader? "Bob's homemade loader"? 00256 virtual const char * getLoaderName(void) const throw() = 0; 00257 00258 /// given the component data, is this something we can load? 00259 virtual bool isMyFormat(IN const Datahash * componentData, 00260 IN const char * path) const = 0; 00261 00262 /// go ahead and load the given component for the given instance 00263 virtual smart_ptr<ComponentData> loadTS( 00264 IN smart_ptr<Instance>& instance, 00265 IN const Datahash * componentData, 00266 IN const char * path) = 0; 00267 }; 00268 00269 00270 /// Must initialize the type instance library at the beginning of time! 00271 void initializeTypeInstanceLibrary(IN smart_ptr<story::Story>& story); 00272 00273 00274 /// Static method for registering type component loaders. Use this method to 00275 /// register your TypeComponentLoader with the framework! 00276 void registerTypeComponentLoader(IN smart_ptr<aesop::TypeComponentLoader>& tcl); 00277 00278 00279 00280 /// Load Instance objects from the given stream. 00281 void loadInstances(IO std::istream& stream, 00282 OUT vec_instance_t& instances); 00283 00284 00285 00286 /// handy utility method for type component loaders: given the three raw 00287 /// data hashes (instance data, type data, and model data) get the value 00288 /// from the appropriate override source (instance, then type, then model) 00289 /// 00290 /// Caller can use the flag parameter to specify if the key is required 00291 /// or not. If not required, a null can be returned if none of the hashes 00292 /// contain the key. Otherwise, an exception would be thrown. 00293 const char * getKeyWithOverrides(IN const char * keyName, 00294 IN const Datahash * instanceData, 00295 IN const Datahash * typeData, 00296 IN const Datahash * modelData, 00297 IN eDatahash_Flag flag); 00298 00299 00300 }; // aesop namespace 00301 00302 #endif // AESOP_TYPEINST_H__ 00303