config/data folders improvements
linux: look for legacy ~/.reicast and ~/.reicast/data else look for ~/.config/flycast and ~/.local/share/flycast and ~/.config/reicast and ~/.local/share/reicast (defaults to flycast) look for bios files in home folder and data folders (android, windows ,macos), then in game folder. on linux, search in /usr/share/flycast and /usr/local/share/flycast and legacy locations
This commit is contained in:
parent
d485da19b7
commit
8f77a5482a
|
@ -81,7 +81,7 @@ bool cfgOpen()
|
||||||
// Config dir not set (android onboarding)
|
// Config dir not set (android onboarding)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const char* filename = "/emu.cfg";
|
const char* filename = "emu.cfg";
|
||||||
std::string config_path_read = get_readonly_config_path(filename);
|
std::string config_path_read = get_readonly_config_path(filename);
|
||||||
cfgPath = get_writable_config_path(filename);
|
cfgPath = get_writable_config_path(filename);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
void AICA_Sample();
|
void AICA_Sample();
|
||||||
void AICA_Sample32();
|
void AICA_Sample32();
|
||||||
|
|
||||||
//u32 ReadChannelReg(u32 channel,u32 reg);
|
|
||||||
void WriteChannelReg(u32 channel, u32 reg, int size);
|
void WriteChannelReg(u32 channel, u32 reg, int size);
|
||||||
|
|
||||||
void sgc_Init();
|
void sgc_Init();
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "stdclass.h"
|
||||||
|
|
||||||
struct MemChip
|
struct MemChip
|
||||||
{
|
{
|
||||||
|
@ -75,54 +76,41 @@ struct MemChip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Load(const std::string& root, const std::string& prefix, const std::string& names_ro, const std::string& title)
|
bool Load(const std::string& prefix, const std::string& names_ro, const std::string& title)
|
||||||
{
|
{
|
||||||
char base[512];
|
const size_t npos = std::string::npos;
|
||||||
char temp[512];
|
size_t start = 0;
|
||||||
char names[512];
|
while (start < names_ro.size())
|
||||||
|
|
||||||
// FIXME: Data loss if buffer is too small
|
|
||||||
strncpy(names,names_ro.c_str(), sizeof(names));
|
|
||||||
names[sizeof(names) - 1] = '\0';
|
|
||||||
|
|
||||||
sprintf(base,"%s",root.c_str());
|
|
||||||
|
|
||||||
char* curr=names;
|
|
||||||
char* next;
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
next=strstr(curr,";");
|
size_t semicolon = names_ro.find(';', start);
|
||||||
if(next) *next=0;
|
std::string name = names_ro.substr(start, semicolon == npos ? semicolon : semicolon - start);
|
||||||
if (curr[0]=='%')
|
|
||||||
{
|
|
||||||
sprintf(temp,"%s%s%s",base,prefix.c_str(),curr+1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf(temp,"%s%s",base,curr);
|
|
||||||
}
|
|
||||||
|
|
||||||
curr=next+1;
|
|
||||||
|
|
||||||
if (Load(temp))
|
size_t percent = name.find('%');
|
||||||
|
if (percent != npos)
|
||||||
|
name = name.replace(percent, 1, prefix);
|
||||||
|
|
||||||
|
std::string fullpath = get_readonly_data_path(name);
|
||||||
|
if (file_exists(fullpath) && Load(fullpath))
|
||||||
{
|
{
|
||||||
INFO_LOG(FLASHROM, "Loaded %s as %s", temp, title.c_str());
|
INFO_LOG(FLASHROM, "Loaded %s as %s", fullpath.c_str(), title.c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} while(next);
|
|
||||||
|
|
||||||
|
|
||||||
|
start = semicolon;
|
||||||
|
if (start != npos)
|
||||||
|
start++;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void Save(const std::string& root, const std::string& prefix, const std::string& name_ro, const std::string& title)
|
|
||||||
{
|
|
||||||
char path[512];
|
|
||||||
|
|
||||||
sprintf(path,"%s%s%s",root.c_str(),prefix.c_str(),name_ro.c_str());
|
void Save(const std::string& prefix, const std::string& name_ro, const std::string& title)
|
||||||
|
{
|
||||||
|
std::string path = get_writable_data_path(prefix + name_ro);
|
||||||
Save(path);
|
Save(path);
|
||||||
|
|
||||||
INFO_LOG(FLASHROM, "Saved %s as %s", path, title.c_str());
|
INFO_LOG(FLASHROM, "Saved %s as %s", path.c_str(), title.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Reset() {}
|
virtual void Reset() {}
|
||||||
virtual bool Serialize(void **data, unsigned int *total_size) { return true; }
|
virtual bool Serialize(void **data, unsigned int *total_size) { return true; }
|
||||||
virtual bool Unserialize(void **data, unsigned int *total_size) { return true; }
|
virtual bool Unserialize(void **data, unsigned int *total_size) { return true; }
|
||||||
|
|
|
@ -164,11 +164,11 @@ void FixUpFlash()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nvmem_load(const std::string& root)
|
static bool nvmem_load()
|
||||||
{
|
{
|
||||||
bool rc;
|
bool rc;
|
||||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||||
rc = sys_nvmem->Load(root, getRomPrefix(), "%nvmem.bin", "nvram");
|
rc = sys_nvmem->Load(getRomPrefix(), "%nvmem.bin", "nvram");
|
||||||
else
|
else
|
||||||
rc = sys_nvmem->Load(get_game_save_prefix() + ".nvmem");
|
rc = sys_nvmem->Load(get_game_save_prefix() + ".nvmem");
|
||||||
if (!rc)
|
if (!rc)
|
||||||
|
@ -180,12 +180,12 @@ static bool nvmem_load(const std::string& root)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadRomFiles(const std::string& root)
|
bool LoadRomFiles()
|
||||||
{
|
{
|
||||||
nvmem_load(root);
|
nvmem_load();
|
||||||
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
|
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
|
||||||
{
|
{
|
||||||
if (sys_rom->Load(root, getRomPrefix(), "%boot.bin;%boot.bin.bin;%bios.bin;%bios.bin.bin", "bootrom"))
|
if (sys_rom->Load(getRomPrefix(), "%boot.bin;%boot.bin.bin;%bios.bin;%bios.bin.bin", "bootrom"))
|
||||||
bios_loaded = true;
|
bios_loaded = true;
|
||||||
else if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
else if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||||
return false;
|
return false;
|
||||||
|
@ -194,19 +194,19 @@ bool LoadRomFiles(const std::string& root)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveRomFiles(const std::string& root)
|
void SaveRomFiles()
|
||||||
{
|
{
|
||||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||||
sys_nvmem->Save(root, getRomPrefix(), "nvmem.bin", "nvmem");
|
sys_nvmem->Save(getRomPrefix(), "nvmem.bin", "nvmem");
|
||||||
else
|
else
|
||||||
sys_nvmem->Save(get_game_save_prefix() + ".nvmem");
|
sys_nvmem->Save(get_game_save_prefix() + ".nvmem");
|
||||||
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
||||||
sys_rom->Save(get_game_save_prefix() + ".nvmem2");
|
sys_rom->Save(get_game_save_prefix() + ".nvmem2");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadHle(const std::string& root)
|
bool LoadHle()
|
||||||
{
|
{
|
||||||
if (!nvmem_load(root))
|
if (!nvmem_load())
|
||||||
WARN_LOG(FLASHROM, "No nvmem loaded\n");
|
WARN_LOG(FLASHROM, "No nvmem loaded\n");
|
||||||
|
|
||||||
reios_reset(sys_rom->data);
|
reios_reset(sys_rom->data);
|
||||||
|
|
|
@ -7,4 +7,9 @@ void map_area0(u32 base);
|
||||||
//Init/Res/Term
|
//Init/Res/Term
|
||||||
void sh4_area0_Init();
|
void sh4_area0_Init();
|
||||||
void sh4_area0_Reset(bool Manual);
|
void sh4_area0_Reset(bool Manual);
|
||||||
void sh4_area0_Term();
|
void sh4_area0_Term();
|
||||||
|
|
||||||
|
bool LoadRomFiles();
|
||||||
|
void SaveRomFiles();
|
||||||
|
bool LoadHle();
|
||||||
|
void FixUpFlash();
|
||||||
|
|
|
@ -482,8 +482,11 @@ struct maple_sega_vmu: maple_base
|
||||||
memset(flash_data, 0, sizeof(flash_data));
|
memset(flash_data, 0, sizeof(flash_data));
|
||||||
memset(lcd_data, 0, sizeof(lcd_data));
|
memset(lcd_data, 0, sizeof(lcd_data));
|
||||||
char tempy[512];
|
char tempy[512];
|
||||||
sprintf(tempy, "/vmu_save_%s.bin", logical_port);
|
sprintf(tempy, "vmu_save_%s.bin", logical_port);
|
||||||
std::string apath = get_writable_data_path(tempy);
|
// VMU saves used to be stored in .reicast, not in .reicast/data
|
||||||
|
std::string apath = get_writable_config_path(tempy);
|
||||||
|
if (!file_exists(apath))
|
||||||
|
apath = get_writable_data_path(tempy);
|
||||||
|
|
||||||
file = fopen(apath.c_str(), "rb+");
|
file = fopen(apath.c_str(), "rb+");
|
||||||
if (!file)
|
if (!file)
|
||||||
|
@ -492,25 +495,19 @@ struct maple_sega_vmu: maple_base
|
||||||
file = fopen(apath.c_str(), "wb");
|
file = fopen(apath.c_str(), "wb");
|
||||||
if (file) {
|
if (file) {
|
||||||
if (!init_emptyvmu())
|
if (!init_emptyvmu())
|
||||||
INFO_LOG(MAPLE, "Failed to initialize an empty VMU, you should reformat it using the BIOS");
|
WARN_LOG(MAPLE, "Failed to initialize an empty VMU, you should reformat it using the BIOS");
|
||||||
|
|
||||||
fwrite(flash_data, sizeof(flash_data), 1, file);
|
fwrite(flash_data, sizeof(flash_data), 1, file);
|
||||||
fseek(file, 0, SEEK_SET);
|
fseek(file, 0, SEEK_SET);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
INFO_LOG(MAPLE, "Unable to create VMU!");
|
ERROR_LOG(MAPLE, "Failed to create VMU save file \"%s\"", apath.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file)
|
if (file != nullptr)
|
||||||
{
|
|
||||||
INFO_LOG(MAPLE, "Failed to create VMU save file \"%s\"", apath.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fread(flash_data, 1, sizeof(flash_data), file);
|
fread(flash_data, 1, sizeof(flash_data), file);
|
||||||
}
|
|
||||||
|
|
||||||
u8 sum = 0;
|
u8 sum = 0;
|
||||||
for (u32 i = 0; i < sizeof(flash_data); i++)
|
for (u32 i = 0; i < sizeof(flash_data); i++)
|
||||||
|
@ -521,20 +518,15 @@ struct maple_sega_vmu: maple_base
|
||||||
|
|
||||||
if (init_emptyvmu())
|
if (init_emptyvmu())
|
||||||
{
|
{
|
||||||
if (!file)
|
if (file != nullptr)
|
||||||
file = fopen(apath.c_str(), "wb");
|
{
|
||||||
|
|
||||||
if (file) {
|
|
||||||
fwrite(flash_data, sizeof(flash_data), 1, file);
|
fwrite(flash_data, sizeof(flash_data), 1, file);
|
||||||
fseek(file, 0, SEEK_SET);
|
fseek(file, 0, SEEK_SET);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
INFO_LOG(MAPLE, "Unable to create VMU!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
INFO_LOG(MAPLE, "Failed to initialize an empty VMU, you should reformat it using the BIOS");
|
WARN_LOG(MAPLE, "Failed to initialize an empty VMU, you should reformat it using the BIOS");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3001,7 +2993,7 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
|
||||||
jvs_length = length - 2;
|
jvs_length = length - 2;
|
||||||
|
|
||||||
u8 calc_crc = 0;
|
u8 calc_crc = 0;
|
||||||
for (int i = 1; i < length; i++)
|
for (u32 i = 1; i < length; i++)
|
||||||
calc_crc = ((calc_crc + buffer_out[i]) & 0xFF);
|
calc_crc = ((calc_crc + buffer_out[i]) & 0xFF);
|
||||||
|
|
||||||
JVS_OUT(calc_crc);
|
JVS_OUT(calc_crc);
|
||||||
|
|
|
@ -76,8 +76,12 @@ static bool naomi_LoadBios(const char *filename, Archive *child_archive, Archive
|
||||||
|
|
||||||
struct BIOS_t *bios = &BIOS[biosid];
|
struct BIOS_t *bios = &BIOS[biosid];
|
||||||
|
|
||||||
std::string basepath = get_readonly_data_path(DATA_PATH);
|
std::string arch_name(filename);
|
||||||
std::unique_ptr<Archive> bios_archive(OpenArchive((basepath + filename).c_str()));
|
std::string path = get_readonly_data_path(arch_name + ".zip");
|
||||||
|
if (!file_exists(path.c_str()))
|
||||||
|
path = get_readonly_data_path(arch_name + ".7z");
|
||||||
|
DEBUG_LOG(NAOMI, "Loading BIOS from %s", path.c_str());
|
||||||
|
std::unique_ptr<Archive> bios_archive(OpenArchive(path.c_str()));
|
||||||
|
|
||||||
bool found_region = false;
|
bool found_region = false;
|
||||||
|
|
||||||
|
@ -232,7 +236,7 @@ static void naomi_cart_LoadZip(const char *filename)
|
||||||
{
|
{
|
||||||
// If a specific BIOS is needed for this game, fail.
|
// If a specific BIOS is needed for this game, fail.
|
||||||
if (game->bios != NULL || !bios_loaded)
|
if (game->bios != NULL || !bios_loaded)
|
||||||
throw NaomiCartException(std::string("Error: cannot load BIOS ") + (game->bios != NULL ? game->bios : "naomi.zip") + " in " + get_readonly_data_path(DATA_PATH));
|
throw NaomiCartException(std::string("Error: cannot load BIOS ") + (game->bios != NULL ? game->bios : "naomi.zip"));
|
||||||
|
|
||||||
// otherwise use the default BIOS
|
// otherwise use the default BIOS
|
||||||
}
|
}
|
||||||
|
|
|
@ -652,7 +652,7 @@ void print_blocks()
|
||||||
|
|
||||||
if (print_stats)
|
if (print_stats)
|
||||||
{
|
{
|
||||||
f=fopen(get_writable_data_path("/blkmap.lst").c_str(),"w");
|
f=fopen(get_writable_data_path("blkmap.lst").c_str(),"w");
|
||||||
print_stats=0;
|
print_stats=0;
|
||||||
|
|
||||||
INFO_LOG(DYNAREC, "Writing blocks to %p", f);
|
INFO_LOG(DYNAREC, "Writing blocks to %p", f);
|
||||||
|
@ -680,9 +680,7 @@ void print_blocks()
|
||||||
fprintf(f,"host_opcodes: %d\n",blk->host_opcodes);
|
fprintf(f,"host_opcodes: %d\n",blk->host_opcodes);
|
||||||
fprintf(f,"il_opcodes: %zd\n",blk->oplist.size());
|
fprintf(f,"il_opcodes: %zd\n",blk->oplist.size());
|
||||||
|
|
||||||
u32 hcode=0;
|
|
||||||
s32 gcode=-1;
|
s32 gcode=-1;
|
||||||
u8* pucode=(u8*)blk->code;
|
|
||||||
|
|
||||||
size_t j=0;
|
size_t j=0;
|
||||||
|
|
||||||
|
|
|
@ -223,12 +223,6 @@ void mem_Term()
|
||||||
sh4_mmr_term();
|
sh4_mmr_term();
|
||||||
sh4_area0_Term();
|
sh4_area0_Term();
|
||||||
|
|
||||||
// done by emulator thread
|
|
||||||
//SaveRomFiles(get_writable_data_path(DATA_PATH));
|
|
||||||
|
|
||||||
//mem_b.Term(); // handled by vmem
|
|
||||||
|
|
||||||
//vmem
|
|
||||||
_vmem_term();
|
_vmem_term();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,8 +85,4 @@ u8* GetMemPtr(u32 Addr,u32 size);
|
||||||
|
|
||||||
bool IsOnRam(u32 addr);
|
bool IsOnRam(u32 addr);
|
||||||
|
|
||||||
bool LoadRomFiles(const std::string& root);
|
|
||||||
void SaveRomFiles(const std::string& root);
|
|
||||||
bool LoadHle(const std::string& root);
|
|
||||||
void FixUpFlash();
|
|
||||||
void SetMemoryHandlers();
|
void SetMemoryHandlers();
|
||||||
|
|
|
@ -205,7 +205,7 @@ std::shared_ptr<InputMapping> InputMapping::LoadMapping(const char *name)
|
||||||
if (it != loaded_mappings.end())
|
if (it != loaded_mappings.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
||||||
std::string path = get_writable_config_path((std::string("/mappings/") + name).c_str());
|
std::string path = get_readonly_config_path((std::string("mappings/") + name).c_str());
|
||||||
FILE *fp = fopen(path.c_str(), "r");
|
FILE *fp = fopen(path.c_str(), "r");
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -222,9 +222,9 @@ bool InputMapping::save(const char *name)
|
||||||
if (!dirty)
|
if (!dirty)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
std::string path = get_writable_config_path("/mappings/");
|
std::string path = get_writable_config_path("mappings/");
|
||||||
make_directory(path);
|
make_directory(path);
|
||||||
path = get_writable_config_path((std::string("/mappings/") + name).c_str());
|
path = get_writable_config_path((std::string("mappings/") + name).c_str());
|
||||||
FILE *fp = fopen(path.c_str(), "w");
|
FILE *fp = fopen(path.c_str(), "w");
|
||||||
if (fp == NULL)
|
if (fp == NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -151,89 +151,139 @@ void* rend_thread(void* p);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Find the user config directory.
|
||||||
|
// The following folders are checked in this order:
|
||||||
|
// $HOME/.reicast
|
||||||
|
// $HOME/.config/flycast
|
||||||
|
// $HOME/.config/reicast
|
||||||
|
// If no folder exists, $HOME/.config/flycast is created and used.
|
||||||
std::string find_user_config_dir()
|
std::string find_user_config_dir()
|
||||||
{
|
{
|
||||||
struct stat info;
|
struct stat info;
|
||||||
std::string home = "";
|
std::string xdg_home;
|
||||||
if(getenv("HOME") != NULL)
|
if (getenv("HOME") != NULL)
|
||||||
{
|
{
|
||||||
// Support for the legacy config dir at "$HOME/.reicast"
|
// Support for the legacy config dir at "$HOME/.reicast"
|
||||||
std::string legacy_home = (std::string)getenv("HOME") + "/.reicast";
|
std::string legacy_home = (std::string)getenv("HOME") + "/.reicast/";
|
||||||
if((stat(legacy_home.c_str(), &info) == 0) && (info.st_mode & S_IFDIR))
|
if (stat(legacy_home.c_str(), &info) == 0 && (info.st_mode & S_IFDIR))
|
||||||
{
|
|
||||||
// "$HOME/.reicast" already exists, let's use it!
|
// "$HOME/.reicast" already exists, let's use it!
|
||||||
return legacy_home;
|
return legacy_home;
|
||||||
}
|
|
||||||
|
|
||||||
/* If $XDG_CONFIG_HOME is not set, we're supposed to use "$HOME/.config" instead.
|
/* If $XDG_CONFIG_HOME is not set, we're supposed to use "$HOME/.config" instead.
|
||||||
* Consult the XDG Base Directory Specification for details:
|
* Consult the XDG Base Directory Specification for details:
|
||||||
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
|
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
|
||||||
*/
|
*/
|
||||||
home = (std::string)getenv("HOME") + "/.config/reicast";
|
xdg_home = (std::string)getenv("HOME") + "/.config";
|
||||||
}
|
}
|
||||||
if(getenv("XDG_CONFIG_HOME") != NULL)
|
if (getenv("XDG_CONFIG_HOME") != NULL)
|
||||||
{
|
|
||||||
// If XDG_CONFIG_HOME is set explicitly, we'll use that instead of $HOME/.config
|
// If XDG_CONFIG_HOME is set explicitly, we'll use that instead of $HOME/.config
|
||||||
home = (std::string)getenv("XDG_CONFIG_HOME") + "/reicast";
|
xdg_home = (std::string)getenv("XDG_CONFIG_HOME");
|
||||||
}
|
|
||||||
|
|
||||||
if(!home.empty())
|
if (!xdg_home.empty())
|
||||||
{
|
{
|
||||||
if((stat(home.c_str(), &info) != 0) || !(info.st_mode & S_IFDIR))
|
std::string fullpath = xdg_home + "/flycast/";
|
||||||
{
|
if (stat(fullpath.c_str(), &info) == 0 && (info.st_mode & S_IFDIR))
|
||||||
// If the directory doesn't exist yet, create it!
|
// Found .config/flycast
|
||||||
mkdir(home.c_str(), 0755);
|
return fullpath;
|
||||||
}
|
fullpath = xdg_home + "/reicast/";
|
||||||
return home;
|
if (stat(fullpath.c_str(), &info) == 0 && (info.st_mode & S_IFDIR))
|
||||||
|
// Found .config/reicast
|
||||||
|
return fullpath;
|
||||||
|
|
||||||
|
// Create .config/flycast
|
||||||
|
fullpath = xdg_home + "/flycast/";
|
||||||
|
mkdir(fullpath.c_str(), 0755);
|
||||||
|
|
||||||
|
return fullpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unable to detect config dir, use the current folder
|
// Unable to detect config dir, use the current folder
|
||||||
return ".";
|
return ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the user data directory.
|
||||||
|
// The following folders are checked in this order:
|
||||||
|
// $HOME/.reicast/data
|
||||||
|
// $HOME/.local/share/flycast
|
||||||
|
// $HOME/.local/share/reicast
|
||||||
|
// If no folder exists, $HOME/.local/share/flycast is created and used.
|
||||||
std::string find_user_data_dir()
|
std::string find_user_data_dir()
|
||||||
{
|
{
|
||||||
struct stat info;
|
struct stat info;
|
||||||
std::string data = "";
|
std::string xdg_home;
|
||||||
if(getenv("HOME") != NULL)
|
if (getenv("HOME") != NULL)
|
||||||
{
|
{
|
||||||
// Support for the legacy config dir at "$HOME/.reicast"
|
// Support for the legacy config dir at "$HOME/.reicast/data"
|
||||||
std::string legacy_data = (std::string)getenv("HOME") + "/.reicast";
|
std::string legacy_data = (std::string)getenv("HOME") + "/.reicast/data/";
|
||||||
if((stat(legacy_data.c_str(), &info) == 0) && (info.st_mode & S_IFDIR))
|
if (stat(legacy_data.c_str(), &info) == 0 && (info.st_mode & S_IFDIR))
|
||||||
{
|
// "$HOME/.reicast/data" already exists, let's use it!
|
||||||
// "$HOME/.reicast" already exists, let's use it!
|
|
||||||
return legacy_data;
|
return legacy_data;
|
||||||
}
|
|
||||||
|
|
||||||
/* If $XDG_DATA_HOME is not set, we're supposed to use "$HOME/.local/share" instead.
|
/* If $XDG_DATA_HOME is not set, we're supposed to use "$HOME/.local/share" instead.
|
||||||
* Consult the XDG Base Directory Specification for details:
|
* Consult the XDG Base Directory Specification for details:
|
||||||
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
|
* http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
|
||||||
*/
|
*/
|
||||||
data = (std::string)getenv("HOME") + "/.local/share/reicast";
|
xdg_home = (std::string)getenv("HOME") + "/.local/share";
|
||||||
}
|
}
|
||||||
if(getenv("XDG_DATA_HOME") != NULL)
|
if (getenv("XDG_DATA_HOME") != NULL)
|
||||||
|
// If XDG_DATA_HOME is set explicitly, we'll use that instead of $HOME/.local/share
|
||||||
|
xdg_home = (std::string)getenv("XDG_DATA_HOME");
|
||||||
|
|
||||||
|
if (!xdg_home.empty())
|
||||||
{
|
{
|
||||||
// If XDG_DATA_HOME is set explicitly, we'll use that instead of $HOME/.config
|
std::string fullpath = xdg_home + "/flycast/";
|
||||||
data = (std::string)getenv("XDG_DATA_HOME") + "/reicast";
|
if (stat(fullpath.c_str(), &info) == 0 && (info.st_mode & S_IFDIR))
|
||||||
|
// Found .local/share/flycast
|
||||||
|
return fullpath;
|
||||||
|
fullpath = xdg_home + "/reicast/";
|
||||||
|
if (stat(fullpath.c_str(), &info) == 0 && (info.st_mode & S_IFDIR))
|
||||||
|
// Found .local/share/reicast
|
||||||
|
return fullpath;
|
||||||
|
|
||||||
|
// Create .local/share/flycast
|
||||||
|
fullpath = xdg_home + "/flycast/";
|
||||||
|
mkdir(fullpath.c_str(), 0755);
|
||||||
|
|
||||||
|
return fullpath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!data.empty())
|
// Unable to detect data dir, use the current folder
|
||||||
{
|
|
||||||
if((stat(data.c_str(), &info) != 0) || !(info.st_mode & S_IFDIR))
|
|
||||||
{
|
|
||||||
// If the directory doesn't exist yet, create it!
|
|
||||||
mkdir(data.c_str(), 0755);
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unable to detect config dir, use the current folder
|
|
||||||
return ".";
|
return ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find a file in the user and system config directories.
|
||||||
|
// The following folders are checked in this order:
|
||||||
|
// $HOME/.reicast
|
||||||
|
// $HOME/.config/flycast
|
||||||
|
// $HOME/.config/reicast
|
||||||
|
// if XDG_CONFIG_DIRS is defined:
|
||||||
|
// <$XDG_CONFIG_DIRS>/flycast
|
||||||
|
// <$XDG_CONFIG_DIRS>/reicast
|
||||||
|
// else
|
||||||
|
// /etc/flycast/
|
||||||
|
// /etc/xdg/flycast/
|
||||||
|
// .
|
||||||
std::vector<std::string> find_system_config_dirs()
|
std::vector<std::string> find_system_config_dirs()
|
||||||
{
|
{
|
||||||
std::vector<std::string> dirs;
|
std::vector<std::string> dirs;
|
||||||
|
|
||||||
|
std::string xdg_home;
|
||||||
|
if (getenv("HOME") != NULL)
|
||||||
|
{
|
||||||
|
// Support for the legacy config dir at "$HOME/.reicast"
|
||||||
|
dirs.push_back((std::string)getenv("HOME") + "/.reicast/");
|
||||||
|
xdg_home = (std::string)getenv("HOME") + "/.config";
|
||||||
|
}
|
||||||
|
if (getenv("XDG_CONFIG_HOME") != NULL)
|
||||||
|
// If XDG_CONFIG_HOME is set explicitly, we'll use that instead of $HOME/.config
|
||||||
|
xdg_home = (std::string)getenv("XDG_CONFIG_HOME");
|
||||||
|
if (!xdg_home.empty())
|
||||||
|
{
|
||||||
|
// XDG config locations
|
||||||
|
dirs.push_back(xdg_home + "/flycast/");
|
||||||
|
dirs.push_back(xdg_home + "/reicast/");
|
||||||
|
}
|
||||||
|
|
||||||
if (getenv("XDG_CONFIG_DIRS") != NULL)
|
if (getenv("XDG_CONFIG_DIRS") != NULL)
|
||||||
{
|
{
|
||||||
std::string s = (std::string)getenv("XDG_CONFIG_DIRS");
|
std::string s = (std::string)getenv("XDG_CONFIG_DIRS");
|
||||||
|
@ -242,24 +292,61 @@ std::vector<std::string> find_system_config_dirs()
|
||||||
std::string::size_type n = s.find(':', pos);
|
std::string::size_type n = s.find(':', pos);
|
||||||
while(n != std::string::npos)
|
while(n != std::string::npos)
|
||||||
{
|
{
|
||||||
dirs.push_back(s.substr(pos, n-pos) + "/reicast");
|
dirs.push_back(s.substr(pos, n-pos) + "/flycast/");
|
||||||
|
dirs.push_back(s.substr(pos, n-pos) + "/reicast/");
|
||||||
pos = n + 1;
|
pos = n + 1;
|
||||||
n = s.find(':', pos);
|
n = s.find(':', pos);
|
||||||
}
|
}
|
||||||
// Separator not found
|
// Separator not found
|
||||||
dirs.push_back(s.substr(pos) + "/reicast");
|
dirs.push_back(s.substr(pos) + "/flycast/");
|
||||||
|
dirs.push_back(s.substr(pos) + "/reicast/");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dirs.push_back("/etc/reicast"); // This isn't part of the XDG spec, but much more common than /etc/xdg/
|
dirs.push_back("/etc/flycast/"); // This isn't part of the XDG spec, but much more common than /etc/xdg/
|
||||||
dirs.push_back("/etc/xdg/reicast");
|
dirs.push_back("/etc/xdg/flycast/");
|
||||||
}
|
}
|
||||||
|
dirs.push_back("./");
|
||||||
|
|
||||||
return dirs;
|
return dirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find a file in the user data directories.
|
||||||
|
// The following folders are checked in this order:
|
||||||
|
// $HOME/.reicast/data
|
||||||
|
// $HOME/.local/share/flycast
|
||||||
|
// $HOME/.local/share/reicast
|
||||||
|
// if XDG_DATA_DIRS is defined:
|
||||||
|
// <$XDG_DATA_DIRS>/flycast
|
||||||
|
// <$XDG_DATA_DIRS>/reicast
|
||||||
|
// else
|
||||||
|
// /usr/local/share/flycast
|
||||||
|
// /usr/share/flycast
|
||||||
|
// /usr/local/share/reicast
|
||||||
|
// /usr/share/reicast
|
||||||
|
// ./data
|
||||||
std::vector<std::string> find_system_data_dirs()
|
std::vector<std::string> find_system_data_dirs()
|
||||||
{
|
{
|
||||||
std::vector<std::string> dirs;
|
std::vector<std::string> dirs;
|
||||||
|
|
||||||
|
std::string xdg_home;
|
||||||
|
if (getenv("HOME") != NULL)
|
||||||
|
{
|
||||||
|
// Support for the legacy data dir at "$HOME/.reicast/data"
|
||||||
|
dirs.push_back((std::string)getenv("HOME") + "/.reicast/data/");
|
||||||
|
xdg_home = (std::string)getenv("HOME") + "/.local/share";
|
||||||
|
}
|
||||||
|
if (getenv("XDG_DATA_HOME") != NULL)
|
||||||
|
// If XDG_DATA_HOME is set explicitly, we'll use that instead of $HOME/.local/share
|
||||||
|
xdg_home = (std::string)getenv("XDG_DATA_HOME");
|
||||||
|
if (!xdg_home.empty())
|
||||||
|
{
|
||||||
|
// XDG data locations
|
||||||
|
dirs.push_back(xdg_home + "/flycast/");
|
||||||
|
dirs.push_back(xdg_home + "/reicast/");
|
||||||
|
dirs.push_back(xdg_home + "/reicast/data/");
|
||||||
|
}
|
||||||
|
|
||||||
if (getenv("XDG_DATA_DIRS") != NULL)
|
if (getenv("XDG_DATA_DIRS") != NULL)
|
||||||
{
|
{
|
||||||
std::string s = (std::string)getenv("XDG_DATA_DIRS");
|
std::string s = (std::string)getenv("XDG_DATA_DIRS");
|
||||||
|
@ -268,18 +355,25 @@ std::vector<std::string> find_system_data_dirs()
|
||||||
std::string::size_type n = s.find(':', pos);
|
std::string::size_type n = s.find(':', pos);
|
||||||
while(n != std::string::npos)
|
while(n != std::string::npos)
|
||||||
{
|
{
|
||||||
dirs.push_back(s.substr(pos, n-pos) + "/reicast");
|
dirs.push_back(s.substr(pos, n-pos) + "/flycast/");
|
||||||
|
dirs.push_back(s.substr(pos, n-pos) + "/reicast/");
|
||||||
pos = n + 1;
|
pos = n + 1;
|
||||||
n = s.find(':', pos);
|
n = s.find(':', pos);
|
||||||
}
|
}
|
||||||
// Separator not found
|
// Separator not found
|
||||||
dirs.push_back(s.substr(pos) + "/reicast");
|
dirs.push_back(s.substr(pos) + "/flycast/");
|
||||||
|
dirs.push_back(s.substr(pos) + "/reicast/");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dirs.push_back("/usr/local/share/reicast");
|
dirs.push_back("/usr/local/share/flycast/");
|
||||||
dirs.push_back("/usr/share/reicast");
|
dirs.push_back("/usr/share/flycast/");
|
||||||
|
dirs.push_back("/usr/local/share/reicast/");
|
||||||
|
dirs.push_back("/usr/share/reicast/");
|
||||||
}
|
}
|
||||||
|
dirs.push_back("./");
|
||||||
|
dirs.push_back("data/");
|
||||||
|
|
||||||
return dirs;
|
return dirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,22 +385,15 @@ int main(int argc, char* argv[])
|
||||||
signal(SIGKILL, clean_exit);
|
signal(SIGKILL, clean_exit);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Set directories */
|
// Set directories
|
||||||
set_user_config_dir(find_user_config_dir());
|
set_user_config_dir(find_user_config_dir());
|
||||||
set_user_data_dir(find_user_data_dir());
|
set_user_data_dir(find_user_data_dir());
|
||||||
std::vector<std::string> dirs;
|
for (const auto& dir : find_system_config_dirs())
|
||||||
dirs = find_system_config_dirs();
|
add_system_config_dir(dir);
|
||||||
for (std::size_t i = 0; i < dirs.size(); i++)
|
for (const auto& dir : find_system_data_dirs())
|
||||||
{
|
add_system_data_dir(dir);
|
||||||
add_system_data_dir(dirs[i]);
|
INFO_LOG(BOOT, "Config dir is: %s", get_writable_config_path("").c_str());
|
||||||
}
|
INFO_LOG(BOOT, "Data dir is: %s", get_writable_data_path("").c_str());
|
||||||
dirs = find_system_data_dirs();
|
|
||||||
for (std::size_t i = 0; i < dirs.size(); i++)
|
|
||||||
{
|
|
||||||
add_system_data_dir(dirs[i]);
|
|
||||||
}
|
|
||||||
INFO_LOG(BOOT, "Config dir is: %s", get_writable_config_path("/").c_str());
|
|
||||||
INFO_LOG(BOOT, "Data dir is: %s", get_writable_data_path("/").c_str());
|
|
||||||
|
|
||||||
#if defined(USE_SDL)
|
#if defined(USE_SDL)
|
||||||
// init video now: on rpi3 it installs a sigsegv handler(?)
|
// init video now: on rpi3 it installs a sigsegv handler(?)
|
||||||
|
|
|
@ -121,7 +121,7 @@ static int allocate_shared_filemem(unsigned size) {
|
||||||
|
|
||||||
// if shmem does not work (or using OSX) fallback to a regular file on disk
|
// if shmem does not work (or using OSX) fallback to a regular file on disk
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
std::string path = get_writable_data_path("/dcnzorz_mem");
|
std::string path = get_writable_data_path("dcnzorz_mem");
|
||||||
fd = open(path.c_str(), O_CREAT|O_RDWR|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO);
|
fd = open(path.c_str(), O_CREAT|O_RDWR|O_TRUNC, S_IRWXU|S_IRWXG|S_IRWXO);
|
||||||
unlink(path.c_str());
|
unlink(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,7 @@ LogManager::LogManager()
|
||||||
if (cfgLoadBool("log", "LogToFile", false))
|
if (cfgLoadBool("log", "LogToFile", false))
|
||||||
{
|
{
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
std::string logPath = get_writable_data_path("/flycast.log");
|
std::string logPath = get_writable_data_path("flycast.log");
|
||||||
#else
|
#else
|
||||||
std::string logPath = "flycast.log";
|
std::string logPath = "flycast.log";
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "hw/maple/maple_cfg.h"
|
#include "hw/maple/maple_cfg.h"
|
||||||
#include "hw/sh4/sh4_mem.h"
|
#include "hw/sh4/sh4_mem.h"
|
||||||
|
#include "hw/holly/sb_mem.h"
|
||||||
|
|
||||||
#include "hw/naomi/naomi_cart.h"
|
#include "hw/naomi/naomi_cart.h"
|
||||||
#include "reios/reios.h"
|
#include "reios/reios.h"
|
||||||
|
@ -551,15 +552,14 @@ static void dc_start_game(const char *path)
|
||||||
dc_reset(true);
|
dc_reset(true);
|
||||||
LoadSettings(false);
|
LoadSettings(false);
|
||||||
|
|
||||||
std::string data_path = get_readonly_data_path(DATA_PATH);
|
|
||||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||||
{
|
{
|
||||||
if ((settings.bios.UseReios && !forced_bios_file) || !LoadRomFiles(data_path))
|
if ((settings.bios.UseReios && !forced_bios_file) || !LoadRomFiles())
|
||||||
{
|
{
|
||||||
if (forced_bios_file)
|
if (forced_bios_file)
|
||||||
throw ReicastException("No BIOS file found");
|
throw ReicastException("No BIOS file found");
|
||||||
|
|
||||||
if (!LoadHle(data_path))
|
if (!LoadHle())
|
||||||
throw ReicastException("Failed to initialize HLE BIOS");
|
throw ReicastException("Failed to initialize HLE BIOS");
|
||||||
|
|
||||||
NOTICE_LOG(BOOT, "Did not load BIOS, using reios");
|
NOTICE_LOG(BOOT, "Did not load BIOS, using reios");
|
||||||
|
@ -567,7 +567,7 @@ static void dc_start_game(const char *path)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LoadRomFiles(data_path);
|
LoadRomFiles();
|
||||||
}
|
}
|
||||||
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
|
||||||
{
|
{
|
||||||
|
@ -591,7 +591,7 @@ static void dc_start_game(const char *path)
|
||||||
// Content load failed. Boot the BIOS
|
// Content load failed. Boot the BIOS
|
||||||
settings.imgread.ImagePath[0] = '\0';
|
settings.imgread.ImagePath[0] = '\0';
|
||||||
forced_bios_file = true;
|
forced_bios_file = true;
|
||||||
if (!LoadRomFiles(data_path))
|
if (!LoadRomFiles())
|
||||||
throw ReicastException("No BIOS file found");
|
throw ReicastException("No BIOS file found");
|
||||||
InitDrive();
|
InitDrive();
|
||||||
}
|
}
|
||||||
|
@ -656,7 +656,7 @@ void* dc_run(void*)
|
||||||
|
|
||||||
sh4_cpu.Run();
|
sh4_cpu.Run();
|
||||||
|
|
||||||
SaveRomFiles(get_writable_data_path(DATA_PATH));
|
SaveRomFiles();
|
||||||
if (reset_requested)
|
if (reset_requested)
|
||||||
{
|
{
|
||||||
dc_reset(false);
|
dc_reset(false);
|
||||||
|
@ -933,7 +933,7 @@ static void LoadCustom()
|
||||||
if (*p == '\0')
|
if (*p == '\0')
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (settings.platform.system == DC_PLATFORM_NAOMI || settings.platform.system == DC_PLATFORM_ATOMISWAVE)
|
else
|
||||||
{
|
{
|
||||||
reios_id = naomi_game_id;
|
reios_id = naomi_game_id;
|
||||||
}
|
}
|
||||||
|
@ -951,9 +951,9 @@ void SaveSettings()
|
||||||
{
|
{
|
||||||
cfgSetAutoSave(false);
|
cfgSetAutoSave(false);
|
||||||
cfgSaveBool("config", "Dynarec.Enabled", settings.dynarec.Enable);
|
cfgSaveBool("config", "Dynarec.Enabled", settings.dynarec.Enable);
|
||||||
if (forced_game_cable == -1 || forced_game_cable != settings.dreamcast.cable)
|
if (forced_game_cable == -1 || forced_game_cable != (int)settings.dreamcast.cable)
|
||||||
cfgSaveInt("config", "Dreamcast.Cable", settings.dreamcast.cable);
|
cfgSaveInt("config", "Dreamcast.Cable", settings.dreamcast.cable);
|
||||||
if (forced_game_region == -1 || forced_game_region != settings.dreamcast.region)
|
if (forced_game_region == -1 || forced_game_region != (int)settings.dreamcast.region)
|
||||||
cfgSaveInt("config", "Dreamcast.Region", settings.dreamcast.region);
|
cfgSaveInt("config", "Dreamcast.Region", settings.dreamcast.region);
|
||||||
cfgSaveInt("config", "Dreamcast.Broadcast", settings.dreamcast.broadcast);
|
cfgSaveInt("config", "Dreamcast.Broadcast", settings.dreamcast.broadcast);
|
||||||
cfgSaveBool("config", "Dreamcast.ForceWindowsCE", settings.dreamcast.ForceWindowsCE);
|
cfgSaveBool("config", "Dreamcast.ForceWindowsCE", settings.dreamcast.ForceWindowsCE);
|
||||||
|
@ -1064,7 +1064,7 @@ static void cleanup_serialize(void *data)
|
||||||
free(data) ;
|
free(data) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string get_savestate_file_path()
|
static std::string get_savestate_file_path(bool writable)
|
||||||
{
|
{
|
||||||
std::string state_file = settings.imgread.ImagePath;
|
std::string state_file = settings.imgread.ImagePath;
|
||||||
size_t lastindex = state_file.find_last_of('/');
|
size_t lastindex = state_file.find_last_of('/');
|
||||||
|
@ -1081,7 +1081,10 @@ static std::string get_savestate_file_path()
|
||||||
if (lastindex != std::string::npos)
|
if (lastindex != std::string::npos)
|
||||||
state_file = state_file.substr(0, lastindex);
|
state_file = state_file.substr(0, lastindex);
|
||||||
state_file = state_file + ".state";
|
state_file = state_file + ".state";
|
||||||
return get_writable_data_path(DATA_PATH) + state_file;
|
if (writable)
|
||||||
|
return get_writable_data_path(state_file);
|
||||||
|
else
|
||||||
|
return get_readonly_data_path(state_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dc_savestate()
|
void dc_savestate()
|
||||||
|
@ -1121,7 +1124,7 @@ void dc_savestate()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = get_savestate_file_path();
|
filename = get_savestate_file_path(true);
|
||||||
f = fopen(filename.c_str(), "wb") ;
|
f = fopen(filename.c_str(), "wb") ;
|
||||||
|
|
||||||
if ( f == NULL )
|
if ( f == NULL )
|
||||||
|
@ -1150,7 +1153,7 @@ void dc_loadstate()
|
||||||
|
|
||||||
dc_stop();
|
dc_stop();
|
||||||
|
|
||||||
filename = get_savestate_file_path();
|
filename = get_savestate_file_path(false);
|
||||||
f = fopen(filename.c_str(), "rb") ;
|
f = fopen(filename.c_str(), "rb") ;
|
||||||
|
|
||||||
if ( f == NULL )
|
if ( f == NULL )
|
||||||
|
|
|
@ -739,7 +739,7 @@ void reios_reset(u8* rom)
|
||||||
// 7078 24 × 24 pixels (72 bytes) characters
|
// 7078 24 × 24 pixels (72 bytes) characters
|
||||||
// 129 32 × 32 pixels (128 bytes) characters
|
// 129 32 × 32 pixels (128 bytes) characters
|
||||||
memset(pFont, 0, 536496);
|
memset(pFont, 0, 536496);
|
||||||
FILE *font = fopen(get_readonly_data_path(DATA_PATH "font.bin").c_str(), "rb");
|
FILE *font = fopen(get_readonly_data_path("font.bin").c_str(), "rb");
|
||||||
if (font == NULL)
|
if (font == NULL)
|
||||||
{
|
{
|
||||||
INFO_LOG(REIOS, "font.bin not found. Using built-in font");
|
INFO_LOG(REIOS, "font.bin not found. Using built-in font");
|
||||||
|
|
|
@ -102,7 +102,7 @@ bool CustomTexture::Init()
|
||||||
std::string game_id = GetGameId();
|
std::string game_id = GetGameId();
|
||||||
if (game_id.length() > 0)
|
if (game_id.length() > 0)
|
||||||
{
|
{
|
||||||
textures_path = get_readonly_data_path(DATA_PATH) + "textures/" + game_id + "/";
|
textures_path = get_readonly_data_path("textures/" + game_id) + "/";
|
||||||
|
|
||||||
DIR *dir = opendir(textures_path.c_str());
|
DIR *dir = opendir(textures_path.c_str());
|
||||||
if (dir != NULL)
|
if (dir != NULL)
|
||||||
|
@ -156,7 +156,7 @@ void CustomTexture::LoadCustomTextureAsync(BaseTextureCacheData *texture_data)
|
||||||
|
|
||||||
void CustomTexture::DumpTexture(u32 hash, int w, int h, TextureType textype, void *src_buffer)
|
void CustomTexture::DumpTexture(u32 hash, int w, int h, TextureType textype, void *src_buffer)
|
||||||
{
|
{
|
||||||
std::string base_dump_dir = get_writable_data_path(DATA_PATH "texdump/");
|
std::string base_dump_dir = get_writable_data_path("texdump/");
|
||||||
if (!file_exists(base_dump_dir))
|
if (!file_exists(base_dump_dir))
|
||||||
make_directory(base_dump_dir);
|
make_directory(base_dump_dir);
|
||||||
std::string game_id = GetGameId();
|
std::string game_id = GetGameId();
|
||||||
|
|
|
@ -1674,8 +1674,10 @@ static void systemdir_selected_callback(bool cancelled, std::string selection)
|
||||||
{
|
{
|
||||||
if (!cancelled)
|
if (!cancelled)
|
||||||
{
|
{
|
||||||
|
selection += "/";
|
||||||
set_user_config_dir(selection);
|
set_user_config_dir(selection);
|
||||||
set_user_data_dir(selection);
|
add_system_data_dir(selection);
|
||||||
|
set_user_data_dir(selection + "data/");
|
||||||
if (cfgOpen())
|
if (cfgOpen())
|
||||||
{
|
{
|
||||||
LoadSettings(false);
|
LoadSettings(false);
|
||||||
|
|
|
@ -150,7 +150,7 @@ u8 *loadOSDButtons(int &width, int &height)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
stbi_set_flip_vertically_on_load(1);
|
stbi_set_flip_vertically_on_load(1);
|
||||||
u8 *image_data = stbi_load(get_readonly_data_path(DATA_PATH "buttons.png").c_str(), &width, &height, &n, STBI_rgb_alpha);
|
u8 *image_data = stbi_load(get_readonly_data_path("buttons.png").c_str(), &width, &height, &n, STBI_rgb_alpha);
|
||||||
if (image_data == nullptr)
|
if (image_data == nullptr)
|
||||||
{
|
{
|
||||||
if (DefaultOSDButtons.empty())
|
if (DefaultOSDButtons.empty())
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
|
|
||||||
VulkanContext *VulkanContext::contextInstance;
|
VulkanContext *VulkanContext::contextInstance;
|
||||||
|
|
||||||
static const char *PipelineCacheFileName = DATA_PATH "vulkan_pipeline.cache";
|
static const char *PipelineCacheFileName = "vulkan_pipeline.cache";
|
||||||
|
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
VKAPI_ATTR static VkBool32 VKAPI_CALL debugUtilsMessengerCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes,
|
VKAPI_ATTR static VkBool32 VKAPI_CALL debugUtilsMessengerCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes,
|
||||||
|
@ -450,7 +450,7 @@ bool VulkanContext::InitDevice()
|
||||||
10000, ARRAY_SIZE(pool_sizes), pool_sizes));
|
10000, ARRAY_SIZE(pool_sizes), pool_sizes));
|
||||||
|
|
||||||
|
|
||||||
std::string cachePath = get_writable_data_path(PipelineCacheFileName);
|
std::string cachePath = get_readonly_data_path(PipelineCacheFileName);
|
||||||
FILE *f = fopen(cachePath.c_str(), "rb");
|
FILE *f = fopen(cachePath.c_str(), "rb");
|
||||||
if (f == nullptr)
|
if (f == nullptr)
|
||||||
pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo());
|
pipelineCache = device->createPipelineCacheUnique(vk::PipelineCacheCreateInfo());
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string user_config_dir;
|
static std::string user_config_dir;
|
||||||
std::string user_data_dir;
|
static std::string user_data_dir;
|
||||||
std::vector<std::string> system_config_dirs;
|
static std::vector<std::string> system_config_dirs;
|
||||||
std::vector<std::string> system_data_dirs;
|
static std::vector<std::string> system_data_dirs;
|
||||||
|
|
||||||
bool file_exists(const std::string& filename)
|
bool file_exists(const std::string& filename)
|
||||||
{
|
{
|
||||||
|
@ -55,24 +55,20 @@ std::string get_writable_config_path(const std::string& filename)
|
||||||
/* Only stuff in the user_config_dir is supposed to be writable,
|
/* Only stuff in the user_config_dir is supposed to be writable,
|
||||||
* so we always return that.
|
* so we always return that.
|
||||||
*/
|
*/
|
||||||
return (user_config_dir + filename);
|
return user_config_dir + filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_readonly_config_path(const std::string& filename)
|
std::string get_readonly_config_path(const std::string& filename)
|
||||||
{
|
{
|
||||||
std::string user_filepath = get_writable_config_path(filename);
|
std::string user_filepath = get_writable_config_path(filename);
|
||||||
if(file_exists(user_filepath))
|
if (file_exists(user_filepath))
|
||||||
{
|
|
||||||
return user_filepath;
|
return user_filepath;
|
||||||
}
|
|
||||||
|
|
||||||
std::string filepath;
|
for (const auto& config_dir : system_config_dirs)
|
||||||
for (size_t i = 0; i < system_config_dirs.size(); i++) {
|
{
|
||||||
filepath = system_config_dirs[i] + filename;
|
std::string filepath = config_dir + filename;
|
||||||
if (file_exists(filepath))
|
if (file_exists(filepath))
|
||||||
{
|
|
||||||
return filepath;
|
return filepath;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not found, so we return the user variant
|
// Not found, so we return the user variant
|
||||||
|
@ -84,31 +80,31 @@ std::string get_writable_data_path(const std::string& filename)
|
||||||
/* Only stuff in the user_data_dir is supposed to be writable,
|
/* Only stuff in the user_data_dir is supposed to be writable,
|
||||||
* so we always return that.
|
* so we always return that.
|
||||||
*/
|
*/
|
||||||
return (user_data_dir + filename);
|
return user_data_dir + filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_readonly_data_path(const std::string& filename)
|
std::string get_readonly_data_path(const std::string& filename)
|
||||||
{
|
{
|
||||||
std::string user_filepath = get_writable_data_path(filename);
|
std::string user_filepath = get_writable_data_path(filename);
|
||||||
if(file_exists(user_filepath))
|
if (file_exists(user_filepath))
|
||||||
{
|
|
||||||
return user_filepath;
|
return user_filepath;
|
||||||
}
|
|
||||||
|
|
||||||
std::string filepath;
|
for (const auto& data_dir : system_data_dirs)
|
||||||
for (size_t i = 0; i < system_data_dirs.size(); i++) {
|
{
|
||||||
filepath = system_data_dirs[i] + filename;
|
std::string filepath = data_dir + filename;
|
||||||
if (file_exists(filepath))
|
if (file_exists(filepath))
|
||||||
{
|
|
||||||
return filepath;
|
return filepath;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Try the game directory
|
||||||
|
std::string filepath = get_game_dir() + filename;
|
||||||
|
if (file_exists(filepath))
|
||||||
|
return filepath;
|
||||||
|
|
||||||
// Not found, so we return the user variant
|
// Not found, so we return the user variant
|
||||||
return user_filepath;
|
return user_filepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t get_last_slash_pos(const std::string& path)
|
size_t get_last_slash_pos(const std::string& path)
|
||||||
{
|
{
|
||||||
size_t lastindex = path.find_last_of('/');
|
size_t lastindex = path.find_last_of('/');
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -127,7 +123,7 @@ std::string get_game_save_prefix()
|
||||||
size_t lastindex = get_last_slash_pos(save_file);
|
size_t lastindex = get_last_slash_pos(save_file);
|
||||||
if (lastindex != std::string::npos)
|
if (lastindex != std::string::npos)
|
||||||
save_file = save_file.substr(lastindex + 1);
|
save_file = save_file.substr(lastindex + 1);
|
||||||
return get_writable_data_path(DATA_PATH) + save_file;
|
return get_writable_data_path(save_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_game_basename()
|
std::string get_game_basename()
|
||||||
|
|
|
@ -49,12 +49,6 @@ public :
|
||||||
void Wait(); //Wait for signal , then reset[if auto]
|
void Wait(); //Wait for signal , then reset[if auto]
|
||||||
};
|
};
|
||||||
|
|
||||||
#if !defined(TARGET_IPHONE)
|
|
||||||
#define DATA_PATH "/data/"
|
|
||||||
#else
|
|
||||||
#define DATA_PATH "/"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Set the path !
|
//Set the path !
|
||||||
void set_user_config_dir(const std::string& dir);
|
void set_user_config_dir(const std::string& dir);
|
||||||
void set_user_data_dir(const std::string& dir);
|
void set_user_data_dir(const std::string& dir);
|
||||||
|
@ -72,6 +66,7 @@ bool make_directory(const std::string& path);
|
||||||
std::string get_game_save_prefix();
|
std::string get_game_save_prefix();
|
||||||
std::string get_game_basename();
|
std::string get_game_basename();
|
||||||
std::string get_game_dir();
|
std::string get_game_dir();
|
||||||
|
size_t get_last_slash_pos(const std::string& path);
|
||||||
|
|
||||||
bool mem_region_lock(void *start, std::size_t len);
|
bool mem_region_lock(void *start, std::size_t len);
|
||||||
bool mem_region_unlock(void *start, std::size_t len);
|
bool mem_region_unlock(void *start, std::size_t len);
|
||||||
|
|
|
@ -192,11 +192,16 @@ LONG ExeptionHandler(EXCEPTION_POINTERS *ExceptionInfo)
|
||||||
void SetupPath()
|
void SetupPath()
|
||||||
{
|
{
|
||||||
char fname[512];
|
char fname[512];
|
||||||
GetModuleFileName(0,fname,512);
|
GetModuleFileName(0, fname, sizeof(fname));
|
||||||
std::string fn = std::string(fname);
|
std::string fn = std::string(fname);
|
||||||
fn=fn.substr(0,fn.find_last_of('\\'));
|
size_t pos = get_last_slash_pos(fn);
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
fn = fn.substr(0, pos) + "\\";
|
||||||
|
else
|
||||||
|
fn = ".\\";
|
||||||
set_user_config_dir(fn);
|
set_user_config_dir(fn);
|
||||||
set_user_data_dir(fn);
|
add_system_data_dir(fn);
|
||||||
|
set_user_data_dir(fn + "data\\");
|
||||||
}
|
}
|
||||||
|
|
||||||
static Win32KeyboardDevice keyboard(0);
|
static Win32KeyboardDevice keyboard(0);
|
||||||
|
|
|
@ -195,13 +195,22 @@ JNIEXPORT jstring JNICALL Java_com_reicast_emulator_emu_JNIdc_initEnvironment(JN
|
||||||
saveAndroidSettingsMid = env->GetMethodID(env->GetObjectClass(emulator), "SaveAndroidSettings", "(Ljava/lang/String;)V");
|
saveAndroidSettingsMid = env->GetMethodID(env->GetObjectClass(emulator), "SaveAndroidSettings", "(Ljava/lang/String;)V");
|
||||||
}
|
}
|
||||||
// Set home directory based on User config
|
// Set home directory based on User config
|
||||||
const char* path = homeDirectory != NULL ? env->GetStringUTFChars(homeDirectory, 0) : "";
|
if (homeDirectory != NULL)
|
||||||
set_user_config_dir(path);
|
{
|
||||||
set_user_data_dir(path);
|
const char *jchar = env->GetStringUTFChars(homeDirectory, 0);
|
||||||
|
std::string path = jchar;
|
||||||
|
if (!path.empty())
|
||||||
|
{
|
||||||
|
if (path.back() != '/')
|
||||||
|
path += '/';
|
||||||
|
set_user_config_dir(path);
|
||||||
|
add_system_data_dir(path);
|
||||||
|
set_user_data_dir(path + "data/");
|
||||||
|
}
|
||||||
|
env->ReleaseStringUTFChars(homeDirectory, jchar);
|
||||||
|
}
|
||||||
INFO_LOG(BOOT, "Config dir is: %s", get_writable_config_path("").c_str());
|
INFO_LOG(BOOT, "Config dir is: %s", get_writable_config_path("").c_str());
|
||||||
INFO_LOG(BOOT, "Data dir is: %s", get_writable_data_path("").c_str());
|
INFO_LOG(BOOT, "Data dir is: %s", get_writable_data_path("").c_str());
|
||||||
if (homeDirectory != NULL)
|
|
||||||
env->ReleaseStringUTFChars(homeDirectory, path);
|
|
||||||
|
|
||||||
if (first_init)
|
if (first_init)
|
||||||
{
|
{
|
||||||
|
|
|
@ -134,27 +134,32 @@ extern "C" void emu_gles_init(int width, int height) {
|
||||||
char *home = getenv("HOME");
|
char *home = getenv("HOME");
|
||||||
if (home != NULL)
|
if (home != NULL)
|
||||||
{
|
{
|
||||||
std::string config_dir = std::string(home) + "/.reicast";
|
std::string config_dir = std::string(home) + "/.reicast/";
|
||||||
|
if (!file_exists(config_dir))
|
||||||
|
config_dir = std::string(home) + "/.flycast/";
|
||||||
int instanceNumber = (int)[[NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.reicast.Flycast"] count];
|
int instanceNumber = (int)[[NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.reicast.Flycast"] count];
|
||||||
if (instanceNumber > 1){
|
if (instanceNumber > 1){
|
||||||
config_dir += "/" + std::to_string(instanceNumber);
|
config_dir += std::to_string(instanceNumber) + "/";
|
||||||
[[NSApp dockTile] setBadgeLabel:@(instanceNumber).stringValue];
|
[[NSApp dockTile] setBadgeLabel:@(instanceNumber).stringValue];
|
||||||
}
|
}
|
||||||
mkdir(config_dir.c_str(), 0755); // create the directory if missing
|
mkdir(config_dir.c_str(), 0755); // create the directory if missing
|
||||||
set_user_config_dir(config_dir);
|
set_user_config_dir(config_dir);
|
||||||
|
add_system_data_dir(config_dir);
|
||||||
|
config_dir += "data/";
|
||||||
|
mkdir(config_dir.c_str(), 0755);
|
||||||
set_user_data_dir(config_dir);
|
set_user_data_dir(config_dir);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
set_user_config_dir(".");
|
set_user_config_dir("./");
|
||||||
set_user_data_dir(".");
|
set_user_data_dir("./");
|
||||||
}
|
}
|
||||||
// Add bundle resources path
|
// Add bundle resources path
|
||||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||||
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
|
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
if (CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX))
|
if (CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX))
|
||||||
add_system_data_dir(std::string(path));
|
add_system_data_dir(std::string(path) + "/");
|
||||||
CFRelease(resourcesURL);
|
CFRelease(resourcesURL);
|
||||||
CFRelease(mainBundle);
|
CFRelease(mainBundle);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue