mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-21 05:09:46 -06:00
Refactor how save data (including SD cards) is initialized (#1898)
* Remove `FATStorage::Open` and `FATStorage::Close` - That's what the constructor and destructor are for, respectively * Add `FATStorage::IsReadOnly` * Slight cleanup of `FATStorage` - Make it move-constructible and move-assignable - Represent the absence of a sync directory with `std::optional`, not an empty string - Add `FATStorageArgs` for later use * Refactor `CartHomebrew` to accept an optional `FATStorageArgs` - `CartHomebrew` uses it to load an SD card image - Not passing a `FATStorage` directly because we won't know if we need to load the card until we parse the ROM - Store the `FATStorage` inside a `std::optional` instead of a pointer - `CartHomebrew::Reset` no longer reloads the SD card; the frontend needs to set it with the `SetSDCard` method * Close `NANDImage::CurFile` when move-assigning - Whoops * Add `Args.h` - To construct a `NDS` or `DSi` with arguments - Mostly intended for system files * Fix incorrect `final` placement * Refactor how `DSi`'s NAND and SD card are set - Provide them via a `DSiArgs` argument in the constructor - Give `DSi_MMCStorage` ownership of the `NANDImage` or `FATStorage` as needed, and expose getters/setters - Replace `DSi_SDHost::Ports` with a `array<unique_ptr, 2>` to reduce the risk of leaks - Store `DSi_MMCStorage`'s disk images in a `std::variant` - The SD card and NAND image are no longer reset in `Reset()`; the frontend will need to do that itself * Add getters/setters on `DSi` itself for its storage media * Remove newly-unused `Platform::ConfigEntry`s * Use `DSi::SetNAND` in the frontend * Add `EmuThread::NeedToRecreateConsole` * Document `NDSArgs` and give its fields default values * Refactor how system files are loaded upon construction - Pass `NDSArgs&&` into `NDS`'s constructor - Use `std::array` for the emulator's BIOS images and the built-in FreeBIOS, to simplify copying and comparison - Initialize the BIOS, firmware, and SD cards from `NDSArgs` or `DSiArgs` - Add a new default constructor for `NDS` (not `DSi`) that initializes the DS with default system files - Embed `FirmwareMem::Firmware` directly instead of in a `unique_ptr` - `SPIHost` now takes a `Firmware&&` that it forwards to `FirmwareMem` - Add `Firmware` getters/setters plus `const` variants for `NDS`, `Firmware`, and `FirmwareMem` - Simplify installation of firmware * Initialize the DSi BIOS in the constructor - Change `DSi::ARM9iBIOS` and `ARM7iBIOS` to `std::array` * Update the frontend to reflect the core's changes * Remove `DSi_SDHost::CloseHandles` * Pass `nullopt` instead of the empty string when folder sync is off * Deduplicate ROM extraction logic - `LoadGBAROM` and `LoadROM` now delegate to `LoadROMData` - Also use `unique_ptr` instead of `new[]` * Oops, missed some `get()`'s * Move `NDS::IsLoadedARM9BIOSBuiltIn` to the header - So it's likelier to be inlined - Same for the ARM7 version * Remove `NDS::SetConsoleType` * Add `NDS::SetFirmware` * Move `GBACart::SetupSave` to be `protected` - It was only ever used inside the class * Rename `GBACart::LoadSave` to `SetSaveMemory` - Same for the cart slot * Declare `GBACartSlot` as a friend of `GBACart::CartCommon` * Revise `GBACartSlot`'s getters and setters - Rename `InsertROM` and `LoadROM` to `SetCart` - Add a `GetCart` method * Clean up getters and setters for NDS and GBA carts * Clean up how carts are inserted into the slots - Remove setters that operate directly on pointers, to simplify error-handling (use ParseROM instead) - Add overloads for all carts that accept a `const u8*` (to copy the ROM data) and a `unique_ptr<u8[]>` (to move the ROM data) - Store all ROM and RAM data in `unique_ptr` - Default-initialize all fields - Simplify constructors and destructors, inheriting where applicable * Refactor GBA save data insertion - Make `SetupSave` private and non-virtual and move its logic to be in `SetSaveMemory` - Add overloads for setting save data in the constructor - Update the SRAM completely in `SetSaveMemory` * Clean up `NDSCart::CartCommon::SetSaveMemory` - Move its declaration next to the other `SaveMemory` methods - Move its (empty) implementation to the header * Add some comments * Add Utils.cpp and Utils.h * Rename some functions in Utils for clarity * Add `GBACart::ParseROM` and `NDSCart::ParseROM` overloads that accept `unique_ptr<u8[]>` - The `u8*` overloads delegate to these new overloads - Also move `SetupSave` for both kinds of carts to be private non-virtual methods * Finalize the `NDSCart` refactor - Add `NDSCartArgs` to pass to `ParseROM` - Add SRAM arguments for all retail carts - Initialize SRAM inside the constructor - Delegate to other constructors where possible * Replace `ROMManager::NDSSave` and `GBASave` with `unique_ptr` * Make both cart slots return the previously-inserted cart in `EjectCart` - Primarily intended for reusing carts when resetting the console * Make `NDS::EjectCart` return the old cart * Initialize both cart slots with the provided ROM (if any) * Make `NDS::EjectGBACart` return the ejected cart * Clean up some comments in Args.h * Rename `ROMManager::LoadBIOS` to `BootToMenu` - Clarifies the intent * Add `ROMManager::LoadDLDISDCard` * Add a doc comment * Refactor how the `NDS` is created or updated - Rewrite `CreateConsole` to read from `Config` and load system files, but accept carts as arguments - Fail without creating an `NDS` if any required system file doesn't load - Add `UpdateConsole`, which delegates to `CreateConsole` if switching modes or starting the app - Use `std::variant` to indicate whether a cart should be removed, inserted, or reused - Load all system files (plus SD cards) in `UpdateConsole` - Eject the cart and reinsert it into the new console if applicable * Respect some more `Config` settings in the `Load*` functions * Remove `InstallNAND` in favor of `LoadNAND` * Fix some potential bugs in `LoadROMData` * Oops, forgot to delete the definition of `InstallNAND` * Add functions to get `FATStorageArgs` - Not the cards themselves, but to get the arguments you _would_ use to load the cards * Refactor `ROMManager::LoadROM` - Load the ROM and save data before trying to initialize the console * Clean up `ROMManager::Reset` and `BootToMenu` - Let `EmuThread::UpdateConsole` do the heavy lifting * Clean up `LoadGBAROM` * Remove some unused functions * Set the default DSi BIOS to be broken in `DSiArgs` * Respect `Config::DSiFullBIOSBoot` when loading DSi BIOS files * Remove some more unused functions * Remove redundant `virtual` specifiers * Refactor `NDSCart::CartCommon::Type()` to return a member instead of a constant - One less virtual dispatch - The cart type is read in `NDSCartSlot::DoSavestate`, which is a path downstream (due to rewinding) * Remove a hash that I computed for debugging purposes * Make `ByteSwap` `constexpr` * Remove an unused `#include` * Remove unnecessary functions from the NDS carts - Mostly overrides that added nothing * Default-initialize all NDSCart fields * Make `GBACart::Type()` not rely on virtual dispatch - `GBACartSlot::DoSavestate` calls it, and savestates can be a hot path downstream * Don't forget to reset the base class in `CartGameSolarSensor::Reset()` * Remove redundant `virtual` specifiers * Default-initialize some fields in `GBACart` * Fix ROMs not loading from archives in the frontend - Whoops * Change how the `Firmware` member is declared * Forgot an include in Utils.cpp * Rename `FirmwareMem::Firmware` to `FirmwareData` to fix a build error on Linux - One of these days I'll convince you people to let me use `camelCaseMemberNames` * Add `override` to places in `DSi_MMCStorage` that warrant it * Fix firmware saving on the frontend - Remove `GetConfigString` and `ConfigEntry::WifiSettingsPath` while I'm at it * Add a non-const `GetNAND()`
This commit is contained in:
@ -81,6 +81,7 @@
|
||||
#include "FrontendUtil.h"
|
||||
#include "OSD.h"
|
||||
|
||||
#include "Args.h"
|
||||
#include "NDS.h"
|
||||
#include "NDSCart.h"
|
||||
#include "GBACart.h"
|
||||
@ -204,29 +205,164 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
|
||||
static_cast<ScreenPanelGL*>(mainWindow->panel)->transferLayout(this);
|
||||
}
|
||||
|
||||
std::unique_ptr<NDS> EmuThread::CreateConsole()
|
||||
std::unique_ptr<NDS> EmuThread::CreateConsole(
|
||||
std::unique_ptr<melonDS::NDSCart::CartCommon>&& ndscart,
|
||||
std::unique_ptr<melonDS::GBACart::CartCommon>&& gbacart
|
||||
) noexcept
|
||||
{
|
||||
auto arm7bios = ROMManager::LoadARM7BIOS();
|
||||
if (!arm7bios)
|
||||
return nullptr;
|
||||
|
||||
auto arm9bios = ROMManager::LoadARM9BIOS();
|
||||
if (!arm9bios)
|
||||
return nullptr;
|
||||
|
||||
auto firmware = ROMManager::LoadFirmware(Config::ConsoleType);
|
||||
if (!firmware)
|
||||
return nullptr;
|
||||
|
||||
NDSArgs ndsargs {
|
||||
std::move(ndscart),
|
||||
std::move(gbacart),
|
||||
*arm9bios,
|
||||
*arm7bios,
|
||||
std::move(*firmware),
|
||||
};
|
||||
|
||||
if (Config::ConsoleType == 1)
|
||||
{
|
||||
return std::make_unique<melonDS::DSi>();
|
||||
auto arm7ibios = ROMManager::LoadDSiARM7BIOS();
|
||||
if (!arm7ibios)
|
||||
return nullptr;
|
||||
|
||||
auto arm9ibios = ROMManager::LoadDSiARM9BIOS();
|
||||
if (!arm9ibios)
|
||||
return nullptr;
|
||||
|
||||
auto nand = ROMManager::LoadNAND(*arm7ibios);
|
||||
if (!nand)
|
||||
return nullptr;
|
||||
|
||||
auto sdcard = ROMManager::LoadDSiSDCard();
|
||||
DSiArgs args {
|
||||
std::move(ndsargs),
|
||||
*arm9ibios,
|
||||
*arm7ibios,
|
||||
std::move(*nand),
|
||||
std::move(sdcard),
|
||||
};
|
||||
|
||||
args.GBAROM = nullptr;
|
||||
|
||||
return std::make_unique<melonDS::DSi>(std::move(args));
|
||||
}
|
||||
|
||||
return std::make_unique<melonDS::NDS>();
|
||||
return std::make_unique<melonDS::NDS>(std::move(ndsargs));
|
||||
}
|
||||
|
||||
void EmuThread::RecreateConsole()
|
||||
bool EmuThread::UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAArgs&& gbaargs) noexcept
|
||||
{
|
||||
if (!NDS || NDS->ConsoleType != Config::ConsoleType)
|
||||
// Let's get the cart we want to use;
|
||||
// if we wnat to keep the cart, we'll eject it from the existing console first.
|
||||
std::unique_ptr<NDSCart::CartCommon> nextndscart;
|
||||
if (std::holds_alternative<Keep>(ndsargs))
|
||||
{ // If we want to keep the existing cart (if any)...
|
||||
nextndscart = NDS ? NDS->EjectCart() : nullptr;
|
||||
ndsargs = {};
|
||||
}
|
||||
else if (const auto ptr = std::get_if<std::unique_ptr<NDSCart::CartCommon>>(&ndsargs))
|
||||
{
|
||||
NDS = nullptr; // To ensure the destructor is called before a new one is created
|
||||
nextndscart = std::move(*ptr);
|
||||
ndsargs = {};
|
||||
}
|
||||
|
||||
if (nextndscart && nextndscart->Type() == NDSCart::Homebrew)
|
||||
{
|
||||
// Load DLDISDCard will return nullopt if the SD card is disabled;
|
||||
// SetSDCard will accept nullopt, which means no SD card
|
||||
auto& homebrew = static_cast<NDSCart::CartHomebrew&>(*nextndscart);
|
||||
homebrew.SetSDCard(ROMManager::LoadDLDISDCard());
|
||||
}
|
||||
|
||||
std::unique_ptr<GBACart::CartCommon> nextgbacart;
|
||||
if (std::holds_alternative<Keep>(gbaargs))
|
||||
{
|
||||
nextgbacart = NDS ? NDS->EjectGBACart() : nullptr;
|
||||
}
|
||||
else if (const auto ptr = std::get_if<std::unique_ptr<GBACart::CartCommon>>(&gbaargs))
|
||||
{
|
||||
nextgbacart = std::move(*ptr);
|
||||
gbaargs = {};
|
||||
}
|
||||
|
||||
if (!NDS || NDS->ConsoleType != Config::ConsoleType)
|
||||
{ // If we're switching between DS and DSi mode, or there's no console...
|
||||
// To ensure the destructor is called before a new one is created,
|
||||
// as the presence of global signal handlers still complicates things a bit
|
||||
NDS = nullptr;
|
||||
NDS::Current = nullptr;
|
||||
|
||||
NDS = CreateConsole();
|
||||
// TODO: Insert ROMs
|
||||
NDS = CreateConsole(std::move(nextndscart), std::move(nextgbacart));
|
||||
NDS::Current = NDS.get();
|
||||
}
|
||||
}
|
||||
|
||||
return NDS != nullptr;
|
||||
}
|
||||
|
||||
auto arm9bios = ROMManager::LoadARM9BIOS();
|
||||
if (!arm9bios)
|
||||
return false;
|
||||
|
||||
auto arm7bios = ROMManager::LoadARM7BIOS();
|
||||
if (!arm7bios)
|
||||
return false;
|
||||
|
||||
auto firmware = ROMManager::LoadFirmware(NDS->ConsoleType);
|
||||
if (!firmware)
|
||||
return false;
|
||||
|
||||
if (NDS->ConsoleType == 1)
|
||||
{ // If the console we're updating is a DSi...
|
||||
DSi& dsi = static_cast<DSi&>(*NDS);
|
||||
|
||||
auto arm9ibios = ROMManager::LoadDSiARM9BIOS();
|
||||
if (!arm9ibios)
|
||||
return false;
|
||||
|
||||
auto arm7ibios = ROMManager::LoadDSiARM7BIOS();
|
||||
if (!arm7ibios)
|
||||
return false;
|
||||
|
||||
auto nandimage = ROMManager::LoadNAND(*arm7ibios);
|
||||
if (!nandimage)
|
||||
return false;
|
||||
|
||||
auto dsisdcard = ROMManager::LoadDSiSDCard();
|
||||
|
||||
dsi.ARM7iBIOS = *arm7ibios;
|
||||
dsi.ARM9iBIOS = *arm9ibios;
|
||||
dsi.SetNAND(std::move(*nandimage));
|
||||
dsi.SetSDCard(std::move(dsisdcard));
|
||||
// We're moving the optional, not the card
|
||||
// (inserting std::nullopt here is okay, it means no card)
|
||||
|
||||
dsi.EjectGBACart();
|
||||
}
|
||||
|
||||
if (NDS->ConsoleType == 0)
|
||||
{
|
||||
NDS->SetGBACart(std::move(nextgbacart));
|
||||
}
|
||||
|
||||
NDS->ARM7BIOS = *arm7bios;
|
||||
NDS->ARM9BIOS = *arm9bios;
|
||||
NDS->SetFirmware(std::move(*firmware));
|
||||
NDS->SetNDSCart(std::move(nextndscart));
|
||||
|
||||
NDS::Current = NDS.get();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EmuThread::updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix)
|
||||
{
|
||||
@ -343,7 +479,8 @@ void EmuThread::run()
|
||||
u32 mainScreenPos[3];
|
||||
Platform::FileHandle* file;
|
||||
|
||||
RecreateConsole();
|
||||
UpdateConsole(nullptr, nullptr);
|
||||
// No carts are inserted when melonDS first boots
|
||||
|
||||
mainScreenPos[0] = 0;
|
||||
mainScreenPos[1] = 0;
|
||||
@ -2507,7 +2644,7 @@ void MainWindow::onBootFirmware()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ROMManager::LoadBIOS(emuThread))
|
||||
if (!ROMManager::BootToMenu(emuThread))
|
||||
{
|
||||
// TODO: better error reporting?
|
||||
QMessageBox::critical(this, "melonDS", "This firmware is not bootable.");
|
||||
@ -2750,13 +2887,12 @@ void MainWindow::onImportSavefile()
|
||||
|
||||
u32 len = FileLength(f);
|
||||
|
||||
u8* data = new u8[len];
|
||||
std::unique_ptr<u8[]> data = std::make_unique<u8[]>(len);
|
||||
Platform::FileRewind(f);
|
||||
Platform::FileRead(data, len, 1, f);
|
||||
Platform::FileRead(data.get(), len, 1, f);
|
||||
|
||||
assert(emuThread->NDS != nullptr);
|
||||
emuThread->NDS->LoadSave(data, len);
|
||||
delete[] data;
|
||||
emuThread->NDS->SetNDSSave(data.get(), len);
|
||||
|
||||
CloseFile(f);
|
||||
emuThread->emuUnpause();
|
||||
|
Reference in New Issue
Block a user