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

KDE's Doxygen guidelines are available online.