diff --git a/src/app/editor/master_editor.cc b/src/app/editor/master_editor.cc index 8a7b4cac..5187a218 100644 --- a/src/app/editor/master_editor.cc +++ b/src/app/editor/master_editor.cc @@ -350,6 +350,7 @@ void MasterEditor::DrawFileMenu() { if (BeginMenu("Options")) { MenuItem("Backup ROM", "", &backup_rom_); + MenuItem("Save New Auto", "", &save_new_auto_); ImGui::Separator(); if (BeginMenu("Experiment Flags")) { if (BeginMenu("Overworld Flags")) { @@ -387,6 +388,8 @@ void MasterEditor::DrawFileMenu() { Checkbox("Save With Change Queue", &mutable_flags()->kSaveWithChangeQueue); Checkbox("Use New ImGui Input", &mutable_flags()->kUseNewImGuiInput); + Checkbox("Use Classic Compression", + &mutable_flags()->kUseClassicCompression); ImGui::EndMenu(); } @@ -568,11 +571,11 @@ void MasterEditor::SaveRom() { RETURN_VOID_IF_ERROR(status_); } if (flags()->overworld.kSaveOverworldMaps) { - if (overworld_editor_.overworld()->CreateTile32Tilemap()) { - status_ = overworld_editor_.overworld()->SaveMap16Tiles(); - RETURN_VOID_IF_ERROR(status_); + if (!overworld_editor_.overworld()->CreateTile32Tilemap()) { status_ = overworld_editor_.overworld()->SaveMap32Tiles(); RETURN_VOID_IF_ERROR(status_); + status_ = overworld_editor_.overworld()->SaveMap16Tiles(); + RETURN_VOID_IF_ERROR(status_); status_ = overworld_editor_.overworld()->SaveOverworldMaps(); RETURN_VOID_IF_ERROR(status_); } else { @@ -598,7 +601,7 @@ void MasterEditor::SaveRom() { RETURN_VOID_IF_ERROR(status_); } - status_ = rom()->SaveToFile(backup_rom_); + status_ = rom()->SaveToFile(backup_rom_, save_new_auto_); } } // namespace editor diff --git a/src/app/editor/master_editor.h b/src/app/editor/master_editor.h index bfd34437..3f3e1ab7 100644 --- a/src/app/editor/master_editor.h +++ b/src/app/editor/master_editor.h @@ -61,7 +61,8 @@ class MasterEditor : public SharedROM, bool about_ = false; bool rom_info_ = false; - bool backup_rom_ = true; + bool backup_rom_ = false; + bool save_new_auto_ = true; bool show_status_ = false; bool rom_assets_loaded_ = false; diff --git a/src/app/rom.cc b/src/app/rom.cc index b273333d..d184d74b 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -347,6 +347,10 @@ absl::Status ROM::LoadFromFile(const absl::string_view& filename, LoadGfxGroups(); } + // Expand the ROM data to 2MB without changing the data in the first 1MB + rom_data_.resize(baseROMSize * 2); + size_ = baseROMSize * 2; + // Set up the resource labels std::string resource_label_filename = absl::StrFormat("%s.labels", filename); resource_label_manager_.LoadLabels(resource_label_filename); @@ -377,7 +381,7 @@ absl::Status ROM::LoadFromBytes(const Bytes& data) { return absl::OkStatus(); } -absl::Status ROM::SaveToFile(bool backup, absl::string_view filename) { +absl::Status ROM::SaveToFile(bool backup, bool save_new, std::string filename) { absl::Status non_firing_status; if (rom_data_.empty()) { return absl::InternalError("ROM data is empty."); @@ -427,11 +431,34 @@ absl::Status ROM::SaveToFile(bool backup, absl::string_view filename) { } } + if (save_new) { + // Create a file of the same name and append the date between the filename + // and file extension + auto now = std::chrono::system_clock::now(); + auto now_c = std::chrono::system_clock::to_time_t(now); + auto filename_no_ext = filename.substr(0, filename.find_last_of(".")); + std::cout << filename_no_ext << std::endl; + filename = absl::StrCat(filename_no_ext, "_", std::ctime(&now_c)); + // Remove spaces from new_filename and replace with _ + filename.erase(std::remove(filename.begin(), filename.end(), ' '), + filename.end()); + // Remove newline character from ctime() + filename.erase(std::remove(filename.begin(), filename.end(), '\n'), + filename.end()); + // Add the file extension back to the new_filename + filename = filename + ".sfc"; + std::cout << filename << std::endl; + } + // Open the file that we know exists for writing - std::ofstream file(filename.data(), std::ios::binary); + std::ofstream file(filename.data(), std::ios::binary | std::ios::app); if (!file) { - return absl::InternalError( - absl::StrCat("Could not open ROM file: ", filename)); + // Create the file if it does not exist + file.open(filename.data(), std::ios::binary); + if (!file) { + return absl::InternalError( + absl::StrCat("Could not open or create ROM file: ", filename)); + } } // Save the data to the file diff --git a/src/app/rom.h b/src/app/rom.h index 2f2af634..01b0baa8 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -133,8 +133,8 @@ constexpr uint32_t gfx_groups_pointer = 0x6237; struct WriteAction { int address; - std::variant, gfx::SNESColor, - std::vector> + std::variant, + gfx::SNESColor, std::vector> value; }; @@ -148,24 +148,11 @@ class ROM : public core::ExperimentFlags { return status; } - template - absl::Status RunTransactionV2(int address, T& var, Args&&... args) { - absl::Status status = WriteHelperV2(var, address); - if (!status.ok()) { - return status; - } - - if constexpr (sizeof...(args) > 0) { - status = WriteHelperV2(std::forward(args)...); - } - - return status; - } - absl::Status WriteHelper(const WriteAction& action) { if (std::holds_alternative(action.value)) { return Write(action.address, std::get(action.value)); - } else if (std::holds_alternative(action.value)) { + } else if (std::holds_alternative(action.value) || + std::holds_alternative(action.value)) { return WriteShort(action.address, std::get(action.value)); } else if (std::holds_alternative>(action.value)) { return WriteVector(action.address, @@ -179,25 +166,7 @@ class ROM : public core::ExperimentFlags { } auto error_message = absl::StrFormat("Invalid write argument type: %s", typeid(action.value).name()); - return absl::InvalidArgumentError(error_message); - } - - template - absl::Status WriteHelperV2(int address, T& var) { - if constexpr (std::is_same_v) { - return Write(address, var); - } else if constexpr (std::is_same_v) { - return WriteShort(address, var); - } else if constexpr (std::is_same_v>) { - return WriteVector(address, var); - } else if constexpr (std::is_same_v) { - return WriteColor(address, var); - } else if constexpr (std::is_same_v>) { - return absl::UnimplementedError( - "WriteHelperV2: std::vector"); - } - auto error_message = - absl::StrFormat("Invalid write argument type: %s", typeid(T).name()); + throw std::runtime_error(error_message); return absl::InvalidArgumentError(error_message); } @@ -291,7 +260,8 @@ class ROM : public core::ExperimentFlags { * @return absl::Status Returns an OK status if the save was successful, * otherwise returns an error status */ - absl::Status SaveToFile(bool backup, absl::string_view filename = ""); + absl::Status SaveToFile(bool backup, bool save_new = false, + std::string filename = ""); /** * Saves the given palette to the ROM if any of its colors have been modified. @@ -403,7 +373,9 @@ class ROM : public core::ExperimentFlags { // Write functions absl::Status Write(int addr, int value) { if (addr >= rom_data_.size()) { - return absl::InvalidArgumentError("Address out of range"); + return absl::InvalidArgumentError(absl::StrFormat( + "Attempt to write %d value failed, address %d out of range", value, + addr)); } rom_data_[addr] = value; return absl::OkStatus(); @@ -411,47 +383,68 @@ class ROM : public core::ExperimentFlags { absl::Status WriteByte(int addr, uint8_t value) { if (addr >= rom_data_.size()) { - return absl::InvalidArgumentError("Address out of range"); + return absl::InvalidArgumentError(absl::StrFormat( + "Attempt to write byte %#02x value failed, address %d out of range", + value, addr)); } rom_data_[addr] = value; + std::string log_str = absl::StrFormat("WriteByte: %#06X: %s", addr, + core::UppercaseHexByte(value).data()); + core::Logger::log(log_str); return absl::OkStatus(); } absl::Status WriteWord(int addr, uint16_t value) { if (addr + 1 >= rom_data_.size()) { - return absl::InvalidArgumentError("Address out of range"); + return absl::InvalidArgumentError(absl::StrFormat( + "Attempt to write word %#04x value failed, address %d out of range", + value, addr)); } rom_data_[addr] = (uint8_t)(value & 0xFF); rom_data_[addr + 1] = (uint8_t)((value >> 8) & 0xFF); + core::Logger::log(absl::StrFormat("WriteWord: %#06X: %s", addr, + core::UppercaseHexWord(value))); return absl::OkStatus(); } absl::Status WriteShort(uint32_t addr, uint16_t value) { if (addr + 1 >= rom_data_.size()) { - return absl::InvalidArgumentError("Address out of range"); + return absl::InvalidArgumentError(absl::StrFormat( + "Attempt to write short %#04x value failed, address %d out of range", + value, addr)); } rom_data_[addr] = (uint8_t)(value & 0xFF); rom_data_[addr + 1] = (uint8_t)((value >> 8) & 0xFF); + core::Logger::log(absl::StrFormat("WriteShort: %#06X: %s", addr, + core::UppercaseHexWord(value))); return absl::OkStatus(); } absl::Status WriteLong(uint32_t addr, uint32_t value) { if (addr + 2 >= rom_data_.size()) { - return absl::InvalidArgumentError("Address out of range"); + return absl::InvalidArgumentError(absl::StrFormat( + "Attempt to write long %#06x value failed, address %d out of range", + value, addr)); } rom_data_[addr] = (uint8_t)(value & 0xFF); rom_data_[addr + 1] = (uint8_t)((value >> 8) & 0xFF); rom_data_[addr + 2] = (uint8_t)((value >> 16) & 0xFF); + core::Logger::log(absl::StrFormat("WriteLong: %#06X: %s", addr, + core::UppercaseHexLong(value))); return absl::OkStatus(); } absl::Status WriteVector(int addr, std::vector data) { if (addr + data.size() > rom_data_.size()) { - return absl::InvalidArgumentError("Address and data size out of range"); + return absl::InvalidArgumentError(absl::StrFormat( + "Attempt to write vector value failed, address %d out of range", + addr)); } for (int i = 0; i < data.size(); i++) { rom_data_[addr + i] = data[i]; } + core::Logger::log(absl::StrFormat("WriteVector: %#06X: %s", addr, + core::UppercaseHexByte(data[0]))); return absl::OkStatus(); } @@ -461,6 +454,8 @@ class ROM : public core::ExperimentFlags { (color.GetSNES() & 0x7C00); // Write the 16-bit color value to the ROM at the specified address + core::Logger::log(absl::StrFormat("WriteColor: %#06X: %s", address, + core::UppercaseHexWord(bgr))); return WriteShort(address, bgr); }