ROM Hack Question Doom / Doom II - how one may import Cache saves (add-ons) without Devmenu ?

  • Thread starter Thread starter mathew77
  • Start date Start date
  • Views Views 9,280
  • Replies Replies 21

mathew77

Lovin' life.
Member
Joined
Jan 19, 2019
Messages
1,595
Solutions
1
Reaction score
1,610
Trophies
2
Age
49
XP
5,153
Country
Kazakhstan
Hello guys!..
I have a problem here related to Doom / DOOM II add-ons (Double Impact, TNT: Evilution, The Plutonia Experiment, John Romero’s SIGIL, Deathless).

I've these addons backup in some 'cache' type, like this (it's my old screenshot):
77e127bdf1297117de4f97213e4ce3f6.jpg
Here's the description text with more info: https://pastebin.com/gBUQ475f
About half a year ago with the working DevMenu It was all good, but now the problem is — DevMenu doesn't work anymore on FW 10.1.0...

As far as I know, Checkpoint or JKSV doesn't work with these 'cache' type game saves. I've tried to put it in BCAT folder and export with JKSV but with 0 results.

How can I import these files to the game to enable DOOM addons, like this:
3b5e53844c491179a5da2b524a19808f.jpg

Help please? The solution!
 
Last edited by mathew77,
I've been told JKSV can see and dump them if they're on the user nand partition. It has problems writing to them though. I was messing around with it recently, but right now I'm really busy with work.

I changed how JKSV scans save data and it can see SD card saves if I turn off the "Force Mount" option now. I added code and wrote an app to retrieve info to create the save file systems, but while it works fine for regular account saves, it doesn't seem to work for cache at the moment.

That's pretty much where I had to leave it for now.
 
I've been told JKSV can see and dump them if they're on the user nand partition. It has problems writing to them though. I was messing around with it recently, but right now I'm really busy with work.

I changed how JKSV scans save data and it can see SD card saves if I turn off the "Force Mount" option now. I added code and wrote an app to retrieve info to create the save file systems, but while it works fine for regular account saves, it doesn't seem to work for cache at the moment.

That's pretty much where I had to leave it for now.

thank you very much for your hard work
 
@burhansalih, and to all who is interested in solution of how to install DOOM add-ons on FW 10.1.0 without Devmenu, here it is:

  • Install the game and it's latest update to the Switch.
  • Copy the switch folder to the root of your microSD card (it contains DBI.nro homebrew).
  • Run dbi v155 homebrew (attached) on your Switch, then connect USB cable to the PC. After that, press X button to enable 'dbi MTP'.
  • The new Switch device appears on the PC. Open it, the open 6: Saves> Installed games > DOOM (or DOOM II).
  • Copy there all 'Cache.000*' folders with add-ons (they MUST be named like this: Cache.0000, Cache.0001, Cache.0002, Cache.0003, and so on, it's right structure you can see right under the spoiler below), then press 'Yes' button every time.
  • After copying is finished, press X to disconnect USB connection and exit the dbi homebrew.
  • Launch the game, select "Add-ons" in the main menu and activate desired Add-ons with the Y button.
Enjoy! ^_^
Code:
09/06/2020  07:40 PM    <DIR>          .
09/06/2020  07:40 PM    <DIR>          ..
01/15/2020  06:46 AM         4,646,543 4.wad
01/15/2020  06:36 AM             6,005 metadata
01/15/2020  06:43 AM           394,110 sigil1.jpg
01/15/2020  06:43 AM           407,659 sigil2.jpg
01/15/2020  06:44 AM           507,691 sigil3.jpg
01/15/2020  06:44 AM           273,669 sigil4.jpg

1 (2).jpg 2.jpg 3.jpg

The dbi homebrew for the Switch attached here, it's github:
 

Attachments

Last edited by mathew77,
@burhansalih, and to all who is interested in solution of how to install DOOM add-ons on FW 10.1.0 without Devmenu, here it is:

  • Install the game and the latest update to the Switch, start the game then close the game.
  • Copy the switch folder to the root of your microSD card (it contains DBI.nro homebrew).
  • Run dbi v155 homebrew (attached) on your Switch, then connect USB cable to the PC. After that, press X button to enable 'dbi MTP'.
  • The new Switch device appears on the PC. Open it, the open 6: Saves> Installed games > DOOM (or DOOM II).
  • Copy there all 'Cache.000*' folders with add-ons (they MUST be named like this: Cache.0000, Cache.0001, Cache.0002, Cache.0003, and so on, it's right structure you can see right under the spoiler below), then press 'Yes' button every time.
  • After copying is finished, press X to disconnect USB connection and exit the dbi homebrew.
  • Launch the game, select "Add-ons" in the main menu and activate desired Add-ons with the Y button.
Enjoy! ^_^
Code:
09/06/2020  07:40 PM    <DIR>          .
09/06/2020  07:40 PM    <DIR>          ..
01/15/2020  06:46 AM         4,646,543 4.wad
01/15/2020  06:36 AM             6,005 metadata
01/15/2020  06:43 AM           394,110 sigil1.jpg
01/15/2020  06:43 AM           407,659 sigil2.jpg
01/15/2020  06:44 AM           507,691 sigil3.jpg
01/15/2020  06:44 AM           273,669 sigil4.jpg


The dbi homebrew for the Switch attached here, it's github:

Legend ill give it a go now
 
@burhansalih How did you sort out the Unkwnown Command error? I keep trying to install the addons via DBI, but I'm not really what you'd call skilled when it comes to Switch hacking.

Thanks in advance!
 
Tinfoil can inject these as well. create a zip file that has the following structure:

__cache__/0/*
__cache__/1/*
__cache__/2/*
__cache__/3/*

make sure [titleid] is somewhere in the zip name, then just click on it from tinfoil's file browser to install it.

--------------------- MERGED ---------------------------

I've been told JKSV can see and dump them if they're on the user nand partition. It has problems writing to them though. I was messing around with it recently, but right now I'm really busy with work.

I changed how JKSV scans save data and it can see SD card saves if I turn off the "Force Mount" option now. I added code and wrote an app to retrieve info to create the save file systems, but while it works fine for regular account saves, it doesn't seem to work for cache at the moment.

That's pretty much where I had to leave it for now.

Cache saves are not like normal saves in that you do not know their sizes from the NACP. There are two ways to go about this:

a) you can either calculate the size needed to store the save then create a cache save larger than this.
b) you just create the same then keep resizing the save larger as you write to it (hacky).

Here is the relevant code from Tinfoil:

Code:
    bool User::create(nx::application::Id titleId, MountType type, u16 index, u64 size)
    {
        if(type == MountType::CACHE)
        {
            auto appControlData = applicationControlData(titleId);

            if(appControlData)
            {
                auto& nacp = appControlData->nacp;
                u64 alignedSize = pow(2, (int)log2(size) + 1);

                if(!nacp.cache_storage_size)
                {
                    nacp.cache_storage_size = alignedSize;
                }

                if(!nacp.cache_storage_journal_size)
                {
                    nacp.cache_storage_journal_size = alignedSize;
                }

                if(!nacp.cache_storage_data_and_journal_size_max)
                {
                    nacp.cache_storage_data_and_journal_size_max = nacp.cache_storage_size + nacp.cache_storage_journal_size;
                }

                FsSaveDataAttribute attr;
                FsSaveDataCreationInfo info;
                FsSaveMeta meta;

                memset(&attr, 0, sizeof(attr));
                memset(&info, 0, sizeof(info));
                memset(&meta, 0, sizeof(meta));

                info.journal_size = nacp.cache_storage_journal_size;
                info.save_data_size = nacp.cache_storage_size;
                info.save_data_space_id = FsSaveDataSpaceId_User;
                info.available_size = 0x4000;
                info.owner_id = titleId;

                attr.application_id = titleId;
                attr.save_data_type = FsSaveDataType_Cache;
                attr.save_data_index = index;

                meta.meta_file_size = 0x40060;
                meta.meta_index = 1;

                if(R_SUCCEEDED(fsCreateSaveDataFileSystem(&attr, &info, &meta)))
                {
                    return true;
                }
                else
                {
                    log::Debug() << "fsCreateSaveDataFileSystem failed";
                }
            }
        }
        else if(type == MountType::USER)
        {
            auto appControlData = applicationControlData(titleId);

            if(appControlData)
            {
                auto& nacp = appControlData->nacp;

                if(!nacp.user_account_save_data_size)
                {
                    log::Warning() << "user_account_save_data_size not set";
                    return false;
                }

                if(!nacp.user_account_save_data_journal_size)
                {
                    log::Warning() << "user_account_save_data_journal_size not set";
                    return false;
                }

                FsSaveDataAttribute attr;
                FsSaveDataCreationInfo info;
                FsSaveMeta meta;
                memset(&attr, 0, sizeof(attr));
                memset(&info, 0, sizeof(info));
                memset(&meta, 0, sizeof(meta));

                info.journal_size = nacp.user_account_save_data_journal_size;
                info.save_data_size = nacp.user_account_save_data_size;
                info.save_data_space_id = FsSaveDataSpaceId_User;
                info.available_size = 0x4000;
                info.owner_id = titleId;

                attr.application_id = titleId;
                attr.save_data_type = FsSaveDataType_Account;
                attr.save_data_index = index;
                attr.uid = id();

                meta.meta_file_size = 0x40060;
                meta.meta_index = 1;

                if(R_SUCCEEDED(fsCreateSaveDataFileSystem(&attr, &info, &meta)))
                {
                    return true;
                }
                else
                {
                    log::Debug() << "fsCreateSaveDataFileSystem failed";
                }
            }
        }
        else
        {
            log::Debug() << "create: unsupported save type";
        }
        return false;
    }
 
Tinfoil can inject these as well. create a zip file that has the following structure:

__cache__/0/*
__cache__/1/*
__cache__/2/*
__cache__/3/*

make sure [titleid] is somewhere in the zip name, then just click on it from tinfoil's file browser to install it.

--------------------- MERGED ---------------------------



Cache saves are not like normal saves in that you do not know their sizes from the NACP. There are two ways to go about this:

a) you can either calculate the size needed to store the save then create a cache save larger than this.
b) you just create the same then keep resizing the save larger as you write to it (hacky).

Here is the relevant code from Tinfoil:

Code:
    bool User::create(nx::application::Id titleId, MountType type, u16 index, u64 size)
    {
        if(type == MountType::CACHE)
        {
            auto appControlData = applicationControlData(titleId);

            if(appControlData)
            {
                auto& nacp = appControlData->nacp;
                u64 alignedSize = pow(2, (int)log2(size) + 1);

                if(!nacp.cache_storage_size)
                {
                    nacp.cache_storage_size = alignedSize;
                }

                if(!nacp.cache_storage_journal_size)
                {
                    nacp.cache_storage_journal_size = alignedSize;
                }

                if(!nacp.cache_storage_data_and_journal_size_max)
                {
                    nacp.cache_storage_data_and_journal_size_max = nacp.cache_storage_size + nacp.cache_storage_journal_size;
                }

                FsSaveDataAttribute attr;
                FsSaveDataCreationInfo info;
                FsSaveMeta meta;

                memset(&attr, 0, sizeof(attr));
                memset(&info, 0, sizeof(info));
                memset(&meta, 0, sizeof(meta));

                info.journal_size = nacp.cache_storage_journal_size;
                info.save_data_size = nacp.cache_storage_size;
                info.save_data_space_id = FsSaveDataSpaceId_User;
                info.available_size = 0x4000;
                info.owner_id = titleId;

                attr.application_id = titleId;
                attr.save_data_type = FsSaveDataType_Cache;
                attr.save_data_index = index;

                meta.meta_file_size = 0x40060;
                meta.meta_index = 1;

                if(R_SUCCEEDED(fsCreateSaveDataFileSystem(&attr, &info, &meta)))
                {
                    return true;
                }
                else
                {
                    log::Debug() << "fsCreateSaveDataFileSystem failed";
                }
            }
        }
        else if(type == MountType::USER)
        {
            auto appControlData = applicationControlData(titleId);

            if(appControlData)
            {
                auto& nacp = appControlData->nacp;

                if(!nacp.user_account_save_data_size)
                {
                    log::Warning() << "user_account_save_data_size not set";
                    return false;
                }

                if(!nacp.user_account_save_data_journal_size)
                {
                    log::Warning() << "user_account_save_data_journal_size not set";
                    return false;
                }

                FsSaveDataAttribute attr;
                FsSaveDataCreationInfo info;
                FsSaveMeta meta;
                memset(&attr, 0, sizeof(attr));
                memset(&info, 0, sizeof(info));
                memset(&meta, 0, sizeof(meta));

                info.journal_size = nacp.user_account_save_data_journal_size;
                info.save_data_size = nacp.user_account_save_data_size;
                info.save_data_space_id = FsSaveDataSpaceId_User;
                info.available_size = 0x4000;
                info.owner_id = titleId;

                attr.application_id = titleId;
                attr.save_data_type = FsSaveDataType_Account;
                attr.save_data_index = index;
                attr.uid = id();

                meta.meta_file_size = 0x40060;
                meta.meta_index = 1;

                if(R_SUCCEEDED(fsCreateSaveDataFileSystem(&attr, &info, &meta)))
                {
                    return true;
                }
                else
                {
                    log::Debug() << "fsCreateSaveDataFileSystem failed";
                }
            }
        }
        else
        {
            log::Debug() << "create: unsupported save type";
        }
        return false;
    }

Have you fixed tinleaf yet?
 
Cache saves are not like normal saves in that you do not know their sizes from the NACP. There are two ways to go about this:

a) you can either calculate the size needed to store the save then create a cache save larger than this.
b) you just create the same then keep resizing the save larger as you write to it (hacky).

Here is the relevant code from Tinfoil:

Code:
    bool User::create(nx::application::Id titleId, MountType type, u16 index, u64 size)
    {
        if(type == MountType::CACHE)
        {
            auto appControlData = applicationControlData(titleId);

            if(appControlData)
            {
                auto& nacp = appControlData->nacp;
                u64 alignedSize = pow(2, (int)log2(size) + 1);

                if(!nacp.cache_storage_size)
                {
                    nacp.cache_storage_size = alignedSize;
                }

                if(!nacp.cache_storage_journal_size)
                {
                    nacp.cache_storage_journal_size = alignedSize;
                }

                if(!nacp.cache_storage_data_and_journal_size_max)
                {
                    nacp.cache_storage_data_and_journal_size_max = nacp.cache_storage_size + nacp.cache_storage_journal_size;
                }

                FsSaveDataAttribute attr;
                FsSaveDataCreationInfo info;
                FsSaveMeta meta;

                memset(&attr, 0, sizeof(attr));
                memset(&info, 0, sizeof(info));
                memset(&meta, 0, sizeof(meta));

                info.journal_size = nacp.cache_storage_journal_size;
                info.save_data_size = nacp.cache_storage_size;
                info.save_data_space_id = FsSaveDataSpaceId_User;
                info.available_size = 0x4000;
                info.owner_id = titleId;

                attr.application_id = titleId;
                attr.save_data_type = FsSaveDataType_Cache;
                attr.save_data_index = index;

                meta.meta_file_size = 0x40060;
                meta.meta_index = 1;

                if(R_SUCCEEDED(fsCreateSaveDataFileSystem(&attr, &info, &meta)))
                {
                    return true;
                }
                else
                {
                    log::Debug() << "fsCreateSaveDataFileSystem failed";
                }
            }
        }
        else if(type == MountType::USER)
        {
            auto appControlData = applicationControlData(titleId);

            if(appControlData)
            {
                auto& nacp = appControlData->nacp;

                if(!nacp.user_account_save_data_size)
                {
                    log::Warning() << "user_account_save_data_size not set";
                    return false;
                }

                if(!nacp.user_account_save_data_journal_size)
                {
                    log::Warning() << "user_account_save_data_journal_size not set";
                    return false;
                }

                FsSaveDataAttribute attr;
                FsSaveDataCreationInfo info;
                FsSaveMeta meta;
                memset(&attr, 0, sizeof(attr));
                memset(&info, 0, sizeof(info));
                memset(&meta, 0, sizeof(meta));

                info.journal_size = nacp.user_account_save_data_journal_size;
                info.save_data_size = nacp.user_account_save_data_size;
                info.save_data_space_id = FsSaveDataSpaceId_User;
                info.available_size = 0x4000;
                info.owner_id = titleId;

                attr.application_id = titleId;
                attr.save_data_type = FsSaveDataType_Account;
                attr.save_data_index = index;
                attr.uid = id();

                meta.meta_file_size = 0x40060;
                meta.meta_index = 1;

                if(R_SUCCEEDED(fsCreateSaveDataFileSystem(&attr, &info, &meta)))
                {
                    return true;
                }
                else
                {
                    log::Debug() << "fsCreateSaveDataFileSystem failed";
                }
            }
        }
        else
        {
            log::Debug() << "create: unsupported save type";
        }
        return false;
    }
I already added this, sort of. My idea was to have it fetch a file from a git repo to create saves for games that didn't have data created yet. I actually have the info for dooms cache saves on my hard drive somewhere. I just haven't had time to take it further.
https://github.com/J-D-K/JKSV/blob/abfa13fbc16ffc7856185e9ce93707e2f7edbba1/src/file.cpp#L515
 
  • Like
Reactions: ShroomKing
I already added this, sort of. My idea was to have it fetch a file from a git repo to create saves for games that didn't have data created yet. I actually have the info for dooms cache saves on my hard drive somewhere. I just haven't had time to take it further.
https://github.com/J-D-K/JKSV/blob/abfa13fbc16ffc7856185e9ce93707e2f7edbba1/src/file.cpp#L515

The service call was there, but not the exact code / params to create the save.

Also, libnx just added those service calls: https://github.com/switchbrew/libnx/commit/c82c8b87607503b92c9e59cdd8b2c624ac37e942

You also do not want to maintain your own database of save parameters. Just read the game's NACP, it contains the settings you need to create its save. That is why the NACP is pulled in the example I gave.

edit: fsDeleteSaveDataFileSystemBySaveDataAttribute is what you want to use to delete the cache saves (as well as other saves).
 
Last edited by blawar,
The service call was there, but not the exact code / params to create the save.

Also, libnx just added those service calls: https://github.com/switchbrew/libnx/commit/c82c8b87607503b92c9e59cdd8b2c624ac37e942

You also do not want to maintain your own database of save parameters. Just read the game's NACP, it contains the settings you need to create its save. That is why the NACP is pulled in the example I gave.
I added it over 6 months ago and had to stop shortly after. Everything was read from a file, set and the system call was used. It worked fine. It was also for another project that wouldn't have the nacp available. The other project might be done with, so yeah, nacp should be fine now.

Oh, I see now. Libnx was updated yesterday with a function I added months ago and I needed it explained to me even though I had it working then.
 
Last edited by JK_,
I was wondering this very same thing this week.
Quake also makes use of Add-ons, and adds Quake64 through that method.

Though, does the same method of putting the Add-ons with DBI also work for Quake?
 
Probably not allowed here, but does anyone have a link to the complete add-on's for Doom, Doom2, and Quake for the Switch currently?
 
Probably not allowed here, but does anyone have a link to the complete add-on's for Doom, Doom2, and Quake for the Switch currently?
You're right, it's not allowed here and I'm sure you read the rules of the forum about this. Just ask google/bing or one of the many other search engines about what you require.
 
  • Like
Reactions: MountainMan23

Site & Scene News

Popular threads in this forum