1 /** @file thinkerdata.cpp 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 #include "doomsday/world/thinkerdata.h"
21 #include "doomsday/world/map.h"
22
23 #include <QMultiHash>
24
25 using namespace de;
26
27 static QMultiHash<Id::Type, ThinkerData *> thinkerLookup;
28
DENG2_PIMPL(ThinkerData)29 DENG2_PIMPL(ThinkerData)
30 {
31 thinker_s *think;
32 Id id; ///< Internal unique ID.
33 Record names;
34
35 Impl(Public *i, Id const &id)
36 : Base(i)
37 , think(0)
38 , id(id)
39 {}
40
41 Impl(Public *i, Impl const &other)
42 : Base(i)
43 , think(other.think)
44 , id(other.id)
45 , names(other.names)
46 {}
47
48 ~Impl()
49 {
50 thinkerLookup.remove(id, &self());
51
52 DENG2_FOR_PUBLIC_AUDIENCE2(Deletion, i)
53 {
54 i->thinkerBeingDeleted(*think);
55 }
56 }
57
58 DENG2_PIMPL_AUDIENCE(Deletion)
59 };
60
DENG2_AUDIENCE_METHOD(ThinkerData,Deletion)61 DENG2_AUDIENCE_METHOD(ThinkerData, Deletion)
62
63 ThinkerData::ThinkerData(Id const &id)
64 : d(new Impl(this, id))
65 {
66 if (d->id)
67 {
68 thinkerLookup.insert(d->id, this);
69 }
70 }
71
ThinkerData(ThinkerData const & other)72 ThinkerData::ThinkerData(ThinkerData const &other) : d(new Impl(this, *other.d))
73 {
74 if (d->id)
75 {
76 thinkerLookup.insert(d->id, this);
77 }
78 }
79
id() const80 Id const &ThinkerData::id() const
81 {
82 return d->id;
83 }
84
setId(Id const & id)85 void ThinkerData::setId(Id const &id)
86 {
87 thinkerLookup.remove(d->id, this);
88 thinkerLookup.insert(id, this);
89
90 d->id = id;
91 }
92
setThinker(thinker_s * thinker)93 void ThinkerData::setThinker(thinker_s *thinker)
94 {
95 d->think = thinker;
96 }
97
think()98 void ThinkerData::think()
99 {
100 /// @todo If there is a think function in the Record, call it now. -jk
101 }
102
duplicate() const103 Thinker::IData *ThinkerData::duplicate() const
104 {
105 return new ThinkerData(*this);
106 }
107
thinker()108 thinker_s &ThinkerData::thinker()
109 {
110 DENG2_ASSERT(d->think != 0);
111 return *d->think;
112 }
113
thinker() const114 thinker_s const &ThinkerData::thinker() const
115 {
116 DENG2_ASSERT(d->think != 0);
117 return *d->think;
118 }
119
objectNamespace()120 Record &ThinkerData::objectNamespace()
121 {
122 return d->names;
123 }
124
objectNamespace() const125 Record const &ThinkerData::objectNamespace() const
126 {
127 return d->names;
128 }
129
initBindings()130 void ThinkerData::initBindings()
131 {}
132
operator >>(Writer & to) const133 void ThinkerData::operator >> (Writer &to) const
134 {
135 to << world::InternalSerialId(world::THINKER_DATA)
136 << d->id
137 << Record(d->names, Record::IgnoreDoubleUnderscoreMembers);
138 }
139
operator <<(Reader & from)140 void ThinkerData::operator << (Reader &from)
141 {
142 thinkerLookup.remove(d->id, this);
143
144 world::InternalSerialId sid;
145 from >> sid;
146
147 switch (sid)
148 {
149 case world::THINKER_DATA:
150 from >> d->id >> d->names;
151 break;
152
153 default:
154 throw DeserializationError("ThinkerData::operator <<",
155 "Invalid serial identifier " +
156 String::number(sid));
157 }
158
159 // The thinker has a new ID.
160 thinkerLookup.insert(d->id, this);
161 }
162
find(Id const & id)163 ThinkerData *ThinkerData::find(Id const &id)
164 {
165 auto found = thinkerLookup.constFind(id);
166 if (found != thinkerLookup.constEnd())
167 {
168 return found.value();
169 }
170 return nullptr;
171 }
172
173 #ifdef DENG2_DEBUG
174 duint32 ThinkerData::DebugCounter::total = 0;
175 ThinkerData::DebugValidator ensureAllPrivateDataIsReleased;
176 #endif
177