Load best available pose in SpeciesFacesPicker

Oh right, I left in a hack to just always pick HAPPY_MASC or HAPPY_FEM, back when it was just the basic colors. Now that we're all the colors, we need to be able to handle fallbacks for missing or unlabeled poses, too!!
This commit is contained in:
Emi Matchu 2021-02-03 02:10:52 -08:00
parent 082af11b5b
commit 75fccf1adf
2 changed files with 42 additions and 17 deletions

View file

@ -40,7 +40,11 @@ import {
petAppearanceFragment, petAppearanceFragment,
} from "./components/useOutfitAppearance"; } from "./components/useOutfitAppearance";
import OutfitPreview from "./components/OutfitPreview"; import OutfitPreview from "./components/OutfitPreview";
import SpeciesColorPicker from "./components/SpeciesColorPicker"; import SpeciesColorPicker, {
useAllValidPetPoses,
getValidPoses,
getClosestPose,
} from "./components/SpeciesColorPicker";
import useCurrentUser from "./components/useCurrentUser"; import useCurrentUser from "./components/useCurrentUser";
import { useLocalStorage } from "./util"; import { useLocalStorage } from "./util";
@ -515,7 +519,7 @@ function ItemPageOutfitPreview({ itemId }) {
// query after this loads, because our Apollo cache can't detect the // query after this loads, because our Apollo cache can't detect the
// shared item appearance. (For standard colors though, our logic to // shared item appearance. (For standard colors though, our logic to
// cover standard-color switches works for this preloading too.) // cover standard-color switches works for this preloading too.)
const { loading, error, data } = useQuery( const { loading: loadingGQL, error: errorGQL, data } = useQuery(
gql` gql`
query ItemPageOutfitPreview($itemId: ID!) { query ItemPageOutfitPreview($itemId: ID!) {
item(id: $itemId) { item(id: $itemId) {
@ -581,6 +585,13 @@ function ItemPageOutfitPreview({ itemId }) {
); );
const couldProbablyModelMoreData = !isProbablySpeciesSpecific; const couldProbablyModelMoreData = !isProbablySpeciesSpecific;
// TODO: Does this double-trigger the HTTP request with SpeciesColorPicker?
const {
loading: loadingValids,
error: errorValids,
valids,
} = useAllValidPetPoses();
// To check whether the item is compatible with this pet, query for the // To check whether the item is compatible with this pet, query for the
// appearance, but only against the cache. That way, we don't send a // appearance, but only against the cache. That way, we don't send a
// redundant network request just for this (the OutfitPreview component will // redundant network request just for this (the OutfitPreview component will
@ -617,6 +628,7 @@ function ItemPageOutfitPreview({ itemId }) {
const borderColor = useColorModeValue("green.700", "green.400"); const borderColor = useColorModeValue("green.700", "green.400");
const errorColor = useColorModeValue("red.600", "red.400"); const errorColor = useColorModeValue("red.600", "red.400");
const error = errorGQL || errorValids;
if (error) { if (error) {
return <Box color="red.400">{error.message}</Box>; return <Box color="red.400">{error.message}</Box>;
} }
@ -648,7 +660,7 @@ function ItemPageOutfitPreview({ itemId }) {
pose={petState.pose} pose={petState.pose}
appearanceId={petState.appearanceId} appearanceId={petState.appearanceId}
wornItemIds={[itemId]} wornItemIds={[itemId]}
isLoading={loading} isLoading={loadingGQL || loadingValids}
spinnerVariant="corner" spinnerVariant="corner"
loadingDelayMs={2000} loadingDelayMs={2000}
engine="canvas" engine="canvas"
@ -717,15 +729,17 @@ function ItemPageOutfitPreview({ itemId }) {
selectedColorId={petState.colorId} selectedColorId={petState.colorId}
compatibleBodies={compatibleBodies} compatibleBodies={compatibleBodies}
couldProbablyModelMoreData={couldProbablyModelMoreData} couldProbablyModelMoreData={couldProbablyModelMoreData}
onChange={({ speciesId, colorId }) => onChange={({ speciesId, colorId }) => {
const validPoses = getValidPoses(valids, speciesId, colorId);
const pose = getClosestPose(validPoses, idealPose);
setPetState({ setPetState({
speciesId, speciesId,
colorId, colorId,
pose: idealPose, pose,
appearanceId: null, appearanceId: null,
}) });
} }}
isLoading={loading} isLoading={loadingGQL || loadingValids}
/> />
</Box> </Box>
</Stack> </Stack>
@ -900,7 +914,7 @@ function SpeciesFacesPicker({
> >
<WarningTwoIcon marginTop="0.4em" marginRight="1" /> <WarningTwoIcon marginTop="0.4em" marginRight="1" />
<Box> <Box>
Error loading this color's thumbnail images. Error loading this color's pet photos.
<br /> <br />
Check your connection and try again. Check your connection and try again.
</Box> </Box>

View file

@ -44,15 +44,12 @@ function SpeciesColorPicker({
} }
} }
`); `);
const { const {
loading: loadingValids, loading: loadingValids,
error: errorValids, error: errorValids,
data: validsBuffer, valids,
} = useFetch("/api/validPetPoses", { responseType: "arrayBuffer" }); } = useAllValidPetPoses();
const valids = React.useMemo(
() => validsBuffer && new DataView(validsBuffer),
[validsBuffer]
);
const allColors = (meta && [...meta.allColors]) || []; const allColors = (meta && [...meta.allColors]) || [];
allColors.sort((a, b) => a.name.localeCompare(b.name)); allColors.sort((a, b) => a.name.localeCompare(b.name));
@ -309,6 +306,20 @@ const SpeciesColorSelect = ({
); );
}; };
export function useAllValidPetPoses() {
const { loading, error, data: validsBuffer } = useFetch(
"/api/validPetPoses",
{ responseType: "arrayBuffer" }
);
const valids = React.useMemo(
() => validsBuffer && new DataView(validsBuffer),
[validsBuffer]
);
return { loading, error, valids };
}
function getPairByte(valids, speciesId, colorId) { function getPairByte(valids, speciesId, colorId) {
// Reading a bit table, owo! // Reading a bit table, owo!
const speciesIndex = speciesId - 1; const speciesIndex = speciesId - 1;
@ -331,7 +342,7 @@ function pairIsValid(valids, speciesId, colorId) {
return getPairByte(valids, speciesId, colorId) !== 0; return getPairByte(valids, speciesId, colorId) !== 0;
} }
function getValidPoses(valids, speciesId, colorId) { export function getValidPoses(valids, speciesId, colorId) {
const pairByte = getPairByte(valids, speciesId, colorId); const pairByte = getPairByte(valids, speciesId, colorId);
const validPoses = new Set(); const validPoses = new Set();
@ -347,7 +358,7 @@ function getValidPoses(valids, speciesId, colorId) {
return validPoses; return validPoses;
} }
function getClosestPose(validPoses, idealPose) { export function getClosestPose(validPoses, idealPose) {
return closestPosesInOrder[idealPose].find((p) => validPoses.has(p)) || null; return closestPosesInOrder[idealPose].find((p) => validPoses.has(p)) || null;
} }