home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / SLAX 6.0.8 / slax-6.0.8.iso / slax / base / 006-devel.lzm / usr / include / kgame / kgameproperty.h < prev    next >
Encoding:
C/C++ Source or Header  |  2005-10-10  |  27.8 KB  |  849 lines

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