Update to v076r01 release.

byuu says:

Changelog:
- fixed linear mirroring issue in memory map (fixes dash in Mega Man X)
- home path for Windows is now %APPDATA%/bsnes (not %APPDATA%/.bsnes)
- home path for OS X and Linux is now ~/.config/bsnes (not ~/.bsnes)
- bsnes-geometry.cfg is now geometry.cfg; and it stores width,height
- I do not yet restore width, height; because the GTK+ and Qt APIs treat window
  resize as implying setMinimumSize
- added bsnes/ui/path; which I have some significant plans for
- fixed a bug in realpath (specified path is not always a folder, so we should
  not always append / as with userpath)
- bsnes.cfg, geometry.cfg and cheats.xml may now optionally exist in the same
  folder as the binary itself
- ruby only imports the nall namespace after including system headers (should
  fix OS X 'decimal' issue)
- nall::fp now uses atof (fixes nall::fp("0.05"))
- I split the CheatDatabase to a separate cheat-database.cpp file; it was
  pretty ugly packed into cheat-editor.cpp
- Makefile now has "options := " line; where you can add "debugger" if you
  like, and in the future maybe more options
  - also works via command-line: make options=debugger
This commit is contained in:
Tim Allen 2011-03-01 10:45:31 +11:00
parent 64072325c4
commit bc5fd8c53c
20 changed files with 172 additions and 169 deletions

View File

@ -1,9 +1,12 @@
include nall/Makefile include nall/Makefile
snes := snes snes := snes
gameboy := gameboy gameboy := gameboy
profile := accuracy profile := compatibility
ui := ui ui := ui
# debugger
options :=
# compiler # compiler
c := $(compiler) -std=gnu99 c := $(compiler) -std=gnu99
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
@ -18,9 +21,11 @@ objects := libco
# profile-guided optimization # profile-guided optimization
# flags += -fprofile-use # flags += -fprofile-use
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
# platform # platform
ifeq ($(platform),x) ifeq ($(platform),x)
link += -s -ldl -lX11 -lXext link += -ldl -lX11 -lXext
else ifeq ($(platform),osx) else ifeq ($(platform),osx)
else ifeq ($(platform),win) else ifeq ($(platform),win)
link += -mwindows link += -mwindows

View File

@ -117,38 +117,7 @@ uintmax_t binary(const char *str) {
} }
double fp(const char *str) { double fp(const char *str) {
if(!str) return 0.0; return atof(str);
bool negate = false;
//check for negation
if(*str == '-') {
negate = true;
str++;
}
intmax_t result_integral = 0;
while(*str) {
uint8_t x = *str++;
if(x >= '0' && x <= '9') x -= '0';
else if(x == '.' || x == ',') break; //break loop and read fractional part
else return (double)result_integral; //invalid value, assume no fractional part
result_integral = result_integral * 10 + x;
}
intmax_t result_fractional = 0;
while(*str) {
uint8_t x = *str++;
if(x >= '0' && x <= '9') x -= '0';
else break; //stop at first invalid character
result_fractional = result_fractional * 10 + x;
}
//calculate fractional portion
double result = (double)result_fractional;
while((uintmax_t)result > 0) result /= 10.0;
result += (double)result_integral;
return !negate ? result : -result;
} }
} }

View File

@ -8,7 +8,6 @@ string realpath(const char *name) {
if(::realpath(name, path)) { if(::realpath(name, path)) {
string result(path); string result(path);
result.transform("\\", "/"); result.transform("\\", "/");
if(result.endswith("/") == false) result.append("/");
return result; return result;
} }
return ""; return "";

View File

@ -1,5 +1,4 @@
#include <ruby/ruby.hpp> #include <ruby/ruby.hpp>
using namespace nall;
#undef mkdir #undef mkdir
#undef usleep #undef usleep

View File

@ -1,6 +1,6 @@
/* /*
ruby ruby
version: 0.06 (2009-05-22) version: 0.06a (2011-02-27)
license: public domain license: public domain
*/ */

View File

@ -24,6 +24,8 @@
#include <windows.h> #include <windows.h>
#endif #endif
using namespace nall;
/* Video */ /* Video */
#define DeclareVideo(Name) \ #define DeclareVideo(Name) \

View File

@ -44,12 +44,8 @@ void Bus::map(
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) { for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
for(unsigned addr = addr_lo; addr <= addr_hi; addr++) { for(unsigned addr = addr_lo; addr <= addr_hi; addr++) {
unsigned destaddr = (bank << 16) | addr; unsigned destaddr = (bank << 16) | addr;
if(mode == MapMode::Linear) { if(mode == MapMode::Linear) destaddr = mirror(base + offset++, length);
destaddr = mirror(base + offset, length); if(mode == MapMode::Shadow) destaddr = mirror(base + destaddr, length);
offset = (offset + 1) % length;
} else if(mode == MapMode::Shadow) {
destaddr = mirror(base + destaddr, length);
}
lookup[(bank << 16) | addr] = id; lookup[(bank << 16) | addr] = id;
target[(bank << 16) | addr] = destaddr; target[(bank << 16) | addr] = destaddr;
} }

View File

@ -1,13 +1,11 @@
namespace SNES { namespace SNES {
namespace Info { namespace Info {
static const char Name[] = "bsnes"; static const char Name[] = "bsnes";
static const char Version[] = "076"; static const char Version[] = "076.01";
static const unsigned SerializerVersion = 18; static const unsigned SerializerVersion = 18;
} }
} }
//#define DEBUGGER
#include <libco/libco.h> #include <libco/libco.h>
#include <nall/algorithm.hpp> #include <nall/algorithm.hpp>

View File

@ -1,7 +1,7 @@
include $(snes)/Makefile include $(snes)/Makefile
include $(gameboy)/Makefile include $(gameboy)/Makefile
ui_objects := ui-main ui-general ui-settings ui-tools ui-input ui-utility ui-cartridge ui-debugger ui_objects := ui-main ui-general ui-settings ui-tools ui-input ui-utility ui-path ui-cartridge ui-debugger
ui_objects += ruby phoenix ui_objects += ruby phoenix
ui_objects += $(if $(call streq,$(platform),win),resource) ui_objects += $(if $(call streq,$(platform),win),resource)
@ -68,6 +68,7 @@ obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwild
obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/settings/*) obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/settings/*)
obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/input/*) obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/input/*)
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/utility/*) obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/utility/*)
obj/ui-path.o: $(ui)/path/path.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/path/*)
obj/ui-cartridge.o: $(ui)/cartridge/cartridge.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/cartridge/*) obj/ui-cartridge.o: $(ui)/cartridge/cartridge.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/cartridge/*)
obj/ui-debugger.o: $(ui)/debugger/debugger.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/debugger/*) obj/ui-debugger.o: $(ui)/debugger/debugger.cpp $(call rwildcard,$(ui)/*.hpp) $(call rwildcard,$(ui)/debugger/*)

View File

@ -28,6 +28,7 @@ struct TopLevelWindow : Window {
#include "tools/tools.hpp" #include "tools/tools.hpp"
#include "input/input.hpp" #include "input/input.hpp"
#include "utility/utility.hpp" #include "utility/utility.hpp"
#include "path/path.hpp"
#include "cartridge/cartridge.hpp" #include "cartridge/cartridge.hpp"
#if defined(DEBUGGER) #if defined(DEBUGGER)

View File

@ -1,12 +1,11 @@
Configuration config; Configuration config;
void Configuration::load() { void Configuration::load() {
configuration::load(string(path.user, "bsnes.cfg")); configuration::load(::path.home("bsnes.cfg"));
} }
void Configuration::save() { void Configuration::save() {
mkdir(path.user, 0755); configuration::save(::path.home("bsnes.cfg"));
configuration::save(string(path.user, "bsnes.cfg"));
} }
void Configuration::create() { void Configuration::create() {

View File

@ -10,8 +10,8 @@ void Application::main(int argc, char **argv) {
config.create(); config.create();
inputMapper.create(); inputMapper.create();
config.path.base = realpath(argv[0]); config.path.base = dir(realpath(argv[0]));
config.path.user = { userpath(), ".bsnes/" }; config.path.user = userpath();
config.load(); config.load();
config.save(); config.save();
@ -57,6 +57,7 @@ void Application::main(int argc, char **argv) {
inputSettings.create(); inputSettings.create();
advancedSettings.create(); advancedSettings.create();
cheatEditor.create(); cheatEditor.create();
cheatDatabase.create();
stateManager.create(); stateManager.create();
#if defined(DEBUGGER) #if defined(DEBUGGER)
debugger.create(); debugger.create();
@ -158,19 +159,23 @@ int main(int argc, char **argv) {
} }
void Application::loadGeometry() { void Application::loadGeometry() {
geometryConfig.load(string(config.path.user, "bsnes-geometry.cfg")); geometryConfig.load(path.home("geometry.cfg"));
foreach(window, windows) { foreach(window, windows) {
lstring position; lstring position;
position.split(",", window->position); position.split(",", window->position);
Geometry geom = window->geometry(); Geometry geom = window->geometry();
window->setGeometry({ (signed)integer(position[0]), (signed)integer(position[1]), geom.width, geom.height }); window->setGeometry({
(signed)integer(position[0]), (signed)integer(position[1]),
geom.width, geom.height
//(unsigned)decimal(position[2]), (unsigned)decimal(position[3])
});
} }
} }
void Application::saveGeometry() { void Application::saveGeometry() {
foreach(window, windows) { foreach(window, windows) {
Geometry geom = window->geometry(); Geometry geom = window->geometry();
window->position = { geom.x, ",", geom.y }; window->position = { geom.x, ",", geom.y, ",", geom.width, ",", geom.height };
} }
geometryConfig.save(string(config.path.user, "bsnes-geometry.cfg")); geometryConfig.save(path.home("geometry.cfg"));
} }

20
bsnes/ui/path/path.cpp Executable file
View File

@ -0,0 +1,20 @@
#include "../base.hpp"
Path path;
string Path::home(const string &filename) {
string path = { config.path.base, filename };
if(file::exists(path)) return path;
path = config.path.user;
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
path.append(".config/");
mkdir(path, 0755);
path.append("bsnes/");
mkdir(path, 0755);
#else
path.append("bsnes/");
mkdir(path, 0755);
#endif
path.append(filename);
return path;
}

5
bsnes/ui/path/path.hpp Executable file
View File

@ -0,0 +1,5 @@
struct Path {
string home(const string &filename);
};
extern Path path;

View File

@ -0,0 +1,93 @@
CheatDatabase cheatDatabase;
void CheatDatabase::create() {
application.addWindow(this, "CheatDatabase", "192,192");
listView.setCheckable(true);
selectAllButton.setText("Select All");
unselectAllButton.setText("Unselect All");
okButton.setText("Ok");
layout.setMargin(5);
layout.append(listView, 0, 0, 5);
controlLayout.append(selectAllButton, 100, 0, 5);
controlLayout.append(unselectAllButton, 100, 0);
controlLayout.append(spacerWidget, 0, 0);
controlLayout.append(okButton, 80, 0);
layout.append(controlLayout, 0, Style::ButtonHeight);
setGeometry({ 0, 0, 600, layout.minimumHeight() + 350 });
append(layout);
selectAllButton.onTick = [this]() {
foreach(item, this->listData, n) this->listView.setChecked(n, true);
};
unselectAllButton.onTick = [this]() {
foreach(item, this->listData, n) this->listView.setChecked(n, false);
};
okButton.onTick = { &CheatDatabase::addCodes, this };
}
void CheatDatabase::findCodes() {
string data;
data.readfile(path.home("cheats.xml"));
if(auto position = strpos(data, SNES::cartridge.sha256())) {
auto startPosition = strpos((const char*)data + position(), ">");
auto endPosition = strpos((const char*)data + position(), "</cartridge>");
string xmlData = {
"<cartridge>\n",
substr((const char*)data + position() + 1, startPosition(), endPosition() - startPosition() - 1),
"</cartridge>\n"
};
setTitle("");
listView.reset();
listData.reset();
xml_element document = xml_parse(xmlData);
foreach(root, document.element) {
if(root.name == "cartridge") foreach(node, root.element) {
if(node.name == "name") setTitle(node.parse());
else if(node.name == "cheat") {
string description, code;
foreach(element, node.element) {
if(element.name == "description") description = element.parse();
else if(element.name == "code") code.append(string(element.parse(), "+"));
}
code.rtrim<1>("+");
code.append("\t");
code.append(description);
listView.append(description);
listData.append(code);
}
}
}
setVisible(true);
} else {
MessageWindow::information(cheatEditor, "Sorry, no cheat codes found for this cartridge.");
}
}
void CheatDatabase::addCodes() {
foreach(code, listData, n) {
if(listView.checked(n)) {
if(auto position = cheatEditor.findUnusedSlot()) {
lstring part;
part.split("\t", code);
SNES::cheat[position()].enabled = false;
SNES::cheat[position()] = part[0];
cheatEditor.cheatList.setChecked(position(), false);
cheatEditor.cheatText[position()][CheatEditor::CheatCode] = part[0];
cheatEditor.cheatText[position()][CheatEditor::CheatDesc] = part[1];
} else {
MessageWindow::warning(*this, "Ran out of empty slots for cheat codes.\nNot all cheat codes were added.");
break;
}
}
}
setVisible(false);
cheatEditor.refresh();
cheatEditor.synchronize();
}

View File

@ -0,0 +1,16 @@
struct CheatDatabase : TopLevelWindow {
VerticalLayout layout;
ListView listView;
HorizontalLayout controlLayout;
Button selectAllButton;
Button unselectAllButton;
Widget spacerWidget;
Button okButton;
lstring listData;
void create();
void findCodes();
void addCodes();
};
extern CheatDatabase cheatDatabase;

View File

@ -100,7 +100,7 @@ void CheatEditor::create() {
descLayout.append(descEdit, 0, 0); descLayout.append(descEdit, 0, 0);
layout.append(descLayout, 0, Style::LineEditHeight, 5); layout.append(descLayout, 0, Style::LineEditHeight, 5);
controlLayout.append(findButton, 100, 0); controlLayout.append(findButton, 100, 0);
controlLayout.append(spacer, 0, 0); controlLayout.append(spacerWidget, 0, 0);
controlLayout.append(clearAllButton, 80, 0, 5); controlLayout.append(clearAllButton, 80, 0, 5);
controlLayout.append(clearButton, 80, 0); controlLayout.append(clearButton, 80, 0);
layout.append(controlLayout, 0, Style::ButtonHeight); layout.append(controlLayout, 0, Style::ButtonHeight);
@ -113,46 +113,13 @@ void CheatEditor::create() {
cheatList.onChange = { &CheatEditor::synchronize, this }; cheatList.onChange = { &CheatEditor::synchronize, this };
cheatList.onTick = { &CheatEditor::toggle, this }; cheatList.onTick = { &CheatEditor::toggle, this };
codeEdit.onChange = descEdit.onChange = { &CheatEditor::bind, this }; codeEdit.onChange = descEdit.onChange = { &CheatEditor::bind, this };
findButton.onTick = { &CheatEditor::findCodes, this }; findButton.onTick = { &CheatDatabase::findCodes, &cheatDatabase };
clearAllButton.onTick = { &CheatEditor::clearAll, this }; clearAllButton.onTick = { &CheatEditor::clearAll, this };
clearButton.onTick = { &CheatEditor::clear, this }; clearButton.onTick = { &CheatEditor::clear, this };
onClose = []() { onClose = []() {
cheatEditor.databaseWindow.setVisible(false); cheatDatabase.setVisible(false);
}; };
//databaseWindow
application.addWindow(&databaseWindow, "CheatDatabase", "192,192");
databaseList.setCheckable(true);
databaseSelectAll.setText("Select All");
databaseUnselectAll.setText("Unselect All");
databaseOk.setText("Ok");
databaseLayout.setMargin(5);
databaseLayout.append(databaseList, 0, 0, 5);
databaseControlLayout.append(databaseSelectAll, 100, 0, 5);
databaseControlLayout.append(databaseUnselectAll, 100, 0);
databaseControlLayout.append(databaseSpacer, 0, 0);
databaseControlLayout.append(databaseOk, 80, 0);
databaseLayout.append(databaseControlLayout, 0, Style::ButtonHeight);
databaseWindow.setGeometry({ 0, 0, 600, layout.minimumHeight() + 250 });
databaseWindow.append(databaseLayout);
databaseSelectAll.onTick = []() {
for(unsigned i = 0; i < cheatEditor.databaseCode.size(); i++) {
cheatEditor.databaseList.setChecked(i, true);
}
};
databaseUnselectAll.onTick = []() {
for(unsigned i = 0; i < cheatEditor.databaseCode.size(); i++) {
cheatEditor.databaseList.setChecked(i, false);
}
};
databaseOk.onTick = { &CheatEditor::addDatabaseCodes, this };
} }
void CheatEditor::synchronize() { void CheatEditor::synchronize() {
@ -201,48 +168,6 @@ void CheatEditor::bind() {
refresh(); refresh();
} }
void CheatEditor::findCodes() {
string data;
data.readfile(string(config.path.user, "cheats.xml"));
if(data == "") data.readfile(string(config.path.base, "cheats.xml"));
if(auto position = strpos(data, SNES::cartridge.sha256())) {
auto startPosition = strpos((const char*)data + position(), ">");
auto endPosition = strpos((const char*)data + position(), "</cartridge>");
string xmlData = {
"<cartridge>\n",
substr((const char*)data + position() + 1, startPosition(), endPosition() - startPosition() - 1),
"</cartridge>\n"
};
databaseWindow.setTitle("");
databaseList.reset();
databaseCode.reset();
xml_element document = xml_parse(xmlData);
foreach(root, document.element) {
if(root.name == "cartridge") foreach(node, root.element) {
if(node.name == "name") databaseWindow.setTitle(node.parse());
else if(node.name == "cheat") {
string description, code;
foreach(element, node.element) {
if(element.name == "description") description = element.parse();
else if(element.name == "code") code.append(string(element.parse(), "+"));
}
code.rtrim<1>("+");
code.append("\t");
code.append(description);
databaseList.append(description);
databaseCode.append(code);
}
}
}
databaseWindow.setVisible(true);
} else {
MessageWindow::information(cheatEditor, "Sorry, no cheat codes found for this cartridge.");
}
}
optional<unsigned> CheatEditor::findUnusedSlot() { optional<unsigned> CheatEditor::findUnusedSlot() {
for(unsigned i = 0; i < 128; i++) { for(unsigned i = 0; i < 128; i++) {
if(cheatText[i][CheatCode] == "" && cheatText[i][CheatDesc] == "") return { true, i }; if(cheatText[i][CheatCode] == "" && cheatText[i][CheatDesc] == "") return { true, i };
@ -250,28 +175,6 @@ optional<unsigned> CheatEditor::findUnusedSlot() {
return { false, 0 }; return { false, 0 };
} }
void CheatEditor::addDatabaseCodes() {
for(unsigned n = 0; n < databaseCode.size(); n++) {
if(databaseList.checked(n)) {
if(auto position = findUnusedSlot()) {
lstring part;
part.split("\t", databaseCode[n]);
SNES::cheat[position()].enabled = false;
SNES::cheat[position()] = part[0];
cheatList.setChecked(position(), false);
cheatText[position()][CheatCode] = part[0];
cheatText[position()][CheatDesc] = part[1];
} else {
MessageWindow::warning(databaseWindow, "Ran out of empty slots for cheat codes.\nNot all cheat codes were added.");
break;
}
}
}
databaseWindow.setVisible(false);
refresh();
synchronize();
}
void CheatEditor::clearAll() { void CheatEditor::clearAll() {
if(MessageWindow::question(cheatEditor, "Permanently erase all entered cheat codes?", MessageWindow::Buttons::YesNo) == MessageWindow::Response::Yes) { if(MessageWindow::question(cheatEditor, "Permanently erase all entered cheat codes?", MessageWindow::Buttons::YesNo) == MessageWindow::Response::Yes) {
for(unsigned i = 0; i < 128; i++) { for(unsigned i = 0; i < 128; i++) {

View File

@ -8,21 +8,11 @@ struct CheatEditor : TopLevelWindow {
Label descLabel; Label descLabel;
LineEdit descEdit; LineEdit descEdit;
HorizontalLayout controlLayout; HorizontalLayout controlLayout;
Label spacer; Widget spacerWidget;
Button findButton; Button findButton;
Button clearAllButton; Button clearAllButton;
Button clearButton; Button clearButton;
TopLevelWindow databaseWindow;
VerticalLayout databaseLayout;
ListView databaseList;
HorizontalLayout databaseControlLayout;
Button databaseSelectAll;
Button databaseUnselectAll;
Label databaseSpacer;
Button databaseOk;
lstring databaseCode;
void load(string filename); void load(string filename);
void save(string filename); void save(string filename);
void create(); void create();
@ -34,11 +24,11 @@ private:
void refresh(); void refresh();
void toggle(unsigned row); void toggle(unsigned row);
void bind(); void bind();
void findCodes();
optional<unsigned> findUnusedSlot(); optional<unsigned> findUnusedSlot();
void addDatabaseCodes();
void clearAll(); void clearAll();
void clear(); void clear();
friend class CheatDatabase;
}; };
extern CheatEditor cheatEditor; extern CheatEditor cheatEditor;

View File

@ -1,3 +1,4 @@
#include "../base.hpp" #include "../base.hpp"
#include "cheat-editor.cpp" #include "cheat-editor.cpp"
#include "cheat-database.cpp"
#include "state-manager.cpp" #include "state-manager.cpp"

View File

@ -1,2 +1,3 @@
#include "cheat-editor.hpp" #include "cheat-editor.hpp"
#include "cheat-database.hpp"
#include "state-manager.hpp" #include "state-manager.hpp"