mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2026-05-11 03:12:15 +00:00
Implemented per-game mod contexts
This commit is contained in:
parent
621ee53bd3
commit
f34909ef42
3 changed files with 70 additions and 39 deletions
|
|
@ -13,8 +13,10 @@ namespace recomp {
|
||||||
uint64_t rom_hash;
|
uint64_t rom_hash;
|
||||||
std::string internal_name;
|
std::string internal_name;
|
||||||
std::u8string game_id;
|
std::u8string game_id;
|
||||||
|
std::u8string mod_subdirectory;
|
||||||
std::span<const char> cache_data;
|
std::span<const char> cache_data;
|
||||||
bool is_enabled;
|
bool is_enabled;
|
||||||
|
bool mods;
|
||||||
|
|
||||||
gpr entrypoint_address;
|
gpr entrypoint_address;
|
||||||
void (*entrypoint)(uint8_t* rdram, recomp_context* context);
|
void (*entrypoint)(uint8_t* rdram, recomp_context* context);
|
||||||
|
|
|
||||||
|
|
@ -99,10 +99,10 @@ namespace recomp {
|
||||||
std::string error_param;
|
std::string error_param;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<ModOpenErrorDetails> scan_mod_folder(const std::filesystem::path& mod_folder);
|
std::vector<ModOpenErrorDetails> scan_mod_folder(const std::u8string& game_id, const std::filesystem::path& mod_folder);
|
||||||
void enable_mod(const std::string& mod_id, bool enabled);
|
void enable_mod(const std::u8string& game_id, const std::string& mod_id, bool enabled);
|
||||||
bool is_mod_enabled(const std::string& mod_id);
|
bool is_mod_enabled(const std::u8string& game_id, const std::string& mod_id);
|
||||||
size_t num_opened_mods();
|
size_t num_opened_mods(const std::u8string& game_id);
|
||||||
|
|
||||||
// Internal functions, TODO move to an internal header.
|
// Internal functions, TODO move to an internal header.
|
||||||
struct ModHandle;
|
struct ModHandle;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <cuchar>
|
||||||
|
|
||||||
#include "librecomp/recomp.h"
|
#include "librecomp/recomp.h"
|
||||||
#include "librecomp/overlays.hpp"
|
#include "librecomp/overlays.hpp"
|
||||||
|
|
@ -46,10 +47,12 @@ enum GameStatus {
|
||||||
// Mutexes
|
// Mutexes
|
||||||
std::mutex game_roms_mutex;
|
std::mutex game_roms_mutex;
|
||||||
std::mutex current_game_mutex;
|
std::mutex current_game_mutex;
|
||||||
|
std::mutex mod_context_mutex{};
|
||||||
|
|
||||||
// Global variables
|
// Global variables
|
||||||
std::filesystem::path config_path;
|
std::filesystem::path config_path;
|
||||||
std::unordered_map<std::u8string, recomp::GameEntry> game_roms {};
|
std::unordered_map<std::u8string, recomp::GameEntry> game_roms {};
|
||||||
|
std::unordered_map<std::u8string, recomp::mods::ModContext> mod_contexts {};
|
||||||
|
|
||||||
std::u8string recomp::GameEntry::stored_filename() const {
|
std::u8string recomp::GameEntry::stored_filename() const {
|
||||||
return game_id + u8".z64";
|
return game_id + u8".z64";
|
||||||
|
|
@ -60,8 +63,25 @@ void recomp::register_config_path(std::filesystem::path path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool recomp::register_game(const recomp::GameEntry& entry) {
|
bool recomp::register_game(const recomp::GameEntry& entry) {
|
||||||
std::lock_guard<std::mutex> lock(game_roms_mutex);
|
// TODO verify that there's no game with this ID already.
|
||||||
game_roms.insert({ entry.game_id, entry });
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(game_roms_mutex);
|
||||||
|
game_roms.insert({ entry.game_id, entry });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan for mods in the main mod folder if enabled.
|
||||||
|
if (entry.mods) {
|
||||||
|
std::vector<recomp::mods::ModOpenErrorDetails> mod_open_errors;
|
||||||
|
{
|
||||||
|
std::lock_guard mod_lock{ mod_context_mutex };
|
||||||
|
recomp::mods::ModContext& mod_context = mod_contexts[entry.game_id];
|
||||||
|
mod_open_errors = mod_context.scan_mod_folder(config_path / "mods" / entry.mod_subdirectory);
|
||||||
|
}
|
||||||
|
for (const auto& cur_error : mod_open_errors) {
|
||||||
|
printf("Error loading mod " PATHFMT ": %s (%s)\n", cur_error.mod_path.c_str(), recomp::mods::error_to_string(cur_error.error).c_str(), cur_error.error_param.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -382,27 +402,40 @@ void ultramodern::quit() {
|
||||||
current_game.reset();
|
current_game.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
recomp::mods::ModContext mod_context{};
|
std::vector<recomp::mods::ModOpenErrorDetails> recomp::mods::scan_mod_folder(const std::u8string& game_id, const std::filesystem::path& mod_folder) {
|
||||||
std::mutex mod_context_mutex{};
|
|
||||||
|
|
||||||
std::vector<recomp::mods::ModOpenErrorDetails> recomp::mods::scan_mod_folder(const std::filesystem::path& mod_folder) {
|
|
||||||
std::lock_guard lock { mod_context_mutex };
|
std::lock_guard lock { mod_context_mutex };
|
||||||
return mod_context.scan_mod_folder(mod_folder);
|
auto find_it = mod_contexts.find(game_id);
|
||||||
|
if (find_it == mod_contexts.end()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return find_it->second.scan_mod_folder(mod_folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void recomp::mods::enable_mod(const std::string& mod_id, bool enabled) {
|
void recomp::mods::enable_mod(const std::u8string& game_id, const std::string& mod_id, bool enabled) {
|
||||||
std::lock_guard lock { mod_context_mutex };
|
std::lock_guard lock { mod_context_mutex };
|
||||||
return mod_context.enable_mod(mod_id, enabled);
|
auto find_it = mod_contexts.find(game_id);
|
||||||
|
if (find_it == mod_contexts.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return find_it->second.enable_mod(mod_id, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool recomp::mods::is_mod_enabled(const std::string& mod_id) {
|
bool recomp::mods::is_mod_enabled(const std::u8string& game_id, const std::string& mod_id) {
|
||||||
std::lock_guard lock { mod_context_mutex };
|
std::lock_guard lock { mod_context_mutex };
|
||||||
return mod_context.is_mod_enabled(mod_id);
|
auto find_it = mod_contexts.find(game_id);
|
||||||
|
if (find_it == mod_contexts.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return find_it->second.is_mod_enabled(mod_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t recomp::mods::num_opened_mods() {
|
size_t recomp::mods::num_opened_mods(const std::u8string& game_id) {
|
||||||
std::lock_guard lock { mod_context_mutex };
|
std::lock_guard lock { mod_context_mutex };
|
||||||
return mod_context.num_opened_mods();
|
auto find_it = mod_contexts.find(game_id);
|
||||||
|
if (find_it == mod_contexts.end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return find_it->second.num_opened_mods();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wait_for_game_started(uint8_t* rdram, recomp_context* context) {
|
bool wait_for_game_started(uint8_t* rdram, recomp_context* context) {
|
||||||
|
|
@ -423,19 +456,25 @@ bool wait_for_game_started(uint8_t* rdram, recomp_context* context) {
|
||||||
|
|
||||||
init(rdram, context, game_entry.entrypoint_address);
|
init(rdram, context, game_entry.entrypoint_address);
|
||||||
|
|
||||||
uint32_t mod_ram_used = 0;
|
if (game_entry.mods) {
|
||||||
std::vector<recomp::mods::ModLoadErrorDetails> mod_load_errors;
|
uint32_t mod_ram_used = 0;
|
||||||
{
|
std::vector<recomp::mods::ModLoadErrorDetails> mod_load_errors;
|
||||||
std::lock_guard lock { mod_context_mutex };
|
{
|
||||||
mod_load_errors = mod_context.load_mods(rdram, recomp::mod_rdram_start, mod_ram_used);
|
std::lock_guard lock { mod_context_mutex };
|
||||||
}
|
auto find_it = mod_contexts.find(current_game.value());
|
||||||
|
if (find_it == mod_contexts.end()) {
|
||||||
if (!mod_load_errors.empty()) {
|
return false;
|
||||||
for (const auto& cur_error : mod_load_errors) {
|
}
|
||||||
printf("Mod %s failed to load with error %d (%s)\n", cur_error.mod_id.c_str(), (int)cur_error.error, cur_error.error_param.c_str());
|
mod_load_errors = find_it->second.load_mods(rdram, recomp::mod_rdram_start, mod_ram_used);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mod_load_errors.empty()) {
|
||||||
|
for (const auto& cur_error : mod_load_errors) {
|
||||||
|
printf("Mod %s failed to load with error %d (%s)\n", cur_error.mod_id.c_str(), (int)cur_error.error, cur_error.error_param.c_str());
|
||||||
|
}
|
||||||
|
game_status.store(GameStatus::None);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
game_status.store(GameStatus::None);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ultramodern::load_shader_cache(game_entry.cache_data);
|
ultramodern::load_shader_cache(game_entry.cache_data);
|
||||||
|
|
@ -496,16 +535,6 @@ void recomp::start(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan for mods in the main mod folder.
|
|
||||||
std::vector<recomp::mods::ModOpenErrorDetails> mod_open_errors;
|
|
||||||
{
|
|
||||||
std::lock_guard mod_lock{ mod_context_mutex };
|
|
||||||
mod_open_errors = mod_context.scan_mod_folder(config_path / "mods");
|
|
||||||
}
|
|
||||||
for (const auto& cur_error : mod_open_errors) {
|
|
||||||
printf("Error loading mod " PATHFMT ": %s (%s)\n", cur_error.mod_path.c_str(), recomp::mods::error_to_string(cur_error.error).c_str(), cur_error.error_param.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate rdram_buffer
|
// Allocate rdram_buffer
|
||||||
std::unique_ptr<uint8_t[]> rdram_buffer = std::make_unique<uint8_t[]>(rdram_size);
|
std::unique_ptr<uint8_t[]> rdram_buffer = std::make_unique<uint8_t[]>(rdram_size);
|
||||||
std::memset(rdram_buffer.get(), 0, rdram_size);
|
std::memset(rdram_buffer.get(), 0, rdram_size);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue