KDEGames

kgameio.h
1 /*
2  This file is part of the KDE games library
3  SPDX-FileCopyrightText: 2001 Martin Heni <kde at heni-online.de>
4  SPDX-FileCopyrightText: 2001 Andreas Beckermann <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #ifndef __KGAMEIO_H__
10 #define __KGAMEIO_H__
11 
12 // own
13 #include "kdegamesprivate_export.h"
14 // Qt
15 #include <QObject>
16 #include <QString>
17 // Std
18 #include <memory>
19 
20 class QEvent;
21 class QGraphicsScene;
22 class QKeyEvent;
23 class QMouseEvent;
24 class KPlayer;
25 class KGame;
26 class KGameIOPrivate;
27 class KGameKeyIOPrivate;
28 class KGameMouseIOPrivate;
29 class KGameProcessIOPrivate;
30 class KGameComputerIOPrivate;
31 
32 /**
33  * \class KGameIO kgameio.h <KGame/KGameIO>
34  *
35  * \short Base class for IO devices for games
36  *
37  * This is the master class for
38  * creating IO game devices. You cannot use it directly.
39  * Either take one of the classes derived from it or
40  * you have to create your own IO class derived from it (more probably).
41  *
42  * The idea behind this class is to provide a common interface
43  * for input devices into your game. By programming a KGameIO
44  * device you need not distinguish the actual IO in the game
45  * anymore. All work is done by the IO's. This allows very
46  * easy reuse in other games as well.
47  * A further advantage of using the IO's is that you can exchange
48  * the control of a player at runtime. E.g. you switch a player
49  * to be controlled by the computer or vice versa.
50  *
51  * To achieve this you have to make all of your player inputs through a
52  * KGameIO. You will usually call KGameIO::sendInput to do so.
53  *
54  * @author Martin Heni <kde at heni-online.de>
55  */
56 class KDEGAMESPRIVATE_EXPORT KGameIO : public QObject
57 {
58  Q_OBJECT
59 
60 public:
61  /**
62  * Constructs a KGameIO object
63  */
64  KGameIO();
65  explicit KGameIO(KPlayer *);
66  ~KGameIO() override;
67 
68  /**
69  * Gives debug output of the game status
70  */
71  void Debug();
72 
73  /**
74  * Identifies the KGameIO via the rtti function
75  */
76  enum IOMode { GenericIO = 1, KeyIO = 2, MouseIO = 4, ProcessIO = 8, ComputerIO = 16 };
77  /**
78  * Run time identification. Predefined values are from IOMode
79  * You MUST overwrite this in derived classes!
80  *
81  * @return rtti value
82  */
83  virtual int rtti() const = 0; // Computer, network, local, ...
84 
85  /**
86  * This function returns the player who owns this IO
87  *
88  * @return the player this IO device is plugged into
89  */
90  KPlayer *player() const;
91 
92  /**
93  * Equivalent to player()->game()
94  * @return the @ref KGame object of this player
95  */
96  KGame *game() const;
97 
98  /**
99  * Sets the player to which this IO belongs to. This
100  * is done automatically when adding a device to a
101  * player
102  *
103  * @param p the player
104  */
105  void setPlayer(KPlayer *p);
106 
107  /**
108  * Init this device by setting the player and e.g. sending an
109  * init message to the device. This initialisation message is
110  * very useful for computer players as you can transmit the
111  * game status to them and only update this status in the setTurn
112  * commands.
113  *
114  * Called by @ref KPlayer::addGameIO only!
115  */
116  virtual void initIO(KPlayer *p);
117 
118  /**
119  * Notifies the IO device that the player's setTurn had been called
120  * Called by KPlayer
121  *
122  * This emits @ref signalPrepareTurn and sends the turn if the send
123  * parameter is set to true.
124  *
125  * @param b turn is true/false
126  */
127  virtual void notifyTurn(bool b);
128 
129  /**
130  * Send an input message using @ref KPlayer::forwardInput
131  */
132  bool sendInput(QDataStream &stream, bool transmit = true, quint32 sender = 0);
133 
134 Q_SIGNALS:
135  /**
136  * Signal generated when @ref KPlayer::myTurn changes. This can either be
137  * when you get the turn status or when you lose it.
138  *
139  * The datastream has to be filled with a move. If you set (or leave) the
140  * send parameter to FALSE then nothing happens: the datastream will be
141  * ignored. If you set it to TRUE @ref sendInput is used to
142  * send the move.
143  *
144  * Often you want to ignore this signal (leave send=FALSE) and send the
145  * message later. This is usually the case for a human player as he probably
146  * doesn't react immediately. But you can still use this e.g. to notify the
147  * player about the turn change.
148  *
149  * Example:
150  * \code
151  * void GameWindow::slotPrepareTurn(QDataStream &stream,bool b,KGameIO *input,bool * )
152  * {
153  * KPlayer *player=input->player();
154  * if (!player->myTurn()) return ;
155  * if (!b) return ; // only do something on setTurn(true)
156  * stream << 1 << 2 << 3; // Some data for the process
157  * }
158  * \endcode
159  *
160  * @param io the KGameIO object itself
161  * @param stream the stream into which the move will be written
162  * @param turn the argument of setTurn
163  * @param send set this to true to send the generated move using @ref
164  * sendInput
165  */
166  void signalPrepareTurn(QDataStream &stream, bool turn, KGameIO *io, bool *send);
167 
168 protected:
169  explicit KGameIO(KGameIOPrivate &dd, KPlayer *player = nullptr);
170 
171 private:
172  Q_DECLARE_PRIVATE_D(d, KGameIO)
173  friend class KGameIOPrivate;
174  friend class KGameKeyIO;
175  friend class KGameMouseIO;
176  friend class KGameProcessIO;
177  friend class KGameComputerIO;
178  std::unique_ptr<KGameIOPrivate> const d;
179  // KF6 TODO: change private d to protected d_ptr, use normal Q_DECLARE_PRIVATE, remove subclass friends
180 
182 };
183 
184 /**
185  * \class KGameKeyIO kgameio.h <KGame/KGameIO>
186  *
187  * The KGameKeyIO class. It is used to process keyboard input
188  * from a widget and create moves for the player it belongs to.
189  * @author Martin Heni <kde at heni-online.de>
190  */
191 class KDEGAMESPRIVATE_EXPORT KGameKeyIO : public KGameIO
192 {
193  Q_OBJECT
194 
195 public:
196  /**
197  * Create a keyboard input devices. All keyboards
198  * inputs of the given widgets are passed through a signal
199  * handler signalKeyEvent and can be used to generate
200  * a valid move for the player.
201  * Note the widget you pass to the constructor must be
202  * the main window of your application, e.g. view->parentWidget()
203  * as QT does not forward your keyevents otherwise. This means
204  * that this might be a different widget compared to the one you
205  * use for mouse inputs!
206  * Example:
207  * \code
208  * KGameKeyIO *input;
209  * input=new KGameKeyIO(myWidget);
210  * connect(input,SIGNAL(signalKeyEvent(KGameIO *,QDataStream &,QKeyEvent *,bool *)),
211  * this,SLOT(slotKeyInput(KGameIO *,QDataStream &,QKeyEvent *,bool *)));
212  * \endcode
213  *
214  * @param parent The parents widget whose keyboard events * should be grabbed
215  */
216  explicit KGameKeyIO(QWidget *parent);
217  ~KGameKeyIO() override;
218 
219  /**
220  * The identification of the IO
221  *
222  * @return KeyIO
223  */
224  int rtti() const override;
225 
226 Q_SIGNALS:
227  /**
228  * Signal handler for keyboard events. This function is called
229  * on every keyboard event. If appropriate it can generate a
230  * move for the player the device belongs to. If this is done
231  * and the event is eaten eatevent needs to be set to true.
232  * What move you generate (i.e. what you write to the stream)
233  * is totally up to you as it will not be evaluated but forwarded
234  * to the player's/game's input move function
235  * Example:
236  * \code
237  * KPlayer *player=input->player(); // Get the player
238  * qint32 key=e->key();
239  * stream << key;
240  * eatevent=true;
241  * \endcode
242  *
243  * @param io the IO device we belong to
244  * @param stream the stream where we write our move into
245  * @param m The QKeyEvent we can evaluate
246  * @param eatevent set this to true if we processed the event
247  */
248  void signalKeyEvent(KGameIO *io, QDataStream &stream, QKeyEvent *m, bool *eatevent);
249 
250 protected:
251  /**
252  * Internal method to process the events
253  */
254  bool eventFilter(QObject *o, QEvent *e) override;
255 
256 private:
257  Q_DECLARE_PRIVATE_D(KGameIO::d, KGameKeyIO)
258  friend class KGameKeyIOPrivate;
259 
261 };
262 
263 /**
264  * \class KGameMouseIO kgameio.h <KGame/KGameIO>
265  *
266  * The KGameMouseIO class. It is used to process mouse input
267  * from a widget and create moves for the player it belongs to.
268  * @author Martin Heni <kde at heni-online.de>
269  */
270 class KDEGAMESPRIVATE_EXPORT KGameMouseIO : public KGameIO
271 {
272  Q_OBJECT
273 
274 public:
275  /**
276  * Creates a mouse IO device. It captures all mouse
277  * event of the given widget and forwards them to the
278  * signal handler signalMouseEvent.
279  * Example:
280  * \code
281  * KGameMouseIO *input;
282  * input=new KGameMouseIO(mView);
283  * connect(input,SIGNAL(signalMouseEvent(KGameIO *,QDataStream &,QMouseEvent *,bool *)),
284  * this,SLOT(slotMouseInput(KGameIO *,QDataStream &,QMouseEvent *,bool *)));
285  * \endcode
286  *
287  * @param parent The widget whose events should be captured
288  * @param trackmouse enables mouse tracking (gives mouse move events)
289  */
290  explicit KGameMouseIO(QWidget *parent, bool trackmouse = false);
291  explicit KGameMouseIO(QGraphicsScene *parent, bool trackmouse = false);
292  ~KGameMouseIO() override;
293 
294  /**
295  * Manually activate or deactivate mouse tracking
296  *
297  * @param b true = tracking on
298  */
299  void setMouseTracking(bool b);
300  /**
301  * The identification of the IO
302  *
303  * @return MouseIO
304  */
305  int rtti() const override;
306 
307 Q_SIGNALS:
308  /**
309  * Signal handler for mouse events. This function is called
310  * on every mouse event. If appropriate it can generate a
311  * move for the player the device belongs to. If this is done
312  * and the event is eaten eatevent needs to be set to true.
313  * @see signalKeyEvent
314  * Example:
315  * \code
316  * KPlayer *player=input->player(); // Get the player
317  * qint32 button=e->button();
318  * stream << button;
319  * eatevent=true;
320  * \endcode
321  *
322  * @param io the IO device we belong to
323  * @param stream the stream where we write our move into
324  * @param m The QMouseEvent we can evaluate
325  * @param eatevent set this to true if we processed the event
326  */
327  void signalMouseEvent(KGameIO *io, QDataStream &stream, QMouseEvent *m, bool *eatevent);
328 
329 protected:
330  /**
331  * Internal event filter
332  */
333  bool eventFilter(QObject *o, QEvent *e) override;
334 
335 private:
336  Q_DECLARE_PRIVATE_D(KGameIO::d, KGameMouseIO)
337  friend class KGameMouseIOPrivate;
338 
340 };
341 
342 /**
343  * \class KGameProcessIO kgameio.h <KGame/KGameIO>
344  *
345  * The KGameProcessIO class. It is used to create a computer player
346  * via a separate process and communicate transparently with it.
347  * Its counterpart is the KGameProcess class which needs
348  * to be used by the computer player. See its documentation
349  * for the definition of the computer player.
350  */
351 class KDEGAMESPRIVATE_EXPORT KGameProcessIO : public KGameIO
352 {
353  Q_OBJECT
354 
355 public:
356  /**
357  * Creates a computer player via a separate process. The process
358  * name is given as fully qualified filename.
359  * Example:
360  * \code
361  * KGameProcessIO *input;
362  * input=new KGameProcessIO(executable_file);
363  * connect(input,SIGNAL(signalPrepareTurn(QDataStream &,bool,KGameIO *,bool *)),
364  * this,SLOT(slotPrepareTurn(QDataStream &,bool,KGameIO *,bool *)));
365  * connect(input,SIGNAL(signalProcessQuery(QDataStream &,KGameProcessIO *)),
366  * this,SLOT(slotProcessQuery(QDataStream &,KGameProcessIO *)));
367  * \endcode
368  *
369  * @param name the filename of the process to start
370  */
371  explicit KGameProcessIO(const QString &name);
372 
373  /**
374  * Deletes the process input devices
375  */
376  ~KGameProcessIO() override;
377 
378  /**
379  * The identification of the IO
380  *
381  * @return ProcessIO
382  */
383  int rtti() const override;
384 
385  /**
386  * Send a message to the process. This is analogous to the sendMessage
387  * commands of KGame. It will result in a signal of the computer player
388  * on which you can react in the process player.
389  *
390  * @param stream - the actual data
391  * @param msgid - the id of the message
392  * @param receiver - not used
393  * @param sender - who send the message
394  */
395  void sendMessage(QDataStream &stream, int msgid, quint32 receiver, quint32 sender);
396 
397  /**
398  * Send a system message to the process. This is analogous to the sendMessage
399  * commands of KGame. It will result in a signal of the computer player
400  * on which you can react in the process player.
401  *
402  * @param stream - the actual data
403  * @param msgid - the id of the message
404  * @param receiver - not used
405  * @param sender - who send the message
406  */
407  void sendSystemMessage(QDataStream &stream, int msgid, quint32 receiver, quint32 sender);
408 
409  /**
410  * Init this device by setting the player and e.g. sending an
411  * init message to the device. Calling this function will emit
412  * the IOAdded signal on which you can react and initilise the
413  * computer player.
414  * This function is called automatically when adding the IO to
415  * a player.
416  */
417  void initIO(KPlayer *p) override;
418 
419  /**
420  * Notifies the IO device that the player's setTurn had been called
421  * Called by KPlayer. You can react on the @ref signalPrepareTurn to
422  * prepare a message for the process, i.e. either update it on
423  * the changes made to the game since the last turn or the initIO
424  * has been called or transmit your gamestatus now.
425  *
426  * @param turn is true/false
427  */
428  void notifyTurn(bool turn) override;
429 
430 protected:
431  /**
432  * Internal combined function for all message handling
433  */
434  void sendAllMessages(QDataStream &stream, int msgid, quint32 receiver, quint32 sender, bool usermsg);
435 
436 protected Q_SLOTS:
437  /**
438  * Internal message handler to receive data from the process
439  */
440  void receivedMessage(const QByteArray &receiveBuffer);
441 
442 Q_SIGNALS:
443  /**
444  * A computer query message is received. This is a 'dummy'
445  * message sent by the process if it needs to communicate
446  * with us. It is not forwarded over the network.
447  * Reacting to this message allows you to 'answer' questions
448  * of the process, e.g. sending addition data which the process
449  * needs to calculate a move.
450  *
451  * Example:
452  * \code
453  * void GameWindow::slotProcessQuery(QDataStream &stream,KGameProcessIO *reply)
454  * {
455  * int no;
456  * stream >> no; // We assume the process sends us an integer question number
457  * if (no==1) // but YOU have to do this in the process player
458  * {
459  * QByteArray buffer;
460  * QDataStream out(buffer,QIODevice::WriteOnly);
461  * reply->sendSystemMessage(out,4242,0,0); // lets reply something...
462  * }
463  * }
464  * \endcode
465  */
466  void signalProcessQuery(QDataStream &stream, KGameProcessIO *me);
467 
468  /**
469  * Signal generated when the computer player is added.
470  * You can use this to communicated with the process and
471  * e.g. send initialisation information to the process.
472  *
473  * @param game the KGameIO object itself
474  * @param stream the stream into which the move will be written
475  * @param p the player itself
476  * @param send set this to false if no move should be generated
477  */
478  void signalIOAdded(KGameIO *game, QDataStream &stream, KPlayer *p, bool *send);
479 
480  /** Text is received by the process on STDERR. This is usually a debug string.
481  * @param msg The text
482  */
483  void signalReceivedStderr(const QString &msg);
484 
485 private:
486  Q_DECLARE_PRIVATE_D(KGameIO::d, KGameProcessIO)
487  friend class KGameProcessIOPrivate;
488 
490 };
491 
492 /**
493  * \class KGameComputerIO kgameio.h <KGame/KGameIO>
494  *
495  * \brief KGameIO variant for real-time games
496  *
497  * The KGameComputerIO class. It is used to create a LOCAL computer player
498  * and communicate transparently with it.
499  * Question: Is this needed or is it overwritten anyway for a real game?
500  *
501  * You most probably don't want to use this if you want to design a turn based
502  * game/player. You'll rather use @ref KGameIO directly, i.e. subclass it
503  * yourself. You just need to use @ref KGameIO::signalPrepareTurn and/or @ref
504  * KGameIO::notifyTurn there.
505  *
506  * This is rather meant to be of use in real time games.
507  *
508  * @author <[email protected]>
509  */
510 class KDEGAMESPRIVATE_EXPORT KGameComputerIO : public KGameIO
511 {
512  Q_OBJECT
513 
514 public:
515  /**
516  * Creates a LOCAL computer player
517  *
518  */
519  KGameComputerIO();
520  explicit KGameComputerIO(KPlayer *player);
521  ~KGameComputerIO() override;
522 
523  int rtti() const override;
524 
525  /**
526  * The number of advance calls until the player (or rather: the IO)
527  * does something (default: 1).
528  */
529  void setReactionPeriod(int advanceCalls);
530  int reactionPeriod() const;
531 
532  /**
533  * Start a QTimer which calls advance every @p ms milli seconds.
534  */
535  void setAdvancePeriod(int ms);
536 
537  void stopAdvancePeriod();
538 
539  /**
540  * Ignore calls number of advance calls. if calls is -1 then all
541  * following advance calls are ignored until unpause is called.
542  *
543  * This simply prevents the internal advance counter to be increased.
544  *
545  * You may want to use this to emulate a "thinking" computer player. Note
546  * that this means if you increase the advance period (see
547  * setAdvancePeriod), i.e. if you change the speed of your game, your
548  * computer player thinks "faster".
549  * @param calls Number of advance calls to be ignored
550  */
551  void pause(int calls = -1);
552 
553  /**
554  * Equivalent to pause(0). Immediately continue to increase the internal
555  * advance counter.
556  */
557  void unpause();
558 
559 public Q_SLOTS:
560  /**
561  * Works kind of similar to QCanvas::advance. Increase the internal
562  * advance counter. If @p reactionPeriod is reached the counter is set back to
563  * 0 and @ref signalReaction is emitted. This is when the player is meant
564  * to do something (move its units or so).
565  *
566  * This is very useful if you use QCanvas as you can use this in your
567  * QCanvas::advance call. The advantage is that if you change the speed
568  * of the game (i.e. change QCanvas::setAdvancePeriod) the computer
569  * player gets slower as well.
570  *
571  * If you don't use QCanvas you can use setAdvancePeriod to get
572  * the same result. Alternatively you can just use a QTimer.
573  *
574  */
575  virtual void advance();
576 
577 Q_SIGNALS:
578  /**
579  * This signal is emitted when your computer player is meant to do
580  * something, or better is meant to be allowed to do something.
581  */
582  void signalReaction();
583 
584 protected:
585  /**
586  * Default implementation simply emits signalReaction
587  */
588  virtual void reaction();
589 
590 private:
591  Q_DECLARE_PRIVATE_D(KGameIO::d, KGameComputerIO)
592  friend class KGameComputerIOPrivate;
593 
595 };
596 
597 #endif
virtual void initIO(KPlayer *p)
Init this device by setting the player and e.g.
Definition: kgameio.cpp:77
virtual void notifyTurn(bool b)
Notifies the IO device that the player's setTurn had been called Called by KPlayer.
Definition: kgameio.cpp:82
Q_SLOTSQ_SLOTS
Base class for IO devices for games.
Definition: kgameio.h:56
IOMode
Identifies the KGameIO via the rtti function.
Definition: kgameio.h:76
The main KDE game object.
Definition: kgame.h:46
Base class for a game player.
Definition: kplayer.h:59
virtual bool eventFilter(QObject *watched, QEvent *event)
Q_SCRIPTABLE Q_NOREPLY void pause()
Q_SIGNALSQ_SIGNALS
virtual int rtti() const =0
Run time identification.
KGameIO variant for real-time games.
Definition: kgameio.h:510
Q_DISABLE_COPY(Class)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Dec 5 2023 03:50:32 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.