53 lines
1.6 KiB
TypeScript
53 lines
1.6 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
import { useCutsceneStore, useSelectedCutscene } from '../store/cutsceneStore';
|
|
|
|
export function usePlayback() {
|
|
const { playState, currentTimeMs, setPlayState, setCurrentTime } = useCutsceneStore();
|
|
const cutscene = useSelectedCutscene();
|
|
const rafRef = useRef<number | null>(null);
|
|
const lastTsRef = useRef<number | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (playState !== 'playing') {
|
|
lastTsRef.current = null;
|
|
if (rafRef.current !== null) {
|
|
cancelAnimationFrame(rafRef.current);
|
|
rafRef.current = null;
|
|
}
|
|
return;
|
|
}
|
|
|
|
function totalDuration() {
|
|
if (!cutscene) return 5000;
|
|
const segMax = cutscene.imageSegments.reduce((m, s) => Math.max(m, s.endMs), 0);
|
|
const content = Math.max(cutscene.durationMs, segMax);
|
|
return content + cutscene.endFadeOutMs + cutscene.endFadeInMs;
|
|
}
|
|
|
|
function tick(ts: number) {
|
|
if (lastTsRef.current === null) lastTsRef.current = ts;
|
|
const delta = ts - lastTsRef.current;
|
|
lastTsRef.current = ts;
|
|
|
|
const newTime = useCutsceneStore.getState().currentTimeMs + delta;
|
|
const total = totalDuration();
|
|
|
|
if (newTime >= total) {
|
|
setCurrentTime(total);
|
|
setPlayState('stopped');
|
|
return;
|
|
}
|
|
|
|
setCurrentTime(newTime);
|
|
rafRef.current = requestAnimationFrame(tick);
|
|
}
|
|
|
|
rafRef.current = requestAnimationFrame(tick);
|
|
return () => {
|
|
if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
|
|
};
|
|
}, [playState, cutscene, setPlayState, setCurrentTime]);
|
|
|
|
return null;
|
|
}
|