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

mathew77

Lovin' life.
OP
Member
Joined
Jan 19, 2019
Messages
1,183
Trophies
0
Age
47
XP
3,672
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,

JK_

Well-Known Member
Member
Joined
Sep 4, 2015
Messages
694
Trophies
1
XP
2,287
Country
United States
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.
 

burhansalih

Well-Known Member
Member
Joined
Jan 11, 2009
Messages
1,598
Trophies
1
Location
London, England
XP
2,479
Country
United Kingdom
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
 

mathew77

Lovin' life.
OP
Member
Joined
Jan 19, 2019
Messages
1,183
Trophies
0
Age
47
XP
3,672
Country
Kazakhstan
@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

  • DBI-v155.zip
    1,018.6 KB · Views: 263
Last edited by mathew77,

burhansalih

Well-Known Member
Member
Joined
Jan 11, 2009
Messages
1,598
Trophies
1
Location
London, England
XP
2,479
Country
United Kingdom
@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
 

LJS777

New Member
Newbie
Joined
Oct 20, 2020
Messages
1
Trophies
0
Age
34
Location
SP
XP
44
Country
Brazil
@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!
 

blawar

Developer
Developer
Joined
Nov 21, 2016
Messages
1,708
Trophies
1
Age
40
XP
4,311
Country
United States
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;
    }
 

burhansalih

Well-Known Member
Member
Joined
Jan 11, 2009
Messages
1,598
Trophies
1
Location
London, England
XP
2,479
Country
United Kingdom
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?
 

JK_

Well-Known Member
Member
Joined
Sep 4, 2015
Messages
694
Trophies
1
XP
2,287
Country
United States
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

blawar

Developer
Developer
Joined
Nov 21, 2016
Messages
1,708
Trophies
1
Age
40
XP
4,311
Country
United States
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,

JK_

Well-Known Member
Member
Joined
Sep 4, 2015
Messages
694
Trophies
1
XP
2,287
Country
United States
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_,

ShadowOne333

QVID PRO QVO
Editorial Team
Joined
Jan 17, 2013
Messages
12,177
Trophies
2
XP
33,601
Country
Mexico
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?
 

mrdude

Developer
Developer
Joined
Dec 11, 2015
Messages
3,071
Trophies
1
Age
56
XP
8,227
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

General chit-chat
Help Users
    K3Nv2 @ K3Nv2: It's Amazon prime