diff --git a/src/server/loaders.js b/src/server/loaders.js index 39168be..bada992 100644 --- a/src/server/loaders.js +++ b/src/server/loaders.js @@ -324,7 +324,7 @@ const buildItemBodiesWithAppearanceDataLoader = (db) => return itemIds.map((itemId) => entities.filter((e) => e.itemId === itemId)); }); -const buildPetTypeLoader = (db) => +const buildPetTypeLoader = (db, loaders) => new DataLoader(async (petTypeIds) => { const qs = petTypeIds.map((_) => "?").join(","); const [rows, _] = await db.execute( @@ -334,6 +334,13 @@ const buildPetTypeLoader = (db) => const entities = rows.map(normalizeRow); + for (const petType of entities) { + loaders.petTypeBySpeciesAndColorLoader.prime( + { speciesId: petType.speciesId, colorId: petType.colorId }, + petType + ); + } + return petTypeIds.map((petTypeId) => entities.find((e) => e.id === petTypeId) ); @@ -577,7 +584,7 @@ const buildCanonicalPetStateForBodyLoader = (db, loaders) => ); }); -const buildPetStateByPetTypeAndAssetsLoader = (db) => +const buildPetStateByPetTypeAndAssetsLoader = (db, loaders) => new DataLoader( async (petTypeIdAndAssetIdsPairs) => { const qs = petTypeIdAndAssetIdsPairs @@ -593,6 +600,10 @@ const buildPetStateByPetTypeAndAssetsLoader = (db) => const entities = rows.map(normalizeRow); + for (const petState of entities) { + loaders.petStateLoader.prime(petState.id, petState); + } + return petTypeIdAndAssetIdsPairs.map(({ petTypeId, swfAssetIds }) => entities.find( (e) => e.petTypeId === petTypeId && e.swfAssetIds === swfAssetIds @@ -721,7 +732,7 @@ function buildLoaders(db) { loaders.itemBodiesWithAppearanceDataLoader = buildItemBodiesWithAppearanceDataLoader( db ); - loaders.petTypeLoader = buildPetTypeLoader(db); + loaders.petTypeLoader = buildPetTypeLoader(db, loaders); loaders.petTypeBySpeciesAndColorLoader = buildPetTypeBySpeciesAndColorLoader( db, loaders @@ -744,7 +755,8 @@ function buildLoaders(db) { loaders ); loaders.petStateByPetTypeAndAssetsLoader = buildPetStateByPetTypeAndAssetsLoader( - db + db, + loaders ); loaders.speciesLoader = buildSpeciesLoader(db); loaders.speciesTranslationLoader = buildSpeciesTranslationLoader(db); diff --git a/src/server/types/Outfit.js b/src/server/types/Outfit.js index 11f0200..d83492d 100644 --- a/src/server/types/Outfit.js +++ b/src/server/types/Outfit.js @@ -1,5 +1,6 @@ const fetch = require("node-fetch"); const { gql } = require("apollo-server"); +const { getPoseFromPetState } = require("../util"); const typeDefs = gql` type Outfit { @@ -8,6 +9,14 @@ const typeDefs = gql` petAppearance: PetAppearance! wornItems: [Item!]! closetedItems: [Item!]! + } + + # TODO: This maybe should move to a separate file? + type Pet { + id: ID! + name: String! + petAppearance: PetAppearance! + wornItems: [Item!]! species: Species! # to be deprecated? can use petAppearance? 🤔 color: Color! # to be deprecated? can use petAppearance? 🤔 @@ -17,7 +26,7 @@ const typeDefs = gql` extend type Query { outfit(id: ID!): Outfit - petOnNeopetsDotCom(petName: String!): Outfit + petOnNeopetsDotCom(petName: String!): Pet } `; @@ -44,6 +53,37 @@ const resolvers = { .map((oir) => ({ id: oir.itemId })); }, }, + Pet: { + species: ({ customPetData }) => ({ + id: customPetData.custom_pet.species_id, + }), + color: ({ customPetData }) => ({ id: customPetData.custom_pet.color_id }), + pose: ({ customPetData, petMetaData }) => + getPoseFromPetData(petMetaData, customPetData), + petAppearance: async ( + { customPetData, petMetaData }, + _, + { petTypeBySpeciesAndColorLoader, petStatesForPetTypeLoader } + ) => { + const petType = await petTypeBySpeciesAndColorLoader.load({ + speciesId: customPetData.custom_pet.species_id, + colorId: customPetData.custom_pet.color_id, + }); + const petStates = await petStatesForPetTypeLoader.load(petType.id); + const pose = getPoseFromPetData(petMetaData, customPetData); + const petState = petStates.find((ps) => getPoseFromPetState(ps) === pose); + return { id: petState.id }; + }, + wornItems: ({ customPetData }) => + Object.values(customPetData.object_info_registry).map((o) => ({ + id: o.obj_info_id, + name: o.name, + description: o.description, + thumbnailUrl: o.thumbnail_url, + rarityIndex: o.rarity_index, + })), + items: (...args) => resolvers.Pet.wornItems(...args), + }, Query: { outfit: (_, { id }) => ({ id }), petOnNeopetsDotCom: async ( @@ -72,23 +112,7 @@ const resolvers = { swfAssetByRemoteIdLoader, }); - const outfit = { - // TODO: This isn't a fully-working Outfit object. It works for the - // client as currently implemented, but we'll probably want to - // move the client and this onto our more generic fields! - species: { id: customPetData.custom_pet.species_id }, - color: { id: customPetData.custom_pet.color_id }, - pose: getPoseFromPetData(petMetaData, customPetData), - items: Object.values(customPetData.object_info_registry).map((o) => ({ - id: o.obj_info_id, - name: o.name, - description: o.description, - thumbnailUrl: o.thumbnail_url, - rarityIndex: o.rarity_index, - })), - }; - - return outfit; + return { name, customPetData, petMetaData }; }, }, }; @@ -129,10 +153,11 @@ async function loadCustomPetData(petName) { } function getPoseFromPetData(petMetaData, petCustomData) { - // TODO: Use custom data to decide if Unconverted. const moodId = petMetaData.mood; const genderId = petMetaData.gender; - if (String(moodId) === "1" && String(genderId) === "1") { + if (Object.keys(petCustomData.custom_pet.biology_by_zone).length === 1) { + return "UNCONVERTED"; + } else if (String(moodId) === "1" && String(genderId) === "1") { return "HAPPY_MASC"; } else if (String(moodId) === "1" && String(genderId) === "2") { return "HAPPY_FEM";