From c79aa25dfb65f50e0dcaeb9df2843d2c62ac6056 Mon Sep 17 00:00:00 2001 From: TuanD Date: Thu, 9 Feb 2023 22:05:01 +0700 Subject: [PATCH] chore: use asset in nft response (#11) --- api/atlas.js | 7 +++-- api/resize.js | 6 ++-- public/interaction.json | 6 +++- src/characters/character.ts | 30 +++++++++---------- src/characters/player.ts | 4 +++ src/scenes/CharSelect.ts | 13 ++++---- src/scenes/Game/Map.ts | 2 ++ src/scenes/Pod/Map.ts | 1 + src/stores/game.ts | 14 ++++++++- src/ui/hud/CharSelect.tsx | 60 ++++++++++++++++++++++--------------- 10 files changed, 88 insertions(+), 55 deletions(-) diff --git a/api/atlas.js b/api/atlas.js index 1a61683..8c30593 100644 --- a/api/atlas.js +++ b/api/atlas.js @@ -6,14 +6,15 @@ import path from "path"; import { readFileSync } from "fs"; export default async function handler(req, res) { - const id = req.query.id; + const atlasURL = decodeURI(req.query.atlasURL); const spine = req.query.spine; + const id = req.query.id; const collection = req.query.collection; let text = ""; if (spine !== "TV-head") { - const url = `${process.env.VITE_CHARACTER_ASSET_PATH}/${spine}/Web/${id}/${spine}.atlas`; + // const url = `${process.env.VITE_CHARACTER_ASSET_PATH}/${spine}/Web/${id}/${spine}.atlas`; - const atlasRes = await fetch(url); + const atlasRes = await fetch(atlasURL); if (!atlasRes.ok) return res.status(404).end(); diff --git a/api/resize.js b/api/resize.js index 8feb63d..2cf908a 100644 --- a/api/resize.js +++ b/api/resize.js @@ -4,11 +4,11 @@ import sharp from "sharp"; import fetch from "isomorphic-unfetch"; export default async function handler(req, res) { - const id = req.query.id; - const collection = req.query.collection; + const textureURL = decodeURI(req.query.textureURL); const image = await fetch( - `${process.env.VITE_TV_HEAD_IMAGE_PATH}/${collection}/${id}` + textureURL + // `${process.env.VITE_TV_HEAD_IMAGE_PATH}/${collection}/${id}` ); const uintArray = new Uint8Array(await image.arrayBuffer()); if (image.ok) { diff --git a/public/interaction.json b/public/interaction.json index 13929a6..c322694 100644 --- a/public/interaction.json +++ b/public/interaction.json @@ -22,7 +22,11 @@ "character": { "id": 25, "spine": "Rabby", - "animSuffix": 1 + "animSuffix": 1, + "urls": { + "atlasURL": "https://storage.googleapis.com/pod-town/verse/char/Rabby/Web/25/Rabby.atlas", + "textureURL": "https://storage.googleapis.com/pod-town/verse/char/Rabby/Web/25/Rabby.png" + } } } ] diff --git a/src/characters/character.ts b/src/characters/character.ts index 588dd10..e7547f5 100644 --- a/src/characters/character.ts +++ b/src/characters/character.ts @@ -1,4 +1,4 @@ -import { CHARACTER_ASSET_PATH, NEKO_COL, RABBY_COL } from "envs"; +import { NEKO_COL, RABBY_COL } from "envs"; import { TILE_SIZE } from "../constants"; import { AnimationDirection, @@ -55,6 +55,10 @@ export class Character extends Phaser.GameObjects.GameObject { follower?: Character; spineConfig?: SpineGameObjectConfig; animSuffix?: string; + urls: { + atlasURL: string; + textureURL: string; + }; }) { const { scene, @@ -65,6 +69,7 @@ export class Character extends Phaser.GameObjects.GameObject { follower, spineConfig = {}, animSuffix = "", + urls: { atlasURL, textureURL }, } = props; super(scene, "character"); @@ -72,20 +77,15 @@ export class Character extends Phaser.GameObjects.GameObject { this.key = `${spine}/${collection}/${id}`; this.scene = scene; - let atlas = `/api/atlas?spine=${spine}&collection=${collection}&id=${id}`; - let texture = `${CHARACTER_ASSET_PATH}/${spine}/Web`; - - switch (spine) { - case "GhostNeko": - atlas = "/characters/ghost-neko/char.atlas"; - texture = ""; - break; - case "TV-head": - texture = `/api/resize?collection=${collection}&id=${id}`; - break; - default: - texture += `/${id}`; - texture += `/${spine}.png`; + let atlas = atlasURL; + if (spine !== "GhostNeko") { + atlas = `/api/atlas?spine=${spine}&collection=${collection}&id=${id}&atlasURL=${encodeURI( + atlasURL + )}`; + } + let texture = textureURL; + if (spine === "TV-head") { + texture = `/api/resize?textureURL=${encodeURI(textureURL)}`; } this.followee = followee; diff --git a/src/characters/player.ts b/src/characters/player.ts index 06c92d4..ea3916f 100644 --- a/src/characters/player.ts +++ b/src/characters/player.ts @@ -14,6 +14,10 @@ type Config = { spineConfig?: SpineGameObjectConfig; animSuffix?: string; collection?: string; + urls: { + atlasURL: string; + textureURL: string; + }; }; export class Player extends Phaser.GameObjects.GameObject { diff --git a/src/scenes/CharSelect.ts b/src/scenes/CharSelect.ts index fc86666..92321fa 100644 --- a/src/scenes/CharSelect.ts +++ b/src/scenes/CharSelect.ts @@ -1,7 +1,6 @@ import { Player } from "characters/player"; import Phaser from "phaser"; import { useGameState } from "stores/game"; -import { CharacterSpine } from "types/character"; import { SceneKey } from "../constants/scenes"; export default class CharSelect extends Phaser.Scene { @@ -31,12 +30,9 @@ export default class CharSelect extends Phaser.Scene { this.load.image("char-shadow", "/characters/shadow.png"); } - loadPlayer( - spine: CharacterSpine = "Neko", - id = 1, - animSuffix = "", - collection = "" - ) { + loadPlayer() { + const { player } = useGameState.getState(); + const { spine, id, animSuffix, collection, urls } = player; this.cameras.main.fadeIn(250); // Destroy existing player before creating new one if (this.player) { @@ -55,6 +51,7 @@ export default class CharSelect extends Phaser.Scene { }, animSuffix, collection, + urls, }); this.player.character?.loadPromise.then((instance) => { @@ -68,7 +65,7 @@ export default class CharSelect extends Phaser.Scene { this.cameras.main.once(Phaser.Cameras.Scene2D.Events.FADE_IN_COMPLETE, () => useGameState.setState({ activeSceneKey: SceneKey.CHAR_SELECT }) ); - this.loadPlayer("GhostNeko", 0, ""); + this.loadPlayer(); this.cameras.main.fadeIn(250); this.light = this.add .image( diff --git a/src/scenes/Game/Map.ts b/src/scenes/Game/Map.ts index 76b1483..6a0e9b0 100644 --- a/src/scenes/Game/Map.ts +++ b/src/scenes/Game/Map.ts @@ -195,6 +195,7 @@ export default class GameMap extends Phaser.Scene { y, scale: 0.4, }, + urls: properties.character.urls, }); char.loadPromise.then((instance) => { // since the NPC is not moving we might want to re extend the collision box so the player won't need to @@ -386,6 +387,7 @@ export default class GameMap extends Phaser.Scene { }, animSuffix: player.animSuffix, collection: player.collection, + urls: player.urls, }); this.player.character?.loadPromise.then((instance) => { diff --git a/src/scenes/Pod/Map.ts b/src/scenes/Pod/Map.ts index b8a46cd..17e8f43 100644 --- a/src/scenes/Pod/Map.ts +++ b/src/scenes/Pod/Map.ts @@ -133,6 +133,7 @@ export default class PodMap extends Phaser.Scene { }, animSuffix: player.animSuffix, collection: player.collection, + urls: player.urls, }); this.player.character?.loadPromise.then((instance) => { diff --git a/src/stores/game.ts b/src/stores/game.ts index e55b073..73ffbba 100644 --- a/src/stores/game.ts +++ b/src/stores/game.ts @@ -22,10 +22,14 @@ import { Menu, Minigame } from "constants/game"; import { utils } from "ethers"; import * as Sentry from "@sentry/react"; -const DEFAULT_PLAYER = { +export const DEFAULT_PLAYER = { id: 0, spine: "GhostNeko" as CharacterSpine, animSuffix: "", + urls: { + atlasURL: "/characters/ghost-neko/char.atlas", + textureURL: "", + }, }; const config: Phaser.Types.Core.GameConfig = { @@ -85,12 +89,20 @@ interface State { animSuffix: string; spine: CharacterSpine; id: number; + urls: { + atlasURL: string; + textureURL: string; + }; }; setPlayer: (p: { collection?: string; animSuffix: string; spine: CharacterSpine; id: number; + urls: { + atlasURL: string; + textureURL: string; + }; }) => void; stopScenes: (...scenes: Array) => void; diff --git a/src/ui/hud/CharSelect.tsx b/src/ui/hud/CharSelect.tsx index 0b22c88..4949c07 100644 --- a/src/ui/hud/CharSelect.tsx +++ b/src/ui/hud/CharSelect.tsx @@ -1,5 +1,5 @@ import { SceneKey } from "constants/scenes"; -import { useGameState } from "stores/game"; +import { DEFAULT_PLAYER, useGameState } from "stores/game"; import { useEffect, useMemo, useState } from "react"; import clsx from "clsx"; import { NFT } from "types/nfts"; @@ -44,7 +44,14 @@ export const CharSelect = () => { } = useGameState(); const [previewChar, setPreviewChar] = useState(ghostNekoItem); - const loadCharacter = (item: NFT, animSuffix: string) => { + const loadCharacter = ( + item: NFT, + animSuffix: string, + urls: { + atlasURL: string; + textureURL: string; + } + ) => { const id = Number(item.token_id); const spine = item.type; const collection = item.token_address; @@ -54,41 +61,46 @@ export const CharSelect = () => { id, spine, collection, + urls, }); setPreviewChar(item); - (getActiveScene() as CharSelectScene).loadPlayer( - spine, - id, - animSuffix, - collection - ); + (getActiveScene() as CharSelectScene).loadPlayer(); }; const selectCharToPreview = (item: NFT) => { if (item.type === "GhostNeko") { - loadCharacter(item, ""); - } else if (item.type === "TV-head") { - loadCharacter( - { - ...item, - name: "TV-Head", - description: - "Another default character of the Verse, but this time players get some degree of personalization with the NFT being the TV screen.", - }, - "" - ); + loadCharacter(item, "", DEFAULT_PLAYER.urls); } else { fetch( `${API_POD_BASE_URL}/verse/nfts/${item.token_address}/${item.token_id}` ) - .then((res) => (res.ok ? res.json() : new Error())) + .then((res) => + res.ok ? res.json() : new Error("Cound't load nfts of user") + ) .then((nftDetail) => { - const { anim_type } = nftDetail; + const { anim_type, character_type, asset, image } = nftDetail; + const webAsset = asset.find((a: any) => a.type === "Web"); const animSuffix = anim_type ? `_${anim_type}` : ""; + const isTVhead = character_type.toLowerCase() === "tv-head"; - loadCharacter(item, animSuffix); - }) - .catch(() => null); + loadCharacter( + { + ...item, + ...(isTVhead + ? { + name: "TV-Head", + description: + "Another default character of the Verse, but this time players get some degree of personalization with the NFT being the TV screen.", + } + : {}), + }, + animSuffix, + { + atlasURL: webAsset.atlas, + textureURL: isTVhead ? image : webAsset.img, + } + ); + }); } };