Add nds-bootstrap interface

- Rework savemngr to use melonDS ROM list for save type
- Use nds-bootstrap in place of akloader for retail game launching
This commit is contained in:
lifehackerhansol 2024-10-05 00:20:05 -07:00
parent 1a88151eee
commit 1a76345468
No known key found for this signature in database
GPG Key ID: 80FB184AFC0B3B0E
9 changed files with 7006 additions and 15 deletions

View File

@ -16,7 +16,7 @@ include $(DEVKITARM)/ds_rules
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD := build
SOURCES := source source/ui source/font source/launcher
SOURCES := source source/ui source/font source/launcher source/saves
INCLUDES := include ../share $(SOURCES)
DATA := data
GRAPHICS :=

View File

@ -0,0 +1,110 @@
/*
Copyright (C) 2024 lifehackerhansol
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <sys/stat.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <nds/ndstypes.h>
#include "../cheatwnd.h"
#include "../dsrom.h"
#include "../flags.h"
#include "../inifile.h"
#include "ILauncher.h"
#include "NdsBootstrapLauncher.h"
#include "nds_loader_arm9.h"
bool NdsBootstrapLauncher::prepareCheats() {
u32 gameCode, crc32;
if (cCheatWnd::romData(mRomPath, gameCode, crc32)) {
FILE* cheatDb = fopen("/__rpg/cheats/usrcheat.dat", "rb");
if (!cheatDb) goto cheat_failed;
long cheatOffset;
size_t cheatSize;
if (cCheatWnd::searchCheatData(cheatDb, gameCode, crc32, cheatOffset, cheatSize)) {
cCheatWnd chtwnd((256) / 2, (192) / 2, 100, 100, NULL, mRomPath);
chtwnd.parse(mRomPath);
chtwnd.writeCheatsToFile("/_nds/nds-bootstrap/cheatData.bin");
FILE* cheatData = fopen("/_nds/nds-bootstrap/cheatData.bin", "rb");
if (cheatData) {
u32 check[2];
fread(check, 1, 8, cheatData);
fclose(cheatData);
// TODO: Delete file, if above 0x8000 bytes
if (check[1] == 0xCF000000) goto cheat_failed;
}
} else {
fclose(cheatDb);
goto cheat_failed;
}
fclose(cheatDb);
}
return true;
cheat_failed:
// Remove cheat bin if exists
if (access("/_nds/nds-bootstrap/cheatData.bin", F_OK) == 0) {
remove("/_nds/nds-bootstrap/cheatData.bin");
}
return false;
}
bool NdsBootstrapLauncher::prepareIni() {
CIniFile ini;
ini.SetString("NDS-BOOTSTRAP", "NDS_PATH", mRomPath);
ini.SetString("NDS-BOOTSTRAP", "SAV_PATH", mSavePath);
ini.SaveIniFile("/_nds/nds-bootstrap.ini");
return true;
}
bool NdsBootstrapLauncher::launchRom(std::string romPath, std::string savePath, u32 flags,
u32 cheatOffset, u32 cheatSize) {
std::string ndsBootstrapPath = "/_nds/nds-bootstrap-release.nds";
std::vector<const char*> argv;
mRomPath = romPath;
mSavePath = savePath;
mFlags = flags;
// mRomPath *should* have the drive name set
// If it doesn't for some reason, default to `fat:/`, because most people are probably using
// this on flashcart
if (mRomPath.find("sd:/", 0) == std::string::npos)
ndsBootstrapPath = "fat:" + ndsBootstrapPath;
else
ndsBootstrapPath = "sd:" + ndsBootstrapPath;
// Create the nds-bootstrap directory if it doesn't exist
if (access("/_nds/nds-bootstrap/", F_OK) != 0) {
mkdir("/_nds/nds-bootstrap/", 0777);
}
// Setup argv to launch nds-bootstrap
argv.push_back(ndsBootstrapPath.c_str());
// Prepare cheat codes if enabled
if (flags & PATCH_CHEATS) {
if (!prepareCheats()) return false;
}
// Setup nds-bootstrap INI parameters
if (!prepareIni()) return false;
// Launch
eRunNdsRetCode rc = runNdsFile(argv[0], argv.size(), &argv[0]);
if (rc == RUN_NDS_OK) return true;
return false;
}

View File

@ -0,0 +1,25 @@
/*
Copyright (C) 2024 lifehackerhansol
SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <nds/ndstypes.h>
#include "../dsrom.h"
#include "ILauncher.h"
class NdsBootstrapLauncher : public ILauncher {
public:
bool launchRom(std::string romPath, std::string savePath, u32 flags, u32 cheatOffset,
u32 cheatSize) override;
private:
bool prepareCheats(void);
bool prepareIni(void);
std::string mRomPath;
std::string mSavePath;
u32 mFlags;
};

View File

@ -36,6 +36,7 @@
#include <sys/iosupport.h>
#include "launcher/HomebrewLauncher.h"
#include "launcher/NdsBootstrapLauncher.h"
using namespace akui;

View File

@ -13,6 +13,7 @@
#include "launcher/HomebrewLauncher.h"
#include "launcher/ILauncher.h"
#include "launcher/NdsBootstrapLauncher.h"
static SAVE_TYPE PrefillGame(u32 aGameCode) {
if (0x45444759 == aGameCode) // YGDE: 2209 - Diary Girl (USA)
@ -135,7 +136,6 @@ TLaunchResult launchRom(const std::string& aFullPath, DSRomInfo& aRomInfo, bool
size_t cheatSize = 0;
std::string saveName;
ILauncher* launcher = nullptr;
#if 0
if (!aRomInfo.isHomebrew()) {
u32 gameCode;
memcpy(&gameCode, aRomInfo.saveInfo().gameCode, sizeof(gameCode)); // because alignment
@ -167,6 +167,8 @@ TLaunchResult launchRom(const std::string& aFullPath, DSRomInfo& aRomInfo, bool
}
saveName = cSaveManager::generateSaveName(aFullPath, aRomInfo.saveInfo().getSlot());
// restore save data only for offical programs
if (isBigSave) {
isBigSave = cSaveManager::initializeSaveFile(aFullPath, aRomInfo.saveInfo().getSlot(),
bigSaveSize);
@ -174,7 +176,6 @@ TLaunchResult launchRom(const std::string& aFullPath, DSRomInfo& aRomInfo, bool
flags |= PATCH_SD_SAVE | (bigSaveMask << PATCH_SAVE_SHIFT);
saveManager().saveLastInfo(aFullPath);
} else {
// restore save data only for offical programs
SAVE_TYPE st = (SAVE_TYPE)aRomInfo.saveInfo().saveType;
if (ST_UNKNOWN == st) st = ST_AUTO;
SAVE_TYPE st_new = PrefillGame(gameCode);
@ -232,12 +233,9 @@ TLaunchResult launchRom(const std::string& aFullPath, DSRomInfo& aRomInfo, bool
launcher = new NdsBootstrapLauncher();
} else {
#endif
if (!aMenu) saveManager().saveLastInfo(aFullPath);
launcher = new HomebrewLauncher();
#if 0
}
#endif
launcher->launchRom(aFullPath, saveName, flags, cheatOffset, cheatSize);
return ELaunchRomOk;
}

View File

@ -22,6 +22,8 @@
#include "systemfilenames.h"
#include "ui.h"
#include "saves/ROMList.h"
using namespace akui;
cSaveManager::cSaveManager() {}
@ -221,6 +223,9 @@ SAVE_TYPE cSaveManager::getSaveTypeByFile(const std::string& romFilename) {
return ST_UNKNOWN;
}
SAVE_TYPE MelonDSROMListToSaveType[] = {ST_NOSAVE, ST_4K, ST_64K, ST_512K, ST_1M, ST_2M,
ST_4M, ST_8M, ST_16M, ST_32M, ST_64M};
void cSaveManager::updateSaveInfoByInfo(SAVE_INFO_EX& gameInfo) {
size_t saveCount = _customSaveList.size();
for (size_t i = 0; i < saveCount; ++i) {
@ -231,13 +236,17 @@ void cSaveManager::updateSaveInfoByInfo(SAVE_INFO_EX& gameInfo) {
}
gameInfo.defaults();
saveCount = _saveList.size();
for (size_t ii = 0; ii < saveCount; ii++) {
if (0 == memcmp(&gameInfo, &_saveList[ii], SAVE_INFO_EX_COMPARE_SIZE)) {
u8 saveType = _saveList[ii].saveType;
if (saveType > ST_UNKNOWN && saveType <= ST_8M)
gameInfo.saveType = _saveList[ii].saveType;
return;
u32 gameCode;
memcpy(&gameCode, gameInfo.gameCode, sizeof(gameCode)); // because alignment
for (size_t i = 0; i < ROMListEntryCount; i++) {
const ROMListEntry* entry = &ROMList[i];
if (gameCode == entry->GameCode) {
if (entry->SaveMemType == 0xFFFFFFFF)
gameInfo.saveType = ST_AUTO;
else
gameInfo.saveType = MelonDSROMListToSaveType[entry->SaveMemType];
break;
}
}
return;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
/*
Copyright 2016-2024 melonDS team
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/.
*/
/* clang-format off */
#ifndef ROMLIST_H
#define ROMLIST_H
#include <stddef.h>
#include <nds/ndstypes.h>
struct ROMListEntry
{
u32 GameCode;
u32 ROMSize;
u32 SaveMemType;
};
extern const ROMListEntry ROMList[];
/// The number of elements in \c ROMList.
extern const size_t ROMListEntryCount;
#endif // ROMLIST_H

View File

@ -2,6 +2,8 @@ This program is originally based on the akmenu project by the Acekard team, who
This program is further developed by yellow wood goblin, who released the source under the GPL-3.0-or-later license. See GPL3.txt for more info.
This provided source integrates ROM list code from the melonDS project, which is licensed under the GPL-3.0-or-later license. See GPL3.txt for more info.
This provided source integrates devkitPro's bootloader, which is licensed under the GPL-2.0-or-later license. See GPL2.txt for more info.
This provided source is collectively licensed under the GPL-3.0-or-later license.