libkdegames Library API Documentation

kgame.cpp

00001 /* 00002 This file is part of the KDE games library 00003 Copyright (C) 2001 Martin Heni (martin@heni-online.de) 00004 Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de) 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License version 2 as published by the Free Software Foundation. 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., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 00019 */ 00020 /* 00021 $Id: kgame.cpp,v 1.89 2003/07/01 00:31:38 mueller Exp $ 00022 */ 00023 00024 #include "kgame.h" 00025 #include "kgame.moc" 00026 #include "kgamepropertyhandler.h" 00027 #include "kgameproperty.h" 00028 #include "kplayer.h" 00029 #include "kgameio.h" 00030 #include "kgameerror.h" 00031 #include "kgamesequence.h" 00032 00033 #include "kgamemessage.h" 00034 00035 #include <unistd.h> 00036 #include <stdio.h> 00037 #include <assert.h> 00038 00039 #include <qbuffer.h> 00040 #include <qtimer.h> 00041 #include <qptrqueue.h> 00042 #include <qfile.h> 00043 00044 #include <klocale.h> 00045 #include <krandomsequence.h> 00046 #include <kdebug.h> 00047 00048 #define KGAME_LOAD_COOKIE 4210 00049 00050 // try to place as much as possible here 00051 // many things are *not* possible here as KGame has to use some inline function 00052 class KGamePrivate 00053 { 00054 public: 00055 KGamePrivate() 00056 { 00057 mUniquePlayerNumber = 0; 00058 mPolicy=KGame::PolicyLocal; 00059 mGameSequence = 0; 00060 } 00061 00062 int mUniquePlayerNumber; 00063 QPtrQueue<KPlayer> mAddPlayerList;// this is a list of to-be-added players. See addPlayer() docu 00064 KRandomSequence* mRandom; 00065 KGame::GamePolicy mPolicy; 00066 KGameSequence* mGameSequence; 00067 00068 00069 KGamePropertyHandler* mProperties; 00070 00071 // player lists 00072 KGame::KGamePlayerList mPlayerList; 00073 KGame::KGamePlayerList mInactivePlayerList; 00074 00075 //KGamePropertys 00076 KGamePropertyInt mMaxPlayer; 00077 KGamePropertyUInt mMinPlayer; 00078 KGamePropertyInt mGameStatus; // Game running? 00079 QValueList<int> mInactiveIdList; 00080 00081 }; 00082 00083 // ------------------- GAME CLASS -------------------------- 00084 KGame::KGame(int cookie,QObject* parent) : KGameNetwork(cookie,parent) 00085 { 00086 kdDebug(11001) << k_funcinfo << " - " << this << ", sizeof(KGame)=" << sizeof(KGame) << endl; 00087 d = new KGamePrivate; 00088 00089 d->mProperties = new KGamePropertyHandler(this); 00090 00091 d->mProperties->registerHandler(KGameMessage::IdGameProperty, 00092 this,SLOT(sendProperty(int, QDataStream&, bool* )), 00093 SLOT(emitSignal(KGamePropertyBase *))); 00094 d->mMaxPlayer.registerData(KGamePropertyBase::IdMaxPlayer, this, i18n("MaxPlayers")); 00095 d->mMaxPlayer.setLocal(-1); // Infinite 00096 d->mMinPlayer.registerData(KGamePropertyBase::IdMinPlayer, this, i18n("MinPlayers")); 00097 d->mMinPlayer.setLocal(0); // Always ok 00098 d->mGameStatus.registerData(KGamePropertyBase::IdGameStatus, this, i18n("GameStatus")); 00099 d->mGameStatus.setLocal(Init); 00100 // d->mUniquePlayerNumber = 0; 00101 d->mRandom = new KRandomSequence; 00102 d->mRandom->setSeed(0); 00103 00104 connect(this, SIGNAL(signalClientConnected(Q_UINT32)), 00105 this, SLOT(slotClientConnected(Q_UINT32))); 00106 connect(this, SIGNAL(signalClientDisconnected(Q_UINT32,bool)), 00107 this, SLOT(slotClientDisconnected(Q_UINT32,bool))); 00108 connect(this, SIGNAL(signalConnectionBroken()), 00109 this, SLOT(slotServerDisconnected())); 00110 00111 setGameSequence(new KGameSequence()); 00112 00113 // BL: FIXME This signal does no longer exist. When we are merging 00114 // MH: super....and how do I find out about the lost conenction now? 00115 // KGame and KGameNetwork, this could be improved! 00116 // connect(this,SIGNAL(signalConnectionLost(KGameClient *)), 00117 // this,SLOT(slotConnectionLost(KGameClient *))); 00118 } 00119 00120 KGame::~KGame() 00121 { 00122 kdDebug(11001) << k_funcinfo << endl; 00123 // Debug(); 00124 reset(); 00125 delete d->mGameSequence; 00126 delete d->mRandom; 00127 delete d; 00128 kdDebug(11001) << k_funcinfo << " done" << endl; 00129 } 00130 00131 bool KGame::reset() 00132 { 00133 deletePlayers(); 00134 deleteInactivePlayers(); 00135 return true; 00136 } 00137 00138 void KGame::deletePlayers() 00139 { 00140 // kdDebug(11001) << k_funcinfo << endl; 00141 KGamePlayerList tmp = d->mPlayerList; // in case of PolicyClean player=d->mPlayerList.first() is infinite 00142 KPlayer *player; 00143 while((player=tmp.first())) 00144 { 00145 delete player; // delete and removes the player 00146 tmp.removeFirst(); 00147 } 00148 // kdDebug(11001) << k_funcinfo << " done" << endl; 00149 } 00150 00151 void KGame::deleteInactivePlayers() 00152 { 00153 KPlayer *player; 00154 while((player=d->mInactivePlayerList.first())) 00155 { 00156 //player->setGame(0); // prevent call backs 00157 d->mInactivePlayerList.remove(player); 00158 delete player; 00159 } 00160 } 00161 00162 bool KGame::load(QString filename,bool reset) 00163 { 00164 if (filename.isNull()) 00165 { 00166 return false; 00167 } 00168 QFile f(filename); 00169 if (!f.open(IO_ReadOnly)) 00170 { 00171 return false; 00172 } 00173 QDataStream s( &f ); 00174 load(s,reset); 00175 f.close(); 00176 return true; 00177 } 00178 00179 bool KGame::load(QDataStream &stream,bool reset) 00180 { return loadgame(stream, false,reset); } 00181 00182 bool KGame::loadgame(QDataStream &stream, bool network,bool resetgame) 00183 { 00184 // Load Game Data 00185 00186 // internal data 00187 Q_INT32 c; 00188 stream >> c; // cookie 00189 00190 if (c!=cookie()) 00191 { 00192 kdWarning(11001) << "Trying to load different game version we="<<cookie() << " saved=" << c << endl; 00193 bool result=false; 00194 emit signalLoadError(stream,network,(int)c,result); 00195 return result; 00196 } 00197 if (resetgame) reset(); 00198 00199 uint i; 00200 stream >> i; 00201 // setPolicy((GamePolicy)i); 00202 00203 stream >> d->mUniquePlayerNumber; 00204 00205 if (gameSequence()) 00206 { 00207 gameSequence()->setCurrentPlayer(0); // TODO !!! 00208 } 00209 int newseed; 00210 stream >> newseed; 00211 d->mRandom->setSeed(newseed); 00212 00213 // Switch off the direct emitting of signals while 00214 // loading properties. This can cause inconsistencies 00215 // otherwise if a property emits and this emit accesses 00216 // a property not yet loaded 00217 // Note we habe to have this external locking to prevent the games unlocking 00218 // to access the players 00219 dataHandler()->lockDirectEmit(); 00220 KPlayer *player; 00221 for ( player=playerList()->first(); player != 0; player=playerList()->next() ) 00222 { 00223 player->dataHandler()->lockDirectEmit(); 00224 // kdDebug(11001) << "Player "<<player->id() << " to indirect emit" <<endl; 00225 } 00226 00227 // Properties 00228 dataHandler()->load(stream); 00229 00230 // If there is additional data to be loaded before players are loaded then do 00231 // this here. 00232 emit signalLoadPrePlayers(stream); 00233 00234 // Load Playerobjects 00235 uint playercount; 00236 stream >> playercount; 00237 kdDebug(11001) << "Loading KGame " << playercount << " KPlayer objects " << endl; 00238 for (i=0;i<playercount;i++) 00239 { 00240 KPlayer *newplayer=loadPlayer(stream,network); 00241 systemAddPlayer(newplayer); 00242 } 00243 00244 Q_INT16 cookie; 00245 stream >> cookie; 00246 if (cookie==KGAME_LOAD_COOKIE) { 00247 kdDebug(11001) << " Game loaded propertly"<<endl; 00248 } else { 00249 kdError(11001) << " Game loading error. probably format error"<<endl; 00250 } 00251 00252 // Switch back on the direct emitting of signals and emit the 00253 // queued signals. 00254 // Note we habe to have this external locking to prevent the games unlocking 00255 // to access the players 00256 dataHandler()->unlockDirectEmit(); 00257 for ( player=playerList()->first(); player != 0; player=playerList()->next() ) 00258 { 00259 player->dataHandler()->unlockDirectEmit(); 00260 // kdDebug(11001) << "Player "<<player->id() << " to direct emit" <<endl; 00261 } 00262 00263 emit signalLoad(stream); 00264 return true; 00265 } 00266 00267 bool KGame::save(QString filename,bool saveplayers) 00268 { 00269 if (filename.isNull()) 00270 { 00271 return false; 00272 } 00273 QFile f(filename); 00274 if (!f.open(IO_WriteOnly)) 00275 { 00276 return false; 00277 } 00278 QDataStream s( &f ); 00279 save(s,saveplayers); 00280 f.close(); 00281 return true; 00282 } 00283 00284 bool KGame::save(QDataStream &stream,bool saveplayers) 00285 { return savegame(stream, false,saveplayers); } 00286 00287 bool KGame::savegame(QDataStream &stream,bool /*network*/,bool saveplayers) 00288 { 00289 // Save Game Data 00290 00291 // internal variables 00292 Q_INT32 c=cookie(); 00293 stream << c; 00294 00295 uint p=(uint)policy(); 00296 stream << p; 00297 stream << d->mUniquePlayerNumber; 00298 int newseed=(int)d->mRandom->getLong(65535); 00299 stream << newseed; 00300 d->mRandom->setSeed(newseed); 00301 00302 // Properties 00303 dataHandler()->save(stream); 00304 00305 // Save all data that need to be saved *before* the players are saved 00306 emit signalSavePrePlayers(stream); 00307 00308 if (saveplayers) 00309 { 00310 savePlayers(stream,playerList()); 00311 } 00312 else 00313 { 00314 stream << (uint)0; // no players saved 00315 } 00316 00317 stream << (Q_INT16)KGAME_LOAD_COOKIE; 00318 00319 emit signalSave(stream); 00320 return true; 00321 } 00322 00323 void KGame::savePlayer(QDataStream &stream,KPlayer* p) 00324 { 00325 // this could be in KGameMessage as well 00326 stream << (Q_INT32)p->rtti(); 00327 stream << (Q_INT32)p->id(); 00328 stream << (Q_INT32)p->calcIOValue(); 00329 p->save(stream); 00330 } 00331 00332 void KGame::savePlayers(QDataStream &stream, KGamePlayerList *list) 00333 { 00334 if (!list) 00335 { 00336 list=playerList(); 00337 } 00338 00339 Q_INT32 cnt=list->count(); 00340 kdDebug(11001) << "Saving KGame " << cnt << " KPlayer objects " << endl; 00341 stream << cnt; 00342 KPlayer *player; 00343 for ( player=list->first(); player != 0; player=list->next() ) 00344 { 00345 savePlayer(stream,player); 00346 } 00347 } 00348 00349 KPlayer *KGame::createPlayer(int /*rtti*/,int /*io*/,bool /*isvirtual*/) 00350 { 00351 kdWarning(11001) << " No user defined player created. Creating default KPlayer. This crashes if you have overwritten KPlayer!!!! " << endl; 00352 return new KPlayer; 00353 } 00354 KPlayer *KGame::loadPlayer(QDataStream& stream,bool isvirtual) 00355 { 00356 Q_INT32 rtti,id,iovalue; 00357 stream >> rtti >> id >> iovalue; 00358 KPlayer *newplayer=findPlayer(id); 00359 if (!newplayer) 00360 { 00361 kdDebug(11001) << k_funcinfo << "Player "<< id << " not found...asking user to create one " << endl; 00362 newplayer=createPlayer(rtti,iovalue,isvirtual); 00363 //emit signalCreatePlayer(newplayer,rtti,iovalue,isvirtual,this); 00364 } 00365 /* 00366 if (!newplayer) 00367 { 00368 kdWarning(11001) << " No user defined player created. Creating default KPlayer. This crashes if you have overwritten KPlayer!!!! " << endl; 00369 newplayer=new KPlayer; 00370 } 00371 else 00372 { 00373 kdDebug(11001) << " USER Player " << newplayer << " done player->rtti=" << newplayer->rtti() << " rtti=" << rtti << endl; 00374 } 00375 */ 00376 newplayer->load(stream); 00377 if (isvirtual) 00378 { 00379 newplayer->setVirtual(true); 00380 } 00381 return newplayer; 00382 } 00383 00384 // ----------------- Player handling ----------------------- 00385 00386 KPlayer * KGame::findPlayer(Q_UINT32 id) const 00387 { 00388 for (QPtrListIterator<KPlayer> it(d->mPlayerList); it.current(); ++it) 00389 { 00390 if (it.current()->id() == id) 00391 { 00392 return it.current(); 00393 } 00394 } 00395 for (QPtrListIterator<KPlayer> it(d->mInactivePlayerList); it.current(); ++it) 00396 { 00397 if (it.current()->id() == id) 00398 { 00399 return it.current(); 00400 } 00401 } 00402 return 0; 00403 } 00404 00405 // it is necessary that addPlayer and systemAddPlayer are called in the same 00406 // order. Ie if addPlayer(foo) followed by addPlayer(bar) is called, you must 00407 // not call systemAddPlayer(bar) followed by systemAddPlayer(foo), as the 00408 // mAddPlayerList would get confused. Should be no problem as long as comServer 00409 // and the clients are working correctly. 00410 // BUT: if addPlayer(foo) does not arrive by any reason while addPlayer(bar) 00411 // does, we would be in trouble... 00412 void KGame::addPlayer(KPlayer* newplayer) 00413 { 00414 kdDebug(11001) << k_funcinfo << ": " << "; maxPlayers=" << maxPlayers() << " playerCount=" << playerCount() << endl; 00415 if (!newplayer) 00416 { 00417 kdFatal(11001) << "trying to add NULL player in KGame::addPlayer()" << endl; 00418 return ; 00419 } 00420 00421 if (maxPlayers() >= 0 && (int)playerCount() >= maxPlayers()) 00422 { 00423 kdWarning(11001) << "cannot add more than " << maxPlayers() << " players - deleting..." << endl; 00424 delete newplayer; 00425 return; 00426 } 00427 00428 if (newplayer->id() == 0) 00429 { 00430 d->mUniquePlayerNumber++; 00431 newplayer->setId(KGameMessage::createPlayerId(d->mUniquePlayerNumber, gameId())); 00432 kdDebug(11001) << k_funcinfo << "NEW!!! player " << newplayer << " now has id " << newplayer->id() << endl; 00433 } 00434 else 00435 { 00436 // this could happen in games which use their own ID management by certain 00437 // reasons. that is NOT recommended 00438 kdDebug(11001) << k_funcinfo << "player " << newplayer << " already has an id: " << newplayer->id() << endl; 00439 } 00440 00441 QByteArray buffer; 00442 QDataStream stream(buffer,IO_WriteOnly); 00443 // We distinguis here what policy we have 00444 if (policy()==PolicyLocal || policy()==PolicyDirty) 00445 { 00446 systemAddPlayer(newplayer); 00447 } 00448 if (policy()==PolicyClean || policy()==PolicyDirty) 00449 { 00450 savePlayer(stream,newplayer); 00451 // Store the player for delayed clean adding 00452 if (policy()==PolicyClean) 00453 { 00454 d->mAddPlayerList.enqueue(newplayer); 00455 } 00456 sendSystemMessage(stream,(int)KGameMessage::IdAddPlayer, 0); 00457 } 00458 } 00459 00460 void KGame::systemAddPlayer(KPlayer* newplayer) 00461 { 00462 if (!newplayer) 00463 { 00464 kdFatal(11001) << "trying to add NULL player in KGame::systemAddPlayer()" << endl; 00465 return ; 00466 } 00467 if (newplayer->id() == 0) 00468 { 00469 kdWarning(11001) << k_funcinfo << "player " << newplayer << " has no ID" << endl; 00470 } 00471 00472 if (findPlayer(newplayer->id())) 00473 { 00474 kdError(11001) << "ERROR: Double adding player !!!!! NOT GOOD !!!!!! " << newplayer->id() << "...I delete it again" << endl; 00475 delete newplayer; 00476 } 00477 else 00478 { 00479 kdDebug(11001) << "Trying to add player " << newplayer <<" maxPlayers="<<maxPlayers()<<" playerCount="<<playerCount() << endl; 00480 // Add the player to the game 00481 d->mPlayerList.append(newplayer); 00482 newplayer->setGame(this); 00483 kdDebug(11001) << "Player: isVirtual=" << newplayer->isVirtual() << endl; 00484 kdDebug(11001) << " id=" << newplayer->id() << " #Players=" 00485 << d->mPlayerList.count() << " added " << newplayer 00486 << " (virtual=" << newplayer->isVirtual() << ")" << endl; 00487 emit signalPlayerJoinedGame(newplayer); 00488 } 00489 } 00490 00491 // Called by the KPlayer destructor 00492 void KGame::playerDeleted(KPlayer *player) 00493 { 00494 kdDebug(11001) << k_funcinfo << ": id (" << player->id() << ") to be removed " << player << endl; 00495 00496 if (policy()==PolicyLocal || policy()==PolicyDirty) 00497 { 00498 systemRemovePlayer(player,false); 00499 } 00500 if (policy()==PolicyClean || policy()==PolicyDirty) 00501 { 00502 if (!player->isVirtual()) 00503 { 00504 kdDebug(11001) << k_funcinfo << ": sending IdRemovePlayer "<<player->id() << endl; 00505 sendSystemMessage(player->id(), KGameMessage::IdRemovePlayer, 0); 00506 } 00507 } 00508 } 00509 00510 bool KGame::removePlayer(KPlayer * player, Q_UINT32 receiver) 00511 {//transmit to all clients, or to receiver only 00512 if (!player) 00513 { 00514 kdFatal(11001) << "trying to remove NULL player in KGame::removePlayer()" << endl; 00515 return false; 00516 } 00517 kdDebug(11001) << k_funcinfo << ": id (" << player->id() << ") to be removed " << player << endl; 00518 00519 if (policy()==PolicyLocal || policy()==PolicyDirty) 00520 { 00521 systemRemovePlayer(player,true); 00522 } 00523 if (policy()==PolicyClean || policy()==PolicyDirty) 00524 { 00525 kdDebug(11001) << k_funcinfo << ": sending IdRemovePlayer "<<player->id() << endl; 00526 sendSystemMessage(player->id(),KGameMessage::IdRemovePlayer, receiver); 00527 } 00528 return true; 00529 // we will receive the message in networkTransmission() 00530 } 00531 00532 void KGame::systemRemovePlayer(KPlayer* player,bool deleteit) 00533 { 00534 kdDebug(11001) << k_funcinfo << endl; 00535 if (!player) 00536 { 00537 kdWarning(11001) << "cannot remove NULL player" << endl; 00538 return; 00539 } 00540 if (!systemRemove(player,deleteit)) 00541 { 00542 kdWarning(11001) << "player " << player << "(" << player->id() << ") Could not be found!" << endl; 00543 } 00544 00545 if (gameStatus()==(int)Run && playerCount()<minPlayers()) 00546 { 00547 kdWarning(11001) << k_funcinfo ": not enough players, PAUSING game\n" << endl; 00548 setGameStatus(Pause); 00549 } 00550 } 00551 00552 bool KGame::systemRemove(KPlayer* p,bool deleteit) 00553 { 00554 if (!p) 00555 { 00556 kdWarning(11001) << "cannot remove NULL player" << endl; 00557 return false; 00558 } 00559 bool result; 00560 kdDebug(11001) << k_funcinfo << ": Player (" << p->id() << ") to be removed " << p << endl; 00561 00562 if (d->mPlayerList.count() == 0) 00563 { 00564 result = false; 00565 } 00566 else 00567 { 00568 result = d->mPlayerList.remove(p); 00569 } 00570 00571 emit signalPlayerLeftGame(p); 00572 00573 p->setGame(0); 00574 if (deleteit) 00575 { 00576 delete p; 00577 } 00578 00579 return result; 00580 } 00581 00582 bool KGame::inactivatePlayer(KPlayer* player) 00583 { 00584 if (!player) 00585 { 00586 return false; 00587 } 00588 kdDebug(11001) << "Inactivate player " << player->id() << endl; 00589 00590 if (policy()==PolicyLocal || policy()==PolicyDirty) 00591 { 00592 systemInactivatePlayer(player); 00593 } 00594 if (policy()==PolicyClean || policy()==PolicyDirty) 00595 { 00596 sendSystemMessage(player->id(), KGameMessage::IdInactivatePlayer); 00597 } 00598 00599 return true; 00600 } 00601 00602 bool KGame::systemInactivatePlayer(KPlayer* player) 00603 { 00604 if (!player || !player->isActive()) 00605 { 00606 return false; 00607 } 00608 kdDebug(11001) << " Inactivate player " << player->id() << endl; 00609 00610 int pid=player->id(); 00611 // Virtual players cannot be deactivated. They will be removed 00612 if (player->isVirtual()) 00613 { 00614 systemRemovePlayer(player,true); 00615 } 00616 else 00617 { 00618 d->mPlayerList.remove(player); 00619 d->mInactivePlayerList.prepend(player); 00620 player->setActive(false); 00621 } 00622 emit signalPlayerLeftGame(player); 00623 if (isAdmin()) 00624 { 00625 d->mInactiveIdList.prepend(pid); 00626 } 00627 return true; 00628 } 00629 00630 bool KGame::activatePlayer(KPlayer * player) 00631 { 00632 if (!player) 00633 { 00634 return false; 00635 } 00636 kdDebug(11001) << k_funcinfo << ": activate " << player->id() << endl; 00637 if (policy()==PolicyLocal || policy()==PolicyDirty) 00638 { 00639 systemActivatePlayer(player); 00640 } 00641 if (policy()==PolicyClean || policy()==PolicyDirty) 00642 { 00643 sendSystemMessage(player->id(), KGameMessage::IdActivatePlayer); 00644 } 00645 return true; 00646 } 00647 00648 bool KGame::systemActivatePlayer(KPlayer* player) 00649 { 00650 if (!player || player->isActive()) 00651 { 00652 return false; 00653 } 00654 kdDebug(11001) << k_funcinfo << ": activate " << player->id() << endl; 00655 00656 d->mInactivePlayerList.remove(player); 00657 player->setActive(true); 00658 addPlayer(player); 00659 if (isAdmin()) 00660 { 00661 d->mInactiveIdList.remove(player->id()); 00662 } 00663 return true; 00664 } 00665 00666 // -------------------- Properties --------------------------- 00667 00668 void KGame::setMaxPlayers(uint maxnumber) 00669 { if (isAdmin()) { d->mMaxPlayer.changeValue(maxnumber); } } 00670 00671 void KGame::setMinPlayers(uint minnumber) 00672 { if (isAdmin()) { d->mMinPlayer.changeValue(minnumber); } } 00673 00674 uint KGame::minPlayers() const 00675 { return d->mMinPlayer.value(); } 00676 00677 int KGame::maxPlayers() const 00678 { return d->mMaxPlayer.value(); } 00679 00680 uint KGame::playerCount() const 00681 { return d->mPlayerList.count(); } 00682 00683 int KGame::gameStatus() const 00684 { return d->mGameStatus.value(); } 00685 00686 bool KGame::isRunning() const 00687 { return d->mGameStatus.value() == Run; } 00688 00689 KGamePropertyHandler* KGame::dataHandler() const 00690 { return d->mProperties; } 00691 00692 00693 KGame::KGamePlayerList* KGame::inactivePlayerList() 00694 { return &d->mInactivePlayerList; } 00695 00696 const KGame::KGamePlayerList* KGame::inactivePlayerList() const 00697 { return &d->mInactivePlayerList; } 00698 00699 KGame::KGamePlayerList* KGame::playerList() 00700 { return &d->mPlayerList; } 00701 00702 const KGame::KGamePlayerList* KGame::playerList() const 00703 { return &d->mPlayerList; } 00704 00705 KRandomSequence* KGame::random() const 00706 { return d->mRandom; } 00707 00708 00709 bool KGame::sendPlayerInput(QDataStream &msg, KPlayer *player, Q_UINT32 sender) 00710 { 00711 if (!player) 00712 { 00713 kdError(11001) << k_funcinfo << ": NULL player" << endl; 00714 return false; 00715 } 00716 if (!isRunning()) 00717 { 00718 kdError(11001) << k_funcinfo << ": game not running" << endl; 00719 return false; 00720 } 00721 00722 kdDebug(11001) << k_funcinfo << ": transmitting playerInput over network" << endl; 00723 sendSystemMessage(msg, (int)KGameMessage::IdPlayerInput, player->id(), sender); 00724 return true; 00725 } 00726 00727 bool KGame::systemPlayerInput(QDataStream &msg, KPlayer *player, Q_UINT32 sender) 00728 { 00729 if (!player) 00730 { 00731 kdError(11001) << k_funcinfo << ": NULL player" << endl; 00732 return false; 00733 } 00734 if (!isRunning()) 00735 { 00736 kdError(11001) << k_funcinfo << ": game not running" << endl; 00737 return false; 00738 } 00739 kdDebug(11001) << "KGame: Got playerInput from messageServer... sender: " << sender << endl; 00740 if (playerInput(msg,player)) 00741 { 00742 playerInputFinished(player); 00743 } 00744 else 00745 { 00746 kdDebug(11001) << k_funcinfo<<": switching off player input"<<endl; 00747 // TODO: (MH 03-2003): We need an return option from playerInput so that 00748 // the player's is not automatically disabled here 00749 if (!player->asyncInput()) 00750 { 00751 player->setTurn(false); // in turn based games we have to switch off input now 00752 } 00753 } 00754 return true; 00755 } 00756 00757 00758 KPlayer * KGame::playerInputFinished(KPlayer *player) 00759 { 00760 kdDebug(11001) << k_funcinfo<<"player input finished for "<<player->id()<<endl; 00761 // Check for game over and if not allow the next player to move 00762 int gameOver = 0; 00763 if (gameSequence()) 00764 { 00765 gameSequence()->setCurrentPlayer(player); 00766 } 00767 // do not call gameSequence()->checkGameOver() to keep backward compatibility! 00768 gameOver = checkGameOver(player); 00769 if (gameOver!=0) 00770 { 00771 if (player) 00772 { 00773 player->setTurn(false); 00774 } 00775 setGameStatus(End); 00776 emit signalGameOver(gameOver,player,this); 00777 } 00778 else if (!player->asyncInput()) 00779 { 00780 player->setTurn(false); // in turn based games we have to switch off input now 00781 if (gameSequence()) 00782 { 00783 QTimer::singleShot(0,this,SLOT(prepareNext())); 00784 } 00785 } 00786 return player; 00787 } 00788 00789 // Per default we do not do anything 00790 int KGame::checkGameOver(KPlayer *player) 00791 { 00792 if (gameSequence()) 00793 { 00794 return gameSequence()->checkGameOver(player); 00795 } 00796 return 0; 00797 } 00798 00799 void KGame::setGameSequence(KGameSequence* sequence) 00800 { 00801 delete d->mGameSequence; 00802 d->mGameSequence = sequence; 00803 if (d->mGameSequence) 00804 { 00805 d->mGameSequence->setGame(this); 00806 } 00807 } 00808 00809 KGameSequence* KGame::gameSequence() const 00810 { 00811 return d->mGameSequence; 00812 } 00813 00814 void KGame::prepareNext() 00815 { 00816 if (gameSequence()) 00817 { 00818 // we don't call gameSequence->nextPlayer() to keep old code working 00819 nextPlayer(gameSequence()->currentPlayer()); 00820 } 00821 } 00822 00823 KPlayer *KGame::nextPlayer(KPlayer *last,bool exclusive) 00824 { 00825 if (gameSequence()) 00826 { 00827 return gameSequence()->nextPlayer(last, exclusive); 00828 } 00829 return 0; 00830 } 00831 00832 void KGame::setGameStatus(int status) 00833 { 00834 kdDebug(11001) << k_funcinfo << ": GAMESTATUS CHANGED to" << status << endl; 00835 if (status==(int)Run && playerCount()<minPlayers()) 00836 { 00837 kdDebug(11001) << k_funcinfo << ": not enough players, pausing game\n" << endl; 00838 status=Pause; 00839 } 00840 d->mGameStatus = status; 00841 } 00842 00843 void KGame::networkTransmission(QDataStream &stream, int msgid, Q_UINT32 receiver, Q_UINT32 sender, Q_UINT32 /*clientID*/) 00844 {//clientID is unused 00845 // message targets a playerobject. If we find it we forward the message to the 00846 // player. Otherwise we proceed here and hope the best that the user processes 00847 // the message 00848 00849 // kdDebug(11001) << k_funcinfo << ": we="<<(int)gameId()<<" id="<<msgid<<" recv=" << receiver << " sender=" << sender << endl; 00850 00851 00852 // *first* notice the game that something has changed - so no return prevents 00853 // this 00854 emit signalMessageUpdate(msgid, receiver, sender); 00855 if (KGameMessage::isPlayer(receiver)) 00856 { 00857 //kdDebug(11001) << "message id " << msgid << " seems to be for a player ("<<active=p->isActive()<<" recv="<< receiver << endl; 00858 KPlayer *p=findPlayer(receiver); 00859 if (p && p->isActive()) 00860 { 00861 p->networkTransmission(stream,msgid,sender); 00862 return; 00863 } 00864 if (p) 00865 { 00866 kdDebug(11001) << "player is here but not active" << endl; 00867 } 00868 else 00869 { 00870 kdDebug(11001) << "no player found" << endl; 00871 } 00872 } 00873 // If it is not for a player it is meant for us!!!! Otherwise the 00874 // gamenetwork would not have passed the message to us! 00875 00876 // GameProperties processed 00877 if (d->mProperties->processMessage(stream, msgid, sender == gameId())) 00878 { 00879 // kdDebug(11001 ) << "KGame: message taken by property - returning" << endl; 00880 return ; 00881 } 00882 00883 switch(msgid) 00884 { 00885 case KGameMessage::IdSetupGame: // Client: First step in setup game 00886 { 00887 Q_INT16 v; 00888 Q_INT32 c; 00889 stream >> v >> c; 00890 kdDebug(11001) << " ===================> (Client) " << k_funcinfo << ": Got IdSetupGame ================== " << endl; 00891 kdDebug(11001) << "our game id is " << gameId() << " Lib version=" << v << " App Cookie=" << c << endl; 00892 // Verify identity of the network partners 00893 if (c!=cookie()) 00894 { 00895 kdError(11001) << "IdGameSetup: Negotiate Game: cookie mismatch I'am="<<cookie()<<" master="<<c<<endl; 00896 sendError(KGameError::Cookie, KGameError::errCookie(cookie(), c)); 00897 disconnect(); // disconnect from master 00898 } 00899 else if (v!=KGameMessage::version()) 00900 { 00901 sendError(KGameError::Version, KGameError::errVersion(v)); 00902 disconnect(); // disconnect from master 00903 } 00904 else 00905 { 00906 setupGame(sender); 00907 } 00908 kdDebug(11001) << "========== (Client) Setup game done\n"; 00909 } 00910 break; 00911 case KGameMessage::IdSetupGameContinue: // Master: second step in game setup 00912 { 00913 kdDebug(11001) << "=====>(Master) " << k_funcinfo << " - IdSetupGameContinue" << endl; 00914 setupGameContinue(stream, sender); 00915 } 00916 break; 00917 case KGameMessage::IdActivatePlayer: // Activate Player 00918 { 00919 int id; 00920 stream >> id; 00921 kdDebug(11001) << "Got IdActivatePlayer id=" << id << endl; 00922 if (sender!=gameId() || policy()!=PolicyDirty) 00923 { 00924 systemActivatePlayer(findPlayer(id)); 00925 } 00926 } 00927 break; 00928 case KGameMessage::IdInactivatePlayer: // Inactivate Player 00929 { 00930 int id; 00931 stream >> id; 00932 kdDebug(11001) << "Got IdInactivatePlayer id=" << id << endl; 00933 if (sender!=gameId() || policy()!=PolicyDirty) 00934 { 00935 systemInactivatePlayer(findPlayer(id)); 00936 } 00937 } 00938 break; 00939 case KGameMessage::IdAddPlayer: 00940 { 00941 kdDebug(11001) << k_funcinfo << ": Got IdAddPlayer" << endl; 00942 if (sender!=gameId() || policy()!=PolicyDirty) 00943 { 00944 KPlayer *newplayer=0; 00945 // We sent the message so the player is already available 00946 if (sender==gameId()) 00947 { 00948 kdDebug(11001) << "dequeue previously added player" << endl; 00949 newplayer = d->mAddPlayerList.dequeue(); 00950 } 00951 else 00952 { 00953 newplayer=loadPlayer(stream,true); 00954 } 00955 systemAddPlayer(newplayer);// the final, local, adding 00956 //systemAddPlayer(stream); 00957 } 00958 } 00959 break; 00960 case KGameMessage::IdRemovePlayer: // Client should delete player id 00961 { 00962 int id; 00963 stream >> id; 00964 kdDebug(11001) << k_funcinfo << ": Got IdRemovePlayer " << id << endl; 00965 KPlayer *p=findPlayer(id); 00966 if (p) 00967 { 00968 // Otherwise the player is already removed 00969 if (sender!=gameId() || policy()!=PolicyDirty) 00970 { 00971 systemRemovePlayer(p,true); 00972 } 00973 } 00974 else 00975 { 00976 kdWarning(11001) << k_funcinfo << "Cannot find player " << id << endl; 00977 } 00978 } 00979 break; 00980 case KGameMessage::IdGameLoad: 00981 { 00982 kdDebug(11001) << "====> (Client) " << k_funcinfo << ": Got IdGameLoad" << endl; 00983 loadgame(stream,true,false); 00984 } 00985 break; 00986 case KGameMessage::IdGameSetupDone: 00987 { 00988 int cid; 00989 stream >> cid; 00990 kdDebug(11001) << "====> (CLIENT) " << k_funcinfo << ": Got IdGameSetupDone for client " 00991 << cid << " we are =" << gameId() << endl; 00992 sendSystemMessage(gameId(), KGameMessage::IdGameConnected, 0); 00993 } 00994 break; 00995 case KGameMessage::IdGameConnected: 00996 { 00997 int cid; 00998 stream >> cid; 00999 kdDebug(11001) << "====> (ALL) " << k_funcinfo << ": Got IdGameConnected for client "<< cid << " we are =" << gameId() << endl; 01000 emit signalClientJoinedGame(cid,this); 01001 } 01002 break; 01003 01004 case KGameMessage::IdSyncRandom: // Master forces a new random seed on us 01005 { 01006 int newseed; 01007 stream >> newseed; 01008 kdDebug(11001) << "CLIENT: setting random seed to " << newseed << endl; 01009 d->mRandom->setSeed(newseed); 01010 } 01011 break; 01012 case KGameMessage::IdDisconnect: 01013 { 01014 // if we disconnect we *always* start a local game. 01015 // this could lead into problems if we just change the message server 01016 if (sender != gameId()) 01017 { 01018 kdDebug(11001) << "client " << sender << " leaves game" << endl; 01019 return; 01020 } 01021 kdDebug(11001) << "leaving the game" << endl; 01022 // start a new local game 01023 // no other client is by default connected to this so this call should be 01024 // enough 01025 setMaster(); 01026 } 01027 break; 01028 default: 01029 { 01030 if (msgid < KGameMessage::IdUser) 01031 { 01032 kdError(11001) << "incorrect message id " << msgid << " - emit anyway" 01033 << endl; 01034 } 01035 kdDebug(11001) << k_funcinfo << ": User data msgid " << msgid << endl; 01036 emit signalNetworkData(msgid - KGameMessage::IdUser,((QBuffer*)stream.device())->readAll(),receiver,sender); 01037 } 01038 break; 01039 } 01040 01041 } 01042 01043 // called by the IdSetupGameContinue Message - MASTER SIDE 01044 // Here the master needs to decide which players can take part at the game 01045 // and which will be deactivated 01046 void KGame::setupGameContinue(QDataStream& stream, Q_UINT32 sender) 01047 { 01048 KPlayer *player; 01049 Q_INT32 cnt; 01050 int i; 01051 stream >> cnt; 01052 01053 QValueList<int> inactivateIds; 01054 01055 KGamePlayerList newPlayerList; 01056 newPlayerList.setAutoDelete(true); 01057 for (i=0;i<cnt;i++) 01058 { 01059 player=loadPlayer(stream,true); 01060 kdDebug(11001) << " Master got player " << player->id() <<" rawgame=" << KGameMessage::rawGameId(player->id()) << " from sender " << sender << endl; 01061 if (KGameMessage::rawGameId(player->id()) != sender) 01062 { 01063 kdError(11001) << "Client tries to add player with wrong game id - cheat possible" << endl; 01064 } 01065 else 01066 { 01067 newPlayerList.append(player); 01068 kdDebug(11001) << " newplayerlist appended " << player->id() << endl; 01069 } 01070 } 01071 01072 newPlayersJoin(playerList(),&newPlayerList,inactivateIds); 01073 01074 01075 kdDebug(11001) << " Master calculates how many players to activate client has cnt=" << cnt << endl; 01076 kdDebug(11001) << " The game has " << playerCount() << " active players" << endl; 01077 kdDebug(11001) << " The user deactivated "<< inactivateIds.count() << " player already " << endl; 01078 kdDebug(11001) << " MaxPlayers for this game is " << maxPlayers() << endl; 01079 01080 // Do we have too many players? (After the programmer disabled some?) 01081 // MH: We cannot use have player here as it CHANGES in the loop 01082 // int havePlayers = cnt+playerCount()-inactivateIds.count(); 01083 kdDebug(11001) << " havePlayers " << cnt+playerCount()-inactivateIds.count() << endl; 01084 while (maxPlayers() > 0 && maxPlayers() < (int)(cnt+playerCount() - inactivateIds.count())) 01085 { 01086 kdDebug(11001) << " Still to deacticvate " 01087 << (int)(cnt+playerCount()-inactivateIds.count())-(int)maxPlayers() 01088 << endl; 01089 KPlayer *currentPlayer=0; 01090 int currentPriority=0x7fff; // MAX_UINT (16bit?) to get the maximum of the list 01091 // find lowest network priority which is not yet in the newPlayerList 01092 // do this for the new players 01093 for ( player=newPlayerList.first(); player != 0; player=newPlayerList.next() ) 01094 { 01095 // Already in the list 01096 if (inactivateIds.find(player->id())!=inactivateIds.end()) 01097 { 01098 continue; 01099 } 01100 if (player->networkPriority()<currentPriority) 01101 { 01102 currentPriority=player->networkPriority(); 01103 currentPlayer=player; 01104 } 01105 } 01106 01107 // find lowest network priority which is not yet in the newPlayerList 01108 // Do this for the network players 01109 for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) 01110 { 01111 // Already in the list 01112 if (inactivateIds.find(player->id())!=inactivateIds.end()) 01113 { 01114 continue; 01115 } 01116 if (player->networkPriority()<currentPriority) 01117 { 01118 currentPriority=player->networkPriority(); 01119 currentPlayer=player; 01120 } 01121 } 01122 01123 // add it to inactivateIds 01124 if (currentPlayer) 01125 { 01126 kdDebug(11001) << "Marking player " << currentPlayer->id() << " for inactivation" << endl; 01127 inactivateIds.append(currentPlayer->id()); 01128 } 01129 else 01130 { 01131 kdError(11001) << "Couldn't find a player to dectivate..That is not so good..." << endl; 01132 break; 01133 } 01134 } 01135 01136 kdDebug(11001) << "Alltogether deactivated " << inactivateIds.count() << " players" << endl; 01137 01138 QValueList<int>::Iterator it; 01139 for ( it = inactivateIds.begin(); it != inactivateIds.end(); ++it ) 01140 { 01141 int pid=*it; 01142 kdDebug(11001) << " pid=" << pid << endl; 01143 } 01144 01145 // Now deactivate the network players from the inactivateId list 01146 //QValueList<int>::Iterator it; 01147 for ( it = inactivateIds.begin(); it != inactivateIds.end(); ++it ) 01148 { 01149 int pid=*it; 01150 if (KGameMessage::rawGameId(pid) == sender) 01151 { 01152 continue; // client's player 01153 } 01154 kdDebug(11001) << " -> the network needs to deactivate " << pid <<endl; 01155 player=findPlayer(pid); 01156 if (player) 01157 { 01158 // We have to make REALLY sure that the player is gone. With any policy 01159 systemInactivatePlayer(player); 01160 if (policy()!=PolicyLocal) 01161 { 01162 sendSystemMessage(player->id(), KGameMessage::IdInactivatePlayer); 01163 } 01164 } 01165 else 01166 { 01167 kdError(11001) << " We should deactivate a player, but cannot find it...not good." << endl; 01168 } 01169 } 01170 01171 // Now send out the player list which the client can activate 01172 for ( player=newPlayerList.first(); player != 0; player=newPlayerList.next() ) 01173 { 01174 kdDebug(11001) << " newplayerlist contains " << player->id() << endl; 01175 // Only activate what is not in the list 01176 if (inactivateIds.find(player->id())!=inactivateIds.end()) 01177 { 01178 continue; 01179 } 01180 kdDebug(11001) << " -> the client can ******** reactivate ******** " << player->id() << endl; 01181 sendSystemMessage(player->id(), KGameMessage::IdActivatePlayer, sender); 01182 } 01183 01184 // Save the game over the network 01185 QByteArray bufferS; 01186 QDataStream streamS(bufferS,IO_WriteOnly); 01187 // Save game over netowrk and save players 01188 savegame(streamS,true,true); 01189 sendSystemMessage(streamS,KGameMessage::IdGameLoad,sender); 01190 01191 01192 // Only to the client first , as the client will add players 01193 sendSystemMessage(sender, KGameMessage::IdGameSetupDone, sender); 01194 } 01195 01196 // called by the IdSetupGame Message - CLIENT SIDE 01197 // Client needs to prepare for network transfer 01198 void KGame::setupGame(Q_UINT32 sender) 01199 { 01200 QByteArray bufferS; 01201 QDataStream streamS(bufferS,IO_WriteOnly); 01202 01203 // Deactivate all players 01204 KGamePlayerList mTmpList(d->mPlayerList); // we need copy otherwise the removal crashes 01205 Q_INT32 cnt=mTmpList.count(); 01206 kdDebug(11001) << "Client: playerlistcount=" << d->mPlayerList.count() << " tmplistcout=" << cnt << endl; 01207 01208 streamS << cnt; 01209 01210 QPtrListIterator<KPlayer> it(mTmpList); 01211 KPlayer *player; 01212 while (it.current()) 01213 { 01214 player=it.current(); 01215 systemInactivatePlayer(player); 01216 // Give the new game id to all players (which are inactivated now) 01217 player->setId(KGameMessage::createPlayerId(player->id(),gameId())); 01218 01219 // Save it for the master to decide what to do 01220 savePlayer(streamS,player); 01221 01222 ++it; 01223 --cnt; 01224 } 01225 if (d->mPlayerList.count() > 0 || cnt!=0) 01226 { 01227 kdFatal(11001) << "KGame::setupGame(): Player list is not empty! or cnt!=0=" <<cnt << endl; 01228 } 01229 01230 sendSystemMessage(streamS,KGameMessage::IdSetupGameContinue,sender); 01231 } 01232 01233 // unused by KGame 01234 void KGame::syncRandom() 01235 { 01236 int newseed=(int)d->mRandom->getLong(65535); 01237 sendSystemMessage(newseed,KGameMessage::IdSyncRandom); // Broadcast 01238 d->mRandom->setSeed(newseed); 01239 } 01240 01241 void KGame::Debug() 01242 { 01243 KGameNetwork::Debug(); 01244 kdDebug(11001) << "------------------- KGAME -------------------------" << endl; 01245 kdDebug(11001) << "this: " << this << endl; 01246 kdDebug(11001) << "uniquePlayer " << d->mUniquePlayerNumber << endl; 01247 kdDebug(11001) << "gameStatus " << gameStatus() << endl; 01248 kdDebug(11001) << "MaxPlayers : " << maxPlayers() << endl; 01249 kdDebug(11001) << "NoOfPlayers : " << playerCount() << endl; 01250 kdDebug(11001) << "NoOfInactive: " << d->mInactivePlayerList.count() << endl; 01251 kdDebug(11001) << "---------------------------------------------------" << endl; 01252 } 01253 01254 void KGame::slotClientConnected(Q_UINT32 clientID) 01255 { 01256 if (isAdmin()) 01257 { 01258 negotiateNetworkGame(clientID); 01259 } 01260 } 01261 01262 void KGame::slotServerDisconnected() // Client side 01263 { 01264 kdDebug(11001) << "======= SERVER DISCONNECT ======="<<endl; 01265 kdDebug(11001) << "+++ (CLIENT)++++++++" << k_funcinfo << ": our GameID="<<gameId() << endl; 01266 01267 int oldgamestatus=gameStatus(); 01268 01269 KPlayer *player; 01270 KGamePlayerList removeList; 01271 kdDebug(11001) << "Playerlist of client=" << d->mPlayerList.count() << " count" << endl; 01272 kdDebug(11001) << "Inactive Playerlist of client=" << d->mInactivePlayerList.count() << " count" << endl; 01273 for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) 01274 { 01275 // TODO: CHECK: id=0, could not connect to server in the first place?? 01276 if (KGameMessage::rawGameId(player->id()) != gameId() && gameId()!=0) 01277 { 01278 kdDebug(11001) << "Player " << player->id() << " belongs to a removed game" << endl; 01279 removeList.append(player); 01280 } 01281 } 01282 01283 for ( player=removeList.first(); player != 0; player=removeList.next() ) 01284 { 01285 kdDebug(11001) << " ---> Removing player " << player->id() << endl; 01286 systemRemovePlayer(player,true); // no network necessary 01287 } 01288 01289 setMaster(); 01290 kdDebug(11001) << " our game id is after setMaster " << gameId() << endl; 01291 01292 KGamePlayerList mReList(d->mInactivePlayerList); 01293 for ( player=mReList.first(); player != 0; player=mReList.next() ) 01294 { 01295 // TODO ?check for priority? Sequence should be ok 01296 if ((int)playerCount()<maxPlayers() || maxPlayers()<0) 01297 { 01298 systemActivatePlayer(player); 01299 } 01300 } 01301 kdDebug(11001) << " Players activated player-cnt=" << playerCount() << endl; 01302 01303 for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) 01304 { 01305 int oldid=player->id(); 01306 player->setId(KGameMessage::createPlayerId(player->id(),gameId())); 01307 kdDebug(11001) << "Player id " << oldid <<" changed to " << player->id() << " as we are now local" << endl; 01308 } 01309 // TODO clear inactive lists ? 01310 Debug(); 01311 for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) 01312 { 01313 player->Debug(); 01314 } 01315 kdDebug(11001) << "+++++++++++" << k_funcinfo << " DONE=" << endl; 01316 emit signalClientLeftGame(0,oldgamestatus,this); 01317 } 01318 01319 void KGame::slotClientDisconnected(Q_UINT32 clientID,bool /*broken*/) // server side 01320 { 01321 kdDebug(11001) << "++++(SERVER)+++++++" << k_funcinfo << " clientId=" << clientID << endl; 01322 01323 int oldgamestatus=gameStatus(); 01324 01325 KPlayer *player; 01326 KGamePlayerList removeList; 01327 kdDebug(11001) << "Playerlist of client=" << d->mPlayerList.count() << " count" << endl; 01328 for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) 01329 { 01330 if (KGameMessage::rawGameId(player->id())==clientID) 01331 { 01332 kdDebug(11001) << "Player " << player->id() << " belongs to the removed game" << endl; 01333 removeList.append(player); 01334 } 01335 } 01336 01337 for ( player=removeList.first(); player != 0; player=removeList.next() ) 01338 { 01339 // try to replace the KGameIO first 01340 bool remove = true; 01341 emit signalReplacePlayerIO(player, &remove); 01342 if (remove) { 01343 // otherwise (no new KGameIO) remove the player 01344 kdDebug(11001) << " ---> Removing player " << player->id() << endl; 01345 removePlayer(player,0); 01346 } 01347 } 01348 01349 // Now add inactive players - sequence should be ok 01350 // TODO remove players from removed game 01351 for (unsigned int idx=0;idx<d->mInactiveIdList.count();idx++) 01352 { 01353 QValueList<int>::Iterator it1 = d->mInactiveIdList.at(idx); 01354 player = findPlayer(*it1); 01355 if (((int)playerCount() < maxPlayers() || maxPlayers() < 0) && player && KGameMessage::rawGameId(*it1) != clientID) 01356 { 01357 activatePlayer(player); 01358 } 01359 } 01360 emit signalClientLeftGame(clientID,oldgamestatus,this); 01361 } 01362 01363 01364 // -------------------- Synchronisation ----------------------- 01365 01366 // this initializes a newly connected client. 01367 // we send the number of players (including type) as well as game status and 01368 // properties to the client. After the initialization has been completed both 01369 // clients should have the same status (ie players, properties, etc) 01370 void KGame::negotiateNetworkGame(Q_UINT32 clientID) 01371 { 01372 kdDebug(11001) << "===========================" << k_funcinfo << ": clientID=" << clientID << " =========================== "<< endl; 01373 if (!isAdmin()) 01374 { 01375 kdError(11001) << k_funcinfo << ": Serious WARNING..only gameAdmin should call this" << endl; 01376 return ; 01377 } 01378 01379 QByteArray buffer; 01380 QDataStream streamGS(buffer,IO_WriteOnly); 01381 01382 // write Game setup specific data 01383 //streamGS << (Q_INT32)maxPlayers(); 01384 //streamGS << (Q_INT32)minPlayers(); 01385 01386 // send to the newly connected client *only* 01387 Q_INT16 v=KGameMessage::version(); 01388 Q_INT32 c=cookie(); 01389 streamGS << v << c; 01390 sendSystemMessage(streamGS, KGameMessage::IdSetupGame, clientID); 01391 } 01392 01393 bool KGame::sendGroupMessage(const QByteArray &msg, int msgid, Q_UINT32 sender, const QString& group) 01394 { 01395 // AB: group must not be i18n'ed!! we should better use an id for group and use 01396 // a groupName() for the name // FIXME 01397 KPlayer *player; 01398 for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) 01399 { 01400 if (player && player->group()==group) 01401 { 01402 sendMessage(msg,msgid,player->id(), sender); 01403 } 01404 } 01405 return true; 01406 } 01407 01408 bool KGame::sendGroupMessage(const QDataStream &msg, int msgid, Q_UINT32 sender, const QString& group) 01409 { return sendGroupMessage(((QBuffer*)msg.device())->buffer(), msgid, sender, group); } 01410 01411 bool KGame::sendGroupMessage(const QString& msg, int msgid, Q_UINT32 sender, const QString& group) 01412 { 01413 QByteArray buffer; 01414 QDataStream stream(buffer, IO_WriteOnly); 01415 stream << msg; 01416 return sendGroupMessage(stream, msgid, sender, group); 01417 } 01418 01419 bool KGame::addProperty(KGamePropertyBase* data) 01420 { return dataHandler()->addProperty(data); } 01421 01422 bool KGame::sendPlayerProperty(int msgid, QDataStream& s, Q_UINT32 playerId) 01423 { return sendSystemMessage(s, msgid, playerId); } 01424 01425 void KGame::sendProperty(int msgid, QDataStream& stream, bool* sent) 01426 { 01427 bool s = sendSystemMessage(stream, msgid); 01428 if (s) 01429 { 01430 *sent = true; 01431 } 01432 } 01433 01434 void KGame::emitSignal(KGamePropertyBase *me) 01435 { 01436 emit signalPropertyChanged(me,this); 01437 } 01438 01439 KGamePropertyBase* KGame::findProperty(int id) const 01440 { return d->mProperties->find(id); } 01441 01442 KGame::GamePolicy KGame::policy() const 01443 { 01444 return d->mPolicy; 01445 } 01446 void KGame::setPolicy(GamePolicy p,bool recursive) 01447 { 01448 // Set KGame policy 01449 d->mPolicy=p; 01450 if (recursive) 01451 { 01452 // Set all KGame property policy 01453 dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false); 01454 01455 // Set all KPLayer (active or inactive) property policy 01456 for (QPtrListIterator<KPlayer> it(d->mPlayerList); it.current(); ++it) 01457 { 01458 it.current()->dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false); 01459 } 01460 for (QPtrListIterator<KPlayer> it(d->mInactivePlayerList); it.current(); ++it) 01461 { 01462 it.current()->dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false); 01463 } 01464 } 01465 } 01466 01467 /* 01468 * vim: et sw=2 01469 */
KDE Logo
This file is part of the documentation for libkdegames Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 14:18:46 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003