Fix most hotkeys to show up in configuration (were missing due to errant !)
[lsnes.git] / src / core / mainloop.cpp
blob04494aa2fe50a84ab36187303094512504d33a60
1 #include "lsnes.hpp"
3 #include "cmdhelp/loadsave.hpp"
4 #include "cmdhelp/mhold.hpp"
5 #include "core/advdumper.hpp"
6 #include "core/command.hpp"
7 #include "core/controller.hpp"
8 #include "core/debug.hpp"
9 #include "core/dispatch.hpp"
10 #include "core/emustatus.hpp"
11 #include "core/framebuffer.hpp"
12 #include "core/framerate.hpp"
13 #include "core/instance.hpp"
14 #include "core/inthread.hpp"
15 #include "core/jukebox.hpp"
16 #include "core/keymapper.hpp"
17 #include "core/mainloop.hpp"
18 #include "core/memorymanip.hpp"
19 #include "core/memorywatch.hpp"
20 #include "core/messages.hpp"
21 #include "core/moviedata.hpp"
22 #include "core/moviefile.hpp"
23 #include "core/multitrack.hpp"
24 #include "core/project.hpp"
25 #include "core/queue.hpp"
26 #include "core/random.hpp"
27 #include "core/rom.hpp"
28 #include "core/runmode.hpp"
29 #include "core/settings.hpp"
30 #include "core/window.hpp"
31 #include "interface/callbacks.hpp"
32 #include "interface/c-interface.hpp"
33 #include "interface/romtype.hpp"
34 #include "library/framebuffer.hpp"
35 #include "library/settingvar.hpp"
36 #include "library/string.hpp"
37 #include "library/zip.hpp"
38 #include "lua/lua.hpp"
40 #include <iomanip>
41 #include <cassert>
42 #include <sstream>
43 #include <iostream>
44 #include <limits>
45 #include <set>
46 #include <sys/time.h>
49 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> movie_dflt_binary(lsnes_setgrp,
50 "movie-default-binary", "Movie‣Saving‣Movies binary", false);
51 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> save_dflt_binary(lsnes_setgrp,
52 "savestate-default-binary", "Movie‣Saving‣Savestates binary", false);
54 namespace
56 settingvar::supervariable<settingvar::model_int<0,999999>> SET_advance_timeout_first(lsnes_setgrp,
57 "advance-timeout", "Delays‣First frame advance", 500);
58 settingvar::supervariable<settingvar::model_int<0,999999>> SET_advance_timeout_subframe(lsnes_setgrp,
59 "advance-subframe-timeout", "Delays‣Subframe advance", 100);
60 settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> SET_pause_on_end(lsnes_setgrp,
61 "pause-on-end", "Movie‣Pause on end", false);
63 //Mode and filename of pending load, one of LOAD_* constants.
64 int loadmode;
65 std::string pending_load;
66 std::string pending_new_project;
67 //Queued saves (all savestates).
68 std::set<std::pair<std::string, int>> queued_saves;
69 //Unsafe rewind.
70 bool do_unsafe_rewind = false;
71 void* unsafe_rewind_obj = NULL;
72 //Stop at frame.
73 bool stop_at_frame_active = false;
74 uint64_t stop_at_frame = 0;
75 //Macro hold.
76 bool macro_hold_1;
77 bool macro_hold_2;
80 void mainloop_signal_need_rewind(void* ptr)
82 auto& core = CORE();
83 if(ptr)
84 core.runmode->start_load();
85 do_unsafe_rewind = true;
86 unsafe_rewind_obj = ptr;
89 portctrl::frame movie_logic::update_controls(bool subframe) throw(std::bad_alloc, std::runtime_error)
91 auto& core = CORE();
92 if(core.lua2->requests_subframe_paint)
93 core.fbuf->redraw_framebuffer();
95 if(subframe) {
96 if(core.runmode->is_advance_subframe()) {
97 //Note that platform::wait() may change value of cancel flag.
98 if(!core.runmode->test_cancel()) {
99 if(core.runmode->set_and_test_advanced())
100 platform::wait(SET_advance_timeout_subframe(*core.settings) * 1000);
101 else
102 platform::wait(SET_advance_timeout_first(*core.settings) * 1000);
103 core.runmode->set_and_test_advanced();
105 if(core.runmode->clear_and_test_cancel()) {
106 stop_at_frame_active = false;
107 core.runmode->set_pause();
109 platform::set_paused(core.runmode->is_paused());
110 } else if(core.runmode->is_advance_frame()) {
112 } else {
113 if(core.runmode->is_skiplag()) {
114 stop_at_frame_active = false;
115 core.runmode->set_pause();
117 core.runmode->clear_and_test_cancel();
119 platform::set_paused(core.runmode->is_paused());
120 core.runmode->set_point(emulator_runmode::P_NONE);
121 core.supdater->update();
122 } else {
123 core.runmode->decay_skiplag();
124 if(core.runmode->is_advance()) {
125 //Note that platform::wait() may change value of cancel flag.
126 if(!core.runmode->test_cancel()) {
127 uint64_t wait = 0;
128 if(!core.runmode->test_advanced())
129 wait = SET_advance_timeout_first(*core.settings) * 1000;
130 else if(core.runmode->is_advance_subframe())
131 wait = SET_advance_timeout_subframe(*core.settings) * 1000;
132 else
133 wait = core.framerate->to_wait_frame(framerate_regulator::get_utime());
134 platform::wait(wait);
135 core.runmode->set_and_test_advanced();
137 if(core.runmode->clear_and_test_cancel()) {
138 stop_at_frame_active = false;
139 core.runmode->set_pause();
141 platform::set_paused(core.runmode->is_paused());
142 } else if(core.runmode->is_freerunning() && core.mlogic->get_movie().readonly_mode() &&
143 SET_pause_on_end(*core.settings) && !stop_at_frame_active) {
144 if(core.mlogic->get_movie().get_current_frame() ==
145 core.mlogic->get_movie().get_frame_count()) {
146 stop_at_frame_active = false;
147 core.runmode->set_pause();
148 platform::set_paused(true);
150 } else if(core.runmode->is_freerunning() && stop_at_frame_active) {
151 if(core.mlogic->get_movie().get_current_frame() >= stop_at_frame) {
152 stop_at_frame_active = false;
153 core.runmode->set_pause();
154 platform::set_paused(true);
156 } else {
157 platform::set_paused(core.runmode->is_paused());
159 core.runmode->set_point(emulator_runmode::P_START);
160 core.supdater->update();
162 platform::flush_command_queue();
163 portctrl::frame tmp = core.controls->get(core.mlogic->get_movie().get_current_frame());
164 core.rom->pre_emulate_frame(tmp); //Preset controls, the lua will override if needed.
165 core.lua2->callback_do_input(tmp, subframe);
166 core.mteditor->process_frame(tmp);
167 core.controls->commit(tmp);
168 return tmp;
171 namespace
174 //Do pending load (automatically unpauses).
175 void mark_pending_load(std::string filename, int lmode)
177 //Convert break pause to ordinary pause.
178 auto& core = CORE();
179 loadmode = lmode;
180 pending_load = filename;
181 core.runmode->decay_break();
182 core.runmode->start_load();
183 platform::cancel_wait();
184 platform::set_paused(false);
187 void mark_pending_save(std::string filename, int smode, int binary)
189 auto& core = CORE();
190 int tmp = -1;
191 if(smode == SAVE_MOVIE) {
192 //Just do this immediately.
193 do_save_movie(filename, binary);
194 core.slotcache->flush(translate_name_mprefix(filename, tmp, -1));
195 return;
197 if(core.runmode->get_point() == emulator_runmode::P_SAVE) {
198 //We can save immediately here.
199 do_save_state(filename, binary);
200 core.slotcache->flush(translate_name_mprefix(filename, tmp, -1));
201 return;
203 queued_saves.insert(std::make_pair(filename, binary));
204 messages << "Pending save on '" << filename << "'" << std::endl;
209 struct lsnes_callbacks : public emucore_callbacks
211 public:
212 ~lsnes_callbacks() throw()
216 int16_t get_input(unsigned port, unsigned index, unsigned control)
218 auto& core = CORE();
219 int16_t x;
220 x = core.mlogic->input_poll(port, index, control);
221 core.lua2->callback_snoop_input(port, index, control, x);
222 return x;
225 int16_t set_input(unsigned port, unsigned index, unsigned control, int16_t value)
227 auto& core = CORE();
228 if(!core.mlogic->get_movie().readonly_mode()) {
229 portctrl::frame f = core.mlogic->get_movie().get_controls();
230 f.axis3(port, index, control, value);
231 core.mlogic->get_movie().set_controls(f);
233 return core.mlogic->get_movie().next_input(port, index, control);
236 void notify_latch(std::list<std::string>& args)
238 CORE().lua2->callback_do_latch(args);
241 void timer_tick(uint32_t increment, uint32_t per_second)
243 auto& core = CORE();
244 if(!*core.mlogic)
245 return;
246 auto& m = core.mlogic->get_mfile();
247 m.rtc_subsecond += increment;
248 while(m.rtc_subsecond >= per_second) {
249 m.rtc_second++;
250 m.rtc_subsecond -= per_second;
254 std::string get_firmware_path()
256 return CORE().setcache->get("firmwarepath");
259 std::string get_base_path()
261 return CORE().rom->msu1_base;
264 time_t get_time()
266 auto& core = CORE();
267 return *core.mlogic ? core.mlogic->get_mfile().rtc_second : 0;
270 time_t get_randomseed()
272 return CORE().random_seed_value;
275 void output_frame(framebuffer::raw& screen, uint32_t fps_n, uint32_t fps_d)
277 auto& core = CORE();
278 core.lua2->callback_do_frame_emulated();
279 core.runmode->set_point(emulator_runmode::P_VIDEO);
280 core.fbuf->redraw_framebuffer(screen, false, true);
281 auto rate = core.rom->get_audio_rate();
282 uint32_t gv = gcd(fps_n, fps_d);
283 uint32_t ga = gcd(rate.first, rate.second);
284 core.mdumper->on_rate_change(rate.first / ga, rate.second / ga);
285 core.mdumper->on_frame(screen, fps_n / gv, fps_d / gv);
288 void action_state_updated()
290 CORE().dispatch->action_update();
293 void memory_read(uint64_t addr, uint64_t value)
295 CORE().dbg->do_callback_read(addr, value);
298 void memory_write(uint64_t addr, uint64_t value)
300 CORE().dbg->do_callback_write(addr, value);
303 void memory_execute(uint64_t addr, uint64_t proc)
305 CORE().dbg->do_callback_exec(addr, proc);
308 void memory_trace(uint64_t proc, const char* str, bool insn)
310 CORE().dbg->do_callback_trace(proc, str, insn);
314 namespace
316 lsnes_callbacks lsnes_callbacks_obj;
317 command::fnptr<> CMD_segfault(lsnes_cmds, "segfault", "Trigger SIGSEGV",
318 "segfault\nTrigger segmentation fault",
319 []() throw(std::bad_alloc, std::runtime_error) {
320 char* ptr = (char*)0x1234;
321 *ptr = 0;
324 command::fnptr<> CMD_div0(lsnes_cmds, "divide-by-0", "Do div0", "divide-by-0\nDo divide by 0",
325 []() throw(std::bad_alloc, std::runtime_error) {
326 static int ptr = 1;
327 static int ptr2 = 0;
328 ptr = ptr / ptr2;
331 command::fnptr<const std::string&> CMD_test4(lsnes_cmds, "test4", "test", "test",
332 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
333 auto& core = CORE();
334 std::list<std::string> _args;
335 std::string args2 = args;
336 for(auto& sym : token_iterator<char>::foreach(args, {" ", "\t"}))
337 _args.push_back(sym);
338 core.lua2->callback_do_latch(_args);
340 command::fnptr<> CMD_count_rerecords(lsnes_cmds, "count-rerecords", "Count rerecords",
341 "Syntax: count-rerecords\nCounts rerecords.\n",
342 []() throw(std::bad_alloc, std::runtime_error) {
343 std::vector<char> tmp;
344 uint64_t x = CORE().mlogic->get_rrdata().write(tmp);
345 messages << x << " rerecord(s)" << std::endl;
348 command::fnptr<const std::string&> CMD_quit_emulator(lsnes_cmds, "quit-emulator", "Quit the emulator",
349 "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
350 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
351 CORE().runmode->set_quit();
352 platform::set_paused(false);
353 platform::cancel_wait();
356 command::fnptr<> CMD_unpause_emulator(lsnes_cmds, "unpause-emulator", "Unpause the emulator",
357 "Syntax: unpause-emulator\nUnpauses the emulator.\n",
358 []() throw(std::bad_alloc, std::runtime_error) {
359 auto& core = CORE();
360 if(core.runmode->is_special())
361 return;
362 core.runmode->set_freerunning();
363 platform::set_paused(false);
364 platform::cancel_wait();
367 command::fnptr<> CMD_pause_emulator(lsnes_cmds, "pause-emulator", "(Un)pause the emulator",
368 "Syntax: pause-emulator\n(Un)pauses the emulator.\n",
369 []() throw(std::bad_alloc, std::runtime_error) {
370 auto& core = CORE();
371 if(core.runmode->is_special())
373 else if(core.runmode->is_freerunning()) {
374 platform::cancel_wait();
375 stop_at_frame_active = false;
376 core.runmode->set_pause();
377 } else {
378 core.runmode->set_freerunning();
379 platform::set_paused(false);
380 platform::cancel_wait();
384 command::fnptr<> CMD_load_jukebox(lsnes_cmds, CLOADSAVE::ldj,
385 []() throw(std::bad_alloc, std::runtime_error) {
386 auto& core = CORE();
387 mark_pending_load(core.jukebox->get_slot_name(), LOAD_STATE_CURRENT);
390 command::fnptr<> CMD_load_jukebox_readwrite(lsnes_cmds, CLOADSAVE::ldjrw,
391 []() throw(std::bad_alloc, std::runtime_error) {
392 auto& core = CORE();
393 mark_pending_load(core.jukebox->get_slot_name(), LOAD_STATE_RW);
396 command::fnptr<> CMD_load_jukebox_readonly(lsnes_cmds, CLOADSAVE::ldjro,
397 []() throw(std::bad_alloc, std::runtime_error) {
398 auto& core = CORE();
399 mark_pending_load(core.jukebox->get_slot_name(), LOAD_STATE_RO);
402 command::fnptr<> CMD_load_jukebox_preserve(lsnes_cmds, CLOADSAVE::ldjp,
403 []() throw(std::bad_alloc, std::runtime_error) {
404 auto& core = CORE();
405 mark_pending_load(core.jukebox->get_slot_name(), LOAD_STATE_PRESERVE);
408 command::fnptr<> CMD_load_jukebox_movie(lsnes_cmds, CLOADSAVE::ldjm,
409 []() throw(std::bad_alloc, std::runtime_error) {
410 auto& core = CORE();
411 mark_pending_load(core.jukebox->get_slot_name(), LOAD_STATE_MOVIE);
414 command::fnptr<> CMD_save_jukebox_c(lsnes_cmds, CLOADSAVE::saj,
415 []() throw(std::bad_alloc, std::runtime_error) {
416 auto& core = CORE();
417 mark_pending_save(core.jukebox->get_slot_name(), SAVE_STATE, -1);
420 command::fnptr<> CMD_padvance_frame(lsnes_cmds, "+advance-frame", "Advance one frame",
421 "Syntax: +advance-frame\nAdvances the emulation by one frame.\n",
422 []() throw(std::bad_alloc, std::runtime_error) {
423 auto& core = CORE();
424 if(core.runmode->is_special())
425 return;
426 core.runmode->set_frameadvance();
427 platform::cancel_wait();
428 platform::set_paused(false);
431 command::fnptr<> CMD_nadvance_frame(lsnes_cmds, "-advance-frame", "Advance one frame",
432 "No help available\n",
433 []() throw(std::bad_alloc, std::runtime_error) {
434 CORE().runmode->set_cancel();
435 platform::cancel_wait();
436 platform::set_paused(false);
439 command::fnptr<> CMD_padvance_poll(lsnes_cmds, "+advance-poll", "Advance one subframe",
440 "Syntax: +advance-poll\nAdvances the emulation by one subframe.\n",
441 []() throw(std::bad_alloc, std::runtime_error) {
442 auto& core = CORE();
443 if(core.runmode->is_special())
444 return;
445 core.runmode->set_subframeadvance();
446 platform::cancel_wait();
447 platform::set_paused(false);
450 command::fnptr<> CMD_nadvance_poll(lsnes_cmds, "-advance-poll", "Advance one subframe",
451 "No help available\n",
452 []() throw(std::bad_alloc, std::runtime_error) {
453 auto& core = CORE();
454 core.runmode->decay_break();
455 core.runmode->set_cancel();
456 platform::cancel_wait();
457 platform::set_paused(false);
460 command::fnptr<> CMD_advance_skiplag(lsnes_cmds, "advance-skiplag", "Skip to next poll",
461 "Syntax: advance-skiplag\nAdvances the emulation to the next poll.\n",
462 []() throw(std::bad_alloc, std::runtime_error) {
463 CORE().runmode->set_skiplag_pending();
464 platform::cancel_wait();
465 platform::set_paused(false);
468 command::fnptr<> CMD_reset_c(lsnes_cmds, "reset", "Reset the system",
469 "Syntax: reset\nReset\nResets the system in beginning of the next frame.\n",
470 []() throw(std::bad_alloc, std::runtime_error) {
471 auto& core = CORE();
472 int sreset_action = core.rom->reset_action(false);
473 if(sreset_action < 0) {
474 platform::error_message("Core does not support resets");
475 messages << "Emulator core does not support resets" << std::endl;
476 return;
478 core.rom->execute_action(sreset_action, std::vector<interface_action_paramval>());
481 command::fnptr<> CMD_hreset_c(lsnes_cmds, "reset-hard", "Reset the system",
482 "Syntax: reset-hard\nReset-hard\nHard resets the system in beginning of the next frame.\n",
483 []() throw(std::bad_alloc, std::runtime_error) {
484 auto& core = CORE();
485 int hreset_action = core.rom->reset_action(true);
486 if(hreset_action < 0) {
487 platform::error_message("Core does not support hard resets");
488 messages << "Emulator core does not support hard resets" << std::endl;
489 return;
491 core.rom->execute_action(hreset_action, std::vector<interface_action_paramval>());
494 command::fnptr<command::arg_filename> CMD_load_c(lsnes_cmds, CLOADSAVE::ld,
495 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
496 mark_pending_load(args, LOAD_STATE_CURRENT);
499 command::fnptr<command::arg_filename> CMD_load_smart_c(lsnes_cmds, CLOADSAVE::ldsm,
500 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
501 mark_pending_load(args, LOAD_STATE_DEFAULT);
504 command::fnptr<command::arg_filename> CMD_load_state_c(lsnes_cmds, CLOADSAVE::ldrw,
505 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
506 mark_pending_load(args, LOAD_STATE_RW);
509 command::fnptr<command::arg_filename> CMD_load_readonly(lsnes_cmds, CLOADSAVE::ldro,
510 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
511 mark_pending_load(args, LOAD_STATE_RO);
514 command::fnptr<command::arg_filename> CMD_load_preserve(lsnes_cmds, CLOADSAVE::ldp,
515 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
516 mark_pending_load(args, LOAD_STATE_PRESERVE);
519 command::fnptr<command::arg_filename> CMD_load_movie_c(lsnes_cmds, CLOADSAVE::ldm,
520 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
521 mark_pending_load(args, LOAD_STATE_MOVIE);
524 command::fnptr<command::arg_filename> CMD_load_allbr_c(lsnes_cmds, CLOADSAVE::ldab,
525 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
526 mark_pending_load(args, LOAD_STATE_ALLBRANCH);
529 command::fnptr<command::arg_filename> CMD_save_state(lsnes_cmds, CLOADSAVE::sa,
530 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
531 mark_pending_save(args, SAVE_STATE, -1);
534 command::fnptr<command::arg_filename> CMD_save_state2(lsnes_cmds, CLOADSAVE::sasb,
535 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
536 mark_pending_save(args, SAVE_STATE, 1);
539 command::fnptr<command::arg_filename> CMD_save_state3(lsnes_cmds, CLOADSAVE::sasz,
540 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
541 mark_pending_save(args, SAVE_STATE, 0);
544 command::fnptr<command::arg_filename> CMD_save_movie(lsnes_cmds, CLOADSAVE::sam,
545 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
546 mark_pending_save(args, SAVE_MOVIE, -1);
549 command::fnptr<command::arg_filename> CMD_save_movie2(lsnes_cmds, CLOADSAVE::samb,
550 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
551 mark_pending_save(args, SAVE_MOVIE, 1);
554 command::fnptr<command::arg_filename> CMD_save_movie3(lsnes_cmds, CLOADSAVE::samz,
555 [](command::arg_filename args) throw(std::bad_alloc, std::runtime_error) {
556 mark_pending_save(args, SAVE_MOVIE, 0);
559 command::fnptr<> CMD_set_rwmode(lsnes_cmds, "set-rwmode", "Switch to recording mode",
560 "Syntax: set-rwmode\nSwitches to recording mode\n",
561 []() throw(std::bad_alloc, std::runtime_error) {
562 auto& core = CORE();
563 core.lua2->callback_movie_lost("readwrite");
564 core.mlogic->get_movie().readonly_mode(false);
565 core.dispatch->mode_change(false);
566 core.lua2->callback_do_readwrite();
567 core.supdater->update();
570 command::fnptr<> CMD_set_romode(lsnes_cmds, "set-romode", "Switch to playback mode",
571 "Syntax: set-romode\nSwitches to playback mode\n",
572 []() throw(std::bad_alloc, std::runtime_error) {
573 auto& core = CORE();
574 core.mlogic->get_movie().readonly_mode(true);
575 core.dispatch->mode_change(true);
576 core.supdater->update();
579 command::fnptr<> CMD_toggle_rwmode(lsnes_cmds, "toggle-rwmode", "Toggle recording mode",
580 "Syntax: toggle-rwmode\nToggles recording mode\n",
581 []() throw(std::bad_alloc, std::runtime_error) {
582 auto& core = CORE();
583 bool c = core.mlogic->get_movie().readonly_mode();
584 if(c)
585 core.lua2->callback_movie_lost("readwrite");
586 core.mlogic->get_movie().readonly_mode(!c);
587 core.dispatch->mode_change(!c);
588 if(c)
589 core.lua2->callback_do_readwrite();
590 core.supdater->update();
593 command::fnptr<> CMD_repaint(lsnes_cmds, "repaint", "Redraw the screen",
594 "Syntax: repaint\nRedraws the screen\n",
595 []() throw(std::bad_alloc, std::runtime_error) {
596 CORE().fbuf->redraw_framebuffer();
599 command::fnptr<> CMD_tpon(lsnes_cmds, "toggle-pause-on-end", "Toggle pause on end", "Toggle pause on end\n",
600 []() throw(std::bad_alloc, std::runtime_error) {
601 auto& core = CORE();
602 bool tmp = SET_pause_on_end(*core.settings);
603 SET_pause_on_end(*core.settings, !tmp);
604 messages << "Pause-on-end is now " << (tmp ? "OFF" : "ON") << std::endl;
607 command::fnptr<> CMD_spon(lsnes_cmds, "set-pause-on-end", "Set pause on end", "Set pause on end\n",
608 []() throw(std::bad_alloc, std::runtime_error) {
609 SET_pause_on_end(*CORE().settings, true);
610 messages << "Pause-on-end is now ON" << std::endl;
613 command::fnptr<> CMD_cpon(lsnes_cmds, "clear-pause-on-end", "Clear pause on end", "Clear pause on end\n",
614 []() throw(std::bad_alloc, std::runtime_error) {
615 SET_pause_on_end(*CORE().settings, false);
616 messages << "Pause-on-end is now OFF" << std::endl;
619 command::fnptr<> CMD_rewind_movie(lsnes_cmds, CLOADSAVE::rewind,
620 []() throw(std::bad_alloc, std::runtime_error) {
621 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_BEGINNING);
624 command::fnptr<> CMD_cancel_save(lsnes_cmds, CLOADSAVE::cancel,
625 []() throw(std::bad_alloc, std::runtime_error) {
626 queued_saves.clear();
627 messages << "Pending saves canceled." << std::endl;
630 command::fnptr<> CMD_mhold1(lsnes_cmds, CMHOLD::p, []() throw(std::bad_alloc, std::runtime_error) {
631 macro_hold_1 = true;
634 command::fnptr<> CMD_mhold2(lsnes_cmds, CMHOLD::r, []() throw(std::bad_alloc, std::runtime_error) {
635 macro_hold_1 = false;
638 command::fnptr<> CMD_mhold3(lsnes_cmds, CMHOLD::t, []() throw(std::bad_alloc, std::runtime_error) {
639 macro_hold_2 = !macro_hold_2;
640 if(macro_hold_2)
641 messages << "Macros are held for next frame." << std::endl;
642 else
643 messages << "Macros are not held for next frame." << std::endl;
646 keyboard::invbind_info IBIND_ipause_emulator(lsnes_invbinds, "pause-emulator", "Speed‣(Un)pause");
647 keyboard::invbind_info IBIND_iadvframe(lsnes_invbinds, "+advance-frame", "Speed‣Advance frame");
648 keyboard::invbind_info IBIND_iadvsubframe(lsnes_invbinds, "+advance-poll", "Speed‣Advance subframe");
649 keyboard::invbind_info IBIND_iskiplag(lsnes_invbinds, "advance-skiplag", "Speed‣Advance poll");
650 keyboard::invbind_info IBIND_ireset(lsnes_invbinds, "reset", "System‣Reset");
651 keyboard::invbind_info IBIND_iset_rwmode(lsnes_invbinds, "set-rwmode", "Movie‣Switch to recording");
652 keyboard::invbind_info IBIND_itoggle_romode(lsnes_invbinds, "set-romode", "Movie‣Switch to playback");
653 keyboard::invbind_info IBIND_itoggle_rwmode(lsnes_invbinds, "toggle-rwmode", "Movie‣Toggle playback");
654 keyboard::invbind_info IBIND_irepaint(lsnes_invbinds, "repaint", "System‣Repaint screen");
655 keyboard::invbind_info IBIND_itogglepause(lsnes_invbinds, "toggle-pause-on-end", "Movie‣Toggle pause-on-end");
657 class mywindowcallbacks : public master_dumper::notifier
659 public:
660 mywindowcallbacks(emulator_dispatch& dispatch, emulator_runmode& runmode, status_updater& _supdater)
661 : supdater(_supdater)
663 closenotify.set(dispatch.close, [this, &runmode]() {
664 try {
665 runmode.set_quit();
666 platform::set_paused(false);
667 platform::cancel_wait();
668 } catch(...) {
672 ~mywindowcallbacks() throw() {}
673 void dump_status_change() throw()
675 supdater.update();
677 private:
678 struct dispatch::target<> closenotify;
679 status_updater& supdater;
682 //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
683 //failing.
684 int handle_load()
686 auto& core = CORE();
687 std::string old_project = *core.mlogic ? core.mlogic->get_mfile().projectid : "";
688 jumpback:
689 if(do_unsafe_rewind && unsafe_rewind_obj) {
690 if(!*core.mlogic)
691 return 0;
692 uint64_t t = framerate_regulator::get_utime();
693 std::vector<char> s;
694 core.lua2->callback_do_unsafe_rewind(s, 0, 0, core.mlogic->get_movie(), unsafe_rewind_obj);
695 core.dispatch->mode_change(false);
696 do_unsafe_rewind = false;
697 core.mlogic->get_mfile().is_savestate = true;
698 core.runmode->set_point(emulator_runmode::P_SAVE);
699 core.supdater->update();
700 messages << "Rewind done in " << (framerate_regulator::get_utime() - t) << " usec."
701 << std::endl;
702 return 1;
704 if(pending_new_project != "") {
705 std::string id = pending_new_project;
706 pending_new_project = "";
707 project_info* old = core.project->get();
708 if(old && old->id == id)
709 goto nothing_to_do;
710 try {
711 auto& p = core.project->load(id);
712 core.project->set(&p);
713 if(core.project->get() != old)
714 delete old;
715 core.slotcache->flush(); //Wrong movie may be stale.
716 core.runmode->end_load(); //Restore previous mode.
717 return 1;
718 } catch(std::exception& e) {
719 platform::error_message(std::string("Can't switch projects: ") + e.what());
720 messages << "Can't switch projects: " << e.what() << std::endl;
721 goto nothing_to_do;
723 nothing_to_do:
724 core.runmode->end_load();
725 platform::set_paused(core.runmode->is_paused());
726 platform::flush_command_queue();
727 if(core.runmode->is_load())
728 goto jumpback;
729 return 0;
731 if(pending_load != "") {
732 try {
733 if(loadmode != LOAD_STATE_BEGINNING && loadmode != LOAD_STATE_ROMRELOAD &&
734 !do_load_state(pending_load, loadmode)) {
735 core.runmode->end_load();
736 pending_load = "";
737 return -1;
739 if(loadmode == LOAD_STATE_BEGINNING)
740 do_load_rewind();
741 if(loadmode == LOAD_STATE_ROMRELOAD)
742 do_load_rom();
743 core.runmode->clear_corrupt();
744 } catch(std::exception& e) {
745 core.runmode->set_corrupt();
746 platform::error_message(std::string("Load failed: ") + e.what());
747 messages << "Load failed: " << e.what() << std::endl;
749 pending_load = "";
750 if(!core.runmode->is_corrupt()) {
751 core.runmode->end_load();
752 core.runmode->set_point(emulator_runmode::P_SAVE);
753 core.supdater->update();
754 platform::flush_command_queue();
755 if(core.runmode->is_quit())
756 return -1;
757 if(core.runmode->is_load())
758 goto jumpback;
760 if(old_project != (*core.mlogic ? core.mlogic->get_mfile().projectid : ""))
761 core.slotcache->flush(); //Wrong movie may be stale.
762 return 1;
764 return 0;
767 //If there are pending saves, perform them.
768 void handle_saves()
770 auto& core = CORE();
771 if(!*core.mlogic)
772 return;
773 if(!queued_saves.empty() || (do_unsafe_rewind && !unsafe_rewind_obj)) {
774 core.rom->runtosave();
775 for(auto i : queued_saves) {
776 do_save_state(i.first, i.second);
777 int tmp = -1;
778 core.slotcache->flush(translate_name_mprefix(i.first, tmp, -1));
780 if(do_unsafe_rewind && !unsafe_rewind_obj) {
781 uint64_t t = framerate_regulator::get_utime();
782 std::vector<char> s = core.rom->save_core_state(true);
783 uint64_t secs = core.mlogic->get_mfile().rtc_second;
784 uint64_t ssecs = core.mlogic->get_mfile().rtc_subsecond;
785 core.lua2->callback_do_unsafe_rewind(s, secs, ssecs, core.mlogic->get_movie(),
786 NULL);
787 do_unsafe_rewind = false;
788 messages << "Rewind point set in " << (framerate_regulator::get_utime() - t)
789 << " usec." << std::endl;
792 queued_saves.clear();
795 bool handle_corrupt()
797 auto& core = CORE();
798 if(!core.runmode->is_corrupt())
799 return false;
800 while(core.runmode->is_corrupt()) {
801 platform::set_paused(true);
802 platform::flush_command_queue();
803 handle_load();
804 if(core.runmode->is_quit())
805 return true;
807 return true;
811 void init_main_callbacks()
813 ecore_callbacks = &lsnes_callbacks_obj;
816 void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_to_succeed) throw(std::bad_alloc,
817 std::runtime_error)
819 lsnes_instance.emu_thread = threads::id();
820 auto& core = CORE();
821 mywindowcallbacks mywcb(*core.dispatch, *core.runmode, *core.supdater);
822 core.iqueue->system_thread_available = true;
823 //Basic initialization.
824 core.commentary->init();
825 core.fbuf->init_special_screens();
826 core.jukebox->set_update([&core]() { core.supdater->update(); });
827 *core.rom = rom;
828 init_main_callbacks();
829 initialize_all_builtin_c_cores();
830 core_core::install_all_handlers();
832 //Load our given movie.
833 bool first_round = false;
834 bool just_did_loadstate = false;
835 bool used = false;
836 try {
837 do_load_state(initial, LOAD_STATE_INITIAL, used);
838 core.runmode->set_point(emulator_runmode::P_SAVE);
839 core.supdater->update();
840 first_round = core.mlogic->get_mfile().is_savestate;
841 just_did_loadstate = first_round;
842 } catch(std::bad_alloc& e) {
843 OOM_panic();
844 } catch(std::exception& e) {
845 if(!used)
846 delete &initial;
847 platform::error_message(std::string("Can't load initial state: ") + e.what());
848 messages << "ERROR: Can't load initial state: " << e.what() << std::endl;
849 if(load_has_to_succeed) {
850 messages << "FATAL: Can't load movie" << std::endl;
851 throw;
853 core.runmode->set_corrupt();
854 core.fbuf->redraw_framebuffer(emu_framebuffer::screen_corrupt);
857 core.runmode->set_pause_cond(initial.start_paused);
858 platform::set_paused(core.runmode->is_paused());
859 stop_at_frame_active = false;
861 core.lua2->run_startup_scripts();
863 while(!core.runmode->is_quit() || !queued_saves.empty()) {
864 if(handle_corrupt()) {
865 first_round = *core.mlogic && core.mlogic->get_mfile().is_savestate;
866 just_did_loadstate = first_round;
867 continue;
869 core.framerate->ack_frame_tick(framerate_regulator::get_utime());
870 core.runmode->decay_skiplag();
872 if(!first_round) {
873 core.controls->reset_framehold();
874 if(!macro_hold_1 && !macro_hold_2) {
875 core.controls->advance_macros();
877 macro_hold_2 = false;
878 core.mlogic->get_movie().get_pollcounters().set_framepflag(false);
879 core.mlogic->new_frame_starting(core.runmode->is_skiplag());
880 core.mlogic->get_movie().get_pollcounters().set_framepflag(true);
881 if(core.runmode->is_quit() && queued_saves.empty())
882 break;
883 handle_saves();
884 int r = 0;
885 if(queued_saves.empty())
886 r = handle_load();
887 if(r > 0 || core.runmode->is_corrupt()) {
888 core.mlogic->get_movie().get_pollcounters().set_framepflag(
889 core.mlogic->get_mfile().is_savestate);
890 first_round = core.mlogic->get_mfile().is_savestate;
891 stop_at_frame_active = false;
892 just_did_loadstate = first_round;
893 core.controls->reset_framehold();
894 core.dbg->do_callback_frame(core.mlogic->get_movie().get_current_frame(), true);
895 continue;
896 } else if(r < 0) {
897 //Not exactly desriable, but this at least won't desync.
898 stop_at_frame_active = false;
899 if(core.runmode->is_quit())
900 goto out;
901 core.runmode->set_pause();
904 if(just_did_loadstate) {
905 //If we just loadstated, we are up to date.
906 if(core.runmode->is_quit())
907 break;
908 platform::set_paused(core.runmode->is_paused());
909 platform::flush_command_queue();
910 //We already have done the reset this frame if we are going to do one at all.
911 core.mlogic->get_movie().set_controls(core.mlogic->update_controls(true));
912 core.mlogic->get_movie().set_all_DRDY();
913 just_did_loadstate = false;
915 core.dbg->do_callback_frame(core.mlogic->get_movie().get_current_frame(), false);
916 core.rom->emulate();
917 random_mix_timing_entropy();
918 if(core.runmode->is_freerunning())
919 platform::wait(core.framerate->to_wait_frame(framerate_regulator::get_utime()));
920 first_round = false;
921 core.lua2->callback_do_frame();
923 out:
924 core.jukebox->unset_update();
925 core.mdumper->end_dumps();
926 core_core::uninstall_all_handlers();
927 core.commentary->kill();
928 core.iqueue->system_thread_available = false;
929 //Kill some things to avoid crashes.
930 core.dbg->core_change();
931 core.project->set(NULL, true);
932 core.mwatch->clear_multi(core.mwatch->enumerate());
935 void set_stop_at_frame(uint64_t frame)
937 auto& core = CORE();
938 stop_at_frame = frame;
939 stop_at_frame_active = (frame != 0);
940 if(!core.runmode->is_special())
941 core.runmode->set_freerunning();
942 platform::set_paused(false);
945 void do_flush_slotinfo()
947 CORE().slotcache->flush();
950 void switch_projects(const std::string& newproj)
952 pending_new_project = newproj;
953 CORE().runmode->start_load();
954 platform::cancel_wait();
955 platform::set_paused(false);
958 void load_new_rom(const romload_request& req)
960 if(_load_new_rom(req)) {
961 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD);
965 void reload_current_rom()
967 if(reload_active_rom()) {
968 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD);
972 void close_rom()
974 if(load_null_rom()) {
975 CORE().runmode->set_pause();
976 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD);
980 void do_break_pause()
982 auto& core = CORE();
983 core.runmode->set_break();
984 core.supdater->update();
985 while(core.runmode->is_paused_break()) {
986 platform::set_paused(true);
987 platform::flush_command_queue();
991 void convert_break_to_pause()
993 auto& core = CORE();
994 if(core.runmode->is_paused_break()) {
995 core.runmode->set_pause();
996 core.supdater->update();