aesop-client.h

Go to the documentation of this file.
00001 /*
00002  * aesop-client.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  * Basic client objects for the aesop client/server framework.
00031  */
00032 
00033 #ifndef AESOP_AESOP_CLIENT_H__
00034 #define AESOP_AESOP_CLIENT_H__
00035 
00036 // includes --------------------------------------------------------------------
00037 #include "aesop-map/map.h"
00038 #include "aesop-physics/aesop-physics.h"
00039 #include "conversation/conversation.h"
00040 #include "crypto/crypto.h"
00041 #include "dialog/dialog.h"
00042 #include "netlib/netlib.h"
00043 #include "story/story.h"
00044 #include "threadsafe/threadsafe_map.h"
00045 #include "xdrbuf/xdrbuf.h"
00046 
00047 
00048 // forward declarations
00049 class Datahash;
00050 namespace aesop {
00051         class MapDynamics;
00052 };
00053 
00054 
00055 namespace aesop {
00056 
00057 ////////////////////////////////////////////////////////////////////////////////
00058 ///
00059 /// \ingroup aesop_core
00060 /// \defgroup aesop_clib AESOP Client Library
00061 ///
00062 /// \n
00063 /// This is the reference implementation of the client side of the AESOP
00064 /// game protocols.  More than a reference, it is hoped that people building
00065 /// their own clients can use this common library for handling client state and
00066 /// server communication, and focus on their own rendering and other features.
00067 ///
00068 /// \n
00069 /// \b DESIGN \b PRINCIPLES \n
00070 /// The client library should be agnostic of (decoupled from) all rendering and
00071 /// input libraries.  This way, implementers of custom clients can use these
00072 /// components without having to link in other third-party libraries etc.
00073 ///
00074 /// As an example, a command-line client (no graphics etc.) should be able to
00075 /// use the Client Library with no problems, and use it to drive all
00076 /// interactions with the server.  
00077 ///
00078 /// The client library does NOT maintain any story or map state.  That is left
00079 /// to the client host.  The client just manages low-level connection state,
00080 /// and forwards richer details on to its host.
00081 ///
00082 /// See the \ref Application object for an example client host.
00083 ///
00084 ////////////////////////////////////////////////////////////////////////////////
00085 /*@{*/
00086 
00087 
00088 /// current client state (NOT player state!  Just overall client state)
00089 enum eClientState {
00090         eClientState_Searching  = 1, ///< waiting for player to select server
00091         eClientState_Connecting = 2, ///< attempting to connect to selected srvr
00092         eClientState_Connected  = 3, ///< successfully connected to server
00093 
00094         // keep this last!
00095         eClientState_Invalid    = 0
00096 };
00097 
00098 
00099 
00100 /// users of the client library must supply an object that implements this
00101 /// interface.
00102 class ClientHost {
00103 public:
00104         // aesop::ClientHost class interface methods ---------------------------
00105         virtual void notifyKey(IN smart_ptr<crypto::DESKey>& desKey) = 0;
00106 
00107         /// we have a dialog for the given player
00108         virtual void requestDialog(IN const char * guid,
00109                                 IN int playerId,
00110                                 IN const Datahash * dialog,
00111                                 IN dialog::Host * host) = 0;
00112 
00113         /// destroy the specified dialog
00114         virtual void destroyDialog(IN const char * guid,
00115                                 IN int playerId) = 0;
00116 
00117         /// the given player is in the specified map.  Note that the map can
00118         ///     be null!  This means the player is not in any map.
00119         virtual void notifyPlayerMap(IN int playerId,
00120                                 IN smart_ptr<MapDynamics>& dyn) = 0;
00121 
00122         /// hook for client libraries to add custom data to outbound UDP packets
00123         virtual void appendGameData(IN xdrbuf::Output * outbuf) = 0;
00124 
00125         /// host is being asked to update animation state of the given object
00126         virtual void updateAnimation(IN smart_ptr<PhysicsObject>& obj,
00127                                 IN const char * animationState) = 0;
00128 
00129 protected:
00130         // virtual destructor --------------------------------------------------
00131         /// you cannot delete through this interface
00132         /// callers must ensure that the Host object lasts as long as the Client
00133         virtual ~ClientHost(void) throw();
00134 };
00135 
00136 
00137 
00138 /// information about a remote server
00139 struct server_info_t {
00140         // constructor, manipulators
00141         server_info_t(void) throw() { this->clear(); }
00142         void clear(void) throw() {
00143                         publicName = "";
00144                         address.clear();
00145                 }
00146         bool isValid(void) const throw() {
00147                         return address.isValid();
00148                 }
00149 
00150         // data fields
00151         std::string             publicName;
00152         netlib::address_t       address;
00153 };
00154 
00155 
00156 
00157 /// a map of servers (key is basically a hash and should not be used for
00158 ///     anything other than as an index into this map)
00159 typedef threadsafe_map<std::string, server_info_t> server_map_t;
00160 
00161 
00162 
00163 /// class that manages local client/player state with the server
00164 class Client { 
00165 public:
00166         // virtual destructor --------------------------------------------------
00167         virtual ~Client(void) throw();
00168 
00169         // aesop::Client class interface methods -------------------------------
00170 
00171         /// what's the story?
00172         virtual story::Story * getStory(void) throw() = 0;
00173 
00174         /// current client network state?
00175         virtual eClientState getState(void) throw() = 0;
00176 
00177         /// what server are we connected to?
00178         ///     returns false if not connected yet.
00179         virtual bool getServer(OUT server_info_t& server) = 0;
00180 
00181         /// what servers have been discovered?  WARNING: you may discover
00182         ///     thousands!  Be careful how you iterate.
00183         virtual const server_map_t& getDiscoveredServers(void) = 0;
00184 
00185         /// caller can ask to connect to a specific server, as specified by the
00186         ///     server key (index into server map from getDiscoveredServers() ).
00187         /// returns true if the request was successfully queued.  false means
00188         ///     that the serverKey is now invalid, or the client is already
00189         ///     connected, or some other internal error.
00190         /// \b Remember: a successful return does not mean the client has
00191         ///     connected!  Connecting can take a long time or fail altogether,
00192         ///     depending on the network and server.  A successful return just
00193         ///     means the client will now try to connect.
00194         virtual bool requestConnect(IN const char * serverKey) = 0;
00195 
00196         /// Caller must call this method repeatedly!  Main network message pump.
00197         /// Returns seconds elapsed since last tick() call.
00198         virtual float tick(void) = 0;
00199 
00200         /// Caller can request that a new player join the game. 
00201         /// Caller provides the local ID of the new player.
00202         /// Returns false if player cannot be created (already exists).
00203         virtual bool createPlayer(IN int playerId) = 0;
00204 
00205         /// Components on the client can request local conversations (system
00206         /// option menus, etc.)
00207         virtual void startLocalConversation(IN const char * guid,
00208                                 IN int playerId,
00209                                 IN smart_ptr<converse::ConversationHost> host) = 0;
00210 
00211         /// is this conversation already going?
00212         virtual bool isConversationUnderway(IN const char * guid) = 0;
00213 
00214         /// player is requesting a new game
00215         /// TODO: move this into the game logic, it doesn't belong here
00216         virtual void newGame(IN int playerId) = 0;
00217 
00218         /// player is asking to move by the specified amount
00219         virtual void requestMove(IN int playerId,
00220                                 IN const point3d_t& delta,
00221                                 IN const point3d_t& euler, ///< euler rotation
00222                                 OUT point3d_t& newPosition) = 0;
00223 
00224         /// retrieve current player position and orientation
00225         virtual bool getPlacement(IN int playerId,
00226                                 OUT placement_t& placement) = 0;
00227 
00228         /// retrieve object for player (can be null if player is not in map)
00229         virtual smart_ptr<PhysicsObject> getPlayerObject(IN int playerId) = 0;
00230 
00231         // public static methods (factories) -----------------------------------
00232         static smart_ptr<Client> create(IN ClientHost * host,
00233                                 IN smart_ptr<story::Story>& story,
00234                                 IN smart_ptr<Datahash>& op_params);
00235 };
00236 
00237 
00238 
00239 };      // aesop namespace
00240 
00241 #endif  // AESOP_AESOP_CLIENT_H__
00242