summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakaRikka <38417346+TakaRikka@users.noreply.github.com>2021-03-08 16:19:42 -0800
committerGitHub <noreply@github.com>2021-03-08 19:19:42 -0500
commitda527d65470f2ad7ee8948838ac54b34f85b325a (patch)
tree9f98a7d7ce2dbfb93a02882c6cbbafbf0da40fb8
parentae9ac84cf9c05ff7eb88e609f5e55d707c31e217 (diff)
add saving/loading memory files (#42)HEAD0.3master
* basic memfile saving/loading adds feature to save basic memory state (only dSv_info_c + some positional data) to mem card, and load it back in later * fix respawn position this will probably be unneeded once save injector is rewritten, but works for now * 0.3 * clang-format Co-authored-by: Pheenoh <pheenoh@gmail.com>
-rw-r--r--.github/workflows/clang-format-check.yml11
-rw-r--r--external/misc/clang-format-check.sh14
-rw-r--r--include/gz_flags.h4
-rw-r--r--include/menu.h5
-rw-r--r--include/menus/memfiles_menu.h23
-rw-r--r--include/save_injector.h1
-rw-r--r--include/utils/card.h2
-rw-r--r--src/gz_flags.cpp4
-rw-r--r--src/lib.cpp2
-rw-r--r--src/menu.cpp4
-rw-r--r--src/menus/memfiles_menu.cpp116
-rw-r--r--src/menus/memory_menu.cpp9
-rw-r--r--src/save_injector.cpp5
-rw-r--r--src/utils/card.cpp96
14 files changed, 281 insertions, 15 deletions
diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml
index 1eb63d8..ce8192f 100644
--- a/.github/workflows/clang-format-check.yml
+++ b/.github/workflows/clang-format-check.yml
@@ -8,9 +8,8 @@ jobs:
steps:
- uses: actions/checkout@v2
- - uses: DoozyX/clang-format-lint-action@v0.11
- with:
- source: '.'
- extensions: 'h,cpp'
- clangFormatVersion: 10
- exclude: './external/gcn_c ./external/libtp_c' \ No newline at end of file
+ - name: Install clang-format
+ run: sudo apt-get install clang-format-10
+ - name: Run clang-format-check
+ run: sh external/misc/clang-format-check.sh
+ \ No newline at end of file
diff --git a/external/misc/clang-format-check.sh b/external/misc/clang-format-check.sh
new file mode 100644
index 0000000..7238131
--- /dev/null
+++ b/external/misc/clang-format-check.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+clangFormatTargets=$(find . -type f ! -path './external/*' -type f -regex '.*\.\(cpp\|hpp\|h\|cc\|cxx\)')
+
+for inputFile in $clangFormatTargets
+do
+ clang-format-10 -style=file $inputFile > $inputFile-formatted
+ diff $inputFile $inputFile-formatted
+ if [ $? != 0 ] ; then
+ exit 1
+ else
+ rm $inputFile-formatted
+ fi
+done
diff --git a/include/gz_flags.h b/include/gz_flags.h
index b2cb0e2..410994e 100644
--- a/include/gz_flags.h
+++ b/include/gz_flags.h
@@ -1,10 +1,10 @@
#pragma once
#include "font.h"
#ifdef WII_PLATFORM
-#define MAX_GZ_FLAGS 14
+#define MAX_GZ_FLAGS 15
#endif
#ifdef GCN_PLATFORM
-#define MAX_GZ_FLAGS 13
+#define MAX_GZ_FLAGS 14
#endif
struct GZFlag {
diff --git a/include/menu.h b/include/menu.h
index 0a14370..314ac49 100644
--- a/include/menu.h
+++ b/include/menu.h
@@ -12,7 +12,7 @@
#define MAX_LINE_LENGTH 50
#define MAX_DESCRIPTION_LENGTH 100
-#define MAX_MENU_RENDER_FLAGS 24
+#define MAX_MENU_RENDER_FLAGS 25
#ifdef GCN_PLATFORM
#define SELECTION_BUTTON (Controller::Pad::A)
@@ -48,7 +48,8 @@ enum MenuIndex {
MN_HUNDO_SAVES_INDEX,
MN_POS_SETTINGS_INDEX,
MN_FLAG_LOG_INDEX,
- MN_AD_SAVES_INDEX
+ MN_AD_SAVES_INDEX,
+ MN_MEM_FILES_INDEX
};
struct ListMember {
diff --git a/include/menus/memfiles_menu.h b/include/menus/memfiles_menu.h
new file mode 100644
index 0000000..0965435
--- /dev/null
+++ b/include/menus/memfiles_menu.h
@@ -0,0 +1,23 @@
+#include "menu.h"
+
+#define MEMFILE_SLOT_INDEX 0
+#define MEMFILE_SAVE_INDEX 1
+#define MEMFILE_LOAD_INDEX 2
+
+struct PositionData {
+ Vec3 link;
+ CameraMatrix cam;
+ uint16_t angle;
+};
+
+extern bool set_position_data;
+extern int8_t memfile_load_delay;
+extern PositionData memfile_posdata;
+
+void set_memfile_position();
+
+class MemfilesMenu : public Menu {
+public:
+ MemfilesMenu() : Menu() {}
+ static void render();
+}; \ No newline at end of file
diff --git a/include/save_injector.h b/include/save_injector.h
index 33c45be..4f5951f 100644
--- a/include/save_injector.h
+++ b/include/save_injector.h
@@ -19,6 +19,7 @@ extern PracticeFile practice_file;
namespace SaveInjector {
void inject_save(void* buffer);
+void inject_memfile(void* buffer);
void inject_default_before();
void inject_default_during();
void inject_default_after();
diff --git a/include/utils/card.h b/include/utils/card.h
index b8274de..d2c6df5 100644
--- a/include/utils/card.h
+++ b/include/utils/card.h
@@ -9,6 +9,8 @@ int32_t card_write(CardInfo* card_info, void* data, int32_t size, int32_t offset
int32_t card_read(CardInfo* card_info, void* data, int32_t size, int32_t offset,
int32_t sector_size);
void store_mem_card(Card& card);
+void store_memfile(Card& card);
void load_mem_card(Card& card);
+void load_memfile(Card& card);
void load_gz_card(bool& card_load);
} // namespace Utilities \ No newline at end of file
diff --git a/src/gz_flags.cpp b/src/gz_flags.cpp
index affd847..8203041 100644
--- a/src/gz_flags.cpp
+++ b/src/gz_flags.cpp
@@ -14,6 +14,7 @@
#include "utils/link.h"
#include "utils/loading.h"
#include "flaglog.h"
+#include "menus/memfiles_menu.h"
bool inject_save_flag = false;
@@ -34,7 +35,8 @@ GZFlag GZ_Flags[MAX_GZ_FLAGS] = {
{&g_cursor_color_flag, Utilities::change_cursor_color, Utilities::change_cursor_color},
{&SceneItems[Scene::DISABLE_BG_INDEX].active, Utilities::disable_bg_music,
Utilities::enable_bg_music},
- {&SceneItems[Scene::DISABLE_SFX_INDEX].active, Utilities::disable_sfx, Utilities::enable_sfx}};
+ {&SceneItems[Scene::DISABLE_SFX_INDEX].active, Utilities::disable_sfx, Utilities::enable_sfx},
+ {&set_position_data, set_memfile_position}};
namespace GZFlags {
void apply_active_flags() {
diff --git a/src/lib.cpp b/src/lib.cpp
index fc4952b..c60be21 100644
--- a/src/lib.cpp
+++ b/src/lib.cpp
@@ -119,7 +119,7 @@ void draw() {
setupRendering();
// Consolas.setupRendering();
if (MenuRendering::is_menu_open()) {
- Font::gz_renderChars("tpgz v0.2", sprite_offsets[MENU_INDEX].x + 35.0f, 25.0f, cursor_rgba,
+ Font::gz_renderChars("tpgz v0.3", sprite_offsets[MENU_INDEX].x + 35.0f, 25.0f, cursor_rgba,
g_drop_shadows);
if (gzIconTex.loadCode == TexCode::TEX_OK) {
Draw::draw_rect(0xFFFFFFFF, {sprite_offsets[MENU_INDEX].x, 5.0f}, {30, 30},
diff --git a/src/menu.cpp b/src/menu.cpp
index ad42e95..31ef734 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -18,6 +18,7 @@
#include "menus/tools_menu.h"
#include "menus/warping_menu.h"
#include "menus/ad_saves_menu.h"
+#include "menus/memfiles_menu.h"
typedef void (*menu_render_t)();
@@ -29,7 +30,8 @@ menu_render_t MenuRenderList[MAX_MENU_RENDER_FLAGS] = {
PracticeMenu::render, CheatsMenu::render, SceneMenu::render,
SettingsMenu::render, ToolsMenu::render, PauseMenu::render,
AmountsMenu::render, AnySavesMenu::render, HundoSavesMenu::render,
- PosSettingsMenu::render, FlagLogMenu::render, ADSavesMenu::render};
+ PosSettingsMenu::render, FlagLogMenu::render, ADSavesMenu::render,
+ MemfilesMenu::render};
menu_render_t currentMenu = nullptr;
diff --git a/src/menus/memfiles_menu.cpp b/src/menus/memfiles_menu.cpp
new file mode 100644
index 0000000..e5613d3
--- /dev/null
+++ b/src/menus/memfiles_menu.cpp
@@ -0,0 +1,116 @@
+#include "menus/memfiles_menu.h"
+#include "controller.h"
+#include "gcn_c/include/card.h"
+#include "font.h"
+#include "utils/card.h"
+#include "libtp_c/include/system.h"
+#include "libtp_c/include/tp.h"
+#include "utils/cursor.h"
+#include "utils/lines.h"
+
+#define LINES 3
+#define MAX_SAVE_SLOTS 9
+
+static Cursor cursor = {0, 0};
+bool init_once = false;
+static uint8_t file_no = 1;
+uint8_t save_delay = 0;
+int8_t memfile_load_delay = 10;
+bool set_position_data = false;
+bool copy_respawn_data = false;
+char fileBuf[9];
+
+PositionData memfile_posdata;
+Vec3 tmpPos = tp_gameInfo.respawn_position;
+uint16_t tmpAngle = tp_gameInfo.respawn_angle;
+
+Line lines[LINES] = {{"file slot:", MEMFILE_SLOT_INDEX, "Select memfile slot"},
+ {"save", MEMFILE_SAVE_INDEX, "Save memfile to slot", false},
+ {"load", MEMFILE_LOAD_INDEX, "Load memfile from slot", false}};
+
+void set_memfile_position() {
+ // respawn pos gets overwritten by default spawn, so reinject respawn info
+ if (!copy_respawn_data) {
+ tmpPos = tp_gameInfo.respawn_position;
+ tmpAngle = tp_gameInfo.respawn_angle;
+ copy_respawn_data = true;
+ }
+
+ if (tp_fopScnRq.isLoading == 0) {
+ memfile_load_delay--;
+ }
+
+ if (memfile_load_delay == 0) {
+ tp_zelAudio.link_debug_ptr->position = memfile_posdata.link;
+ tp_matrixInfo.matrix_info->target = memfile_posdata.cam.target;
+ tp_matrixInfo.matrix_info->pos = memfile_posdata.cam.pos;
+ tp_zelAudio.link_debug_ptr->facing = memfile_posdata.angle;
+ tp_gameInfo.respawn_position = tmpPos;
+ tp_gameInfo.respawn_angle = tmpAngle;
+ set_position_data = false;
+ copy_respawn_data = false;
+ memfile_load_delay = 10;
+ }
+}
+
+void MemfilesMenu::render() {
+ if (button_is_pressed(BACK_BUTTON) && save_delay == 0) {
+ init_once = false;
+ MenuRendering::set_menu(MN_MEMORY_INDEX);
+ return;
+ }
+
+ if (!init_once) {
+ current_input = 0;
+ init_once = true;
+ }
+
+ if (save_delay > 0) {
+ save_delay--;
+ }
+
+ switch (cursor.y) {
+ case MEMFILE_SLOT_INDEX: {
+ if (button_is_pressed(Controller::DPAD_LEFT) && file_no > 1) {
+ file_no--;
+ } else if (button_is_pressed(Controller::DPAD_RIGHT) && file_no < MAX_SAVE_SLOTS) {
+ file_no++;
+ }
+ break;
+ }
+ }
+
+ if (current_input == SELECTION_BUTTON && a_held == false) {
+ switch (cursor.y) {
+ case MEMFILE_SAVE_INDEX: {
+ static Card card;
+ tp_sprintf(fileBuf, "tpgz_s%d", file_no);
+ card.file_name = fileBuf;
+ card.sector_size = SECTOR_SIZE;
+ tp_sprintf(card.file_name_buffer, card.file_name);
+ card.card_result = CARDProbeEx(0, nullptr, &card.sector_size);
+ if (card.card_result == Ready) {
+ Utilities::store_memfile(card);
+ }
+ save_delay = 20;
+ break;
+ }
+ case MEMFILE_LOAD_INDEX: {
+ static Card card;
+ tp_sprintf(fileBuf, "tpgz_s%d", file_no);
+ card.file_name = fileBuf;
+ card.sector_size = SECTOR_SIZE;
+ tp_sprintf(card.file_name_buffer, card.file_name);
+ card.card_result = CARDProbeEx(0, NULL, &card.sector_size);
+ Utilities::load_memfile(card);
+ set_position_data = true;
+ break;
+ }
+ }
+ }
+
+ tp_sprintf(lines[MEMFILE_SLOT_INDEX].value, " <%d>", file_no);
+
+ Utilities::move_cursor(cursor, LINES, 0, false, false, false, true);
+ Utilities::render_lines(lines, cursor.y, LINES);
+};
diff --git a/src/menus/memory_menu.cpp b/src/menus/memory_menu.cpp
index 3e294e3..51d993f 100644
--- a/src/menus/memory_menu.cpp
+++ b/src/menus/memory_menu.cpp
@@ -5,13 +5,14 @@
#include "utils/cursor.h"
#include "utils/lines.h"
-#define LINES 2
+#define LINES 3
static Cursor cursor = {0, 0};
bool init_once = false;
Line lines[LINES] = {{"watches", 0, "Manage memory watches", false},
- {"memory editor", 1, "View/edit memory", false}};
+ {"memory editor", 1, "View/edit memory", false},
+ {"mem files", 2, "Save/Load memory files", false}};
void MemoryMenu::render() {
if (button_is_pressed(BACK_BUTTON)) {
@@ -35,6 +36,10 @@ void MemoryMenu::render() {
MenuRendering::set_menu(MN_MEMORY_EDITOR_INDEX);
return;
}
+ case 2: {
+ MenuRendering::set_menu(MN_MEM_FILES_INDEX);
+ return;
+ }
}
}
diff --git a/src/save_injector.cpp b/src/save_injector.cpp
index b124056..ff23c0a 100644
--- a/src/save_injector.cpp
+++ b/src/save_injector.cpp
@@ -13,6 +13,11 @@ void inject_save(void* buffer) {
tp_getSave(&tp_gameInfo, tp_gameInfo.dungeon_temp_flags.mStageNum);
};
+void inject_memfile(void* buffer) {
+ tp_memcpy((void*)&tp_gameInfo, buffer, 3818);
+ tp_getSave(&tp_gameInfo, tp_gameInfo.dungeon_temp_flags.mStageNum);
+};
+
void inject_default_before() {
tp_gameInfo.spawn_speed = 0.0f;
tp_gameInfo.loading_animation = 13; // instant load
diff --git a/src/utils/card.cpp b/src/utils/card.cpp
index b758e2b..19338a4 100644
--- a/src/utils/card.cpp
+++ b/src/utils/card.cpp
@@ -1,8 +1,13 @@
#include "utils/card.h"
#include "commands.h"
#include "fifo_queue.h"
+#include "utils/loading.h"
#include "libtp_c/include/math.h"
#include "libtp_c/include/system.h"
+#include "menus/practice_menu.h"
+#include "save_injector.h"
+#include "libtp_c/include/tp.h"
+#include "menus/memfiles_menu.h"
#include "saves.h"
namespace Utilities {
@@ -83,6 +88,13 @@ void load_save_layout(GZSaveLayout& save_layout) {
g_font = save_layout.g_font;
}
+void load_position_data(PositionData& pos_data) {
+ memfile_posdata.link = pos_data.link;
+ memfile_posdata.cam.target = pos_data.cam.target;
+ memfile_posdata.cam.pos = pos_data.cam.pos;
+ memfile_posdata.angle = pos_data.angle;
+}
+
void setup_save_file(GZSaveFile& save_file) {
save_file.header.version = GZ_SAVE_VERSION_NUMBER;
save_file.header.entries = GZ_SAVE_ENTRIES_AMNT;
@@ -153,6 +165,21 @@ int32_t read_save_file(CardInfo* card_info, GZSaveFile& save_file, int32_t secto
return result;
}
+int32_t read_memfile(CardInfo* card_info, PositionData& posData, int32_t sector_size) {
+ int32_t result = Ready;
+#define assert_result(stmt) \
+ if ((result = (stmt)) != Ready) { \
+ return result; \
+ }
+
+ assert_result(card_read(card_info, (void*)sTmpBuf, 3818, 0, sector_size));
+
+ assert_result(card_read(card_info, &posData, sizeof(posData), 3819, sector_size));
+
+#undef assert_result
+ return result;
+}
+
void store_mem_card(Card& card) {
#ifndef WII_PLATFORM
GZSaveFile save_file;
@@ -182,6 +209,46 @@ void store_mem_card(Card& card) {
#endif
}
+void store_memfile(Card& card) {
+ PositionData posData;
+ posData.link = tp_zelAudio.link_debug_ptr->position;
+ posData.cam.target = tp_matrixInfo.matrix_info->target;
+ posData.cam.pos = tp_matrixInfo.matrix_info->pos;
+ posData.angle = tp_zelAudio.link_debug_ptr->facing;
+ uint32_t file_size =
+ (uint32_t)(tp_ceil((double)3818 / (double)card.sector_size) * card.sector_size);
+ card.card_result = CARDDelete(0, card.file_name_buffer);
+ card.card_result = CARDCreate(0, card.file_name_buffer, file_size, &card.card_info);
+ if (card.card_result == Ready || card.card_result == Exist) {
+ card.card_result = CARDOpen(0, card.file_name_buffer, &card.card_info);
+ if (card.card_result == Ready) {
+ for (uint8_t i = 0; i < 0x20; i++) {
+ *((tp_gameInfo.overworld_flags.ordon_flags.flags +
+ (tp_gameInfo.dungeon_temp_flags.mStageNum * 0x20)) +
+ i) = tp_gameInfo.temp_flags.flags[i];
+ }
+ tp_gameInfo.player.player_spawn_id = 0;
+ tp_gameInfo.player.player_room_id = tp_gameInfo.last_room_id;
+ tp_strcpy((char*)tp_gameInfo.player.player_stage, (char*)tp_gameInfo.current_stage);
+ card.card_result =
+ Utilities::card_write(&card.card_info, &tp_gameInfo, 3818, 0, card.sector_size);
+
+ card.card_result = Utilities::card_write(&card.card_info, &posData, sizeof(posData),
+ 3819, card.sector_size);
+ if (card.card_result == Ready) {
+ tp_osReport("saved memfile!");
+ FIFOQueue::push("saved memfile!", Queue);
+ } else {
+ tp_osReport("failed to save");
+ char buff[32];
+ tp_sprintf(buff, "failed to save: %d", card.card_result);
+ FIFOQueue::push(buff, Queue);
+ }
+ card.card_result = CARDClose(&card.card_info);
+ }
+ }
+}
+
void load_mem_card(Card& card) {
#ifndef WII_PLATFORM
card.card_result = CARDOpen(0, card.file_name_buffer, &card.card_info);
@@ -205,6 +272,35 @@ void load_mem_card(Card& card) {
#endif
}
+void load_memfile(Card& card) {
+#ifndef WII_PLATFORM
+ card.card_result = CARDOpen(0, card.file_name_buffer, &card.card_info);
+ if (card.card_result == Ready) {
+ PositionData posData;
+ card.card_result = read_memfile(&card.card_info, posData, card.sector_size);
+ if (card.card_result == Ready) {
+ tp_osReport("loaded memfile!");
+ FIFOQueue::push("loaded memfile!", Queue);
+ SaveInjector::inject_default_before();
+ SaveInjector::inject_memfile((void*)sTmpBuf);
+ SaveInjector::inject_default_during();
+ SaveInjector::inject_default_after();
+ load_position_data(posData);
+ inject_save_flag = true;
+ fifo_visible = true;
+ MenuRendering::set_menu(MN_NONE_INDEX);
+
+ } else {
+ tp_osReport("failed to load");
+ char buff[32];
+ tp_sprintf(buff, "failed to load: %d", card.card_result);
+ FIFOQueue::push(buff, Queue);
+ }
+ card.card_result = CARDClose(&card.card_info);
+ }
+#endif
+}
+
void load_gz_card(bool& card_load) {
uint8_t frame_count = TP::get_frame_count();
if (card_load && frame_count > 200) {