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.
*/
export default function useOutfitAppearance(outfitState) {
const { wornItemIds, speciesId, colorId } = outfitState;
const {
wornItemIds,
speciesId,
colorId,
emotion,
genderPresentation,
} = outfitState;
const { loading, error, data } = useQuery(
gql`
query($wornItemIds: [ID!]!, $speciesId: ID!, $colorId: ID!) {
petAppearance(speciesId: $speciesId, colorId: $colorId) {
query(
$wornItemIds: [ID!]!
$speciesId: ID!
$colorId: ID!
$emotion: Emotion!
$genderPresentation: GenderPresentation!
) {
petAppearance(
speciesId: $speciesId
colorId: $colorId
emotion: $emotion
genderPresentation: $genderPresentation
) {
...PetAppearanceForOutfitPreview
}
@ -26,7 +43,13 @@ export default function useOutfitAppearance(outfitState) {
${petAppearanceFragment}
`,
{
variables: { wornItemIds, speciesId, colorId },
variables: {
wornItemIds,
speciesId,
colorId,
emotion,
genderPresentation,
},
}
);
@ -41,7 +64,9 @@ export function getVisibleLayers(petAppearance, itemAppearances) {
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();
// 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;
});
const allRestrictedZoneIds = itemAppearances
const allRestrictedZoneIds = validItemAppearances
.map((l) => l.restrictedZones)
.flat()
.map((z) => z.id);

View file

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

View file

@ -3,7 +3,7 @@ const { gql } = require("apollo-server");
const connectToDb = require("./db");
const buildLoaders = require("./loaders");
const neopets = require("./neopets");
const { capitalize } = require("./util");
const { capitalize, getEmotion, getGenderPresentation } = require("./util");
const typeDefs = gql`
enum LayerImageSize {
@ -111,7 +111,12 @@ const typeDefs = gql`
offset: Int
limit: Int
): ItemSearchResult!
petAppearance(speciesId: ID!, colorId: ID!): PetAppearance
petAppearance(
speciesId: ID!
colorId: ID!
emotion: Emotion!
genderPresentation: GenderPresentation!
): PetAppearance
petAppearances(speciesId: ID!, colorId: ID!): [PetAppearance!]!
petOnNeopetsDotCom(petName: String!): Outfit
@ -162,34 +167,9 @@ const resolvers = {
},
PetAppearance: {
id: ({ petState }) => petState.id,
genderPresentation: ({ petState }) => {
if (petState.female === 1) {
return "FEMININE";
} 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)}`
);
}
},
genderPresentation: ({ petState }) =>
getGenderPresentation(petState.female),
emotion: ({ petState }) => getEmotion(petState.moodId),
approximateThumbnailUrl: ({ petType, petState }) => {
return `http://pets.neopets.com/cp/${petType.basicImageHash}/${petState.moodId}/1.png`;
},
@ -285,15 +265,26 @@ const resolvers = {
},
petAppearance: async (
_,
{ speciesId, colorId },
{ speciesId, colorId, emotion, genderPresentation },
{ petTypeLoader, petStateLoader }
) => {
const petType = await petTypeLoader.load({
speciesId,
colorId,
});
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 (
_,

View file

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

View file

@ -2,4 +2,28 @@ function capitalize(str) {
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 };