Merge pull request #458 from TwilitRealm/feature/autosave

Autosave Feature
This commit is contained in:
TakaRikka
2026-05-02 13:03:29 -07:00
committed by GitHub
12 changed files with 169 additions and 4 deletions
+1
View File
@@ -1429,6 +1429,7 @@ set(DUSK_FILES
src/dusk/globals.cpp
src/dusk/gyro.cpp
src/dusk/gamepad_color.cpp
src/dusk/autosave.cpp
src/dusk/io.cpp
src/dusk/layout.cpp
src/dusk/logging.cpp
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#ifndef AUTOSAVE_H
#define AUTOSAVE_H
#include <m_Do/m_Do_MemCardRWmng.h>
#include <m_Do/m_Do_MemCard.h>
void noAutoSave();
void triggerAutoSave();
void updateAutoSave();
void enterAutoSave();
void autoSaving();
void waitingForWrite();
void endAutoSave();
#endif
+1
View File
@@ -81,6 +81,7 @@ struct UserSettings {
ConfigVar<bool> instantSaves;
ConfigVar<bool> instantText;
ConfigVar<bool> sunsSong;
ConfigVar<bool> autoSave;
// Preferences
ConfigVar<bool> enableMirrorMode;
+11
View File
@@ -17,6 +17,11 @@
#include <cstdio>
#include <cstring>
#if TARGET_PC
#include <f_ap/f_ap_game.h>
#include <dusk/autosave.h>
#endif
char* daDoor20_c::getStopBmdName() {
switch (door_param2_c::getKind(this)) {
case 3:
@@ -196,6 +201,7 @@ void daDoor20_c::setEventPrm() {
} else {
roomNo = FRoomNo;
}
if (dComIfGp_roomControl_checkStatusFlag(roomNo, 1)) {
if (door_param2_c::getKind(this) == 9) {
if (daPy_py_c::checkNowWolf()) {
@@ -564,6 +570,11 @@ int daDoor20_c::openEnd(int param_1) {
openEnd_1();
break;
}
#if TARGET_PC
triggerAutoSave();
#endif
return 1;
}
+19
View File
@@ -41,6 +41,7 @@
#if TARGET_PC
#include "dusk/memory.h"
#include <dusk/autosave.h>
#endif
#if DEBUG
@@ -700,6 +701,10 @@ static u8 lbl_8074CAE4;
static u32 l_sceneChangeStartTick;
#endif
#if TARGET_PC
static BOOL autoSaved;
#endif
static int dScnPly_Execute(dScnPly_c* i_this) {
#if DEBUG
fapGm_HIO_c::startCpuTimer();
@@ -742,6 +747,15 @@ static int dScnPly_Execute(dScnPly_c* i_this) {
}
}
#if TARGET_PC
if (!dComIfGp_event_runCheck() && !fopOvlpM_IsPeek() && !dComIfG_resetToOpening(i_this) &&
!dComIfGp_isEnableNextStage() && autoSaved == FALSE)
{
triggerAutoSave();
autoSaved = TRUE;
}
#endif
dKy_itudemo_se();
#if DEBUG
@@ -1593,6 +1607,11 @@ static int dScnPly_Create(scene_class* i_this) {
dScnPly_c* a_this = (dScnPly_c*)i_this;
int phase_state = dComLbG_PhaseHandler(&a_this->field_0x1c4, l_method, a_this);
#if TARGET_PC
autoSaved = FALSE;
#endif
return phase_state;
}
+8
View File
@@ -27,7 +27,11 @@
#include "lingcod/lingcod.h"
#endif
#if TARGET_PC
#include "dusk/settings.h"
#include <f_ap/f_ap_game.h>
#include <dusk/autosave.h>
#endif
static u8 dSv_item_rename(u8 i_itemNo) {
switch (i_itemNo) {
@@ -345,6 +349,10 @@ void dSv_player_item_c::setItem(int i_slotNo, u8 i_itemNo) {
dComIfGp_setSelectItem(i);
}
}
#if TARGET_PC
triggerAutoSave();
#endif
}
u8 dSv_player_item_c::getItem(int i_slotNo, bool i_checkCombo) const {
+88
View File
@@ -0,0 +1,88 @@
#include "dusk/autosave.h"
#include "imgui/ImGuiConsole.hpp"
u8 mSaveBuffer[QUEST_LOG_SIZE * 3];
u8 mAutoSaveProc = 0;
int autoSaveWriteState = 0;
typedef void (*AutoSaveFuncs)();
static AutoSaveFuncs AutoSaveFuncsProc[] = {
noAutoSave, enterAutoSave, autoSaving, waitingForWrite, endAutoSave,
};
void noAutoSave() {}
void triggerAutoSave() {
if (dusk::getSettings().game.autoSave && mAutoSaveProc == 0 &&
strcmp(dComIfGp_getStartStageName(), "F_SP102") != 0)
{
mAutoSaveProc = 1;
}
}
void updateAutoSave() {
(AutoSaveFuncsProc[mAutoSaveProc])();
}
void writeAutoSave() {
int stageNo = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo());
dComIfGs_putSave(stageNo);
dComIfGs_setMemoryToCard(mSaveBuffer, dComIfGs_getDataNum());
mDoMemCdRWm_SetCheckSumGameData(mSaveBuffer, dComIfGs_getDataNum());
u8* save = mSaveBuffer;
for (int i = 0; i < 3; i++) {
mDoMemCdRWm_TestCheckSumGameData(save);
save += QUEST_LOG_SIZE;
}
g_mDoMemCd_control.save(mSaveBuffer, sizeof(mSaveBuffer), 0);
}
void autoSaving() {
int cardState = g_mDoMemCd_control.LoadSync(mSaveBuffer, sizeof(mSaveBuffer), 0);
if (cardState != 0) {
if (cardState == 2) {
mAutoSaveProc = 1;
} else if (cardState == 1) {
writeAutoSave();
mAutoSaveProc = 3;
}
}
}
void enterAutoSave() {
u32 cardStatus = g_mDoMemCd_control.getStatus(0);
if (cardStatus != 14) {
switch (cardStatus) {
case 2:
g_mDoMemCd_control.load();
mAutoSaveProc = 2;
break;
case 3:
case 4:
case 5:
break;
default:
mAutoSaveProc = 0;
break;
}
}
}
void waitingForWrite() {
autoSaveWriteState = g_mDoMemCd_control.SaveSync();
if (autoSaveWriteState == 2) {
mAutoSaveProc = 0;
} else if (autoSaveWriteState == 1) {
mAutoSaveProc = 4;
}
}
void endAutoSave() {
dusk::g_imguiConsole.AddToast("Saving...", 2.0f);
mAutoSaveProc = 0;
}
+1 -1
View File
@@ -365,7 +365,7 @@ namespace dusk {
}
if (dusk::IsGameLaunched && !m_isLaunchInitialized) {
m_toasts.emplace_back(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ?
AddToast(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ?
"Tap to toggle menu"s :
"Press F1 to toggle menu"s,
4.f);
+1
View File
@@ -44,6 +44,7 @@ static void ApplyPresetDusk() {
s.game.enableFrameInterpolation.setValue(true);
s.game.sunsSong.setValue(true);
s.game.bloomMode.setValue(BloomMode::Dusk);
s.game.autoSave.setValue(true);
}
// =========================================================================
+11
View File
@@ -121,6 +121,17 @@ namespace dusk {
ImGui::SetTooltip("Tears of Light dropped by Shadow Insects pop out faster like the HD version.");
}
config::ImGuiCheckbox("Autosave", getSettings().game.autoSave);
const bool autoSaveHovered = ImGui::IsItemHovered();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.72f, 0.2f, 1.0f));
ImGui::TextUnformatted("[EXPERIMENTAL]");
ImGui::PopStyleColor();
if (autoSaveHovered || ImGui::IsItemHovered()) {
ImGui::SetTooltip("Autosaves the game when going to a new area,\n"
"opening a dungeon door, or getting a new item.");
}
config::ImGuiCheckbox("Instant Saves", getSettings().game.instantSaves);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Skip the delay when writing to the Memory Card.");
+4 -2
View File
@@ -32,7 +32,7 @@ UserSettings g_userSettings = {
.disableRupeeCutscenes {"game.disableRupeeCutscenes", false},
.noSwordRecoil {"game.noSwordRecoil", false},
.damageMultiplier {"game.damageMultiplier", 1},
.noHeartDrops{"game.noHeartDrops", false},
.noHeartDrops {"game.noHeartDrops", false},
.instantDeath {"game.instantDeath", false},
.fastClimbing {"game.fastClimbing", false},
.noMissClimbing {"game.noMissClimbing", false},
@@ -41,6 +41,7 @@ UserSettings g_userSettings = {
.instantSaves {"game.instantSaves", false},
.instantText {"game.instantText", false},
.sunsSong {"game.sunsSong", false},
.autoSave {"game.autoSave", false},
// Preferences
.enableMirrorMode {"game.enableMirrorMode", false},
@@ -53,7 +54,7 @@ UserSettings g_userSettings = {
.bloomMode {"game.bloomMode", BloomMode::Classic},
.bloomMultiplier {"game.bloomMultiplier", 1.0f},
.disableWaterRefraction {"game.disableWaterRefraction", false},
.enableFrameInterpolation = {"game.enableFrameInterpolation", false},
.enableFrameInterpolation {"game.enableFrameInterpolation", false},
.internalResolutionScale {"game.internalResolutionScale", 0},
.shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1},
.enableDepthOfField {"game.enableDepthOfField", true},
@@ -154,6 +155,7 @@ void registerSettings() {
Register(g_userSettings.game.instantSaves);
Register(g_userSettings.game.instantText);
Register(g_userSettings.game.sunsSong);
Register(g_userSettings.game.autoSave);
Register(g_userSettings.game.enableMirrorMode);
Register(g_userSettings.game.invertCameraXAxis);
Register(g_userSettings.game.invertCameraYAxis);
+7 -1
View File
@@ -23,8 +23,12 @@
#include "f_op/f_op_scene_mng.h"
#include "m_Do/m_Do_graphic.h"
#include "m_Do/m_Do_main.h"
#if TARGET_PC
#include "tracy/Tracy.hpp"
#include <dusk/gamepad_color.h>
#include <dusk/autosave.h>
#endif
fapGm_HIO_c::fapGm_HIO_c() {
mUsingHostIO = true;
@@ -737,7 +741,8 @@ static void fapGm_AfterRecord() {
static void duskExecute() {
handleGamepadColor();
updateAutoSave();
if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) {
if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) {
dynamic_cast<daAlink_c*>(link)->handleWolfHowl();
@@ -815,6 +820,7 @@ void fapGm_Execute() {
#else
fpcM_ManagementFunc(NULL, fapGm_After);
#endif
cCt_Counter(0);
#ifdef TARGET_PC
dusk::speedrun::onGameFrame();