KDEGames

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

KDE's Doxygen guidelines are available online.