• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdegames API Reference
  • KDE Home
  • Contact Us
 

libkdegames/libkdegamesprivate/kgame

  • sources
  • kde-4.14
  • kdegames
  • libkdegames
  • libkdegamesprivate
  • kgame
kgame.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the KDE games library
3  Copyright (C) 2001 Martin Heni (kde at heni-online.de)
4  Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de)
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License version 2 as published by the Free Software Foundation.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "kgame.h"
22 #include "kgame.moc"
23 #include "kgamepropertyhandler.h"
24 #include "kgameproperty.h"
25 #include "kplayer.h"
26 #include "kgameio.h"
27 #include "kgameerror.h"
28 #include "kgamesequence.h"
29 
30 #include "kgamemessage.h"
31 
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <assert.h>
35 
36 #include <QBuffer>
37 #include <QTimer>
38 #include <QFile>
39 #include <QList>
40 #include <QQueue>
41 
42 #include <klocale.h>
43 #include <krandomsequence.h>
44 #include <kdebug.h>
45 
46 #define KGAME_LOAD_COOKIE 4210
47 
48 // try to place as much as possible here
49 // many things are *not* possible here as KGame has to use some inline function
50 class KGamePrivate
51 {
52 public:
53  KGamePrivate()
54  {
55  mUniquePlayerNumber = 0;
56  mPolicy=KGame::PolicyLocal;
57  mGameSequence = 0;
58  }
59 
60  int mUniquePlayerNumber;
61  QQueue<KPlayer*> mAddPlayerList;// this is a list of to-be-added players. See addPlayer() docu
62  KRandomSequence* mRandom;
63  KGame::GamePolicy mPolicy;
64  KGameSequence* mGameSequence;
65 
66 
67  KGamePropertyHandler* mProperties;
68 
69  // player lists
70  KGame::KGamePlayerList mPlayerList;
71  KGame::KGamePlayerList mInactivePlayerList;
72 
73  //KGamePropertys
74  KGamePropertyInt mMaxPlayer;
75  KGamePropertyUInt mMinPlayer;
76  KGamePropertyInt mGameStatus; // Game running?
77  QList<int> mInactiveIdList;
78 
79 };
80 
81 // ------------------- GAME CLASS --------------------------
82 KGame::KGame(int cookie,QObject* parent)
83  : KGameNetwork(cookie,parent),
84  d( new KGamePrivate )
85 {
86  kDebug(11001) << " - " << this << ", sizeof(KGame)=" << sizeof(KGame);
87 
88  d->mProperties = new KGamePropertyHandler(this);
89 
90  d->mProperties->registerHandler(KGameMessage::IdGameProperty,
91  this,SLOT(sendProperty(int,QDataStream&,bool*)),
92  SLOT(emitSignal(KGamePropertyBase*)));
93  d->mMaxPlayer.registerData(KGamePropertyBase::IdMaxPlayer, this, i18n("MaxPlayers"));
94  d->mMaxPlayer.setLocal(-1); // Infinite
95  d->mMinPlayer.registerData(KGamePropertyBase::IdMinPlayer, this, i18n("MinPlayers"));
96  d->mMinPlayer.setLocal(0); // Always ok
97  d->mGameStatus.registerData(KGamePropertyBase::IdGameStatus, this, i18n("GameStatus"));
98  d->mGameStatus.setLocal(Init);
99  // d->mUniquePlayerNumber = 0;
100  d->mRandom = new KRandomSequence;
101  d->mRandom->setSeed(0);
102 
103  connect(this, SIGNAL(signalClientConnected(quint32)),
104  this, SLOT(slotClientConnected(quint32)));
105  connect(this, SIGNAL(signalClientDisconnected(quint32,bool)),
106  this, SLOT(slotClientDisconnected(quint32,bool)));
107  connect(this, SIGNAL(signalConnectionBroken()),
108  this, SLOT(slotServerDisconnected()));
109 
110  setGameSequence(new KGameSequence());
111 
112  // BL: FIXME This signal does no longer exist. When we are merging
113  // MH: super....and how do I find out about the lost conenction now?
114  // KGame and KGameNetwork, this could be improved!
115 // connect(this,SIGNAL(signalConnectionLost(KGameClient*)),
116 // this,SLOT(slotConnectionLost(KGameClient*)));
117 }
118 
119 KGame::~KGame()
120 {
121  kDebug(11001) ;
122 // Debug();
123  reset();
124  delete d->mGameSequence;
125  delete d->mRandom;
126  delete d;
127  kDebug(11001) << "done";
128 }
129 
130 bool KGame::reset()
131 {
132  deletePlayers();
133  deleteInactivePlayers();
134  return true;
135 }
136 
137 void KGame::deletePlayers()
138 {
139 // kDebug(11001) ;
140  /* Bugs 303142 and 305000. KPlayer destructor removes
141  * player from the list and makes iterators invalid.
142  * qDeleteAll crashes in that case. */
143  while (!d->mPlayerList.isEmpty())
144  {
145  delete d->mPlayerList.takeFirst();
146  }
147  // qDeleteAll(d->mPlayerList);
148  //NOTE by majewsky: An earlier implementation copied the mPlayerList before
149  //deleting the elements with a takeFirst loop. I therefore chose not to clear()
150  //the list in order not to break anything. The old code had the following
151  //comment: "in case of PolicyClean player=d->mPlayerList.first() is infinite"
152 // kDebug(11001) << "done";
153 }
154 
155 void KGame::deleteInactivePlayers()
156 {
157  qDeleteAll(d->mInactivePlayerList);
158  d->mInactivePlayerList.clear();
159 }
160 
161 bool KGame::load(const QString& filename,bool reset)
162 {
163  if (filename.isNull())
164  {
165  return false;
166  }
167  QFile f(filename);
168  if (!f.open(QIODevice::ReadOnly))
169  {
170  return false;
171  }
172  QDataStream s( &f );
173  load(s,reset);
174  f.close();
175  return true;
176 }
177 
178 bool KGame::load(QDataStream &stream,bool reset)
179 { return loadgame(stream, false,reset); }
180 
181 bool KGame::loadgame(QDataStream &stream, bool network,bool resetgame)
182 {
183  // Load Game Data
184 
185  // internal data
186  qint32 c;
187  stream >> c; // cookie
188 
189  if (c!=cookie())
190  {
191  kWarning(11001) << "Trying to load different game version we="<<cookie() << "saved=" << c;
192  bool result=false;
193  emit signalLoadError(stream,network,(int)c,result);
194  return result;
195  }
196  if (resetgame) reset();
197 
198  uint i;
199  stream >> i;
200 // setPolicy((GamePolicy)i);
201 
202  stream >> d->mUniquePlayerNumber;
203 
204  if (gameSequence())
205  {
206  gameSequence()->setCurrentPlayer(0); // TODO !!!
207  }
208  int newseed;
209  stream >> newseed;
210  d->mRandom->setSeed(newseed);
211 
212  // Switch off the direct emitting of signals while
213  // loading properties. This can cause inconsistencies
214  // otherwise if a property emits and this emit accesses
215  // a property not yet loaded
216  // Note we habe to have this external locking to prevent the games unlocking
217  // to access the players
218  dataHandler()->lockDirectEmit();
219 
220  for ( KGamePlayerList::iterator it = playerList()->begin(); it!=playerList()->end();it++ )
221  {
222  (*it)->dataHandler()->lockDirectEmit();
223  // kDebug(11001) << "Player "<<player->id() << "to indirect emit";
224  }
225 
226  // Properties
227  dataHandler()->load(stream);
228 
229  // If there is additional data to be loaded before players are loaded then do
230  // this here.
231  emit signalLoadPrePlayers(stream);
232 
233  // Switch back on the direct emitting of signals and emit the
234  // queued signals for properties.
235  // Unlocks properties before loading players in order to make game
236  // initializations related to properties before using them in players
237  // initialization
238  dataHandler()->unlockDirectEmit();
239 
240  // Load Playerobjects
241  uint playercount;
242  stream >> playercount;
243  kDebug(11001) << "Loading KGame" << playercount << "KPlayer objects";
244  for (i=0;i<playercount;i++)
245  {
246  KPlayer *newplayer=loadPlayer(stream,network);
247  systemAddPlayer(newplayer);
248  }
249 
250  qint16 cookie;
251  stream >> cookie;
252  if (cookie==KGAME_LOAD_COOKIE) {
253  kDebug(11001) << " Game loaded propertly";
254  } else {
255  kError(11001) << " Game loading error. probably format error";
256  }
257 
258  // Switch back on the direct emitting of signals and emit the
259  // queued signals for players.
260  // Note we habe to have this external locking to prevent the games unlocking
261  // to access the players
262  for ( KGamePlayerList::iterator it = playerList()->begin(); it!=playerList()->end();it++ )
263  {
264  (*it)->dataHandler()->unlockDirectEmit();
265  // kDebug(11001) << "Player "<<player->id() << "to direct emit";
266  }
267 
268  emit signalLoad(stream);
269  return true;
270 }
271 
272 bool KGame::save(const QString& filename,bool saveplayers)
273 {
274  if (filename.isNull())
275  {
276  return false;
277  }
278  QFile f(filename);
279  if (!f.open(QIODevice::WriteOnly))
280  {
281  return false;
282  }
283  QDataStream s( &f );
284  save(s,saveplayers);
285  f.close();
286  return true;
287 }
288 
289 bool KGame::save(QDataStream &stream,bool saveplayers)
290 { return savegame(stream, false,saveplayers); }
291 
292 bool KGame::savegame(QDataStream &stream,bool /*network*/,bool saveplayers)
293 {
294  // Save Game Data
295 
296  // internal variables
297  qint32 c=cookie();
298  stream << c;
299 
300  uint p=(uint)policy();
301  stream << p;
302  stream << d->mUniquePlayerNumber;
303  int newseed=(int)d->mRandom->getLong(65535);
304  stream << newseed;
305  d->mRandom->setSeed(newseed);
306 
307  // Properties
308  dataHandler()->save(stream);
309 
310  // Save all data that need to be saved *before* the players are saved
311  emit signalSavePrePlayers(stream);
312 
313  if (saveplayers)
314  {
315  savePlayers(stream,playerList());
316  }
317  else
318  {
319  stream << (uint)0; // no players saved
320  }
321 
322  stream << (qint16)KGAME_LOAD_COOKIE;
323 
324  emit signalSave(stream);
325  return true;
326 }
327 
328 void KGame::savePlayer(QDataStream &stream,KPlayer* p)
329 {
330 // this could be in KGameMessage as well
331  stream << (qint32)p->rtti();
332  stream << (qint32)p->id();
333  stream << (qint32)p->calcIOValue();
334  p->save(stream);
335 }
336 
337 void KGame::savePlayers(QDataStream &stream, KGamePlayerList *list)
338 {
339  if (!list)
340  {
341  list=playerList();
342  }
343 
344  qint32 cnt=list->count();
345  kDebug(11001) << "Saving KGame" << cnt << "KPlayer objects";
346  stream << cnt;
347 
348  for ( KGamePlayerList::iterator it = playerList()->begin(); it!=playerList()->end();it++ )
349  {
350  savePlayer(stream,*it);
351  }
352 }
353 
354 KPlayer *KGame::createPlayer(int /*rtti*/,int /*io*/,bool /*isvirtual*/)
355 {
356  kWarning(11001) << " No user defined player created. Creating default KPlayer. This crashes if you have overwritten KPlayer!!!! ";
357  return new KPlayer;
358 }
359 KPlayer *KGame::loadPlayer(QDataStream& stream,bool isvirtual)
360 {
361  qint32 rtti,id,iovalue;
362  stream >> rtti >> id >> iovalue;
363  KPlayer *newplayer=findPlayer(id);
364  if (!newplayer)
365  {
366  kDebug(11001) << "Player "<< id << "not found...asking user to create one";
367  newplayer=createPlayer(rtti,iovalue,isvirtual);
368  //emit signalCreatePlayer(newplayer,rtti,iovalue,isvirtual,this);
369  }
370  /*
371  if (!newplayer)
372  {
373  kWarning(11001) << " No user defined player created. Creating default KPlayer. This crashes if you have overwritten KPlayer!!!! ";
374  newplayer=new KPlayer;
375  }
376  else
377  {
378  kDebug(11001) << " USER Player" << newplayer << "done player->rtti=" << newplayer->rtti() << "rtti=" << rtti;
379  }
380  */
381  newplayer->load(stream);
382  if (isvirtual)
383  {
384  newplayer->setVirtual(true);
385  }
386  return newplayer;
387 }
388 
389 // ----------------- Player handling -----------------------
390 
391 KPlayer * KGame::findPlayer(quint32 id) const
392 {
393  for ( KGamePlayerList::iterator it = d->mPlayerList.begin(); it!=d->mPlayerList.end();it++ )
394  {
395  if ((*it)->id() == id)
396  {
397  return *it;
398  }
399  }
400  for ( KGamePlayerList::iterator it = d->mInactivePlayerList.begin(); it!=d->mInactivePlayerList.end();it++ )
401  {
402  if ((*it)->id() == id)
403  {
404  return *it;
405  }
406  }
407  return 0;
408 }
409 
410 // it is necessary that addPlayer and systemAddPlayer are called in the same
411 // order. Ie if addPlayer(foo) followed by addPlayer(bar) is called, you must
412 // not call systemAddPlayer(bar) followed by systemAddPlayer(foo), as the
413 // mAddPlayerList would get confused. Should be no problem as long as comServer
414 // and the clients are working correctly.
415 // BUT: if addPlayer(foo) does not arrive by any reason while addPlayer(bar)
416 // does, we would be in trouble...
417 bool KGame::addPlayer(KPlayer* newplayer)
418 {
419  kDebug(11001) << ": " << "; maxPlayers=" << maxPlayers() << "playerCount=" << playerCount();
420  if (!newplayer)
421  {
422  kFatal(11001) << "trying to add NULL player in KGame::addPlayer()";
423  return false;
424  }
425 
426  if (maxPlayers() >= 0 && (int)playerCount() >= maxPlayers())
427  {
428  kWarning(11001) << "cannot add more than" << maxPlayers() << "players - deleting...";
429  return false;
430  }
431 
432  if (newplayer->id() == 0)
433  {
434  d->mUniquePlayerNumber++;
435  newplayer->setId(KGameMessage::createPlayerId(d->mUniquePlayerNumber, gameId()));
436  kDebug(11001) << "NEW!!! player" << newplayer << "now has id" << newplayer->id();
437  }
438  else
439  {
440  // this could happen in games which use their own ID management by certain
441  // reasons. that is NOT recommended
442  kDebug(11001) << "player" << newplayer << "already has an id:" << newplayer->id();
443  }
444 
445  QByteArray buffer;
446  QDataStream stream(&buffer,QIODevice::WriteOnly);
447  // We distinguis here what policy we have
448  if (policy()==PolicyLocal || policy()==PolicyDirty)
449  {
450  if ( !systemAddPlayer(newplayer) )
451  return false;
452  }
453  if (policy()==PolicyClean || policy()==PolicyDirty)
454  {
455  savePlayer(stream,newplayer);
456  // Store the player for delayed clean adding
457  if (policy()==PolicyClean)
458  {
459  d->mAddPlayerList.enqueue(newplayer);
460  }
461  sendSystemMessage(stream,(int)KGameMessage::IdAddPlayer, 0);
462  }
463  return true;
464 }
465 
466 bool KGame::systemAddPlayer(KPlayer* newplayer)
467 {
468  if (!newplayer)
469  {
470  kFatal(11001) << "trying to add NULL player in KGame::systemAddPlayer()";
471  return false ;
472  }
473  if (newplayer->id() == 0)
474  {
475  kWarning(11001) << "player" << newplayer << "has no ID";
476  }
477 
478  if (findPlayer(newplayer->id()))
479  {
480  kError(11001) << "ERROR: Double adding player !!!!! NOT GOOD !!!!!! " << newplayer->id() << "...I delete it again";
481  delete newplayer;
482  return false;
483  }
484  else
485  {
486  kDebug(11001) << "Trying to add player" << newplayer <<" maxPlayers="<<maxPlayers()<<" playerCount="<<playerCount();
487  // Add the player to the game
488  d->mPlayerList.append(newplayer);
489  newplayer->setGame(this);
490  kDebug(11001) << "Player: isVirtual=" << newplayer->isVirtual();
491  kDebug(11001) << " id=" << newplayer->id() << " #Players="
492  << d->mPlayerList.count() << "added" << newplayer
493  << " (virtual=" << newplayer->isVirtual() << ")";
494  emit signalPlayerJoinedGame(newplayer);
495  }
496  return true;
497 }
498 
499 // Called by the KPlayer destructor
500 void KGame::playerDeleted(KPlayer *player)
501 {
502  kDebug(11001) << ": id (" << player->id() << ") to be removed" << player;
503 
504  if (policy()==PolicyLocal || policy()==PolicyDirty)
505  {
506  systemRemovePlayer(player,false);
507  }
508  if (policy()==PolicyClean || policy()==PolicyDirty)
509  {
510  if (!player->isVirtual())
511  {
512  kDebug(11001) << ": sending IdRemovePlayer "<<player->id();
513  sendSystemMessage(player->id(), KGameMessage::IdRemovePlayer, 0);
514  }
515  }
516 }
517 
518 bool KGame::removePlayer(KPlayer * player, quint32 receiver)
519 {//transmit to all clients, or to receiver only
520  if (!player)
521  {
522  kFatal(11001) << "trying to remove NULL player in KGame::removePlayer( )" ;
523  return false;
524  }
525  kDebug(11001) << ": id (" << player->id() << ") to be removed" << player;
526 
527  if (policy()==PolicyLocal || policy()==PolicyDirty)
528  {
529  systemRemovePlayer(player,true);
530  return true; // player is gone
531  }
532  if (policy()==PolicyClean || policy()==PolicyDirty)
533  {
534  kDebug(11001) << ": sending IdRemovePlayer "<<player->id();
535  sendSystemMessage(player->id(),KGameMessage::IdRemovePlayer, receiver);
536  }
537  return true;
538  // we will receive the message in networkTransmission()
539 }
540 
541 void KGame::systemRemovePlayer(KPlayer* player,bool deleteit)
542 {
543  kDebug(11001) ;
544  if (!player)
545  {
546  kWarning(11001) << "cannot remove NULL player";
547  return;
548  }
549  systemRemove(player,deleteit);
550 
551  if (gameStatus()==(int)Run && playerCount()<minPlayers())
552  {
553  kWarning(11001) << ": not enough players, PAUSING game\n";
554  setGameStatus(Pause);
555  }
556 }
557 
558 bool KGame::systemRemove(KPlayer* p,bool deleteit)
559 {
560  if (!p)
561  {
562  kWarning(11001) << "cannot remove NULL player";
563  return false;
564  }
565  bool result;
566  kDebug(11001) << ": Player (" << p->id() << ") to be removed" << p;
567 
568  if (d->mPlayerList.count() == 0)
569  {
570  result = false;
571  }
572  else
573  {
574 
575  result = d->mPlayerList.removeAll(p);
576  }
577 
578  emit signalPlayerLeftGame(p);
579 
580  p->setGame(0);
581  if (deleteit)
582  {
583  delete p;
584  }
585 
586  return result;
587 }
588 
589 bool KGame::inactivatePlayer(KPlayer* player)
590 {
591  if (!player)
592  {
593  return false;
594  }
595  kDebug(11001) << "Inactivate player" << player->id();
596 
597  if (policy()==PolicyLocal || policy()==PolicyDirty)
598  {
599  if ( !systemInactivatePlayer(player) )
600  return false;
601  }
602  if (policy()==PolicyClean || policy()==PolicyDirty)
603  {
604  sendSystemMessage(player->id(), KGameMessage::IdInactivatePlayer);
605  }
606 
607  return true;
608 }
609 
610 bool KGame::systemInactivatePlayer(KPlayer* player)
611 {
612  if (!player || !player->isActive())
613  {
614  return false;
615  }
616  kDebug(11001) << "Inactivate player" << player->id();
617 
618  int pid=player->id();
619  // Virtual players cannot be deactivated. They will be removed
620  if (player->isVirtual())
621  {
622  systemRemovePlayer(player,true);
623  return false; // don't touch player after this!
624  }
625  else
626  {
627  d->mPlayerList.removeAll(player);
628  d->mInactivePlayerList.prepend(player);
629  player->setActive(false);
630  }
631  emit signalPlayerLeftGame(player);
632  if (isAdmin())
633  {
634  d->mInactiveIdList.prepend(pid);
635  }
636  return true;
637 }
638 
639 bool KGame::activatePlayer(KPlayer * player)
640 {
641  if (!player)
642  {
643  return false;
644  }
645  kDebug(11001) << ": activate" << player->id();
646  if (policy()==PolicyLocal || policy()==PolicyDirty)
647  {
648  if ( !systemActivatePlayer(player) )
649  return false;
650  }
651  if (policy()==PolicyClean || policy()==PolicyDirty )
652  {
653  sendSystemMessage(player->id(), KGameMessage::IdActivatePlayer);
654  }
655  return true;
656 }
657 
658 bool KGame::systemActivatePlayer(KPlayer* player)
659 {
660  if (!player || player->isActive())
661  {
662  return false;
663  }
664  kDebug(11001) << ": activate" << player->id();
665 
666  d->mInactivePlayerList.removeAll(player);
667  player->setActive(true);
668  if ( !addPlayer(player) ) // player is gone
669  return false;
670 
671  if (isAdmin())
672  {
673  d->mInactiveIdList.removeAll(player->id());
674  }
675  return true;
676 }
677 
678 // -------------------- Properties ---------------------------
679 
680 void KGame::setMaxPlayers(uint maxnumber)
681 { if (isAdmin()) { d->mMaxPlayer.changeValue(maxnumber); } }
682 
683 void KGame::setMinPlayers(uint minnumber)
684 { if (isAdmin()) { d->mMinPlayer.changeValue(minnumber); } }
685 
686 uint KGame::minPlayers() const
687 { return d->mMinPlayer.value(); }
688 
689 int KGame::maxPlayers() const
690 { return d->mMaxPlayer.value(); }
691 
692 uint KGame::playerCount() const
693 { return d->mPlayerList.count(); }
694 
695 int KGame::gameStatus() const
696 { return d->mGameStatus.value(); }
697 
698 bool KGame::isRunning() const
699 { return d->mGameStatus.value() == Run; }
700 
701 KGamePropertyHandler* KGame::dataHandler() const
702 { return d->mProperties; }
703 
704 
705 KGame::KGamePlayerList* KGame::inactivePlayerList()
706 { return &d->mInactivePlayerList; }
707 
708 const KGame::KGamePlayerList* KGame::inactivePlayerList() const
709 { return &d->mInactivePlayerList; }
710 
711 KGame::KGamePlayerList* KGame::playerList()
712 { return &d->mPlayerList; }
713 
714 const KGame::KGamePlayerList* KGame::playerList() const
715 { return &d->mPlayerList; }
716 
717 KRandomSequence* KGame::random() const
718 { return d->mRandom; }
719 
720 
721 bool KGame::sendPlayerInput(QDataStream &msg, KPlayer *player, quint32 sender)
722 {
723  if (!player)
724  {
725  kError(11001) << ": NULL player";
726  return false;
727  }
728  if (!isRunning())
729  {
730  kError(11001) << ": game not running";
731  return false;
732  }
733 
734  kDebug(11001) << ": transmitting playerInput over network";
735  sendSystemMessage(msg, (int)KGameMessage::IdPlayerInput, player->id(), sender);
736  return true;
737 }
738 
739 bool KGame::systemPlayerInput(QDataStream &msg, KPlayer *player, quint32 sender)
740 {
741  if (!player)
742  {
743  kError(11001) << ": NULL player";
744  return false;
745  }
746  if (!isRunning())
747  {
748  kError(11001) << ": game not running";
749  return false;
750  }
751  kDebug(11001) << "KGame: Got playerInput from messageServer... sender:" << sender;
752  if (playerInput(msg,player))
753  {
754  playerInputFinished(player);
755  }
756  else
757  {
758  kDebug(11001) <<": switching off player input";
759  // TODO: (MH 03-2003): We need an return option from playerInput so that
760  // the player's is not automatically disabled here
761  if (!player->asyncInput())
762  {
763  player->setTurn(false); // in turn based games we have to switch off input now
764  }
765  }
766  return true;
767 }
768 
769 
770 KPlayer * KGame::playerInputFinished(KPlayer *player)
771 {
772  if ( !player )
773  return 0;
774 
775  kDebug(11001) <<"player input finished for "<<player->id();
776  // Check for game over and if not allow the next player to move
777  int gameOver = 0;
778  if (gameSequence())
779  {
780  gameSequence()->setCurrentPlayer(player);
781  }
782  // do not call gameSequence()->checkGameOver() to keep backward compatibility!
783  gameOver = checkGameOver(player);
784  if (gameOver!=0)
785  {
786  player->setTurn(false);
787  setGameStatus(End);
788  emit signalGameOver(gameOver,player,this);
789  }
790  else if (!player->asyncInput())
791  {
792  player->setTurn(false); // in turn based games we have to switch off input now
793  if (gameSequence())
794  {
795  QTimer::singleShot(0,this,SLOT(prepareNext()));
796  }
797  }
798  return player;
799 }
800 
801 // Per default we do not do anything
802 int KGame::checkGameOver(KPlayer *player)
803 {
804  if (gameSequence())
805  {
806  return gameSequence()->checkGameOver(player);
807  }
808  return 0;
809 }
810 
811 void KGame::setGameSequence(KGameSequence* sequence)
812 {
813  delete d->mGameSequence;
814  d->mGameSequence = sequence;
815  if (d->mGameSequence)
816  {
817  d->mGameSequence->setGame(this);
818  }
819 }
820 
821 KGameSequence* KGame::gameSequence() const
822 {
823  return d->mGameSequence;
824 }
825 
826 void KGame::prepareNext()
827 {
828  if (gameSequence())
829  {
830  // we don't call gameSequence->nextPlayer() to keep old code working
831  nextPlayer(gameSequence()->currentPlayer());
832  }
833 }
834 
835 KPlayer *KGame::nextPlayer(KPlayer *last,bool exclusive)
836 {
837  if (gameSequence())
838  {
839  return gameSequence()->nextPlayer(last, exclusive);
840  }
841  return 0;
842 }
843 
844 void KGame::setGameStatus(int status)
845 {
846  kDebug(11001) << ": GAMESTATUS CHANGED to" << status;
847  if (status==(int)Run && playerCount()<minPlayers())
848  {
849  kDebug(11001) << ": not enough players, pausing game\n";
850  status=Pause;
851  }
852  d->mGameStatus = status;
853 }
854 
855 void KGame::networkTransmission(QDataStream &stream, int msgid, quint32 receiver, quint32 sender, quint32 /*clientID*/)
856 {//clientID is unused
857  // message targets a playerobject. If we find it we forward the message to the
858  // player. Otherwise we proceed here and hope the best that the user processes
859  // the message
860 
861 // kDebug(11001) << ": we="<<(int)gameId()<<" id="<<msgid<<" recv=" << receiver << "sender=" << sender;
862 
863 
864  // *first* notice the game that something has changed - so no return prevents
865  // this
866  emit signalMessageUpdate(msgid, receiver, sender);
867  if (KGameMessage::isPlayer(receiver))
868  {
869  //kDebug(11001) << "message id" << msgid << "seems to be for a player ("<<active=p->isActive()<<" recv="<< receiver;
870  KPlayer *p=findPlayer(receiver);
871  if (p && p->isActive())
872  {
873  p->networkTransmission(stream,msgid,sender);
874  return;
875  }
876  if (p)
877  {
878  kDebug(11001) << "player is here but not active";
879  }
880  else
881  {
882  kDebug(11001) << "no player found";
883  }
884  }
885  // If it is not for a player it is meant for us!!!! Otherwise the
886  // gamenetwork would not have passed the message to us!
887 
888  // GameProperties processed
889  if (d->mProperties->processMessage(stream, msgid, sender == gameId()))
890  {
891 // kDebug(11001 ) << "KGame: message taken by property - returning";
892  return ;
893  }
894 
895  switch(msgid)
896  {
897  case KGameMessage::IdSetupGame: // Client: First step in setup game
898  {
899  qint16 v;
900  qint32 c;
901  stream >> v >> c;
902  kDebug(11001) << " ===================> (Client) " << ": Got IdSetupGame ==================";
903  kDebug(11001) << "our game id is" << gameId() << "Lib version=" << v << "App Cookie=" << c;
904  // Verify identity of the network partners
905  if (c!=cookie())
906  {
907  kError(11001) << "IdGameSetup: Negotiate Game: cookie mismatch I'am="<<cookie()<<" master="<<c;
908  sendError(KGameError::Cookie, KGameError::errCookie(cookie(), c));
909  disconnect(); // disconnect from master
910  }
911  else if (v!=KGameMessage::version())
912  {
913  sendError(KGameError::Version, KGameError::errVersion(v));
914  disconnect(); // disconnect from master
915  }
916  else
917  {
918  setupGame(sender);
919  }
920  kDebug(11001) << "========== (Client) Setup game done\n";
921  }
922  break;
923  case KGameMessage::IdSetupGameContinue: // Master: second step in game setup
924  {
925  kDebug(11001) << "=====>(Master) " << " - IdSetupGameContinue";
926  setupGameContinue(stream, sender);
927  }
928  break;
929  case KGameMessage::IdActivatePlayer: // Activate Player
930  {
931  int id;
932  stream >> id;
933  kDebug(11001) << "Got IdActivatePlayer id=" << id;
934  if (sender!=gameId() || policy()!=PolicyDirty)
935  {
936  systemActivatePlayer(findPlayer(id));
937  }
938  }
939  break;
940  case KGameMessage::IdInactivatePlayer: // Inactivate Player
941  {
942  int id;
943  stream >> id;
944  kDebug(11001) << "Got IdInactivatePlayer id=" << id;
945  if (sender!=gameId() || policy()!=PolicyDirty)
946  {
947  systemInactivatePlayer(findPlayer(id));
948  }
949  }
950  break;
951  case KGameMessage::IdAddPlayer:
952  {
953  kDebug(11001) << ": Got IdAddPlayer";
954  if (sender!=gameId() || policy()!=PolicyDirty)
955  {
956  KPlayer *newplayer=0;
957  // We sent the message so the player is already available
958  if (sender==gameId())
959  {
960  kDebug(11001) << "dequeue previously added player";
961  newplayer = d->mAddPlayerList.dequeue();
962  }
963  else
964  {
965  newplayer=loadPlayer(stream,true);
966  }
967  systemAddPlayer(newplayer);// the final, local, adding
968  //systemAddPlayer(stream);
969  }
970  }
971  break;
972  case KGameMessage::IdRemovePlayer: // Client should delete player id
973  {
974  int id;
975  stream >> id;
976  kDebug(11001) << ": Got IdRemovePlayer" << id;
977  KPlayer *p=findPlayer(id);
978  if (p)
979  {
980  // Otherwise the player is already removed
981  if (sender!=gameId() || policy()!=PolicyDirty)
982  {
983  systemRemovePlayer(p,true);
984  }
985  }
986  else
987  {
988  kWarning(11001) << "Cannot find player" << id;
989  }
990  }
991  break;
992  case KGameMessage::IdGameLoad:
993  {
994  kDebug(11001) << "====> (Client) " << ": Got IdGameLoad";
995  loadgame(stream,true,false);
996  }
997  break;
998  case KGameMessage::IdGameSetupDone:
999  {
1000  int cid;
1001  stream >> cid;
1002  kDebug(11001) << "====> (CLIENT) " << ": Got IdGameSetupDone for client "
1003  << cid << "we are =" << gameId();
1004  sendSystemMessage(gameId(), KGameMessage::IdGameConnected, 0);
1005  }
1006  break;
1007  case KGameMessage::IdGameConnected:
1008  {
1009  int cid;
1010  stream >> cid;
1011  kDebug(11001) << "====> (ALL) " << ": Got IdGameConnected for client "<< cid << "we are =" << gameId();
1012  emit signalClientJoinedGame(cid,this);
1013  }
1014  break;
1015 
1016  case KGameMessage::IdSyncRandom: // Master forces a new random seed on us
1017  {
1018  int newseed;
1019  stream >> newseed;
1020  kDebug(11001) << "CLIENT: setting random seed to" << newseed;
1021  d->mRandom->setSeed(newseed);
1022  }
1023  break;
1024  case KGameMessage::IdDisconnect:
1025  {
1026  // if we disconnect we *always* start a local game.
1027  // this could lead into problems if we just change the message server
1028  if (sender != gameId())
1029  {
1030  kDebug(11001) << "client" << sender << "leaves game";
1031  return;
1032  }
1033  kDebug(11001) << "leaving the game";
1034  // start a new local game
1035  // no other client is by default connected to this so this call should be
1036  // enough
1037  setMaster();
1038  }
1039  break;
1040  default:
1041  {
1042  if (msgid < KGameMessage::IdUser)
1043  {
1044  kError(11001) << "incorrect message id" << msgid << " - emit anyway";
1045  }
1046  kDebug(11001) << ": User data msgid" << msgid;
1047  emit signalNetworkData(msgid - KGameMessage::IdUser,((QBuffer*)stream.device())->readAll(),receiver,sender);
1048  }
1049  break;
1050  }
1051 
1052 }
1053 
1054 // called by the IdSetupGameContinue Message - MASTER SIDE
1055 // Here the master needs to decide which players can take part at the game
1056 // and which will be deactivated
1057 void KGame::setupGameContinue(QDataStream& stream, quint32 sender)
1058 {
1059  KPlayer *player;
1060  qint32 cnt;
1061  int i;
1062  stream >> cnt;
1063 
1064  QList<int> inactivateIds;
1065 
1066  KGamePlayerList newPlayerList;
1067  for (i=0;i<cnt;i++)
1068  {
1069  player=loadPlayer(stream,true);
1070  kDebug(11001) << "Master got player" << player->id() <<" rawgame=" << KGameMessage::rawGameId(player->id()) << "from sender" << sender;
1071  if (KGameMessage::rawGameId(player->id()) != sender)
1072  {
1073  kError(11001) << "Client tries to add player with wrong game id - cheat possible";
1074  }
1075  else
1076  {
1077  newPlayerList.append(player);
1078  kDebug(11001) << "newplayerlist appended" << player->id();
1079  }
1080  }
1081 
1082  newPlayersJoin(playerList(),&newPlayerList,inactivateIds);
1083 
1084 
1085  kDebug(11001) << "Master calculates how many players to activate client has cnt=" << cnt;
1086  kDebug(11001) << "The game has" << playerCount() << "active players";
1087  kDebug(11001) << "The user deactivated "<< inactivateIds.count() << "player already";
1088  kDebug(11001) << "MaxPlayers for this game is" << maxPlayers();
1089 
1090  // Do we have too many players? (After the programmer disabled some?)
1091  // MH: We cannot use have player here as it CHANGES in the loop
1092  // int havePlayers = cnt+playerCount()-inactivateIds.count();
1093  kDebug(11001) << "havePlayers" << cnt+playerCount()-inactivateIds.count();
1094  while (maxPlayers() > 0 && maxPlayers() < (int)(cnt+playerCount() - inactivateIds.count()))
1095  {
1096  kDebug(11001) << " Still to deacticvate "
1097  << (int)(cnt+playerCount()-inactivateIds.count())-(int)maxPlayers()
1098 ;
1099  KPlayer *currentPlayer=0;
1100  int currentPriority=0x7fff; // MAX_UINT (16bit?) to get the maximum of the list
1101  // find lowest network priority which is not yet in the newPlayerList
1102  // do this for the new players
1103  for ( KGamePlayerList::iterator it = newPlayerList.begin(); it!=newPlayerList.end();it++ )
1104  {
1105  KPlayer* player = *it;
1106  // Already in the list
1107  if (inactivateIds.indexOf(player->id())!=-1)
1108  {
1109  continue;
1110  }
1111  if (player->networkPriority()<currentPriority)
1112  {
1113  currentPriority=player->networkPriority();
1114  currentPlayer=player;
1115  }
1116  }
1117 
1118  // find lowest network priority which is not yet in the newPlayerList
1119  // Do this for the network players
1120  for ( KGamePlayerList::iterator it = d->mPlayerList.begin(); it!=d->mPlayerList.end();it++ )
1121  {
1122  KPlayer* player = *it;
1123  // Already in the list
1124  if (inactivateIds.indexOf(player->id())!=-1)
1125  {
1126  continue;
1127  }
1128  if (player->networkPriority()<currentPriority)
1129  {
1130  currentPriority=player->networkPriority();
1131  currentPlayer=player;
1132  }
1133  }
1134 
1135  // add it to inactivateIds
1136  if (currentPlayer)
1137  {
1138  kDebug(11001) << "Marking player" << currentPlayer->id() << "for inactivation";
1139  inactivateIds.append(currentPlayer->id());
1140  }
1141  else
1142  {
1143  kError(11001) << "Couldn't find a player to dectivate..That is not so good...";
1144  break;
1145  }
1146  }
1147 
1148  kDebug(11001) << "Alltogether deactivated" << inactivateIds.count() << "players";
1149 
1150  QList<int>::Iterator it;
1151  for ( it = inactivateIds.begin(); it != inactivateIds.end(); ++it )
1152  {
1153  int pid=*it;
1154  kDebug(11001) << "pid=" << pid;
1155  }
1156 
1157  // Now deactivate the network players from the inactivateId list
1158  //QValueList<int>::Iterator it;
1159  for ( it = inactivateIds.begin(); it != inactivateIds.end(); ++it )
1160  {
1161  int pid=*it;
1162  if (KGameMessage::rawGameId(pid) == sender)
1163  {
1164  continue; // client's player
1165  }
1166  kDebug(11001) << " -> the network needs to deactivate" << pid;
1167  player=findPlayer(pid);
1168  if (player)
1169  {
1170  // We have to make REALLY sure that the player is gone. With any policy
1171  if (systemInactivatePlayer(player) && policy()!=PolicyLocal)
1172  {
1173  sendSystemMessage(player->id(), KGameMessage::IdInactivatePlayer);
1174  } else
1175  player = 0;
1176  }
1177  else
1178  {
1179  kError(11001) << "We should deactivate a player, but cannot find it...not good.";
1180  }
1181  }
1182 
1183  // Now send out the player list which the client can activate
1184  for ( KGamePlayerList::iterator it = newPlayerList.begin(); it!=newPlayerList.end();it++ )
1185  {
1186  KPlayer* player = *it;
1187  kDebug(11001) << "newplayerlist contains" << player->id();
1188  // Only activate what is not in the list
1189  if (inactivateIds.indexOf(player->id())!=-1)
1190  {
1191  continue;
1192  }
1193  kDebug(11001) << " -> the client can ******** reactivate ******** " << player->id();
1194  sendSystemMessage(player->id(), KGameMessage::IdActivatePlayer, sender);
1195  }
1196 
1197  // Save the game over the network
1198  QByteArray bufferS;
1199  QDataStream streamS(&bufferS,QIODevice::WriteOnly);
1200  // Save game over netowrk and save players
1201  savegame(streamS,true,true);
1202  sendSystemMessage(streamS,KGameMessage::IdGameLoad,sender);
1203 
1204 
1205  // Only to the client first , as the client will add players
1206  sendSystemMessage(sender, KGameMessage::IdGameSetupDone, sender);
1207 
1208  //Finally delete content of the newPlayerList
1209  qDeleteAll(newPlayerList);
1210  newPlayerList.clear();
1211 }
1212 
1213 // called by the IdSetupGame Message - CLIENT SIDE
1214 // Client needs to prepare for network transfer
1215 void KGame::setupGame(quint32 sender)
1216 {
1217  QByteArray bufferS;
1218  QDataStream streamS(&bufferS,QIODevice::WriteOnly);
1219 
1220  // Deactivate all players
1221  KGamePlayerList mTmpList(d->mPlayerList); // we need copy otherwise the removal crashes
1222  qint32 cnt=mTmpList.count();
1223  kDebug(11001) << "Client: playerlistcount=" << d->mPlayerList.count() << "tmplistcout=" << cnt;
1224 
1225  streamS << cnt;
1226 
1227  KGamePlayerList::iterator it = mTmpList.begin();
1228  KPlayer *player;
1229  while (it!=mTmpList.end())
1230  {
1231  player=*it;
1232  ++it;
1233  --cnt;
1234 
1235  if (!systemInactivatePlayer(player))
1236  continue; // player is gone
1237 
1238  // Give the new game id to all players (which are inactivated now)
1239  player->setId(KGameMessage::createPlayerId(player->id(),gameId()));
1240 
1241  // Save it for the master to decide what to do
1242  savePlayer(streamS,player);
1243  }
1244  if (d->mPlayerList.count() > 0 || cnt!=0)
1245  {
1246  kFatal(11001) << "KGame::setupGame(): Player list is not empty! or cnt!=0=" <<cnt;
1247  }
1248 
1249  sendSystemMessage(streamS,KGameMessage::IdSetupGameContinue,sender);
1250 }
1251 
1252 // unused by KGame
1253 void KGame::syncRandom()
1254 {
1255  int newseed=(int)d->mRandom->getLong(65535);
1256  sendSystemMessage(newseed,KGameMessage::IdSyncRandom); // Broadcast
1257  d->mRandom->setSeed(newseed);
1258 }
1259 
1260 void KGame::Debug()
1261 {
1262  KGameNetwork::Debug();
1263  kDebug(11001) << "------------------- KGAME -------------------------";
1264  kDebug(11001) << "this: " << this;
1265  kDebug(11001) << "uniquePlayer " << d->mUniquePlayerNumber;
1266  kDebug(11001) << "gameStatus " << gameStatus();
1267  kDebug(11001) << "MaxPlayers : " << maxPlayers();
1268  kDebug(11001) << "NoOfPlayers : " << playerCount();
1269  kDebug(11001) << "NoOfInactive: " << d->mInactivePlayerList.count();
1270  kDebug(11001) << "---------------------------------------------------";
1271 }
1272 
1273 void KGame::slotClientConnected(quint32 clientID)
1274 {
1275  if (isAdmin())
1276  {
1277  negotiateNetworkGame(clientID);
1278  }
1279 }
1280 
1281 void KGame::slotServerDisconnected() // Client side
1282 {
1283  kDebug(11001) << "======= SERVER DISCONNECT =======";
1284  kDebug(11001) << "+++ (CLIENT)++++++++" << ": our GameID="<<gameId();
1285 
1286  int oldgamestatus=gameStatus();
1287 
1288 
1289  KGamePlayerList removeList;
1290  kDebug(11001) << "Playerlist of client=" << d->mPlayerList.count() << "count";
1291  kDebug(11001) << "Inactive Playerlist of client=" << d->mInactivePlayerList.count() << "count";
1292  for ( KGamePlayerList::iterator it = d->mPlayerList.begin(); it!=d->mPlayerList.end();it++ )
1293  {
1294  KPlayer* player = *it;
1295  // TODO: CHECK: id=0, could not connect to server in the first place??
1296  if (KGameMessage::rawGameId(player->id()) != gameId() && gameId()!=0)
1297  {
1298  kDebug(11001) << "Player" << player->id() << "belongs to a removed game";
1299  removeList.append(player);
1300  }
1301  }
1302 
1303  for ( KGamePlayerList::iterator it = removeList.begin(); it!=removeList.end();it++ )
1304  {
1305  KPlayer* player = *it;
1306  bool remove = true;
1307  emit signalReplacePlayerIO(player, &remove);
1308  if (remove)
1309  {
1310  kDebug(11001) << " ---> Removing player" << player->id();
1311  systemRemovePlayer(player,true); // no network necessary
1312  }
1313  }
1314 
1315  setMaster();
1316  kDebug(11001) << "our game id is after setMaster" << gameId();
1317 
1318  KGamePlayerList mReList(d->mInactivePlayerList);
1319  for ( KGamePlayerList::iterator it = mReList.begin(); it!=mReList.end();it++ )
1320  {
1321  KPlayer* player = *it;
1322  // TODO ?check for priority? Sequence should be ok
1323  if ((int)playerCount()<maxPlayers() || maxPlayers()<0)
1324  {
1325  systemActivatePlayer(player);
1326  }
1327  }
1328  kDebug(11001) << "Players activated player-cnt=" << playerCount();
1329 
1330  for ( KGamePlayerList::iterator it = d->mPlayerList.begin(); it!=d->mPlayerList.end();it++ )
1331  {
1332  KPlayer* player = *it;
1333  int oldid=player->id();
1334  d->mUniquePlayerNumber++;
1335  player->setId(KGameMessage::createPlayerId(d->mUniquePlayerNumber,gameId()));
1336  kDebug(11001) << "Player id" << oldid <<" changed to" << player->id() << "as we are now local";
1337  }
1338  // TODO clear inactive lists ?
1339  Debug();
1340  for ( KGamePlayerList::iterator it = d->mPlayerList.begin(); it!=d->mPlayerList.end();it++ )
1341  {
1342  KPlayer* player = *it;
1343  player->Debug();
1344  }
1345  kDebug(11001) << "+++++++++++" << "DONE=";
1346  emit signalClientLeftGame(0,oldgamestatus,this);
1347 }
1348 
1349 void KGame::slotClientDisconnected(quint32 clientID,bool /*broken*/) // server side
1350 {
1351  kDebug(11001) << "++++(SERVER)+++++++" << "clientId=" << clientID;
1352 
1353  int oldgamestatus=gameStatus();
1354 
1355  KPlayer *player;
1356  KGamePlayerList removeList;
1357  kDebug(11001) << "Playerlist of client=" << d->mPlayerList.count() << "count";
1358  for ( KGamePlayerList::iterator it = d->mPlayerList.begin(); it!=d->mPlayerList.end();it++ )
1359  {
1360  KPlayer* player = *it;
1361  if (KGameMessage::rawGameId(player->id())==clientID)
1362  {
1363  kDebug(11001) << "Player" << player->id() << "belongs to the removed game";
1364  removeList.append(player);
1365  }
1366  }
1367 
1368  for ( KGamePlayerList::iterator it = removeList.begin(); it!=removeList.end();it++ )
1369  {
1370  KPlayer* player = *it;
1371  // try to replace the KGameIO first
1372  bool remove = true;
1373  emit signalReplacePlayerIO(player, &remove);
1374  if (remove) {
1375  // otherwise (no new KGameIO) remove the player
1376  kDebug(11001) << " ---> Removing player" << player->id();
1377  removePlayer(player,0);
1378  }
1379  }
1380 
1381  // Now add inactive players - sequence should be ok
1382  // TODO remove players from removed game
1383  for (int idx=0;idx<d->mInactiveIdList.count();idx++)
1384  {
1385  int it1 = d->mInactiveIdList.at(idx);
1386  player = findPlayer(it1);
1387  if (((int)playerCount() < maxPlayers() || maxPlayers() < 0) && player && KGameMessage::rawGameId(it1) != clientID)
1388  {
1389  activatePlayer(player);
1390  }
1391  }
1392  emit signalClientLeftGame(clientID,oldgamestatus,this);
1393 }
1394 
1395 
1396 // -------------------- Synchronization -----------------------
1397 
1398 // this initializes a newly connected client.
1399 // we send the number of players (including type) as well as game status and
1400 // properties to the client. After the initialization has been completed both
1401 // clients should have the same status (ie players, properties, etc)
1402 void KGame::negotiateNetworkGame(quint32 clientID)
1403 {
1404  kDebug(11001) << "===========================" << ": clientID=" << clientID << " =========================== ";
1405  if (!isAdmin())
1406  {
1407  kError(11001) << ": Serious WARNING..only gameAdmin should call this";
1408  return ;
1409  }
1410 
1411  QByteArray buffer;
1412  QDataStream streamGS(&buffer,QIODevice::WriteOnly);
1413 
1414  // write Game setup specific data
1415  //streamGS << (qint32)maxPlayers();
1416  //streamGS << (qint32)minPlayers();
1417 
1418  // send to the newly connected client *only*
1419  qint16 v=KGameMessage::version();
1420  qint32 c=cookie();
1421  streamGS << v << c;
1422  sendSystemMessage(streamGS, KGameMessage::IdSetupGame, clientID);
1423 }
1424 
1425 bool KGame::sendGroupMessage(const QByteArray &msg, int msgid, quint32 sender, const QString& group)
1426 {
1427 // AB: group must not be i18n'ed!! we should better use an id for group and use
1428 // a groupName() for the name // FIXME
1429 
1430  for ( KGamePlayerList::iterator it = d->mPlayerList.begin(); it!=d->mPlayerList.end();it++ )
1431  {
1432  KPlayer* player = *it;
1433  if (player && player->group()==group)
1434  {
1435  sendMessage(msg,msgid,player->id(), sender);
1436  }
1437  }
1438  return true;
1439 }
1440 
1441 bool KGame::sendGroupMessage(const QDataStream &msg, int msgid, quint32 sender, const QString& group)
1442 { return sendGroupMessage(((QBuffer*)msg.device())->buffer(), msgid, sender, group); }
1443 
1444 bool KGame::sendGroupMessage(const QString& msg, int msgid, quint32 sender, const QString& group)
1445 {
1446  QByteArray buffer;
1447  QDataStream stream(&buffer, QIODevice::WriteOnly);
1448  stream << msg;
1449  return sendGroupMessage(stream, msgid, sender, group);
1450 }
1451 
1452 bool KGame::addProperty(KGamePropertyBase* data)
1453 { return dataHandler()->addProperty(data); }
1454 
1455 bool KGame::sendPlayerProperty(int msgid, QDataStream& s, quint32 playerId)
1456 { return sendSystemMessage(s, msgid, playerId); }
1457 
1458 void KGame::sendProperty(int msgid, QDataStream& stream, bool* sent)
1459 {
1460  bool s = sendSystemMessage(stream, msgid);
1461  if (s)
1462  {
1463  *sent = true;
1464  }
1465 }
1466 
1467 void KGame::emitSignal(KGamePropertyBase *me)
1468 {
1469  emit signalPropertyChanged(me,this);
1470 }
1471 
1472 KGamePropertyBase* KGame::findProperty(int id) const
1473 { return d->mProperties->find(id); }
1474 
1475 KGame::GamePolicy KGame::policy() const
1476 {
1477  return d->mPolicy;
1478 }
1479 void KGame::setPolicy(GamePolicy p,bool recursive)
1480 {
1481  // Set KGame policy
1482  d->mPolicy=p;
1483  if (recursive)
1484  {
1485  // Set all KGame property policy
1486  dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false);
1487 
1488  // Set all KPLayer (active or inactive) property policy
1489  for ( KGamePlayerList::iterator it = d->mPlayerList.begin(); it!=d->mPlayerList.end();it++ )
1490  {
1491  (*it)->dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false);
1492  }
1493  for ( KGamePlayerList::iterator it = d->mInactivePlayerList.begin(); it!=d->mInactivePlayerList.end();it++ )
1494  {
1495  (*it)->dataHandler()->setPolicy((KGamePropertyBase::PropertyPolicy)p,false);
1496  }
1497  }
1498 }
1499 
1500 /*
1501  * vim: et sw=2
1502  */
KGameError::Cookie
Definition: kgameerror.h:36
KGameSequence
This class takes care of round or move management as well of the gameover condition.
Definition: kgamesequence.h:44
KGame::reset
virtual bool reset()
Resets the game, i.e.
Definition: kgame.cpp:130
KGame::setMaxPlayers
void setMaxPlayers(uint maxnumber)
Set the maximal number of players.
Definition: kgame.cpp:680
KGame::emitSignal
void emitSignal(KGamePropertyBase *me)
Called by KGamePropertyHandler only! Internal function!
Definition: kgame.cpp:1467
KGameError::errCookie
static QByteArray errCookie(int localCookie, int remoteCookie)
Generate an error message with Erorr Code = ErrCookie.
Definition: kgameerror.cpp:35
KGameNetwork::sendMessage
bool sendMessage(const QByteArray &buffer, int msgid, quint32 receiver=0, quint32 sender=0)
Send a network message msg with a given message ID msgid to all clients.
Definition: kgamenetwork.cpp:459
KGame::signalSavePrePlayers
void signalSavePrePlayers(QDataStream &stream)
The game will be saved to the given stream.
KGameMessage::createPlayerId
static quint32 createPlayerId(int player, quint32 game)
Creates a fully qualified player ID which contains the original player id in the lower bits and the g...
Definition: kgamemessage.cpp:27
KGame::deleteInactivePlayers
void deleteInactivePlayers()
Definition: kgame.cpp:155
KGame::addPlayer
bool addPlayer(KPlayer *newplayer)
Note that KPlayer::save must be implemented properly, as well as KPlayer::rtti This will only send a ...
Definition: kgame.cpp:417
KGamePropertyHandler::lockDirectEmit
void lockDirectEmit()
Called by the KGame or KPlayer object or the handler itself to delay emmiting of signals.
Definition: kgamepropertyhandler.cpp:276
KGameMessage::IdGameLoad
Definition: kgamemessage.h:143
KPlayer::setVirtual
void setVirtual(bool v)
Definition: kplayer.cpp:253
KPlayer::id
quint32 id() const
Returns the id of the player.
Definition: kplayer.cpp:247
KGameNetwork::signalConnectionBroken
void signalConnectionBroken()
Our connection to the KMessageServer has broken.
KGameMessage::IdUser
Definition: kgamemessage.h:169
KGame::systemPlayerInput
virtual bool systemPlayerInput(QDataStream &msg, KPlayer *player, quint32 sender=0)
Called when a player input arrives from KMessageServer.
Definition: kgame.cpp:739
QQueue< KPlayer * >
KGame::signalSave
void signalSave(QDataStream &stream)
The game will be saved to the given stream.
KGame::savePlayers
void savePlayers(QDataStream &stream, KGamePlayerList *list=0)
Save the player list to a stream.
Definition: kgame.cpp:337
KGame::policy
GamePolicy policy() const
Definition: kgame.cpp:1475
KGame::systemAddPlayer
bool systemAddPlayer(KPlayer *newplayer)
Adds a player to the game.
Definition: kgame.cpp:466
kgame.h
KGame::removePlayer
bool removePlayer(KPlayer *player)
Sends a message over the network, msgid=IdRemovePlayer.
Definition: kgame.h:220
QByteArray
KGame::loadgame
virtual bool loadgame(QDataStream &stream, bool network, bool reset)
Load a saved game, from file OR network.
Definition: kgame.cpp:181
KGameNetwork::sendError
void sendError(int error, const QByteArray &message, quint32 receiver=0, quint32 sender=0)
Sends a network message.
Definition: kgamenetwork.cpp:462
KGameNetwork::signalClientConnected
void signalClientConnected(quint32 clientID)
This signal is emitted whenever the KMessageServer sends us a message that a new client connected...
KPlayer::setTurn
bool setTurn(bool b, bool exclusive=true)
Sets whether this player is the next to turn.
Definition: kplayer.cpp:342
KPlayer::calcIOValue
int calcIOValue()
Calculates a checksum over the IO devices.
Definition: kplayer.cpp:331
QDataStream
KGamePropertyHandler
A collection class for KGameProperty objects.
Definition: kgamepropertyhandler.h:73
QObject::sender
QObject * sender() const
KGame::systemInactivatePlayer
bool systemInactivatePlayer(KPlayer *player)
inactivates player.
Definition: kgame.cpp:610
KGame::signalLoadPrePlayers
void signalLoadPrePlayers(QDataStream &stream)
The game will be loaded from the given stream.
KGame::systemRemovePlayer
void systemRemovePlayer(KPlayer *player, bool deleteit)
Removes a player from the game.
Definition: kgame.cpp:541
KGameError::Version
Definition: kgameerror.h:37
KGamePropertyBase::PropertyPolicy
PropertyPolicy
The policy of the property.
Definition: kgameproperty.h:112
KGame::negotiateNetworkGame
virtual void negotiateNetworkGame(quint32 clientID)
This member function will transmit e.g.
Definition: kgame.cpp:1402
KGame::activatePlayer
bool activatePlayer(KPlayer *player)
sends activate player: internal use only?
Definition: kgame.cpp:639
KGameMessage::isPlayer
static bool isPlayer(quint32 id)
Checks whether a message receiver/sender is a player.
Definition: kgamemessage.cpp:45
KGameMessage::IdRemovePlayer
Definition: kgamemessage.h:155
KGameMessage::IdDisconnect
Definition: kgamemessage.h:146
KGameMessage::IdGameSetupDone
Definition: kgamemessage.h:147
KGame::gameStatus
int gameStatus() const
returns the game status, ie running,pause,ended,...
Definition: kgame.cpp:695
KPlayer::Debug
void Debug()
Gives debug output of the game status.
Definition: kplayer.cpp:483
QBuffer
KGame::signalClientLeftGame
void signalClientLeftGame(int clientID, int oldgamestatus, KGame *me)
This signal is emitted after a network partner left the game (either by a broken connection or volunt...
KGamePropertyHandler::load
virtual bool load(QDataStream &stream)
Loads properties from the datastream.
Definition: kgamepropertyhandler.cpp:181
KGame::playerInput
virtual bool playerInput(QDataStream &msg, KPlayer *player)=0
A player input occurred.
KGame::End
Definition: kgame.h:123
KGame::newPlayersJoin
virtual void newPlayersJoin(KGamePlayerList *oldplayer, KGamePlayerList *newplayer, QList< int > &inactivate)
This virtual function can be overwritten for your own player management.
Definition: kgame.h:750
KGame::setMinPlayers
void setMinPlayers(uint minnumber)
Set the minimal number of players.
Definition: kgame.cpp:683
KGame::dataHandler
KGamePropertyHandler * dataHandler() const
Returns a pointer to the KGame property handler.
Definition: kgame.cpp:701
KGame::inactivatePlayer
bool inactivatePlayer(KPlayer *player)
sends inactivate player: internal use only?
Definition: kgame.cpp:589
KPlayer::setId
void setId(quint32 i)
Definition: kplayer.cpp:228
KGameError::errVersion
static QByteArray errVersion(int remoteVersion)
Definition: kgameerror.cpp:26
KGameNetwork::cookie
int cookie() const
Application cookie.
Definition: kgamenetwork.cpp:98
KGame::sendGroupMessage
bool sendGroupMessage(const QByteArray &msg, int msgid, quint32 sender, const QString &group)
See KGameNetwork::sendMessage.
Definition: kgame.cpp:1425
QFile
KGame::deletePlayers
void deletePlayers()
Definition: kgame.cpp:137
KGame::slotServerDisconnected
void slotServerDisconnected()
This slot is called whenever the connection to the server is lost (ie the signal KGameNetwork::signal...
Definition: kgame.cpp:1281
KPlayer::isVirtual
bool isVirtual() const
Is this player a virtual player, ie is it created by mirroring a real player from another network gam...
Definition: kplayer.cpp:256
QString::isNull
bool isNull() const
KGame::signalLoad
void signalLoad(QDataStream &stream)
The game will be loaded from the given stream.
KGame::Pause
Definition: kgame.h:122
QList::indexOf
int indexOf(const T &value, int from) const
KGame::GamePolicy
GamePolicy
The policy of the property.
Definition: kgame.h:88
KGame::Debug
virtual void Debug()
Gives debug output of the game status.
Definition: kgame.cpp:1260
KGame::Run
Definition: kgame.h:121
KGameSequence::checkGameOver
virtual int checkGameOver(KPlayer *player)
Check whether the game is over.
Definition: kgamesequence.cpp:141
KGame::PolicyDirty
Definition: kgame.h:92
KGame::savegame
virtual bool savegame(QDataStream &stream, bool network, bool saveplayers)
Save a game, to file OR network.
Definition: kgame.cpp:292
KGame::savePlayer
void savePlayer(QDataStream &stream, KPlayer *player)
Prepare a player for being added.
Definition: kgame.cpp:328
QList::count
int count(const T &value) const
KGame::checkGameOver
virtual int checkGameOver(KPlayer *player)
Definition: kgame.cpp:802
kgamepropertyhandler.h
KGamePropertyHandler::save
virtual bool save(QDataStream &stream)
Saves properties into the datastream.
Definition: kgamepropertyhandler.cpp:203
QList::append
void append(const T &value)
kgameproperty.h
KGame::random
KRandomSequence * random() const
Returns a pointer to the game's KRandomSequence.
Definition: kgame.cpp:717
KPlayer::setActive
void setActive(bool v)
Set an player as active (true) or inactive (false)
Definition: kplayer.cpp:160
KGame::playerInputFinished
KPlayer * playerInputFinished(KPlayer *player)
Called after the player input is processed by the game.
Definition: kgame.cpp:770
KGame::sendPlayerProperty
bool sendPlayerProperty(int msgid, QDataStream &s, quint32 playerId)
This is called by KPlayer::sendProperty only! Internal function!
Definition: kgame.cpp:1455
KGame::PolicyLocal
Definition: kgame.h:93
KGame::inactivePlayerList
KGamePlayerList * inactivePlayerList()
Returns a list of all inactive players.
Definition: kgame.cpp:705
QObject
KGame::isRunning
bool isRunning() const
Is the game running.
Definition: kgame.cpp:698
KGameSequence::nextPlayer
virtual KPlayer * nextPlayer(KPlayer *last, bool exclusive=true)
Select the next player in a turn based game.
Definition: kgamesequence.cpp:71
KGame::Init
Definition: kgame.h:120
KPlayer::load
virtual bool load(QDataStream &stream)
Load a saved player, from file OR network.
Definition: kplayer.cpp:370
KGamePropertyBase::IdMinPlayer
Definition: kgameproperty.h:59
KPlayer::group
virtual const QString & group() const
Query the group the player belongs to.
Definition: kplayer.cpp:238
KPlayer::asyncInput
bool asyncInput() const
Query whether this player does asynchronous input.
Definition: kplayer.cpp:150
KPlayer::networkPriority
int networkPriority() const
Returns whether this player can be replaced by a network connection player.
Definition: kplayer.cpp:265
KGame::signalPlayerJoinedGame
void signalPlayerJoinedGame(KPlayer *player)
a player joined the game
KGameMessage::IdPlayerInput
Definition: kgamemessage.h:162
KGameSequence::setCurrentPlayer
virtual void setCurrentPlayer(KPlayer *p)
Definition: kgamesequence.cpp:66
KGame::findPlayer
KPlayer * findPlayer(quint32 id) const
Returns the player object for a given player id.
Definition: kgame.cpp:391
kgamesequence.h
KPlayer::save
virtual bool save(QDataStream &stream)
Save a player to a file OR to network.
Definition: kplayer.cpp:396
QString
kgameio.h
QList< KPlayer * >
KGame::slotClientDisconnected
void slotClientDisconnected(quint32 clientId, bool broken)
This slot is called whenever the connection to a client is lost (ie the signal KGameNetwork::signalCl...
Definition: kgame.cpp:1349
KGame::signalLoadError
void signalLoadError(QDataStream &stream, bool network, int cookie, bool &result)
Is emmited if a game with a different version cookie is loaded.
KGame::KGamePlayerList
QList< KPlayer * > KGamePlayerList
Definition: kgame.h:65
QFile::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
kgamemessage.h
KPlayer
Base class for a game player.
Definition: kplayer.h:69
KGameMessage::IdSyncRandom
Definition: kgamemessage.h:145
KGame::signalGameOver
void signalGameOver(int status, KPlayer *current, KGame *me)
Is emitted after a call to gameOver() returns a non zero return code.
KGameMessage::IdInactivatePlayer
Definition: kgamemessage.h:157
KGamePropertyHandler::setPolicy
void setPolicy(KGamePropertyBase::PropertyPolicy p, bool userspace=true)
Set the policy for all kgame variables which are currently registerd in the KGame proeprty handler...
Definition: kgamepropertyhandler.cpp:225
QList::end
iterator end()
KGame::KGame
KGame(int cookie=42, QObject *parent=0)
Create a KGame object.
Definition: kgame.cpp:82
KGamePropertyBase
Base class of KGameProperty.
Definition: kgameproperty.h:45
KGameMessage::IdActivatePlayer
Definition: kgamemessage.h:156
KGameNetwork::isAdmin
bool isAdmin() const
The admin of a game is the one who initializes newly connected clients using negotiateNetworkGame and...
Definition: kgamenetwork.cpp:104
KGame::PolicyClean
Definition: kgame.h:91
KGame::signalReplacePlayerIO
void signalReplacePlayerIO(KPlayer *player, bool *remove)
When a client disconnects from the game usually all players from that client are removed.
QFile::close
virtual void close()
KGame::signalNetworkData
void signalNetworkData(int msgid, const QByteArray &buffer, quint32 receiver, quint32 sender)
We got an user defined update message.
KGame::signalPlayerLeftGame
void signalPlayerLeftGame(KPlayer *player)
a player left the game because of a broken connection or so!
KGameMessage::IdAddPlayer
Definition: kgamemessage.h:154
KGame::prepareNext
virtual void prepareNext()
Definition: kgame.cpp:826
KGame::syncRandom
void syncRandom()
syncronise the random numbers with all network clients not used by KGame - if it should be kept then ...
Definition: kgame.cpp:1253
KGame::load
virtual bool load(QDataStream &stream, bool reset=true)
Load a saved game, from file OR network.
Definition: kgame.cpp:178
KGamePropertyBase::IdMaxPlayer
Definition: kgameproperty.h:58
KGame::systemActivatePlayer
bool systemActivatePlayer(KPlayer *player)
activates player.
Definition: kgame.cpp:658
KGameNetwork
The KGameNetwork class is the KGame class with network support.
Definition: kgamenetwork.h:46
KGame::networkTransmission
virtual void networkTransmission(QDataStream &stream, int msgid, quint32 receiver, quint32 sender, quint32 clientID)
This will either forward an incoming message to a specified player (see KPlayer::networkTransmission)...
Definition: kgame.cpp:855
KGame::loadPlayer
KPlayer * loadPlayer(QDataStream &stream, bool isvirtual=false)
Load the player list from a stream.
Definition: kgame.cpp:359
KPlayer::setGame
void setGame(KGame *game)
sets the game the player belongs to.
Definition: kplayer.cpp:135
KGameMessage::IdSetupGame
Definition: kgamemessage.h:141
KGame::sendPlayerInput
virtual bool sendPlayerInput(QDataStream &msg, KPlayer *player, quint32 sender=0)
Called by KPlayer to send a player input to the KMessageServer.
Definition: kgame.cpp:721
KGamePropertyHandler::addProperty
bool addProperty(KGamePropertyBase *data, const QString &name=QString())
Adds a KGameProperty property to the handler.
Definition: kgamepropertyhandler.cpp:144
KGame::signalPropertyChanged
void signalPropertyChanged(KGamePropertyBase *property, KGame *me)
This signal is emmited if a player property changes its value and the property is set to notify this ...
kplayer.h
KGame::minPlayers
uint minPlayers() const
What is the minimal number of players?
Definition: kgame.cpp:686
KGame::setGameStatus
void setGameStatus(int status)
sets the game status
Definition: kgame.cpp:844
KGameMessage::IdGameProperty
Definition: kgamemessage.h:151
KGame::addProperty
bool addProperty(KGamePropertyBase *data)
docu: see KPlayer
Definition: kgame.cpp:1452
KGameMessage::rawGameId
static quint32 rawGameId(quint32 playerid)
Returns the raw game id, that is, the game id the player belongs to.
Definition: kgamemessage.cpp:40
KGame::playerList
KGamePlayerList * playerList()
Returns a list of all active players.
Definition: kgame.cpp:711
KGame::gameSequence
KGameSequence * gameSequence() const
Definition: kgame.cpp:821
KPlayer::networkTransmission
void networkTransmission(QDataStream &stream, int msgid, quint32 sender)
Receives a message.
Definition: kplayer.cpp:409
KGame::slotClientConnected
void slotClientConnected(quint32 clientId)
Calls negotiateNetworkGame() See KGameNetwork::signalClientConnected.
Definition: kgame.cpp:1273
KGameNetwork::disconnect
void disconnect()
Disconnect the current connection and establish a new local one.
Definition: kgamenetwork.cpp:285
KGamePropertyBase::IdGameStatus
Definition: kgameproperty.h:57
KGameNetwork::gameId
quint32 gameId() const
The unique ID of this game.
Definition: kgamenetwork.cpp:86
KGameMessage::IdGameConnected
Definition: kgamemessage.h:144
KGame::~KGame
virtual ~KGame()
Destructs the game.
Definition: kgame.cpp:119
KGame::signalClientJoinedGame
void signalClientJoinedGame(quint32 clientid, KGame *me)
Is emmited after a client is successfully connected to the game.
KGame::setGameSequence
void setGameSequence(KGameSequence *sequence)
Set a new KGameSequence to control player management.
Definition: kgame.cpp:811
KGame::save
virtual bool save(QDataStream &stream, bool saveplayers=true)
Save a game to a file OR to network.
Definition: kgame.cpp:289
KPlayer::isActive
bool isActive() const
Is this player an active player.
Definition: kplayer.cpp:155
QDataStream::device
QIODevice * device() const
KGameNetwork::Debug
virtual void Debug()
Gives debug output of the game status.
Definition: kgamenetwork.cpp:517
KPlayer::rtti
virtual int rtti() const
The idendification of the player.
Definition: kplayer.cpp:125
KGame::maxPlayers
int maxPlayers() const
What is the maximal number of players?
Definition: kgame.cpp:689
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KGameNetwork::sendSystemMessage
bool sendSystemMessage(const QByteArray &buffer, int msgid, quint32 receiver=0, quint32 sender=0)
Sends a network message msg with a given msg id msgid to all clients.
Definition: kgamenetwork.cpp:408
KGame::findProperty
KGamePropertyBase * findProperty(int id) const
This function allows to find the pointer to a player property when you know it's id.
Definition: kgame.cpp:1472
kgameerror.h
KGameProperty< int >
KGame::playerDeleted
void playerDeleted(KPlayer *player)
Called by the destructor of KPlayer to remove itself from the game.
Definition: kgame.cpp:500
KGameNetwork::signalClientDisconnected
void signalClientDisconnected(quint32 clientID, bool broken)
This signal is emitted whenever the KMessageServer sends us a message that a connection to a client w...
QList::begin
iterator begin()
KGAME_LOAD_COOKIE
#define KGAME_LOAD_COOKIE
Definition: kgame.cpp:46
KGamePropertyHandler::unlockDirectEmit
void unlockDirectEmit()
Removes the lock from the emitting of property signals.
Definition: kgamepropertyhandler.cpp:281
KGameMessage::version
static int version()
Definition: kgamemessage.cpp:100
KGame::setPolicy
void setPolicy(GamePolicy p, bool recursive=true)
Changes the consistency policy of a property.
Definition: kgame.cpp:1479
KGameNetwork::setMaster
void setMaster()
Definition: kgamenetwork.cpp:114
KGame::playerCount
uint playerCount() const
Returns how many players are plugged into the game.
Definition: kgame.cpp:692
KGame::signalMessageUpdate
void signalMessageUpdate(int msgid, quint32 receiver, quint32 sender)
We got an network message.
KGame::sendProperty
void sendProperty(int msgid, QDataStream &stream, bool *sent)
Called by KGamePropertyHandler only! Internal function!
Definition: kgame.cpp:1458
QTimer::singleShot
singleShot
KGame::createPlayer
virtual KPlayer * createPlayer(int rtti, int io, bool isvirtual)
This virtual function is called if the KGame needs to create a new player.
Definition: kgame.cpp:354
KGame::nextPlayer
virtual KPlayer * nextPlayer(KPlayer *last, bool exclusive=true)
Definition: kgame.cpp:835
KGameMessage::IdSetupGameContinue
Definition: kgamemessage.h:142
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:18:54 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

libkdegames/libkdegamesprivate/kgame

Skip menu "libkdegames/libkdegamesprivate/kgame"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdegames API Reference

Skip menu "kdegames API Reference"
  • granatier
  • kapman
  • kblackbox
  • kgoldrunner
  • kigo
  • kmahjongg
  • KShisen
  • ksquares
  • libkdegames
  •   highscore
  •   libkdegamesprivate
  •     kgame
  • libkmahjongg
  • palapeli
  •   libpala

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal