2 #include <snes/snes.hpp>
3 #include <ui-libsnes/libsnes.hpp>
5 #include "core/command.hpp"
6 #include "core/framerate.hpp"
7 #include "core/keymapper.hpp"
8 #include "core/lua.hpp"
9 #include "core/mainloop.hpp"
10 #include "core/misc.hpp"
11 #include "core/moviedata.hpp"
12 #include "core/rom.hpp"
13 #include "core/rrdata.hpp"
14 #include "core/window.hpp"
16 #include "plat-sdl/platform.hpp"
21 #if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE) || defined(__APPLE__)
26 class my_interfaced
: public SNES::Interface
28 string
path(SNES::Cartridge::Slot slot
, const string
&hint
)
34 struct moviefile
generate_movie_template(std::vector
<std::string
> cmdline
, loaded_rom
& r
)
36 struct moviefile movie
;
37 movie
.port1
= PT_GAMEPAD
;
38 movie
.port2
= PT_NONE
;
39 movie
.coreversion
= bsnes_core_version
;
40 movie
.projectid
= get_random_hexstring(40);
41 movie
.gametype
= gtype::togametype(r
.rtype
, r
.region
);
42 movie
.rom_sha256
= r
.rom
.sha256
;
43 movie
.romxml_sha256
= r
.rom_xml
.sha256
;
44 movie
.slota_sha256
= r
.slota
.sha256
;
45 movie
.slotaxml_sha256
= r
.slota_xml
.sha256
;
46 movie
.slotb_sha256
= r
.slotb
.sha256
;
47 movie
.slotbxml_sha256
= r
.slotb_xml
.sha256
;
48 movie
.movie_sram
= load_sram_commandline(cmdline
);
49 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++) {
51 if(o
.length() >= 9 && o
.substr(0, 9) == "--prefix=")
52 movie
.prefix
= sanitize_prefix(o
.substr(9));
53 if(o
.length() >= 8 && o
.substr(0, 8) == "--port1=")
54 movie
.port1
= porttype_info::lookup(o
.substr(8)).value
;
55 if(o
.length() >= 8 && o
.substr(0, 8) == "--port2=")
56 movie
.port2
= porttype_info::lookup(o
.substr(8)).value
;
57 if(o
.length() >= 11 && o
.substr(0, 11) == "--gamename=")
58 movie
.gamename
= o
.substr(11);
59 if(o
.length() >= 9 && o
.substr(0, 9) == "--author=") {
60 std::string line
= o
.substr(9);
61 auto g
= split_author(line
);
62 movie
.authors
.push_back(g
);
64 if(o
.length() >= 13 && o
.substr(0, 13) == "--rtc-second=") {
65 movie
.rtc_second
= movie
.movie_rtc_second
= parse_value
<int64_t>(o
.substr(13));
67 if(o
.length() >= 16 && o
.substr(0, 16) == "--rtc-subsecond=") {
68 movie
.rtc_subsecond
= movie
.movie_rtc_subsecond
= parse_value
<int64_t>(o
.substr(16));
69 if(movie
.rtc_subsecond
< 0 || movie
.rtc_subsecond
> 3462619485019ULL)
70 throw std::runtime_error("Bad RTC subsecond value (range is 0-3462619485019)");
73 movie
.input
.clear(movie
.port1
, movie
.port2
);
80 void run_extra_scripts(const std::vector
<std::string
>& cmdline
)
82 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++) {
84 if(o
.length() >= 6 && o
.substr(0, 6) == "--run=") {
85 std::string file
= o
.substr(6);
86 messages
<< "--- Running " << file
<< " --- " << std::endl
;
87 command::invokeC("run-script " + file
);
88 messages
<< "--- End running " << file
<< " --- " << std::endl
;
93 void sdl_main_loop(struct loaded_rom
& rom
, struct moviefile
& initial
, bool load_has_to_succeed
= false)
94 throw(std::bad_alloc
, std::runtime_error
);
98 struct loaded_rom
* rom
;
99 struct moviefile
* initial
;
100 bool load_has_to_succeed
;
103 void* emulator_thread(void* _args
)
105 struct emu_args
* args
= reinterpret_cast<struct emu_args
*>(_args
);
107 main_loop(*args
->rom
, *args
->initial
, args
->load_has_to_succeed
);
108 notify_emulator_exit();
109 } catch(std::bad_alloc
& e
) {
111 } catch(std::exception
& e
) {
112 messages
<< "FATAL: " << e
.what() << std::endl
;
113 platform::fatal_error();
117 void* joystick_thread(void* _args
)
119 joystick_plugin::thread_fn();
122 void sdl_main_loop(struct loaded_rom
& rom
, struct moviefile
& initial
, bool load_has_to_succeed
)
123 throw(std::bad_alloc
, std::runtime_error
)
126 struct emu_args args
;
128 args
.initial
= &initial
;
129 args
.load_has_to_succeed
= load_has_to_succeed
;
132 t
= &thread::create(emulator_thread
, &args
);
133 t2
= &thread::create(joystick_thread
, &args
);
135 joystick_plugin::signal();
140 } catch(std::bad_alloc
& e
) {
146 int main(int argc
, char** argv
)
149 std::vector
<std::string
> cmdline
;
150 for(int i
= 1; i
< argc
; i
++)
151 cmdline
.push_back(argv
[i
]);
152 if(cmdline
.size() == 1 && cmdline
[0] == "--version") {
153 std::cout
<< "lsnes rr" << lsnes_version
<< " (" << lsnes_git_revision
<< ")" << std::endl
;
154 std::cout
<< snes_library_id() << " (" << SNES::Info::Profile
<< " core)" << std::endl
;
158 SNES::interface
= &intrf
;
163 std::ostringstream x
;
164 x
<< snes_library_id() << " (" << SNES::Info::Profile
<< " core)";
165 bsnes_core_version
= x
.str();
170 messages
<< "BSNES version: " << bsnes_core_version
<< std::endl
;
171 messages
<< "lsnes version: lsnes rr" << lsnes_version
<< std::endl
;
172 messages
<< "Command line is: ";
173 for(auto k
= cmdline
.begin(); k
!= cmdline
.end(); k
++)
174 messages
<< "\"" << *k
<< "\" ";
175 messages
<< std::endl
;
177 std::string cfgpath
= get_config_path();
179 messages
<< "Saving per-user data to: " << get_config_path() << std::endl
;
180 messages
<< "--- Running lsnesrc --- " << std::endl
;
181 command::invokeC("run-script " + cfgpath
+ "/lsnes.rc");
182 messages
<< "--- End running lsnesrc --- " << std::endl
;
184 run_extra_scripts(cmdline
);
186 messages
<< "--- Loading ROM ---" << std::endl
;
189 r
= load_rom_from_commandline(cmdline
);
191 } catch(std::bad_alloc
& e
) {
193 } catch(std::exception
& e
) {
194 messages
<< "FATAL: Can't load ROM: " << e
.what() << std::endl
;
198 messages
<< "Detected region: " << gtype::tostring(r
.rtype
, r
.region
) << std::endl
;
199 if(r
.region
== REGION_PAL
)
200 set_nominal_framerate(322445.0/6448.0);
201 else if(r
.region
== REGION_NTSC
)
202 set_nominal_framerate(10738636.0/178683.0);
204 messages
<< "--- Internal memory mappings ---" << std::endl
;
206 messages
<< "--- End of Startup --- " << std::endl
;
208 movie
.force_corrupt
= true;
212 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++)
213 if(i
->length() > 0 && (*i
)[0] != '-') {
216 movie
= moviefile(*i
);
218 } catch(std::bad_alloc
& e
) {
220 } catch(std::exception
& e
) {
221 messages
<< "Error loading '" << *i
<< "': " << e
.what() << std::endl
;
225 movie
= generate_movie_template(cmdline
, r
);
226 sdl_main_loop(r
, movie
);
227 } catch(std::bad_alloc
& e
) {
229 } catch(std::exception
& e
) {
230 messages
<< "FATAL: " << e
.what() << std::endl
;