1 /** @file thinkerdata.h  Base class for thinker private data.
2  *
3  * @authors Copyright (c) 2014-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4  *
5  * @par License
6  * GPL: http://www.gnu.org/licenses/gpl.html
7  *
8  * <small>This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by the
10  * Free Software Foundation; either version 2 of the License, or (at your
11  * option) any later version. This program is distributed in the hope that it
12  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14  * Public License for more details. You should have received a copy of the GNU
15  * General Public License along with this program; if not, write to the Free
16  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17  * 02110-1301 USA</small>
18   */
19 
20 #ifndef LIBDOOMSDAY_THINKERDATA_H
21 #define LIBDOOMSDAY_THINKERDATA_H
22 
23 #include "thinker.h"
24 
25 #include <de/Process>
26 #include <de/Id>
27 #include <de/IObject>
28 #include <de/ISerializable>
29 
30 /**
31  * Base class for thinker private data.
32  *
33  * Contains internal functionality common to all thinkers regardless of their type.
34  */
35 class LIBDOOMSDAY_PUBLIC ThinkerData
36         : public Thinker::IData
37         , public de::IObject
38         , public de::ISerializable
39         , public de::Deletable
40 {
41 public:
42     DENG2_DEFINE_AUDIENCE2(Deletion, void thinkerBeingDeleted(thinker_s &))
43 
44 public:
45     ThinkerData(de::Id const &id = de::Id::none());
46     ThinkerData(ThinkerData const &other);
47 
48     /**
49      * Returns the unique and persistent ID of the thinker.
50      *
51      * Note that due to historical reasons game-side mobj IDs are separately enumerated
52      * 16-bit numbers.
53      *
54      * @return Thinker ID.
55      *
56      * @todo Use this for identifying all thinkers everywhere, including mobjs.
57      */
58     de::Id const &id() const;
59 
60     void setId(de::Id const &id);
61 
62     void setThinker(thinker_s *thinker) override;
63     void think() override;
64     IData *duplicate() const override;
65 
66     thinker_s &thinker();
67     thinker_s const &thinker() const;
68 
69     /**
70      * Initializes Doomsday Script bindings for the thinker. This is called
71      * when the thinker is added to the world, so mobjs have been assigned
72      * their IDs.
73      */
74     virtual void initBindings();
75 
76     // Implements IObject.
77     de::Record &objectNamespace() override;
78     de::Record const &objectNamespace() const override;
79 
80     // Implements ISerializable.
81     void operator >> (de::Writer &to) const override;
82     void operator << (de::Reader &from) override;
83 
84 public:
85     /*
86      * Finds a thinker based on its unique identifier. This searches all ThinkerData
87      * instances in existence at the moment. If there happens to be multiple ThinkerData
88      * instances with the same ID, returns the most recently created instance.
89      *
90      * @param id  Identifier.
91      * @return Thinker or @c nullptr.
92      */
93     static ThinkerData *find(de::Id const &id);
94 
95 private:
96     DENG2_PRIVATE(d)
97 
98 #ifdef DENG2_DEBUG
99 public:
100     struct DebugCounter {
101         de::Id id;
102         static de::duint32 total;
103 
DebugCounterDebugCounter104         DebugCounter()  { total++; }
~DebugCounterDebugCounter105         ~DebugCounter() { total--; }
106     };
107     DebugCounter _debugCounter;
108 
109     struct DebugValidator {
DebugValidatorDebugValidator110         DebugValidator()  { DENG2_ASSERT(DebugCounter::total == 0); }
~DebugValidatorDebugValidator111         ~DebugValidator() { DENG2_ASSERT(DebugCounter::total == 0); }
112     };
113 #endif
114 };
115 
116 DENG2_SCRIPT_ARGUMENT_TYPE(ThinkerData *,
117     if (!arg) return ScriptLex::NONE;
118     return scriptArgumentAsText(arg->objectNamespace());
119 )
120 
121 DENG2_SCRIPT_ARGUMENT_TYPE(ThinkerData const *,
122     if (!arg) return ScriptLex::NONE;
123     return scriptArgumentAsText(arg->objectNamespace());
124 )
125 
126 #endif // LIBDOOMSDAY_THINKERDATA_H
127