Botcraft 1.21.5
Loading...
Searching...
No Matches
Tag.cpp
Go to the documentation of this file.
2
3namespace ProtocolCraft
4{
5 using namespace Internal;
6
7 namespace NBT
8 {
9 enum class TagType : char
10 {
11 TagEnd = 0,
12 TagByte,
14 TagInt,
15 TagLong,
20 TagList,
24 };
25
26 std::string ReadNBTString(ReadIterator& iter, size_t& length);
27 void WriteNBTString(const std::string& s, WriteContainer& container);
28
29 template<typename T>
30 constexpr std::string_view GetTagName()
31 {
32 if constexpr (std::is_same_v<T, TagEnd>)
33 {
34 return "TagEnd";
35 }
36 else if constexpr (std::is_same_v<T, TagByte>)
37 {
38 return "TagByte";
39 }
40 else if constexpr (std::is_same_v<T, TagShort>)
41 {
42 return "TagShort";
43 }
44 else if constexpr (std::is_same_v<T, TagInt>)
45 {
46 return "TagInt";
47 }
48 else if constexpr (std::is_same_v<T, TagLong>)
49 {
50 return "TagLong";
51 }
52 else if constexpr (std::is_same_v<T, TagFloat>)
53 {
54 return "TagFloat";
55 }
56 else if constexpr (std::is_same_v<T, TagDouble>)
57 {
58 return "TagDouble";
59 }
60 else if constexpr (std::is_same_v<T, TagByteArray>)
61 {
62 return "TagByteArray";
63 }
64 else if constexpr (std::is_same_v<T, TagString>)
65 {
66 return "TagString";
67 }
68 else if constexpr (std::is_same_v<T, TagList>)
69 {
70 return "TagList";
71 }
72 else if constexpr (std::is_same_v<T, TagCompound>)
73 {
74 return "TagCompound";
75 }
76 else if constexpr (std::is_same_v<T, TagIntArray>)
77 {
78 return "TagIntArray";
79 }
80 else if constexpr (std::is_same_v<T, TagLongArray>)
81 {
82 return "TagLongArray";
83 }
84
85 return "Unknown tag";
86 }
87
88
89 const std::string& Tag::GetName() const
90 {
91 return name;
92 }
93
94 void Tag::ReadUnnamedImpl(ReadIterator& iter, size_t& length)
95 {
96 const TagType type = static_cast<TagType>(ReadData<char>(iter, length));
97
98 if (type == TagType::TagEnd)
99 {
101 return;
102 }
103
104#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
105 // Name is read but ignored
106 name = ReadNBTString(iter, length);
107#endif
108 name = "";
109
110 switch (type)
111 {
112 case TagType::TagEnd:
113 // Should not happen but for completeness
114 break;
115 case TagType::TagByte:
116 val = ReadData<char>(iter, length);
117 break;
119 val = ReadData<short>(iter, length);
120 break;
121 case TagType::TagInt:
122 val = ReadData<int>(iter, length);
123 break;
124 case TagType::TagLong:
125 val = ReadData<long long int>(iter, length);
126 break;
128 val = ReadData<float>(iter, length);
129 break;
131 val = ReadData<double>(iter, length);
132 break;
134 // Special case, use int as size instead of varint
135 val = ReadData<Vector<char, int>>(iter, length);
136 break;
138 val = ReadNBTString(iter, length);
139 break;
140 case TagType::TagList:
141 val = ReadData<TagList>(iter, length);
142 break;
144 val = ReadData<TagCompound>(iter, length);
145 break;
147 // Special case, use int as size instead of varint
148 val = ReadData<Vector<int, int>>(iter, length);
149 break;
151 // Special case, use int as size instead of varint
152 val = ReadData<Vector<long long int, int>>(iter, length);
153 break;
154 default:
155 break;
156 }
157 }
158
160 {
161 WriteData<char>(static_cast<char>(val.index()), container);
162
163 if (std::holds_alternative<TagEnd>(val))
164 {
165 return;
166 }
167
168#if PROTOCOL_VERSION < 764 /* < 1.20.2 */
169 // Always empty string is written as this is unnamed
170 WriteNBTString("", container);
171#endif
172
173 std::visit([&](auto&& arg)
174 {
175 using T = std::decay_t<decltype(arg)>;
176
177 if constexpr (std::is_same_v<T, TagEnd>)
178 {
179 return;
180 }
181 else if constexpr (std::is_same_v<T, TagByteArray>)
182 {
183 // Special case, use int as size instead of varint
184 WriteData<Vector<char, int>>(arg, container);
185 }
186 else if constexpr (std::is_same_v<T, TagString>)
187 {
188 WriteNBTString(arg, container);
189 }
190 else if constexpr (std::is_same_v<T, RecursiveWrapper<TagList>>)
191 {
192 WriteData<TagList>(arg.get(), container);
193 }
194 else if constexpr (std::is_same_v<T, RecursiveWrapper<TagCompound>>)
195 {
196 WriteData<TagCompound>(arg.get(), container);
197 }
198 else if constexpr (std::is_same_v<T, TagIntArray>)
199 {
200 // Special case, use int as size instead of varint
201 WriteData<Vector<int, int>>(arg, container);
202 }
203 else if constexpr (std::is_same_v<T, TagLongArray>)
204 {
205 // Special case, use int as size instead of varint
206 WriteData<Vector<long long int, int>>(arg, container);
207 }
208 else
209 {
210 WriteData<T>(arg, container);
211 }
212 }, val);
213 }
214
215 void Tag::ReadImpl(ReadIterator& iter, size_t& length)
216 {
217 const TagType type = static_cast<TagType>(ReadData<char>(iter, length));
218
219 if (type == TagType::TagEnd)
220 {
222 return;
223 }
224
225 name = ReadNBTString(iter, length);
226
227 switch (type)
228 {
229 case TagType::TagEnd:
230 // Should not happen but for completeness
231 break;
232 case TagType::TagByte:
233 val = ReadData<char>(iter, length);
234 break;
236 val = ReadData<short>(iter, length);
237 break;
238 case TagType::TagInt:
239 val = ReadData<int>(iter, length);
240 break;
241 case TagType::TagLong:
242 val = ReadData<long long int>(iter, length);
243 break;
245 val = ReadData<float>(iter, length);
246 break;
248 val = ReadData<double>(iter, length);
249 break;
251 // Special case, use int as size instead of varint
252 val = ReadData<Vector<char, int>>(iter, length);
253 break;
255 val = ReadNBTString(iter, length);
256 break;
257 case TagType::TagList:
258 val = ReadData<TagList>(iter, length);
259 break;
261 val = ReadData<TagCompound>(iter, length);
262 break;
264 // Special case, use int as size instead of varint
265 val = ReadData<Vector<int, int>>(iter, length);
266 break;
268 // Special case, use int as size instead of varint
269 val = ReadData<Vector<long long int, int>>(iter, length);
270 break;
271 default:
272 break;
273 }
274 }
275
276 void Tag::WriteImpl(WriteContainer& container) const
277 {
278 WriteData<char>(static_cast<char>(val.index()), container);
279
280 if (std::holds_alternative<TagEnd>(val))
281 {
282 return;
283 }
284
285 WriteNBTString(name, container);
286
287 std::visit([&](auto&& arg)
288 {
289 using T = std::decay_t<decltype(arg)>;
290
291 if constexpr (std::is_same_v<T, TagEnd>)
292 {
293 return;
294 }
295 else if constexpr (std::is_same_v<T, TagByteArray>)
296 {
297 // Special case, use int as size instead of varint
298 WriteData<Vector<char, int>>(arg, container);
299 }
300 else if constexpr (std::is_same_v<T, TagString>)
301 {
302 WriteNBTString(arg, container);
303 }
304 else if constexpr (std::is_same_v<T, RecursiveWrapper<TagList>>)
305 {
306 WriteData<TagList>(arg.get(), container);
307 }
308 else if constexpr (std::is_same_v<T, RecursiveWrapper<TagCompound>>)
309 {
310 WriteData<TagCompound>(arg.get(), container);
311 }
312 else if constexpr (std::is_same_v<T, TagIntArray>)
313 {
314 // Special case, use int as size instead of varint
315 WriteData<Vector<int, int>>(arg, container);
316 }
317 else if constexpr (std::is_same_v<T, TagLongArray>)
318 {
319 // Special case, use int as size instead of varint
320 WriteData<Vector<long long int, int>>(arg, container);
321 }
322 else
323 {
324 WriteData<T>(arg, container);
325 }
326 }, val);
327 }
328
330 {
331 Json::Value output;
332
333 std::visit([&](auto&& arg)
334 {
335 using T = std::decay_t<decltype(arg)>;
336
337 if constexpr (std::is_same_v<T, TagEnd>)
338 {
339 output["type"] = GetTagName<T>();
340 }
341 else if constexpr (std::is_same_v<T, RecursiveWrapper<TagList>>)
342 {
343 output["type"] = GetTagName<TagList>();
344 output["content"] = arg.get();
345 output["name"] = GetName();
346 }
347 else if constexpr (std::is_same_v<T, RecursiveWrapper<TagCompound>>)
348 {
349 output["type"] = GetTagName<TagCompound>();
350 output["content"] = arg.get();
351 output["name"] = GetName();
352 }
353 else
354 {
355 output["type"] = GetTagName<T>();
356 output["content"] = arg;
357 output["name"] = GetName();
358 }
359 }, val);
360
361 return output;
362 }
363
364 const Tag& Tag::operator[](const std::string& s) const
365 {
366 if (!std::holds_alternative<RecursiveWrapper<TagCompound>>(val))
367 {
368 throw std::runtime_error("NBT::Tag is not a TagCompound");
369 }
370
371 return get<TagCompound>().at(s);
372 }
373
374 size_t Tag::size() const
375 {
376 size_t output;
377
378 std::visit([&](auto&& arg)
379 {
380 using T = std::decay_t<decltype(arg)>;
381
382 if constexpr (std::is_same_v<T, RecursiveWrapper<TagList>> ||
383 std::is_same_v<T, RecursiveWrapper<TagCompound>>)
384 {
385 output = arg.get().size();
386 }
387 else if constexpr (
388 std::is_same_v<T, TagByteArray> ||
389 std::is_same_v<T, TagIntArray> ||
390 std::is_same_v<T, TagLongArray>
391 )
392 {
393 output = arg.size();
394 }
395 else
396 {
397 throw std::runtime_error("NBT::Tag is not a container, no size() method implemented");
398 }
399 }, val);
400
401 return output;
402 }
403
404 bool Tag::contains(const std::string& s) const
405 {
406 return is<TagCompound>() && get<TagCompound>().count(s);
407 }
408
409
410 void TagList::ReadImpl(ReadIterator& iter, size_t& length)
411 {
412 const TagType tags_type = static_cast<TagType>(ReadData<char>(iter, length));
413
414 switch (tags_type)
415 {
416 case TagType::TagEnd:
417 {
418 const int vector_size = ReadData<int>(iter, length);
419 vals = std::vector<TagEnd>(vector_size);
420 break;
421 }
422 case TagType::TagByte:
423 // Special case, use int as size instead of varint
424 vals = ReadData<Vector<char, int>>(iter, length);
425 break;
427 // Special case, use int as size instead of varint
428 vals = ReadData<Vector<short, int>>(iter, length);
429 break;
430 case TagType::TagInt:
431 // Special case, use int as size instead of varint
432 vals = ReadData<Vector<int, int>>(iter, length);
433 break;
434 case TagType::TagLong:
435 // Special case, use int as size instead of varint
436 vals = ReadData<Vector<long long int, int>>(iter, length);
437 break;
439 // Special case, use int as size instead of varint
440 vals = ReadData<Vector<float, int>>(iter, length);
441 break;
443 // Special case, use int as size instead of varint
444 vals = ReadData<Vector<double, int>>(iter, length);
445 break;
447 // Special case, use int as size instead of varint
448 vals = ReadData<Vector<Vector<char, int>, int>>(iter, length);
449 break;
451 {
452 std::vector<std::string> values = std::vector<std::string>(ReadData<int>(iter, length));
453 for (size_t i = 0; i < values.size(); ++i)
454 {
455 values[i] = ReadNBTString(iter, length);
456 }
457 vals = values;
458 break;
459 }
460 case TagType::TagList:
461 // Special case, use int as size instead of varint
462 vals = ReadData<Vector<TagList, int>>(iter, length);
463 break;
465 // Special case, use int as size instead of varint
466 vals = ReadData<Vector<TagCompound, int>>(iter, length);
467 break;
469 // Special case, use int as size instead of varint
470 vals = ReadData<Vector<Vector<int, int>, int>>(iter, length);
471 break;
473 // Special case, use int as size instead of varint
474 vals = ReadData<Vector<Vector<long long int, int>, int>>(iter, length);
475 break;
476 default:
477 break;
478 }
479 }
480
481 void TagList::WriteImpl(WriteContainer& container) const
482 {
483 WriteData<char>(static_cast<char>(vals.index()), container);
484
485 std::visit([&](auto&& arg)
486 {
487 using T = std::decay_t<decltype(arg)>;
488
489 if constexpr (std::is_same_v<T, std::vector<TagEnd>>)
490 {
491 WriteData<int>(static_cast<int>(arg.size()), container);
492 }
493 else if constexpr (std::is_same_v<T, std::vector<TagByteArray>>)
494 {
495 // Special case, use int as size instead of varint
496 WriteData<Vector<Vector<char, int>, int>>(arg, container);
497 }
498 else if constexpr (std::is_same_v<T, std::vector<TagString>>)
499 {
500 WriteData<int>(static_cast<int>(arg.size()), container);
501 for (size_t i = 0; i < arg.size(); ++i)
502 {
503 WriteNBTString(arg[i], container);
504 }
505 }
506 else if constexpr (std::is_same_v<T, std::vector<TagIntArray>>)
507 {
508 // Special case, use int as size instead of varint
509 WriteData<Vector<Vector<int, int>, int>>(arg, container);
510 }
511 else if constexpr (std::is_same_v<T, std::vector<TagLongArray>>)
512 {
513 // Special case, use int as size instead of varint
514 WriteData<Vector<Vector<long long int, int>, int>>(arg, container);
515 }
516 else
517 {
518 // Special case, use int as size instead of varint
519 WriteData<Vector<typename T::value_type, int>>(arg, container);
520 }
521 }, vals);
522 }
523
525 {
526 Json::Value output;
527
528 std::visit([&](auto&& arg)
529 {
530 using T = std::decay_t<decltype(arg)>;
531
532 if constexpr (std::is_same_v<T, std::vector<TagEnd>>)
533 {
534 output = Json::Array();
535 for (size_t i = 0; i < arg.size(); ++i)
536 {
537 output.push_back({});
538 }
539 }
540 else
541 {
542 output = arg;
543 }
544 }, vals);
545
546 return output;
547 }
548
549 size_t TagList::size() const
550 {
551 size_t output;
552
553 std::visit([&](auto&& arg)
554 {
555 output = arg.size();
556 }, vals);
557
558 return output;
559 }
560
561
562 const Tag& TagCompound::operator[](const std::string& s) const
563 {
564 return at(s);
565 }
566
567 bool TagCompound::contains(const std::string& s) const
568 {
569 return count(s) > 0;
570 }
571
572 void TagCompound::ReadImpl(ReadIterator& iter, size_t& length)
573 {
574 while (true)
575 {
576 const Tag tag = ReadData<Tag>(iter, length);
577
578 // If it's a TagEnd, stop reading data
579 if (tag.is<TagEnd>())
580 {
581 break;
582 }
583
584 // Else insert it
585 insert({ tag.GetName(), tag });
586 }
587 }
588
590 {
591 // Write each named tag
592 for (const auto& p : *this)
593 {
594 WriteData<Tag>(p.second, container);
595 }
596
597 // Add additional end tag
598 WriteData<char>(static_cast<char>(TagType::TagEnd), container);
599 }
600
602 {
603 // std::map<std::string, Tag> is directly convertible to Json::Value
604 // Tag.name will be duplicated as both keys and part of value though
605 return *static_cast<const std::map<std::string, Tag>*>(this);
606 }
607
608
609 std::string ReadNBTString(ReadIterator& iter, size_t& length)
610 {
611 const unsigned short size = ReadData<unsigned short>(iter, length);
612
613 return ReadRawString(iter, length, size);
614 }
615
616 void WriteNBTString(const std::string& s, WriteContainer& container)
617 {
618 WriteData<unsigned short>(static_cast<unsigned short>(s.size()), container);
619 WriteRawString(s, container);
620 }
621 }
622}
Template magic to have a full type instead of an incomplete one as required for example by std::varia...
Real class declaration, just a derived class of std::vector<Value>
Definition Json.hpp:180
Main class, basically a JsonVariant with extra utility functions it doesn't inherit JsonVariant direc...
Definition Json.hpp:45
void push_back(const Value &value)
Definition Json.cpp:257
virtual Json::Value SerializeImpl() const override
Definition Tag.cpp:601
virtual void WriteImpl(WriteContainer &container) const override
Definition Tag.cpp:589
virtual void ReadImpl(ReadIterator &iter, size_t &length) override
Definition Tag.cpp:572
bool contains(const std::string &s) const
Definition Tag.cpp:567
const Tag & operator[](const std::string &s) const
Definition Tag.cpp:562
virtual Json::Value SerializeImpl() const override
Definition Tag.cpp:524
virtual void WriteImpl(WriteContainer &container) const override
Definition Tag.cpp:481
virtual void ReadImpl(ReadIterator &iter, size_t &length) override
Definition Tag.cpp:410
Internal::TagListVariant vals
Definition Tag.hpp:151
size_t size() const
Definition Tag.cpp:549
std::string name
Definition Tag.hpp:124
bool contains(const std::string &s) const
Definition Tag.cpp:404
size_t size() const
Definition Tag.cpp:374
bool is() const
Definition Tag.hpp:173
void WriteUnnamedImpl(WriteContainer &container) const
Definition Tag.cpp:159
virtual void WriteImpl(WriteContainer &container) const override
Definition Tag.cpp:276
virtual void ReadImpl(ReadIterator &iter, size_t &length) override
Definition Tag.cpp:215
const std::string & GetName() const
Definition Tag.cpp:89
virtual Json::Value SerializeImpl() const override
Definition Tag.cpp:329
void ReadUnnamedImpl(ReadIterator &iter, size_t &length)
Definition Tag.cpp:94
const Tag & operator[](const std::string &s) const
Definition Tag.cpp:364
Internal::TagVariant val
Definition Tag.hpp:123
std::variant< TagEnd, TagByte, TagShort, TagInt, TagLong, TagFloat, TagDouble, TagByteArray, TagString, ProtocolCraft::Internal::RecursiveWrapper< TagList >, ProtocolCraft::Internal::RecursiveWrapper< TagCompound >, TagIntArray, TagLongArray > TagVariant
Definition Tag.hpp:45
constexpr std::string_view GetTagName()
Definition Tag.cpp:30
double TagDouble
Definition Tag.hpp:21
std::string TagString
Definition Tag.hpp:23
std::vector< long long int > TagLongArray
Definition Tag.hpp:27
long long int TagLong
Definition Tag.hpp:19
std::string ReadNBTString(ReadIterator &iter, size_t &length)
Definition Tag.cpp:609
void WriteNBTString(const std::string &s, WriteContainer &container)
Definition Tag.cpp:616
std::vector< int > TagIntArray
Definition Tag.hpp:26
std::monostate TagEnd
Definition Tag.hpp:15
std::vector< char > TagByteArray
Definition Tag.hpp:22
std::string ReadRawString(ReadIterator &iter, size_t &length, const size_t size)
void WriteRawString(const std::string &s, WriteContainer &container)
std::vector< unsigned char > WriteContainer
std::vector< unsigned char >::const_iterator ReadIterator