mirror of https://github.com/bsnes-emu/bsnes.git
Update to icarus 20151117.
byuu says: This release adds a settings dialog that lets you control the library path, optionally generate manifest.bml files, and optionally bypass the internal games database (so far this is only the US SNES set.) Also, the settings.bml file can exist in the same folder as the binary now (portable mode). Plus it can share the same config file as higan/tomoko itself does. This will allow you to change the library location in either program and have it affect the other program as well. It's a bit hackish, but it works >_> Note: don't use this with higan v095.06 or earlier, or bad things will happen.
This commit is contained in:
parent
41c478ac4a
commit
6adfe71836
|
@ -20,12 +20,12 @@ auto Icarus::bsxSatellaviewManifest(vector<uint8_t>& buffer, const string& locat
|
|||
auto Icarus::bsxSatellaviewImport(vector<uint8_t>& buffer, const string& location) -> bool {
|
||||
auto name = prefixname(location);
|
||||
auto source = pathname(location);
|
||||
string target{settings.libraryPath, "BS-X Satellaview/", name, ".bs/"};
|
||||
string target{settings["Library/Location"].text(), "BS-X Satellaview/", name, ".bs/"};
|
||||
//if(directory::exists(target)) return failure("game already exists");
|
||||
|
||||
string markup;
|
||||
|
||||
if(settings.useDatabase && !markup) {
|
||||
if(settings["icarus/UseDatabase"].boolean() && !markup) {
|
||||
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
|
||||
for(auto node : database.bsxSatellaview) {
|
||||
if(node.name() != "release") continue;
|
||||
|
@ -37,7 +37,7 @@ auto Icarus::bsxSatellaviewImport(vector<uint8_t>& buffer, const string& locatio
|
|||
}
|
||||
}
|
||||
|
||||
if(settings.useHeuristics && !markup) {
|
||||
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
|
||||
BsxSatellaviewCartridge cartridge{buffer.data(), buffer.size()};
|
||||
if(markup = cartridge.markup) {
|
||||
markup.append("\n");
|
||||
|
@ -50,7 +50,7 @@ auto Icarus::bsxSatellaviewImport(vector<uint8_t>& buffer, const string& locatio
|
|||
if(!markup) return failure("failed to parse ROM image");
|
||||
if(!directory::create(target)) return failure("library path unwritable");
|
||||
|
||||
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);
|
||||
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
|
||||
file::write({target, "program.rom"}, buffer);
|
||||
return success();
|
||||
}
|
||||
|
|
|
@ -22,12 +22,12 @@ auto Icarus::famicomManifest(vector<uint8_t>& buffer, const string& location) ->
|
|||
auto Icarus::famicomImport(vector<uint8_t>& buffer, const string& location) -> bool {
|
||||
auto name = prefixname(location);
|
||||
auto source = pathname(location);
|
||||
string target{settings.libraryPath, "Famicom/", name, ".fc/"};
|
||||
string target{settings["Library/Location"].text(), "Famicom/", name, ".fc/"};
|
||||
//if(directory::exists(target)) return failure("game already exists");
|
||||
|
||||
string markup;
|
||||
|
||||
//if(settings.useHeuristics && !markup) {
|
||||
//if(settings["icarus/UseHeuristics"].boolean() && !markup) {
|
||||
FamicomCartridge cartridge{buffer.data(), buffer.size()};
|
||||
if(markup = cartridge.markup) {
|
||||
markup.append("\n");
|
||||
|
@ -40,7 +40,7 @@ auto Icarus::famicomImport(vector<uint8_t>& buffer, const string& location) -> b
|
|||
if(!markup) return failure("failed to parse ROM image");
|
||||
if(!directory::create(target)) return failure("library path unwritable");
|
||||
|
||||
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);
|
||||
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
|
||||
file::write({target, "ines.rom"}, buffer.data(), 16);
|
||||
file::write({target, "program.rom"}, buffer.data() + 16, cartridge.prgrom);
|
||||
if(!cartridge.chrrom) return success();
|
||||
|
|
|
@ -20,12 +20,12 @@ auto Icarus::gameBoyAdvanceManifest(vector<uint8_t>& buffer, const string& locat
|
|||
auto Icarus::gameBoyAdvanceImport(vector<uint8_t>& buffer, const string& location) -> bool {
|
||||
auto name = prefixname(location);
|
||||
auto source = pathname(location);
|
||||
string target{settings.libraryPath, "Game Boy Advance/", name, ".gba/"};
|
||||
string target{settings["Library/Location"].text(), "Game Boy Advance/", name, ".gba/"};
|
||||
//if(directory::exists(target)) return failure("game already exists");
|
||||
|
||||
string markup;
|
||||
|
||||
if(settings.useHeuristics && !markup) {
|
||||
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
|
||||
GameBoyAdvanceCartridge cartridge{buffer.data(), buffer.size()};
|
||||
if(markup = cartridge.markup) {
|
||||
markup.append("\n");
|
||||
|
@ -38,7 +38,7 @@ auto Icarus::gameBoyAdvanceImport(vector<uint8_t>& buffer, const string& locatio
|
|||
if(!markup) return failure("failed to parse ROM image");
|
||||
if(!directory::create(target)) return failure("library path unwritable");
|
||||
|
||||
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);
|
||||
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
|
||||
file::write({target, "program.rom"}, buffer);
|
||||
return success();
|
||||
}
|
||||
|
|
|
@ -20,12 +20,12 @@ auto Icarus::gameBoyColorManifest(vector<uint8_t>& buffer, const string& locatio
|
|||
auto Icarus::gameBoyColorImport(vector<uint8_t>& buffer, const string& location) -> bool {
|
||||
auto name = prefixname(location);
|
||||
auto source = pathname(location);
|
||||
string target{settings.libraryPath, "Game Boy Color/", name, ".gbc/"};
|
||||
string target{settings["Library/Location"].text(), "Game Boy Color/", name, ".gbc/"};
|
||||
//if(directory::exists(target)) return failure("game already exists");
|
||||
|
||||
string markup;
|
||||
|
||||
if(settings.useHeuristics && !markup) {
|
||||
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
|
||||
GameBoyCartridge cartridge{buffer.data(), buffer.size()};
|
||||
if(markup = cartridge.markup) {
|
||||
markup.append("\n");
|
||||
|
@ -38,7 +38,7 @@ auto Icarus::gameBoyColorImport(vector<uint8_t>& buffer, const string& location)
|
|||
if(!markup) return failure("failed to parse ROM image");
|
||||
if(!directory::create(target)) return failure("library path unwritable");
|
||||
|
||||
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);
|
||||
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
|
||||
file::write({target, "program.rom"}, buffer);
|
||||
return success();
|
||||
}
|
||||
|
|
|
@ -20,12 +20,12 @@ auto Icarus::gameBoyManifest(vector<uint8_t>& buffer, const string& location) ->
|
|||
auto Icarus::gameBoyImport(vector<uint8_t>& buffer, const string& location) -> bool {
|
||||
auto name = prefixname(location);
|
||||
auto source = pathname(location);
|
||||
string target{settings.libraryPath, "Game Boy/", name, ".gb/"};
|
||||
string target{settings["Library/Location"].text(), "Game Boy/", name, ".gb/"};
|
||||
//if(directory::exists(target)) return failure("game already exists");
|
||||
|
||||
string markup;
|
||||
|
||||
if(settings.useHeuristics && !markup) {
|
||||
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
|
||||
GameBoyCartridge cartridge{buffer.data(), buffer.size()};
|
||||
if(markup = cartridge.markup) {
|
||||
markup.append("\n");
|
||||
|
@ -38,7 +38,7 @@ auto Icarus::gameBoyImport(vector<uint8_t>& buffer, const string& location) -> b
|
|||
if(!markup) return failure("failed to parse ROM image");
|
||||
if(!directory::create(target)) return failure("library path unwritable");
|
||||
|
||||
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);
|
||||
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
|
||||
file::write({target, "program.rom"}, buffer);
|
||||
return success();
|
||||
}
|
||||
|
|
|
@ -20,12 +20,12 @@ auto Icarus::sufamiTurboManifest(vector<uint8_t>& buffer, const string& location
|
|||
auto Icarus::sufamiTurboImport(vector<uint8_t>& buffer, const string& location) -> bool {
|
||||
auto name = prefixname(location);
|
||||
auto source = pathname(location);
|
||||
string target{settings.libraryPath, "Sufami Turbo/", name, ".st/"};
|
||||
string target{settings["Library/Location"].text(), "Sufami Turbo/", name, ".st/"};
|
||||
//if(directory::exists(target)) return failure("game already exists");
|
||||
|
||||
string markup;
|
||||
|
||||
if(settings.useDatabase && !markup) {
|
||||
if(settings["icarus/UseDatabase"].boolean() && !markup) {
|
||||
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
|
||||
for(auto node : database.sufamiTurbo) {
|
||||
if(node.name() != "release") continue;
|
||||
|
@ -37,7 +37,7 @@ auto Icarus::sufamiTurboImport(vector<uint8_t>& buffer, const string& location)
|
|||
}
|
||||
}
|
||||
|
||||
if(settings.useHeuristics && !markup) {
|
||||
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
|
||||
SufamiTurboCartridge cartridge{buffer.data(), buffer.size()};
|
||||
if(markup = cartridge.markup) {
|
||||
markup.append("\n");
|
||||
|
@ -50,7 +50,7 @@ auto Icarus::sufamiTurboImport(vector<uint8_t>& buffer, const string& location)
|
|||
if(!markup) return failure("failed to parse ROM image");
|
||||
if(!directory::create(target)) return failure("library path unwritable");
|
||||
|
||||
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);
|
||||
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
|
||||
file::write({target, "program.rom"}, buffer);
|
||||
return success();
|
||||
}
|
||||
|
|
|
@ -25,14 +25,14 @@ auto Icarus::superFamicomManifest(vector<uint8_t>& buffer, const string& locatio
|
|||
auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location) -> bool {
|
||||
auto name = prefixname(location);
|
||||
auto source = pathname(location);
|
||||
string target{settings.libraryPath, "Super Famicom/", name, ".sfc/"};
|
||||
string target{settings["Library/Location"].text(), "Super Famicom/", name, ".sfc/"};
|
||||
//if(directory::exists(target)) return failure("game already exists");
|
||||
|
||||
string markup;
|
||||
vector<Markup::Node> roms;
|
||||
bool firmwareAppended = true;
|
||||
|
||||
if(settings.useDatabase && !markup) {
|
||||
if(settings["icarus/UseDatabase"].boolean() && !markup) {
|
||||
auto digest = Hash::SHA256(buffer.data(), buffer.size()).digest();
|
||||
for(auto node : database.superFamicom) {
|
||||
if(node.name() != "release") continue;
|
||||
|
@ -44,7 +44,7 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
|
|||
}
|
||||
}
|
||||
|
||||
if(settings.useHeuristics && !markup) {
|
||||
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
|
||||
SuperFamicomCartridge cartridge{buffer.data(), buffer.size()};
|
||||
if(markup = cartridge.markup) {
|
||||
firmwareAppended = cartridge.firmware_appended;
|
||||
|
@ -59,7 +59,7 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
|
|||
superFamicomImportScanManifest(roms, document["cartridge"]);
|
||||
for(auto rom : roms) {
|
||||
auto name = rom["name"].text();
|
||||
auto size = rom["size"].decimal();
|
||||
auto size = rom["size"].natural();
|
||||
if(name == "program.rom" || name == "data.rom" || firmwareAppended) continue;
|
||||
if(file::size({source, name}) != size) return failure({"firmware (", name, ") missing or invalid"});
|
||||
}
|
||||
|
@ -67,11 +67,11 @@ auto Icarus::superFamicomImport(vector<uint8_t>& buffer, const string& location)
|
|||
if(!markup) return failure("failed to parse ROM image");
|
||||
if(!directory::create(target)) return failure("library path unwritable");
|
||||
|
||||
if(settings.createManifests) file::write({target, "manifest.bml"}, markup);
|
||||
if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, markup);
|
||||
unsigned offset = (buffer.size() & 0x7fff) == 512 ? 512 : 0; //skip header if present
|
||||
for(auto rom : roms) {
|
||||
auto name = rom["name"].text();
|
||||
auto size = rom["size"].decimal();
|
||||
auto size = rom["size"].natural();
|
||||
if(name == "program.rom" || name == "data.rom" || firmwareAppended) {
|
||||
if(size > buffer.size() - offset) return failure("ROM image is missing data");
|
||||
file::write({target, name}, buffer.data() + offset, size);
|
||||
|
|
|
@ -4,6 +4,14 @@ using namespace nall;
|
|||
#include <hiro/hiro.hpp>
|
||||
using namespace hiro;
|
||||
|
||||
//if file already exists in the same path as the binary; use it (portable mode)
|
||||
//if not, use default requested path (*nix/user mode)
|
||||
auto locate(string pathname, string filename) -> string {
|
||||
string location{programpath(), filename};
|
||||
if(file_system_object::exists(location)) return location;
|
||||
return {pathname, filename};
|
||||
}
|
||||
|
||||
#include "settings.cpp"
|
||||
Settings settings;
|
||||
|
||||
|
@ -27,6 +35,7 @@ Icarus icarus;
|
|||
|
||||
#include "ui/ui.hpp"
|
||||
#include "ui/scan-dialog.cpp"
|
||||
#include "ui/settings-dialog.cpp"
|
||||
#include "ui/import-dialog.cpp"
|
||||
#include "ui/error-dialog.cpp"
|
||||
|
||||
|
@ -38,6 +47,7 @@ auto nall::main(lstring args) -> void {
|
|||
}
|
||||
|
||||
new ScanDialog;
|
||||
new SettingsDialog;
|
||||
new ImportDialog;
|
||||
new ErrorDialog;
|
||||
scanDialog->show();
|
||||
|
|
|
@ -1,31 +1,24 @@
|
|||
struct Settings : Configuration::Document {
|
||||
struct Settings : Markup::Node {
|
||||
Settings();
|
||||
~Settings();
|
||||
|
||||
Configuration::Node root;
|
||||
string activePath;
|
||||
string libraryPath;
|
||||
bool createManifests = false;
|
||||
bool useDatabase = true;
|
||||
bool useHeuristics = true;
|
||||
};
|
||||
|
||||
Settings::Settings() {
|
||||
root.append(activePath, "ActivePath");
|
||||
root.append(libraryPath, "LibraryPath");
|
||||
root.append(createManifests, "CreateManifests");
|
||||
root.append(useDatabase, "UseDatabase");
|
||||
root.append(useHeuristics, "UseHeuristics");
|
||||
append(root, "Settings");
|
||||
Markup::Node::operator=(BML::unserialize(string::read(locate({configpath(), "icarus/"}, "settings.bml"))));
|
||||
|
||||
directory::create({configpath(), "icarus/"});
|
||||
load({configpath(), "icarus/settings.bml"});
|
||||
save({configpath(), "icarus/settings.bml"});
|
||||
auto set = [&](const string& name, const string& value) {
|
||||
//create node and set to default value only if it does not already exist
|
||||
if(!operator[](name)) operator()(name).setValue(value);
|
||||
};
|
||||
|
||||
if(!activePath) activePath = userpath();
|
||||
if(!libraryPath) libraryPath = {userpath(), "Emulation/"};
|
||||
set("Library/Location", {userpath(), "Emulation/"});
|
||||
|
||||
set("icarus/Path", userpath());
|
||||
set("icarus/CreateManifests", false);
|
||||
set("icarus/UseDatabase", true);
|
||||
set("icarus/UseHeuristics", true);
|
||||
}
|
||||
|
||||
Settings::~Settings() {
|
||||
save({configpath(), "icarus/settings.bml"});
|
||||
file::write(locate({configpath(), "icarus/"}, "settings.bml"), BML::serialize(*this));
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ ScanDialog::ScanDialog() {
|
|||
layout.setMargin(5);
|
||||
pathEdit.onActivate([&] { refresh(); });
|
||||
refreshButton.setImage(Icon::Action::Refresh).setBordered(false).onActivate([&] {
|
||||
pathEdit.setText(settings.activePath);
|
||||
pathEdit.setText(settings["icarus/Path"].text());
|
||||
refresh();
|
||||
});
|
||||
homeButton.setImage(Icon::Go::Home).setBordered(false).onActivate([&] {
|
||||
|
@ -13,7 +13,7 @@ ScanDialog::ScanDialog() {
|
|||
refresh();
|
||||
});
|
||||
upButton.setImage(Icon::Go::Up).setBordered(false).onActivate([&] {
|
||||
pathEdit.setText(dirname(settings.activePath));
|
||||
pathEdit.setText(dirname(settings["icarus/Path"].text()));
|
||||
refresh();
|
||||
});
|
||||
scanList.onActivate([&] { activate(); });
|
||||
|
@ -27,8 +27,10 @@ ScanDialog::ScanDialog() {
|
|||
if(item.cell(0).checkable()) item.cell(0).setChecked(false);
|
||||
}
|
||||
});
|
||||
createManifestsLabel.setChecked(settings.createManifests).setText("Create Manifests").onToggle([&] {
|
||||
settings.createManifests = createManifestsLabel.checked();
|
||||
settingsButton.setText("Settings ...").onActivate([&] {
|
||||
settingsDialog->setCentered(*this);
|
||||
settingsDialog->setVisible();
|
||||
settingsDialog->setFocused();
|
||||
});
|
||||
importButton.setText("Import ...").onActivate([&] { import(); });
|
||||
|
||||
|
@ -39,7 +41,7 @@ ScanDialog::ScanDialog() {
|
|||
|
||||
auto ScanDialog::show() -> void {
|
||||
setVisible();
|
||||
pathEdit.setText(settings.activePath);
|
||||
pathEdit.setText(settings["icarus/Path"].text());
|
||||
refresh();
|
||||
}
|
||||
|
||||
|
@ -50,7 +52,8 @@ auto ScanDialog::refresh() -> void {
|
|||
auto pathname = pathEdit.text().transform("\\", "/").rtrim("/").append("/");
|
||||
if(!directory::exists(pathname)) return;
|
||||
|
||||
pathEdit.setText(settings.activePath = pathname);
|
||||
settings["icarus/Path"].setValue(pathname);
|
||||
pathEdit.setText(pathname);
|
||||
auto contents = directory::icontents(pathname);
|
||||
|
||||
for(auto& name : contents) {
|
||||
|
@ -72,7 +75,7 @@ auto ScanDialog::refresh() -> void {
|
|||
|
||||
auto ScanDialog::activate() -> void {
|
||||
if(auto item = scanList.selected()) {
|
||||
string location{settings.activePath, item.cell(0).text()};
|
||||
string location{settings["icarus/Path"].text(), item.cell(0).text()};
|
||||
if(directory::exists(location) && !gamePakType(suffixname(location))) {
|
||||
pathEdit.setText(location);
|
||||
refresh();
|
||||
|
@ -84,7 +87,7 @@ auto ScanDialog::import() -> void {
|
|||
lstring filenames;
|
||||
for(auto& item : scanList.items()) {
|
||||
if(item.cell(0).checked()) {
|
||||
filenames.append(string{settings.activePath, item.cell(0).text()});
|
||||
filenames.append(string{settings["icarus/Path"].text(), item.cell(0).text()});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
SettingsDialog::SettingsDialog() {
|
||||
settingsDialog = this;
|
||||
|
||||
layout.setMargin(5);
|
||||
locationLabel.setText("Library Location:");
|
||||
locationEdit.setEditable(false).setText(settings["Library/Location"].text());
|
||||
changeLocationButton.setText("Change ...").onActivate([&] {
|
||||
if(auto location = BrowserDialog().setParent(*this).setTitle("Select Library Location").selectFolder()) {
|
||||
settings["Library/Location"].setValue(location);
|
||||
locationEdit.setText(location);
|
||||
}
|
||||
});
|
||||
createManifestsOption.setText("Create Manifests (not recommended; breaks backward-compatibility)")
|
||||
.setChecked(settings["icarus/CreateManifests"].boolean()).onToggle([&] {
|
||||
settings["icarus/CreateManifests"].setValue(createManifestsOption.checked());
|
||||
});
|
||||
useDatabaseOption.setText("Use Database (highly recommended; provides bit-perfect memory mapping)")
|
||||
.setChecked(settings["icarus/UseDatabase"].boolean()).onToggle([&] {
|
||||
settings["icarus/UseDatabase"].setValue(useDatabaseOption.checked());
|
||||
});
|
||||
|
||||
setTitle("icarus Settings");
|
||||
setSize({480, layout.minimumSize().height()});
|
||||
}
|
|
@ -19,8 +19,21 @@ struct ScanDialog : Window {
|
|||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Button selectAllButton{&controlLayout, Size{100, 0}};
|
||||
Button unselectAllButton{&controlLayout, Size{100, 0}};
|
||||
CheckLabel createManifestsLabel{&controlLayout, Size{~0, 0}};
|
||||
Button importButton{&controlLayout, Size{80, 0}};
|
||||
Widget controlSpacer{&controlLayout, Size{~0, 0}};
|
||||
Button settingsButton{&controlLayout, Size{100, 0}};
|
||||
Button importButton{&controlLayout, Size{100, 0}};
|
||||
};
|
||||
|
||||
struct SettingsDialog : Window {
|
||||
SettingsDialog();
|
||||
|
||||
VerticalLayout layout{this};
|
||||
HorizontalLayout locationLayout{&layout, Size{~0, 0}};
|
||||
Label locationLabel{&locationLayout, Size{0, 0}};
|
||||
LineEdit locationEdit{&locationLayout, Size{~0, 0}};
|
||||
Button changeLocationButton{&locationLayout, Size{80, 0}};
|
||||
CheckLabel createManifestsOption{&layout, Size{~0, 0}, 2};
|
||||
CheckLabel useDatabaseOption{&layout, Size{~0, 0}};
|
||||
};
|
||||
|
||||
struct ImportDialog : Window {
|
||||
|
@ -50,5 +63,6 @@ struct ErrorDialog : Window {
|
|||
};
|
||||
|
||||
ScanDialog* scanDialog = nullptr;
|
||||
SettingsDialog* settingsDialog = nullptr;
|
||||
ImportDialog* importDialog = nullptr;
|
||||
ErrorDialog* errorDialog = nullptr;
|
||||
|
|
Loading…
Reference in New Issue