mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-20 05:16:24 -04:00
Mod SDK: Arc Overlays (#2280)
* Mod SDK: Arc Overlays * Use DVD Functions for Arc overlays * Re-add Fetchcontent for json.hpp * Fix build for actions * Make sure buffer usues aligned length * Add include so msvc compiles * Arc Overlays fixes: remove _arc suffix, handle getting overlayed file size from arcs, copy data correctly, etc. * Reload overlayed data during loading screens * Rename sync function * Free overlayed files on load instead of re-loading them * Rework arc overlays & load overlay files into host memory --------- Co-authored-by: Luke Street <luke@street.dev>
This commit is contained in:
+12
-2
@@ -262,14 +262,16 @@ Installs hooks on game functions and resolves symbols by name. You'll rarely cal
|
||||
### OverlayService (`mods/svc/overlay.h`)
|
||||
|
||||
Registers DVD file overlays at runtime: the dynamic counterpart to the static `overlay/` directory (see
|
||||
[Asset Overlays](#asset-overlays)). Overlay a disc path with a file from your bundle, or with a caller-owned buffer
|
||||
[Asset Overlays](#asset-overlays)). Overlay a disc path with a file from your bundle, a file within an archive,
|
||||
or with a caller-owned buffer
|
||||
(copied on registration):
|
||||
|
||||
```cpp
|
||||
IMPORT_SERVICE(OverlayService, svc_overlay);
|
||||
|
||||
OverlayHandle handle = 0;
|
||||
svc_overlay->add_file(mod_ctx, "/res/Msgus.arc", "res/replacement.arc", &handle);
|
||||
svc_overlay->add_file(mod_ctx, "/Movie/demo_movie98_00.thp", "res/replacement.thp", &handle); // Replaces the demo movie
|
||||
svc_overlay->add_file(mod_ctx, "/res/Object/Kmdl/archive/bmwr/al.bmd", "res/link_model.bmd", &handle); // Replaces link's model
|
||||
svc_overlay->add_buffer(mod_ctx, "/generated.txt", data, size, nullptr);
|
||||
svc_overlay->remove(mod_ctx, handle);
|
||||
```
|
||||
@@ -278,6 +280,9 @@ svc_overlay->remove(mod_ctx, handle);
|
||||
on the disc are added as new files. Changes are applied at the next frame boundary, and data the game already read
|
||||
stays in memory until the file is re-read: sometimes a scene reload, and in the worst case, a full restart.
|
||||
|
||||
Dusklight reloads core archive files during scene transitions so modifications to Link, Midna or other globally-loaded
|
||||
data get refreshed without a full restart.
|
||||
|
||||
See [Asset Overlays](#asset-overlays) for priority and conflict handling.
|
||||
|
||||
### TextureService (`mods/svc/texture.h`)
|
||||
@@ -882,6 +887,11 @@ For reference parameters (e.g. `const cXyz& pos`), `arg_ref<cXyz>` yields a dire
|
||||
|
||||
Files placed under `overlay/` in the `.dusk` archive override game files at the corresponding path, equivalent to
|
||||
replacing files in the .iso. This requires no code: an archive with just `mod.json` and `overlay/` is a complete mod.
|
||||
To replace a file within an `.arc` archive, replace the archive suffix with a directory and place the replacement at
|
||||
its path within the archive.
|
||||
|
||||
- `overlay/Audiores/Stream/menu_select.ast` replaces the main title's audio stream.
|
||||
- `overlay/res/Layout/main2D/main2d/timg/midona64.bti` replaces Midna's UI icon inside `main2D.arc`.
|
||||
|
||||
Files placed under `textures/` register as texture replacements, and act just like the user's general
|
||||
`texture_replacements/` directory: Dolphin-style naming, matched by texture hash
|
||||
|
||||
Vendored
+1
-1
Submodule extern/aurora updated: cf3ffc9886...0f15fb65d1
@@ -6,11 +6,17 @@
|
||||
#include "global.h"
|
||||
#include "helpers/endian.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#endif
|
||||
|
||||
class JKRHeap;
|
||||
|
||||
/**
|
||||
* @ingroup jsystem-jkernel
|
||||
*
|
||||
*
|
||||
*/
|
||||
struct SArcHeader {
|
||||
/* 0x00 */ BE(u32) signature;
|
||||
@@ -25,7 +31,7 @@ struct SArcHeader {
|
||||
|
||||
/**
|
||||
* @ingroup jsystem-jkernel
|
||||
*
|
||||
*
|
||||
*/
|
||||
struct SArcDataInfo {
|
||||
/* 0x00 */ BE(u32) num_nodes;
|
||||
@@ -59,7 +65,7 @@ extern u32 sCurrentDirID__10JKRArchive; // JKRArchive::sCurrentDirID
|
||||
|
||||
/**
|
||||
* @ingroup jsystem-jkernel
|
||||
*
|
||||
*
|
||||
*/
|
||||
class JKRArchive : public JKRFileLoader {
|
||||
public:
|
||||
@@ -192,9 +198,7 @@ public:
|
||||
u32 countFile() const { return mArcInfoBlock->num_file_entries; }
|
||||
s32 countDirectory() const { return mArcInfoBlock->num_nodes; }
|
||||
u8 getMountMode() const { return mMountMode; }
|
||||
bool isFileEntry(u32 param_0) const {
|
||||
return getFileAttribute(param_0) & 1;
|
||||
}
|
||||
bool isFileEntry(u32 param_0) const { return getFileAttribute(param_0) & 1; }
|
||||
|
||||
public:
|
||||
/* 0x00 */ // vtable
|
||||
@@ -210,7 +214,36 @@ public:
|
||||
/* 0x54 */ const char* mStringTable;
|
||||
|
||||
#if TARGET_PC
|
||||
u32 getFileSize(SDIFileEntry* entry) const;
|
||||
void* getOverlayData(SDIFileEntry* entry, u32* outSize);
|
||||
bool getOverlayFileSize(SDIFileEntry* entry, u32* outSize) const;
|
||||
static void notifyOverlayFilesChanged();
|
||||
|
||||
protected:
|
||||
void** mFileData;
|
||||
|
||||
struct ArcOverlayResource {
|
||||
u32 entryIndex;
|
||||
u32 size;
|
||||
u64 generation;
|
||||
};
|
||||
|
||||
// Resource pointers remain valid until removed through the JKR resource APIs.
|
||||
// That way, any pointers to old overlay data remain valid even when the overlay changed.
|
||||
std::unordered_map<void*, ArcOverlayResource> mArcOverlayResources;
|
||||
mutable std::unordered_map<u32, void*> mActiveArcOverlayResources;
|
||||
mutable std::string mArcOverlaysPath;
|
||||
mutable std::unordered_map<u32, std::string> mIdxToPathMap;
|
||||
mutable bool mArcOverlaysPathResolved = false;
|
||||
|
||||
bool buildArcOverlaysPath() const;
|
||||
void buildIndexToPathMap(u32 dirIndex, const std::string& currentPath) const;
|
||||
bool getOverlayPath(SDIFileEntry* entry, std::string& path) const;
|
||||
void* getActiveOverlayData(SDIFileEntry* entry, u32* outSize) const;
|
||||
bool copyOverlayData(void* buffer, u32 bufferSize, SDIFileEntry* entry, u32* outSize);
|
||||
bool getOverlayResourceSize(const void* data, u32* outSize) const;
|
||||
bool removeOverlayResource(void* resource, bool freeResource);
|
||||
void removeAllOverlayResources();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@@ -234,7 +267,7 @@ public:
|
||||
} else if (attr & JKRARCHIVE_ATTR_YAZ0) {
|
||||
return COMPRESSION_YAZ0;
|
||||
} else {
|
||||
return COMPRESSION_YAY0;
|
||||
return COMPRESSION_YAY0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +276,9 @@ public:
|
||||
|
||||
protected:
|
||||
static DUSK_GAME_DATA u32 sCurrentDirID;
|
||||
#if TARGET_PC
|
||||
static std::atomic<u64> sArcOverlayGeneration;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline JKRCompression JKRConvertAttrToCompressionType(int attr) {
|
||||
@@ -261,8 +297,8 @@ inline bool JKRRemoveResource(void* resource, JKRFileLoader* fileLoader) {
|
||||
return JKRFileLoader::removeResource(resource, fileLoader);
|
||||
}
|
||||
|
||||
inline JKRArchive* JKRMountArchive(void* ptr, JKRHeap* heap,
|
||||
JKRArchive::EMountDirection mountDirection) {
|
||||
inline JKRArchive* JKRMountArchive(
|
||||
void* ptr, JKRHeap* heap, JKRArchive::EMountDirection mountDirection) {
|
||||
return JKRArchive::mount(ptr, heap, mountDirection);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ size_t JASResArcLoader::getResSize(JKRArchive const* i_archiveP, u16 i_resourceI
|
||||
return 0;
|
||||
}
|
||||
|
||||
return file->data_size;
|
||||
return DUSK_IF_ELSE(i_archiveP->getFileSize(file), file->data_size);
|
||||
}
|
||||
|
||||
size_t JASResArcLoader::getResMaxSize(JKRArchive const* i_archiveP) {
|
||||
@@ -27,9 +27,16 @@ size_t JASResArcLoader::getResMaxSize(JKRArchive const* i_archiveP) {
|
||||
for (index = 0; index < fileEntries; index++) {
|
||||
JKRArchive::SDIFileEntry* file = i_archiveP->findIdxResource(index);
|
||||
if (file) {
|
||||
#if TARGET_PC
|
||||
const u32 fileSize = i_archiveP->getFileSize(file);
|
||||
if (maxSize < fileSize) {
|
||||
maxSize = fileSize;
|
||||
}
|
||||
#else
|
||||
if (maxSize < file->data_size) {
|
||||
maxSize = file->data_size;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,6 +196,13 @@ cleanup:
|
||||
|
||||
void* JKRAramArchive::fetchResource(SDIFileEntry* pEntry, u32* pOutSize) {
|
||||
JUT_ASSERT(442, isMounted());
|
||||
|
||||
#if TARGET_PC
|
||||
if (void* data = getOverlayData(pEntry, pOutSize); data != nullptr) {
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 outSize;
|
||||
u8* outBuf;
|
||||
if (pOutSize == NULL) {
|
||||
@@ -231,6 +238,13 @@ void* JKRAramArchive::fetchResource(SDIFileEntry* pEntry, u32* pOutSize) {
|
||||
void* JKRAramArchive::fetchResource(void* buffer, u32 bufferSize, SDIFileEntry* pEntry,
|
||||
u32* resourceSize) {
|
||||
JUT_ASSERT(515, isMounted());
|
||||
|
||||
#if TARGET_PC
|
||||
if (copyOverlayData(buffer, bufferSize, pEntry, resourceSize)) {
|
||||
return buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 size = pEntry->data_size;
|
||||
if (size > bufferSize) {
|
||||
size = bufferSize;
|
||||
@@ -337,6 +351,12 @@ u32 JKRAramArchive::getExpandedResSize(const void* ptr) const {
|
||||
return this->getResSize(ptr);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (u32 size; getOverlayResourceSize(ptr, &size)) {
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
JKRArchive::SDIFileEntry* entry = this->findPtrResource(ptr);
|
||||
if (entry == NULL) {
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
@@ -7,6 +7,37 @@
|
||||
|
||||
#if TARGET_PC
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
#include "JSystem/JKernel/JKRDvdRipper.h"
|
||||
#if _WIN32
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
std::atomic<u64> JKRArchive::sArcOverlayGeneration{0};
|
||||
|
||||
namespace {
|
||||
|
||||
void* alloc_overlay_buffer(u32 size) {
|
||||
#if _WIN32
|
||||
return _aligned_malloc(size, alignof(std::max_align_t));
|
||||
#else
|
||||
return std::malloc(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void free_overlay_buffer(void* data) {
|
||||
#if _WIN32
|
||||
_aligned_free(data);
|
||||
#else
|
||||
std::free(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
DUSK_GAME_DATA u32 JKRArchive::sCurrentDirID;
|
||||
@@ -42,6 +73,7 @@ JKRArchive::JKRArchive(s32 entryNumber, JKRArchive::EMountMode mountMode) {
|
||||
|
||||
JKRArchive::~JKRArchive() {
|
||||
#if TARGET_PC
|
||||
removeAllOverlayResources();
|
||||
if (mFileData != nullptr) {
|
||||
JKRHeap::getSystemHeap()->free(mFileData);
|
||||
mFileData = nullptr;
|
||||
@@ -270,4 +302,240 @@ void JKRArchive::initFileDataPointers() {
|
||||
mFiles[i].index = i;
|
||||
}
|
||||
}
|
||||
|
||||
void JKRArchive::notifyOverlayFilesChanged() {
|
||||
sArcOverlayGeneration.fetch_add(1, std::memory_order_release);
|
||||
}
|
||||
|
||||
bool JKRArchive::buildArcOverlaysPath() const {
|
||||
if (mArcOverlaysPathResolved) {
|
||||
return !mArcOverlaysPath.empty();
|
||||
}
|
||||
mArcOverlaysPathResolved = true;
|
||||
|
||||
if (mEntryNum < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char pathBuffer[1024];
|
||||
if (!DVDConvertEntrynumToPath(mEntryNum, pathBuffer, sizeof(pathBuffer))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path{pathBuffer};
|
||||
constexpr std::string_view extension{".arc"};
|
||||
if (path.size() < extension.size() ||
|
||||
path.compare(path.size() - extension.size(), extension.size(), extension) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
path.resize(path.size() - extension.size());
|
||||
path.push_back('/');
|
||||
|
||||
mArcOverlaysPath = std::move(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
void JKRArchive::buildIndexToPathMap(u32 dirIndex, const std::string& currentPath) const {
|
||||
const SDIDirEntry& dir = mNodes[dirIndex];
|
||||
for (int i = 0; i < dir.num_entries; i++) {
|
||||
const SDIFileEntry& entry = mFiles[dir.first_file_index + i];
|
||||
std::string entryName{&mStringTable[entry.getNameOffset()]};
|
||||
if (entryName == "." || entryName == "..") {
|
||||
continue;
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
buildIndexToPathMap(entry.data_offset, currentPath + entryName + "/");
|
||||
} else {
|
||||
mIdxToPathMap[entry.index] = currentPath + entryName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool JKRArchive::getOverlayPath(SDIFileEntry* entry, std::string& path) const {
|
||||
if (entry == nullptr || !buildArcOverlaysPath()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mIdxToPathMap.empty()) {
|
||||
buildIndexToPathMap(0, std::string{&mStringTable[mNodes[0].name_offset]} + "/");
|
||||
}
|
||||
|
||||
const auto pathIt = mIdxToPathMap.find(entry->index);
|
||||
if (pathIt == mIdxToPathMap.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
path = mArcOverlaysPath + pathIt->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
void* JKRArchive::getActiveOverlayData(SDIFileEntry* entry, u32* outSize) const {
|
||||
const auto activeIt = mActiveArcOverlayResources.find(entry->index);
|
||||
if (activeIt == mActiveArcOverlayResources.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto resourceIt = mArcOverlayResources.find(activeIt->second);
|
||||
const u64 generation = sArcOverlayGeneration.load(std::memory_order_acquire);
|
||||
if (resourceIt == mArcOverlayResources.end() || resourceIt->second.generation != generation) {
|
||||
// Keep the allocation owned so raw pointers returned by earlier fetches remain valid.
|
||||
mActiveArcOverlayResources.erase(activeIt);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (outSize != nullptr) {
|
||||
*outSize = resourceIt->second.size;
|
||||
}
|
||||
return resourceIt->first;
|
||||
}
|
||||
|
||||
void* JKRArchive::getOverlayData(SDIFileEntry* entry, u32* outSize) {
|
||||
if (entry == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (void* data = getActiveOverlayData(entry, outSize)) {
|
||||
return data;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!getOverlayPath(entry, path)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
constexpr u32 alignmentMask = 0x1f;
|
||||
const u64 generation = sArcOverlayGeneration.load(std::memory_order_acquire);
|
||||
DVDFileInfo fileInfo{};
|
||||
if (!DVDOpen(path.c_str(), &fileInfo)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const u32 logicalSize = fileInfo.length;
|
||||
if (logicalSize > static_cast<u32>(std::numeric_limits<s32>::max()) - alignmentMask) {
|
||||
DVDClose(&fileInfo);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const u32 readSize = ALIGN_NEXT(logicalSize, 0x20);
|
||||
const u32 allocationSize = readSize == 0 ? 1 : readSize;
|
||||
void* data = alloc_overlay_buffer(allocationSize);
|
||||
if (data == nullptr) {
|
||||
DVDClose(&fileInfo);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const s32 status = DVDReadPrio(&fileInfo, data, readSize, 0, 2);
|
||||
DVDClose(&fileInfo);
|
||||
if (status < DVD_RESULT_GOOD || static_cast<u32>(status) != logicalSize) {
|
||||
free_overlay_buffer(data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mArcOverlayResources.emplace(data, ArcOverlayResource{
|
||||
.entryIndex = entry->index,
|
||||
.size = logicalSize,
|
||||
.generation = generation,
|
||||
});
|
||||
mActiveArcOverlayResources[entry->index] = data;
|
||||
|
||||
if (outSize != nullptr) {
|
||||
*outSize = logicalSize;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
bool JKRArchive::copyOverlayData(void* buffer, u32 bufferSize, SDIFileEntry* entry, u32* outSize) {
|
||||
u32 overlaySize;
|
||||
const void* overlayData = getOverlayData(entry, &overlaySize);
|
||||
if (overlayData == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const u32 copySize = overlaySize < bufferSize ? overlaySize : bufferSize;
|
||||
if (copySize != 0) {
|
||||
memcpy(buffer, overlayData, copySize);
|
||||
}
|
||||
if (outSize != nullptr) {
|
||||
*outSize = copySize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JKRArchive::getOverlayResourceSize(const void* data, u32* outSize) const {
|
||||
const auto resourceIt = mArcOverlayResources.find(const_cast<void*>(data));
|
||||
if (resourceIt == mArcOverlayResources.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outSize != nullptr) {
|
||||
*outSize = resourceIt->second.size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JKRArchive::getOverlayFileSize(SDIFileEntry* entry, u32* outSize) const {
|
||||
if (entry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 activeSize;
|
||||
if (getActiveOverlayData(entry, &activeSize) != nullptr) {
|
||||
if (outSize != nullptr) {
|
||||
*outSize = activeSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!getOverlayPath(entry, path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DVDFileInfo fileInfo{};
|
||||
if (!DVDOpen(path.c_str(), &fileInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outSize != nullptr) {
|
||||
*outSize = fileInfo.length;
|
||||
}
|
||||
DVDClose(&fileInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 JKRArchive::getFileSize(SDIFileEntry* entry) const {
|
||||
u32 size;
|
||||
if (getOverlayFileSize(entry, &size)) {
|
||||
return size;
|
||||
}
|
||||
return entry != nullptr ? entry->getSize() : 0;
|
||||
}
|
||||
|
||||
bool JKRArchive::removeOverlayResource(void* resource, bool freeResource) {
|
||||
const auto resourceIt = mArcOverlayResources.find(resource);
|
||||
if (resourceIt == mArcOverlayResources.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto activeIt = mActiveArcOverlayResources.find(resourceIt->second.entryIndex);
|
||||
if (activeIt != mActiveArcOverlayResources.end() && activeIt->second == resource) {
|
||||
mActiveArcOverlayResources.erase(activeIt);
|
||||
}
|
||||
|
||||
if (freeResource) {
|
||||
free_overlay_buffer(resource);
|
||||
}
|
||||
mArcOverlayResources.erase(resourceIt);
|
||||
return true;
|
||||
}
|
||||
|
||||
void JKRArchive::removeAllOverlayResources() {
|
||||
mActiveArcOverlayResources.clear();
|
||||
for (const auto& key : mArcOverlayResources | std::views::keys) {
|
||||
free_overlay_buffer(key);
|
||||
}
|
||||
mArcOverlayResources.clear();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -246,6 +246,7 @@ u32 JKRArchive::readResource(void* buffer, u32 bufferSize, u16 id) {
|
||||
|
||||
void JKRArchive::removeResourceAll() {
|
||||
if (mArcInfoBlock && mMountMode != MOUNT_MEM) {
|
||||
IF_DUSK(removeAllOverlayResources();)
|
||||
SDIFileEntry* fileEntry = mFiles;
|
||||
for (int i = 0; i < mArcInfoBlock->num_file_entries; i++) {
|
||||
if (JKAR_DATA(fileEntry)) {
|
||||
@@ -259,6 +260,13 @@ void JKRArchive::removeResourceAll() {
|
||||
|
||||
bool JKRArchive::removeResource(void* resource) {
|
||||
JUT_ASSERT(678, resource != NULL);
|
||||
|
||||
#if TARGET_PC
|
||||
if (removeOverlayResource(resource, true)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDIFileEntry* fileEntry = findPtrResource(resource);
|
||||
if (fileEntry == NULL)
|
||||
return false;
|
||||
@@ -270,6 +278,13 @@ bool JKRArchive::removeResource(void* resource) {
|
||||
|
||||
bool JKRArchive::detachResource(void* resource) {
|
||||
JUT_ASSERT(707, resource != NULL);
|
||||
|
||||
#if TARGET_PC
|
||||
if (removeOverlayResource(resource, false)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDIFileEntry* fileEntry = findPtrResource(resource);
|
||||
if (fileEntry == NULL)
|
||||
return false;
|
||||
@@ -280,6 +295,13 @@ bool JKRArchive::detachResource(void* resource) {
|
||||
|
||||
u32 JKRArchive::getResSize(const void* resource) const {
|
||||
JUT_ASSERT(732, resource != NULL);
|
||||
|
||||
#if TARGET_PC
|
||||
if (u32 size; getOverlayResourceSize(resource, &size)) {
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDIFileEntry* fileEntry = findPtrResource(resource);
|
||||
if (fileEntry == NULL)
|
||||
return -1;
|
||||
|
||||
@@ -226,6 +226,13 @@ bool JKRCompArchive::open(s32 entryNum) {
|
||||
|
||||
void* JKRCompArchive::fetchResource(SDIFileEntry *fileEntry, u32 *pSize) {
|
||||
JUT_ASSERT(597, isMounted());
|
||||
|
||||
#if TARGET_PC
|
||||
if (void* data = getOverlayData(fileEntry, pSize); data != nullptr) {
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 ptrSize;
|
||||
u32 size = fileEntry->data_size;
|
||||
int compression = JKRConvertAttrToCompressionType(u8(fileEntry->type_flags_and_name_offset >> 0x18));
|
||||
@@ -274,6 +281,13 @@ void *JKRCompArchive::fetchResource(void *data, u32 compressedSize, SDIFileEntry
|
||||
{
|
||||
u32 size = 0;
|
||||
JUT_ASSERT(708, isMounted());
|
||||
|
||||
#if TARGET_PC
|
||||
if (copyOverlayData(data, compressedSize, fileEntry, pSize)) {
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 fileSize = fileEntry->data_size;
|
||||
u32 alignedSize = ALIGN_NEXT(fileSize, 32);
|
||||
u32 fileFlag = fileEntry->type_flags_and_name_offset >> 0x18;
|
||||
@@ -319,6 +333,7 @@ void *JKRCompArchive::fetchResource(void *data, u32 compressedSize, SDIFileEntry
|
||||
|
||||
void JKRCompArchive::removeResourceAll() {
|
||||
if (mArcInfoBlock != NULL && mMountMode != MOUNT_MEM) {
|
||||
IF_DUSK(removeAllOverlayResources();)
|
||||
SDIFileEntry* fileEntry = mFiles;
|
||||
for (int i = 0; i < mArcInfoBlock->num_file_entries; i++) {
|
||||
int tmp = fileEntry->type_flags_and_name_offset >> 0x18;
|
||||
@@ -336,6 +351,12 @@ void JKRCompArchive::removeResourceAll() {
|
||||
}
|
||||
|
||||
bool JKRCompArchive::removeResource(void* resource) {
|
||||
#if TARGET_PC
|
||||
if (removeOverlayResource(resource, true)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDIFileEntry* fileEntry = findPtrResource(resource);
|
||||
if (!fileEntry)
|
||||
return false;
|
||||
@@ -356,6 +377,12 @@ u32 JKRCompArchive::getExpandedResSize(const void *resource) const
|
||||
return getResSize(resource);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (u32 size; getOverlayResourceSize(resource, &size)) {
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDIFileEntry *fileEntry = findPtrResource(resource);
|
||||
if(!fileEntry) {
|
||||
return 0xffffffff;
|
||||
|
||||
@@ -147,6 +147,13 @@ cleanup:
|
||||
|
||||
void* JKRDvdArchive::fetchResource(SDIFileEntry* fileEntry, u32* returnSize) {
|
||||
JUT_ASSERT(428, isMounted());
|
||||
|
||||
#if TARGET_PC
|
||||
if (void* data = getOverlayData(fileEntry, returnSize); data != nullptr) {
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 tempReturnSize;
|
||||
if (returnSize == NULL) {
|
||||
returnSize = &tempReturnSize;
|
||||
@@ -181,6 +188,13 @@ void* JKRDvdArchive::fetchResource(SDIFileEntry* fileEntry, u32* returnSize) {
|
||||
void* JKRDvdArchive::fetchResource(void* buffer, u32 bufferSize, SDIFileEntry* fileEntry,
|
||||
u32* returnSize) {
|
||||
JUT_ASSERT(504, isMounted());
|
||||
|
||||
#if TARGET_PC
|
||||
if (copyOverlayData(buffer, bufferSize, fileEntry, returnSize)) {
|
||||
return buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 size = fileEntry->data_size;
|
||||
JKRCompression fileCompression = JKRConvertAttrToCompressionType(u8(fileEntry->type_flags_and_name_offset >> 24));
|
||||
|
||||
@@ -344,6 +358,12 @@ u32 JKRDvdArchive::getExpandedResSize(const void* resource) const {
|
||||
return getResSize(resource);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (u32 size; getOverlayResourceSize(resource, &size)) {
|
||||
return size;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDIFileEntry* fileEntry = findPtrResource(resource);
|
||||
if (!fileEntry) {
|
||||
return -1;
|
||||
|
||||
@@ -135,6 +135,13 @@ bool JKRMemArchive::open(void* buffer, u32 bufferSize, JKRMemBreakFlag flag) {
|
||||
|
||||
void* JKRMemArchive::fetchResource(SDIFileEntry* fileEntry, u32* resourceSize) {
|
||||
JUT_ASSERT(555, isMounted());
|
||||
|
||||
#if TARGET_PC
|
||||
if (void* data = getOverlayData(fileEntry, resourceSize); data != nullptr) {
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!JKAR_DATA(fileEntry)) {
|
||||
JKAR_DATA(fileEntry) = mArchiveData + fileEntry->data_offset;
|
||||
}
|
||||
@@ -149,6 +156,13 @@ void* JKRMemArchive::fetchResource(SDIFileEntry* fileEntry, u32* resourceSize) {
|
||||
void* JKRMemArchive::fetchResource(void* buffer, u32 bufferSize, SDIFileEntry* fileEntry,
|
||||
u32* resourceSize) {
|
||||
JUT_ASSERT(595, isMounted());
|
||||
|
||||
#if TARGET_PC
|
||||
if (copyOverlayData(buffer, bufferSize, fileEntry, resourceSize)) {
|
||||
return buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 srcLength = fileEntry->data_size;
|
||||
if (srcLength > bufferSize) {
|
||||
srcLength = bufferSize;
|
||||
@@ -173,6 +187,8 @@ void* JKRMemArchive::fetchResource(void* buffer, u32 bufferSize, SDIFileEntry* f
|
||||
void JKRMemArchive::removeResourceAll(void) {
|
||||
JUT_ASSERT(642, isMounted());
|
||||
|
||||
IF_DUSK(removeAllOverlayResources();)
|
||||
|
||||
if (mArcInfoBlock == NULL)
|
||||
return;
|
||||
if (mMountMode == MOUNT_MEM)
|
||||
@@ -192,6 +208,12 @@ void JKRMemArchive::removeResourceAll(void) {
|
||||
bool JKRMemArchive::removeResource(void* resource) {
|
||||
JUT_ASSERT(673, isMounted());
|
||||
|
||||
#if TARGET_PC
|
||||
if (removeOverlayResource(resource, true)) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDIFileEntry* fileEntry = findPtrResource(resource);
|
||||
if (!fileEntry)
|
||||
return false;
|
||||
@@ -231,6 +253,12 @@ u32 JKRMemArchive::fetchResource_subroutine(u8* src, u32 srcLength, u8* dst, u32
|
||||
}
|
||||
|
||||
u32 JKRMemArchive::getExpandedResSize(const void* resource) const {
|
||||
#if TARGET_PC
|
||||
if (u32 overlaySize; getOverlayResourceSize(resource, &overlaySize)) {
|
||||
return overlaySize;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDIFileEntry* fileEntry = findPtrResource(resource);
|
||||
if (fileEntry == NULL)
|
||||
return -1;
|
||||
|
||||
@@ -311,6 +311,11 @@ u32 dLib_getExpandSizeFromAramArchive(JKRAramArchive* i_aramArchive, char const*
|
||||
JUT_ASSERT(1260, readAddress == header);
|
||||
JKRArchive::SDIFileEntry* entry = i_aramArchive->findFsResource(param_2, 0);
|
||||
JUT_ASSERT(1263, entry != NULL);
|
||||
#if TARGET_PC
|
||||
if (u32 size; i_aramArchive->getOverlayFileSize(entry, &size)) {
|
||||
return ALIGN_NEXT(size, 32);
|
||||
}
|
||||
#endif
|
||||
u32 uVar1 = ALIGN_NEXT(JKRDecompExpandSize(header), 32);
|
||||
u32 uVar5 = ALIGN_NEXT(entry->data_size, 32);
|
||||
return uVar1 > uVar5 ? uVar1 : uVar5;
|
||||
|
||||
+2
-2
@@ -335,7 +335,7 @@ int dRes_info_c::loadResource() {
|
||||
#endif
|
||||
void* res = mArchive->getIdxResource(fileIndex);
|
||||
#if TARGET_PC
|
||||
u32 size = mArchive->findIdxResource(fileIndex)->data_size;
|
||||
u32 size = mArchive->getFileSize(mArchive->findIdxResource(fileIndex));
|
||||
std::string fileName = mArchive->mStringTable +
|
||||
(mArchive->findIdxResource(fileIndex)->type_flags_and_name_offset & 0xFFFFFF);
|
||||
DuskLog.debug("Loading Resource: {} (Size: {})", fileName, size);
|
||||
@@ -369,7 +369,7 @@ int dRes_info_c::loadResource() {
|
||||
parentHeap = NULL;
|
||||
}
|
||||
|
||||
int rt = dComIfG_setObjectRes(arcName, res, entry->data_size, parentHeap);
|
||||
int rt = dComIfG_setObjectRes(arcName, res, DUSK_IF_ELSE(mArchive->getFileSize(entry),entry->data_size), parentHeap);
|
||||
JUT_ASSERT(788, rt);
|
||||
} else if (nodeType == 'BMDP') {
|
||||
#if DEBUG
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "registry.hpp"
|
||||
#include "slot_map.hpp"
|
||||
|
||||
#include "aurora/dvd.h"
|
||||
#include <borealis/log.hpp>
|
||||
#include "JSystem/JKernel/JKRArchive.h"
|
||||
#include "aurora/dvd.h"
|
||||
#include "dusk/mods/loader/loader.hpp"
|
||||
#include "mods/svc/overlay.h"
|
||||
|
||||
@@ -24,7 +25,7 @@ constexpr borealis::Log Log{"dusk::mods::overlay"};
|
||||
struct OverlayFileData {
|
||||
std::string bundlePath;
|
||||
std::shared_ptr<ModBundle> bundle;
|
||||
std::shared_ptr<const std::vector<u8> > buffer;
|
||||
std::shared_ptr<const std::vector<u8>> buffer;
|
||||
};
|
||||
|
||||
// Keyed by the id passed to Aurora as per-file userdata. Guarded by s_overlayMutex: Aurora may
|
||||
@@ -98,6 +99,7 @@ void append_runtime_overlays(std::vector<AuroraOverlayFile>& files, LoadedMod& m
|
||||
|
||||
for (const auto* slot : slots) {
|
||||
const auto id = s_nextOverlayId++;
|
||||
|
||||
if (slot->buffer != nullptr) {
|
||||
s_overlayFiles.emplace(id, OverlayFileData{{}, nullptr, slot->buffer});
|
||||
} else {
|
||||
@@ -110,7 +112,7 @@ void append_runtime_overlays(std::vector<AuroraOverlayFile>& files, LoadedMod& m
|
||||
|
||||
struct OpenOverlayFile {
|
||||
std::vector<u8> ownedData;
|
||||
std::shared_ptr<const std::vector<u8> > shared;
|
||||
std::shared_ptr<const std::vector<u8>> shared;
|
||||
size_t pos = 0;
|
||||
|
||||
[[nodiscard]] const std::vector<u8>& data() const {
|
||||
@@ -200,6 +202,7 @@ void overlay_sync_files() {
|
||||
|
||||
Log.debug("Registering {} overlay file(s).", files.size());
|
||||
aurora_dvd_overlay_files(files.data(), files.size(), nullptr);
|
||||
JKRArchive::notifyOverlayFilesChanged();
|
||||
|
||||
for (const auto& file : files) {
|
||||
std::free(const_cast<char*>(file.fileName));
|
||||
@@ -220,13 +223,13 @@ uint64_t overlay_add_file(
|
||||
|
||||
uint64_t overlay_add_buffer(LoadedMod& mod, std::string discPath, std::vector<u8> data) {
|
||||
const auto size = data.size();
|
||||
const auto handle = s_runtimeOverlays.emplace(mod,
|
||||
RuntimeOverlaySlot{
|
||||
.discPath = std::move(discPath),
|
||||
.buffer = std::make_shared<const std::vector<u8>>(std::move(data)),
|
||||
.size = size,
|
||||
.order = s_nextRuntimeOrder++,
|
||||
});
|
||||
const auto handle = s_runtimeOverlays.emplace(
|
||||
mod, RuntimeOverlaySlot{
|
||||
.discPath = std::move(discPath),
|
||||
.buffer = std::make_shared<const std::vector<u8>>(std::move(data)),
|
||||
.size = size,
|
||||
.order = s_nextRuntimeOrder++,
|
||||
});
|
||||
s_overlaysDirty = true;
|
||||
return handle;
|
||||
}
|
||||
@@ -275,13 +278,12 @@ ModResult overlay_add_file(
|
||||
try {
|
||||
size = mod->bundle->getFileSize(bundlePath);
|
||||
} catch (const std::exception& e) {
|
||||
Log.error(
|
||||
"[{}] overlay add_file '{}' failed: {}", mod->metadata.id, bundlePath, e.what());
|
||||
Log.error("[{}] overlay add_file '{}' failed: {}", mod->metadata.id, bundlePath, e.what());
|
||||
return MOD_UNAVAILABLE;
|
||||
}
|
||||
if (size > kMaxOverlayFileSize) {
|
||||
Log.error("[{}] overlay add_file '{}' failed: file too large ({} bytes)",
|
||||
mod->metadata.id, bundlePath, size);
|
||||
Log.error("[{}] overlay add_file '{}' failed: file too large ({} bytes)", mod->metadata.id,
|
||||
bundlePath, size);
|
||||
return MOD_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user