Matchu
81b2a2b4a2
We add jsbuilding-rails to get esbuild running in the app, and then we copy-paste the files we need from impress-2020 into here! I stopped at the point where it was building successfully, but it's not running correctly: it's not sure about `process.env` in `next`, and I think the right next step is to delete the NextJS deps altogether and use React Router instead.
135 lines
4.8 KiB
JavaScript
135 lines
4.8 KiB
JavaScript
import gql from "graphql-tag";
|
|
|
|
function getVisibleLayers(petAppearance, itemAppearances) {
|
|
if (!petAppearance) {
|
|
return [];
|
|
}
|
|
|
|
const validItemAppearances = itemAppearances.filter((a) => a);
|
|
|
|
const petLayers = petAppearance.layers.map((l) => ({ ...l, source: "pet" }));
|
|
|
|
const itemLayers = validItemAppearances
|
|
.map((a) => a.layers)
|
|
.flat()
|
|
.map((l) => ({ ...l, source: "item" }));
|
|
|
|
let allLayers = [...petLayers, ...itemLayers];
|
|
|
|
const itemRestrictedZoneIds = new Set(
|
|
validItemAppearances
|
|
.map((a) => a.restrictedZones)
|
|
.flat()
|
|
.map((z) => z.id)
|
|
);
|
|
const petRestrictedZoneIds = new Set(
|
|
petAppearance.restrictedZones.map((z) => z.id)
|
|
);
|
|
|
|
const visibleLayers = allLayers.filter((layer) => {
|
|
// When an item restricts a zone, it hides pet layers of the same zone.
|
|
// We use this to e.g. make a hat hide a hair ruff.
|
|
//
|
|
// NOTE: Items' restricted layers also affect what items you can wear at
|
|
// the same time. We don't enforce anything about that here, and
|
|
// instead assume that the input by this point is valid!
|
|
if (layer.source === "pet" && itemRestrictedZoneIds.has(layer.zone.id)) {
|
|
return false;
|
|
}
|
|
|
|
// When a pet appearance restricts a zone, or when the pet is Unconverted,
|
|
// it makes body-specific items incompatible. We use this to disallow UCs
|
|
// from wearing certain body-specific Biology Effects, Statics, etc, while
|
|
// still allowing non-body-specific items in those zones! (I think this
|
|
// happens for some Invisible pet stuff, too?)
|
|
//
|
|
// TODO: We shouldn't be *hiding* these zones, like we do with items; we
|
|
// should be doing this way earlier, to prevent the item from even
|
|
// showing up even in search results!
|
|
//
|
|
// NOTE: This can result in both pet layers and items occupying the same
|
|
// zone, like Static, so long as the item isn't body-specific! That's
|
|
// correct, and the item layer should be on top! (Here, we implement
|
|
// it by placing item layers second in the list, and rely on JS sort
|
|
// stability, and *then* rely on the UI to respect that ordering when
|
|
// rendering them by depth. Not great! 😅)
|
|
//
|
|
// NOTE: We used to also include the pet appearance's *occupied* zones in
|
|
// this condition, not just the restricted zones, as a sensible
|
|
// defensive default, even though we weren't aware of any relevant
|
|
// items. But now we know that actually the "Bruce Brucey B Mouth"
|
|
// occupies the real Mouth zone, and still should be visible and
|
|
// above pet layers! So, we now only check *restricted* zones.
|
|
//
|
|
// NOTE: UCs used to implement their restrictions by listing specific
|
|
// zones, but it seems that the logic has changed to just be about
|
|
// UC-ness and body-specific-ness, and not necessarily involve the
|
|
// set of restricted zones at all. (This matters because e.g. UCs
|
|
// shouldn't show _any_ part of the Rainy Day Umbrella, but most UCs
|
|
// don't restrict Right-Hand Item (Zone 49).) Still, I'm keeping the
|
|
// zone restriction case running too, because I don't think it
|
|
// _hurts_ anything, and I'm not confident enough in this conclusion.
|
|
//
|
|
// TODO: Do Invisibles follow this new rule like UCs, too? Or do they still
|
|
// use zone restrictions?
|
|
if (
|
|
layer.source === "item" &&
|
|
layer.bodyId !== "0" &&
|
|
(petAppearance.pose === "UNCONVERTED" ||
|
|
petRestrictedZoneIds.has(layer.zone.id))
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
// A pet appearance can also restrict its own zones. The Wraith Uni is an
|
|
// interesting example: it has a horn, but its zone restrictions hide it!
|
|
if (layer.source === "pet" && petRestrictedZoneIds.has(layer.zone.id)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
visibleLayers.sort((a, b) => a.zone.depth - b.zone.depth);
|
|
|
|
return visibleLayers;
|
|
}
|
|
|
|
// TODO: The web client could save bandwidth by applying @client to the `depth`
|
|
// field, because it already has zone depths cached.
|
|
export const itemAppearanceFragmentForGetVisibleLayers = gql`
|
|
fragment ItemAppearanceForGetVisibleLayers on ItemAppearance {
|
|
id
|
|
layers {
|
|
id
|
|
bodyId
|
|
zone {
|
|
id
|
|
depth
|
|
}
|
|
}
|
|
restrictedZones {
|
|
id
|
|
}
|
|
}
|
|
`;
|
|
|
|
// TODO: The web client could save bandwidth by applying @client to the `depth`
|
|
// field, because it already has zone depths cached.
|
|
export const petAppearanceFragmentForGetVisibleLayers = gql`
|
|
fragment PetAppearanceForGetVisibleLayers on PetAppearance {
|
|
id
|
|
pose
|
|
layers {
|
|
id
|
|
zone {
|
|
id
|
|
depth
|
|
}
|
|
}
|
|
restrictedZones {
|
|
id
|
|
}
|
|
}
|
|
`;
|
|
|
|
export default getVisibleLayers;
|