5#include "absl/strings/str_cat.h"
6#include "nlohmann/json.hpp"
13 : rom_(rom), game_data_(game_data) {}
16 if (
rom_ ==
nullptr) {
17 return absl::InvalidArgumentError(
"ROM is null");
24 return absl::OkStatus();
31 return absl::OkStatus();
36 return absl::InvalidArgumentError(
"ROM is null");
48 return absl::OkStatus();
61 return absl::InvalidArgumentError(
"Invalid room ID");
65 return absl::OkStatus();
74 return absl::InvalidArgumentError(
"Invalid room ID");
93 return absl::FailedPreconditionError(
"Nothing to undo");
96 return absl::OkStatus();
105 return absl::FailedPreconditionError(
"Nothing to redo");
108 return absl::OkStatus();
162 return absl::InvalidArgumentError(
"ROM is null");
166 return absl::OkStatus();
171 return absl::InvalidArgumentError(
"ROM is null");
181 return absl::OkStatus();
186 return std::make_unique<DungeonEditorSystem>(rom, game_data);
190 using json = nlohmann::json;
194 tmpl[
"room_id"] = room.
id();
198 props[
"blockset"] = room.
blockset();
199 props[
"palette"] = room.
palette();
202 tmpl[
"properties"] = props;
205 json objects_arr = json::array();
208 obj_json[
"id"] = obj.id_;
209 obj_json[
"x"] = obj.x_;
210 obj_json[
"y"] = obj.y_;
211 obj_json[
"size"] = obj.size_;
212 obj_json[
"layer"] = obj.GetLayerValue();
213 objects_arr.push_back(obj_json);
215 tmpl[
"objects"] = objects_arr;
218 json sprites_arr = json::array();
219 for (
const auto& sprite : room.
GetSprites()) {
221 spr_json[
"id"] = sprite.id();
222 spr_json[
"x"] = sprite.x();
223 spr_json[
"y"] = sprite.y();
224 spr_json[
"subtype"] = sprite.subtype();
225 spr_json[
"layer"] = sprite.layer();
226 sprites_arr.push_back(spr_json);
228 tmpl[
"sprites"] = sprites_arr;
231 json items_arr = json::array();
234 item_json[
"position"] = item.position;
235 item_json[
"item"] = item.item;
236 items_arr.push_back(item_json);
238 tmpl[
"pot_items"] = items_arr;
244 bool apply_properties) {
245 using json = nlohmann::json;
249 tmpl = json::parse(json_str);
250 }
catch (
const json::parse_error& err) {
251 return absl::InvalidArgumentError(
252 absl::StrCat(
"Invalid JSON: ", err.what()));
255 if (!tmpl.contains(
"version") || tmpl[
"version"].get<
int>() != 1) {
256 return absl::InvalidArgumentError(
"Unsupported template version");
260 if (apply_properties && tmpl.contains(
"properties")) {
261 const auto& props = tmpl[
"properties"];
262 if (props.contains(
"blockset"))
264 if (props.contains(
"palette"))
266 if (props.contains(
"layout"))
268 if (props.contains(
"spriteset"))
273 if (tmpl.contains(
"objects")) {
276 for (
const auto& obj_json : tmpl[
"objects"]) {
277 int16_t obj_id = obj_json.value(
"id",
static_cast<int16_t
>(0));
278 uint8_t obj_x = obj_json.value(
"x",
static_cast<uint8_t
>(0));
279 uint8_t obj_y = obj_json.value(
"y",
static_cast<uint8_t
>(0));
280 uint8_t obj_size = obj_json.value(
"size",
static_cast<uint8_t
>(0));
281 uint8_t obj_layer = obj_json.value(
"layer",
static_cast<uint8_t
>(0));
282 objects.emplace_back(obj_id, obj_x, obj_y, obj_size, obj_layer);
287 if (tmpl.contains(
"sprites")) {
290 for (
const auto& spr_json : tmpl[
"sprites"]) {
291 uint8_t spr_id = spr_json.value(
"id",
static_cast<uint8_t
>(0));
292 uint8_t spr_x = spr_json.value(
"x",
static_cast<uint8_t
>(0));
293 uint8_t spr_y = spr_json.value(
"y",
static_cast<uint8_t
>(0));
294 uint8_t spr_sub = spr_json.value(
"subtype",
static_cast<uint8_t
>(0));
295 uint8_t spr_layer = spr_json.value(
"layer",
static_cast<uint8_t
>(0));
296 sprites.emplace_back(spr_id, spr_x, spr_y, spr_sub, spr_layer);
301 if (tmpl.contains(
"pot_items")) {
304 for (
const auto& item_json : tmpl[
"pot_items"]) {
306 item.
position = item_json.value(
"position",
static_cast<uint16_t
>(0));
307 item.
item = item_json.value(
"item",
static_cast<uint8_t
>(0));
308 items.push_back(item);
312 return absl::OkStatus();
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
int GetCurrentRoom() const
absl::Status SaveRoom(int room_id)
absl::Status InitializeObjectEditor()
void SetExternalRoom(Room *room)
RoomChangedCallback room_changed_callback_
absl::Status SaveDungeon()
void SetRoomChangedCallback(RoomChangedCallback callback)
absl::Status SaveRoomData(int room_id)
std::shared_ptr< DungeonObjectEditor > object_editor_
DungeonEditorSystem(Rom *rom, GameData *game_data=nullptr)
std::shared_ptr< DungeonObjectEditor > GetObjectEditor()
absl::Status SetCurrentRoom(int room_id)
EditorState editor_state_
std::vector< UndoPoint > redo_history_
absl::Status Initialize()
absl::Status LoadRoomData(int room_id)
absl::Status ReloadRoom(int room_id)
std::vector< UndoPoint > undo_history_
absl::Status LoadDungeon(int dungeon_id)
std::function< void(int room_id)> RoomChangedCallback
EditorState GetEditorState() const
absl::StatusOr< Room > GetRoom(int room_id)
void SetLayoutId(uint8_t id)
absl::Status SaveObjects()
uint8_t spriteset() const
const std::vector< zelda3::Sprite > & GetSprites() const
const std::vector< RoomObject > & GetTileObjects() const
void SetSpriteset(uint8_t ss)
void SetBlockset(uint8_t bs)
void SetPalette(uint8_t pal)
uint8_t layout_id() const
const std::vector< PotItem > & GetPotItems() const
absl::Status ApplyRoomLayoutTemplate(Room &room, const std::string &json_str, bool apply_properties)
Apply a previously exported layout template to a room.
absl::StatusOr< std::string > ExportRoomLayoutTemplate(const Room &room)
Export a room's layout as a JSON template string.
constexpr int kNumberOfRooms
std::unique_ptr< DungeonEditorSystem > CreateDungeonEditorSystem(Rom *rom, GameData *game_data)
Factory function to create dungeon editor system.
#define RETURN_IF_ERROR(expr)
std::chrono::steady_clock::time_point last_save_time