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..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,16 +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 || 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); + /** * 判断是否有无存储紧急回避时的数据 */ @@ -55,8 +71,7 @@ export async function loadFastSaveGame() { * 移除紧急回避的数据 */ export async function removeFastSaveGameRecord() { + autoFastSaveGame.cancel(); webgalStore.dispatch(saveActions.resetFastSave()); - await setStorageAsync(); - // await localforage.setItem(isFastSaveKey, false); - // await localforage.setItem(fastSaveGameKey, null); + await dumpFastSaveToStorageSerial(); } 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/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 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'))} +
+ )}
{