item_attributes.cpp

main 392 lines · 8.7 KB Raw
Alex Alex Commit Map Editor 18/10/2026 23:40
1//////////////////////////////////////////////////////////////////////
2// This file is part of Remere's Map Editor
3//////////////////////////////////////////////////////////////////////
4// Remere's Map Editor is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Remere's Map Editor is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16//////////////////////////////////////////////////////////////////////
17
18#include "main.h"
19
20#include "item_attributes.h"
21#include "filehandle.h"
22
23ItemAttributes::ItemAttributes() :
24 attributes(nullptr) {
25 ////
26}
27
28ItemAttributes::ItemAttributes(const ItemAttributes& o) {
29 if (o.attributes) {
30 attributes = newd ItemAttributeMap(*o.attributes);
31 }
32}
33
34ItemAttributes::~ItemAttributes() {
35 clearAllAttributes();
36}
37
38void ItemAttributes::createAttributes() {
39 if (!attributes) {
40 attributes = newd ItemAttributeMap;
41 }
42}
43
44void ItemAttributes::clearAllAttributes() {
45 if (attributes) {
46 delete attributes;
47 }
48 attributes = nullptr;
49}
50
51ItemAttributeMap ItemAttributes::getAttributes() const {
52 if (attributes) {
53 return *attributes;
54 }
55 return ItemAttributeMap();
56}
57
58void ItemAttributes::setAttribute(const std::string& key, const ItemAttribute& value) {
59 createAttributes();
60 (*attributes)[key] = value;
61}
62
63void ItemAttributes::setAttribute(const std::string& key, const std::string& value) {
64 createAttributes();
65 (*attributes)[key].set(value);
66}
67
68void ItemAttributes::setAttribute(const std::string& key, int32_t value) {
69 createAttributes();
70 (*attributes)[key].set(value);
71}
72
73void ItemAttributes::setAttribute(const std::string& key, double value) {
74 createAttributes();
75 (*attributes)[key].set(value);
76}
77
78void ItemAttributes::setAttribute(const std::string& key, bool value) {
79 createAttributes();
80 (*attributes)[key].set(value);
81}
82
83void ItemAttributes::eraseAttribute(const std::string& key) {
84 if (!attributes) {
85 return;
86 }
87
88 ItemAttributeMap::iterator iter = attributes->find(key);
89
90 if (iter != attributes->end()) {
91 attributes->erase(iter);
92 }
93}
94
95const std::string* ItemAttributes::getStringAttribute(const std::string& key) const {
96 if (!attributes) {
97 return nullptr;
98 }
99
100 ItemAttributeMap::iterator iter = attributes->find(key);
101 if (iter != attributes->end()) {
102 return iter->second.getString();
103 }
104 return nullptr;
105}
106
107const int32_t* ItemAttributes::getIntegerAttribute(const std::string& key) const {
108 if (!attributes) {
109 return nullptr;
110 }
111
112 ItemAttributeMap::iterator iter = attributes->find(key);
113 if (iter != attributes->end()) {
114 return iter->second.getInteger();
115 }
116 return nullptr;
117}
118
119const double* ItemAttributes::getFloatAttribute(const std::string& key) const {
120 if (!attributes) {
121 return nullptr;
122 }
123
124 ItemAttributeMap::iterator iter = attributes->find(key);
125 if (iter != attributes->end()) {
126 return iter->second.getFloat();
127 }
128 return nullptr;
129}
130
131const bool* ItemAttributes::getBooleanAttribute(const std::string& key) const {
132 if (!attributes) {
133 return nullptr;
134 }
135
136 ItemAttributeMap::iterator iter = attributes->find(key);
137 if (iter != attributes->end()) {
138 return iter->second.getBoolean();
139 }
140 return nullptr;
141}
142
143bool ItemAttributes::hasStringAttribute(const std::string& key) const {
144 return getStringAttribute(key) != nullptr;
145}
146
147bool ItemAttributes::hasIntegerAttribute(const std::string& key) const {
148 return getIntegerAttribute(key) != nullptr;
149}
150
151bool ItemAttributes::hasFloatAttribute(const std::string& key) const {
152 return getFloatAttribute(key) != nullptr;
153}
154
155bool ItemAttributes::hasBooleanAttribute(const std::string& key) const {
156 return getBooleanAttribute(key) != nullptr;
157}
158
159// Attribute type
160// Can hold either int, bool or std::string
161// Without using newd to allocate them
162
163ItemAttribute::ItemAttribute() :
164 type(ItemAttribute::NONE) {
165 ////
166}
167
168ItemAttribute::ItemAttribute(const std::string& str) :
169 type(ItemAttribute::STRING) {
170 new (data) std::string(str);
171}
172
173ItemAttribute::ItemAttribute(int32_t i) :
174 type(ItemAttribute::INTEGER) {
175 *reinterpret_cast<int*>(data) = i;
176}
177
178ItemAttribute::ItemAttribute(double f) :
179 type(ItemAttribute::DOUBLE) {
180 *reinterpret_cast<double*>(data) = f;
181}
182
183ItemAttribute::ItemAttribute(bool b) {
184 *reinterpret_cast<bool*>(data) = b;
185}
186
187ItemAttribute::ItemAttribute(const ItemAttribute& o) :
188 type(ItemAttribute::NONE) {
189 *this = o;
190}
191
192ItemAttribute& ItemAttribute::operator=(const ItemAttribute& o) {
193 if (&o == this) {
194 return *this;
195 }
196
197 clear();
198 type = o.type;
199 if (type == STRING) {
200 new (data) std::string(*reinterpret_cast<const std::string*>(&o.data));
201 } else if (type == INTEGER) {
202 *reinterpret_cast<int32_t*>(data) = *reinterpret_cast<const int32_t*>(&o.data);
203 } else if (type == FLOAT) {
204 *reinterpret_cast<float*>(data) = *reinterpret_cast<const float*>(&o.data);
205 } else if (type == DOUBLE) {
206 *reinterpret_cast<double*>(data) = *reinterpret_cast<const double*>(&o.data);
207 } else if (type == BOOLEAN) {
208 *reinterpret_cast<bool*>(data) = *reinterpret_cast<const bool*>(&o.data);
209 } else {
210 type = NONE;
211 }
212
213 return *this;
214}
215
216ItemAttribute::~ItemAttribute() {
217 clear();
218}
219
220void ItemAttribute::clear() {
221 if (type == STRING) {
222 (reinterpret_cast<std::string*>(&data))->~basic_string();
223 type = NONE;
224 }
225}
226
227void ItemAttribute::set(const std::string& str) {
228 clear();
229 type = STRING;
230 new (data) std::string(str);
231}
232
233void ItemAttribute::set(int32_t i) {
234 clear();
235 type = INTEGER;
236 *reinterpret_cast<int32_t*>(&data) = i;
237}
238
239void ItemAttribute::set(double y) {
240 clear();
241 type = DOUBLE;
242 *reinterpret_cast<double*>(&data) = y;
243}
244
245void ItemAttribute::set(bool b) {
246 clear();
247 type = BOOLEAN;
248 *reinterpret_cast<bool*>(&data) = b;
249}
250
251const std::string* ItemAttribute::getString() const {
252 if (type == STRING) {
253 return reinterpret_cast<const std::string*>(&data);
254 }
255 return nullptr;
256}
257
258const int32_t* ItemAttribute::getInteger() const {
259 if (type == INTEGER) {
260 return reinterpret_cast<const int32_t*>(&data);
261 }
262 return nullptr;
263}
264
265const double* ItemAttribute::getFloat() const {
266 if (type == DOUBLE) {
267 return reinterpret_cast<const double*>(&data);
268 }
269 return nullptr;
270}
271
272const bool* ItemAttribute::getBoolean() const {
273 if (type == BOOLEAN) {
274 return reinterpret_cast<const bool*>(&data);
275 }
276 return nullptr;
277}
278
279bool ItemAttributes::unserializeAttributeMap(const IOMap& maphandle, BinaryNode* stream) {
280 uint16_t n;
281 if (stream->getU16(n)) {
282 createAttributes();
283
284 std::string key;
285 ItemAttribute attrib;
286
287 while (n--) {
288 if (!stream->getString(key)) {
289 return false;
290 }
291 if (!attrib.unserialize(maphandle, stream)) {
292 return false;
293 }
294 (*attributes)[key] = attrib;
295 }
296 }
297 return true;
298}
299
300void ItemAttributes::serializeAttributeMap(const IOMap& maphandle, NodeFileWriteHandle& f) const {
301 // Maximum of 65535 attributes per item
302 f.addU16(std::min((size_t)0xFFFF, attributes->size()));
303
304 ItemAttributeMap::const_iterator attribute = attributes->begin();
305 int i = 0;
306 while (attribute != attributes->end() && i <= 0xFFFF) {
307 const std::string& key = attribute->first;
308 if (key.size() > 0xFFFF) {
309 f.addString(key.substr(0, 65535));
310 } else {
311 f.addString(key);
312 }
313
314 attribute->second.serialize(maphandle, f);
315 ++attribute, ++i;
316 }
317}
318
319bool ItemAttribute::unserialize(const IOMap& maphandle, BinaryNode* stream) {
320 // Read type
321 uint8_t rtype;
322 stream->getU8(rtype);
323
324 // Read contents
325 switch (rtype) {
326 case STRING: {
327 std::string str;
328 if (!stream->getLongString(str)) {
329 return false;
330 }
331 set(str);
332 break;
333 }
334 case INTEGER: {
335 uint32_t u32;
336 if (!stream->getU32(u32)) {
337 return false;
338 }
339 set(*reinterpret_cast<int32_t*>(&u32));
340 break;
341 }
342 case FLOAT: {
343 uint32_t u32;
344 if (!stream->getU32(u32)) {
345 return false;
346 }
347 set((double)*reinterpret_cast<float*>(&u32));
348 break;
349 }
350 case DOUBLE: {
351 uint64_t u64;
352 if (!stream->getU64(u64)) {
353 return false;
354 }
355 set(*reinterpret_cast<double*>(&u64));
356 break;
357 }
358 case BOOLEAN: {
359 uint8_t b;
360 if (!stream->getU8(b)) {
361 return false;
362 }
363 set(b != 0);
364 }
365 default:
366 break;
367 }
368 return true;
369}
370
371void ItemAttribute::serialize(const IOMap& maphandle, NodeFileWriteHandle& f) const {
372 // Write type
373 f.addU8((uint8_t)(type));
374
375 // Write contents
376 switch (type) {
377 case STRING:
378 f.addLongString(*getString());
379 break;
380 case INTEGER:
381 f.addU32(*(uint32_t*)getInteger());
382 break;
383 case DOUBLE:
384 f.addU64(*(uint64_t*)getFloat());
385 break;
386 case BOOLEAN:
387 f.addU8(*(uint8_t*)getBoolean());
388 default:
389 break;
390 }
391}
392
Top