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 "core/multitrack.hpp"
10 #include "lua/lua.hpp"
11 #include "library/string.hpp"
12 #include "core/mainloop.hpp"
13 #include "core/movie.hpp"
14 #include "core/moviedata.hpp"
15 #include "core/moviefile.hpp"
16 #include "core/memorymanip.hpp"
17 #include "core/memorywatch.hpp"
18 #include "core/project.hpp"
19 #include "core/rom.hpp"
20 #include "core/romloader.hpp"
21 #include "core/rrdata.hpp"
22 #include "core/settings.hpp"
23 #include "core/window.hpp"
24 #include "interface/callbacks.hpp"
25 #include "interface/romtype.hpp"
26 #include "library/framebuffer.hpp"
27 #include "library/pixfmt-lrgb.hpp"
28 #include "library/zip.hpp"
38 #define SPECIAL_FRAME_START 0
39 #define SPECIAL_FRAME_VIDEO 1
40 #define SPECIAL_SAVEPOINT 2
41 #define SPECIAL_NONE 3
43 void update_movie_state();
44 time_t random_seed_value
= 0;
46 setting_var
<setting_var_model_bool
<setting_yes_no
>> jukebox_dflt_binary(lsnes_vset
, "jukebox-default-binary",
47 "Movie‣Saving‣Saveslots binary", true);
48 setting_var
<setting_var_model_bool
<setting_yes_no
>> movie_dflt_binary(lsnes_vset
, "movie-default-binary",
49 "Movie‣Saving‣Movies binary", false);
50 setting_var
<setting_var_model_bool
<setting_yes_no
>> save_dflt_binary(lsnes_vset
, "savestate-default-binary",
51 "Movie‣Saving‣Savestates binary", false);
55 setting_var
<setting_var_model_int
<0,999999>> advance_timeout_first(lsnes_vset
, "advance-timeout",
56 "Delays‣First frame advance", 500);
57 setting_var
<setting_var_model_int
<0,999999>> advance_timeout_subframe(lsnes_vset
, "advance-subframe-timeout",
58 "Delays‣Subframe advance", 100);
59 setting_var
<setting_var_model_bool
<setting_yes_no
>> pause_on_end(lsnes_vset
, "pause-on-end",
60 "Movie‣Pause on end", false);
61 setting_var
<setting_var_model_int
<0,999999999>> jukebox_size(lsnes_vset
, "jukebox-size",
62 "Movie‣Number of save slots", 12);
66 ADVANCE_QUIT
, //Quit the emulator.
67 ADVANCE_AUTO
, //Normal (possibly slowed down play).
68 ADVANCE_LOAD
, //Loading a state.
69 ADVANCE_FRAME
, //Frame advance.
70 ADVANCE_SUBFRAME
, //Subframe advance.
71 ADVANCE_SKIPLAG
, //Skip lag (oneshot, reverts to normal).
72 ADVANCE_SKIPLAG_PENDING
, //Activate skip lag mode at next frame.
73 ADVANCE_PAUSE
, //Unconditional pause.
77 threadid_class emulation_thread
;
78 //Flags related to repeating advance.
81 //Emulator advance mode. Detemines pauses at start of frame / subframe, etc..
82 enum advance_mode amode
;
83 //Mode and filename of pending load, one of LOAD_* constants.
86 std::string pending_load
;
87 std::string pending_new_project
;
88 //Queued saves (all savestates).
89 std::set
<std::pair
<std::string
, int>> queued_saves
;
91 size_t save_jukebox_pointer
;
92 //Special subframe location. One of SPECIAL_* constants.
95 bool last_hires
= false;
96 bool last_interlace
= false;
98 bool do_unsafe_rewind
= false;
99 void* unsafe_rewind_obj
= NULL
;
101 bool stop_at_frame_active
= false;
102 uint64_t stop_at_frame
= 0;
107 enum advance_mode old_mode
;
109 std::string
save_jukebox_name(size_t i
)
111 return (stringfmt() << "${project}" << (i
+ 1) << ".lsmv").str();
114 std::map
<std::string
, std::string
> slotinfo_cache
;
116 std::string
vector_to_string(const std::vector
<char>& x
)
118 std::string
y(x
.begin(), x
.end());
119 while(y
.length() > 0 && y
[y
.length() - 1] < 32)
120 y
= y
.substr(0, y
.length() - 1);
124 std::string
get_slotinfo(const std::string
& _filename
)
126 std::string filename
= resolve_relative_path(_filename
);
127 if(!slotinfo_cache
.count(filename
)) {
128 std::ostringstream out
;
130 moviefile::brief_info
info(filename
);
131 if(our_movie
.projectid
== info
.projectid
)
132 out
<< info
.rerecords
<< "R/" << info
.current_frame
<< "F";
134 out
<< "Wrong movie";
136 out
<< "Nonexistent";
138 slotinfo_cache
[filename
] = out
.str();
140 return slotinfo_cache
[filename
];
143 void flush_slotinfo(const std::string
& filename
)
145 slotinfo_cache
.erase(resolve_relative_path(filename
));
148 void flush_slotinfo()
150 slotinfo_cache
.clear();
153 class _lsnes_pflag_handler
: public movie::poll_flag
156 ~_lsnes_pflag_handler()
161 return our_rom
.rtype
->get_pflag();
163 void set_pflag(int flag
)
165 our_rom
.rtype
->set_pflag(flag
);
167 } lsnes_pflag_handler
;
170 void mainloop_signal_need_rewind(void* ptr
)
174 amode
= ADVANCE_LOAD
;
176 do_unsafe_rewind
= true;
177 unsafe_rewind_obj
= ptr
;
180 controller_frame
movie_logic::update_controls(bool subframe
) throw(std::bad_alloc
, std::runtime_error
)
182 if(lua_requests_subframe_paint
)
183 redraw_framebuffer();
186 if(amode
== ADVANCE_SUBFRAME
) {
187 if(!cancel_advance
) {
189 platform::wait(advance_timeout_first
* 1000);
191 platform::wait(advance_timeout_subframe
* 1000);
192 advanced_once
= true;
195 stop_at_frame_active
= false;
196 amode
= ADVANCE_PAUSE
;
197 cancel_advance
= false;
199 platform::set_paused(amode
== ADVANCE_PAUSE
);
200 } else if(amode
== ADVANCE_FRAME
) {
203 if(amode
== ADVANCE_SKIPLAG
) {
204 stop_at_frame_active
= false;
205 amode
= ADVANCE_PAUSE
;
207 platform::set_paused(amode
== ADVANCE_PAUSE
);
208 cancel_advance
= false;
210 location_special
= SPECIAL_NONE
;
211 update_movie_state();
213 if(amode
== ADVANCE_SKIPLAG_PENDING
)
214 amode
= ADVANCE_SKIPLAG
;
215 if(amode
== ADVANCE_FRAME
|| amode
== ADVANCE_SUBFRAME
) {
216 if(!cancel_advance
) {
219 wait
= advance_timeout_first
* 1000;
220 else if(amode
== ADVANCE_SUBFRAME
)
221 wait
= advance_timeout_subframe
* 1000;
223 wait
= to_wait_frame(get_utime());
224 platform::wait(wait
);
225 advanced_once
= true;
228 stop_at_frame_active
= false;
229 amode
= ADVANCE_PAUSE
;
230 cancel_advance
= false;
232 platform::set_paused(amode
== ADVANCE_PAUSE
);
233 } else if(amode
== ADVANCE_AUTO
&& movb
.get_movie().readonly_mode() && pause_on_end
&&
234 !stop_at_frame_active
) {
235 if(movb
.get_movie().get_current_frame() == movb
.get_movie().get_frame_count()) {
236 stop_at_frame_active
= false;
237 amode
= ADVANCE_PAUSE
;
238 platform::set_paused(true);
240 } else if(amode
== ADVANCE_AUTO
&& stop_at_frame_active
) {
241 if(movb
.get_movie().get_current_frame() >= stop_at_frame
) {
242 stop_at_frame_active
= false;
243 amode
= ADVANCE_PAUSE
;
244 platform::set_paused(true);
247 platform::set_paused((amode
== ADVANCE_PAUSE
));
248 cancel_advance
= false;
250 location_special
= SPECIAL_FRAME_START
;
251 update_movie_state();
253 platform::flush_command_queue();
254 controller_frame tmp
= controls
.get(movb
.get_movie().get_current_frame());
255 our_rom
.rtype
->pre_emulate_frame(tmp
); //Preset controls, the lua will override if needed.
256 lua_callback_do_input(tmp
, subframe
);
257 multitrack_editor
.process_frame(tmp
);
258 controls
.commit(tmp
);
265 //Do pending load (automatically unpauses).
266 void mark_pending_load(const std::string
& filename
, int lmode
)
269 pending_load
= filename
;
271 amode
= ADVANCE_LOAD
;
272 platform::cancel_wait();
273 platform::set_paused(false);
276 void mark_pending_save(const std::string
& filename
, int smode
, int binary
)
279 if(smode
== SAVE_MOVIE
) {
280 //Just do this immediately.
281 do_save_movie(filename
, binary
);
282 flush_slotinfo(translate_name_mprefix(filename
, tmp
, false));
285 if(location_special
== SPECIAL_SAVEPOINT
) {
286 //We can save immediately here.
287 do_save_state(filename
, binary
);
288 flush_slotinfo(translate_name_mprefix(filename
, tmp
, false));
291 queued_saves
.insert(std::make_pair(filename
, binary
));
292 messages
<< "Pending save on '" << filename
<< "'" << std::endl
;
295 struct jukebox_size_listener
: public setting_var_listener
297 jukebox_size_listener() { lsnes_vset
.add_listener(*this); }
298 ~jukebox_size_listener() throw() {lsnes_vset
.remove_listener(*this); };
299 void on_setting_change(setting_var_group
& grp
, const setting_var_base
& val
)
301 if(val
.get_iname() == "jukebox-size") {
302 if(save_jukebox_pointer
>= jukebox_size
)
303 save_jukebox_pointer
= 0;
305 update_movie_state();
310 void update_movie_state()
312 bool readonly
= false;
313 static unsigned last_controllers
= 0;
316 our_rom
.region
->fill_framerate_magic(magic
);
317 voice_frame_number(movb
.get_movie().get_current_frame(), 1.0 * magic
[1] / magic
[0]);
319 auto& _status
= platform::get_emustatus();
320 if(!system_corrupt
) {
321 _status
.set("!frame", (stringfmt() << movb
.get_movie().get_current_frame()).str());
322 _status
.set("!length", (stringfmt() << movb
.get_movie().get_frame_count()).str());
323 _status
.set("!lag", (stringfmt() << movb
.get_movie().get_lag_frames()).str());
324 if(location_special
== SPECIAL_FRAME_START
)
325 _status
.set("!subframe", "0");
326 else if(location_special
== SPECIAL_SAVEPOINT
)
327 _status
.set("!subframe", "S");
328 else if(location_special
== SPECIAL_FRAME_VIDEO
)
329 _status
.set("!subframe", "V");
331 _status
.set("!subframe", (stringfmt() << movb
.get_movie().next_poll_number()).str());
333 _status
.set("!frame", "N/A");
334 _status
.set("!length", "N/A");
335 _status
.set("!lag", "N/A");
336 _status
.set("!subframe", "N/A");
339 _status
.set("!dumping", (information_dispatch::get_dumper_count() ? "Y" : ""));
340 auto& mo
= movb
.get_movie();
341 readonly
= mo
.readonly_mode();
343 _status
.set("!mode", "C");
345 _status
.set("!mode", "R");
346 else if(mo
.get_frame_count() >= mo
.get_current_frame())
347 _status
.set("!mode", "P");
349 _status
.set("!mode", "F");
351 if(jukebox_size
> 0) {
353 std::string sfilen
= translate_name_mprefix(save_jukebox_name(save_jukebox_pointer
), tmp
, false);
354 _status
.set("!saveslot", (stringfmt() << (save_jukebox_pointer
+ 1)).str());
355 _status
.set("!saveslotinfo", get_slotinfo(sfilen
));
357 _status
.erase("!saveslot");
358 _status
.erase("!saveslotinfo");
360 _status
.set("!speed", (stringfmt() << (unsigned)(100 * get_realized_multiplier() + 0.5)).str());
362 if(!system_corrupt
) {
363 time_t timevalue
= static_cast<time_t>(our_movie
.rtc_second
);
364 struct tm
* time_decompose
= gmtime(&timevalue
);
365 char datebuffer
[512];
366 strftime(datebuffer
, 511, "%Y%m%d(%a)T%H%M%S", time_decompose
);
367 _status
.set("RTC", datebuffer
);
369 _status
.set("RTC", "N/A");
372 auto mset
= controls
.active_macro_set();
374 std::ostringstream mss
;
376 if(!mfirst
) mss
<< ",";
380 _status
.set("!macros", mss
.str());
385 if(!multitrack_editor
.any_records())
386 c
= movb
.get_movie().get_controls();
388 c
= controls
.get_committed();
389 for(unsigned i
= 0;; i
++) {
390 auto pindex
= controls
.lcid_to_pcid(i
);
391 if(pindex
.first
< 0 || !controls
.is_present(pindex
.first
, pindex
.second
)) {
392 for(unsigned j
= i
; j
< last_controllers
; j
++)
393 _status
.erase((stringfmt() << "P" << (j
+ 1)).str());
394 last_controllers
= i
;
397 char32_t buffer
[MAX_DISPLAY_LENGTH
];
398 c
.display(pindex
.first
, pindex
.second
, buffer
);
399 std::u32string _buffer
= buffer
;
400 if(readonly
&& multitrack_editor
.is_enabled()) {
401 multitrack_edit::state st
= multitrack_editor
.get(pindex
.first
, pindex
.second
);
402 if(st
== multitrack_edit::MT_PRESERVE
)
403 _buffer
+= U
" (keep)";
404 else if(st
== multitrack_edit::MT_OVERWRITE
)
405 _buffer
+= U
" (rewrite)";
406 else if(st
== multitrack_edit::MT_OR
)
408 else if(st
== multitrack_edit::MT_XOR
)
409 _buffer
+= U
" (XOR)";
411 _buffer
+= U
" (\?\?\?)";
413 _status
.set((stringfmt() << "P" << (i
+ 1)).str(), _buffer
);
415 notify_status_update();
418 uint64_t audio_irq_time
;
419 uint64_t controller_irq_time
;
420 uint64_t frame_irq_time
;
423 struct lsnes_callbacks
: public emucore_callbacks
426 ~lsnes_callbacks() throw()
430 int16_t get_input(unsigned port
, unsigned index
, unsigned control
)
433 x
= movb
.input_poll(port
, index
, control
);
434 lua_callback_snoop_input(port
, index
, control
, x
);
438 int16_t set_input(unsigned port
, unsigned index
, unsigned control
, int16_t value
)
440 if(!movb
.get_movie().readonly_mode()) {
441 controller_frame f
= movb
.get_movie().get_controls();
442 f
.axis3(port
, index
, control
, value
);
443 movb
.get_movie().set_controls(f
);
445 return movb
.get_movie().next_input(port
, index
, control
);
448 void notify_latch(std::list
<std::string
>& args
)
450 lua_callback_do_latch(args
);
453 void timer_tick(uint32_t increment
, uint32_t per_second
)
455 our_movie
.rtc_subsecond
+= increment
;
456 while(our_movie
.rtc_subsecond
>= per_second
) {
457 our_movie
.rtc_second
++;
458 our_movie
.rtc_subsecond
-= per_second
;
462 std::string
get_firmware_path()
464 return lsnes_vset
["firmwarepath"].str();
467 std::string
get_base_path()
469 return our_rom
.msu1_base
;
474 return our_movie
.rtc_second
;
477 time_t get_randomseed()
479 return random_seed_value
;
482 void output_frame(framebuffer_raw
& screen
, uint32_t fps_n
, uint32_t fps_d
)
484 lua_callback_do_frame_emulated();
485 location_special
= SPECIAL_FRAME_VIDEO
;
486 update_movie_state();
487 redraw_framebuffer(screen
, false, true);
488 uint32_t g
= gcd(fps_n
, fps_d
);
491 information_dispatch::do_frame(screen
, fps_n
, fps_d
);
494 void action_state_updated()
496 graphics_driver_action_updated();
502 function_ptr_command
<const std::string
&> test4(lsnes_cmd
, "test4", "test", "test",
503 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
504 std::list
<std::string
> _args
;
505 std::string args2
= args
;
508 extract_token(args2
, sym
, " \t");
509 _args
.push_back(sym
);
511 lua_callback_do_latch(_args
);
513 function_ptr_command
<> count_rerecords(lsnes_cmd
, "count-rerecords", "Count rerecords",
514 "Syntax: count-rerecords\nCounts rerecords.\n",
515 []() throw(std::bad_alloc
, std::runtime_error
) {
516 std::vector
<char> tmp
;
517 uint64_t x
= rrdata
.write(tmp
);
518 messages
<< x
<< " rerecord(s)" << std::endl
;
521 function_ptr_command
<const std::string
&> quit_emulator(lsnes_cmd
, "quit-emulator", "Quit the emulator",
522 "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
523 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
524 amode
= ADVANCE_QUIT
;
525 platform::set_paused(false);
526 platform::cancel_wait();
529 function_ptr_command
<> unpause_emulator(lsnes_cmd
, "unpause-emulator", "Unpause the emulator",
530 "Syntax: unpause-emulator\nUnpauses the emulator.\n",
531 []() throw(std::bad_alloc
, std::runtime_error
) {
532 amode
= ADVANCE_AUTO
;
533 platform::set_paused(false);
534 platform::cancel_wait();
535 messages
<< "Unpaused" << std::endl
;
538 function_ptr_command
<> pause_emulator(lsnes_cmd
, "pause-emulator", "(Un)pause the emulator",
539 "Syntax: pause-emulator\n(Un)pauses the emulator.\n",
540 []() throw(std::bad_alloc
, std::runtime_error
) {
541 if(amode
!= ADVANCE_AUTO
) {
542 amode
= ADVANCE_AUTO
;
543 platform::set_paused(false);
544 platform::cancel_wait();
545 messages
<< "Unpaused" << std::endl
;
547 platform::cancel_wait();
548 cancel_advance
= false;
549 stop_at_frame_active
= false;
550 amode
= ADVANCE_PAUSE
;
551 messages
<< "Paused" << std::endl
;
555 function_ptr_command
<> save_jukebox_prev(lsnes_cmd
, "cycle-jukebox-backward", "Cycle save jukebox backwards",
556 "Syntax: cycle-jukebox-backward\nCycle save jukebox backwards\n",
557 []() throw(std::bad_alloc
, std::runtime_error
) {
558 if(jukebox_size
== 0)
560 if(save_jukebox_pointer
== 0)
561 save_jukebox_pointer
= jukebox_size
- 1;
563 save_jukebox_pointer
--;
564 if(save_jukebox_pointer
>= jukebox_size
)
565 save_jukebox_pointer
= 0;
566 update_movie_state();
569 function_ptr_command
<> save_jukebox_next(lsnes_cmd
, "cycle-jukebox-forward", "Cycle save jukebox forwards",
570 "Syntax: cycle-jukebox-forward\nCycle save jukebox forwards\n",
571 []() throw(std::bad_alloc
, std::runtime_error
) {
572 if(jukebox_size
== 0)
574 if(save_jukebox_pointer
>= jukebox_size
- 1)
575 save_jukebox_pointer
= 0;
577 save_jukebox_pointer
++;
578 if(save_jukebox_pointer
>= jukebox_size
)
579 save_jukebox_pointer
= 0;
580 update_movie_state();
583 function_ptr_command
<> load_jukebox(lsnes_cmd
, "load-jukebox", "Load save from jukebox",
584 "Syntax: load-jukebox\nLoad save from jukebox\n",
585 []() throw(std::bad_alloc
, std::runtime_error
) {
586 if(jukebox_size
== 0)
587 throw std::runtime_error("No slot selected");
588 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_CURRENT
);
591 function_ptr_command
<> load_jukebox_readwrite(lsnes_cmd
, "load-jukebox-readwrite", "Load save from jukebox in"
592 " read-write mode", "Syntax: load-jukebox-readwrite\nLoad save from jukebox in read-write mode\n",
593 []() throw(std::bad_alloc
, std::runtime_error
) {
594 if(jukebox_size
== 0)
595 throw std::runtime_error("No slot selected");
596 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_RW
);
599 function_ptr_command
<> load_jukebox_readonly(lsnes_cmd
, "load-jukebox-readonly", "Load save from jukebox in "
600 "read-only mode", "Syntax: load-jukebox-readonly\nLoad save from jukebox in read-only mode\n",
601 []() throw(std::bad_alloc
, std::runtime_error
) {
602 if(jukebox_size
== 0)
603 throw std::runtime_error("No slot selected");
604 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_RO
);
607 function_ptr_command
<> load_jukebox_preserve(lsnes_cmd
, "load-jukebox-preserve", "Load save from jukebox, "
608 "preserving input", "Syntax: load-jukebox-preserve\nLoad save from jukebox, preserving input\n",
609 []() throw(std::bad_alloc
, std::runtime_error
) {
610 if(jukebox_size
== 0)
611 throw std::runtime_error("No slot selected");
612 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_PRESERVE
);
615 function_ptr_command
<> load_jukebox_movie(lsnes_cmd
, "load-jukebox-movie", "Load save from jukebox as movie",
616 "Syntax: load-jukebox-movie\nLoad save from jukebox as movie\n",
617 []() throw(std::bad_alloc
, std::runtime_error
) {
618 if(jukebox_size
== 0)
619 throw std::runtime_error("No slot selected");
620 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_MOVIE
);
623 function_ptr_command
<> save_jukebox_c(lsnes_cmd
, "save-jukebox", "Save save to jukebox",
624 "Syntax: save-jukebox\nSave save to jukebox\n",
625 []() throw(std::bad_alloc
, std::runtime_error
) {
626 if(jukebox_size
== 0)
627 throw std::runtime_error("No slot selected");
628 mark_pending_save(save_jukebox_name(save_jukebox_pointer
), SAVE_STATE
, -1);
631 function_ptr_command
<> padvance_frame(lsnes_cmd
, "+advance-frame", "Advance one frame",
632 "Syntax: +advance-frame\nAdvances the emulation by one frame.\n",
633 []() throw(std::bad_alloc
, std::runtime_error
) {
634 amode
= ADVANCE_FRAME
;
635 cancel_advance
= false;
636 advanced_once
= false;
637 platform::cancel_wait();
638 platform::set_paused(false);
641 function_ptr_command
<> nadvance_frame(lsnes_cmd
, "-advance-frame", "Advance one frame",
642 "No help available\n",
643 []() throw(std::bad_alloc
, std::runtime_error
) {
644 cancel_advance
= true;
645 platform::cancel_wait();
646 platform::set_paused(false);
649 function_ptr_command
<> padvance_poll(lsnes_cmd
, "+advance-poll", "Advance one subframe",
650 "Syntax: +advance-poll\nAdvances the emulation by one subframe.\n",
651 []() throw(std::bad_alloc
, std::runtime_error
) {
652 amode
= ADVANCE_SUBFRAME
;
653 cancel_advance
= false;
654 advanced_once
= false;
655 platform::cancel_wait();
656 platform::set_paused(false);
659 function_ptr_command
<> nadvance_poll(lsnes_cmd
, "-advance-poll", "Advance one subframe",
660 "No help available\n",
661 []() throw(std::bad_alloc
, std::runtime_error
) {
662 cancel_advance
= true;
663 platform::cancel_wait();
664 platform::set_paused(false);
667 function_ptr_command
<> advance_skiplag(lsnes_cmd
, "advance-skiplag", "Skip to next poll",
668 "Syntax: advance-skiplag\nAdvances the emulation to the next poll.\n",
669 []() throw(std::bad_alloc
, std::runtime_error
) {
670 amode
= ADVANCE_SKIPLAG_PENDING
;
671 platform::cancel_wait();
672 platform::set_paused(false);
675 function_ptr_command
<> reset_c(lsnes_cmd
, "reset", "Reset the system",
676 "Syntax: reset\nReset\nResets the system in beginning of the next frame.\n",
677 []() throw(std::bad_alloc
, std::runtime_error
) {
678 int sreset_action
= our_rom
.rtype
->reset_action(false);
679 if(sreset_action
< 0) {
680 platform::error_message("Core does not support resets");
681 messages
<< "Emulator core does not support resets" << std::endl
;
684 our_rom
.rtype
->execute_action(sreset_action
, std::vector
<interface_action_paramval
>());
687 function_ptr_command
<> hreset_c(lsnes_cmd
, "reset-hard", "Reset the system",
688 "Syntax: reset-hard\nReset-hard\nHard resets the system in beginning of the next frame.\n",
689 []() throw(std::bad_alloc
, std::runtime_error
) {
690 int hreset_action
= our_rom
.rtype
->reset_action(true);
691 if(hreset_action
< 0) {
692 platform::error_message("Core does not support hard resets");
693 messages
<< "Emulator core does not support hard resets" << std::endl
;
696 our_rom
.rtype
->execute_action(hreset_action
, std::vector
<interface_action_paramval
>());
699 function_ptr_command
<arg_filename
> load_c(lsnes_cmd
, "load", "Load savestate (current mode)",
700 "Syntax: load <file>\nLoads SNES state from <file> in current mode\n",
701 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
702 mark_pending_load(args
, LOAD_STATE_CURRENT
);
705 function_ptr_command
<arg_filename
> load_smart_c(lsnes_cmd
, "load-smart", "Load savestate (heuristic mode)",
706 "Syntax: load <file>\nLoads SNES state from <file> in heuristic mode\n",
707 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
708 mark_pending_load(args
, LOAD_STATE_DEFAULT
);
711 function_ptr_command
<arg_filename
> load_state_c(lsnes_cmd
, "load-state", "Load savestate (R/W)",
712 "Syntax: load-state <file>\nLoads SNES state from <file> in Read/Write mode\n",
713 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
714 mark_pending_load(args
, LOAD_STATE_RW
);
717 function_ptr_command
<arg_filename
> load_readonly(lsnes_cmd
, "load-readonly", "Load savestate (RO)",
718 "Syntax: load-readonly <file>\nLoads SNES state from <file> in read-only mode\n",
719 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
720 mark_pending_load(args
, LOAD_STATE_RO
);
723 function_ptr_command
<arg_filename
> load_preserve(lsnes_cmd
, "load-preserve", "Load savestate (preserve "
724 "input)", "Syntax: load-preserve <file>\nLoads SNES state from <file> preserving input\n",
725 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
726 mark_pending_load(args
, LOAD_STATE_PRESERVE
);
729 function_ptr_command
<arg_filename
> load_movie_c(lsnes_cmd
, "load-movie", "Load movie",
730 "Syntax: load-movie <file>\nLoads SNES movie from <file>\n",
731 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
732 mark_pending_load(args
, LOAD_STATE_MOVIE
);
736 function_ptr_command
<arg_filename
> save_state(lsnes_cmd
, "save-state", "Save state",
737 "Syntax: save-state <file>\nSaves SNES state to <file>\n",
738 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
739 mark_pending_save(args
, SAVE_STATE
, -1);
742 function_ptr_command
<arg_filename
> save_state2(lsnes_cmd
, "save-state-binary", "Save state (binary)",
743 "Syntax: save-state-binary <file>\nSaves binary state to <file>\n",
744 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
745 mark_pending_save(args
, SAVE_STATE
, 1);
748 function_ptr_command
<arg_filename
> save_state3(lsnes_cmd
, "save-state-zip", "Save state (zip)",
749 "Syntax: save-state-zip <file>\nSaves zip state to <file>\n",
750 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
751 mark_pending_save(args
, SAVE_STATE
, 0);
754 function_ptr_command
<arg_filename
> save_movie(lsnes_cmd
, "save-movie", "Save movie",
755 "Syntax: save-movie <file>\nSaves SNES movie to <file>\n",
756 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
757 mark_pending_save(args
, SAVE_MOVIE
, -1);
760 function_ptr_command
<arg_filename
> save_movie2(lsnes_cmd
, "save-movie-binary", "Save movie (binary)",
761 "Syntax: save-movie-binary <file>\nSaves binary movie to <file>\n",
762 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
763 mark_pending_save(args
, SAVE_MOVIE
, 1);
766 function_ptr_command
<arg_filename
> save_movie3(lsnes_cmd
, "save-movie-zip", "Save movie (zip)",
767 "Syntax: save-movie-zip <file>\nSaves zip movie to <file>\n",
768 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
769 mark_pending_save(args
, SAVE_MOVIE
, 0);
772 function_ptr_command
<> set_rwmode(lsnes_cmd
, "set-rwmode", "Switch to read/write mode",
773 "Syntax: set-rwmode\nSwitches to read/write mode\n",
774 []() throw(std::bad_alloc
, std::runtime_error
) {
775 lua_callback_movie_lost("readwrite");
776 movb
.get_movie().readonly_mode(false);
777 notify_mode_change(false);
778 lua_callback_do_readwrite();
779 update_movie_state();
782 function_ptr_command
<> set_romode(lsnes_cmd
, "set-romode", "Switch to read-only mode",
783 "Syntax: set-romode\nSwitches to read-only mode\n",
784 []() throw(std::bad_alloc
, std::runtime_error
) {
785 movb
.get_movie().readonly_mode(true);
786 notify_mode_change(true);
787 update_movie_state();
790 function_ptr_command
<> toggle_rwmode(lsnes_cmd
, "toggle-rwmode", "Toggle read/write mode",
791 "Syntax: toggle-rwmode\nToggles read/write mode\n",
792 []() throw(std::bad_alloc
, std::runtime_error
) {
793 bool c
= movb
.get_movie().readonly_mode();
795 lua_callback_movie_lost("readwrite");
796 movb
.get_movie().readonly_mode(!c
);
797 notify_mode_change(!c
);
799 lua_callback_do_readwrite();
800 update_movie_state();
803 function_ptr_command
<> repaint(lsnes_cmd
, "repaint", "Redraw the screen",
804 "Syntax: repaint\nRedraws the screen\n",
805 []() throw(std::bad_alloc
, std::runtime_error
) {
806 redraw_framebuffer();
809 function_ptr_command
<> tpon(lsnes_cmd
, "toggle-pause-on-end", "Toggle pause on end", "Toggle pause on end\n",
810 []() throw(std::bad_alloc
, std::runtime_error
) {
811 bool tmp
= pause_on_end
;
812 pause_on_end
.set(!tmp
);
813 messages
<< "Pause-on-end is now " << (tmp
? "OFF" : "ON") << std::endl
;
816 function_ptr_command
<> spon(lsnes_cmd
, "set-pause-on-end", "Set pause on end", "Set pause on end\n",
817 []() throw(std::bad_alloc
, std::runtime_error
) {
818 pause_on_end
.set(true);
819 messages
<< "Pause-on-end is now ON" << std::endl
;
822 function_ptr_command
<> cpon(lsnes_cmd
, "clear-pause-on-end", "Clear pause on end", "Clear pause on end\n",
823 []() throw(std::bad_alloc
, std::runtime_error
) {
824 pause_on_end
.set(false);
825 messages
<< "Pause-on-end is now OFF" << std::endl
;
828 function_ptr_command
<> rewind_movie(lsnes_cmd
, "rewind-movie", "Rewind movie to the beginning",
829 "Syntax: rewind-movie\nRewind movie to the beginning\n",
830 []() throw(std::bad_alloc
, std::runtime_error
) {
831 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_BEGINNING
);
834 function_ptr_command
<> cancel_save(lsnes_cmd
, "cancel-saves", "Cancel all pending saves", "Syntax: "
835 "cancel-save\nCancel pending saves\n",
836 []() throw(std::bad_alloc
, std::runtime_error
) {
837 queued_saves
.clear();
838 messages
<< "Pending saves canceled." << std::endl
;
841 function_ptr_command
<> flushslots(lsnes_cmd
, "flush-slotinfo", "Flush slotinfo cache",
842 "Flush slotinfo cache\n",
843 []() throw(std::bad_alloc
, std::runtime_error
) {
847 function_ptr_command
<> mhold1(lsnes_cmd
, "+hold-macro", "Hold macro (hold)",
848 "Hold macros enable\n", []() throw(std::bad_alloc
, std::runtime_error
) {
852 function_ptr_command
<> mhold2(lsnes_cmd
, "-hold-macro", "Hold macro (hold)",
853 "Hold macros disable\n", []() throw(std::bad_alloc
, std::runtime_error
) {
854 macro_hold_1
= false;
857 function_ptr_command
<> mhold3(lsnes_cmd
, "hold-macro", "Hold macro (toggle)",
858 "Hold macros toggle\n", []() throw(std::bad_alloc
, std::runtime_error
) {
859 macro_hold_2
= !macro_hold_2
;
861 messages
<< "Macros are held for next frame." << std::endl
;
863 messages
<< "Macros are not held for next frame." << std::endl
;
866 inverse_bind
imhold1(lsnes_mapper
, "+hold-macro", "Macro‣Hold all macros");
867 inverse_bind
imhold2(lsnes_mapper
, "hold-macro", "Macro‣Hold all macros (typed)");
868 inverse_bind
ipause_emulator(lsnes_mapper
, "pause-emulator", "Speed‣(Un)pause");
869 inverse_bind
ijback(lsnes_mapper
, "cycle-jukebox-backward", "Slot select‣Cycle backwards");
870 inverse_bind
ijforward(lsnes_mapper
, "cycle-jukebox-forward", "Slot select‣Cycle forwards");
871 inverse_bind
iloadj(lsnes_mapper
, "load-jukebox", "Load‣Selected slot");
872 inverse_bind
iloadjrw(lsnes_mapper
, "load-jukebox-readwrite", "Load‣Selected slot (readwrite mode)");
873 inverse_bind
iloadjro(lsnes_mapper
, "load-jukebox-readonly", "Load‣Selected slot (readonly mode)");
874 inverse_bind
iloadjp(lsnes_mapper
, "load-jukebox-preserve", "Load‣Selected slot (preserve input)");
875 inverse_bind
iloadjm(lsnes_mapper
, "load-jukebox-movie", "Load‣Selected slot (as movie)");
876 inverse_bind
isavej(lsnes_mapper
, "save-jukebox", "Save‣Selected slot");
877 inverse_bind
iadvframe(lsnes_mapper
, "+advance-frame", "Speed‣Advance frame");
878 inverse_bind
iadvsubframe(lsnes_mapper
, "+advance-poll", "Speed‣Advance subframe");
879 inverse_bind
iskiplag(lsnes_mapper
, "advance-skiplag", "Speed‣Advance poll");
880 inverse_bind
ireset(lsnes_mapper
, "reset", "System‣Reset");
881 inverse_bind
iset_rwmode(lsnes_mapper
, "set-rwmode", "Movie‣Switch to read/write");
882 inverse_bind
itoggle_romode(lsnes_mapper
, "set-romode", "Movie‣Switch to read-only");
883 inverse_bind
itoggle_rwmode(lsnes_mapper
, "toggle-rwmode", "Movie‣Toggle read-only");
884 inverse_bind
irepaint(lsnes_mapper
, "repaint", "System‣Repaint screen");
885 inverse_bind
itogglepause(lsnes_mapper
, "toggle-pause-on-end", "Movie‣Toggle pause-on-end");
886 inverse_bind
irewind_movie(lsnes_mapper
, "rewind-movie", "Movie‣Rewind movie");
887 inverse_bind
icancel_saves(lsnes_mapper
, "cancel-saves", "Save‣Cancel pending saves");
888 inverse_bind
iload1(lsnes_mapper
, "load ${project}1.lsmv", "Load‣Slot 1");
889 inverse_bind
iload2(lsnes_mapper
, "load ${project}2.lsmv", "Load‣Slot 2");
890 inverse_bind
iload3(lsnes_mapper
, "load ${project}3.lsmv", "Load‣Slot 3");
891 inverse_bind
iload4(lsnes_mapper
, "load ${project}4.lsmv", "Load‣Slot 4");
892 inverse_bind
iload5(lsnes_mapper
, "load ${project}5.lsmv", "Load‣Slot 5");
893 inverse_bind
iload6(lsnes_mapper
, "load ${project}6.lsmv", "Load‣Slot 6");
894 inverse_bind
iload7(lsnes_mapper
, "load ${project}7.lsmv", "Load‣Slot 7");
895 inverse_bind
iload8(lsnes_mapper
, "load ${project}8.lsmv", "Load‣Slot 8");
896 inverse_bind
iload9(lsnes_mapper
, "load ${project}9.lsmv", "Load‣Slot 9");
897 inverse_bind
iload10(lsnes_mapper
, "load ${project}10.lsmv", "Load‣Slot 10");
898 inverse_bind
iload11(lsnes_mapper
, "load ${project}11.lsmv", "Load‣Slot 11");
899 inverse_bind
iload12(lsnes_mapper
, "load ${project}12.lsmv", "Load‣Slot 12");
900 inverse_bind
iload13(lsnes_mapper
, "load ${project}13.lsmv", "Load‣Slot 13");
901 inverse_bind
iload14(lsnes_mapper
, "load ${project}14.lsmv", "Load‣Slot 14");
902 inverse_bind
iload15(lsnes_mapper
, "load ${project}15.lsmv", "Load‣Slot 15");
903 inverse_bind
iload16(lsnes_mapper
, "load ${project}16.lsmv", "Load‣Slot 16");
904 inverse_bind
iload17(lsnes_mapper
, "load ${project}17.lsmv", "Load‣Slot 17");
905 inverse_bind
iload18(lsnes_mapper
, "load ${project}18.lsmv", "Load‣Slot 18");
906 inverse_bind
iload19(lsnes_mapper
, "load ${project}19.lsmv", "Load‣Slot 19");
907 inverse_bind
iload20(lsnes_mapper
, "load ${project}20.lsmv", "Load‣Slot 20");
908 inverse_bind
iload21(lsnes_mapper
, "load ${project}21.lsmv", "Load‣Slot 21");
909 inverse_bind
iload22(lsnes_mapper
, "load ${project}22.lsmv", "Load‣Slot 22");
910 inverse_bind
iload23(lsnes_mapper
, "load ${project}23.lsmv", "Load‣Slot 23");
911 inverse_bind
iload24(lsnes_mapper
, "load ${project}24.lsmv", "Load‣Slot 24");
912 inverse_bind
iload25(lsnes_mapper
, "load ${project}25.lsmv", "Load‣Slot 25");
913 inverse_bind
iload26(lsnes_mapper
, "load ${project}26.lsmv", "Load‣Slot 26");
914 inverse_bind
iload27(lsnes_mapper
, "load ${project}27.lsmv", "Load‣Slot 27");
915 inverse_bind
iload28(lsnes_mapper
, "load ${project}28.lsmv", "Load‣Slot 28");
916 inverse_bind
iload29(lsnes_mapper
, "load ${project}29.lsmv", "Load‣Slot 29");
917 inverse_bind
iload30(lsnes_mapper
, "load ${project}30.lsmv", "Load‣Slot 30");
918 inverse_bind
iload31(lsnes_mapper
, "load ${project}31.lsmv", "Load‣Slot 31");
919 inverse_bind
iload32(lsnes_mapper
, "load ${project}32.lsmv", "Load‣Slot 32");
920 inverse_bind
isave1(lsnes_mapper
, "save-state ${project}1.lsmv", "Save‣Slot 1");
921 inverse_bind
isave2(lsnes_mapper
, "save-state ${project}2.lsmv", "Save‣Slot 2");
922 inverse_bind
isave3(lsnes_mapper
, "save-state ${project}3.lsmv", "Save‣Slot 3");
923 inverse_bind
isave4(lsnes_mapper
, "save-state ${project}4.lsmv", "Save‣Slot 4");
924 inverse_bind
isave5(lsnes_mapper
, "save-state ${project}5.lsmv", "Save‣Slot 5");
925 inverse_bind
isave6(lsnes_mapper
, "save-state ${project}6.lsmv", "Save‣Slot 6");
926 inverse_bind
isave7(lsnes_mapper
, "save-state ${project}7.lsmv", "Save‣Slot 7");
927 inverse_bind
isave8(lsnes_mapper
, "save-state ${project}8.lsmv", "Save‣Slot 8");
928 inverse_bind
isave9(lsnes_mapper
, "save-state ${project}9.lsmv", "Save‣Slot 9");
929 inverse_bind
isave10(lsnes_mapper
, "save-state ${project}10.lsmv", "Save‣Slot 10");
930 inverse_bind
isave11(lsnes_mapper
, "save-state ${project}11.lsmv", "Save‣Slot 11");
931 inverse_bind
isave12(lsnes_mapper
, "save-state ${project}12.lsmv", "Save‣Slot 12");
932 inverse_bind
isave13(lsnes_mapper
, "save-state ${project}13.lsmv", "Save‣Slot 13");
933 inverse_bind
isave14(lsnes_mapper
, "save-state ${project}14.lsmv", "Save‣Slot 14");
934 inverse_bind
isave15(lsnes_mapper
, "save-state ${project}15.lsmv", "Save‣Slot 15");
935 inverse_bind
isave16(lsnes_mapper
, "save-state ${project}16.lsmv", "Save‣Slot 16");
936 inverse_bind
isave17(lsnes_mapper
, "save-state ${project}17.lsmv", "Save‣Slot 17");
937 inverse_bind
isave18(lsnes_mapper
, "save-state ${project}18.lsmv", "Save‣Slot 18");
938 inverse_bind
isave19(lsnes_mapper
, "save-state ${project}19.lsmv", "Save‣Slot 19");
939 inverse_bind
isave20(lsnes_mapper
, "save-state ${project}20.lsmv", "Save‣Slot 20");
940 inverse_bind
isave21(lsnes_mapper
, "save-state ${project}21.lsmv", "Save‣Slot 21");
941 inverse_bind
isave22(lsnes_mapper
, "save-state ${project}22.lsmv", "Save‣Slot 22");
942 inverse_bind
isave23(lsnes_mapper
, "save-state ${project}23.lsmv", "Save‣Slot 23");
943 inverse_bind
isave24(lsnes_mapper
, "save-state ${project}24.lsmv", "Save‣Slot 24");
944 inverse_bind
isave25(lsnes_mapper
, "save-state ${project}25.lsmv", "Save‣Slot 25");
945 inverse_bind
isave26(lsnes_mapper
, "save-state ${project}26.lsmv", "Save‣Slot 26");
946 inverse_bind
isave27(lsnes_mapper
, "save-state ${project}27.lsmv", "Save‣Slot 27");
947 inverse_bind
isave28(lsnes_mapper
, "save-state ${project}28.lsmv", "Save‣Slot 28");
948 inverse_bind
isave29(lsnes_mapper
, "save-state ${project}29.lsmv", "Save‣Slot 29");
949 inverse_bind
isave30(lsnes_mapper
, "save-state ${project}30.lsmv", "Save‣Slot 30");
950 inverse_bind
isave31(lsnes_mapper
, "save-state ${project}31.lsmv", "Save‣Slot 31");
951 inverse_bind
isave32(lsnes_mapper
, "save-state ${project}32.lsmv", "Save‣Slot 32");
953 bool on_quit_prompt
= false;
954 class mywindowcallbacks
: public information_dispatch
957 mywindowcallbacks() : information_dispatch("mainloop-window-callbacks")
959 closenotify
.set(notify_close
, [this]() {
961 amode
= ADVANCE_QUIT
;
962 platform::set_paused(false);
963 platform::cancel_wait();
966 on_quit_prompt
= true;
968 amode
= ADVANCE_QUIT
;
969 platform::set_paused(false);
970 platform::cancel_wait();
973 on_quit_prompt
= false;
976 ~mywindowcallbacks() throw() {}
977 void on_new_dumper(const std::string
& n
)
979 update_movie_state();
981 void on_destroy_dumper(const std::string
& n
)
983 update_movie_state();
986 struct dispatch_target
<> closenotify
;
989 //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
993 std::string old_project
= our_movie
.projectid
;
995 if(do_unsafe_rewind
&& unsafe_rewind_obj
) {
996 uint64_t t
= get_utime();
998 lua_callback_do_unsafe_rewind(s
, 0, 0, movb
.get_movie(), unsafe_rewind_obj
);
999 notify_mode_change(false);
1000 do_unsafe_rewind
= false;
1001 our_movie
.is_savestate
= true;
1002 location_special
= SPECIAL_SAVEPOINT
;
1003 update_movie_state();
1004 messages
<< "Rewind done in " << (get_utime() - t
) << " usec." << std::endl
;
1007 if(pending_new_project
!= "") {
1008 std::string id
= pending_new_project
;
1009 pending_new_project
= "";
1010 project_info
* old
= project_get();
1011 if(old
&& old
->id
== id
)
1014 auto& p
= project_load(id
);
1016 if(project_get() != old
)
1018 flush_slotinfo(); //Wrong movie may be stale.
1020 } catch(std::exception
& e
) {
1021 platform::error_message(std::string("Can't switch projects: ") + e
.what());
1022 messages
<< "Can't switch projects: " << e
.what() << std::endl
;
1027 platform::set_paused(amode
== ADVANCE_PAUSE
);
1028 platform::flush_command_queue();
1029 if(amode
== ADVANCE_LOAD
)
1033 if(pending_load
!= "") {
1034 system_corrupt
= false;
1035 if(loadmode
!= LOAD_STATE_BEGINNING
&& loadmode
!= LOAD_STATE_ROMRELOAD
&&
1036 !do_load_state(pending_load
, loadmode
)) {
1037 movb
.get_movie().set_pflag_handler(&lsnes_pflag_handler
);
1042 if(loadmode
== LOAD_STATE_BEGINNING
)
1043 do_load_beginning(false);
1044 if(loadmode
== LOAD_STATE_ROMRELOAD
)
1045 do_load_beginning(true);
1046 } catch(std::exception
& e
) {
1047 platform::error_message(std::string("Load failed: ") + e
.what());
1048 messages
<< "Load failed: " << e
.what() << std::endl
;
1050 movb
.get_movie().set_pflag_handler(&lsnes_pflag_handler
);
1052 amode
= load_paused
? ADVANCE_PAUSE
: ADVANCE_AUTO
;
1053 platform::set_paused(load_paused
);
1054 load_paused
= false;
1055 if(!system_corrupt
) {
1056 location_special
= SPECIAL_SAVEPOINT
;
1057 update_movie_state();
1058 platform::flush_command_queue();
1059 if(amode
== ADVANCE_QUIT
)
1061 if(amode
== ADVANCE_LOAD
)
1064 if(old_project
!= our_movie
.projectid
)
1065 flush_slotinfo(); //Wrong movie may be stale.
1071 //If there are pending saves, perform them.
1074 if(!queued_saves
.empty() || (do_unsafe_rewind
&& !unsafe_rewind_obj
)) {
1075 our_rom
.rtype
->runtosave();
1076 for(auto i
: queued_saves
) {
1077 do_save_state(i
.first
, i
.second
);
1079 flush_slotinfo(translate_name_mprefix(i
.first
, tmp
, false));
1081 if(do_unsafe_rewind
&& !unsafe_rewind_obj
) {
1082 uint64_t t
= get_utime();
1083 std::vector
<char> s
= our_rom
.save_core_state(true);
1084 uint64_t secs
= our_movie
.rtc_second
;
1085 uint64_t ssecs
= our_movie
.rtc_subsecond
;
1086 lua_callback_do_unsafe_rewind(s
, secs
, ssecs
, movb
.get_movie(), NULL
);
1087 do_unsafe_rewind
= false;
1088 messages
<< "Rewind point set in " << (get_utime() - t
) << " usec." << std::endl
;
1091 queued_saves
.clear();
1094 bool handle_corrupt()
1098 while(system_corrupt
) {
1099 platform::set_paused(true);
1100 platform::flush_command_queue();
1102 if(amode
== ADVANCE_QUIT
)
1109 void main_loop(struct loaded_rom
& rom
, struct moviefile
& initial
, bool load_has_to_succeed
) throw(std::bad_alloc
,
1112 platform::system_thread_available(true);
1113 //Basic initialization.
1114 dispatch_set_error_streams(&messages
.getstream());
1115 emulation_thread
= this_thread_id();
1116 jukebox_size_listener jlistener
;
1118 init_special_screens();
1120 lsnes_callbacks lsnes_callbacks_obj
;
1121 ecore_callbacks
= &lsnes_callbacks_obj
;
1122 movb
.get_movie().set_pflag_handler(&lsnes_pflag_handler
);
1123 core_core::install_all_handlers();
1125 //Load our given movie.
1126 bool first_round
= false;
1127 bool just_did_loadstate
= false;
1129 do_load_state(initial
, LOAD_STATE_INITIAL
);
1130 location_special
= SPECIAL_SAVEPOINT
;
1131 update_movie_state();
1132 first_round
= our_movie
.is_savestate
;
1133 just_did_loadstate
= first_round
;
1134 } catch(std::bad_alloc
& e
) {
1136 } catch(std::exception
& e
) {
1137 platform::error_message(std::string("Can't load initial state: ") + e
.what());
1138 messages
<< "ERROR: Can't load initial state: " << e
.what() << std::endl
;
1139 if(load_has_to_succeed
) {
1140 messages
<< "FATAL: Can't load movie" << std::endl
;
1141 platform::fatal_error();
1143 system_corrupt
= true;
1144 update_movie_state();
1145 redraw_framebuffer(screen_corrupt
);
1148 movb
.get_movie().set_pflag_handler(&lsnes_pflag_handler
);
1149 lua_callback_startup();
1151 platform::set_paused(initial
.start_paused
);
1152 amode
= initial
.start_paused
? ADVANCE_PAUSE
: ADVANCE_AUTO
;
1153 stop_at_frame_active
= false;
1154 uint64_t time_x
= get_utime();
1155 while(amode
!= ADVANCE_QUIT
|| !queued_saves
.empty()) {
1156 if(handle_corrupt()) {
1157 first_round
= our_movie
.is_savestate
;
1158 just_did_loadstate
= first_round
;
1161 ack_frame_tick(get_utime());
1162 if(amode
== ADVANCE_SKIPLAG_PENDING
)
1163 amode
= ADVANCE_SKIPLAG
;
1166 controls
.reset_framehold();
1167 movb
.get_movie().get_pollcounters().set_framepflag(false);
1168 movb
.new_frame_starting(amode
== ADVANCE_SKIPLAG
);
1169 movb
.get_movie().get_pollcounters().set_framepflag(true);
1170 if(!macro_hold_1
&& !macro_hold_2
) {
1171 controls
.advance_macros();
1173 macro_hold_2
= false;
1174 if(amode
== ADVANCE_QUIT
&& queued_saves
.empty())
1178 if(queued_saves
.empty())
1180 if(r
> 0 || system_corrupt
) {
1181 movb
.get_movie().get_pollcounters().set_framepflag(our_movie
.is_savestate
);
1182 first_round
= our_movie
.is_savestate
;
1184 amode
= ADVANCE_PAUSE
;
1187 stop_at_frame_active
= false;
1188 just_did_loadstate
= first_round
;
1189 controls
.reset_framehold();
1192 //Not exactly desriable, but this at least won't desync.
1193 stop_at_frame_active
= false;
1194 if(amode
== ADVANCE_QUIT
)
1196 amode
= ADVANCE_PAUSE
;
1199 if(just_did_loadstate
) {
1200 //If we just loadstated, we are up to date.
1201 if(amode
== ADVANCE_QUIT
)
1203 platform::set_paused(amode
== ADVANCE_PAUSE
);
1204 platform::flush_command_queue();
1205 //We already have done the reset this frame if we are going to do one at all.
1206 movb
.get_movie().set_controls(movb
.update_controls(true));
1207 movb
.get_movie().set_all_DRDY();
1208 just_did_loadstate
= false;
1210 frame_irq_time
= get_utime() - time_x
;
1211 our_rom
.rtype
->emulate();
1212 random_mix_timing_entropy();
1213 time_x
= get_utime();
1214 if(amode
== ADVANCE_AUTO
)
1215 platform::wait(to_wait_frame(get_utime()));
1216 first_round
= false;
1217 lua_callback_do_frame();
1219 information_dispatch::do_dump_end();
1220 core_core::uninstall_all_handlers();
1222 platform::system_thread_available(false);
1225 void set_stop_at_frame(uint64_t frame
)
1227 stop_at_frame
= frame
;
1228 stop_at_frame_active
= (frame
!= 0);
1229 amode
= ADVANCE_AUTO
;
1230 platform::set_paused(false);
1233 void do_flush_slotinfo()
1238 void switch_projects(const std::string
& newproj
)
1240 pending_new_project
= newproj
;
1241 amode
= ADVANCE_LOAD
;
1242 old_mode
= ADVANCE_PAUSE
;
1243 platform::cancel_wait();
1244 platform::set_paused(false);
1247 void load_new_rom(const romload_request
& req
)
1249 if(_load_new_rom(req
)) {
1250 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
1254 void reload_current_rom()
1256 if(reload_active_rom()) {
1257 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
1263 if(load_null_rom()) {
1265 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);