mirror of
https://github.com/libretro/RetroArch
synced 2024-12-27 15:29:23 +00:00
Initial take on subsystems support.
This commit is contained in:
parent
88526a4ab7
commit
c81de5119d
@ -122,6 +122,9 @@ void autosave_unlock(autosave_t *handle)
|
||||
|
||||
void autosave_free(autosave_t *handle)
|
||||
{
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
slock_lock(handle->cond_lock);
|
||||
handle->quit = true;
|
||||
slock_unlock(handle->cond_lock);
|
||||
@ -139,7 +142,7 @@ void autosave_free(autosave_t *handle)
|
||||
void lock_autosave(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE(g_extern.autosave); i++)
|
||||
for (i = 0; i < g_extern.num_autosave; i++)
|
||||
{
|
||||
if (g_extern.autosave[i])
|
||||
autosave_lock(g_extern.autosave[i]);
|
||||
@ -149,7 +152,7 @@ void lock_autosave(void)
|
||||
void unlock_autosave(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE(g_extern.autosave); i++)
|
||||
for (i = 0; i < g_extern.num_autosave; i++)
|
||||
{
|
||||
if (g_extern.autosave[i])
|
||||
autosave_unlock(g_extern.autosave[i]);
|
||||
|
33
dynamic.c
33
dynamic.c
@ -185,6 +185,21 @@ void libretro_free_system_info(struct retro_system_info *info)
|
||||
memset(info, 0, sizeof(*info));
|
||||
}
|
||||
|
||||
const struct retro_game_special_info *libretro_find_subsystem_info(const struct retro_game_special_info *info, unsigned num_info,
|
||||
const char *ident)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < num_info; i++)
|
||||
{
|
||||
if (!strcmp(info[i].ident, ident))
|
||||
return &info[i];
|
||||
else if (!strcmp(info[i].desc, ident)) // Doesn't hurt
|
||||
return &info[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool find_first_libretro(char *path, size_t size,
|
||||
const char *dir, const char *rom_path)
|
||||
{
|
||||
@ -417,6 +432,7 @@ void uninit_libretro_sym(void)
|
||||
}
|
||||
|
||||
// No longer valid.
|
||||
free(g_extern.system.special);
|
||||
memset(&g_extern.system, 0, sizeof(g_extern.system));
|
||||
#ifdef HAVE_CAMERA
|
||||
g_extern.camera_active = false;
|
||||
@ -914,6 +930,23 @@ bool rarch_environment_cb(unsigned cmd, void *data)
|
||||
return driver_update_system_av_info((const struct retro_system_av_info*)data);
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_SET_SPECIAL_GAME_TYPES:
|
||||
{
|
||||
RARCH_LOG("Environ SET_SPECIAL_GAME_TYPES.\n");
|
||||
unsigned i;
|
||||
const struct retro_game_special_info *info = (const struct retro_game_special_info*)data;
|
||||
for (i = 0; info[i].ident; i++)
|
||||
RARCH_LOG("Special game type: %s (ident: %s)\n", info[i].desc, info[i].ident);
|
||||
|
||||
free(g_extern.system.special);
|
||||
g_extern.system.special = (struct retro_game_special_info*)calloc(i, sizeof(*g_extern.system.special));
|
||||
if (!g_extern.system.special)
|
||||
return false;
|
||||
|
||||
memcpy(g_extern.system.special, info, i * sizeof(*g_extern.system.special));
|
||||
break;
|
||||
}
|
||||
|
||||
case RETRO_ENVIRONMENT_EXEC:
|
||||
case RETRO_ENVIRONMENT_EXEC_ESCAPE:
|
||||
|
||||
|
@ -64,6 +64,8 @@ void libretro_free_system_info(struct retro_system_info *info);
|
||||
// Transforms a library id to a name suitable as a pathname.
|
||||
void libretro_get_current_core_pathname(char *name, size_t size);
|
||||
|
||||
const struct retro_game_special_info *libretro_find_subsystem_info(const struct retro_game_special_info *info, unsigned num_info, const char *ident);
|
||||
|
||||
extern void (*pretro_init)(void);
|
||||
extern void (*pretro_deinit)(void);
|
||||
|
||||
|
275
file.c
275
file.c
@ -143,35 +143,8 @@ static ssize_t read_rom_file(const char *path, void **buf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static const char *ramtype2str(int type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case RETRO_MEMORY_SAVE_RAM:
|
||||
case RETRO_MEMORY_SNES_GAME_BOY_RAM:
|
||||
case RETRO_MEMORY_SNES_BSX_RAM:
|
||||
return ".srm";
|
||||
|
||||
case RETRO_MEMORY_RTC:
|
||||
case RETRO_MEMORY_SNES_GAME_BOY_RTC:
|
||||
return ".rtc";
|
||||
|
||||
case RETRO_MEMORY_SNES_BSX_PRAM:
|
||||
return ".pram";
|
||||
|
||||
case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM:
|
||||
return ".aram";
|
||||
case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM:
|
||||
return ".bram";
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to save valuable RAM data somewhere ...
|
||||
static void dump_to_file_desperate(const void *data, size_t size, int type)
|
||||
static void dump_to_file_desperate(const void *data, size_t size, unsigned type)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
const char *base = getenv("APPDATA");
|
||||
@ -185,14 +158,13 @@ static void dump_to_file_desperate(const void *data, size_t size, int type)
|
||||
goto error;
|
||||
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "%s/RetroArch-recovery-", base);
|
||||
snprintf(path, sizeof(path), "%s/RetroArch-recovery-%u", base, type);
|
||||
char timebuf[PATH_MAX];
|
||||
|
||||
time_t time_;
|
||||
time(&time_);
|
||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d-%H-%M-%S", localtime(&time_));
|
||||
strlcat(path, timebuf, sizeof(path));
|
||||
strlcat(path, ramtype2str(type), sizeof(path));
|
||||
|
||||
if (write_file(path, data, size))
|
||||
RARCH_WARN("Succeeded in saving RAM data to \"%s\".\n", path);
|
||||
@ -248,6 +220,7 @@ bool load_state(const char *path)
|
||||
bool ret = true;
|
||||
RARCH_LOG("State size: %u bytes.\n", (unsigned)size);
|
||||
|
||||
#if 0
|
||||
void *block_buf[2] = {NULL, NULL};
|
||||
int block_type[2] = {-1, -1};
|
||||
size_t block_size[2] = {0};
|
||||
@ -315,6 +288,8 @@ bool load_state(const char *path)
|
||||
for (i = 0; i < 2; i++)
|
||||
if (block_buf[i])
|
||||
free(block_buf[i]);
|
||||
#endif
|
||||
ret = pretro_unserialize(buf, size);
|
||||
|
||||
free(buf);
|
||||
return ret;
|
||||
@ -362,175 +337,163 @@ void save_ram_file(const char *path, int type)
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_ROMS 4
|
||||
|
||||
static bool load_roms(unsigned rom_type, const char **rom_paths, size_t roms)
|
||||
static bool load_roms(const struct retro_game_special_info *special, const struct string_list *roms)
|
||||
{
|
||||
size_t i;
|
||||
unsigned i;
|
||||
bool ret = true;
|
||||
|
||||
if (roms == 0)
|
||||
struct retro_game_info *info = (struct retro_game_info*)calloc(roms->size, sizeof(*info));
|
||||
if (!info)
|
||||
return false;
|
||||
|
||||
if (roms > MAX_ROMS)
|
||||
return false;
|
||||
|
||||
void *rom_buf[MAX_ROMS] = {NULL};
|
||||
long rom_len[MAX_ROMS] = {0};
|
||||
struct retro_game_info info[MAX_ROMS] = {{NULL}};
|
||||
|
||||
if (!g_extern.system.info.need_fullpath)
|
||||
for (i = 0; i < roms->size; i++)
|
||||
{
|
||||
RARCH_LOG("Loading ROM file: %s.\n", rom_paths[0]);
|
||||
if ((rom_len[0] = read_rom_file(rom_paths[0], &rom_buf[0])) == -1)
|
||||
const char *path = roms->elems[i].data;
|
||||
int attr = roms->elems[i].attr.i;
|
||||
|
||||
bool need_fullpath = attr & 2;
|
||||
bool require_rom = attr & 4;
|
||||
|
||||
if (require_rom && !*path)
|
||||
{
|
||||
RARCH_ERR("Could not read ROM file.\n");
|
||||
RARCH_LOG("libretro core requires a ROM, but none were provided.\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
RARCH_LOG("ROM size: %u bytes.\n", (unsigned)rom_len[0]);
|
||||
}
|
||||
else
|
||||
RARCH_LOG("ROM loading skipped. Implementation will load it on its own.\n");
|
||||
info[i].path = *path ? path : NULL;
|
||||
|
||||
info[0].path = rom_paths[0];
|
||||
info[0].data = rom_buf[0];
|
||||
info[0].size = rom_len[0];
|
||||
info[0].meta = NULL; // Not relevant at this moment.
|
||||
|
||||
for (i = 1; i < roms; i++)
|
||||
{
|
||||
if (rom_paths[i] &&
|
||||
!g_extern.system.info.need_fullpath &&
|
||||
(rom_len[i] = read_file(rom_paths[i], &rom_buf[i])) == -1)
|
||||
if (!need_fullpath && *path) // Load the ROM into memory.
|
||||
{
|
||||
RARCH_ERR("Could not read ROM file: \"%s\".\n", rom_paths[i]);
|
||||
ret = false;
|
||||
goto end;
|
||||
RARCH_LOG("Loading ROM file: %s.\n", path);
|
||||
// First ROM is significant, attempt to do patching, CRC checking, etc ...
|
||||
long size = i == 0 ? read_rom_file(path, (void**)&info[i].data) : read_file(path, (void**)&info[i].data);
|
||||
if (size < 0)
|
||||
{
|
||||
RARCH_ERR("Could not read ROM file \"%s\".\n", path);
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
info[i].size = size;
|
||||
}
|
||||
|
||||
info[i].path = rom_paths[i];
|
||||
info[i].data = rom_buf[i];
|
||||
info[i].size = rom_len[i];
|
||||
info[i].meta = NULL;
|
||||
else
|
||||
RARCH_LOG("ROM loading skipped. Implementation will load it on its own.\n");
|
||||
}
|
||||
|
||||
if (rom_type == 0)
|
||||
ret = pretro_load_game(&info[0]);
|
||||
if (special)
|
||||
ret = pretro_load_game_special(special->id, info, roms->size);
|
||||
else
|
||||
ret = pretro_load_game_special(rom_type, info, roms);
|
||||
ret = pretro_load_game(info);
|
||||
|
||||
if (!ret)
|
||||
RARCH_ERR("Failed to load game.\n");
|
||||
|
||||
end:
|
||||
for (i = 0; i < MAX_ROMS; i++)
|
||||
free(rom_buf[i]);
|
||||
for (i = 0; i < roms->size; i++)
|
||||
free((void*)info[i].data);
|
||||
free(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool load_normal_rom(void)
|
||||
bool init_rom_file(void)
|
||||
{
|
||||
if (g_extern.libretro_no_rom && g_extern.system.no_game)
|
||||
return pretro_load_game(NULL);
|
||||
else if (g_extern.libretro_no_rom && !g_extern.system.no_game)
|
||||
{
|
||||
RARCH_ERR("No ROM is used, but libretro core does not support this.\n");
|
||||
unsigned i;
|
||||
|
||||
g_extern.temporary_roms = string_list_new();
|
||||
if (!g_extern.temporary_roms)
|
||||
return false;
|
||||
|
||||
const struct retro_game_special_info *special = NULL;
|
||||
|
||||
if (*g_extern.subsystem)
|
||||
{
|
||||
special = libretro_find_subsystem_info(g_extern.system.special, g_extern.system.num_special,
|
||||
g_extern.subsystem);
|
||||
|
||||
if (!special)
|
||||
{
|
||||
RARCH_ERR("Failed to find subsystem \"%s\" in libretro implementation.\n",
|
||||
g_extern.subsystem);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (special->num_roms && !g_extern.subsystem_fullpaths)
|
||||
{
|
||||
RARCH_ERR("libretro core requires special ROMs, but none were provided.\n");
|
||||
return false;
|
||||
}
|
||||
else if (special->num_roms && special->num_roms != g_extern.subsystem_fullpaths->size)
|
||||
{
|
||||
RARCH_ERR("libretro core requires %u ROMs for subsystem \"%s\", but %u ROMs were provided.\n", special->num_roms, special->desc,
|
||||
(unsigned)g_extern.subsystem_fullpaths->size);
|
||||
return false;
|
||||
}
|
||||
else if (!special->num_roms && g_extern.subsystem_fullpaths && g_extern.subsystem_fullpaths->size)
|
||||
{
|
||||
RARCH_ERR("libretro core takes no ROMs for subsystem \"%s\", but %u ROMs were provided.\n", special->desc,
|
||||
(unsigned)g_extern.subsystem_fullpaths->size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
union string_list_elem_attr attr;
|
||||
struct string_list *roms = string_list_new();
|
||||
if (!roms)
|
||||
return false;
|
||||
|
||||
if (*g_extern.subsystem)
|
||||
{
|
||||
for (i = 0; i < g_extern.subsystem_fullpaths->size; i++)
|
||||
{
|
||||
attr.i = special->roms[i].block_extract;
|
||||
attr.i |= special->roms[i].need_fullpath << 1;
|
||||
attr.i |= special->roms[i].required << 2;
|
||||
string_list_append(roms, g_extern.subsystem_fullpaths->elems[i].data, attr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *path = g_extern.fullpath;
|
||||
return load_roms(0, &path, 1);
|
||||
attr.i = g_extern.system.info.block_extract;
|
||||
attr.i |= g_extern.system.info.need_fullpath << 1;
|
||||
attr.i |= (!g_extern.system.no_game) << 2;
|
||||
string_list_append(roms, g_extern.fullpath, attr);
|
||||
}
|
||||
}
|
||||
|
||||
static bool load_sgb_rom(void)
|
||||
{
|
||||
const char *path[2] = {
|
||||
*g_extern.fullpath ? g_extern.fullpath : NULL,
|
||||
g_extern.gb_rom_path
|
||||
};
|
||||
|
||||
return load_roms(RETRO_GAME_TYPE_SUPER_GAME_BOY, path, 2);
|
||||
}
|
||||
|
||||
static bool load_bsx_rom(bool slotted)
|
||||
{
|
||||
const char *path[2] = {
|
||||
*g_extern.fullpath ? g_extern.fullpath : NULL,
|
||||
g_extern.bsx_rom_path
|
||||
};
|
||||
|
||||
return load_roms(slotted ? RETRO_GAME_TYPE_BSX_SLOTTED : RETRO_GAME_TYPE_BSX, path, 2);
|
||||
}
|
||||
|
||||
static bool load_sufami_rom(void)
|
||||
{
|
||||
const char *path[3] = {
|
||||
*g_extern.fullpath ? g_extern.fullpath : NULL,
|
||||
*g_extern.sufami_rom_path[0] ? g_extern.sufami_rom_path[0] : NULL,
|
||||
*g_extern.sufami_rom_path[1] ? g_extern.sufami_rom_path[1] : NULL,
|
||||
};
|
||||
|
||||
return load_roms(RETRO_GAME_TYPE_SUFAMI_TURBO, path, 3);
|
||||
}
|
||||
|
||||
bool init_rom_file(enum rarch_game_type type)
|
||||
{
|
||||
#ifdef HAVE_ZLIB
|
||||
if (*g_extern.fullpath && !g_extern.system.block_extract)
|
||||
// Try to extract every ROM we're going to load if appropriate.
|
||||
for (i = 0; i < roms->size; i++)
|
||||
{
|
||||
const char *ext = path_get_extension(g_extern.fullpath);
|
||||
// block extract check
|
||||
if (roms->elems[i].attr.i & 1)
|
||||
continue;
|
||||
|
||||
const char *ext = path_get_extension(roms->elems[i].data);
|
||||
|
||||
const char *valid_ext = special ?
|
||||
special->roms[i].valid_extensions :
|
||||
g_extern.system.info.valid_extensions;
|
||||
|
||||
if (ext && !strcasecmp(ext, "zip"))
|
||||
{
|
||||
g_extern.rom_file_temporary = true;
|
||||
|
||||
if (!zlib_extract_first_rom(g_extern.fullpath, sizeof(g_extern.fullpath), g_extern.system.valid_extensions))
|
||||
char temporary_rom[PATH_MAX];
|
||||
strlcpy(temporary_rom, roms->elems[i].data, sizeof(temporary_rom));
|
||||
if (!zlib_extract_first_rom(temporary_rom, sizeof(temporary_rom), valid_ext))
|
||||
{
|
||||
RARCH_ERR("Failed to extract ROM from zipped file: %s.\n", g_extern.fullpath);
|
||||
g_extern.rom_file_temporary = false;
|
||||
RARCH_ERR("Failed to extract ROM from zipped file: %s.\n", temporary_rom);
|
||||
string_list_free(roms);
|
||||
return false;
|
||||
}
|
||||
|
||||
strlcpy(g_extern.last_rom, g_extern.fullpath, sizeof(g_extern.last_rom));
|
||||
string_list_append(g_extern.temporary_roms, temporary_rom, attr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case RARCH_CART_SGB:
|
||||
if (!load_sgb_rom())
|
||||
return false;
|
||||
break;
|
||||
|
||||
case RARCH_CART_NORMAL:
|
||||
if (!load_normal_rom())
|
||||
return false;
|
||||
break;
|
||||
|
||||
case RARCH_CART_BSX:
|
||||
if (!load_bsx_rom(false))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
if (!load_bsx_rom(true))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
if (!load_sufami_rom())
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
RARCH_ERR("Invalid ROM type.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Set attr to need_fullpath as appropriate.
|
||||
|
||||
bool ret = load_roms(special, roms);
|
||||
string_list_free(roms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
2
file.h
2
file.h
@ -36,7 +36,7 @@ bool save_state(const char *path);
|
||||
void load_ram_file(const char *path, int type);
|
||||
void save_ram_file(const char *path, int type);
|
||||
|
||||
bool init_rom_file(enum rarch_game_type type);
|
||||
bool init_rom_file(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -244,12 +244,7 @@ void menu_rom_history_push_current(void)
|
||||
|
||||
char tmp[PATH_MAX];
|
||||
|
||||
// We loaded a zip, and fullpath points to the extracted file.
|
||||
// Look at basename instead.
|
||||
if (g_extern.rom_file_temporary)
|
||||
snprintf(tmp, sizeof(tmp), "%s.zip", g_extern.basename);
|
||||
else
|
||||
strlcpy(tmp, g_extern.fullpath, sizeof(tmp));
|
||||
strlcpy(tmp, g_extern.fullpath, sizeof(tmp));
|
||||
|
||||
if (*tmp)
|
||||
path_resolve_realpath(tmp, sizeof(tmp));
|
||||
|
34
general.h
34
general.h
@ -316,15 +316,6 @@ struct settings
|
||||
bool core_specific_config;
|
||||
};
|
||||
|
||||
enum rarch_game_type
|
||||
{
|
||||
RARCH_CART_NORMAL = 0,
|
||||
RARCH_CART_SGB,
|
||||
RARCH_CART_BSX,
|
||||
RARCH_CART_BSX_SLOTTED,
|
||||
RARCH_CART_SUFAMI
|
||||
};
|
||||
|
||||
typedef struct rarch_resolution
|
||||
{
|
||||
unsigned idx;
|
||||
@ -358,9 +349,8 @@ struct global
|
||||
#endif
|
||||
bool force_fullscreen;
|
||||
|
||||
bool rom_file_temporary;
|
||||
char last_rom[PATH_MAX];
|
||||
enum rarch_game_type game_type;
|
||||
struct string_list *temporary_roms;
|
||||
|
||||
uint32_t cart_crc;
|
||||
|
||||
char gb_rom_path[PATH_MAX];
|
||||
@ -386,11 +376,15 @@ struct global
|
||||
|
||||
char basename[PATH_MAX];
|
||||
char fullpath[PATH_MAX];
|
||||
char savefile_name_srm[PATH_MAX];
|
||||
char savefile_name_rtc[PATH_MAX]; // Make sure that fill_pathname has space.
|
||||
char savefile_name_psrm[PATH_MAX];
|
||||
char savefile_name_asrm[PATH_MAX];
|
||||
char savefile_name_bsrm[PATH_MAX];
|
||||
|
||||
// A list of save types and associated paths for all ROMs.
|
||||
struct string_list *savefiles;
|
||||
|
||||
// For --subsystem ROMs.
|
||||
char subsystem[256];
|
||||
struct string_list *subsystem_fullpaths;
|
||||
|
||||
char savefile_name[PATH_MAX];
|
||||
char savestate_name[PATH_MAX];
|
||||
|
||||
// Used on reentrancy to use a savestate dir.
|
||||
@ -448,6 +442,9 @@ struct global
|
||||
retro_usec_t frame_time_last;
|
||||
|
||||
core_option_manager_t *core_options;
|
||||
|
||||
struct retro_game_special_info *special;
|
||||
unsigned num_special;
|
||||
} system;
|
||||
|
||||
struct
|
||||
@ -563,7 +560,8 @@ struct global
|
||||
unsigned turbo_count;
|
||||
|
||||
// Autosave support.
|
||||
autosave_t *autosave[2];
|
||||
autosave_t **autosave;
|
||||
unsigned num_autosave;
|
||||
|
||||
// Netplay.
|
||||
#ifdef HAVE_NETPLAY
|
||||
|
69
libretro.h
69
libretro.h
@ -162,7 +162,7 @@ extern "C" {
|
||||
|
||||
// Regular save ram. This ram is usually found on a game cartridge, backed up by a battery.
|
||||
// If save game data is too complex for a single memory buffer,
|
||||
// the SYSTEM_DIRECTORY environment callback can be used.
|
||||
// the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment callback can be used.
|
||||
#define RETRO_MEMORY_SAVE_RAM 0
|
||||
|
||||
// Some games have a built-in clock to keep track of time.
|
||||
@ -175,21 +175,6 @@ extern "C" {
|
||||
// Video ram lets a frontend peek into a game systems video RAM (VRAM).
|
||||
#define RETRO_MEMORY_VIDEO_RAM 3
|
||||
|
||||
// Special memory types.
|
||||
#define RETRO_MEMORY_SNES_BSX_RAM ((1 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_BSX_PRAM ((2 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM ((3 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM ((4 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_GAME_BOY_RAM ((5 << 8) | RETRO_MEMORY_SAVE_RAM)
|
||||
#define RETRO_MEMORY_SNES_GAME_BOY_RTC ((6 << 8) | RETRO_MEMORY_RTC)
|
||||
|
||||
// Special game types passed into retro_load_game_special().
|
||||
// Only used when multiple ROMs are required.
|
||||
#define RETRO_GAME_TYPE_BSX 0x101
|
||||
#define RETRO_GAME_TYPE_BSX_SLOTTED 0x102
|
||||
#define RETRO_GAME_TYPE_SUFAMI_TURBO 0x103
|
||||
#define RETRO_GAME_TYPE_SUPER_GAME_BOY 0x104
|
||||
|
||||
// Keysyms used for ID in input state callback when polling RETRO_KEYBOARD.
|
||||
enum retro_key
|
||||
{
|
||||
@ -614,9 +599,59 @@ enum retro_mod
|
||||
// e.g. for cases where the frontend wants to call directly into the core.
|
||||
//
|
||||
// If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK **MUST** be called from within retro_set_environment().
|
||||
//
|
||||
#define RETRO_ENVIRONMENT_SET_SPECIAL_GAME_TYPES 34
|
||||
// const struct retro_game_special_info * --
|
||||
// This environment call introduces the concept of libretro "subsystems".
|
||||
// A subsystem is a variant of a libretro core which supports different kinds of games.
|
||||
// The purpose of this is to support e.g. emulators which might have special needs, e.g. Super Nintendos Super GameBoy, Sufami Turbo.
|
||||
// It can also be used to pick among subsystems in an explicit way if the libretro implementation is a multi-system emulator itself.
|
||||
//
|
||||
// Loading a game via a subsystem is done with retro_load_game_special(),
|
||||
// and this environment call allows a libretro core to expose which subsystems are supported for use with retro_load_game_special().
|
||||
// A core passes an array of retro_game_special_info which is terminated with a zeroed out retro_game_special_info struct.
|
||||
//
|
||||
// If a core wants to use this functionality, SET_SPECIAL_GAME_TYPES **MUST** be called from within retro_set_environment().
|
||||
|
||||
struct retro_game_special_memory_info
|
||||
{
|
||||
const char *extension; // The extension associated with a memory type, e.g. "psram".
|
||||
unsigned type; // The memory type for retro_get_memory(). This should be at least 0x100 to avoid conflict with standardized libretro memory types.
|
||||
};
|
||||
|
||||
struct retro_game_special_rom_info
|
||||
{
|
||||
const char *desc; // Describes what the ROM is (SGB bios, GB rom, etc).
|
||||
const char *ident; // A computer friendly short string identifier for the ROM type. Must be [a-z].
|
||||
const char *valid_extensions; // Same definition as retro_get_system_info().
|
||||
bool need_fullpath; // Same definition as retro_get_system_info().
|
||||
bool block_extract; // Same definition as retro_get_system_info().
|
||||
bool required; // This is set if the ROM is required to load a game. If this is set to false, a zeroed-out retro_game_info can be passed.
|
||||
|
||||
// ROMs can have multiple associated persistent memory types (retro_get_memory()).
|
||||
const struct retro_game_special_memory_info *memory;
|
||||
unsigned num_memory;
|
||||
};
|
||||
|
||||
struct retro_game_special_info
|
||||
{
|
||||
const char *desc; // Human-readable string of the subsystem type, e.g. "Super GameBoy"
|
||||
// A computer friendly short string identifier for the subsystem type.
|
||||
// This name must be [a-z].
|
||||
// E.g. if desc is "Super GameBoy", this can be "sgb".
|
||||
// This identifier can be used for command-line interfaces, etc.
|
||||
const char *ident;
|
||||
|
||||
// Infos for each ROM. The first entry is assumed to be the "most significant" ROM for frontend purposes.
|
||||
// E.g. with Super GameBoy, the first ROM should be the GameBoy ROM, as it is the most "significant" ROM to a user.
|
||||
// If a frontend creates new file paths based on the ROM used (e.g. savestates), it should use the path for the first ROM to do so.
|
||||
const struct retro_game_special_rom_info *roms;
|
||||
|
||||
unsigned num_roms; // Number of ROMs associated with a subsystem.
|
||||
unsigned id; // The type passed to retro_load_game_special().
|
||||
};
|
||||
|
||||
typedef void (*retro_proc_address_t)(void);
|
||||
|
||||
// libretro API extension functions:
|
||||
// (None here so far).
|
||||
//////
|
||||
|
411
retroarch.c
411
retroarch.c
@ -836,19 +836,53 @@ static void set_basename(const char *path)
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
static void set_special_paths(char **argv, unsigned roms)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
// First ROM is the significant one.
|
||||
set_basename(argv[0]);
|
||||
|
||||
g_extern.subsystem_fullpaths = string_list_new();
|
||||
rarch_assert(g_extern.subsystem_fullpaths);
|
||||
|
||||
union string_list_elem_attr attr;
|
||||
attr.i = 0;
|
||||
|
||||
for (i = 0; i < roms; i++)
|
||||
string_list_append(g_extern.subsystem_fullpaths, argv[i], attr);
|
||||
|
||||
// We defer SRAM path updates until we can resolve it.
|
||||
// It is more complicated for special game types.
|
||||
|
||||
if (!g_extern.has_set_state_path)
|
||||
fill_pathname_noext(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name));
|
||||
|
||||
if (path_is_directory(g_extern.savestate_name))
|
||||
{
|
||||
fill_pathname_dir(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name));
|
||||
RARCH_LOG("Redirecting save state to \"%s\".\n", g_extern.savestate_name);
|
||||
}
|
||||
|
||||
// If this is already set,
|
||||
// do not overwrite it as this was initialized before in a menu or otherwise.
|
||||
if (!*g_settings.system_directory)
|
||||
fill_pathname_basedir(g_settings.system_directory, argv[0], sizeof(g_settings.system_directory));
|
||||
}
|
||||
|
||||
static void set_paths(const char *path)
|
||||
{
|
||||
set_basename(path);
|
||||
|
||||
if (!g_extern.has_set_save_path)
|
||||
fill_pathname_noext(g_extern.savefile_name_srm, g_extern.basename, ".srm", sizeof(g_extern.savefile_name_srm));
|
||||
fill_pathname_noext(g_extern.savefile_name, g_extern.basename, ".srm", sizeof(g_extern.savefile_name));
|
||||
if (!g_extern.has_set_state_path)
|
||||
fill_pathname_noext(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name));
|
||||
|
||||
if (path_is_directory(g_extern.savefile_name_srm))
|
||||
if (path_is_directory(g_extern.savefile_name))
|
||||
{
|
||||
fill_pathname_dir(g_extern.savefile_name_srm, g_extern.basename, ".srm", sizeof(g_extern.savefile_name_srm));
|
||||
RARCH_LOG("Redirecting save file to \"%s\".\n", g_extern.savefile_name_srm);
|
||||
fill_pathname_dir(g_extern.savefile_name, g_extern.basename, ".srm", sizeof(g_extern.savefile_name));
|
||||
RARCH_LOG("Redirecting save file to \"%s\".\n", g_extern.savefile_name);
|
||||
}
|
||||
if (path_is_directory(g_extern.savestate_name))
|
||||
{
|
||||
@ -895,7 +929,6 @@ static void parse_input(int argc, char *argv[])
|
||||
{ "size", 1, &val, 's' },
|
||||
#endif
|
||||
{ "verbose", 0, NULL, 'v' },
|
||||
{ "gameboy", 1, NULL, 'g' },
|
||||
{ "config", 1, NULL, 'c' },
|
||||
{ "appendconfig", 1, &val, 'C' },
|
||||
{ "mouse", 1, NULL, 'm' },
|
||||
@ -905,11 +938,7 @@ static void parse_input(int argc, char *argv[])
|
||||
{ "justifiers", 0, NULL, 'J' },
|
||||
{ "dualanalog", 1, NULL, 'A' },
|
||||
{ "savestate", 1, NULL, 'S' },
|
||||
{ "bsx", 1, NULL, 'b' },
|
||||
{ "bsxslot", 1, NULL, 'B' },
|
||||
{ "multitap", 0, NULL, '4' },
|
||||
{ "sufamiA", 1, NULL, 'Y' },
|
||||
{ "sufamiB", 1, NULL, 'Z' },
|
||||
#ifdef HAVE_BSV_MOVIE
|
||||
{ "bsvplay", 1, NULL, 'P' },
|
||||
{ "bsvrecord", 1, NULL, 'R' },
|
||||
@ -932,6 +961,7 @@ static void parse_input(int argc, char *argv[])
|
||||
{ "no-patch", 0, &val, 'n' },
|
||||
{ "detach", 0, NULL, 'D' },
|
||||
{ "features", 0, &val, 'f' },
|
||||
{ "subsystem", 1, NULL, 'Z' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
@ -959,7 +989,7 @@ static void parse_input(int argc, char *argv[])
|
||||
#define BSV_MOVIE_ARG
|
||||
#endif
|
||||
|
||||
const char *optstring = "hs:fvS:m:p4jJA:g:b:c:B:Y:Z:U:DN:" BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG;
|
||||
const char *optstring = "hs:fvS:m:p4jJA:c:U:DN:" BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@ -970,7 +1000,6 @@ static void parse_input(int argc, char *argv[])
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'h':
|
||||
@ -992,6 +1021,10 @@ static void parse_input(int argc, char *argv[])
|
||||
g_extern.has_set_libretro_device[1] = true;
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
strlcpy(g_extern.subsystem, optarg, sizeof(g_extern.subsystem));
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
port = strtol(optarg, NULL, 0);
|
||||
if (port < 1 || port > MAX_PLAYERS)
|
||||
@ -1005,7 +1038,7 @@ static void parse_input(int argc, char *argv[])
|
||||
break;
|
||||
|
||||
case 's':
|
||||
strlcpy(g_extern.savefile_name_srm, optarg, sizeof(g_extern.savefile_name_srm));
|
||||
strlcpy(g_extern.savefile_name, optarg, sizeof(g_extern.savefile_name));
|
||||
g_extern.has_set_save_path = true;
|
||||
break;
|
||||
|
||||
@ -1013,31 +1046,6 @@ static void parse_input(int argc, char *argv[])
|
||||
g_extern.force_fullscreen = true;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
strlcpy(g_extern.gb_rom_path, optarg, sizeof(g_extern.gb_rom_path));
|
||||
g_extern.game_type = RARCH_CART_SGB;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
strlcpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path));
|
||||
g_extern.game_type = RARCH_CART_BSX;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
strlcpy(g_extern.bsx_rom_path, optarg, sizeof(g_extern.bsx_rom_path));
|
||||
g_extern.game_type = RARCH_CART_BSX_SLOTTED;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
strlcpy(g_extern.sufami_rom_path[0], optarg, sizeof(g_extern.sufami_rom_path[0]));
|
||||
g_extern.game_type = RARCH_CART_SUFAMI;
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
strlcpy(g_extern.sufami_rom_path[1], optarg, sizeof(g_extern.sufami_rom_path[1]));
|
||||
g_extern.game_type = RARCH_CART_SUFAMI;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
strlcpy(g_extern.savestate_name, optarg, sizeof(g_extern.savestate_name));
|
||||
g_extern.has_set_state_path = true;
|
||||
@ -1239,14 +1247,16 @@ static void parse_input(int argc, char *argv[])
|
||||
rarch_fail(1, "parse_input()");
|
||||
}
|
||||
}
|
||||
else if (optind < argc)
|
||||
else if (!*g_extern.subsystem && optind < argc)
|
||||
set_paths(argv[optind]);
|
||||
else if (*g_extern.subsystem && optind < argc)
|
||||
set_special_paths(argv + optind, argc - optind);
|
||||
else
|
||||
g_extern.libretro_no_rom = true;
|
||||
|
||||
// Copy SRM/state dirs used, so they can be reused on reentrancy.
|
||||
if (g_extern.has_set_save_path && path_is_directory(g_extern.savefile_name_srm))
|
||||
strlcpy(g_extern.savefile_dir, g_extern.savefile_name_srm, sizeof(g_extern.savefile_dir));
|
||||
if (g_extern.has_set_save_path && path_is_directory(g_extern.savefile_name))
|
||||
strlcpy(g_extern.savefile_dir, g_extern.savefile_name, sizeof(g_extern.savefile_dir));
|
||||
if (g_extern.has_set_state_path && path_is_directory(g_extern.savestate_name))
|
||||
strlcpy(g_extern.savestate_dir, g_extern.savestate_name, sizeof(g_extern.savestate_dir));
|
||||
}
|
||||
@ -1302,73 +1312,26 @@ static void init_controllers(void)
|
||||
|
||||
static inline void load_save_files(void)
|
||||
{
|
||||
switch (g_extern.game_type)
|
||||
{
|
||||
case RARCH_CART_NORMAL:
|
||||
load_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SAVE_RAM);
|
||||
load_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_RTC);
|
||||
break;
|
||||
unsigned i;
|
||||
if (!g_extern.savefiles)
|
||||
return;
|
||||
|
||||
case RARCH_CART_SGB:
|
||||
load_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_GAME_BOY_RAM);
|
||||
load_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_SNES_GAME_BOY_RTC);
|
||||
break;
|
||||
|
||||
case RARCH_CART_BSX:
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
load_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_BSX_RAM);
|
||||
load_ram_file(g_extern.savefile_name_psrm, RETRO_MEMORY_SNES_BSX_PRAM);
|
||||
break;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
load_ram_file(g_extern.savefile_name_asrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM);
|
||||
load_ram_file(g_extern.savefile_name_bsrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < g_extern.savefiles->size; i++)
|
||||
load_ram_file(g_extern.savefiles->elems[i].data, g_extern.savefiles->elems[i].attr.i);
|
||||
}
|
||||
|
||||
static inline void save_files(void)
|
||||
{
|
||||
switch (g_extern.game_type)
|
||||
unsigned i;
|
||||
if (!g_extern.savefiles)
|
||||
return;
|
||||
|
||||
for (i = 0; i < g_extern.savefiles->size; i++)
|
||||
{
|
||||
case RARCH_CART_NORMAL:
|
||||
RARCH_LOG("Saving regular SRAM.\n");
|
||||
RARCH_LOG("SRM: %s\n", g_extern.savefile_name_srm);
|
||||
RARCH_LOG("RTC: %s\n", g_extern.savefile_name_rtc);
|
||||
save_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SAVE_RAM);
|
||||
save_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_RTC);
|
||||
break;
|
||||
|
||||
case RARCH_CART_SGB:
|
||||
RARCH_LOG("Saving Gameboy SRAM.\n");
|
||||
RARCH_LOG("SRM: %s\n", g_extern.savefile_name_srm);
|
||||
RARCH_LOG("RTC: %s\n", g_extern.savefile_name_rtc);
|
||||
save_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_GAME_BOY_RAM);
|
||||
save_ram_file(g_extern.savefile_name_rtc, RETRO_MEMORY_SNES_GAME_BOY_RTC);
|
||||
break;
|
||||
|
||||
case RARCH_CART_BSX:
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
RARCH_LOG("Saving BSX (P)RAM.\n");
|
||||
RARCH_LOG("SRM: %s\n", g_extern.savefile_name_srm);
|
||||
RARCH_LOG("PSRM: %s\n", g_extern.savefile_name_psrm);
|
||||
save_ram_file(g_extern.savefile_name_srm, RETRO_MEMORY_SNES_BSX_RAM);
|
||||
save_ram_file(g_extern.savefile_name_psrm, RETRO_MEMORY_SNES_BSX_PRAM);
|
||||
break;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
RARCH_LOG("Saving Sufami turbo A/B RAM.\n");
|
||||
RARCH_LOG("ASRM: %s\n", g_extern.savefile_name_asrm);
|
||||
RARCH_LOG("BSRM: %s\n", g_extern.savefile_name_bsrm);
|
||||
save_ram_file(g_extern.savefile_name_asrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM);
|
||||
save_ram_file(g_extern.savefile_name_bsrm, RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
unsigned type = g_extern.savefiles->elems[i].attr.i;
|
||||
const char *path = g_extern.savefiles->elems[i].data;
|
||||
RARCH_LOG("Saving RAM type #%u to \"%s\".\n", type, path);
|
||||
save_ram_file(path, type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1727,54 +1690,29 @@ static void init_libretro_cbs(void)
|
||||
#if defined(HAVE_THREADS)
|
||||
void rarch_init_autosave(void)
|
||||
{
|
||||
int ram_types[2] = {-1, -1};
|
||||
const char *ram_paths[2] = {NULL, NULL};
|
||||
if (g_settings.autosave_interval < 1 || !g_extern.savefiles)
|
||||
return;
|
||||
|
||||
switch (g_extern.game_type)
|
||||
g_extern.autosave = (autosave_t**)calloc(g_extern.savefiles->size, sizeof(*g_extern.autosave));
|
||||
if (!g_extern.autosave)
|
||||
return;
|
||||
|
||||
g_extern.num_autosave = g_extern.savefiles->size;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < g_extern.savefiles->size; i++)
|
||||
{
|
||||
case RARCH_CART_BSX:
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
ram_types[0] = RETRO_MEMORY_SNES_BSX_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_SNES_BSX_PRAM;
|
||||
ram_paths[0] = g_extern.savefile_name_srm;
|
||||
ram_paths[1] = g_extern.savefile_name_psrm;
|
||||
break;
|
||||
const char *path = g_extern.savefiles->elems[i].data;
|
||||
unsigned type = g_extern.savefiles->elems[i].attr.i;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
ram_types[0] = RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM;
|
||||
ram_paths[0] = g_extern.savefile_name_asrm;
|
||||
ram_paths[1] = g_extern.savefile_name_bsrm;
|
||||
break;
|
||||
|
||||
case RARCH_CART_SGB:
|
||||
ram_types[0] = RETRO_MEMORY_SNES_GAME_BOY_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_SNES_GAME_BOY_RTC;
|
||||
ram_paths[0] = g_extern.savefile_name_srm;
|
||||
ram_paths[1] = g_extern.savefile_name_rtc;
|
||||
break;
|
||||
|
||||
default:
|
||||
ram_types[0] = RETRO_MEMORY_SAVE_RAM;
|
||||
ram_types[1] = RETRO_MEMORY_RTC;
|
||||
ram_paths[0] = g_extern.savefile_name_srm;
|
||||
ram_paths[1] = g_extern.savefile_name_rtc;
|
||||
}
|
||||
|
||||
if (g_settings.autosave_interval > 0)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < sizeof(g_extern.autosave) / sizeof(g_extern.autosave[0]); i++)
|
||||
if (pretro_get_memory_size(type) > 0)
|
||||
{
|
||||
if (ram_paths[i] && *ram_paths[i] && pretro_get_memory_size(ram_types[i]) > 0)
|
||||
{
|
||||
g_extern.autosave[i] = autosave_new(ram_paths[i],
|
||||
pretro_get_memory_data(ram_types[i]),
|
||||
pretro_get_memory_size(ram_types[i]),
|
||||
g_settings.autosave_interval);
|
||||
if (!g_extern.autosave[i])
|
||||
RARCH_WARN("Could not initialize autosave.\n");
|
||||
}
|
||||
g_extern.autosave[i] = autosave_new(path,
|
||||
pretro_get_memory_data(type),
|
||||
pretro_get_memory_size(type),
|
||||
g_settings.autosave_interval);
|
||||
if (!g_extern.autosave[i])
|
||||
RARCH_WARN("Could not initialize autosave.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1782,12 +1720,10 @@ void rarch_init_autosave(void)
|
||||
void rarch_deinit_autosave(void)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE(g_extern.autosave); i++)
|
||||
{
|
||||
if (g_extern.autosave[i])
|
||||
autosave_free(g_extern.autosave[i]);
|
||||
g_extern.autosave[i] = NULL;
|
||||
}
|
||||
for (i = 0; i < g_extern.num_autosave; i++)
|
||||
autosave_free(g_extern.autosave[i]);
|
||||
free(g_extern.autosave);
|
||||
g_extern.num_autosave = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1838,84 +1774,85 @@ static void set_savestate_auto_index(void)
|
||||
|
||||
static void fill_pathnames(void)
|
||||
{
|
||||
switch (g_extern.game_type)
|
||||
string_list_free(g_extern.savefiles);
|
||||
g_extern.savefiles = string_list_new();
|
||||
rarch_assert(g_extern.savefiles);
|
||||
|
||||
// For subsystems, we know exactly which RAM types are supported.
|
||||
if (*g_extern.subsystem)
|
||||
{
|
||||
case RARCH_CART_BSX:
|
||||
case RARCH_CART_BSX_SLOTTED:
|
||||
// BSX PSRM
|
||||
if (!g_extern.has_set_save_path)
|
||||
unsigned i;
|
||||
const struct retro_game_special_info *info = libretro_find_subsystem_info(g_extern.system.special, g_extern.system.num_special, g_extern.subsystem);
|
||||
|
||||
// We'll handle this error gracefully later.
|
||||
unsigned num_roms = info ? info->num_roms : 0;
|
||||
bool use_sram_dir = path_is_directory(g_extern.savefile_name);
|
||||
|
||||
for (i = 0; i < num_roms; i++)
|
||||
{
|
||||
unsigned j;
|
||||
for (j = 0; j < info->roms[i].num_memory; j++)
|
||||
{
|
||||
fill_pathname(g_extern.savefile_name_srm,
|
||||
g_extern.bsx_rom_path, ".srm", sizeof(g_extern.savefile_name_srm));
|
||||
const struct retro_game_special_memory_info *mem = &info->roms[i].memory[j];
|
||||
union string_list_elem_attr attr;
|
||||
|
||||
char path[PATH_MAX];
|
||||
char ext[32];
|
||||
|
||||
snprintf(ext, sizeof(ext), ".%s", mem->extension);
|
||||
|
||||
if (use_sram_dir)
|
||||
{
|
||||
// Redirect ROM fullpath to save directory.
|
||||
strlcpy(path, g_extern.savefile_name, sizeof(path));
|
||||
fill_pathname_dir(path, g_extern.subsystem_fullpaths->elems[i].data, ext,
|
||||
sizeof(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
fill_pathname(path, g_extern.subsystem_fullpaths->elems[i].data,
|
||||
ext, sizeof(path));
|
||||
}
|
||||
|
||||
attr.i = mem->type;
|
||||
string_list_append(g_extern.savefiles, path, attr);
|
||||
}
|
||||
}
|
||||
|
||||
fill_pathname(g_extern.savefile_name_psrm,
|
||||
g_extern.savefile_name_srm, ".psrm", sizeof(g_extern.savefile_name_psrm));
|
||||
// Let other relevant paths be inferred from the main SRAM location.
|
||||
if (!g_extern.has_set_save_path)
|
||||
fill_pathname_noext(g_extern.savefile_name, g_extern.basename, ".srm", sizeof(g_extern.savefile_name));
|
||||
if (path_is_directory(g_extern.savefile_name))
|
||||
{
|
||||
fill_pathname_dir(g_extern.savefile_name, g_extern.basename, ".srm", sizeof(g_extern.savefile_name));
|
||||
RARCH_LOG("Redirecting save file to \"%s\".\n", g_extern.savefile_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
attr.i = RETRO_MEMORY_SAVE_RAM;
|
||||
string_list_append(g_extern.savefiles, g_extern.savefile_name, attr);
|
||||
|
||||
if (!g_extern.has_set_state_path)
|
||||
{
|
||||
fill_pathname(g_extern.savestate_name,
|
||||
g_extern.bsx_rom_path, ".state", sizeof(g_extern.savestate_name));
|
||||
}
|
||||
break;
|
||||
|
||||
case RARCH_CART_SUFAMI:
|
||||
if (g_extern.has_set_save_path && *g_extern.sufami_rom_path[0] && *g_extern.sufami_rom_path[1])
|
||||
RARCH_WARN("Sufami Turbo SRAM paths will be inferred from their respective paths to avoid conflicts.\n");
|
||||
|
||||
// SUFAMI ARAM
|
||||
fill_pathname(g_extern.savefile_name_asrm,
|
||||
g_extern.sufami_rom_path[0], ".srm", sizeof(g_extern.savefile_name_asrm));
|
||||
|
||||
// SUFAMI BRAM
|
||||
fill_pathname(g_extern.savefile_name_bsrm,
|
||||
g_extern.sufami_rom_path[1], ".srm", sizeof(g_extern.savefile_name_bsrm));
|
||||
|
||||
if (!g_extern.has_set_state_path)
|
||||
{
|
||||
fill_pathname(g_extern.savestate_name,
|
||||
*g_extern.sufami_rom_path[0] ?
|
||||
g_extern.sufami_rom_path[0] : g_extern.sufami_rom_path[1],
|
||||
".state", sizeof(g_extern.savestate_name));
|
||||
}
|
||||
break;
|
||||
|
||||
case RARCH_CART_SGB:
|
||||
if (!g_extern.has_set_save_path)
|
||||
{
|
||||
fill_pathname(g_extern.savefile_name_srm,
|
||||
g_extern.gb_rom_path, ".srm", sizeof(g_extern.savefile_name_srm));
|
||||
}
|
||||
|
||||
if (!g_extern.has_set_state_path)
|
||||
{
|
||||
fill_pathname(g_extern.savestate_name,
|
||||
g_extern.gb_rom_path, ".state", sizeof(g_extern.savestate_name));
|
||||
}
|
||||
|
||||
fill_pathname(g_extern.savefile_name_rtc,
|
||||
g_extern.savefile_name_srm, ".rtc", sizeof(g_extern.savefile_name_rtc));
|
||||
break;
|
||||
|
||||
default:
|
||||
// Infer .rtc save path from save ram path.
|
||||
fill_pathname(g_extern.savefile_name_rtc,
|
||||
g_extern.savefile_name_srm, ".rtc", sizeof(g_extern.savefile_name_rtc));
|
||||
// Infer .rtc save path from save ram path.
|
||||
char savefile_name_rtc[PATH_MAX];
|
||||
attr.i = RETRO_MEMORY_RTC;
|
||||
fill_pathname(savefile_name_rtc,
|
||||
g_extern.savefile_name, ".rtc", sizeof(savefile_name_rtc));
|
||||
string_list_append(g_extern.savefiles, savefile_name_rtc, attr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_BSV_MOVIE
|
||||
fill_pathname(g_extern.bsv.movie_path, g_extern.savefile_name_srm, "", sizeof(g_extern.bsv.movie_path));
|
||||
fill_pathname(g_extern.bsv.movie_path, g_extern.savefile_name, "", sizeof(g_extern.bsv.movie_path));
|
||||
#endif
|
||||
|
||||
if (*g_extern.basename)
|
||||
{
|
||||
if (!(*g_extern.ups_name))
|
||||
if (!*g_extern.ups_name)
|
||||
fill_pathname_noext(g_extern.ups_name, g_extern.basename, ".ups", sizeof(g_extern.ups_name));
|
||||
|
||||
if (!(*g_extern.bps_name))
|
||||
if (!*g_extern.bps_name)
|
||||
fill_pathname_noext(g_extern.bps_name, g_extern.basename, ".bps", sizeof(g_extern.bps_name));
|
||||
|
||||
if (!(*g_extern.ips_name))
|
||||
if (!*g_extern.ips_name)
|
||||
fill_pathname_noext(g_extern.ips_name, g_extern.basename, ".ips", sizeof(g_extern.ips_name));
|
||||
}
|
||||
}
|
||||
@ -2530,19 +2467,22 @@ void rarch_disk_control_append_image(const char *path)
|
||||
rarch_deinit_autosave();
|
||||
#endif
|
||||
|
||||
// Update paths for our new image.
|
||||
// If we actually use append_image,
|
||||
// we assume that we started out in a single disk case,
|
||||
// and that this way of doing it makes the most sense.
|
||||
set_paths(path);
|
||||
fill_pathnames();
|
||||
// TODO: Need to figure out what to do with subsystems case.
|
||||
if (!*g_extern.subsystem)
|
||||
{
|
||||
// Update paths for our new image.
|
||||
// If we actually use append_image,
|
||||
// we assume that we started out in a single disk case,
|
||||
// and that this way of doing it makes the most sense.
|
||||
set_paths(path);
|
||||
fill_pathnames();
|
||||
}
|
||||
|
||||
#if defined(HAVE_THREADS)
|
||||
rarch_init_autosave();
|
||||
#endif
|
||||
|
||||
rarch_disk_control_set_eject(false, false);
|
||||
|
||||
}
|
||||
|
||||
void rarch_disk_control_set_eject(bool new_state, bool log)
|
||||
@ -2874,7 +2814,6 @@ static void init_state(void)
|
||||
{
|
||||
g_extern.video_active = true;
|
||||
g_extern.audio_active = true;
|
||||
g_extern.game_type = RARCH_CART_NORMAL;
|
||||
}
|
||||
|
||||
static void init_state_first(void)
|
||||
@ -3007,19 +2946,18 @@ int rarch_main_init(int argc, char *argv[])
|
||||
|
||||
if (g_extern.libretro_no_rom && !g_extern.libretro_dummy)
|
||||
{
|
||||
if (!init_rom_file(g_extern.game_type))
|
||||
if (!init_rom_file())
|
||||
goto error;
|
||||
}
|
||||
else if (!g_extern.libretro_dummy)
|
||||
{
|
||||
fill_pathnames();
|
||||
|
||||
if (!init_rom_file(g_extern.game_type))
|
||||
if (!init_rom_file())
|
||||
goto error;
|
||||
|
||||
set_savestate_auto_index();
|
||||
|
||||
|
||||
if (!g_extern.sram_load_disable)
|
||||
load_save_files();
|
||||
else
|
||||
@ -3278,13 +3216,24 @@ void rarch_main_deinit(void)
|
||||
pretro_deinit();
|
||||
uninit_libretro_sym();
|
||||
|
||||
if (g_extern.rom_file_temporary)
|
||||
if (g_extern.temporary_roms)
|
||||
{
|
||||
RARCH_LOG("Removing temporary ROM file: %s.\n", g_extern.last_rom);
|
||||
if (remove(g_extern.last_rom) < 0)
|
||||
RARCH_ERR("Failed to remove temporary file: %s.\n", g_extern.last_rom);
|
||||
g_extern.rom_file_temporary = false;
|
||||
unsigned i;
|
||||
for (i = 0; i < g_extern.temporary_roms->size; i++)
|
||||
{
|
||||
const char *path = g_extern.temporary_roms->elems[i].data;
|
||||
RARCH_LOG("Removing temporary ROM file: %s.\n", path);
|
||||
if (remove(path) < 0)
|
||||
RARCH_ERR("Failed to remove temporary file: %s.\n", path);
|
||||
}
|
||||
}
|
||||
string_list_free(g_extern.temporary_roms);
|
||||
g_extern.temporary_roms = NULL;
|
||||
|
||||
string_list_free(g_extern.subsystem_fullpaths);
|
||||
string_list_free(g_extern.savefiles);
|
||||
g_extern.subsystem_fullpaths = NULL;
|
||||
g_extern.savefiles = NULL;
|
||||
|
||||
g_extern.main_is_init = false;
|
||||
}
|
||||
|
@ -1009,8 +1009,8 @@ bool config_load_file(const char *path, bool set_defaults)
|
||||
else if (path_is_directory(tmp_str))
|
||||
{
|
||||
strlcpy(g_extern.savefile_dir, tmp_str, sizeof(g_extern.savefile_dir));
|
||||
strlcpy(g_extern.savefile_name_srm, tmp_str, sizeof(g_extern.savefile_name_srm));
|
||||
fill_pathname_dir(g_extern.savefile_name_srm, g_extern.basename, ".srm", sizeof(g_extern.savefile_name_srm));
|
||||
strlcpy(g_extern.savefile_name, tmp_str, sizeof(g_extern.savefile_name));
|
||||
fill_pathname_dir(g_extern.savefile_name, g_extern.basename, ".srm", sizeof(g_extern.savefile_name));
|
||||
}
|
||||
else
|
||||
RARCH_WARN("savefile_directory is not a directory, ignoring ...\n");
|
||||
|
Loading…
Reference in New Issue
Block a user