summary refs log tree commit diff stats
path: root/vendor
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2021-02-02 13:01:35 -0500
committerKelly Rauchenberger <fefferburbia@gmail.com>2021-02-02 13:01:35 -0500
commit7166c9b831f9c6a50ba42272682b776d01e5703e (patch)
treeb27c4b695a8cd5f64c680e358bb919e86ef7cd74 /vendor
parent362c332000a65acc060660dcb6bb0ec6f99cbafe (diff)
downloadtanetane-7166c9b831f9c6a50ba42272682b776d01e5703e.tar.gz
tanetane-7166c9b831f9c6a50ba42272682b776d01e5703e.tar.bz2
tanetane-7166c9b831f9c6a50ba42272682b776d01e5703e.zip
Map rendering Works but I don't want to use Tileson so I'm gonna change that
Mainly bc Tileson requires std::filesystem, which my clang is too old for apparently, and while I can use gcc instead I just want to not, I suppose. Also Tileson's API is very weird RE const correctness? Idk. And also being able to parse the tmx files rather than exporting to json would be preferable.
Diffstat (limited to 'vendor')
-rw-r--r--vendor/tileson.hpp7391
1 files changed, 7391 insertions, 0 deletions
diff --git a/vendor/tileson.hpp b/vendor/tileson.hpp new file mode 100644 index 0000000..f8545ed --- /dev/null +++ b/vendor/tileson.hpp
@@ -0,0 +1,7391 @@
1///
2/// T I L E S O N V E R S I O N 1 . 3 . 0
3/// ------------------------------------------------
4/// BSD 2-Clause License
5///
6/// Copyright (c) 2020, Robin Berg Pettersen
7/// All rights reserved.
8///
9/// Redistribution and use in source and binary forms, with or without
10/// modification, are permitted provided that the following conditions are met:
11///
12/// 1. Redistributions of source code must retain the above copyright notice, this
13/// list of conditions and the following disclaimer.
14///
15/// 2. Redistributions in binary form must reproduce the above copyright notice,
16/// this list of conditions and the following disclaimer in the documentation
17/// and/or other materials provided with the distribution.
18///
19/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20/// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21/// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22/// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23/// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24/// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25/// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26/// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27/// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28/// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#ifndef TILESON_TILESON_H
31#define TILESON_TILESON_H
32
33
34/*** Start of inlined file: json11.hpp ***/
35/*** Start of inlined file: json11.cpp ***/
36
37/*** Start of inlined file: json11.hpp ***/
38/* Copyright (c) 2013 Dropbox, Inc.
39 *
40 * Permission is hereby granted, free of charge, to any person obtaining a copy
41 * of this software and associated documentation files (the "Software"), to deal
42 * in the Software without restriction, including without limitation the rights
43 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
44 * copies of the Software, and to permit persons to whom the Software is
45 * furnished to do so, subject to the following conditions:
46 *
47 * The above copyright notice and this permission notice shall be included in
48 * all copies or substantial portions of the Software.
49 *
50 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
52 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
53 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
54 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
55 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
56 * THE SOFTWARE.
57 */
58
59#pragma once
60
61#include <string>
62#include <vector>
63#include <map>
64#include <memory>
65#include <initializer_list>
66
67#define JSON11_IS_DEFINED
68
69#ifdef _MSC_VER
70#if _MSC_VER <= 1800 // VS 2013
71 #ifndef noexcept
72 #define noexcept throw()
73 #endif
74
75 #ifndef snprintf
76 #define snprintf _snprintf_s
77 #endif
78 #endif
79#endif
80
81namespace json11 {
82
83 enum JsonParse {
84 STANDARD, COMMENTS
85 };
86
87 class JsonValue;
88
89 class Json final {
90 public:
91 // Types
92 enum Type {
93 NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT
94 };
95
96 // Array and object typedefs
97 typedef std::vector<Json> array;
98 typedef std::map<std::string, Json> object;
99
100 // Constructors for the various types of JSON value.
101 inline Json() noexcept; // NUL
102 inline Json(std::nullptr_t) noexcept; // NUL
103 inline Json(double value); // NUMBER
104 inline Json(int value); // NUMBER
105 inline Json(bool value); // BOOL
106 inline Json(const std::string &value); // STRING
107 inline Json(std::string &&value); // STRING
108 inline Json(const char * value); // STRING
109 inline Json(const array &values); // ARRAY
110 inline Json(array &&values); // ARRAY
111 inline Json(const object &values); // OBJECT
112 inline Json(object &&values); // OBJECT
113
114 // Implicit constructor: anything with a to_json() function.
115 template <class T, class = decltype(&T::to_json)>
116 inline Json(const T & t) : Json(t.to_json()) {}
117
118 // Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
119 template <class M, typename std::enable_if<
120 std::is_constructible<std::string, decltype(std::declval<M>().begin()->first)>::value
121 && std::is_constructible<Json, decltype(std::declval<M>().begin()->second)>::value,
122 int>::type = 0>
123 inline Json(const M & m) : Json(object(m.begin(), m.end())) {}
124
125 // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
126 template <class V, typename std::enable_if<
127 std::is_constructible<Json, decltype(*std::declval<V>().begin())>::value,
128 int>::type = 0>
129 inline Json(const V & v) : Json(array(v.begin(), v.end())) {}
130
131 // This prevents Json(some_pointer) from accidentally producing a bool. Use
132 // Json(bool(some_pointer)) if that behavior is desired.
133 Json(void *) = delete;
134
135 // Accessors
136 inline Type type() const;
137
138 inline bool is_null() const { return type() == NUL; }
139 inline bool is_number() const { return type() == NUMBER; }
140 inline bool is_bool() const { return type() == BOOL; }
141 inline bool is_string() const { return type() == STRING; }
142 inline bool is_array() const { return type() == ARRAY; }
143 inline bool is_object() const { return type() == OBJECT; }
144
145 // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not
146 // distinguish between integer and non-integer numbers - number_value() and int_value()
147 // can both be applied to a NUMBER-typed object.
148 inline double number_value() const;
149 inline int int_value() const;
150
151 // Return the enclosed value if this is a boolean, false otherwise.
152 inline bool bool_value() const;
153 // Return the enclosed string if this is a string, "" otherwise.
154 inline const std::string &string_value() const;
155 // Return the enclosed std::vector if this is an array, or an empty vector otherwise.
156 inline const array &array_items() const;
157 // Return the enclosed std::map if this is an object, or an empty map otherwise.
158 inline const object &object_items() const;
159
160 // Return a reference to arr[i] if this is an array, Json() otherwise.
161 inline const Json & operator[](size_t i) const;
162 // Return a reference to obj[key] if this is an object, Json() otherwise.
163 inline const Json & operator[](const std::string &key) const;
164
165 // Serialize.
166 inline void dump(std::string &out) const;
167 inline std::string dump() const {
168 std::string out;
169 dump(out);
170 return out;
171 }
172
173 // Parse. If parse fails, return Json() and assign an error message to err.
174 static inline Json parse(const std::string & in,
175 std::string & err,
176 JsonParse strategy = JsonParse::STANDARD);
177 static inline Json parse(const char * in,
178 std::string & err,
179 JsonParse strategy = JsonParse::STANDARD) {
180 if (in) {
181 return parse(std::string(in), err, strategy);
182 } else {
183 err = "null input";
184 return nullptr;
185 }
186 }
187 // Parse multiple objects, concatenated or separated by whitespace
188 static inline std::vector<Json> parse_multi(
189 const std::string & in,
190 std::string::size_type & parser_stop_pos,
191 std::string & err,
192 JsonParse strategy = JsonParse::STANDARD);
193
194 static inline std::vector<Json> parse_multi(
195 const std::string & in,
196 std::string & err,
197 JsonParse strategy = JsonParse::STANDARD) {
198 std::string::size_type parser_stop_pos;
199 return parse_multi(in, parser_stop_pos, err, strategy);
200 }
201
202 inline bool operator== (const Json &rhs) const;
203 inline bool operator< (const Json &rhs) const;
204 inline bool operator!= (const Json &rhs) const { return !(*this == rhs); }
205 inline bool operator<= (const Json &rhs) const { return !(rhs < *this); }
206 inline bool operator> (const Json &rhs) const { return (rhs < *this); }
207 inline bool operator>= (const Json &rhs) const { return !(*this < rhs); }
208
209 /* has_shape(types, err)
210 *
211 * Return true if this is a JSON object and, for each item in types, has a field of
212 * the given type. If not, return false and set err to a descriptive message.
213 */
214 typedef std::initializer_list<std::pair<std::string, Type>> shape;
215 inline bool has_shape(const shape & types, std::string & err) const;
216
217 private:
218 std::shared_ptr<JsonValue> m_ptr;
219 };
220
221// Internal class hierarchy - JsonValue objects are not exposed to users of this API.
222 class JsonValue {
223 protected:
224 friend class Json;
225 friend class JsonInt;
226 friend class JsonDouble;
227 virtual Json::Type type() const = 0;
228 virtual bool equals(const JsonValue * other) const = 0;
229 virtual bool less(const JsonValue * other) const = 0;
230 virtual void dump(std::string &out) const = 0;
231 virtual double number_value() const;
232 virtual int int_value() const;
233 virtual bool bool_value() const;
234 virtual const std::string &string_value() const;
235 virtual const Json::array &array_items() const;
236 virtual const Json &operator[](size_t i) const;
237 virtual const Json::object &object_items() const;
238 virtual const Json &operator[](const std::string &key) const;
239 virtual ~JsonValue() {}
240 };
241
242} // namespace json11
243
244/*** End of inlined file: json11.hpp ***/
245
246#include <cassert>
247#include <cmath>
248#include <cstdlib>
249#include <cstdio>
250#include <limits>
251
252namespace json11 {
253
254 static const int max_depth = 200;
255
256 using std::string;
257 using std::vector;
258 using std::map;
259 using std::make_shared;
260 using std::initializer_list;
261 using std::move;
262
263/* Helper for representing null - just a do-nothing struct, plus comparison
264 * operators so the helpers in JsonValue work. We can't use nullptr_t because
265 * it may not be orderable.
266 */
267 struct NullStruct {
268 bool operator==(NullStruct) const { return true; }
269 bool operator<(NullStruct) const { return false; }
270 };
271
272/* * * * * * * * * * * * * * * * * * * *
273 * Serialization
274 */
275
276 static void dump(NullStruct, string &out) {
277 out += "null";
278 }
279
280 static void dump(double value, string &out) {
281 if (std::isfinite(value)) {
282 char buf[32];
283 snprintf(buf, sizeof buf, "%.17g", value);
284 out += buf;
285 } else {
286 out += "null";
287 }
288 }
289
290 static void dump(int value, string &out) {
291 char buf[32];
292 snprintf(buf, sizeof buf, "%d", value);
293 out += buf;
294 }
295
296 static void dump(bool value, string &out) {
297 out += value ? "true" : "false";
298 }
299
300 static void dump(const string &value, string &out) {
301 out += '"';
302 for (size_t i = 0; i < value.length(); i++) {
303 const char ch = value[i];
304 if (ch == '\\') {
305 out += "\\\\";
306 } else if (ch == '"') {
307 out += "\\\"";
308 } else if (ch == '\b') {
309 out += "\\b";
310 } else if (ch == '\f') {
311 out += "\\f";
312 } else if (ch == '\n') {
313 out += "\\n";
314 } else if (ch == '\r') {
315 out += "\\r";
316 } else if (ch == '\t') {
317 out += "\\t";
318 } else if (static_cast<uint8_t>(ch) <= 0x1f) {
319 char buf[8];
320 snprintf(buf, sizeof buf, "\\u%04x", ch);
321 out += buf;
322 } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
323 && static_cast<uint8_t>(value[i+2]) == 0xa8) {
324 out += "\\u2028";
325 i += 2;
326 } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
327 && static_cast<uint8_t>(value[i+2]) == 0xa9) {
328 out += "\\u2029";
329 i += 2;
330 } else {
331 out += ch;
332 }
333 }
334 out += '"';
335 }
336
337 static void dump(const Json::array &values, string &out) {
338 bool first = true;
339 out += "[";
340 for (const auto &value : values) {
341 if (!first)
342 out += ", ";
343 value.dump(out);
344 first = false;
345 }
346 out += "]";
347 }
348
349 static void dump(const Json::object &values, string &out) {
350 bool first = true;
351 out += "{";
352 for (const auto &kv : values) {
353 if (!first)
354 out += ", ";
355 dump(kv.first, out);
356 out += ": ";
357 kv.second.dump(out);
358 first = false;
359 }
360 out += "}";
361 }
362
363 void Json::dump(string &out) const {
364 m_ptr->dump(out);
365 }
366
367/* * * * * * * * * * * * * * * * * * * *
368 * Value wrappers
369 */
370
371 template <Json::Type tag, typename T>
372 class Value : public JsonValue {
373 protected:
374
375 // Constructors
376 explicit Value(const T &value) : m_value(value) {}
377 explicit Value(T &&value) : m_value(move(value)) {}
378
379 // Get type tag
380 Json::Type type() const override {
381 return tag;
382 }
383
384 // Comparisons
385 bool equals(const JsonValue * other) const override {
386 return m_value == static_cast<const Value<tag, T> *>(other)->m_value;
387 }
388 bool less(const JsonValue * other) const override {
389 return m_value < static_cast<const Value<tag, T> *>(other)->m_value;
390 }
391
392 const T m_value;
393 void dump(string &out) const override { json11::dump(m_value, out); }
394 };
395
396 class JsonDouble final : public Value<Json::NUMBER, double> {
397 double number_value() const override { return m_value; }
398 int int_value() const override { return static_cast<int>(m_value); }
399 bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
400 bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
401 public:
402 explicit JsonDouble(double value) : Value(value) {}
403 };
404
405 class JsonInt final : public Value<Json::NUMBER, int> {
406 double number_value() const override { return m_value; }
407 int int_value() const override { return m_value; }
408 bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
409 bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
410 public:
411 explicit JsonInt(int value) : Value(value) {}
412 };
413
414 class JsonBoolean final : public Value<Json::BOOL, bool> {
415 bool bool_value() const override { return m_value; }
416 public:
417 explicit JsonBoolean(bool value) : Value(value) {}
418 };
419
420 class JsonString final : public Value<Json::STRING, string> {
421 const string &string_value() const override { return m_value; }
422 public:
423 explicit JsonString(const string &value) : Value(value) {}
424 explicit JsonString(string &&value) : Value(move(value)) {}
425 };
426
427 class JsonArray final : public Value<Json::ARRAY, Json::array> {
428 const Json::array &array_items() const override { return m_value; }
429 const Json & operator[](size_t i) const override;
430 public:
431 explicit JsonArray(const Json::array &value) : Value(value) {}
432 explicit JsonArray(Json::array &&value) : Value(move(value)) {}
433 };
434
435 class JsonObject final : public Value<Json::OBJECT, Json::object> {
436 const Json::object &object_items() const override { return m_value; }
437 const Json & operator[](const string &key) const override;
438 public:
439 explicit JsonObject(const Json::object &value) : Value(value) {}
440 explicit JsonObject(Json::object &&value) : Value(move(value)) {}
441 };
442
443 class JsonNull final : public Value<Json::NUL, NullStruct> {
444 public:
445 JsonNull() : Value({}) {}
446 };
447
448/* * * * * * * * * * * * * * * * * * * *
449 * Static globals - static-init-safe
450 */
451 struct Statics {
452 const std::shared_ptr<JsonValue> null = make_shared<JsonNull>();
453 const std::shared_ptr<JsonValue> t = make_shared<JsonBoolean>(true);
454 const std::shared_ptr<JsonValue> f = make_shared<JsonBoolean>(false);
455 const string empty_string;
456 const vector<Json> empty_vector;
457 const map<string, Json> empty_map;
458 Statics() {}
459 };
460
461 static const Statics & statics() {
462 static const Statics s {};
463 return s;
464 }
465
466 static const Json & static_null() {
467 // This has to be separate, not in Statics, because Json() accesses statics().null.
468 static const Json json_null;
469 return json_null;
470 }
471
472/* * * * * * * * * * * * * * * * * * * *
473 * Constructors
474 */
475
476 Json::Json() noexcept : m_ptr(statics().null) {}
477 Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {}
478 Json::Json(double value) : m_ptr(make_shared<JsonDouble>(value)) {}
479 Json::Json(int value) : m_ptr(make_shared<JsonInt>(value)) {}
480 Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}
481 Json::Json(const string &value) : m_ptr(make_shared<JsonString>(value)) {}
482 Json::Json(string &&value) : m_ptr(make_shared<JsonString>(move(value))) {}
483 Json::Json(const char * value) : m_ptr(make_shared<JsonString>(value)) {}
484 Json::Json(const Json::array &values) : m_ptr(make_shared<JsonArray>(values)) {}
485 Json::Json(Json::array &&values) : m_ptr(make_shared<JsonArray>(move(values))) {}
486 Json::Json(const Json::object &values) : m_ptr(make_shared<JsonObject>(values)) {}
487 Json::Json(Json::object &&values) : m_ptr(make_shared<JsonObject>(move(values))) {}
488
489/* * * * * * * * * * * * * * * * * * * *
490 * Accessors
491 */
492
493 inline Json::Type Json::type() const { return m_ptr->type(); }
494 inline double Json::number_value() const { return m_ptr->number_value(); }
495 inline int Json::int_value() const { return m_ptr->int_value(); }
496 inline bool Json::bool_value() const { return m_ptr->bool_value(); }
497 inline const string & Json::string_value() const { return m_ptr->string_value(); }
498 inline const vector<Json> & Json::array_items() const { return m_ptr->array_items(); }
499 inline const map<string, Json> & Json::object_items() const { return m_ptr->object_items(); }
500 inline const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; }
501 inline const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; }
502
503 inline double JsonValue::number_value() const { return 0; }
504 inline int JsonValue::int_value() const { return 0; }
505 inline bool JsonValue::bool_value() const { return false; }
506 inline const string & JsonValue::string_value() const { return statics().empty_string; }
507 inline const vector<Json> & JsonValue::array_items() const { return statics().empty_vector; }
508 inline const map<string, Json> & JsonValue::object_items() const { return statics().empty_map; }
509 inline const Json & JsonValue::operator[] (size_t) const { return static_null(); }
510 inline const Json & JsonValue::operator[] (const string &) const { return static_null(); }
511
512 inline const Json & JsonObject::operator[] (const string &key) const {
513 auto iter = m_value.find(key);
514 return (iter == m_value.end()) ? static_null() : iter->second;
515 }
516 inline const Json & JsonArray::operator[] (size_t i) const {
517 if (i >= m_value.size()) return static_null();
518 else return m_value[i];
519 }
520
521/* * * * * * * * * * * * * * * * * * * *
522 * Comparison
523 */
524
525 bool Json::operator== (const Json &other) const {
526 if (m_ptr == other.m_ptr)
527 return true;
528 if (m_ptr->type() != other.m_ptr->type())
529 return false;
530
531 return m_ptr->equals(other.m_ptr.get());
532 }
533
534 bool Json::operator< (const Json &other) const {
535 if (m_ptr == other.m_ptr)
536 return false;
537 if (m_ptr->type() != other.m_ptr->type())
538 return m_ptr->type() < other.m_ptr->type();
539
540 return m_ptr->less(other.m_ptr.get());
541 }
542
543/* * * * * * * * * * * * * * * * * * * *
544 * Parsing
545 */
546
547/* esc(c)
548 *
549 * Format char c suitable for printing in an error message.
550 */
551 static inline string esc(char c) {
552 char buf[12];
553 if (static_cast<uint8_t>(c) >= 0x20 && static_cast<uint8_t>(c) <= 0x7f) {
554 snprintf(buf, sizeof buf, "'%c' (%d)", c, c);
555 } else {
556 snprintf(buf, sizeof buf, "(%d)", c);
557 }
558 return string(buf);
559 }
560
561 static inline bool in_range(long x, long lower, long upper) {
562 return (x >= lower && x <= upper);
563 }
564
565 namespace {
566/* JsonParser
567 *
568 * Object that tracks all state of an in-progress parse.
569 */
570 struct JsonParser final {
571
572 /* State
573 */
574 const string &str;
575 size_t i;
576 string &err;
577 bool failed;
578 const JsonParse strategy;
579
580 /* fail(msg, err_ret = Json())
581 *
582 * Mark this parse as failed.
583 */
584 Json fail(string &&msg) {
585 return fail(move(msg), Json());
586 }
587
588 template <typename T>
589 T fail(string &&msg, const T err_ret) {
590 if (!failed)
591 err = std::move(msg);
592 failed = true;
593 return err_ret;
594 }
595
596 /* consume_whitespace()
597 *
598 * Advance until the current character is non-whitespace.
599 */
600 void consume_whitespace() {
601 while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t')
602 i++;
603 }
604
605 /* consume_comment()
606 *
607 * Advance comments (c-style inline and multiline).
608 */
609 bool consume_comment() {
610 bool comment_found = false;
611 if (str[i] == '/') {
612 i++;
613 if (i == str.size())
614 return fail("unexpected end of input after start of comment", false);
615 if (str[i] == '/') { // inline comment
616 i++;
617 // advance until next line, or end of input
618 while (i < str.size() && str[i] != '\n') {
619 i++;
620 }
621 comment_found = true;
622 }
623 else if (str[i] == '*') { // multiline comment
624 i++;
625 if (i > str.size()-2)
626 return fail("unexpected end of input inside multi-line comment", false);
627 // advance until closing tokens
628 while (!(str[i] == '*' && str[i+1] == '/')) {
629 i++;
630 if (i > str.size()-2)
631 return fail(
632 "unexpected end of input inside multi-line comment", false);
633 }
634 i += 2;
635 comment_found = true;
636 }
637 else
638 return fail("malformed comment", false);
639 }
640 return comment_found;
641 }
642
643 /* consume_garbage()
644 *
645 * Advance until the current character is non-whitespace and non-comment.
646 */
647 void consume_garbage() {
648 consume_whitespace();
649 if(strategy == JsonParse::COMMENTS) {
650 bool comment_found = false;
651 do {
652 comment_found = consume_comment();
653 if (failed) return;
654 consume_whitespace();
655 }
656 while(comment_found);
657 }
658 }
659
660 /* get_next_token()
661 *
662 * Return the next non-whitespace character. If the end of the input is reached,
663 * flag an error and return 0.
664 */
665 char get_next_token() {
666 consume_garbage();
667 if (failed) return static_cast<char>(0);
668 if (i == str.size())
669 return fail("unexpected end of input", static_cast<char>(0));
670
671 return str[i++];
672 }
673
674 /* encode_utf8(pt, out)
675 *
676 * Encode pt as UTF-8 and add it to out.
677 */
678 void encode_utf8(long pt, string & out) {
679 if (pt < 0)
680 return;
681
682 if (pt < 0x80) {
683 out += static_cast<char>(pt);
684 } else if (pt < 0x800) {
685 out += static_cast<char>((pt >> 6) | 0xC0);
686 out += static_cast<char>((pt & 0x3F) | 0x80);
687 } else if (pt < 0x10000) {
688 out += static_cast<char>((pt >> 12) | 0xE0);
689 out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
690 out += static_cast<char>((pt & 0x3F) | 0x80);
691 } else {
692 out += static_cast<char>((pt >> 18) | 0xF0);
693 out += static_cast<char>(((pt >> 12) & 0x3F) | 0x80);
694 out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
695 out += static_cast<char>((pt & 0x3F) | 0x80);
696 }
697 }
698
699 /* parse_string()
700 *
701 * Parse a string, starting at the current position.
702 */
703 string parse_string() {
704 string out;
705 long last_escaped_codepoint = -1;
706 while (true) {
707 if (i == str.size())
708 return fail("unexpected end of input in string", "");
709
710 char ch = str[i++];
711
712 if (ch == '"') {
713 encode_utf8(last_escaped_codepoint, out);
714 return out;
715 }
716
717 if (in_range(ch, 0, 0x1f))
718 return fail("unescaped " + esc(ch) + " in string", "");
719
720 // The usual case: non-escaped characters
721 if (ch != '\\') {
722 encode_utf8(last_escaped_codepoint, out);
723 last_escaped_codepoint = -1;
724 out += ch;
725 continue;
726 }
727
728 // Handle escapes
729 if (i == str.size())
730 return fail("unexpected end of input in string", "");
731
732 ch = str[i++];
733
734 if (ch == 'u') {
735 // Extract 4-byte escape sequence
736 string esc = str.substr(i, 4);
737 // Explicitly check length of the substring. The following loop
738 // relies on std::string returning the terminating NUL when
739 // accessing str[length]. Checking here reduces brittleness.
740 if (esc.length() < 4) {
741 return fail("bad \\u escape: " + esc, "");
742 }
743 for (size_t j = 0; j < 4; j++) {
744 if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
745 && !in_range(esc[j], '0', '9'))
746 return fail("bad \\u escape: " + esc, "");
747 }
748
749 long codepoint = strtol(esc.data(), nullptr, 16);
750
751 // JSON specifies that characters outside the BMP shall be encoded as a pair
752 // of 4-hex-digit \u escapes encoding their surrogate pair components. Check
753 // whether we're in the middle of such a beast: the previous codepoint was an
754 // escaped lead (high) surrogate, and this is a trail (low) surrogate.
755 if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF)
756 && in_range(codepoint, 0xDC00, 0xDFFF)) {
757 // Reassemble the two surrogate pairs into one astral-plane character, per
758 // the UTF-16 algorithm.
759 encode_utf8((((last_escaped_codepoint - 0xD800) << 10)
760 | (codepoint - 0xDC00)) + 0x10000, out);
761 last_escaped_codepoint = -1;
762 } else {
763 encode_utf8(last_escaped_codepoint, out);
764 last_escaped_codepoint = codepoint;
765 }
766
767 i += 4;
768 continue;
769 }
770
771 encode_utf8(last_escaped_codepoint, out);
772 last_escaped_codepoint = -1;
773
774 if (ch == 'b') {
775 out += '\b';
776 } else if (ch == 'f') {
777 out += '\f';
778 } else if (ch == 'n') {
779 out += '\n';
780 } else if (ch == 'r') {
781 out += '\r';
782 } else if (ch == 't') {
783 out += '\t';
784 } else if (ch == '"' || ch == '\\' || ch == '/') {
785 out += ch;
786 } else {
787 return fail("invalid escape character " + esc(ch), "");
788 }
789 }
790 }
791
792 /* parse_number()
793 *
794 * Parse a double.
795 */
796 Json parse_number() {
797 size_t start_pos = i;
798
799 if (str[i] == '-')
800 i++;
801
802 // Integer part
803 if (str[i] == '0') {
804 i++;
805 if (in_range(str[i], '0', '9'))
806 return fail("leading 0s not permitted in numbers");
807 } else if (in_range(str[i], '1', '9')) {
808 i++;
809 while (in_range(str[i], '0', '9'))
810 i++;
811 } else {
812 return fail("invalid " + esc(str[i]) + " in number");
813 }
814
815 if (str[i] != '.' && str[i] != 'e' && str[i] != 'E'
816 && (i - start_pos) <= static_cast<size_t>(std::numeric_limits<int>::digits10)) {
817 return std::atoi(str.c_str() + start_pos);
818 }
819
820 // Decimal part
821 if (str[i] == '.') {
822 i++;
823 if (!in_range(str[i], '0', '9'))
824 return fail("at least one digit required in fractional part");
825
826 while (in_range(str[i], '0', '9'))
827 i++;
828 }
829
830 // Exponent part
831 if (str[i] == 'e' || str[i] == 'E') {
832 i++;
833
834 if (str[i] == '+' || str[i] == '-')
835 i++;
836
837 if (!in_range(str[i], '0', '9'))
838 return fail("at least one digit required in exponent");
839
840 while (in_range(str[i], '0', '9'))
841 i++;
842 }
843
844 return std::strtod(str.c_str() + start_pos, nullptr);
845 }
846
847 /* expect(str, res)
848 *
849 * Expect that 'str' starts at the character that was just read. If it does, advance
850 * the input and return res. If not, flag an error.
851 */
852 Json expect(const string &expected, Json res) {
853 assert(i != 0);
854 i--;
855 if (str.compare(i, expected.length(), expected) == 0) {
856 i += expected.length();
857 return res;
858 } else {
859 return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
860 }
861 }
862
863 /* parse_json()
864 *
865 * Parse a JSON object.
866 */
867 Json parse_json(int depth) {
868 if (depth > max_depth) {
869 return fail("exceeded maximum nesting depth");
870 }
871
872 char ch = get_next_token();
873 if (failed)
874 return Json();
875
876 if (ch == '-' || (ch >= '0' && ch <= '9')) {
877 i--;
878 return parse_number();
879 }
880
881 if (ch == 't')
882 return expect("true", true);
883
884 if (ch == 'f')
885 return expect("false", false);
886
887 if (ch == 'n')
888 return expect("null", Json());
889
890 if (ch == '"')
891 return parse_string();
892
893 if (ch == '{') {
894 map<string, Json> data;
895 ch = get_next_token();
896 if (ch == '}')
897 return data;
898
899 while (1) {
900 if (ch != '"')
901 return fail("expected '\"' in object, got " + esc(ch));
902
903 string key = parse_string();
904 if (failed)
905 return Json();
906
907 ch = get_next_token();
908 if (ch != ':')
909 return fail("expected ':' in object, got " + esc(ch));
910
911 data[std::move(key)] = parse_json(depth + 1);
912 if (failed)
913 return Json();
914
915 ch = get_next_token();
916 if (ch == '}')
917 break;
918 if (ch != ',')
919 return fail("expected ',' in object, got " + esc(ch));
920
921 ch = get_next_token();
922 }
923 return data;
924 }
925
926 if (ch == '[') {
927 vector<Json> data;
928 ch = get_next_token();
929 if (ch == ']')
930 return data;
931
932 while (1) {
933 i--;
934 data.push_back(parse_json(depth + 1));
935 if (failed)
936 return Json();
937
938 ch = get_next_token();
939 if (ch == ']')
940 break;
941 if (ch != ',')
942 return fail("expected ',' in list, got " + esc(ch));
943
944 ch = get_next_token();
945 (void)ch;
946 }
947 return data;
948 }
949
950 return fail("expected value, got " + esc(ch));
951 }
952 };
953 }//namespace {
954
955 Json Json::parse(const string &in, string &err, JsonParse strategy) {
956 JsonParser parser { in, 0, err, false, strategy };
957 Json result = parser.parse_json(0);
958
959 // Check for any trailing garbage
960 parser.consume_garbage();
961 if (parser.failed)
962 return Json();
963 if (parser.i != in.size() &&
964 ((parser.i + 1) != in.size() && in[parser.i] != 0)) //RBP: If there is only 1 character diff, it is probably just a terminating zero from a memory read.
965 {
966 return parser.fail("unexpected trailing " + esc(in[parser.i]));
967 }
968 return result;
969 }
970
971// Documented in json11.hpp
972 vector<Json> Json::parse_multi(const string &in,
973 std::string::size_type &parser_stop_pos,
974 string &err,
975 JsonParse strategy) {
976 JsonParser parser { in, 0, err, false, strategy };
977 parser_stop_pos = 0;
978 vector<Json> json_vec;
979 while (parser.i != in.size() && !parser.failed) {
980 json_vec.push_back(parser.parse_json(0));
981 if (parser.failed)
982 break;
983
984 // Check for another object
985 parser.consume_garbage();
986 if (parser.failed)
987 break;
988 parser_stop_pos = parser.i;
989 }
990 return json_vec;
991 }
992
993/* * * * * * * * * * * * * * * * * * * *
994 * Shape-checking
995 */
996
997 bool Json::has_shape(const shape & types, string & err) const {
998 if (!is_object()) {
999 err = "expected JSON object, got " + dump();
1000 return false;
1001 }
1002
1003 const auto& obj_items = object_items();
1004 for (auto & item : types) {
1005 const auto it = obj_items.find(item.first);
1006 if (it == obj_items.cend() || it->second.type() != item.second) {
1007 err = "bad type for " + item.first + " in " + dump();
1008 return false;
1009 }
1010 }
1011
1012 return true;
1013 }
1014
1015} // namespace json11
1016
1017/*** End of inlined file: json11.cpp ***/
1018
1019/*** End of inlined file: json11.hpp ***/
1020
1021
1022/*** Start of inlined file: tileson_parser.hpp ***/
1023//
1024// Created by robin on 22.03.2020.
1025//
1026
1027#ifndef TILESON_TILESON_PARSER_HPP
1028#define TILESON_TILESON_PARSER_HPP
1029
1030//RBP: FS-namespace is defined in tileson_parser now!
1031#if _MSC_VER && !__INTEL_COMPILER
1032 #include <filesystem>
1033 namespace fs = std::filesystem;
1034#elif __MINGW64__
1035 #if __MINGW64_VERSION_MAJOR > 6
1036 #include <filesystem>
1037 namespace fs = std::filesystem;
1038 #else
1039 #include <experimental/filesystem>
1040 namespace fs = std::experimental::filesystem;
1041 #endif
1042#elif __clang__
1043 #if __clang_major__ < 8
1044 #include <experimental/filesystem>
1045 namespace fs = std::experimental::filesystem;
1046 #else
1047 #include <filesystem>
1048 namespace fs = std::filesystem;
1049 #endif
1050#else //Linux
1051 #if __GNUC__ < 8 //GCC major version less than 8
1052 #include <experimental/filesystem>
1053 namespace fs = std::experimental::filesystem;
1054 #else
1055 #include <filesystem>
1056 namespace fs = std::filesystem;
1057 #endif
1058#endif
1059
1060#include <fstream>
1061#include <sstream>
1062#include <memory>
1063
1064
1065/*** Start of inlined file: Tools.hpp ***/
1066//
1067// Created by robin on 31.07.2020.
1068//
1069
1070#ifndef TILESON_TOOLS_HPP
1071#define TILESON_TOOLS_HPP
1072
1073#include <cstdint>
1074#include <vector>
1075#include <string_view>
1076namespace tson
1077{
1078 class Tools
1079 {
1080
1081 public:
1082 Tools() = delete;
1083 ~Tools() = delete;
1084 inline static std::vector<uint8_t> Base64DecodedStringToBytes(std::string_view str);
1085 inline static std::vector<uint32_t> BytesToUnsignedInts(const std::vector<uint8_t> &bytes);
1086 //inline static std::vector<int> BytesToInts(const std::vector<uint8_t> &bytes);
1087 };
1088
1089 /*!
1090 * When you have decoded a Base64 string, you'll get a string representing bytes. This function turns them into actual bytes.
1091 * @param str
1092 * @return
1093 */
1094 std::vector<uint8_t> Tools::Base64DecodedStringToBytes(std::string_view str)
1095 {
1096 std::vector<uint8_t> bytes;
1097 for(size_t i = 0; i < str.size(); ++i)
1098 {
1099 uint8_t u8 = static_cast<uint8_t>(str[i]);
1100 bytes.push_back(u8);
1101 }
1102 return bytes;
1103 }
1104
1105 /*!
1106 * Converts bytes into unsigned int values. The bytes are converted in the Little Endian byte order to fit Tiled's specs.
1107 * @param bytes A vector of bytes.
1108 * @return Bytes converted to unsigned ints
1109 */
1110 std::vector<uint32_t> Tools::BytesToUnsignedInts(const std::vector<uint8_t> &bytes)
1111 {
1112 std::vector<uint32_t> uints;
1113 std::vector<uint8_t> toConvert;
1114 //uint32_t size8 = (compressed[55] << 24) | (compressed[56] << 16) | (compressed[57] << 8) | compressed[58]; //Should be 66000
1115
1116 for(size_t i = 0; i < bytes.size(); ++i)
1117 {
1118 toConvert.push_back(bytes[i]);
1119 if(toConvert.size() == 4)
1120 {
1121 uint32_t u32 = (toConvert[3] << 24) | (toConvert[2] << 16) | (toConvert[1] << 8) | toConvert[0];
1122 uints.push_back(u32);
1123 toConvert.clear();
1124 }
1125 }
1126
1127 return uints;
1128 }
1129
1130 /*!
1131 * While the Tiled specification uses unsigned ints for their tiles, Tileson uses regular ints.
1132 * This may be changed in the future, but should in reality never really become an issue.
1133 *
1134 * Update 2020-11-09: This will cause problems when tiles has flip flags!
1135 *
1136 * int differences:
1137 * int max: 2147483647
1138 * uint max: 4294967295
1139 *
1140 * @param bytes A vector of bytes.
1141 * @return Bytes converted to ints
1142 */
1143 /*std::vector<int> Tools::BytesToInts(const std::vector<uint8_t> &bytes)
1144 {
1145 std::vector<int> ints;
1146 std::vector<uint8_t> toConvert;
1147 //uint32_t size8 = (compressed[55] << 24) | (compressed[56] << 16) | (compressed[57] << 8) | compressed[58]; //Should be 66000
1148
1149 for(size_t i = 0; i < bytes.size(); ++i)
1150 {
1151 toConvert.push_back(bytes[i]);
1152 if(toConvert.size() == 4)
1153 {
1154 uint32_t u32 = (toConvert[3] << 24) | (toConvert[2] << 16) | (toConvert[1] << 8) | toConvert[0];
1155 ints.push_back(u32);
1156 toConvert.clear();
1157 }
1158 }
1159
1160 return ints;
1161 }*/
1162}
1163
1164#endif //TILESON_TOOLS_HPP
1165
1166/*** End of inlined file: Tools.hpp ***/
1167
1168
1169/*** Start of inlined file: Base64Decompressor.hpp ***/
1170//
1171// Created by robin on 29.07.2020.
1172// The Base64 decoding logic is heavily based on: https://github.com/ReneNyffenegger/cpp-base64
1173//
1174
1175#ifndef TILESON_BASE64DECOMPRESSOR_HPP
1176#define TILESON_BASE64DECOMPRESSOR_HPP
1177
1178
1179/*** Start of inlined file: IDecompressor.hpp ***/
1180//
1181// Created by robin on 29.07.2020.
1182//
1183
1184#ifndef TILESON_IDECOMPRESSOR_HPP
1185#define TILESON_IDECOMPRESSOR_HPP
1186
1187#include <string_view>
1188
1189namespace tson
1190{
1191 template <class TIn, class TOut>
1192 class IDecompressor
1193 {
1194 public:
1195 /*!
1196 * If the name matches with 'compression' or 'encoding' the decompress() function will
1197 * be called automatically for the actual Layer. Encoding-related matching is handled first!
1198 *
1199 * Known values:
1200 *
1201 * compression: zlib, gzip, zstd (since Tiled 1.3) or empty (default) (tilelayer only).
1202 * encoding: csv (default) or base64 (tilelayer only).
1203 *
1204 * @return
1205 */
1206 [[nodiscard]] virtual const std::string &name() const = 0;
1207
1208 /*!
1209 * Used primarily for Tiled related decompression.
1210 * @param input Input data
1211 * @return Decompressed data
1212 */
1213 virtual TOut decompress(const TIn &input) = 0;
1214
1215 /*!
1216 * Used for whole file decompression. Not related to Tiled
1217 * @param path
1218 * @return
1219 */
1220 virtual TOut decompressFile(const fs::path &path) = 0;
1221
1222 /*!
1223 * Used for whole file decompression. Not related to Tiled
1224 * @param path
1225 * @return
1226 */
1227 virtual TOut decompress(const void *data, size_t size) = 0;
1228 };
1229}
1230
1231#endif //TILESON_IDECOMPRESSOR_HPP
1232
1233/*** End of inlined file: IDecompressor.hpp ***/
1234
1235#include <string>
1236
1237namespace tson
1238{
1239 class Base64Decompressor : public IDecompressor<std::string_view, std::string>
1240 {
1241 public:
1242 [[nodiscard]] inline const std::string &name() const override;
1243
1244 inline std::string decompress(const std::string_view &s) override;
1245
1246 inline std::string decompressFile(const fs::path &path) override;
1247 inline std::string decompress(const void *data, size_t size) override;
1248
1249 private:
1250 inline unsigned int pos_of_char(const unsigned char chr);
1251 inline static const std::string NAME = "base64";
1252 };
1253
1254 const std::string &Base64Decompressor::name() const
1255 {
1256 return NAME;
1257 }
1258
1259 std::string Base64Decompressor::decompress(const std::string_view &s)
1260 {
1261
1262 size_t length_of_string = s.length();
1263 if (!length_of_string) return std::string("");
1264
1265 size_t in_len = length_of_string;
1266 size_t pos = 0;
1267
1268 //
1269 // The approximate length (bytes) of the decoded string might be one ore
1270 // two bytes smaller, depending on the amount of trailing equal signs
1271 // in the encoded string. This approximation is needed to reserve
1272 // enough space in the string to be returned.
1273 //
1274 size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
1275 std::string ret;
1276 ret.reserve(approx_length_of_decoded_string);
1277
1278 while (pos < in_len) {
1279
1280 unsigned int pos_of_char_1 = pos_of_char(s[pos+1] );
1281
1282 ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char(s[pos+0]) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4)));
1283
1284 if (s[pos+2] != '=' && s[pos+2] != '.') { // accept URL-safe base 64 strings, too, so check for '.' also.
1285
1286 unsigned int pos_of_char_2 = pos_of_char(s[pos+2] );
1287 ret.push_back(static_cast<std::string::value_type>( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2)));
1288
1289 if (s[pos+3] != '=' && s[pos+3] != '.') {
1290 ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(s[pos+3]) ));
1291 }
1292 }
1293
1294 pos += 4;
1295 }
1296
1297 return ret;
1298 }
1299
1300 unsigned int Base64Decompressor::pos_of_char(const unsigned char chr)
1301 {
1302 //
1303 // Return the position of chr within base64_encode()
1304 //
1305
1306 if (chr >= 'A' && chr <= 'Z') return chr - 'A';
1307 else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1;
1308 else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2;
1309 else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters (
1310 else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_'
1311
1312 throw "If input is correct, this line should never be reached.";
1313 }
1314
1315 /*!
1316 * UNUSED! Does nothing
1317 * @param path
1318 * @return
1319 */
1320 std::string Base64Decompressor::decompressFile(const fs::path &path)
1321 {
1322 return std::string();
1323 }
1324
1325 /*!
1326 * UNUSED! Does nothing
1327 * @param path
1328 * @return
1329 */
1330 std::string Base64Decompressor::decompress(const void *data, size_t size)
1331 {
1332 return std::string();
1333 }
1334}
1335
1336#endif //TILESON_BASE64DECOMPRESSOR_HPP
1337
1338/*** End of inlined file: Base64Decompressor.hpp ***/
1339
1340
1341/*** Start of inlined file: Lzma.hpp ***/
1342//
1343// Created by robin on 16.01.2021.
1344//
1345//#include "../../extras/pocketlzma.hpp"
1346#ifdef POCKETLZMA_POCKETLZMA_H
1347
1348#ifndef TILESON_LZMA_HPP
1349#define TILESON_LZMA_HPP
1350
1351namespace tson
1352{
1353 class Lzma : public IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>
1354 {
1355 public:
1356 inline const std::string &name() const override
1357 {
1358 return NAME;
1359 }
1360
1361 inline std::vector<uint8_t> decompress(const std::vector<uint8_t> &input) override
1362 {
1363 std::vector<uint8_t> out;
1364
1365 plz::PocketLzma p;
1366 plz::StatusCode status = p.decompress(input, out);
1367
1368 if(status != plz::StatusCode::Ok)
1369 return std::vector<uint8_t>();
1370
1371 return out;
1372 }
1373
1374 inline std::vector<uint8_t> decompressFile(const fs::path &path) override
1375 {
1376 std::vector<uint8_t> in;
1377 std::vector<uint8_t> out;
1378
1379 plz::PocketLzma p;
1380 plz::FileStatus fileStatus = plz::File::FromFile(path.u8string(), in);
1381 if(fileStatus.status() != plz::FileStatus::Code::Ok)
1382 return std::vector<uint8_t>();
1383
1384 plz::StatusCode status = p.decompress(in, out);
1385
1386 if(status != plz::StatusCode::Ok)
1387 return std::vector<uint8_t>();
1388
1389 return out;
1390 }
1391
1392 inline std::vector<uint8_t> decompress(const void *data, size_t size) override
1393 {
1394 std::vector<uint8_t> out;
1395
1396 plz::PocketLzma p;
1397 plz::StatusCode status = p.decompress((uint8_t*) data, size, out);
1398
1399 if(status != plz::StatusCode::Ok)
1400 return std::vector<uint8_t>();
1401
1402 return out;
1403 }
1404
1405 private:
1406 inline static const std::string NAME {"lzma"};
1407 };
1408}
1409
1410#endif //TILESON_LZMA_HPP
1411
1412#endif
1413/*** End of inlined file: Lzma.hpp ***/
1414
1415
1416/*** Start of inlined file: DecompressorContainer.hpp ***/
1417//
1418// Created by robin on 30.07.2020.
1419//
1420
1421#ifndef TILESON_DECOMPRESSORCONTAINER_HPP
1422#define TILESON_DECOMPRESSORCONTAINER_HPP
1423
1424#include <memory>
1425#include <vector>
1426#include <string_view>
1427#include <functional>
1428namespace tson
1429{
1430 class DecompressorContainer
1431 {
1432 public:
1433 inline DecompressorContainer() = default;
1434 template <typename T, typename... Args>
1435 inline void add(Args &&... args);
1436 inline void remove(std::string_view name);
1437 inline bool contains(std::string_view name) const;
1438 inline bool empty() const;
1439 inline size_t size() const;
1440 inline void clear();
1441
1442 inline IDecompressor<std::string_view, std::string> *get(std::string_view name);
1443 private:
1444 //Key: name,
1445 std::vector<std::unique_ptr<IDecompressor<std::string_view, std::string>>> m_decompressors;
1446 };
1447
1448 template<typename T, typename... Args>
1449 void DecompressorContainer::add(Args &&... args)
1450 {
1451 m_decompressors.emplace_back(new T(args...));
1452 }
1453
1454 /*!
1455 *
1456 * @param name The name of the decompressor to check whether exists.
1457 * @return Whether a decompressor with the given name exists or not.
1458 */
1459 bool DecompressorContainer::contains(std::string_view name) const
1460 {
1461 auto iter = std::find_if(m_decompressors.begin(), m_decompressors.end(), [&](const auto &item)
1462 {
1463 return item->name() == name;
1464 });
1465
1466 return iter != m_decompressors.end();
1467 }
1468
1469 /*!
1470 * Removed an element with the given name.
1471 * @param name The name of the decompressor
1472 */
1473 void DecompressorContainer::remove(std::string_view name)
1474 {
1475 auto iter = std::remove_if(m_decompressors.begin(), m_decompressors.end(), [&](const auto &item)
1476 {
1477 return item->name() == name;
1478 });
1479 m_decompressors.erase(iter);
1480 }
1481
1482 size_t DecompressorContainer::size() const
1483 {
1484 return m_decompressors.size();
1485 }
1486
1487 /*!
1488 *
1489 * @param name The name of the container
1490 * @return An ICompressor pointer if it exists. nullptr otherwise.
1491 */
1492 IDecompressor<std::string_view, std::string> *DecompressorContainer::get(std::string_view name)
1493 {
1494 auto iter = std::find_if(m_decompressors.begin(), m_decompressors.end(), [&](const auto &item)
1495 {
1496 return item->name() == name;
1497 });
1498
1499 return (iter != m_decompressors.end()) ? iter->get() : nullptr;
1500 }
1501
1502 /*!
1503 * Check if container is empty
1504 * @return Whether or not the container is empty
1505 */
1506 bool DecompressorContainer::empty() const
1507 {
1508 return m_decompressors.empty();
1509 }
1510
1511 /*!
1512 * Clears all IDecompressor elements in the container
1513 */
1514 void DecompressorContainer::clear()
1515 {
1516 m_decompressors.clear();
1517 }
1518}
1519#endif //TILESON_DECOMPRESSORCONTAINER_HPP
1520
1521/*** End of inlined file: DecompressorContainer.hpp ***/
1522
1523
1524/*** Start of inlined file: MemoryStream.hpp ***/
1525//
1526// Created by robin on 22.03.2020.
1527//
1528
1529#ifndef TILESON_MEMORYSTREAM_HPP
1530#define TILESON_MEMORYSTREAM_HPP
1531
1532
1533/*** Start of inlined file: MemoryBuffer.hpp ***/
1534//
1535// Created by robin on 22.03.2020.
1536//
1537
1538#ifndef TILESON_MEMORYBUFFER_HPP
1539#define TILESON_MEMORYBUFFER_HPP
1540
1541#include <iostream>
1542
1543namespace tson
1544{
1545 class MemoryBuffer : public std::basic_streambuf<char> {
1546 public:
1547 MemoryBuffer(const uint8_t *p, size_t l) {
1548 setg((char*)p, (char*)p, (char*)p + l);
1549 }
1550 };
1551}
1552
1553#endif //TILESON_MEMORYBUFFER_HPP
1554
1555/*** End of inlined file: MemoryBuffer.hpp ***/
1556
1557namespace tson
1558{
1559 class MemoryStream : public std::istream {
1560 public:
1561 MemoryStream(const uint8_t *p, size_t l) :
1562 std::istream(&m_buffer),
1563 m_buffer(p, l) {
1564 rdbuf(&m_buffer);
1565 }
1566
1567 private:
1568 MemoryBuffer m_buffer;
1569 };
1570}
1571
1572#endif //TILESON_MEMORYSTREAM_HPP
1573
1574/*** End of inlined file: MemoryStream.hpp ***/
1575
1576
1577/*** Start of inlined file: Map.hpp ***/
1578//
1579// Created by robin on 22.03.2020.
1580//
1581
1582#ifndef TILESON_MAP_HPP
1583#define TILESON_MAP_HPP
1584
1585
1586/*** Start of inlined file: Color.hpp ***/
1587//
1588// Created by robin on 09.08.2019.
1589//
1590
1591#ifndef TILESON_COLOR_HPP
1592#define TILESON_COLOR_HPP
1593
1594#include <type_traits>
1595#include <cstdint>
1596#include <string>
1597
1598namespace tson
1599{
1600
1601 template<typename T>
1602 class Color
1603 {
1604
1605 public:
1606 /*!
1607 * Parses color from Tiled's own color format, which is #aarrggbb in hex format or optionally #rrggbb.
1608 * @param color Color in "#rrggbbaa" hex format.
1609 * @example "#ffaa07ff" and "#aa07ff". In cases where alpha is not a value, it is set to 255.
1610 */
1611 inline explicit Color(const std::string &color)
1612 {
1613 parseHexString(color);
1614 }
1615 inline Color(T red, T green, T blue, T alpha);
1616 inline Color() { r = g = b = 0; a = 255; }
1617
1618 inline bool operator==(const Color &rhs) const;
1619 inline bool operator==(const std::string &rhs) const;
1620 inline bool operator!=(const Color &rhs) const;
1621
1622 inline Color<float> asFloat();
1623 inline Color<uint8_t> asInt();
1624
1625 /*! Red */
1626 T r;
1627 /*! Green */
1628 T g;
1629 /*! Blue */
1630 T b;
1631 /*! Alpha */
1632 T a;
1633
1634 private:
1635 void parseHexString(const std::string &color)
1636 {
1637 if constexpr (std::is_same<T, float>::value)
1638 {
1639 if (color.size() == 9)
1640 {
1641 a = (float) std::stoi(color.substr(1, 2), nullptr, 16) / 255;
1642 r = (float) std::stoi(color.substr(3, 2), nullptr, 16) / 255;
1643 g = (float) std::stoi(color.substr(5, 2), nullptr, 16) / 255;
1644 b = (float) std::stoi(color.substr(7, 2), nullptr, 16) / 255;
1645 }
1646 else if (color.size() == 7)
1647 {
1648 r = (float) std::stoi(color.substr(1, 2), nullptr, 16) / 255;
1649 g = (float) std::stoi(color.substr(3, 2), nullptr, 16) / 255;
1650 b = (float) std::stoi(color.substr(5, 2), nullptr, 16) / 255;
1651 a = 1.f;
1652 }
1653 }
1654 else
1655 {
1656 if (color.size() == 9)
1657 {
1658 a = std::stoi(color.substr(1, 2), nullptr, 16);
1659 r = std::stoi(color.substr(3, 2), nullptr, 16);
1660 g = std::stoi(color.substr(5, 2), nullptr, 16);
1661 b = std::stoi(color.substr(7, 2), nullptr, 16);
1662 }
1663 else if (color.size() == 7)
1664 {
1665 r = std::stoi(color.substr(1, 2), nullptr, 16);
1666 g = std::stoi(color.substr(3, 2), nullptr, 16);
1667 b = std::stoi(color.substr(5, 2), nullptr, 16);
1668 a = 255;
1669 }
1670 }
1671 }
1672
1673 };
1674
1675 typedef Color<uint8_t> Colori;
1676 typedef Color<float> Colorf;
1677
1678 /*!
1679 * Gets the Color as a float. Only useful if the template related to the current color is NOT float
1680 * @tparam T The template type
1681 * @return If the T type is float, the value will be returned as a copy of itself. Else: All values will be divided by 255
1682 * before returning.
1683 */
1684 template<typename T>
1685 tson::Colorf Color<T>::asFloat()
1686 {
1687 if constexpr (std::is_same<T, float>::value)
1688 *this;
1689 else
1690 return tson::Colorf((float) r / 255, (float) g / 255, (float) b / 255, (float) a / 255);
1691 }
1692
1693 /*!
1694 * Gets the Color as an 32-bit variable, where each channel is 8-bit.
1695 * Only useful if the template related to the current color is NOT already 8-bit int
1696 * @tparam T The template type
1697 * @return If the T type is float, the value of each channel will be multiplied by 255. Else: The value will be returned as a copy of itself.
1698 */
1699 template<typename T>
1700 tson::Colori Color<T>::asInt()
1701 {
1702 if constexpr (std::is_same<T, float>::value)
1703 return tson::Colori((float) r * 255, (float) g * 255, (float) b * 255, (float) a * 255);
1704 else
1705 *this;
1706 }
1707
1708 /*!
1709 * Create a new color in rgba (red, green, blue, alpha) format
1710 * @tparam T the template type for each channel. Usually uint8_t (8-bit int) or float.
1711 * @param red Red channel
1712 * @param green Green channel
1713 * @param blue Blue channel
1714 * @param alpha Alpha channel
1715 */
1716 template<typename T>
1717 Color<T>::Color(T red, T green, T blue, T alpha)
1718 {
1719 r = red;
1720 g = green;
1721 b = blue;
1722 a = alpha;
1723 }
1724
1725 template<typename T>
1726 bool Color<T>::operator==(const std::string &rhs) const {
1727 Color other {rhs};
1728 return *this == other;
1729 }
1730
1731 template<typename T>
1732 bool Color<T>::operator==(const Color &rhs) const
1733 {
1734 return r == rhs.r &&
1735 g == rhs.g &&
1736 b == rhs.b &&
1737 a == rhs.a;
1738 }
1739
1740 template<typename T>
1741 bool Color<T>::operator!=(const Color &rhs) const
1742 {
1743 return !(rhs == *this);
1744 }
1745
1746}
1747
1748#endif //TILESON_COLOR_HPP
1749
1750/*** End of inlined file: Color.hpp ***/
1751
1752
1753/*** Start of inlined file: Vector2.hpp ***/
1754//
1755// Created by robin on 31.07.2019.
1756//
1757
1758#ifndef TILESON_VECTOR2_HPP
1759#define TILESON_VECTOR2_HPP
1760
1761namespace tson
1762{
1763 template<typename T>
1764 class Vector2
1765 {
1766
1767 public:
1768 inline Vector2(T xPos, T yPos);
1769 inline Vector2() { x = y = 0; }
1770
1771 inline bool operator==(const Vector2 &rhs) const;
1772 inline bool operator!=(const Vector2 &rhs) const;
1773
1774 T x;
1775 T y;
1776 };
1777
1778 /*!
1779 *
1780 * @tparam T template type
1781 * @param xPos x-position
1782 * @param yPos y-position
1783 */
1784 template<typename T>
1785 Vector2<T>::Vector2(T xPos, T yPos)
1786 {
1787 x = xPos;
1788 y = yPos;
1789 }
1790
1791 template<typename T>
1792 bool Vector2<T>::operator==(const Vector2 &rhs) const
1793 {
1794 return x == rhs.x &&
1795 y == rhs.y;
1796 }
1797
1798 template<typename T>
1799 bool Vector2<T>::operator!=(const Vector2 &rhs) const
1800 {
1801 return !(rhs == *this);
1802 }
1803
1804 typedef Vector2<int> Vector2i;
1805 typedef Vector2<float> Vector2f;
1806}
1807
1808#endif //TILESON_VECTOR2_HPP
1809
1810/*** End of inlined file: Vector2.hpp ***/
1811
1812//#include "../external/json.hpp"
1813
1814/*** Start of inlined file: IJson.hpp ***/
1815//
1816// Created by robin on 06.01.2021.
1817//
1818
1819#ifndef TILESON_IJSON_HPP
1820#define TILESON_IJSON_HPP
1821
1822namespace tson
1823{
1824 class IJson
1825 {
1826 public:
1827
1828 virtual IJson& operator[](std::string_view key) = 0;
1829 virtual IJson &at(std::string_view key) = 0;
1830 virtual IJson &at(size_t pos) = 0;
1831 /*!
1832 * If current json object is an array, this will get all elements of it!
1833 * @return An array
1834 */
1835 [[nodiscard]] virtual std::vector<std::unique_ptr<IJson>> array() = 0;
1836 [[nodiscard]] virtual std::vector<std::unique_ptr<IJson>> &array(std::string_view key) = 0;
1837 /*!
1838 * Get the size of an object. This will be equal to the number of
1839 * variables an object contains.
1840 * @return
1841 */
1842 [[nodiscard]] virtual size_t size() const = 0;
1843 [[nodiscard]] virtual bool parse(const fs::path &path) = 0;
1844 [[nodiscard]] virtual bool parse(const void *data, size_t size) = 0;
1845
1846 template <typename T>
1847 [[nodiscard]] T get(std::string_view key);
1848 template <typename T>
1849 [[nodiscard]] T get();
1850 [[nodiscard]] virtual size_t count(std::string_view key) const = 0;
1851 [[nodiscard]] virtual bool any(std::string_view key) const = 0;
1852 [[nodiscard]] virtual bool isArray() const = 0;
1853 [[nodiscard]] virtual bool isObject() const = 0;
1854 [[nodiscard]] virtual bool isNull() const = 0;
1855
1856 protected:
1857 [[nodiscard]] virtual int32_t getInt32(std::string_view key) = 0;
1858 [[nodiscard]] virtual uint32_t getUInt32(std::string_view key) = 0;
1859 [[nodiscard]] virtual int64_t getInt64(std::string_view key) = 0;
1860 [[nodiscard]] virtual uint64_t getUInt64(std::string_view key) = 0;
1861 [[nodiscard]] virtual double getDouble(std::string_view key) = 0;
1862 [[nodiscard]] virtual float getFloat(std::string_view key) = 0;
1863 [[nodiscard]] virtual std::string getString(std::string_view key) = 0;
1864 [[nodiscard]] virtual bool getBool(std::string_view key) = 0;
1865
1866 [[nodiscard]] virtual int32_t getInt32() = 0;
1867 [[nodiscard]] virtual uint32_t getUInt32() = 0;
1868 [[nodiscard]] virtual int64_t getInt64() = 0;
1869 [[nodiscard]] virtual uint64_t getUInt64() = 0;
1870 [[nodiscard]] virtual double getDouble() = 0;
1871 [[nodiscard]] virtual float getFloat() = 0;
1872 [[nodiscard]] virtual std::string getString() = 0;
1873 [[nodiscard]] virtual bool getBool() = 0;
1874 };
1875
1876 template<typename T>
1877 T IJson::get(std::string_view key)
1878 {
1879 if constexpr (std::is_same<T, double>::value)
1880 return getDouble(key);
1881 if constexpr (std::is_same<T, float>::value)
1882 return getFloat(key);
1883 else if constexpr (std::is_same<T, int32_t>::value)
1884 return getInt32(key);
1885 else if constexpr (std::is_same<T, uint32_t>::value)
1886 return getUInt32(key);
1887 else if constexpr (std::is_same<T, int64_t>::value)
1888 return getInt64(key);
1889 else if constexpr (std::is_same<T, uint64_t>::value)
1890 return getUInt64(key);
1891 else if constexpr (std::is_same<T, std::string>::value)
1892 return getString(key);
1893 else if constexpr (std::is_same<T, bool>::value)
1894 return getBool(key);
1895 else
1896 return nullptr;
1897 }
1898
1899 template<typename T>
1900 T IJson::get()
1901 {
1902 if constexpr (std::is_same<T, double>::value)
1903 return getDouble();
1904 if constexpr (std::is_same<T, float>::value)
1905 return getFloat();
1906 else if constexpr (std::is_same<T, int32_t>::value)
1907 return getInt32();
1908 else if constexpr (std::is_same<T, uint32_t>::value)
1909 return getUInt32();
1910 else if constexpr (std::is_same<T, int64_t>::value)
1911 return getInt64();
1912 else if constexpr (std::is_same<T, uint64_t>::value)
1913 return getUInt64();
1914 else if constexpr (std::is_same<T, std::string>::value)
1915 return getString();
1916 else if constexpr (std::is_same<T, bool>::value)
1917 return getBool();
1918 else
1919 return nullptr;
1920 }
1921
1922}
1923
1924#endif //TILESON_IJSON_HPP
1925
1926/*** End of inlined file: IJson.hpp ***/
1927
1928
1929
1930/*** Start of inlined file: NlohmannJson.hpp ***/
1931//
1932// Created by robin on 08.01.2021.
1933//
1934
1935#ifdef INCLUDE_NLOHMANN_JSON_HPP_
1936
1937#ifndef TILESON_NLOHMANNJSON_HPP
1938#define TILESON_NLOHMANNJSON_HPP
1939
1940namespace tson
1941{
1942 class NlohmannJson : public tson::IJson
1943 {
1944 public:
1945 inline NlohmannJson() = default;
1946
1947 IJson &operator[](std::string_view key) override
1948 {
1949 if(m_arrayCache.count(key.data()) == 0)
1950 m_arrayCache[key.data()] = std::make_unique<NlohmannJson>(&m_json->operator[](key.data()));//.front());
1951
1952 return *m_arrayCache[key.data()].get();
1953 }
1954
1955 inline explicit NlohmannJson(nlohmann::json *json) : m_json {json}
1956 {
1957
1958 }
1959
1960 inline IJson& at(std::string_view key) override
1961 {
1962 if(m_arrayCache.count(key.data()) == 0)
1963 m_arrayCache[key.data()] = std::make_unique<NlohmannJson>(&m_json->operator[](key.data()));//.front());
1964
1965 return *m_arrayCache[key.data()].get();
1966 }
1967
1968 inline IJson& at(size_t pos) override
1969 {
1970 if(m_arrayPosCache.count(pos) == 0)
1971 m_arrayPosCache[pos] = std::make_unique<NlohmannJson>(&m_json->at(pos));
1972
1973 return *m_arrayPosCache[pos];
1974 }
1975
1976 std::vector<std::unique_ptr<IJson>> array() override
1977 {
1978 std::vector<std::unique_ptr<IJson>> vec;
1979 for(auto &item : *m_json)
1980 {
1981 nlohmann::json *ptr = &item;
1982 vec.emplace_back(std::make_unique<NlohmannJson>(ptr));
1983 }
1984
1985 return vec;
1986 }
1987
1988 inline std::vector<std::unique_ptr<IJson>> &array(std::string_view key) override
1989 {
1990 if(m_arrayListDataCache.count(key.data()) == 0)
1991 {
1992 if (m_json->count(key.data()) > 0 && m_json->operator[](key.data()).is_array())
1993 {
1994 std::for_each(m_json->operator[](key.data()).begin(), m_json->operator[](key.data()).end(), [&](nlohmann::json &item)
1995 {
1996 nlohmann::json *ptr = &item;
1997 m_arrayListDataCache[key.data()].emplace_back(std::make_unique<NlohmannJson>(ptr));
1998 });
1999 }
2000 }
2001
2002 return m_arrayListDataCache[key.data()];
2003 }
2004
2005 [[nodiscard]] inline size_t size() const override
2006 {
2007 return m_json->size();
2008 }
2009
2010 inline bool parse(const fs::path &path) override
2011 {
2012 clearCache();
2013 m_data = nullptr;
2014 m_json = nullptr;
2015 if (fs::exists(path) && fs::is_regular_file(path))
2016 {
2017 m_data = std::make_unique<nlohmann::json>();
2018 std::ifstream i(path.u8string());
2019 try
2020 {
2021 i >> *m_data;
2022 m_json = m_data.get();
2023 }
2024 catch (const nlohmann::json::parse_error &error)
2025 {
2026 std::string message = "Parse error: ";
2027 message += std::string(error.what());
2028 message += std::string("\n");
2029 std::cerr << message;
2030 return false;
2031 }
2032 return true;
2033 }
2034 return false;
2035 }
2036
2037 inline bool parse(const void *data, size_t size) override
2038 {
2039 clearCache();
2040 m_json = nullptr;
2041 m_data = std::make_unique<nlohmann::json>();
2042 tson::MemoryStream mem{(uint8_t *) data, size};
2043 try
2044 {
2045 mem >> *m_data;
2046 m_json = m_data.get();
2047 }
2048 catch (const nlohmann::json::parse_error &error)
2049 {
2050 std::string message = "Parse error: ";
2051 message += std::string(error.what());
2052 message += std::string("\n");
2053 std::cerr << message;
2054 return false;
2055 }
2056 return true;
2057 }
2058
2059 [[nodiscard]] inline size_t count(std::string_view key) const override
2060 {
2061 return m_json->count(key);
2062 }
2063
2064 [[nodiscard]] inline bool any(std::string_view key) const override
2065 {
2066 return count(key) > 0;
2067 }
2068
2069 [[nodiscard]] inline bool isArray() const override
2070 {
2071 return m_json->is_array();
2072 }
2073
2074 [[nodiscard]] inline bool isObject() const override
2075 {
2076 return m_json->is_object();
2077 }
2078
2079 [[nodiscard]] inline bool isNull() const override
2080 {
2081 return m_json->is_null();
2082 }
2083
2084 protected:
2085 [[nodiscard]] inline int32_t getInt32(std::string_view key) override
2086 {
2087 return m_json->operator[](key.data()).get<int32_t>();
2088 }
2089
2090 [[nodiscard]] inline uint32_t getUInt32(std::string_view key) override
2091 {
2092 return m_json->operator[](key.data()).get<uint32_t>();
2093 }
2094
2095 [[nodiscard]] inline int64_t getInt64(std::string_view key) override
2096 {
2097 return m_json->operator[](key.data()).get<int64_t>();
2098 }
2099
2100 [[nodiscard]] inline uint64_t getUInt64(std::string_view key) override
2101 {
2102 return m_json->operator[](key.data()).get<uint64_t>();
2103 }
2104
2105 [[nodiscard]] inline double getDouble(std::string_view key) override
2106 {
2107 return m_json->operator[](key.data()).get<double>();
2108 }
2109
2110 [[nodiscard]] inline std::string getString(std::string_view key) override
2111 {
2112 return m_json->operator[](key.data()).get<std::string>();
2113 }
2114
2115 [[nodiscard]] inline bool getBool(std::string_view key) override
2116 {
2117 return m_json->operator[](key.data()).get<bool>();
2118 }
2119
2120 [[nodiscard]] float getFloat(std::string_view key) override
2121 {
2122 return m_json->operator[](key.data()).get<float>();
2123 }
2124
2125 [[nodiscard]] inline int32_t getInt32() override
2126 {
2127 return m_json->get<int32_t>();
2128 }
2129
2130 [[nodiscard]] inline uint32_t getUInt32() override
2131 {
2132 return m_json->get<uint32_t>();
2133 }
2134
2135 [[nodiscard]] inline int64_t getInt64() override
2136 {
2137 return m_json->get<int64_t>();
2138 }
2139
2140 [[nodiscard]] inline uint64_t getUInt64() override
2141 {
2142 return m_json->get<uint64_t>();
2143 }
2144
2145 [[nodiscard]] inline double getDouble() override
2146 {
2147 return m_json->get<double>();
2148 }
2149
2150 [[nodiscard]] inline std::string getString() override
2151 {
2152 return m_json->get<std::string>();
2153 }
2154
2155 [[nodiscard]] inline bool getBool() override
2156 {
2157 return m_json->get<bool>();
2158 }
2159
2160 [[nodiscard]] float getFloat() override
2161 {
2162 return m_json->get<float>();
2163 }
2164
2165 private:
2166 inline void clearCache()
2167 {
2168 m_arrayCache.clear();
2169 m_arrayPosCache.clear();
2170 m_arrayListDataCache.clear();
2171 }
2172
2173 nlohmann::json *m_json = nullptr;
2174 std::unique_ptr<nlohmann::json> m_data = nullptr; //Only used if this is the owner json!
2175
2176 //Cache!
2177 std::map<std::string, std::unique_ptr<IJson>> m_arrayCache;
2178 std::map<size_t, std::unique_ptr<IJson>> m_arrayPosCache;
2179 std::map<std::string, std::vector<std::unique_ptr<IJson>>> m_arrayListDataCache;
2180
2181 };
2182}
2183#endif //TILESON_NLOHMANNJSON_HPP
2184
2185#endif //INCLUDE_NLOHMANN_JSON_HPP_
2186/*** End of inlined file: NlohmannJson.hpp ***/
2187
2188
2189/*** Start of inlined file: PicoJson.hpp ***/
2190//
2191// Created by robin on 11.01.2021.
2192//
2193
2194#ifdef picojson_h
2195#ifndef TILESON_PICOJSON_HPP
2196#define TILESON_PICOJSON_HPP
2197
2198namespace tson
2199{
2200 class PicoJson : public tson::IJson
2201 {
2202 public:
2203 inline PicoJson() = default;
2204
2205 IJson &operator[](std::string_view key) override
2206 {
2207 if(m_arrayCache.count(key.data()) == 0)
2208 {
2209 if(m_json->is<picojson::object>())
2210 {
2211 picojson::object &o = m_json->get<picojson::object>();
2212 m_arrayCache[key.data()] = std::make_unique<PicoJson>(&o[key.data()]);
2213 }
2214 }
2215
2216 return *m_arrayCache[key.data()].get();
2217 }
2218
2219 inline explicit PicoJson(picojson::value *json) : m_json {json}
2220 {
2221
2222 }
2223
2224 inline IJson& at(std::string_view key) override
2225 {
2226 if(m_arrayCache.count(key.data()) == 0)
2227 {
2228 if(m_json->is<picojson::object>())
2229 {
2230 picojson::object &o = m_json->get<picojson::object>();
2231 m_arrayCache[key.data()] = std::make_unique<PicoJson>(&o[key.data()]);
2232 }
2233 }
2234 return *m_arrayCache[key.data()].get();
2235 }
2236
2237 inline IJson& at(size_t pos) override
2238 {
2239 if(m_arrayPosCache.count(pos) == 0)
2240 {
2241 picojson::array &a = m_json->get<picojson::array>();
2242 m_arrayPosCache[pos] = std::make_unique<PicoJson>(&a.at(pos));
2243 }
2244
2245 return *m_arrayPosCache[pos];
2246 }
2247
2248 std::vector<std::unique_ptr<IJson>> array() override
2249 {
2250 std::vector<std::unique_ptr<IJson>> vec;
2251 if(m_json->is<picojson::array>())
2252 {
2253 picojson::array &a = m_json->get<picojson::array>();
2254 for (auto &item : a)
2255 {
2256 picojson::value *ptr = &item;
2257 vec.emplace_back(std::make_unique<PicoJson>(ptr));
2258 }
2259 }
2260
2261 return vec;
2262 }
2263
2264 inline std::vector<std::unique_ptr<IJson>> &array(std::string_view key) override
2265 {
2266 if(m_arrayListDataCache.count(key.data()) == 0)
2267 {
2268 if(count(key.data()) > 0)
2269 {
2270 if (isObject())
2271 {
2272 picojson::object &obj = m_json->get<picojson::object>();
2273 picojson::value &v = obj.at(key.data());
2274 bool isArray = v.is<picojson::array>();
2275 if (isArray)
2276 {
2277 picojson::array &a = v.get<picojson::array>();
2278
2279 std::for_each(a.begin(), a.end(), [&](picojson::value &item)
2280 {
2281 picojson::value *ptr = &item;
2282 m_arrayListDataCache[key.data()].emplace_back(std::make_unique<PicoJson>(ptr));
2283 });
2284 }
2285 }
2286 }
2287 }
2288
2289 return m_arrayListDataCache[key.data()];
2290 }
2291
2292 [[nodiscard]] inline size_t size() const override
2293 {
2294 if (m_json->is<picojson::object>())
2295 {
2296 picojson::object obj = m_json->get<picojson::object>();
2297 return obj.size();
2298 }
2299 return 0;
2300 }
2301
2302 inline bool parse(const fs::path &path) override
2303 {
2304 clearCache();
2305 m_data = nullptr;
2306 m_json = nullptr;
2307 if (fs::exists(path) && fs::is_regular_file(path))
2308 {
2309 m_data = std::make_unique<picojson::value>();
2310 std::ifstream i(path.u8string());
2311 try
2312 {
2313 std::string error = picojson::parse(*m_data, i);
2314 if(!error.empty())
2315 {
2316 std::cerr << "PicoJson parse error: " << error << "\n";
2317 return false;
2318 }
2319 //i >> *m_data;
2320 m_json = m_data.get();
2321 }
2322 catch (const std::exception &error)
2323 {
2324 std::string message = "Parse error: ";
2325 message += std::string(error.what());
2326 message += std::string("\n");
2327 std::cerr << message;
2328 return false;
2329 }
2330 return true;
2331 }
2332 return false;
2333 }
2334
2335 inline bool parse(const void *data, size_t size) override
2336 {
2337 clearCache();
2338 m_json = nullptr;
2339 m_data = std::make_unique<picojson::value>();
2340 tson::MemoryStream mem{(uint8_t *) data, size};
2341 try
2342 {
2343 std::string error = picojson::parse(*m_data, mem);
2344 if(!error.empty())
2345 {
2346 std::cerr << "PicoJson parse error: " << error << "\n";
2347 return false;
2348 }
2349 //mem >> *m_data;
2350 m_json = m_data.get();
2351 }
2352 catch (const std::exception &error)
2353 {
2354 std::string message = "Parse error: ";
2355 message += std::string(error.what());
2356 message += std::string("\n");
2357 std::cerr << message;
2358 return false;
2359 }
2360 return true;
2361 }
2362
2363 [[nodiscard]] inline size_t count(std::string_view key) const override
2364 {
2365 if (isObject())
2366 {
2367 picojson::object obj = m_json->get<picojson::object>();
2368 return obj.count(key.data());
2369 }
2370
2371 return m_json->contains(key.data()) ? 1 : 0;
2372 }
2373
2374 [[nodiscard]] inline bool any(std::string_view key) const override
2375 {
2376 return count(key) > 0;
2377 }
2378
2379 [[nodiscard]] inline bool isArray() const override
2380 {
2381 return m_json->is<picojson::array>();
2382 }
2383
2384 [[nodiscard]] inline bool isObject() const override
2385 {
2386 return m_json->is<picojson::object>();
2387 }
2388
2389 [[nodiscard]] inline bool isNull() const override
2390 {
2391 return m_json->is<picojson::null>();
2392 }
2393
2394 protected:
2395 [[nodiscard]] inline int32_t getInt32(std::string_view key) override
2396 {
2397 picojson::object obj = m_json->get<picojson::object>();
2398 return static_cast<int32_t>(getDouble(key));
2399 }
2400
2401 [[nodiscard]] inline uint32_t getUInt32(std::string_view key) override
2402 {
2403 picojson::object obj = m_json->get<picojson::object>();
2404 return static_cast<uint32_t>(getDouble(key));
2405 }
2406
2407 [[nodiscard]] inline int64_t getInt64(std::string_view key) override
2408 {
2409 picojson::object obj = m_json->get<picojson::object>();
2410 return static_cast<int64_t>(getDouble(key));
2411 }
2412
2413 [[nodiscard]] inline uint64_t getUInt64(std::string_view key) override
2414 {
2415 picojson::object obj = m_json->get<picojson::object>();
2416 return static_cast<uint64_t>(getDouble(key));
2417 }
2418
2419 [[nodiscard]] inline double getDouble(std::string_view key) override
2420 {
2421 picojson::object obj = m_json->get<picojson::object>();
2422 return obj[key.data()].get<double>();
2423 }
2424
2425 [[nodiscard]] inline std::string getString(std::string_view key) override
2426 {
2427 picojson::object obj = m_json->get<picojson::object>();
2428 return obj[key.data()].get<std::string>();
2429 }
2430
2431 [[nodiscard]] inline bool getBool(std::string_view key) override
2432 {
2433 picojson::object obj = m_json->get<picojson::object>();
2434 return obj[key.data()].get<bool>();
2435 }
2436
2437 [[nodiscard]] float getFloat(std::string_view key) override
2438 {
2439 picojson::object obj = m_json->get<picojson::object>();
2440 return static_cast<float>(getDouble(key));
2441 }
2442
2443 [[nodiscard]] inline int32_t getInt32() override
2444 {
2445 return static_cast<int32_t>(getDouble());
2446 }
2447
2448 [[nodiscard]] inline uint32_t getUInt32() override
2449 {
2450 return static_cast<uint32_t>(getDouble());
2451 }
2452
2453 [[nodiscard]] inline int64_t getInt64() override
2454 {
2455 return static_cast<int64_t>(getDouble());
2456 }
2457
2458 [[nodiscard]] inline uint64_t getUInt64() override
2459 {
2460 return static_cast<uint64_t>(getDouble());
2461 }
2462
2463 [[nodiscard]] inline double getDouble() override
2464 {
2465 return m_json->get<double>();
2466 }
2467
2468 [[nodiscard]] inline std::string getString() override
2469 {
2470 return m_json->get<std::string>();
2471 }
2472
2473 [[nodiscard]] inline bool getBool() override
2474 {
2475 return m_json->get<bool>();
2476 }
2477
2478 [[nodiscard]] float getFloat() override
2479 {
2480 return static_cast<float>(getDouble());
2481 }
2482
2483 private:
2484 inline void clearCache()
2485 {
2486 m_arrayCache.clear();
2487 m_arrayPosCache.clear();
2488 m_arrayListDataCache.clear();
2489 }
2490
2491 picojson::value *m_json = nullptr;
2492 std::unique_ptr<picojson::value> m_data = nullptr; //Only used if this is the owner json!
2493
2494 //Cache!
2495 std::map<std::string, std::unique_ptr<IJson>> m_arrayCache;
2496 std::map<size_t, std::unique_ptr<IJson>> m_arrayPosCache;
2497 std::map<std::string, std::vector<std::unique_ptr<IJson>>> m_arrayListDataCache;
2498
2499 };
2500}
2501#endif //TILESON_PICOJSON_HPP
2502#endif
2503
2504/*** End of inlined file: PicoJson.hpp ***/
2505
2506//#include "../json/Gason.hpp" //Unsupported
2507
2508/*** Start of inlined file: Json11.hpp ***/
2509//
2510// Created by robin on 16.01.2021.
2511//
2512
2513#ifndef TILESON_JSON11_HPP
2514#define TILESON_JSON11_HPP
2515
2516namespace tson
2517{
2518 class Json11 : public tson::IJson
2519 {
2520 public:
2521 inline Json11() = default;
2522
2523 IJson &operator[](std::string_view key) override
2524 {
2525 if(m_arrayCache.count(key.data()) == 0)
2526 {
2527 if(m_json->is_object())
2528 {
2529 m_arrayCache[key.data()] = std::make_unique<Json11>(m_json->operator[](key.data()));
2530 }
2531 }
2532
2533 return *m_arrayCache[key.data()].get();
2534 }
2535
2536 inline explicit Json11(const json11::Json &json) : m_json {&json}
2537 {
2538
2539 }
2540
2541 inline IJson& at(std::string_view key) override
2542 {
2543 if(m_arrayCache.count(key.data()) == 0)
2544 {
2545 if(m_json->is_object())
2546 {
2547 m_arrayCache[key.data()] = std::make_unique<Json11>(m_json->operator[](key.data()));
2548 }
2549 }
2550 return *m_arrayCache[key.data()].get();
2551 }
2552
2553 inline IJson& at(size_t pos) override
2554 {
2555 if(m_arrayPosCache.count(pos) == 0)
2556 {
2557 const std::vector<json11::Json> &a = m_json->array_items();
2558 m_arrayPosCache[pos] = std::make_unique<Json11>(a.at(pos));
2559 }
2560
2561 return *m_arrayPosCache[pos];
2562 }
2563
2564 std::vector<std::unique_ptr<IJson>> array() override
2565 {
2566 std::vector<std::unique_ptr<IJson>> vec;
2567 if(m_json->is_array())
2568 {
2569 for (const json11::Json &item : m_json->array_items())
2570 {
2571 vec.emplace_back(std::make_unique<Json11>(item));
2572 }
2573 }
2574
2575 return vec;
2576 }
2577
2578 inline std::vector<std::unique_ptr<IJson>> &array(std::string_view key) override
2579 {
2580 if(m_arrayListDataCache.count(key.data()) == 0)
2581 {
2582 if(count(key.data()) > 0)
2583 {
2584 if(isObject())
2585 {
2586 const json11::Json &v = m_json->operator[](key.data());
2587 if(v.is_array())
2588 {
2589 for (const json11::Json &item : v.array_items())
2590 {
2591 m_arrayListDataCache[key.data()].emplace_back(std::make_unique<Json11>(item));
2592 }
2593 }
2594 }
2595 }
2596 }
2597
2598 return m_arrayListDataCache[key.data()];
2599 }
2600
2601 [[nodiscard]] inline size_t size() const override
2602 {
2603 if(m_json->is_object())
2604 return m_json->object_items().size();
2605 else if(m_json->is_array())
2606 return m_json->array_items().size();
2607
2608 return 0;
2609 }
2610
2611 inline bool parse(const fs::path &path) override
2612 {
2613 clearCache();
2614 m_data = nullptr;
2615 m_json = nullptr;
2616 if (fs::exists(path) && fs::is_regular_file(path))
2617 {
2618 std::ifstream file(path.u8string());
2619 std::string str;
2620
2621 file.seekg(0, std::ios::end);
2622 str.reserve(file.tellg());
2623 file.seekg(0, std::ios::beg);
2624
2625 str.assign((std::istreambuf_iterator<char>(file)),
2626 std::istreambuf_iterator<char>());
2627
2628 m_data = std::make_unique<json11::Json>();
2629
2630 try
2631 {
2632 std::string strError;
2633 *m_data = json11::Json::parse(str, strError);
2634 if(!strError.empty())
2635 {
2636 std::cerr << strError << "\n";
2637 return false;
2638 }
2639 m_json = m_data.get();
2640 }
2641 catch (const std::exception &error)
2642 {
2643 std::string message = "Json11 parse error: ";
2644 message += std::string(error.what());
2645 message += std::string("\n");
2646 std::cerr << message;
2647 return false;
2648 }
2649 return true;
2650 }
2651 return false;
2652 }
2653
2654 inline bool parse(const void *data, size_t size) override
2655 {
2656 clearCache();
2657 m_json = nullptr;
2658 std::string str;
2659
2660 str.reserve(size);
2661
2662 tson::MemoryStream mem{(uint8_t *) data, size};
2663
2664 str.assign((std::istreambuf_iterator<char>(mem)),
2665 std::istreambuf_iterator<char>());
2666
2667 m_data = std::make_unique<json11::Json>();
2668
2669 try
2670 {
2671 std::string strError;
2672
2673 *m_data = json11::Json::parse(str, strError);
2674 if(!strError.empty())
2675 {
2676 std::cout << strError << "\n";
2677 return false;
2678 }
2679 m_json = m_data.get();
2680 }
2681 catch (const std::exception &error)
2682 {
2683 std::string message = "Json11 parse error: ";
2684 message += std::string(error.what());
2685 message += std::string("\n");
2686 std::cerr << message;
2687 return false;
2688 }
2689 return true;
2690 }
2691
2692 [[nodiscard]] inline size_t count(std::string_view key) const override
2693 {
2694 if (isObject())
2695 {
2696 //const json11::Json &j = m_json->operator[](key.data());
2697 //size_t s1 = j.object_items().size();
2698 return m_json->object_items().count(key.data());
2699 }
2700
2701 return 0;
2702 }
2703
2704 [[nodiscard]] inline bool any(std::string_view key) const override
2705 {
2706 return count(key) > 0;
2707 }
2708
2709 [[nodiscard]] inline bool isArray() const override
2710 {
2711 return m_json->is_array();
2712 }
2713
2714 [[nodiscard]] inline bool isObject() const override
2715 {
2716 return m_json->is_object();
2717 }
2718
2719 [[nodiscard]] inline bool isNull() const override
2720 {
2721 return m_json->is_null();
2722 }
2723
2724 protected:
2725 [[nodiscard]] inline int32_t getInt32(std::string_view key) override
2726 {
2727 return static_cast<int32_t>(getDouble(key));
2728 }
2729
2730 [[nodiscard]] inline uint32_t getUInt32(std::string_view key) override
2731 {
2732 return static_cast<uint32_t>(getDouble(key));
2733 }
2734
2735 [[nodiscard]] inline int64_t getInt64(std::string_view key) override
2736 {
2737 return static_cast<int64_t>(getDouble(key));
2738 }
2739
2740 [[nodiscard]] inline uint64_t getUInt64(std::string_view key) override
2741 {
2742 return static_cast<uint64_t>(getDouble(key));
2743 }
2744
2745 [[nodiscard]] inline double getDouble(std::string_view key) override
2746 {
2747 return m_json->operator[](key.data()).number_value();
2748 }
2749
2750 [[nodiscard]] inline std::string getString(std::string_view key) override
2751 {
2752 return m_json->operator[](key.data()).string_value(); // .get<std::string>();
2753 }
2754
2755 [[nodiscard]] inline bool getBool(std::string_view key) override
2756 {
2757 return m_json->operator[](key.data()).bool_value();
2758 }
2759
2760 [[nodiscard]] float getFloat(std::string_view key) override
2761 {
2762 return static_cast<float>(getDouble(key));
2763 }
2764
2765 [[nodiscard]] inline int32_t getInt32() override
2766 {
2767 return static_cast<int32_t>(getDouble());
2768 }
2769
2770 [[nodiscard]] inline uint32_t getUInt32() override
2771 {
2772 return static_cast<uint32_t>(getDouble());
2773 }
2774
2775 [[nodiscard]] inline int64_t getInt64() override
2776 {
2777 return static_cast<int64_t>(getDouble());
2778 }
2779
2780 [[nodiscard]] inline uint64_t getUInt64() override
2781 {
2782 return static_cast<uint64_t>(getDouble());
2783 }
2784
2785 [[nodiscard]] inline double getDouble() override
2786 {
2787 return m_json->number_value();
2788 }
2789
2790 [[nodiscard]] inline std::string getString() override
2791 {
2792 return m_json->string_value();
2793 }
2794
2795 [[nodiscard]] inline bool getBool() override
2796 {
2797 return m_json->bool_value();
2798 }
2799
2800 [[nodiscard]] float getFloat() override
2801 {
2802 return static_cast<float>(getDouble());
2803 }
2804
2805 private:
2806
2807 inline void clearCache()
2808 {
2809 m_arrayCache.clear();
2810 m_arrayPosCache.clear();
2811 m_arrayListDataCache.clear();
2812 }
2813
2814 //Owner values
2815 char *m_endptr;
2816 std::unique_ptr<json11::Json> m_data = nullptr; //Only used if this is the owner json!
2817
2818 const json11::Json *m_json = nullptr;
2819
2820 //Cache!
2821 std::map<std::string, std::unique_ptr<IJson>> m_arrayCache;
2822 std::map<size_t, std::unique_ptr<IJson>> m_arrayPosCache;
2823 std::map<std::string, std::vector<std::unique_ptr<IJson>>> m_arrayListDataCache;
2824
2825 };
2826}
2827
2828#endif //TILESON_JSON11_HPP
2829
2830/*** End of inlined file: Json11.hpp ***/
2831
2832
2833
2834/*** Start of inlined file: Layer.hpp ***/
2835//
2836// Created by robin on 22.03.2020.
2837//
2838
2839#ifndef TILESON_LAYER_HPP
2840#define TILESON_LAYER_HPP
2841
2842#include <set>
2843//#include "../external/json.hpp"
2844
2845
2846/*** Start of inlined file: Chunk.hpp ***/
2847//
2848// Created by robin on 22.03.2020.
2849//
2850
2851#ifndef TILESON_CHUNK_HPP
2852#define TILESON_CHUNK_HPP
2853
2854//#include "../external/json.hpp"
2855
2856namespace tson
2857{
2858 class Chunk
2859 {
2860 public:
2861 inline Chunk() = default;
2862 inline explicit Chunk(IJson &json);
2863 inline bool parse(IJson &json);
2864
2865 [[nodiscard]] inline const std::vector<int> &getData() const;
2866 [[nodiscard]] inline const std::string &getBase64Data() const;
2867 [[nodiscard]] inline const Vector2i &getSize() const;
2868 [[nodiscard]] inline const Vector2i &getPosition() const;
2869
2870 private:
2871 std::vector<int> m_data; /*! 'data' (when uint array): Array of unsigned int (GIDs) or base64-encoded data. tilelayer only. */
2872 std::string m_base64Data; /*! 'data' (when string): Array of unsigned int (GIDs) or base64-encoded data. */
2873 tson::Vector2i m_size; /*! x='width' (in tiles) and y='height' (in tiles): */
2874 tson::Vector2i m_position; /*! 'x' and 'y' position in tiles */
2875 };
2876}
2877
2878#endif //TILESON_CHUNK_HPP
2879
2880/*!
2881 * Parses 'chunk' data from Tiled json and stores the values in this class
2882 * @param json json-data
2883 */
2884tson::Chunk::Chunk(IJson &json)
2885{
2886 parse(json);
2887}
2888
2889/*!
2890 * Parses 'chunk' data from Tiled json and stores the values in this class
2891 * @param json json-data
2892 * @return true if all mandatory fields was found. false otherwise.
2893 */
2894bool tson::Chunk::parse(IJson &json)
2895{
2896 bool allFound = true;
2897
2898 if(json.count("width") > 0 && json.count("height") > 0)
2899 m_size = {json["width"].get<int>(), json["height"].get<int>()}; else allFound = false;
2900 if(json.count("x") > 0 && json.count("y") > 0)
2901 m_position = {json["x"].get<int>(), json["y"].get<int>()}; else allFound = false;
2902
2903 //Handle DATA (Optional)
2904 if(json.count("data") > 0)
2905 {
2906 if(json["data"].isArray())
2907 {
2908 auto &data = json.array("data");
2909 std::for_each(data.begin(), data.end(), [&](std::unique_ptr<IJson> &item) { m_data.push_back(item->get<int>()); });
2910 }
2911 else
2912 m_base64Data = json["data"].get<std::string>();
2913 }
2914
2915 return allFound;
2916}
2917
2918/*!
2919 * 'data' (when uint array): Array of unsigned int (GIDs) or base64-encoded data. tilelayer only.
2920 * @return list of tile ids
2921 */
2922const std::vector<int> &tson::Chunk::getData() const
2923{
2924 return m_data;
2925}
2926
2927/*!
2928 * 'data' (when string): Array of unsigned int (GIDs) or base64-encoded data.
2929 * @return base64 string
2930 */
2931const std::string &tson::Chunk::getBase64Data() const
2932{
2933 return m_base64Data;
2934}
2935
2936/*!
2937 * x='width' (in tiles) and y='height' (in tiles).
2938 * @return Size (x and y), containing the values from the fields 'width' and 'height' in Tiled
2939 */
2940const tson::Vector2i &tson::Chunk::getSize() const
2941{
2942 return m_size;
2943}
2944
2945/*!
2946 * 'x' and 'y' position in tiles
2947 * @return Position in int
2948 */
2949const tson::Vector2i &tson::Chunk::getPosition() const
2950{
2951 return m_position;
2952}
2953/*** End of inlined file: Chunk.hpp ***/
2954
2955
2956/*** Start of inlined file: Object.hpp ***/
2957//
2958// Created by robin on 22.03.2020.
2959//
2960
2961#ifndef TILESON_OBJECT_HPP
2962#define TILESON_OBJECT_HPP
2963
2964//#include "../external/json.hpp"
2965
2966
2967/*** Start of inlined file: PropertyCollection.hpp ***/
2968//
2969// Created by robin on 22.03.2020.
2970//
2971
2972#ifndef TILESON_PROPERTYCOLLECTION_HPP
2973#define TILESON_PROPERTYCOLLECTION_HPP
2974
2975
2976/*** Start of inlined file: Property.hpp ***/
2977//
2978// Created by robin on 22.03.2020.
2979//
2980
2981#ifndef TILESON_PROPERTY_HPP
2982#define TILESON_PROPERTY_HPP
2983
2984//#include "../../TilesonConfig.h"
2985
2986//#if USE_CPP17_FILESYSTEM
2987
2988#include <any>
2989#include <string>
2990
2991/*** Start of inlined file: Enums.hpp ***/
2992//
2993// Created by robin on 22.03.2020.
2994//
2995
2996#ifndef TILESON_ENUMS_HPP
2997#define TILESON_ENUMS_HPP
2998#include <cstdint>
2999
3000/*** Start of inlined file: EnumBitflags.hpp ***/
3001//
3002// Created by robin on 08.11.2020.
3003//
3004
3005#ifndef TILESON_ENUMBITFLAGS_HPP
3006#define TILESON_ENUMBITFLAGS_HPP
3007
3008#include <type_traits>
3009#include <iostream>
3010
3011namespace tson
3012{
3013 #define ENABLE_BITMASK_OPERATORS(x) \
3014 template<> \
3015 struct EnableBitMaskOperators<x> \
3016 { \
3017 static const bool enable = true; \
3018 };
3019
3020 template<typename Enum>
3021 struct EnableBitMaskOperators
3022 {
3023 static const bool enable = false;
3024 };
3025
3026 template<typename Enum>
3027 typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type
3028 operator |(Enum lhs, Enum rhs)
3029 {
3030 static_assert(std::is_enum<Enum>::value,
3031 "template parameter is not an enum type");
3032
3033 using underlying = typename std::underlying_type<Enum>::type;
3034
3035 return static_cast<Enum> (
3036 static_cast<underlying>(lhs) |
3037 static_cast<underlying>(rhs)
3038 );
3039 }
3040
3041 //Permissions operator &(Permissions lhs, Permissions rhs)
3042 template<typename Enum>
3043 typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type
3044 operator &(Enum lhs, Enum rhs)
3045 {
3046 static_assert(std::is_enum<Enum>::value,
3047 "template parameter is not an enum type");
3048
3049 using underlying = typename std::underlying_type<Enum>::type;
3050
3051 return static_cast<Enum> (
3052 static_cast<underlying>(lhs) &
3053 static_cast<underlying>(rhs)
3054 );
3055 }
3056
3057 //Permissions operator ^(Permissions lhs, Permissions rhs)
3058 template<typename Enum>
3059 typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type
3060 operator ^(Enum lhs, Enum rhs)
3061 {
3062 static_assert(std::is_enum<Enum>::value,
3063 "template parameter is not an enum type");
3064
3065 using underlying = typename std::underlying_type<Enum>::type;
3066
3067 return static_cast<Enum> (
3068 static_cast<underlying>(lhs) ^
3069 static_cast<underlying>(rhs)
3070 );
3071 }
3072
3073 //Permissions operator ~(Permissions rhs)
3074 template<typename Enum>
3075 typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type
3076 operator ~(Enum rhs)
3077 {
3078 static_assert(std::is_enum<Enum>::value,
3079 "template parameter is not an enum type");
3080
3081 using underlying = typename std::underlying_type<Enum>::type;
3082
3083 return static_cast<Enum> (
3084 ~static_cast<underlying>(rhs)
3085 );
3086 }
3087
3088 //Permissions& operator |=(Permissions &lhs, Permissions rhs)
3089 template<typename Enum>
3090 typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type
3091 &operator |=(Enum &lhs, Enum rhs)
3092 {
3093 static_assert(std::is_enum<Enum>::value,
3094 "template parameter is not an enum type");
3095
3096 using underlying = typename std::underlying_type<Enum>::type;
3097
3098 lhs = static_cast<Enum> (
3099 static_cast<underlying>(lhs) |
3100 static_cast<underlying>(rhs)
3101 );
3102
3103 return lhs;
3104 }
3105
3106 //Permissions& operator &=(Permissions &lhs, Permissions rhs)
3107 template<typename Enum>
3108 typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type
3109 &operator &=(Enum &lhs, Enum rhs)
3110 {
3111 static_assert(std::is_enum<Enum>::value,
3112 "template parameter is not an enum type");
3113
3114 using underlying = typename std::underlying_type<Enum>::type;
3115
3116 lhs = static_cast<Enum> (
3117 static_cast<underlying>(lhs) &
3118 static_cast<underlying>(rhs)
3119 );
3120
3121 return lhs;
3122 }
3123
3124 //Permissions& operator ^=(Permissions &lhs, Permissions rhs)
3125 template<typename Enum>
3126 typename std::enable_if<EnableBitMaskOperators<Enum>::enable, Enum>::type
3127 &operator ^=(Enum &lhs, Enum rhs)
3128 {
3129 static_assert(std::is_enum<Enum>::value,
3130 "template parameter is not an enum type");
3131
3132 using underlying = typename std::underlying_type<Enum>::type;
3133
3134 lhs = static_cast<Enum> (
3135 static_cast<underlying>(lhs) ^
3136 static_cast<underlying>(rhs)
3137 );
3138
3139 return lhs;
3140 }
3141}
3142
3143#endif //TILESON_ENUMBITFLAGS_HPP
3144
3145/*** End of inlined file: EnumBitflags.hpp ***/
3146
3147
3148namespace tson
3149{
3150 /*!
3151 * Type used in Property.hpp
3152 */
3153 enum class Type : uint8_t
3154 {
3155 Undefined = 0,
3156 Color = 1, /*! color */
3157 File = 2, /*! file */
3158 Int = 3, /*! int */
3159 Boolean = 4, /*! bool */
3160 Float = 5, /*! float */
3161 String = 6 /*! string */
3162 };
3163
3164 /*!
3165 * Layer.hpp - LayerType
3166 * //'type': tilelayer, objectgroup, imagelayer or group
3167 */
3168 enum class LayerType : uint8_t
3169 {
3170 Undefined = 0,
3171 TileLayer = 1,
3172 ObjectGroup = 2,
3173 ImageLayer = 3,
3174 Group = 4
3175 };
3176
3177 /*!
3178 * Map.hpp - ParseStatus
3179 */
3180 enum class ParseStatus : uint8_t
3181 {
3182 OK = 0, //OK unless otherwise stated
3183 FileNotFound = 1,
3184 ParseError = 2,
3185 MissingData = 3,
3186 DecompressionError = 4
3187 };
3188
3189 /*!
3190 * Object.hpp - ObjectType
3191 */
3192 enum class ObjectType : uint8_t
3193 {
3194 Undefined = 0,
3195 Object = 1,
3196 Ellipse = 2,
3197 Rectangle = 3,
3198 Point = 4,
3199 Polygon = 5,
3200 Polyline = 6,
3201 Text = 7,
3202 Template = 8
3203 };
3204
3205 static constexpr uint32_t FLIPPED_HORIZONTALLY_FLAG = 0x80000000;
3206 static constexpr uint32_t FLIPPED_VERTICALLY_FLAG = 0x40000000;
3207 static constexpr uint32_t FLIPPED_DIAGONALLY_FLAG = 0x20000000;
3208 /*!
3209 * Object.hpp - ObjectFlipFlags
3210 */
3211 enum class TileFlipFlags : uint32_t
3212 {
3213 None = 0,
3214 Diagonally = FLIPPED_DIAGONALLY_FLAG,
3215 Vertically = FLIPPED_VERTICALLY_FLAG,
3216 Horizontally = FLIPPED_HORIZONTALLY_FLAG
3217 };
3218
3219 /*!
3220 * Tileset.hpp - ObjectAlignment
3221 */
3222 enum class ObjectAlignment : uint8_t
3223 {
3224 Unspecified = 0, //unspecified
3225 TopLeft = 1, //topleft
3226 Top = 2, //top
3227 TopRight = 3, //topright
3228 Left = 4, //left
3229 Center = 5, //center
3230 Right = 6, //right
3231 BottomLeft = 7, //bottomleft
3232 Bottom = 8, //bottom
3233 BottomRight = 9 //bottomright
3234 };
3235
3236 ENABLE_BITMASK_OPERATORS(TileFlipFlags)
3237}
3238
3239#endif //TILESON_ENUMS_HPP
3240
3241/*** End of inlined file: Enums.hpp ***/
3242
3243
3244//#include "../external/json.hpp"
3245
3246namespace tson
3247{
3248 class Property
3249 {
3250 public:
3251
3252 //enum class Type : uint8_t
3253 //{
3254 // Undefined = 0,
3255 // Color = 1, /*! color */
3256 // File = 2, /*! file */
3257 // Int = 3, /*! int */
3258 // Boolean = 4, /*! bool */
3259 // Float = 5, /*! float */
3260 // String = 6 /*! string */
3261 //};
3262
3263 inline Property();
3264 inline Property(IJson &json);
3265 inline Property(std::string name, std::any value, Type type);
3266
3267 inline void setValue(const std::any &value);
3268 inline void setStrValue(const std::string &value);
3269 inline void setName(const std::string &name);
3270
3271 [[nodiscard]] inline const std::type_info& getValueType() const;
3272 inline std::string getValueTypeInfo();
3273 [[nodiscard]]inline const std::any &getValue() const;
3274 template <typename T>
3275 inline T getValue() const;
3276 [[nodiscard]] inline const std::string &getName() const;
3277 [[nodiscard]] inline Type getType() const;
3278
3279 protected:
3280 inline void setTypeByString(const std::string &str);
3281 inline void setValueByType(IJson &json);
3282
3283 Type m_type = Type::Undefined;
3284 std::string m_name;
3285 std::any m_value; //Using std::any to assign any type
3286 };
3287
3288 template<typename T>
3289 T Property::getValue() const
3290 {
3291 bool isCorrectType = (m_value.type() == typeid(T));
3292
3293 if(isCorrectType)
3294 {
3295 T value = std::any_cast<T>(m_value);
3296 return value;
3297 }
3298 else
3299 {
3300 static T defaultValue;
3301 return defaultValue;
3302 }
3303 }
3304}
3305
3306tson::Property::Property() : m_name {"unnamed"}
3307{
3308
3309}
3310
3311tson::Property::Property(IJson &json)
3312{
3313 setTypeByString(json["type"].get<std::string>());
3314 setValueByType(json["value"]);
3315 m_name = json["name"].get<std::string>();
3316}
3317
3318tson::Property::Property(std::string name, std::any value, Type type) : m_name { move(name) }, m_value { move(value) }, m_type {type}
3319{
3320
3321}
3322
3323void tson::Property::setValue(const std::any &value)
3324{
3325 m_value = value;
3326}
3327
3328/*!
3329 * Sets the value specifically as string.
3330 * When not specified as std::string, the default is that the value will be set as char * when adding a value like "test"
3331 * This function is to make sure the value is added as string.
3332 * @param value
3333 */
3334void tson::Property::setStrValue(const std::string &value)
3335{
3336 m_value = value;
3337}
3338
3339const std::any &tson::Property::getValue() const
3340{
3341 return m_value;
3342}
3343
3344void tson::Property::setName(const std::string &name)
3345{
3346 m_name = name;
3347}
3348
3349const std::string &tson::Property::getName() const
3350{
3351 return m_name;
3352}
3353
3354/*!
3355 * Gets the value type as std::value_info.
3356 * This can easily be compared to types like this:
3357 * Check if int: getValueType() == typeid(int)
3358 * @return
3359 */
3360
3361const std::type_info &tson::Property::getValueType() const
3362{
3363 return m_value.type();
3364}
3365
3366/*!
3367 * Gets the value type as std::string
3368 * Examples of known types:
3369 * "i" = int
3370 * "f" = float
3371 * "b" = bool
3372 * @return
3373 */
3374std::string tson::Property::getValueTypeInfo()
3375{
3376 return m_value.type().name();
3377}
3378
3379tson::Type tson::Property::getType() const
3380{
3381 return m_type;
3382}
3383
3384void tson::Property::setTypeByString(const std::string &str)
3385{
3386 if(str == "color")
3387 m_type = tson::Type::Color;
3388 else if(str == "file")
3389 m_type = tson::Type::File;
3390 else if(str == "int")
3391 m_type = tson::Type::Int;
3392 else if(str == "bool")
3393 m_type = tson::Type::Boolean;
3394 else if(str == "float")
3395 m_type = tson::Type::Float;
3396 else if(str == "string")
3397 m_type = tson::Type::String;
3398 else
3399 m_type = tson::Type::Undefined;
3400}
3401
3402void tson::Property::setValueByType(IJson &json)
3403{
3404 switch(m_type)
3405 {
3406 case Type::Color:
3407 m_value = Colori(json.get<std::string>());
3408 break;
3409
3410 case Type::File:
3411 m_value = fs::path(json.get<std::string>());
3412 break;
3413
3414 case Type::Int:
3415 m_value = json.get<int>();
3416 break;
3417
3418 case Type::Boolean:
3419 m_value = json.get<bool>();
3420 break;
3421
3422 case Type::Float:
3423 m_value = json.get<float>();
3424 break;
3425
3426 case Type::String:
3427 setStrValue(json.get<std::string>());
3428 break;
3429
3430 default:
3431 setStrValue(json.get<std::string>());
3432 break;
3433
3434 }
3435}
3436
3437#endif //TILESON_PROPERTY_HPP
3438
3439/*** End of inlined file: Property.hpp ***/
3440
3441//#include "../external/json.hpp"
3442#include <map>
3443
3444namespace tson
3445{
3446 class PropertyCollection
3447 {
3448 public:
3449 inline PropertyCollection() = default;
3450
3451 inline explicit PropertyCollection(std::string id);
3452
3453 inline tson::Property * add(const tson::Property &property);
3454 inline tson::Property * add(IJson &json);
3455 inline tson::Property * add(const std::string &name, const std::any &value, tson::Type type);
3456
3457 inline void remove(const std::string &name);
3458
3459 inline void setValue(const std::string &name, const std::any &value);
3460 inline void setId(const std::string &id);
3461
3462 inline bool hasProperty(const std::string &name);
3463 inline tson::Property * getProperty(const std::string &name);
3464 inline std::map<std::string, Property> &getProperties();
3465 inline std::vector<Property*> get();
3466 template <typename T>
3467 inline T getValue(const std::string &name);
3468 [[nodiscard]] inline const std::string &getId() const;
3469 [[nodiscard]] inline size_t getSize() const;
3470
3471 protected:
3472 std::string m_id;
3473 std::map<std::string, tson::Property> m_properties;
3474 };
3475}
3476
3477template<typename T>
3478T tson::PropertyCollection::getValue(const std::string &name)
3479{
3480 static T defaultT;
3481 return (m_properties.count(name) > 0) ? m_properties[name].getValue<T>() : defaultT;
3482}
3483
3484tson::PropertyCollection::PropertyCollection(std::string id) : m_id {std::move(id)}
3485{
3486
3487}
3488
3489tson::Property *tson::PropertyCollection::add(const tson::Property &property)
3490{
3491 m_properties[property.getName()] = property;
3492 return &m_properties[property.getName()];
3493}
3494
3495tson::Property *tson::PropertyCollection::add(IJson &json)
3496{
3497 tson::Property property = tson::Property(json);
3498 std::string name = property.getName();
3499 m_properties[name] = std::move(property);
3500 return &m_properties[name];
3501}
3502
3503tson::Property *tson::PropertyCollection::add(const std::string &name, const std::any &value, tson::Type type)
3504{
3505 m_properties[name] = {name, value, type};
3506 return &m_properties[name];
3507}
3508
3509void tson::PropertyCollection::remove(const std::string &name)
3510{
3511 m_properties.erase(name);
3512}
3513
3514/*!
3515 * Sets a value IF the property already exists. Does nothing otherwise.
3516 * See add() for adding new properties
3517 * @param name
3518 * @param value
3519 */
3520void tson::PropertyCollection::setValue(const std::string &name, const std::any &value)
3521{
3522 if(m_properties.count(name) > 0)
3523 m_properties[name].setValue(value);
3524}
3525
3526void tson::PropertyCollection::setId(const std::string &id)
3527{
3528 m_id = id;
3529}
3530
3531bool tson::PropertyCollection::hasProperty(const std::string &name)
3532{
3533 return m_properties.count(name) > 0;
3534}
3535
3536tson::Property *tson::PropertyCollection::getProperty(const std::string &name)
3537{
3538 return (m_properties.count(name) > 0) ? &m_properties[name] : nullptr;
3539}
3540
3541std::map<std::string, tson::Property> &tson::PropertyCollection::getProperties()
3542{
3543 return m_properties;
3544}
3545
3546/*!
3547 * Gets vector of pointers to all the existing properties
3548 * @return
3549 */
3550std::vector<tson::Property *> tson::PropertyCollection::get()
3551{
3552 std::vector<tson::Property *> props;
3553 for(auto &i : m_properties)
3554 props.emplace_back(&i.second);
3555
3556 return props;
3557}
3558
3559const std::string &tson::PropertyCollection::getId() const
3560{
3561 return m_id;
3562}
3563
3564size_t tson::PropertyCollection::getSize() const
3565{
3566 return m_properties.size();
3567}
3568
3569#endif //TILESON_PROPERTYCOLLECTION_HPP
3570
3571/*** End of inlined file: PropertyCollection.hpp ***/
3572
3573
3574/*** Start of inlined file: Text.hpp ***/
3575//
3576// Created by robin on 05.08.2019.
3577//
3578
3579#ifndef TILESON_TEXT_HPP
3580#define TILESON_TEXT_HPP
3581
3582#include <string>
3583
3584namespace tson
3585{
3586 class Text
3587 {
3588 public:
3589 inline Text() = default;
3590 /*!
3591 *
3592 * @param _text Text
3593 * @param _wrap If the text is marked as wrapped
3594 */
3595 inline Text(std::string _text, bool _wrap, tson::Colori _color) : text {std::move(_text)}, wrap {_wrap}, color {_color} {};
3596 //Just make it simple
3597 std::string text;
3598 tson::Colori color;
3599 bool wrap{};
3600 };
3601}
3602
3603#endif //TILESON_TEXT_HPP
3604
3605/*** End of inlined file: Text.hpp ***/
3606
3607namespace tson
3608{
3609 class Object
3610 {
3611 public:
3612 //enum class Type : uint8_t
3613 //{
3614 // Undefined = 0,
3615 // Object = 1,
3616 // Ellipse = 2,
3617 // Rectangle = 3,
3618 // Point = 4,
3619 // Polygon = 5,
3620 // Polyline = 6,
3621 // Text = 7,
3622 // Template = 8
3623 //};
3624
3625 inline Object() = default;
3626 inline explicit Object(IJson &json);
3627 inline bool parse(IJson &json);
3628
3629 [[nodiscard]] inline ObjectType getObjectType() const;
3630 [[nodiscard]] inline bool isEllipse() const;
3631 [[nodiscard]] inline uint32_t getGid() const;
3632 [[nodiscard]] inline const Vector2i &getSize() const;
3633 [[nodiscard]] inline int getId() const;
3634 [[nodiscard]] inline const std::string &getName() const;
3635 [[nodiscard]] inline bool isPoint() const;
3636 [[nodiscard]] inline float getRotation() const;
3637 [[nodiscard]] inline const std::string &getTemplate() const;
3638 [[nodiscard]] inline const std::string &getType() const;
3639 [[nodiscard]] inline bool isVisible() const;
3640 [[nodiscard]] inline const Vector2i &getPosition() const;
3641
3642 [[nodiscard]] inline const std::vector<tson::Vector2i> &getPolygons() const;
3643 [[nodiscard]] inline const std::vector<tson::Vector2i> &getPolylines() const;
3644 [[nodiscard]] inline PropertyCollection &getProperties();
3645 [[nodiscard]] inline const Text &getText() const;
3646
3647 template <typename T>
3648 inline T get(const std::string &name);
3649 inline tson::Property * getProp(const std::string &name);
3650
3651 //v1.2.0-stuff
3652 [[nodiscard]] inline TileFlipFlags getFlipFlags() const;
3653 inline bool hasFlipFlags(TileFlipFlags flags);
3654
3655 private:
3656 inline void setObjectTypeByJson(IJson &json);
3657
3658 ObjectType m_objectType = ObjectType::Undefined; /*! Says with object type this is */
3659 bool m_ellipse {}; /*! 'ellipse': Used to mark an object as an ellipse */
3660 uint32_t m_gid {}; /*! 'gid': GID, only if object comes from a Tilemap */
3661 tson::Vector2i m_size; /*! x = 'width' (Width in pixels), y = 'height' (Height in pixels). Ignored if using a gid.)*/
3662 int m_id{}; /*! 'id': Incremental id - unique across all objects */
3663 std::string m_name; /*! 'name': String assigned to name field in editor*/
3664 bool m_point {}; /*! 'point': Used to mark an object as a point */
3665 std::vector<tson::Vector2i> m_polygon; /*! 'polygon': A list of x,y coordinates in pixels */
3666 std::vector<tson::Vector2i> m_polyline; /*! 'polyline': A list of x,y coordinates in pixels */
3667 tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */
3668 float m_rotation {}; /*! 'rotation': Angle in degrees clockwise */
3669 std::string m_template; /*! 'template': Reference to a template file, in case object is a template instance */
3670 tson::Text m_text; /*! first: 'text' second: 'wrap' */
3671 std::string m_type; /*! 'type': String assigned to type field in editor */
3672 bool m_visible {}; /*! 'visible': Whether object is shown in editor. */
3673 tson::Vector2i m_position; /*! 'x' and 'y': coordinate in pixels */
3674
3675 //v1.2.0-stuff
3676 tson::TileFlipFlags m_flipFlags = TileFlipFlags::None; /*! Resolved using bit 32, 31 and 30 from gid */
3677 };
3678
3679 /*!
3680 * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>")
3681 * @tparam T The template value
3682 * @param name Name of the property
3683 * @return The actual value, if it exists. Otherwise: The default value of the type.
3684 */
3685 template<typename T>
3686 T tson::Object::get(const std::string &name)
3687 {
3688 return m_properties.getValue<T>(name);
3689 }
3690}
3691
3692/*!
3693 * Parses a json Tiled object
3694 * @param json
3695 */
3696tson::Object::Object(IJson &json)
3697{
3698 parse(json);
3699}
3700
3701/*!
3702 * Parses a json Tiled object and autoamtically determines the object type based on the data presented.
3703 * Call getObjectType() to see what object type it is.
3704 * @param json
3705 * @return true if all mandatory fields was found. false otherwise.
3706 */
3707bool tson::Object::parse(IJson &json)
3708{
3709 bool allFound = true;
3710
3711 if(json.count("ellipse") > 0) m_ellipse = json["ellipse"].get<bool>(); //Optional
3712 if(json.count("gid") > 0)
3713 {
3714 uint32_t gid = json["gid"].get<uint32_t>(); //Optional
3715 if (gid & FLIPPED_HORIZONTALLY_FLAG) m_flipFlags |= TileFlipFlags::Horizontally;
3716 if (gid & FLIPPED_VERTICALLY_FLAG) m_flipFlags |= TileFlipFlags::Vertically;
3717 if (gid & FLIPPED_DIAGONALLY_FLAG) m_flipFlags |= TileFlipFlags::Diagonally;
3718
3719 // Clear flags
3720 gid &= ~(FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG);
3721
3722 m_gid = gid;
3723 }
3724 if(json.count("id") > 0) m_id = json["id"].get<int>(); else allFound = false;
3725 if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false;
3726 if(json.count("point") > 0) m_point = json["point"].get<bool>(); //Optional
3727 if(json.count("rotation") > 0) m_rotation = json["rotation"].get<float>(); else allFound = false;
3728 if(json.count("template") > 0) m_template = json["template"].get<std::string>(); //Optional
3729 if(json.count("type") > 0) m_type = json["type"].get<std::string>(); else allFound = false;
3730 if(json.count("visible") > 0) m_visible = json["visible"].get<bool>(); else allFound = false;
3731
3732 if(json.count("width") > 0 && json.count("height") > 0)
3733 m_size = {json["width"].get<int>(), json["height"].get<int>()}; else allFound = false;
3734 if(json.count("x") > 0 && json.count("y") > 0)
3735 m_position = {json["x"].get<int>(), json["y"].get<int>()}; else allFound = false;
3736
3737 if(json.count("text") > 0)
3738 {
3739 bool hasColor = json["text"].count("color") > 0;
3740 tson::Color c = (hasColor) ? tson::Colori(json["text"]["color"].get<std::string>()) : tson::Colori();
3741 m_text = {json["text"]["text"].get<std::string>(), json["text"]["wrap"].get<bool>(), c}; //Optional
3742 }
3743
3744 setObjectTypeByJson(json);
3745
3746 if(m_objectType == ObjectType::Template)
3747 allFound = true; //Just accept anything with this type
3748
3749 //More advanced data
3750 if(json.count("polygon") > 0 && json["polygon"].isArray())
3751 {
3752 auto &polygon = json.array("polygon");
3753 std::for_each(polygon.begin(), polygon.end(),[&](std::unique_ptr<IJson> &item)
3754 {
3755 IJson &j = *item;
3756 m_polygon.emplace_back(j["x"].get<int>(), j["y"].get<int>());
3757 });
3758
3759 }
3760
3761 if(json.count("polyline") > 0 && json["polyline"].isArray())
3762 {
3763 auto &polyline = json.array("polyline");
3764 std::for_each(polyline.begin(), polyline.end(),[&](std::unique_ptr<IJson> &item)
3765 {
3766 IJson &j = *item;
3767 m_polyline.emplace_back(j["x"].get<int>(), j["y"].get<int>());
3768 });
3769 }
3770
3771 if(json.count("properties") > 0 && json["properties"].isArray())
3772 {
3773 auto &properties = json.array("properties");
3774 std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item)
3775 {
3776 m_properties.add(*item);
3777 });
3778 }
3779
3780 return allFound;
3781}
3782
3783/*!
3784 * Sets an object type based on json data.
3785 * @param json
3786 */
3787void tson::Object::setObjectTypeByJson(IJson &json)
3788{
3789 m_objectType = ObjectType::Undefined;
3790 if(m_ellipse)
3791 m_objectType = ObjectType::Ellipse;
3792 else if(m_point)
3793 m_objectType = ObjectType::Point;
3794 else if(json.count("polygon") > 0)
3795 m_objectType = ObjectType::Polygon;
3796 else if(json.count("polyline") > 0)
3797 m_objectType = ObjectType::Polyline;
3798 else if(json.count("text") > 0)
3799 m_objectType = ObjectType::Text;
3800 else if(json.count("gid") > 0)
3801 m_objectType = ObjectType::Object;
3802 else if(json.count("template") > 0)
3803 m_objectType = ObjectType::Template;
3804 else
3805 m_objectType = ObjectType::Rectangle;
3806}
3807
3808/*!
3809 * Gets what type of object this is.
3810 * @return
3811 */
3812
3813tson::ObjectType tson::Object::getObjectType() const
3814{
3815 return m_objectType;
3816}
3817
3818/*!
3819 * 'ellipse': Used to mark an object as an ellipse
3820 * @return
3821 */
3822bool tson::Object::isEllipse() const
3823{
3824 return m_ellipse;
3825}
3826
3827/*!
3828 * 'gid': GID, only if object comes from a Tilemap
3829 * @return
3830 */
3831uint32_t tson::Object::getGid() const
3832{
3833 return m_gid;
3834}
3835
3836/*!
3837 * x = 'width' (Width in pixels), y = 'height' (Height in pixels). Ignored if using a gid.)
3838 * @return
3839 */
3840const tson::Vector2i &tson::Object::getSize() const
3841{
3842 return m_size;
3843}
3844
3845/*!
3846 * 'id': Incremental id - unique across all objects
3847 * @return
3848 */
3849int tson::Object::getId() const
3850{
3851 return m_id;
3852}
3853
3854/*!
3855 * 'name': String assigned to name field in editor
3856 * @return
3857 */
3858const std::string &tson::Object::getName() const
3859{
3860 return m_name;
3861}
3862
3863/*!
3864 * 'point': Used to mark an object as a point
3865 * @return true if the object is of type point
3866 */
3867bool tson::Object::isPoint() const
3868{
3869 return m_point;
3870}
3871
3872/*!
3873 * 'rotation': Angle in degrees clockwise
3874 * @return
3875 */
3876float tson::Object::getRotation() const
3877{
3878 return m_rotation;
3879}
3880
3881/*!
3882 * 'template': Reference to a template file, in case object is a template instance
3883 * @return
3884 */
3885const std::string &tson::Object::getTemplate() const
3886{
3887 return m_template;
3888}
3889
3890/*!
3891 * 'type': String assigned to type field in editor
3892 * @return
3893 */
3894const std::string &tson::Object::getType() const
3895{
3896 return m_type;
3897}
3898
3899/*!
3900 * 'visible': Whether object is shown in editor.
3901 * @return
3902 */
3903bool tson::Object::isVisible() const
3904{
3905 return m_visible;
3906}
3907
3908/*!
3909 * 'x' and 'y': coordinate in pixels
3910 * @return
3911 */
3912const tson::Vector2i &tson::Object::getPosition() const
3913{
3914 return m_position;
3915}
3916
3917/*!
3918 * 'polygon': A list of x,y coordinates in pixels.
3919 * If this is a Polygon type, this function will return the points used to create it
3920 * @return
3921 */
3922const std::vector<tson::Vector2i> &tson::Object::getPolygons() const
3923{
3924 return m_polygon;
3925}
3926
3927/*!
3928 * 'polyline': A list of x,y coordinates in pixels
3929 * If this is a Polyline type, this function will return the points used to create it
3930 * @return
3931 */
3932const std::vector<tson::Vector2i> &tson::Object::getPolylines() const
3933{
3934 return m_polyline;
3935}
3936
3937/*!
3938 * 'properties': A list of properties (name, value, type).
3939 * @return
3940 */
3941tson::PropertyCollection &tson::Object::getProperties()
3942{
3943 return m_properties;
3944}
3945
3946/*!
3947 * 'type': String assigned to type field in editor
3948 * @return
3949 */
3950const tson::Text &tson::Object::getText() const
3951{
3952 return m_text;
3953}
3954
3955/*!
3956 * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>");
3957 * @param name Name of the property
3958 * @return
3959 */
3960tson::Property *tson::Object::getProp(const std::string &name)
3961{
3962 if(m_properties.hasProperty(name))
3963 return m_properties.getProperty(name);
3964 return nullptr;
3965}
3966
3967/*!
3968 * Get all flip flags
3969 * @return
3970 */
3971tson::TileFlipFlags tson::Object::getFlipFlags() const
3972{
3973 return m_flipFlags;
3974}
3975
3976/*!
3977 *
3978 * @param flags Which flags to check for. Several flags can be checked at once using the bitwise or operator.
3979 * Example:
3980 * hasFlipFlags(TileFlipFlags::Vertically | TileFlipFlags::Horizontally)
3981 *
3982 * @return true if the flag(s) specified are set
3983 */
3984bool tson::Object::hasFlipFlags(TileFlipFlags flags)
3985{
3986 return ((m_flipFlags & flags) == flags) ? true : false;
3987}
3988
3989#endif //TILESON_OBJECT_HPP
3990
3991/*** End of inlined file: Object.hpp ***/
3992
3993
3994/*** Start of inlined file: TileObject.hpp ***/
3995//
3996// Created by robin on 26.07.2020.
3997//
3998
3999#ifndef TILESON_TILEOBJECT_HPP
4000#define TILESON_TILEOBJECT_HPP
4001
4002
4003/*** Start of inlined file: Rect.hpp ***/
4004//
4005// Created by robin on 24.07.2020.
4006//
4007
4008#ifndef TILESON_RECT_HPP
4009#define TILESON_RECT_HPP
4010
4011namespace tson
4012{
4013 class Rect
4014 {
4015 public:
4016
4017 inline Rect();
4018 inline Rect(int x_, int y_, int width_, int height_);
4019
4020 inline bool operator==(const Rect &rhs) const;
4021 inline bool operator!=(const Rect &rhs) const;
4022
4023 int x;
4024 int y;
4025 int width;
4026 int height;
4027 };
4028
4029 Rect::Rect()
4030 {
4031
4032 }
4033
4034 Rect::Rect(int x_, int y_, int width_, int height_)
4035 {
4036 x = x_;
4037 y = y_;
4038 width = width_;
4039 height = height_;
4040 }
4041
4042 bool Rect::operator==(const Rect &rhs) const
4043 {
4044 return x == rhs.x &&
4045 y == rhs.y &&
4046 width == rhs.width &&
4047 height == rhs.height;
4048 }
4049
4050 bool Rect::operator!=(const Rect &rhs) const
4051 {
4052 return !(rhs == *this);
4053 }
4054}
4055
4056#endif //TILESON_RECT_HPP
4057
4058/*** End of inlined file: Rect.hpp ***/
4059
4060namespace tson
4061{
4062 class Tile;
4063 class TileObject
4064 {
4065 public:
4066 inline TileObject() = default;
4067 inline TileObject(const std::tuple<int, int> &posInTileUnits, tson::Tile *tile);
4068
4069 inline void initialize(const std::tuple<int, int> &posInTileUnits, tson::Tile *tile); //Defined in tileson_forward.hpp
4070
4071 inline Tile *getTile() const;
4072 inline const Vector2i &getPositionInTileUnits() const;
4073 inline const Vector2f &getPosition() const;
4074 inline const tson::Rect &getDrawingRect() const; //Defined in tileson_forward.hpp
4075
4076 private:
4077 tson::Tile *m_tile;
4078 tson::Vector2i m_posInTileUnits;
4079 tson::Vector2f m_position;
4080
4081 };
4082
4083 TileObject::TileObject(const std::tuple<int, int> &posInTileUnits, tson::Tile *tile)
4084 {
4085 initialize(posInTileUnits, tile);
4086 }
4087
4088 /*!
4089 * Get a pointer to the related tile
4090 * @return
4091 */
4092 Tile *TileObject::getTile() const
4093 {
4094 return m_tile;
4095 }
4096
4097 /*!
4098 * Gets the position of the tile in tile units
4099 * @return
4100 */
4101 const Vector2i &TileObject::getPositionInTileUnits() const
4102 {
4103 return m_posInTileUnits;
4104 }
4105
4106 /*!
4107 * Gets the position of the tile in pixels.
4108 * @return
4109 */
4110 const Vector2f &TileObject::getPosition() const
4111 {
4112 return m_position;
4113 }
4114}
4115
4116#endif //TILESON_TILEOBJECT_HPP
4117
4118/*** End of inlined file: TileObject.hpp ***/
4119
4120
4121/*** Start of inlined file: FlaggedTile.hpp ***/
4122//
4123// Created by robin on 13.11.2020.
4124//
4125
4126#ifndef TILESON_FLAGGEDTILE_HPP
4127#define TILESON_FLAGGEDTILE_HPP
4128
4129namespace tson
4130{
4131 class FlaggedTile
4132 {
4133
4134 public:
4135 FlaggedTile(size_t x_, size_t y_, uint32_t id_, uint32_t tileId_) : x {x_}, y {y_}, id {id_}, tileId {tileId_}
4136 {
4137
4138 }
4139 size_t x;
4140 size_t y;
4141 /*! Full ID, including flag */
4142 uint32_t id;
4143 /*! ID of the flagged tile */
4144 uint32_t tileId;
4145 };
4146}
4147#endif //TILESON_FLAGGEDTILE_HPP
4148
4149/*** End of inlined file: FlaggedTile.hpp ***/
4150
4151namespace tson
4152{
4153 class Tile;
4154 class Map;
4155
4156 class Layer
4157 {
4158 public:
4159 inline Layer() = default;
4160 inline Layer(IJson &json, tson::Map *map);
4161 inline bool parse(IJson &json, tson::Map *map);
4162
4163 [[nodiscard]] inline const std::string &getCompression() const;
4164 [[nodiscard]] inline const std::vector<uint32_t> &getData() const;
4165 [[nodiscard]] inline const std::string &getBase64Data() const;
4166 [[nodiscard]] inline const std::string &getDrawOrder() const;
4167 [[nodiscard]] inline const std::string &getEncoding() const;
4168 [[nodiscard]] inline int getId() const;
4169 [[nodiscard]] inline const std::string &getImage() const;
4170 [[nodiscard]] inline const std::string &getName() const;
4171 [[nodiscard]] inline const Vector2f &getOffset() const;
4172 [[nodiscard]] inline float getOpacity() const;
4173 [[nodiscard]] inline const Vector2i &getSize() const;
4174 [[nodiscard]] inline const Colori &getTransparentcolor() const;
4175
4176 [[nodiscard]] inline LayerType getType() const;
4177
4178 [[nodiscard]] inline const std::string &getTypeStr() const;
4179 [[nodiscard]] inline bool isVisible() const;
4180 [[nodiscard]] inline int getX() const;
4181 [[nodiscard]] inline int getY() const;
4182
4183 [[nodiscard]] inline std::vector<tson::Chunk> &getChunks();
4184 [[nodiscard]] inline std::vector<tson::Layer> &getLayers();
4185 [[nodiscard]] inline std::vector<tson::Object> &getObjects();
4186 [[nodiscard]] inline PropertyCollection &getProperties();
4187
4188 inline tson::Object *getObj(int id);
4189 inline tson::Object *firstObj(const std::string &name);
4190 inline std::vector<tson::Object> getObjectsByName(const std::string &name);
4191 inline std::vector<tson::Object> getObjectsByType(tson::ObjectType type);
4192
4193 template <typename T>
4194 inline T get(const std::string &name);
4195 inline tson::Property * getProp(const std::string &name);
4196
4197 inline void assignTileMap(std::map<uint32_t, tson::Tile*> *tileMap);
4198 inline void createTileData(const Vector2i &mapSize, bool isInfiniteMap);
4199
4200 [[nodiscard]] inline const std::map<std::tuple<int, int>, tson::Tile *> &getTileData() const;
4201 inline tson::Tile * getTileData(int x, int y);
4202
4203 //v1.2.0-stuff
4204 [[nodiscard]] inline const Colori &getTintColor() const;
4205 [[nodiscard]] inline tson::Map *getMap() const;
4206
4207 [[nodiscard]] inline const std::map<std::tuple<int, int>, tson::TileObject> &getTileObjects() const;
4208 inline tson::TileObject * getTileObject(int x, int y);
4209 [[nodiscard]] inline const std::set<uint32_t> &getUniqueFlaggedTiles() const;
4210 inline void resolveFlaggedTiles();
4211
4212 private:
4213 inline void setTypeByString();
4214
4215 std::vector<tson::Chunk> m_chunks; /*! 'chunks': Array of chunks (optional). tilelayer only. */
4216 std::string m_compression; /*! 'compression': zlib, gzip or empty (default). tilelayer only. */
4217 std::vector<uint32_t> m_data; /*! 'data' (when uint array): Array of unsigned int (GIDs) or base64-encoded
4218 * data. tilelayer only. */
4219 std::string m_base64Data; /*! 'data' (when string): Array of unsigned int (GIDs) or base64-encoded
4220 * data. tilelayer only. */
4221 std::string m_drawOrder; /*! 'draworder': topdown (default) or index. objectgroup only. */
4222 std::string m_encoding; /*! 'encoding': csv (default) or base64. tilelayer only. */
4223 int m_id{}; /*! 'id': Incremental id - unique across all layers */
4224 std::string m_image; /*! 'image': Image used by this layer. imagelayer only. */
4225 std::vector<tson::Layer> m_layers; /*! 'layers': Array of layers. group on */
4226 std::string m_name; /*! 'name': Name assigned to this layer */
4227 std::vector<tson::Object> m_objects; /*! 'objects': Array of objects. objectgroup only. */
4228 tson::Vector2f m_offset; /*! 'offsetx' and 'offsety': Horizontal and Vertical layer offset in pixels
4229 * (default: {0, 0}) */
4230 float m_opacity{}; /*! 'opacity': Value between 0 and 1 */
4231 tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */
4232 tson::Vector2i m_size; /*! x = 'width': (Column count. Same as map width for fixed-size maps.)
4233 y = 'height': Row count. Same as map height for fixed-size maps. */
4234 tson::Colori m_transparentcolor; /*! 'transparentcolor': Hex-formatted color (#RRGGBB) (optional, imagelayer only */
4235 std::string m_typeStr; /*! 'type': tilelayer, objectgroup, imagelayer or group */
4236 LayerType m_type {LayerType::Undefined}; /*! Layer type as enum*/
4237 bool m_visible{}; /*! 'visible': Whether layer is shown or hidden in editor */
4238 int m_x{}; /*! 'x': Horizontal layer offset in tiles. Always 0. */
4239 int m_y{}; /*! 'y': Vertical layer offset in tiles. Always 0. */
4240
4241 std::map<uint32_t, tson::Tile*> *m_tileMap;
4242 std::map<std::tuple<int, int>, tson::Tile*> m_tileData; /*! Key: Tuple of x and y pos in tile units. */
4243
4244 //v1.2.0-stuff
4245 tson::Colori m_tintcolor; /*! 'tintcolor': Hex-formatted color (#RRGGBB or #AARRGGBB) that is multiplied with
4246 * any graphics drawn by this layer or any child layers (optional). */
4247 inline void decompressData(); /*! Defined in tileson_forward.hpp */
4248 inline void queueFlaggedTile(size_t x, size_t y, uint32_t id); /*! Queue a flagged tile */
4249
4250 tson::Map * m_map; /*! The map who owns this layer */
4251 std::map<std::tuple<int, int>, tson::TileObject> m_tileObjects;
4252 std::set<uint32_t> m_uniqueFlaggedTiles;
4253 std::vector<tson::FlaggedTile> m_flaggedTiles;
4254
4255 };
4256
4257 /*!
4258 * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>")
4259 * @tparam T The template value
4260 * @param name Name of the property
4261 * @return The actual value, if it exists. Otherwise: The default value of the type.
4262 */
4263 template<typename T>
4264 T Layer::get(const std::string &name)
4265 {
4266 return m_properties.getValue<T>(name);
4267 }
4268}
4269
4270/*!
4271 * Parses a Tiled layer from json
4272 * @param json
4273 */
4274tson::Layer::Layer(IJson &json, tson::Map *map)
4275{
4276 parse(json, map);
4277}
4278
4279void tson::Layer::queueFlaggedTile(size_t x, size_t y, uint32_t id)
4280{
4281 uint32_t tileId = id;
4282 tileId &= ~(FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG);
4283 m_uniqueFlaggedTiles.insert(id);
4284 m_flaggedTiles.emplace_back(x, y, id, tileId);
4285}
4286
4287/*!
4288 * Parses a Tiled layer from json
4289 * @param json
4290 * @return true if all mandatory fields was found. false otherwise.
4291 */
4292bool tson::Layer::parse(IJson &json, tson::Map *map)
4293{
4294 m_map = map;
4295
4296 bool allFound = true;
4297 if(json.count("tintcolor") > 0) m_tintcolor = tson::Colori(json["tintcolor"].get<std::string>()); //Optional
4298 if(json.count("compression") > 0) m_compression = json["compression"].get<std::string>(); //Optional
4299 if(json.count("draworder") > 0) m_drawOrder = json["draworder"].get<std::string>(); //Optional
4300 if(json.count("encoding") > 0) m_encoding = json["encoding"].get<std::string>(); //Optional
4301 if(json.count("id") > 0) m_id = json["id"].get<int>(); //Optional
4302 if(json.count("image") > 0) m_image = json["image"].get<std::string>(); //Optional
4303 if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false;
4304 if(json.count("offsetx") > 0 && json.count("offsety") > 0)
4305 m_offset = {json["offsetx"].get<float>(), json["offsety"].get<float>()}; //Optional
4306 if(json.count("opacity") > 0) m_opacity = json["opacity"].get<float>(); else allFound = false;
4307 if(json.count("width") > 0 && json.count("height") > 0)
4308 m_size = {json["width"].get<int>(), json["height"].get<int>()}; //else allFound = false; - Not mandatory for all layers!
4309 if(json.count("transparentcolor") > 0) m_transparentcolor = tson::Colori(json["transparentcolor"].get<std::string>()); //Optional
4310 if(json.count("type") > 0) m_typeStr = json["type"].get<std::string>(); else allFound = false;
4311 if(json.count("visible") > 0) m_visible = json["visible"].get<bool>(); else allFound = false;
4312 if(json.count("x") > 0) m_x = json["x"].get<int>(); else allFound = false;
4313 if(json.count("y") > 0) m_y = json["y"].get<int>(); else allFound = false;
4314
4315 //Handle DATA (Optional)
4316 if(json.count("data") > 0)
4317 {
4318 if(json["data"].isArray())
4319 {
4320 auto &array = json.array("data");
4321 std::for_each(array.begin(), array.end(), [&](std::unique_ptr<IJson> &item) { m_data.push_back(item->get<uint32_t>()); });
4322 }
4323 else
4324 {
4325 m_base64Data = json["data"].get<std::string>();
4326 decompressData();
4327 }
4328 }
4329
4330 //More advanced data
4331 if(json.count("chunks") > 0 && json["chunks"].isArray())
4332 {
4333 auto &chunks = json.array("chunks");
4334 std::for_each(chunks.begin(), chunks.end(), [&](std::unique_ptr<IJson> &item) { m_chunks.emplace_back(*item); });
4335 }
4336 if(json.count("layers") > 0 && json["layers"].isArray())
4337 {
4338 auto &layers = json.array("layers");
4339 std::for_each(layers.begin(), layers.end(), [&](std::unique_ptr<IJson> &item) { m_layers.emplace_back(*item, m_map); });
4340 }
4341 if(json.count("objects") > 0 && json["objects"].isArray())
4342 {
4343 auto &objects = json.array("objects");
4344 std::for_each(objects.begin(), objects.end(), [&](std::unique_ptr<IJson> &item) { m_objects.emplace_back(*item); });
4345 }
4346 if(json.count("properties") > 0 && json["properties"].isArray())
4347 {
4348 auto &properties = json.array("properties");
4349 std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item); });
4350 }
4351
4352 setTypeByString();
4353
4354 return allFound;
4355}
4356
4357/*!
4358 * Copies all objects with a name that equals the parameter
4359 * @param name Name of the objects to return
4360 * @return All objects with a matching name
4361 */
4362std::vector<tson::Object> tson::Layer::getObjectsByName(const std::string &name)
4363{
4364 std::vector<tson::Object> found;
4365
4366 std::copy_if(m_objects.begin(), m_objects.end(), std::back_inserter(found), [&](const tson::Object &item)
4367 {
4368 return item.getName() == name;
4369 });
4370
4371 return found;
4372}
4373
4374/*!
4375 * Copies all objects with a type that equals the parameter
4376 * @param type LayerType of the objects to return
4377 * @return All objects with a matching type
4378 */
4379std::vector<tson::Object> tson::Layer::getObjectsByType(tson::ObjectType type)
4380{
4381 std::vector<tson::Object> found;
4382
4383 std::copy_if(m_objects.begin(), m_objects.end(), std::back_inserter(found), [&](const tson::Object &item)
4384 {
4385 return item.getObjectType() == type;
4386 });
4387
4388 return found;
4389}
4390
4391/*!
4392 * Returns the first object with the given name
4393 * @param name Name of the object to find.
4394 * @return A pointer to the object if found. nullptr otherwise.
4395 */
4396tson::Object *tson::Layer::firstObj(const std::string &name)
4397{
4398 auto result = std::find_if(m_objects.begin(), m_objects.end(), [&](const tson::Object &obj){return obj.getName() == name; });
4399 if(result == m_objects.end())
4400 return nullptr;
4401
4402 return &result.operator*();
4403}
4404
4405/*!
4406 * Get an object by ID
4407 * @param id Unique ID of the object
4408 * @return A pointer to the object if found. nullptr otherwise.
4409 */
4410tson::Object *tson::Layer::getObj(int id)
4411{
4412 auto result = std::find_if(m_objects.begin(), m_objects.end(), [&](const tson::Object &obj){return obj.getId() == id; });
4413 if(result == m_objects.end())
4414 return nullptr;
4415
4416 return &result.operator*();
4417}
4418
4419/*!
4420 * Set type by string
4421 * tilelayer, objectgroup, imagelayer or group
4422 */
4423void tson::Layer::setTypeByString()
4424{
4425 if(m_typeStr == "tilelayer") m_type = LayerType::TileLayer;
4426 else if(m_typeStr == "objectgroup") m_type = LayerType::ObjectGroup;
4427 else if(m_typeStr == "imagelayer") m_type = LayerType::ImageLayer;
4428 else if(m_typeStr == "group") m_type = LayerType::Group;
4429 else m_type = LayerType::Undefined;
4430}
4431
4432/*!
4433 * 'compression': zlib, gzip or empty (default). tilelayer only.
4434 * @return
4435 */
4436const std::string &tson::Layer::getCompression() const
4437{
4438 return m_compression;
4439}
4440
4441/*!
4442 * 'data' (when uint array): Array of unsigned int (GIDs) or base64-encoded data. tilelayer only.
4443 * @return
4444 */
4445const std::vector<uint32_t> &tson::Layer::getData() const
4446{
4447 return m_data;
4448}
4449
4450/*!
4451 * 'data' (when string): Array of unsigned int (GIDs) or base64-encoded data. tilelayer only.
4452 * @return
4453 */
4454const std::string &tson::Layer::getBase64Data() const
4455{
4456 return m_base64Data;
4457}
4458
4459/*!
4460 * 'draworder': topdown (default) or index. objectgroup only.
4461 * @return
4462 */
4463const std::string &tson::Layer::getDrawOrder() const
4464{
4465 return m_drawOrder;
4466}
4467
4468/*!
4469 * 'encoding': csv (default) or base64. tilelayer only.
4470 * @return
4471 */
4472const std::string &tson::Layer::getEncoding() const
4473{
4474 return m_encoding;
4475}
4476
4477/*!
4478 * 'id': Incremental id - unique across all layers
4479 * @return
4480 */
4481int tson::Layer::getId() const
4482{
4483 return m_id;
4484}
4485
4486/*!
4487 * 'image': Image used by this layer. imagelayer only.
4488 * @return
4489 */
4490const std::string &tson::Layer::getImage() const
4491{
4492 return m_image;
4493}
4494
4495/*!
4496 * 'name': Name assigned to this layer
4497 * @return
4498 */
4499const std::string &tson::Layer::getName() const
4500{
4501 return m_name;
4502}
4503
4504/*!
4505 * 'offsetx' and 'offsety': Horizontal and Vertical layer offset in pixels (default: {0, 0})
4506 * @return
4507 */
4508const tson::Vector2f &tson::Layer::getOffset() const
4509{
4510 return m_offset;
4511}
4512
4513/*!
4514 * 'opacity': Value between 0 and 1
4515 * @return
4516 */
4517float tson::Layer::getOpacity() const
4518{
4519 return m_opacity;
4520}
4521
4522/*!
4523 * x = 'width': (Column count. Same as map width for fixed-size maps.)
4524 * y = 'height': Row count. Same as map height for fixed-size maps.
4525 * @return width and height as a single size
4526 */
4527const tson::Vector2i &tson::Layer::getSize() const
4528{
4529 return m_size;
4530}
4531
4532/*!
4533 * 'transparentcolor': Color created from a hex color (#RRGGBB) (optional, imagelayer only)
4534 * @return color as color object with rgba channel.
4535 */
4536const tson::Colori &tson::Layer::getTransparentcolor() const
4537{
4538 return m_transparentcolor;
4539}
4540
4541/*!
4542 * 'type': tilelayer, objectgroup, imagelayer or group
4543 * @return string with the object type
4544 */
4545const std::string &tson::Layer::getTypeStr() const
4546{
4547 return m_typeStr;
4548}
4549
4550/*!
4551 * 'visible': Whether layer is shown or hidden in editor
4552 * @return
4553 */
4554bool tson::Layer::isVisible() const
4555{
4556 return m_visible;
4557}
4558
4559/*!
4560 * 'x': Horizontal layer offset in tiles. Always 0.
4561 * @return x value (always 0 for layer)
4562 */
4563int tson::Layer::getX() const
4564{
4565 return m_x;
4566}
4567
4568/*!
4569 * 'y': Horizontal layer offset in tiles. Always 0.
4570 * @return y value (always 0 for layer)
4571 */
4572int tson::Layer::getY() const
4573{
4574 return m_y;
4575}
4576
4577/*!
4578 * 'chunks': Array of chunks (optional). tilelayer only.
4579 * @return
4580 */
4581std::vector<tson::Chunk> &tson::Layer::getChunks()
4582{
4583 return m_chunks;
4584}
4585
4586/*!
4587 * 'layers': Array of layers. group on
4588 * @return
4589 */
4590std::vector<tson::Layer> &tson::Layer::getLayers()
4591{
4592 return m_layers;
4593}
4594
4595/*!
4596 * 'objects': Array of objects. objectgroup only.
4597 * @return
4598 */
4599std::vector<tson::Object> &tson::Layer::getObjects()
4600{
4601 return m_objects;
4602}
4603
4604/*!
4605 * 'properties': A list of properties (name, value, type).
4606 * @return
4607 */
4608tson::PropertyCollection &tson::Layer::getProperties()
4609{
4610 return m_properties;
4611}
4612
4613/*!
4614 * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>");
4615 * @param name Name of the property
4616 * @return
4617 */
4618tson::Property *tson::Layer::getProp(const std::string &name)
4619{
4620 if(m_properties.hasProperty(name))
4621 return m_properties.getProperty(name);
4622 return nullptr;
4623}
4624
4625/*!
4626 * Get layer type
4627 * @return Layer type as enum
4628 */
4629tson::LayerType tson::Layer::getType() const
4630{
4631 return m_type;
4632}
4633
4634/*!
4635 * Assigns a tilemap of pointers to existing tiles.
4636 * @param tileMap The tilemap. key: tile id, value: pointer to Tile.
4637 */
4638void tson::Layer::assignTileMap(std::map<uint32_t, tson::Tile *> *tileMap)
4639{
4640 m_tileMap = tileMap;
4641}
4642
4643/*!
4644 * Get tile data as some kind of map with x and y position with pointers to existing tiles.
4645 * Map only contains tiles that are not empty. x and y position is in tile units.
4646 *
4647 * Example of getting tile from the returned map:
4648 *
4649 * Tile *tile = tileData[{0, 4}];
4650 *
4651 * @return A map that represents the data returned from getData() in a 2D map with Tile pointers.
4652 */
4653const std::map<std::tuple<int, int>, tson::Tile *> &tson::Layer::getTileData() const
4654{
4655 return m_tileData;
4656}
4657
4658/*!
4659 * A safe way to get tile data
4660 * Get tile data as some kind of map with x and y position with pointers to existing tiles.
4661 * Map only contains tiles that are not empty. x and y position is in tile units.
4662 *
4663 * Example of getting tile:
4664 * Tile *tile = layer->getTileData(0, 4)
4665 *
4666 * @param x X position in tile units
4667 * @param y Y position in tile units
4668 * @return pointer to tile, if it exists. nullptr otherwise.
4669 */
4670tson::Tile *tson::Layer::getTileData(int x, int y)
4671{
4672 return (m_tileData.count({x, y}) > 0) ? m_tileData[{x,y}] : nullptr;
4673}
4674
4675/*!
4676 * Used for getting the tson::Map who is the parent of this Layer.
4677 * @return a pointer to the tson::Map where this layer is contained.
4678 */
4679tson::Map *tson::Layer::getMap() const
4680{
4681 return m_map;
4682}
4683
4684/*!
4685 *
4686 * This is only supported for non-infinite maps!
4687 *
4688 * @param mapSize The size of the map
4689 * @param isInfiniteMap Whether or not the current map is infinte.
4690 */
4691void tson::Layer::createTileData(const Vector2i &mapSize, bool isInfiniteMap)
4692{
4693 size_t x = 0;
4694 size_t y = 0;
4695 if(!isInfiniteMap)
4696 {
4697 std::for_each(m_data.begin(), m_data.end(), [&](uint32_t tileId)
4698 {
4699 if (x == mapSize.x)
4700 {
4701 ++y;
4702 x = 0;
4703 }
4704
4705 if (tileId > 0 && m_tileMap->count(tileId) > 0)
4706 {
4707 m_tileData[{x, y}] = m_tileMap->at(tileId);
4708 m_tileObjects[{x, y}] = {{x, y}, m_tileData[{x, y}]};
4709 }
4710 else if(tileId > 0 && m_tileMap->count(tileId) == 0) //Tile with flip flags!
4711 {
4712 queueFlaggedTile(x, y, tileId);
4713 }
4714 x++;
4715 });
4716
4717 }
4718}
4719
4720const std::map<std::tuple<int, int>, tson::TileObject> &tson::Layer::getTileObjects() const
4721{
4722 return m_tileObjects;
4723}
4724
4725tson::TileObject *tson::Layer::getTileObject(int x, int y)
4726{
4727 return (m_tileObjects.count({x, y}) > 0) ? &m_tileObjects[{x,y}] : nullptr;
4728}
4729
4730const std::set<uint32_t> &tson::Layer::getUniqueFlaggedTiles() const
4731{
4732 return m_uniqueFlaggedTiles;
4733}
4734
4735void tson::Layer::resolveFlaggedTiles()
4736{
4737 std::for_each(m_flaggedTiles.begin(), m_flaggedTiles.end(), [&](const tson::FlaggedTile &tile)
4738 {
4739 if (tile.id > 0 && m_tileMap->count(tile.id) > 0)
4740 {
4741 m_tileData[{tile.x, tile.y}] = m_tileMap->at(tile.id);
4742 m_tileObjects[{tile.x, tile.y}] = {{tile.x, tile.y}, m_tileData[{tile.x, tile.y}]};
4743 }
4744 });
4745}
4746
4747/*!
4748 * 'tintcolor': Hex-formatted color (#RRGGBB or #AARRGGBB) that is multiplied with any graphics drawn by this layer or any child layers (optional).
4749 *
4750 * @return tintcolor
4751 */
4752const tson::Colori &tson::Layer::getTintColor() const
4753{
4754 return m_tintcolor;
4755}
4756
4757#endif //TILESON_LAYER_HPP
4758
4759/*** End of inlined file: Layer.hpp ***/
4760
4761
4762/*** Start of inlined file: Tileset.hpp ***/
4763//
4764// Created by robin on 22.03.2020.
4765//
4766
4767#ifndef TILESON_TILESET_HPP
4768#define TILESON_TILESET_HPP
4769
4770//#include "../external/json.hpp"
4771
4772
4773/*** Start of inlined file: WangSet.hpp ***/
4774//
4775// Created by robin on 22.03.2020.
4776//
4777
4778#ifndef TILESON_WANGSET_HPP
4779#define TILESON_WANGSET_HPP
4780
4781//#include "../external/json.hpp"
4782
4783/*** Start of inlined file: WangColor.hpp ***/
4784//
4785// Created by robin on 22.03.2020.
4786//
4787
4788#ifndef TILESON_WANGCOLOR_HPP
4789#define TILESON_WANGCOLOR_HPP
4790
4791//#include "../external/json.hpp"
4792
4793namespace tson
4794{
4795 class WangColor
4796 {
4797 public:
4798 inline WangColor() = default;
4799 inline explicit WangColor(IJson &json);
4800 inline bool parse(IJson &json);
4801
4802 [[nodiscard]] inline const Colori &getColor() const;
4803 [[nodiscard]] inline const std::string &getName() const;
4804 [[nodiscard]] inline float getProbability() const;
4805 [[nodiscard]] inline int getTile() const;
4806
4807 private:
4808 tson::Colori m_color; /*! 'color': Hex-formatted color (#RRGGBB or #AARRGGBB) */
4809 std::string m_name; /*! 'name': Name of the Wang color */
4810 float m_probability{}; /*! 'probability': Probability used when randomizing */
4811 int m_tile{}; /*! 'tile': Local ID of tile representing the Wang color */
4812 };
4813}
4814
4815tson::WangColor::WangColor(IJson &json)
4816{
4817 parse(json);
4818}
4819
4820bool tson::WangColor::parse(IJson &json)
4821{
4822 bool allFound = true;
4823
4824 if(json.count("color") > 0) m_color = tson::Colori(json["color"].get<std::string>()); else allFound = false;
4825 if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false;
4826 if(json.count("probability") > 0) m_probability = json["probability"].get<float>(); else allFound = false;
4827 if(json.count("tile") > 0) m_tile = json["tile"].get<int>(); else allFound = false;
4828
4829 return allFound;
4830}
4831
4832/*!
4833 * 'color': Color object created from hex-formatted string (#RRGGBB or #AARRGGBB)
4834 * @return
4835 */
4836const tson::Colori &tson::WangColor::getColor() const
4837{
4838 return m_color;
4839}
4840
4841/*!
4842 * 'name': Name of the Wang color
4843 * @return
4844 */
4845const std::string &tson::WangColor::getName() const
4846{
4847 return m_name;
4848}
4849
4850/*!
4851 * 'probability': Probability used when randomizing
4852 * @return
4853 */
4854float tson::WangColor::getProbability() const
4855{
4856 return m_probability;
4857}
4858
4859/*!
4860 * 'tile': Local ID of tile representing the Wang color
4861 * @return
4862 */
4863int tson::WangColor::getTile() const
4864{
4865 return m_tile;
4866}
4867
4868#endif //TILESON_WANGCOLOR_HPP
4869
4870/*** End of inlined file: WangColor.hpp ***/
4871
4872
4873
4874/*** Start of inlined file: WangTile.hpp ***/
4875//
4876// Created by robin on 22.03.2020.
4877//
4878
4879#ifndef TILESON_WANGTILE_HPP
4880#define TILESON_WANGTILE_HPP
4881
4882//#include "../external/json.hpp"
4883
4884namespace tson
4885{
4886 class WangTile
4887 {
4888 public:
4889 inline WangTile() = default;
4890 inline explicit WangTile(IJson &json);
4891 inline bool parse(IJson &json);
4892
4893 [[nodiscard]] inline bool hasDFlip() const;
4894 [[nodiscard]] inline bool hasHFlip() const;
4895 [[nodiscard]] inline int getTileid() const;
4896 [[nodiscard]] inline bool hasVFlip() const;
4897
4898 [[nodiscard]] inline const std::vector<int> &getWangIds() const;
4899
4900 private:
4901 bool m_dflip{}; /*! 'dflip': Tile is flipped diagonally */
4902 bool m_hflip{}; /*! 'hflip': Tile is flipped horizontally */
4903 int m_tileid{}; /*! 'tileid': Local ID of tile */
4904 bool m_vflip{}; /*! 'vflip': Tile is flipped vertically */
4905 std::vector<int> m_wangId; /*! 'wangid': Array of Wang color indexes (uchar[8])*/
4906 };
4907}
4908
4909tson::WangTile::WangTile(IJson &json)
4910{
4911 parse(json);
4912}
4913
4914/*!
4915 * Parses a wang tile from Tiled json.
4916 * @param json A Tiled json file
4917 * @return true if all mandatory fields were found. False otherwise.
4918 */
4919bool tson::WangTile::parse(IJson &json)
4920{
4921 bool allFound = true;
4922
4923 if(json.count("dflip") > 0) m_dflip = json["dflip"].get<bool>(); else allFound = false;
4924 if(json.count("hflip") > 0) m_hflip = json["hflip"].get<bool>(); else allFound = false;
4925 if(json.count("vflip") > 0) m_vflip = json["vflip"].get<bool>(); else allFound = false;
4926 if(json.count("tileid") > 0) m_tileid = json["tileid"].get<int>(); else allFound = false;
4927
4928 if(json.count("wangid") > 0 && json["wangid"].isArray())
4929 {
4930 auto &wangid = json.array("wangid");
4931 std::for_each(wangid.begin(), wangid.end(), [&](std::unique_ptr<IJson> &item) { m_wangId.emplace_back(item->get<int>()); });
4932 }
4933
4934 return allFound;
4935}
4936
4937/*!
4938 * 'dflip': Tile is flipped diagonally
4939 * @return
4940 */
4941bool tson::WangTile::hasDFlip() const
4942{
4943 return m_dflip;
4944}
4945
4946/*!
4947 * 'hflip': Tile is flipped horizontally
4948 * @return
4949 */
4950bool tson::WangTile::hasHFlip() const
4951{
4952 return m_hflip;
4953}
4954
4955/*!
4956 * 'tileid': Local ID of tile
4957 * @return
4958 */
4959int tson::WangTile::getTileid() const
4960{
4961 return m_tileid;
4962}
4963
4964/*!
4965 * 'vflip': Tile is flipped vertically
4966 * @return
4967 */
4968bool tson::WangTile::hasVFlip() const
4969{
4970 return m_vflip;
4971}
4972
4973/*!
4974 * 'wangid': Array of Wang color indexes (uchar[8])
4975 * @return
4976 */
4977const std::vector<int> &tson::WangTile::getWangIds() const
4978{
4979 return m_wangId;
4980}
4981
4982#endif //TILESON_WANGTILE_HPP
4983
4984/*** End of inlined file: WangTile.hpp ***/
4985
4986namespace tson
4987{
4988 class WangSet
4989 {
4990 public:
4991 inline WangSet() = default;
4992 inline explicit WangSet(IJson &json);
4993 inline bool parse(IJson &json);
4994
4995 [[nodiscard]] inline const std::string &getName() const;
4996 [[nodiscard]] inline int getTile() const;
4997
4998 [[nodiscard]] inline const std::vector<tson::WangTile> &getWangTiles() const;
4999 [[nodiscard]] inline const std::vector<tson::WangColor> &getCornerColors() const;
5000 [[nodiscard]] inline const std::vector<tson::WangColor> &getEdgeColors() const;
5001
5002 inline PropertyCollection &getProperties();
5003
5004 template <typename T>
5005 inline T get(const std::string &name);
5006 inline tson::Property * getProp(const std::string &name);
5007
5008 private:
5009 std::string m_name; /*! 'name': Name of the Wang set */
5010 int m_tile{}; /*! 'tile': Local ID of tile representing the Wang set */
5011 std::vector<tson::WangTile> m_wangTiles; /*! 'wangtiles': Array of Wang tiles */
5012 std::vector<tson::WangColor> m_cornerColors; /*! 'cornercolors': Array of Wang colors */
5013 std::vector<tson::WangColor> m_edgeColors; /*! 'edgecolors': Array of Wang colors */
5014 tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */
5015
5016 };
5017
5018 /*!
5019 * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>")
5020 * @tparam T The template value
5021 * @param name Name of the property
5022 * @return The actual value, if it exists. Otherwise: The default value of the type.
5023 */
5024 template<typename T>
5025 T tson::WangSet::get(const std::string &name)
5026 {
5027 return m_properties.getValue<T>(name);
5028 }
5029}
5030
5031tson::WangSet::WangSet(IJson &json)
5032{
5033 parse(json);
5034}
5035
5036bool tson::WangSet::parse(IJson &json)
5037{
5038 bool allFound = true;
5039
5040 if(json.count("tile") > 0) m_tile = json["tile"].get<int>(); else allFound = false;
5041 if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false;
5042
5043 //More advanced data
5044 if(json.count("wangtiles") > 0 && json["wangtiles"].isArray())
5045 {
5046 auto &wangtiles = json.array("wangtiles");
5047 std::for_each(wangtiles.begin(), wangtiles.end(), [&](std::unique_ptr<IJson> &item) { m_wangTiles.emplace_back(*item); });
5048 }
5049 if(json.count("cornercolors") > 0 && json["cornercolors"].isArray())
5050 {
5051 auto &cornercolors = json.array("cornercolors");
5052 std::for_each(cornercolors.begin(), cornercolors.end(), [&](std::unique_ptr<IJson> &item) { m_cornerColors.emplace_back(*item); });
5053 }
5054 if(json.count("edgecolors") > 0 && json["edgecolors"].isArray())
5055 {
5056 auto &edgecolors = json.array("edgecolors");
5057 std::for_each(edgecolors.begin(), edgecolors.end(), [&](std::unique_ptr<IJson> &item) { m_edgeColors.emplace_back(*item); });
5058 }
5059 if(json.count("properties") > 0 && json["properties"].isArray())
5060 {
5061 auto &properties = json.array("properties");
5062 std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item); });
5063 }
5064
5065 return allFound;
5066}
5067
5068/*!
5069 * 'name': Name of the Wang set
5070 * @return
5071 */
5072const std::string &tson::WangSet::getName() const
5073{
5074 return m_name;
5075}
5076
5077/*!
5078 * 'tile': Local ID of tile representing the Wang set
5079 * @return
5080 */
5081int tson::WangSet::getTile() const
5082{
5083 return m_tile;
5084}
5085
5086/*!
5087 * 'wangtiles': Array of Wang tiles
5088 * @return
5089 */
5090const std::vector<tson::WangTile> &tson::WangSet::getWangTiles() const
5091{
5092 return m_wangTiles;
5093}
5094
5095/*!
5096 * 'cornercolors': Array of Wang colors
5097 * @return
5098 */
5099const std::vector<tson::WangColor> &tson::WangSet::getCornerColors() const
5100{
5101 return m_cornerColors;
5102}
5103
5104/*!
5105 * 'edgecolors': Array of Wang colors
5106 * @return
5107 */
5108const std::vector<tson::WangColor> &tson::WangSet::getEdgeColors() const
5109{
5110 return m_edgeColors;
5111}
5112
5113/*!
5114 * 'properties': A list of properties (name, value, type).
5115 * @return
5116 */
5117tson::PropertyCollection &tson::WangSet::getProperties()
5118{
5119 return m_properties;
5120}
5121
5122/*!
5123 * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>");
5124 * @param name Name of the property
5125 * @return
5126 */
5127tson::Property *tson::WangSet::getProp(const std::string &name)
5128{
5129 if(m_properties.hasProperty(name))
5130 return m_properties.getProperty(name);
5131
5132 return nullptr;
5133}
5134
5135#endif //TILESON_WANGSET_HPP
5136
5137/*** End of inlined file: WangSet.hpp ***/
5138
5139
5140/*** Start of inlined file: Tile.hpp ***/
5141//
5142// Created by robin on 22.03.2020.
5143//
5144
5145#ifndef TILESON_TILE_HPP
5146#define TILESON_TILE_HPP
5147
5148//#include "../external/json.hpp"
5149
5150
5151/*** Start of inlined file: Frame.hpp ***/
5152//
5153// Created by robin on 22.03.2020.
5154//
5155
5156#ifndef TILESON_FRAME_HPP
5157#define TILESON_FRAME_HPP
5158
5159//#include "../external/json.hpp"
5160
5161namespace tson
5162{
5163 class Frame
5164 {
5165 public:
5166 inline Frame() = default;
5167 inline Frame(int duration, int tileId);
5168 inline explicit Frame(IJson &json);
5169
5170 inline bool parse(IJson &json);
5171
5172 [[nodiscard]] inline int getDuration() const;
5173 [[nodiscard]] inline int getTileId() const;
5174
5175 private:
5176 int m_duration {}; /*! 'duration': Frame duration in milliseconds */
5177 int m_tileId {}; /*! 'tileid': Local tile ID representing this frame */
5178 };
5179}
5180
5181/*!
5182 *
5183 * @param duration duration in milliseconds
5184 * @param tileId TileId
5185 */
5186tson::Frame::Frame(int duration, int tileId) : m_duration {duration}, m_tileId {tileId}
5187{
5188
5189}
5190
5191/*!
5192 * Parses frame data from json
5193 * @param json
5194 */
5195tson::Frame::Frame(IJson &json)
5196{
5197 parse(json);
5198}
5199
5200/*!
5201 * Parses frame data from json
5202 * @param json
5203 * @return true if all mandatory fields was found. false otherwise.
5204 */
5205bool tson::Frame::parse(IJson &json)
5206{
5207 bool allFound = true;
5208
5209 if(json.count("duration") > 0) m_duration = json["duration"].get<int>(); else allFound = false;
5210 if(json.count("tileid") > 0) m_tileId = json["tileid"].get<int>(); else allFound = false;
5211
5212 return allFound;
5213}
5214
5215/*!
5216 * 'duration': Frame duration in milliseconds
5217 * @return Duration in milliseconds
5218 */
5219int tson::Frame::getDuration() const
5220{
5221 return m_duration;
5222}
5223
5224/*!
5225 * 'tileid': Local tile ID representing this frame
5226 * @return tile id
5227 */
5228int tson::Frame::getTileId() const
5229{
5230 return m_tileId;
5231}
5232
5233#endif //TILESON_FRAME_HPP
5234
5235/*** End of inlined file: Frame.hpp ***/
5236
5237namespace tson
5238{
5239 class Tileset;
5240
5241 class Tile
5242 {
5243 public:
5244 inline Tile() = default;
5245 inline Tile(IJson &json, tson::Tileset *tileset, tson::Map *map);
5246 inline Tile(uint32_t id, tson::Tileset *tileset, tson::Map *map);
5247 inline Tile(uint32_t id, tson::Map *map); //v1.2.0
5248 inline bool parse(IJson &json, tson::Tileset *tileset, tson::Map *map);
5249 inline bool parseId(IJson &json);
5250
5251 [[nodiscard]] inline uint32_t getId() const;
5252
5253 [[nodiscard]] inline const fs::path &getImage() const;
5254
5255 [[nodiscard]] inline const Vector2i &getImageSize() const;
5256 [[nodiscard]] inline const std::string &getType() const;
5257
5258 [[nodiscard]] inline const std::vector<tson::Frame> &getAnimation() const;
5259 [[nodiscard]] inline const Layer &getObjectgroup() const;
5260 [[nodiscard]] inline PropertyCollection &getProperties();
5261 [[nodiscard]] inline const std::vector<int> &getTerrain() const;
5262
5263 template <typename T>
5264 inline T get(const std::string &name);
5265 inline tson::Property * getProp(const std::string &name);
5266
5267 //v1.2.0-stuff
5268 inline void setProperties(const tson::PropertyCollection &properties);
5269
5270 inline tson::Tileset * getTileset() const;
5271 inline tson::Map * getMap() const;
5272 inline const tson::Rect &getDrawingRect() const;
5273 inline const tson::Vector2f getPosition(const std::tuple<int, int> &tileDataPos);
5274 inline const tson::Vector2i getPositionInTileUnits(const std::tuple<int, int> &tileDataPos);
5275 inline const tson::Vector2i getTileSize() const; /*! Declared in tileson_forward.hpp */
5276
5277 [[nodiscard]] inline TileFlipFlags getFlipFlags() const;
5278 inline bool hasFlipFlags(TileFlipFlags flags);
5279 [[nodiscard]] inline uint32_t getGid() const;
5280
5281 inline void addTilesetAndPerformCalculations(tson::Tileset *tileset); //v1.2.0
5282
5283 private:
5284 std::vector<tson::Frame> m_animation; /*! 'animation': Array of Frames */
5285 uint32_t m_id {}; /*! 'id': Local ID of the tile */
5286
5287 fs::path m_image; /*! 'image': Image representing this tile (optional)*/
5288
5289 tson::Vector2i m_imageSize; /*! x = 'imagewidth' and y = 'imageheight': in pixels */
5290 tson::Layer m_objectgroup; /*! 'objectgroup': Layer with type objectgroup (optional) */
5291 tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */
5292 std::vector<int> m_terrain; /*! 'terrain': Index of terrain for each corner of tile */
5293 std::string m_type; /*! 'type': The type of the tile (optional) */
5294
5295 //v1.2.0-stuff
5296 uint32_t m_gid {}; /*! id without flip flags */
5297 tson::Tileset * m_tileset; /*! A pointer to the tileset where this Tile comes from */
5298 tson::Map * m_map; /*! A pointer to the map where this tile is contained */
5299 tson::Rect m_drawingRect; /*! A rect that shows which part of the tileset that is used for this tile */
5300 tson::TileFlipFlags m_flipFlags = TileFlipFlags::None; /*! Resolved using bit 32, 31 and 30 from gid */
5301 inline void performDataCalculations(); /*! Declared in tileson_forward.hpp - Calculate all the values used in the tile class. */
5302 inline void manageFlipFlagsByIdThenRemoveFlags(uint32_t &id);
5303 friend class Layer;
5304 };
5305
5306 /*!
5307 * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>")
5308 * @tparam T The template value
5309 * @param name Name of the property
5310 * @return The actual value, if it exists. Otherwise: The default value of the type.
5311 */
5312 template<typename T>
5313 T tson::Tile::get(const std::string &name)
5314 {
5315 return m_properties.getValue<T>(name);
5316 }
5317}
5318
5319tson::Tile::Tile(IJson &json, tson::Tileset *tileset, tson::Map *map)
5320{
5321 parse(json, tileset, map);
5322}
5323
5324/*!
5325 * Used in cases where you have a tile without any property
5326 * @param id
5327 */
5328tson::Tile::Tile(uint32_t id, tson::Tileset *tileset, tson::Map *map) : m_id {id}, m_gid {id}
5329{
5330 m_tileset = tileset;
5331 m_map = map;
5332 manageFlipFlagsByIdThenRemoveFlags(m_gid);
5333 performDataCalculations();
5334}
5335
5336/*!
5337 * Used in cases where you have a FLIP FLAGGED tile
5338 * @param id
5339 */
5340tson::Tile::Tile(uint32_t id, tson::Map *map) : m_id {id}, m_gid {id}
5341{
5342 m_map = map;
5343 manageFlipFlagsByIdThenRemoveFlags(m_gid);
5344}
5345
5346/*!
5347 * For flip flagged tiles, tilesets must be resolved later.
5348 * @param tileset
5349 */
5350void tson::Tile::addTilesetAndPerformCalculations(tson::Tileset *tileset)
5351{
5352 m_tileset = tileset;
5353 performDataCalculations();
5354}
5355
5356/*!
5357 * Parses a tile from a Tiled json. id on tile is store as id + 1 to match the references in data containers.
5358 * @param json
5359 * @return
5360 */
5361bool tson::Tile::parse(IJson &json, tson::Tileset *tileset, tson::Map *map)
5362{
5363 m_tileset = tileset;
5364 m_map = map;
5365
5366 if(json.count("image") > 0) m_image = fs::path(json["image"].get<std::string>()); //Optional
5367
5368 bool allFound = parseId(json);
5369
5370 if(json.count("type") > 0) m_type = json["type"].get<std::string>(); //Optional
5371 if(json.count("objectgroup") > 0) m_objectgroup = tson::Layer(json["objectgroup"], m_map); //Optional
5372
5373 if(json.count("imagewidth") > 0 && json.count("imageheight") > 0)
5374 m_imageSize = {json["imagewidth"].get<int>(), json["imageheight"].get<int>()}; //Optional
5375
5376 //More advanced data
5377 if(json.count("animation") > 0 && json["animation"].isArray())
5378 {
5379 auto &animation = json.array("animation");
5380 std::for_each(animation.begin(), animation.end(), [&](std::unique_ptr<IJson> &item) { m_animation.emplace_back(*item); });
5381 }
5382 if(json.count("terrain") > 0 && json["terrain"].isArray())
5383 {
5384 auto &terrain = json.array("terrain");
5385 std::for_each(terrain.begin(), terrain.end(), [&](std::unique_ptr<IJson> &item) { m_terrain.emplace_back(item->get<int>()); });
5386 }
5387
5388 if(json.count("properties") > 0 && json["properties"].isArray())
5389 {
5390 auto &properties = json.array("properties");
5391 std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item); });
5392 }
5393
5394 performDataCalculations();
5395
5396 return allFound;
5397}
5398
5399/*!
5400 * 'id': Local ID of the tile
5401 * @return
5402 */
5403uint32_t tson::Tile::getId() const
5404{
5405 return m_id;
5406}
5407
5408/*!
5409 * 'image': Image representing this tile (optional)
5410 * @return
5411 */
5412
5413const fs::path &tson::Tile::getImage() const { return m_image; }
5414
5415/*!
5416 * x = 'imagewidth' and y = 'imageheight': in pixels
5417 * @return
5418 */
5419const tson::Vector2i &tson::Tile::getImageSize() const
5420{
5421 return m_imageSize;
5422}
5423
5424/*!
5425 * 'type': The type of the tile (optional)
5426 * @return
5427 */
5428const std::string &tson::Tile::getType() const
5429{
5430 return m_type;
5431}
5432
5433/*!
5434 * 'animation': Array of Frames
5435 * @return
5436 */
5437const std::vector<tson::Frame> &tson::Tile::getAnimation() const
5438{
5439 return m_animation;
5440}
5441
5442/*!
5443 * 'objectgroup': Layer with type objectgroup (optional)
5444 * @return
5445 */
5446const tson::Layer &tson::Tile::getObjectgroup() const
5447{
5448 return m_objectgroup;
5449}
5450
5451/*!
5452 * 'properties': A list of properties (name, value, type).
5453 * @return
5454 */
5455tson::PropertyCollection &tson::Tile::getProperties()
5456{
5457 return m_properties;
5458}
5459
5460/*!
5461 * 'terrain': Index of terrain for each corner of tile
5462 * @return
5463 */
5464const std::vector<int> &tson::Tile::getTerrain() const
5465{
5466 return m_terrain;
5467}
5468
5469/*!
5470 * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>");
5471 * @param name Name of the property
5472 * @return
5473 */
5474tson::Property *tson::Tile::getProp(const std::string &name)
5475{
5476 if(m_properties.hasProperty(name))
5477 return m_properties.getProperty(name);
5478
5479 return nullptr;
5480}
5481
5482/*!
5483 * Used for getting the tson::Tileset who is the parent of this Tile.
5484 * @return a pointer to the tson::Tileset where this tile is contained.
5485 */
5486tson::Tileset *tson::Tile::getTileset() const
5487{
5488 return m_tileset;
5489}
5490
5491/*!
5492 * Used for getting the tson::Map who is the parent of this Tile.
5493 * @return a pointer to the tson::Map where this tile is contained.
5494 */
5495tson::Map *tson::Tile::getMap() const
5496{
5497 return m_map;
5498}
5499
5500/*!
5501 * Get the information needed to draw the Tile based on its current tileset
5502 * @return a tson::Rect containing the information needed to draw the tile.
5503 */
5504const tson::Rect &tson::Tile::getDrawingRect() const
5505{
5506 return m_drawingRect;
5507}
5508
5509/*!
5510 * Helper function.
5511 *
5512 * Get the position of the tile in tile units.
5513 * The size of each unit is determined by the tile size property of the map.
5514 * Example: If the tile size is 16x16 in the map, a tile unit of [2, 4] would be [32, 64] in pixels.
5515 * If you want the position in pixels: use getPosition() instead.
5516 *
5517 * @return Position of tile in tile units.
5518 */
5519const tson::Vector2i tson::Tile::getPositionInTileUnits(const std::tuple<int, int> &tileDataPos)
5520{
5521 return {std::get<0>(tileDataPos), std::get<1>(tileDataPos)};
5522}
5523
5524void tson::Tile::manageFlipFlagsByIdThenRemoveFlags(uint32_t &id)
5525{
5526 if (id & FLIPPED_HORIZONTALLY_FLAG) m_flipFlags |= TileFlipFlags::Horizontally;
5527 if (id & FLIPPED_VERTICALLY_FLAG) m_flipFlags |= TileFlipFlags::Vertically;
5528 if (id & FLIPPED_DIAGONALLY_FLAG) m_flipFlags |= TileFlipFlags::Diagonally;
5529
5530 id &= ~(FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG);
5531}
5532
5533tson::TileFlipFlags tson::Tile::getFlipFlags() const
5534{
5535 return m_flipFlags;
5536}
5537
5538/*!
5539 *
5540 * @param flags Which flags to check for. Several flags can be checked at once using the bitwise or operator.
5541 * Example:
5542 * hasFlipFlags(TileFlipFlags::Vertically | TileFlipFlags::Horizontally)
5543 *
5544 * @return true if the flag(s) specified are set
5545 */
5546bool tson::Tile::hasFlipFlags(tson::TileFlipFlags flags)
5547{
5548 return ((m_flipFlags & flags) == flags) ? true : false;
5549}
5550
5551uint32_t tson::Tile::getGid() const
5552{
5553 return m_gid;
5554}
5555
5556void tson::Tile::setProperties(const tson::PropertyCollection &properties)
5557{
5558 m_properties = properties;
5559}
5560
5561#endif //TILESON_TILE_HPP
5562
5563/*** End of inlined file: Tile.hpp ***/
5564
5565
5566/*** Start of inlined file: Terrain.hpp ***/
5567//
5568// Created by robin on 22.03.2020.
5569//
5570
5571#ifndef TILESON_TERRAIN_HPP
5572#define TILESON_TERRAIN_HPP
5573
5574//#include "../external/json.hpp"
5575
5576namespace tson
5577{
5578 class Terrain
5579 {
5580 public:
5581 inline Terrain() = default;
5582 inline Terrain(std::string name, int tile);
5583 inline explicit Terrain(IJson &json);
5584
5585 inline bool parse(IJson &json);
5586
5587 [[nodiscard]] inline const std::string &getName() const;
5588 [[nodiscard]] inline int getTile() const;
5589 [[nodiscard]] inline PropertyCollection &getProperties();
5590
5591 template <typename T>
5592 inline T get(const std::string &name);
5593 inline tson::Property * getProp(const std::string &name);
5594
5595 private:
5596 std::string m_name; /*! 'name': Name of terrain */
5597 int m_tile {}; /*! 'tile': Local ID of tile representing terrain */
5598 tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */
5599 };
5600
5601 /*!
5602 * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>")
5603 * @tparam T The template value
5604 * @param name Name of the property
5605 * @return The actual value, if it exists. Otherwise: The default value of the type.
5606 */
5607 template<typename T>
5608 T tson::Terrain::get(const std::string &name)
5609 {
5610 return m_properties.getValue<T>(name);
5611 }
5612}
5613
5614tson::Terrain::Terrain(std::string name, int tile) : m_name {std::move(name)}, m_tile {tile}
5615{
5616
5617}
5618
5619tson::Terrain::Terrain(IJson &json)
5620{
5621 parse(json);
5622}
5623
5624bool tson::Terrain::parse(IJson &json)
5625{
5626 bool allFound = true;
5627
5628 if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false;
5629 if(json.count("tile") > 0) m_tile = json["tile"].get<int>(); else allFound = false;
5630
5631 if(json.count("properties") > 0 && json["properties"].isArray())
5632 {
5633 auto &properties = json.array("properties");
5634 std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item); });
5635 }
5636
5637 return allFound;
5638}
5639
5640/*!
5641 * 'name': Name of terrain
5642 * @return
5643 */
5644const std::string &tson::Terrain::getName() const
5645{
5646 return m_name;
5647}
5648
5649/*!
5650 * 'tile': Local ID of tile representing terrain
5651 * @return
5652 */
5653int tson::Terrain::getTile() const
5654{
5655 return m_tile;
5656}
5657
5658/*!
5659 * 'properties': A list of properties (name, value, type). *Missing from the official Tiled documentation...*
5660 * @return
5661 */
5662tson::PropertyCollection &tson::Terrain::getProperties()
5663{
5664 return m_properties;
5665}
5666
5667/*!
5668 * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>");
5669 * @param name Name of the property
5670 * @return
5671 */
5672tson::Property *tson::Terrain::getProp(const std::string &name)
5673{
5674 if(m_properties.hasProperty(name))
5675 return m_properties.getProperty(name);
5676 return nullptr;
5677}
5678
5679#endif //TILESON_TERRAIN_HPP
5680
5681/*** End of inlined file: Terrain.hpp ***/
5682
5683
5684/*** Start of inlined file: Grid.hpp ***/
5685//
5686// Created by robin on 22.03.2020.
5687//
5688
5689#ifndef TILESON_GRID_HPP
5690#define TILESON_GRID_HPP
5691
5692#include <string>
5693//#include "../external/json.hpp"
5694
5695namespace tson
5696{
5697 class Grid
5698 {
5699 public:
5700 inline Grid() = default;
5701 inline explicit Grid(IJson &json);
5702
5703 inline bool parse(IJson &json);
5704
5705 [[nodiscard]] inline const std::string &getOrientation() const;
5706 [[nodiscard]] inline const Vector2i &getSize() const;
5707
5708 private:
5709 std::string m_orientation; /*! 'orientation': Orientation of the grid for the tiles in this tileset (orthogonal or isometric) */
5710 tson::Vector2i m_size; /*! 'width' and 'height': Size. */
5711 };
5712}
5713
5714/*!
5715 * Parses Tiled grid data from json
5716 * @param json
5717 */
5718tson::Grid::Grid(IJson &json)
5719{
5720 parse(json);
5721}
5722
5723/*!
5724 * Parses Tiled grid data from json
5725 * @param json
5726 * @return true if all mandatory fields was found. false otherwise.
5727 */
5728bool tson::Grid::parse(IJson &json)
5729{
5730 bool allFound = true;
5731
5732 if(json.count("orientation") > 0) m_orientation = json["orientation"].get<std::string>(); //Optional
5733
5734 if(json.count("width") > 0 && json.count("height") > 0)
5735 m_size = {json["width"].get<int>(), json["height"].get<int>()}; else allFound = false;
5736
5737 return allFound;
5738}
5739
5740/*!
5741 * 'orientation': Orientation of the grid for the tiles in this tileset (orthogonal or isometric)
5742 * @return orientation as string
5743 */
5744const std::string &tson::Grid::getOrientation() const
5745{
5746 return m_orientation;
5747}
5748
5749/*!
5750 * 'width' and 'height': Size.
5751 * @return size as int
5752 */
5753const tson::Vector2i &tson::Grid::getSize() const
5754{
5755 return m_size;
5756}
5757
5758#endif //TILESON_GRID_HPP
5759
5760/*** End of inlined file: Grid.hpp ***/
5761
5762#include <functional>
5763
5764namespace tson
5765{
5766 class Map;
5767 class Tileset
5768 {
5769 public:
5770 inline Tileset() = default;
5771 inline explicit Tileset(IJson &json, tson::Map *map);
5772 inline bool parse(IJson &json, tson::Map *map);
5773
5774 [[nodiscard]] inline int getColumns() const;
5775 [[nodiscard]] inline int getFirstgid() const;
5776
5777 [[nodiscard]] inline const fs::path &getImagePath() const;
5778 [[nodiscard]] inline const fs::path &getImage() const;
5779
5780 [[nodiscard]] inline const Vector2i &getImageSize() const;
5781 [[nodiscard]] inline int getMargin() const;
5782 [[nodiscard]] inline const std::string &getName() const;
5783 [[nodiscard]] inline int getSpacing() const;
5784 [[nodiscard]] inline int getTileCount() const;
5785 [[nodiscard]] inline const Vector2i &getTileSize() const;
5786 [[nodiscard]] inline const Colori &getTransparentColor() const;
5787
5788 [[nodiscard]] inline const std::string &getType() const;
5789 [[nodiscard]] inline std::vector<tson::Tile> &getTiles();
5790 [[nodiscard]] inline const std::vector<tson::WangSet> &getWangsets() const;
5791 [[nodiscard]] inline PropertyCollection &getProperties();
5792 [[nodiscard]] inline const std::vector<tson::Terrain> &getTerrains() const;
5793 [[nodiscard]] inline const Vector2i &getTileOffset() const;
5794 [[nodiscard]] inline const Grid &getGrid() const;
5795
5796 inline tson::Tile * getTile(int id);
5797 inline tson::Terrain * getTerrain(const std::string &name);
5798
5799 template <typename T>
5800 inline T get(const std::string &name);
5801 inline tson::Property * getProp(const std::string &name);
5802
5803 //v1.2.0-stuff
5804 [[nodiscard]] inline tson::Map *getMap() const;
5805 [[nodiscard]] inline ObjectAlignment getObjectAlignment() const;
5806
5807 inline static tson::ObjectAlignment StringToAlignment(std::string_view str);
5808
5809 private:
5810 inline void generateMissingTiles();
5811
5812 int m_columns {}; /*! 'columns': The number of tile columns in the tileset */
5813 int m_firstgid {}; /*! 'firstgid': GID corresponding to the first tile in the set */
5814
5815 fs::path m_image; /*! 'image': Image used for tiles in this set */
5816
5817 tson::Vector2i m_imageSize; /*! x = 'imagewidth' and y = 'imageheight': in pixels */
5818 int m_margin {}; /*! 'margin': Buffer between image edge and first tile (pixels)*/
5819 std::string m_name; /*! 'name': Name given to this tileset */
5820 int m_spacing {}; /*! 'spacing': Spacing between adjacent tiles in image (pixels)*/
5821 int m_tileCount {}; /*! 'tilecount': The number of tiles in this tileset */
5822 tson::Vector2i m_tileSize; /*! x = 'tilewidth' and y = 'tileheight': Maximum size of tiles in this set */
5823 tson::Colori m_transparentColor; /*! 'transparentcolor': Hex-formatted color (#RRGGBB) (optional) */
5824 std::string m_type; /*! 'type': tileset (for tileset files, since 1.0) */
5825
5826 std::vector<tson::Tile> m_tiles; /*! 'tiles': Array of Tiles (optional) */
5827 std::vector<tson::WangSet> m_wangsets; /*! 'wangsets':Array of Wang sets (since 1.1.5) */
5828 tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */
5829
5830 std::vector<tson::Terrain> m_terrains; /*! 'terrains': Array of Terrains (optional) */
5831 tson::Vector2i m_tileOffset; /*! 'x' and 'y': See <tileoffset> (optional) */
5832 tson::Grid m_grid; /*! 'grid': This element is only used in case of isometric orientation, and determines
5833 how tile overlays for terrain and collision information are rendered. */
5834
5835 //v1.2.0-stuff
5836 tson::ObjectAlignment m_objectAlignment{tson::ObjectAlignment::Unspecified}; /*! 'objectalignment': Alignment to use for tile objects. Tiled 1.4.*/
5837 tson::Map * m_map; /*! The map who owns this tileset */
5838 };
5839
5840 /*!
5841 * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>")
5842 * @tparam T The template value
5843 * @param name Name of the property
5844 * @return The actual value, if it exists. Otherwise: The default value of the type.
5845 */
5846 template<typename T>
5847 T tson::Tileset::get(const std::string &name)
5848 {
5849 return m_properties.getValue<T>(name);
5850 }
5851}
5852
5853tson::Tileset::Tileset(IJson &json, tson::Map *map)
5854{
5855 parse(json, map);
5856}
5857
5858bool tson::Tileset::parse(IJson &json, tson::Map *map)
5859{
5860 m_map = map;
5861 bool allFound = true;
5862
5863 if(json.count("columns") > 0) m_columns = json["columns"].get<int>(); else allFound = false;
5864 if(json.count("firstgid") > 0) m_firstgid = json["firstgid"].get<int>(); else allFound = false;
5865
5866 if(json.count("image") > 0) m_image = fs::path(json["image"].get<std::string>()); else allFound = false;
5867
5868 if(json.count("margin") > 0) m_margin = json["margin"].get<int>(); else allFound = false;
5869 if(json.count("name") > 0) m_name = json["name"].get<std::string>(); else allFound = false;
5870 if(json.count("spacing") > 0) m_spacing = json["spacing"].get<int>(); else allFound = false;
5871 if(json.count("tilecount") > 0) m_tileCount = json["tilecount"].get<int>(); else allFound = false;
5872 if(json.count("transparentcolor") > 0) m_transparentColor = tson::Colori(json["transparentcolor"].get<std::string>()); //Optional
5873 if(json.count("type") > 0) m_type = json["type"].get<std::string>();
5874 if(json.count("grid") > 0) m_grid = tson::Grid(json["grid"]);
5875
5876 if(json.count("imagewidth") > 0 && json.count("imageheight") > 0)
5877 m_imageSize = {json["imagewidth"].get<int>(), json["imageheight"].get<int>()}; else allFound = false;
5878 if(json.count("tilewidth") > 0 && json.count("tileheight") > 0)
5879 m_tileSize = {json["tilewidth"].get<int>(), json["tileheight"].get<int>()}; else allFound = false;
5880 if(json.count("tileoffset") > 0)
5881 m_tileOffset = {json["tileoffset"]["x"].get<int>(), json["tileoffset"]["y"].get<int>()};
5882
5883 //More advanced data
5884 if(json.count("wangsets") > 0 && json["wangsets"].isArray())
5885 {
5886 auto &wangsets = json.array("wangsets");
5887 std::for_each(wangsets.begin(), wangsets.end(), [&](std::unique_ptr<IJson> &item) { m_wangsets.emplace_back(*item); });
5888 }
5889 if(json.count("tiles") > 0 && json["tiles"].isArray())
5890 {
5891 auto &tiles = json.array("tiles");
5892 std::for_each(tiles.begin(), tiles.end(), [&](std::unique_ptr<IJson> &item) { m_tiles.emplace_back(*item, this, m_map); });
5893 }
5894 if(json.count("terrains") > 0 && json["terrains"].isArray())
5895 {
5896 auto &terrains = json.array("terrains");
5897 std::for_each(terrains.begin(), terrains.end(), [&](std::unique_ptr<IJson> &item) { m_terrains.emplace_back(*item); });
5898 }
5899
5900 if(json.count("properties") > 0 && json["properties"].isArray())
5901 {
5902 auto &properties = json.array("properties");
5903 std::for_each(properties.begin(), properties.end(), [&](std::unique_ptr<IJson> &item) { m_properties.add(*item); });
5904 }
5905
5906 if(json.count("objectalignment") > 0)
5907 {
5908 std::string alignment = json["objectalignment"].get<std::string>();
5909 m_objectAlignment = StringToAlignment(alignment);
5910 }
5911
5912 generateMissingTiles();
5913
5914 return allFound;
5915}
5916
5917/*!
5918 * 'columns': The number of tile columns in the tileset
5919 * @return
5920 */
5921int tson::Tileset::getColumns() const
5922{
5923 return m_columns;
5924}
5925
5926/*!
5927 * 'firstgid': GID corresponding to the first tile in the set
5928 * @return
5929 */
5930int tson::Tileset::getFirstgid() const
5931{
5932 return m_firstgid;
5933}
5934
5935/*!
5936 * 'image': Image used for tiles in this set
5937 * @return
5938 */
5939
5940const fs::path &tson::Tileset::getImagePath() const { return m_image; }
5941
5942/*!
5943 * x = 'imagewidth' and y = 'imageheight': in pixels
5944 * @return
5945 */
5946const tson::Vector2i &tson::Tileset::getImageSize() const
5947{
5948 return m_imageSize;
5949}
5950
5951/*!
5952 * 'margin': Buffer between image edge and first tile (pixels)
5953 * @return
5954 */
5955int tson::Tileset::getMargin() const
5956{
5957 return m_margin;
5958}
5959
5960/*!
5961 * 'name': Name given to this tileset
5962 * @return
5963 */
5964const std::string &tson::Tileset::getName() const
5965{
5966 return m_name;
5967}
5968
5969/*!
5970 * 'spacing': Spacing between adjacent tiles in image (pixels)
5971 * @return
5972 */
5973int tson::Tileset::getSpacing() const
5974{
5975 return m_spacing;
5976}
5977
5978/*!
5979 * 'tilecount': The number of tiles in this tileset
5980 * @return
5981 */
5982int tson::Tileset::getTileCount() const
5983{
5984 return m_tileCount;
5985}
5986
5987/*!
5988 * x = 'tilewidth' and y = 'tileheight': Maximum size of tiles in this set
5989 * @return
5990 */
5991const tson::Vector2i &tson::Tileset::getTileSize() const
5992{
5993 return m_tileSize;
5994}
5995
5996/*!
5997 * 'transparentcolor': Color object created by hex-formatted color (#RRGGBB) (optional)
5998 * @return
5999 */
6000const tson::Colori &tson::Tileset::getTransparentColor() const
6001{
6002 return m_transparentColor;
6003}
6004
6005/*!
6006 * 'type': tileset (for tileset files, since 1.0)
6007 * @return
6008 */
6009const std::string &tson::Tileset::getType() const
6010{
6011 return m_type;
6012}
6013
6014/*!
6015 * 'image': Image used for tiles in this set
6016 * @return
6017 */
6018
6019const fs::path &tson::Tileset::getImage() const { return m_image; }
6020
6021/*!
6022 * 'tiles': Array of Tiles (optional)
6023 * @return
6024 */
6025std::vector<tson::Tile> &tson::Tileset::getTiles()
6026{
6027 return m_tiles;
6028}
6029
6030/*!
6031 * 'wangsets':Array of Wang sets (since Tiled 1.1.5)
6032 * @return
6033 */
6034const std::vector<tson::WangSet> &tson::Tileset::getWangsets() const
6035{
6036 return m_wangsets;
6037}
6038
6039/*!
6040 * 'properties': A list of properties (name, value, type).
6041 * @return
6042 */
6043tson::PropertyCollection &tson::Tileset::getProperties()
6044{
6045 return m_properties;
6046}
6047
6048/*!
6049 * 'terrains': Array of Terrains (optional)
6050 * @return
6051 */
6052const std::vector<tson::Terrain> &tson::Tileset::getTerrains() const
6053{
6054 return m_terrains;
6055}
6056
6057/*!
6058 * 'x' and 'y': See <tileoffset> (optional)
6059 * @return
6060 */
6061const tson::Vector2i &tson::Tileset::getTileOffset() const
6062{
6063 return m_tileOffset;
6064}
6065
6066/*!
6067 * 'grid': This element is only used in case of isometric orientation, and determines
6068 * how tile overlays for terrain and collision information are rendered.
6069 * @return
6070 */
6071const tson::Grid &tson::Tileset::getGrid() const
6072{
6073 return m_grid;
6074}
6075
6076/*!
6077 * Gets a tile by ID (Tiled ID + 1)
6078 * @param id The ID of the tile stored in Tiled map + 1. Example: If ID was stored in Tiled map as 0, the corresponding value in Tileson is 1.
6079 * This is to make sure the IDs of tiles matches their references in containers.
6080 * @return A pointer to the Tile if found. nullptr otherwise.
6081 */
6082tson::Tile *tson::Tileset::getTile(int id)
6083{
6084 auto result = std::find_if(m_tiles.begin(), m_tiles.end(), [&](const tson::Tile & item) { return item.getId() == id;});
6085 if(result == m_tiles.end())
6086 return nullptr;
6087
6088 return &result.operator*();
6089}
6090
6091/*!
6092 * Get an existing Terrain object by name
6093 * @param name
6094 * @return A pointer to the Terrain if found. nullptr otherwise.
6095 */
6096tson::Terrain *tson::Tileset::getTerrain(const std::string &name)
6097{
6098 auto result = std::find_if(m_terrains.begin(), m_terrains.end(), [&](const tson::Terrain & item) { return item.getName() == name;});
6099 if(result == m_terrains.end())
6100 return nullptr;
6101
6102 return &result.operator*();
6103}
6104
6105/*!
6106 * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>");
6107 * @param name Name of the property
6108 * @return
6109 */
6110tson::Property *tson::Tileset::getProp(const std::string &name)
6111{
6112 if(m_properties.hasProperty(name))
6113 return m_properties.getProperty(name);
6114
6115 return nullptr;
6116}
6117
6118/*!
6119 * Tiled only has tiles with a property stored in the map. This function makes sure even the ones with no properties will exist.
6120 */
6121void tson::Tileset::generateMissingTiles()
6122{
6123 std::vector<uint32_t> tileIds;
6124 for(auto &tile : m_tiles)
6125 tileIds.push_back(tile.getId());
6126
6127 for(uint32_t i = m_firstgid; i < m_firstgid + m_tileCount; ++i)
6128 {
6129 if(std::count(tileIds.begin(), tileIds.end(), i) == 0)
6130 {
6131 m_tiles.emplace_back(Tile(i, this, m_map));
6132 }
6133 }
6134}
6135
6136/*!
6137 * Used for getting the tson::Map who is the parent of this Tileset.
6138 * @return a pointer to the tson::Map where this tileset is contained.
6139 */
6140tson::Map *tson::Tileset::getMap() const
6141{
6142 return m_map;
6143}
6144
6145/*!
6146 *
6147 * @param str The string you want to convert
6148 * @return Alignment enum based on the string from the input.
6149 */
6150tson::ObjectAlignment tson::Tileset::StringToAlignment(std::string_view str)
6151{
6152 if(str == "unspecified") return tson::ObjectAlignment::Unspecified;
6153 else if(str == "topleft") return tson::ObjectAlignment::TopLeft;
6154 else if(str == "top") return tson::ObjectAlignment::Top;
6155 else if(str == "topright") return tson::ObjectAlignment::TopRight;
6156 else if(str == "left") return tson::ObjectAlignment::Left;
6157 else if(str == "center") return tson::ObjectAlignment::Center;
6158 else if(str == "right") return tson::ObjectAlignment::Right;
6159 else if(str == "bottomleft") return tson::ObjectAlignment::BottomLeft;
6160 else if(str == "bottom") return tson::ObjectAlignment::Bottom;
6161 else if(str == "bottomright") return tson::ObjectAlignment::BottomRight;
6162 else
6163 return tson::ObjectAlignment::Unspecified;
6164}
6165
6166tson::ObjectAlignment tson::Tileset::getObjectAlignment() const
6167{
6168 return m_objectAlignment;
6169}
6170
6171#endif //TILESON_TILESET_HPP
6172/*** End of inlined file: Tileset.hpp ***/
6173
6174namespace tson
6175{
6176 class Map
6177 {
6178 public:
6179 inline Map() = default;
6180 inline Map(ParseStatus status, std::string description);
6181 inline explicit Map(IJson &json, tson::DecompressorContainer *decompressors);
6182 inline bool parse(IJson &json, tson::DecompressorContainer *decompressors);
6183
6184 [[nodiscard]] inline const Colori &getBackgroundColor() const;
6185 [[nodiscard]] inline const Vector2i &getSize() const;
6186 [[nodiscard]] inline int getHexsideLength() const;
6187 [[nodiscard]] inline bool isInfinite() const;
6188 [[nodiscard]] inline int getNextLayerId() const;
6189 [[nodiscard]] inline int getNextObjectId() const;
6190 [[nodiscard]] inline const std::string &getOrientation() const;
6191 [[nodiscard]] inline const std::string &getRenderOrder() const;
6192 [[nodiscard]] inline const std::string &getStaggerAxis() const;
6193 [[nodiscard]] inline const std::string &getStaggerIndex() const;
6194 [[nodiscard]] inline const std::string &getTiledVersion() const;
6195 [[nodiscard]] inline const Vector2i &getTileSize() const;
6196 [[nodiscard]] inline const std::string &getType() const;
6197 [[nodiscard]] inline int getVersion() const;
6198
6199 [[nodiscard]] inline std::vector<tson::Layer> &getLayers();
6200 [[nodiscard]] inline PropertyCollection &getProperties();
6201 [[nodiscard]] inline std::vector<tson::Tileset> &getTilesets();
6202
6203 [[nodiscard]] inline ParseStatus getStatus() const;
6204 [[nodiscard]] inline const std::string &getStatusMessage() const;
6205 [[nodiscard]] inline const std::map<uint32_t, tson::Tile *> &getTileMap() const;
6206
6207 inline Layer * getLayer(const std::string &name);
6208 inline Tileset * getTileset(const std::string &name);
6209
6210 template <typename T>
6211 inline T get(const std::string &name);
6212 inline tson::Property * getProp(const std::string &name);
6213
6214 //v1.2.0
6215 [[nodiscard]] inline int getCompressionLevel() const;
6216 inline DecompressorContainer *getDecompressors();
6217 inline Tileset * getTilesetByGid(uint32_t gid);
6218
6219 private:
6220 inline void createTilesetData(IJson &json);
6221 inline void processData();
6222
6223 Colori m_backgroundColor; /*! 'backgroundcolor': Hex-formatted color (#RRGGBB or #AARRGGBB) (optional)*/;
6224 Vector2i m_size; /*! 'width' and 'height' of a Tiled map */
6225 int m_hexsideLength {}; /*! 'hexsidelength': Length of the side of a hex tile in pixels */
6226 bool m_isInfinite {}; /*! 'infinite': Whether the map has infinite dimensions*/
6227 std::vector<tson::Layer> m_layers; /*! 'layers': Array of layers. group on */
6228 int m_nextLayerId {}; /*! 'nextlayerid': Auto-increments for each layer */
6229 int m_nextObjectId {}; /*! 'nextobjectid': Auto-increments for each placed object */
6230 std::string m_orientation; /*! 'orientation': orthogonal, isometric, staggered or hexagonal */
6231 tson::PropertyCollection m_properties; /*! 'properties': A list of properties (name, value, type). */
6232 std::string m_renderOrder; /*! 'renderorder': Rendering direction (orthogonal maps only) */
6233 std::string m_staggerAxis; /*! 'staggeraxis': x or y (staggered / hexagonal maps only) */
6234 std::string m_staggerIndex; /*! 'staggerindex': odd or even (staggered / hexagonal maps only) */
6235 std::string m_tiledVersion; /*! 'tiledversion': The Tiled version used to save the file */
6236 Vector2i m_tileSize; /*! 'tilewidth': and 'tileheight' of a map */
6237 std::vector<tson::Tileset> m_tilesets; /*! 'tilesets': Array of Tilesets */
6238 std::string m_type; /*! 'type': map (since 1.0) */
6239 int m_version{}; /*! 'version': The JSON format version*/
6240
6241 ParseStatus m_status {ParseStatus::OK};
6242 std::string m_statusMessage {"OK"};
6243
6244 std::map<uint32_t, tson::Tile*> m_tileMap; /*! key: Tile ID. Value: Pointer to Tile*/
6245
6246 //v1.2.0
6247 int m_compressionLevel {-1}; /*! 'compressionlevel': The compression level to use for tile layer
6248 * data (defaults to -1, which means to use the algorithm default)
6249 * Introduced in Tiled 1.3*/
6250 tson::DecompressorContainer * m_decompressors;
6251 std::map<uint32_t, tson::Tile> m_flaggedTileMap; /*! key: Tile ID. Value: Tile*/
6252 };
6253
6254 /*!
6255 * A shortcut for getting a property. Alternative to getProperties().getValue<T>("<name>")
6256 * @tparam T The template value
6257 * @param name Name of the property
6258 * @return The actual value, if it exists. Otherwise: The default value of the type.
6259 */
6260 template<typename T>
6261 T tson::Map::get(const std::string &name)
6262 {
6263 return m_properties.getValue<T>(name);
6264 }
6265}
6266
6267/*!
6268 * When errors have happened before the map starts parsing, just keep the statuses
6269 * @param status The status
6270 * @param description Description of the status
6271 */
6272tson::Map::Map(tson::ParseStatus status, std::string description) : m_status {status}, m_statusMessage { std::move(description) }
6273{
6274
6275}
6276
6277/*!
6278 * Parses a json of a Tiled map.
6279 * @param json A json object with the format of Map
6280 * @return true if all mandatory fields was found. false otherwise.
6281 */
6282tson::Map::Map(IJson &json, tson::DecompressorContainer *decompressors)
6283{
6284 parse(json, decompressors);
6285}
6286
6287/*!
6288 * Parses a json of a Tiled map.
6289 * @param json A json object with the format of Map
6290 * @return true if all mandatory fields was found. false otherwise.
6291 */
6292bool tson::Map::parse(IJson &json, tson::DecompressorContainer *decompressors)
6293{
6294 m_decompressors = decompressors;
6295
6296 bool allFound = true;
6297 if(json.count("compressionlevel") > 0)
6298 m_compressionLevel = json["compressionlevel"].get<int>(); //Tiled 1.3 - Optional
6299
6300 if(json.count("backgroundcolor") > 0) m_backgroundColor = Colori(json["backgroundcolor"].get<std::string>()); //Optional
6301 if(json.count("width") > 0 && json.count("height") > 0 )
6302 m_size = {json["width"].get<int>(), json["height"].get<int>()}; else allFound = false;
6303 if(json.count("hexsidelength") > 0) m_hexsideLength = json["hexsidelength"].get<int>(); //Optional
6304 if(json.count("infinite") > 0) m_isInfinite = json["infinite"].get<bool>(); //Optional
6305 if(json.count("nextlayerid") > 0) m_nextLayerId = json["nextlayerid"].get<int>(); //Optional
6306 if(json.count("nextobjectid") > 0) m_nextObjectId = json["nextobjectid"].get<int>(); else allFound = false;
6307 if(json.count("orientation") > 0) m_orientation = json["orientation"].get<std::string>(); else allFound = false;
6308 if(json.count("renderorder") > 0) m_renderOrder = json["renderorder"].get<std::string>(); //Optional
6309 if(json.count("staggeraxis") > 0) m_staggerAxis = json["staggeraxis"].get<std::string>(); //Optional
6310 if(json.count("staggerindex") > 0) m_staggerIndex = json["staggerindex"].get<std::string>(); //Optional
6311 if(json.count("tiledversion") > 0) m_tiledVersion = json["tiledversion"].get<std::string>(); else allFound = false;
6312 if(json.count("tilewidth") > 0 && json.count("tileheight") > 0 )
6313 m_tileSize = {json["tilewidth"].get<int>(), json["tileheight"].get<int>()}; else allFound = false;
6314 if(json.count("type") > 0) m_type = json["type"].get<std::string>(); //Optional
6315 if(json.count("version") > 0) m_version = json["version"].get<int>(); else allFound = false;
6316
6317 //More advanced data
6318 if(json.count("layers") > 0 && json["layers"].isArray())
6319 {
6320 auto &array = json.array("layers");
6321 std::for_each(array.begin(), array.end(), [&](std::unique_ptr<IJson> &item)
6322 {
6323 m_layers.emplace_back(*item, this);
6324 });
6325 }
6326
6327 if(json.count("properties") > 0 && json["properties"].isArray())
6328 {
6329 auto &array = json.array("properties");
6330 std::for_each(array.begin(), array.end(), [&](std::unique_ptr<IJson> &item)
6331 {
6332 m_properties.add(*item);
6333 });
6334 }
6335 createTilesetData(json);
6336 processData();
6337
6338 return allFound;
6339}
6340
6341/*!
6342 * Tileset data must be created in two steps to prevent malformed tson::Tileset pointers inside tson::Tile
6343 */
6344void tson::Map::createTilesetData(IJson &json)
6345{
6346 if(json.count("tilesets") > 0 && json["tilesets"].isArray())
6347 {
6348 //First created tileset objects
6349 auto &tilesets = json.array("tilesets");
6350 std::for_each(tilesets.begin(), tilesets.end(), [&](std::unique_ptr<IJson> &item)
6351 {
6352 m_tilesets.emplace_back();
6353 });
6354
6355 int i = 0;
6356 //Then do the parsing
6357 std::for_each(tilesets.begin(), tilesets.end(), [&](std::unique_ptr<IJson> &item)
6358 {
6359 m_tilesets[i].parse(*item, this);
6360 ++i;
6361 });
6362 }
6363}
6364
6365/*!
6366 * Processes the parsed data and uses the data to create helpful objects, like tile maps.
6367 */
6368void tson::Map::processData()
6369{
6370 m_tileMap.clear();
6371 for(auto &tileset : m_tilesets)
6372 {
6373 std::for_each(tileset.getTiles().begin(), tileset.getTiles().end(), [&](tson::Tile &tile) { m_tileMap[tile.getGid()] = &tile; });
6374 }
6375 std::for_each(m_layers.begin(), m_layers.end(), [&](tson::Layer &layer)
6376 {
6377 layer.assignTileMap(&m_tileMap);
6378 layer.createTileData(m_size, m_isInfinite);
6379 const std::set<uint32_t> &flaggedTiles = layer.getUniqueFlaggedTiles();
6380 for(uint32_t ftile : flaggedTiles)
6381 {
6382 tson::Tile tile {ftile, layer.getMap()};
6383 if(m_tileMap.count(tile.getGid()))
6384 {
6385 tson::Tile *originalTile = m_tileMap[tile.getGid()];
6386 tile.addTilesetAndPerformCalculations(originalTile->getTileset());
6387 tile.setProperties(originalTile->getProperties());
6388 m_flaggedTileMap[ftile] = tile;
6389 m_tileMap[ftile] = &m_flaggedTileMap[ftile];
6390 }
6391 }
6392 layer.resolveFlaggedTiles();
6393 });
6394}
6395
6396/*!
6397 * 'backgroundcolor': Color created from a hex-formatted color string (#RRGGBB or #AARRGGBB) (optional)
6398 * @return string as color
6399 */
6400const tson::Colori &tson::Map::getBackgroundColor() const
6401{
6402 return m_backgroundColor;
6403}
6404
6405/*!
6406 * 'width' and 'height' of a Tiled map
6407 * @return
6408 */
6409const tson::Vector2<int> &tson::Map::getSize() const
6410{
6411 return m_size;
6412}
6413
6414/*!
6415 * 'hexsidelength': Length of the side of a hex tile in pixels
6416 * @return
6417 */
6418int tson::Map::getHexsideLength() const
6419{
6420 return m_hexsideLength;
6421}
6422
6423/*!
6424 * 'infinite': Whether the map has infinite dimensions
6425 * @return
6426 */
6427bool tson::Map::isInfinite() const
6428{
6429 return m_isInfinite;
6430}
6431
6432/*!
6433 * 'nextlayerid': Auto-increments for each layer
6434 * @return
6435 */
6436int tson::Map::getNextLayerId() const
6437{
6438 return m_nextLayerId;
6439}
6440
6441/*!
6442 * 'nextobjectid': Auto-increments for each placed object
6443 * @return
6444 */
6445int tson::Map::getNextObjectId() const
6446{
6447 return m_nextObjectId;
6448}
6449
6450/*!
6451 * 'orientation': orthogonal, isometric, staggered or hexagonal
6452 * @return
6453 */
6454const std::string &tson::Map::getOrientation() const
6455{
6456 return m_orientation;
6457}
6458
6459/*!
6460 * 'renderorder': Rendering direction (orthogonal maps only)
6461 * @return
6462 */
6463const std::string &tson::Map::getRenderOrder() const
6464{
6465 return m_renderOrder;
6466}
6467
6468/*!
6469 * 'staggeraxis': x or y (staggered / hexagonal maps only)
6470 * @return
6471 */
6472const std::string &tson::Map::getStaggerAxis() const
6473{
6474 return m_staggerAxis;
6475}
6476
6477/*!
6478 * 'staggerindex': odd or even (staggered / hexagonal maps only)
6479 * @return
6480 */
6481const std::string &tson::Map::getStaggerIndex() const
6482{
6483 return m_staggerIndex;
6484}
6485
6486/*!
6487 * 'tiledversion': The Tiled version used to save the file
6488 * @return
6489 */
6490const std::string &tson::Map::getTiledVersion() const
6491{
6492 return m_tiledVersion;
6493}
6494
6495/*!
6496 * 'tilewidth': and 'tileheight' of a map
6497 * @return
6498 */
6499const tson::Vector2<int> &tson::Map::getTileSize() const
6500{
6501 return m_tileSize;
6502}
6503
6504/*!
6505 * 'type': map (since 1.0)
6506 * @return
6507 */
6508const std::string &tson::Map::getType() const
6509{
6510 return m_type;
6511}
6512
6513/*!
6514 * 'version': The JSON format version
6515 * @return
6516 */
6517int tson::Map::getVersion() const
6518{
6519 return m_version;
6520}
6521
6522/*!
6523 * 'layers': Array of layers. group on
6524 * @return
6525 */
6526std::vector<tson::Layer> &tson::Map::getLayers()
6527{
6528 return m_layers;
6529}
6530
6531/*!
6532 * 'properties': A list of properties (name, value, type).
6533 * @return
6534 */
6535tson::PropertyCollection &tson::Map::getProperties()
6536{
6537 return m_properties;
6538}
6539
6540/*!
6541 * 'tilesets': Array of Tilesets
6542 * @return
6543 */
6544std::vector<tson::Tileset> &tson::Map::getTilesets()
6545{
6546 return m_tilesets;
6547}
6548
6549tson::Layer *tson::Map::getLayer(const std::string &name)
6550{
6551 auto result = std::find_if(m_layers.begin(), m_layers.end(), [&](const tson::Layer &item) { return item.getName() == name; });
6552 if(result == m_layers.end())
6553 return nullptr;
6554
6555 return &result.operator*();
6556}
6557
6558/*!
6559 * Gets a tileset by name
6560 *
6561 * @param name Name of the tileset
6562 * @return tileset with the matching name
6563 */
6564tson::Tileset *tson::Map::getTileset(const std::string &name)
6565{
6566 auto result = std::find_if(m_tilesets.begin(), m_tilesets.end(), [&](const tson::Tileset &item) {return item.getName() == name; });
6567 if(result == m_tilesets.end())
6568 return nullptr;
6569
6570 return &result.operator*();
6571}
6572
6573/*!
6574 * Gets a tileset by gid (graphical ID of a tile). These are always unique, no matter how many tilesets you have
6575 *
6576 * @param gid Graphical ID of a tile
6577 * @return tileset related to the actual gid
6578 */
6579tson::Tileset *tson::Map::getTilesetByGid(uint32_t gid)
6580{
6581 auto result = std::find_if(m_tilesets.begin(), m_tilesets.end(), [&](const tson::Tileset &tileset)
6582 {
6583 int firstId = tileset.getFirstgid(); //First tile id of the tileset
6584 int lastId = (firstId + tileset.getTileCount()) - 1;
6585
6586 return (gid >= firstId && gid <= lastId);
6587 });
6588 if(result == m_tilesets.end())
6589 return nullptr;
6590
6591 return &result.operator*();
6592}
6593
6594/*!
6595 * Shortcut for getting a property object. Alternative to getProperties().getProperty("<name>");
6596 * @param name Name of the property
6597 * @return
6598 */
6599tson::Property *tson::Map::getProp(const std::string &name)
6600{
6601 if(m_properties.hasProperty(name))
6602 return m_properties.getProperty(name);
6603 return nullptr;
6604}
6605
6606tson::ParseStatus tson::Map::getStatus() const
6607{
6608 return m_status;
6609}
6610
6611const std::string &tson::Map::getStatusMessage() const
6612{
6613 return m_statusMessage;
6614}
6615
6616/*!
6617 * Get a tile map with pointers to every existing tile.
6618 * @return
6619 */
6620const std::map<uint32_t, tson::Tile *> &tson::Map::getTileMap() const
6621{
6622 return m_tileMap;
6623}
6624
6625tson::DecompressorContainer *tson::Map::getDecompressors()
6626{
6627 return m_decompressors;
6628}
6629
6630/*!
6631 * 'compressionlevel': The compression level to use for tile layer data (defaults to -1, which means to use the algorithm default)
6632 *
6633 * @return The compression level
6634 */
6635int tson::Map::getCompressionLevel() const
6636{
6637 return m_compressionLevel;
6638}
6639
6640#endif //TILESON_MAP_HPP
6641
6642/*** End of inlined file: Map.hpp ***/
6643
6644
6645/*** Start of inlined file: Project.hpp ***/
6646//
6647// Created by robin on 01.08.2020.
6648//
6649
6650#ifndef TILESON_PROJECT_HPP
6651#define TILESON_PROJECT_HPP
6652
6653#include <fstream>
6654#include <sstream>
6655#include <memory>
6656
6657/*** Start of inlined file: World.hpp ***/
6658//
6659// Created by robin on 01.08.2020.
6660//
6661
6662#ifndef TILESON_WORLD_HPP
6663#define TILESON_WORLD_HPP
6664
6665
6666/*** Start of inlined file: WorldMapData.hpp ***/
6667//
6668// Created by robin on 01.08.2020.
6669//
6670
6671#ifndef TILESON_WORLDMAPDATA_HPP
6672#define TILESON_WORLDMAPDATA_HPP
6673
6674namespace tson
6675{
6676 class WorldMapData
6677 {
6678 public:
6679 inline WorldMapData(const fs::path &folder_, IJson &json);
6680 inline void parse(const fs::path &folder_, IJson &json);
6681 //inline WorldMapData(fs::path folder_, std::string fileName_) : folder {std::move(folder_)}, fileName {fileName_}
6682 //{
6683 // path = folder / fileName;
6684 //}
6685
6686 fs::path folder;
6687 fs::path path;
6688 std::string fileName;
6689 tson::Vector2i size;
6690 tson::Vector2i position;
6691 };
6692
6693 WorldMapData::WorldMapData(const fs::path &folder_, IJson &json)
6694 {
6695 parse(folder_, json);
6696 }
6697
6698 void WorldMapData::parse(const fs::path &folder_, IJson &json)
6699 {
6700 folder = folder_;
6701 if(json.count("fileName") > 0) fileName = json["fileName"].get<std::string>();
6702 if(json.count("height") > 0) size = {json["width"].get<int>(), json["height"].get<int>()};
6703 if(json.count("x") > 0) position = {json["x"].get<int>(), json["y"].get<int>()};
6704
6705 path = (!fileName.empty()) ? folder / fileName : folder;
6706 }
6707}
6708
6709#endif //TILESON_WORLDMAPDATA_HPP
6710/*** End of inlined file: WorldMapData.hpp ***/
6711
6712#include <memory>
6713namespace tson
6714{
6715 class Tileson;
6716 class World
6717 {
6718 public:
6719 #ifdef JSON11_IS_DEFINED
6720 inline explicit World(std::unique_ptr<tson::IJson> jsonParser = std::make_unique<tson::Json11>()) : m_json {std::move(jsonParser)}
6721 {
6722 }
6723
6724 inline explicit World(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser = std::make_unique<tson::Json11>());
6725 #else
6726 inline explicit World(std::unique_ptr<tson::IJson> jsonParser) : m_json {std::move(jsonParser)}
6727 {
6728 }
6729
6730 inline explicit World(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser);
6731 #endif
6732 inline bool parse(const fs::path &path);
6733 inline int loadMaps(tson::Tileson *parser); //tileson_forward.hpp
6734 inline bool contains(std::string_view filename);
6735 inline const WorldMapData *get(std::string_view filename) const;
6736
6737 [[nodiscard]] inline const fs::path &getPath() const;
6738 [[nodiscard]] inline const fs::path &getFolder() const;
6739 [[nodiscard]] inline const std::vector<WorldMapData> &getMapData() const;
6740 [[nodiscard]] inline bool onlyShowAdjacentMaps() const;
6741 [[nodiscard]] inline const std::string &getType() const;
6742 [[nodiscard]] inline const std::vector<std::unique_ptr<tson::Map>> &getMaps() const;
6743
6744 private:
6745 inline void parseJson(IJson &json);
6746
6747 std::unique_ptr<IJson> m_json = nullptr;
6748 fs::path m_path;
6749 fs::path m_folder;
6750 std::vector<WorldMapData> m_mapData;
6751 std::vector<std::unique_ptr<tson::Map>> m_maps;
6752 bool m_onlyShowAdjacentMaps;
6753 std::string m_type;
6754 };
6755
6756 World::World(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser) : m_json {std::move(jsonParser)}
6757 {
6758 parse(path);
6759 }
6760
6761 bool World::parse(const fs::path &path)
6762 {
6763 m_path = path;
6764 m_folder = m_path.parent_path();
6765
6766 if(!m_json->parse(path))
6767 return false;
6768
6769 parseJson(*m_json);
6770 return true;
6771 }
6772
6773 const fs::path &World::getPath() const
6774 {
6775 return m_path;
6776 }
6777
6778 const std::vector<WorldMapData> &World::getMapData() const
6779 {
6780 return m_mapData;
6781 }
6782
6783 bool World::onlyShowAdjacentMaps() const
6784 {
6785 return m_onlyShowAdjacentMaps;
6786 }
6787
6788 const std::string &World::getType() const
6789 {
6790 return m_type;
6791 }
6792
6793 void World::parseJson(IJson &json)
6794 {
6795 if(json.count("onlyShowAdjacentMaps") > 0) m_onlyShowAdjacentMaps = json["onlyShowAdjacentMaps"].get<bool>();
6796 if(json.count("type") > 0) m_type = json["type"].get<std::string>();
6797
6798 if(json["maps"].isArray())
6799 {
6800 auto &maps = json.array("maps");
6801 std::for_each(maps.begin(), maps.end(), [&](std::unique_ptr<IJson> &item) { m_mapData.emplace_back(m_folder, *item); });
6802 }
6803 }
6804
6805 const fs::path &World::getFolder() const
6806 {
6807 return m_folder;
6808 }
6809
6810 /*!
6811 * Check if there is WorldMapData in the world that contains the current filename.
6812 * Filename = <file>.<extension>
6813 * @param filename
6814 * @return
6815 */
6816 bool World::contains(std::string_view filename)
6817 {
6818 //Note: might be moved to std::ranges from C++20.
6819 return std::any_of(m_mapData.begin(), m_mapData.end(), [&](const auto &item) { return item.fileName == filename; });
6820 }
6821
6822 /*!
6823 * Get a map by its filename
6824 * @param filename Filename (including extension) - (example: file.json)
6825 * @return pointer to WorldMapData or nullptr if not exists
6826 */
6827 const WorldMapData * World::get(std::string_view filename) const
6828 {
6829 auto iter = std::find_if(m_mapData.begin(), m_mapData.end(), [&](const auto &item) { return item.fileName == filename; });
6830 return (iter == m_mapData.end()) ? nullptr : iter.operator->();
6831 }
6832
6833 /*!
6834 * Get all maps that have been loaded by loadMaps().
6835 * NOTE: This is untested, and was a last second addition to Tileson 1.2.0, as I had forgot about the loadMaps() functionality (also untested)
6836 * If you find anything malfunctioning - please report.
6837 * @return All maps loaded by loadMaps()
6838 */
6839 const std::vector<std::unique_ptr<tson::Map>> &World::getMaps() const
6840 {
6841 return m_maps;
6842 }
6843
6844}
6845
6846#endif //TILESON_WORLD_HPP
6847/*** End of inlined file: World.hpp ***/
6848
6849
6850
6851/*** Start of inlined file: ProjectFolder.hpp ***/
6852//
6853// Created by robin on 01.08.2020.
6854//
6855
6856#ifndef TILESON_PROJECTFOLDER_HPP
6857#define TILESON_PROJECTFOLDER_HPP
6858
6859namespace tson
6860{
6861 class ProjectFolder
6862 {
6863 public:
6864 inline ProjectFolder(const fs::path &path);
6865
6866 inline const fs::path &getPath() const;
6867 inline bool hasWorldFile() const;
6868 inline const std::vector<ProjectFolder> &getSubFolders() const;
6869 inline const std::vector<fs::path> &getFiles() const;
6870 inline const World &getWorld() const;
6871
6872 private:
6873 inline void loadData();
6874 fs::path m_path;
6875 bool m_hasWorldFile;
6876 tson::World m_world;
6877 std::vector<ProjectFolder> m_subFolders;
6878 std::vector<fs::path> m_files;
6879
6880 };
6881
6882 ProjectFolder::ProjectFolder(const fs::path &path) : m_path {path}
6883 {
6884 loadData();
6885 }
6886
6887 void ProjectFolder::loadData()
6888 {
6889 m_hasWorldFile = false;
6890 m_subFolders.clear();
6891 m_files.clear();
6892 //Search and see if there is a World file .world file
6893 fs::path worldPath;
6894 for (const auto & entry : fs::directory_iterator(m_path))
6895 {
6896 if(fs::is_regular_file(entry.path()))
6897 {
6898 if(entry.path().extension() == ".world")
6899 {
6900 m_hasWorldFile = true;
6901 worldPath = entry.path();
6902 }
6903 }
6904 }
6905
6906 if(m_hasWorldFile)
6907 m_world.parse(worldPath);
6908
6909 for (const auto & entry : fs::directory_iterator(m_path))
6910 {
6911 if (fs::is_directory(entry.path()))
6912 m_subFolders.emplace_back(entry.path());//.loadData(); - loadData() is called in the constructor, so don't call again.
6913 else if (fs::is_regular_file(entry.path()))
6914 {
6915 if(m_hasWorldFile && m_world.contains(entry.path().filename().u8string()))
6916 m_files.emplace_back(entry.path());
6917 else if(!m_hasWorldFile)
6918 m_files.emplace_back(entry.path());
6919 }
6920 }
6921
6922 }
6923
6924 const fs::path &ProjectFolder::getPath() const
6925 {
6926 return m_path;
6927 }
6928
6929 bool ProjectFolder::hasWorldFile() const
6930 {
6931 return m_hasWorldFile;
6932 }
6933
6934 const std::vector<ProjectFolder> &ProjectFolder::getSubFolders() const
6935 {
6936 return m_subFolders;
6937 }
6938
6939 const std::vector<fs::path> &ProjectFolder::getFiles() const
6940 {
6941 return m_files;
6942 }
6943
6944 /*!
6945 * Only gives useful data if hasWorldFile() is true!
6946 * @return
6947 */
6948 const World &ProjectFolder::getWorld() const
6949 {
6950 return m_world;
6951 }
6952}
6953
6954#endif //TILESON_PROJECTFOLDER_HPP
6955/*** End of inlined file: ProjectFolder.hpp ***/
6956
6957
6958/*** Start of inlined file: ProjectData.hpp ***/
6959//
6960// Created by robin on 01.08.2020.
6961//
6962
6963#ifndef TILESON_PROJECTDATA_HPP
6964#define TILESON_PROJECTDATA_HPP
6965
6966namespace tson
6967{
6968 class ProjectData
6969 {
6970 public:
6971 ProjectData() = default;
6972 std::string automappingRulesFile;
6973 std::vector<std::string> commands;
6974 std::string extensionsPath;
6975 std::vector<std::string> folders;
6976 std::string objectTypesFile;
6977
6978 //Tileson specific
6979 fs::path basePath;
6980 std::vector<tson::ProjectFolder> folderPaths;
6981 };
6982}
6983
6984#endif //TILESON_PROJECTDATA_HPP
6985/*** End of inlined file: ProjectData.hpp ***/
6986
6987namespace tson
6988{
6989 class Project
6990 {
6991 public:
6992 #ifdef JSON11_IS_DEFINED
6993 inline explicit Project(std::unique_ptr<tson::IJson> jsonParser = std::make_unique<tson::Json11>()) : m_json {std::move(jsonParser)}
6994 {
6995
6996 }
6997 inline explicit Project(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser = std::make_unique<tson::Json11>());
6998 #else
6999 inline explicit Project(std::unique_ptr<tson::IJson> jsonParser) : m_json {std::move(jsonParser)}
7000 {
7001
7002 }
7003 inline explicit Project(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser);
7004 #endif
7005 inline bool parse(const fs::path &path);
7006
7007 [[nodiscard]] inline const ProjectData &getData() const;
7008 [[nodiscard]] inline const fs::path &getPath() const;
7009 [[nodiscard]] inline const std::vector<ProjectFolder> &getFolders() const;
7010
7011 private:
7012 inline void parseJson(IJson &json);
7013 fs::path m_path;
7014 std::vector<ProjectFolder> m_folders;
7015 ProjectData m_data;
7016 std::unique_ptr<IJson> m_json = nullptr;
7017 };
7018
7019 Project::Project(const fs::path &path, std::unique_ptr<tson::IJson> jsonParser) : m_json {std::move(jsonParser)}
7020 {
7021 parse(path);
7022 }
7023
7024 bool Project::parse(const fs::path &path)
7025 {
7026 m_path = path;
7027 std::ifstream i(m_path.u8string());
7028
7029 try
7030 {
7031 if(!m_json->parse(path))
7032 return false;
7033 }
7034 catch(const std::exception &error)
7035 {
7036 std::string message = "Parse error: ";
7037 message += std::string(error.what());
7038 message += std::string("\n");
7039 return false;
7040 }
7041 parseJson(*m_json);
7042 return true;
7043 }
7044
7045 const ProjectData &Project::getData() const
7046 {
7047 return m_data;
7048 }
7049
7050 void Project::parseJson(IJson &json)
7051 {
7052 m_data.basePath = m_path.parent_path(); //The directory of the project file
7053
7054 if(json.count("automappingRulesFile") > 0) m_data.automappingRulesFile = json["automappingRulesFile"].get<std::string>();
7055 if(json.count("commands") > 0)
7056 {
7057 m_data.commands.clear();
7058 auto &commands = json.array("commands");
7059 std::for_each(commands.begin(), commands.end(), [&](std::unique_ptr<IJson> &item)
7060 {
7061 m_data.commands.emplace_back(item->get<std::string>());
7062 });
7063 }
7064 if(json.count("extensionsPath") > 0) m_data.extensionsPath = json["extensionsPath"].get<std::string>();
7065 if(json.count("folders") > 0)
7066 {
7067 m_data.folders.clear();
7068 m_data.folderPaths.clear();
7069 auto &folders = json.array("folders");
7070 std::for_each(folders.begin(), folders.end(), [&](std::unique_ptr<IJson> &item)
7071 {
7072 std::string folder = item->get<std::string>();
7073 m_data.folders.emplace_back(folder);
7074 m_data.folderPaths.emplace_back(m_data.basePath / folder);
7075 m_folders.emplace_back(m_data.basePath / folder);
7076 });
7077 }
7078 if(json.count("objectTypesFile") > 0) m_data.objectTypesFile = json["objectTypesFile"].get<std::string>();
7079
7080 }
7081
7082 const fs::path &Project::getPath() const
7083 {
7084 return m_path;
7085 }
7086
7087 const std::vector<ProjectFolder> &Project::getFolders() const
7088 {
7089 return m_folders;
7090 }
7091
7092}
7093
7094#endif //TILESON_PROJECT_HPP
7095
7096/*** End of inlined file: Project.hpp ***/
7097
7098namespace tson
7099{
7100 class Tileson
7101 {
7102 public:
7103 #ifdef JSON11_IS_DEFINED
7104 inline explicit Tileson(std::unique_ptr<tson::IJson> jsonParser = std::make_unique<tson::Json11>(), bool includeBase64Decoder = true);
7105 #else
7106 inline explicit Tileson(std::unique_ptr<tson::IJson> jsonParser, bool includeBase64Decoder = true);
7107 #endif
7108
7109 inline std::unique_ptr<tson::Map> parse(const fs::path &path, std::unique_ptr<IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>> decompressor = nullptr);
7110 inline std::unique_ptr<tson::Map> parse(const void * data, size_t size, std::unique_ptr<IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>> decompressor = nullptr);
7111 inline tson::DecompressorContainer *decompressors();
7112
7113 private:
7114 inline std::unique_ptr<tson::Map> parseJson();
7115 std::unique_ptr<tson::IJson> m_json;
7116 tson::DecompressorContainer m_decompressors;
7117 };
7118}
7119
7120/*!
7121 *
7122 * @param includeBase64Decoder Includes the base64-decoder from "Base64Decompressor.hpp" if true.
7123 * Otherwise no other decompressors/decoders than whatever the user itself have added will be used.
7124 */
7125tson::Tileson::Tileson(std::unique_ptr<tson::IJson> jsonParser, bool includeBase64Decoder) : m_json {std::move(jsonParser)}
7126{
7127 if(includeBase64Decoder)
7128 m_decompressors.add<Base64Decompressor>();
7129}
7130
7131/*!
7132 * Parses Tiled json map data by file
7133 * @param path path to file
7134 * @return parsed data as Map
7135 */
7136std::unique_ptr<tson::Map> tson::Tileson::parse(const fs::path &path, std::unique_ptr<IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>> decompressor)
7137{
7138
7139 bool result = false;
7140
7141 if(decompressor != nullptr)
7142 {
7143 std::vector<uint8_t> decompressed = decompressor->decompressFile(path);
7144 result = (decompressed.empty()) ? false : true;
7145 if(!result)
7146 return std::make_unique<tson::Map>(tson::ParseStatus::DecompressionError, "Error during decompression");
7147 result = m_json->parse(&decompressed[0], decompressed.size());
7148 if(result)
7149 return std::move(parseJson());
7150 }
7151 else if(m_json->parse(path))
7152 {
7153 return std::move(parseJson());
7154 }
7155
7156 std::string msg = "File not found: ";
7157 msg += std::string(path.u8string());
7158 return std::make_unique<tson::Map>(tson::ParseStatus::FileNotFound, msg);
7159}
7160
7161/*!
7162 * Parses Tiled json map data by memory
7163 * @param data The data to parse
7164 * @param size The size of the data to parse
7165 * @return parsed data as Map
7166 */
7167std::unique_ptr<tson::Map> tson::Tileson::parse(const void *data, size_t size, std::unique_ptr<IDecompressor<std::vector<uint8_t>, std::vector<uint8_t>>> decompressor)
7168{
7169 bool result = false;
7170
7171 if(decompressor != nullptr)
7172 {
7173 std::vector<uint8_t> decompressed = decompressor->decompress(data, size);
7174 result = (decompressed.empty()) ? false : true;
7175 if(!result)
7176 return std::make_unique<tson::Map>(tson::ParseStatus::DecompressionError, "Error during decompression");
7177 result = m_json->parse(&decompressed[0], decompressed.size());
7178 }
7179 else
7180 result = m_json->parse(data, size);
7181
7182 if(!result)
7183 return std::make_unique<tson::Map>(tson::ParseStatus::ParseError, "Memory error");
7184
7185 return std::move(parseJson());
7186}
7187
7188/*!
7189 * Common parsing functionality for doing the json parsing
7190 * @param json Tiled json to parse
7191 * @return parsed data as Map
7192 */
7193std::unique_ptr<tson::Map> tson::Tileson::parseJson()
7194{
7195 std::unique_ptr<tson::Map> map = std::make_unique<tson::Map>();
7196
7197 if(map->parse(*m_json, &m_decompressors))
7198 return std::move(map);
7199
7200 return std::make_unique<tson::Map> (tson::ParseStatus::MissingData, "Missing map data...");
7201}
7202
7203/*!
7204 * Gets the decompressor container used when something is either encoded or compressed (regardless: IDecompressor is used as base).
7205 * These are used specifically for tile layers, and are connected by checking the name of the IDecompressor. If the name of a decompressor
7206 * matches with an encoding or a compression, its decompress() function will be used.
7207 *
7208 * @return The container including all decompressors.
7209 */
7210tson::DecompressorContainer *tson::Tileson::decompressors()
7211{
7212 return &m_decompressors;
7213}
7214
7215#endif //TILESON_TILESON_PARSER_HPP
7216
7217/*** End of inlined file: tileson_parser.hpp ***/
7218
7219
7220/*** Start of inlined file: tileson_forward.hpp ***/
7221//
7222// Created by robin on 25.07.2020.
7223//
7224
7225#ifndef TILESON_TILESON_FORWARD_HPP
7226#define TILESON_TILESON_FORWARD_HPP
7227/*!
7228 * T I L E S O N F O R W A R D D E C L A R A T I O N S
7229 * -------------------------------------------------------
7230 *
7231 * Due to cross-references we have forward declarations that cannot be resolved during the
7232 * implementation, thus the implementations must be done later when the class definition itself is known.
7233 *
7234 * All those forward declarations can be found below.
7235 */
7236
7237// T i l e . h p p
7238// ---------------------
7239
7240/*!
7241 * Really just a shortcut to retrieve the tile size from the map.
7242 * @return TileSize based on the map property for tile size.
7243 */
7244const tson::Vector2i tson::Tile::getTileSize() const
7245{
7246 if(m_map != nullptr)
7247 return m_map->getTileSize();
7248 else
7249 return {0,0};
7250}
7251
7252bool tson::Tile::parseId(IJson &json)
7253{
7254 if(json.count("id") > 0)
7255 {
7256 m_id = json["id"].get<uint32_t>() + 1;
7257 if (m_tileset != nullptr)
7258 m_gid = m_tileset->getFirstgid() + m_id - 1;
7259 else
7260 m_gid = m_id;
7261 manageFlipFlagsByIdThenRemoveFlags(m_gid);
7262 return true;
7263 }
7264 return false;
7265}
7266
7267/*!
7268 * Uses tson::Tileset and tson::Map data to calculate related values for tson::Tile.
7269 * Added in v1.2.0
7270 */
7271void tson::Tile::performDataCalculations()
7272{
7273 if(m_tileset == nullptr || m_map == nullptr)
7274 return;
7275
7276 int firstId = m_tileset->getFirstgid(); //First tile id of the tileset
7277 int columns = m_tileset->getColumns();
7278 int rows = m_tileset->getTileCount() / columns;
7279 int lastId = (m_tileset->getFirstgid() + m_tileset->getTileCount()) - 1;
7280
7281 if (getGid() >= firstId && getGid() <= lastId)
7282 {
7283 int baseTilePosition = ((int)getGid() - firstId);
7284
7285 int tileModX = (baseTilePosition % columns);
7286 int currentRow = (baseTilePosition / columns);
7287 int offsetX = (tileModX != 0) ? ((tileModX) * m_map->getTileSize().x) : (0 * m_map->getTileSize().x);
7288 int offsetY = (currentRow < rows-1) ? (currentRow * m_map->getTileSize().y) : ((rows-1) * m_map->getTileSize().y);
7289
7290 m_drawingRect = { offsetX, offsetY, m_map->getTileSize().x, m_map->getTileSize().y };
7291 }
7292 else
7293 m_drawingRect = {0, 0, 0, 0};
7294}
7295
7296/*!
7297 * Get the position of the tile in pixels based on the tile data position from the current layer.
7298 * @return The position of the tile in Pixels
7299 */
7300const tson::Vector2f tson::Tile::getPosition(const std::tuple<int, int> &tileDataPos)
7301{
7302 return {((float) std::get<0>(tileDataPos)) * m_drawingRect.width, ((float) std::get<1>(tileDataPos)) * m_drawingRect.height};
7303}
7304
7305// T i l e O b j e c t . h p p
7306// ---------------------
7307
7308/*!
7309 * In cases where the empty constructor is called, this must be called manually
7310 * for this class to make sense
7311 * @param posInTileUnits
7312 * @param tile
7313 */
7314void tson::TileObject::initialize(const std::tuple<int, int> &posInTileUnits, tson::Tile *tile)
7315{
7316 m_tile = tile;
7317 m_posInTileUnits = tile->getPositionInTileUnits(posInTileUnits);
7318 m_position = tile->getPosition(posInTileUnits);
7319}
7320
7321const tson::Rect &tson::TileObject::getDrawingRect() const
7322{
7323 return m_tile->getDrawingRect();
7324}
7325
7326// L a y e r . h p p
7327// -------------------
7328
7329/*!
7330 * Decompresses data if there are matching decompressors
7331 */
7332void tson::Layer::decompressData()
7333{
7334
7335 tson::DecompressorContainer *container = m_map->getDecompressors();
7336 if(container->empty())
7337 return;
7338
7339 if(m_encoding.empty() && m_compression.empty())
7340 return;
7341
7342 std::string data = m_base64Data;
7343 bool hasBeenDecoded = false;
7344 if(!m_encoding.empty() && container->contains(m_encoding))
7345 {
7346 data = container->get(m_encoding)->decompress(data);
7347 hasBeenDecoded = true;
7348 }
7349
7350 if(!m_compression.empty() && container->contains(m_compression))
7351 {
7352 data = container->get(m_compression)->decompress(data);
7353 }
7354
7355 if(hasBeenDecoded)
7356 {
7357 std::vector<uint8_t> bytes = tson::Tools::Base64DecodedStringToBytes(data);
7358 m_data = tson::Tools::BytesToUnsignedInts(bytes);
7359 }
7360}
7361
7362// W o r l d . h p p
7363// ------------------
7364
7365/*!
7366 * Loads the actual maps based on the world data.
7367 * @param parser A Tileson object used for parsing the maps of the world.
7368 * @return How many maps who were parsed. Remember to call getStatus() for the actual map to find out if everything went okay.
7369 */
7370
7371int tson::World::loadMaps(tson::Tileson *parser)
7372{
7373 m_maps.clear();
7374 std::for_each(m_mapData.begin(), m_mapData.end(), [&](const tson::WorldMapData &data)
7375 {
7376 if(fs::exists(data.path))
7377 {
7378 std::unique_ptr<tson::Map> map = parser->parse(data.path);
7379 m_maps.push_back(std::move(map));
7380 }
7381 });
7382
7383 return m_maps.size();
7384}
7385
7386#endif //TILESON_TILESON_FORWARD_HPP
7387
7388/*** End of inlined file: tileson_forward.hpp ***/
7389
7390#endif //TILESON_TILESON_H
7391