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