show updated pet appearance in outfit preview!

This commit is contained in:
Matt Dunn-Rankin 2020-05-02 22:32:08 -07:00
parent a064e5b471
commit 6e1e0a5c0b
5 changed files with 110 additions and 52 deletions

View file

@ -6,12 +6,29 @@ import { useQuery } from "@apollo/react-hooks";
* visibleLayers for rendering. * visibleLayers for rendering.
*/ */
export default function useOutfitAppearance(outfitState) { export default function useOutfitAppearance(outfitState) {
const { wornItemIds, speciesId, colorId } = outfitState; const {
wornItemIds,
speciesId,
colorId,
emotion,
genderPresentation,
} = outfitState;
const { loading, error, data } = useQuery( const { loading, error, data } = useQuery(
gql` gql`
query($wornItemIds: [ID!]!, $speciesId: ID!, $colorId: ID!) { query(
petAppearance(speciesId: $speciesId, colorId: $colorId) { $wornItemIds: [ID!]!
$speciesId: ID!
$colorId: ID!
$emotion: Emotion!
$genderPresentation: GenderPresentation!
) {
petAppearance(
speciesId: $speciesId
colorId: $colorId
emotion: $emotion
genderPresentation: $genderPresentation
) {
...PetAppearanceForOutfitPreview ...PetAppearanceForOutfitPreview
} }
@ -26,7 +43,13 @@ export default function useOutfitAppearance(outfitState) {
${petAppearanceFragment} ${petAppearanceFragment}
`, `,
{ {
variables: { wornItemIds, speciesId, colorId }, variables: {
wornItemIds,
speciesId,
colorId,
emotion,
genderPresentation,
},
} }
); );
@ -41,7 +64,9 @@ export function getVisibleLayers(petAppearance, itemAppearances) {
return []; return [];
} }
const allAppearances = [petAppearance, ...itemAppearances].filter((a) => a); const validItemAppearances = itemAppearances.filter((a) => a);
const allAppearances = [petAppearance, ...validItemAppearances];
let allLayers = allAppearances.map((a) => a.layers).flat(); let allLayers = allAppearances.map((a) => a.layers).flat();
// Clean up our data a bit, by ensuring only one layer per zone. This // Clean up our data a bit, by ensuring only one layer per zone. This
@ -51,7 +76,7 @@ export function getVisibleLayers(petAppearance, itemAppearances) {
return allLayers.findIndex((l2) => l2.zone.id === l.zone.id) === i; return allLayers.findIndex((l2) => l2.zone.id === l.zone.id) === i;
}); });
const allRestrictedZoneIds = itemAppearances const allRestrictedZoneIds = validItemAppearances
.map((l) => l.restrictedZones) .map((l) => l.restrictedZones)
.flat() .flat()
.map((z) => z.id); .map((z) => z.id);

View file

@ -183,21 +183,34 @@ const outfitStateReducer = (apolloClient) => (baseState, action) => {
closetedItemIds.delete(itemId); closetedItemIds.delete(itemId);
}); });
case "setPose": case "setPose":
const { emotion, genderPresentation } = action; return produce(baseState, (state) => {
return { ...baseState, emotion, genderPresentation }; const { emotion, genderPresentation } = action;
state.emotion = emotion;
state.genderPresentation = genderPresentation;
});
case "reset": case "reset":
const { name, speciesId, colorId, wornItemIds, closetedItemIds } = action; return produce(baseState, (state) => {
return { const {
name, name,
speciesId: speciesId ? String(speciesId) : baseState.speciesId, speciesId,
colorId: colorId ? String(colorId) : baseState.colorId, colorId,
wornItemIds: wornItemIds emotion,
genderPresentation,
wornItemIds,
closetedItemIds,
} = action;
state.name = name;
state.speciesId = speciesId ? String(speciesId) : baseState.speciesId;
state.colorId = colorId ? String(colorId) : baseState.colorId;
state.emotion = emotion;
state.genderPresentation = genderPresentation;
state.wornItemIds = wornItemIds
? new Set(wornItemIds.map(String)) ? new Set(wornItemIds.map(String))
: baseState.wornItemIds, : baseState.wornItemIds;
closetedItemIds: closetedItemIds state.closetedItemIds = closetedItemIds
? new Set(closetedItemIds.map(String)) ? new Set(closetedItemIds.map(String))
: baseState.closetedItemIds, : baseState.closetedItemIds;
}; });
default: default:
throw new Error(`unexpected action ${JSON.stringify(action)}`); throw new Error(`unexpected action ${JSON.stringify(action)}`);
} }

View file

@ -3,7 +3,7 @@ const { gql } = require("apollo-server");
const connectToDb = require("./db"); const connectToDb = require("./db");
const buildLoaders = require("./loaders"); const buildLoaders = require("./loaders");
const neopets = require("./neopets"); const neopets = require("./neopets");
const { capitalize } = require("./util"); const { capitalize, getEmotion, getGenderPresentation } = require("./util");
const typeDefs = gql` const typeDefs = gql`
enum LayerImageSize { enum LayerImageSize {
@ -111,7 +111,12 @@ const typeDefs = gql`
offset: Int offset: Int
limit: Int limit: Int
): ItemSearchResult! ): ItemSearchResult!
petAppearance(speciesId: ID!, colorId: ID!): PetAppearance petAppearance(
speciesId: ID!
colorId: ID!
emotion: Emotion!
genderPresentation: GenderPresentation!
): PetAppearance
petAppearances(speciesId: ID!, colorId: ID!): [PetAppearance!]! petAppearances(speciesId: ID!, colorId: ID!): [PetAppearance!]!
petOnNeopetsDotCom(petName: String!): Outfit petOnNeopetsDotCom(petName: String!): Outfit
@ -162,34 +167,9 @@ const resolvers = {
}, },
PetAppearance: { PetAppearance: {
id: ({ petState }) => petState.id, id: ({ petState }) => petState.id,
genderPresentation: ({ petState }) => { genderPresentation: ({ petState }) =>
if (petState.female === 1) { getGenderPresentation(petState.female),
return "FEMININE"; emotion: ({ petState }) => getEmotion(petState.moodId),
} else if (petState.female === 0) {
return "MASCULINE";
} else if (petState.female === null) {
return null;
} else {
throw new Error(
`unrecognized gender value ${JSON.stringify(petState.female)}`
);
}
},
emotion: ({ petState }) => {
if (petState.moodId === "1") {
return "HAPPY";
} else if (petState.moodId === "2") {
return "SAD";
} else if (petState.moodId === "4") {
return "SICK";
} else if (petState.moodId === null) {
return null;
} else {
throw new Error(
`unrecognized moodId ${JSON.stringify(petState.moodId)}`
);
}
},
approximateThumbnailUrl: ({ petType, petState }) => { approximateThumbnailUrl: ({ petType, petState }) => {
return `http://pets.neopets.com/cp/${petType.basicImageHash}/${petState.moodId}/1.png`; return `http://pets.neopets.com/cp/${petType.basicImageHash}/${petState.moodId}/1.png`;
}, },
@ -285,15 +265,26 @@ const resolvers = {
}, },
petAppearance: async ( petAppearance: async (
_, _,
{ speciesId, colorId }, { speciesId, colorId, emotion, genderPresentation },
{ petTypeLoader, petStateLoader } { petTypeLoader, petStateLoader }
) => { ) => {
const petType = await petTypeLoader.load({ const petType = await petTypeLoader.load({
speciesId, speciesId,
colorId, colorId,
}); });
const petStates = await petStateLoader.load(petType.id); const petStates = await petStateLoader.load(petType.id);
return { petType, petState: petStates[0] }; // TODO: This could be optimized into the query condition 🤔
const petState = petStates.find(
(ps) =>
getEmotion(ps.moodId) === emotion &&
getGenderPresentation(ps.female) === genderPresentation
);
if (!petState) {
return null;
}
return { petType, petState };
}, },
petAppearances: async ( petAppearances: async (
_, _,

View file

@ -6,7 +6,12 @@ describe("PetAppearance", () => {
const res = await query({ const res = await query({
query: gql` query: gql`
query { query {
petAppearance(speciesId: "54", colorId: "75") { petAppearance(
speciesId: "54"
colorId: "75"
emotion: HAPPY
genderPresentation: FEMININE
) {
layers { layers {
id id
imageUrl(size: SIZE_600) imageUrl(size: SIZE_600)

View file

@ -2,4 +2,28 @@ function capitalize(str) {
return str[0].toUpperCase() + str.slice(1); return str[0].toUpperCase() + str.slice(1);
} }
module.exports = { capitalize }; function getEmotion(moodId) {
if (moodId === "1") {
return "HAPPY";
} else if (moodId === "2") {
return "SAD";
} else if (moodId === "4") {
return "SICK";
} else if (moodId === null) {
return null;
} else {
throw new Error(`unrecognized moodId ${JSON.stringify(moodId)}`);
}
}
function getGenderPresentation(modelPetWasFemale) {
if (modelPetWasFemale === 1) {
return "FEMININE";
} else if (modelPetWasFemale === 0) {
return "MASCULINE";
} else {
return null;
}
}
module.exports = { capitalize, getEmotion, getGenderPresentation };