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

View file

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