@@ -88,7 +88,12 @@ void recomp::do_rom_pio(uint8_t* rdram, gpr ram_address, uint32_t physical_addr)
8888struct {
8989 std::vector<char > save_buffer;
9090 std::thread saving_thread;
91+ std::filesystem::path save_file_path;
9192 moodycamel::LightweightSemaphore write_sempahore;
93+ // Used to tell the saving thread that a file swap is pending.
94+ moodycamel::LightweightSemaphore swap_file_pending_sempahore;
95+ // Used to tell the consumer thread that the saving thread is ready for a file swap.
96+ moodycamel::LightweightSemaphore swap_file_ready_sempahore;
9297 std::mutex save_buffer_mutex;
9398} save_context;
9499
@@ -97,7 +102,15 @@ const std::u8string save_folder = u8"saves";
97102extern std::filesystem::path config_path;
98103
99104std::filesystem::path get_save_file_path () {
100- return config_path / save_folder / (std::u8string{recomp::current_game_id ()} + u8" .bin" );
105+ return save_context.save_file_path ;
106+ }
107+
108+ void set_save_file_path (const std::u8string& subfolder, const std::u8string& name) {
109+ std::filesystem::path save_folder_path = config_path / save_folder;
110+ if (!subfolder.empty ()) {
111+ save_folder_path = save_folder_path / subfolder;
112+ }
113+ save_context.save_file_path = save_folder_path / (name + u8" .bin" );
101114}
102115
103116void update_save_file () {
@@ -143,6 +156,10 @@ void saving_thread_func(RDRAM_ARG1) {
143156 if (save_buffer_updated) {
144157 update_save_file ();
145158 }
159+
160+ if (save_context.swap_file_pending_sempahore .tryWait ()) {
161+ save_context.swap_file_ready_sempahore .signal ();
162+ }
146163 }
147164}
148165
@@ -207,14 +224,12 @@ size_t get_save_size(recomp::SaveType save_type) {
207224 return 0 ;
208225}
209226
210- void ultramodern::init_saving (RDRAM_ARG1 ) {
227+ void read_save_file ( ) {
211228 std::filesystem::path save_file_path = get_save_file_path ();
212229
213230 // Ensure the save file directory exists.
214231 std::filesystem::create_directories (save_file_path.parent_path ());
215232
216- save_context.save_buffer .resize (get_save_size (recomp::get_save_type ()));
217-
218233 // Read the save file if it exists.
219234 std::ifstream save_file = recomp::open_input_file_with_backup (save_file_path, std::ios_base::binary);
220235 if (save_file.good ()) {
@@ -224,10 +239,28 @@ void ultramodern::init_saving(RDRAM_ARG1) {
224239 // Otherwise clear the save file to all zeroes.
225240 std::fill (save_context.save_buffer .begin (), save_context.save_buffer .end (), 0 );
226241 }
242+ }
243+
244+ void ultramodern::init_saving (RDRAM_ARG1) {
245+ set_save_file_path (u8" " , recomp::current_game_id ());
246+
247+ save_context.save_buffer .resize (get_save_size (recomp::get_save_type ()));
248+
249+ read_save_file ();
227250
228251 save_context.saving_thread = std::thread{saving_thread_func, PASS_RDRAM};
229252}
230253
254+ void ultramodern::change_save_file (const std::u8string& subfolder, const std::u8string& name) {
255+ // Tell the saving thread that a file swap is pending.
256+ save_context.swap_file_pending_sempahore .signal ();
257+ // Wait until the saving thread indicates it's ready to swap files.
258+ save_context.swap_file_ready_sempahore .wait ();
259+ // Perform the save file swap.
260+ set_save_file_path (subfolder, name);
261+ read_save_file ();
262+ }
263+
231264void ultramodern::join_saving_thread () {
232265 if (save_context.saving_thread .joinable ()) {
233266 save_context.saving_thread .join ();
0 commit comments