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"