yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
sprite_asset_json.h
Go to the documentation of this file.
1#ifndef YAZE_CORE_SPRITE_ASSET_JSON_H_
2#define YAZE_CORE_SPRITE_ASSET_JSON_H_
3#include <set>
4#include <stdexcept>
5#include <vector>
6
7#include "absl/status/statusor.h"
8#include "core/sprite_asset.h"
10#include "nlohmann/json.hpp"
11namespace yaze::project {
12inline nlohmann::json SpriteAssetToJson(const SpriteAssetBinding& asset) {
13 nlohmann::json rows = nlohmann::json::array();
14 for (const auto& row : asset.palette_rows)
15 rows.push_back({{"group", row.group}, {"index", row.index}});
16 nlohmann::json result = {{"version", 1},
17 {"zsm_path", asset.zsm_path},
18 {"catalog_key", asset.catalog_key},
19 {"draw_adapter", asset.draw_adapter},
20 {"source_path", asset.source_path},
21 {"source_label", asset.source_label},
22 {"source_sha256", asset.source_sha256},
23 {"sheets", asset.sheets},
24 {"palette_rows", rows}};
25 if (!asset.behavior.profile.empty()) {
26 result["version"] = 2;
27 result["behavior"] = SpriteBehaviorToJson(asset.behavior);
28 }
29 return result;
30}
31
32inline absl::StatusOr<SpriteAssetBinding> SpriteAssetFromJson(
33 const nlohmann::json& value) {
34 auto invalid = [] {
35 return absl::InvalidArgumentError("Invalid sprite asset binding v1");
36 };
37 try {
38 if (!value.is_object() || !value.at("version").is_number_integer())
39 return invalid();
40 const bool behavior_version = value.at("version") == 2;
41 if ((!behavior_version && value.at("version") != 1) ||
42 value.size() != (behavior_version ? 10 : 9))
43 return invalid();
45 if (behavior_version) {
46 auto behavior = SpriteBehaviorFromJson(value.at("behavior"));
47 if (!behavior.ok())
48 return behavior.status();
49 asset.behavior = std::move(*behavior);
50 }
51 asset.zsm_path = value.at("zsm_path").get<std::string>();
52 asset.catalog_key = value.at("catalog_key").get<std::string>();
53 asset.draw_adapter = value.at("draw_adapter").get<std::string>();
54 asset.source_path = value.at("source_path").get<std::string>();
55 asset.source_label = value.at("source_label").get<std::string>();
56 asset.source_sha256 = value.at("source_sha256").get<std::string>();
57 if (asset.zsm_path.empty() ||
58 asset.zsm_path.find('\0') != std::string::npos ||
59 (asset.draw_adapter != "literal_v1" &&
60 asset.draw_adapter != "oracle_maple_v1"))
61 return invalid();
62 if (!asset.source_path.empty()) {
63 if (asset.source_label.empty() || asset.source_sha256.size() != 64 ||
64 asset.source_sha256.find_first_not_of("0123456789abcdef") !=
65 std::string::npos)
66 return invalid();
67 } else if (!asset.source_label.empty() || !asset.source_sha256.empty()) {
68 return invalid();
69 }
70 const auto& sheets = value.at("sheets");
71 const auto& rows = value.at("palette_rows");
72 if (!sheets.is_array() || sheets.size() != 8 || !rows.is_array() ||
73 rows.size() != 8)
74 return invalid();
75 for (size_t i = 0; i < 8; ++i) {
76 if (!sheets[i].is_number_integer() || sheets[i] < 0 || sheets[i] > 255)
77 return invalid();
78 asset.sheets[i] = sheets[i].get<int>();
79 if (!rows[i].is_object() || rows[i].size() != 2 ||
80 !rows[i].at("index").is_number_integer() || rows[i].at("index") < 0 ||
81 rows[i].at("index") > 255)
82 return invalid();
83 auto& row = asset.palette_rows[i];
84 row.group = rows[i].at("group").get<std::string>();
85 row.index = rows[i].at("index").get<int>();
86 if (row.group != "auto" && row.group != "global_sprites" &&
87 row.group != "sprites_aux1" && row.group != "sprites_aux2" &&
88 row.group != "sprites_aux3")
89 return invalid();
90 }
91 return asset;
92 } catch (const nlohmann::json::exception&) {
93 return invalid();
94 }
95}
96
97inline absl::StatusOr<SpriteAssetBinding> ParseSpriteAssetBinding(
98 const std::string& text) {
99 if (text.size() > 65536)
100 return absl::ResourceExhaustedError("Sprite asset binding exceeds 64 KiB");
101 try {
102 std::vector<std::set<std::string>> keys;
103 auto value = nlohmann::json::parse(
104 text, [&](int depth, nlohmann::json::parse_event_t event,
105 nlohmann::json& node) {
106 if (depth > 16)
107 throw std::runtime_error("Sprite asset nesting exceeds limit");
108 if (event == nlohmann::json::parse_event_t::object_start)
109 keys.emplace_back();
110 else if (event == nlohmann::json::parse_event_t::key) {
111 if (!keys.back().insert(node.get<std::string>()).second)
112 throw std::runtime_error("Duplicate sprite asset field");
113 } else if (event == nlohmann::json::parse_event_t::object_end)
114 keys.pop_back();
115 return true;
116 });
117 return SpriteAssetFromJson(value);
118 } catch (const std::exception& e) {
119 return absl::InvalidArgumentError(e.what());
120 }
121}
122} // namespace yaze::project
123#endif
absl::StatusOr< SpriteBehavior > SpriteBehaviorFromJson(const nlohmann::json &json)
nlohmann::json SpriteBehaviorToJson(const SpriteBehavior &behavior)
absl::StatusOr< SpriteAssetBinding > ParseSpriteAssetBinding(const std::string &text)
nlohmann::json SpriteAssetToJson(const SpriteAssetBinding &asset)
absl::StatusOr< SpriteAssetBinding > SpriteAssetFromJson(const nlohmann::json &value)
std::array< uint8_t, 8 > sheets
std::array< SpritePaletteBinding, 8 > palette_rows