Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions librecomp/include/librecomp/game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace recomp {
Sram,
Flashram,
AllowAll, // Allows all save types to work and reports eeprom size as 16kbit.
Custom, // Custom save type for recomp with a configurable size.
};

struct GameEntry {
Expand All @@ -25,6 +26,7 @@ namespace recomp {
std::string mod_game_id;
std::span<const char> cache_data;
SaveType save_type = SaveType::None;
uint32_t custom_save_size = 0;
bool is_enabled;

gpr entrypoint_address;
Expand Down Expand Up @@ -99,6 +101,7 @@ namespace recomp {
bool eeprom_allowed();
bool sram_allowed();
bool flashram_allowed();
bool custom_saving_allowed();

void start_game(const std::u8string& game_id);
std::u8string current_game_id();
Expand Down
62 changes: 59 additions & 3 deletions librecomp/src/pi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,12 @@ void save_clear(uint32_t start, uint32_t size, char value) {
save_context.write_sempahore.signal();
}

size_t get_save_size(recomp::SaveType save_type) {
size_t get_save_size(recomp::SaveType save_type, uint32_t custom_save_size) {
switch (save_type) {
case recomp::SaveType::AllowAll:
return std::max(custom_save_size, 0x20000U);
case recomp::SaveType::Custom:
return custom_save_size;
case recomp::SaveType::Flashram:
return 0x20000;
case recomp::SaveType::Sram:
Expand All @@ -203,13 +206,38 @@ size_t get_save_size(recomp::SaveType save_type) {
return 0;
}

void ultramodern::init_saving(RDRAM_ARG1) {
void ultramodern::init_saving(RDRAM_ARG uint32_t custom_save_size) {
std::filesystem::path save_file_path = get_save_file_path();

// Ensure the save file directory exists.
std::filesystem::create_directories(save_file_path.parent_path());

save_context.save_buffer.resize(get_save_size(recomp::get_save_type()));
recomp::SaveType save_type = recomp::get_save_type();
if (save_type == recomp::SaveType::Custom) {
if (custom_save_size == 0) {
ultramodern::error_handling::message_box(
"The current game's GameEntry uses the \"Custom\" save type, but\n"
"the custom save size has not been specified.\n"
"\n"
"This can be done by setting \"custom_save_size\" in the\n"
"GameEntry passed to \"recomp::register_game\"."
);
ULTRAMODERN_QUICK_EXIT();
}
}
else if (save_type != recomp::SaveType::AllowAll) {
if (custom_save_size != 0) {
ultramodern::error_handling::message_box(
"The current game's GameEntry \"custom_save_size\" has been set, but\n"
"the current game does not use the \"Custom\" save type.\n"
"\n"
"Only the \"Custom\" save type has a configurable saving size.\n"
);
ULTRAMODERN_QUICK_EXIT();
}
}

save_context.save_buffer.resize(get_save_size(save_type, custom_save_size));

// Read the save file if it exists.
std::ifstream save_file = recomp::open_input_file_with_backup(save_file_path, std::ios_base::binary);
Expand Down Expand Up @@ -361,3 +389,31 @@ extern "C" void osEPiRawStartDma_recomp(RDRAM_ARG recomp_context * ctx) {
);
ULTRAMODERN_QUICK_EXIT();
}

// Custom recomp saving mechanism.

// Called from the recompiled code as `void recomp_save_write(void* rdram_address, u32 offset, u32 count);`
extern "C" void recomp_save_write(uint8_t* rdram, recomp_context* ctx) {
if (!recomp::custom_saving_allowed()) {
ultramodern::error_handling::message_box("Attempted to use custom saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}
int32_t rdram_address = ctx->r4;
uint32_t offset = ctx->r5;
uint32_t count = ctx->r6;

save_write(rdram, rdram_address, offset, count);
}

// Called from the recompiled code as `void recomp_save_read(void* rdram_address, u32 offset, u32 count);`
extern "C" void recomp_save_read(uint8_t* rdram, recomp_context* ctx) {
if (!recomp::custom_saving_allowed()) {
ultramodern::error_handling::message_box("Attempted to use custom saving with other save type");
ULTRAMODERN_QUICK_EXIT();
}
int32_t rdram_address = ctx->r4;
uint32_t offset = ctx->r5;
uint32_t count = ctx->r6;

save_read(rdram, rdram_address, offset, count);
}
8 changes: 7 additions & 1 deletion librecomp/src/recomp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ bool wait_for_game_started(uint8_t* rdram, recomp_context* context) {
recomp::init_heap(rdram, recomp::mod_rdram_start + mod_ram_used);

save_type = game_entry.save_type;
ultramodern::init_saving(rdram);
ultramodern::init_saving(rdram, game_entry.custom_save_size);

try {
game_entry.entrypoint(rdram, context);
Expand Down Expand Up @@ -591,6 +591,12 @@ bool recomp::flashram_allowed() {
save_type == SaveType::AllowAll;
}

bool recomp::custom_saving_allowed() {
return
save_type == SaveType::Custom ||
save_type == SaveType::AllowAll;
}

void recomp::start(
const recomp::Version& version,
ultramodern::renderer::WindowHandle window_handle,
Expand Down
2 changes: 1 addition & 1 deletion ultramodern/include/ultramodern/ultramodern.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ constexpr uint32_t save_size = 1024 * 1024 / 8; // Maximum save size, 1Mbit for

// Initialization.
void preinit(RDRAM_ARG renderer::WindowHandle window_handle);
void init_saving(RDRAM_ARG1);
void init_saving(RDRAM_ARG uint32_t custom_save_size);
void init_events(RDRAM_ARG renderer::WindowHandle window_handle);
void init_timers(RDRAM_ARG1);
void init_thread_cleanup();
Expand Down