KDEGames

kgameproperty.h
1 /*
2  This file is part of the KDE games library
3  SPDX-FileCopyrightText: 2001 Andreas Beckermann <[email protected]>
4  SPDX-FileCopyrightText: 2001 Martin Heni <kde at heni-online.de>
5 
6  SPDX-License-Identifier: LGPL-2.0-only
7 */
8 
9 #ifndef __KGAMEPROPERTY_H_
10 #define __KGAMEPROPERTY_H_
11 
12 // own
13 #include "libkdegamesprivate_export.h"
14 // Qt
15 #include <QDataStream>
16 #include <QDebug>
17 #include <QIODevice>
18 // Std
19 #include <typeinfo>
20 
21 class KGame;
22 class KPlayer;
24 using namespace std;
25 
26 /**
27  * \class KGamePropertyBase kgameproperty.h <KGame/KGameProperty>
28  *
29  * @short Base class of KGameProperty
30  *
31  * The KGamePropertyBase class is the base class of KGameProperty. See
32  * KGameProperty for further information.
33  *
34  * @author Andreas Beckermann <[email protected]>
35  **/
36 class KDEGAMESPRIVATE_EXPORT KGamePropertyBase
37 {
38 public:
39  enum PropertyDataIds { // these belong to KPlayer/KGame!
40  //KPlayer
41  IdGroup=1,
42  IdUserId=2,
43  IdAsyncInput=3,
44  IdTurn=4,
45  IdName=5,
46 
47  //KGame
48  IdGameStatus=6,
49  IdMaxPlayer=7,
50  IdMinPlayer=8,
51 
52  // Input Grabbing
53  IdGrabInput=16,
54  IdReleaseInput=17,
55 
56  IdCommand, // Reserved for internal use
57  IdUser=256,
58 
59  IdAutomatic=0x7000 // Id's from here on are automatically given (16bit)
60  };
61 
62  /**
63  * Commands for advanced properties (qint8)
64  **/
66  {
67  // General
68  CmdLock=1,
69 
70  // Array
71  CmdAt=51,
72  CmdResize=52,
73  CmdFill=53,
74  CmdSort=54,
75  // List (could be the same id's actually)
76  CmdInsert=61,
77  CmdAppend=62,
78  CmdRemove=63,
79  CmdClear=64
80  };
81 
82  /**
83  * The policy of the property. This can be PolicyClean (setValue uses
84  * send), PolicyDirty (setValue uses changeValue) or
85  * PolicyLocal (setValue uses setLocal).
86  *
87  * A "clean" policy means that the property is always the same on every
88  * client. This is achieved by calling send which actually changes
89  * the value only when the message from the MessageServer is received.
90  *
91  * A "dirty" policy means that as soon as setValue is called the
92  * property is changed immediately. And additionally sent over network.
93  * This can sometimes lead to bugs as the other clients do not
94  * immediately have the same value. For more information see
95  * changeValue.
96  *
97  * PolicyLocal means that a KGameProperty behaves like ever
98  * "normal" variable. Whenever setValue is called (e.g. using "=")
99  * the value of the property is changes immediately without sending it
100  * over network. You might want to use this if you are sure that all
101  * clients set the property at the same time.
102  **/
104  {
105  PolicyUndefined = 0,
106  PolicyClean = 1,
107  PolicyDirty = 2,
108  PolicyLocal = 3
109  };
110 
111 
112  /**
113  * Constructs a KGamePropertyBase object and calls registerData.
114  * @param id The id of this property. MUST be UNIQUE! Used to send and
115  * receive changes in the property of the player automatically via
116  * network.
117  * @param owner The owner of the object. Must be a KGamePropertyHandler which manages
118  * the changes made to this object, i.e. which will send the new data
119  **/
120  KGamePropertyBase(int id, KGamePropertyHandler* owner);
121 
122  KGamePropertyBase(int id, KGame* parent);
123  KGamePropertyBase(int id, KPlayer* parent);
124 
125  /**
126  * Creates a KGamePropertyBase object without an owner. Remember to call
127  * registerData!
128  **/
130 
131  virtual ~KGamePropertyBase();
132 
133  /**
134  * Changes the consistency policy of a property. The
135  * PropertyPolicy is one of PolicyClean (defaulz), PolicyDirty or PolicyLocal.
136  *
137  * It is up to you to decide how you want to work.
138  **/
139  void setPolicy(PropertyPolicy p) { mFlags.bits.policy = p; }
140 
141  /**
142  * @return The default policy of the property
143  **/
144  PropertyPolicy policy() const { return (PropertyPolicy)mFlags.bits.policy; }
145 
146  /**
147  * Sets this property to emit a signal on value changed.
148  * As the properties do not inherit QObject for optimization
149  * this signal is emitted via the KPlayer or KGame object
150  **/
151  void setEmittingSignal(bool p) { mFlags.bits.emitsignal=p; }
152 
153  /**
154  * See also setEmittingSignal
155  * @return Whether this property emits a signal on value change
156  **/
157  bool isEmittingSignal() const { return mFlags.bits.emitsignal; }
158 
159  /**
160  * Sets this property to try to optimize signal and network handling
161  * by not sending it out when the property value is not changed.
162  **/
163  void setOptimized(bool p) { mFlags.bits.optimize = p ; }
164 
165  /**
166  * See also setOptimize
167  * @return Whether the property optimizes access (signals,network traffic)
168  **/
169  bool isOptimized() const { return mFlags.bits.optimize; }
170 
171  /**
172  * @return Whether this property is "dirty". See also setDirty
173  **/
174  bool isDirty() const { return mFlags.bits.dirty; }
175 
176  /**
177  * A locked property can only be changed by the player who has set the
178  * lock. See also setLocked
179  * @return Whether this property is currently locked.
180  **/
181  bool isLocked() const { return mFlags.bits.locked; }
182 
183  /**
184  * A locked property can only be changed by the player who has set the
185  * lock.
186  *
187  * You can only call this if isLocked is false. A message is sent
188  * over network so that the property is locked for all players except
189  * you.
190  *
191  * @return returns false if the property can not be locked, i.e. it is already locked
192  *
193  **/
194  bool lock();
195 
196  /**
197  * A locked property can only be changed by the player who has set the
198  * lock.
199  *
200  * You can only call this if isLocked is false. A message is sent
201  * over network so that the property is locked for all players except
202  * you.
203  *
204  * @return returns false if the property can not be locked, i.e. it is already locked
205  *
206  **/
207  bool unlock(bool force=false);
208 
209  /**
210  * This will read the value of this property from the stream. You MUST
211  * overwrite this method in order to use this class
212  * @param s The stream to read from
213  **/
214  virtual void load(QDataStream& s) = 0;
215 
216  /**
217  * Write the value into a stream. MUST be overwritten
218  **/
219  virtual void save(QDataStream& s) = 0;
220 
221  /**
222  * send a command to advanced properties like arrays
223  * @param stream The stream containing the data of the command
224  * @param msgid The ID of the command - see PropertyCommandIds
225  * @param isSender whether this client is also the sender of the command
226  **/
227  virtual void command(QDataStream &stream, int msgid, bool isSender=false);
228 
229  /**
230  * @return The id of this property
231  **/
232  int id() const { return mId; }
233 
234  /**
235  * @return a type_info of the data this property contains.
236  **/
237  virtual const type_info* typeinfo() { return &typeid(this); }
238 
239  /**
240  * You have to register a KGamePropertyBase before you can use it.
241  *
242  * You MUST call this before you can use KGamePropertyBase!
243  *
244  * @param id the id of this KGamePropertyBase object. The id MUST be
245  * unique, i.e. you cannot have two properties with the same id for one
246  * player, although (currently) nothing prevents you from doing so. But
247  * you will get strange results!
248  *
249  * @param owner The owner of this data. This will send the data
250  * using KPropertyHandler::sendProperty whenever you call send
251  *
252  * @param p If not 0 you can set the policy of the property here
253  *
254  * @param name if not 0 you can assign a name to this property
255  *
256  **/
257  int registerData(int id, KGamePropertyHandler* owner,PropertyPolicy p, const QString& name=QString());
258 
259  /**
260  * This is an overloaded member function, provided for convenience.
261  * It differs from the above function only in what argument(s) it accepts.
262  **/
263  int registerData(int id, KGamePropertyHandler* owner, const QString& name=QString());
264 
265  /**
266  * This is an overloaded member function, provided for convenience.
267  * It differs from the above function only in what argument(s) it accepts.
268  **/
269  int registerData(int id, KGame* owner, const QString& name=QString());
270 
271  /**
272  * This is an overloaded member function, provided for convenience.
273  * It differs from the above function only in what argument(s) it accepts.
274  **/
275  int registerData(int id, KPlayer* owner, const QString& name=QString());
276 
277  /**
278  * This is an overloaded member function, provided for convenience.
279  * It differs from the above function only in what argument(s) it accepts.
280  * In particular you can use this function to create properties which
281  * will have an automatic id assigned. The new id is returned.
282  **/
283  int registerData(KGamePropertyHandler* owner,PropertyPolicy p=PolicyUndefined, const QString& name=QString() );
284 
285  void unregisterData();
286 
287 
288 protected:
289  /**
290  * A locked property can only be changed by the player who has set the
291  * lock.
292  *
293  * You can only call this if isLocked is false. A message is sent
294  * over network so that the property is locked for all players except
295  * you.
296  * Usually you use lock and unlock to access this property
297  *
298  **/
299  void setLock(bool l);
300 
301  /**
302  * Sets the "dirty" flag of the property. If a property is "dirty" i.e.
303  * KGameProperty::setLocal has been called there is no guarantee
304  * that all clients share the same value. You have to ensure this
305  * yourself e.g. by calling KGameProperty::setLocal on every
306  * client. You can also ignore the dirty flag and continue working withe
307  * the property depending on your situation.
308  **/
309  void setDirty(bool d) { mFlags.bits.dirty = d ; }
310 
311  /**
312  * Forward the data to the owner of this property which then sends it
313  * over network. save is used to store the data into a stream so
314  * you have to make sure that function is working properly if you
315  * implement your own property!
316  *
317  * Note: this sends the <em>current</em> property!
318  *
319  * Might be obsolete - KGamePropertyArray still uses it. Is this a bug
320  * or correct?
321  **/
322  bool sendProperty();
323 
324  /**
325  * Forward the data to the owner of this property which then sends it
326  * over network. save is used to store the data into a stream so
327  * you have to make sure that function is working properly if you
328  * implement your own property!
329  *
330  * This function is used by send to send the data over network.
331  * This does <em>not</em> send the current value but the explicitly
332  * given value.
333  *
334  * @return TRUE if the message could be sent successfully, otherwise
335  * FALSE
336  **/
337  bool sendProperty(const QByteArray& b);
338 
339  /**
340  * Causes the parent object to emit a signal on value change
341  **/
342  void emitSignal();
343 
344 protected:
345  KGamePropertyHandler* mOwner;
346 
347  // Having this as a union of the bitfield and the char
348  // allows us to stream this quantity easily (if we need to)
349  // At the moment it is not yet transmitted
350  union Flags {
351  char flag;
352  struct {
353  // unsigned char dosave : 1; // do save this property
354  // unsigned char delaytransmit : 1; // do not send immediately on
355  // change but a KPlayer:QTimer
356  // sends it later on - fast
357  // changing variables
358  unsigned char emitsignal : 1; // KPlayer notifies on variable change (true)
359  //unsigned char readonly : 1; // whether the property can be changed (false)
360  unsigned char optimize : 1; // whether the property tries to optimize send/emit (false)
361  unsigned char dirty: 1; // whether the property dirty (setLocal() was used)
362  unsigned char policy : 2; // whether the property is always consistent (see PropertyPolicy)
363  unsigned char locked: 1; // whether the property is locked (true)
364  } bits;
365  } mFlags;
366 
367 private:
368  friend class KGamePropertyHandler;
369  void init();
370 
371 private:
372  int mId;
373 
374 };
375 
376 /**
377  * \class KGameProperty kgameproperty.h <KGame/KGameProperty>
378  *
379  * @short A class for network transparent games
380  *
381  * Note: The entire API documentation is obsolete!
382  *
383  * The class KGameProperty can store any form of data and will transmit it via
384  * network whenever you call send. This makes network transparent games
385  * very easy. You first have to register the data to a KGamePropertyHandler
386  * using KGamePropertyBase::registerData (which is called by the
387  * constructor). For the KGamePropertyHandler you can use
388  * KGame::dataHandler or KPlayer::dataHandler but you can also create your
389  * own data handler.
390  *
391  * There are several concepts you can follow when writing network games. These
392  * concepts differ completely from the way how data is transferred so you should
393  * decide which one to use. You can also mix these concepts for a single
394  * property but we do not recommend this. The concepts:
395  * <ul>
396  * <li> Always Consistent (clean)
397  * <li> Not Always Consistent (dirty)
398  * <li> A Mixture (very dirty)
399  * </ul>
400  * I repeat: we do <em>not</em> recommend the third option ("a mixture"). Unless
401  * you have a good reason for this you will probably introduce some hard to find
402  * (and to fix) bugs.
403  *
404  * @section Always consistent (clean):
405  *
406  * This "policy" is default. Whenever you create a KGameProperty it is always
407  * consistent. This means that consistency is the most important thing for the
408  * property. This is achieved by using send to change the value of the
409  * property. send needs a running KMessageServer and therefore
410  * <em>MUST</em> be plugged into a KGamePropertyHandler using either
411  * registerData or the constructor. The parent of the dataHandler must be able
412  * to send messages (see above: the message server must be running). If you use
413  * send to change the value of a property you won't see the effect
414  * immediately: The new value is first transferred to the message server which
415  * queues the message. As soon as <em>all</em> messages in the message server
416  * which are before the changed property have been transferred the message
417  * server delivers the new value of the KGameProperty to all clients. A
418  * QTimer::singleShot is used to queue the messages inside the
419  * KMessageServer.
420  *
421  * This means that if you do the following:
422  * \code
423  * KGamePropertyInt myProperty(id, dataHandler());
424  * myProperty.initData(0);
425  * myProperty = 10;
426  * int value = myProperty.value();
427  * \endcode
428  * then "value" will be "0". initData is used to initialize the property
429  * (e.g. when the KMessageServer is not yet running or can not yet be
430  * reached). This is because "myProperty = 10" or "myProperty.send(10)" send a
431  * message to the KMessageServer which uses QTimer::singleShot to
432  * queue the message. The game first has to go back into the event loop where
433  * the message is received. The KGamePropertyHandler receives the new value
434  * sets the property. So if you need the new value you need to store it in a
435  * different variable (see setLocal which creates one for you until the
436  * message is received). The KGamePropertyHandler emits a signal (unless
437  * you called setEmitSignal with false) when the new value is received:
438  * KGamePropertyHandler::signalPropertyChanged. You can use this to react
439  * to a changed property.
440  *
441  * This may look quite confusing but it has a <em>big</em> advantage: all
442  * KGameProperty objects are ensured to have the same value on all clients in
443  * the game at every time. This way you will save you a lot of trouble as
444  * debugging can be very difficult if the value of a property changes
445  * immediately on client A but only after one or two additional messages
446  * (function calls, status changes, ...) on client B.
447  *
448  * The only disadvantage of this (clean) concept is that you cannot use a
449  * changed variable immediately but have to wait for the KMessageServer to
450  * change it. You probably want to use
451  * KGamePropertyHandler::signalPropertyChanged for this.
452  *
453  * @section Not Always Consistent (dirty):
454  *
455  * There are a lot of people who don't want to use the (sometimes quite complex)
456  * "clean" way. You can use setAlwaysConsistent to change the default
457  * behaviour of the KGameProperty. If a property is not always consistent
458  * it will use changeValue to send the property. changeValue also uses
459  * send to send the new value over network but it also uses
460  * setLocal to create a local copy of the property. This copy is created
461  * dynamically and is deleted again as soon as the next message from the network
462  * is received. To use the example above again:
463  * \code
464  * KGamePropertyInt myProperty(id, dataHandler());
465  * myProperty.setAlwaysConsistent(false);
466  * myProperty.initData(0);
467  * myProperty = 10;
468  * int value = myProperty.value();
469  * \endcode
470  * Now this example will "work" so value now is 10. Additionally the
471  * KMessageServer receives a message from the local client (just as explained
472  * above in "Always Consistent"). As soon as the message returns to the local
473  * client again the local value is deleted, as the "network value" has the same
474  * value as the local one. So you won't lose the ability to use the always
475  * consistent "clean" value of the property if you use the "dirty" way. Just use
476  * networkValue to access the value which is consistent among all clients.
477  *
478  * The advantage of this concept is clear: you can use a KGameProperty as
479  * every other variable as the changes value takes immediate effect.
480  * Additionally you can be sure that the value is transferred to all clients.
481  * You will usually not experience serious bugs just because you use the "dirty"
482  * way. Several events have to happen at once to get these "strange errors"
483  * which result in inconsistent properties (like "game running" on client A but
484  * "game ended/paused" on client B). But note that there is a very good reason
485  * for the existence of these different concepts of KGameProperty. I have
486  * myself experienced such a "strange error" and it took me several days to find
487  * the reason until I could fix it. So I personally recommend the "clean" way.
488  * On the other hand if you want to port a non-network game to a network game
489  * you will probably start with "dirty" properties as it is you will not have to
490  * change that much code...
491  *
492  * @section A Mixture (very dirty):
493  *
494  * You can also mix the concepts above. Note that we really don't recommend
495  * this. With a mixture I mean something like this:
496  * \code
497  * KGamePropertyInt myProperty(id, dataHandler());
498  * myProperty.setAlwaysConsistent(false);
499  * myProperty.initData(0);
500  * myProperty = 10;
501  * myProperty.setAlwaysConsistent(true);
502  * myProperty = 20;
503  * \endcode
504  * (totally senseless example, btw) I.e. I am speaking of mixing both concepts
505  * for a single property. Things like
506  * \code
507  * KGamePropertyInt myProperty1(id1, dataHandler());
508  * KGamePropertyInt myProperty2(id2, dataHandler());
509  * myProperty1.initData(0);
510  * myProperty2.initData(0);
511  * myProperty1.setAlwaysConsistent(false);
512  * myProperty2.setAlwaysConsistent(true);
513  * myProperty1 = 10;
514  * myProperty2 = 20;
515  * \endcode
516  * are ok. But mixing the concepts for a single property will make it nearly
517  * impossible to you to debug your game.
518  *
519  * So the right thing to do(tm) is to decide in the constructor whether you want
520  * a "clean" or "dirty" property.
521  *
522  * Even if you have decided for one of the concepts you still can manually
523  * follow another concept than the "policy" of your property. So if you use an
524  * always consistent KGameProperty you still can manually call
525  * changeValue as if it was not always consistent. Note that although this is
526  * also kind of a "mixture" as described above this is very useful sometimes. In
527  * contrast to the "mixture" above you don't have the problem that you don't
528  * exactly know which concept you are currently following because you used the
529  * function of the other concept only once.
530  *
531  * @section Custom classes:
532  *
533  * If you want to use a custom class with KGameProperty you have to implement the
534  * operators << and >> for QDataStream:
535  * \code
536  * class Card
537  * {
538  * public:
539  * int type;
540  * int suite;
541  * };
542  * QDataStream& operator<<(QDataStream& stream, Card& card)
543  * {
544  * qint16 type = card.type;
545  * qint16 suite = card.suite;
546  * s << type;
547  * s << suite;
548  * return s;
549  * }
550  * QDataStream& operator>>(QDataStream& stream, Card& card)
551  * {
552  * qint16 type;
553  * qint16 suite;
554  * s >> type;
555  * s >> suite;
556  * card.type = (int)type;
557  * card.suite = (int)suite;
558  * return s;
559  * }
560  *
561  * class Player : KPlayer
562  * {
563  * [...]
564  * KGameProperty<Card> mCards;
565  * };
566  * \endcode
567  *
568  * Note: unlike most QT classes KGameProperty objects are *not* deleted
569  * automatically! So if you create an object using e.g. KGameProperty<int>* data =
570  * new KGameProperty(id, dataHandler()) you have to put a delete data into your
571  * destructor!
572  *
573  * @author Andreas Beckermann <[email protected]>
574  **/
575 template<class type>
577 {
578 public:
579  /**
580  * Constructs a KGameProperty object. A KGameProperty object will transmit
581  * any changes to the KMessageServer and then to all clients in the
582  * game (including the one that has sent the new value)
583  * @param id The id of this property. <em>MUST be UNIQUE</em>! Used to send and
584  * receive changes in the property of the playere automatically via
585  * network.
586  * @param owner The parent of the object. Must be a KGame which manages
587  * the changes made to this object, i.e. which will send the new data.
588  * Note that in contrast to most KDE/QT classes KGameProperty objects
589  * are <em>not</em> deleted automatically!
590  **/
591 // TODO: ID: Very ugly - better use something like parent()->propertyId() or so which assigns a free id automatically.
592  KGameProperty(int id, KGamePropertyHandler* owner) : KGamePropertyBase(id, owner) { init(); }
593 
594  /**
595  * This constructor does nothing. You have to call
596  * KGamePropertyBase::registerData
597  * yourself before using the KGameProperty object.
598  **/
600 
601  ~KGameProperty() override {}
602 
603  /**
604  * Set the value depending on the current policy (see
605  * setConsistent). By default KGameProperty just uses send to set
606  * the value of a property. This behaviour can be changed by using
607  * setConsistent.
608  * @param v The new value of the property
609  **/
610  void setValue(type v)
611  {
612  switch (policy()) {
613  case PolicyClean:
614  send(v);
615  break;
616  case PolicyDirty:
617  changeValue(v);
618  break;
619  case PolicyLocal:
620  setLocal(v);
621  break;
622  default: // NEVER!
623  qCritical() << "Undefined Policy in property" << id();
624  return;
625  }
626  }
627 
628 
629  /**
630  * This function sends a new value over network.
631  *
632  * Note that the value DOES NOT change when you call this function. This
633  * function saves the value into a QDataStream and calls
634  * sendProperty where it gets forwarded to the owner and finally the
635  * value is sent over network. The KMessageServer now sends the
636  * value to ALL clients - even the one who called this function. As soon
637  * as the value from the message server is received load is called
638  * and _then_ the value of the KGameProperty has been set.
639  *
640  * This ensures that a KGameProperty has _always_ the same value on
641  * _every_ client in the network. Note that this means you can NOT do
642  * something like
643  * \code
644  * myProperty.send(1);
645  * doSomething(myProperty);
646  * \endcode
647  * as myProperty has not yet been set when doSomething is being called.
648  *
649  * You are informed about a value change by a signal from the parent of
650  * the property which can be deactivated by setEmittingSignal because of
651  * performance (you probably don't have to deactivate it - except you
652  * want to write a real-time game like Command&Conquer with a lot of
653  * activity). See emitSignal
654  *
655  * Note that if there is no KMessageServer accessible - before
656  * the property has been registered to the KGamePropertyHandler (as
657  * it is the case e.g. before a KPlayer has been plugged into the
658  * KGame object) the property is *not* sent but set *locally* (see
659  * setLocal)!
660  *
661  * @param v The new value of the property
662  * @return whether the property could be sent successfully
663  * @see setValue setLocal changeValue value
664  **/
665  bool send(type v)
666  {
667  if (isOptimized() && mData == v) {
668  return true;
669  }
670  if (isLocked()) {
671  return false;
672  }
673  QByteArray b;
674  QDataStream stream(&b, QIODevice::WriteOnly);
675  stream << v;
676  if (!sendProperty(b)) {
677  setLocal(v);
678  return false;
679  }
680  return true;
681  }
682 
683  /**
684  * This function sets the value of the property directly, i.e. it
685  * doesn't send it to the network.
686  *
687  * Int contrast to @see you change _only_ the local value when using
688  * this function. You do _not_ change the value of any other client. You
689  * probably don't want to use this if you are using a dedicated server
690  * (which is the only "client" which is allowed to change a value) but
691  * rather want to use send().
692  *
693  * But if you use your clients as servers (i.e. all clients receive a
694  * players turn and then calculate the reaction of the game theirselves)
695  * then you probably want to use setLocal as you can do things like
696  * \code
697  * myProperty.setLocal(1);
698  * doSomething(myProperty);
699  * \endcode
700  * on every client.
701  *
702  * If you want to set the value locally AND send it over network you
703  * want to call changeValue!
704  *
705  * You can also use setPolicy to set the default policy to
706  * PolicyLocal.
707  *
708  * @see setValue send changeValue value
709  **/
710  bool setLocal(type v)
711  {
712  if (isOptimized() && mData == v) {
713  return false;
714  }
715  if (isLocked()) {
716  return false;
717  }
718  mData = v;
719  setDirty(true);
720  if (isEmittingSignal()) {
721  emitSignal();
722  }
723  return true;
724  }
725 
726  /**
727  * This function does both, change the local value and change the
728  * network value. The value is sent over network first, then changed
729  * locally.
730  *
731  * This function is a convenience function and just calls send
732  * followed by setLocal
733  *
734  * Note that emitSignal is also called twice: once after
735  * setLocal and once when the value from send is received
736  *
737  * @see send setLocal setValue value
738  **/
739  void changeValue(type v)
740  {
741  send(v);
742  setLocal(v);
743  }
744 
745  /**
746  * Saves the object to a stream.
747  * @param stream The stream to save to
748  **/
749  void save(QDataStream &stream) override
750  {
751  stream << mData;
752  }
753 
754  /**
755  * @return The local value (see setLocal) if it is existing,
756  * otherwise the network value which is always consistent on every
757  * client.
758  **/
759  const type& value() const
760  {
761  return mData;
762  }
763 
764  /**
765  * Reads from a stream and assigns the read value to this object.
766  *
767  * This function is called automatically when a new value is received
768  * over network (i.e. it has been sent using send on this or any
769  * other client) or when a game is loaded (and maybe on some other
770  * events).
771  *
772  * Also calls emitSignal if isEmittingSignal is TRUE.
773  * @param s The stream to read from
774  **/
775  void load(QDataStream& s) override
776  {
777  s >> mData;
778  setDirty(false);
779  if (isEmittingSignal()) {
780  emitSignal();
781  }
782  }
783 
784  /**
785  * This calls setValue to change the value of the property. Note
786  * that depending on the policy (see setAlwaysConsistent) the
787  * returned value might be different from the assigned value!!
788  *
789  * So if you use setPolicy(PolicyClean):
790  * \code
791  * int a, b = 10;
792  * myProperty = b;
793  * a = myProperty.value();
794  * \endcode
795  * Here a and b would differ!
796  * The value is actually set as soon as it is received from the
797  * KMessageServer which forwards it to ALL clients in the network.
798  *
799  * If you use a clean policy (see setPolicy) then
800  * the returned value is the assigned value
801  **/
802  const type& operator=(const type& t)
803  {
804  setValue(t);
805  return value();
806  }
807 
808  /**
809  * This copies the data of property to the KGameProperty object.
810  *
811  * Equivalent to setValue(property.value());
812  **/
813  const type& operator=(const KGameProperty& property)
814  {
815  setValue(property.value());
816  return value();
817  }
818 
819  /**
820  * Yeah, you can do it!
821  * \code
822  * int a = myGamePropertyInt;
823  * \endcode
824  * If you don't see it: you don't have to use integerData.value()
825  **/
826  operator type() const { return value(); }
827 
828  const type_info* typeinfo() override { return &typeid(type); }
829 
830 private:
831  void init() { }
832 
833 private:
834  type mData;
835 };
836 
837 
842 
843 #endif
bool setLocal(type v)
This function sets the value of the property directly, i.e.
bool isDirty() const
KGameProperty()
This constructor does nothing.
Type type(const QSqlDatabase &db)
QCA_EXPORT void init()
bool isOptimized() const
See also setOptimize.
void load(QDataStream &s) override
Reads from a stream and assigns the read value to this object.
The main KDE game object.
Definition: kgame.h:57
KGameProperty(int id, KGamePropertyHandler *owner)
Constructs a KGameProperty object.
void changeValue(type v)
This function does both, change the local value and change the network value.
Base class for a game player.
Definition: kplayer.h:60
void setOptimized(bool p)
Sets this property to try to optimize signal and network handling by not sending it out when the prop...
void setDirty(bool d)
Sets the "dirty" flag of the property.
PropertyPolicy
The policy of the property.
void setValue(type v)
Set the value depending on the current policy (see setConsistent).
A class for network transparent games.
bool isLocked() const
A locked property can only be changed by the player who has set the lock.
A collection class for KGameProperty objects.
const type & operator=(const KGameProperty &property)
This copies the data of property to the KGameProperty object.
PropertyCommandIds
Commands for advanced properties (qint8)
Definition: kgameproperty.h:65
Base class of KGameProperty.
Definition: kgameproperty.h:36
virtual const type_info * typeinfo()
void setPolicy(PropertyPolicy p)
Changes the consistency policy of a property.
bool send(type v)
This function sends a new value over network.
const type_info * typeinfo() override
const type & value() const
const type & operator=(const type &t)
This calls setValue to change the value of the property.
PropertyPolicy policy() const
void setEmittingSignal(bool p)
Sets this property to emit a signal on value changed.
bool isEmittingSignal() const
See also setEmittingSignal.
void save(QDataStream &stream) override
Saves the object to a stream.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Tue May 17 2022 03:46:11 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.