diff options
Diffstat (limited to 'libkdegames/kgame/kgame.cpp')
-rw-r--r-- | libkdegames/kgame/kgame.cpp | 1475 |
1 files changed, 0 insertions, 1475 deletions
diff --git a/libkdegames/kgame/kgame.cpp b/libkdegames/kgame/kgame.cpp deleted file mode 100644 index 2eebac64..00000000 --- a/libkdegames/kgame/kgame.cpp +++ /dev/null @@ -1,1475 +0,0 @@ -/* - This file is part of the KDE games library - Copyright (C) 2001 Martin Heni (martin@heni-online.de) - Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2 as published by the Free Software Foundation. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -/* - $Id$ -*/ - -#include "kgame.h" -#include "kgame.moc" -#include "kgamepropertyhandler.h" -#include "kgameproperty.h" -#include "kplayer.h" -#include "kgameio.h" -#include "kgameerror.h" -#include "kgamesequence.h" - -#include "kgamemessage.h" - -#include <unistd.h> -#include <stdio.h> -#include <assert.h> - -#include <tqbuffer.h> -#include <tqtimer.h> -#include <tqptrqueue.h> -#include <tqfile.h> - -#include <klocale.h> -#include <krandomsequence.h> -#include <kdebug.h> - -#define KGAME_LOAD_COOKIE 4210 - -// try to place as much as possible here -// many things are *not* possible here as KGame has to use some inline function -class KGamePrivate -{ -public: - KGamePrivate() - { - mUniquePlayerNumber = 0; - mPolicy=KGame::PolicyLocal; - mGameSequence = 0; - } - - int mUniquePlayerNumber; - TQPtrQueue<KPlayer> mAddPlayerList;// this is a list of to-be-added players. See addPlayer() docu - KRandomSequence* mRandom; - KGame::GamePolicy mPolicy; - KGameSequence* mGameSequence; - - - KGamePropertyHandler* mProperties; - - // player lists - KGame::KGamePlayerList mPlayerList; - KGame::KGamePlayerList mInactivePlayerList; - - //KGamePropertys - KGamePropertyInt mMaxPlayer; - KGamePropertyUInt mMinPlayer; - KGamePropertyInt mGametqStatus; // Game running? - TQValueList<int> mInactiveIdList; - -}; - -// ------------------- GAME CLASS -------------------------- -KGame::KGame(int cookie,TQObject* parent) : KGameNetwork(cookie,parent) -{ - kdDebug(11001) << k_funcinfo << " - " << this << ", sizeof(KGame)=" << sizeof(KGame) << endl; - d = new KGamePrivate; - - d->mProperties = new KGamePropertyHandler(this); - - d->mProperties->registerHandler(KGameMessage::IdGameProperty, - this,TQT_SLOT(sendProperty(int, TQDataStream&, bool* )), - TQT_SLOT(emitSignal(KGamePropertyBase *))); - d->mMaxPlayer.registerData(KGamePropertyBase::IdMaxPlayer, this, i18n("MaxPlayers")); - d->mMaxPlayer.setLocal(-1); // Infinite - d->mMinPlayer.registerData(KGamePropertyBase::IdMinPlayer, this, i18n("MinPlayers")); - d->mMinPlayer.setLocal(0); // Always ok - d->mGametqStatus.registerData(KGamePropertyBase::IdGametqStatus, this, i18n("GameStatus")); - d->mGametqStatus.setLocal(Init); - // d->mUniquePlayerNumber = 0; - d->mRandom = new KRandomSequence; - d->mRandom->setSeed(0); - - connect(this, TQT_SIGNAL(signalClientConnected(TQ_UINT32)), - this, TQT_SLOT(slotClientConnected(TQ_UINT32))); - connect(this, TQT_SIGNAL(signalClientDisconnected(TQ_UINT32,bool)), - this, TQT_SLOT(slotClientDisconnected(TQ_UINT32,bool))); - connect(this, TQT_SIGNAL(signalConnectionBroken()), - this, TQT_SLOT(slotServerDisconnected())); - - setGameSequence(new KGameSequence()); - - // BL: FIXME This signal does no longer exist. When we are merging - // MH: super....and how do I find out about the lost conenction now? - // KGame and KGameNetwork, this could be improved! -// connect(this,TQT_SIGNAL(signalConnectionLost(KGameClient *)), -// this,TQT_SLOT(slotConnectionLost(KGameClient *))); -} - -KGame::~KGame() -{ - kdDebug(11001) << k_funcinfo << endl; -// Debug(); - reset(); - delete d->mGameSequence; - delete d->mRandom; - delete d; - kdDebug(11001) << k_funcinfo << " done" << endl; -} - -bool KGame::reset() -{ - deletePlayers(); - deleteInactivePlayers(); - return true; -} - -void KGame::deletePlayers() -{ -// kdDebug(11001) << k_funcinfo << endl; - KGamePlayerList tmp = d->mPlayerList; // in case of PolicyClean player=d->mPlayerList.first() is infinite - KPlayer *player; - while((player=tmp.first())) - { - delete player; // delete and removes the player - tmp.removeFirst(); - } -// kdDebug(11001) << k_funcinfo << " done" << endl; -} - -void KGame::deleteInactivePlayers() -{ - KPlayer *player; - while((player=d->mInactivePlayerList.first())) - { - //player->setGame(0); // prevent call backs - d->mInactivePlayerList.remove(player); - delete player; - } -} - -bool KGame::load(TQString filename,bool reset) -{ - if (filename.isNull()) - { - return false; - } - TQFile f(filename); - if (!f.open(IO_ReadOnly)) - { - return false; - } - TQDataStream s( &f ); - load(s,reset); - f.close(); - return true; -} - -bool KGame::load(TQDataStream &stream,bool reset) -{ return loadgame(stream, false,reset); } - -bool KGame::loadgame(TQDataStream &stream, bool network,bool resetgame) -{ - // Load Game Data - - // internal data - TQ_INT32 c; - stream >> c; // cookie - - if (c!=cookie()) - { - kdWarning(11001) << "Trying to load different game version we="<<cookie() << " saved=" << c << endl; - bool result=false; - emit signalLoadError(stream,network,(int)c,result); - return result; - } - if (resetgame) reset(); - - uint i; - stream >> i; -// setPolicy((GamePolicy)i); - - stream >> d->mUniquePlayerNumber; - - if (gameSequence()) - { - gameSequence()->setCurrentPlayer(0); // TODO !!! - } - int newseed; - stream >> newseed; - d->mRandom->setSeed(newseed); - - // Switch off the direct emitting of signals while - // loading properties. This can cause inconsistencies - // otherwise if a property emits and this emit accesses - // a property not yet loaded - // Note we habe to have this external locking to prevent the games unlocking - // to access the players - dataHandler()->lockDirectEmit(); - KPlayer *player; - for ( player=playerList()->first(); player != 0; player=playerList()->next() ) - { - player->dataHandler()->lockDirectEmit(); - // kdDebug(11001) << "Player "<<player->id() << " to indirect emit" <<endl; - } - - // Properties - dataHandler()->load(stream); - - // If there is additional data to be loaded before players are loaded then do - // this here. - emit signalLoadPrePlayers(stream); - - // Load Playerobjects - uint playercount; - stream >> playercount; - kdDebug(11001) << "Loading KGame " << playercount << " KPlayer objects " << endl; - for (i=0;i<playercount;i++) - { - KPlayer *newplayer=loadPlayer(stream,network); - systemAddPlayer(newplayer); - } - - TQ_INT16 cookie; - stream >> cookie; - if (cookie==KGAME_LOAD_COOKIE) { - kdDebug(11001) << " Game loaded propertly"<<endl; - } else { - kdError(11001) << " Game loading error. probably format error"<<endl; - } - - // Switch back on the direct emitting of signals and emit the - // queued signals. - // Note we habe to have this external locking to prevent the games unlocking - // to access the players - dataHandler()->unlockDirectEmit(); - for ( player=playerList()->first(); player != 0; player=playerList()->next() ) - { - player->dataHandler()->unlockDirectEmit(); - // kdDebug(11001) << "Player "<<player->id() << " to direct emit" <<endl; - } - - emit signalLoad(stream); - return true; -} - -bool KGame::save(TQString filename,bool saveplayers) -{ - if (filename.isNull()) - { - return false; - } - TQFile f(filename); - if (!f.open(IO_WriteOnly)) - { - return false; - } - TQDataStream s( &f ); - save(s,saveplayers); - f.close(); - return true; -} - -bool KGame::save(TQDataStream &stream,bool saveplayers) -{ return savegame(stream, false,saveplayers); } - -bool KGame::savegame(TQDataStream &stream,bool /*network*/,bool saveplayers) -{ - // Save Game Data - - // internal variables - TQ_INT32 c=cookie(); - stream << c; - - uint p=(uint)policy(); - stream << p; - stream << d->mUniquePlayerNumber; - int newseed=(int)d->mRandom->getLong(65535); - stream << newseed; - d->mRandom->setSeed(newseed); - - // Properties - dataHandler()->save(stream); - - // Save all data that need to be saved *before* the players are saved - emit signalSavePrePlayers(stream); - - if (saveplayers) - { - savePlayers(stream,playerList()); - } - else - { - stream << (uint)0; // no players saved - } - - stream << (TQ_INT16)KGAME_LOAD_COOKIE; - - emit signalSave(stream); - return true; -} - -void KGame::savePlayer(TQDataStream &stream,KPlayer* p) -{ -// this could be in KGameMessage as well - stream << (TQ_INT32)p->rtti(); - stream << (TQ_INT32)p->id(); - stream << (TQ_INT32)p->calcIOValue(); - p->save(stream); -} - -void KGame::savePlayers(TQDataStream &stream, KGamePlayerList *list) -{ - if (!list) - { - list=playerList(); - } - - TQ_INT32 cnt=list->count(); - kdDebug(11001) << "Saving KGame " << cnt << " KPlayer objects " << endl; - stream << cnt; - KPlayer *player; - for ( player=list->first(); player != 0; player=list->next() ) - { - savePlayer(stream,player); - } -} - -KPlayer *KGame::createPlayer(int /*rtti*/,int /*io*/,bool /*isvirtual*/) -{ - kdWarning(11001) << " No user defined player created. Creating default KPlayer. This crashes if you have overwritten KPlayer!!!! " << endl; - return new KPlayer; -} -KPlayer *KGame::loadPlayer(TQDataStream& stream,bool isvirtual) -{ - TQ_INT32 rtti,id,iovalue; - stream >> rtti >> id >> iovalue; - KPlayer *newplayer=findPlayer(id); - if (!newplayer) - { - kdDebug(11001) << k_funcinfo << "Player "<< id << " not found...asking user to create one " << endl; - newplayer=createPlayer(rtti,iovalue,isvirtual); - //emit signalCreatePlayer(newplayer,rtti,iovalue,isvirtual,this); - } - /* - if (!newplayer) - { - kdWarning(11001) << " No user defined player created. Creating default KPlayer. This crashes if you have overwritten KPlayer!!!! " << endl; - newplayer=new KPlayer; - } - else - { - kdDebug(11001) << " USER Player " << newplayer << " done player->rtti=" << newplayer->rtti() << " rtti=" << rtti << endl; - } - */ - newplayer->load(stream); - if (isvirtual) - { - newplayer->setVirtual(true); - } - return newplayer; -} - -// ----------------- Player handling ----------------------- - -KPlayer * KGame::findPlayer(TQ_UINT32 id) const -{ - for (TQPtrListIterator<KPlayer> it(d->mPlayerList); it.current(); ++it) - { - if (it.current()->id() == id) - { - return it.current(); - } - } - for (TQPtrListIterator<KPlayer> it(d->mInactivePlayerList); it.current(); ++it) - { - if (it.current()->id() == id) - { - return it.current(); - } - } - return 0; -} - -// it is necessary that addPlayer and systemAddPlayer are called in the same -// order. Ie if addPlayer(foo) followed by addPlayer(bar) is called, you must -// not call systemAddPlayer(bar) followed by systemAddPlayer(foo), as the -// mAddPlayerList would get confused. Should be no problem as long as comServer -// and the clients are working correctly. -// BUT: if addPlayer(foo) does not arrive by any reason while addPlayer(bar) -// does, we would be in trouble... -void KGame::addPlayer(KPlayer* newplayer) -{ - kdDebug(11001) << k_funcinfo << ": " << "; maxPlayers=" << maxPlayers() << " playerCount=" << playerCount() << endl; - if (!newplayer) - { - kdFatal(11001) << "trying to add NULL player in KGame::addPlayer()" << endl; - return ; - } - - if (maxPlayers() >= 0 && (int)playerCount() >= maxPlayers()) - { - kdWarning(11001) << "cannot add more than " << maxPlayers() << " players - deleting..." << endl; - delete newplayer; - return; - } - - if (newplayer->id() == 0) - { - d->mUniquePlayerNumber++; - newplayer->setId(KGameMessage::createPlayerId(d->mUniquePlayerNumber, gameId())); - kdDebug(11001) << k_funcinfo << "NEW!!! player " << newplayer << " now has id " << newplayer->id() << endl; - } - else - { - // this could happen in games which use their own ID management by certain - // reasons. that is NOT recommended - kdDebug(11001) << k_funcinfo << "player " << newplayer << " already has an id: " << newplayer->id() << endl; - } - - TQByteArray buffer; - TQDataStream stream(buffer,IO_WriteOnly); - // We distinguis here what policy we have - if (policy()==PolicyLocal || policy()==PolicyDirty) - { - systemAddPlayer(newplayer); - } - if (policy()==PolicyClean || policy()==PolicyDirty) - { - savePlayer(stream,newplayer); - // Store the player for delayed clean adding - if (policy()==PolicyClean) - { - d->mAddPlayerList.enqueue(newplayer); - } - sendSystemMessage(stream,(int)KGameMessage::IdAddPlayer, 0); - } -} - -void KGame::systemAddPlayer(KPlayer* newplayer) -{ - if (!newplayer) - { - kdFatal(11001) << "trying to add NULL player in KGame::systemAddPlayer()" << endl; - return ; - } - if (newplayer->id() == 0) - { - kdWarning(11001) << k_funcinfo << "player " << newplayer << " has no ID" << endl; - } - - if (findPlayer(newplayer->id())) - { - kdError(11001) << "ERROR: Double adding player !!!!! NOT GOOD !!!!!! " << newplayer->id() << "...I delete it again" << endl; - delete newplayer; - } - else - { - kdDebug(11001) << "Trying to add player " << newplayer <<" maxPlayers="<<maxPlayers()<<" playerCount="<<playerCount() << endl; - // Add the player to the game - d->mPlayerList.append(newplayer); - newplayer->setGame(this); - kdDebug(11001) << "Player: isVirtual=" << newplayer->isVirtual() << endl; - kdDebug(11001) << " id=" << newplayer->id() << " #Players=" - << d->mPlayerList.count() << " added " << newplayer - << " (virtual=" << newplayer->isVirtual() << ")" << endl; - emit signalPlayerJoinedGame(newplayer); - } -} - -// Called by the KPlayer destructor -void KGame::playerDeleted(KPlayer *player) -{ - kdDebug(11001) << k_funcinfo << ": id (" << player->id() << ") to be removed " << player << endl; - - if (policy()==PolicyLocal || policy()==PolicyDirty) - { - systemRemovePlayer(player,false); - } - if (policy()==PolicyClean || policy()==PolicyDirty) - { - if (!player->isVirtual()) - { - kdDebug(11001) << k_funcinfo << ": sending IdRemovePlayer "<<player->id() << endl; - sendSystemMessage(player->id(), KGameMessage::IdRemovePlayer, 0); - } - } -} - -bool KGame::removePlayer(KPlayer * player, TQ_UINT32 receiver) -{//transmit to all clients, or to receiver only - if (!player) - { - kdFatal(11001) << "trying to remove NULL player in KGame::removePlayer()" << endl; - return false; - } - kdDebug(11001) << k_funcinfo << ": id (" << player->id() << ") to be removed " << player << endl; - - if (policy()==PolicyLocal || policy()==PolicyDirty) - { - systemRemovePlayer(player,true); - } - if (policy()==PolicyClean || policy()==PolicyDirty) - { - kdDebug(11001) << k_funcinfo << ": sending IdRemovePlayer "<<player->id() << endl; - sendSystemMessage(player->id(),KGameMessage::IdRemovePlayer, receiver); - } - return true; - // we will receive the message in networkTransmission() -} - -void KGame::systemRemovePlayer(KPlayer* player,bool deleteit) -{ - kdDebug(11001) << k_funcinfo << endl; - if (!player) - { - kdWarning(11001) << "cannot remove NULL player" << endl; - return; - } - if (!systemRemove(player,deleteit)) - { - kdWarning(11001) << "player " << player << "(" << player->id() << ") Could not be found!" << endl; - } - - if (gametqStatus()==(int)Run && playerCount()<minPlayers()) - { - kdWarning(11001) << k_funcinfo ": not enough players, PAUSING game\n" << endl; - setGametqStatus(Pause); - } -} - -bool KGame::systemRemove(KPlayer* p,bool deleteit) -{ - if (!p) - { - kdWarning(11001) << "cannot remove NULL player" << endl; - return false; - } - bool result; - kdDebug(11001) << k_funcinfo << ": Player (" << p->id() << ") to be removed " << p << endl; - - if (d->mPlayerList.count() == 0) - { - result = false; - } - else - { - result = d->mPlayerList.remove(p); - } - - emit signalPlayerLeftGame(p); - - p->setGame(0); - if (deleteit) - { - delete p; - } - - return result; -} - -bool KGame::inactivatePlayer(KPlayer* player) -{ - if (!player) - { - return false; - } - kdDebug(11001) << "Inactivate player " << player->id() << endl; - - if (policy()==PolicyLocal || policy()==PolicyDirty) - { - systemInactivatePlayer(player); - } - if (policy()==PolicyClean || policy()==PolicyDirty) - { - sendSystemMessage(player->id(), KGameMessage::IdInactivatePlayer); - } - - return true; -} - -bool KGame::systemInactivatePlayer(KPlayer* player) -{ - if (!player || !player->isActive()) - { - return false; - } - kdDebug(11001) << " Inactivate player " << player->id() << endl; - - int pid=player->id(); - // Virtual players cannot be deactivated. They will be removed - if (player->isVirtual()) - { - systemRemovePlayer(player,true); - } - else - { - d->mPlayerList.remove(player); - d->mInactivePlayerList.prepend(player); - player->setActive(false); - } - emit signalPlayerLeftGame(player); - if (isAdmin()) - { - d->mInactiveIdList.prepend(pid); - } - return true; -} - -bool KGame::activatePlayer(KPlayer * player) -{ - if (!player) - { - return false; - } - kdDebug(11001) << k_funcinfo << ": activate " << player->id() << endl; - if (policy()==PolicyLocal || policy()==PolicyDirty) - { - systemActivatePlayer(player); - } - if (policy()==PolicyClean || policy()==PolicyDirty) - { - sendSystemMessage(player->id(), KGameMessage::IdActivatePlayer); - } - return true; -} - -bool KGame::systemActivatePlayer(KPlayer* player) -{ - if (!player || player->isActive()) - { - return false; - } - kdDebug(11001) << k_funcinfo << ": activate " << player->id() << endl; - - d->mInactivePlayerList.remove(player); - player->setActive(true); - addPlayer(player); - if (isAdmin()) - { - d->mInactiveIdList.remove(player->id()); - } - return true; -} - -// -------------------- Properties --------------------------- - -void KGame::setMaxPlayers(uint maxnumber) -{ if (isAdmin()) { d->mMaxPlayer.changeValue(maxnumber); } } - -void KGame::setMinPlayers(uint minnumber) -{ if (isAdmin()) { d->mMinPlayer.changeValue(minnumber); } } - -uint KGame::minPlayers() const -{ return d->mMinPlayer.value(); } - -int KGame::maxPlayers() const -{ return d->mMaxPlayer.value(); } - -uint KGame::playerCount() const -{ return d->mPlayerList.count(); } - -int KGame::gametqStatus() const -{ return d->mGametqStatus.value(); } - -bool KGame::isRunning() const -{ return d->mGametqStatus.value() == Run; } - -KGamePropertyHandler* KGame::dataHandler() const -{ return d->mProperties; } - - -KGame::KGamePlayerList* KGame::inactivePlayerList() -{ return &d->mInactivePlayerList; } - -const KGame::KGamePlayerList* KGame::inactivePlayerList() const -{ return &d->mInactivePlayerList; } - -KGame::KGamePlayerList* KGame::playerList() -{ return &d->mPlayerList; } - -const KGame::KGamePlayerList* KGame::playerList() const -{ return &d->mPlayerList; } - -KRandomSequence* KGame::random() const -{ return d->mRandom; } - - -bool KGame::sendPlayerInput(TQDataStream &msg, KPlayer *player, TQ_UINT32 sender) -{ - if (!player) - { - kdError(11001) << k_funcinfo << ": NULL player" << endl; - return false; - } - if (!isRunning()) - { - kdError(11001) << k_funcinfo << ": game not running" << endl; - return false; - } - - kdDebug(11001) << k_funcinfo << ": transmitting playerInput over network" << endl; - sendSystemMessage(msg, (int)KGameMessage::IdPlayerInput, player->id(), sender); - return true; -} - -bool KGame::systemPlayerInput(TQDataStream &msg, KPlayer *player, TQ_UINT32 sender) -{ - if (!player) - { - kdError(11001) << k_funcinfo << ": NULL player" << endl; - return false; - } - if (!isRunning()) - { - kdError(11001) << k_funcinfo << ": game not running" << endl; - return false; - } - kdDebug(11001) << "KGame: Got playerInput from messageServer... sender: " << sender << endl; - if (playerInput(msg,player)) - { - playerInputFinished(player); - } - else - { - kdDebug(11001) << k_funcinfo<<": switching off player input"<<endl; - // TODO: (MH 03-2003): We need an return option from playerInput so that - // the player's is not automatically disabled here - if (!player->asyncInput()) - { - player->setTurn(false); // in turn based games we have to switch off input now - } - } - return true; -} - - -KPlayer * KGame::playerInputFinished(KPlayer *player) -{ - kdDebug(11001) << k_funcinfo<<"player input finished for "<<player->id()<<endl; - // Check for game over and if not allow the next player to move - int gameOver = 0; - if (gameSequence()) - { - gameSequence()->setCurrentPlayer(player); - } - // do not call gameSequence()->checkGameOver() to keep backward compatibility! - gameOver = checkGameOver(player); - if (gameOver!=0) - { - if (player) - { - player->setTurn(false); - } - setGametqStatus(End); - emit signalGameOver(gameOver,player,this); - } - else if (!player->asyncInput()) - { - player->setTurn(false); // in turn based games we have to switch off input now - if (gameSequence()) - { - TQTimer::singleShot(0,this,TQT_SLOT(prepareNext())); - } - } - return player; -} - -// Per default we do not do anything -int KGame::checkGameOver(KPlayer *player) -{ - if (gameSequence()) - { - return gameSequence()->checkGameOver(player); - } - return 0; -} - -void KGame::setGameSequence(KGameSequence* sequence) -{ - delete d->mGameSequence; - d->mGameSequence = sequence; - if (d->mGameSequence) - { - d->mGameSequence->setGame(this); - } -} - -KGameSequence* KGame::gameSequence() const -{ - return d->mGameSequence; -} - -void KGame::prepareNext() -{ - if (gameSequence()) - { - // we don't call gameSequence->nextPlayer() to keep old code working - nextPlayer(gameSequence()->currentPlayer()); - } -} - -KPlayer *KGame::nextPlayer(KPlayer *last,bool exclusive) -{ - if (gameSequence()) - { - return gameSequence()->nextPlayer(last, exclusive); - } - return 0; -} - -void KGame::setGametqStatus(int status) -{ - kdDebug(11001) << k_funcinfo << ": GAMESTATUS CHANGED to" << status << endl; - if (status==(int)Run && playerCount()<minPlayers()) - { - kdDebug(11001) << k_funcinfo << ": not enough players, pausing game\n" << endl; - status=Pause; - } - d->mGametqStatus = status; -} - -void KGame::networkTransmission(TQDataStream &stream, int msgid, TQ_UINT32 receiver, TQ_UINT32 sender, TQ_UINT32 /*clientID*/) -{//clientID is unused - // message targets a playerobject. If we find it we forward the message to the - // player. Otherwise we proceed here and hope the best that the user processes - // the message - -// kdDebug(11001) << k_funcinfo << ": we="<<(int)gameId()<<" id="<<msgid<<" recv=" << receiver << " sender=" << sender << endl; - - - // *first* notice the game that something has changed - so no return prevents - // this - emit signalMessageUpdate(msgid, receiver, sender); - if (KGameMessage::isPlayer(receiver)) - { - //kdDebug(11001) << "message id " << msgid << " seems to be for a player ("<<active=p->isActive()<<" recv="<< receiver << endl; - KPlayer *p=findPlayer(receiver); - if (p && p->isActive()) - { - p->networkTransmission(stream,msgid,sender); - return; - } - if (p) - { - kdDebug(11001) << "player is here but not active" << endl; - } - else - { - kdDebug(11001) << "no player found" << endl; - } - } - // If it is not for a player it is meant for us!!!! Otherwise the - // gamenetwork would not have passed the message to us! - - // GameProperties processed - if (d->mProperties->processMessage(stream, msgid, sender == gameId())) - { -// kdDebug(11001 ) << "KGame: message taken by property - returning" << endl; - return ; - } - - switch(msgid) - { - case KGameMessage::IdSetupGame: // Client: First step in setup game - { - TQ_INT16 v; - TQ_INT32 c; - stream >> v >> c; - kdDebug(11001) << " ===================> (Client) " << k_funcinfo << ": Got IdSetupGame ================== " << endl; - kdDebug(11001) << "our game id is " << gameId() << " Lib version=" << v << " App Cookie=" << c << endl; - // Verify identity of the network partners - if (c!=cookie()) - { - kdError(11001) << "IdGameSetup: Negotiate Game: cookie mismatch I'am="<<cookie()<<" master="<<c<<endl; - sendError(KGameError::Cookie, KGameError::errCookie(cookie(), c)); - disconnect(); // disconnect from master - } - else if (v!=KGameMessage::version()) - { - sendError(KGameError::Version, KGameError::errVersion(v)); - disconnect(); // disconnect from master - } - else - { - setupGame(sender); - } - kdDebug(11001) << "========== (Client) Setup game done\n"; - } - break; - case KGameMessage::IdSetupGameContinue: // Master: second step in game setup - { - kdDebug(11001) << "=====>(Master) " << k_funcinfo << " - IdSetupGameContinue" << endl; - setupGameContinue(stream, sender); - } - break; - case KGameMessage::IdActivatePlayer: // Activate Player - { - int id; - stream >> id; - kdDebug(11001) << "Got IdActivatePlayer id=" << id << endl; - if (sender!=gameId() || policy()!=PolicyDirty) - { - systemActivatePlayer(findPlayer(id)); - } - } - break; - case KGameMessage::IdInactivatePlayer: // Inactivate Player - { - int id; - stream >> id; - kdDebug(11001) << "Got IdInactivatePlayer id=" << id << endl; - if (sender!=gameId() || policy()!=PolicyDirty) - { - systemInactivatePlayer(findPlayer(id)); - } - } - break; - case KGameMessage::IdAddPlayer: - { - kdDebug(11001) << k_funcinfo << ": Got IdAddPlayer" << endl; - if (sender!=gameId() || policy()!=PolicyDirty) - { - KPlayer *newplayer=0; - // We sent the message so the player is already available - if (sender==gameId()) - { - kdDebug(11001) << "dequeue previously added player" << endl; - newplayer = d->mAddPlayerList.dequeue(); - } - else - { - newplayer=loadPlayer(stream,true); - } - systemAddPlayer(newplayer);// the final, local, adding - //systemAddPlayer(stream); - } - } - break; - case KGameMessage::IdRemovePlayer: // Client should delete player id - { - int id; - stream >> id; - kdDebug(11001) << k_funcinfo << ": Got IdRemovePlayer " << id << endl; - KPlayer *p=findPlayer(id); - if (p) - { - // Otherwise the player is already removed - if (sender!=gameId() || policy()!=PolicyDirty) - { - systemRemovePlayer(p,true); - } - } - else - { - kdWarning(11001) << k_funcinfo << "Cannot find player " << id << endl; - } - } - break; - case KGameMessage::IdGameLoad: - { - kdDebug(11001) << "====> (Client) " << k_funcinfo << ": Got IdGameLoad" << endl; - loadgame(stream,true,false); - } - break; - case KGameMessage::IdGameSetupDone: - { - int cid; - stream >> cid; - kdDebug(11001) << "====> (CLIENT) " << k_funcinfo << ": Got IdGameSetupDone for client " - << cid << " we are =" << gameId() << endl; - sendSystemMessage(gameId(), KGameMessage::IdGameConnected, 0); - } - break; - case KGameMessage::IdGameConnected: - { - int cid; - stream >> cid; - kdDebug(11001) << "====> (ALL) " << k_funcinfo << ": Got IdGameConnected for client "<< cid << " we are =" << gameId() << endl; - emit signalClientJoinedGame(cid,this); - } - break; - - case KGameMessage::IdSyncRandom: // Master forces a new random seed on us - { - int newseed; - stream >> newseed; - kdDebug(11001) << "CLIENT: setting random seed to " << newseed << endl; - d->mRandom->setSeed(newseed); - } - break; - case KGameMessage::IdDisconnect: - { - // if we disconnect we *always* start a local game. - // this could lead into problems if we just change the message server - if (sender != gameId()) - { - kdDebug(11001) << "client " << sender << " leaves game" << endl; - return; - } - kdDebug(11001) << "leaving the game" << endl; - // start a new local game - // no other client is by default connected to this so this call should be - // enough - setMaster(); - } - break; - default: - { - if (msgid < KGameMessage::IdUser) - { - kdError(11001) << "incorrect message id " << msgid << " - emit anyway" - << endl; - } - kdDebug(11001) << k_funcinfo << ": User data msgid " << msgid << endl; - emit signalNetworkData(msgid - KGameMessage::IdUser,((TQBuffer*)stream.device())->readAll(),receiver,sender); - } - break; - } - -} - -// called by the IdSetupGameContinue Message - MASTER SIDE -// Here the master needs to decide which players can take part at the game -// and which will be deactivated -void KGame::setupGameContinue(TQDataStream& stream, TQ_UINT32 sender) -{ - KPlayer *player; - TQ_INT32 cnt; - int i; - stream >> cnt; - - TQValueList<int> inactivateIds; - - KGamePlayerList newPlayerList; - newPlayerList.setAutoDelete(true); - for (i=0;i<cnt;i++) - { - player=loadPlayer(stream,true); - kdDebug(11001) << " Master got player " << player->id() <<" rawgame=" << KGameMessage::rawGameId(player->id()) << " from sender " << sender << endl; - if (KGameMessage::rawGameId(player->id()) != sender) - { - kdError(11001) << "Client tries to add player with wrong game id - cheat possible" << endl; - } - else - { - newPlayerList.append(player); - kdDebug(11001) << " newplayerlist appended " << player->id() << endl; - } - } - - newPlayersJoin(playerList(),&newPlayerList,inactivateIds); - - - kdDebug(11001) << " Master calculates how many players to activate client has cnt=" << cnt << endl; - kdDebug(11001) << " The game has " << playerCount() << " active players" << endl; - kdDebug(11001) << " The user deactivated "<< inactivateIds.count() << " player already " << endl; - kdDebug(11001) << " MaxPlayers for this game is " << maxPlayers() << endl; - - // Do we have too many players? (After the programmer disabled some?) - // MH: We cannot use have player here as it CHANGES in the loop - // int havePlayers = cnt+playerCount()-inactivateIds.count(); - kdDebug(11001) << " havePlayers " << cnt+playerCount()-inactivateIds.count() << endl; - while (maxPlayers() > 0 && maxPlayers() < (int)(cnt+playerCount() - inactivateIds.count())) - { - kdDebug(11001) << " Still to deacticvate " - << (int)(cnt+playerCount()-inactivateIds.count())-(int)maxPlayers() - << endl; - KPlayer *currentPlayer=0; - int currentPriority=0x7fff; // MAX_UINT (16bit?) to get the maximum of the list - // find lowest network priority which is not yet in the newPlayerList - // do this for the new players - for ( player=newPlayerList.first(); player != 0; player=newPlayerList.next() ) - { - // Already in the list - if (inactivateIds.find(player->id())!=inactivateIds.end()) - { - continue; - } - if (player->networkPriority()<currentPriority) - { - currentPriority=player->networkPriority(); - currentPlayer=player; - } - } - - // find lowest network priority which is not yet in the newPlayerList - // Do this for the network players - for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) - { - // Already in the list - if (inactivateIds.find(player->id())!=inactivateIds.end()) - { - continue; - } - if (player->networkPriority()<currentPriority) - { - currentPriority=player->networkPriority(); - currentPlayer=player; - } - } - - // add it to inactivateIds - if (currentPlayer) - { - kdDebug(11001) << "Marking player " << currentPlayer->id() << " for inactivation" << endl; - inactivateIds.append(currentPlayer->id()); - } - else - { - kdError(11001) << "Couldn't find a player to dectivate..That is not so good..." << endl; - break; - } - } - - kdDebug(11001) << "Alltogether deactivated " << inactivateIds.count() << " players" << endl; - - TQValueList<int>::Iterator it; - for ( it = inactivateIds.begin(); it != inactivateIds.end(); ++it ) - { - int pid=*it; - kdDebug(11001) << " pid=" << pid << endl; - } - - // Now deactivate the network players from the inactivateId list - //TQValueList<int>::Iterator it; - for ( it = inactivateIds.begin(); it != inactivateIds.end(); ++it ) - { - int pid=*it; - if (KGameMessage::rawGameId(pid) == sender) - { - continue; // client's player - } - kdDebug(11001) << " -> the network needs to deactivate " << pid <<endl; - player=findPlayer(pid); - if (player) - { - // We have to make REALLY sure that the player is gone. With any policy - systemInactivatePlayer(player); - if (policy()!=PolicyLocal) - { - sendSystemMessage(player->id(), KGameMessage::IdInactivatePlayer); - } - } - else - { - kdError(11001) << " We should deactivate a player, but cannot find it...not good." << endl; - } - } - - // Now send out the player list which the client can activate - for ( player=newPlayerList.first(); player != 0; player=newPlayerList.next() ) - { - kdDebug(11001) << " newplayerlist contains " << player->id() << endl; - // Only activate what is not in the list - if (inactivateIds.find(player->id())!=inactivateIds.end()) - { - continue; - } - kdDebug(11001) << " -> the client can ******** reactivate ******** " << player->id() << endl; - sendSystemMessage(player->id(), KGameMessage::IdActivatePlayer, sender); - } - - // Save the game over the network - TQByteArray bufferS; - TQDataStream streamS(bufferS,IO_WriteOnly); - // Save game over netowrk and save players - savegame(streamS,true,true); - sendSystemMessage(streamS,KGameMessage::IdGameLoad,sender); - - - // Only to the client first , as the client will add players - sendSystemMessage(sender, KGameMessage::IdGameSetupDone, sender); -} - -// called by the IdSetupGame Message - CLIENT SIDE -// Client needs to prepare for network transfer -void KGame::setupGame(TQ_UINT32 sender) -{ - TQByteArray bufferS; - TQDataStream streamS(bufferS,IO_WriteOnly); - - // Deactivate all players - KGamePlayerList mTmpList(d->mPlayerList); // we need copy otherwise the removal crashes - TQ_INT32 cnt=mTmpList.count(); - kdDebug(11001) << "Client: playerlistcount=" << d->mPlayerList.count() << " tmplistcout=" << cnt << endl; - - streamS << cnt; - - TQPtrListIterator<KPlayer> it(mTmpList); - KPlayer *player; - while (it.current()) - { - player=it.current(); - systemInactivatePlayer(player); - // Give the new game id to all players (which are inactivated now) - player->setId(KGameMessage::createPlayerId(player->id(),gameId())); - - // Save it for the master to decide what to do - savePlayer(streamS,player); - - ++it; - --cnt; - } - if (d->mPlayerList.count() > 0 || cnt!=0) - { - kdFatal(11001) << "KGame::setupGame(): Player list is not empty! or cnt!=0=" <<cnt << endl; - } - - sendSystemMessage(streamS,KGameMessage::IdSetupGameContinue,sender); -} - -// unused by KGame -void KGame::syncRandom() -{ - int newseed=(int)d->mRandom->getLong(65535); - sendSystemMessage(newseed,KGameMessage::IdSyncRandom); // Broadcast - d->mRandom->setSeed(newseed); -} - -void KGame::Debug() -{ - KGameNetwork::Debug(); - kdDebug(11001) << "------------------- KGAME -------------------------" << endl; - kdDebug(11001) << "this: " << this << endl; - kdDebug(11001) << "uniquePlayer " << d->mUniquePlayerNumber << endl; - kdDebug(11001) << "gameStatus " << gametqStatus() << endl; - kdDebug(11001) << "MaxPlayers : " << maxPlayers() << endl; - kdDebug(11001) << "NoOfPlayers : " << playerCount() << endl; - kdDebug(11001) << "NoOfInactive: " << d->mInactivePlayerList.count() << endl; - kdDebug(11001) << "---------------------------------------------------" << endl; -} - -void KGame::slotClientConnected(TQ_UINT32 clientID) -{ - if (isAdmin()) - { - negotiateNetworkGame(clientID); - } -} - -void KGame::slotServerDisconnected() // Client side -{ - kdDebug(11001) << "======= SERVER DISCONNECT ======="<<endl; - kdDebug(11001) << "+++ (CLIENT)++++++++" << k_funcinfo << ": our GameID="<<gameId() << endl; - - int oldgamestatus=gametqStatus(); - - KPlayer *player; - KGamePlayerList removeList; - kdDebug(11001) << "Playerlist of client=" << d->mPlayerList.count() << " count" << endl; - kdDebug(11001) << "Inactive Playerlist of client=" << d->mInactivePlayerList.count() << " count" << endl; - for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) - { - // TODO: CHECK: id=0, could not connect to server in the first place?? - if (KGameMessage::rawGameId(player->id()) != gameId() && gameId()!=0) - { - kdDebug(11001) << "Player " << player->id() << " belongs to a removed game" << endl; - removeList.append(player); - } - } - - for ( player=removeList.first(); player != 0; player=removeList.next() ) - { - bool remove = true; - emit signalReplacePlayerIO(player, &remove); - if (remove) - { - kdDebug(11001) << " ---> Removing player " << player->id() << endl; - systemRemovePlayer(player,true); // no network necessary - } - } - - setMaster(); - kdDebug(11001) << " our game id is after setMaster " << gameId() << endl; - - KGamePlayerList mReList(d->mInactivePlayerList); - for ( player=mReList.first(); player != 0; player=mReList.next() ) - { - // TODO ?check for priority? Sequence should be ok - if ((int)playerCount()<maxPlayers() || maxPlayers()<0) - { - systemActivatePlayer(player); - } - } - kdDebug(11001) << " Players activated player-cnt=" << playerCount() << endl; - - for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) - { - int oldid=player->id(); - d->mUniquePlayerNumber++; - player->setId(KGameMessage::createPlayerId(d->mUniquePlayerNumber,gameId())); - kdDebug(11001) << "Player id " << oldid <<" changed to " << player->id() << " as we are now local" << endl; - } - // TODO clear inactive lists ? - Debug(); - for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) - { - player->Debug(); - } - kdDebug(11001) << "+++++++++++" << k_funcinfo << " DONE=" << endl; - emit signalClientLeftGame(0,oldgamestatus,this); -} - -void KGame::slotClientDisconnected(TQ_UINT32 clientID,bool /*broken*/) // server side -{ - kdDebug(11001) << "++++(SERVER)+++++++" << k_funcinfo << " clientId=" << clientID << endl; - - int oldgamestatus=gametqStatus(); - - KPlayer *player; - KGamePlayerList removeList; - kdDebug(11001) << "Playerlist of client=" << d->mPlayerList.count() << " count" << endl; - for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) - { - if (KGameMessage::rawGameId(player->id())==clientID) - { - kdDebug(11001) << "Player " << player->id() << " belongs to the removed game" << endl; - removeList.append(player); - } - } - - for ( player=removeList.first(); player != 0; player=removeList.next() ) - { - // try to replace the KGameIO first - bool remove = true; - emit signalReplacePlayerIO(player, &remove); - if (remove) { - // otherwise (no new KGameIO) remove the player - kdDebug(11001) << " ---> Removing player " << player->id() << endl; - removePlayer(player,0); - } - } - - // Now add inactive players - sequence should be ok - // TODO remove players from removed game - for (unsigned int idx=0;idx<d->mInactiveIdList.count();idx++) - { - TQValueList<int>::Iterator it1 = d->mInactiveIdList.at(idx); - player = findPlayer(*it1); - if (((int)playerCount() < maxPlayers() || maxPlayers() < 0) && player && KGameMessage::rawGameId(*it1) != clientID) - { - activatePlayer(player); - } - } - emit signalClientLeftGame(clientID,oldgamestatus,this); -} - - -// -------------------- Synchronisation ----------------------- - -// this initializes a newly connected client. -// we send the number of players (including type) as well as game status and -// properties to the client. After the initialization has been completed both -// clients should have the same status (ie players, properties, etc) -void KGame::negotiateNetworkGame(TQ_UINT32 clientID) -{ - kdDebug(11001) << "===========================" << k_funcinfo << ": clientID=" << clientID << " =========================== "<< endl; - if (!isAdmin()) - { - kdError(11001) << k_funcinfo << ": Serious WARNING..only gameAdmin should call this" << endl; - return ; - } - - TQByteArray buffer; - TQDataStream streamGS(buffer,IO_WriteOnly); - - // write Game setup specific data - //streamGS << (TQ_INT32)maxPlayers(); - //streamGS << (TQ_INT32)minPlayers(); - - // send to the newly connected client *only* - TQ_INT16 v=KGameMessage::version(); - TQ_INT32 c=cookie(); - streamGS << v << c; - sendSystemMessage(streamGS, KGameMessage::IdSetupGame, clientID); -} - -bool KGame::sendGroupMessage(const TQByteArray &msg, int msgid, TQ_UINT32 sender, const TQString& group) -{ -// AB: group must not be i18n'ed!! we should better use an id for group and use -// a groupName() for the name // FIXME - KPlayer *player; - for ( player=d->mPlayerList.first(); player != 0; player=d->mPlayerList.next() ) - { - if (player && player->group()==group) - { - sendMessage(msg,msgid,player->id(), sender); - } - } - return true; -} - -bool KGame::sendGroupMessage(const TQDataStream &msg, int msgid, TQ_UINT32 sender, const TQString& group) -{ return sendGroupMessage(((TQBuffer*)msg.device())->buffer(), msgid, sender, group); } - -bool KGame::sendGroupMessage(const TQString& msg, int msgid, TQ_UINT32 sender, const TQString& group) -{ - TQByteArray buffer; - TQDataStream stream(buffer, IO_WriteOnly); - stream << msg; - return sendGroupMessage(stream, msgid, sender, group); -} - -bool KGame::addProperty(KGamePropertyBase* data) -{ return dataHandler()->addProperty(data); } - -bool KGame::sendPlayerProperty(int msgid, TQDataStream& s, TQ_UINT32 playerId) -{ return sendSystemMessage(s, msgid, playerId); } - -void KGame::sendProperty(int msgid, TQDataStream& stream, bool* sent) -{ - bool s = sendSystemMessage(stream, msgid); - if (s) - { - *sent = true; - } -} - -void KGame::emitSignal(KGamePropertyBase *me) -{ - emit signalPropertyChanged(me,this); -} - -KGamePropertyBase* KGame::findProperty(int id) const -{ return d->mProperties->find(id); } - -KGame::GamePolicy KGame::policy() const -{ - return d->mPolicy; -} -void KGame::setPolicy(GamePolicy p,bool recursive) -{ - // Set KGame policy - d->mPolicy=p; - if (recursive) - { - // Set all KGame property policy - dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false); - - // Set all KPLayer (active or inactive) property policy - for (TQPtrListIterator<KPlayer> it(d->mPlayerList); it.current(); ++it) - { - it.current()->dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false); - } - for (TQPtrListIterator<KPlayer> it(d->mInactivePlayerList); it.current(); ++it) - { - it.current()->dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false); - } - } -} - -/* - * vim: et sw=2 - */ |