Files
dusklight/src/dusk/dvd_asset.cpp
T
Pieter-Jan Briers 977ad16806 GCN PAL support (#533)
* Basic PAL ISO & language support

Probably still needs much more work

* Add language selector to pre-launch

* Store DVDDiskID in a global

Can use this later for things

* More version system API improvements

* d_name mostly region switching fully

JPN doesn't work yet cuz it'll be a nightmare, probably.

* More version switching support

* Mark GCN PAL as supported ROM

* Fix remaining REL assets to have PAL offsets

* d_a_mg_fish PAL

* d_a_mg_fshop PAL

* isRegionUsa helper

* d_menu_fishing PAL

* d_msg_class PAL

* m_Do_MemCardRWmng PAL

* Update CARDInit call & remove DUSK_TP_VERSION

* Fix Ganon cape

Missed this one.

* Remove tp_version from Sentry

---------

Co-authored-by: Luke Street <luke@street.dev>
2026-04-25 15:46:12 -06:00

140 lines
4.2 KiB
C++

#include "dusk/dvd_asset.hpp"
#include "dusk/logging.h"
#include "dusk/endian.h"
#include "dolphin/dvd.h"
#include "DynamicLink.h"
#include "JSystem/JKernel/JKRArchive.h"
#include "JSystem/JKernel/JKRDvdRipper.h"
#include <cstring>
namespace dusk {
static const u8* s_dolData = nullptr; // pointer to dol data
static size_t s_dolSize = 0;
struct DolHeader {
BE(u32) textOffset[7];
BE(u32) dataOffset[11];
BE(u32) textAddr[7];
BE(u32) dataAddr[11];
BE(u32) textSize[7];
BE(u32) dataSize[11];
};
struct DolSection {
u32 fileOffset;
u32 vaddr;
u32 size;
};
static DolSection s_dolSections[18]; // 7 text + 11 data
static int s_dolSectionCount = 0;
static bool EnsureDolParsed() {
if (s_dolData) return true;
s32 sz = 0;
const u8* p = DVDGetDOLLocation(&sz);
if (!p || sz < 256) {
DuskLog.fatal("dvd_asset: DVDGetDOLLocation failed (size={})", sz);
return false;
}
s_dolData = p;
s_dolSize = sz;
const auto* hdr = (const DolHeader*)s_dolData;
s_dolSectionCount = 0;
for (int i = 0; i < 7; i++) {
u32 off = hdr->textOffset[i];
u32 addr = hdr->textAddr[i];
u32 sz = hdr->textSize[i];
if (sz > 0 && off > 0) {
s_dolSections[s_dolSectionCount++] = {off, addr, sz};
}
}
for (int i = 0; i < 11; i++) {
u32 off = hdr->dataOffset[i];
u32 addr = hdr->dataAddr[i];
u32 sz = hdr->dataSize[i];
if (sz > 0 && off > 0) {
s_dolSections[s_dolSectionCount++] = {off, addr, sz};
}
}
return true;
}
static s32 DolVaToFileOffset(u32 va) {
if (!EnsureDolParsed()) return -1;
for (int i = 0; i < s_dolSectionCount; i++) {
const auto& sec = s_dolSections[i];
if (va >= sec.vaddr && va < sec.vaddr + sec.size) {
return static_cast<s32>(sec.fileOffset + (va - sec.vaddr));
}
}
DuskLog.fatal("dvd_asset: VA 0x{:08X} not found in any DOL section", va);
return -1;
}
static u32 GetOffsetForVersion(std::initializer_list<OffsetVersion> version) {
const auto gameVersion = dusk::version::getGameVersion();
for (auto elem : version) {
if (elem.mGameVersion == gameVersion) {
return elem.mOffset;
}
}
DuskLog.fatal("Unable to find offset for this game version!");
}
bool LoadDolAsset(void* dst, std::initializer_list<OffsetVersion> virtualAddress, s32 size) {
s32 fileOffset = DolVaToFileOffset(GetOffsetForVersion(virtualAddress));
if (fileOffset < 0) {
return false;
}
if (size <= 0 || (size_t)(fileOffset + size) > s_dolSize) {
DuskLog.fatal("dvd_asset: DOL read out of range (offset={:#x} size={:#x} dolSize={})", fileOffset, size, s_dolSize);
return false;
}
std::memcpy(dst, s_dolData + fileOffset, size);
return true;
}
bool LoadRelAsset(void* dst, const char* dvdPath, std::initializer_list<OffsetVersion> offset, s32 size) {
auto resOffset = GetOffsetForVersion(offset);
void* p = JKRDvdRipper::loadToMainRAM(dvdPath, (u8*)dst, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, resOffset, nullptr, nullptr);
if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, resOffset, size);
return p != nullptr;
}
bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::initializer_list<OffsetVersion> offset, s32 size) {
auto resOffset = GetOffsetForVersion(offset);
// On TARGET_PC, cDyl_InitCallback skips DynamicModuleControl::initialize() due to static linking
// Mount RELS.arc on first use so sArchive is available
static bool s_mountAttempted = false;
if (!DynamicModuleControl::sArchive && !s_mountAttempted) {
s_mountAttempted = true; DynamicModuleControl::initialize();
}
if (!DynamicModuleControl::sArchive) {
DuskLog.fatal("dvd_asset: RELS archive not mounted"); return false;
}
const u8* rel = static_cast<const u8*>(DynamicModuleControl::sArchive->getResource(memType, relFileName));
if (!rel) {
DuskLog.fatal("dvd_asset: {} not found in RELS archive", relFileName); return false;
}
std::memcpy(dst, rel + resOffset, size);
return true;
}
} // namespace dusk