mirror of
https://github.com/N64Recomp/N64ModernRuntime.git
synced 2025-10-30 08:02:29 +00:00
Added a mechanism to swap save files at runtime and a corresponding mod API export (#101)
Some checks are pending
validate / ubuntu (x64, Release) (push) Waiting to run
validate / ubuntu (arm64, Debug) (push) Waiting to run
validate / ubuntu (arm64, Release) (push) Waiting to run
validate / ubuntu (x64, Debug) (push) Waiting to run
validate / windows (x64, Debug) (push) Waiting to run
validate / windows (x64, Release) (push) Waiting to run
validate / macos (arm64, Debug) (push) Waiting to run
validate / macos (arm64, Release) (push) Waiting to run
validate / macos (x64, Debug) (push) Waiting to run
validate / macos (x64, Release) (push) Waiting to run
Some checks are pending
validate / ubuntu (x64, Release) (push) Waiting to run
validate / ubuntu (arm64, Debug) (push) Waiting to run
validate / ubuntu (arm64, Release) (push) Waiting to run
validate / ubuntu (x64, Debug) (push) Waiting to run
validate / windows (x64, Debug) (push) Waiting to run
validate / windows (x64, Release) (push) Waiting to run
validate / macos (arm64, Debug) (push) Waiting to run
validate / macos (arm64, Release) (push) Waiting to run
validate / macos (x64, Debug) (push) Waiting to run
validate / macos (x64, Release) (push) Waiting to run
This commit is contained in:
parent
cacb14fee5
commit
1f2a5838ab
5 changed files with 59 additions and 4 deletions
|
|
@ -109,6 +109,7 @@ namespace recomp {
|
|||
|
||||
void start_game(const std::u8string& game_id);
|
||||
std::u8string current_game_id();
|
||||
std::string current_mod_game_id();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -63,6 +63,16 @@ void recomp_get_mod_version(uint8_t* rdram, recomp_context* ctx, size_t mod_inde
|
|||
*patch_out = version.patch;
|
||||
}
|
||||
|
||||
void recomp_change_save_file(uint8_t* rdram, recomp_context* ctx, size_t mod_index) {
|
||||
std::string name = _arg_string<0>(rdram, ctx);
|
||||
std::u8string name_u8 = std::u8string{reinterpret_cast<const char8_t*>(name.data()), name.size()};
|
||||
|
||||
std::string mod_id = recomp::mods::get_mod_id(mod_index);
|
||||
std::u8string mod_id_u8 = std::u8string{reinterpret_cast<const char8_t*>(mod_id.data()), mod_id.size()};
|
||||
|
||||
ultramodern::change_save_file(mod_id_u8, name_u8);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -75,5 +85,6 @@ void recomp::mods::register_config_exports() {
|
|||
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_ext_base_export("recomp_get_mod_version", recomp_get_mod_version);
|
||||
recomp::overlays::register_ext_base_export("recomp_change_save_file", recomp_change_save_file);
|
||||
recomp::overlays::register_base_export("recomp_free_config_string", recomp_free_config_string);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,12 @@ void recomp::do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr)
|
|||
struct {
|
||||
std::vector<char> save_buffer;
|
||||
std::thread saving_thread;
|
||||
std::filesystem::path save_file_path;
|
||||
moodycamel::LightweightSemaphore write_sempahore;
|
||||
// Used to tell the saving thread that a file swap is pending.
|
||||
moodycamel::LightweightSemaphore swap_file_pending_sempahore;
|
||||
// Used to tell the consumer thread that the saving thread is ready for a file swap.
|
||||
moodycamel::LightweightSemaphore swap_file_ready_sempahore;
|
||||
std::mutex save_buffer_mutex;
|
||||
} save_context;
|
||||
|
||||
|
|
@ -97,7 +102,15 @@ const std::u8string save_folder = u8"saves";
|
|||
extern std::filesystem::path config_path;
|
||||
|
||||
std::filesystem::path get_save_file_path() {
|
||||
return config_path / save_folder / (std::u8string{recomp::current_game_id()} + u8".bin");
|
||||
return save_context.save_file_path;
|
||||
}
|
||||
|
||||
void set_save_file_path(const std::u8string& subfolder, const std::u8string& name) {
|
||||
std::filesystem::path save_folder_path = config_path / save_folder;
|
||||
if (!subfolder.empty()) {
|
||||
save_folder_path = save_folder_path / subfolder;
|
||||
}
|
||||
save_context.save_file_path = save_folder_path / (name + u8".bin");
|
||||
}
|
||||
|
||||
void update_save_file() {
|
||||
|
|
@ -143,6 +156,10 @@ void saving_thread_func(RDRAM_ARG1) {
|
|||
if (save_buffer_updated) {
|
||||
update_save_file();
|
||||
}
|
||||
|
||||
if (save_context.swap_file_pending_sempahore.tryWait()) {
|
||||
save_context.swap_file_ready_sempahore.signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -207,14 +224,12 @@ size_t get_save_size(recomp::SaveType save_type) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void ultramodern::init_saving(RDRAM_ARG1) {
|
||||
void read_save_file() {
|
||||
std::filesystem::path save_file_path = get_save_file_path();
|
||||
|
||||
// Ensure the save file directory exists.
|
||||
std::filesystem::create_directories(save_file_path.parent_path());
|
||||
|
||||
save_context.save_buffer.resize(get_save_size(recomp::get_save_type()));
|
||||
|
||||
// Read the save file if it exists.
|
||||
std::ifstream save_file = recomp::open_input_file_with_backup(save_file_path, std::ios_base::binary);
|
||||
if (save_file.good()) {
|
||||
|
|
@ -224,10 +239,28 @@ void ultramodern::init_saving(RDRAM_ARG1) {
|
|||
// Otherwise clear the save file to all zeroes.
|
||||
std::fill(save_context.save_buffer.begin(), save_context.save_buffer.end(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ultramodern::init_saving(RDRAM_ARG1) {
|
||||
set_save_file_path(u8"", recomp::current_game_id());
|
||||
|
||||
save_context.save_buffer.resize(get_save_size(recomp::get_save_type()));
|
||||
|
||||
read_save_file();
|
||||
|
||||
save_context.saving_thread = std::thread{saving_thread_func, PASS_RDRAM};
|
||||
}
|
||||
|
||||
void ultramodern::change_save_file(const std::u8string& subfolder, const std::u8string& name) {
|
||||
// Tell the saving thread that a file swap is pending.
|
||||
save_context.swap_file_pending_sempahore.signal();
|
||||
// Wait until the saving thread indicates it's ready to swap files.
|
||||
save_context.swap_file_ready_sempahore.wait();
|
||||
// Perform the save file swap.
|
||||
set_save_file_path(subfolder, name);
|
||||
read_save_file();
|
||||
}
|
||||
|
||||
void ultramodern::join_saving_thread() {
|
||||
if (save_context.saving_thread.joinable()) {
|
||||
save_context.saving_thread.join();
|
||||
|
|
|
|||
|
|
@ -490,6 +490,13 @@ std::u8string recomp::current_game_id() {
|
|||
return current_game.value();
|
||||
};
|
||||
|
||||
std::string recomp::current_mod_game_id() {
|
||||
auto find_it = game_roms.find(current_game_id());
|
||||
const recomp::GameEntry& game_entry = find_it->second;
|
||||
|
||||
return game_entry.mod_game_id;
|
||||
}
|
||||
|
||||
void recomp::start_game(const std::u8string& game_id) {
|
||||
std::lock_guard<std::mutex> lock(current_game_mutex);
|
||||
current_game = game_id;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ void init_events(RDRAM_ARG renderer::WindowHandle window_handle);
|
|||
void init_timers(RDRAM_ARG1);
|
||||
void init_thread_cleanup();
|
||||
|
||||
// Saving
|
||||
void change_save_file(const std::u8string& subfolder, const std::u8string& name);
|
||||
|
||||
// Thread queues.
|
||||
constexpr PTR(PTR(OSThread)) running_queue = (PTR(PTR(OSThread)))-1;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue