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