KDEGames

kplayer.cpp
1 /*
2  This file is part of the KDE games library
3  SPDX-FileCopyrightText: 2001 Martin Heni <kde at heni-online.de>
4  SPDX-FileCopyrightText: 2001 Andreas Beckermann <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #include "kplayer.h"
10 
11 // own
12 #include "kgame.h"
13 #include "kgameio.h"
14 #include "kgamemessage.h"
15 #include "kgameproperty.h"
16 #include "kgamepropertyhandler.h"
17 // KF
18 #include <KLocalizedString>
19 // Qt
20 #include <QBuffer>
21 // Std
22 #include <cassert>
23 #include <cstdio>
24 
25 #define KPLAYER_LOAD_COOKIE 7285
26 
27 class KPlayerPrivate
28 {
29 public:
30  KPlayerPrivate()
31  {
32  mNetworkPlayer = nullptr;
33  }
34 
35  KGame *mGame;
36  bool mActive; // active player
37  KPlayer::KGameIOList mInputList;
38 
39  // GameProperty
40  KGamePropertyBool mAsyncInput; // async input allowed
41  KGamePropertyBool mMyTurn; // Is it my turn to play (only useful if not async)?
42  KGamePropertyInt mUserId; // a user defined id
43 
44  quint32 mId;
45  bool mVirtual; // virtual player
46  int mPriority; // tag for replacement
47 
48  KPlayer *mNetworkPlayer; // replacement player
49 
50  KGamePropertyHandler mProperties;
51 
52  // Playerdata
54  KGamePropertyQString mGroup;
55 };
56 
58  : QObject()
59  , d(new KPlayerPrivate)
60 {
61  init();
62 }
63 
64 void KPlayer::init()
65 {
66  // note that NO KGame object exists here! so we cannot use KGameProperty::send!
67  qCDebug(GAMES_PRIVATE_KGAME) << ": this=" << this << ", sizeof(this)=" << sizeof(KPlayer);
68  qCDebug(GAMES_PRIVATE_KGAME) << "sizeof(m_Group)=" << sizeof(d->mGroup);
69 
70  d->mProperties.registerHandler(KGameMessage::IdPlayerProperty, this, SLOT(sendProperty(int, QDataStream &, bool *)), SLOT(emitSignal(KGamePropertyBase *)));
71  d->mVirtual = false;
72  d->mActive = true;
73  d->mGame = nullptr;
74  d->mId = 0; // "0" is always an invalid ID!
75  d->mPriority = 0;
76  // I guess we cannot translate the group otherwise no
77  // international connections are possible
78 
79  d->mUserId.registerData(KGamePropertyBase::IdUserId, this, i18n("UserId"));
80  d->mUserId.setLocal(0);
81  d->mGroup.registerData(KGamePropertyBase::IdGroup, this, i18n("Group"));
82  d->mGroup.setLocal(i18n("default"));
83  d->mName.registerData(KGamePropertyBase::IdName, this, i18n("Name"));
84  d->mName.setLocal(i18n("default"));
85 
86  d->mAsyncInput.registerData(KGamePropertyBase::IdAsyncInput, this, i18n("AsyncInput"));
87  d->mAsyncInput.setLocal(false);
88  d->mMyTurn.registerData(KGamePropertyBase::IdTurn, this, i18n("myTurn"));
89  d->mMyTurn.setLocal(false);
90  d->mMyTurn.setEmittingSignal(true);
91  d->mMyTurn.setOptimized(false);
92 }
93 
94 KPlayer::~KPlayer()
95 {
96  qCDebug(GAMES_PRIVATE_KGAME) << ": this=" << this << ", id=" << this->id();
97 
98  // Delete IODevices
99  qDeleteAll(d->mInputList);
100  d->mInputList.clear();
101  if (game()) {
102  game()->playerDeleted(this);
103  }
104 
105  // note: mProperties does not use autoDelete or so - user must delete objects
106  // himself
107  d->mProperties.clear();
108  qCDebug(GAMES_PRIVATE_KGAME) << "done";
109 }
110 
111 int KPlayer::rtti() const
112 {
113  return 0;
114 }
115 
117 {
118  return &d->mInputList;
119 }
120 
122 {
123  d->mGame = game;
124 }
125 
127 {
128  return d->mGame;
129 }
130 
132 {
133  d->mAsyncInput = a;
134 }
135 
137 {
138  return d->mAsyncInput.value();
139 }
140 
141 bool KPlayer::isActive() const
142 {
143  return d->mActive;
144 }
145 
146 void KPlayer::setActive(bool v)
147 {
148  d->mActive = v;
149 }
150 
151 int KPlayer::userId() const
152 {
153  return d->mUserId.value();
154 }
155 
156 void KPlayer::setUserId(int i)
157 {
158  d->mUserId = i;
159 }
160 
161 bool KPlayer::myTurn() const
162 {
163  return d->mMyTurn.value();
164 }
165 
166 bool KPlayer::forwardMessage(QDataStream &msg, int msgid, quint32 receiver, quint32 sender)
167 {
168  if (!isActive()) {
169  return false;
170  }
171  if (!game()) {
172  return false;
173  }
174  qCDebug(GAMES_PRIVATE_KGAME) << ": to game sender=" << sender << ""
175  << "recv=" << receiver << "msgid=" << msgid;
176  return game()->sendSystemMessage(msg, msgid, receiver, sender);
177 }
178 
179 bool KPlayer::forwardInput(QDataStream &msg, bool transmit, quint32 sender)
180 {
181  if (!isActive()) {
182  return false;
183  }
184  if (!game()) {
185  return false;
186  }
187 
188  qCDebug(GAMES_PRIVATE_KGAME) << ": to game playerInput(sender=" << sender << ")";
189  if (!asyncInput() && !myTurn()) {
190  qCDebug(GAMES_PRIVATE_KGAME) << ": rejected cause it is not our turn";
191  return false;
192  }
193 
194  // AB: I hope I remember the usage correctly:
195  // this function is called twice (on sender side) - once with transmit = true
196  // where it sends the input to the comserver and once with transmit = false
197  // where it really looks at the input
198  if (transmit) {
199  qCDebug(GAMES_PRIVATE_KGAME) << "indirect playerInput";
200  return game()->sendPlayerInput(msg, this, sender);
201  } else {
202  qCDebug(GAMES_PRIVATE_KGAME) << "direct playerInput";
203  return game()->systemPlayerInput(msg, this, sender);
204  }
205 }
206 
207 void KPlayer::setId(quint32 newid)
208 {
209  // Needs to be after the sendProcess
210  d->mId = newid;
211 }
212 
213 void KPlayer::setGroup(const QString &group)
214 {
215  d->mGroup = group;
216 }
217 
218 const QString &KPlayer::group() const
219 {
220  return d->mGroup.value();
221 }
222 
223 void KPlayer::setName(const QString &name)
224 {
225  d->mName = name;
226 }
227 
228 const QString &KPlayer::name() const
229 {
230  return d->mName.value();
231 }
232 
233 quint32 KPlayer::id() const
234 {
235  return d->mId;
236 }
237 
239 {
240  return &d->mProperties;
241 }
242 
244 {
245  d->mVirtual = v;
246 }
247 
248 bool KPlayer::isVirtual() const
249 {
250  return d->mVirtual;
251 }
252 
254 {
255  d->mNetworkPlayer = p;
256 }
257 
259 {
260  return d->mNetworkPlayer;
261 }
262 
264 {
265  return d->mPriority;
266 }
267 
269 {
270  d->mPriority = p;
271 }
272 
274 {
275  if (!input) {
276  return false;
277  }
278  d->mInputList.append(input);
279  input->initIO(this); // set player and init device
280  return true;
281 }
282 
283 // input=0, remove all
284 bool KPlayer::removeGameIO(KGameIO *targetinput, bool deleteit)
285 {
286  qCDebug(GAMES_PRIVATE_KGAME) << ":" << targetinput << "delete=" << deleteit;
287  bool result = true;
288  if (!targetinput) // delete all
289  {
290  KGameIO *input;
291  while (!d->mInputList.isEmpty()) {
292  input = d->mInputList.first();
293  if (input)
294  removeGameIO(input, deleteit);
295  }
296  } else {
297  // qCDebug(GAMES_PRIVATE_KGAME) << "remove IO" << targetinput;
298  if (deleteit) {
299  delete targetinput;
300  } else {
301  targetinput->setPlayer(nullptr);
302  result = d->mInputList.removeAll(targetinput);
303  }
304  }
305  return result;
306 }
307 
308 bool KPlayer::hasRtti(int rtti) const
309 {
310  return findRttiIO(rtti) != nullptr;
311 }
312 
313 KGameIO *KPlayer::findRttiIO(int rtti) const
314 {
315  QListIterator<KGameIO *> it(d->mInputList);
316  while (it.hasNext()) {
317  KGameIO *curGameIO = it.next();
318  if (curGameIO->rtti() == rtti) {
319  return curGameIO;
320  }
321  }
322  return nullptr;
323 }
324 
326 {
327  int value = 0;
328  QListIterator<KGameIO *> it(d->mInputList);
329  while (it.hasNext()) {
330  value |= it.next()->rtti();
331  }
332  return value;
333 }
334 
335 bool KPlayer::setTurn(bool b, bool exclusive)
336 {
337  qCDebug(GAMES_PRIVATE_KGAME) << ":" << id() << " (" << this << ") to" << b;
338  if (!isActive()) {
339  return false;
340  }
341 
342  // if we get to do an exclusive turn all other players are disallowed
343  if (exclusive && b && game()) {
344  for (KGame::KGamePlayerList::iterator it = game()->playerList()->begin(); it != game()->playerList()->end(); ++it) {
345  if ((*it) == this) {
346  continue;
347  }
348  (*it)->setTurn(false, false);
349  }
350  }
351 
352  // Return if nothing changed
353  d->mMyTurn = b;
354 
355  return true;
356 }
357 
359 {
360  qint32 id, priority;
361  stream >> id >> priority;
362  setId(id);
363  setNetworkPriority(priority);
364 
365  // Load Player Data
366  // FIXME: maybe set all properties setEmitSignal(false) before?
367  d->mProperties.load(stream);
368 
369  qint16 cookie;
370  stream >> cookie;
371  if (cookie == KPLAYER_LOAD_COOKIE) {
372  qCDebug(GAMES_PRIVATE_KGAME) << " Player loaded properly";
373  } else {
374  qCCritical(GAMES_PRIVATE_KGAME) << " Player loading error. probably format error";
375  }
376 
377  // Q_EMIT signalLoad(stream);
378  return true;
379 }
380 
382 {
383  stream << (qint32)id() << (qint32)networkPriority();
384 
385  d->mProperties.save(stream);
386 
387  stream << (qint16)KPLAYER_LOAD_COOKIE;
388 
389  // Q_EMIT signalSave(stream);
390  return true;
391 }
392 
393 void KPlayer::networkTransmission(QDataStream &stream, int msgid, quint32 sender)
394 {
395  // qCDebug(GAMES_PRIVATE_KGAME) ": msgid=" << msgid << "sender=" << sender << "we are=" << id();
396  // PlayerProperties processed
397  bool issender;
398  if (game()) {
399  issender = sender == game()->gameId();
400  } else {
401  issender = true;
402  }
403  if (d->mProperties.processMessage(stream, msgid, issender)) {
404  return;
405  }
406  switch (msgid) {
407  case KGameMessage::IdPlayerInput: {
408  qCDebug(GAMES_PRIVATE_KGAME) << ": Got player move "
409  << "KPlayer (virtual) forwards it to the game object";
410  forwardInput(stream, false);
411  } break;
412  default:
413  Q_EMIT signalNetworkData(msgid - KGameMessage::IdUser, ((QBuffer *)stream.device())->readAll(), sender, this);
414  qCDebug(GAMES_PRIVATE_KGAME) << ": "
415  << "User data msgid" << msgid;
416  break;
417  }
418 }
419 
421 {
422  return d->mProperties.find(id);
423 }
424 
426 {
427  return d->mProperties.addProperty(data);
428 }
429 
430 void KPlayer::sendProperty(int msgid, QDataStream &stream, bool *sent)
431 {
432  if (game()) {
433  bool s = game()->sendPlayerProperty(msgid, stream, id());
434  if (s) {
435  *sent = true;
436  }
437  }
438 }
439 
441 {
442  // Notify KGameIO (Process) for a new turn
443  if (me->id() == KGamePropertyBase::IdTurn) {
444  // qCDebug(GAMES_PRIVATE_KGAME) << ": for KGamePropertyBase::IdTurn";
445  QListIterator<KGameIO *> it(d->mInputList);
446  while (it.hasNext()) {
447  it.next()->notifyTurn(d->mMyTurn.value());
448  }
449  }
450  Q_EMIT signalPropertyChanged(me, this);
451 }
452 
453 // --------------------- DEBUG --------------------
455 {
456  qCDebug(GAMES_PRIVATE_KGAME) << "------------------- KPLAYER -----------------------";
457  qCDebug(GAMES_PRIVATE_KGAME) << "this: " << this;
458  qCDebug(GAMES_PRIVATE_KGAME) << "rtti: " << rtti();
459  qCDebug(GAMES_PRIVATE_KGAME) << "id : " << id();
460  qCDebug(GAMES_PRIVATE_KGAME) << "Name : " << name();
461  qCDebug(GAMES_PRIVATE_KGAME) << "Group: " << group();
462  qCDebug(GAMES_PRIVATE_KGAME) << "Async: " << asyncInput();
463  qCDebug(GAMES_PRIVATE_KGAME) << "myTurn: " << myTurn();
464  qCDebug(GAMES_PRIVATE_KGAME) << "Virtual:" << isVirtual();
465  qCDebug(GAMES_PRIVATE_KGAME) << "Active: " << isActive();
466  qCDebug(GAMES_PRIVATE_KGAME) << "Priority:" << networkPriority();
467  qCDebug(GAMES_PRIVATE_KGAME) << "Game :" << game();
468  qCDebug(GAMES_PRIVATE_KGAME) << "#IOs: " << d->mInputList.count();
469  qCDebug(GAMES_PRIVATE_KGAME) << "---------------------------------------------------";
470 }
virtual const QString & name() const
Definition: kplayer.cpp:228
virtual void initIO(KPlayer *p)
Init this device by setting the player and e.g.
Definition: kgameio.cpp:77
virtual bool load(QDataStream &stream)
Load a saved player, from file OR network.
Definition: kplayer.cpp:358
void setVirtual(bool v)
Definition: kplayer.cpp:243
bool myTurn() const
is it my turn to go
Definition: kplayer.cpp:161
void signalNetworkData(int msgid, const QByteArray &buffer, quint32 sender, KPlayer *me)
The player object got a message which was targeted at it but has no default method to process it.
Q_EMITQ_EMIT
bool asyncInput() const
Query whether this player does asynchronous input.
Definition: kplayer.cpp:136
Base class for IO devices for games.
Definition: kgameio.h:56
void networkTransmission(QDataStream &stream, int msgid, quint32 sender)
Receives a message.
Definition: kplayer.cpp:393
bool isActive() const
Is this player an active player.
Definition: kplayer.cpp:141
KGamePlayerList * playerList()
Returns a list of all active players.
Definition: kgame.cpp:681
int networkPriority() const
Returns whether this player can be replaced by a network connection player.
Definition: kplayer.cpp:263
bool setTurn(bool b, bool exclusive=true)
Sets whether this player is the next to turn.
Definition: kplayer.cpp:335
bool hasNext() const const
QIODevice * device() const const
QObject * sender() const const
void emitSignal(KGamePropertyBase *me)
Called by KGameProperty only! Internal function!
Definition: kplayer.cpp:440
KGamePropertyHandler * dataHandler()
Definition: kplayer.cpp:238
The main KDE game object.
Definition: kgame.h:55
Base class for a game player.
Definition: kplayer.h:59
void setName(const QString &name)
Sets the name of the player.
Definition: kplayer.cpp:223
bool hasRtti(int rtti) const
Checks whether this player has a IO device of the given rtti type.
Definition: kplayer.cpp:308
virtual int rtti() const
The identification of the player.
Definition: kplayer.cpp:111
KGame * game() const
Query to which game the player belongs to.
Definition: kplayer.cpp:126
virtual const QString & group() const
Query the group the player belongs to.
Definition: kplayer.cpp:218
const T & next()
bool sendPlayerProperty(int msgid, QDataStream &s, quint32 playerId)
This is called by KPlayer::sendProperty only! Internal function!
Definition: kgame.cpp:1355
bool addGameIO(KGameIO *input)
Adds an IO device for the player.
Definition: kplayer.cpp:273
int calcIOValue()
Calculates a checksum over the IO devices.
Definition: kplayer.cpp:325
virtual bool save(QDataStream &stream)
Save a player to a file OR to network.
Definition: kplayer.cpp:381
QString i18n(const char *text, const TYPE &arg...)
quint32 id() const
Returns the id of the player.
Definition: kplayer.cpp:233
void setPlayer(KPlayer *p)
Sets the player to which this IO belongs to.
Definition: kgameio.cpp:72
KGameIOList * ioList()
Returns a list of input devices.
Definition: kplayer.cpp:116
void setNetworkPriority(int b)
Set whether this player can be replaced by a network player.
Definition: kplayer.cpp:268
A collection class for KGameProperty objects.
quint32 gameId() const
The unique ID of this game.
Base class of KGameProperty.
Definition: kgameproperty.h:36
void setAsyncInput(bool a)
Set whether this player can make turns/input all the time (true) or only when it is its turn (false) ...
Definition: kplayer.cpp:131
KGamePropertyBase * findProperty(int id) const
Searches for a property of the player given its id.
Definition: kplayer.cpp:420
void sendProperty(int msgid, QDataStream &stream, bool *sent)
Called by KGameProperty only! Internal function!
Definition: kplayer.cpp:430
bool isVirtual() const
Is this player a virtual player, i.e.
Definition: kplayer.cpp:248
bool addProperty(KGamePropertyBase *data)
Adds a property to a player.
Definition: kplayer.cpp:425
void signalPropertyChanged(KGamePropertyBase *property, KPlayer *me)
This signal is emitted if a player property changes its value and the property is set to notify this ...
bool removeGameIO(KGameIO *input=nullptr, bool deleteit=true)
remove (and delete) a game IO device
Definition: kplayer.cpp:284
virtual int rtti() const =0
Run time identification.
int userId() const
Returns the user defined id of the player This value can be used arbitrary by you to have some user i...
Definition: kplayer.cpp:151
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.
virtual bool forwardMessage(QDataStream &msg, int msgid, quint32 receiver=0, quint32 sender=0)
Forwards Message to the game object..internal use only.
Definition: kplayer.cpp:166
void setActive(bool v)
Set an player as active (true) or inactive (false)
Definition: kplayer.cpp:146
virtual bool sendPlayerInput(QDataStream &msg, KPlayer *player, quint32 sender=0)
Called by KPlayer to send a player input to the KMessageServer.
Definition: kgame.cpp:698
KGameIO * findRttiIO(int rtti) const
Finds the KGameIO devies with the given rtti code.
Definition: kplayer.cpp:313
virtual bool forwardInput(QDataStream &msg, bool transmit=true, quint32 sender=0)
Forwards input to the game object..internal use only.
Definition: kplayer.cpp:179
void playerDeleted(KPlayer *player)
Called by the destructor of KPlayer to remove itself from the game.
Definition: kgame.cpp:474
QList::iterator end()
void setGame(KGame *game)
sets the game the player belongs to.
Definition: kplayer.cpp:121
void Debug()
Gives debug output of the game status.
Definition: kplayer.cpp:454
void setGroup(const QString &group)
A group the player belongs to.
Definition: kplayer.cpp:213
void setNetworkPlayer(KPlayer *p)
Sets this network player replacement.
Definition: kplayer.cpp:253
virtual bool systemPlayerInput(QDataStream &msg, KPlayer *player, quint32 sender=0)
Called when a player input arrives from KMessageServer.
Definition: kgame.cpp:714
KPlayer * networkPlayer() const
Returns the player which got inactivated to allow this player to be set up via network.
Definition: kplayer.cpp:258
KPlayer()
Create a new player object.
Definition: kplayer.cpp:57
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Feb 7 2023 03:55:25 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.