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

KDE's Doxygen guidelines are available online.