Warning, file /games/libkdegames/src/private/kgame/kgameproperty.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     This file is part of the KDE games library
0003     SPDX-FileCopyrightText: 2001 Andreas Beckermann <b_mann@gmx.de>
0004     SPDX-FileCopyrightText: 2001 Martin Heni <kde at heni-online.de>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #ifndef __KGAMEPROPERTY_H_
0010 #define __KGAMEPROPERTY_H_
0011 
0012 // own
0013 #include "kdegamesprivate_export.h"
0014 // Qt
0015 #include <QDataStream>
0016 #include <QDebug>
0017 #include <QIODevice>
0018 // Std
0019 #include <typeinfo>
0020 
0021 class KGame;
0022 class KPlayer;
0023 class KGamePropertyHandler;
0024 using namespace std;
0025 
0026 /**
0027  * \class KGamePropertyBase kgameproperty.h <KGame/KGameProperty>
0028  *
0029  * @short Base class of KGameProperty
0030  *
0031  * The KGamePropertyBase class is the base class of KGameProperty. See
0032  * KGameProperty for further information.
0033  *
0034  * @author Andreas Beckermann <b_mann@gmx.de>
0035  */
0036 class KDEGAMESPRIVATE_EXPORT KGamePropertyBase
0037 {
0038 public:
0039     enum PropertyDataIds { // these belong to KPlayer/KGame!
0040         // KPlayer
0041         IdGroup = 1,
0042         IdUserId = 2,
0043         IdAsyncInput = 3,
0044         IdTurn = 4,
0045         IdName = 5,
0046 
0047         // KGame
0048         IdGameStatus = 6,
0049         IdMaxPlayer = 7,
0050         IdMinPlayer = 8,
0051 
0052         // Input Grabbing
0053         IdGrabInput = 16,
0054         IdReleaseInput = 17,
0055 
0056         IdCommand, // Reserved for internal use
0057         IdUser = 256,
0058 
0059         IdAutomatic = 0x7000 // Id's from here on are automatically given (16bit)
0060     };
0061 
0062     /**
0063      * Commands for advanced properties (qint8)
0064      */
0065     enum PropertyCommandIds {
0066         // General
0067         CmdLock = 1,
0068 
0069         // Array
0070         CmdAt = 51,
0071         CmdResize = 52,
0072         CmdFill = 53,
0073         CmdSort = 54,
0074 
0075         // List (could be the same id's actually)
0076         CmdInsert = 61,
0077         CmdAppend = 62,
0078         CmdRemove = 63,
0079         CmdClear = 64
0080     };
0081 
0082     /**
0083      * The policy of the property. This can be PolicyClean (setValue uses
0084      * send), PolicyDirty (setValue uses changeValue) or
0085      * PolicyLocal (setValue uses setLocal).
0086      *
0087      * A "clean" policy means that the property is always the same on every
0088      * client. This is achieved by calling send which actually changes
0089      * the value only when the message from the MessageServer is received.
0090      *
0091      * A "dirty" policy means that as soon as setValue is called the
0092      * property is changed immediately. And additionally sent over network.
0093      * This can sometimes lead to bugs as the other clients do not
0094      * immediately have the same value. For more information see
0095      * changeValue.
0096      *
0097      * PolicyLocal means that a KGameProperty behaves like ever
0098      * "normal" variable. Whenever setValue is called (e.g. using "=")
0099      * the value of the property is changes immediately without sending it
0100      * over network. You might want to use this if you are sure that all
0101      * clients set the property at the same time.
0102      */
0103     enum PropertyPolicy { PolicyUndefined = 0, PolicyClean = 1, PolicyDirty = 2, PolicyLocal = 3 };
0104 
0105     /**
0106      * Constructs a KGamePropertyBase object and calls registerData.
0107      * @param id The id of this property. MUST be UNIQUE! Used to send and
0108      * receive changes in the property of the player automatically via
0109      * network.
0110      * @param owner The owner of the object. Must be a KGamePropertyHandler which manages
0111      * the changes made to this object, i.e. which will send the new data
0112      */
0113     KGamePropertyBase(int id, KGamePropertyHandler *owner);
0114 
0115     KGamePropertyBase(int id, KGame *parent);
0116     KGamePropertyBase(int id, KPlayer *parent);
0117 
0118     /**
0119      * Creates a KGamePropertyBase object without an owner. Remember to call
0120      * registerData!
0121      */
0122     KGamePropertyBase();
0123 
0124     virtual ~KGamePropertyBase();
0125 
0126     /**
0127      * Changes the consistency policy of a property. The
0128      * PropertyPolicy is one of PolicyClean (defaulz), PolicyDirty or PolicyLocal.
0129      *
0130      * It is up to you to decide how you want to work.
0131      */
0132     void setPolicy(PropertyPolicy p)
0133     {
0134         mFlags.bits.policy = p;
0135     }
0136 
0137     /**
0138      * @return The default policy of the property
0139      */
0140     PropertyPolicy policy() const
0141     {
0142         return (PropertyPolicy)mFlags.bits.policy;
0143     }
0144 
0145     /**
0146      * Sets this property to emit a signal on value changed.
0147      * As the properties do not inherit QObject for optimization
0148      * this signal is emitted via the KPlayer or KGame object
0149      */
0150     void setEmittingSignal(bool p)
0151     {
0152         mFlags.bits.emitsignal = p;
0153     }
0154 
0155     /**
0156      * See also setEmittingSignal
0157      * @return Whether this property emits a signal on value change
0158      */
0159     bool isEmittingSignal() const
0160     {
0161         return mFlags.bits.emitsignal;
0162     }
0163 
0164     /**
0165      * Sets this property to try to optimize signal and network handling
0166      * by not sending it out when the property value is not changed.
0167      */
0168     void setOptimized(bool p)
0169     {
0170         mFlags.bits.optimize = p;
0171     }
0172 
0173     /**
0174      * See also setOptimize
0175      * @return Whether the property optimizes access (signals,network traffic)
0176      */
0177     bool isOptimized() const
0178     {
0179         return mFlags.bits.optimize;
0180     }
0181 
0182     /**
0183      * @return Whether this property is "dirty". See also setDirty
0184      */
0185     bool isDirty() const
0186     {
0187         return mFlags.bits.dirty;
0188     }
0189 
0190     /**
0191      * A locked property can only be changed by the player who has set the
0192      * lock. See also setLocked
0193      * @return Whether this property is currently locked.
0194      */
0195     bool isLocked() const
0196     {
0197         return mFlags.bits.locked;
0198     }
0199 
0200     /**
0201      * A locked property can only be changed by the player who has set the
0202      * lock.
0203      *
0204      * You can only call this if isLocked is false. A message is sent
0205      * over network so that the property is locked for all players except
0206      * you.
0207      *
0208      * @return returns false if the property can not be locked, i.e. it is already locked
0209      *
0210      */
0211     bool lock();
0212 
0213     /**
0214      * A locked property can only be changed by the player who has set the
0215      * lock.
0216      *
0217      * You can only call this if isLocked is false. A message is sent
0218      * over network so that the property is locked for all players except
0219      * you.
0220      *
0221      * @return returns false if the property can not be locked, i.e. it is already locked
0222      *
0223      */
0224     bool unlock(bool force = false);
0225 
0226     /**
0227      * This will read the value of this property from the stream. You MUST
0228      * overwrite this method in order to use this class
0229      * @param s The stream to read from
0230      */
0231     virtual void load(QDataStream &s) = 0;
0232 
0233     /**
0234      * Write the value into a stream. MUST be overwritten
0235      */
0236     virtual void save(QDataStream &s) = 0;
0237 
0238     /**
0239      * send a command to advanced properties like arrays
0240      * @param stream The stream containing the data of the command
0241      * @param msgid The ID of the command - see PropertyCommandIds
0242      * @param isSender whether this client is also the sender of the command
0243      */
0244     virtual void command(QDataStream &stream, int msgid, bool isSender = false);
0245 
0246     /**
0247      * @return The id of this property
0248      */
0249     int id() const
0250     {
0251         return mId;
0252     }
0253 
0254     /**
0255      * @return a type_info of the data this property contains.
0256      */
0257     virtual const type_info *typeinfo()
0258     {
0259         return &typeid(this);
0260     }
0261 
0262     /**
0263      * You have to register a KGamePropertyBase before you can use it.
0264      *
0265      * You MUST call this before you can use KGamePropertyBase!
0266      *
0267      * @param id the id of this KGamePropertyBase object. The id MUST be
0268      * unique, i.e. you cannot have two properties with the same id for one
0269      * player, although (currently) nothing prevents you from doing so. But
0270      * you will get strange results!
0271      *
0272      * @param owner The owner of this data. This will send the data
0273      * using KPropertyHandler::sendProperty whenever you call send
0274      *
0275      * @param p If not 0 you can set the policy of the property here
0276      *
0277      * @param name if not 0 you can assign a name to this property
0278      *
0279      */
0280     int registerData(int id, KGamePropertyHandler *owner, PropertyPolicy p, const QString &name = QString());
0281 
0282     /**
0283      * This is an overloaded member function, provided for convenience.
0284      * It differs from the above function only in what argument(s) it accepts.
0285      */
0286     int registerData(int id, KGamePropertyHandler *owner, const QString &name = QString());
0287 
0288     /**
0289      * This is an overloaded member function, provided for convenience.
0290      * It differs from the above function only in what argument(s) it accepts.
0291      */
0292     int registerData(int id, KGame *owner, const QString &name = QString());
0293 
0294     /**
0295      * This is an overloaded member function, provided for convenience.
0296      * It differs from the above function only in what argument(s) it accepts.
0297      */
0298     int registerData(int id, KPlayer *owner, const QString &name = QString());
0299 
0300     /**
0301      * This is an overloaded member function, provided for convenience.
0302      * It differs from the above function only in what argument(s) it accepts.
0303      * In particular you can use this function to create properties which
0304      * will have an automatic id assigned. The new id is returned.
0305      */
0306     int registerData(KGamePropertyHandler *owner, PropertyPolicy p = PolicyUndefined, const QString &name = QString());
0307 
0308     void unregisterData();
0309 
0310 protected:
0311     /**
0312      * A locked property can only be changed by the player who has set the
0313      * lock.
0314      *
0315      * You can only call this if isLocked is false. A message is sent
0316      * over network so that the property is locked for all players except
0317      * you.
0318      * Usually you use lock and unlock to access this property
0319      *
0320      */
0321     void setLock(bool l);
0322 
0323     /**
0324      * Sets the "dirty" flag of the property. If a property is "dirty" i.e.
0325      * KGameProperty::setLocal has been called there is no guarantee
0326      * that all clients share the same value. You have to ensure this
0327      * yourself e.g. by calling KGameProperty::setLocal on every
0328      * client. You can also ignore the dirty flag and continue working withe
0329      * the property depending on your situation.
0330      */
0331     void setDirty(bool d)
0332     {
0333         mFlags.bits.dirty = d;
0334     }
0335 
0336     /**
0337      * Forward the data to the owner of this property which then sends it
0338      * over network. save is used to store the data into a stream so
0339      * you have to make sure that function is working properly if you
0340      * implement your own property!
0341      *
0342      * Note: this sends the <em>current</em> property!
0343      *
0344      * Might be obsolete - KGamePropertyArray still uses it. Is this a bug
0345      * or correct?
0346      */
0347     bool sendProperty();
0348 
0349     /**
0350      * Forward the data to the owner of this property which then sends it
0351      * over network. save is used to store the data into a stream so
0352      * you have to make sure that function is working properly if you
0353      * implement your own property!
0354      *
0355      * This function is used by send to send the data over network.
0356      * This does <em>not</em> send the current value but the explicitly
0357      * given value.
0358      *
0359      * @return TRUE if the message could be sent successfully, otherwise
0360      * FALSE
0361      */
0362     bool sendProperty(const QByteArray &b);
0363 
0364     /**
0365      * Causes the parent object to emit a signal on value change
0366      */
0367     void emitSignal();
0368 
0369 protected:
0370     KGamePropertyHandler *mOwner;
0371 
0372     // Having this as a union of the bitfield and the char
0373     // allows us to stream this quantity easily (if we need to)
0374     // At the moment it is not yet transmitted
0375     union Flags {
0376         char flag;
0377         struct {
0378             // unsigned char dosave : 1;   // do save this property
0379             // unsigned char delaytransmit : 1;   // do not send immediately on
0380             // change but a KPlayer:QTimer
0381             // sends it later on - fast
0382             // changing variables
0383             unsigned char emitsignal : 1; // KPlayer notifies on variable change (true)
0384             // unsigned char readonly : 1; // whether the property can be changed (false)
0385             unsigned char optimize : 1; // whether the property tries to optimize send/emit (false)
0386             unsigned char dirty : 1; // whether the property dirty (setLocal() was used)
0387             unsigned char policy : 2; // whether the property is always consistent (see PropertyPolicy)
0388             unsigned char locked : 1; // whether the property is locked (true)
0389         } bits;
0390     } mFlags;
0391 
0392 private:
0393     friend class KGamePropertyHandler;
0394     void init();
0395 
0396 private:
0397     int mId;
0398 };
0399 
0400 /**
0401  * \class KGameProperty kgameproperty.h <KGame/KGameProperty>
0402  *
0403  * @short A class for network transparent games
0404  *
0405  * Note: The entire API documentation is obsolete!
0406  *
0407  * The class KGameProperty can store any form of data and will transmit it via
0408  * network whenever you call send. This makes network transparent games
0409  * very easy. You first have to register the data to a KGamePropertyHandler
0410  * using KGamePropertyBase::registerData (which is called by the
0411  * constructor). For the KGamePropertyHandler you can use
0412  * KGame::dataHandler or KPlayer::dataHandler but you can also create your
0413  * own data handler.
0414  *
0415  * There are several concepts you can follow when writing network games. These
0416  * concepts differ completely from the way how data is transferred so you should
0417  * decide which one to use. You can also mix these concepts for a single
0418  * property but we do not recommend this. The concepts:
0419  * <ul>
0420  * <li> Always Consistent (clean)
0421  * <li> Not Always Consistent (dirty)
0422  * <li> A Mixture (very dirty)
0423  * </ul>
0424  * I repeat: we do <em>not</em> recommend the third option ("a mixture"). Unless
0425  * you have a good reason for this you will probably introduce some hard to find
0426  * (and to fix) bugs.
0427  *
0428  * @section Always consistent (clean):
0429  *
0430  * This "policy" is default. Whenever you create a KGameProperty it is always
0431  * consistent. This means that consistency is the most important thing for the
0432  * property. This is achieved by using send to change the value of the
0433  * property. send needs a running KMessageServer and therefore
0434  * <em>MUST</em> be plugged into a KGamePropertyHandler using either
0435  * registerData or the constructor. The parent of the dataHandler must be able
0436  * to send messages (see above: the message server must be running). If you use
0437  * send to change the value of a property you won't see the effect
0438  * immediately: The new value is first transferred to the message server which
0439  * queues the message. As soon as <em>all</em> messages in the message server
0440  * which are before the changed property have been transferred the message
0441  * server delivers the new value of the KGameProperty to all clients. A
0442  * QTimer::singleShot is used to queue the messages inside the
0443  * KMessageServer.
0444  *
0445  * This means that if you do the following:
0446  * \code
0447  * KGamePropertyInt myProperty(id, dataHandler());
0448  * myProperty.initData(0);
0449  * myProperty = 10;
0450  * int value = myProperty.value();
0451  * \endcode
0452  * then "value" will be "0". initData is used to initialize the property
0453  * (e.g. when the KMessageServer is not yet running or can not yet be
0454  * reached). This is because "myProperty = 10" or "myProperty.send(10)" send a
0455  * message to the KMessageServer which uses QTimer::singleShot to
0456  * queue the message. The game first has to go back into the event loop where
0457  * the message is received. The KGamePropertyHandler receives the new value
0458  * sets the property. So if you need the new value you need to store it in a
0459  * different variable (see setLocal which creates one for you until the
0460  * message is received). The KGamePropertyHandler emits a signal (unless
0461  * you called setEmitSignal with false) when the new value is received:
0462  * KGamePropertyHandler::signalPropertyChanged. You can use this to react
0463  * to a changed property.
0464  *
0465  * This may look quite confusing but it has a <em>big</em> advantage: all
0466  * KGameProperty objects are ensured to have the same value on all clients in
0467  * the game at every time. This way you will save you a lot of trouble as
0468  * debugging can be very difficult if the value of a property changes
0469  * immediately on client A but only after one or two additional messages
0470  * (function calls, status changes, ...) on client B.
0471  *
0472  * The only disadvantage of this (clean) concept is that you cannot use a
0473  * changed variable immediately but have to wait for the KMessageServer to
0474  * change it. You probably want to use
0475  * KGamePropertyHandler::signalPropertyChanged for this.
0476  *
0477  * @section Not Always Consistent (dirty):
0478  *
0479  * There are a lot of people who don't want to use the (sometimes quite complex)
0480  * "clean" way. You can use setAlwaysConsistent to change the default
0481  * behaviour of the KGameProperty. If a property is not always consistent
0482  * it will use changeValue to send the property.  changeValue also uses
0483  * send to send the new value over network but it also uses
0484  * setLocal to create a local copy of the property. This copy is created
0485  * dynamically and is deleted again as soon as the next message from the network
0486  * is received. To use the example above again:
0487  * \code
0488  * KGamePropertyInt myProperty(id, dataHandler());
0489  * myProperty.setAlwaysConsistent(false);
0490  * myProperty.initData(0);
0491  * myProperty = 10;
0492  * int value = myProperty.value();
0493  * \endcode
0494  * Now this example will "work" so value now is 10. Additionally the
0495  * KMessageServer receives a message from the local client (just as explained
0496  * above in "Always Consistent"). As soon as the message returns to the local
0497  * client again the local value is deleted, as the "network value" has the same
0498  * value as the local one. So you won't lose the ability to use the always
0499  * consistent "clean" value of the property if you use the "dirty" way. Just use
0500  * networkValue to access the value which is consistent among all clients.
0501  *
0502  * The advantage of this concept is clear: you can use a KGameProperty as
0503  * every other variable as the changes value takes immediate effect.
0504  * Additionally you can be sure that the value is transferred to all clients.
0505  * You will usually not experience serious bugs just because you use the "dirty"
0506  * way. Several events have to happen at once to get these "strange errors"
0507  * which result in inconsistent properties (like "game running" on client A but
0508  * "game ended/paused" on client B).  But note that there is a very good reason
0509  * for the existence of these different concepts of KGameProperty. I have
0510  * myself experienced such a "strange error" and it took me several days to find
0511  * the reason until I could fix it. So I personally recommend the "clean" way.
0512  * On the other hand if you want to port a non-network game to a network game
0513  * you will probably start with "dirty" properties as it is you will not have to
0514  * change that much code...
0515  *
0516  * @section A Mixture (very dirty):
0517  *
0518  * You can also mix the concepts above. Note that we really don't recommend
0519  * this. With a mixture I mean something like this:
0520  * \code
0521  * KGamePropertyInt myProperty(id, dataHandler());
0522  * myProperty.setAlwaysConsistent(false);
0523  * myProperty.initData(0);
0524  * myProperty = 10;
0525  * myProperty.setAlwaysConsistent(true);
0526  * myProperty = 20;
0527  * \endcode
0528  * (totally senseless example, btw) I.e. I am speaking of mixing both concepts
0529  * for a single property. Things like
0530  * \code
0531  * KGamePropertyInt myProperty1(id1, dataHandler());
0532  * KGamePropertyInt myProperty2(id2, dataHandler());
0533  * myProperty1.initData(0);
0534  * myProperty2.initData(0);
0535  * myProperty1.setAlwaysConsistent(false);
0536  * myProperty2.setAlwaysConsistent(true);
0537  * myProperty1 = 10;
0538  * myProperty2 = 20;
0539  * \endcode
0540  * are ok. But mixing the concepts for a single property will make it nearly
0541  * impossible to you to debug your game.
0542  *
0543  * So the right thing to do(tm) is to decide in the constructor whether you want
0544  * a "clean" or "dirty" property.
0545  *
0546  * Even if you have decided for one of the concepts you still can manually
0547  * follow another concept than the "policy" of your property. So if you use an
0548  * always consistent KGameProperty you still can manually call
0549  * changeValue as if it was not always consistent. Note that although this is
0550  * also kind of a "mixture" as described above this is very useful sometimes. In
0551  * contrast to the "mixture" above you don't have the problem that you don't
0552  * exactly know which concept you are currently following because you used the
0553  * function of the other concept only once.
0554  *
0555  * @section Custom classes:
0556  *
0557  * If you want to use a custom class with KGameProperty you have to implement the
0558  * operators << and >> for QDataStream:
0559  * \code
0560  * class Card
0561  * {
0562  * public:
0563  * int type;
0564  * int suite;
0565  * };
0566  * QDataStream& operator<<(QDataStream& stream, Card& card)
0567  * {
0568  * qint16 type = card.type;
0569  * qint16 suite = card.suite;
0570  * s << type;
0571  * s << suite;
0572  * return s;
0573  * }
0574  * QDataStream& operator>>(QDataStream& stream, Card& card)
0575  * {
0576  * qint16 type;
0577  * qint16 suite;
0578  * s >> type;
0579  * s >> suite;
0580  * card.type = (int)type;
0581  * card.suite = (int)suite;
0582  * return s;
0583  * }
0584  *
0585  * class Player : KPlayer
0586  * {
0587  * [...]
0588  * KGameProperty<Card> mCards;
0589  * };
0590  * \endcode
0591  *
0592  * Note: unlike most QT classes KGameProperty objects are *not* deleted
0593  * automatically! So if you create an object using e.g. KGameProperty<int>* data =
0594  * new KGameProperty(id, dataHandler()) you have to put a delete data into your
0595  * destructor!
0596  *
0597  * @author Andreas Beckermann <b_mann@gmx.de>
0598  */
0599 template<class type>
0600 class KGameProperty : public KGamePropertyBase
0601 {
0602 public:
0603     /**
0604      * Constructs a KGameProperty object. A KGameProperty object will transmit
0605      * any changes to the KMessageServer and then to all clients in the
0606      * game (including the one that has sent the new value)
0607      * @param id The id of this property. <em>MUST be UNIQUE</em>! Used to send and
0608      * receive changes in the property of the playere automatically via
0609      * network.
0610      * @param owner The parent of the object. Must be a KGame which manages
0611      * the changes made to this object, i.e. which will send the new data.
0612      * Note that in contrast to most KDE/QT classes KGameProperty objects
0613      * are <em>not</em> deleted automatically!
0614      */
0615     // TODO: ID: Very ugly - better use something like parent()->propertyId() or so which assigns a free id automatically.
0616     KGameProperty(int id, KGamePropertyHandler *owner)
0617         : KGamePropertyBase(id, owner)
0618     {
0619         init();
0620     }
0621 
0622     /**
0623      * This constructor does nothing. You have to call
0624      * KGamePropertyBase::registerData
0625      * yourself before using the KGameProperty object.
0626      */
0627     KGameProperty()
0628         : KGamePropertyBase()
0629     {
0630         init();
0631     }
0632 
0633     ~KGameProperty() override
0634     {
0635     }
0636 
0637     /**
0638      * Set the value depending on the current policy (see
0639      * setConsistent). By default KGameProperty just uses send to set
0640      * the value of a property. This behaviour can be changed by using
0641      * setConsistent.
0642      * @param v The new value of the property
0643      */
0644     void setValue(type v)
0645     {
0646         switch (policy()) {
0647         case PolicyClean:
0648             send(v);
0649             break;
0650         case PolicyDirty:
0651             changeValue(v);
0652             break;
0653         case PolicyLocal:
0654             setLocal(v);
0655             break;
0656         default: // NEVER!
0657             qCritical() << "Undefined Policy in property" << id();
0658             return;
0659         }
0660     }
0661 
0662     /**
0663      * This function sends a new value over network.
0664      *
0665      * Note that the value DOES NOT change when you call this function. This
0666      * function saves the value into a QDataStream and calls
0667      * sendProperty where it gets forwarded to the owner and finally the
0668      * value is sent over network. The KMessageServer now sends the
0669      * value to ALL clients - even the one who called this function. As soon
0670      * as the value from the message server is received load is called
0671      * and _then_ the value of the KGameProperty has been set.
0672      *
0673      * This ensures that a KGameProperty has _always_ the same value on
0674      * _every_ client in the network. Note that this means you can NOT do
0675      * something like
0676      * \code
0677      * myProperty.send(1);
0678      * doSomething(myProperty);
0679      * \endcode
0680      * as myProperty has not yet been set when doSomething is being called.
0681      *
0682      * You are informed about a value change by a signal from the parent of
0683      * the property which can be deactivated by setEmittingSignal because of
0684      * performance (you probably don't have to deactivate it - except you
0685      * want to write a real-time game like Command&Conquer with a lot of
0686      * activity). See emitSignal
0687      *
0688      * Note that if there is no KMessageServer accessible - before
0689      * the property has been registered to the KGamePropertyHandler (as
0690      * it is the case e.g. before a KPlayer has been plugged into the
0691      * KGame object) the property is *not* sent but set *locally* (see
0692      * setLocal)!
0693      *
0694      * @param v The new value of the property
0695      * @return whether the property could be sent successfully
0696      * @see setValue setLocal changeValue value
0697      */
0698     bool send(type v)
0699     {
0700         if (isOptimized() && mData == v) {
0701             return true;
0702         }
0703         if (isLocked()) {
0704             return false;
0705         }
0706         QByteArray b;
0707         QDataStream stream(&b, QIODevice::WriteOnly);
0708         stream << v;
0709         if (!sendProperty(b)) {
0710             setLocal(v);
0711             return false;
0712         }
0713         return true;
0714     }
0715 
0716     /**
0717      * This function sets the value of the property directly, i.e. it
0718      * doesn't send it to the network.
0719      *
0720      * Int contrast to @see you change _only_ the local value when using
0721      * this function. You do _not_ change the value of any other client. You
0722      * probably don't want to use this if you are using a dedicated server
0723      * (which is the only "client" which is allowed to change a value) but
0724      * rather want to use send().
0725      *
0726      * But if you use your clients as servers (i.e. all clients receive a
0727      * players turn and then calculate the reaction of the game theirselves)
0728      * then you probably want to use setLocal as you can do things like
0729      * \code
0730      * myProperty.setLocal(1);
0731      * doSomething(myProperty);
0732      * \endcode
0733      * on every client.
0734      *
0735      * If you want to set the value locally AND send it over network you
0736      * want to call changeValue!
0737      *
0738      * You can also use setPolicy to set the default policy to
0739      * PolicyLocal.
0740      *
0741      * @see setValue send changeValue value
0742      */
0743     bool setLocal(type v)
0744     {
0745         if (isOptimized() && mData == v) {
0746             return false;
0747         }
0748         if (isLocked()) {
0749             return false;
0750         }
0751         mData = v;
0752         setDirty(true);
0753         if (isEmittingSignal()) {
0754             emitSignal();
0755         }
0756         return true;
0757     }
0758 
0759     /**
0760      * This function does both, change the local value and change the
0761      * network value. The value is sent over network first, then changed
0762      * locally.
0763      *
0764      * This function is a convenience function and just calls send
0765      * followed by setLocal
0766      *
0767      * Note that emitSignal is also called twice: once after
0768      * setLocal and once when the value from send is received
0769      *
0770      * @see send setLocal setValue value
0771      */
0772     void changeValue(type v)
0773     {
0774         send(v);
0775         setLocal(v);
0776     }
0777 
0778     /**
0779      * Saves the object to a stream.
0780      * @param stream The stream to save to
0781      */
0782     void save(QDataStream &stream) override
0783     {
0784         stream << mData;
0785     }
0786 
0787     /**
0788      * @return The local value (see setLocal) if it is existing,
0789      * otherwise the network value which is always consistent on every
0790      * client.
0791      */
0792     const type &value() const
0793     {
0794         return mData;
0795     }
0796 
0797     /**
0798      * Reads from a stream and assigns the read value to this object.
0799      *
0800      * This function is called automatically when a new value is received
0801      * over network (i.e. it has been sent using send on this or any
0802      * other client) or when a game is loaded (and maybe on some other
0803      * events).
0804      *
0805      * Also calls emitSignal if isEmittingSignal is TRUE.
0806      * @param s The stream to read from
0807      */
0808     void load(QDataStream &s) override
0809     {
0810         s >> mData;
0811         setDirty(false);
0812         if (isEmittingSignal()) {
0813             emitSignal();
0814         }
0815     }
0816 
0817     /**
0818      * This calls setValue to change the value of the property. Note
0819      * that depending on the policy (see setAlwaysConsistent) the
0820      * returned value might be different from the assigned value!!
0821      *
0822      * So if you use setPolicy(PolicyClean):
0823      * \code
0824      * int a, b = 10;
0825      * myProperty = b;
0826      * a = myProperty.value();
0827      * \endcode
0828      * Here a and b would differ!
0829      * The value is actually set as soon as it is received from the
0830      * KMessageServer which forwards it to ALL clients in the network.
0831      *
0832      * If you use a clean policy (see setPolicy) then
0833      * the returned value is the assigned value
0834      */
0835     const type &operator=(const type &t)
0836     {
0837         setValue(t);
0838         return value();
0839     }
0840 
0841     /**
0842      * This copies the data of property to the KGameProperty object.
0843      *
0844      * Equivalent to setValue(property.value());
0845      */
0846     const type &operator=(const KGameProperty &property)
0847     {
0848         setValue(property.value());
0849         return value();
0850     }
0851 
0852     /**
0853      * Yeah, you can do it!
0854      * \code
0855      *  int a = myGamePropertyInt;
0856      * \endcode
0857      * If you don't see it: you don't have to use integerData.value()
0858      */
0859     operator type() const
0860     {
0861         return value();
0862     }
0863 
0864     const type_info *typeinfo() override
0865     {
0866         return &typeid(type);
0867     }
0868 
0869 private:
0870     void init()
0871     {
0872     }
0873 
0874 private:
0875     type mData;
0876 };
0877 
0878 typedef KGameProperty<int> KGamePropertyInt;
0879 typedef KGameProperty<unsigned int> KGamePropertyUInt;
0880 typedef KGameProperty<QString> KGamePropertyQString;
0881 typedef KGameProperty<qint8> KGamePropertyBool;
0882 
0883 #endif