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"
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);
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.
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
;
70 bool do_unsafe_rewind
= false;
71 void* unsafe_rewind_obj
= NULL
;
73 bool stop_at_frame_active
= false;
74 uint64_t stop_at_frame
= 0;
80 void mainloop_signal_need_rewind(void* ptr
)
84 core
.runmode
->start_load();
85 do_unsafe_rewind
= true;
86 unsafe_rewind_obj
= ptr
;
89 bool movie_logic::notify_user_poll() throw(std::bad_alloc
, std::runtime_error
)
91 return CORE().runmode
->is_skiplag();
94 portctrl::frame
movie_logic::update_controls(bool subframe
, bool forced
) throw(std::bad_alloc
, std::runtime_error
)
97 if(core
.lua2
->requests_subframe_paint
)
98 core
.fbuf
->redraw_framebuffer();
101 if(core
.runmode
->is_advance_subframe()) {
102 //Note that platform::wait() may change value of cancel flag.
103 if(!core
.runmode
->test_cancel()) {
104 if(core
.runmode
->set_and_test_advanced())
105 platform::wait(SET_advance_timeout_subframe(*core
.settings
) * 1000);
107 platform::wait(SET_advance_timeout_first(*core
.settings
) * 1000);
108 core
.runmode
->set_and_test_advanced();
110 if(core
.runmode
->clear_and_test_cancel()) {
111 stop_at_frame_active
= false;
112 core
.runmode
->set_pause();
114 platform::set_paused(core
.runmode
->is_paused());
115 } else if(core
.runmode
->is_advance_frame()) {
118 if(core
.runmode
->is_skiplag() && forced
) {
119 stop_at_frame_active
= false;
120 core
.runmode
->set_pause();
122 core
.runmode
->clear_and_test_cancel();
124 platform::set_paused(core
.runmode
->is_paused());
125 core
.runmode
->set_point(emulator_runmode::P_NONE
);
126 core
.supdater
->update();
128 core
.runmode
->decay_skiplag();
129 if(core
.runmode
->is_advance()) {
130 //Note that platform::wait() may change value of cancel flag.
131 if(!core
.runmode
->test_cancel()) {
133 if(!core
.runmode
->test_advanced())
134 wait
= SET_advance_timeout_first(*core
.settings
) * 1000;
135 else if(core
.runmode
->is_advance_subframe())
136 wait
= SET_advance_timeout_subframe(*core
.settings
) * 1000;
138 wait
= core
.framerate
->to_wait_frame(framerate_regulator::get_utime());
139 platform::wait(wait
);
140 core
.runmode
->set_and_test_advanced();
142 if(core
.runmode
->clear_and_test_cancel()) {
143 stop_at_frame_active
= false;
144 core
.runmode
->set_pause();
146 platform::set_paused(core
.runmode
->is_paused());
147 } else if(core
.runmode
->is_freerunning() && core
.mlogic
->get_movie().readonly_mode() &&
148 SET_pause_on_end(*core
.settings
) && !stop_at_frame_active
) {
149 if(core
.mlogic
->get_movie().get_current_frame() ==
150 core
.mlogic
->get_movie().get_frame_count()) {
151 stop_at_frame_active
= false;
152 core
.runmode
->set_pause();
153 platform::set_paused(true);
155 } else if(core
.runmode
->is_freerunning() && stop_at_frame_active
) {
156 if(core
.mlogic
->get_movie().get_current_frame() >= stop_at_frame
) {
157 stop_at_frame_active
= false;
158 core
.runmode
->set_pause();
159 platform::set_paused(true);
162 platform::set_paused(core
.runmode
->is_paused());
164 core
.runmode
->set_point(emulator_runmode::P_START
);
165 core
.supdater
->update();
167 platform::flush_command_queue();
168 portctrl::frame tmp
= core
.controls
->get(core
.mlogic
->get_movie().get_current_frame());
169 core
.rom
->pre_emulate_frame(tmp
); //Preset controls, the lua will override if needed.
170 core
.lua2
->callback_do_input(tmp
, subframe
);
171 core
.mteditor
->process_frame(tmp
);
172 core
.controls
->commit(tmp
);
179 //Do pending load (automatically unpauses).
180 void mark_pending_load(std::string filename
, int lmode
)
182 //Convert break pause to ordinary pause.
185 pending_load
= filename
;
186 core
.runmode
->decay_break();
187 core
.runmode
->start_load();
188 platform::cancel_wait();
189 platform::set_paused(false);
192 void mark_pending_save(std::string filename
, int smode
, int binary
)
196 if(smode
== SAVE_MOVIE
) {
197 //Just do this immediately.
198 do_save_movie(filename
, binary
);
199 core
.slotcache
->flush(translate_name_mprefix(filename
, tmp
, -1));
202 if(core
.runmode
->get_point() == emulator_runmode::P_SAVE
) {
203 //We can save immediately here.
204 do_save_state(filename
, binary
);
205 core
.slotcache
->flush(translate_name_mprefix(filename
, tmp
, -1));
208 queued_saves
.insert(std::make_pair(filename
, binary
));
209 messages
<< "Pending save on '" << filename
<< "'" << std::endl
;
214 struct lsnes_callbacks
: public emucore_callbacks
217 ~lsnes_callbacks() throw()
221 int16_t get_input(unsigned port
, unsigned index
, unsigned control
)
225 x
= core
.mlogic
->input_poll(port
, index
, control
);
226 core
.lua2
->callback_snoop_input(port
, index
, control
, x
);
230 int16_t set_input(unsigned port
, unsigned index
, unsigned control
, int16_t value
)
233 if(!core
.mlogic
->get_movie().readonly_mode()) {
234 portctrl::frame f
= core
.mlogic
->get_movie().get_controls();
235 f
.axis3(port
, index
, control
, value
);
236 core
.mlogic
->get_movie().set_controls(f
);
238 return core
.mlogic
->get_movie().next_input(port
, index
, control
);
241 void notify_latch(std::list
<std::string
>& args
)
243 CORE().lua2
->callback_do_latch(args
);
246 void timer_tick(uint32_t increment
, uint32_t per_second
)
251 auto& m
= core
.mlogic
->get_mfile();
252 m
.dyn
.rtc_subsecond
+= increment
;
253 while(m
.dyn
.rtc_subsecond
>= per_second
) {
255 m
.dyn
.rtc_subsecond
-= per_second
;
259 std::string
get_firmware_path()
261 return SET_firmwarepath(*CORE().settings
);
264 std::string
get_base_path()
266 return CORE().rom
->get_msu1_base();
272 return *core
.mlogic
? core
.mlogic
->get_mfile().dyn
.rtc_second
: 0;
275 time_t get_randomseed()
277 return CORE().random_seed_value
;
280 void output_frame(framebuffer::raw
& screen
, uint32_t fps_n
, uint32_t fps_d
)
283 core
.lua2
->callback_do_frame_emulated();
284 core
.runmode
->set_point(emulator_runmode::P_VIDEO
);
285 core
.fbuf
->redraw_framebuffer(screen
, false, true);
286 auto rate
= core
.rom
->get_audio_rate();
287 uint32_t gv
= gcd(fps_n
, fps_d
);
288 uint32_t ga
= gcd(rate
.first
, rate
.second
);
289 core
.mdumper
->on_rate_change(rate
.first
/ ga
, rate
.second
/ ga
);
290 core
.mdumper
->on_frame(screen
, fps_n
/ gv
, fps_d
/ gv
);
293 void action_state_updated()
295 CORE().dispatch
->action_update();
298 void memory_read(uint64_t addr
, uint64_t value
)
300 CORE().dbg
->do_callback_read(addr
, value
);
303 void memory_write(uint64_t addr
, uint64_t value
)
305 CORE().dbg
->do_callback_write(addr
, value
);
308 void memory_execute(uint64_t addr
, uint64_t proc
)
310 CORE().dbg
->do_callback_exec(addr
, proc
);
313 void memory_trace(uint64_t proc
, const char* str
, bool insn
)
315 CORE().dbg
->do_callback_trace(proc
, str
, insn
);
321 lsnes_callbacks lsnes_callbacks_obj
;
322 command::fnptr
<> CMD_segfault(lsnes_cmds
, "segfault", "Trigger SIGSEGV",
323 "segfault\nTrigger segmentation fault",
324 []() throw(std::bad_alloc
, std::runtime_error
) {
325 char* ptr
= (char*)0x1234;
329 command::fnptr
<> CMD_div0(lsnes_cmds
, "divide-by-0", "Do div0", "divide-by-0\nDo divide by 0",
330 []() throw(std::bad_alloc
, std::runtime_error
) {
336 command::fnptr
<const std::string
&> CMD_test4(lsnes_cmds
, "test4", "test", "test",
337 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
339 std::list
<std::string
> _args
;
340 std::string args2
= args
;
341 for(auto& sym
: token_iterator
<char>::foreach(args
, {" ", "\t"}))
342 _args
.push_back(sym
);
343 core
.lua2
->callback_do_latch(_args
);
345 command::fnptr
<> CMD_count_rerecords(lsnes_cmds
, "count-rerecords", "Count rerecords",
346 "Syntax: count-rerecords\nCounts rerecords.\n",
347 []() throw(std::bad_alloc
, std::runtime_error
) {
348 std::vector
<char> tmp
;
349 uint64_t x
= CORE().mlogic
->get_rrdata().write(tmp
);
350 messages
<< x
<< " rerecord(s)" << std::endl
;
353 command::fnptr
<const std::string
&> CMD_quit_emulator(lsnes_cmds
, "quit-emulator", "Quit the emulator",
354 "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
355 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
356 CORE().runmode
->set_quit();
357 platform::set_paused(false);
358 platform::cancel_wait();
361 command::fnptr
<> CMD_unpause_emulator(lsnes_cmds
, "unpause-emulator", "Unpause the emulator",
362 "Syntax: unpause-emulator\nUnpauses the emulator.\n",
363 []() throw(std::bad_alloc
, std::runtime_error
) {
365 if(core
.runmode
->is_special())
367 core
.runmode
->set_freerunning();
368 platform::set_paused(false);
369 platform::cancel_wait();
372 command::fnptr
<> CMD_pause_emulator(lsnes_cmds
, "pause-emulator", "(Un)pause the emulator",
373 "Syntax: pause-emulator\n(Un)pauses the emulator.\n",
374 []() throw(std::bad_alloc
, std::runtime_error
) {
376 if(core
.runmode
->is_special())
378 else if(core
.runmode
->is_freerunning()) {
379 platform::cancel_wait();
380 stop_at_frame_active
= false;
381 core
.runmode
->set_pause();
383 core
.runmode
->set_freerunning();
384 platform::set_paused(false);
385 platform::cancel_wait();
389 command::fnptr
<> CMD_load_jukebox(lsnes_cmds
, CLOADSAVE::ldj
,
390 []() throw(std::bad_alloc
, std::runtime_error
) {
392 mark_pending_load(core
.jukebox
->get_slot_name(), LOAD_STATE_CURRENT
);
395 command::fnptr
<> CMD_load_jukebox_readwrite(lsnes_cmds
, CLOADSAVE::ldjrw
,
396 []() throw(std::bad_alloc
, std::runtime_error
) {
398 mark_pending_load(core
.jukebox
->get_slot_name(), LOAD_STATE_RW
);
401 command::fnptr
<> CMD_load_jukebox_readonly(lsnes_cmds
, CLOADSAVE::ldjro
,
402 []() throw(std::bad_alloc
, std::runtime_error
) {
404 mark_pending_load(core
.jukebox
->get_slot_name(), LOAD_STATE_RO
);
407 command::fnptr
<> CMD_load_jukebox_preserve(lsnes_cmds
, CLOADSAVE::ldjp
,
408 []() throw(std::bad_alloc
, std::runtime_error
) {
410 mark_pending_load(core
.jukebox
->get_slot_name(), LOAD_STATE_PRESERVE
);
413 command::fnptr
<> CMD_load_jukebox_movie(lsnes_cmds
, CLOADSAVE::ldjm
,
414 []() throw(std::bad_alloc
, std::runtime_error
) {
416 mark_pending_load(core
.jukebox
->get_slot_name(), LOAD_STATE_MOVIE
);
419 command::fnptr
<> CMD_save_jukebox_c(lsnes_cmds
, CLOADSAVE::saj
,
420 []() throw(std::bad_alloc
, std::runtime_error
) {
422 mark_pending_save(core
.jukebox
->get_slot_name(), SAVE_STATE
, -1);
425 command::fnptr
<> CMD_padvance_frame(lsnes_cmds
, "+advance-frame", "Advance one frame",
426 "Syntax: +advance-frame\nAdvances the emulation by one frame.\n",
427 []() throw(std::bad_alloc
, std::runtime_error
) {
429 if(core
.runmode
->is_special())
431 core
.runmode
->set_frameadvance();
432 platform::cancel_wait();
433 platform::set_paused(false);
436 command::fnptr
<> CMD_nadvance_frame(lsnes_cmds
, "-advance-frame", "Advance one frame",
437 "No help available\n",
438 []() throw(std::bad_alloc
, std::runtime_error
) {
439 CORE().runmode
->set_cancel();
440 platform::cancel_wait();
441 platform::set_paused(false);
444 command::fnptr
<> CMD_padvance_poll(lsnes_cmds
, "+advance-poll", "Advance one subframe",
445 "Syntax: +advance-poll\nAdvances the emulation by one subframe.\n",
446 []() throw(std::bad_alloc
, std::runtime_error
) {
448 if(core
.runmode
->is_special())
450 core
.runmode
->set_subframeadvance();
451 platform::cancel_wait();
452 platform::set_paused(false);
455 command::fnptr
<> CMD_nadvance_poll(lsnes_cmds
, "-advance-poll", "Advance one subframe",
456 "No help available\n",
457 []() throw(std::bad_alloc
, std::runtime_error
) {
459 core
.runmode
->decay_break();
460 core
.runmode
->set_cancel();
461 platform::cancel_wait();
462 platform::set_paused(false);
465 command::fnptr
<> CMD_advance_skiplag(lsnes_cmds
, "advance-skiplag", "Skip to next poll",
466 "Syntax: advance-skiplag\nAdvances the emulation to the next poll.\n",
467 []() throw(std::bad_alloc
, std::runtime_error
) {
468 CORE().runmode
->set_skiplag_pending();
469 platform::cancel_wait();
470 platform::set_paused(false);
473 command::fnptr
<> CMD_reset_c(lsnes_cmds
, "reset", "Reset the system",
474 "Syntax: reset\nReset\nResets the system in beginning of the next frame.\n",
475 []() throw(std::bad_alloc
, std::runtime_error
) {
477 int sreset_action
= core
.rom
->reset_action(false);
478 if(sreset_action
< 0) {
479 platform::error_message("Core does not support resets");
480 messages
<< "Emulator core does not support resets" << std::endl
;
483 core
.rom
->execute_action(sreset_action
, std::vector
<interface_action_paramval
>());
486 command::fnptr
<> CMD_hreset_c(lsnes_cmds
, "reset-hard", "Reset the system",
487 "Syntax: reset-hard\nReset-hard\nHard resets the system in beginning of the next frame.\n",
488 []() throw(std::bad_alloc
, std::runtime_error
) {
490 int hreset_action
= core
.rom
->reset_action(true);
491 if(hreset_action
< 0) {
492 platform::error_message("Core does not support hard resets");
493 messages
<< "Emulator core does not support hard resets" << std::endl
;
496 core
.rom
->execute_action(hreset_action
, std::vector
<interface_action_paramval
>());
499 command::fnptr
<command::arg_filename
> CMD_load_c(lsnes_cmds
, CLOADSAVE::ld
,
500 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
501 mark_pending_load(args
, LOAD_STATE_CURRENT
);
504 command::fnptr
<command::arg_filename
> CMD_load_smart_c(lsnes_cmds
, CLOADSAVE::ldsm
,
505 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
506 mark_pending_load(args
, LOAD_STATE_DEFAULT
);
509 command::fnptr
<command::arg_filename
> CMD_load_state_c(lsnes_cmds
, CLOADSAVE::ldrw
,
510 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
511 mark_pending_load(args
, LOAD_STATE_RW
);
514 command::fnptr
<command::arg_filename
> CMD_load_readonly(lsnes_cmds
, CLOADSAVE::ldro
,
515 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
516 mark_pending_load(args
, LOAD_STATE_RO
);
519 command::fnptr
<command::arg_filename
> CMD_load_preserve(lsnes_cmds
, CLOADSAVE::ldp
,
520 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
521 mark_pending_load(args
, LOAD_STATE_PRESERVE
);
524 command::fnptr
<command::arg_filename
> CMD_load_movie_c(lsnes_cmds
, CLOADSAVE::ldm
,
525 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
526 mark_pending_load(args
, LOAD_STATE_MOVIE
);
529 command::fnptr
<command::arg_filename
> CMD_load_allbr_c(lsnes_cmds
, CLOADSAVE::ldab
,
530 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
531 mark_pending_load(args
, LOAD_STATE_ALLBRANCH
);
534 command::fnptr
<command::arg_filename
> CMD_save_state(lsnes_cmds
, CLOADSAVE::sa
,
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_state2(lsnes_cmds
, CLOADSAVE::sasb
,
540 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
541 mark_pending_save(args
, SAVE_STATE
, 1);
544 command::fnptr
<command::arg_filename
> CMD_save_state3(lsnes_cmds
, CLOADSAVE::sasz
,
545 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
546 mark_pending_save(args
, SAVE_STATE
, 0);
549 command::fnptr
<command::arg_filename
> CMD_save_movie(lsnes_cmds
, CLOADSAVE::sam
,
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_movie2(lsnes_cmds
, CLOADSAVE::samb
,
555 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
556 mark_pending_save(args
, SAVE_MOVIE
, 1);
559 command::fnptr
<command::arg_filename
> CMD_save_movie3(lsnes_cmds
, CLOADSAVE::samz
,
560 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
561 mark_pending_save(args
, SAVE_MOVIE
, 0);
564 command::fnptr
<command::arg_filename
> CMD_load_rom(lsnes_cmds
, CLOADSAVE::lrom
,
565 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
571 command::fnptr
<> CMD_reload_rom(lsnes_cmds
, CLOADSAVE::rlrom
,
572 []() throw(std::bad_alloc
, std::runtime_error
) {
573 reload_current_rom();
576 command::fnptr
<> CMD_close_rom(lsnes_cmds
, CLOADSAVE::clrom
,
577 []() throw(std::bad_alloc
, std::runtime_error
) {
581 command::fnptr
<> CMD_set_rwmode(lsnes_cmds
, "set-rwmode", "Switch to recording mode",
582 "Syntax: set-rwmode\nSwitches to recording mode\n",
583 []() throw(std::bad_alloc
, std::runtime_error
) {
585 core
.lua2
->callback_movie_lost("readwrite");
586 core
.mlogic
->get_movie().readonly_mode(false);
587 core
.dispatch
->mode_change(false);
588 core
.lua2
->callback_do_readwrite();
589 core
.supdater
->update();
592 command::fnptr
<> CMD_set_romode(lsnes_cmds
, "set-romode", "Switch to playback mode",
593 "Syntax: set-romode\nSwitches to playback mode\n",
594 []() throw(std::bad_alloc
, std::runtime_error
) {
596 core
.mlogic
->get_movie().readonly_mode(true);
597 core
.dispatch
->mode_change(true);
598 core
.supdater
->update();
601 command::fnptr
<> CMD_toggle_rwmode(lsnes_cmds
, "toggle-rwmode", "Toggle recording mode",
602 "Syntax: toggle-rwmode\nToggles recording mode\n",
603 []() throw(std::bad_alloc
, std::runtime_error
) {
605 bool c
= core
.mlogic
->get_movie().readonly_mode();
607 core
.lua2
->callback_movie_lost("readwrite");
608 core
.mlogic
->get_movie().readonly_mode(!c
);
609 core
.dispatch
->mode_change(!c
);
611 core
.lua2
->callback_do_readwrite();
612 core
.supdater
->update();
615 command::fnptr
<> CMD_repaint(lsnes_cmds
, "repaint", "Redraw the screen",
616 "Syntax: repaint\nRedraws the screen\n",
617 []() throw(std::bad_alloc
, std::runtime_error
) {
618 CORE().fbuf
->redraw_framebuffer();
621 command::fnptr
<> CMD_tpon(lsnes_cmds
, "toggle-pause-on-end", "Toggle pause on end", "Toggle pause on end\n",
622 []() throw(std::bad_alloc
, std::runtime_error
) {
624 bool tmp
= SET_pause_on_end(*core
.settings
);
625 SET_pause_on_end(*core
.settings
, !tmp
);
626 messages
<< "Pause-on-end is now " << (tmp
? "OFF" : "ON") << std::endl
;
629 command::fnptr
<> CMD_spon(lsnes_cmds
, "set-pause-on-end", "Set pause on end", "Set pause on end\n",
630 []() throw(std::bad_alloc
, std::runtime_error
) {
631 SET_pause_on_end(*CORE().settings
, true);
632 messages
<< "Pause-on-end is now ON" << std::endl
;
635 command::fnptr
<> CMD_cpon(lsnes_cmds
, "clear-pause-on-end", "Clear pause on end", "Clear pause on end\n",
636 []() throw(std::bad_alloc
, std::runtime_error
) {
637 SET_pause_on_end(*CORE().settings
, false);
638 messages
<< "Pause-on-end is now OFF" << std::endl
;
641 command::fnptr
<> CMD_rewind_movie(lsnes_cmds
, CLOADSAVE::rewind
,
642 []() throw(std::bad_alloc
, std::runtime_error
) {
643 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_BEGINNING
);
646 command::fnptr
<> CMD_cancel_save(lsnes_cmds
, CLOADSAVE::cancel
,
647 []() throw(std::bad_alloc
, std::runtime_error
) {
648 queued_saves
.clear();
649 messages
<< "Pending saves canceled." << std::endl
;
652 command::fnptr
<> CMD_mhold1(lsnes_cmds
, CMHOLD::p
, []() throw(std::bad_alloc
, std::runtime_error
) {
656 command::fnptr
<> CMD_mhold2(lsnes_cmds
, CMHOLD::r
, []() throw(std::bad_alloc
, std::runtime_error
) {
657 macro_hold_1
= false;
660 command::fnptr
<> CMD_mhold3(lsnes_cmds
, CMHOLD::t
, []() throw(std::bad_alloc
, std::runtime_error
) {
661 macro_hold_2
= !macro_hold_2
;
663 messages
<< "Macros are held for next frame." << std::endl
;
665 messages
<< "Macros are not held for next frame." << std::endl
;
668 keyboard::invbind_info
IBIND_ipause_emulator(lsnes_invbinds
, "pause-emulator", "Speed‣(Un)pause");
669 keyboard::invbind_info
IBIND_iadvframe(lsnes_invbinds
, "+advance-frame", "Speed‣Advance frame");
670 keyboard::invbind_info
IBIND_iadvsubframe(lsnes_invbinds
, "+advance-poll", "Speed‣Advance subframe");
671 keyboard::invbind_info
IBIND_iskiplag(lsnes_invbinds
, "advance-skiplag", "Speed‣Advance poll");
672 keyboard::invbind_info
IBIND_ireset(lsnes_invbinds
, "reset", "System‣Reset");
673 keyboard::invbind_info
IBIND_iset_rwmode(lsnes_invbinds
, "set-rwmode", "Movie‣Switch to recording");
674 keyboard::invbind_info
IBIND_itoggle_romode(lsnes_invbinds
, "set-romode", "Movie‣Switch to playback");
675 keyboard::invbind_info
IBIND_itoggle_rwmode(lsnes_invbinds
, "toggle-rwmode", "Movie‣Toggle playback");
676 keyboard::invbind_info
IBIND_irepaint(lsnes_invbinds
, "repaint", "System‣Repaint screen");
677 keyboard::invbind_info
IBIND_itogglepause(lsnes_invbinds
, "toggle-pause-on-end", "Movie‣Toggle pause-on-end");
679 class mywindowcallbacks
: public master_dumper::notifier
682 mywindowcallbacks(emulator_dispatch
& dispatch
, emulator_runmode
& runmode
, status_updater
& _supdater
)
683 : supdater(_supdater
)
685 closenotify
.set(dispatch
.close
, [this, &runmode
]() {
688 platform::set_paused(false);
689 platform::cancel_wait();
694 ~mywindowcallbacks() throw() {}
695 void dump_status_change() throw()
700 struct dispatch::target
<> closenotify
;
701 status_updater
& supdater
;
704 //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
709 std::string old_project
= *core
.mlogic
? core
.mlogic
->get_mfile().projectid
: "";
711 if(do_unsafe_rewind
&& unsafe_rewind_obj
) {
714 uint64_t t
= framerate_regulator::get_utime();
715 core
.lua2
->callback_do_unsafe_rewind(core
.mlogic
->get_movie(), unsafe_rewind_obj
);
716 core
.dispatch
->mode_change(false);
717 do_unsafe_rewind
= false;
718 core
.runmode
->set_point(emulator_runmode::P_SAVE
);
719 core
.supdater
->update();
720 core
.runmode
->end_load(); //Restore previous mode.
721 messages
<< "Rewind done in " << (framerate_regulator::get_utime() - t
) << " usec."
725 if(pending_new_project
!= "") {
726 std::string id
= pending_new_project
;
727 pending_new_project
= "";
728 project_info
* old
= core
.project
->get();
729 if(old
&& old
->id
== id
)
732 auto& p
= core
.project
->load(id
);
733 core
.project
->set(&p
);
734 if(core
.project
->get() != old
)
736 core
.slotcache
->flush(); //Wrong movie may be stale.
737 core
.runmode
->end_load(); //Restore previous mode.
738 if(core
.mlogic
->get_mfile().dyn
.save_frame
)
739 core
.runmode
->set_point(emulator_runmode::P_SAVE
);
740 core
.supdater
->update();
742 } catch(std::exception
& e
) {
743 platform::error_message(std::string("Can't switch projects: ") + e
.what());
744 messages
<< "Can't switch projects: " << e
.what() << std::endl
;
748 core
.runmode
->end_load();
749 platform::set_paused(core
.runmode
->is_paused());
750 platform::flush_command_queue();
751 if(core
.runmode
->is_load())
755 if(pending_load
!= "") {
757 if(loadmode
!= LOAD_STATE_BEGINNING
&& loadmode
!= LOAD_STATE_ROMRELOAD
&&
758 !do_load_state(pending_load
, loadmode
)) {
759 core
.runmode
->end_load();
763 if(loadmode
== LOAD_STATE_BEGINNING
)
765 if(loadmode
== LOAD_STATE_ROMRELOAD
)
767 core
.runmode
->clear_corrupt();
768 } catch(std::exception
& e
) {
769 core
.runmode
->set_corrupt();
770 platform::error_message(std::string("Load failed: ") + e
.what());
771 messages
<< "Load failed: " << e
.what() << std::endl
;
774 if(!core
.runmode
->is_corrupt()) {
775 core
.runmode
->end_load();
776 core
.runmode
->set_point(emulator_runmode::P_SAVE
);
777 core
.supdater
->update();
778 platform::flush_command_queue();
779 if(core
.runmode
->is_quit())
781 if(core
.runmode
->is_load())
784 if(old_project
!= (*core
.mlogic
? core
.mlogic
->get_mfile().projectid
: ""))
785 core
.slotcache
->flush(); //Wrong movie may be stale.
791 //If there are pending saves, perform them.
797 if(!queued_saves
.empty() || (do_unsafe_rewind
&& !unsafe_rewind_obj
)) {
798 core
.rom
->runtosave();
799 for(auto i
: queued_saves
) {
800 do_save_state(i
.first
, i
.second
);
802 core
.slotcache
->flush(translate_name_mprefix(i
.first
, tmp
, -1));
804 if(do_unsafe_rewind
&& !unsafe_rewind_obj
) {
805 uint64_t t
= framerate_regulator::get_utime();
806 core
.mlogic
->get_mfile().dyn
.savestate
= core
.rom
->save_core_state(true);
807 core
.lua2
->callback_do_unsafe_rewind(core
.mlogic
->get_movie(), NULL
);
808 do_unsafe_rewind
= false;
809 messages
<< "Rewind point set in " << (framerate_regulator::get_utime() - t
)
810 << " usec." << std::endl
;
813 queued_saves
.clear();
816 bool handle_corrupt()
819 if(!core
.runmode
->is_corrupt())
821 while(core
.runmode
->is_corrupt()) {
822 platform::set_paused(true);
823 platform::flush_command_queue();
825 if(core
.runmode
->is_quit())
832 void init_main_callbacks()
834 ecore_callbacks
= &lsnes_callbacks_obj
;
837 void main_loop(struct loaded_rom
& rom
, struct moviefile
& initial
, bool load_has_to_succeed
) throw(std::bad_alloc
,
840 lsnes_instance
.emu_thread
= threads::id();
842 mywindowcallbacks
mywcb(*core
.dispatch
, *core
.runmode
, *core
.supdater
);
843 core
.iqueue
->system_thread_available
= true;
844 //Basic initialization.
845 core
.commentary
->init();
846 core
.fbuf
->init_special_screens();
847 core
.jukebox
->set_update([&core
]() { core
.supdater
->update(); });
849 init_main_callbacks();
850 initialize_all_builtin_c_cores();
851 core_core::install_all_handlers();
853 //Load our given movie.
854 bool first_round
= false;
855 bool just_did_loadstate
= false;
858 do_load_state(initial
, LOAD_STATE_INITIAL
, used
);
859 core
.runmode
->set_point(emulator_runmode::P_SAVE
);
860 core
.supdater
->update();
861 first_round
= core
.mlogic
->get_mfile().dyn
.save_frame
;
862 just_did_loadstate
= first_round
;
863 } catch(std::bad_alloc
& e
) {
865 } catch(std::exception
& e
) {
868 platform::error_message(std::string("Can't load initial state: ") + e
.what());
869 messages
<< "ERROR: Can't load initial state: " << e
.what() << std::endl
;
870 if(load_has_to_succeed
) {
871 messages
<< "FATAL: Can't load movie" << std::endl
;
874 core
.runmode
->set_corrupt();
875 core
.fbuf
->redraw_framebuffer(emu_framebuffer::screen_corrupt
);
878 core
.runmode
->set_pause_cond(initial
.start_paused
);
879 platform::set_paused(core
.runmode
->is_paused());
880 stop_at_frame_active
= false;
882 core
.lua2
->run_startup_scripts();
884 while(!core
.runmode
->is_quit() || !queued_saves
.empty()) {
885 if(handle_corrupt()) {
886 first_round
= *core
.mlogic
&& core
.mlogic
->get_mfile().dyn
.save_frame
;
887 just_did_loadstate
= first_round
;
890 core
.framerate
->ack_frame_tick(framerate_regulator::get_utime());
891 core
.runmode
->decay_skiplag();
894 core
.controls
->reset_framehold();
895 if(!macro_hold_1
&& !macro_hold_2
) {
896 core
.controls
->advance_macros();
898 macro_hold_2
= false;
899 core
.mlogic
->get_movie().get_pollcounters().set_framepflag(false);
900 core
.mlogic
->new_frame_starting(core
.runmode
->is_skiplag());
901 core
.mlogic
->get_movie().get_pollcounters().set_framepflag(true);
902 if(core
.runmode
->is_quit() && queued_saves
.empty())
906 if(queued_saves
.empty())
908 if(r
> 0 || core
.runmode
->is_corrupt()) {
909 core
.mlogic
->get_movie().get_pollcounters().set_framepflag(
910 core
.mlogic
->get_mfile().dyn
.save_frame
!= 0);
911 first_round
= core
.mlogic
->get_mfile().dyn
.save_frame
;
912 stop_at_frame_active
= false;
913 just_did_loadstate
= first_round
;
914 core
.controls
->reset_framehold();
915 core
.dbg
->do_callback_frame(core
.mlogic
->get_movie().get_current_frame(), true);
918 //Not exactly desriable, but this at least won't desync.
919 stop_at_frame_active
= false;
920 if(core
.runmode
->is_quit())
922 core
.runmode
->set_pause();
925 if(just_did_loadstate
) {
926 //If we just loadstated, we are up to date.
927 if(core
.runmode
->is_quit())
929 platform::set_paused(core
.runmode
->is_paused());
930 platform::flush_command_queue();
931 //We already have done the reset this frame if we are going to do one at all.
932 core
.mlogic
->get_movie().set_controls(core
.mlogic
->update_controls(true));
933 core
.mlogic
->get_movie().set_all_DRDY();
934 just_did_loadstate
= false;
936 core
.dbg
->do_callback_frame(core
.mlogic
->get_movie().get_current_frame(), false);
938 random_mix_timing_entropy();
939 if(core
.runmode
->is_freerunning())
940 platform::wait(core
.framerate
->to_wait_frame(framerate_regulator::get_utime()));
942 core
.lua2
->callback_do_frame();
945 core
.jukebox
->unset_update();
946 core
.mdumper
->end_dumps();
947 core_core::uninstall_all_handlers();
948 core
.commentary
->kill();
949 core
.iqueue
->system_thread_available
= false;
950 //Kill some things to avoid crashes.
951 core
.dbg
->core_change();
952 core
.project
->set(NULL
, true);
953 core
.mwatch
->clear_multi(core
.mwatch
->enumerate());
959 void set_stop_at_frame(uint64_t frame
)
962 stop_at_frame
= frame
;
963 stop_at_frame_active
= (frame
!= 0);
964 if(!core
.runmode
->is_special())
965 core
.runmode
->set_freerunning();
966 platform::set_paused(false);
969 void do_flush_slotinfo()
971 CORE().slotcache
->flush();
974 void switch_projects(const std::string
& newproj
)
976 pending_new_project
= newproj
;
977 CORE().runmode
->start_load();
978 platform::cancel_wait();
979 platform::set_paused(false);
982 void load_new_rom(const romload_request
& req
)
984 if(_load_new_rom(req
)) {
985 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
989 void reload_current_rom()
991 if(reload_active_rom()) {
992 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
998 if(load_null_rom()) {
999 CORE().runmode
->set_pause();
1000 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
1004 void do_break_pause()
1006 auto& core
= CORE();
1007 core
.runmode
->set_break();
1008 core
.supdater
->update();
1009 core
.fbuf
->redraw_framebuffer();
1010 while(core
.runmode
->is_paused_break()) {
1011 platform::set_paused(true);
1012 platform::flush_command_queue();
1016 void convert_break_to_pause()
1018 auto& core
= CORE();
1019 if(core
.runmode
->is_paused_break()) {
1020 core
.runmode
->set_pause();
1021 core
.supdater
->update();