terom@185: #ifndef NETWORKCLIENT_HH terom@185: #define NETWORKCLIENT_HH terom@185: terom@186: #include "../GameState.hh" terom@186: #include "Session.hh" terom@186: #include "Object.hh" terom@185: terom@185: // forward-declare terom@274: class NetworkClient; terom@185: class NetworkClientLocalPlayer; terom@185: class NetworkClientRemotePlayer; terom@185: terom@294: /** terom@294: * Our specialized NetworkObject_ClientController that overrides handle_create to create the right kind of terom@294: * object (a subclass of NetowrkClientObject). terom@294: */ terom@274: class NetworkClientController : public NetworkObject_ClientController { terom@274: protected: terom@294: /** terom@294: * The NetworkClient terom@294: */ terom@274: NetworkClient &client; terom@274: terom@274: public: terom@294: /** terom@294: * Control objects on the given client using the client.netsession's NETCHAN_CORE channel terom@294: */ terom@274: NetworkClientController (NetworkClient &client); terom@274: terom@274: protected: terom@274: /** terom@294: * We override handle_create from NetworkObject_ClientController to call one of the on_* methods, which creates terom@294: * a NetworkClientObject subclass terom@294: * terom@294: * @see NetworkObject_ClientController::handle_create terom@274: */ terom@274: virtual void handle_create (NetworkObjectID obj_id, NetworkMessageID msg_id, NetworkPacketInput &pkt, NetworkNode *node); terom@294: terom@294: /** terom@294: * Handle NETMSG_SERVER_HELLO -> NetworkClientLocalPlayer terom@294: */ terom@274: void on_server_hello (NetworkObjectID obj_id, NetworkPacketInput &pkt); terom@294: terom@294: /** terom@294: * Handle NETMSG_PLAYER_INFO -> NetworkClientRemotePlayer terom@294: */ terom@274: void on_player_info (NetworkObjectID obj_id, NetworkPacketInput &pkt); terom@294: terom@294: /** terom@294: * Handle NETMSG_PLAYER_JOIN -> NetworkClientRemotePlayer terom@294: */ terom@274: void on_player_join (NetworkObjectID obj_id, NetworkPacketInput &pkt); terom@294: terom@294: /** terom@294: * Handle NETMSG_PROJECTILE_PLAYER_FIRED -> NetworkClientProjectile terom@294: */ terom@276: void on_projectile_player_fired (NetworkObjectID obj_id, NetworkPacketInput &pkt); terom@274: }; terom@274: terom@294: /** terom@294: * Our NetworkClient, that connects to a NetworkServer. This has the GameState, NetworkSession, NetworkClientController, etc. terom@294: */ terom@187: class NetworkClient { terom@274: friend class NetworkClientController; terom@274: friend class NetworkClientObject; terom@274: friend class NetworkClientPlayerBase; terom@185: friend class NetworkClientLocalPlayer; terom@185: friend class NetworkClientRemotePlayer; terom@223: friend class NetworkClientProjectile; terom@185: terom@187: protected: terom@294: /** terom@294: * The GameState terom@294: */ terom@187: GameState &state; terom@294: terom@187: CL_SlotContainer slots; terom@294: terom@294: /** terom@294: * The connect()-mode NetworkSession terom@294: */ terom@294: NetworkSession netsession; terom@187: terom@294: /** terom@294: * The server NetworkNode from Netsession::connect terom@294: */ terom@185: NetworkNode *server; terom@294: terom@294: /** terom@294: * Our specialized NetworkObject_ClientController terom@294: */ terom@274: NetworkClientController controller; terom@185: terom@185: public: terom@294: /** terom@294: * Create a NetworkClient with the given GameState, connecting a server on the given NetworkAddress terom@294: * terom@294: * @param state the GameState to use terom@294: * @param connect_to the address to connect to terom@294: */ terom@185: NetworkClient (GameState &state, const NetworkAddress &connect_to); terom@274: terom@274: protected: terom@274: /** terom@294: * Receive the NETCHAN_TERRAIN_ARRAY message from the server and apply it to our GameState::world terrain terom@274: */ terom@203: void on_terrain_array (NetworkPacketInput &pkt, NetworkNode *node); terom@185: terom@185: public: terom@294: /** terom@294: * Called by NetworkClientRemotePlayer when they get disconnected. Doesn't do anything currently terom@294: */ terom@185: void player_quit (NetworkClientRemotePlayer *player); terom@185: }; terom@185: terom@294: /** terom@294: * Our base NetworkObject_Client object, containing the NetworkClient and a CL_SlotContainer for conveniance terom@294: */ terom@274: class NetworkClientObject : public NetworkObject_Client { terom@200: protected: terom@294: /** terom@294: * The NetworkClient terom@294: */ terom@185: NetworkClient &client; terom@185: terom@185: CL_SlotContainer slots; terom@294: terom@294: /** terom@294: * Construct this using the given client and obj_id, passing the client.controller and obj_id to the terom@294: * NetworkObject_Client's constructor terom@294: */ terom@274: NetworkClientObject (NetworkClient &client, NetworkObjectID obj_id); terom@223: }; terom@223: terom@294: /** terom@294: * Our base class for NetworkClient Players, this implements most of the server -> client messages terom@294: * terom@294: * This inherits from NetworkClientObject and virtually from Player, as classes should inherit from both this and terom@294: * LocalPlayer/RemotePlayer terom@294: */ terom@274: class NetworkClientPlayerBase : public NetworkClientObject, public virtual Player { terom@200: protected: terom@294: /** terom@294: * Dummy-initialize Player, initialize NetworkClientObject, and hook up our signals terom@294: */ terom@274: NetworkClientPlayerBase (NetworkClient &client, NetworkObjectID obj_id, Vector position); terom@200: terom@302: protected: terom@302: // @{ terom@302: /** terom@302: * These should never be called directly, always via the network terom@302: */ terom@302: virtual void spawn (Vector position); terom@302: virtual void respawn (TimeMS dt); terom@302: // @} terom@303: terom@303: /** terom@303: * Ignore, the servers tells us this terom@303: */ terom@303: virtual void die (bool start_timer = true); terom@302: terom@200: private: terom@294: /** terom@294: * NETMSG_PLAYER_POSITION -> PhysicsObject::updatePhysics terom@294: */ terom@200: void on_position (NetworkPacketInput &pkt); terom@294: terom@294: /** terom@294: * NETMSG_PLAYER_DIG -> Player::handleDig terom@294: */ terom@200: void on_dig (NetworkPacketInput &pkt); terom@294: terom@294: /** terom@294: * NETMSG_PLAYER_WEAPON_CHANGE -> Player::rope.handleChangeWeapon terom@294: */ terom@239: void on_weapon_change (NetworkPacketInput &pkt); terom@294: terom@294: /** terom@294: * NETMSG_PLAYER_ROPE_THROW -> Player::rope.updateState(ROPE_FLYING) terom@294: */ terom@241: void on_rope_throw (NetworkPacketInput &pkt); terom@294: terom@294: /** terom@294: * NETMSG_PLAYER_ROPE_FIXED -> Player::rope.updateState(ROPE_FIXED) terom@294: */ terom@241: void on_rope_fixed (NetworkPacketInput &pkt); terom@294: terom@294: /** terom@294: * NETMSG_PLAYER_ROPE_RELEASED -> Player::rope.updateState(ROPE_FOLDED) terom@294: */ terom@241: void on_rope_released (NetworkPacketInput &pkt); terom@294: terom@294: /** terom@294: * NETMSG_PLAYER_ROPE_LENGTH -> Player::Rope.updateLength terom@294: */ terom@241: void on_rope_length (NetworkPacketInput &pkt); terom@302: terom@302: /** terom@302: * NETMSG_PLAYER_SPAWN -> Player::spawn terom@302: */ terom@302: void on_spawn (NetworkPacketInput &pkt); terom@302: terom@302: /** terom@302: * NETMSG_PLAYER_Die -> Player::die terom@302: */ terom@302: void on_die (NetworkPacketInput &pkt); terom@200: }; terom@200: terom@294: /** terom@294: * Our NetworkClientPlayerBase + LocalPlayer specialization, this lets us handle local input terom@294: */ terom@274: class NetworkClientLocalPlayer : public NetworkClientPlayerBase, public LocalPlayer { terom@185: public: terom@294: /** terom@294: * Calls NetworkClientPlayerBase/Player constructors, calls GameState::setLocalPlayer terom@294: */ terom@274: NetworkClientLocalPlayer (NetworkClient &client, NetworkObjectID obj_id, Vector position); terom@185: terom@294: /** terom@294: * Overriden from LocalPlayer to send a NETMSG_CLIENT_INPUT message without executing LocalPlayer::handleInput terom@294: * locally terom@294: */ terom@277: virtual void handleInput (PlayerInput input, TimeMS dt); terom@185: }; terom@185: terom@294: /** terom@294: * Our NetworkClientPlayerBase + RemotePlayer specialization, this lets us handle players quitting terom@294: */ terom@274: class NetworkClientRemotePlayer : public NetworkClientPlayerBase, public RemotePlayer { terom@185: public: terom@294: /** terom@294: * Calls NetworkClientPlayerBase/Player constructors and hooks up signals terom@294: */ terom@274: NetworkClientRemotePlayer (NetworkClient &client, NetworkObjectID obj_id, Vector position); terom@185: terom@185: private: terom@294: /** terom@294: * Calls NetworkClient::player_quit, and then destroys ourselves terom@294: */ terom@200: void on_quit (NetworkPacketInput &pkt); terom@185: }; terom@185: terom@294: /** terom@294: * A Projectile that was created on the server terom@294: */ terom@274: class NetworkClientProjectile : public NetworkClientObject, public Projectile { terom@223: public: terom@294: /** terom@294: * Call Projectile's constructor, hook up signals and call player->weaponFired terom@294: */ terom@276: NetworkClientProjectile (NetworkClient &client, NetworkObjectID obj_id, Player *player, Vector position, terom@276: Vector velocity, Weapon *weapon); terom@224: terom@224: protected: terom@294: /** terom@294: * Overrides Projectile::onDestroy to ignore this, as we must wait for the server to tell us where it impacted terom@294: * so that we can remove the ground reliably terom@294: */ terom@224: virtual void onDestroy (Vector position, bool removeGround); terom@296: terom@296: /** terom@296: * Overrides Projectile::onHitPlayer to ignore this, as we must wait for the server to tell us if it really did terom@296: * happen. terom@296: */ terom@296: virtual void onHitPlayer (Player *player, Health damage); terom@224: terom@224: private: terom@294: /** terom@294: * NETMSG_PROJECTILE_DESTROY -> Projectile::onDestory terom@294: */ terom@224: void on_destroy (NetworkPacketInput &pkt); terom@296: terom@296: /** terom@296: * NETMSG_PROJECTILE_HIT_PLAYER -> Projectile::onHitPlayer terom@296: */ terom@296: void on_hit_player (NetworkPacketInput &pkt); terom@223: }; terom@223: terom@185: #endif