1 #include "cmdhelp/loadsave.hpp"
2 #include "core/advdumper.hpp"
3 #include "core/audioapi.hpp"
4 #include "core/dispatch.hpp"
5 #include "core/emustatus.hpp"
6 #include "core/framerate.hpp"
7 #include "core/inthread.hpp"
8 #include "core/jukebox.hpp"
9 #include "core/memorywatch.hpp"
10 #include "core/movie.hpp"
11 #include "core/moviedata.hpp"
12 #include "core/moviefile.hpp"
13 #include "core/multitrack.hpp"
14 #include "core/project.hpp"
15 #include "core/rom.hpp"
16 #include "core/runmode.hpp"
17 #include "lua/lua.hpp"
21 const int _lsnes_status::pause_none
= 0;
22 const int _lsnes_status::pause_normal
= 1;
23 const int _lsnes_status::pause_break
= 2;
24 const uint64_t _lsnes_status::subframe_savepoint
= 0xFFFFFFFFFFFFFFFEULL
;
25 const uint64_t _lsnes_status::subframe_video
= 0xFFFFFFFFFFFFFFFFULL
;
27 slotinfo_cache::slotinfo_cache(movie_logic
& _mlogic
, command::group
& _cmd
)
28 : mlogic(_mlogic
), cmd(_cmd
),
29 flushcmd(cmd
, CLOADSAVE::flushslots
, [this]() { this->flush(); })
33 std::string
slotinfo_cache::get(const std::string
& _filename
)
35 std::string filename
= resolve_relative_path(_filename
);
36 if(!cache
.count(filename
)) {
37 std::ostringstream out
;
39 moviefile::brief_info
info(filename
);
42 else if(mlogic
.get_mfile().projectid
== info
.projectid
)
43 out
<< info
.rerecords
<< "R/" << info
.current_frame
<< "F";
49 cache
[filename
] = out
.str();
51 return cache
[filename
];
54 void slotinfo_cache::flush(const std::string
& _filename
)
56 cache
.erase(resolve_relative_path(_filename
));
59 void slotinfo_cache::flush()
64 status_updater::status_updater(project_state
& _project
, movie_logic
& _mlogic
, voice_commentary
& _commentary
,
65 triplebuffer::triplebuffer
<_lsnes_status
>& _status
, emulator_runmode
& _runmode
, master_dumper
& _mdumper
,
66 save_jukebox
& _jukebox
, slotinfo_cache
& _slotcache
, framerate_regulator
& _framerate
,
67 controller_state
& _controls
, multitrack_edit
& _mteditor
, lua_state
& _lua2
, loaded_rom
& _rom
,
68 memwatch_set
& _mwatch
, emulator_dispatch
& _dispatch
)
69 : project(_project
), mlogic(_mlogic
), commentary(_commentary
), status(_status
), runmode(_runmode
),
70 mdumper(_mdumper
), jukebox(_jukebox
), slotcache(_slotcache
), framerate(_framerate
), controls(_controls
),
71 mteditor(_mteditor
), lua2(_lua2
), rom(_rom
), mwatch(_mwatch
), dispatch(_dispatch
)
76 void status_updater::update()
78 auto p
= project
.get();
79 bool readonly
= false;
82 rom
.region_fill_framerate_magic(magic
);
84 commentary
.frame_number(mlogic
.get_movie().get_current_frame(),
85 1.0 * magic
[1] / magic
[0]);
87 commentary
.frame_number(0, 60.0); //Default.
89 auto& _status
= status
.get_write();
91 if(mlogic
&& !runmode
.is_corrupt()) {
92 _status
.movie_valid
= true;
93 _status
.curframe
= mlogic
.get_movie().get_current_frame();
94 _status
.length
= mlogic
.get_movie().get_frame_count();
95 _status
.lag
= mlogic
.get_movie().get_lag_frames();
96 if(runmode
.get_point() == emulator_runmode::P_START
)
98 else if(runmode
.get_point() == emulator_runmode::P_SAVE
)
99 _status
.subframe
= _lsnes_status::subframe_savepoint
;
100 else if(runmode
.get_point() == emulator_runmode::P_VIDEO
)
101 _status
.subframe
= _lsnes_status::subframe_video
;
103 _status
.subframe
= mlogic
.get_movie().next_poll_number();
105 _status
.movie_valid
= false;
106 _status
.curframe
= 0;
109 _status
.subframe
= 0;
111 _status
.dumping
= (mdumper
.get_dumper_count() > 0);
112 if(runmode
.is_paused_break())
113 _status
.pause
= _lsnes_status::pause_break
;
114 else if(runmode
.is_paused_normal())
115 _status
.pause
= _lsnes_status::pause_normal
;
117 _status
.pause
= _lsnes_status::pause_none
;
119 auto& mo
= mlogic
.get_movie();
120 readonly
= mo
.readonly_mode();
121 if(runmode
.is_corrupt())
125 else if(mo
.get_frame_count() >= mo
.get_current_frame())
131 _status
.saveslot_valid
= true;
133 std::string sfilen
= translate_name_mprefix(jukebox
.get_slot_name(), tmp
, -1);
134 _status
.saveslot
= jukebox
.get_slot() + 1;
135 _status
.slotinfo
= utf8::to32(slotcache
.get(sfilen
));
137 _status
.saveslot_valid
= false;
139 _status
.branch_valid
= (p
!= NULL
);
140 if(p
) _status
.branch
= utf8::to32(p
->get_branch_string());
142 std::string cur_branch
= mlogic
? mlogic
.get_mfile().current_branch() :
144 _status
.mbranch_valid
= (cur_branch
!= "");
145 _status
.mbranch
= utf8::to32(cur_branch
);
147 _status
.speed
= (unsigned)(100 * framerate
.get_realized_multiplier() + 0.5);
149 if(mlogic
&& !runmode
.is_corrupt()) {
150 time_t timevalue
= static_cast<time_t>(mlogic
.get_mfile().dyn
.rtc_second
);
151 struct tm
* time_decompose
= gmtime(&timevalue
);
152 char datebuffer
[512];
153 strftime(datebuffer
, 511, "%Y%m%d(%a)T%H%M%S", time_decompose
);
154 _status
.rtc
= utf8::to32(datebuffer
);
155 _status
.rtc_valid
= true;
157 _status
.rtc_valid
= false;
160 auto mset
= controls
.active_macro_set();
162 std::ostringstream mss
;
164 if(!mfirst
) mss
<< ",";
168 _status
.macros
= utf8::to32(mss
.str());
171 if(!mteditor
.any_records())
172 c
= mlogic
.get_movie().get_controls();
174 c
= controls
.get_committed();
175 _status
.inputs
.clear();
176 for(unsigned i
= 0;; i
++) {
177 auto pindex
= controls
.lcid_to_pcid(i
);
178 if(pindex
.first
< 0 || !controls
.is_present(pindex
.first
, pindex
.second
))
180 char32_t buffer
[MAX_DISPLAY_LENGTH
];
181 c
.display(pindex
.first
, pindex
.second
, buffer
);
182 std::u32string _buffer
= buffer
;
183 if(readonly
&& mteditor
.is_enabled()) {
184 multitrack_edit::state st
= mteditor
.get(pindex
.first
, pindex
.second
);
185 if(st
== multitrack_edit::MT_PRESERVE
)
186 _buffer
+= U
" (keep)";
187 else if(st
== multitrack_edit::MT_OVERWRITE
)
188 _buffer
+= U
" (rewrite)";
189 else if(st
== multitrack_edit::MT_OR
)
191 else if(st
== multitrack_edit::MT_XOR
)
192 _buffer
+= U
" (XOR)";
194 _buffer
+= U
" (\?\?\?)";
196 _status
.inputs
.push_back(_buffer
);
199 _status
.lvars
= lua2
.get_watch_vars();
201 _status
.mvars
= mwatch
.get_window_vars();
203 _status
.valid
= true;
207 dispatch
.status_update();