mirror of
https://github.com/mupen64plus/mupen64plus-ui-console.git
synced 2025-04-02 10:52:34 -04:00
Basic support for GB cart loader command.
Definition of GB carts loaded inside transferpak is done through the mupen64plus.cfg file as follow : [TransferPak] GB-rom-1 = "path/to/gb_rom.gb" GB-ram-1 = "path/to/gb_rom.sav" GB-rom-2 ... GB-ram-2 ... Setting an empty GB ROM acts as if GB cart was removed form TransferPak. Setting an empty GB RAM let the Core generate a blank save file. These parameters are modifiable during emulator execution. You just need to trigger the GB cart change button, and these parameters will be reloaded. You can also specify these at program startup using command-line arguments --gb-{rom,ram}-{1,2,3,4}
This commit is contained in:
parent
36d7cd8eb3
commit
5e17accad0
5 changed files with 227 additions and 3 deletions
2
README
2
README
|
@ -42,6 +42,8 @@ Parameters:
|
|||
--emumode (mode) : set emu mode to: 0=Pure Interpreter 1=Interpreter 2=DynaRec
|
||||
--testshots (list) : take screenshots at frames given in comma-separated (list), then quit
|
||||
--set (param-spec) : set a configuration variable, format: ParamSection[ParamName]=Value
|
||||
--gb-rom-{1,2,3,4} : define GB cart rom to load inside transferpak {1,2,3,4}"
|
||||
--gb-ram-{1,2,3,4} : define GB cart ram to load inside transferpak {1,2,3,4}"
|
||||
--core-compare-send : use the Core Comparison debugging feature, in data sending mode
|
||||
--core-compare-recv : use the Core Comparison debugging feature, in data receiving mode
|
||||
--nosaveoptions : do not save the given command-line options in configuration file
|
||||
|
|
|
@ -73,6 +73,10 @@ ptr_ConfigGetParamFloat ConfigGetParamFloat = NULL;
|
|||
ptr_ConfigGetParamBool ConfigGetParamBool = NULL;
|
||||
ptr_ConfigGetParamString ConfigGetParamString = NULL;
|
||||
|
||||
ptr_ConfigExternalOpen ConfigExternalOpen = NULL;
|
||||
ptr_ConfigExternalClose ConfigExternalClose = NULL;
|
||||
ptr_ConfigExternalGetParameter ConfigExternalGetParameter = NULL;
|
||||
|
||||
ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath = NULL;
|
||||
ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath = NULL;
|
||||
ptr_ConfigGetUserDataPath ConfigGetUserDataPath = NULL;
|
||||
|
@ -239,6 +243,10 @@ m64p_error AttachCoreLib(const char *CoreLibFilepath)
|
|||
ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreHandle, "ConfigGetParamBool");
|
||||
ConfigGetParamString = (ptr_ConfigGetParamString) osal_dynlib_getproc(CoreHandle, "ConfigGetParamString");
|
||||
|
||||
ConfigExternalOpen = (ptr_ConfigExternalOpen) osal_dynlib_getproc(CoreHandle, "ConfigExternalOpen");
|
||||
ConfigExternalClose = (ptr_ConfigExternalClose) osal_dynlib_getproc(CoreHandle, "ConfigExternalClose");
|
||||
ConfigExternalGetParameter = (ptr_ConfigExternalGetParameter) osal_dynlib_getproc(CoreHandle, "ConfigExternalGetParameter");
|
||||
|
||||
ConfigGetSharedDataFilepath = (ptr_ConfigGetSharedDataFilepath) osal_dynlib_getproc(CoreHandle, "ConfigGetSharedDataFilepath");
|
||||
ConfigGetUserConfigPath = (ptr_ConfigGetUserConfigPath) osal_dynlib_getproc(CoreHandle, "ConfigGetUserConfigPath");
|
||||
ConfigGetUserDataPath = (ptr_ConfigGetUserDataPath) osal_dynlib_getproc(CoreHandle, "ConfigGetUserDataPath");
|
||||
|
@ -304,6 +312,10 @@ m64p_error DetachCoreLib(void)
|
|||
ConfigGetParamBool = NULL;
|
||||
ConfigGetParamString = NULL;
|
||||
|
||||
ConfigExternalOpen = NULL;
|
||||
ConfigExternalClose = NULL;
|
||||
ConfigExternalGetParameter = NULL;
|
||||
|
||||
ConfigGetSharedDataFilepath = NULL;
|
||||
ConfigGetUserDataPath = NULL;
|
||||
ConfigGetUserCachePath = NULL;
|
||||
|
|
|
@ -70,6 +70,10 @@ extern ptr_ConfigGetParamFloat ConfigGetParamFloat;
|
|||
extern ptr_ConfigGetParamBool ConfigGetParamBool;
|
||||
extern ptr_ConfigGetParamString ConfigGetParamString;
|
||||
|
||||
extern ptr_ConfigExternalOpen ConfigExternalOpen;
|
||||
extern ptr_ConfigExternalClose ConfigExternalClose;
|
||||
extern ptr_ConfigExternalGetParameter ConfigExternalGetParameter;
|
||||
|
||||
extern ptr_ConfigGetSharedDataFilepath ConfigGetSharedDataFilepath;
|
||||
extern ptr_ConfigGetUserConfigPath ConfigGetUserConfigPath;
|
||||
extern ptr_ConfigGetUserDataPath ConfigGetUserDataPath;
|
||||
|
|
192
src/main.c
192
src/main.c
|
@ -22,9 +22,9 @@
|
|||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/* This is the main application entry point for the console-only front-end
|
||||
* for Mupen64Plus v2.0.
|
||||
* for Mupen64Plus v2.0.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -37,6 +37,7 @@
|
|||
#include "m64p_types.h"
|
||||
#include "main.h"
|
||||
#include "osal_preproc.h"
|
||||
#include "osal_files.h"
|
||||
#include "plugin.h"
|
||||
#include "version.h"
|
||||
|
||||
|
@ -56,6 +57,7 @@ int g_Verbose = 0;
|
|||
static m64p_handle l_ConfigCore = NULL;
|
||||
static m64p_handle l_ConfigVideo = NULL;
|
||||
static m64p_handle l_ConfigUI = NULL;
|
||||
static m64p_handle l_ConfigTransferPak = NULL;
|
||||
|
||||
static const char *l_CoreLibPath = NULL;
|
||||
static const char *l_ConfigDirPath = NULL;
|
||||
|
@ -151,6 +153,69 @@ static void FrameCallback(unsigned int FrameIndex)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static char *formatstr(const char *fmt, ...)
|
||||
{
|
||||
int size = 128, ret;
|
||||
char *str = (char *)malloc(size), *newstr;
|
||||
va_list args;
|
||||
|
||||
/* There are two implementations of vsnprintf we have to deal with:
|
||||
* C99 version: Returns the number of characters which would have been written
|
||||
* if the buffer had been large enough, and -1 on failure.
|
||||
* Windows version: Returns the number of characters actually written,
|
||||
* and -1 on failure or truncation.
|
||||
* NOTE: An implementation equivalent to the Windows one appears in glibc <2.1.
|
||||
*/
|
||||
while (str != NULL)
|
||||
{
|
||||
va_start(args, fmt);
|
||||
ret = vsnprintf(str, size, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// Successful result?
|
||||
if (ret >= 0 && ret < size)
|
||||
return str;
|
||||
|
||||
// Increment the capacity of the buffer
|
||||
if (ret >= size)
|
||||
size = ret + 1; // C99 version: We got the needed buffer size
|
||||
else
|
||||
size *= 2; // Windows version: Keep guessing
|
||||
|
||||
newstr = (char *)realloc(str, size);
|
||||
if (newstr == NULL)
|
||||
free(str);
|
||||
str = newstr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int is_path_separator(char c)
|
||||
{
|
||||
return strchr(OSAL_DIR_SEPARATORS, c) != NULL;
|
||||
}
|
||||
|
||||
char* combinepath(const char* first, const char *second)
|
||||
{
|
||||
size_t len_first, off_second = 0;
|
||||
|
||||
if (first == NULL || second == NULL)
|
||||
return NULL;
|
||||
|
||||
len_first = strlen(first);
|
||||
|
||||
while (is_path_separator(first[len_first-1]))
|
||||
len_first--;
|
||||
|
||||
while (is_path_separator(second[off_second]))
|
||||
off_second++;
|
||||
|
||||
return formatstr("%.*s%c%s", (int) len_first, first, OSAL_DIR_SEPARATORS[0], second + off_second);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************************************************
|
||||
* Configuration handling
|
||||
*/
|
||||
|
@ -160,6 +225,7 @@ static m64p_error OpenConfigurationHandles(void)
|
|||
float fConfigParamsVersion;
|
||||
int bSaveConfig = 0;
|
||||
m64p_error rval;
|
||||
unsigned int i;
|
||||
|
||||
/* Open Configuration sections for core library and console User Interface */
|
||||
rval = (*ConfigOpenSection)("Core", &l_ConfigCore);
|
||||
|
@ -176,6 +242,13 @@ static m64p_error OpenConfigurationHandles(void)
|
|||
return rval;
|
||||
}
|
||||
|
||||
rval = (*ConfigOpenSection)("Transferpak", &l_ConfigTransferPak);
|
||||
if (rval != M64ERR_SUCCESS)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "failed to open 'Transferpak' configuration section");
|
||||
return rval;
|
||||
}
|
||||
|
||||
rval = (*ConfigOpenSection)("UI-Console", &l_ConfigUI);
|
||||
if (rval != M64ERR_SUCCESS)
|
||||
{
|
||||
|
@ -214,8 +287,25 @@ static m64p_error OpenConfigurationHandles(void)
|
|||
(*ConfigSetDefaultString)(l_ConfigUI, "InputPlugin", "mupen64plus-input-sdl" OSAL_DLL_EXTENSION, "Filename of input plugin");
|
||||
(*ConfigSetDefaultString)(l_ConfigUI, "RspPlugin", "mupen64plus-rsp-hle" OSAL_DLL_EXTENSION, "Filename of RSP plugin");
|
||||
|
||||
if (bSaveConfig && ConfigSaveSection != NULL) /* ConfigSaveSection was added in Config API v2.1.0 */
|
||||
for(i = 1; i < 5; ++i) {
|
||||
char key[64];
|
||||
char desc[2048];
|
||||
#define SET_DEFAULT_STRING(key_fmt, default_value, desc_fmt) \
|
||||
do { \
|
||||
snprintf(key, sizeof(key), key_fmt, i); \
|
||||
snprintf(desc, sizeof(desc), desc_fmt, i); \
|
||||
(*ConfigSetDefaultString)(l_ConfigTransferPak, key, default_value, desc); \
|
||||
} while(0)
|
||||
|
||||
SET_DEFAULT_STRING("GB-rom-%u", "", "Filename of the GB ROM to load into transferpak %u");
|
||||
SET_DEFAULT_STRING("GB-ram-%u", "", "Filename of the GB RAM to load into transferpak %u");
|
||||
#undef SET_DEFAULT_STRING
|
||||
}
|
||||
|
||||
if (bSaveConfig && ConfigSaveSection != NULL) { /* ConfigSaveSection was added in Config API v2.1.0 */
|
||||
(*ConfigSaveSection)("UI-Console");
|
||||
(*ConfigSaveSection)("Transferpak");
|
||||
}
|
||||
|
||||
return M64ERR_SUCCESS;
|
||||
}
|
||||
|
@ -270,6 +360,8 @@ static void printUsage(const char *progname)
|
|||
" --savestate (filepath) : savestate loaded at startup\n"
|
||||
" --testshots (list) : take screenshots at frames given in comma-separated (list), then quit\n"
|
||||
" --set (param-spec) : set a configuration variable, format: ParamSection[ParamName]=Value\n"
|
||||
" --gb-rom-{1,2,3,4} : define GB cart rom to load inside transferpak {1,2,3,4}\n"
|
||||
" --gb-ram-{1,2,3,4} : define GB cart ram to load inside transferpak {1,2,3,4}\n"
|
||||
" --core-compare-send : use the Core Comparison debugging feature, in data sending mode\n"
|
||||
" --core-compare-recv : use the Core Comparison debugging feature, in data receiving mode\n"
|
||||
" --nosaveoptions : do not save the given command-line options in configuration file\n"
|
||||
|
@ -584,6 +676,21 @@ static m64p_error ParseCommandLineFinal(int argc, const char **argv)
|
|||
{
|
||||
l_SaveOptions = 0;
|
||||
}
|
||||
#define PARSE_GB_CART_PARAM(param, key) \
|
||||
else if (strcmp(argv[i], param) == 0) \
|
||||
{ \
|
||||
ConfigSetParameter(l_ConfigTransferPak, key, M64TYPE_STRING, argv[i+1]); \
|
||||
i++; \
|
||||
}
|
||||
PARSE_GB_CART_PARAM("--gb-rom-1", "GB-rom-1")
|
||||
PARSE_GB_CART_PARAM("--gb-ram-1", "GB-ram-1")
|
||||
PARSE_GB_CART_PARAM("--gb-rom-2", "GB-rom-2")
|
||||
PARSE_GB_CART_PARAM("--gb-ram-2", "GB-ram-2")
|
||||
PARSE_GB_CART_PARAM("--gb-rom-3", "GB-rom-3")
|
||||
PARSE_GB_CART_PARAM("--gb-ram-3", "GB-ram-3")
|
||||
PARSE_GB_CART_PARAM("--gb-rom-4", "GB-rom-4")
|
||||
PARSE_GB_CART_PARAM("--gb-ram-4", "GB-ram-4")
|
||||
#undef PARSE_GB_CART_PARAM
|
||||
else if (ArgsLeft == 0)
|
||||
{
|
||||
/* this is the last arg, it should be a ROM filename */
|
||||
|
@ -606,6 +713,79 @@ static m64p_error ParseCommandLineFinal(int argc, const char **argv)
|
|||
return M64ERR_INPUT_INVALID;
|
||||
}
|
||||
|
||||
static char* gb_cart_loader_get_mem_file(void* cb_data, const char* mem, int control_id)
|
||||
{
|
||||
#define MUPEN64PLUS_CFG_NAME "mupen64plus.cfg"
|
||||
m64p_handle core_config;
|
||||
char key[64];
|
||||
char value[4096];
|
||||
const char* configdir = NULL;
|
||||
char* cfgfilepath = NULL;
|
||||
|
||||
/* reset ROM filename */
|
||||
char* mem_filename = NULL;
|
||||
|
||||
snprintf(key, sizeof(key), "GB-%s-%u", mem, control_id + 1);
|
||||
|
||||
/* XXX: use external config API to force reload of file content */
|
||||
configdir = ConfigGetUserConfigPath();
|
||||
if (configdir == NULL) {
|
||||
DebugMessage(M64MSG_ERROR, "Can't get user config path !");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cfgfilepath = combinepath(configdir, MUPEN64PLUS_CFG_NAME);
|
||||
if (cfgfilepath == NULL) {
|
||||
DebugMessage(M64MSG_ERROR, "Can't get config file path: %s + %s!", configdir, MUPEN64PLUS_CFG_NAME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ConfigExternalOpen(cfgfilepath, &core_config) != M64ERR_SUCCESS) {
|
||||
DebugMessage(M64MSG_ERROR, "Can't open config file %s!", cfgfilepath);
|
||||
goto release_cfgfilepath;
|
||||
}
|
||||
|
||||
if (ConfigExternalGetParameter(core_config, "Transferpak", key, value, sizeof(value)) != M64ERR_SUCCESS) {
|
||||
DebugMessage(M64MSG_ERROR, "Can't get parameter %s", key);
|
||||
goto close_config;
|
||||
}
|
||||
|
||||
size_t len = strlen(value);
|
||||
if (len < 2 || value[0] != '"' || value[len-1] != '"') {
|
||||
DebugMessage(M64MSG_ERROR, "Invalid string format %s", value);
|
||||
goto close_config;
|
||||
}
|
||||
|
||||
value[len-1] = '\0';
|
||||
mem_filename = strdup(value + 1);
|
||||
|
||||
ConfigSetParameter(l_ConfigTransferPak, key, M64TYPE_STRING, mem_filename);
|
||||
|
||||
close_config:
|
||||
ConfigExternalClose(core_config);
|
||||
release_cfgfilepath:
|
||||
free(cfgfilepath);
|
||||
return mem_filename;
|
||||
}
|
||||
|
||||
static char* gb_cart_loader_get_rom(void* cb_data, int control_id)
|
||||
{
|
||||
return gb_cart_loader_get_mem_file(cb_data, "rom", control_id);
|
||||
}
|
||||
|
||||
static char* gb_cart_loader_get_ram(void* cb_data, int control_id)
|
||||
{
|
||||
return gb_cart_loader_get_mem_file(cb_data, "ram", control_id);
|
||||
}
|
||||
|
||||
static m64p_gb_cart_loader l_gb_cart_loader =
|
||||
{
|
||||
NULL,
|
||||
gb_cart_loader_get_rom,
|
||||
gb_cart_loader_get_ram
|
||||
};
|
||||
|
||||
|
||||
/*********************************************************************************************************
|
||||
* main function
|
||||
*/
|
||||
|
@ -785,6 +965,12 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
/* set gb cart loader */
|
||||
if ((*CoreDoCommand)(M64CMD_SET_GB_CART_LOADER, sizeof(l_gb_cart_loader), &l_gb_cart_loader) != M64ERR_SUCCESS)
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "Couldn't set GB cart loader, transferpak and GB carts will not work.");
|
||||
}
|
||||
|
||||
/* load savestate at startup */
|
||||
if (l_SaveStatePath != NULL)
|
||||
{
|
||||
|
|
|
@ -29,6 +29,26 @@
|
|||
#include "m64p_types.h"
|
||||
#include "osal_preproc.h"
|
||||
|
||||
/* some file-related preprocessor definitions */
|
||||
#if defined(WIN32) && !defined(__MINGW32__)
|
||||
#include <io.h> // For _unlink()
|
||||
|
||||
#define unlink _unlink
|
||||
|
||||
#define OSAL_DIR_SEPARATORS "\\/"
|
||||
#define PATH_MAX _MAX_PATH
|
||||
#else /* Not WIN32 */
|
||||
#include <limits.h> // for PATH_MAX
|
||||
#include <unistd.h> // for unlink()
|
||||
|
||||
#define OSAL_DIR_SEPARATORS "/"
|
||||
|
||||
/* PATH_MAX only may be defined by limits.h */
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* data structure for linked list of shared libraries found in a directory */
|
||||
typedef struct _osal_lib_search {
|
||||
char filepath[PATH_MAX];
|
||||
|
|
Loading…
Add table
Reference in a new issue