Aurora DVD support (#43)

* Aurora DVD support

* Remove commented code

* Restore STUB_LOG
This commit is contained in:
Luke Street
2026-03-09 01:33:04 -06:00
committed by GitHub
parent 79938769fc
commit 3ce7aa3c9f
12 changed files with 47 additions and 423 deletions
-218
View File
@@ -1,218 +0,0 @@
#include "dusk/dvd_emu.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unordered_map>
#include "dolphin/os.h"
#include "dusk/logging.h"
#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#define PATH_SEP '\\'
#else
#include <sys/stat.h>
#include <unistd.h>
#define PATH_SEP '/'
#endif
namespace {
s32 g_nextEntryNum = 1;
// Lazy-init to avoid crash during DLL static initialization
std::string& g_basePath() {
static std::string instance = "data";
return instance;
}
std::unordered_map<s32, std::string>& getEntryPaths() {
static std::unordered_map<s32, std::string> instance;
return instance;
}
} // namespace
namespace DvdEmu {
void setBasePath(const char* path) {
#ifdef _WIN32
char exePath[MAX_PATH];
GetModuleFileNameA(NULL, exePath, MAX_PATH);
// Get the directory of the .exe
char* lastSlash = strrchr(exePath, '\\');
if (lastSlash) {
*lastSlash = '\0';
}
// exeDir + "/" + path
g_basePath() = exePath;
g_basePath() += PATH_SEP;
g_basePath() += path;
#else
g_basePath() = path;
#endif
DuskLog.debug("[DvdEmu] Base path set to: %s\n", g_basePath().c_str());
}
const char* getBasePath() {
return g_basePath().c_str();
}
std::string convertPath(const char* gcPath) {
std::string result = g_basePath();
// Skip leading slashes
const char* p = gcPath;
while (*p == '/' || *p == '\\')
p++;
result += PATH_SEP;
// Append path, converting slashes
while (*p) {
if (*p == '/' || *p == '\\') {
result += PATH_SEP;
} else {
result += *p;
}
p++;
}
return result;
}
bool fileExists(const char* gcPath) {
std::string fullPath = convertPath(gcPath);
#ifdef _WIN32
DWORD attrib = GetFileAttributesA(fullPath.c_str());
bool exists = (attrib != INVALID_FILE_ATTRIBUTES && !(attrib & FILE_ATTRIBUTE_DIRECTORY));
#else
struct stat st;
bool exists = (stat(fullPath.c_str(), &st) == 0 && S_ISREG(st.st_mode));
#endif
if (exists) {
DuskLog.info("[DvdEmu] FOUND: {}", gcPath);
} else {
DuskLog.warn("[DvdEmu] MISSING: {}", gcPath);
}
return exists;
}
u32 getFileSize(const char* gcPath) {
std::string fullPath = convertPath(gcPath);
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f)
return 0;
fseek(f, 0, SEEK_END);
u32 size = (u32)ftell(f);
fclose(f);
return size;
}
void* loadFile(const char* gcPath, u32* outSize, void* heap) {
std::string fullPath = convertPath(gcPath);
DuskLog.debug("[DvdEmu] Loading request: '{}'", gcPath);
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f) {
DuskLog.error("[DvdEmu] Failed to open file at physical path: {}", fullPath.c_str());
if (outSize)
*outSize = 0;
return nullptr;
}
fseek(f, 0, SEEK_END);
u32 size = (u32)ftell(f);
fseek(f, 0, SEEK_SET);
// Allocate with 32-byte alignment (matching GameCube)
void* data;
#ifdef _WIN32
data = _aligned_malloc(size, 32);
#else
data = aligned_alloc(32, (size + 31) & ~31);
#endif
if (!data) {
DuskLog.fatal("[DvdEmu] Failed to allocate {} bytes for {}", size, gcPath);
fclose(f);
if (outSize)
*outSize = 0;
return nullptr;
}
u32 bytesRead = (u32)fread(data, 1, size, f);
fclose(f);
if (bytesRead != size) {
DuskLog.fatal("[DvdEmu] Read error: expected {}, got {} for {}", size, bytesRead,
gcPath);
}
if (outSize)
*outSize = bytesRead;
DuskLog.info("[DvdEmu] Loaded {} ({} bytes)", gcPath, bytesRead);
return data;
}
u32 loadFileToBuffer(const char* gcPath, void* buffer, u32 bufferSize, u32 offset) {
std::string fullPath = convertPath(gcPath);
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f) {
DuskLog.error("[DvdEmu] Failed to open file for buffer load: {}", fullPath.c_str());
return 0;
}
if (offset > 0) {
fseek(f, offset, SEEK_SET);
}
u32 bytesRead = (u32)fread(buffer, 1, bufferSize, f);
fclose(f);
return bytesRead;
}
} // namespace DvdEmu
// Entry-Number System (emulates DVD's entry system)
s32 DVDConvertPathToEntrynum_Emu(const char* path) {
if (!DvdEmu::fileExists(path)) {
printf("[DVD] Error: File not found for entrynum conversion: %s\n", path);
return -1;
}
// Check if already registered
for (const auto& pair : getEntryPaths()) {
if (pair.second == path) {
return pair.first;
}
}
// Assign new entry number
s32 entryNum = g_nextEntryNum++;
getEntryPaths()[entryNum] = path;
return entryNum;
}
void DVDRegisterPath(s32 entryNum, const char* path) {
getEntryPaths()[entryNum] = path;
}
const char* DVDGetPathForEntry(s32 entryNum) {
auto it = getEntryPaths().find(entryNum);
if (it != getEntryPaths().end()) {
return it->second.c_str();
}
return nullptr;
}
-118
View File
@@ -9,7 +9,6 @@
#include <condition_variable>
#include <unordered_map>
#include <memory>
#include <dusk/dvd_emu.h>
#include <dusk/logging.h>
@@ -1169,123 +1168,6 @@ void AIStopDMA(void) {
STUB_LOG();
}
#pragma mark DVD
#include <dolphin/dvd.h>
s32 DVDCancel(volatile DVDCommandBlock* block) {
STUB_LOG();
return 0;
}
s32 DVDCancel(DVDCommandBlock* block) {
STUB_LOG();
return 0;
}
BOOL DVDChangeDir(const char* dirName) {
STUB_LOG();
return TRUE;
}
BOOL DVDCheckDisk(void) {
STUB_LOG();
return TRUE;
}
BOOL DVDClose(DVDFileInfo* fileInfo) {
STUB_LOG();
return TRUE;
}
int DVDCloseDir(DVDDir* dir) {
STUB_LOG();
return 0;
}
s32 DVDConvertPathToEntrynum(const char* pathPtr) {
return DVDConvertPathToEntrynum_Emu(pathPtr);
}
BOOL DVDFastOpen(s32 entrynum, DVDFileInfo* fileInfo) {
const char* path = DVDGetPathForEntry(entrynum);
if (!path) {
OSReport("[DVD] DVDFastOpen: no path for entry %d\n", entrynum);
return FALSE;
}
u32 fileSize = DvdEmu::getFileSize(path);
if (fileSize == 0) {
OSReport("[DVD] DVDFastOpen: file not found or empty for entry %d (%s)\n", entrynum, path);
return FALSE;
}
// Repurpose startAddr to store entrynum for later DVDReadPrio lookups
fileInfo->startAddr = (u32)entrynum;
fileInfo->length = fileSize;
fileInfo->callback = NULL;
fileInfo->cb.state = 0;
return TRUE;
}
s32 DVDGetCommandBlockStatus(const DVDCommandBlock* block) {
STUB_LOG();
return 0;
}
DVDDiskID* DVDGetCurrentDiskID(void) {
STUB_LOG();
return NULL;
}
s32 DVDGetDriveStatus(void) {
STUB_LOG();
return 0;
}
void DVDInit(void) {
STUB_LOG();
}
BOOL DVDOpen(const char* fileName, DVDFileInfo* fileInfo) {
s32 entryNum = DVDConvertPathToEntrynum(fileName);
if (entryNum < 0) {
OSReport("[DVD] DVDOpen: file not found: %s\n", fileName);
return FALSE;
}
return DVDFastOpen(entryNum, fileInfo);
}
int DVDOpenDir(const char* dirName, DVDDir* dir) {
STUB_LOG();
return 0;
}
BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset,
DVDCallback callback, s32 prio) {
// Synchronous read, then invoke callback with result
s32 entryNum = (s32)fileInfo->startAddr;
const char* path = DVDGetPathForEntry(entryNum);
if (!path) {
OSReport("[DVD] DVDReadAsyncPrio: no path for entry %d\n", entryNum);
if (callback) callback(-1, fileInfo);
return FALSE;
}
u32 bytesRead = DvdEmu::loadFileToBuffer(path, addr, (u32)length, (u32)offset);
if (callback) {
callback((s32)bytesRead, fileInfo);
}
return TRUE;
}
int DVDReadDir(DVDDir* dir, DVDDirEntry* dirent) {
STUB_LOG();
return 0;
}
s32 DVDReadPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset, s32 prio) {
s32 entryNum = (s32)fileInfo->startAddr;
const char* path = DVDGetPathForEntry(entryNum);
if (!path) {
OSReport("[DVD] DVDReadPrio: no path for entry %d\n", entryNum);
return -1;
}
u32 bytesRead = DvdEmu::loadFileToBuffer(path, addr, (u32)length, (u32)offset);
return (s32)bytesRead;
}
void DVDReadAbsAsyncForBS(void* a, struct bb2struct* b, int c, int d, void (*e)()) {
STUB_LOG();
}
void DVDReadDiskID(void* a, DVDDiskID* b, void (*c)()) {
STUB_LOG();
}
void DVDReset() {
STUB_LOG();
}
#pragma mark GX
#include <dolphin/gx.h>
+25 -25
View File
@@ -44,13 +44,14 @@
#include <chrono>
#include <thread>
#include "SSystem/SComponent/c_API.h"
#include "dusk/dvd_emu.h"
#include "dusk/dusk.h"
#include "dusk/logging.h"
#include <aurora/aurora.h>
#include <aurora/event.h>
#include <aurora/main.h>
#include <aurora/dvd.h>
#include <dolphin/dvd.h>
#include "cxxopts.hpp"
@@ -67,7 +68,7 @@ const int audioHeapSize = 0x14D800;
#endif
// =========================================================================
// LOAD_COPYDATE - PC Version using DvdEmu
// LOAD_COPYDATE - PC Version
// =========================================================================
#define COPYDATE_PATH "/str/Final/Release/COPYDATE"
@@ -75,33 +76,26 @@ s32 LOAD_COPYDATE(void*) {
char buffer[32];
memset(buffer, 0, sizeof(buffer));
u32 size = 0;
void* data = DvdEmu::loadFile(COPYDATE_PATH, &size, nullptr);
DVDFileInfo fi;
if (DVDOpen(COPYDATE_PATH, &fi)) {
u32 readLen = (fi.length < sizeof(buffer) - 1) ? fi.length : sizeof(buffer) - 1;
// DVDReadPrio requires 32-byte aligned buffer and length rounded up to 32
u32 alignedLen = (readLen + 31) & ~31;
alignas(32) char readBuf[64];
DVDReadPrio(&fi, readBuf, alignedLen, 0, 2);
DVDClose(&fi);
// Fallback: Try root if not found
if (!data) {
data = DvdEmu::loadFile("/COPYDATE", &size, nullptr);
}
if (data) {
u32 copyLen = (size < sizeof(buffer) - 1) ? size : sizeof(buffer) - 1;
memcpy(buffer, data, copyLen);
buffer[copyLen] = '\0';
#ifdef _WIN32
_aligned_free(data);
#else
free(data);
#endif
memcpy(buffer, readBuf, readLen);
buffer[readLen] = '\0';
} else {
strcpy(buffer, "PC PORT BUILD");
OSReport("Warning: COPYDATE file not found at %s\n", COPYDATE_PATH);
DuskLog.warn("COPYDATE file not found at {}", COPYDATE_PATH);
}
memcpy(mDoMain::COPYDATE_STRING, buffer, sizeof(mDoMain::COPYDATE_STRING) - 1);
mDoMain::COPYDATE_STRING[sizeof(mDoMain::COPYDATE_STRING) - 1] = '\0';
OS_REPORT("\x1b[36mCOPYDATE=[%s]\n\x1b[m", mDoMain::COPYDATE_STRING);
DuskLog.info("COPYDATE=[{}]", mDoMain::COPYDATE_STRING);
return 1;
}
@@ -203,8 +197,11 @@ int game_main(int argc, char* argv[]) {
arg_options.add_options()
("l,log-level", "Log level from " + std::to_string(AuroraLogLevel::LOG_DEBUG) + " to " + std::to_string(AuroraLogLevel::LOG_FATAL), cxxopts::value<uint8_t>()->default_value("0"))
("h,help", "Print usage");
("h,help", "Print usage")
("dvd", "Path to DVD image file", cxxopts::value<std::string>()->default_value("game.iso"));
arg_options.parse_positional({"dvd"});
arg_options.positional_help("<dvd-image>");
arg_options.allow_unrecognised_options();
parsed_arg_options = arg_options.parse(argc, argv);
@@ -234,10 +231,13 @@ int game_main(int argc, char* argv[]) {
auroraInfo = aurora_initialize(argc, argv, &config);
OSInit();
const auto& dvd_path = parsed_arg_options["dvd"].as<std::string>();
DuskLog.info("Loading DVD image: {}", dvd_path);
if (!aurora_dvd_open(dvd_path.c_str())) {
DuskLog.fatal("Failed to open DVD image: {}", dvd_path);
}
// 3. Init DVD Emulation
DvdEmu::setBasePath("data");
OSInit();
mDoMain::sPowerOnTime = OSGetTime();