6#include "absl/strings/str_cat.h"
7#include "nlohmann/json.hpp"
26 auto room_lookup_const = [&room](
int room_id) ->
const Room* {
27 return room_id == room.
id() ? &room :
nullptr;
29 auto room_lookup_mut = [&room](
int room_id) ->
Room* {
30 return room_id == room.
id() ? &room :
nullptr;
37 return absl::OkStatus();
43 : rom_(rom), game_data_(game_data) {}
53 if (
rom_ ==
nullptr) {
54 return absl::InvalidArgumentError(
"ROM is null");
61 return absl::OkStatus();
68 return absl::OkStatus();
73 return absl::InvalidArgumentError(
"ROM is null");
75 std::vector<int> room_ids;
76 room_ids.reserve(
rooms_.size() + 1);
80 for (
const auto& [room_id, room] :
rooms_) {
82 if (std::find(room_ids.begin(), room_ids.end(), room_id) ==
84 room_ids.push_back(room_id);
88 for (
int room_id : room_ids) {
90 if (room ==
nullptr) {
94 if (room ==
nullptr || !room->
IsLoaded()) {
103 auto room_lookup_const = [
this](
int room_id) ->
const Room* {
106 auto room_lookup_mut = [
this](
int room_id) ->
Room* {
118 return absl::OkStatus();
131 return absl::InvalidArgumentError(
"Invalid room ID");
147 return absl::InvalidArgumentError(
"Invalid room ID");
168 return absl::FailedPreconditionError(
"Nothing to undo");
171 return absl::OkStatus();
180 return absl::FailedPreconditionError(
"Nothing to redo");
183 return absl::OkStatus();
231 int current_room_id) {
246 return absl::OkStatus();
257 return absl::OkStatus();
261 return absl::OkStatus();
265 if (room ==
nullptr) {
269 if (room ==
nullptr) {
270 return absl::NotFoundError(
"Current room is not available");
273 return absl::OkStatus();
280 auto it =
rooms_.find(room_id);
288 return SaveSingleRoomState(
rom_, room);
301 return absl::InvalidArgumentError(
"ROM is null");
304 return absl::InvalidArgumentError(
"Invalid room ID");
316 return absl::OkStatus();
321 return absl::InvalidArgumentError(
"ROM is null");
324 return absl::InvalidArgumentError(
"Invalid room ID");
328 if (room ==
nullptr) {
332 if (room ==
nullptr) {
333 return absl::NotFoundError(
"Room is not available");
336 return absl::OkStatus();
344 return std::make_unique<DungeonEditorSystem>(rom, game_data);
348 using json = nlohmann::json;
352 tmpl[
"room_id"] = room.
id();
356 props[
"blockset"] = room.
blockset();
357 props[
"palette"] = room.
palette();
360 tmpl[
"properties"] = props;
363 json objects_arr = json::array();
366 obj_json[
"id"] = obj.id_;
367 obj_json[
"x"] = obj.x_;
368 obj_json[
"y"] = obj.y_;
369 obj_json[
"size"] = obj.size_;
370 obj_json[
"layer"] = obj.GetLayerValue();
371 objects_arr.push_back(obj_json);
373 tmpl[
"objects"] = objects_arr;
376 json sprites_arr = json::array();
377 for (
const auto& sprite : room.
GetSprites()) {
379 spr_json[
"id"] = sprite.id();
380 spr_json[
"x"] = sprite.x();
381 spr_json[
"y"] = sprite.y();
382 spr_json[
"subtype"] = sprite.subtype();
383 spr_json[
"layer"] = sprite.layer();
384 sprites_arr.push_back(spr_json);
386 tmpl[
"sprites"] = sprites_arr;
389 json items_arr = json::array();
392 item_json[
"position"] = item.position;
393 item_json[
"item"] = item.item;
394 items_arr.push_back(item_json);
396 tmpl[
"pot_items"] = items_arr;
402 bool apply_properties) {
403 using json = nlohmann::json;
407 tmpl = json::parse(json_str);
408 }
catch (
const json::parse_error& err) {
409 return absl::InvalidArgumentError(
410 absl::StrCat(
"Invalid JSON: ", err.what()));
413 if (!tmpl.contains(
"version") || tmpl[
"version"].get<
int>() != 1) {
414 return absl::InvalidArgumentError(
"Unsupported template version");
418 if (apply_properties && tmpl.contains(
"properties")) {
419 const auto& props = tmpl[
"properties"];
420 if (props.contains(
"blockset"))
422 if (props.contains(
"palette"))
424 if (props.contains(
"layout"))
426 if (props.contains(
"spriteset"))
431 if (tmpl.contains(
"objects")) {
434 for (
const auto& obj_json : tmpl[
"objects"]) {
435 int16_t obj_id = obj_json.value(
"id",
static_cast<int16_t
>(0));
436 uint8_t obj_x = obj_json.value(
"x",
static_cast<uint8_t
>(0));
437 uint8_t obj_y = obj_json.value(
"y",
static_cast<uint8_t
>(0));
438 uint8_t obj_size = obj_json.value(
"size",
static_cast<uint8_t
>(0));
439 uint8_t obj_layer = obj_json.value(
"layer",
static_cast<uint8_t
>(0));
440 objects.emplace_back(obj_id, obj_x, obj_y, obj_size, obj_layer);
445 if (tmpl.contains(
"sprites")) {
448 for (
const auto& spr_json : tmpl[
"sprites"]) {
449 uint8_t spr_id = spr_json.value(
"id",
static_cast<uint8_t
>(0));
450 uint8_t spr_x = spr_json.value(
"x",
static_cast<uint8_t
>(0));
451 uint8_t spr_y = spr_json.value(
"y",
static_cast<uint8_t
>(0));
452 uint8_t spr_sub = spr_json.value(
"subtype",
static_cast<uint8_t
>(0));
453 uint8_t spr_layer = spr_json.value(
"layer",
static_cast<uint8_t
>(0));
454 sprites.emplace_back(spr_id, spr_x, spr_y, spr_sub, spr_layer);
459 if (tmpl.contains(
"pot_items")) {
462 for (
const auto& item_json : tmpl[
"pot_items"]) {
464 item.
position = item_json.value(
"position",
static_cast<uint16_t
>(0));
465 item.
item = item_json.value(
"item",
static_cast<uint8_t
>(0));
466 items.push_back(item);
470 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()
Room * GetManagedRoom(int room_id)
absl::Status RefreshRomBackedState(Room *external_room, int current_room_id)
absl::Status SaveManagedRoom(Room &room)
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)
std::unordered_map< int, Room > rooms_
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
absl::Status BindObjectEditorToCurrentRoom()
EditorState GetEditorState() const
absl::StatusOr< Room > GetRoom(int room_id)
void SetLayoutId(uint8_t id)
absl::Status SaveObjects(const DungeonStreamLayout *layout=nullptr)
absl::Status SaveRoomHeader()
absl::Status SaveObjectStreamHeader(const DungeonStreamLayout *layout=nullptr)
uint8_t spriteset() const
const std::vector< zelda3::Sprite > & GetSprites() const
absl::Status SaveSprites(const DungeonStreamLayout *layout=nullptr)
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 SaveSingleRoomState(Rom *rom, Room &room)
absl::Status SaveAllChests(Rom *rom, absl::Span< const Room > rooms)
absl::Status SaveAllPotItems(Rom *rom, absl::Span< const Room > rooms)
absl::Status ApplyRoomLayoutTemplate(Room &room, const std::string &json_str, bool apply_properties)
Apply a previously exported layout template to a room.
absl::Status SaveAllTorches(Rom *rom, absl::Span< const Room > rooms)
absl::StatusOr< std::string > ExportRoomLayoutTemplate(const Room &room)
Export a room's layout as a JSON template string.
Room LoadRoomFromRom(Rom *rom, int room_id)
constexpr int kNumberOfRooms
absl::Status SaveAllCollision(Rom *rom, absl::Span< Room > rooms)
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