import "./App.css"; import classnames from "classnames"; import React, { useCallback, useMemo, useState } from "react"; import UAParser from "ua-parser-js"; import { DebugTab } from "./components/DebugTab"; import { KeyboardControlComponent } from "./components/KeyboardControl"; import { NodeDetail } from "./components/NodeDetail"; import { PixiComponent } from "./components/PixiComponent"; import QuestProgress from "./components/QuestProgress"; import Sidebar from "./components/Sidebar"; import TabContent from "./components/TabContent"; import Tabs from "./components/Tabs"; import { UseGameStateContext } from "./contexts"; import { GameState } from "./data/GameState"; import { GameStateFactory } from "./game/GameStateFactory"; import { createQuest } from "./game/OnCreateQuest"; import { batchifySetState } from "./lib/util/batchify"; import { Lazy } from "./lib/util/misc"; import { updaterGenerator2 } from "./lib/util/updaterGenerator"; import { computeQuestEfficiencyPercent, remapQuestEfficiencyToGrade } from "./game/EfficiencyCalculator"; // TODO(bowei): on mobile, for either ios or android, when in portrait locked orientation, we want to serve a landscape // experience - similar to a native app which is landscape locked. // (on mobile in already landscape orientation, and in all desktop, serve ordinary orientation.) // also note that android webapp supports manifest.json setting orientation, but not in the browser // FOR NOW - ignore this const browser = new UAParser().getBrowser(); let forceRotate = false; if ( browser.name === "Mobile Safari" && window.innerWidth < window.innerHeight ) { forceRotate = true; } const tabLabels = ["Quest Progress", "Node Details", "Debug"]; const initialGameState: Lazy<GameState> = new Lazy(() => new GameStateFactory({}).create() ); function App() { const [gameState, setGameState] = useState<GameState>(function factory() { return initialGameState.get(); }); let [batchedSetGameState, fireBatch] = useMemo( () => batchifySetState(setGameState), [setGameState] ); let updaters = useMemo( () => updaterGenerator2(initialGameState.get(), batchedSetGameState), [batchedSetGameState] ); let createQuestCb = useCallback(() => createQuest(updaters), [ updaters, ]); let tabViews: JSX.Element[] = []; tabViews = [ <QuestProgress spSpentThisQuest={gameState.playerSave.spSpentThisQuest} createQuestCb={createQuestCb} activeQuest={gameState.playerSave.activeQuest} playerResourceAmounts={gameState.computed.playerResourceAmounts} updaters={updaters.playerSave} score={gameState.playerSave.score} efficiencyGrade={remapQuestEfficiencyToGrade(computeQuestEfficiencyPercent(gameState.playerSave))} questInitialAmount={gameState.playerSave.questInitialAmount} />, <NodeDetail selectedPointNode={gameState.playerUI.selectedPointNode} allocatedPointNodeSet={gameState.playerSave.allocatedPointNodeSet} worldGen={gameState.worldGen} hasActiveQuest={gameState.playerSave.activeQuest !== undefined} />, <DebugTab selectedPointNode={gameState.playerUI.selectedPointNode} allocatedPointNodeSet={gameState.playerSave.allocatedPointNodeSet} worldGen={gameState.worldGen} playerSave={gameState.playerSave} computed={gameState.computed} />, ]; return ( <div className={classnames({ App: true, "force-landscape": forceRotate })}> <UseGameStateContext.Provider value={[gameState, updaters, fireBatch]}> <PixiComponent originalSetGameState={setGameState} /> <Sidebar> <Tabs value={gameState.playerUI.activeTab} labels={tabLabels} onChange={updaters.playerUI.activeTab.getUpdater()} /> {tabViews.map((component, i) => { return ( <TabContent key={i} showContent={gameState.playerUI.activeTab === i} > {component} </TabContent> ); })} </Sidebar> </UseGameStateContext.Provider> <KeyboardControlComponent intent={gameState.intent} updaters={updaters.intent} ></KeyboardControlComponent> </div> ); } export default App;