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

KDE's Doxygen guidelines are available online.