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 <b_mann@gmx.de>
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
20class QEvent;
21class QGraphicsScene;
22class QKeyEvent;
23class QMouseEvent;
24class KPlayer;
25class KGame;
26class KGameIOPrivate;
27class KGameKeyIOPrivate;
28class KGameMouseIOPrivate;
29class KGameProcessIOPrivate;
30class 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 */
56class KDEGAMESPRIVATE_EXPORT KGameIO : public QObject
57{
58 Q_OBJECT
59
60public:
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
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
168protected:
169 explicit KGameIO(KGameIOPrivate &dd, KPlayer *player = nullptr);
170
171private:
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 */
191class KDEGAMESPRIVATE_EXPORT KGameKeyIO : public KGameIO
192{
193 Q_OBJECT
194
195public:
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
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
250protected:
251 /**
252 * Internal method to process the events
253 */
254 bool eventFilter(QObject *o, QEvent *e) override;
255
256private:
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 */
270class KDEGAMESPRIVATE_EXPORT KGameMouseIO : public KGameIO
271{
272 Q_OBJECT
273
274public:
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
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
329protected:
330 /**
331 * Internal event filter
332 */
333 bool eventFilter(QObject *o, QEvent *e) override;
334
335private:
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 */
351class KDEGAMESPRIVATE_EXPORT KGameProcessIO : public KGameIO
352{
353 Q_OBJECT
354
355public:
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
430protected:
431 /**
432 * Internal combined function for all message handling
433 */
434 void sendAllMessages(QDataStream &stream, int msgid, quint32 receiver, quint32 sender, bool usermsg);
435
436protected Q_SLOTS:
437 /**
438 * Internal message handler to receive data from the process
439 */
440 void receivedMessage(const QByteArray &receiveBuffer);
441
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 */
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 */
484
485private:
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 <b_mann@gmx.de>
509 */
510class KDEGAMESPRIVATE_EXPORT KGameComputerIO : public KGameIO
511{
512 Q_OBJECT
513
514public:
515 /**
516 * Creates a LOCAL computer player
517 *
518 */
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
559public 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
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 */
583
584protected:
585 /**
586 * Default implementation simply emits signalReaction
587 */
588 virtual void reaction();
589
590private:
592 friend class KGameComputerIOPrivate;
593
595};
596
597#endif
KGameIO variant for real-time games.
Definition kgameio.h:511
void signalReaction()
This signal is emitted when your computer player is meant to do something, or better is meant to be a...
Base class for IO devices for games.
Definition kgameio.h:57
void signalPrepareTurn(QDataStream &stream, bool turn, KGameIO *io, bool *send)
Signal generated when KPlayer::myTurn changes.
virtual int rtti() const =0
Run time identification.
IOMode
Identifies the KGameIO via the rtti function.
Definition kgameio.h:76
The KGameKeyIO class.
Definition kgameio.h:192
void signalKeyEvent(KGameIO *io, QDataStream &stream, QKeyEvent *m, bool *eatevent)
Signal handler for keyboard events.
The KGameMouseIO class.
Definition kgameio.h:271
void signalMouseEvent(KGameIO *io, QDataStream &stream, QMouseEvent *m, bool *eatevent)
Signal handler for mouse events.
The KGameProcessIO class.
Definition kgameio.h:352
void signalIOAdded(KGameIO *game, QDataStream &stream, KPlayer *p, bool *send)
Signal generated when the computer player is added.
void signalProcessQuery(QDataStream &stream, KGameProcessIO *me)
A computer query message is received.
void signalReceivedStderr(const QString &msg)
Text is received by the process on STDERR.
The main KDE game object.
Definition kgame.h:47
Base class for a game player.
Definition kplayer.h:60
Q_SCRIPTABLE Q_NOREPLY void pause()
Q_SIGNALSQ_SIGNALS
Q_SLOTSQ_SLOTS
virtual bool eventFilter(QObject *watched, QEvent *event)
T qobject_cast(QObject *object)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 17 2024 11:48:03 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.