Преглед на файлове

Rewriting all of the rejoin logic to be managed by dispatcher, should be much less buggy

Kirk Trombley преди 5 години
родител
ревизия
56e3f36c32

+ 1 - 3
client/src/components/screens/GamePanel/GamePanel.jsx

@@ -44,9 +44,7 @@ export default () => {
     : (
       <Container>
         <StreetViewWrapper>
-          <PositionedStreetView
-            onPanoMoved={(lat, lng, head, pitch) => console.log(`${lat}, ${lng}, ${head}, ${pitch}`)}
-          />
+          <PositionedStreetView />
         </StreetViewWrapper>
         <GuessPane />
       </Container>

+ 16 - 13
client/src/components/screens/GamePanel/PositionedStreetView.jsx

@@ -1,7 +1,8 @@
-import React, { useRef, useEffect, useCallback } from "react";
+import React, { useRef, useEffect } from "react";
 import styled from "styled-components";
 import usePano from "./usePano";
-import { useTargetPoint } from "../../../domain/gameStore";
+import { useTargetPoint, usePanoStartPosition, usePanoStartPov } from "../../../domain/gameStore";
+import { savePanoPositionToLocalStorage, savePanoPovToLocalStorage } from "../../../domain/localStorageMethods";
 
 const Container = styled.div`
   position: relative;
@@ -33,22 +34,24 @@ const ResetButton = styled.div`
   }
 `
 
-export default ({ onPanoMoved }) => {
+export default () => {
+  const startPosition = usePanoStartPosition();
+  const startPov = usePanoStartPov();
   const resetPosition = useTargetPoint();
-  const startPosition = resetPosition; // TODO swap this out later
   const panoDivRef = useRef(null);
-  const panoRef = usePano(panoDivRef, startPosition);
-  const panoChangeCallback = useCallback(() => {
-    const pos = panoRef.current.getPosition();
-    const pov = panoRef.current.getPov();
-    onPanoMoved(pos.lat(), pos.lng(), pov.heading, pov.pitch);
-  }, [panoRef, onPanoMoved]);
+  const panoRef = usePano(panoDivRef, startPosition, startPov);
   useEffect(() => {
     if (panoRef.current) {
-      panoRef.current.addListener("position_changed", panoChangeCallback);
-      panoRef.current.addListener("pov_changed", panoChangeCallback);
+      panoRef.current.addListener("position_changed", () => {
+        const { lat, lng } = panoRef.current.getPosition();
+        savePanoPositionToLocalStorage(lat(), lng());
+      });
+      panoRef.current.addListener("pov_changed", () => {
+        const { heading, pitch } = panoRef.current.getPov();
+        savePanoPovToLocalStorage(heading, pitch);
+      });
     }
-  }, [panoRef, panoChangeCallback]);
+  }, [panoRef]);
 
   return (
     <Container>

+ 9 - 3
client/src/components/screens/GamePanel/usePano.jsx

@@ -1,23 +1,29 @@
 import { useRef, useEffect } from "react";
 /* global google */
 
-export default (panoDivRef, position) => {
+export default (panoDivRef, position, pov) => {
   const panoRef = useRef(null);
   const { lat, lng } = position;
+  const { heading, pitch } = pov;
   useEffect(() => {
+    const position = { lat, lng };
+    const pov = { heading, pitch };
     if (panoRef.current) {
       console.log("Attempted to create a new Pano");
+      panoRef.current.setPosition(position);
+      panoRef.current.setPov(pov);
       return;
     }
 
     panoRef.current = new google.maps.StreetViewPanorama(panoDivRef.current, {
-      position: { lat, lng },
+      position,
+      pov,
       addressControl: false,
       showRoadLabels: false,
       clickToGo: true,
       visible: true,
     });
-  }, [panoDivRef, lat, lng]);
+  }, [panoDivRef, lat, lng, heading, pitch]);
 
   return panoRef;
 }

+ 9 - 13
client/src/components/screens/HomePage.jsx

@@ -2,7 +2,7 @@ import React from 'react';
 import styled from 'styled-components';
 import GameCreationForm from '../util/GameCreationForm';
 import { dispatch } from '../../domain/gameStore';
-import { useGameInfoFromLocalStorage } from '../../domain/localStorageMethods';
+import { hasSavedGameInfo } from '../../domain/localStorageMethods';
 import DelayedButton from '../util/DelayedButton';
 
 const Container = styled.div`
@@ -26,11 +26,11 @@ const RejoinContainer = styled.div`
   align-items: center;
 `;
 
-const Rejoin = ({ gameId, playerName, playerId }) => (
+const Rejoin = () => (
   <RejoinContainer>
     <RejoinLabel>Looks like you were in a game before that you didn't finish!</RejoinLabel>
     <DelayedButton 
-      onEnd={() => dispatch.rejoinGame(gameId, playerName, playerId)}
+      onEnd={() => dispatch.rejoinGame()}
       countDownFormatter={rem => `Rejoining in ${rem}s...`}
     >
       Rejoin Game?
@@ -38,13 +38,9 @@ const Rejoin = ({ gameId, playerName, playerId }) => (
   </RejoinContainer>
 );
 
-export default () => {
-  const { gameId, playerName, playerId } = useGameInfoFromLocalStorage();
-
-  return (
-    <Container>
-      <GameCreationForm afterCreate={gameId => dispatch.goToLobby(gameId)}/>
-      {gameId && playerName && playerId && <Rejoin {...{ gameId, playerName, playerId }} />}
-    </Container>
-  );
-};
+export default () => (
+  <Container>
+    <GameCreationForm afterCreate={gameId => dispatch.goToLobby(gameId)}/>
+    {hasSavedGameInfo() && <Rejoin />}
+  </Container>
+);

+ 27 - 13
client/src/domain/gameStore.js

@@ -4,8 +4,10 @@ import { joinGame, sendGuess, getCurrentRound } from "./apiMethods";
 import {
   saveGameInfoToLocalStorage,
   clearGameInfoFromLocalStorage,
-  clearPointFromLocalStorage,
-  clearTimerFromLocalStorage,
+  getGameInfoFromLocalStorage,
+  saveTimerToLocalStorage,
+  clearRoundInfoFromLocalStorage,
+  getRoundInfoFromLocalStorage,
 } from "./localStorageMethods";
 
 export const [
@@ -18,6 +20,8 @@ export const [
     useCurrentRound,
     useTargetPoint,
     useRoundSeconds,
+    usePanoStartPosition,
+    usePanoStartPov,
   },
   dispatch,
 ] = createStore({
@@ -37,6 +41,8 @@ export const [
   currentRound: null,
   targetPoint: null,
   roundSeconds: 0,
+  panoStartPosition: null,
+  panoStartPov: null,
 }, {
   setPlayerName: ([set], playerName) => set({ playerName }),
   goToLobby: ([set], gameId) => set({ 
@@ -48,31 +54,35 @@ export const [
     const gameId = get.gameId();
     const name = get.playerName();
     const { playerId } = await joinGame(gameId, name);
+    // TODO pull this chunk out
     const { currentRound, coord, timer } = await getCurrentRound(gameId, playerId);
     set({
       playerId,
       currentRound,
       targetPoint: coord,
+      panoStartPosition: coord,
+      panoStartPov: { heading: 0, pitch: 0 },
       roundSeconds: timer,
     });
-    clearTimerFromLocalStorage();
-    clearPointFromLocalStorage();
     saveGameInfoToLocalStorage(gameId, name, playerId);
   },
-  rejoinGame: async ([set], gameId, playerName, playerId) => {
+  rejoinGame: async ([set]) => {
+    const { gameId, playerName, playerId } = getGameInfoFromLocalStorage();
+    set({ gameId, playerName, playerId });
     const { currentRound, coord, timer } = await getCurrentRound(gameId, playerId);
-    set({ 
-      gameId, 
-      playerName, 
-      playerId,
+    const { savedPosition, savedPov, savedTimer } = getRoundInfoFromLocalStorage();
+    set({
       currentRound,
       targetPoint: coord,
-      roundSeconds: timer,
+      roundSeconds: savedTimer ?? timer,
+      panoStartPosition: savedPosition ?? coord,
+      panoStartPov: savedPov ?? { heading: 0, pitch: 0 },
       gameState: IN_ROUND,
     });
   },
   startRound: ([set]) => set({ gameState: IN_ROUND }),
   submitGuess: async ([set, get], selectedPoint) => {
+    clearRoundInfoFromLocalStorage();
     const gameId = get.gameId();
     const playerId = get.playerId();
     const roundNum = get.currentRound();
@@ -96,6 +106,8 @@ export const [
     set({
       currentRound,
       targetPoint: coord,
+      panoStartPosition: coord,
+      panoStartPov: { heading: 0, pitch: 0 },
       roundSeconds: timer,
     });
   },
@@ -105,10 +117,12 @@ export const [
     }
     set({ gameState: POST_GAME });
     if (clearSavedGame) {
-      clearTimerFromLocalStorage();
-      clearPointFromLocalStorage();
+      clearRoundInfoFromLocalStorage();
       clearGameInfoFromLocalStorage();
     }
   },
-  setRoundSeconds: ([set], roundSeconds) => set({ roundSeconds }),
+  setRoundSeconds: ([set], roundSeconds) => {
+    set({ roundSeconds });
+    saveTimerToLocalStorage(roundSeconds);
+  },
 });

+ 55 - 30
client/src/domain/localStorageMethods.js

@@ -2,9 +2,19 @@
 const localStorageGameId = "terrassumptions:gameId";
 const localStoragePlayerName = "terrassumptions:playerName";
 const localStoragePlayerId = "terrassumptions:playerId";
+
 const localStorageTimer = "terrassumptions:timer";
-const localStoragePointLat = "terrassumptions:point:lat";
-const localStoragePointLng = "terrassumptions:point:lng";
+
+const localStoragePanoLat = "terrassumptions:pano:lat";
+const localStoragePanoLng = "terrassumptions:pano:lng";
+const localStoragePanoHeading = "terrassumptions:pano:heading";
+const localStoragePanoPitch = "terrassumptions:pano:pitch";
+
+export const hasSavedGameInfo = () => (
+  localStorage.getItem(localStorageGameId) !== null &&
+  localStorage.getItem(localStoragePlayerName) !== null &&
+  localStorage.getItem(localStoragePlayerId) !== null
+)
 
 export const saveGameInfoToLocalStorage = (gameId, playerName, playerId) => {
   localStorage.setItem(localStorageGameId, gameId);
@@ -12,44 +22,59 @@ export const saveGameInfoToLocalStorage = (gameId, playerName, playerId) => {
   localStorage.setItem(localStoragePlayerId, playerId);
 }
 
-export const clearGameInfoFromLocalStorage = () => {
-  localStorage.removeItem(localStorageGameId);
-  localStorage.removeItem(localStoragePlayerName);
-  localStorage.removeItem(localStoragePlayerId);
-}
-
-export const useGameInfoFromLocalStorage = () => {
-  const gameId = localStorage.getItem(localStorageGameId);
-  const playerName = localStorage.getItem(localStoragePlayerName);
-  const playerId = localStorage.getItem(localStoragePlayerId);
-  return { gameId, playerName, playerId };
-}
-
 export const saveTimerToLocalStorage = (timer) => {
   localStorage.setItem(localStorageTimer, timer.toString());
 }
 
-export const clearTimerFromLocalStorage = () => {
-  localStorage.removeItem(localStorageTimer);
+export const savePanoPositionToLocalStorage = (lat, lng) => {
+  localStorage.setItem(localStoragePanoLat, lat.toString());
+  localStorage.setItem(localStoragePanoLng, lng.toString());
 }
 
-export const useTimerFromLocalStorage = () => {
-  const timer = localStorage.getItem(localStorageTimer);
-  return timer === null ? null : Number.parseInt(timer);
+export const savePanoPovToLocalStorage = (heading, pitch) => {
+  localStorage.setItem(localStoragePanoHeading, heading.toString());
+  localStorage.setItem(localStoragePanoPitch, pitch.toString());
 }
 
-export const savePointToLocalStorage = (lat, lng) => {
-  localStorage.setItem(localStoragePointLat, lat.toString());
-  localStorage.setItem(localStoragePointLng, lng.toString());
+export const clearGameInfoFromLocalStorage = () => {
+  localStorage.removeItem(localStorageGameId);
+  localStorage.removeItem(localStoragePlayerName);
+  localStorage.removeItem(localStoragePlayerId);
 }
 
-export const clearPointFromLocalStorage = () => {
-  localStorage.removeItem(localStoragePointLat);
-  localStorage.removeItem(localStoragePointLng);
+export const clearRoundInfoFromLocalStorage = () => {
+  localStorage.removeItem(localStorageTimer);
+  localStorage.removeItem(localStoragePanoLat);
+  localStorage.removeItem(localStoragePanoLng);
+  localStorage.removeItem(localStoragePanoHeading);
+  localStorage.removeItem(localStoragePanoPitch);
 }
 
-export const usePointFromLocalStorage = () => {
-  const lat = localStorage.getItem(localStoragePointLat);
-  const lng = localStorage.getItem(localStoragePointLng);
-  return lat === null || lng === null ? null : { lat: Number.parseFloat(lat), lng: Number.parseFloat(lng) };
+export const getGameInfoFromLocalStorage = () => ({
+  gameId: localStorage.getItem(localStorageGameId),
+  playerName: localStorage.getItem(localStoragePlayerName),
+  playerId: localStorage.getItem(localStoragePlayerId),
+})
+
+const parseFloatFromStorage = key => {
+  const val = localStorage.getItem(key);
+  return val === null ? null : Number.parseFloat(val);
 }
+
+export const getRoundInfoFromLocalStorage = () => {
+  const position = {
+    lat: parseFloatFromStorage(localStoragePanoLat),
+    lng: parseFloatFromStorage(localStoragePanoLng),
+  };
+  const pov = {
+    heading: parseFloatFromStorage(localStoragePanoHeading),
+    pitch: parseFloatFromStorage(localStoragePanoPitch),
+  };
+  const timer = localStorage.getItem(localStorageTimer);
+
+  return {
+    savedPosition: position.lat !== null && position.lng !== null ? position : null,
+    savedPov: pov.heading !== null && pov.pitch !== null ? pov : null,
+    savedTimer: timer !== null ? Number.parseInt(timer) : null,
+  }
+};