Skip to content
Merged
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
1 change: 1 addition & 0 deletions packages/webgal/public/game/config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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;
2 changes: 2 additions & 0 deletions packages/webgal/src/Core/controller/gamePlay/backToTitle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
15 changes: 2 additions & 13 deletions packages/webgal/src/Core/controller/gamePlay/startContinueGame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
25 changes: 20 additions & 5 deletions packages/webgal/src/Core/controller/storage/fastSaveLoad.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,49 @@
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';

export let fastSaveGameKey = '';
export let isFastSaveKey = '';
let lock = true;
let dumpFastSaveTask = Promise.resolve();

export function initKey() {
lock = false;
fastSaveGameKey = `FastSaveKey-${WebGAL.gameName}-${WebGAL.gameKey}`;
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);

/**
* 判断是否有无存储紧急回避时的数据
*/
Expand Down Expand Up @@ -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();
}
4 changes: 2 additions & 2 deletions packages/webgal/src/Core/gameScripts/end.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

/**
* 结束游戏
Expand All @@ -24,7 +24,7 @@ export const end = (sentence: ISentence): IPerform => {
setTimeout(() => {
WebGAL.sceneManager.resetScene();
}, 5);
dispatch(saveActions.resetFastSave());
removeFastSaveGameRecord();
dumpToStorageFast();
sceneFetcher(sceneUrl).then((rawScene) => {
// 场景写入到运行时
Expand Down
6 changes: 5 additions & 1 deletion packages/webgal/src/Core/initializeScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 终端

Expand Down Expand Up @@ -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
Expand Down
30 changes: 19 additions & 11 deletions packages/webgal/src/UI/Title/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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变化
Expand Down Expand Up @@ -72,17 +75,22 @@ export default function Title() {
>
{renderButtonText(t('start.title'))}
</div>
<div
className={applyStyle('Title_button', styles.Title_button)}
onClick={async () => {
playSeClick();
dispatch(setVisibility({ component: 'showTitle', visibility: false }));
continueGame();
}}
onMouseEnter={playSeEnter}
>
{renderButtonText(t('continue.title'))}
</div>
{enableContinue && (
<div
className={`${applyStyle('Title_button', styles.Title_button)} ${
!fastSaveData ? applyStyle('Title_button_disabled', styles.Title_button_disabled) : ''
}`}
onClick={() => {
if (fastSaveData) {
playSeClick();
continueGame();
}
}}
Comment on lines +83 to +88

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

“继续游戏”按钮逻辑中缺少了隐藏标题界面的 dispatch 调用。这会导致在加载存档数据后,标题界面仍然显示在最上层,用户无法看到游戏画面。建议添加 dispatch(setVisibility({ component: 'showTitle', visibility: false }));

Suggested change
onClick={() => {
if (!latestSave) return;
playSeClick();
loadGameFromStageData(latestSave);
}}
onClick={() => {
if (!latestSave) return;
playSeClick();
dispatch(setVisibility({ component: 'showTitle', visibility: false }));
loadGameFromStageData(latestSave);
}}

onMouseEnter={fastSaveData ? playSeEnter : undefined}
>
{renderButtonText(t('continue.title'))}
</div>
)}
<div
className={applyStyle('Title_button', styles.Title_button)}
onClick={() => {
Expand Down
Loading