mirror of
https://github.com/mihawk-99/PS5_RetroArch.git
synced 2026-10-18 23:09:29 -05:00
Content folders are named as ES-DE names its systems; older folders follow
Testers kept reporting folders EmulationStation did not detect. The title
made a folder in content/ for each system named as RetroArch's databases
are ("Sony - PlayStation 2"); it now names each as ES-DE names the system
("ps2", "snes", "genesis", the 50 platform ids, all of them ES-DE system
names checked against ES-DE 3.5.0's own systems file), so content/ is
ES-DE's own layout, <ROM folder>/<system>.
- ps5_library_make_system_folders makes content/ first when it is missing:
a copy of the title without its empty folders had none at all, because
the frontend made content/ only later and the step gave up.
- ps5_library_rename_system_folders, at each start before any frontend:
a folder an earlier build made under RetroArch's name is renamed to the
ES-DE one, or merged into it when none of its entries' names is taken
there (else left as it is, still its system's). The paths in RetroArch's
playlists (and their scan folders) and the per-folder overrides, core
options, shader presets and remaps under config/ follow; a core whose
folder bears the content folder's own name (MAME, ScummVM) keeps its
files, which are that core's. Folders the user named (PS1) stay as they
are and are still recognised.
- The WebUI's Add Game puts a game in the system's ES-DE folder.
- README: content/<system>/ with ES-DE's names (content/Saturn/ was out of
date: only system/Saturn is made).
Evidence: tests/ps5_library_test.c (system folders by ES-DE name, a missing
content folder made, a rename, a merge, a clash left in place, a folder
whose name only begins the same, playlists, per-folder settings, a core
folder named as the content folder): python3 -m unittest
tests.test_ps5_library OK. On the console (evidence/esde-folder-names,
with the commits after this one): a home launch renamed three seeded
folders (a rename and two merges), the playlist and options file followed,
and every ES-DE system path is /app0/content/<name>. tools/verify.sh: all
five gates PASS.
This commit is contained in:
1 parent
43216d5d5a
commit
6b70c9b130
8 files changed
+374
-28
No files matched your search
@@ -212,7 +212,7 @@ usually `/data/homebrew/PPSA99169/`.
|
||||
| Folder or file | Purpose |
|
||||
| --- | --- |
|
||||
| `content/` | Your content; available to WebUI uploads and downloads |
|
||||
| `content/Saturn/` | Saturn disc images; created automatically |
|
||||
| `content/<system>/` | A folder for each installed system, named as EmulationStation (ES-DE) names it: `psx`, `ps2`, `snes`, `saturn`; created automatically |
|
||||
| `system/` | General BIOS and system data |
|
||||
| `system/Saturn/` | Saturn BIOS files; created automatically |
|
||||
| `system/pcsx2/bios/` | PlayStation 2 BIOS (your own dump) |
|
||||
|
||||
+7
-1
@@ -406,7 +406,13 @@ int main(int process_argc, char **process_argv)
|
||||
* screen the picker, which restarts the title as RetroArch or EmulationStation;
|
||||
* those two are their own executables, started through LoadExec. */
|
||||
/* A folder in content for each system the installed cores run, before any frontend:
|
||||
* a launch from the home screen goes to the picker from here (issue 33). */
|
||||
* a launch from the home screen goes to the picker from here (issue 33). Folders
|
||||
* earlier builds named as RetroArch does are renamed as ES-DE names them first. */
|
||||
const int renamed_folders =
|
||||
ps5_library_rename_system_folders("/app0/content", "/app0/playlists", "/app0/config");
|
||||
if (renamed_folders > 0)
|
||||
ps5::debug::mark_value("startup: system folders renamed as ES-DE names them",
|
||||
renamed_folders);
|
||||
const int system_folders =
|
||||
ps5_library_make_system_folders("/app0/content", "/app0/info", "/app0/cores");
|
||||
if (system_folders > 0)
|
||||
|
||||
+199
-2
@@ -19,6 +19,7 @@
|
||||
#include <strings.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* --- the JSON RetroArch writes its playlists in ----------------------------------- */
|
||||
|
||||
@@ -1470,6 +1471,9 @@ int ps5_library_load_content_at(struct ps5_library *library, const char *playlis
|
||||
|
||||
int ps5_library_make_system_folders(const char *content, const char *info, const char *cores)
|
||||
{
|
||||
/* An install copied without its empty folders has no content folder at all */
|
||||
if (mkdir(content, 0777) == 0)
|
||||
chmod(content, 0777); /* FTP's reach: the title's folders are 0777 */
|
||||
/* The systems content already has a folder for (top level), by platform. */
|
||||
char **names = folder_names(content, "");
|
||||
if (!names)
|
||||
@@ -1505,8 +1509,7 @@ int ps5_library_make_system_folders(const char *content, const char *info, const
|
||||
if (!platform || !platform->database || has[platform - platforms])
|
||||
continue;
|
||||
char path[PS5_LIBRARY_PATH_MAX];
|
||||
if (snprintf(path, sizeof(path), "%s/%s", content, platform->database) >=
|
||||
(int)sizeof(path))
|
||||
if (snprintf(path, sizeof(path), "%s/%s", content, platform->id) >= (int)sizeof(path))
|
||||
continue;
|
||||
has[platform - platforms] = 1;
|
||||
const int created = mkdir(path, 0777) == 0;
|
||||
@@ -1518,6 +1521,200 @@ int ps5_library_make_system_folders(const char *content, const char *info, const
|
||||
return made;
|
||||
}
|
||||
|
||||
static int is_folder(const char *path)
|
||||
{
|
||||
struct stat status;
|
||||
return stat(path, &status) == 0 && S_ISDIR(status.st_mode);
|
||||
}
|
||||
|
||||
static int is_there(const char *path)
|
||||
{
|
||||
struct stat status;
|
||||
return lstat(path, &status) == 0;
|
||||
}
|
||||
|
||||
/* Moves every entry of from into to, none of whose names may be taken there, and removes
|
||||
* from. 0; -1 with everything back where it was. */
|
||||
static int move_entries(const char *from, const char *to)
|
||||
{
|
||||
char **names = folder_names(from, "");
|
||||
if (!names)
|
||||
return -1;
|
||||
char source[PS5_LIBRARY_PATH_MAX], target[PS5_LIBRARY_PATH_MAX];
|
||||
size_t moved = 0, count = 0;
|
||||
int failed = 0;
|
||||
for (; names[count]; count++)
|
||||
if (strcmp(names[count], ".") != 0 && strcmp(names[count], "..") != 0 &&
|
||||
(!joined(source, sizeof(source), from, names[count]) ||
|
||||
!joined(target, sizeof(target), to, names[count]) || is_there(target)))
|
||||
failed = 1;
|
||||
for (; !failed && moved < count; moved++)
|
||||
if (strcmp(names[moved], ".") != 0 && strcmp(names[moved], "..") != 0 &&
|
||||
(!joined(source, sizeof(source), from, names[moved]) ||
|
||||
!joined(target, sizeof(target), to, names[moved]) || rename(source, target) != 0))
|
||||
failed = 1;
|
||||
if (failed)
|
||||
while (moved-- > 0) /* the ones moved before the failure go back */
|
||||
if (strcmp(names[moved], ".") != 0 && strcmp(names[moved], "..") != 0 &&
|
||||
joined(source, sizeof(source), from, names[moved]) &&
|
||||
joined(target, sizeof(target), to, names[moved]))
|
||||
rename(target, source);
|
||||
free_names(names);
|
||||
if (failed)
|
||||
return -1;
|
||||
rmdir(from); /* everything moved: the paths change whether or not it goes */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Each "<content>/<old>" in a file that is followed by '/' or '"' (a game's path, or a
|
||||
* playlist's scan folder) becomes "<content>/<new>"; the file is replaced only when that
|
||||
* changed something. */
|
||||
static void rewrite_paths(const char *file, const char *content, const char *const *old_names,
|
||||
const char *const *new_names, size_t pairs)
|
||||
{
|
||||
FILE *input = fopen(file, "rb");
|
||||
if (!input)
|
||||
return;
|
||||
char *text = NULL;
|
||||
long length = 0;
|
||||
if (fseek(input, 0, SEEK_END) == 0 && (length = ftell(input)) > 0 && length < (64L << 20) &&
|
||||
fseek(input, 0, SEEK_SET) == 0 && (text = (char *)malloc((size_t)length)) != NULL &&
|
||||
fread(text, 1, (size_t)length, input) != (size_t)length)
|
||||
{
|
||||
free(text);
|
||||
text = NULL;
|
||||
}
|
||||
fclose(input);
|
||||
if (!text)
|
||||
return;
|
||||
const size_t content_length = strlen(content);
|
||||
size_t longest = 0;
|
||||
for (size_t p = 0; p < pairs; p++)
|
||||
if (strlen(new_names[p]) > longest)
|
||||
longest = strlen(new_names[p]);
|
||||
/* each match is at least content_length + 2 long and grows by at most longest */
|
||||
char *out =
|
||||
(char *)malloc((size_t)length + ((size_t)length / (content_length + 2) + 1) * longest);
|
||||
size_t written = 0, changes = 0;
|
||||
for (long at = 0; out && at < length;)
|
||||
{
|
||||
size_t p = pairs;
|
||||
if ((size_t)(length - at) > content_length &&
|
||||
memcmp(text + at, content, content_length) == 0 &&
|
||||
text[at + (long)content_length] == '/')
|
||||
for (p = 0; p < pairs; p++)
|
||||
{
|
||||
const size_t old_length = strlen(old_names[p]);
|
||||
const long end = at + (long)(content_length + 1 + old_length);
|
||||
if (end < length && (text[end] == '/' || text[end] == '"') &&
|
||||
memcmp(text + at + content_length + 1, old_names[p], old_length) == 0)
|
||||
break;
|
||||
}
|
||||
if (p == pairs)
|
||||
{
|
||||
out[written++] = text[at++];
|
||||
continue;
|
||||
}
|
||||
const size_t new_length = strlen(new_names[p]);
|
||||
memcpy(out + written, content, content_length);
|
||||
out[written + content_length] = '/';
|
||||
memcpy(out + written + content_length + 1, new_names[p], new_length);
|
||||
written += content_length + 1 + new_length;
|
||||
at += (long)(content_length + 1 + strlen(old_names[p]));
|
||||
changes++;
|
||||
}
|
||||
free(text);
|
||||
char temporary[PS5_LIBRARY_PATH_MAX];
|
||||
FILE *output = NULL;
|
||||
if (out && changes &&
|
||||
snprintf(temporary, sizeof(temporary), "%s.tmp", file) < (int)sizeof(temporary) &&
|
||||
(output = fopen(temporary, "wb")) != NULL)
|
||||
{
|
||||
const int complete = fwrite(out, 1, written, output) == written;
|
||||
if (fclose(output) == 0 && complete && rename(temporary, file) == 0)
|
||||
chmod(file, 0777); /* FTP's reach: the title's files are 0777 */
|
||||
else
|
||||
remove(temporary);
|
||||
}
|
||||
free(out);
|
||||
}
|
||||
|
||||
static void rewrite_playlists(const char *folder, const char *content, const char *const *old_names,
|
||||
const char *const *new_names, size_t pairs)
|
||||
{
|
||||
char **names = folder_names(folder, ".lpl");
|
||||
char path[PS5_LIBRARY_PATH_MAX];
|
||||
for (size_t i = 0; names && names[i]; i++)
|
||||
if (joined(path, sizeof(path), folder, names[i]))
|
||||
rewrite_paths(path, content, old_names, new_names, pairs);
|
||||
free_names(names);
|
||||
}
|
||||
|
||||
/* RetroArch's settings for a content folder, named after it, in each core's folder under
|
||||
* root: content directory overrides and core options, shader presets, remaps. */
|
||||
static void rename_folder_settings(const char *root, const char *const *old_names,
|
||||
const char *const *new_names, size_t pairs)
|
||||
{
|
||||
static const char *const kinds[] = {".cfg", ".opt", ".slangp", ".glslp", ".cgp", ".rmp"};
|
||||
char **cores = folder_names(root, "");
|
||||
char folder[PS5_LIBRARY_PATH_MAX], from[PS5_LIBRARY_PATH_MAX], to[PS5_LIBRARY_PATH_MAX];
|
||||
for (size_t c = 0; cores && cores[c]; c++)
|
||||
{
|
||||
if (cores[c][0] == '.' || !joined(folder, sizeof(folder), root, cores[c]) ||
|
||||
!is_folder(folder))
|
||||
continue;
|
||||
for (size_t p = 0; p < pairs; p++)
|
||||
for (size_t k = 0;
|
||||
k < sizeof(kinds) / sizeof(kinds[0]) && strcmp(cores[c], old_names[p]) != 0; k++)
|
||||
if (snprintf(from, sizeof(from), "%s/%s%s", folder, old_names[p], kinds[k]) <
|
||||
(int)sizeof(from) &&
|
||||
snprintf(to, sizeof(to), "%s/%s%s", folder, new_names[p], kinds[k]) <
|
||||
(int)sizeof(to) &&
|
||||
is_file(from) && !is_there(to))
|
||||
rename(from, to);
|
||||
}
|
||||
free_names(cores);
|
||||
}
|
||||
|
||||
int ps5_library_rename_system_folders(const char *content, const char *playlists,
|
||||
const char *config)
|
||||
{
|
||||
char **names = folder_names(content, "");
|
||||
if (!names)
|
||||
return -1;
|
||||
const char *old_names[sizeof(platforms) / sizeof(platforms[0])];
|
||||
const char *new_names[sizeof(platforms) / sizeof(platforms[0])];
|
||||
size_t pairs = 0;
|
||||
char from[PS5_LIBRARY_PATH_MAX], to[PS5_LIBRARY_PATH_MAX];
|
||||
for (size_t i = 0; names[i]; i++)
|
||||
{
|
||||
const struct platform *platform = NULL;
|
||||
for (size_t p = 0; !platform && p < sizeof(platforms) / sizeof(platforms[0]); p++)
|
||||
if (platforms[p].database && strcmp(platforms[p].database, names[i]) == 0)
|
||||
platform = &platforms[p];
|
||||
if (!platform || !joined(from, sizeof(from), content, names[i]) ||
|
||||
!joined(to, sizeof(to), content, platform->id) || !is_folder(from))
|
||||
continue;
|
||||
if (is_there(to) ? !is_folder(to) || move_entries(from, to) != 0 : rename(from, to) != 0)
|
||||
continue;
|
||||
chmod(to, 0777); /* FTP's reach: the title's folders are 0777 */
|
||||
old_names[pairs] = platform->database;
|
||||
new_names[pairs++] = platform->id;
|
||||
}
|
||||
free_names(names);
|
||||
if (pairs)
|
||||
{
|
||||
char folder[PS5_LIBRARY_PATH_MAX];
|
||||
rewrite_playlists(playlists, content, old_names, new_names, pairs);
|
||||
if (joined(folder, sizeof(folder), playlists, "builtin"))
|
||||
rewrite_playlists(folder, content, old_names, new_names, pairs);
|
||||
rename_folder_settings(config, old_names, new_names, pairs);
|
||||
if (joined(folder, sizeof(folder), config, "remaps"))
|
||||
rename_folder_settings(folder, old_names, new_names, pairs);
|
||||
}
|
||||
return (int)pairs;
|
||||
}
|
||||
|
||||
void ps5_library_free(struct ps5_library *library)
|
||||
{
|
||||
free(library->systems);
|
||||
|
||||
+16
-5
@@ -125,13 +125,24 @@ extern "C"
|
||||
/* A platform's RetroArch database name ("Sony - PlayStation"), or NULL. */
|
||||
const char *ps5_library_platform_database(const char *id);
|
||||
|
||||
/* A folder in content for each system the installed cores run, named as RetroArch
|
||||
* names it ("Nintendo - Nintendo Entertainment System"), so games have a place to go
|
||||
* and every frontend knows their system. A system the content folder already has a
|
||||
* folder for, whatever its name ("PS1", "Genesis"), gets none: nothing is renamed or
|
||||
* moved. A database no platform here stands for (Satellaview, CD32...) gets none.
|
||||
/* A folder in content for each system the installed cores run, named as ES-DE names
|
||||
* it ("nes", "ps2", "megadrive"... its system's id here), so games have a place to go
|
||||
* and every frontend knows their system. content is made first when it is missing. A
|
||||
* system the content folder already has a folder for, whatever its name ("PS1"), gets
|
||||
* none. A database no platform here stands for (Satellaview, CD32...) gets none.
|
||||
* Returns how many folders it made, or -1 when content cannot be read. */
|
||||
int ps5_library_make_system_folders(const char *content, const char *info, const char *cores);
|
||||
/* The folders earlier builds made under RetroArch's names ("Sony - PlayStation 2")
|
||||
* renamed to ES-DE's ("ps2"), with what refers to them: the paths in the playlists
|
||||
* (playlists and playlists/builtin) and the per-folder overrides, core options, shader
|
||||
* presets and remaps under config (config/<core>, config/remaps/<core>). Where the
|
||||
* ES-DE folder exists, the old folder's entries move into it when none of their names
|
||||
* is taken there, and the old folder goes; otherwise it is left as it is (it is still
|
||||
* its system's). A core folder named as the content folder keeps its files, which are
|
||||
* that core's own. Returns how many folders it renamed or merged, or -1 when content
|
||||
* cannot be read. */
|
||||
int ps5_library_rename_system_folders(const char *content, const char *playlists,
|
||||
const char *config);
|
||||
|
||||
/* Game mode's launch command for a game (src/ps5_game.h): RetroArch's command line
|
||||
* with its system's core, shell-quoted. 0, or -1 when it does not fit. */
|
||||
|
||||
+1
-1
@@ -2977,7 +2977,7 @@ bool add_target(const std::string &system, const std::string &filename, std::str
|
||||
why = "This file type is not supported by the installed cores for this system.";
|
||||
return false;
|
||||
}
|
||||
relative = selected->second.at("name") + '/' + filename;
|
||||
relative = selected->first + '/' + filename; /* the system's folder is its ES-DE name */
|
||||
key = game_key("/app0/content/" + relative);
|
||||
for (const auto &game : load_games())
|
||||
if (game.system == system && game.key == key)
|
||||
|
||||
+145
-13
@@ -42,6 +42,16 @@ static void core(const char *dir, const char *name, const char *database, const
|
||||
write_text(path, text);
|
||||
}
|
||||
|
||||
/* A file's text, at most size - 1 bytes of it. */
|
||||
static const char *read_back(const char *path, char *out, size_t size)
|
||||
{
|
||||
FILE *file = fopen(path, "rb");
|
||||
assert(file);
|
||||
out[fread(out, 1, size - 1, file)] = '\0';
|
||||
fclose(file);
|
||||
return out;
|
||||
}
|
||||
|
||||
static const struct ps5_library_system *system_of(const struct ps5_library *library, const char *id)
|
||||
{
|
||||
for (size_t i = 0; i < library->system_count; i++)
|
||||
@@ -368,8 +378,8 @@ int main(int argc, char **argv)
|
||||
assert(system_of(&library, "snes")->game_count == 2);
|
||||
ps5_library_free(&library);
|
||||
|
||||
/* A folder for each system the installed cores run, named as RetroArch names it; a
|
||||
* system with a folder already (any name) gets none, and nothing is renamed. */
|
||||
/* A folder for each system the installed cores run, named as ES-DE names it; a system
|
||||
* with a folder already (any name) gets none. */
|
||||
{
|
||||
char root[1024], content[1100], info[1100], cores[1100], path[2048];
|
||||
snprintf(root, sizeof(root), "%s/folders", dir);
|
||||
@@ -400,12 +410,8 @@ int main(int argc, char **argv)
|
||||
snprintf(path, sizeof(path), "%s/stella_libretro.info", info);
|
||||
write_text(path, "database = \"Atari - 2600\"\n"); /* no core beside it: not installed */
|
||||
assert(ps5_library_make_system_folders(content, info, cores) == 10);
|
||||
const char *expected[] = {
|
||||
"Sega - Game Gear", "Sega - Master System - Mark III",
|
||||
"Sega - Mega-CD - Sega CD", "Sega - Mega Drive - Genesis",
|
||||
"Sega - SG-1000", "Nintendo - Super Nintendo Entertainment System",
|
||||
"Nintendo - GameCube", "Nintendo - Wii",
|
||||
"Commodore - Amiga", "FBNeo - Arcade Games"};
|
||||
const char *expected[] = {"gamegear", "mastersystem", "segacd", "genesis", "sg-1000",
|
||||
"snes", "gc", "wii", "amiga", "fbneo"};
|
||||
for (size_t i = 0; i < sizeof(expected) / sizeof(expected[0]); i++)
|
||||
{
|
||||
struct stat st;
|
||||
@@ -414,10 +420,16 @@ int main(int argc, char **argv)
|
||||
/* Each one is its system's to every frontend. */
|
||||
assert(ps5_library_platform(expected[i]));
|
||||
}
|
||||
const char *absent[] = {"Sony - PlayStation", "Nintendo - Sufami Turbo",
|
||||
"Nintendo - Satellaview", "Sega - PICO",
|
||||
"Commodore - CD32", "Atari - 2600",
|
||||
"Nintendo - Wii (Digital)"};
|
||||
const char *absent[] = {"Sony - PlayStation",
|
||||
"psx",
|
||||
"Nintendo - Sufami Turbo",
|
||||
"Nintendo - Satellaview",
|
||||
"Sega - PICO",
|
||||
"Commodore - CD32",
|
||||
"Atari - 2600",
|
||||
"atari2600",
|
||||
"Nintendo - Wii (Digital)",
|
||||
"Sega - Mega Drive - Genesis"};
|
||||
for (size_t i = 0; i < sizeof(absent) / sizeof(absent[0]); i++)
|
||||
{
|
||||
struct stat st;
|
||||
@@ -425,10 +437,130 @@ int main(int argc, char **argv)
|
||||
assert(stat(path, &st) != 0);
|
||||
}
|
||||
assert(ps5_library_make_system_folders(content, info, cores) == 0); /* once */
|
||||
/* An install copied without its empty folders: content is made too */
|
||||
snprintf(path, sizeof(path), "%s/missing", root);
|
||||
assert(ps5_library_make_system_folders(path, info, cores) == 11);
|
||||
snprintf(path, sizeof(path), "%s/missing/psx", root);
|
||||
assert(stat(path, &(struct stat){0}) == 0);
|
||||
snprintf(path, sizeof(path), "%s/no/such/content", root);
|
||||
assert(ps5_library_make_system_folders(path, info, cores) == -1);
|
||||
}
|
||||
/* Folders earlier builds named as RetroArch does, renamed as ES-DE names them, with the
|
||||
* playlists' paths and the per-folder settings that name them. */
|
||||
{
|
||||
char root[1024], content[1100], playlists[1100], config[1100], path[2048], text[4096],
|
||||
want[2048];
|
||||
snprintf(root, sizeof(root), "%s/renamed", dir);
|
||||
snprintf(content, sizeof(content), "%s/content", root);
|
||||
snprintf(playlists, sizeof(playlists), "%s/playlists", root);
|
||||
snprintf(config, sizeof(config), "%s/config", root);
|
||||
const char *folders[] = {"",
|
||||
"/content",
|
||||
"/content/Sony - PlayStation 2",
|
||||
"/content/Nintendo - Game Boy",
|
||||
"/content/gb",
|
||||
"/content/Nintendo - Game Boy Advance",
|
||||
"/content/gba",
|
||||
"/content/MAME",
|
||||
"/content/PS1",
|
||||
"/playlists",
|
||||
"/playlists/builtin",
|
||||
"/config",
|
||||
"/config/PS5SX2",
|
||||
"/config/MAME",
|
||||
"/config/remaps",
|
||||
"/config/remaps/PS5SX2"};
|
||||
for (size_t i = 0; i < sizeof(folders) / sizeof(folders[0]); i++)
|
||||
{
|
||||
snprintf(path, sizeof(path), "%s%s", root, folders[i]);
|
||||
assert(mkdir(path, 0755) == 0);
|
||||
}
|
||||
const char *files[] = {"content/Sony - PlayStation 2/Disc.iso",
|
||||
"content/Nintendo - Game Boy/One.gb",
|
||||
"content/gb/Two.gb",
|
||||
"content/Nintendo - Game Boy Advance/Same.gba",
|
||||
"content/gba/Same.gba",
|
||||
"content/MAME/game.zip",
|
||||
"content/PS1/Disc.cue",
|
||||
"config/PS5SX2/Sony - PlayStation 2.cfg",
|
||||
"config/PS5SX2/Sony - PlayStation 2.opt",
|
||||
"config/remaps/PS5SX2/Sony - PlayStation 2.rmp",
|
||||
"config/MAME/MAME.cfg",
|
||||
"config/MAME/MAME.slangp"};
|
||||
for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); i++)
|
||||
{
|
||||
snprintf(path, sizeof(path), "%s/%s", root, files[i]);
|
||||
write_text(path, "x");
|
||||
}
|
||||
snprintf(path, sizeof(path), "%s/Sony - PlayStation 2.lpl", playlists);
|
||||
snprintf(text, sizeof(text),
|
||||
"{\"scan_content_dir\": \"%s/Sony - PlayStation 2\", \"items\": [{\"path\": "
|
||||
"\"%s/Sony - PlayStation 2/Disc.iso\"}]}",
|
||||
content, content);
|
||||
write_text(path, text);
|
||||
snprintf(path, sizeof(path), "%s/Nintendo - Game Boy.lpl", playlists);
|
||||
snprintf(text, sizeof(text),
|
||||
"{\"items\": [{\"path\": \"%s/Nintendo - Game Boy/One.gb\"}, {\"path\": "
|
||||
"\"%s/Nintendo - Game Boy Advance/Same.gba\"}]}",
|
||||
content, content);
|
||||
write_text(path, text);
|
||||
snprintf(path, sizeof(path), "%s/builtin/content_history.lpl", playlists);
|
||||
snprintf(text, sizeof(text), "{\"items\": [{\"path\": \"%s/MAME/game.zip#game.bin\"}]}",
|
||||
content);
|
||||
write_text(path, text);
|
||||
|
||||
/* Renamed (ps2, mame), merged (gb), left where a name is taken (gba's), and a
|
||||
* folder that is not a name of RetroArch's untouched (PS1). */
|
||||
assert(ps5_library_rename_system_folders(content, playlists, config) == 3);
|
||||
const char *there[] = {
|
||||
"ps2/Disc.iso", "gb/One.gb", "gb/Two.gb", "Nintendo - Game Boy Advance/Same.gba",
|
||||
"gba/Same.gba", "mame/game.zip", "PS1/Disc.cue"};
|
||||
for (size_t i = 0; i < sizeof(there) / sizeof(there[0]); i++)
|
||||
{
|
||||
snprintf(path, sizeof(path), "%s/%s", content, there[i]);
|
||||
assert(stat(path, &(struct stat){0}) == 0);
|
||||
}
|
||||
const char *gone[] = {"Sony - PlayStation 2", "Nintendo - Game Boy", "MAME"};
|
||||
for (size_t i = 0; i < sizeof(gone) / sizeof(gone[0]); i++)
|
||||
{
|
||||
snprintf(path, sizeof(path), "%s/%s", content, gone[i]);
|
||||
assert(stat(path, &(struct stat){0}) != 0);
|
||||
}
|
||||
/* The playlists follow; a folder whose name only begins the same is left. */
|
||||
snprintf(path, sizeof(path), "%s/Sony - PlayStation 2.lpl", playlists);
|
||||
read_back(path, text, sizeof(text));
|
||||
snprintf(want, sizeof(want), "\"scan_content_dir\": \"%s/ps2\"", content);
|
||||
assert(strstr(text, want));
|
||||
snprintf(want, sizeof(want), "\"%s/ps2/Disc.iso\"", content);
|
||||
assert(strstr(text, want) && !strstr(text, "PlayStation 2/"));
|
||||
snprintf(path, sizeof(path), "%s/Nintendo - Game Boy.lpl", playlists);
|
||||
read_back(path, text, sizeof(text));
|
||||
snprintf(want, sizeof(want), "\"%s/gb/One.gb\"", content);
|
||||
assert(strstr(text, want));
|
||||
snprintf(want, sizeof(want), "\"%s/Nintendo - Game Boy Advance/Same.gba\"", content);
|
||||
assert(strstr(text, want));
|
||||
snprintf(path, sizeof(path), "%s/builtin/content_history.lpl", playlists);
|
||||
read_back(path, text, sizeof(text));
|
||||
snprintf(want, sizeof(want), "\"%s/mame/game.zip#game.bin\"", content);
|
||||
assert(strstr(text, want));
|
||||
/* The per-folder settings follow; a core named as the folder keeps its own. */
|
||||
const char *settings[] = {"PS5SX2/ps2.cfg", "PS5SX2/ps2.opt", "remaps/PS5SX2/ps2.rmp",
|
||||
"MAME/MAME.cfg", "MAME/MAME.slangp"};
|
||||
for (size_t i = 0; i < sizeof(settings) / sizeof(settings[0]); i++)
|
||||
{
|
||||
snprintf(path, sizeof(path), "%s/%s", config, settings[i]);
|
||||
assert(stat(path, &(struct stat){0}) == 0);
|
||||
}
|
||||
snprintf(path, sizeof(path), "%s/PS5SX2/Sony - PlayStation 2.cfg", config);
|
||||
assert(stat(path, &(struct stat){0}) != 0);
|
||||
snprintf(path, sizeof(path), "%s/MAME/mame.cfg", config);
|
||||
assert(stat(path, &(struct stat){0}) != 0);
|
||||
assert(ps5_library_rename_system_folders(content, playlists, config) == 0); /* once */
|
||||
snprintf(path, sizeof(path), "%s/none", root);
|
||||
assert(ps5_library_rename_system_folders(path, playlists, config) == -1);
|
||||
}
|
||||
puts("ps5_library: platforms, playlists, systems, cores, folders, labels, favourites, history, "
|
||||
"runtime logs, game mode commands, content folders and system folders PASS");
|
||||
"runtime logs, game mode commands, content folders, system folders and their ES-DE "
|
||||
"names PASS");
|
||||
return 0;
|
||||
}
|
||||
@@ -407,10 +407,10 @@ for core_name in "${core_names[@]}"; do
|
||||
cp -- "$root/build/cores/stage/info/${core_name}_libretro.info" "$dist/cores/"
|
||||
done
|
||||
|
||||
# A folder in content/ for each system the staged cores run, named as RetroArch names
|
||||
# it ("Nintendo - Nintendo Entertainment System"), so a fresh install has a place for
|
||||
# every system's games (issue 33). The title makes the same ones at each start
|
||||
# (src/ps5_library.c, ps5_library_make_system_folders): this is that code, on the host.
|
||||
# A folder in content/ for each system the staged cores run, named as ES-DE names it
|
||||
# ("nes", "ps2"), so a fresh install has a place for every system's games (issue 33). The
|
||||
# title makes the same ones at each start (src/ps5_library.c,
|
||||
# ps5_library_make_system_folders): this is that code, on the host.
|
||||
cc -std=c11 -O2 -Wall -Wextra -Werror -I"$root/src" "$root/tools/system-folders.c" \
|
||||
"$root/src/ps5_library.c" -o "$root/build/system-folders"
|
||||
rm -rf -- "$dist/content"
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ function addDestination() {
|
||||
const system = addGame.systems.find(s => s.id === $('#add-system').value);
|
||||
$('#add-system-icon').replaceChildren(systemIcon(system?.id));
|
||||
$('#add-file').accept = system ? [...new Set(system.extensions.split('|'))].map(x => '.' + x).join(',') : '';
|
||||
$('#add-destination').textContent = system && addGame.file ? 'Destination: /app0/content/' + system.name + '/' + addGame.file.name : 'Select the system this game belongs to.';
|
||||
$('#add-destination').textContent = system && addGame.file ? 'Destination: /app0/content/' + system.id + '/' + addGame.file.name : 'Select the system this game belongs to.';
|
||||
}
|
||||
async function openAddGame() {
|
||||
if (addGame) return;
|
||||
|
||||
Reference in new issue
Block a user