mirror of
https://github.com/risingPhil/PokeMe64.git
synced 2026-03-23 19:04:24 -05:00
Merged feature/backup cartridge save to flashcart sd Summary: * Add menu options to backup/restore a save from a pokémon gen I/II cartridge to the N64 flashcarts' SD card. This is only compatible with 64Drive, Everdrive64, ED64Plus and SummerCart64! * Add menu option to wipe a save from a cartridge * Add menu option to reset the in-game clock of gen II cartridges. This will let the game prompt to update the clock on the next time you try to load the save file. Before it was quite hard to reset the game clock without starting a new save. Especially for crystal you had to calculate some kind of password to make it work. Not anymore. PokeMe64 now makes this easy! Commits: * Write a hello world of sorts for writing to SD card. This just writes a file sd://helloworld.txt to the sd card. It will form the basis for implementing save backup * Implement save file backup functionality. It works! But it needs some UI work (progress bar or something), because it takes > 5 seconds * Add ProgressBarWidget and SceneWithProgressBar * Add DataCopyScene and implement backup/restore with progress indication properly Added a new DataCopyScene which takes care of displaying a progress bar while we're backup'ing or restoring data. I also implemented cartridge Rom and Save backup to (micro)SD card and Save restore from (micro)SD card to the cartridge. And it works! I verified it with my Pokémon Blue cartridge: I can back up its save, play the game, release almost all pokémon, go to a different location and save again and then restore the previous save using PokeMe64 Rom backup also works: I can play the resulting rom in VisualBoyAdvance without any issue. I can also use the save that I backed up in VisualBoyAdvance. So right now, you can take an emulator save/pkhex save and transfer it to an actual (original) pokémon cartridge and it will work! However, it's not ready for release yet for a few reasons: - It will currently always output to sd:/gb_out.sav and sd:/rom.gb. I want it to output to sd:/<cartridgetitle>_<trainername>.sav and sd:/<cartridgetitle_<trainername>.gb instead. In fact I want PokeMe64 to add numbers to the save file in case one already exists with that name. - libdragon currently doesn't have the functionality to create directories. I wish PokeMe64 to backup to a directory called PokeMe64, even if the directory doesn't exist yet. - I want a file selector so you can select which save file to restore. This way you could have multiple saves. In theory that would also allow you to transfer a pokémon red save to a pokémon blue cartridge and so on. - I want to have a wipe save option - I need to safeguard PokeMe64 for corrupted save data. Right now, for reproduction carts PokeMe64 crashes while trying to decode the trainerName. This is because the actual save file is not accessible on a reproduction cart. If I'm going to allow people to restore random saves (even from different versions alltogether), I need PokeMe64 to be robust enough for people to be able to wipe the save file or restore a different one. (in order for them to be able to correct their mistake without having to take out the battery). In order to be robust enough, I should make sure to check the CRC checksum of the save file before going to the main menu. And if it doesn't match, I should offer a reduced menu to the user. So... no release of this feature until I resolve all the topics above. But man, it's so satisfying to see it work in the current form already! The functionality itself just works on first try! * Add FileBrowserWidget and rework TestScene to use it for testing purposes * Add SelectFileScene and connect everything together. * Generate unique save file names <gameName>_<trainerName>_<uniquenumber>.sav (the last part is optional) This allows you to backup your save multiple times without overwriting the pre-existing ones. * Add option to wipe save and validate save CRC before continuing to main menu If an invalid/corrupt save is found, the user will only be offered the backup/restore options The wipe save option exists in case the user messes up and restores a save that makes the gameboy crash on bootup. (I don't know if that can actually happen, but just in case) After all: the backup/restore options allow for restoring saves of different games than the cartridge you're restoring to. (a red save to a blue cartridge, ...) Therefore the user could also -accidentally- restore a gold save to a blue cartridge (for example). So yeah, that option is only there to fix theoretic accidents without the user having to take out the battery. * Add "Reset clock" function so you can easily reconfigure your game clock in gen 2 There's no straightforward in gen 2 to reconfigure the in-game clock. There's an arcane key combination that's the worst on Pokémon Crystal and requires you to calculate some kind of password. Now PokeMe64 makes it easy: the "Reset Clock" function sets a flag that will let the game prompt you in the main menu to reconfigure the date/time again. * Update README.md * Move Reset Clock option to the main menu * Some usability tweaks of the SelectFileScene - Add title - Add scroll arrows - Make it possible to go back to the previous scene - Increase PokeMe64 version to 0.2 * Ask confirmation before wiping the save
156 lines
4.6 KiB
C++
156 lines
4.6 KiB
C++
#ifndef SDCARDFILEBROWSERWIDGET_H
|
|
#define SDCARDFILEBROWSERWIDGET_H
|
|
|
|
#include "core/Sprite.h"
|
|
#include "core/RDPQGraphics.h"
|
|
#include "widget/IWidget.h"
|
|
#include "widget/VerticalList.h"
|
|
#include "widget/MenuItemWidget.h"
|
|
#include "widget/ImageWidget.h"
|
|
#include "widget/IScrollWindowListener.h"
|
|
|
|
#include <vector>
|
|
|
|
typedef struct FileBrowserWidgetStyle
|
|
{
|
|
VerticalListStyle listStyle;
|
|
MenuItemStyle itemStyle;
|
|
ImageWidgetStyle scrollArrowUpStyle;
|
|
ImageWidgetStyle scrollArrowDownStyle;
|
|
} FileBrowserWidgetStyle;
|
|
|
|
typedef struct FileBrowserWidgetStatus
|
|
{
|
|
std::vector<MenuItemWidget*>& itemList;
|
|
int err;
|
|
} FileBrowserWidgetStatus;
|
|
|
|
/**
|
|
* @brief This widget allows you to browse the SD card filesystem and
|
|
* select a file
|
|
*
|
|
*/
|
|
class FileBrowserWidget : public IWidget, public IScrollWindowListener
|
|
{
|
|
public:
|
|
FileBrowserWidget(AnimationManager& animManager);
|
|
virtual ~FileBrowserWidget();
|
|
|
|
/**
|
|
* @brief Returns whether the widget is currently focused
|
|
*/
|
|
bool isFocused() const override;
|
|
|
|
/**
|
|
* @brief Sets whether the widget is currently focused
|
|
*
|
|
*/
|
|
void setFocused(bool isFocused) override;
|
|
|
|
/**
|
|
* @brief Returns whether the widget is currently visible
|
|
*/
|
|
bool isVisible() const override;
|
|
|
|
/**
|
|
* @brief Changes the visibility of the widget
|
|
*/
|
|
void setVisible(bool visible) override;
|
|
|
|
/**
|
|
* @brief Returns the current (relative) bounds of the widget
|
|
*/
|
|
Rectangle getBounds() const override;
|
|
|
|
/**
|
|
* @brief Changes the current (relative) bounds of the widget
|
|
*/
|
|
void setBounds(const Rectangle& bounds) override;
|
|
|
|
/**
|
|
* @brief Returns the size (width/height) of the widget
|
|
*/
|
|
Dimensions getSize() const override;
|
|
|
|
/**
|
|
* @brief Sets the style of this widget
|
|
*/
|
|
void setStyle(const FileBrowserWidgetStyle& style);
|
|
|
|
/**
|
|
* @brief Handles user input
|
|
*
|
|
* For button presses, it is advised to track button release situations instead of
|
|
* button presses for executing an action. Otherwise the key press might be handled again immediately
|
|
* in the next scene/widget because the user wouldn't have had the time to actually release the key.
|
|
*/
|
|
bool handleUserInput(const joypad_inputs_t& userInput) override;
|
|
|
|
/**
|
|
* @brief Renders the widget
|
|
*
|
|
* @param gfx The graphics instance that must be used to render the widget
|
|
* @param parentBounds The bounds of the parent widget or scene. You must add the x,y offset of your own bounds
|
|
* to the parentBounds to get the absolute bounds for rendering.
|
|
*
|
|
* Getting the parentBounds as an argument of this function was done because a parent widget may be
|
|
* animated or change positions independent of the child widget. But when the parent widget moves, the child must as well!
|
|
*/
|
|
void render(RDPQGraphics& gfx, const Rectangle& parentBounds) override;
|
|
|
|
const FileBrowserWidgetStatus& getStatus() const;
|
|
|
|
/**
|
|
* @brief Retrieves the currently set path
|
|
*/
|
|
const char* getPath() const;
|
|
/**
|
|
* @brief Sets the current path of the FileBrowserWidget
|
|
*/
|
|
void setPath(const char* path);
|
|
|
|
/**
|
|
* @brief Internal callback function for when you press A on a directory
|
|
*/
|
|
void onConfirmDirectory(const char* path);
|
|
|
|
/**
|
|
* @brief Internal callback function for when you press A on a file
|
|
*/
|
|
void onConfirmFile(const char* path);
|
|
|
|
void setItemConfirmedCallback(void (*onItemConfirmed)(void*, const char*), void* context);
|
|
|
|
/**
|
|
* @brief Sets a file extension filter. The files that have such an extension will be shown,
|
|
* whereas non-matching files WON'T be shown
|
|
*/
|
|
void setFileExtensionToFilter(const char* fileExtensionFilter);
|
|
|
|
void onScrollWindowChanged(const ScrollWindowUpdate& update) override;
|
|
protected:
|
|
private:
|
|
void clearList();
|
|
void loadDirectoryItems();
|
|
bool goToParentDirectory();
|
|
|
|
std::vector<char*> duplicatedDirEntNameList_;
|
|
// we are responsible for deleting the ItemMenuWidget instances
|
|
// so we need to keep track of them.
|
|
std::vector<MenuItemWidget*> itemWidgetList_;
|
|
VerticalList listWidget_;
|
|
ImageWidget scrollArrowUp_;
|
|
ImageWidget scrollArrowDown_;
|
|
FileBrowserWidgetStyle style_;
|
|
FileBrowserWidgetStatus status_;
|
|
Rectangle bounds_;
|
|
char pathBuffer_[4096];
|
|
void (*onItemConfirmedCallback_)(void*, const char*);
|
|
void* onItemConfirmedCallbackContext_;
|
|
const char* fileExtensionFilter_;
|
|
bool focused_;
|
|
bool visible_;
|
|
bool bButtonPressed_;
|
|
};
|
|
|
|
#endif |