File indexing completed on 2024-12-01 03:46:41

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 __KGAMEPROCESS_H_
0010 #define __KGAMEPROCESS_H_
0011 
0012 // KDEGames
0013 #define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API
0014 #include <libkdegamesprivate/kgame/kgamemessage.h>
0015 #include <libkdegamesprivate/kgame/kmessageio.h>
0016 // Qt
0017 #include <QFile>
0018 #include <QObject>
0019 
0020 class QRandomGenerator;
0021 
0022 class KPlayer;
0023 class KMessageFilePipe;
0024 class KGameProcessPrivate;
0025 
0026 class KMessageFilePipe : public KMessageIO
0027 {
0028     Q_OBJECT
0029 
0030 public:
0031     explicit KMessageFilePipe(QObject *parent, QFile *readFile, QFile *writeFile);
0032     ~KMessageFilePipe() override;
0033     bool isConnected() const override;
0034     void send(const QByteArray &msg) override;
0035     void exec();
0036 
0037     /**
0038       @return FALSE as this is no network IO.
0039     */
0040     bool isNetwork() const override
0041     {
0042         return false;
0043     }
0044 
0045     /**
0046      * The runtime identification
0047      */
0048     int rtti() const override
0049     {
0050         return 4;
0051     }
0052 
0053 private:
0054     QFile *mReadFile;
0055     QFile *mWriteFile;
0056     QByteArray mReceiveBuffer;
0057     int mReceiveCount;
0058 };
0059 
0060 /**
0061  * \class KGameProcess kgameprocess.h <KGame/KGameProcess>
0062  *
0063  * This is the process class used on the computer player
0064  * side to communicate with its counterpart KProcessIO class.
0065  * Using these two classes will give fully transparent communication
0066  * via QDataStreams.
0067  */
0068 class KGameProcess : public QObject
0069 {
0070     Q_OBJECT
0071 
0072 public:
0073     /**
0074      * Creates a KGameProcess class. Done only in the computer
0075      * player. To activate the communication you have to call
0076      * the exec function of this class which will listen
0077      * to the communication and emit signals to notify you of
0078      * any incoming messages.
0079      * Note: This function will only return after you set
0080      * setTerminate(true) in one of the received signals.
0081      * So you can not do any computer calculation after the exec function.
0082      * Instead you react on the signals which are emitted after a
0083      * message is received and perform the calculations there!
0084      * Example:
0085      * \code
0086      *  int main(int argc ,char * argv[])
0087      *  {
0088      *    KGameProcess proc;
0089      *    connect(&proc,SIGNAL(signalCommand(QDataStream &,int ,int ,int )),
0090      *                    this,SLOT(slotCommand(QDataStream & ,int ,int ,int )));
0091      *    connect(&proc,SIGNAL(signalInit(QDataStream &,int)),
0092      *                    this,SLOT(slotInit(QDataStream & ,int )));
0093      *    connect(&proc,SIGNAL(signalTurn(QDataStream &,bool )),
0094      *                    this,SLOT(slotTurn(QDataStream & ,bool )));
0095      *    return proc.exec(argc,argv);
0096      *  }
0097      *  \endcode
0098      */
0099     KGameProcess();
0100     /**
0101      * Destruct the process
0102      */
0103     ~KGameProcess() override;
0104 
0105     /**
0106      * Enters the event loop of the computer process. Does only
0107      * return on setTerminate(true)!
0108      */
0109     bool exec();
0110 
0111     /**
0112      * Should the computer process leave its exec function?
0113      * Activated if you setTerminate(true);
0114      *
0115      * @return true/false
0116      */
0117     bool terminate() const
0118     {
0119         return mTerminate;
0120     }
0121 
0122     /**
0123      * Set this to true if the computer process should end, ie
0124      * leave its exec function.
0125      *
0126      * @param b true for exit the exec function
0127      */
0128     void setTerminate(bool b)
0129     {
0130         mTerminate = b;
0131     }
0132 
0133     /**
0134      * Sends a message to the corresponding KGameIO
0135      * device. Works like the sendSystemMessage but
0136      * for user id's
0137      *
0138      * @param stream the QDataStream containing the message
0139      * @param msgid the message id for the message
0140      * @param receiver unused
0141      */
0142     void sendMessage(QDataStream &stream, int msgid, quint32 receiver = 0);
0143 
0144     /**
0145      * Sends a system message to the corresponding KGameIO device.
0146      * This will normally be either a performed move or a query
0147      * (IdProcessQuery). The query option is a way to communicate
0148      * with the KGameIO at the other side and e.g. retrieve some
0149      * game relevant data from here.
0150      * Example for a query:
0151      * \code
0152      *  QByteArray buffer;
0153      *  QDataStream out(buffer,QIODevice::WriteOnly);
0154      *  int msgid=KGameMessage::IdProcessQuery;
0155      *  out << (int)1;
0156      *  proc.sendSystemMessage(out,msgid,0);
0157      * \endcode
0158      *
0159      * @param stream the QDataStream containing the message
0160      * @param msgid the message id for the message
0161      * @param receiver unused
0162      */
0163     void sendSystemMessage(QDataStream &stream, int msgid, quint32 receiver = 0);
0164 
0165     /**
0166      * Returns a pointer to a QRandomGenerator. You can generate
0167      * random numbers via e.g.
0168      * \code
0169      *   random()->bounded(100);
0170      * \endcode
0171      *
0172      * @return QRandomGenerator pointer
0173      */
0174     QRandomGenerator *random();
0175 
0176 protected Q_SLOTS:
0177     /**
0178      * A message is received via the interprocess connection. The
0179      * appropriate signals are called.
0180      */
0181     void receivedMessage(const QByteArray &receiveBuffer);
0182 
0183 Q_SIGNALS:
0184     /**
0185      * The generic communication signal. You have to connect to this
0186      * signal to generate a valid computer response onto arbitrary messages.
0187      * All signals but IdIOAdded and IdTurn end up here!
0188      * Example:
0189      * \code
0190      * void Computer::slotCommand(int &msgid,QDataStream &in,QDataStream &out)
0191      * {
0192      *   qint32 data,move;
0193      *   in >> data;
0194      *   // compute move ...
0195      *   move=data*2;
0196      *   out << move;
0197      * }
0198      * \endcode
0199      *
0200      * @param inputStream the incoming data stream
0201      * @param msgid the message id of the message which got transmitted to the computer
0202      * @param receiver the id of the receiver
0203      * @param sender the id of the sender
0204      */
0205     void signalCommand(QDataStream &inputStream, int msgid, int receiver, int sender);
0206 
0207     /**
0208      * This signal is emitted if the computer player should perform a turn.
0209      * Calculations can be made here and the move can then be send back with
0210      * sendSystemMessage with the message id KGameMessage::IdPlayerInput.
0211      * These must provide a move which complies to your other move syntax as
0212      * e.g. produces by keyboard or mouse input.
0213      * Additional data which have been written into the stream from the
0214      * ProcessIO's signal signalPrepareTurn can be retrieved from the
0215      * stream here.
0216      * Example:
0217      * \code
0218      * void slotTurn(QDataStream &in,bool turn)
0219      * {
0220      *   int id;
0221      *   int recv;
0222      *   QByteArray buffer;
0223      *   QDataStream out(buffer,QIODevice::WriteOnly);
0224      *   if (turn)
0225      *   {
0226      *     // Create a move - the format is yours to decide
0227      *     // It arrives exactly as this in the kgame inputMove function!!
0228      *     qint8 x1,y1,pl;
0229      *     pl=-1;
0230      *     x1=proc.random()->bounded(8);
0231      *     y1=proc.random()->bounded(8);
0232      *     // Stream it
0233      *     out << pl << x1 << y1;
0234      *     id=KGameMessage::IdPlayerInput;
0235      *     proc.sendSystemMessage(out,id,0);
0236      *   }
0237      * }
0238      * \endcode
0239      *
0240      * @param stream The datastream which contains user data
0241      * @param turn True or false whether the turn is activated or deactivated
0242      *
0243      */
0244     void signalTurn(QDataStream &stream, bool turn);
0245 
0246     /**
0247      * This signal is emitted when the process is initialized, i.e. added
0248      * to a KPlayer. Initial initialization can be performed here be reacting
0249      * to the KProcessIO signal signalIOAdded and retrieving the data here
0250      * from the stream.
0251      * It works just as the signalTurn() but is only send when the player is
0252      * added to the game, i.e. it needs some initialization data
0253      *
0254      * @param stream The datastream which contains user data
0255      * @param userid The userId of the player. (Careful to rely on it yet)
0256      */
0257     void signalInit(QDataStream &stream, int userid);
0258 
0259 protected:
0260     bool mTerminate;
0261     KMessageFilePipe *mMessageIO;
0262 
0263 private:
0264     friend class KGameProcessPrivate;
0265     KGameProcessPrivate *const d;
0266 
0267     Q_DISABLE_COPY(KGameProcess)
0268 };
0269 #endif