• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

libkdegames/kggzmod

module.cpp

Go to the documentation of this file.
00001 /*
00002     This file is part of the kggzmod library.
00003     Copyright (c) 2005 - 2007 Josef Spillner <josef@ggzgamingzone.org>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "module.h"
00022 #include "module_private.h"
00023 
00024 #include <kggzmod/statistics.h>
00025 #include "player_private.h"
00026 #include "statistics_private.h"
00027 #include "misc_private.h"
00028 
00029 #include <kggznet/kggzraw.h>
00030 
00031 #include <kdebug.h>
00032 
00033 #include <stdlib.h> // for getenv()
00034 
00035 using namespace KGGZMod;
00036 
00037 // Implementation notes:
00038 // 1) all classes have private counterparts to keep the API clean
00039 //  this is a bit clumsy in the source but also offers ABI compatibility
00040 // 2) classes always take ownership of their private objects
00041 //  i.e. after calling obj->init(opriv) the caller mustn't delete opriv
00042 //  and certainly not do anything else including calling init() again
00043 
00044 static Module *s_module = NULL;
00045 
00046 Module::Module(const QString &name)
00047 : QObject()
00048 {
00049     s_module = this;
00050 
00051     d = new ModulePrivate();
00052 
00053     d->m_name = name;
00054 
00055     d->m_fd = -1;
00056 
00057     d->m_net = 0;
00058     d->m_notifier = 0;
00059     d->m_gnotifier = 0;
00060 
00061     d->m_state = created;
00062 
00063     d->m_playerseats = 0;
00064     d->m_spectatorseats = 0;
00065 
00066     d->m_myseat = -1;
00067 
00068     connect(d, SIGNAL(signalEvent(const KGGZMod::Event&)), this, SIGNAL(signalEvent(const KGGZMod::Event&)));
00069     connect(d, SIGNAL(signalError()), this, SIGNAL(signalError()));
00070     connect(d, SIGNAL(signalNetwork(int)), this, SIGNAL(signalNetwork(int)));
00071 
00072     d->connect();
00073 }
00074 
00075 Module::~Module()
00076 {
00077     d->disconnect();
00078     delete d;
00079 
00080     s_module = NULL;
00081 }
00082 
00083 void Module::sendRequest(Request request)
00084 {
00085     d->sendRequest(request);
00086 }
00087 
00088 QList<Player*> Module::players() const
00089 {
00090     return d->m_players;
00091 }
00092 
00093 QList<Player*> Module::spectators() const
00094 {
00095     return d->m_spectators;
00096 }
00097 
00098 Module::State Module::state() const
00099 {
00100     return d->m_state;
00101 }
00102 
00103 void ModulePrivate::sendRequest(Request request)
00104 {
00105     if(!m_net)
00106     {
00107         kDebug(11003) << "[kggzmod] error: not connected";
00108         return;
00109     }
00110 
00111     kDebug(11003) << "[kggzmod] debug: send a request";
00112     kDebug(11003) << "[kggzmod] info: send request" << requestString(request.type());
00113 
00114     Request::Type opcode = request.type();
00115     // FIXME: in networking we always assume sizeof(opcode) = 4!
00116 
00117     if(opcode == Request::state)
00118     {
00119         *m_net << opcode;
00120         *m_net << (qint8)request.data["state"].toInt();
00121     }
00122     if(opcode == Request::stand)
00123     {
00124         *m_net << opcode;
00125     }
00126     if(opcode == Request::sit)
00127     {
00128         *m_net << opcode;
00129         *m_net << request.data["seat"].toInt();
00130     }
00131     if(opcode == Request::boot)
00132     {
00133         *m_net << opcode;
00134         *m_net << request.data["player"];
00135     }
00136     if(opcode == Request::bot)
00137     {
00138         *m_net << opcode;
00139         *m_net << request.data["seat"].toInt();
00140     }
00141     if(opcode == Request::open)
00142     {
00143         *m_net << opcode;
00144         *m_net << request.data["seat"].toInt();
00145     }
00146     if(opcode == Request::chat)
00147     {
00148         *m_net << opcode;
00149         *m_net << request.data["message"];
00150     }
00151     if(opcode == Request::info)
00152     {
00153         *m_net << opcode;
00154         *m_net << request.data["seat"].toInt();
00155     }
00156     if(opcode == Request::rankings)
00157     {
00158         *m_net << opcode;
00159     }
00160 }
00161 
00162 QString ModulePrivate::requestString(Request::Type requestcode)
00163 {
00164     QString str;
00165     QMap<Request::Type, QString> requestcodes;
00166 
00167     requestcodes[Request::state] = "Request::state";
00168     requestcodes[Request::stand] = "Request::stand";
00169     requestcodes[Request::sit] = "Request::sit";
00170     requestcodes[Request::boot] = "Request::boot";
00171     requestcodes[Request::bot] = "Request::bot";
00172     requestcodes[Request::open] = "Request::open";
00173     requestcodes[Request::chat] = "Request::chat";
00174     requestcodes[Request::info] = "Request::info";
00175     requestcodes[Request::rankings] = "Request::rankings";
00176 
00177     if(requestcodes.contains(requestcode))
00178     {
00179         str = requestcodes[requestcode];
00180     }
00181     else
00182     {
00183         str = "??unknown??";
00184     }
00185 
00186     str += " (" + QString::number(requestcode) + ')';
00187 
00188     return str;
00189 }
00190 
00191 QString ModulePrivate::opcodeString(GGZEvents opcode)
00192 {
00193     QString str;
00194     QMap<GGZEvents, QString> opcodes;
00195 
00196     opcodes[msglaunch] = "msglaunch";
00197     opcodes[msgserver] = "msgserver";
00198     opcodes[msgserverfd] = "msgserverfd";
00199     opcodes[msgplayer] = "msgplayer";
00200     opcodes[msgseat] = "msgseat";
00201     opcodes[msgspectatorseat] = "msgspectatorseat";
00202     opcodes[msgchat] = "msgchat";
00203     opcodes[msgstats] = "msgstats";
00204     opcodes[msginfo] = "msginfo";
00205     opcodes[msgrankings] = "msgrankings";
00206 
00207     if(opcodes.contains(opcode))
00208     {
00209         str = opcodes[opcode];
00210     }
00211     else
00212     {
00213         str = "??unknown??";
00214     }
00215 
00216     str += " (" + QString::number(opcode) + ')';
00217 
00218     return str;
00219 }
00220 
00221 void ModulePrivate::slotGGZError()
00222 {
00223     kDebug(11003) << "[kggzmod] error: disconnection from GGZ core client";
00224     disconnect();
00225     emit signalError();
00226 }
00227 
00228 void ModulePrivate::slotGGZEvent()
00229 {
00230     int opcodetmp, ret;
00231     GGZEvents opcode;
00232     QString _host;
00233     int _port;
00234     QString _player, _message;
00235     int _fd;
00236     int _isspectator, _seat;
00237     int _seattype;
00238     int _hasrecord, _hasrating, _hasranking, _hashighscore;
00239     int _wins, _losses, _ties, _forfeits, _rating, _ranking, _highscore;
00240     int _num;
00241     QString _realname, _photo;
00242     QList<Player*>::Iterator it;
00243 
00244     kDebug(11003) << "[kggzmod] debug: input from GGZ has arrived";
00245     *m_net >> opcodetmp;
00246     opcode = (GGZEvents)opcodetmp;
00247 
00248     kDebug(11003) << "[kggzmod] info: got GGZ input" << opcodeString(opcode);
00249 
00250     if((opcode < msglaunch) || (opcode > msgrankings))
00251     {
00252         kDebug(11003) << "[kggzmod] error: unknown opcode";
00253         disconnect();
00254         emit signalError();
00255         return;
00256     }
00257 
00258     // FIXME: also treat ggzmod 'error' events as signalError()!
00259 
00260     if(opcode == msglaunch)
00261     {
00262         Event e(Event::launch);
00263         emit signalEvent(e);
00264 
00265         // FIXME: ggzmod doesn't provide a "launch" event
00266 
00267         sendRequest(StateRequest(Module::connected));
00268     }
00269     if(opcode == msgserver)
00270     {
00271         //Event e(Event::server);
00272         *m_net >> _host;
00273         *m_net >> _port;
00274         *m_net >> _player;
00275         //e.data["host"] = _host;
00276         //e.data["player"] = _player;
00277         //e.data["port"] = QString::number(_port);
00278         //emit signalEvent(e);
00279 
00280         // FIXME: we don't handle this variant
00281 
00282         kDebug(11003) << "[kggzmod] error: we don't handle msgserver";
00283         disconnect();
00284         emit signalError();
00285     }
00286     if(opcode == msgserverfd)
00287     {
00288         sendRequest(StateRequest(Module::waiting));
00289 
00290         Event e(Event::server);
00291         // FIXME: this is a send_fd operation, might not be portable!
00292         kDebug(11003) << "[kggzmod] debug: go read fd with ancillary data";
00293         ret = readfiledescriptor(m_fd, &_fd);
00294         if(!ret)
00295         {
00296             kDebug(11003) << "[kggzmod] error: socket reading failed";
00297             disconnect();
00298             emit signalError();
00299             return;
00300         }
00301 
00302         kDebug(11003) << "[kggzmod] debug: server fd =" << _fd;
00303         e.data["fd"] = QString::number(_fd);
00304         emit signalEvent(e);
00305 
00306         m_gnotifier = new QSocketNotifier(_fd, QSocketNotifier::Read, this);
00307         QObject::connect(m_gnotifier, SIGNAL(activated(int)), SIGNAL(signalNetwork(int)));
00308     }
00309     if(opcode == msgplayer)
00310     {
00311         Event e(Event::self);
00312         *m_net >> _player;
00313         *m_net >> _isspectator;
00314         *m_net >> _seat;
00315         e.data["player"] = _player;
00316 
00317         m_myseat = _seat;
00318         m_myspectator = (_isspectator != 0);
00319 
00320         insertPlayer((_isspectator ? Player::spectator : Player::player),
00321             e.data["player"], _seat);
00322         e.m_player = findPlayer((_isspectator ? Player::spectator : Player::player),
00323             e.data["player"]);
00324 
00325         emit signalEvent(e);
00326     }
00327     if(opcode == msgseat)
00328     {
00329         Event e(Event::seat);
00330         *m_net >> _seat;
00331         *m_net >> _seattype;
00332         *m_net >> _player;
00333         e.data["player"] = _player;
00334 
00335         insertPlayer((Player::Type)_seattype, e.data["player"], _seat);
00336         e.m_player = findPlayer((Player::Type)_seattype, e.data["player"]);
00337 
00338         if(_seat >= m_playerseats) m_playerseats = _seat + 1;
00339 
00340         emit signalEvent(e);
00341     }
00342     if(opcode == msgspectatorseat)
00343     {
00344         Event e(Event::seat);
00345         *m_net >> _seat;
00346         *m_net >> _player;
00347         e.data["player"] = _player;
00348 
00349         insertPlayer(Player::spectator, e.data["player"], _seat);
00350         e.m_player = findPlayer(Player::spectator, e.data["player"]);
00351 
00352         if(_seat >= m_spectatorseats) m_spectatorseats = _seat + 1;
00353 
00354         emit signalEvent(e);
00355     }
00356     if(opcode == msgchat)
00357     {
00358         Event e(Event::chat);
00359         *m_net >> _player;
00360         *m_net >> _message;
00361         e.data["player"] = _player;
00362         e.data["message"] = _message;
00363 
00364         e.m_player = findPlayer(Player::player, e.data["player"]);
00365 
00366         emit signalEvent(e);
00367     }
00368     if(opcode == msgstats)
00369     {
00370         Event e(Event::stats);
00371 
00372         for(int i = 0; i < m_playerseats + m_spectatorseats; i++)
00373         {
00374             *m_net >> _hasrecord;
00375             *m_net >> _hasrating;
00376             *m_net >> _hasranking;
00377             *m_net >> _hashighscore;
00378             *m_net >> _wins;
00379             *m_net >> _losses;
00380             *m_net >> _ties;
00381             *m_net >> _forfeits;
00382             *m_net >> _rating;
00383             *m_net >> _ranking;
00384             *m_net >> _highscore;
00385 
00386             Statistics *stat = new Statistics();
00387             StatisticsPrivate *statpriv = new StatisticsPrivate();
00388             statpriv->hasrecord = false;
00389             statpriv->hasrating = false;
00390             statpriv->hasranking = false;
00391             statpriv->hashighscore = false;
00392 
00393             if(_hasrecord)
00394             {
00395                 statpriv->wins = _wins;
00396                 statpriv->losses = _wins;
00397                 statpriv->ties = _ties;
00398                 statpriv->forfeits = _forfeits;
00399                 statpriv->hasrecord = true;
00400             }
00401             if(_hasrating)
00402             {
00403                 statpriv->rating = _rating;
00404                 statpriv->hasrating = true;
00405             }
00406             if(_hasranking)
00407             {
00408                 statpriv->ranking = _ranking;
00409                 statpriv->hasranking = true;
00410             }
00411             if(_hashighscore)
00412             {
00413                 statpriv->highscore = _highscore;
00414                 statpriv->hashighscore = true;
00415             }
00416             stat->init(statpriv);
00417 
00418             Player *p;
00419             if(i < m_playerseats) p = m_players.at(i);
00420             else p = m_spectators.at(i);
00421             p->d->m_stats = stat;
00422         }
00423 
00424         emit signalEvent(e);
00425     }
00426     if(opcode == msginfo)
00427     {
00428         Event e(Event::info);
00429 
00430         *m_net >> _num;
00431 
00432         for(int i = 0; i < _num; i++)
00433         {
00434             *m_net >> _seat;
00435             *m_net >> _realname;
00436             *m_net >> _photo;
00437             *m_net >> _host;
00438             //e.data["realname"] = QString(_realname);
00439             //e.data["photo"] = QString(_photo);
00440             //e.data["host"] = QString(_host);
00441 
00442             for(it = m_players.begin(); it != m_players.end(); it++)
00443             {
00444                 if((*it)->seat() == _seat)
00445                 {
00446                     Player *p = (*it);
00447                     p->d->m_realname = _realname;
00448                     p->d->m_hostname = _host;
00449                     p->d->m_photo = _photo;
00450                     break;
00451                 }
00452             }
00453         }
00454 
00455         emit signalEvent(e);
00456     }
00457     if(opcode == msgrankings)
00458     {
00459         Event e(Event::rankings);
00460         kDebug(11003) << "[kggzmod] debug: rankings message";
00461 
00462         *m_net >> _num;
00463         e.data["num"] = QString::number(_num);
00464 
00465         for(int i = 0; i < _num; i++)
00466         {
00467             kDebug(11003) << " ~~rankings: iterate~~ " << i;
00468             *m_net >> _realname;
00469             *m_net >> _ranking;
00470             *m_net >> _highscore;
00471             e.data["name" + QString::number(i)] = _realname;
00472             e.data["position" + QString::number(i)] = QString::number(_ranking);
00473             e.data["score" + QString::number(i)] = QString::number(_highscore);
00474         }
00475 
00476         emit signalEvent(e);
00477     }
00478 }
00479 
00480 void ModulePrivate::connect()
00481 {
00482     kDebug(11003) << "[kggzmod] debug: connect() to GGZ";
00483 
00484     if(!Module::isGGZ())
00485     {
00486         kDebug(11003) << "[kggzmod] info: GGZMODE not set, ignore";
00487         // FIXME: alternatively throw error as well?
00488         return;
00489     }
00490 
00491     QString ggzsocket = getenv("GGZSOCKET");
00492     if(ggzsocket.isNull())
00493     {
00494         kDebug(11003) << "[kggzmod] error: GGZSOCKET not set";
00495         emit signalError();
00496         return;
00497     }
00498 
00499     m_fd = ggzsocket.toInt();
00500     kDebug(11003) << "[kggzmod] debug: use socket" << ggzsocket;
00501     kDebug(11003) << "[kggzmod] debug: numeric socket" << m_fd;
00502 
00503     m_net = new KGGZRaw();
00504     m_net->setNetwork(m_fd);
00505 
00506     QObject::connect(m_net, SIGNAL(signalError()), SLOT(slotGGZError()));
00507 
00508     m_notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
00509     QObject::connect(m_notifier, SIGNAL(activated(int)), SLOT(slotGGZEvent()));
00510 
00511     kDebug(11003) << "[kggzmod] debug: connect() is finished";
00512 }
00513 
00514 void ModulePrivate::disconnect()
00515 {
00516     delete m_gnotifier;
00517     delete m_notifier;
00518 
00519     m_net->deleteLater();
00520     m_net->disconnect();
00521 
00522     m_net = 0;
00523     m_notifier = 0;
00524     m_gnotifier = 0;
00525 }
00526 
00527 Player *ModulePrivate::self() const
00528 {
00529     if(m_myseat == -1)
00530     {
00531         return 0;
00532     }
00533 
00534     if(m_myspectator)
00535     {
00536         return m_spectators.at(m_myseat);
00537     }
00538     else
00539     {
00540         return m_players.at(m_myseat);
00541     }
00542 
00543     return 0;
00544 }
00545 
00546 Player* ModulePrivate::findPlayer(Player::Type seattype, const QString &name)
00547 {
00548     QList<Player*>::Iterator it;
00549 
00550     if(seattype == Player::spectator)
00551     {
00552         for(it = m_spectators.begin(); it != m_spectators.end(); it++)
00553         {
00554             if((*it)->name() == name)
00555             {
00556                 return (*it);
00557             }
00558         }
00559     }
00560     else
00561     {
00562         for(it = m_players.begin(); it != m_players.end(); it++)
00563         {
00564             if((*it)->name() == name)
00565             {
00566                 return (*it);
00567             }
00568         }
00569     }
00570 
00571     return 0;
00572 }
00573 
00574 void ModulePrivate::insertPlayer(Player::Type seattype, const QString &name, int seat)
00575 {
00576     QList<Player*>::Iterator it;
00577 
00578     if(seat == -1)
00579     {
00580         return;
00581     }
00582 
00583     Player *p = new Player();
00584     PlayerPrivate *ppriv = new PlayerPrivate();
00585     ppriv->m_type = seattype;
00586     ppriv->m_name = name;
00587     ppriv->m_seat = seat;
00588     ppriv->m_stats = 0;
00589     p->init(ppriv);
00590 
00591     if(seattype == Player::spectator)
00592     {
00593         if(seat < m_spectators.count())
00594         {
00595             m_spectators.replace(seat, p);
00596         }
00597         else
00598         {
00599             m_spectators.append(p);
00600         }
00601     }
00602     else
00603     {
00604         if(seat < m_players.count())
00605         {
00606             m_players.replace(seat, p);
00607         }
00608         else
00609         {
00610             m_players.append(p);
00611         }
00612     }
00613 }
00614 
00615 bool Module::isGGZ()
00616 {
00617     if(getenv("GGZMODE")) return true;
00618     else return false;
00619 }
00620 
00621 Player *Module::self() const
00622 {
00623     return d->self();
00624 }
00625 
00626 Module *Module::instance()
00627 {
00628     return s_module;
00629 }
00630 
00631 #include "module.moc"
00632 #include "module_private.moc"

libkdegames/kggzmod

Skip menu "libkdegames/kggzmod"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • kblackbox
  • kgoldrunner
  • kmahjongg
  • ksquares
  • libkdegames
  •   highscore
  •   kgame
  •   kggzgames
  •   kggzmod
  •   kggznet
  • libkmahjongg
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal