typeinst.h

Go to the documentation of this file.
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