3 #include "core/advdumper.hpp"
4 #include "core/command.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/mainloop.hpp"
7 #include "core/framerate.hpp"
8 #include "core/keymapper.hpp"
9 #include "interface/romtype.hpp"
10 #include "core/loadlib.hpp"
11 #include "lua/lua.hpp"
12 #include "core/mainloop.hpp"
13 #include "core/misc.hpp"
14 #include "core/moviedata.hpp"
15 #include "core/rom.hpp"
16 #include "core/rrdata.hpp"
17 #include "core/settings.hpp"
18 #include "core/window.hpp"
19 #include "library/string.hpp"
26 class myavsnoop
: public information_dispatch
29 myavsnoop(adv_dumper
& _dumper
, uint64_t frames_to_dump
)
30 : information_dispatch("myavsnoop-monitor"), dumper(_dumper
)
33 total
= frames_to_dump
;
40 void on_frame(struct framebuffer_raw
& _frame
, uint32_t fps_n
, uint32_t fps_d
)
43 if(frames_dumped
% 100 == 0) {
44 std::cout
<< "Dumping frame " << frames_dumped
<< "/" << total
<< " ("
45 << (100 * frames_dumped
/ total
) << "%)" << std::endl
;
47 if(frames_dumped
== total
) {
48 //Rough way to end it.
50 information_dispatch::do_dump_end();
57 std::cout
<< "Finished!" << std::endl
;
60 uint64_t frames_dumped
;
65 void dumper_startup(adv_dumper
& dumper
, const std::string
& mode
, const std::string
& prefix
, uint64_t length
)
67 std::cout
<< "Invoking dumper" << std::endl
;
69 dumper
.start(mode
, prefix
);
70 } catch(std::exception
& e
) {
71 std::cerr
<< "Can't start dumper: " << e
.what() << std::endl
;
74 if(information_dispatch::get_dumper_count()) {
75 std::cout
<< "Dumper attach confirmed" << std::endl
;
77 std::cout
<< "Can't start dumper!" << std::endl
;
80 new myavsnoop(dumper
, length
);
83 void startup_lua_scripts(const std::vector
<std::string
>& cmdline
)
85 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++) {
87 if(a
.length() > 6 && a
.substr(0, 6) == "--lua=") {
88 lsnes_cmd
.invoke("run-lua " + a
.substr(6));
93 struct adv_dumper
& locate_dumper(const std::string
& name
)
95 adv_dumper
* _dumper
= NULL
;
96 std::set
<adv_dumper
*> dumpers
= adv_dumper::get_dumper_set();
101 std::cerr
<< "No such dumper '" << name
<< "' found (try --dumper=list)" << std::endl
;
107 std::string
format_details(unsigned detail
)
110 if((detail
& adv_dumper::target_type_mask
) == adv_dumper::target_type_file
)
111 r
= r
+ "TARGET_FILE";
112 else if((detail
& adv_dumper::target_type_mask
) == adv_dumper::target_type_prefix
)
113 r
= r
+ "TARGET_PREFIX";
114 else if((detail
& adv_dumper::target_type_mask
) == adv_dumper::target_type_special
)
115 r
= r
+ "TARGET_SPECIAL";
117 r
= r
+ "TARGET_UNKNOWN";
121 adv_dumper
& get_dumper(const std::vector
<std::string
>& cmdline
, std::string
& mode
, std::string
& prefix
,
124 bool dumper_given
= false;
126 bool mode_given
= false;
129 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++) {
131 if(a
.length() >= 7 && a
.substr(0, 7) == "--core=") {
132 preferred_core_default
= a
.substr(7);
133 } else if(a
.length() >= 9 && a
.substr(0, 9) == "--dumper=") {
135 dumper
= a
.substr(9);
136 } else if(a
.length() >= 7 && a
.substr(0, 7) == "--mode=") {
139 } else if(a
.length() >= 9 && a
.substr(0, 9) == "--prefix=")
140 prefix
= a
.substr(9);
141 else if(a
.length() >= 9 && a
.substr(0, 9) == "--length=")
143 length
= boost::lexical_cast
<uint64_t>(a
.substr(9));
145 throw std::runtime_error("Length out of range (1-)");
146 } catch(std::exception
& e
) {
147 std::cerr
<< "Bad --length: " << e
.what() << std::endl
;
150 else if(a
.length() >= 9 && a
.substr(0, 9) == "--option=") {
151 std::string nameval
= a
.substr(9);
152 size_t s
= nameval
.find_first_of("=");
153 if(s
>= nameval
.length()) {
154 std::cerr
<< "Invalid option syntax (expected --option=foo=bar)" << std::endl
;
157 std::string name
= nameval
.substr(0, s
);
158 std::string val
= nameval
.substr(s
+ 1);
160 lsnes_vset
[name
].str(val
);
161 } catch(std::exception
& e
) {
162 std::cerr
<< "Can't set '" << name
<< "' to '" << val
<< "': " << e
.what()
166 } else if(a
.length() >= 12 && a
.substr(0, 15) == "--load-library=")
168 new loaded_library(a
.substr(15));
169 handle_post_loadlibrary();
170 } catch(std::runtime_error
& e
) {
171 std::cerr
<< "Can't load '" << a
.substr(15) << "': " << e
.what() << std::endl
;
175 if(preferred_core_default
== "list") {
177 std::set
<std::pair
<std::string
, std::string
>> cores
;
178 for(auto i
: core_type::get_core_types())
179 cores
.insert(std::make_pair(i
->get_core_shortname(), i
->get_core_identifier()));
181 std::cout
<< i
.first
<< " -> " << i
.second
<< std::endl
;
184 if(dumper
== "list") {
186 std::set
<adv_dumper
*> dumpers
= adv_dumper::get_dumper_set();
187 std::cout
<< "Dumpers available:" << std::endl
;
188 for(auto i
: dumpers
)
189 std::cout
<< i
->id() << "\t" << i
->name() << std::endl
;
193 std::cerr
<< "Dumper required (--dumper=foo)" << std::endl
;
198 adv_dumper
& _dumper
= locate_dumper(dumper
);
199 std::set
<std::string
> modes
= _dumper
.list_submodes();
201 unsigned d
= _dumper
.mode_details("");
202 std::cout
<< "No modes available for " << dumper
<< " (" << format_details(d
) << ")"
206 std::cout
<< "Modes available for " << dumper
<< ":" << std::endl
;
207 for(auto i
: modes
) {
208 unsigned d
= _dumper
.mode_details(i
);
209 std::cout
<< i
<< "\t" << _dumper
.modename(i
) << "\t(" << format_details(d
) << ")"
214 adv_dumper
& _dumper
= locate_dumper(dumper
);
215 if(!mode_given
&& !_dumper
.list_submodes().empty()) {
216 std::cerr
<< "Mode required for this dumper" << std::endl
;
219 if(mode_given
&& _dumper
.list_submodes().empty()) {
220 std::cerr
<< "This dumper does not have mode select" << std::endl
;
223 if(mode_given
&& !_dumper
.list_submodes().count(mode
)) {
224 std::cerr
<< "'" << mode
<< "' is not a valid mode for '" << dumper
<< "'" << std::endl
;
228 std::cerr
<< "--length=<frames> has to be specified" << std::endl
;
231 return locate_dumper(dumper
);
235 int main(int argc
, char** argv
)
238 std::vector
<std::string
> cmdline
;
239 for(int i
= 1; i
< argc
; i
++)
240 cmdline
.push_back(argv
[i
]);
242 std::string mode
, prefix
;
244 adv_dumper
& dumper
= get_dumper(cmdline
, mode
, prefix
, length
);
250 messages
<< "lsnes version: lsnes rr" << lsnes_version
<< std::endl
;
251 messages
<< "Command line is: ";
252 for(auto k
= cmdline
.begin(); k
!= cmdline
.end(); k
++)
253 messages
<< "\"" << *k
<< "\" ";
254 messages
<< std::endl
;
256 std::string cfgpath
= get_config_path();
257 autoload_libraries();
259 for(auto i
: cmdline
) {
261 if(r
= regex("--firmware-path=(.*)", i
)) {
263 lsnes_vsetc
.set("firmwarepath", r
[1]);
264 std::cerr
<< "Set firmware path to '" << r
[1] << "'" << std::endl
;
265 } catch(std::exception
& e
) {
266 std::cerr
<< "Can't set firmware path to '" << r
[1] << "': " << e
.what() << std::endl
;
269 if(r
= regex("--setting-(.*)=(.*)", i
)) {
271 lsnes_vset
[r
[1]].str(r
[2]);
272 std::cerr
<< "Set " << r
[1] << " to '" << r
[2] << "'" << std::endl
;
273 } catch(std::exception
& e
) {
274 std::cerr
<< "Can't set " << r
[1] << " to '" << r
[2] << "': " << e
.what() << std::endl
;
279 messages
<< "--- Loading ROM ---" << std::endl
;
282 std::map
<std::string
, std::string
> tmp
;
283 r
= load_rom_from_commandline(cmdline
);
284 r
.load(tmp
, 1000000000, 0);
285 messages
<< "Using core: " << r
.rtype
->get_core_identifier() << std::endl
;
286 } catch(std::bad_alloc
& e
) {
288 } catch(std::exception
& e
) {
289 messages
<< "FATAL: Can't load ROM: " << e
.what() << std::endl
;
293 messages
<< "Detected region: " << r
.rtype
->combine_region(*r
.region
).get_name() << std::endl
;
294 set_nominal_framerate(r
.region
->approx_framerate());
296 messages
<< "--- Internal memory mappings ---" << std::endl
;
298 messages
<< "--- End of Startup --- " << std::endl
;
304 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++)
305 if(i
->length() > 0 && (*i
)[0] != '-') {
308 movie
= moviefile(*i
, *r
.rtype
);
310 } catch(std::bad_alloc
& e
) {
312 } catch(std::exception
& e
) {
313 messages
<< "Error loading '" << *i
<< "': " << e
.what() << std::endl
;
317 throw std::runtime_error("Specifying movie is required");
319 throw std::runtime_error("Can't load any of the movies specified");
320 //Load ROM before starting the dumper.
322 messages
<< "Using core: " << our_rom
->rtype
->get_core_identifier() << std::endl
;
323 our_rom
->region
= &movie
.gametype
->get_region();
324 our_rom
->load(movie
.settings
, movie
.movie_rtc_second
, movie
.movie_rtc_subsecond
);
325 startup_lua_scripts(cmdline
);
326 dumper_startup(dumper
, mode
, prefix
, length
);
327 main_loop(r
, movie
, true);
328 } catch(std::bad_alloc
& e
) {
330 } catch(std::exception
& e
) {
331 messages
<< "FATAL: " << e
.what() << std::endl
;
335 information_dispatch::do_dump_end();