00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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>
00034
00035 using namespace KGGZMod;
00036
00037
00038
00039
00040
00041
00042
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
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
00259
00260 if(opcode == msglaunch)
00261 {
00262 Event e(Event::launch);
00263 emit signalEvent(e);
00264
00265
00266
00267 sendRequest(StateRequest(Module::connected));
00268 }
00269 if(opcode == msgserver)
00270 {
00271
00272 *m_net >> _host;
00273 *m_net >> _port;
00274 *m_net >> _player;
00275
00276
00277
00278
00279
00280
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
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
00439
00440
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
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"