import {MapRender} from './MapRender'; import {MapContainer} from "./MapContainer"; import {throttle, debounce} from 'throttle-debounce'; import {Timeline} from './Render/Timeline'; import {SpecHUD} from './Render/SpecHUD'; import {AnalyseMenu} from './AnalyseMenu' import {AsyncParser} from "./Data/AsyncParser"; import {getMapBoundaries} from "./MapBoundries"; import {createSignal} from "solid-js"; import {Session, StateUpdate} from "./Session"; import {DemoHead} from "../../header"; export interface AnalyseProps { header: DemoHead; isStored: boolean; parser: AsyncParser; } export const Analyser = (props: AnalyseProps) => { const parser = props.parser; const intervalPerTick = props.header.duration / props.header.ticks; const [tick, setTick] = createSignal(0); const [scale, setScale] = createSignal(1); const [playing, setPlaying] = createSignal(false); const [sessionName, setSessionName] = createSignal(""); let lastFrameTime = 0; let playStartTick = 0; let playStartTime = 0; const onUpdate = (update: StateUpdate) => { if (update["tick"]) { setTick(update["tick"]); } if (update["playing"]) { setPlaying(update["playing"]); } } let session: Session | null = null; if (props.isStored && window.location.hash) { const parsed = parseInt(window.location.hash.substr(1), 10); if (('#' + parsed) === window.location.hash) { setTick(Math.floor(parsed)); } else { const name = window.location.hash.substring(1); Session.join(name, onUpdate); setSessionName(name); } } const map = parser.demo.header.map; const backgroundBoundaries = getMapBoundaries(map); if (!backgroundBoundaries) { throw new Error(`Map not supported "${map}".`); } const worldSize = { width: backgroundBoundaries.boundary_max.x - backgroundBoundaries.boundary_min.x, height: backgroundBoundaries.boundary_max.y - backgroundBoundaries.boundary_min.y, }; const setTickNow = (tick) => { lastFrameTime = 0; playStartTick = tick; playStartTime = window.performance.now(); setTick(tick); setHash(tick); if (session) { session.update({tick}); } } const pause = () => { setPlaying(false); lastFrameTime = 0; if (session) { session.update({playing: false}); } } const play = () => { playStartTick = tick(); playStartTime = window.performance.now(); setPlaying(true); requestAnimationFrame(animFrame); if (session) { session.update({playing: false}); } } const togglePlay = () => { if (playing()) { pause(); } else { play(); } } const syncPlayTick = debounce(500, () => { if (session) { session.update({ playing: playing(), tick: tick(), }); } }); const setHash = debounce(250, (tick) => { if (!session && props.isStored) { history.replaceState('', '', '#' + tick); } }); const animFrame = (timestamp:number) => { const timePassed = (timestamp - playStartTime) / 1000; const targetTick = playStartTick + (Math.round(timePassed / intervalPerTick)); lastFrameTime = timestamp; if (targetTick >= (parser.demo.tick - 1)) { pause(); } setHash(targetTick); setTick(targetTick); syncPlayTick(); if (playing()) { requestAnimationFrame(animFrame); } } const players = () => parser.getPlayersAtTick(tick()); const buildings = () => parser.getBuildingsAtTick(tick()); const kills = parser.getKills(); const playButtonText = () => (playing()) ? '⏸' : '▶️'; const disabled = session && !session.isOwner(); const isShared = () => sessionName() !== ''; console.log(intervalPerTick); const timeTitle = () => `${tickToTime(tick(), intervalPerTick)} (tick ${tick()})`; return (
{ session = Session.create({ tick: tick(), playing: playing() }); setSessionName(session.sessionName); }} canShare={props.isStored && !disabled} isShared={isShared()} />
{ setTickNow(tick); })} disabled={disabled}/>
); } function tickToTime(tick: number, intervalPerTick: number): string { let seconds = Math.floor(tick * intervalPerTick); return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, '0')}`; }