[GB] Add support for per-game overrides (#1370)

* [GB] Add support for per-game overrides

Alleyway is a buggy game that does not work properly when a Game Boy
Printer is connected. In order to work around this issue, this adds
upport for built-in per-software Game Boy overrides. In addition, this
renames various variables to make their meaning clearer.

* This only supports built-in overrides. External INI files are not
  supported.
* Only the Game Boy Printer option is supported, this only takes effect
  on game startup and the general configuration option is restored when
  the game is unloaded.
* As a result, it is possible to override the per-game override by
  manually setting the option while the game is running, this is working
  as intended.
* Future refactors of the option handling will manage overrides better.
* Switch `gbPrinterEnabled` default to off.

Fixes #1368
This commit is contained in:
Fabrice de Gans 2024-11-24 12:15:26 -08:00 committed by GitHub
parent 611f3a3409
commit a8ec85d536
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 57 additions and 27 deletions

View File

@ -70,7 +70,7 @@ extern struct CoreOptions {
int skipSaveGameBattery = 1;
int skipSaveGameCheats = 0;
int useBios = 0;
int winGbPrinterEnabled = 1;
int gbPrinterEnabled = 0;
uint32_t speedup_throttle = 100;
uint32_t speedup_frame_skip = 9;
uint32_t throttle = 100;

View File

@ -1416,7 +1416,7 @@ void gbWriteMemory(uint16_t address, uint8_t value)
EmuReseted = false;
gbMemory[0xff02] = value;
if (gbSerialOn && (GetLinkMode() == LINK_GAMEBOY_IPC || GetLinkMode() == LINK_GAMEBOY_SOCKET
|| GetLinkMode() == LINK_DISCONNECTED || coreOptions.winGbPrinterEnabled)) {
|| GetLinkMode() == LINK_DISCONNECTED || coreOptions.gbPrinterEnabled)) {
gbSerialTicks = GBSERIAL_CLOCK_TICKS;

4
src/gb-over.ini Normal file
View File

@ -0,0 +1,4 @@
# Game Boy Overrrides
[ALLEY WAY]
gbPrinter = 0

View File

@ -590,7 +590,7 @@ void retro_init(void)
coreOptions.parseDebug = true;
coreOptions.cheatsEnabled = 0;
coreOptions.skipSaveGameBattery = 0;
coreOptions.winGbPrinterEnabled = 0;
coreOptions.gbPrinterEnabled = 0;
struct retro_log_callback log;
struct retro_rumble_interface rumble;

View File

@ -189,7 +189,7 @@ struct option argOptions[] = {
{ "gb-emulator-type", required_argument, 0, OPT_GB_EMULATOR_TYPE },
{ "gb-frame-skip", required_argument, 0, OPT_GB_FRAME_SKIP },
{ "gb-palette-option", required_argument, 0, OPT_GB_PALETTE_OPTION },
{ "gb-printer", no_argument, &coreOptions.winGbPrinterEnabled, 1 },
{ "gb-printer", no_argument, &coreOptions.gbPrinterEnabled, 1 },
{ "gdb", required_argument, 0, 'G' },
{ "help", no_argument, &optPrintUsage, 1 },
{ "ifb-filter", required_argument, 0, 'I' },
@ -236,7 +236,7 @@ struct option argOptions[] = {
{ "no-speedup-mute", no_argument, 0, OPT_NO_SPEEDUP_MUTE },
{ "use-bios", no_argument, &coreOptions.useBios, 1 },
{ "verbose", required_argument, 0, 'v' },
{ "win-gb-printer-enabled", no_argument, &coreOptions.winGbPrinterEnabled, 1 },
{ "win-gb-printer-enabled", no_argument, &coreOptions.gbPrinterEnabled, 1 },
{ NULL, no_argument, NULL, 0 }
@ -351,7 +351,7 @@ void LoadConfig()
coreOptions.speedup_throttle_frame_skip = ReadPref("speedupThrottleFrameSkip", 0);
coreOptions.speedup_mute = ReadPref("speedupMute", 1);
coreOptions.useBios = ReadPrefHex("useBiosGBA");
coreOptions.winGbPrinterEnabled = ReadPref("gbPrinter", 0);
coreOptions.gbPrinterEnabled = ReadPref("gbPrinter", 0);
int soundQuality = (ReadPrefHex("soundQuality", 1));
switch (soundQuality) {

View File

@ -59,6 +59,7 @@ set(VBAM_WX_COMMON
${VBAM_GENERATED_DIR}/wx/builtin-over.h
${VBAM_GENERATED_DIR}/wx/cmdhandlers.h
${VBAM_GENERATED_DIR}/wx/cmd-evtable.h
${VBAM_GENERATED_DIR}/wx/gb-builtin-over.h
)
if(NOT ZIP_PROGRAM)
@ -642,6 +643,12 @@ add_custom_command(
DEPENDS ${CMAKE_SOURCE_DIR}/src/vba-over.ini ${BIN2C}
)
add_custom_command(
OUTPUT ${VBAM_GENERATED_DIR}/wx/gb-builtin-over.h
COMMAND ${BIN2C} ${CMAKE_SOURCE_DIR}/src/gb-over.ini ${VBAM_GENERATED_DIR}/wx/gb-builtin-over.h gb_builtin_over
DEPENDS ${CMAKE_SOURCE_DIR}/src/gb-over.ini ${BIN2C}
)
set(VBAM_LOCALIZABLE_FILES ${VBAM_WX_COMMON} ${VBAM_LOCALIZABLE_WX_CONFIG_FILES})
list(APPEND VBAM_LOCALIZABLE_FILES
audio/internal/dsound.cpp

View File

@ -1990,7 +1990,7 @@ EVT_HANDLER(GameBoyAdvanceConfigure, "Game Boy Advance options...")
XRCCTRL(*dlg, "GameCode", wxControl)
->SetLabel(s);
cmt = wxString((const char*)&g_rom[0xa0], wxConvLibc, 12);
wxFileConfig* cfg = wxGetApp().overrides;
wxFileConfig* cfg = wxGetApp().overrides_.get();
if (cfg->HasGroup(s)) {
cfg->SetPath(s);
@ -2024,7 +2024,7 @@ EVT_HANDLER(GameBoyAdvanceConfigure, "Game Boy Advance options...")
if (panel->game_type() == IMAGE_GBA) {
agbPrintEnable(OPTION(kPrefAgbPrint));
wxString s = wxString((const char*)&g_rom[0xac], wxConvLibc, 4);
wxFileConfig* cfg = wxGetApp().overrides;
wxFileConfig* cfg = wxGetApp().overrides_.get();
bool chg;
if (cfg->HasGroup(s)) {
@ -2297,7 +2297,7 @@ EVT_HANDLER(RetainAspect, "Retain aspect ratio when resizing")
EVT_HANDLER(Printer, "Enable printer emulation")
{
GetMenuOptionInt("Printer", &coreOptions.winGbPrinterEnabled, 1);
GetMenuOptionInt("Printer", &coreOptions.gbPrinterEnabled, 1);
#if (defined __WIN32__ || defined _WIN32)
#ifndef NO_LINK
gbSerialFunction = gbStartLink;
@ -2305,7 +2305,7 @@ EVT_HANDLER(Printer, "Enable printer emulation")
gbSerialFunction = NULL;
#endif
#endif
if (coreOptions.winGbPrinterEnabled)
if (coreOptions.gbPrinterEnabled)
gbSerialFunction = gbPrinterSend;
update_opts();

View File

@ -312,7 +312,7 @@ std::array<Option, kNbOptions>& Option::All() {
Option(OptionID::kPrefFlashSize, &g_owned_opts.flash_size, 0, 1),
Option(OptionID::kPrefFrameSkip, &g_owned_opts.frame_skip, -1, 9),
Option(OptionID::kPrefGBPaletteOption, &gbPaletteOption, 0, 2),
Option(OptionID::kPrefGBPrinter, &coreOptions.winGbPrinterEnabled, 0, 1),
Option(OptionID::kPrefGBPrinter, &coreOptions.gbPrinterEnabled, 0, 1),
Option(OptionID::kPrefGDBBreakOnLoad, &g_owned_opts.gdb_break_on_load),
Option(OptionID::kPrefGDBPort, &gopts.gdb_port, 0, 65535),
#ifndef NO_LINK

View File

@ -287,6 +287,15 @@ void GameArea::LoadGame(const wxString& name)
gbApplyPatch(UTF8(pfn.GetFullPath()));
}
// Apply overrides.
wxFileConfig* cfg = wxGetApp().gb_overrides_.get();
const std::string& title = g_gbCartData.title();
if (cfg->HasGroup(title)) {
cfg->SetPath(title);
coreOptions.gbPrinterEnabled = cfg->Read("gbPrinter", coreOptions.gbPrinterEnabled);
cfg->SetPath("/");
}
// start sound; this must happen before CPU stuff
gb_effects_config.enabled = OPTION(kSoundGBEnableEffects);
gb_effects_config.surround = OPTION(kSoundGBSurround);
@ -359,7 +368,7 @@ void GameArea::LoadGame(const wxString& name)
gbaUpdateRomSize(size);
}
wxFileConfig* cfg = wxGetApp().overrides;
wxFileConfig* cfg = wxGetApp().overrides_.get();
wxString id = wxString((const char*)&g_rom[0xac], wxConvLibc, 4);
if (cfg->HasGroup(id)) {
@ -456,7 +465,7 @@ void GameArea::LoadGame(const wxString& name)
SuspendScreenSaver();
// probably only need to do this for GB carts
if (coreOptions.winGbPrinterEnabled)
if (coreOptions.gbPrinterEnabled)
gbSerialFunction = gbPrinterSend;
// probably only need to do this for GBA carts
@ -666,6 +675,9 @@ void GameArea::UnloadGame(bool destruct)
if (loaded == IMAGE_GB) {
gbCleanUp();
gbCheatRemoveAll();
// Reset overrides.
coreOptions.gbPrinterEnabled = OPTION(kPrefGBPrinter);
} else if (loaded == IMAGE_GBA) {
CPUCleanUp();
cheatsDeleteAll(false);

View File

@ -31,6 +31,7 @@
#include "components/user_config/user_config.h"
#include "core/gba/gbaSound.h"
#include "wx/gb-builtin-over.h"
#include "wx/builtin-over.h"
#include "wx/builtin-xrc.h"
#include "wx/config/cmdtab.h"
@ -470,13 +471,17 @@ bool wxvbamApp::OnInit() {
}
}
// load gb-over.ini
wxMemoryInputStream stream(gb_builtin_over, sizeof(gb_builtin_over));
gb_overrides_ = std::make_unique<wxFileConfig>(stream);
// load vba-over.ini
// rather than dealing with wxConfig's broken search path, just use
// the same one that the xrc overrides use
// this also allows us to override a group at a time, add commments, and
// add the file from which the group came
wxMemoryInputStream mis(builtin_over, sizeof(builtin_over));
overrides = new wxFileConfig(mis);
overrides_ = std::make_unique<wxFileConfig>(mis);
wxRegEx cmtre;
// not the most efficient thing to do: read entire file into a string
// just to parse the comments out
@ -486,8 +491,8 @@ bool wxvbamApp::OnInit() {
long grp_idx;
#define CMT_RE_START wxT("(^|[\n\r])# ?([^\n\r]*)(\r?\n|\r)\\[")
for (cont = overrides->GetFirstGroup(s, grp_idx); cont;
cont = overrides->GetNextGroup(s, grp_idx)) {
for (cont = overrides_->GetFirstGroup(s, grp_idx); cont;
cont = overrides_->GetNextGroup(s, grp_idx)) {
// apparently even MacOSX sometimes uses the old \r by itself
wxString cmt(CMT_RE_START);
cmt += s + wxT("\\]");
@ -497,7 +502,7 @@ bool wxvbamApp::OnInit() {
else
cmt = wxEmptyString;
overrides->Write(s + wxT("/comment"), cmt);
overrides_->Write(s + wxT("/comment"), cmt);
}
if (vba_over.FileExists()) {
@ -513,10 +518,10 @@ bool wxvbamApp::OnInit() {
for (cont = ov.GetFirstGroup(s, grp_idx); cont;
cont = ov.GetNextGroup(s, grp_idx)) {
overrides->DeleteGroup(s);
overrides->SetPath(s);
overrides_->DeleteGroup(s);
overrides_->SetPath(s);
ov.SetPath(s);
overrides->Write(wxT("path"), GetConfigurationPath());
overrides_->Write(wxT("path"), GetConfigurationPath());
// apparently even MacOSX sometimes uses \r by itself
wxString cmt(CMT_RE_START);
cmt += s + wxT("\\]");
@ -526,15 +531,15 @@ bool wxvbamApp::OnInit() {
else
cmt = wxEmptyString;
overrides->Write(wxT("comment"), cmt);
overrides_->Write(wxT("comment"), cmt);
long ent_idx;
for (cont = ov.GetFirstEntry(s, ent_idx); cont;
cont = ov.GetNextEntry(s, ent_idx))
overrides->Write(s, ov.Read(s, wxEmptyString));
overrides_->Write(s, ov.Read(s, wxEmptyString));
ov.SetPath(wxT("/"));
overrides->SetPath(wxT("/"));
overrides_->SetPath(wxT("/"));
}
}
@ -822,7 +827,6 @@ wxvbamApp::~wxvbamApp() {
free(home);
home = NULL;
}
delete overrides;
#ifndef NO_ONLINEUPDATES
shutdownAutoupdater();

View File

@ -1,11 +1,13 @@
#ifndef VBAM_WX_WXVBAM_H_
#define VBAM_WX_WXVBAM_H_
#include <cstdio>
#include <ctime>
#include <list>
#include <memory>
#include <stdexcept>
#include <iostream>
#include <stdio.h>
#include <time.h>
#include <wx/log.h>
#include <wx/propdlg.h>
#include <wx/datetime.h>
@ -106,7 +108,8 @@ public:
widgets::SdlPoller* sdl_poller() { return &sdl_poller_; }
// vba-over.ini
wxFileConfig* overrides = nullptr;
std::unique_ptr<wxFileConfig> overrides_;
std::unique_ptr<wxFileConfig> gb_overrides_;
wxFileName rom_database;
wxFileName rom_database_scene;