File indexing completed on 2024-06-16 03:57:55

0001 /*
0002     This file is part of the KDE games library
0003     SPDX-FileCopyrightText: 2001 Martin Heni <kde at heni-online.de>
0004     SPDX-FileCopyrightText: 2001 Andreas Beckermann <b_mann@gmx.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #ifndef __KGAMENETWORK_H_
0010 #define __KGAMENETWORK_H_
0011 
0012 // own
0013 #include "kdegamesprivate_export.h"
0014 // Qt
0015 #include <QObject>
0016 #include <QString>
0017 // Std
0018 #include <memory>
0019 
0020 class KGameIO;
0021 class KMessageIO;
0022 class KMessageClient;
0023 class KMessageServer;
0024 
0025 class KGameNetworkPrivate;
0026 
0027 /**
0028  * \class KGameNetwork kgamenetwork.h <KGame/KGameNetwork>
0029  *
0030  * The KGameNetwork class is the KGame class with network
0031  * support. All other features are the same but they are
0032  * now network transparent. It is not used directly but
0033  * only via a KGame object. So you do not really have
0034  * to bother with this object.
0035  *
0036  * @short The main KDE game object
0037  */
0038 class KDEGAMESPRIVATE_EXPORT KGameNetwork : public QObject
0039 {
0040     Q_OBJECT
0041 
0042 public:
0043     /**
0044      * Create a KGameNetwork object
0045      */
0046     explicit KGameNetwork(int cookie = 42, QObject *parent = nullptr);
0047     ~KGameNetwork() override;
0048 
0049     /**
0050      * Gives debug output of the game status
0051      */
0052     virtual void Debug();
0053 
0054     /**
0055      * @return TRUE if this is a network game - i.e. you are either MASTER or
0056      * connected to a remote MASTER.
0057      */
0058     bool isNetwork() const;
0059 
0060     /**
0061      * Is this the game MASTER (i.e. has started theKMessageServer). A
0062      * game has always exactly one MASTER. This is either a KGame object (i.e. a
0063      * Client) or an own MessageServer-process. A KGame object that has the
0064      * MASTER status is always admin.
0065      *
0066      * You probably don't want to use this. It is a mostly internal method which
0067      * will probably become protected. Better use isAdmin
0068      *
0069      * @see isAdmin
0070      * @return Whether this client has started the KMessageServer
0071      */
0072     bool isMaster() const;
0073 
0074     /**
0075      * The admin of a game is the one who initializes newly connected clients
0076      * using  negotiateNetworkGame and is allowed to configure the game.
0077      * E.g. only the admin is allowed to use KGame::setMaxPlayers.
0078      *
0079      * If one KGame object in the game is MASTER then this client is the admin
0080      * as well. isMaster and isAdmin differ only if the KMessageServer
0081      * is running in an own process.
0082      * @return Whether this client (KGame object) is the admin
0083      */
0084     bool isAdmin() const;
0085 
0086     /**
0087      * The unique ID of this game
0088      *
0089      * @return int id
0090      */
0091     quint32 gameId() const;
0092 
0093     /**
0094      * Inits a network game as network MASTER. Note that if the
0095      * KMessageServer is not yet started it will be started here (see
0096      * setMaster). Any existing connection will be disconnected.
0097      *
0098      * If you already offer connections the port is changed.
0099      *
0100      * @param port The port on which the service is offered
0101      * @return true if it worked
0102      */
0103     bool offerConnections(quint16 port);
0104 
0105     void setDiscoveryInfo(const QString &type, const QString &name = QString());
0106 
0107     /**
0108      * Inits a network game as a network CLIENT
0109      *
0110      * @param host the host to which we want to connect
0111      * @param port the port we want to connect to
0112      *
0113      * @return true if connected
0114      */
0115     bool connectToServer(const QString &host, quint16 port);
0116     bool connectToServer(KMessageIO *connection);
0117 
0118     /**
0119      * @return The port we are listening to if offerConnections was called
0120      * or the port we are connected to if connectToServer was called.
0121      * Otherwise 0.
0122      */
0123     quint16 port() const;
0124 
0125     /**
0126      * @return The name of the host that we are currently connected to is
0127      * isNetwork is TRUE and we are not the MASTER, i.e. if connectToServer
0128      * was called. Otherwise this will return "localhost".
0129      */
0130     QString hostName() const;
0131 
0132     /**
0133      * Stops offering server connections - only for game MASTER
0134      * @return true
0135      */
0136     bool stopServerConnection();
0137 
0138     /**
0139      * Changes the maximal connection number of the KMessageServer to max.
0140      * -1 Means infinite connections are possible. Note that existing
0141      * connections are not affected, so even if you set this to 0 in a running
0142      * game no client is being disconnected. You can call this only if you are
0143      * the ADMIN!
0144      *
0145      * @see KMessageServer::setMaxClients
0146      * @param max The maximal number of connections possible.
0147      */
0148     void setMaxClients(int max);
0149 
0150     // AB: is this now internal only? Can we make it protected (maybe with
0151     // friends)? sendSystemMessage AND sendMessage is very confusing to the
0152     // user.
0153     /**
0154      * Sends a network message msg with a given msg id msgid to all clients.
0155      * Use this to communicate with KGame (e.g. to add a player ot to configure
0156      * the game - usually not necessary).
0157      *
0158      * For your own messages use  sendMessage instead! This is mostly
0159      * internal!
0160      *
0161      * @param buffer the message which will be send. See messages.txt for contents
0162      * @param msgid an id for this message. See
0163      * KGameMessage::GameMessageIds
0164      * @param receiver the KGame / KPlayer this message is for.
0165      * @param sender The KGame / KPlayer this message is from (i.e.
0166      * you). You
0167      * probably want to leave this 0, then KGameNetwork will create the correct
0168      * value for you. You might want to use this if you send a message from a
0169      * specific player.
0170      * @return true if worked
0171      */
0172     // AB: TODO: doc on how "receiver" and "sender" should be created!
0173     bool sendSystemMessage(const QByteArray &buffer, int msgid, quint32 receiver = 0, quint32 sender = 0);
0174 
0175     /**
0176      * @overload
0177      */
0178     bool sendSystemMessage(int data, int msgid, quint32 receiver = 0, quint32 sender = 0);
0179 
0180     /**
0181      * @overload
0182      */
0183     bool sendSystemMessage(const QDataStream &msg, int msgid, quint32 receiver = 0, quint32 sender = 0);
0184 
0185     /**
0186      * @overload
0187      */
0188     bool sendSystemMessage(const QString &msg, int msgid, quint32 receiver = 0, quint32 sender = 0);
0189 
0190     /**
0191      * Sends a network message
0192      * @param error The error code
0193      * @param message The error message - use KGameError
0194      * @param receiver the KGame / KPlayer this message is for. 0 For
0195      * all
0196      * @param sender The KGame / KPlayer this message is from (i.e.
0197      * you). You probably want to leave this 0, then KGameNetwork will create
0198      * the correct value for you. You might want to use this if you send a
0199      * message from a specific player.
0200      */
0201     void sendError(int error, const QByteArray &message, quint32 receiver = 0, quint32 sender = 0);
0202 
0203     /**
0204      * Are we still offer offering server connections - only for game MASTER
0205      * @return true/false
0206      */
0207     bool isOfferingConnections() const;
0208 
0209     /**
0210      * Application cookie. this identifies the game application. It
0211      * help to distinguish between e.g. KPoker and KWin4
0212      * @return the application cookie
0213      */
0214     int cookie() const;
0215 
0216     /**
0217      * Send a network message msg with a given message ID msgid to all clients.
0218      * You want to use this to send a message to the clients.
0219      *
0220      * Note that a message is always sent to ALL clients! This is necessary so
0221      * that all clients always have the same data and can easily be changed from
0222      * network to non-network without restarting the game. If you want a
0223      * specific KGame / KPlayer to react to the message use the
0224      * receiver and sender parameters. See KGameMessage::calsMessageId
0225      *
0226      * SendMessage differs from sendSystemMessage only by the msgid parameter.
0227      * sendSystemMessage is thought as a KGame only method while
0228      * sendMessage is for public use. The msgid parameter will be
0229      * +=KGameMessage::IdUser and in KGame::signalNetworkData msgid will
0230      * be -= KGameMessage::IdUser again, so that one can easily distinguish
0231      * between system and user messages.
0232      *
0233      * Use sendSystemMessage to communicate with KGame (e.g. by adding a
0234      * player) and sendMessage for your own user message.
0235      *
0236      * Note: a player should send messages through a KGameIO!
0237      *
0238      * @param buffer the message which will be send. See messages.txt for contents
0239      * @param msgid an id for this message. See KGameMessage::GameMessageIds
0240      * @param receiver the KGame / KPlayer this message is for.
0241      * @param sender The KGame / KPlayer this message is from (i.e.
0242      * you). You
0243      * probably want to leave this 0, then KGameNetwork will create the correct
0244      * value for you. You might want to use this if you send a message from a
0245      * specific player.
0246      * @return true if worked
0247      */
0248     // AB: TODO: doc on how "receiver" and "sender" should be created!
0249     bool sendMessage(const QByteArray &buffer, int msgid, quint32 receiver = 0, quint32 sender = 0);
0250 
0251     /**
0252      * This is an overloaded member function, provided for convenience.
0253      */
0254     bool sendMessage(const QDataStream &msg, int msgid, quint32 receiver = 0, quint32 sender = 0);
0255 
0256     /**
0257      * This is an overloaded member function, provided for convenience.
0258      */
0259     bool sendMessage(const QString &msg, int msgid, quint32 receiver = 0, quint32 sender = 0);
0260 
0261     /**
0262      * This is an overloaded member function, provided for convenience.
0263      */
0264     bool sendMessage(int data, int msgid, quint32 receiver = 0, quint32 sender = 0);
0265 
0266     /**
0267      * Called by ReceiveNetworkTransmission(). Will be overwritten by
0268      * KGame and handle the incoming message.
0269      */
0270     virtual void networkTransmission(QDataStream &, int, quint32, quint32, quint32 clientID) = 0;
0271 
0272     /**
0273      * Disconnect the current connection and establish a new local one.
0274      */
0275     void disconnect();
0276 
0277     /**
0278      * If you are the ADMIN of the game you can give the ADMIN status away to
0279      * another client. Use this e.g. if you want to quit the game or if you want
0280      * another client to administrate the game (note that disconnect calls
0281      * this automatically).
0282      * @param clientID the ID of the new ADMIN (note: this is the _client_ID
0283      * which has nothing to do with the player IDs. See KMessageServer)
0284      */
0285     void electAdmin(quint32 clientID);
0286 
0287     /**
0288      * Don't use this unless you really know what you're doing! You might
0289      * experience some strange behaviour if you send your messages directly
0290      * through the KMessageClient!
0291      *
0292      * @return a pointer to the KMessageClient used internally to send the
0293      * messages. You should rather use one of the send functions!
0294      */
0295     KMessageClient *messageClient() const;
0296 
0297     /**
0298      * Don't use this unless you really know what you are doing! You might
0299      * experience some strange behaviour if you use the message server directly!
0300      *
0301      * @return a pointer to the message server if this is the MASTER KGame
0302      * object. Note that it might be possible that no KGame object contains
0303      * the KMessageServer at all! It might even run stand alone!
0304      */
0305     KMessageServer *messageServer() const;
0306 
0307     /**
0308      * You should call this before doing thigs like, e.g. qApp->processEvents().
0309      * Don't forget to call unlock once you are done!
0310      *
0311      * @see KMessageClient::lock
0312      */
0313     virtual void lock();
0314 
0315     /**
0316      * @see KMessageClient::unlock
0317      */
0318     virtual void unlock();
0319 
0320 Q_SIGNALS:
0321     /**
0322      * A network error occurred
0323      * @param error the error code
0324      * @param text the error text
0325      */
0326     void signalNetworkErrorMessage(int error, const QString &text);
0327 
0328     /**
0329      * Our connection to the KMessageServer has broken.
0330      * See KMessageClient::connectionBroken
0331      */
0332     void signalConnectionBroken();
0333 
0334     /**
0335      * This signal is emitted whenever the KMessageServer sends us a message that a
0336      * new client connected. KGame uses this to call KGame::negotiateNetworkGame
0337      * for the newly connected client if we are admin (see isAdmin)
0338      *
0339      * @see KMessageClient::eventClientConnected
0340      *
0341      * @param clientID the ID of the newly connected client
0342      */
0343     void signalClientConnected(quint32 clientID);
0344 
0345     /**
0346      * This signal is emitted whenever the KMessageServer sends us a message
0347      * that a connection to a client was detached. The second parameter can be used
0348      * to distinguish between network errors or removing on purpose.
0349      *
0350      * @see KMessageClient::eventClientDisconnected
0351      *
0352      * @param clientID the client that has disconnected
0353      * @param broken true if the connection was lost because of a network error, false
0354      *        if the connection was closed by the message server admin.
0355      */
0356     void signalClientDisconnected(quint32 clientID, bool broken);
0357 
0358     /**
0359      * This client gets or loses the admin status.
0360      * @see KMessageClient::adminStatusChanged
0361      * @param isAdmin True if this client gets the ADMIN status otherwise FALSE
0362      */
0363     void signalAdminStatusChanged(bool isAdmin);
0364 
0365 protected:
0366     /**
0367      * @internal
0368      * Start a KMessageServer object and use it as the MASTER of the game.
0369      * Note that you must not call this if there is already another master
0370      * running!
0371      */
0372     void setMaster();
0373 
0374 protected Q_SLOTS:
0375     /**
0376      * Called by KMessageClient::broadcastReceived() and will check if the
0377      * message format is valid. If it is not, it will generate an error (see
0378      * signalNetworkVersionError and signalNetworkErorrMessage).
0379      * If it is valid, the pure virtual method networkTransmission() is called.
0380      * (This one is overwritten in KGame.)
0381      */
0382     void receiveNetworkTransmission(const QByteArray &a, quint32 clientID);
0383 
0384     /**
0385      * This KGame object receives or loses the admin status.
0386      * @param isAdmin Whether we are admin or not
0387      */
0388     void slotAdminStatusChanged(bool isAdmin);
0389 
0390     /**
0391      * Called when the network connection is about to terminate. Is used
0392      * to store the network parameter like the game id
0393      */
0394     void aboutToLoseConnection(quint32 id);
0395 
0396     /**
0397      * Called when the network connection is terminated. Used to clean
0398      * up the disconnect parameter
0399      */
0400     void slotResetConnection();
0401 
0402 private:
0403     void tryPublish();
0404     void tryStopPublishing();
0405 
0406 private:
0407     std::unique_ptr<KGameNetworkPrivate> const d;
0408 };
0409 
0410 #endif