PS3 Adding an image to save file

Hi,
is there a way to add an image to save file so its displayed in XMB? Copying it to dir with game save files doesnt work.
 
Last edited by a moderator:
Hi,
is there a way to add an image to save file so its displayed in XMB? Copying it to dir with game save files doesnt work.
rebuild database after copying file. installing the file with a custom pkg will allow to avoid rebuilding.
 
Actually You don't need rebuild database after icon changing. It is needed only if installed package wasn't have ICON0.PNG so it wasn't registered (if this is even possible, items without icon is probably displaying as "Corrupted Data"). Otherwise is sufficient to just replace file.

Is there a way to copy a file in that C file?
What "C file"? What are You talking about? If You have in mind one of the files of source code, then it have nothing to do with XMB.
 
Actually You don't need rebuild database after icon changing. It is needed only if installed package wasn't have ICON0.PNG so it wasn't registered (if this is even possible, items without icon is probably displaying as "Corrupted Data"). Otherwise is sufficient to just replace file.


What "C file"? What are You talking about? If You have in mind one of the files of source code, then it have nothing to do with XMB.
but to xmb to display save icon, it has to be copied from game's files to save dir
and by C file i mean that pastelink at the top (ps3 saving routine)
 
but to xmb to display save icon, it has to be copied from game's files to save dir
and by C file i mean that pastelink at the top (ps3 saving routine)

there's no paste link at the top.

you can just copy & paste the source code here, between [ code ] [ /code ] tags.
 
I just realized that You asking about save implementation in homebrew app. Somehow I missed the category in which You asking. I'm sorry.

If You works in official SDK, then it have documentations i.e explaining how to ask system to make save. I don't know how it looks like in PSL1GHT but probably is similar (if exist...). Creating folder and putting there data (PARAM.SFO, ICON0.PNG etc.) is not enough because PS3 must create valid PARAM.PFD for it and put register of save into database. I never see a homebrew which using standard Save Data, rather just custom dirs on HDD (most often just $USRDIR of app parent dir) which of course are "transparent" to XMB.
 
Last edited:
Btw, there are many games that contains an additional ICON0.PNG (inside some of the USRDIR folders or files) used for the save and for the gamedata. I mean... the game contains several ICON0.PNG files used for different purposes:
1) The main game ICON0.PNG (located next to the PARAM.SFO)
2) The ICON0.PNG for the saves
3) The ICON0.PNG for the gamedata installation

An example of this are the games from naughty dog (uncharteds, the last of us, etc...), there is a folder (at some path under USRDIR) where you can see the additional icons for the saves and gamedata
Most of the other games does the same... is just we cant see that files because are "packed" inside container files (PSARC or others). An example of this are the killzones

If you modify this images in the game files then the game is going to use them to generate the gamedata installation and the saves


*but be careful, i found a game (the orange box) that uses an anti-tampering protection, lol... if you modify the ICON0.PNG used for the saves and gamedata the PS3 considers is corrupted
 
Am not sure I fully understand the request.
Are we talking about making a homebrew that would replace the icon of an existing XMB game save entry, to use a custom icon rather than the default one?

If so, I have never tried this but maybe manually swapping the appropriate icon file might work & remove the need for a specific homebrew:
/dev_hdd0/home/<userid>/savedata/<SAVEDATA_DIRECTORY>/ICON0.PNG

The icon png file format must follow certain specs otherwise it will most likely be an issue.
You can also import game saves from USB in which you could try changing the icon before importing to ps3.

Check the wiki for more details:
https://www.psdevwiki.com/ps3/PS3_Savedata
 
Last edited:
I never see a homebrew which using standard Save Data, rather just custom dirs on HDD (most often just $USRDIR of app parent dir) which of course are "transparent" to XMB.

that statement might have been true in the past... ;)

Apollo actually creates a valid PS3 savegame just like a regular game would do, by using the internal ps3 functions.
The example source code can be found on my repo, it's based on a psl1ght example by Kakaroto.
https://github.com/bucanero/apollo-ps3/blob/master/source/save_util.c
 
I have in mind save for app itself just like games doing. But fair point and excellent code example. ^^
 
I just realized that You asking about save implementation in homebrew app. Somehow I missed the category in which You asking. I'm sorry.

If You works in official SDK, then it have documentations i.e explaining how to ask system to make save. I don't know how it looks like in PSL1GHT but probably is similar (if exist...). Creating folder and putting there data (PARAM.SFO, ICON0.PNG etc.) is not enough because PS3 must create valid PARAM.PFD for it and put register of save into database. I never see a homebrew which using standard Save Data, rather just custom dirs on HDD (most often just $USRDIR of app parent dir) which of course are "transparent" to XMB.
SM64 uses PSL1GHT and it saves to standard save data

You can also import game saves from USB in which you could try changing the icon before importing to ps3.
Tried. PS3 only displays the icon when save is on USB. When copied to the HDD, it disappears

there's no paste link at the top.

you can just copy & paste the source code here, between [ code ] [ /code ] tags.
I remember putting it there, but here it is
ps3_save.c:
Code:
#ifdef TARGET_PS3
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include <sys/thread.h>
#include <sys/memory.h>
#include <sys/mutex.h>
#include <sysutil/sysutil.h>
#include <sysutil/save.h>

#include "macros.h"
#include "game/save_file.h"

#define SYS_MEMORY_CONTAINER_INVALID 0xFFFFFFFFU

#define SAVE_DIRNAME "SM64"
#define SAVE_FILENAME "SAVE"
#define SAVE_TITLE "Super Mario 64"
#define SAVE_SUBTITLE "Super Mario 64 save data"

#define SAVE_SIZE 2048
#define SAVE_SIZE_KB (SAVE_SIZE / 1024)
#define SAVE_MAX_FILES 3 // save + icon + pic
#define SAVE_MAX_DIRS 1

#define XMAX(a, b) (((a) > (b)) ? (a) : (b))

enum SaveMode {
 MODE_NONE,
 MODE_SAVE,
 MODE_LOAD,
 MODE_SAVE_DONE,
 MODE_LOAD_DONE,
};

static uint8_t save_data[SAVE_SIZE];
static uint32_t pending_save_size = 0;

static sys_ppu_thread_t save_thread;
static sys_mutex_t save_mutex;
static volatile int thread_mode = MODE_NONE;
static volatile int thread_ret = 0;

static bool init_done = false;

static inline void get_save_description(char *buf, int bufsize) {
 buf[0] = '\0';
 for (int i = 0; i < NUM_SAVE_FILES; ++i) {
 const int ret = snprintf(
 buf, bufsize,
 "FILE %c: %d\n",
 'A' + i,
 save_file_get_total_star_count(i, COURSE_MIN - 1, COURSE_MAX - 1)
 );
 if (ret < 0) break;
 buf += ret;
 bufsize -= ret;
 }
}

static void save_status_cb(sysSaveCallbackResult *res, sysSaveStatusIn *in, sysSaveStatusOut *out) {
 res->result = SYS_SAVE_CALLBACK_RESULT_CONTINUE;
 out->setParam = &in->getParam;

 if (thread_mode == MODE_SAVE) {
 out->recreateMode = SYS_SAVE_RECREATE_MODE_DELETE;

 if ((in->freeSpaceKB + in->sizeKB) < (SAVE_SIZE_KB + in->systemSizeKB)) {
 res->result = SYS_SAVE_CALLBACK_RESULT_NO_SPACE_LEFT;
 res->missingSpaceKB = (SAVE_SIZE_KB + in->systemSizeKB) -
 (in->freeSpaceKB + in->sizeKB);
 }

 char detail[SYS_SAVE_MAX_DETAIL];
 get_save_description(detail, sizeof(detail));

 strncpy(in->getParam.title, SAVE_TITLE, SYS_SAVE_MAX_TITLE);
 strncpy(in->getParam.subtitle, SAVE_SUBTITLE, SYS_SAVE_MAX_SUBTITLE);
 strncpy(in->getParam.detail, detail, SYS_SAVE_MAX_DETAIL);
 } else if (thread_mode == MODE_LOAD) {
 out->recreateMode = SYS_SAVE_RECREATE_MODE_OVERWRITE_NOT_CORRUPTED;

 for (uint32_t i = 0; i < in->numFiles; i++) {
 switch (in->fileList[i].fileType) {
 case SYS_SAVE_FILETYPE_STANDARD_FILE:
 pending_save_size = in->fileList[i].fileSize;
 break;
 case SYS_SAVE_FILETYPE_CONTENT_ICON0:
 // TODO
 break;
 case SYS_SAVE_FILETYPE_CONTENT_PIC1:
 // TODO
 break;
 default:
 break;
 }
 }

 if (pending_save_size == 0) {
 printf("save_status_cb: could not find valid save data\n");
 res->result = SYS_SAVE_CALLBACK_RESULT_CORRUPTED;
 return;
 }
 }
}

static void save_file_cb(sysSaveCallbackResult *res, sysSaveFileIn *in, sysSaveFileOut *out) {
 memset(out, 0, sizeof(*out));

 switch (thread_mode) {
 case MODE_SAVE:
 printf("save_file_cb: writing save data\n");
 out->fileOperation = SYS_SAVE_FILE_OPERATION_WRITE;
 thread_mode = MODE_SAVE_DONE;
 break;
 case MODE_LOAD:
 printf("save_file_cb: reading save data\n");
 out->fileOperation = SYS_SAVE_FILE_OPERATION_READ;
 thread_mode = MODE_LOAD_DONE;
 break;
 case MODE_SAVE_DONE:
 res->result = SYS_SAVE_CALLBACK_RESULT_DONE;
 return;
 case MODE_LOAD_DONE:
 if (in->previousOperationResultSize != SAVE_SIZE)
 res->result = SYS_SAVE_CALLBACK_RESULT_CORRUPTED;
 else
 res->result = SYS_SAVE_CALLBACK_RESULT_DONE;
 return;
 default:
 break;
 }

 out->filename = SAVE_FILENAME;
 out->fileType = SYS_SAVE_FILETYPE_STANDARD_FILE;
 out->size = SAVE_SIZE;
 out->bufferSize = SAVE_SIZE;
 out->buffer = save_data;

 res->result = SYS_SAVE_CALLBACK_RESULT_CONTINUE;
 res->incrementProgress = 100;
}

static void save_thread_func(UNUSED void *arg) {
 thread_ret = -1;

 pending_save_size = 0;

 sysSaveBufferSettings bufset;
 memset(&bufset, 0, sizeof(bufset));
 bufset.maxDirectories = SAVE_MAX_DIRS;
 bufset.maxFiles = SAVE_MAX_FILES;
 bufset.bufferSize = XMAX(
 SAVE_MAX_FILES * sizeof(sysSaveFileStatus),
 SAVE_MAX_DIRS * sizeof(sysSaveDirectoryList)
 );
 bufset.buffer = malloc(bufset.bufferSize);

 if (!bufset.buffer) {
 printf("save_thread: could not alloc %u bytes for save buffer\n", bufset.bufferSize);
 return;
 }

 sysMutexLock(save_mutex, 30000);

 if (thread_mode == MODE_SAVE) {
 thread_ret = sysSaveAutoSave2(
 SYS_SAVE_CURRENT_VERSION,
 SAVE_DIRNAME,
 SYS_SAVE_ERROR_DIALOG_SHOW_ONCE,
 &bufset,
 save_status_cb,
 save_file_cb,
 SYS_MEMORY_CONTAINER_INVALID,
 NULL
 );
 } else {
 thread_ret = sysSaveAutoLoad2(
 SYS_SAVE_CURRENT_VERSION,
 SAVE_DIRNAME,
 SYS_SAVE_ERROR_DIALOG_SHOW_ONCE,
 &bufset,
 save_status_cb,
 save_file_cb,
 SYS_MEMORY_CONTAINER_INVALID,
 NULL
 );
 }

 sysMutexUnlock(save_mutex);

 free(bufset.buffer);

 sysThreadExit(0);
}

static inline void wait_thread(void) {
 u64 retval;
 if (thread_mode != MODE_NONE) {
 sysThreadJoin(save_thread, &retval);
 thread_mode = MODE_NONE;
 }
}

static inline void spawn_thread(const int mode) {
 thread_mode = mode;
 sysThreadCreate(&save_thread, save_thread_func, NULL, 1500, 0x10000, THREAD_JOINABLE, "sm64 save");
}

bool ps3_save_init(void) {
 sys_mutex_attr_t mattr;
 sysMutexAttrInitialize(mattr);
 sysMutexCreate(&save_mutex, &mattr);
 init_done = true;
 return true;
}

bool ps3_save_write(const void *data, const uint32_t ofs, const uint32_t size) {
 sysMutexLock(save_mutex, 30000);
 memcpy(save_data + ofs, data, size);
 sysMutexUnlock(save_mutex);
 return true;
}

bool ps3_save_read(void *data, const uint32_t ofs, const uint32_t size) {
 sysMutexLock(save_mutex, 30000);
 memcpy(data, save_data + ofs, size);
 sysMutexUnlock(save_mutex);
 return true;
}

bool ps3_save_save(void) {
 wait_thread(); // wait for previous operation to complete
 spawn_thread(MODE_SAVE);
 // no use waiting for a pending save, we got a mutex on writes
 return true;
}

bool ps3_save_load(void) {
 wait_thread(); // wait for previous operation to complete
 spawn_thread(MODE_LOAD);
 wait_thread(); // wait until the save is done
 return (thread_ret == 0);
}

void ps3_save_shutdown(void) {
 if (init_done) {
 init_done = false;
 wait_thread();
 sysMutexDestroy(save_mutex);
 }
}

#endif // TARGET_PS3
 
Last edited:
SM64 uses PSL1GHT and it saves to standard save data


Tried. PS3 only displays the icon when save is on USB. When copied to the HDD, it disappears

have you tried checking my example?
https://github.com/bucanero/apollo-ps3/blob/master/source/save_util.c

My source code creates a save using the internal ps3 functions, with a valid ICON0.PNG (and also supports the additional PIC1.PNG)
The code reads a .png file in a buffer, and then uses that buffer as the icon0.png .

if you compare it, the sources are similar... so just take the parts you need.
 

Similar threads

Back
Top