forked from OpenNeo/impress
Display alt styles in outfit editor when selected
Yay it works(*)! But two major missing pieces: - Outfit saving doesn't persist it at all - Item compatibility is unaffected: items will still appear in search and in the preview, even when they don't fit anymore.
This commit is contained in:
parent
3ebbfc4967
commit
c2de6f7167
7 changed files with 65 additions and 8 deletions
|
@ -11,7 +11,8 @@ class AltStylesController < ApplicationController
|
|||
respond_to do |format|
|
||||
format.html { render }
|
||||
format.json {
|
||||
render json: @alt_styles.as_json(
|
||||
render json: @alt_styles.includes(swf_assets: [:zone]).as_json(
|
||||
include: {swf_assets: {include: [:zone], methods: [:image_url]}},
|
||||
methods: [:series_name, :adjective_name, :thumbnail_url],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ function WardrobePreviewAndControls({
|
|||
speciesId: outfitState.speciesId,
|
||||
colorId: outfitState.colorId,
|
||||
pose: outfitState.pose,
|
||||
altStyleId: outfitState.altStyleId,
|
||||
appearanceId: outfitState.appearanceId,
|
||||
wornItemIds: outfitState.wornItemIds,
|
||||
onChangeHasAnimations: setHasAnimations,
|
||||
|
|
|
@ -413,11 +413,12 @@ function ItemSupportPetCompatibilityRuleFields({
|
|||
*/
|
||||
function ItemSupportAppearanceLayers({ item }) {
|
||||
const outfitState = React.useContext(OutfitStateContext);
|
||||
const { speciesId, colorId, pose, appearanceId } = outfitState;
|
||||
const { speciesId, colorId, pose, altStyleId, appearanceId } = outfitState;
|
||||
const { error, visibleLayers } = useOutfitAppearance({
|
||||
speciesId,
|
||||
colorId,
|
||||
pose,
|
||||
altStyleId,
|
||||
appearanceId,
|
||||
wornItemIds: [item.id],
|
||||
});
|
||||
|
|
|
@ -52,6 +52,7 @@ export function useOutfitPreview({
|
|||
speciesId,
|
||||
colorId,
|
||||
pose,
|
||||
altStyleId,
|
||||
wornItemIds,
|
||||
appearanceId = null,
|
||||
isLoading = false,
|
||||
|
@ -68,6 +69,7 @@ export function useOutfitPreview({
|
|||
speciesId,
|
||||
colorId,
|
||||
pose,
|
||||
altStyleId,
|
||||
appearanceId,
|
||||
wornItemIds,
|
||||
});
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
import React from "react";
|
||||
import gql from "graphql-tag";
|
||||
import { useQuery } from "@apollo/client";
|
||||
|
||||
import getVisibleLayers, {
|
||||
itemAppearanceFragmentForGetVisibleLayers,
|
||||
petAppearanceFragmentForGetVisibleLayers,
|
||||
} from "../components/getVisibleLayers";
|
||||
} from "./getVisibleLayers";
|
||||
import { useAltStyle } from "../loaders/alt-styles";
|
||||
|
||||
/**
|
||||
* useOutfitAppearance downloads the outfit's appearance data, and returns
|
||||
* visibleLayers for rendering.
|
||||
*/
|
||||
export default function useOutfitAppearance(outfitState) {
|
||||
const { wornItemIds, speciesId, colorId, pose, appearanceId } = outfitState;
|
||||
const { wornItemIds, speciesId, colorId, pose, altStyleId, appearanceId } =
|
||||
outfitState;
|
||||
|
||||
// We split this query out from the other one, so that we can HTTP cache it.
|
||||
//
|
||||
|
@ -102,7 +105,13 @@ export default function useOutfitAppearance(outfitState) {
|
|||
},
|
||||
);
|
||||
|
||||
const petAppearance = data1?.petAppearance;
|
||||
const {
|
||||
isLoading: loading3,
|
||||
error: error3,
|
||||
data: altStyle,
|
||||
} = useAltStyle(altStyleId, speciesId);
|
||||
|
||||
const petAppearance = altStyle?.appearance ?? data1?.petAppearance;
|
||||
const items = data2?.items;
|
||||
const itemAppearances = React.useMemo(
|
||||
() => (items || []).map((i) => i.appearance),
|
||||
|
@ -116,8 +125,8 @@ export default function useOutfitAppearance(outfitState) {
|
|||
const bodyId = petAppearance?.bodyId;
|
||||
|
||||
return {
|
||||
loading: loading1 || loading2,
|
||||
error: error1 || error2,
|
||||
loading: loading1 || loading2 || loading3,
|
||||
error: error1 || error2 || error3,
|
||||
petAppearance,
|
||||
items: items || [],
|
||||
itemAppearances,
|
||||
|
|
|
@ -8,6 +8,17 @@ export function useAltStylesForSpecies(speciesId, options = {}) {
|
|||
});
|
||||
}
|
||||
|
||||
// NOTE: This is actually just a wrapper for `useAltStylesForSpecies`, to share
|
||||
// the same cache key!
|
||||
export function useAltStyle(id, speciesId, options = {}) {
|
||||
const query = useAltStylesForSpecies(speciesId, options);
|
||||
|
||||
return {
|
||||
...query,
|
||||
data: query.data?.find((s) => s.id === id) ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
async function loadAltStylesForSpecies(speciesId) {
|
||||
const res = await fetch(
|
||||
`/species/${encodeURIComponent(speciesId)}/alt-styles.json`,
|
||||
|
@ -35,5 +46,37 @@ function normalizeAltStyle(altStyleData) {
|
|||
seriesName: altStyleData.series_name,
|
||||
adjectiveName: altStyleData.adjective_name,
|
||||
thumbnailUrl: altStyleData.thumbnail_url,
|
||||
|
||||
// This matches the PetAppearanceForOutfitPreview GQL fragment!
|
||||
appearance: {
|
||||
bodyId: String(altStyleData.body_id),
|
||||
pose: "UNKNOWN",
|
||||
isGlitched: false,
|
||||
species: { id: String(altStyleData.species_id) },
|
||||
color: { id: String(altStyleData.species_id) },
|
||||
layers: altStyleData.swf_assets.map(normalizeSwfAssetToLayer),
|
||||
restrictedZones: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeSwfAssetToLayer(swfAssetData) {
|
||||
return {
|
||||
id: String(swfAssetData.id),
|
||||
zone: {
|
||||
id: String(swfAssetData.zone.id),
|
||||
depth: swfAssetData.zone.depth,
|
||||
label: swfAssetData.zone.label,
|
||||
},
|
||||
bodyId: swfAssetData.body_id,
|
||||
knownGlitches: [], // TODO
|
||||
|
||||
// HACK: We're just simplifying this adapter, but it would be better to
|
||||
// actually check what file formats the manifest says!
|
||||
// TODO: For example, these do generally have SVGs, we could use them!
|
||||
svgUrl: null,
|
||||
canvasMovieLibraryUrl: null,
|
||||
imageUrl: swfAssetData.image_url,
|
||||
swfUrl: swfAssetData.url,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ class SwfAsset < ApplicationRecord
|
|||
size_key = size.join('x')
|
||||
|
||||
image_dir = "#{self['type']}/#{partition_path}#{self.remote_id}"
|
||||
"//#{host}/#{image_dir}/#{size_key}.png?#{image_version}"
|
||||
"https://#{host}/#{image_dir}/#{size_key}.png?#{image_version}"
|
||||
end
|
||||
|
||||
def images
|
||||
|
|
Loading…
Reference in a new issue