Hex editor
[lsnes.git] / src / core / mainloop.cpp
blobd91ea2b0e9bf81c1a88c4444aa822d418d9a48c5
1 #include "lsnes.hpp"
3 #include "core/command.hpp"
4 #include "core/controller.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/framebuffer.hpp"
7 #include "core/framerate.hpp"
8 #include "core/inthread.hpp"
9 #include "lua/lua.hpp"
10 #include "library/string.hpp"
11 #include "core/mainloop.hpp"
12 #include "core/movie.hpp"
13 #include "core/moviedata.hpp"
14 #include "core/moviefile.hpp"
15 #include "core/memorymanip.hpp"
16 #include "core/memorywatch.hpp"
17 #include "core/project.hpp"
18 #include "core/rom.hpp"
19 #include "core/romloader.hpp"
20 #include "core/rrdata.hpp"
21 #include "core/settings.hpp"
22 #include "core/window.hpp"
23 #include "interface/callbacks.hpp"
24 #include "interface/romtype.hpp"
25 #include "library/framebuffer.hpp"
26 #include "library/pixfmt-lrgb.hpp"
27 #include "library/zip.hpp"
29 #include <iomanip>
30 #include <cassert>
31 #include <sstream>
32 #include <iostream>
33 #include <limits>
34 #include <set>
35 #include <sys/time.h>
37 #define SPECIAL_FRAME_START 0
38 #define SPECIAL_FRAME_VIDEO 1
39 #define SPECIAL_SAVEPOINT 2
40 #define SPECIAL_NONE 3
42 void update_movie_state();
43 time_t random_seed_value = 0;
45 setting_var<setting_var_model_bool<setting_yes_no>> jukebox_dflt_binary(lsnes_vset, "jukebox-default-binary",
46 "Movie‣Saving‣Saveslots binary", true);
47 setting_var<setting_var_model_bool<setting_yes_no>> movie_dflt_binary(lsnes_vset, "movie-default-binary",
48 "Movie‣Saving‣Movies binary", false);
49 setting_var<setting_var_model_bool<setting_yes_no>> save_dflt_binary(lsnes_vset, "savestate-default-binary",
50 "Movie‣Saving‣Savestates binary", false);
52 namespace
54 setting_var<setting_var_model_int<0,999999>> advance_timeout_first(lsnes_vset, "advance-timeout",
55 "Delays‣First frame advance", 500);
56 setting_var<setting_var_model_int<0,999999>> advance_timeout_subframe(lsnes_vset, "advance-subframe-timeout",
57 "Delays‣Subframe advance", 100);
58 setting_var<setting_var_model_bool<setting_yes_no>> pause_on_end(lsnes_vset, "pause-on-end",
59 "Movie‣Pause on end", false);
60 setting_var<setting_var_model_int<0,999999999>> jukebox_size(lsnes_vset, "jukebox-size",
61 "Movie‣Number of save slots", 12);
63 enum advance_mode
65 ADVANCE_QUIT, //Quit the emulator.
66 ADVANCE_AUTO, //Normal (possibly slowed down play).
67 ADVANCE_LOAD, //Loading a state.
68 ADVANCE_FRAME, //Frame advance.
69 ADVANCE_SUBFRAME, //Subframe advance.
70 ADVANCE_SKIPLAG, //Skip lag (oneshot, reverts to normal).
71 ADVANCE_SKIPLAG_PENDING, //Activate skip lag mode at next frame.
72 ADVANCE_PAUSE, //Unconditional pause.
75 //Our thread.
76 threadid_class emulation_thread;
77 //Flags related to repeating advance.
78 bool advanced_once;
79 bool cancel_advance;
80 //Emulator advance mode. Detemines pauses at start of frame / subframe, etc..
81 enum advance_mode amode;
82 //Mode and filename of pending load, one of LOAD_* constants.
83 bool load_paused;
84 int loadmode;
85 std::string pending_load;
86 std::string pending_new_project;
87 //Queued saves (all savestates).
88 std::set<std::pair<std::string, int>> queued_saves;
89 //Save jukebox.
90 size_t save_jukebox_pointer;
91 //Special subframe location. One of SPECIAL_* constants.
92 int location_special;
93 //Last frame params.
94 bool last_hires = false;
95 bool last_interlace = false;
96 //Unsafe rewind.
97 bool do_unsafe_rewind = false;
98 void* unsafe_rewind_obj = NULL;
99 //Stop at frame.
100 bool stop_at_frame_active = false;
101 uint64_t stop_at_frame = 0;
102 //Macro hold.
103 bool macro_hold_1;
104 bool macro_hold_2;
106 enum advance_mode old_mode;
108 std::string save_jukebox_name(size_t i)
110 return (stringfmt() << "${project}" << (i + 1) << ".lsmv").str();
113 std::map<std::string, std::string> slotinfo_cache;
115 std::string vector_to_string(const std::vector<char>& x)
117 std::string y(x.begin(), x.end());
118 while(y.length() > 0 && y[y.length() - 1] < 32)
119 y = y.substr(0, y.length() - 1);
120 return y;
123 std::string get_slotinfo(const std::string& _filename)
125 std::string filename = resolve_relative_path(_filename);
126 if(!slotinfo_cache.count(filename)) {
127 std::ostringstream out;
128 try {
129 moviefile::brief_info info(filename);
130 if(our_movie.projectid == info.projectid)
131 out << info.rerecords << "R/" << info.current_frame << "F";
132 else
133 out << "Wrong movie";
134 } catch(...) {
135 out << "Nonexistent";
137 slotinfo_cache[filename] = out.str();
139 return slotinfo_cache[filename];
142 void flush_slotinfo(const std::string& filename)
144 slotinfo_cache.erase(resolve_relative_path(filename));
147 void flush_slotinfo()
149 slotinfo_cache.clear();
152 class _lsnes_pflag_handler : public movie::poll_flag
154 public:
155 ~_lsnes_pflag_handler()
158 int get_pflag()
160 return our_rom.rtype->get_pflag();
162 void set_pflag(int flag)
164 our_rom.rtype->set_pflag(flag);
166 } lsnes_pflag_handler;
169 void mainloop_signal_need_rewind(void* ptr)
171 if(ptr) {
172 old_mode = amode;
173 amode = ADVANCE_LOAD;
175 do_unsafe_rewind = true;
176 unsafe_rewind_obj = ptr;
179 controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_alloc, std::runtime_error)
181 if(lua_requests_subframe_paint)
182 redraw_framebuffer();
184 if(subframe) {
185 if(amode == ADVANCE_SUBFRAME) {
186 if(!cancel_advance) {
187 if(!advanced_once)
188 platform::wait(advance_timeout_first * 1000);
189 else
190 platform::wait(advance_timeout_subframe * 1000);
191 advanced_once = true;
193 if(cancel_advance) {
194 stop_at_frame_active = false;
195 amode = ADVANCE_PAUSE;
196 cancel_advance = false;
198 platform::set_paused(amode == ADVANCE_PAUSE);
199 } else if(amode == ADVANCE_FRAME) {
201 } else {
202 if(amode == ADVANCE_SKIPLAG) {
203 stop_at_frame_active = false;
204 amode = ADVANCE_PAUSE;
206 platform::set_paused(amode == ADVANCE_PAUSE);
207 cancel_advance = false;
209 location_special = SPECIAL_NONE;
210 update_movie_state();
211 } else {
212 if(amode == ADVANCE_SKIPLAG_PENDING)
213 amode = ADVANCE_SKIPLAG;
214 if(amode == ADVANCE_FRAME || amode == ADVANCE_SUBFRAME) {
215 if(!cancel_advance) {
216 uint64_t wait = 0;
217 if(!advanced_once)
218 wait = advance_timeout_first * 1000;
219 else if(amode == ADVANCE_SUBFRAME)
220 wait = advance_timeout_subframe * 1000;
221 else
222 wait = to_wait_frame(get_utime());
223 platform::wait(wait);
224 advanced_once = true;
226 if(cancel_advance) {
227 stop_at_frame_active = false;
228 amode = ADVANCE_PAUSE;
229 cancel_advance = false;
231 platform::set_paused(amode == ADVANCE_PAUSE);
232 } else if(amode == ADVANCE_AUTO && movb.get_movie().readonly_mode() && pause_on_end &&
233 !stop_at_frame_active) {
234 if(movb.get_movie().get_current_frame() == movb.get_movie().get_frame_count()) {
235 stop_at_frame_active = false;
236 amode = ADVANCE_PAUSE;
237 platform::set_paused(true);
239 } else if(amode == ADVANCE_AUTO && stop_at_frame_active) {
240 if(movb.get_movie().get_current_frame() >= stop_at_frame) {
241 stop_at_frame_active = false;
242 amode = ADVANCE_PAUSE;
243 platform::set_paused(true);
245 } else {
246 platform::set_paused((amode == ADVANCE_PAUSE));
247 cancel_advance = false;
249 location_special = SPECIAL_FRAME_START;
250 update_movie_state();
252 platform::flush_command_queue();
253 controller_frame tmp = controls.get(movb.get_movie().get_current_frame());
254 our_rom.rtype->pre_emulate_frame(tmp); //Preset controls, the lua will override if needed.
255 lua_callback_do_input(tmp, subframe);
256 controls.commit(tmp);
257 return tmp;
260 namespace
263 //Do pending load (automatically unpauses).
264 void mark_pending_load(const std::string& filename, int lmode)
266 loadmode = lmode;
267 pending_load = filename;
268 old_mode = amode;
269 amode = ADVANCE_LOAD;
270 platform::cancel_wait();
271 platform::set_paused(false);
274 void mark_pending_save(const std::string& filename, int smode, int binary)
276 int tmp = -1;
277 if(smode == SAVE_MOVIE) {
278 //Just do this immediately.
279 do_save_movie(filename, binary);
280 flush_slotinfo(translate_name_mprefix(filename, tmp, false));
281 return;
283 if(location_special == SPECIAL_SAVEPOINT) {
284 //We can save immediately here.
285 do_save_state(filename, binary);
286 flush_slotinfo(translate_name_mprefix(filename, tmp, false));
287 return;
289 queued_saves.insert(std::make_pair(filename, binary));
290 messages << "Pending save on '" << filename << "'" << std::endl;
293 struct jukebox_size_listener : public setting_var_listener
295 jukebox_size_listener() { lsnes_vset.add_listener(*this); }
296 ~jukebox_size_listener() throw() {lsnes_vset.remove_listener(*this); };
297 void on_setting_change(setting_var_group& grp, const setting_var_base& val)
299 if(val.get_iname() == "jukebox-size") {
300 if(save_jukebox_pointer >= jukebox_size)
301 save_jukebox_pointer = 0;
303 update_movie_state();
308 void update_movie_state()
310 static unsigned last_controllers = 0;
312 uint64_t magic[4];
313 our_rom.region->fill_framerate_magic(magic);
314 voice_frame_number(movb.get_movie().get_current_frame(), 1.0 * magic[1] / magic[0]);
316 auto& _status = platform::get_emustatus();
317 if(!system_corrupt) {
318 _status.set("!frame", (stringfmt() << movb.get_movie().get_current_frame()).str());
319 _status.set("!length", (stringfmt() << movb.get_movie().get_frame_count()).str());
320 _status.set("!lag", (stringfmt() << movb.get_movie().get_lag_frames()).str());
321 if(location_special == SPECIAL_FRAME_START)
322 _status.set("!subframe", "0");
323 else if(location_special == SPECIAL_SAVEPOINT)
324 _status.set("!subframe", "S");
325 else if(location_special == SPECIAL_FRAME_VIDEO)
326 _status.set("!subframe", "V");
327 else
328 _status.set("!subframe", (stringfmt() << movb.get_movie().next_poll_number()).str());
329 } else {
330 _status.set("!frame", "N/A");
331 _status.set("!length", "N/A");
332 _status.set("!lag", "N/A");
333 _status.set("!subframe", "N/A");
336 _status.set("!dumping", (information_dispatch::get_dumper_count() ? "Y" : ""));
337 auto& mo = movb.get_movie();
338 if(system_corrupt)
339 _status.set("!mode", "C");
340 else if(!mo.readonly_mode())
341 _status.set("!mode", "R");
342 else if(mo.get_frame_count() >= mo.get_current_frame())
343 _status.set("!mode", "P");
344 else
345 _status.set("!mode", "F");
347 if(jukebox_size > 0) {
348 int tmp = -1;
349 std::string sfilen = translate_name_mprefix(save_jukebox_name(save_jukebox_pointer), tmp, false);
350 _status.set("!saveslot", (stringfmt() << (save_jukebox_pointer + 1)).str());
351 _status.set("!saveslotinfo", get_slotinfo(sfilen));
352 } else {
353 _status.erase("!saveslot");
354 _status.erase("!saveslotinfo");
356 _status.set("!speed", (stringfmt() << (unsigned)(100 * get_realized_multiplier() + 0.5)).str());
358 if(!system_corrupt) {
359 time_t timevalue = static_cast<time_t>(our_movie.rtc_second);
360 struct tm* time_decompose = gmtime(&timevalue);
361 char datebuffer[512];
362 strftime(datebuffer, 511, "%Y%m%d(%a)T%H%M%S", time_decompose);
363 _status.set("RTC", datebuffer);
364 } else {
365 _status.set("RTC", "N/A");
368 auto mset = controls.active_macro_set();
369 bool mfirst = true;
370 std::ostringstream mss;
371 for(auto i: mset) {
372 if(!mfirst) mss << ",";
373 mss << i;
374 mfirst = false;
376 _status.set("!macros", mss.str());
378 do_watch_memory();
380 controller_frame c;
381 if(movb.get_movie().readonly_mode())
382 c = movb.get_movie().get_controls();
383 else
384 c = controls.get_committed();
385 for(unsigned i = 0;; i++) {
386 auto pindex = controls.lcid_to_pcid(i);
387 if(pindex.first < 0 || !controls.is_present(pindex.first, pindex.second)) {
388 for(unsigned j = i; j < last_controllers; j++)
389 _status.erase((stringfmt() << "P" << (j + 1)).str());
390 last_controllers = i;
391 break;
393 char32_t buffer[MAX_DISPLAY_LENGTH];
394 c.display(pindex.first, pindex.second, buffer);
395 _status.set((stringfmt() << "P" << (i + 1)).str(), buffer);
397 notify_status_update();
400 uint64_t audio_irq_time;
401 uint64_t controller_irq_time;
402 uint64_t frame_irq_time;
404 struct lsnes_callbacks : public emucore_callbacks
406 public:
407 ~lsnes_callbacks() throw()
411 int16_t get_input(unsigned port, unsigned index, unsigned control)
413 int16_t x;
414 x = movb.input_poll(port, index, control);
415 lua_callback_snoop_input(port, index, control, x);
416 return x;
419 int16_t set_input(unsigned port, unsigned index, unsigned control, int16_t value)
421 if(!movb.get_movie().readonly_mode()) {
422 controller_frame f = movb.get_movie().get_controls();
423 f.axis3(port, index, control, value);
424 movb.get_movie().set_controls(f);
426 return movb.get_movie().next_input(port, index, control);
429 void timer_tick(uint32_t increment, uint32_t per_second)
431 our_movie.rtc_subsecond += increment;
432 while(our_movie.rtc_subsecond >= per_second) {
433 our_movie.rtc_second++;
434 our_movie.rtc_subsecond -= per_second;
438 std::string get_firmware_path()
440 return lsnes_vset["firmwarepath"].str();
443 std::string get_base_path()
445 return our_rom.msu1_base;
448 time_t get_time()
450 return our_movie.rtc_second;
453 time_t get_randomseed()
455 return random_seed_value;
458 void output_frame(framebuffer_raw& screen, uint32_t fps_n, uint32_t fps_d)
460 lua_callback_do_frame_emulated();
461 location_special = SPECIAL_FRAME_VIDEO;
462 update_movie_state();
463 redraw_framebuffer(screen, false, true);
464 uint32_t g = gcd(fps_n, fps_d);
465 fps_n /= g;
466 fps_d /= g;
467 information_dispatch::do_frame(screen, fps_n, fps_d);
470 void action_state_updated()
472 graphics_driver_action_updated();
476 namespace
478 function_ptr_command<> count_rerecords(lsnes_cmd, "count-rerecords", "Count rerecords",
479 "Syntax: count-rerecords\nCounts rerecords.\n",
480 []() throw(std::bad_alloc, std::runtime_error) {
481 std::vector<char> tmp;
482 uint64_t x = rrdata::write(tmp);
483 messages << x << " rerecord(s)" << std::endl;
486 function_ptr_command<const std::string&> quit_emulator(lsnes_cmd, "quit-emulator", "Quit the emulator",
487 "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
488 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
489 amode = ADVANCE_QUIT;
490 platform::set_paused(false);
491 platform::cancel_wait();
494 function_ptr_command<> unpause_emulator(lsnes_cmd, "unpause-emulator", "Unpause the emulator",
495 "Syntax: unpause-emulator\nUnpauses the emulator.\n",
496 []() throw(std::bad_alloc, std::runtime_error) {
497 amode = ADVANCE_AUTO;
498 platform::set_paused(false);
499 platform::cancel_wait();
500 messages << "Unpaused" << std::endl;
503 function_ptr_command<> pause_emulator(lsnes_cmd, "pause-emulator", "(Un)pause the emulator",
504 "Syntax: pause-emulator\n(Un)pauses the emulator.\n",
505 []() throw(std::bad_alloc, std::runtime_error) {
506 if(amode != ADVANCE_AUTO) {
507 amode = ADVANCE_AUTO;
508 platform::set_paused(false);
509 platform::cancel_wait();
510 messages << "Unpaused" << std::endl;
511 } else {
512 platform::cancel_wait();
513 cancel_advance = false;
514 stop_at_frame_active = false;
515 amode = ADVANCE_PAUSE;
516 messages << "Paused" << std::endl;
520 function_ptr_command<> save_jukebox_prev(lsnes_cmd, "cycle-jukebox-backward", "Cycle save jukebox backwards",
521 "Syntax: cycle-jukebox-backward\nCycle save jukebox backwards\n",
522 []() throw(std::bad_alloc, std::runtime_error) {
523 if(jukebox_size == 0)
524 return;
525 if(save_jukebox_pointer == 0)
526 save_jukebox_pointer = jukebox_size - 1;
527 else
528 save_jukebox_pointer--;
529 if(save_jukebox_pointer >= jukebox_size)
530 save_jukebox_pointer = 0;
531 update_movie_state();
534 function_ptr_command<> save_jukebox_next(lsnes_cmd, "cycle-jukebox-forward", "Cycle save jukebox forwards",
535 "Syntax: cycle-jukebox-forward\nCycle save jukebox forwards\n",
536 []() throw(std::bad_alloc, std::runtime_error) {
537 if(jukebox_size == 0)
538 return;
539 if(save_jukebox_pointer >= jukebox_size - 1)
540 save_jukebox_pointer = 0;
541 else
542 save_jukebox_pointer++;
543 if(save_jukebox_pointer >= jukebox_size)
544 save_jukebox_pointer = 0;
545 update_movie_state();
548 function_ptr_command<> load_jukebox(lsnes_cmd, "load-jukebox", "Load save from jukebox",
549 "Syntax: load-jukebox\nLoad save from jukebox\n",
550 []() throw(std::bad_alloc, std::runtime_error) {
551 if(jukebox_size == 0)
552 throw std::runtime_error("No slot selected");
553 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_CURRENT);
556 function_ptr_command<> load_jukebox_readwrite(lsnes_cmd, "load-jukebox-readwrite", "Load save from jukebox in"
557 " read-write mode", "Syntax: load-jukebox-readwrite\nLoad save from jukebox in read-write mode\n",
558 []() throw(std::bad_alloc, std::runtime_error) {
559 if(jukebox_size == 0)
560 throw std::runtime_error("No slot selected");
561 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_RW);
564 function_ptr_command<> load_jukebox_readonly(lsnes_cmd, "load-jukebox-readonly", "Load save from jukebox in "
565 "read-only mode", "Syntax: load-jukebox-readonly\nLoad save from jukebox in read-only mode\n",
566 []() throw(std::bad_alloc, std::runtime_error) {
567 if(jukebox_size == 0)
568 throw std::runtime_error("No slot selected");
569 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_RO);
572 function_ptr_command<> load_jukebox_preserve(lsnes_cmd, "load-jukebox-preserve", "Load save from jukebox, "
573 "preserving input", "Syntax: load-jukebox-preserve\nLoad save from jukebox, preserving input\n",
574 []() throw(std::bad_alloc, std::runtime_error) {
575 if(jukebox_size == 0)
576 throw std::runtime_error("No slot selected");
577 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_PRESERVE);
580 function_ptr_command<> load_jukebox_movie(lsnes_cmd, "load-jukebox-movie", "Load save from jukebox as movie",
581 "Syntax: load-jukebox-movie\nLoad save from jukebox as movie\n",
582 []() throw(std::bad_alloc, std::runtime_error) {
583 if(jukebox_size == 0)
584 throw std::runtime_error("No slot selected");
585 mark_pending_load(save_jukebox_name(save_jukebox_pointer), LOAD_STATE_MOVIE);
588 function_ptr_command<> save_jukebox_c(lsnes_cmd, "save-jukebox", "Save save to jukebox",
589 "Syntax: save-jukebox\nSave save to jukebox\n",
590 []() throw(std::bad_alloc, std::runtime_error) {
591 if(jukebox_size == 0)
592 throw std::runtime_error("No slot selected");
593 mark_pending_save(save_jukebox_name(save_jukebox_pointer), SAVE_STATE, -1);
596 function_ptr_command<> padvance_frame(lsnes_cmd, "+advance-frame", "Advance one frame",
597 "Syntax: +advance-frame\nAdvances the emulation by one frame.\n",
598 []() throw(std::bad_alloc, std::runtime_error) {
599 amode = ADVANCE_FRAME;
600 cancel_advance = false;
601 advanced_once = false;
602 platform::cancel_wait();
603 platform::set_paused(false);
606 function_ptr_command<> nadvance_frame(lsnes_cmd, "-advance-frame", "Advance one frame",
607 "No help available\n",
608 []() throw(std::bad_alloc, std::runtime_error) {
609 cancel_advance = true;
610 platform::cancel_wait();
611 platform::set_paused(false);
614 function_ptr_command<> padvance_poll(lsnes_cmd, "+advance-poll", "Advance one subframe",
615 "Syntax: +advance-poll\nAdvances the emulation by one subframe.\n",
616 []() throw(std::bad_alloc, std::runtime_error) {
617 amode = ADVANCE_SUBFRAME;
618 cancel_advance = false;
619 advanced_once = false;
620 platform::cancel_wait();
621 platform::set_paused(false);
624 function_ptr_command<> nadvance_poll(lsnes_cmd, "-advance-poll", "Advance one subframe",
625 "No help available\n",
626 []() throw(std::bad_alloc, std::runtime_error) {
627 cancel_advance = true;
628 platform::cancel_wait();
629 platform::set_paused(false);
632 function_ptr_command<> advance_skiplag(lsnes_cmd, "advance-skiplag", "Skip to next poll",
633 "Syntax: advance-skiplag\nAdvances the emulation to the next poll.\n",
634 []() throw(std::bad_alloc, std::runtime_error) {
635 amode = ADVANCE_SKIPLAG_PENDING;
636 platform::cancel_wait();
637 platform::set_paused(false);
640 function_ptr_command<> reset_c(lsnes_cmd, "reset", "Reset the system",
641 "Syntax: reset\nReset\nResets the system in beginning of the next frame.\n",
642 []() throw(std::bad_alloc, std::runtime_error) {
643 int sreset_action = our_rom.rtype->reset_action(false);
644 if(sreset_action < 0) {
645 platform::error_message("Core does not support resets");
646 messages << "Emulator core does not support resets" << std::endl;
647 return;
649 our_rom.rtype->execute_action(sreset_action, std::vector<interface_action_paramval>());
652 function_ptr_command<> hreset_c(lsnes_cmd, "reset-hard", "Reset the system",
653 "Syntax: reset-hard\nReset-hard\nHard resets the system in beginning of the next frame.\n",
654 []() throw(std::bad_alloc, std::runtime_error) {
655 int hreset_action = our_rom.rtype->reset_action(true);
656 if(hreset_action < 0) {
657 platform::error_message("Core does not support hard resets");
658 messages << "Emulator core does not support hard resets" << std::endl;
659 return;
661 our_rom.rtype->execute_action(hreset_action, std::vector<interface_action_paramval>());
664 function_ptr_command<arg_filename> load_c(lsnes_cmd, "load", "Load savestate (current mode)",
665 "Syntax: load <file>\nLoads SNES state from <file> in current mode\n",
666 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
667 mark_pending_load(args, LOAD_STATE_CURRENT);
670 function_ptr_command<arg_filename> load_smart_c(lsnes_cmd, "load-smart", "Load savestate (heuristic mode)",
671 "Syntax: load <file>\nLoads SNES state from <file> in heuristic mode\n",
672 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
673 mark_pending_load(args, LOAD_STATE_DEFAULT);
676 function_ptr_command<arg_filename> load_state_c(lsnes_cmd, "load-state", "Load savestate (R/W)",
677 "Syntax: load-state <file>\nLoads SNES state from <file> in Read/Write mode\n",
678 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
679 mark_pending_load(args, LOAD_STATE_RW);
682 function_ptr_command<arg_filename> load_readonly(lsnes_cmd, "load-readonly", "Load savestate (RO)",
683 "Syntax: load-readonly <file>\nLoads SNES state from <file> in read-only mode\n",
684 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
685 mark_pending_load(args, LOAD_STATE_RO);
688 function_ptr_command<arg_filename> load_preserve(lsnes_cmd, "load-preserve", "Load savestate (preserve "
689 "input)", "Syntax: load-preserve <file>\nLoads SNES state from <file> preserving input\n",
690 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
691 mark_pending_load(args, LOAD_STATE_PRESERVE);
694 function_ptr_command<arg_filename> load_movie_c(lsnes_cmd, "load-movie", "Load movie",
695 "Syntax: load-movie <file>\nLoads SNES movie from <file>\n",
696 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
697 mark_pending_load(args, LOAD_STATE_MOVIE);
701 function_ptr_command<arg_filename> save_state(lsnes_cmd, "save-state", "Save state",
702 "Syntax: save-state <file>\nSaves SNES state to <file>\n",
703 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
704 mark_pending_save(args, SAVE_STATE, -1);
707 function_ptr_command<arg_filename> save_state2(lsnes_cmd, "save-state-binary", "Save state (binary)",
708 "Syntax: save-state-binary <file>\nSaves binary state to <file>\n",
709 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
710 mark_pending_save(args, SAVE_STATE, 1);
713 function_ptr_command<arg_filename> save_state3(lsnes_cmd, "save-state-zip", "Save state (zip)",
714 "Syntax: save-state-zip <file>\nSaves zip state to <file>\n",
715 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
716 mark_pending_save(args, SAVE_STATE, 0);
719 function_ptr_command<arg_filename> save_movie(lsnes_cmd, "save-movie", "Save movie",
720 "Syntax: save-movie <file>\nSaves SNES movie to <file>\n",
721 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
722 mark_pending_save(args, SAVE_MOVIE, -1);
725 function_ptr_command<arg_filename> save_movie2(lsnes_cmd, "save-movie-binary", "Save movie (binary)",
726 "Syntax: save-movie-binary <file>\nSaves binary movie to <file>\n",
727 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
728 mark_pending_save(args, SAVE_MOVIE, 1);
731 function_ptr_command<arg_filename> save_movie3(lsnes_cmd, "save-movie-zip", "Save movie (zip)",
732 "Syntax: save-movie-zip <file>\nSaves zip movie to <file>\n",
733 [](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
734 mark_pending_save(args, SAVE_MOVIE, 0);
737 function_ptr_command<> set_rwmode(lsnes_cmd, "set-rwmode", "Switch to read/write mode",
738 "Syntax: set-rwmode\nSwitches to read/write mode\n",
739 []() throw(std::bad_alloc, std::runtime_error) {
740 lua_callback_movie_lost("readwrite");
741 movb.get_movie().readonly_mode(false);
742 notify_mode_change(false);
743 lua_callback_do_readwrite();
744 update_movie_state();
747 function_ptr_command<> set_romode(lsnes_cmd, "set-romode", "Switch to read-only mode",
748 "Syntax: set-romode\nSwitches to read-only mode\n",
749 []() throw(std::bad_alloc, std::runtime_error) {
750 movb.get_movie().readonly_mode(true);
751 notify_mode_change(true);
752 update_movie_state();
755 function_ptr_command<> toggle_rwmode(lsnes_cmd, "toggle-rwmode", "Toggle read/write mode",
756 "Syntax: toggle-rwmode\nToggles read/write mode\n",
757 []() throw(std::bad_alloc, std::runtime_error) {
758 bool c = movb.get_movie().readonly_mode();
759 if(c)
760 lua_callback_movie_lost("readwrite");
761 movb.get_movie().readonly_mode(!c);
762 notify_mode_change(!c);
763 if(c)
764 lua_callback_do_readwrite();
765 update_movie_state();
768 function_ptr_command<> repaint(lsnes_cmd, "repaint", "Redraw the screen",
769 "Syntax: repaint\nRedraws the screen\n",
770 []() throw(std::bad_alloc, std::runtime_error) {
771 redraw_framebuffer();
774 function_ptr_command<> tpon(lsnes_cmd, "toggle-pause-on-end", "Toggle pause on end", "Toggle pause on end\n",
775 []() throw(std::bad_alloc, std::runtime_error) {
776 bool tmp = pause_on_end;
777 pause_on_end.set(!tmp);
778 messages << "Pause-on-end is now " << (tmp ? "OFF" : "ON") << std::endl;
781 function_ptr_command<> spon(lsnes_cmd, "set-pause-on-end", "Set pause on end", "Set pause on end\n",
782 []() throw(std::bad_alloc, std::runtime_error) {
783 pause_on_end.set(true);
784 messages << "Pause-on-end is now ON" << std::endl;
787 function_ptr_command<> cpon(lsnes_cmd, "clear-pause-on-end", "Clear pause on end", "Clear pause on end\n",
788 []() throw(std::bad_alloc, std::runtime_error) {
789 pause_on_end.set(false);
790 messages << "Pause-on-end is now OFF" << std::endl;
793 function_ptr_command<> rewind_movie(lsnes_cmd, "rewind-movie", "Rewind movie to the beginning",
794 "Syntax: rewind-movie\nRewind movie to the beginning\n",
795 []() throw(std::bad_alloc, std::runtime_error) {
796 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_BEGINNING);
799 function_ptr_command<> cancel_save(lsnes_cmd, "cancel-saves", "Cancel all pending saves", "Syntax: "
800 "cancel-save\nCancel pending saves\n",
801 []() throw(std::bad_alloc, std::runtime_error) {
802 queued_saves.clear();
803 messages << "Pending saves canceled." << std::endl;
806 function_ptr_command<> flushslots(lsnes_cmd, "flush-slotinfo", "Flush slotinfo cache",
807 "Flush slotinfo cache\n",
808 []() throw(std::bad_alloc, std::runtime_error) {
809 flush_slotinfo();
812 function_ptr_command<> mhold1(lsnes_cmd, "+hold-macro", "Hold macro (hold)",
813 "Hold macros enable\n", []() throw(std::bad_alloc, std::runtime_error) {
814 macro_hold_1 = true;
817 function_ptr_command<> mhold2(lsnes_cmd, "-hold-macro", "Hold macro (hold)",
818 "Hold macros disable\n", []() throw(std::bad_alloc, std::runtime_error) {
819 macro_hold_1 = false;
822 function_ptr_command<> mhold3(lsnes_cmd, "hold-macro", "Hold macro (toggle)",
823 "Hold macros toggle\n", []() throw(std::bad_alloc, std::runtime_error) {
824 macro_hold_2 = !macro_hold_2;
825 if(macro_hold_2)
826 messages << "Macros are held for next frame." << std::endl;
827 else
828 messages << "Macros are not held for next frame." << std::endl;
831 inverse_bind imhold1(lsnes_mapper, "+hold-macro", "Macro‣Hold all macros");
832 inverse_bind imhold2(lsnes_mapper, "hold-macro", "Macro‣Hold all macros (typed)");
833 inverse_bind ipause_emulator(lsnes_mapper, "pause-emulator", "Speed‣(Un)pause");
834 inverse_bind ijback(lsnes_mapper, "cycle-jukebox-backward", "Slot select‣Cycle backwards");
835 inverse_bind ijforward(lsnes_mapper, "cycle-jukebox-forward", "Slot select‣Cycle forwards");
836 inverse_bind iloadj(lsnes_mapper, "load-jukebox", "Load‣Selected slot");
837 inverse_bind iloadjrw(lsnes_mapper, "load-jukebox-readwrite", "Load‣Selected slot (readwrite mode)");
838 inverse_bind iloadjro(lsnes_mapper, "load-jukebox-readonly", "Load‣Selected slot (readonly mode)");
839 inverse_bind iloadjp(lsnes_mapper, "load-jukebox-preserve", "Load‣Selected slot (preserve input)");
840 inverse_bind iloadjm(lsnes_mapper, "load-jukebox-movie", "Load‣Selected slot (as movie)");
841 inverse_bind isavej(lsnes_mapper, "save-jukebox", "Save‣Selected slot");
842 inverse_bind iadvframe(lsnes_mapper, "+advance-frame", "Speed‣Advance frame");
843 inverse_bind iadvsubframe(lsnes_mapper, "+advance-poll", "Speed‣Advance subframe");
844 inverse_bind iskiplag(lsnes_mapper, "advance-skiplag", "Speed‣Advance poll");
845 inverse_bind ireset(lsnes_mapper, "reset", "System‣Reset");
846 inverse_bind iset_rwmode(lsnes_mapper, "set-rwmode", "Movie‣Switch to read/write");
847 inverse_bind itoggle_romode(lsnes_mapper, "set-romode", "Movie‣Switch to read-only");
848 inverse_bind itoggle_rwmode(lsnes_mapper, "toggle-rwmode", "Movie‣Toggle read-only");
849 inverse_bind irepaint(lsnes_mapper, "repaint", "System‣Repaint screen");
850 inverse_bind itogglepause(lsnes_mapper, "toggle-pause-on-end", "Movie‣Toggle pause-on-end");
851 inverse_bind irewind_movie(lsnes_mapper, "rewind-movie", "Movie‣Rewind movie");
852 inverse_bind icancel_saves(lsnes_mapper, "cancel-saves", "Save‣Cancel pending saves");
853 inverse_bind iload1(lsnes_mapper, "load ${project}1.lsmv", "Load‣Slot 1");
854 inverse_bind iload2(lsnes_mapper, "load ${project}2.lsmv", "Load‣Slot 2");
855 inverse_bind iload3(lsnes_mapper, "load ${project}3.lsmv", "Load‣Slot 3");
856 inverse_bind iload4(lsnes_mapper, "load ${project}4.lsmv", "Load‣Slot 4");
857 inverse_bind iload5(lsnes_mapper, "load ${project}5.lsmv", "Load‣Slot 5");
858 inverse_bind iload6(lsnes_mapper, "load ${project}6.lsmv", "Load‣Slot 6");
859 inverse_bind iload7(lsnes_mapper, "load ${project}7.lsmv", "Load‣Slot 7");
860 inverse_bind iload8(lsnes_mapper, "load ${project}8.lsmv", "Load‣Slot 8");
861 inverse_bind iload9(lsnes_mapper, "load ${project}9.lsmv", "Load‣Slot 9");
862 inverse_bind iload10(lsnes_mapper, "load ${project}10.lsmv", "Load‣Slot 10");
863 inverse_bind iload11(lsnes_mapper, "load ${project}11.lsmv", "Load‣Slot 11");
864 inverse_bind iload12(lsnes_mapper, "load ${project}12.lsmv", "Load‣Slot 12");
865 inverse_bind iload13(lsnes_mapper, "load ${project}13.lsmv", "Load‣Slot 13");
866 inverse_bind iload14(lsnes_mapper, "load ${project}14.lsmv", "Load‣Slot 14");
867 inverse_bind iload15(lsnes_mapper, "load ${project}15.lsmv", "Load‣Slot 15");
868 inverse_bind iload16(lsnes_mapper, "load ${project}16.lsmv", "Load‣Slot 16");
869 inverse_bind iload17(lsnes_mapper, "load ${project}17.lsmv", "Load‣Slot 17");
870 inverse_bind iload18(lsnes_mapper, "load ${project}18.lsmv", "Load‣Slot 18");
871 inverse_bind iload19(lsnes_mapper, "load ${project}19.lsmv", "Load‣Slot 19");
872 inverse_bind iload20(lsnes_mapper, "load ${project}20.lsmv", "Load‣Slot 20");
873 inverse_bind iload21(lsnes_mapper, "load ${project}21.lsmv", "Load‣Slot 21");
874 inverse_bind iload22(lsnes_mapper, "load ${project}22.lsmv", "Load‣Slot 22");
875 inverse_bind iload23(lsnes_mapper, "load ${project}23.lsmv", "Load‣Slot 23");
876 inverse_bind iload24(lsnes_mapper, "load ${project}24.lsmv", "Load‣Slot 24");
877 inverse_bind iload25(lsnes_mapper, "load ${project}25.lsmv", "Load‣Slot 25");
878 inverse_bind iload26(lsnes_mapper, "load ${project}26.lsmv", "Load‣Slot 26");
879 inverse_bind iload27(lsnes_mapper, "load ${project}27.lsmv", "Load‣Slot 27");
880 inverse_bind iload28(lsnes_mapper, "load ${project}28.lsmv", "Load‣Slot 28");
881 inverse_bind iload29(lsnes_mapper, "load ${project}29.lsmv", "Load‣Slot 29");
882 inverse_bind iload30(lsnes_mapper, "load ${project}30.lsmv", "Load‣Slot 30");
883 inverse_bind iload31(lsnes_mapper, "load ${project}31.lsmv", "Load‣Slot 31");
884 inverse_bind iload32(lsnes_mapper, "load ${project}32.lsmv", "Load‣Slot 32");
885 inverse_bind isave1(lsnes_mapper, "save-state ${project}1.lsmv", "Save‣Slot 1");
886 inverse_bind isave2(lsnes_mapper, "save-state ${project}2.lsmv", "Save‣Slot 2");
887 inverse_bind isave3(lsnes_mapper, "save-state ${project}3.lsmv", "Save‣Slot 3");
888 inverse_bind isave4(lsnes_mapper, "save-state ${project}4.lsmv", "Save‣Slot 4");
889 inverse_bind isave5(lsnes_mapper, "save-state ${project}5.lsmv", "Save‣Slot 5");
890 inverse_bind isave6(lsnes_mapper, "save-state ${project}6.lsmv", "Save‣Slot 6");
891 inverse_bind isave7(lsnes_mapper, "save-state ${project}7.lsmv", "Save‣Slot 7");
892 inverse_bind isave8(lsnes_mapper, "save-state ${project}8.lsmv", "Save‣Slot 8");
893 inverse_bind isave9(lsnes_mapper, "save-state ${project}9.lsmv", "Save‣Slot 9");
894 inverse_bind isave10(lsnes_mapper, "save-state ${project}10.lsmv", "Save‣Slot 10");
895 inverse_bind isave11(lsnes_mapper, "save-state ${project}11.lsmv", "Save‣Slot 11");
896 inverse_bind isave12(lsnes_mapper, "save-state ${project}12.lsmv", "Save‣Slot 12");
897 inverse_bind isave13(lsnes_mapper, "save-state ${project}13.lsmv", "Save‣Slot 13");
898 inverse_bind isave14(lsnes_mapper, "save-state ${project}14.lsmv", "Save‣Slot 14");
899 inverse_bind isave15(lsnes_mapper, "save-state ${project}15.lsmv", "Save‣Slot 15");
900 inverse_bind isave16(lsnes_mapper, "save-state ${project}16.lsmv", "Save‣Slot 16");
901 inverse_bind isave17(lsnes_mapper, "save-state ${project}17.lsmv", "Save‣Slot 17");
902 inverse_bind isave18(lsnes_mapper, "save-state ${project}18.lsmv", "Save‣Slot 18");
903 inverse_bind isave19(lsnes_mapper, "save-state ${project}19.lsmv", "Save‣Slot 19");
904 inverse_bind isave20(lsnes_mapper, "save-state ${project}20.lsmv", "Save‣Slot 20");
905 inverse_bind isave21(lsnes_mapper, "save-state ${project}21.lsmv", "Save‣Slot 21");
906 inverse_bind isave22(lsnes_mapper, "save-state ${project}22.lsmv", "Save‣Slot 22");
907 inverse_bind isave23(lsnes_mapper, "save-state ${project}23.lsmv", "Save‣Slot 23");
908 inverse_bind isave24(lsnes_mapper, "save-state ${project}24.lsmv", "Save‣Slot 24");
909 inverse_bind isave25(lsnes_mapper, "save-state ${project}25.lsmv", "Save‣Slot 25");
910 inverse_bind isave26(lsnes_mapper, "save-state ${project}26.lsmv", "Save‣Slot 26");
911 inverse_bind isave27(lsnes_mapper, "save-state ${project}27.lsmv", "Save‣Slot 27");
912 inverse_bind isave28(lsnes_mapper, "save-state ${project}28.lsmv", "Save‣Slot 28");
913 inverse_bind isave29(lsnes_mapper, "save-state ${project}29.lsmv", "Save‣Slot 29");
914 inverse_bind isave30(lsnes_mapper, "save-state ${project}30.lsmv", "Save‣Slot 30");
915 inverse_bind isave31(lsnes_mapper, "save-state ${project}31.lsmv", "Save‣Slot 31");
916 inverse_bind isave32(lsnes_mapper, "save-state ${project}32.lsmv", "Save‣Slot 32");
918 bool on_quit_prompt = false;
919 class mywindowcallbacks : public information_dispatch
921 public:
922 mywindowcallbacks() : information_dispatch("mainloop-window-callbacks")
924 closenotify.set(notify_close, [this]() {
925 if(on_quit_prompt) {
926 amode = ADVANCE_QUIT;
927 platform::set_paused(false);
928 platform::cancel_wait();
929 return;
931 on_quit_prompt = true;
932 try {
933 amode = ADVANCE_QUIT;
934 platform::set_paused(false);
935 platform::cancel_wait();
936 } catch(...) {
938 on_quit_prompt = false;
941 ~mywindowcallbacks() throw() {}
942 void on_new_dumper(const std::string& n)
944 update_movie_state();
946 void on_destroy_dumper(const std::string& n)
948 update_movie_state();
950 private:
951 struct dispatch_target<> closenotify;
952 } mywcb;
954 //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
955 //failing.
956 int handle_load()
958 std::string old_project = our_movie.projectid;
959 jumpback:
960 if(do_unsafe_rewind && unsafe_rewind_obj) {
961 uint64_t t = get_utime();
962 std::vector<char> s;
963 lua_callback_do_unsafe_rewind(s, 0, 0, movb.get_movie(), unsafe_rewind_obj);
964 notify_mode_change(false);
965 do_unsafe_rewind = false;
966 our_movie.is_savestate = true;
967 location_special = SPECIAL_SAVEPOINT;
968 update_movie_state();
969 messages << "Rewind done in " << (get_utime() - t) << " usec." << std::endl;
970 return 1;
972 if(pending_new_project != "") {
973 std::string id = pending_new_project;
974 pending_new_project = "";
975 project_info* old = project_get();
976 if(old && old->id == id)
977 goto nothing_to_do;
978 try {
979 auto& p = project_load(id);
980 project_set(&p);
981 if(project_get() != old)
982 delete old;
983 flush_slotinfo(); //Wrong movie may be stale.
984 return 1;
985 } catch(std::exception& e) {
986 platform::error_message(std::string("Can't switch projects: ") + e.what());
987 messages << "Can't switch projects: " << e.what() << std::endl;
988 goto nothing_to_do;
990 nothing_to_do:
991 amode = old_mode;
992 platform::set_paused(amode == ADVANCE_PAUSE);
993 platform::flush_command_queue();
994 if(amode == ADVANCE_LOAD)
995 goto jumpback;
996 return 0;
998 if(pending_load != "") {
999 system_corrupt = false;
1000 if(loadmode != LOAD_STATE_BEGINNING && loadmode != LOAD_STATE_ROMRELOAD &&
1001 !do_load_state(pending_load, loadmode)) {
1002 movb.get_movie().set_pflag_handler(&lsnes_pflag_handler);
1003 pending_load = "";
1004 return -1;
1006 try {
1007 if(loadmode == LOAD_STATE_BEGINNING)
1008 do_load_beginning(false);
1009 if(loadmode == LOAD_STATE_ROMRELOAD)
1010 do_load_beginning(true);
1011 } catch(std::exception& e) {
1012 platform::error_message(std::string("Load failed: ") + e.what());
1013 messages << "Load failed: " << e.what() << std::endl;
1015 movb.get_movie().set_pflag_handler(&lsnes_pflag_handler);
1016 pending_load = "";
1017 amode = load_paused ? ADVANCE_PAUSE : ADVANCE_AUTO;
1018 platform::set_paused(load_paused);
1019 load_paused = false;
1020 if(!system_corrupt) {
1021 location_special = SPECIAL_SAVEPOINT;
1022 update_movie_state();
1023 platform::flush_command_queue();
1024 if(amode == ADVANCE_QUIT)
1025 return -1;
1026 if(amode == ADVANCE_LOAD)
1027 goto jumpback;
1029 if(old_project != our_movie.projectid)
1030 flush_slotinfo(); //Wrong movie may be stale.
1031 return 1;
1033 return 0;
1036 //If there are pending saves, perform them.
1037 void handle_saves()
1039 if(!queued_saves.empty() || (do_unsafe_rewind && !unsafe_rewind_obj)) {
1040 our_rom.rtype->runtosave();
1041 for(auto i : queued_saves) {
1042 do_save_state(i.first, i.second);
1043 int tmp = -1;
1044 flush_slotinfo(translate_name_mprefix(i.first, tmp, false));
1046 if(do_unsafe_rewind && !unsafe_rewind_obj) {
1047 uint64_t t = get_utime();
1048 std::vector<char> s = our_rom.save_core_state(true);
1049 uint64_t secs = our_movie.rtc_second;
1050 uint64_t ssecs = our_movie.rtc_subsecond;
1051 lua_callback_do_unsafe_rewind(s, secs, ssecs, movb.get_movie(), NULL);
1052 do_unsafe_rewind = false;
1053 messages << "Rewind point set in " << (get_utime() - t) << " usec." << std::endl;
1056 queued_saves.clear();
1059 bool handle_corrupt()
1061 if(!system_corrupt)
1062 return false;
1063 while(system_corrupt) {
1064 platform::set_paused(true);
1065 platform::flush_command_queue();
1066 handle_load();
1067 if(amode == ADVANCE_QUIT)
1068 return true;
1070 return true;
1074 void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_to_succeed) throw(std::bad_alloc,
1075 std::runtime_error)
1077 platform::system_thread_available(true);
1078 //Basic initialization.
1079 dispatch_set_error_streams(&messages.getstream());
1080 emulation_thread = this_thread_id();
1081 jukebox_size_listener jlistener;
1082 voicethread_task();
1083 init_special_screens();
1084 our_rom = rom;
1085 lsnes_callbacks lsnes_callbacks_obj;
1086 ecore_callbacks = &lsnes_callbacks_obj;
1087 movb.get_movie().set_pflag_handler(&lsnes_pflag_handler);
1088 core_core::install_all_handlers();
1090 //Load our given movie.
1091 bool first_round = false;
1092 bool just_did_loadstate = false;
1093 try {
1094 do_load_state(initial, LOAD_STATE_INITIAL);
1095 location_special = SPECIAL_SAVEPOINT;
1096 update_movie_state();
1097 first_round = our_movie.is_savestate;
1098 just_did_loadstate = first_round;
1099 } catch(std::bad_alloc& e) {
1100 OOM_panic();
1101 } catch(std::exception& e) {
1102 platform::error_message(std::string("Can't load initial state: ") + e.what());
1103 messages << "ERROR: Can't load initial state: " << e.what() << std::endl;
1104 if(load_has_to_succeed) {
1105 messages << "FATAL: Can't load movie" << std::endl;
1106 platform::fatal_error();
1108 system_corrupt = true;
1109 update_movie_state();
1110 redraw_framebuffer(screen_corrupt);
1113 movb.get_movie().set_pflag_handler(&lsnes_pflag_handler);
1114 lua_callback_startup();
1116 platform::set_paused(initial.start_paused);
1117 amode = initial.start_paused ? ADVANCE_PAUSE : ADVANCE_AUTO;
1118 stop_at_frame_active = false;
1119 uint64_t time_x = get_utime();
1120 while(amode != ADVANCE_QUIT || !queued_saves.empty()) {
1121 if(handle_corrupt()) {
1122 first_round = our_movie.is_savestate;
1123 just_did_loadstate = first_round;
1124 continue;
1126 ack_frame_tick(get_utime());
1127 if(amode == ADVANCE_SKIPLAG_PENDING)
1128 amode = ADVANCE_SKIPLAG;
1130 if(!first_round) {
1131 controls.reset_framehold();
1132 movb.new_frame_starting(amode == ADVANCE_SKIPLAG);
1133 if(!macro_hold_1 && !macro_hold_2) {
1134 controls.advance_macros();
1136 macro_hold_2 = false;
1137 if(amode == ADVANCE_QUIT && queued_saves.empty())
1138 break;
1139 handle_saves();
1140 int r = 0;
1141 if(queued_saves.empty())
1142 r = handle_load();
1143 if(r > 0 || system_corrupt) {
1144 first_round = our_movie.is_savestate;
1145 if(system_corrupt)
1146 amode = ADVANCE_PAUSE;
1147 else
1148 amode = old_mode;
1149 stop_at_frame_active = false;
1150 just_did_loadstate = first_round;
1151 controls.reset_framehold();
1152 continue;
1153 } else if(r < 0) {
1154 //Not exactly desriable, but this at least won't desync.
1155 stop_at_frame_active = false;
1156 if(amode == ADVANCE_QUIT)
1157 return;
1158 amode = ADVANCE_PAUSE;
1161 if(just_did_loadstate) {
1162 //If we just loadstated, we are up to date.
1163 if(amode == ADVANCE_QUIT)
1164 break;
1165 platform::set_paused(amode == ADVANCE_PAUSE);
1166 platform::flush_command_queue();
1167 //We already have done the reset this frame if we are going to do one at all.
1168 movb.get_movie().set_controls(movb.update_controls(true));
1169 movb.get_movie().set_all_DRDY();
1170 just_did_loadstate = false;
1172 frame_irq_time = get_utime() - time_x;
1173 our_rom.rtype->emulate();
1174 time_x = get_utime();
1175 if(amode == ADVANCE_AUTO)
1176 platform::wait(to_wait_frame(get_utime()));
1177 first_round = false;
1178 lua_callback_do_frame();
1180 information_dispatch::do_dump_end();
1181 core_core::uninstall_all_handlers();
1182 voicethread_kill();
1183 platform::system_thread_available(false);
1186 void set_stop_at_frame(uint64_t frame)
1188 stop_at_frame = frame;
1189 stop_at_frame_active = (frame != 0);
1190 amode = ADVANCE_AUTO;
1191 platform::set_paused(false);
1194 void do_flush_slotinfo()
1196 flush_slotinfo();
1199 void switch_projects(const std::string& newproj)
1201 pending_new_project = newproj;
1202 amode = ADVANCE_LOAD;
1203 old_mode = ADVANCE_PAUSE;
1204 platform::cancel_wait();
1205 platform::set_paused(false);
1208 void load_new_rom(const romload_request& req)
1210 if(_load_new_rom(req)) {
1211 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD);
1215 void reload_current_rom()
1217 if(reload_active_rom()) {
1218 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD);
1222 void close_rom()
1224 if(load_null_rom()) {
1225 load_paused = true;
1226 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD);