Implement API to allow mods to read their config values

This commit is contained in:
Mr-Wiseguy 2025-01-31 01:59:13 -05:00
parent b59a568632
commit 499c69c7d9
5 changed files with 101 additions and 0 deletions

View file

@ -20,6 +20,7 @@ add_library(librecomp STATIC
"${CMAKE_CURRENT_SOURCE_DIR}/src/mod_events.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/mod_hooks.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/mod_manifest.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/mod_config_api.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/overlays.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/pak.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/pi.cpp"

View file

@ -1,6 +1,8 @@
#ifndef __RECOMP_HELPERS__
#define __RECOMP_HELPERS__
#include <string>
#include "recomp.h"
#include <ultramodern/ultra64.h>
@ -51,6 +53,26 @@ inline float _arg_float_f14(uint8_t* rdram, recomp_context* ctx) {
return ctx->f14.fl;
}
template <int arg_index>
std::string _arg_string(uint8_t* rdram, recomp_context* ctx) {
PTR(char) str = _arg<arg_index, PTR(char)>(rdram, ctx);
// Get the length of the byteswapped string.
size_t len = 0;
while (MEM_B(str, len) != 0x00) {
len++;
}
std::string ret{};
ret.reserve(len + 1);
for (size_t i = 0; i < len; i++) {
ret += (char)MEM_B(str, i);
}
return ret;
}
template <typename T>
void _return(recomp_context* ctx, T val) {
static_assert(sizeof(T) <= 4 && "Only 32-bit value returns supported currently");

View file

@ -335,7 +335,9 @@ namespace recomp {
void set_mod_index(const std::string &mod_game_id, const std::string &mod_id, size_t index);
const ConfigSchema &get_mod_config_schema(const std::string &mod_id) const;
const std::vector<char> &get_mod_thumbnail(const std::string &mod_id) const;
void set_mod_config_value(size_t mod_index, const std::string &option_id, const ConfigValueVariant &value);
void set_mod_config_value(const std::string &mod_id, const std::string &option_id, const ConfigValueVariant &value);
ConfigValueVariant get_mod_config_value(size_t mod_index, const std::string &option_id);
ConfigValueVariant get_mod_config_value(const std::string &mod_id, const std::string &option_id);
void set_mods_config_path(const std::filesystem::path &path);
void set_mod_config_directory(const std::filesystem::path &path);
@ -561,10 +563,15 @@ namespace recomp {
bool is_mod_auto_enabled(const std::string& mod_id);
const ConfigSchema &get_mod_config_schema(const std::string &mod_id);
const std::vector<char> &get_mod_thumbnail(const std::string &mod_id);
void set_mod_config_value(size_t mod_index, const std::string &option_id, const ConfigValueVariant &value);
void set_mod_config_value(const std::string &mod_id, const std::string &option_id, const ConfigValueVariant &value);
ConfigValueVariant get_mod_config_value(size_t mod_index, const std::string &option_id);
ConfigValueVariant get_mod_config_value(const std::string &mod_id, const std::string &option_id);
ModContentTypeId register_mod_content_type(const ModContentType& type);
bool register_mod_container_type(const std::string& extension, const std::vector<ModContentTypeId>& content_types, bool requires_manifest);
void register_config_exports();
}
};

View file

@ -0,0 +1,60 @@
#include "librecomp/mods.hpp"
#include "librecomp/helpers.hpp"
#include "librecomp/addresses.hpp"
void recomp_get_config_u32(uint8_t* rdram, recomp_context* ctx, size_t mod_index) {
recomp::mods::ConfigValueVariant val = recomp::mods::get_mod_config_value(mod_index, _arg_string<0>(rdram, ctx));
if (uint32_t* as_u32 = std::get_if<uint32_t>(&val)) {
_return(ctx, *as_u32);
}
else {
_return(ctx, uint32_t{0});
}
}
void recomp_get_config_double(uint8_t* rdram, recomp_context* ctx, size_t mod_index) {
recomp::mods::ConfigValueVariant val = recomp::mods::get_mod_config_value(mod_index, _arg_string<0>(rdram, ctx));
if (double* as_double = std::get_if<double>(&val)) {
ctx->f0.d = *as_double;
}
else {
ctx->f0.d = 0.0;
}
}
void recomp_get_config_string(uint8_t* rdram, recomp_context* ctx, size_t mod_index) {
recomp::mods::ConfigValueVariant val = recomp::mods::get_mod_config_value(mod_index, _arg_string<0>(rdram, ctx));
if (std::string* as_string = std::get_if<std::string>(&val)) {
const std::string& str = *as_string;
// Allocate space in the recomp heap to hold the string, including the null terminator.
size_t alloc_size = (str.size() + 1 + 15) & ~15;
gpr offset = reinterpret_cast<uint8_t*>(recomp::alloc(rdram, alloc_size)) - rdram;
gpr addr = offset + 0xFFFFFFFF80000000ULL;
// Copy the string's data into the allocated memory and null terminate it.
for (size_t i = 0; i < str.size(); i++) {
MEM_B(i, addr) = str[i];
}
MEM_B(str.size(), addr) = 0;
// Return the allocated memory.
ctx->r2 = addr;
}
else {
_return(ctx, NULLPTR);
}
}
void recomp_free_config_string(uint8_t* rdram, recomp_context* ctx) {
gpr str_rdram = (gpr)_arg<0, PTR(char)>(rdram, ctx);
gpr offset = str_rdram - 0xFFFFFFFF80000000ULL;
recomp::free(rdram, rdram + offset);
}
void recomp::mods::register_config_exports() {
recomp::overlays::register_ext_base_export("recomp_get_config_u32", recomp_get_config_u32);
recomp::overlays::register_ext_base_export("recomp_get_config_double", recomp_get_config_double);
recomp::overlays::register_ext_base_export("recomp_get_config_string", recomp_get_config_string);
recomp::overlays::register_base_export("recomp_free_config_string", recomp_free_config_string);
}

View file

@ -530,11 +530,21 @@ const std::vector<char> &recomp::mods::get_mod_thumbnail(const std::string &mod_
return mod_context->get_mod_thumbnail(mod_id);
}
void recomp::mods::set_mod_config_value(size_t mod_index, const std::string &option_id, const ConfigValueVariant &value) {
std::lock_guard lock{ mod_context_mutex };
return mod_context->set_mod_config_value(mod_index, option_id, value);
}
void recomp::mods::set_mod_config_value(const std::string &mod_id, const std::string &option_id, const ConfigValueVariant &value) {
std::lock_guard lock{ mod_context_mutex };
return mod_context->set_mod_config_value(mod_id, option_id, value);
}
recomp::mods::ConfigValueVariant recomp::mods::get_mod_config_value(size_t mod_index, const std::string &option_id) {
std::lock_guard lock{ mod_context_mutex };
return mod_context->get_mod_config_value(mod_index, option_id);
}
recomp::mods::ConfigValueVariant recomp::mods::get_mod_config_value(const std::string &mod_id, const std::string &option_id) {
std::lock_guard lock{ mod_context_mutex };
return mod_context->get_mod_config_value(mod_id, option_id);
@ -711,6 +721,7 @@ void recomp::start(
}
recomp::register_heap_exports();
recomp::mods::register_config_exports();
std::thread game_thread{[](ultramodern::renderer::WindowHandle window_handle, uint8_t* rdram) {
debug_printf("[Recomp] Starting\n");