/* This file is part of the KDE games library Copyright (C) 2001 Martin Heni (martin@heni-online.de) Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* $Id$ */ #ifndef __KGAMENETWORK_H_ #define __KGAMENETWORK_H_ #include #include #include class KGameIO; class KMessageClient; class KMessageServer; class KGameNetworkPrivate; /** * The KGameNetwork class is the KGame class with network * support. All other features are the same but they are * now network transparent. It is not used directly but * only via a KGame object. So you do not really have * to bother with this object. * * @short The main KDE game object * @author Martin Heni * @version $Id$ */ class KDE_EXPORT KGameNetwork : public TQObject { Q_OBJECT TQ_OBJECT public: /** * Create a KGameNetwork object */ KGameNetwork(int cookie=42,TQObject* parent=0); virtual ~KGameNetwork(); /** * Gives debug output of the game status **/ virtual void Debug(); /** * @return TRUE if this is a network game - i.e. you are either MASTER or * connected to a remote MASTER. **/ bool isNetwork() const; /** * Is this the game MASTER (i.e. has started theKMessageServer). A * game has always exactly one MASTER. This is either a KGame object (i.e. a * Client) or an own MessageServer-process. A KGame object that has the * MASTER status is always admin. * * You probably don't want to use this. It is a mostly internal method which * will probably become protected. Better use isAdmin * * @see isAdmin * @return Whether this client has started the KMessageServer **/ bool isMaster() const; /** * The admin of a game is the one who initializes newly connected clients * using negotiateNetworkGame and is allowed to configure the game. * E.g. only the admin is allowed to use KGame::setMaxPlayers. * * If one KGame object in the game is MASTER then this client is the admin * as well. isMaster and isAdmin differ only if the KMessageServer * is running in an own process. * @return Whether this client (KGame object) is the admin **/ bool isAdmin() const; /** * The unique ID of this game * * @return int id **/ TQ_UINT32 gameId() const; /** * Inits a network game as network MASTER. Note that if the * KMessageServer is not yet started it will be started here (see * setMaster). Any existing connection will be disconnected. * * If you already offer connections the port is changed. * * @param port The port on which the service is offered * @return true if it worked **/ bool offerConnections (TQ_UINT16 port); /** * Announces game MASTER on network using DNS-SD. Clients then can discover it using * DNSSD::ServiceBrowser (or KGameConnectWidget) instead of manually entering * IP address. * @param type service type (something like _twin4._tcp). * It should be unique for application. * @param name game name that will be displayed by clients. If not * set hostname will be used. In case of name conflict -2, -3 and so on will be added to name. * @since 3.4 **/ void setDiscoveryInfo(const TQString& type, const TQString& name=TQString()); /** * Inits a network game as a network CLIENT * * @param host the host to which we want to connect * @param port the port we want to connect to * * @return true if connected **/ bool connectToServer(const TQString& host, TQ_UINT16 port); /** * @since 3.2 * @return The port we are listening to if offerConnections was called * or the port we are connected to if connectToServer was called. * Otherwise 0. **/ TQ_UINT16 port() const; /** * @since 3.2 * @return The name of the host that we are currently connected to is * isNetwork is TRUE and we are not the MASTER, i.e. if connectToServer * was called. Otherwise this will return "localhost". **/ TQString hostName() const; /** * Stops offering server connections - only for game MASTER * @return true **/ bool stopServerConnection(); /** * Changes the maximal connection number of the KMessageServer to max. * -1 Means infinite connections are possible. Note that existing * connections are not affected, so even if you set this to 0 in a running * game no client is being disconnected. You can call this only if you are * the ADMIN! * * @see KMessageServer::setMaxClients * @param max The maximal number of connections possible. **/ void setMaxClients(int max); //AB: is this now internal only? Can we make it protected (maybe with //friends)? sendSystemMessage AND sendMessage is very confusing to the //user. /** * Sends a network message msg with a given msg id msgid to all clients. * Use this to communicate with KGame (e.g. to add a player ot to configure * the game - usually not necessary). * * For your own messages use sendMessage instead! This is mostly * internal! * * @param buffer the message which will be send. See messages.txt for contents * @param msgid an id for this message. See * KGameMessage::GameMessageIds * @param receiver the KGame / KPlayer this message is for. * @param sender The KGame / KPlayer this message is from (i.e. * you). You * probably want to leave this 0, then KGameNetwork will create the correct * value for you. You might want to use this if you send a message from a * specific player. * @return true if worked */ // AB: TODO: doc on how "receiver" and "sender" should be created! bool sendSystemMessage(const TQByteArray& buffer, int msgid, TQ_UINT32 receiver=0, TQ_UINT32 sender=0); /** * @overload **/ bool sendSystemMessage(int data, int msgid, TQ_UINT32 receiver=0, TQ_UINT32 sender=0); /** * @overload **/ bool sendSystemMessage(const TQDataStream &msg, int msgid, TQ_UINT32 receiver=0, TQ_UINT32 sender=0); /** * @overload **/ bool sendSystemMessage(const TQString& msg, int msgid, TQ_UINT32 receiver=0, TQ_UINT32 sender=0); /** * Sends a network message * @param error The error code * @param message The error message - use KGameError * @param receiver the KGame / KPlayer this message is for. 0 For * all * @param sender The KGame / KPlayer this message is from (i.e. * you). You probably want to leave this 0, then KGameNetwork will create * the correct value for you. You might want to use this if you send a * message from a specific player. **/ void sendError(int error, const TQByteArray& message, TQ_UINT32 receiver=0, TQ_UINT32 sender=0); /** * Are we still offer offering server connections - only for game MASTER * @return true/false **/ bool isOfferingConnections() const; /** * Application cookie. this idendifies the game application. It * help to distinguish between e.g. KPoker and KWin4 * @return the application cookie **/ int cookie() const; /** * Send a network message msg with a given message ID msgid to all clients. * You want to use this to send a message to the clients. * * Note that a message is always sent to ALL clients! This is necessary so * that all clients always have the same data and can easily be changed from * network to non-network without restarting the game. If you want a * specific KGame / KPlayer to react to the message use the * receiver and sender parameters. See KGameMessage::calsMessageId * * SendMessage differs from sendSystemMessage only by the msgid parameter. * sendSystemMessage is thought as a KGame only mehtod while * sendMessage is for public use. The msgid parameter will be * +=KGameMessage::IdUser and in KGame::signalNetworkData msgid will * be -= KGameMessage::IdUser again, so that one can easily distinguish * between system and user messages. * * Use sendSystemMessage to comunicate with KGame (e.g. by adding a * player) and sendMessage for your own user message. * * Note: a player should send messages through a KGameIO! * * @param buffer the message which will be send. See messages.txt for contents * @param msgid an id for this message. See KGameMessage::GameMessageIds * @param receiver the KGame / KPlayer this message is for. * @param sender The KGame / KPlayer this message is from (i.e. * you). You * probably want to leave this 0, then KGameNetwork will create the correct * value for you. You might want to use this if you send a message from a * specific player. * @return true if worked **/ // AB: TODO: doc on how "receiver" and "sender" should be created! bool sendMessage(const TQByteArray& buffer, int msgid, TQ_UINT32 receiver=0, TQ_UINT32 sender=0); /** * This is an overloaded member function, provided for convenience. **/ bool sendMessage(const TQDataStream &msg, int msgid, TQ_UINT32 receiver=0, TQ_UINT32 sender=0); /** * This is an overloaded member function, provided for convenience. **/ bool sendMessage(const TQString& msg, int msgid, TQ_UINT32 receiver=0, TQ_UINT32 sender=0); /** * This is an overloaded member function, provided for convenience. **/ bool sendMessage(int data, int msgid, TQ_UINT32 receiver=0, TQ_UINT32 sender=0); /** * Called by ReceiveNetworkTransmission(). Will be overwritten by * KGame and handle the incoming message. **/ virtual void networkTransmission(TQDataStream&, int, TQ_UINT32, TQ_UINT32, TQ_UINT32 clientID) = 0; /** * Disconnect the current connection and establish a new local one. **/ void disconnect(); /** * If you are the ADMIN of the game you can give the ADMIN status away to * another client. Use this e.g. if you want to quit the game or if you want * another client to administrate the game (note that disconnect calls * this automatically). * @param clientID the ID of the new ADMIN (note: this is the _client_ID * which has nothing to do with the player IDs. See KMessageServer) **/ void electAdmin(TQ_UINT32 clientID); /** * Don't use this unless you really know what youre doing! You might * experience some strange behaviour if you send your messages directly * through the KMessageClient! * * @return a pointer to the KMessageClient used internally to send the * messages. You should rather use one of the send functions! **/ KMessageClient* messageClient() const; /** * Don't use this unless you really know what you are doing! You might * experience some strange behaviour if you use the message server directly! * * @return a pointer to the message server if this is the MASTER KGame * object. Note that it might be possible that no KGame object contains * the KMessageServer at all! It might even run stand alone! **/ KMessageServer* messageServer() const; /** * You should call this before doing thigs like, e.g. tqApp->processEvents(). * Don't forget to call unlock once you are done! * * @see KMessageClient::lock **/ virtual void lock(); /** * @see KMessageClient::unlock **/ virtual void unlock(); signals: /** * A network error occurred * @param error the error code * @param text the error text */ void signalNetworkErrorMessage(int error, TQString text); /** * Our connection to the KMessageServer has broken. * See KMessageClient::connectionBroken **/ void signalConnectionBroken(); /** * This signal is emitted whenever the KMessageServer sends us a message that a * new client connected. KGame uses this to call KGame::negotiateNetworkGame * for the newly connected client if we are admin (see isAdmin) * * @see KMessageClient::eventClientConnected * * @param clientID the ID of the newly connected client **/ void signalClientConnected(TQ_UINT32 clientID); /** * This signal is emitted whenever the KMessageServer sends us a message * that a connection to a client was detached. The second parameter can be used * to distinguish between network errors or removing on purpose. * * @see KMessageClient::eventClientDisconnected * * @param clientID the client that has disconnected * @param broken true if the connection was lost because of a network error, false * if the connection was closed by the message server admin. */ void signalClientDisconnected(TQ_UINT32 clientID, bool broken); /** * This client gets or loses the admin status. * @see KMessageClient::adminStatusChanged * @param isAdmin True if this client gets the ADMIN status otherwise FALSE **/ void signalAdminStatusChanged(bool isAdmin); protected: /** * @internal * Start a KMessageServer object and use it as the MASTER of the game. * Note that you must not call this if there is already another master * running! **/ void setMaster(); protected slots: /** * Called by KMessageClient::broadcastReceived() and will check if the * message format is valid. If it is not, it will generate an error (see * signalNetworkVersionError and signalNetworkErorrMessage). * If it is valid, the pure virtual method networkTransmission() is called. * (This one is overwritten in KGame.) **/ void receiveNetworkTransmission(const TQByteArray& a, TQ_UINT32 clientID); /** * This KGame object receives or loses the admin status. * @param isAdmin Whether we are admin or not **/ void slotAdminStatusChanged(bool isAdmin); /** * Called when the network connection is about to terminate. Is used * to store the network parameter like the game id */ void aboutToLoseConnection(TQ_UINT32 id); /** * Called when the network connection is terminated. Used to clean * up the disconnect parameter */ void slotResetConnection(); private: void tryPublish(); void tryStopPublishing(); KGameNetworkPrivate* d; }; #endif