Skip to content

Commit

Permalink
Merge pull request #63 from w3irDv/enh/mngslot
Browse files Browse the repository at this point in the history
1.6.4 -> batch restore+wipe/tag slots&backupsets+UI
  • Loading branch information
w3irDv authored Jan 6, 2025
2 parents 0f6c2bc + 31da646 commit d6a5424
Show file tree
Hide file tree
Showing 58 changed files with 4,224 additions and 758 deletions.
11 changes: 5 additions & 6 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ jobs:
with:
fetch-depth: 0
- name: Docker Layer Caching
uses: jpribyl/action-docker-[email protected]
uses: ScribeMD/docker-[email protected]
continue-on-error: true
id: cache
with:
key: savemii-docker-cache-{hash}
restore-keys: |
savemii-docker-cache-
key: savemii-docker-cache-${{ hashFiles('DockerFile')}}
- name: Build artifacts
run: |
docker build . --file Dockerfile --tag builder
Expand All @@ -25,11 +24,11 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: SaveMiiModWUTPort-Aroma
path: SaveMiiModWUTPort-Aroma.zip
path: build/Aroma/*
if-no-files-found: warn
- name: Upload HBL version
uses: actions/upload-artifact@v4
with:
name: SaveMiiModWUTPort-HBL
path: SaveMiiModWUTPort-HBL.zip
path: build/HBL/*
if-no-files-found: warn
19 changes: 11 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ CONTENT :=
ICON := meta/wuhb/icon.png
TV_SPLASH := meta/wuhb/tv-splash.png
DRC_SPLASH := meta/wuhb/drc-splash.png
ROMFS := languages
ROMFS := romfs

#-------------------------------------------------------------------------------
# options for code generation
Expand Down Expand Up @@ -156,13 +156,16 @@ clean:

#-------------------------------------------------------------------------------
release: $(BUILD)
@mkdir -p SaveMiiModWUTPort
@cp savemii.rpx SaveMiiModWUTPort
@cp meta/hbl/icon.png SaveMiiModWUTPort
@cp meta/hbl/meta.xml SaveMiiModWUTPort
@zip -9 -r SaveMiiModWUTPort-HBL.zip SaveMiiModWUTPort
@zip -9 SaveMiiModWUTPort-Aroma.zip savemii.wuhb
@rm -rf SaveMiiModWUTPort
@mkdir -p build/Aroma/wiiu/apps/SaveMiiModWUTPort
@mkdir -p build/HBL/wiiu/apps/SaveMiiModWUTPort
@rm -rf build/Aroma/wiiu/apps/SaveMiiModWUTPort/*
@rm -rf build/HBL/wiiu/apps/SaveMiiModWUTPort/*
@cp savemii.rpx build/HBL/wiiu/apps/SaveMiiModWUTPort
@cp meta/hbl/icon.png build/HBL/wiiu/apps/SaveMiiModWUTPort
@cp meta/hbl/meta.xml build/HBL/wiiu/apps/SaveMiiModWUTPort
@cp savemii.wuhb build/Aroma/wiiu/apps/SaveMiiModWUTPort
@zip -9 -r SaveMiiModWUTPort-HBL.zip build/HBL
@zip -9 -r SaveMiiModWUTPort-Aroma.zip build/Aroma
#-------------------------------------------------------------------------------
else
.PHONY: all
Expand Down
103 changes: 103 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,109 @@ For sorting Titles press R to change sorting method and press L to change betwee

Use it at your own risk and please report any issues that may occur.

## Quick Notes

Move across screen by using Up/Down D-Pad buttons. Cycle between options by using Left/Right D-Pad buttons. "A" to select a task / enter a menu. "B" to go back to the previous menu. Special functions can be accessed by using "X/Y/+/-" buttons, as described at the bottom line in each menu.

### Wii U Title Management / vWii Title Management

Allows you to backup/restore/wipe individual titles.

1. First select the title you want to manage.
1. Wii U titles: If the title has not been initialized (you have not created an initial save by playing to it beforehand) it will be marked as "Not init" and will appear in yellow. You can try to manage it (restore from a previous backup), but the outcome is uncertain. It is recommended to first play and create "real" savedata before trying to restore any backup.
1. An special case of this are vWii injects. They have both a Wii U title with no savedata that will appear in "Wii U Title Management" marked as "Not init", and a vWii title where the game's savedata is that will appear in vWii Title Management after you play it and create an initial game savedata. Savedata for these titles must be managed from the vWii Management tasks. Just in case, Savemii allows you to manage the Wii U title portion, but it usually doesn't contain any savedata.
2. Select the task you want to do:
1. Backup: Copy savedata from USB/NAND to SD
2. Restore: Copy savedata from SD to USB/NAND
3. Wipe: Delete savedata from USB/NAND
4. Export / Import to Loadiine: Legacy options to manage Loadiine savedata
5. Copy to other Device: If savedata for a title is present in USB and NAND, copy it from one storage to the other

#### Backup
1. Select a slot to store the savedata. You can select any number from 0 to 255, each one representing a different folder in the SD card.
2. For Wii U titles, select which data to save:
1. All users: Recommended option. Will backup all game data.
2. From user: xxxxxxxx. Will only backup the data for the specified user/profile. In this case, you must also specify if you want to save the "common" data or not. "Common" savedata is data shared by all profiles. Titles can have common save data, profile savedata or both.
3. Press "A" to initiate the backup. After the backup is done, you can tag the slot with a meaningful name pressing "+" button while you are in the backup menu. If the slot is unneeded, you can delete it by pressing "-" button.

*Wii U titles savedata layout:*
```
sd:/wiiu/backups/
xxxxxxxxyyyyyyyy/ # Title Id
0/
saveMiiMeta.json
80000001/ # one folder for each profile
... # savedata
80000002/
...
...
common/
...
1/ # one folder for each slot
...
```
For vWii titles, savedata is directly under the slot folder.

#### Restore
1. Select a slot to get the data from. By default, data from the "root" backupSet (the one where the manual backups are stored) is used. But you can also use slots from batch backupSets, by pressing "X" button in this menu and selecting the backupSet you want to use. BackupSets can be tagged by pressing "+" button in the BackupSet List Menu, or from the BackupSet Management in Main menu.
To identify which data the slot contains: If the slot has been tagged, you will see its tag next to the slot number. On the top screen line, you will see which backupSet is being used. And at the last screen line, you can see when the savedata were taken, and from which console.
2. For Wii U titles, select witch data to restore:
1. `From: All users / To: Same user than Source`
This will restore all save data (profiles+common) from the selected slot keeping the same userid that was used to backup the data. This option can only be used to restore previous savedata from the same console, or if the profile ids in the new console are identical to the ones in the source console. If profile ids from source and target differ, you must use the next option.
2. `From: select source user / To: select target user`. This will copy savedata from the specified source profile id in the slot backup to the specified target profile id in the console. You can specify if copy common savedata or not.
If you are just copying the savedata from one profile id to a different one in the same console, choose `copy common savedata: no`. If you are restoring to a new console with different profile ids, just choose `copy common savedata: yes` once for any of the profile ids, and copy the rest of profiles with `copy common savedata: no`
3. Press "A" to initiate the restore.

#### Wipe
Sometimes you will need to wipe savedata in the console before restoring a previous backup: If a restore is unsuccesful, you can try to wipe previous data before attempting a new restore. Options are the same than in the *Backup* task, but now refer to savedata for the specified title in the NAND or in the USB.

#### Copy to other device
If a title has savedata in the NAND and in the USB, you can copy it between both storages. Options are the same than in the *Restore* task.

### Batch Backup

You can backup savedata for all Wii U titles and all Wii titles at once using this tasks. Savedata will be stored in a "Backup set" in the `batch` directori, and can after be used to restore individual titles or to batch restore all of them.
BackupSets can be tagged by pressing "+" button in the BackupSet List menu or by entering in the menu Backupset Management from the Main menu.

```
sd:/wiiu/backups/batch/
${timestamp}/
saveMiiMeta.json
xxxxxxxxyyyyyyyy/ # one folder for each title
0/ # slot containing USB or NAND savedata for the title
saveMiiMeta.json
80000001/
...
80000002/
...
... one folder for each profile
common/
...
1/ # slot containing NAND savedata for titles simultaneously installed in USB and NAND
...
xxxxxxxxxyyyyyyyy/
0/
...
```

### Batch Restore

This task allows you to restore the savedata for all titles already installed in the Wii U or in the vWii from a batch backupSet,
1. Select wether you want to restore Wii U titles or vWii titles
2. Select the backupSet you want to restore from
3. Select wich data to restore. Options are the same than in the *Restore* task. You can also choose if you want to perform a full backup (recommended) or to wipe data before restoring it.
4. The list of all titles that are installed, that have a backup in the backupset, and that match the savedata criteria choosen in the previous step will appear. You can select / deselect which titles to restore. Titles with "Not Init" will be skipped by default.
5. Once you have reviewed the list of titles to be restored, press "A". A summary screen will appear, and if it is OK, you can initiate the restore.
6. Once the restore is completed, a summary screen will show the number of sucess/failed/skipped titles.
7. The list of all titles will appear again, now showing the restored status. You can try to select failed titles and restore them again to see what the error is. Succesfully restored titles will be skipped.

### Backupset management
In this menu you can tag backupsets ("+") or delete the ones you don't need ("-"). You can also set the one you want to use to restore savedata ("A").


----


Reasons to use this over original mod:

- Faster copy speeds
Expand Down
5 changes: 5 additions & 0 deletions include/ApplicationState.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ class ApplicationState {
SUBSTATE_RETURN,
};

enum eSubstateCalled {
NONE
};

virtual void render() = 0;
virtual eSubState update(Input *input) = 0;

};
102 changes: 96 additions & 6 deletions include/BackupSetList.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,127 @@
#include <string>
#include <vector>
#include <memory>
#include <set>

class BSMetadataValues {
friend class BSMetadata;
friend class BackupSetList;
public:

template <class T>
class attr {
public:
std::set<std::string,T> range;
std::set<std::string>::iterator iterator;
};
attr<std::greater<std::string>> year;
attr<std::greater<std::string>> month;
attr<std::less<std::string>> serialId;
attr<std::less<std::string>> tag;

template <typename T>
static void Right (T & metadataAttrValues);

template <typename T>
static void Left (T & metadataAttrValues);

void resetFilter();

};

class BSMetadata {
public:
friend class BackupSetItem;
friend class BackupSetList;
BSMetadata(std::string year = "*", std::string month = "*",
std::string serialId = "*", std::string tag = "*") :
year(year),month(month),serialId(serialId),tag(tag) {};
BSMetadata(BSMetadataValues & bsMetadataValues) :
year(*(bsMetadataValues.year.iterator)),month(*(bsMetadataValues.month.iterator)),
serialId(*(bsMetadataValues.serialId.iterator)),tag(*(bsMetadataValues.tag.iterator)) {};
private:
std::string year;
std::string month;
std::string serialId;
std::string tag;
};

class BackupSetItem {
public:
friend class BackupSetList;
BackupSetItem(std::string entryPath,BSMetadata bsItemMetadata) :
entryPath(entryPath),bsItemMetadata(bsItemMetadata) {};
private:
std::string entryPath;
BSMetadata bsItemMetadata;
};

struct BackupSetItemView {
std::string entryPath;
std::string serialId;
std::string tag;
};


class BackupSetList {
public:
friend class BackupSetListState;

friend class BackupSetListFilterState;
BackupSetList() {};
BackupSetList(const char *backupSetListRoot);
static std::unique_ptr<BackupSetList> currentBackupSetList;

void sort(bool sortAscending = false);
static bool getSortAscending() { return sortAscending;};
std::string at(int i);
void add(std::string backupSet);
std::string getSerialIdAt(int i);
std::string getStretchedSerialIdAt(int i);
std::string getTagAt(int i);
void setTagBSVAt(int i, const std::string & tag);
void setTagBSAt(int i, const std::string & tag);
void add(std::string entryPath,std::string serialId,std::string tag);

int getSizeView() { return this->entriesView;};
int getSize() { return this->entries;};

void filter();
void filter(BSMetadata filterDef);
void resetTagRange();
BSMetadataValues *getBSMetadataValues() {return &bsMetadataValues; };

static const std::string ROOT_BS;
static std::string getBackupSetSubPath() { return backupSetSubPath; }
static std::string getBackupSetEntry() { return backupSetEntry; }
static std::string getBackupSetSubPath() { return backupSetSubPath; };
static std::string getBackupSetPath() { return currentBackupSetList->backupSetListRoot+backupSetSubPath; };
static std::string getBackupSetEntry() { return backupSetEntry; };
static std::string getBackupSetSubPath(int i);
static void setBackupSetEntry(int i);
static void setBackupSetSubPath();
static void initBackupSetList();
static void setBackupSetSubPathToRoot() { backupSetSubPath = "/"; }
static void setBackupSetToRoot() { setBackupSetEntry(0); setBackupSetSubPathToRoot();}
static void saveBackupSetSubPath() { savedBackupSetSubPath = backupSetSubPath; }
static void restoreBackupSetSubPath() { backupSetSubPath = savedBackupSetSubPath; }

static bool getIsInitializationRequired() { return isInitializationRequired; }
static void setIsInitializationRequired(bool isInitializationRequired_) {
BackupSetList::isInitializationRequired = isInitializationRequired_;
}

private:
static bool sortAscending;
std::vector<std::string> backupSets;
std::vector<BackupSetItemView> backupSetsView;
std::vector<BackupSetItem> backupSets;
std::vector<std::string> serialIds;
std::vector<std::string> tags;
std::vector<int> v2b;
BSMetadataValues bsMetadataValues;
int entriesView;
int entries;
std::string backupSetListRoot;
static std::string backupSetSubPath;
static std::string backupSetEntry;
static std::string savedBackupSetSubPath;
inline static bool isInitializationRequired = false;

};


55 changes: 48 additions & 7 deletions include/Metadata.h
Original file line number Diff line number Diff line change
@@ -1,30 +1,71 @@
#pragma once

#include <BackupSetList.h>
#include <jansson.h>
#include <utils/StringUtils.h>
//#include <utils/StringUtils.h>
#include <savemng.h>
#include <string>

class Metadata {
public:
Metadata(uint32_t high, uint32_t low, uint8_t s) : highID(high),
lowID(low),
slot(s),
path (getDynamicBackupPath(highID, lowID, slot).append("/savemiiMeta.json")) {
}
path (getDynamicBackupPath(highID, lowID, slot).append("/savemiiMeta.json")),
Date({}),
storage({}),
serialId(this->unknownSerialId),
tag({}) { }

Metadata(uint32_t high, uint32_t low, uint8_t s, std::string datetime) : highID(high),
lowID(low),
slot(s),
path (getBatchBackupPath(highID, lowID, slot, datetime).append("/savemiiMeta.json")) {
}
path (getBatchBackupPath(highID, lowID, slot, datetime).append("/savemiiMeta.json")),
Date({}),
storage({}),
serialId(this->unknownSerialId),
tag({}) { }

// guess date from batchBackupRoot, to infer a savemiiMeta.json for <1.6.4 batchBackups
Metadata(const std::string & path) : storage({}),
serialId(this->unknownSerialId),
tag({}) {
Date = path.substr(path.length()-17,17);
if (Date.substr(0,2) != "20")
Date="";
this->path = path + ("/savemiiMeta.json");
}

Metadata(const std::string & datetime, const std::string & storage, const std::string & serialId,const std::string & tag ) :
Date(datetime),
storage(storage),
serialId(serialId),
tag(tag) {
path = getBatchBackupPathRoot(datetime)+"/savemiiMeta.json";
}


bool read();
bool write();
std::string simpleFormat();
std::string get();
bool set(const std::string &date,bool isUSB);
static std::string serialId;
static std::string thisConsoleSerialId;
static std::string unknownSerialId;
std::string getDate() { return Date;};
std::string getTag() { return tag;};
void setTag(std::string tag_) { this->tag = tag_;};
std::string getSerialId() { return serialId;};

private:
uint32_t highID;
uint32_t lowID;
uint8_t slot;
std::string path;
};

std::string Date;
std::string storage;
std::string serialId;
std::string tag;
};

Loading

0 comments on commit d6a5424

Please sign in to comment.