KDEGames

kgameio.cpp
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 #include "kgameio.h"
10 
11 // own
12 #include "kgame.h"
13 #include "kgamemessage.h"
14 #include "kmessageio.h"
15 #include "kplayer.h"
16 // Qt
17 #include <QBuffer>
18 #include <QEvent>
19 #include <QGraphicsScene>
20 #include <QKeyEvent>
21 #include <QMouseEvent>
22 #include <QTimer>
23 #include <QWidget>
24 // Std
25 #include <cstdlib>
26 
27 class KGameIOPrivate
28 {
29 public:
30  KGameIOPrivate()
31  : mPlayer(nullptr)
32  {
33  }
34 
35  KPlayer *mPlayer;
36 };
37 
38 // ----------------------- Generic IO -------------------------
40  : KGameIO(*new KGameIOPrivate)
41 {
42 }
43 
45  : KGameIO(*new KGameIOPrivate, player)
46 {
47 }
48 
49 KGameIO::KGameIO(KGameIOPrivate &dd, KPlayer *player)
50  : d(&dd)
51 {
52  qCDebug(GAMES_PRIVATE_KGAME) << ": this=" << this << ", sizeof(this)" << sizeof(KGameIO);
53  if (player) {
54  player->addGameIO(this);
55  }
56 }
57 
58 KGameIO::~KGameIO()
59 {
60  qCDebug(GAMES_PRIVATE_KGAME) << ": this=" << this;
61  // unregister ourselves
62  if (player()) {
63  player()->removeGameIO(this, false);
64  }
65 }
66 
68 {
69  return d->mPlayer;
70 }
71 
73 {
74  d->mPlayer = p;
75 }
76 
78 {
79  setPlayer(p);
80 }
81 
82 void KGameIO::notifyTurn(bool b)
83 {
84  if (!player()) {
85  qCWarning(GAMES_PRIVATE_KGAME) << ": player() is NULL";
86  return;
87  }
88  bool sendit = false;
89  QByteArray buffer;
90  QDataStream stream(&buffer, QIODevice::WriteOnly);
91  Q_EMIT signalPrepareTurn(stream, b, this, &sendit);
92  if (sendit) {
93  QDataStream ostream(buffer);
94  quint32 sender = player()->id(); // force correct sender
95  qCDebug(GAMES_PRIVATE_KGAME) << "Prepare turn sendInput";
96  sendInput(ostream, true, sender);
97  }
98 }
99 
101 {
102  if (!player()) {
103  return nullptr;
104  }
105  return player()->game();
106 }
107 
108 bool KGameIO::sendInput(QDataStream &s, bool transmit, quint32 sender)
109 {
110  if (!player()) {
111  return false;
112  }
113  return player()->forwardInput(s, transmit, sender);
114 }
115 
117 {
118  qCDebug(GAMES_PRIVATE_KGAME) << "------------------- KGAMEINPUT --------------------";
119  qCDebug(GAMES_PRIVATE_KGAME) << "this: " << this;
120  qCDebug(GAMES_PRIVATE_KGAME) << "rtti : " << rtti();
121  qCDebug(GAMES_PRIVATE_KGAME) << "Player: " << player();
122  qCDebug(GAMES_PRIVATE_KGAME) << "---------------------------------------------------";
123 }
124 
125 // ----------------------- Key IO ---------------------------
126 class KGameKeyIOPrivate : public KGameIOPrivate
127 {
128 };
129 
131  : KGameIO(*new KGameKeyIOPrivate)
132 {
133  if (parent) {
134  qCDebug(GAMES_PRIVATE_KGAME) << "Key Event filter installed";
135  parent->installEventFilter(this);
136  }
137 }
138 
139 KGameKeyIO::~KGameKeyIO()
140 {
141  if (parent()) {
142  parent()->removeEventFilter(this);
143  }
144 }
145 
146 int KGameKeyIO::rtti() const
147 {
148  return KeyIO;
149 }
150 
152 {
153  if (!player()) {
154  return false;
155  }
156 
157  // key press/release
158  if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) {
159  QKeyEvent *k = (QKeyEvent *)e;
160  // qCDebug(GAMES_PRIVATE_KGAME) << "KGameKeyIO" << this << "key press/release" << k->key();
161  QByteArray buffer;
162  QDataStream stream(&buffer, QIODevice::WriteOnly);
163  bool eatevent = false;
164  Q_EMIT signalKeyEvent(this, stream, k, &eatevent);
165  QDataStream msg(buffer);
166 
167  if (eatevent && sendInput(msg)) {
168  return eatevent;
169  }
170  return false; // do not eat otherwise
171  }
172  return QObject::eventFilter(o, e); // standard event processing
173 }
174 
175 // ----------------------- Mouse IO ---------------------------
176 class KGameMouseIOPrivate : public KGameIOPrivate
177 {
178 };
179 
180 KGameMouseIO::KGameMouseIO(QWidget *parent, bool trackmouse)
181  : KGameIO(*new KGameMouseIOPrivate)
182 {
183  if (parent) {
184  qCDebug(GAMES_PRIVATE_KGAME) << "Mouse Event filter installed tracking=" << trackmouse;
185  parent->installEventFilter(this);
186  parent->setMouseTracking(trackmouse);
187  }
188 }
189 
190 KGameMouseIO::KGameMouseIO(QGraphicsScene *parent, bool /*trackmouse*/)
191  : KGameIO(*new KGameMouseIOPrivate)
192 {
193  if (parent) {
194  // qCDebug(GAMES_PRIVATE_KGAME) << "Mouse Event filter installed tracking=" << trackmouse;
195  parent->installEventFilter(this);
196  // parent->setMouseTracking(trackmouse);
197  }
198 }
199 
200 KGameMouseIO::~KGameMouseIO()
201 {
202  if (parent()) {
203  parent()->removeEventFilter(this);
204  }
205 }
206 
208 {
209  return MouseIO;
210 }
211 
213 {
214  if (parent()) {
215  ((QWidget *)parent())->setMouseTracking(b);
216  }
217 }
218 
220 {
221  if (!player()) {
222  return false;
223  }
224  // qCDebug(GAMES_PRIVATE_KGAME) << "KGameMouseIO" << this << QLatin1String( " " ) << e->type();
225 
226  // mouse action
231  QMouseEvent *k = (QMouseEvent *)e;
232  // qCDebug(GAMES_PRIVATE_KGAME) << "KGameMouseIO" << this;
233  QByteArray buffer;
234  QDataStream stream(&buffer, QIODevice::WriteOnly);
235  bool eatevent = false;
236  Q_EMIT signalMouseEvent(this, stream, k, &eatevent);
237  // qCDebug(GAMES_PRIVATE_KGAME) << "################# eatevent=" << eatevent;
238  QDataStream msg(buffer);
239  if (eatevent && sendInput(msg)) {
240  return eatevent;
241  }
242  return false; // do not eat otherwise
243  }
244  return QObject::eventFilter(o, e); // standard event processing
245 }
246 
247 // ----------------------- KGameProcesPrivate ---------------------------
248 class KGameProcessIOPrivate : public KGameIOPrivate
249 {
250 public:
251  KGameProcessIOPrivate()
252  {
253  // mMessageServer = 0;
254  // mMessageClient = 0;
255  mProcessIO = nullptr;
256  }
257  // KMessageServer *mMessageServer;
258  // KMessageClient *mMessageClient;
259  KMessageProcess *mProcessIO;
260 };
261 
262 // ----------------------- Process IO ---------------------------
264  : KGameIO(*new KGameProcessIOPrivate)
265 {
267 
268  qCDebug(GAMES_PRIVATE_KGAME) << ": this=" << this << ", sizeof(this)=" << sizeof(KGameProcessIO);
269 
270  // qCDebug(GAMES_PRIVATE_KGAME) << "================= KMEssageServer ====================";
271  // d->mMessageServer=new KMessageServer(0,this);
272  // qCDebug(GAMES_PRIVATE_KGAME) << "================= KMEssageClient ====================";
273  // d->mMessageClient=new KMessageClient(this);
274  qCDebug(GAMES_PRIVATE_KGAME) << "================= KMEssageProcessIO ====================";
275  d->mProcessIO = new KMessageProcess(this, name);
276  qCDebug(GAMES_PRIVATE_KGAME) << "================= KMEssage Add client ====================";
277  // d->mMessageServer->addClient(d->mProcessIO);
278  // qCDebug(GAMES_PRIVATE_KGAME) << "================= KMEssage SetSErver ====================";
279  // d->mMessageClient->setServer(d->mMessageServer);
280  qCDebug(GAMES_PRIVATE_KGAME) << "================= KMEssage: Connect ====================";
281  // connect(d->mMessageClient, SIGNAL(broadcastReceived(QByteArray,quint32)),
282  // this, SLOT(clientMessage(QByteArray,quint32)));
283  // connect(d->mMessageClient, SIGNAL(forwardReceived(QByteArray,quint32,QValueList<quint32>)),
284  // this, SLOT(clientMessage(QByteArray,quint32,QValueList<quint32>)));
285  connect(d->mProcessIO, &KMessageProcess::received, this, &KGameProcessIO::receivedMessage);
286  // Relay signal
287  connect(d->mProcessIO, &KMessageProcess::signalReceivedStderr, this, &KGameProcessIO::signalReceivedStderr);
288  // qCDebug(GAMES_PRIVATE_KGAME) << "Our client is id="<<d->mMessageClient->id();
289 }
290 
292 {
294 
295  qCDebug(GAMES_PRIVATE_KGAME) << ": this=" << this;
296  qCDebug(GAMES_PRIVATE_KGAME) << "player=" << player();
297  if (player()) {
298  player()->removeGameIO(this, false);
299  }
300  if (d->mProcessIO) {
301  delete d->mProcessIO;
302  d->mProcessIO = nullptr;
303  }
304 }
305 
307 {
308  return ProcessIO;
309 }
310 
312 {
313  KGameIO::initIO(p);
314  // Send 'hello' to process
315  QByteArray buffer;
316  QDataStream stream(&buffer, QIODevice::WriteOnly);
317 
318  bool sendit = true;
319  if (p) {
320  qint16 id = p->userId();
321  stream << id;
322  Q_EMIT signalIOAdded(this, stream, p, &sendit);
323  if (sendit) {
324  quint32 sender = p->id();
325  qCDebug(GAMES_PRIVATE_KGAME) << "Sending IOAdded to process player !!!!!!!!!!!!!! ";
326  sendSystemMessage(stream, KGameMessage::IdIOAdded, 0, sender);
327  }
328  }
329 }
330 
332 {
333  if (!player()) {
334  qCWarning(GAMES_PRIVATE_KGAME) << ": player() is NULL";
335  return;
336  }
337  bool sendit = true;
338  QByteArray buffer;
339  QDataStream stream(&buffer, QIODevice::WriteOnly);
340  stream << (qint8)b;
341  Q_EMIT signalPrepareTurn(stream, b, this, &sendit);
342  if (sendit) {
343  quint32 sender = player()->id();
344  qCDebug(GAMES_PRIVATE_KGAME) << "Sending Turn to process player !!!!!!!!!!!!!! ";
345  sendSystemMessage(stream, KGameMessage::IdTurn, 0, sender);
346  }
347 }
348 
349 void KGameProcessIO::sendSystemMessage(QDataStream &stream, int msgid, quint32 receiver, quint32 sender)
350 {
351  sendAllMessages(stream, msgid, receiver, sender, false);
352 }
353 
354 void KGameProcessIO::sendMessage(QDataStream &stream, int msgid, quint32 receiver, quint32 sender)
355 {
356  sendAllMessages(stream, msgid, receiver, sender, true);
357 }
358 
359 void KGameProcessIO::sendAllMessages(QDataStream &stream, int msgid, quint32 receiver, quint32 sender, bool usermsg)
360 {
362 
363  qCDebug(GAMES_PRIVATE_KGAME) << "==============> KGameProcessIO::sendMessage (usermsg=" << usermsg << ")";
364  // if (!player()) return ;
365  // if (!player()->isActive()) return ;
366 
367  if (usermsg) {
368  msgid += KGameMessage::IdUser;
369  }
370 
371  qCDebug(GAMES_PRIVATE_KGAME) << "=============* ProcessIO (" << msgid << "," << receiver << "," << sender << ") ===========";
372 
373  QByteArray buffer;
374  QDataStream ostream(&buffer, QIODevice::WriteOnly);
375  QBuffer *device = (QBuffer *)stream.device();
376  QByteArray data = device->buffer();
377  ;
378 
379  KGameMessage::createHeader(ostream, sender, receiver, msgid);
380  // ostream.writeRawBytes(data.data()+device->at(),data.size()-device->at());
381  ostream.writeRawData(data.data(), data.size());
382  qCDebug(GAMES_PRIVATE_KGAME) << " Adding user data from pos=" << device->pos() << " amount=" << data.size() << "byte";
383  // if (d->mMessageClient) d->mMessageClient->sendBroadcast(buffer);
384  if (d->mProcessIO) {
385  d->mProcessIO->send(buffer);
386  }
387 }
388 
389 // void KGameProcessIO::clientMessage(const QByteArray& receiveBuffer, quint32 clientID, const QValueList <quint32> &recv)
390 void KGameProcessIO::receivedMessage(const QByteArray &receiveBuffer)
391 {
392  QDataStream stream(receiveBuffer);
393  int msgid;
394  quint32 sender;
395  quint32 receiver;
396  KGameMessage::extractHeader(stream, sender, receiver, msgid);
397 
398  qCDebug(GAMES_PRIVATE_KGAME) << "************* Got process message sender =" << sender << "receiver=" << receiver << " msgid=" << msgid;
399 
400  // Cut out the header part...to not confuse network code
401  QBuffer *buf = (QBuffer *)stream.device();
402  QByteArray newbuffer;
403  newbuffer = QByteArray::fromRawData(buf->buffer().data() + buf->pos(), buf->size() - buf->pos());
404  QDataStream ostream(newbuffer);
405  qCDebug(GAMES_PRIVATE_KGAME) << "Newbuffer size=" << newbuffer.size();
406 
407  // This is a dummy message which allows us the process to talk with its owner
408  if (msgid == KGameMessage::IdProcessQuery) {
409  Q_EMIT signalProcessQuery(ostream, this);
410  } else if (player()) {
411  sender = player()->id(); // force correct sender
412  if (msgid == KGameMessage::IdPlayerInput) {
413  sendInput(ostream, true, sender);
414  } else {
415  player()->forwardMessage(ostream, msgid, receiver, sender);
416  }
417  } else {
418  qCDebug(GAMES_PRIVATE_KGAME) << ": Got message from process but no player defined!";
419  }
420  newbuffer.clear();
421 }
422 
423 // ----------------------- Computer IO --------------------------
424 class KGameComputerIOPrivate : public KGameIOPrivate
425 {
426  // TODO: maybe these should be KGameProperties!!
427 public:
428  KGameComputerIOPrivate()
429  {
430  mAdvanceCounter = 0;
431  mReactionPeriod = 0;
432 
433  mPauseCounter = 0;
434 
435  mAdvanceTimer = nullptr;
436  }
437  int mAdvanceCounter;
438  int mReactionPeriod;
439 
440  int mPauseCounter;
441 
442  QTimer *mAdvanceTimer;
443 };
444 
446  : KGameIO(*new KGameComputerIOPrivate)
447 {
448 }
449 
451  : KGameIO(*new KGameComputerIOPrivate, p)
452 {
453 }
454 
455 KGameComputerIO::~KGameComputerIO()
456 {
458 
459  if (d->mAdvanceTimer) {
460  delete d->mAdvanceTimer;
461  }
462 }
463 
465 {
466  return ComputerIO;
467 }
468 
470 {
472 
473  d->mReactionPeriod = calls;
474 }
475 
476 int KGameComputerIO::reactionPeriod() const
477 {
478  Q_D(const KGameComputerIO);
479 
480  return d->mReactionPeriod;
481 }
482 
484 {
486 
487  stopAdvancePeriod();
488  d->mAdvanceTimer = new QTimer(this);
489  connect(d->mAdvanceTimer, &QTimer::timeout, this, &KGameComputerIO::advance);
490  d->mAdvanceTimer->start(ms);
491 }
492 
493 void KGameComputerIO::stopAdvancePeriod()
494 {
496 
497  if (d->mAdvanceTimer) {
498  d->mAdvanceTimer->stop();
499  delete d->mAdvanceTimer;
500  }
501 }
502 
503 void KGameComputerIO::pause(int calls)
504 {
506 
507  d->mPauseCounter = calls;
508 }
509 
511 {
512  pause(0);
513 }
514 
516 {
518 
519  if (d->mPauseCounter > 0) {
520  d->mPauseCounter--;
521  return;
522  } else if (d->mPauseCounter < 0) {
523  return;
524  }
525  d->mAdvanceCounter++;
526  if (d->mAdvanceCounter >= d->mReactionPeriod) {
527  d->mAdvanceCounter = 0;
528  reaction();
529  }
530 }
531 
533 {
535 }
536 
537 #include "moc_kgameio.cpp"
KGameIO()
Constructs a KGameIO object.
Definition: kgameio.cpp:39
void removeEventFilter(QObject *obj)
void signalKeyEvent(KGameIO *io, QDataStream &stream, QKeyEvent *m, bool *eatevent)
Signal handler for keyboard events.
QByteArray & buffer()
void signalReaction()
This signal is emitted when your computer player is meant to do something, or better is meant to be a...
virtual void initIO(KPlayer *p)
Init this device by setting the player and e.g.
Definition: kgameio.cpp:77
void initIO(KPlayer *p) override
Init this device by setting the player and e.g.
Definition: kgameio.cpp:311
virtual void notifyTurn(bool b)
Notifies the IO device that the player's setTurn had been called Called by KPlayer.
Definition: kgameio.cpp:82
void sendMessage(QDataStream &stream, int msgid, quint32 receiver, quint32 sender)
Send a message to the process.
Definition: kgameio.cpp:354
void signalReceivedStderr(const QString &msg)
Text is received by the process on STDERR.
void Debug()
Gives debug output of the game status.
Definition: kgameio.cpp:116
KGameComputerIO()
Creates a LOCAL computer player.
Definition: kgameio.cpp:445
bool eventFilter(QObject *o, QEvent *e) override
Internal method to process the events.
Definition: kgameio.cpp:151
QByteArray fromRawData(const char *data, int size)
virtual qint64 pos() const const override
Q_EMITQ_EMIT
void setAdvancePeriod(int ms)
Start a QTimer which calls advance every ms milli seconds.
Definition: kgameio.cpp:483
Base class for IO devices for games.
Definition: kgameio.h:56
int rtti() const override
The identification of the IO.
Definition: kgameio.cpp:146
QIODevice * device() const const
QObject * sender() const const
The main KDE game object.
Definition: kgame.h:55
void clear()
void setReactionPeriod(int advanceCalls)
The number of advance calls until the player (or rather: the IO) does something (default: 1).
Definition: kgameio.cpp:469
Base class for a game player.
Definition: kplayer.h:59
void signalProcessQuery(QDataStream &stream, KGameProcessIO *me)
A computer query message is received.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KGame * game() const
Query to which game the player belongs to.
Definition: kplayer.cpp:126
static void extractHeader(QDataStream &msg, quint32 &sender, quint32 &receiver, int &msgid)
Retrieves the information like cookie,sender,receiver,...
virtual bool eventFilter(QObject *watched, QEvent *event)
void notifyTurn(bool turn) override
Notifies the IO device that the player's setTurn had been called Called by KPlayer.
Definition: kgameio.cpp:331
KGameKeyIO(QWidget *parent)
Create a keyboard input devices.
Definition: kgameio.cpp:130
int rtti() const override
The identification of the IO.
Definition: kgameio.cpp:207
bool addGameIO(KGameIO *input)
Adds an IO device for the player.
Definition: kplayer.cpp:273
void pause(int calls=-1)
Ignore calls number of advance calls.
Definition: kgameio.cpp:503
quint32 id() const
Returns the id of the player.
Definition: kplayer.cpp:233
void setPlayer(KPlayer *p)
Sets the player to which this IO belongs to.
Definition: kgameio.cpp:72
bool sendInput(QDataStream &stream, bool transmit=true, quint32 sender=0)
Send an input message using KPlayer::forwardInput.
Definition: kgameio.cpp:108
void installEventFilter(QObject *filterObj)
void timeout()
void unpause()
Equivalent to pause(0).
Definition: kgameio.cpp:510
int writeRawData(const char *s, int len)
void setMouseTracking(bool b)
Manually activate or deactivate mouse tracking.
Definition: kgameio.cpp:212
int rtti() const override
Run time identification.
Definition: kgameio.cpp:464
void signalPrepareTurn(QDataStream &stream, bool turn, KGameIO *io, bool *send)
Signal generated when KPlayer::myTurn changes.
virtual qint64 size() const const override
int rtti() const override
The identification of the IO.
Definition: kgameio.cpp:306
bool removeGameIO(KGameIO *input=nullptr, bool deleteit=true)
remove (and delete) a game IO device
Definition: kplayer.cpp:284
KGameProcessIO(const QString &name)
Creates a computer player via a separate process.
Definition: kgameio.cpp:263
virtual int rtti() const =0
Run time identification.
virtual void advance()
Works kind of similar to QCanvas::advance.
Definition: kgameio.cpp:515
int userId() const
Returns the user defined id of the player This value can be used arbitrary by you to have some user i...
Definition: kplayer.cpp:151
void sendSystemMessage(QDataStream &stream, int msgid, quint32 receiver, quint32 sender)
Send a system message to the process.
Definition: kgameio.cpp:349
virtual bool forwardMessage(QDataStream &msg, int msgid, quint32 receiver=0, quint32 sender=0)
Forwards Message to the game object..internal use only.
Definition: kplayer.cpp:166
QEvent::Type type() const const
void receivedMessage(const QByteArray &receiveBuffer)
Internal message handler to receive data from the process.
Definition: kgameio.cpp:390
bool eventFilter(QObject *o, QEvent *e) override
Internal event filter.
Definition: kgameio.cpp:219
int size() const const
virtual void reaction()
Default implementation simply emits signalReaction.
Definition: kgameio.cpp:532
void signalIOAdded(KGameIO *game, QDataStream &stream, KPlayer *p, bool *send)
Signal generated when the computer player is added.
~KGameProcessIO() override
Deletes the process input devices.
Definition: kgameio.cpp:291
virtual bool forwardInput(QDataStream &msg, bool transmit=true, quint32 sender=0)
Forwards input to the game object..internal use only.
Definition: kplayer.cpp:179
static void createHeader(QDataStream &msg, quint32 sender, quint32 receiver, int msgid)
Creates a message header given cookie,sender,receiver,...
KGameMouseIO(QWidget *parent, bool trackmouse=false)
Creates a mouse IO device.
Definition: kgameio.cpp:180
KGameIO variant for real-time games.
Definition: kgameio.h:531
KGame * game() const
Equivalent to player()->game()
Definition: kgameio.cpp:100
void sendAllMessages(QDataStream &stream, int msgid, quint32 receiver, quint32 sender, bool usermsg)
Internal combined function for all message handling.
Definition: kgameio.cpp:359
QObject * parent() const const
Q_D(Todo)
char * data()
void signalMouseEvent(KGameIO *io, QDataStream &stream, QMouseEvent *m, bool *eatevent)
Signal handler for mouse events.
KPlayer * player() const
This function returns the player who owns this IO.
Definition: kgameio.cpp:67
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 04:08:12 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.