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