File indexing completed on 2024-09-22 03:48:33

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 __KGAMEIO_H__
0010 #define __KGAMEIO_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 QEvent;
0021 class QGraphicsScene;
0022 class QKeyEvent;
0023 class QMouseEvent;
0024 class KPlayer;
0025 class KGame;
0026 class KGameIOPrivate;
0027 class KGameKeyIOPrivate;
0028 class KGameMouseIOPrivate;
0029 class KGameProcessIOPrivate;
0030 class KGameComputerIOPrivate;
0031 
0032 /**
0033  *  \class KGameIO kgameio.h <KGame/KGameIO>
0034  *
0035  *  \short Base class for IO devices for games
0036  *
0037  *  This is the master class for
0038  *  creating IO game devices. You cannot use it directly.
0039  *  Either take one of the classes derived from it or
0040  *  you have to create your own IO class derived from it (more probably).
0041  *
0042  *  The idea behind this class is to provide a common interface
0043  *  for input devices into your game. By programming a KGameIO
0044  *  device you need not distinguish the actual IO in the game
0045  *  anymore. All work is done by the IO's. This allows very
0046  *  easy reuse in other games as well.
0047  *  A further advantage of using the IO's is that you can exchange
0048  *  the control of a player at runtime. E.g. you switch a player
0049  *  to be controlled by the computer or vice versa.
0050  *
0051  *  To achieve this you have to make all of your player inputs through a
0052  *  KGameIO. You will usually call KGameIO::sendInput to do so.
0053  *
0054  *  @author Martin Heni <kde at heni-online.de>
0055  */
0056 class KDEGAMESPRIVATE_EXPORT KGameIO : public QObject
0057 {
0058     Q_OBJECT
0059 
0060 public:
0061     /**
0062      * Constructs a KGameIO object
0063      */
0064     KGameIO();
0065     explicit KGameIO(KPlayer *);
0066     ~KGameIO() override;
0067 
0068     /**
0069      * Gives debug output of the game status
0070      */
0071     void Debug();
0072 
0073     /**
0074      * Identifies the KGameIO via the rtti function
0075      */
0076     enum IOMode { GenericIO = 1, KeyIO = 2, MouseIO = 4, ProcessIO = 8, ComputerIO = 16 };
0077     /**
0078      * Run time identification. Predefined values are from IOMode
0079      * You MUST overwrite this in derived classes!
0080      *
0081      * @return rtti value
0082      */
0083     virtual int rtti() const = 0; // Computer, network, local, ...
0084 
0085     /**
0086      * This function returns the player who owns this IO
0087      *
0088      * @return the player this IO device is plugged into
0089      */
0090     KPlayer *player() const;
0091 
0092     /**
0093      * Equivalent to player()->game()
0094      * @return the @ref KGame object of this player
0095      */
0096     KGame *game() const;
0097 
0098     /**
0099      * Sets the player to which this IO belongs to. This
0100      * is done automatically when adding a device to a
0101      * player
0102      *
0103      * @param p the player
0104      */
0105     void setPlayer(KPlayer *p);
0106 
0107     /**
0108      * Init this device by setting the player and e.g. sending an
0109      * init message to the device. This initialisation message is
0110      * very useful for computer players as you can transmit the
0111      * game status to them and only update this status in the setTurn
0112      * commands.
0113      *
0114      * Called by @ref KPlayer::addGameIO only!
0115      */
0116     virtual void initIO(KPlayer *p);
0117 
0118     /**
0119      * Notifies the IO device that the player's setTurn had been called
0120      * Called by KPlayer
0121      *
0122      * This emits @ref signalPrepareTurn and sends the turn if the send
0123      * parameter is set to true.
0124      *
0125      * @param b turn is true/false
0126      */
0127     virtual void notifyTurn(bool b);
0128 
0129     /**
0130      * Send an input message using @ref KPlayer::forwardInput
0131      */
0132     bool sendInput(QDataStream &stream, bool transmit = true, quint32 sender = 0);
0133 
0134 Q_SIGNALS:
0135     /**
0136      * Signal generated when @ref KPlayer::myTurn changes. This can either be
0137      * when you get the turn status or when you lose it.
0138      *
0139      * The datastream has to be filled with a move. If you set (or leave) the
0140      * send parameter to FALSE then nothing happens: the datastream will be
0141      * ignored. If you set it to TRUE @ref sendInput is used to
0142      * send the move.
0143      *
0144      * Often you want to ignore this signal (leave send=FALSE) and send the
0145      * message later. This is usually the case for a human player as he probably
0146      * doesn't react immediately. But you can still use this e.g. to notify the
0147      * player about the turn change.
0148      *
0149      * Example:
0150      * \code
0151      *  void GameWindow::slotPrepareTurn(QDataStream &stream,bool b,KGameIO *input,bool * )
0152      *  {
0153      *    KPlayer *player=input->player();
0154      *    if (!player->myTurn()) return ;
0155      *    if (!b) return ;        // only do something on setTurn(true)
0156      *    stream << 1 << 2 << 3;  // Some data for the process
0157      *  }
0158      * \endcode
0159      *
0160      * @param io the KGameIO object itself
0161      * @param stream the stream into which the move will be written
0162      * @param turn the argument of setTurn
0163      * @param send set this to true to send the generated move using @ref
0164      * sendInput
0165      */
0166     void signalPrepareTurn(QDataStream &stream, bool turn, KGameIO *io, bool *send);
0167 
0168 protected:
0169     explicit KGameIO(KGameIOPrivate &dd, KPlayer *player = nullptr);
0170 
0171 private:
0172     Q_DECLARE_PRIVATE_D(d, KGameIO)
0173     friend class KGameIOPrivate;
0174     friend class KGameKeyIO;
0175     friend class KGameMouseIO;
0176     friend class KGameProcessIO;
0177     friend class KGameComputerIO;
0178     std::unique_ptr<KGameIOPrivate> const d;
0179     // KF6 TODO: change private d to protected d_ptr, use normal Q_DECLARE_PRIVATE, remove subclass friends
0180 
0181     Q_DISABLE_COPY(KGameIO)
0182 };
0183 
0184 /**
0185  *  \class KGameKeyIO kgameio.h <KGame/KGameIO>
0186  *
0187  *  The KGameKeyIO class. It is used to process keyboard input
0188  *  from a widget and create moves for the player it belongs to.
0189  *  @author Martin Heni <kde at heni-online.de>
0190  */
0191 class KDEGAMESPRIVATE_EXPORT KGameKeyIO : public KGameIO
0192 {
0193     Q_OBJECT
0194 
0195 public:
0196     /**
0197      * Create a keyboard input devices. All keyboards
0198      * inputs of the given widgets are passed through a signal
0199      * handler signalKeyEvent and can be used to generate
0200      * a valid move for the player.
0201      * Note the widget you pass to the constructor must be
0202      * the main window of your application, e.g. view->parentWidget()
0203      * as QT does not forward your keyevents otherwise. This means
0204      * that this might be a different widget compared to the one you
0205      * use for mouse inputs!
0206      * Example:
0207      * \code
0208      * KGameKeyIO *input;
0209      *  input=new KGameKeyIO(myWidget);
0210      *  connect(input,SIGNAL(signalKeyEvent(KGameIO *,QDataStream &,QKeyEvent *,bool *)),
0211      *          this,SLOT(slotKeyInput(KGameIO *,QDataStream &,QKeyEvent *,bool *)));
0212      * \endcode
0213      *
0214      * @param parent The parents widget whose keyboard events * should be grabbed
0215      */
0216     explicit KGameKeyIO(QWidget *parent);
0217     ~KGameKeyIO() override;
0218 
0219     /**
0220      * The identification of the IO
0221      *
0222      * @return KeyIO
0223      */
0224     int rtti() const override;
0225 
0226 Q_SIGNALS:
0227     /**
0228      * Signal handler for keyboard events. This function is called
0229      * on every keyboard event. If appropriate it can generate a
0230      * move for the player the device belongs to. If this is done
0231      * and the event is eaten eatevent needs to be set to true.
0232      * What move you generate (i.e. what you write to the stream)
0233      * is totally up to you as it will not be evaluated but forwarded
0234      * to the player's/game's  input move function
0235      * Example:
0236      * \code
0237      * KPlayer *player=input->player(); // Get the player
0238      * qint32 key=e->key();
0239      * stream << key;
0240      * eatevent=true;
0241      * \endcode
0242      *
0243      * @param io the IO device we belong to
0244      * @param stream the stream where we write our move into
0245      * @param m The QKeyEvent we can evaluate
0246      * @param eatevent set this to true if we processed the event
0247      */
0248     void signalKeyEvent(KGameIO *io, QDataStream &stream, QKeyEvent *m, bool *eatevent);
0249 
0250 protected:
0251     /**
0252      * Internal method to process the events
0253      */
0254     bool eventFilter(QObject *o, QEvent *e) override;
0255 
0256 private:
0257     Q_DECLARE_PRIVATE_D(KGameIO::d, KGameKeyIO)
0258     friend class KGameKeyIOPrivate;
0259 
0260     Q_DISABLE_COPY(KGameKeyIO)
0261 };
0262 
0263 /**
0264  *  \class KGameMouseIO kgameio.h <KGame/KGameIO>
0265  *
0266  *  The KGameMouseIO class. It is used to process mouse input
0267  *  from a widget and create moves for the player it belongs to.
0268  *  @author Martin Heni <kde at heni-online.de>
0269  */
0270 class KDEGAMESPRIVATE_EXPORT KGameMouseIO : public KGameIO
0271 {
0272     Q_OBJECT
0273 
0274 public:
0275     /**
0276      * Creates a mouse IO device. It captures all mouse
0277      * event of the given widget and forwards them to the
0278      * signal handler signalMouseEvent.
0279      * Example:
0280      * \code
0281      * KGameMouseIO *input;
0282      * input=new KGameMouseIO(mView);
0283      * connect(input,SIGNAL(signalMouseEvent(KGameIO *,QDataStream &,QMouseEvent *,bool *)),
0284      *        this,SLOT(slotMouseInput(KGameIO *,QDataStream &,QMouseEvent *,bool *)));
0285      * \endcode
0286      *
0287      * @param parent The widget whose events should be captured
0288      * @param trackmouse enables mouse tracking (gives mouse move events)
0289      */
0290     explicit KGameMouseIO(QWidget *parent, bool trackmouse = false);
0291     explicit KGameMouseIO(QGraphicsScene *parent, bool trackmouse = false);
0292     ~KGameMouseIO() override;
0293 
0294     /**
0295      * Manually activate or deactivate mouse tracking
0296      *
0297      * @param b true = tracking on
0298      */
0299     void setMouseTracking(bool b);
0300     /**
0301      * The identification of the IO
0302      *
0303      * @return MouseIO
0304      */
0305     int rtti() const override;
0306 
0307 Q_SIGNALS:
0308     /**
0309      * Signal handler for mouse events. This function is called
0310      * on every mouse event. If appropriate it can generate a
0311      * move for the player the device belongs to. If this is done
0312      * and the event is eaten eatevent needs to be set to true.
0313      * @see signalKeyEvent
0314      * Example:
0315      * \code
0316      * KPlayer *player=input->player(); // Get the player
0317      * qint32 button=e->button();
0318      * stream << button;
0319      * eatevent=true;
0320      * \endcode
0321      *
0322      * @param io the IO device we belong to
0323      * @param stream the stream where we write our move into
0324      * @param m The QMouseEvent we can evaluate
0325      * @param eatevent set this to true if we processed the event
0326      */
0327     void signalMouseEvent(KGameIO *io, QDataStream &stream, QMouseEvent *m, bool *eatevent);
0328 
0329 protected:
0330     /**
0331      * Internal event filter
0332      */
0333     bool eventFilter(QObject *o, QEvent *e) override;
0334 
0335 private:
0336     Q_DECLARE_PRIVATE_D(KGameIO::d, KGameMouseIO)
0337     friend class KGameMouseIOPrivate;
0338 
0339     Q_DISABLE_COPY(KGameMouseIO)
0340 };
0341 
0342 /**
0343  *  \class KGameProcessIO kgameio.h <KGame/KGameIO>
0344  *
0345  *  The KGameProcessIO class. It is used to create a computer player
0346  *  via a separate process and communicate transparently with it.
0347  *  Its counterpart is the KGameProcess class which needs
0348  *  to be used by the computer player. See its documentation
0349  *  for the definition of the computer player.
0350  */
0351 class KDEGAMESPRIVATE_EXPORT KGameProcessIO : public KGameIO
0352 {
0353     Q_OBJECT
0354 
0355 public:
0356     /**
0357      * Creates a computer player via a separate process. The process
0358      * name is given as fully qualified filename.
0359      * Example:
0360      * \code
0361      * KGameProcessIO *input;
0362      *   input=new KGameProcessIO(executable_file);
0363      *  connect(input,SIGNAL(signalPrepareTurn(QDataStream &,bool,KGameIO *,bool *)),
0364      *          this,SLOT(slotPrepareTurn(QDataStream &,bool,KGameIO *,bool *)));
0365      *  connect(input,SIGNAL(signalProcessQuery(QDataStream &,KGameProcessIO *)),
0366      *          this,SLOT(slotProcessQuery(QDataStream &,KGameProcessIO *)));
0367      * \endcode
0368      *
0369      * @param name the filename of the process to start
0370      */
0371     explicit KGameProcessIO(const QString &name);
0372 
0373     /**
0374      * Deletes the process input devices
0375      */
0376     ~KGameProcessIO() override;
0377 
0378     /**
0379      * The identification of the IO
0380      *
0381      * @return ProcessIO
0382      */
0383     int rtti() const override;
0384 
0385     /**
0386      * Send a message to the process. This is analogous to the sendMessage
0387      * commands of KGame. It will result in a signal of the computer player
0388      * on which you can react in the process player.
0389      *
0390      * @param stream  - the actual data
0391      * @param msgid - the id of the message
0392      * @param receiver - not used
0393      * @param sender - who send the message
0394      */
0395     void sendMessage(QDataStream &stream, int msgid, quint32 receiver, quint32 sender);
0396 
0397     /**
0398      * Send a system message to the process. This is analogous to the sendMessage
0399      * commands of KGame. It will result in a signal of the computer player
0400      * on which you can react in the process player.
0401      *
0402      * @param stream  - the actual data
0403      * @param msgid - the id of the message
0404      * @param receiver - not used
0405      * @param sender - who send the message
0406      */
0407     void sendSystemMessage(QDataStream &stream, int msgid, quint32 receiver, quint32 sender);
0408 
0409     /**
0410      * Init this device by setting the player and e.g. sending an
0411      * init message to the device. Calling this function will emit
0412      * the IOAdded signal on which you can react and initilise the
0413      * computer player.
0414      * This function is called automatically when adding the IO to
0415      * a player.
0416      */
0417     void initIO(KPlayer *p) override;
0418 
0419     /**
0420      *  Notifies the IO device that the player's setTurn had been called
0421      *  Called by KPlayer. You can react on the @ref signalPrepareTurn to
0422      *  prepare a message for the process, i.e. either update it on
0423      * the changes made to the game since the last turn or the initIO
0424      * has been called or transmit your gamestatus now.
0425      *
0426      *  @param turn is true/false
0427      */
0428     void notifyTurn(bool turn) override;
0429 
0430 protected:
0431     /**
0432      * Internal combined function for all message handling
0433      */
0434     void sendAllMessages(QDataStream &stream, int msgid, quint32 receiver, quint32 sender, bool usermsg);
0435 
0436 protected Q_SLOTS:
0437     /**
0438      * Internal message handler to receive data from the process
0439      */
0440     void receivedMessage(const QByteArray &receiveBuffer);
0441 
0442 Q_SIGNALS:
0443     /**
0444      * A computer query message is received. This is a 'dummy'
0445      * message sent by the process if it needs to communicate
0446      * with us. It is not forwarded over the network.
0447      * Reacting to this message allows you to 'answer' questions
0448      * of the process, e.g. sending addition data which the process
0449      * needs to calculate a move.
0450      *
0451      * Example:
0452      * \code
0453      *  void GameWindow::slotProcessQuery(QDataStream &stream,KGameProcessIO *reply)
0454      *  {
0455      *    int no;
0456      *    stream >> no;  // We assume the process sends us an integer question number
0457      *    if (no==1)     // but YOU have to do this in the process player
0458      *    {
0459      *      QByteArray buffer;
0460      *      QDataStream out(buffer,QIODevice::WriteOnly);
0461      *      reply->sendSystemMessage(out,4242,0,0);  // lets reply something...
0462      *    }
0463      *  }
0464      * \endcode
0465      */
0466     void signalProcessQuery(QDataStream &stream, KGameProcessIO *me);
0467 
0468     /**
0469      * Signal generated when the computer player is added.
0470      * You can use this to communicated with the process and
0471      * e.g. send initialisation information to the process.
0472      *
0473      * @param game the KGameIO object itself
0474      * @param stream the stream into which the move will be written
0475      * @param p the player itself
0476      * @param send set this to false if no move should be generated
0477      */
0478     void signalIOAdded(KGameIO *game, QDataStream &stream, KPlayer *p, bool *send);
0479 
0480     /** Text is received by the process on STDERR. This is usually a debug string.
0481      * @param msg The text
0482      */
0483     void signalReceivedStderr(const QString &msg);
0484 
0485 private:
0486     Q_DECLARE_PRIVATE_D(KGameIO::d, KGameProcessIO)
0487     friend class KGameProcessIOPrivate;
0488 
0489     Q_DISABLE_COPY(KGameProcessIO)
0490 };
0491 
0492 /**
0493  *  \class KGameComputerIO kgameio.h <KGame/KGameIO>
0494  *
0495  *  \brief KGameIO variant for real-time games
0496  *
0497  *  The KGameComputerIO class. It is used to create a LOCAL computer player
0498  *  and communicate transparently with it.
0499  *  Question: Is this needed or is it overwritten anyway for a real game?
0500  *
0501  *  You most probably don't want to use this if you want to design a turn based
0502  *  game/player. You'll rather use @ref KGameIO directly, i.e. subclass it
0503  *  yourself. You just need to use @ref KGameIO::signalPrepareTurn and/or @ref
0504  *  KGameIO::notifyTurn there.
0505  *
0506  *  This is rather meant to be of use in real time games.
0507  *
0508  *  @author  <b_mann@gmx.de>
0509  */
0510 class KDEGAMESPRIVATE_EXPORT KGameComputerIO : public KGameIO
0511 {
0512     Q_OBJECT
0513 
0514 public:
0515     /**
0516      * Creates a LOCAL computer player
0517      *
0518      */
0519     KGameComputerIO();
0520     explicit KGameComputerIO(KPlayer *player);
0521     ~KGameComputerIO() override;
0522 
0523     int rtti() const override;
0524 
0525     /**
0526      * The number of advance calls until the player (or rather: the IO)
0527      * does something (default: 1).
0528      */
0529     void setReactionPeriod(int advanceCalls);
0530     int reactionPeriod() const;
0531 
0532     /**
0533      * Start a QTimer which calls advance every @p ms milli seconds.
0534      */
0535     void setAdvancePeriod(int ms);
0536 
0537     void stopAdvancePeriod();
0538 
0539     /**
0540      * Ignore calls number of advance calls. if calls is -1 then all
0541      * following advance calls are ignored until unpause is called.
0542      *
0543      * This simply prevents the internal advance counter to be increased.
0544      *
0545      * You may want to use this to emulate a "thinking" computer player. Note
0546      * that this means if you increase the advance period (see
0547      * setAdvancePeriod), i.e. if you change the speed of your game, your
0548      * computer player thinks "faster".
0549      * @param calls Number of advance calls to be ignored
0550      */
0551     void pause(int calls = -1);
0552 
0553     /**
0554      * Equivalent to pause(0). Immediately continue to increase the internal
0555      * advance counter.
0556      */
0557     void unpause();
0558 
0559 public Q_SLOTS:
0560     /**
0561      * Works kind of similar to QCanvas::advance. Increase the internal
0562      * advance counter. If @p reactionPeriod is reached the counter is set back to
0563      * 0 and @ref signalReaction is emitted. This is when the player is meant
0564      * to do something (move its units or so).
0565      *
0566      * This is very useful if you use QCanvas as you can use this in your
0567      * QCanvas::advance call. The advantage is that if you change the speed
0568      * of the game (i.e. change QCanvas::setAdvancePeriod) the computer
0569      * player gets slower as well.
0570      *
0571      * If you don't use QCanvas you can use setAdvancePeriod to get
0572      * the same result. Alternatively you can just use a QTimer.
0573      *
0574      */
0575     virtual void advance();
0576 
0577 Q_SIGNALS:
0578     /**
0579      * This signal is emitted when your computer player is meant to do
0580      * something, or better is meant to be allowed to do something.
0581      */
0582     void signalReaction();
0583 
0584 protected:
0585     /**
0586      * Default implementation simply emits signalReaction
0587      */
0588     virtual void reaction();
0589 
0590 private:
0591     Q_DECLARE_PRIVATE_D(KGameIO::d, KGameComputerIO)
0592     friend class KGameComputerIOPrivate;
0593 
0594     Q_DISABLE_COPY(KGameComputerIO)
0595 };
0596 
0597 #endif