reconnect the save manager thing

This commit is contained in:
Arisotura
2022-01-03 19:12:11 +01:00
parent 3abfa269ba
commit 52a9abde6f
11 changed files with 167 additions and 97 deletions

View File

@ -0,0 +1,542 @@
/*
Copyright 2016-2021 Arisotura
This file is part of melonDS.
melonDS is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <utility>
#ifdef ARCHIVE_SUPPORT_ENABLED
#include "ArchiveUtil.h"
#endif
#include "ROMManager.h"
#include "Config.h"
#include "Platform.h"
#include "NDS.h"
#include "DSi.h"
#include "AREngine.h"
namespace ROMManager
{
std::string FullROMPath = "";
std::string BaseROMDir = "";
std::string BaseROMName = "";
std::string BaseAssetName = "";
int GBACartType = -1;
SaveManager* NDSSave = nullptr;
int LastSep(std::string path)
{
int i = path.length() - 1;
while (i >= 0)
{
if (path[i] == '/' || path[i] == '\\')
return i;
i--;
}
return -1;
}
std::string GetAssetPath(std::string configpath, std::string ext)
{
if (configpath.empty())
configpath = BaseROMDir;
for (;;)
{
int i = configpath.length() - 1;
if (configpath[i] == '/' || configpath[i] == '\\')
configpath = configpath.substr(0, i);
else
break;
}
if (!configpath.empty())
configpath += "/";
return configpath + BaseAssetName + ext;
}
QString VerifyDSBIOS()
{
FILE* f;
long len;
f = Platform::OpenLocalFile(Config::BIOS9Path, "rb");
if (!f) return "DS ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
if (len != 0x1000)
{
fclose(f);
return "DS ARM9 BIOS is not a valid BIOS dump.";
}
fclose(f);
f = Platform::OpenLocalFile(Config::BIOS7Path, "rb");
if (!f) return "DS ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
if (len != 0x4000)
{
fclose(f);
return "DS ARM7 BIOS is not a valid BIOS dump.";
}
fclose(f);
return "";
}
QString VerifyDSiBIOS()
{
FILE* f;
long len;
// TODO: check the first 32 bytes
f = Platform::OpenLocalFile(Config::DSiBIOS9Path, "rb");
if (!f) return "DSi ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
if (len != 0x10000)
{
fclose(f);
return "DSi ARM9 BIOS is not a valid BIOS dump.";
}
fclose(f);
f = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb");
if (!f) return "DSi ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
if (len != 0x10000)
{
fclose(f);
return "DSi ARM7 BIOS is not a valid BIOS dump.";
}
fclose(f);
return "";
}
QString VerifyDSFirmware()
{
FILE* f;
long len;
f = Platform::OpenLocalFile(Config::FirmwarePath, "rb");
if (!f) return "DS firmware was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
if (len == 0x20000)
{
// 128KB firmware, not bootable
fclose(f);
// TODO report it somehow? detect in core?
return "";
}
else if (len != 0x40000 && len != 0x80000)
{
fclose(f);
return "DS firmware is not a valid firmware dump.";
}
fclose(f);
return "";
}
QString VerifyDSiFirmware()
{
FILE* f;
long len;
f = Platform::OpenLocalFile(Config::DSiFirmwarePath, "rb");
if (!f) return "DSi firmware was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END);
len = ftell(f);
if (len != 0x20000)
{
// not 128KB
// TODO: check whether those work
fclose(f);
return "DSi firmware is not a valid firmware dump.";
}
fclose(f);
return "";
}
QString VerifyDSiNAND()
{
FILE* f;
long len;
f = Platform::OpenLocalFile(Config::DSiNANDPath, "r+b");
if (!f) return "DSi NAND was not found or could not be accessed. Check your emu settings.";
// TODO: some basic checks
// check that it has the nocash footer, and all
fclose(f);
return "";
}
QString VerifySetup()
{
QString res;
if (Config::ExternalBIOSEnable)
{
res = VerifyDSBIOS();
if (!res.isEmpty()) return res;
}
if (Config::ConsoleType == 1)
{
res = VerifyDSiBIOS();
if (!res.isEmpty()) return res;
if (Config::ExternalBIOSEnable)
{
res = VerifyDSiFirmware();
if (!res.isEmpty()) return res;
}
res = VerifyDSiNAND();
if (!res.isEmpty()) return res;
}
else
{
if (Config::ExternalBIOSEnable)
{
res = VerifyDSFirmware();
if (!res.isEmpty()) return res;
}
}
return "";
}
void Reset()
{
NDS::SetConsoleType(Config::ConsoleType);
NDS::Reset();
if (!BaseROMName.empty())
{
if (Config::DirectBoot || NDS::NeedsDirectBoot())
{
NDS::SetupDirectBoot(BaseROMName);
}
}
}
bool LoadBIOS()
{
NDS::SetConsoleType(Config::ConsoleType);
if (NDS::NeedsDirectBoot())
return false;
if (NDSSave) delete NDSSave;
NDSSave = nullptr;
FullROMPath = "";
BaseROMDir = "";
BaseROMName = "";
BaseAssetName = "";
NDS::Reset();
return true;
}
bool LoadROM(QStringList filepath, bool reset)
{
if (filepath.empty()) return false;
u8* filedata;
u32 filelen;
std::string fullpath;
std::string basepath;
std::string romname;
int num = filepath.count();
if (num == 1)
{
// regular file
std::string filename = filepath.at(0).toStdString();
FILE* f = Platform::OpenFile(filename, "rb", true);
if (!f) return false;
fseek(f, 0, SEEK_END);
long len = ftell(f);
if (len > 0x40000000)
{
fclose(f);
return false;
}
fseek(f, 0, SEEK_SET);
filedata = new u8[len];
size_t nread = fread(filedata, (size_t)len, 1, f);
if (nread != 1)
{
fclose(f);
delete[] filedata;
return false;
}
fclose(f);
filelen = (u32)len;
fullpath = filename;
int pos = LastSep(filename);
basepath = filename.substr(0, pos);
romname = filename.substr(pos+1);
}
#ifdef ARCHIVE_SUPPORT_ENABLED
else if (num == 2)
{
// file inside archive
u32 lenread = Archive::ExtractFileFromArchive(filepath.at(0), filepath.at(1), &filedata, &filelen);
if (lenread < 0) return false;
if (!filedata) return false;
if (lenread != filelen)
{
delete[] filedata;
return false;
}
std::string std_archivepath = filepath.at(0).toStdString();
basepath = std_archivepath.substr(0, LastSep(std_archivepath));
std::string std_romname = filepath.at(1).toStdString();
romname = std_romname.substr(LastSep(std_romname)+1);
fullpath = std_archivepath + "//" + std_romname;
}
#endif
else
return false;
if (NDSSave) delete NDSSave;
NDSSave = nullptr;
FullROMPath = fullpath;
BaseROMDir = basepath;
BaseROMName = romname;
BaseAssetName = romname.substr(0, romname.rfind('.'));
if (reset)
{
NDS::SetConsoleType(Config::ConsoleType);
NDS::Reset();
}
u32 savelen = 0;
u8* savedata = nullptr;
std::string savname = GetAssetPath(Config::SaveFilePath, ".sav");
FILE* sav = Platform::OpenFile(savname, "rb", true);
if (sav)
{
fseek(sav, 0, SEEK_END);
savelen = (u32)ftell(sav);
fseek(sav, 0, SEEK_SET);
savedata = new u8[savelen];
fread(savedata, savelen, 1, sav);
fclose(sav);
}
bool res = NDS::LoadCart(filedata, filelen, savedata, savelen);
if (res && reset)
{
if (Config::DirectBoot || NDS::NeedsDirectBoot())
{
NDS::SetupDirectBoot(romname);
}
}
if (res)
{
NDSSave = new SaveManager(savname);
}
delete[] savedata;
delete[] filedata;
return res;
}
void EjectCart()
{
if (NDSSave) delete NDSSave;
NDSSave = nullptr;
NDS::EjectCart();
FullROMPath = "";
BaseROMDir = "";
BaseROMName = "";
BaseAssetName = "";
}
QString CartLabel()
{
if (BaseROMName.empty())
return "(none)";
QString ret = QString::fromStdString(BaseROMName);
int maxlen = 32;
if (ret.length() > maxlen)
ret = ret.left(maxlen-6) + "..." + ret.right(3);
return ret;
}
void LoadGBAAddon(int type)
{
NDS::LoadGBAAddon(type);
GBACartType = type;
}
// PLACEHOLDER
QString GBACartLabel()
{
switch (GBACartType)
{
case 0:
return "it's a ROM (TODO)";
case NDS::GBAAddon_RAMExpansion:
return "Memory expansion";
}
return "(none)";
}
void ROMIcon(u8 (&data)[512], u16 (&palette)[16], u32* iconRef)
{
int index = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
for (int k = 0; k < 8; k++)
{
for (int l = 0; l < 8; l++)
{
u8 pal_index = index % 2 ? data[index/2] >> 4 : data[index/2] & 0x0F;
u8 r = ((palette[pal_index] >> 0) & 0x1F) * 255 / 31;
u8 g = ((palette[pal_index] >> 5) & 0x1F) * 255 / 31;
u8 b = ((palette[pal_index] >> 10) & 0x1F) * 255 / 31;
u8 a = pal_index ? 255: 0;
u32* row = &iconRef[256 * i + 32 * k + 8 * j];
row[l] = (a << 24) | (r << 16) | (g << 8) | b;
index++;
}
}
}
}
}
#define SEQ_FLIPV(i) ((i & 0b1000000000000000) >> 15)
#define SEQ_FLIPH(i) ((i & 0b0100000000000000) >> 14)
#define SEQ_PAL(i) ((i & 0b0011100000000000) >> 11)
#define SEQ_BMP(i) ((i & 0b0000011100000000) >> 8)
#define SEQ_DUR(i) ((i & 0b0000000011111111) >> 0)
void AnimatedROMIcon(u8 (&data)[8][512], u16 (&palette)[8][16], u16 (&sequence)[64], u32 (&animatedTexRef)[32 * 32 * 64], std::vector<int> &animatedSequenceRef)
{
for (int i = 0; i < 64; i++)
{
if (!sequence[i])
break;
u32* frame = &animatedTexRef[32 * 32 * i];
ROMIcon(data[SEQ_BMP(sequence[i])], palette[SEQ_PAL(sequence[i])], frame);
if (SEQ_FLIPH(sequence[i]))
{
for (int x = 0; x < 32; x++)
{
for (int y = 0; y < 32/2; y++)
{
std::swap(frame[x * 32 + y], frame[x * 32 + (32 - 1 - y)]);
}
}
}
if (SEQ_FLIPV(sequence[i]))
{
for (int x = 0; x < 32/2; x++)
{
for (int y = 0; y < 32; y++)
{
std::swap(frame[x * 32 + y], frame[(32 - 1 - x) * 32 + y]);
}
}
}
for (int j = 0; j < SEQ_DUR(sequence[i]); j++)
animatedSequenceRef.push_back(i);
}
}
}