File indexing completed on 2024-06-16 03:57:55
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 #include "kgameio.h" 0010 0011 // own 0012 #include "kgame.h" 0013 #include "kgamemessage.h" 0014 #include "kmessageio.h" 0015 #include "kplayer.h" 0016 #include <kdegamesprivate_kgame_logging.h> 0017 // Qt 0018 #include <QBuffer> 0019 #include <QEvent> 0020 #include <QGraphicsScene> 0021 #include <QKeyEvent> 0022 #include <QMouseEvent> 0023 #include <QTimer> 0024 #include <QWidget> 0025 // Std 0026 #include <cstdlib> 0027 0028 class KGameIOPrivate 0029 { 0030 public: 0031 KGameIOPrivate() = default; 0032 virtual ~KGameIOPrivate() = default; 0033 0034 public: 0035 KPlayer *mPlayer = nullptr; 0036 }; 0037 0038 // ----------------------- Generic IO ------------------------- 0039 KGameIO::KGameIO() 0040 : KGameIO(*new KGameIOPrivate) 0041 { 0042 } 0043 0044 KGameIO::KGameIO(KPlayer *player) 0045 : KGameIO(*new KGameIOPrivate, player) 0046 { 0047 } 0048 0049 KGameIO::KGameIO(KGameIOPrivate &dd, KPlayer *player) 0050 : d(&dd) 0051 { 0052 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": this=" << this << ", sizeof(this)" << sizeof(KGameIO); 0053 if (player) { 0054 player->addGameIO(this); 0055 } 0056 } 0057 0058 KGameIO::~KGameIO() 0059 { 0060 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": this=" << this; 0061 // unregister ourselves 0062 if (player()) { 0063 player()->removeGameIO(this, false); 0064 } 0065 } 0066 0067 KPlayer *KGameIO::player() const 0068 { 0069 return d->mPlayer; 0070 } 0071 0072 void KGameIO::setPlayer(KPlayer *p) 0073 { 0074 d->mPlayer = p; 0075 } 0076 0077 void KGameIO::initIO(KPlayer *p) 0078 { 0079 setPlayer(p); 0080 } 0081 0082 void KGameIO::notifyTurn(bool b) 0083 { 0084 if (!player()) { 0085 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << ": player() is NULL"; 0086 return; 0087 } 0088 bool sendit = false; 0089 QByteArray buffer; 0090 QDataStream stream(&buffer, QIODevice::WriteOnly); 0091 Q_EMIT signalPrepareTurn(stream, b, this, &sendit); 0092 if (sendit) { 0093 QDataStream ostream(buffer); 0094 quint32 sender = player()->id(); // force correct sender 0095 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Prepare turn sendInput"; 0096 sendInput(ostream, true, sender); 0097 } 0098 } 0099 0100 KGame *KGameIO::game() const 0101 { 0102 if (!player()) { 0103 return nullptr; 0104 } 0105 return player()->game(); 0106 } 0107 0108 bool KGameIO::sendInput(QDataStream &s, bool transmit, quint32 sender) 0109 { 0110 if (!player()) { 0111 return false; 0112 } 0113 return player()->forwardInput(s, transmit, sender); 0114 } 0115 0116 void KGameIO::Debug() 0117 { 0118 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "------------------- KGAMEINPUT --------------------"; 0119 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "this: " << this; 0120 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "rtti : " << rtti(); 0121 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Player: " << player(); 0122 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "---------------------------------------------------"; 0123 } 0124 0125 // ----------------------- Key IO --------------------------- 0126 class KGameKeyIOPrivate : public KGameIOPrivate 0127 { 0128 }; 0129 0130 KGameKeyIO::KGameKeyIO(QWidget *parent) 0131 : KGameIO(*new KGameKeyIOPrivate) 0132 { 0133 if (parent) { 0134 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Key Event filter installed"; 0135 parent->installEventFilter(this); 0136 } 0137 } 0138 0139 KGameKeyIO::~KGameKeyIO() 0140 { 0141 if (parent()) { 0142 parent()->removeEventFilter(this); 0143 } 0144 } 0145 0146 int KGameKeyIO::rtti() const 0147 { 0148 return KeyIO; 0149 } 0150 0151 bool KGameKeyIO::eventFilter(QObject *o, QEvent *e) 0152 { 0153 if (!player()) { 0154 return false; 0155 } 0156 0157 // key press/release 0158 if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) { 0159 QKeyEvent *k = (QKeyEvent *)e; 0160 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "KGameKeyIO" << this << "key press/release" << k->key(); 0161 QByteArray buffer; 0162 QDataStream stream(&buffer, QIODevice::WriteOnly); 0163 bool eatevent = false; 0164 Q_EMIT signalKeyEvent(this, stream, k, &eatevent); 0165 QDataStream msg(buffer); 0166 0167 if (eatevent && sendInput(msg)) { 0168 return eatevent; 0169 } 0170 return false; // do not eat otherwise 0171 } 0172 return QObject::eventFilter(o, e); // standard event processing 0173 } 0174 0175 // ----------------------- Mouse IO --------------------------- 0176 class KGameMouseIOPrivate : public KGameIOPrivate 0177 { 0178 }; 0179 0180 KGameMouseIO::KGameMouseIO(QWidget *parent, bool trackmouse) 0181 : KGameIO(*new KGameMouseIOPrivate) 0182 { 0183 if (parent) { 0184 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Mouse Event filter installed tracking=" << trackmouse; 0185 parent->installEventFilter(this); 0186 parent->setMouseTracking(trackmouse); 0187 } 0188 } 0189 0190 KGameMouseIO::KGameMouseIO(QGraphicsScene *parent, bool /*trackmouse*/) 0191 : KGameIO(*new KGameMouseIOPrivate) 0192 { 0193 if (parent) { 0194 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Mouse Event filter installed tracking=" << trackmouse; 0195 parent->installEventFilter(this); 0196 // parent->setMouseTracking(trackmouse); 0197 } 0198 } 0199 0200 KGameMouseIO::~KGameMouseIO() 0201 { 0202 if (parent()) { 0203 parent()->removeEventFilter(this); 0204 } 0205 } 0206 0207 int KGameMouseIO::rtti() const 0208 { 0209 return MouseIO; 0210 } 0211 0212 void KGameMouseIO::setMouseTracking(bool b) 0213 { 0214 if (parent()) { 0215 ((QWidget *)parent())->setMouseTracking(b); 0216 } 0217 } 0218 0219 bool KGameMouseIO::eventFilter(QObject *o, QEvent *e) 0220 { 0221 if (!player()) { 0222 return false; 0223 } 0224 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "KGameMouseIO" << this << QLatin1String( " " ) << e->type(); 0225 0226 // mouse action 0227 if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::MouseButtonDblClick 0228 || e->type() == QEvent::Wheel || e->type() == QEvent::MouseMove || e->type() == QEvent::GraphicsSceneMousePress 0229 || e->type() == QEvent::GraphicsSceneMouseRelease || e->type() == QEvent::GraphicsSceneMouseDoubleClick || e->type() == QEvent::GraphicsSceneWheel 0230 || e->type() == QEvent::GraphicsSceneMouseMove) { 0231 QMouseEvent *k = (QMouseEvent *)e; 0232 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "KGameMouseIO" << this; 0233 QByteArray buffer; 0234 QDataStream stream(&buffer, QIODevice::WriteOnly); 0235 bool eatevent = false; 0236 Q_EMIT signalMouseEvent(this, stream, k, &eatevent); 0237 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "################# eatevent=" << eatevent; 0238 QDataStream msg(buffer); 0239 if (eatevent && sendInput(msg)) { 0240 return eatevent; 0241 } 0242 return false; // do not eat otherwise 0243 } 0244 return QObject::eventFilter(o, e); // standard event processing 0245 } 0246 0247 // ----------------------- KGameProcesPrivate --------------------------- 0248 class KGameProcessIOPrivate : public KGameIOPrivate 0249 { 0250 public: 0251 KGameProcessIOPrivate() = default; 0252 0253 public: 0254 // KMessageServer *mMessageServer = nullptr; 0255 // KMessageClient *mMessageClient = nullptr; 0256 KMessageProcess *mProcessIO = nullptr; 0257 }; 0258 0259 // ----------------------- Process IO --------------------------- 0260 KGameProcessIO::KGameProcessIO(const QString &name) 0261 : KGameIO(*new KGameProcessIOPrivate) 0262 { 0263 Q_D(KGameProcessIO); 0264 0265 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": this=" << this << ", sizeof(this)=" << sizeof(KGameProcessIO); 0266 0267 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "================= KMEssageServer ===================="; 0268 // d->mMessageServer=new KMessageServer(0,this); 0269 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "================= KMEssageClient ===================="; 0270 // d->mMessageClient=new KMessageClient(this); 0271 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "================= KMEssageProcessIO ===================="; 0272 d->mProcessIO = new KMessageProcess(this, name); 0273 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "================= KMEssage Add client ===================="; 0274 // d->mMessageServer->addClient(d->mProcessIO); 0275 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "================= KMEssage SetSErver ===================="; 0276 // d->mMessageClient->setServer(d->mMessageServer); 0277 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "================= KMEssage: Connect ===================="; 0278 // connect(d->mMessageClient, SIGNAL(broadcastReceived(QByteArray,quint32)), 0279 // this, SLOT(clientMessage(QByteArray,quint32))); 0280 // connect(d->mMessageClient, SIGNAL(forwardReceived(QByteArray,quint32,QValueList<quint32>)), 0281 // this, SLOT(clientMessage(QByteArray,quint32,QValueList<quint32>))); 0282 connect(d->mProcessIO, &KMessageProcess::received, this, &KGameProcessIO::receivedMessage); 0283 // Relay signal 0284 connect(d->mProcessIO, &KMessageProcess::signalReceivedStderr, this, &KGameProcessIO::signalReceivedStderr); 0285 // qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Our client is id="<<d->mMessageClient->id(); 0286 } 0287 0288 KGameProcessIO::~KGameProcessIO() 0289 { 0290 Q_D(KGameProcessIO); 0291 0292 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": this=" << this; 0293 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "player=" << player(); 0294 if (player()) { 0295 player()->removeGameIO(this, false); 0296 } 0297 if (d->mProcessIO) { 0298 delete d->mProcessIO; 0299 d->mProcessIO = nullptr; 0300 } 0301 } 0302 0303 int KGameProcessIO::rtti() const 0304 { 0305 return ProcessIO; 0306 } 0307 0308 void KGameProcessIO::initIO(KPlayer *p) 0309 { 0310 KGameIO::initIO(p); 0311 // Send 'hello' to process 0312 QByteArray buffer; 0313 QDataStream stream(&buffer, QIODevice::WriteOnly); 0314 0315 bool sendit = true; 0316 if (p) { 0317 qint16 id = p->userId(); 0318 stream << id; 0319 Q_EMIT signalIOAdded(this, stream, p, &sendit); 0320 if (sendit) { 0321 quint32 sender = p->id(); 0322 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Sending IOAdded to process player !!!!!!!!!!!!!! "; 0323 sendSystemMessage(stream, KGameMessage::IdIOAdded, 0, sender); 0324 } 0325 } 0326 } 0327 0328 void KGameProcessIO::notifyTurn(bool b) 0329 { 0330 if (!player()) { 0331 qCWarning(KDEGAMESPRIVATE_KGAME_LOG) << ": player() is NULL"; 0332 return; 0333 } 0334 bool sendit = true; 0335 QByteArray buffer; 0336 QDataStream stream(&buffer, QIODevice::WriteOnly); 0337 stream << (qint8)b; 0338 Q_EMIT signalPrepareTurn(stream, b, this, &sendit); 0339 if (sendit) { 0340 quint32 sender = player()->id(); 0341 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Sending Turn to process player !!!!!!!!!!!!!! "; 0342 sendSystemMessage(stream, KGameMessage::IdTurn, 0, sender); 0343 } 0344 } 0345 0346 void KGameProcessIO::sendSystemMessage(QDataStream &stream, int msgid, quint32 receiver, quint32 sender) 0347 { 0348 sendAllMessages(stream, msgid, receiver, sender, false); 0349 } 0350 0351 void KGameProcessIO::sendMessage(QDataStream &stream, int msgid, quint32 receiver, quint32 sender) 0352 { 0353 sendAllMessages(stream, msgid, receiver, sender, true); 0354 } 0355 0356 void KGameProcessIO::sendAllMessages(QDataStream &stream, int msgid, quint32 receiver, quint32 sender, bool usermsg) 0357 { 0358 Q_D(KGameProcessIO); 0359 0360 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "==============> KGameProcessIO::sendMessage (usermsg=" << usermsg << ")"; 0361 // if (!player()) return ; 0362 // if (!player()->isActive()) return ; 0363 0364 if (usermsg) { 0365 msgid += KGameMessage::IdUser; 0366 } 0367 0368 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "=============* ProcessIO (" << msgid << "," << receiver << "," << sender << ") ==========="; 0369 0370 QByteArray buffer; 0371 QDataStream ostream(&buffer, QIODevice::WriteOnly); 0372 QBuffer *device = (QBuffer *)stream.device(); 0373 QByteArray data = device->buffer(); 0374 ; 0375 0376 KGameMessage::createHeader(ostream, sender, receiver, msgid); 0377 // ostream.writeRawBytes(data.data()+device->at(),data.size()-device->at()); 0378 ostream.writeRawData(data.data(), data.size()); 0379 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << " Adding user data from pos=" << device->pos() << " amount=" << data.size() << "byte"; 0380 // if (d->mMessageClient) d->mMessageClient->sendBroadcast(buffer); 0381 if (d->mProcessIO) { 0382 d->mProcessIO->send(buffer); 0383 } 0384 } 0385 0386 // void KGameProcessIO::clientMessage(const QByteArray& receiveBuffer, quint32 clientID, const QValueList <quint32> &recv) 0387 void KGameProcessIO::receivedMessage(const QByteArray &receiveBuffer) 0388 { 0389 QDataStream stream(receiveBuffer); 0390 int msgid; 0391 quint32 sender; 0392 quint32 receiver; 0393 KGameMessage::extractHeader(stream, sender, receiver, msgid); 0394 0395 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "************* Got process message sender =" << sender << "receiver=" << receiver << " msgid=" << msgid; 0396 0397 // Cut out the header part...to not confuse network code 0398 QBuffer *buf = (QBuffer *)stream.device(); 0399 QByteArray newbuffer; 0400 newbuffer = QByteArray::fromRawData(buf->buffer().data() + buf->pos(), buf->size() - buf->pos()); 0401 QDataStream ostream(newbuffer); 0402 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << "Newbuffer size=" << newbuffer.size(); 0403 0404 // This is a dummy message which allows us the process to talk with its owner 0405 if (msgid == KGameMessage::IdProcessQuery) { 0406 Q_EMIT signalProcessQuery(ostream, this); 0407 } else if (player()) { 0408 sender = player()->id(); // force correct sender 0409 if (msgid == KGameMessage::IdPlayerInput) { 0410 sendInput(ostream, true, sender); 0411 } else { 0412 player()->forwardMessage(ostream, msgid, receiver, sender); 0413 } 0414 } else { 0415 qCDebug(KDEGAMESPRIVATE_KGAME_LOG) << ": Got message from process but no player defined!"; 0416 } 0417 newbuffer.clear(); 0418 } 0419 0420 // ----------------------- Computer IO -------------------------- 0421 class KGameComputerIOPrivate : public KGameIOPrivate 0422 { 0423 // TODO: maybe these should be KGameProperties!! 0424 public: 0425 KGameComputerIOPrivate() = default; 0426 0427 public: 0428 int mAdvanceCounter = 0; 0429 int mReactionPeriod = 0; 0430 0431 int mPauseCounter = 0; 0432 0433 QTimer *mAdvanceTimer = nullptr; 0434 }; 0435 0436 KGameComputerIO::KGameComputerIO() 0437 : KGameIO(*new KGameComputerIOPrivate) 0438 { 0439 } 0440 0441 KGameComputerIO::KGameComputerIO(KPlayer *p) 0442 : KGameIO(*new KGameComputerIOPrivate, p) 0443 { 0444 } 0445 0446 KGameComputerIO::~KGameComputerIO() 0447 { 0448 Q_D(KGameComputerIO); 0449 0450 if (d->mAdvanceTimer) { 0451 delete d->mAdvanceTimer; 0452 } 0453 } 0454 0455 int KGameComputerIO::rtti() const 0456 { 0457 return ComputerIO; 0458 } 0459 0460 void KGameComputerIO::setReactionPeriod(int calls) 0461 { 0462 Q_D(KGameComputerIO); 0463 0464 d->mReactionPeriod = calls; 0465 } 0466 0467 int KGameComputerIO::reactionPeriod() const 0468 { 0469 Q_D(const KGameComputerIO); 0470 0471 return d->mReactionPeriod; 0472 } 0473 0474 void KGameComputerIO::setAdvancePeriod(int ms) 0475 { 0476 Q_D(KGameComputerIO); 0477 0478 stopAdvancePeriod(); 0479 d->mAdvanceTimer = new QTimer(this); 0480 connect(d->mAdvanceTimer, &QTimer::timeout, this, &KGameComputerIO::advance); 0481 d->mAdvanceTimer->start(ms); 0482 } 0483 0484 void KGameComputerIO::stopAdvancePeriod() 0485 { 0486 Q_D(KGameComputerIO); 0487 0488 if (d->mAdvanceTimer) { 0489 d->mAdvanceTimer->stop(); 0490 delete d->mAdvanceTimer; 0491 } 0492 } 0493 0494 void KGameComputerIO::pause(int calls) 0495 { 0496 Q_D(KGameComputerIO); 0497 0498 d->mPauseCounter = calls; 0499 } 0500 0501 void KGameComputerIO::unpause() 0502 { 0503 pause(0); 0504 } 0505 0506 void KGameComputerIO::advance() 0507 { 0508 Q_D(KGameComputerIO); 0509 0510 if (d->mPauseCounter > 0) { 0511 d->mPauseCounter--; 0512 return; 0513 } else if (d->mPauseCounter < 0) { 0514 return; 0515 } 0516 d->mAdvanceCounter++; 0517 if (d->mAdvanceCounter >= d->mReactionPeriod) { 0518 d->mAdvanceCounter = 0; 0519 reaction(); 0520 } 0521 } 0522 0523 void KGameComputerIO::reaction() 0524 { 0525 Q_EMIT signalReaction(); 0526 } 0527 0528 #include "moc_kgameio.cpp"