mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2025-10-30 08:02:29 +00:00
Implement API to allow mods to read their config values
This commit is contained in:
parent
b59a568632
commit
499c69c7d9
5 changed files with 101 additions and 0 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
60
librecomp/src/mod_config_api.cpp
Normal file
60
librecomp/src/mod_config_api.cpp
Normal 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);
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue