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
19 changes: 16 additions & 3 deletions packages/webgal/src/Core/controller/stage/resetStage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import { WebGAL } from '@/Core/WebGAL';
import { initState, stageStateManager } from '@/Core/Modules/stage/stageStateManager';
import { stopFast } from '@/Core/controller/gamePlay/fastSkip';

export const resetStage = (resetBacklog: boolean, resetSceneAndVar = true) => {
export interface ResetStageOptions {
commitStageState?: boolean;
}

export const resetStage = (resetBacklog: boolean, resetSceneAndVar = true, options: ResetStageOptions = {}) => {
const { commitStageState = true } = options;
/**
* 清空运行时
*/
Expand All @@ -24,8 +29,16 @@ export const resetStage = (resetBacklog: boolean, resetSceneAndVar = true) => {
// 清空舞台状态表
const initSceneDataCopy = cloneDeep(initState);
const currentVars = stageStateManager.getCalculationStageState().GameVar;
stageStateManager.resetAllStageState(initSceneDataCopy, { skipAnimation: true });
if (commitStageState) {
stageStateManager.resetAllStageState(initSceneDataCopy, { skipAnimation: true });
} else {
stageStateManager.resetCalculationStageState(initSceneDataCopy);
}
if (!resetSceneAndVar) {
stageStateManager.setStageAndCommit('GameVar', currentVars);
if (commitStageState) {
stageStateManager.setStageAndCommit('GameVar', currentVars);
} else {
stageStateManager.setStage('GameVar', currentVars);
}
}
};
55 changes: 55 additions & 0 deletions packages/webgal/src/Core/util/syncWithEditor/previewSyncRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ export const startPreviewSyncRuntime = () => {
const targetTransformBaselines = createTargetTransformBaselineManager();
const embeddedLaunchIdPromise = requestEmbeddedLaunchId();
let transport!: PreviewSyncTransport;
let nextSyncSceneRevision = 0;
let activeSyncSceneRevision: number | null = null;

const createRequestId = () => `req-${Date.now()}-${Math.random().toString(16).slice(2)}`;

Expand Down Expand Up @@ -133,9 +135,33 @@ export const startPreviewSyncRuntime = () => {
lastPublishedSentenceId = null;
lastPublishedStageState = null;
setEffectBaselines.clear();
activeSyncSceneRevision = null;
WebGAL.gameplay.isFastPreview = false;
targetTransformBaselines.invalidateCurrentRevision();
};

const startSyncSceneTransaction = () => {
nextSyncSceneRevision += 1;
activeSyncSceneRevision = nextSyncSceneRevision;
return activeSyncSceneRevision;
};

const isActiveSyncSceneRevision = (revision: number) => activeSyncSceneRevision === revision;

const finishSyncSceneTransaction = (revision: number) => {
if (!isActiveSyncSceneRevision(revision)) {
return false;
}

activeSyncSceneRevision = null;
return true;
};

const cancelActiveSyncScene = () => {
activeSyncSceneRevision = null;
WebGAL.gameplay.isFastPreview = false;
};

const buildStageStateSnapshot = (stageState: StageStateSnapshot): StageSnapshotUpdatedPayload['stageState'] => {
return JSON.parse(JSON.stringify(stageState)) as StageSnapshotUpdatedPayload['stageState'];
};
Expand All @@ -152,6 +178,9 @@ export const startPreviewSyncRuntime = () => {
if (!registered) {
return;
}
if (activeSyncSceneRevision !== null) {
return;
}

const sceneName = WebGAL.sceneManager.sceneData.currentScene.sceneName;
const sentenceId = WebGAL.sceneManager.sceneData.currentSentenceId;
Expand All @@ -178,6 +207,10 @@ export const startPreviewSyncRuntime = () => {
}
};

const publishSettledStageSnapshot = () => {
publishStageSnapshot(true, stageStateManager.getViewStageState());
};

const registerPreview = async (socket: PreviewSyncTransportSocket) => {
const requestId = createRequestId();
pendingRegisterRequestId = requestId;
Expand Down Expand Up @@ -222,6 +255,8 @@ export const startPreviewSyncRuntime = () => {
};

const handleSyncScene = (payload: SyncScenePayload) => {
const syncSceneRevision = startSyncSceneTransaction();
const isLatestSyncScene = () => isActiveSyncSceneRevision(syncSceneRevision);
setEffectBaselines.clear();
const { transformBaselineRevision } = payload;
if (transformBaselineRevision) {
Expand All @@ -232,7 +267,11 @@ export const startPreviewSyncRuntime = () => {

executePreviewSyncSceneCommand(payload, {
onFastPreviewTimeout: emitFastPreviewTimeout,
isLatest: isLatestSyncScene,
onBeforeTargetScriptExecute: () => {
if (!isLatestSyncScene()) {
return;
}
if (!transformBaselineRevision) {
return;
}
Expand All @@ -243,22 +282,37 @@ export const startPreviewSyncRuntime = () => {
);
},
onSettled: (result) => {
if (!finishSyncSceneTransaction(syncSceneRevision)) {
return;
}

if (result === null) {
if (transformBaselineRevision) {
targetTransformBaselines.failRevision(transformBaselineRevision);
}
return;
}

if (!transformBaselineRevision) {
publishSettledStageSnapshot();
return;
}

const isSyncSettled = isTargetTransformBaselineSyncSettled(result, payload);
if (!isSyncSettled || !targetTransformBaselines.publishCapturedSnapshot(transformBaselineRevision)) {
targetTransformBaselines.failRevision(transformBaselineRevision);
publishSettledStageSnapshot();
return;
}

setEffectBaselines.clear();
publishSettledStageSnapshot();
},
});
};

const handleRunSnippet = (payload: RunSnippetPayload) => {
cancelActiveSyncScene();
setEffectBaselines.clear();
targetTransformBaselines.invalidateCurrentRevision();
applyPreviewDebugVariables(payload.debugVariables);
Expand Down Expand Up @@ -293,6 +347,7 @@ export const startPreviewSyncRuntime = () => {
};

const handleRunSceneContent = (payload: RunSceneContentPayload) => {
cancelActiveSyncScene();
setEffectBaselines.clear();
targetTransformBaselines.invalidateCurrentRevision();
resetStage(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,19 @@ export interface PreviewSyncSceneCommandCallbacks {
onFastPreviewTimeout?: FastPreviewTimeoutEmitter;
onBeforeTargetScriptExecute?: () => void;
onSettled?: (result: FastPreviewResult | null) => void;
isLatest?: () => boolean;
}

interface RunFastPreviewOptions {
onBeforeTargetScriptExecute?: () => void;
isLatest?: () => boolean;
}

export function executePreviewSyncSceneCommand(
{ sceneName, sentenceId, debugVariables, settleMode = 'normal' }: SyncScenePayload,
callbacks: PreviewSyncSceneCommandCallbacks = {},
): void {
const isLatest = () => callbacks.isLatest?.() ?? true;
logger.warn('正在跳转到' + sceneName + ':' + sentenceId);
WebGAL.gameplay.isFastPreview = false;

Expand All @@ -57,22 +60,39 @@ export function executePreviewSyncSceneCommand(

sceneFetcher(sceneUrl)
.then((rawScene) => {
resetStage(true);
if (!isLatest()) {
return;
}

resetStage(true, true, { commitStageState: false });
applyPreviewDebugVariables(debugVariables);
WebGAL.sceneManager.sceneData.currentScene = sceneParser(rawScene, sceneName, sceneUrl);
const currentSceneName = WebGAL.sceneManager.sceneData.currentScene.sceneName;
void runFastPreview(sentenceId, currentSceneName, callbacks.onFastPreviewTimeout, settleMode, {
onBeforeTargetScriptExecute: callbacks.onBeforeTargetScriptExecute,
isLatest: callbacks.isLatest,
})
.then((result) => {
if (!isLatest()) {
return;
}

callbacks.onSettled?.(result);
})
.catch((error) => {
if (!isLatest()) {
return;
}

logger.error('实时预览跳转错误', error);
callbacks.onSettled?.(null);
});
})
.catch((error) => {
if (!isLatest()) {
return;
}

stopFast();
WebGAL.gameplay.isFastPreview = false;
logger.error('实时预览跳转错误', error);
Expand All @@ -86,7 +106,8 @@ export async function runFastPreview(
onFastPreviewTimeout?: FastPreviewTimeoutEmitter,
settleMode: SyncSceneSettleMode = 'normal',
options: RunFastPreviewOptions = {},
): Promise<FastPreviewResult> {
): Promise<FastPreviewResult | null> {
const isLatest = () => options.isLatest?.() ?? true;
const fastPreviewStartTime = performance.now();
const baseSceneStackDepth = WebGAL.sceneManager.sceneData.sceneStack.length;
stopFast();
Expand Down Expand Up @@ -117,6 +138,10 @@ export async function runFastPreview(

try {
while (shouldContinueFastPreview(sentenceId, currentSceneName, baseSceneStackDepth)) {
if (!isLatest()) {
return null;
}

const prevSentenceId = WebGAL.sceneManager.sceneData.currentSentenceId;
const prevSceneName = WebGAL.sceneManager.sceneData.currentScene.sceneName;
const isForwarded = forward({
Expand All @@ -135,6 +160,9 @@ export async function runFastPreview(
if (awaitedSceneWrite) {
suspendedElapsedMs += performance.now() - sceneWriteWaitStart;
}
if (!isLatest()) {
return null;
}

if (!isForwarded && !awaitedSceneWrite) {
stopReason = 'no-progress';
Expand Down Expand Up @@ -164,14 +192,20 @@ export async function runFastPreview(
}
}
} finally {
WebGAL.gameplay.isFastPreview = false;
if (isLatest()) {
WebGAL.gameplay.isFastPreview = false;
}
}

if (settleMode === 'immediate') {
WebGAL.gameplay.performController.discardUncommittedNonHoldPerforms(true);
WebGAL.gameplay.performController.clearNonHoldPerformsFromStageState();
}

if (!isLatest()) {
return null;
}

commitForward();

const forwardedLineCount =
Expand Down
Loading