From 2a79ad3b723407b1ec4cdee1308ccf5587fcf1c0 Mon Sep 17 00:00:00 2001 From: ChangeSuger Date: Sat, 23 May 2026 16:53:36 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20continue=20game=20function=20update?= =?UTF-8?q?=20-=20=E5=A2=9E=E5=8A=A0=20Enable=5FContinue=20=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E9=85=8D=E7=BD=AE=E7=BB=A7=E7=BB=AD=E6=B8=B8?= =?UTF-8?q?=E6=88=8F=E6=8C=89=E9=92=AE=E6=98=AF=E5=90=A6=E5=90=AF=E7=94=A8?= =?UTF-8?q?=20-=20=E7=BB=A7=E7=BB=AD=E6=B8=B8=E6=88=8F=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E4=BC=9A=E5=9C=A8=E6=B2=A1=E6=9C=89=E8=87=AA=E5=8A=A8=E5=AD=98?= =?UTF-8?q?=E6=A1=A3=E6=97=B6=E7=BD=AE=E7=81=B0=20-=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=AD=98=E6=A1=A3=E7=9A=84=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E7=8E=B0=E5=9C=A8=E4=BC=9A=E5=9C=A8?= =?UTF-8?q?=20end=20=E7=BB=93=E6=9D=9F=E6=97=B6=E5=88=A0=E9=99=A4=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=AD=98=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/webgal/public/game/config.txt | 1 + .../Core/controller/gamePlay/backToTitle.ts | 2 ++ .../controller/gamePlay/startContinueGame.ts | 15 ++-------- .../Core/controller/storage/fastSaveLoad.ts | 10 +++++-- packages/webgal/src/Core/gameScripts/end.ts | 4 +-- packages/webgal/src/UI/Title/Title.tsx | 30 ++++++++++++------- 6 files changed, 33 insertions(+), 29 deletions(-) diff --git a/packages/webgal/public/game/config.txt b/packages/webgal/public/game/config.txt index 972b4e06c..c2c6f05ac 100644 --- a/packages/webgal/public/game/config.txt +++ b/packages/webgal/public/game/config.txt @@ -4,3 +4,4 @@ Title_img:WebGAL_New_Enter_Image.webp; Title_bgm:s_Title.mp3; Game_Logo:WebGalEnter.webp; Enable_Appreciation:true; +Enable_Continue:true; diff --git a/packages/webgal/src/Core/controller/gamePlay/backToTitle.ts b/packages/webgal/src/Core/controller/gamePlay/backToTitle.ts index 7711349f9..80927591f 100644 --- a/packages/webgal/src/Core/controller/gamePlay/backToTitle.ts +++ b/packages/webgal/src/Core/controller/gamePlay/backToTitle.ts @@ -5,9 +5,11 @@ import { stopAuto } from '@/Core/controller/gamePlay/autoPlay'; import { stopFast } from '@/Core/controller/gamePlay/fastSkip'; import { setEbg } from '@/Core/gameScripts/changeBg/setEbg'; import { stageStateManager } from '@/Core/Modules/stage/stageStateManager'; +import { fastSaveGame } from '../storage/fastSaveLoad'; export const backToTitle = () => { if (webgalStore.getState().GUI.showTitle) return; + fastSaveGame(); const dispatch = webgalStore.dispatch; stopAllPerform(); stopAuto(); diff --git a/packages/webgal/src/Core/controller/gamePlay/startContinueGame.ts b/packages/webgal/src/Core/controller/gamePlay/startContinueGame.ts index b61cdd9ec..67ec27c09 100644 --- a/packages/webgal/src/Core/controller/gamePlay/startContinueGame.ts +++ b/packages/webgal/src/Core/controller/gamePlay/startContinueGame.ts @@ -34,20 +34,9 @@ export async function continueGame() { * 重设模糊背景 */ setEbg(stageStateManager.getViewStageState().bgName); - // 当且仅当游戏未开始时使用快速存档 - // 当游戏开始后 使用原来的逻辑 - if ((await hasFastSaveRecord()) && WebGAL.sceneManager.sceneData.currentSentenceId === 0) { + if ((await hasFastSaveRecord())) { + webgalStore.dispatch(setVisibility({ component: 'showTitle', visibility: false })); // 恢复记录 await loadFastSaveGame(); - return; - } - if ( - WebGAL.sceneManager.sceneData.currentSentenceId === 0 && - WebGAL.sceneManager.sceneData.currentScene.sceneName === 'start.txt' - ) { - // 如果游戏没有开始,开始游戏 - nextSentence(); - } else { - restorePerform(); } } diff --git a/packages/webgal/src/Core/controller/storage/fastSaveLoad.ts b/packages/webgal/src/Core/controller/storage/fastSaveLoad.ts index 61c5975cb..b71f178e1 100644 --- a/packages/webgal/src/Core/controller/storage/fastSaveLoad.ts +++ b/packages/webgal/src/Core/controller/storage/fastSaveLoad.ts @@ -22,6 +22,11 @@ export function initKey() { * 用于紧急回避时的数据存储 & 快速保存 */ export async function fastSaveGame() { + const showTitle = webgalStore.getState().GUI.showTitle; + if (showTitle) { + // 如果在标题界面,不进行快速保存 + return; + } const saveData: ISaveData = generateCurrentStageData(-1, false); const newSaveData = cloneDeep(saveData); webgalStore.dispatch(saveActions.setFastSave(newSaveData)); @@ -48,6 +53,7 @@ export async function loadFastSaveGame() { if (!loadFile) { return; } + removeFastSaveGameRecord(); loadGameFromStageData(loadFile); } @@ -56,7 +62,5 @@ export async function loadFastSaveGame() { */ export async function removeFastSaveGameRecord() { webgalStore.dispatch(saveActions.resetFastSave()); - await setStorageAsync(); - // await localforage.setItem(isFastSaveKey, false); - // await localforage.setItem(fastSaveGameKey, null); + await dumpFastSaveToStorage(); } diff --git a/packages/webgal/src/Core/gameScripts/end.ts b/packages/webgal/src/Core/gameScripts/end.ts index b2c041f60..b9d1ebf0d 100644 --- a/packages/webgal/src/Core/gameScripts/end.ts +++ b/packages/webgal/src/Core/gameScripts/end.ts @@ -9,7 +9,7 @@ import { setVisibility } from '@/store/GUIReducer'; import { playBgm } from '@/Core/controller/stage/playBgm'; import { WebGAL } from '@/Core/WebGAL'; import { dumpToStorageFast } from '@/Core/controller/storage/storageController'; -import { saveActions } from '@/store/savesReducer'; +import { removeFastSaveGameRecord } from '../controller/storage/fastSaveLoad'; /** * 结束游戏 @@ -24,7 +24,7 @@ export const end = (sentence: ISentence): IPerform => { setTimeout(() => { WebGAL.sceneManager.resetScene(); }, 5); - dispatch(saveActions.resetFastSave()); + removeFastSaveGameRecord(); dumpToStorageFast(); sceneFetcher(sceneUrl).then((rawScene) => { // 场景写入到运行时 diff --git a/packages/webgal/src/UI/Title/Title.tsx b/packages/webgal/src/UI/Title/Title.tsx index 6caf8c922..281094114 100644 --- a/packages/webgal/src/UI/Title/Title.tsx +++ b/packages/webgal/src/UI/Title/Title.tsx @@ -16,6 +16,7 @@ import styles from './title.module.scss'; /** 标题页 */ export default function Title() { const userDataState = useSelector((state: RootState) => state.userData); + const userSaveData = useSelector((state: RootState) => state.saveData); const GUIState = useSelector((state: RootState) => state.GUI); const dispatch = useDispatch(); const fullScreen = userDataState.optionData.fullScreen; @@ -24,6 +25,8 @@ export default function Title() { const t = useTrans('title.'); const tCommon = useTrans('common.'); const { playSeEnter, playSeClick } = useSoundEffect(); + const fastSaveData = userSaveData.quickSaveData; + const enableContinue = userDataState.globalGameVar.Enable_Continue !== false; const applyStyle = useApplyStyle('title'); useConfigData(); // 监听基础ConfigData变化 @@ -72,17 +75,22 @@ export default function Title() { > {renderButtonText(t('start.title'))} -
{ - playSeClick(); - dispatch(setVisibility({ component: 'showTitle', visibility: false })); - continueGame(); - }} - onMouseEnter={playSeEnter} - > - {renderButtonText(t('continue.title'))} -
+ {enableContinue && ( +
{ + if (fastSaveData) { + playSeClick(); + continueGame(); + } + }} + onMouseEnter={fastSaveData ? playSeEnter : undefined} + > + {renderButtonText(t('continue.title'))} +
+ )}
{ From 79f53f3a1cefa7c67c1f0cbca4b467aeaef7a469 Mon Sep 17 00:00:00 2001 From: Mahiru Date: Thu, 28 May 2026 00:15:03 +0800 Subject: [PATCH 2/2] fix: throttle continue autosave --- .../Core/controller/storage/fastSaveLoad.ts | 23 ++++++++++++++----- packages/webgal/src/Core/initializeScript.ts | 6 ++++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/webgal/src/Core/controller/storage/fastSaveLoad.ts b/packages/webgal/src/Core/controller/storage/fastSaveLoad.ts index b71f178e1..b666b6ed6 100644 --- a/packages/webgal/src/Core/controller/storage/fastSaveLoad.ts +++ b/packages/webgal/src/Core/controller/storage/fastSaveLoad.ts @@ -1,9 +1,10 @@ import { webgalStore } from '@/store/store'; -import { getStorageAsync, setStorageAsync } from '@/Core/controller/storage/storageController'; +import { getStorageAsync } from '@/Core/controller/storage/storageController'; import { ISaveData } from '@/store/userDataInterface'; import { loadGameFromStageData } from '@/Core/controller/storage/loadGame'; import { generateCurrentStageData } from '@/Core/controller/storage/saveGame'; import cloneDeep from 'lodash/cloneDeep'; +import throttle from 'lodash/throttle'; import { WebGAL } from '@/Core/WebGAL'; import { saveActions } from '@/store/savesReducer'; import { dumpFastSaveToStorage, getFastSaveFromStorage } from '@/Core/controller/storage/savesController'; @@ -11,6 +12,7 @@ import { dumpFastSaveToStorage, getFastSaveFromStorage } from '@/Core/controller export let fastSaveGameKey = ''; export let isFastSaveKey = ''; let lock = true; +let dumpFastSaveTask = Promise.resolve(); export function initKey() { lock = false; @@ -18,21 +20,30 @@ export function initKey() { isFastSaveKey = `FastSaveActive-${WebGAL.gameName}-${WebGAL.gameKey}`; } +function dumpFastSaveToStorageSerial() { + dumpFastSaveTask = dumpFastSaveTask.catch(() => {}).then(dumpFastSaveToStorage); + return dumpFastSaveTask; +} + /** * 用于紧急回避时的数据存储 & 快速保存 */ export async function fastSaveGame() { const showTitle = webgalStore.getState().GUI.showTitle; - if (showTitle) { - // 如果在标题界面,不进行快速保存 + if (showTitle || WebGAL.sceneManager.sceneData.currentSentenceId === 0) { + // 如果在标题界面或游戏未开始,不进行快速保存 return; } const saveData: ISaveData = generateCurrentStageData(-1, false); const newSaveData = cloneDeep(saveData); webgalStore.dispatch(saveActions.setFastSave(newSaveData)); - await dumpFastSaveToStorage(); + await dumpFastSaveToStorageSerial(); } +export const autoFastSaveGame = throttle(() => { + void fastSaveGame(); +}, 1000); + /** * 判断是否有无存储紧急回避时的数据 */ @@ -53,7 +64,6 @@ export async function loadFastSaveGame() { if (!loadFile) { return; } - removeFastSaveGameRecord(); loadGameFromStageData(loadFile); } @@ -61,6 +71,7 @@ export async function loadFastSaveGame() { * 移除紧急回避的数据 */ export async function removeFastSaveGameRecord() { + autoFastSaveGame.cancel(); webgalStore.dispatch(saveActions.resetFastSave()); - await dumpFastSaveToStorage(); + await dumpFastSaveToStorageSerial(); } diff --git a/packages/webgal/src/Core/initializeScript.ts b/packages/webgal/src/Core/initializeScript.ts index 9d34aaa4c..f6373f6c9 100644 --- a/packages/webgal/src/Core/initializeScript.ts +++ b/packages/webgal/src/Core/initializeScript.ts @@ -15,6 +15,7 @@ import { __INFO } from '@/config/info'; import { WebGAL } from '@/Core/WebGAL'; import { loadTemplate } from '@/Core/util/coreInitialFunction/templateLoader'; import { stageStateManager } from '@/Core/Modules/stage/stageStateManager'; +import { autoFastSaveGame } from './controller/storage/fastSaveLoad'; export const isIOS = window.__WEBGAL_DEVICE_INFO__?.isIOS ?? false; // 判断是否是 iOS 终端 @@ -57,7 +58,10 @@ export const initializeScript = (): void => { * 启动Pixi */ WebGAL.gameplay.pixiStage = new PixiStage(); - stageStateManager.setCommitHandler(syncPixiStageState); + stageStateManager.setCommitHandler((stageState, options) => { + syncPixiStageState(stageState, options); + if (options.notifyReact) autoFastSaveGame(); + }); /** * iOS 设备 卸载所有 Service Worker