Support tools can set appearance glitched state!
this is also very good! :3
This commit is contained in:
parent
2929c3373e
commit
1c8eba4698
2 changed files with 170 additions and 7 deletions
|
@ -213,7 +213,7 @@ function PosePickerSupportNavigator({
|
||||||
function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
|
function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
|
||||||
const { supportSecret } = useSupport();
|
const { supportSecret } = useSupport();
|
||||||
|
|
||||||
const [mutate, { loading, error, data }] = useMutation(
|
const [mutatePose, poseMutation] = useMutation(
|
||||||
gql`
|
gql`
|
||||||
mutation PosePickerSupportSetPetAppearancePose(
|
mutation PosePickerSupportSetPetAppearancePose(
|
||||||
$appearanceId: ID!
|
$appearanceId: ID!
|
||||||
|
@ -248,6 +248,41 @@ function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [mutateIsGlitched, isGlitchedMutation] = useMutation(
|
||||||
|
gql`
|
||||||
|
mutation PosePickerSupportSetPetAppearanceIsGlitched(
|
||||||
|
$appearanceId: ID!
|
||||||
|
$isGlitched: Boolean!
|
||||||
|
$supportSecret: String!
|
||||||
|
) {
|
||||||
|
setPetAppearanceIsGlitched(
|
||||||
|
appearanceId: $appearanceId
|
||||||
|
isGlitched: $isGlitched
|
||||||
|
supportSecret: $supportSecret
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
isGlitched
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
refetchQueries: [
|
||||||
|
{
|
||||||
|
query: gql`
|
||||||
|
query PosePickerSupportRefetchCanonicalAppearances(
|
||||||
|
$speciesId: ID!
|
||||||
|
$colorId: ID!
|
||||||
|
) {
|
||||||
|
...CanonicalPetAppearances
|
||||||
|
}
|
||||||
|
${canonicalPetAppearancesFragment}
|
||||||
|
`,
|
||||||
|
variables: { speciesId, colorId },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Box display="flex" flexDirection="row" alignItems="center">
|
<Box display="flex" flexDirection="row" alignItems="center">
|
||||||
|
@ -255,10 +290,16 @@ function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
|
||||||
size="sm"
|
size="sm"
|
||||||
value={petAppearance.pose}
|
value={petAppearance.pose}
|
||||||
flex="0 1 200px"
|
flex="0 1 200px"
|
||||||
icon={loading ? <Spinner /> : data ? <CheckCircleIcon /> : undefined}
|
icon={
|
||||||
|
poseMutation.loading ? (
|
||||||
|
<Spinner />
|
||||||
|
) : poseMutation.data ? (
|
||||||
|
<CheckCircleIcon />
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const pose = e.target.value;
|
const pose = e.target.value;
|
||||||
mutate({
|
mutatePose({
|
||||||
variables: {
|
variables: {
|
||||||
appearanceId: petAppearance.id,
|
appearanceId: petAppearance.id,
|
||||||
pose,
|
pose,
|
||||||
|
@ -276,7 +317,7 @@ function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
|
||||||
/* Discard errors here; we'll show them in the UI! */
|
/* Discard errors here; we'll show them in the UI! */
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
isInvalid={error != null}
|
isInvalid={poseMutation.error != null}
|
||||||
>
|
>
|
||||||
{Object.entries(POSE_NAMES).map(([pose, name]) => (
|
{Object.entries(POSE_NAMES).map(([pose, name]) => (
|
||||||
<option key={pose} value={pose}>
|
<option key={pose} value={pose}>
|
||||||
|
@ -289,14 +330,45 @@ function PosePickerSupportPoseFields({ petAppearance, speciesId, colorId }) {
|
||||||
marginLeft="2"
|
marginLeft="2"
|
||||||
flex="0 1 150px"
|
flex="0 1 150px"
|
||||||
value={petAppearance.isGlitched}
|
value={petAppearance.isGlitched}
|
||||||
cursor="not-allowed"
|
icon={
|
||||||
isReadOnly
|
isGlitchedMutation.loading ? (
|
||||||
|
<Spinner />
|
||||||
|
) : isGlitchedMutation.data ? (
|
||||||
|
<CheckCircleIcon />
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
|
onChange={(e) => {
|
||||||
|
const isGlitched = e.target.value === "true";
|
||||||
|
mutateIsGlitched({
|
||||||
|
variables: {
|
||||||
|
appearanceId: petAppearance.id,
|
||||||
|
isGlitched,
|
||||||
|
supportSecret,
|
||||||
|
},
|
||||||
|
optimisticResponse: {
|
||||||
|
__typename: "Mutation",
|
||||||
|
setPetAppearanceIsGlitched: {
|
||||||
|
__typename: "PetAppearance",
|
||||||
|
id: petAppearance.id,
|
||||||
|
isGlitched,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).catch((e) => {
|
||||||
|
/* Discard errors here; we'll show them in the UI! */
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
isInvalid={isGlitchedMutation.error != null}
|
||||||
>
|
>
|
||||||
<option value="false">Valid</option>
|
<option value="false">Valid</option>
|
||||||
<option value="true">Glitched</option>
|
<option value="true">Glitched</option>
|
||||||
</Select>
|
</Select>
|
||||||
</Box>
|
</Box>
|
||||||
{error && <Box color="red.400">{error.message}</Box>}
|
{poseMutation.error && (
|
||||||
|
<Box color="red.400">{poseMutation.error.message}</Box>
|
||||||
|
)}
|
||||||
|
{isGlitchedMutation.error && (
|
||||||
|
<Box color="red.400">{isGlitchedMutation.error.message}</Box>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,6 +267,12 @@ const typeDefs = gql`
|
||||||
pose: Pose!
|
pose: Pose!
|
||||||
supportSecret: String!
|
supportSecret: String!
|
||||||
): PetAppearance!
|
): PetAppearance!
|
||||||
|
|
||||||
|
setPetAppearanceIsGlitched(
|
||||||
|
appearanceId: ID!
|
||||||
|
isGlitched: Boolean!
|
||||||
|
supportSecret: String!
|
||||||
|
): PetAppearance!
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -1027,6 +1033,91 @@ const resolvers = {
|
||||||
|
|
||||||
return { id: appearanceId };
|
return { id: appearanceId };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setPetAppearanceIsGlitched: async (
|
||||||
|
_,
|
||||||
|
{ appearanceId, isGlitched, supportSecret },
|
||||||
|
{
|
||||||
|
colorTranslationLoader,
|
||||||
|
speciesTranslationLoader,
|
||||||
|
petStateLoader,
|
||||||
|
petTypeLoader,
|
||||||
|
db,
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
if (supportSecret !== process.env["SUPPORT_SECRET"]) {
|
||||||
|
throw new Error(`Support secret is incorrect. Try setting up again?`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldPetState = await petStateLoader.load(appearanceId);
|
||||||
|
|
||||||
|
const [
|
||||||
|
result,
|
||||||
|
] = await db.execute(
|
||||||
|
`UPDATE pet_states SET glitched = ? WHERE id = ? LIMIT 1`,
|
||||||
|
[isGlitched, appearanceId]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.affectedRows !== 1) {
|
||||||
|
throw new Error(
|
||||||
|
`Expected to affect 1 layer, but affected ${result.affectedRows}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we changed it, so clear it from cache
|
||||||
|
petStateLoader.clear(appearanceId);
|
||||||
|
|
||||||
|
if (process.env["SUPPORT_TOOLS_DISCORD_WEBHOOK_URL"]) {
|
||||||
|
try {
|
||||||
|
const petType = await petTypeLoader.load(oldPetState.petTypeId);
|
||||||
|
const [colorTranslation, speciesTranslation] = await Promise.all([
|
||||||
|
colorTranslationLoader.load(petType.colorId),
|
||||||
|
speciesTranslationLoader.load(petType.speciesId),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const colorName = capitalize(colorTranslation.name);
|
||||||
|
const speciesName = capitalize(speciesTranslation.name);
|
||||||
|
|
||||||
|
const pose = getPoseFromPetState(oldPetState);
|
||||||
|
const oldGlitchinessState =
|
||||||
|
String(oldPetState.glitched) === "1" ? "Glitched" : "Valid";
|
||||||
|
const newGlitchinessState = isGlitched ? "Glitched" : "Valid";
|
||||||
|
|
||||||
|
await logToDiscord({
|
||||||
|
embeds: [
|
||||||
|
{
|
||||||
|
title: `🛠 ${colorName} ${speciesName}`,
|
||||||
|
thumbnail: {
|
||||||
|
url: `http://pets.neopets.com/cp/${
|
||||||
|
petType.basicImageHash || petType.imageHash
|
||||||
|
}/1/6.png`,
|
||||||
|
height: 150,
|
||||||
|
width: 150,
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: `Appearance ${appearanceId}`,
|
||||||
|
value: `${oldGlitchinessState} → **${newGlitchinessState}**`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "As a reminder…",
|
||||||
|
value: "…the thumbnail might not match!",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
url: `https://impress-2020.openneo.net/outfits/new?species=${petType.speciesId}&color=${petType.colorId}&pose=${pose}&state=${appearanceId}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error sending Discord support log", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("No Discord support webhook provided, skipping");
|
||||||
|
}
|
||||||
|
|
||||||
|
return { id: appearanceId };
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue