forked from phenom/healer-man
59 lines
2.5 KiB
TypeScript
59 lines
2.5 KiB
TypeScript
import { SRGBColorSpace, Texture, TextureLoader } from "three";
|
|
import { fetchCombatMediaAsset, combatMediaPackReady } from "../game/combatMediaPack";
|
|
import { preloadCombatEffectManifest, shadowfiendOriginalModelAsset } from "../game/combatPresentation";
|
|
import { parseOriginalWowModelGraph, type OriginalWowModelGraph } from "./originalWowModelRuntime";
|
|
|
|
export interface ShadowfiendMedia {
|
|
readonly graph: OriginalWowModelGraph;
|
|
readonly textures: ReadonlyMap<number, Texture>;
|
|
}
|
|
|
|
let shadowfiendMediaRequest: Promise<ShadowfiendMedia | null> | null = null;
|
|
let preparedShadowfiendMedia: ShadowfiendMedia | null = null;
|
|
|
|
export function getPreparedShadowfiendMedia(): ShadowfiendMedia | null {
|
|
return combatMediaPackReady() ? preparedShadowfiendMedia : null;
|
|
}
|
|
|
|
/** Prepare the immutable client model once, before a Priest can cast in gameplay. */
|
|
export function preloadShadowfiendMedia(): Promise<ShadowfiendMedia | null> {
|
|
if (!combatMediaPackReady()) return Promise.resolve(null);
|
|
if (shadowfiendMediaRequest) return shadowfiendMediaRequest;
|
|
shadowfiendMediaRequest = (async () => {
|
|
await preloadCombatEffectManifest();
|
|
const url = shadowfiendOriginalModelAsset()?.effectGraphUrl;
|
|
if (!url) return null;
|
|
const response = await fetchCombatMediaAsset(url);
|
|
if (!response.ok) throw new Error(`Shadowfiend model request failed: ${response.status}`);
|
|
const graph = parseOriginalWowModelGraph(await response.json());
|
|
const textures = new Map<number, Texture>();
|
|
const ownedTextures: Texture[] = [];
|
|
const loader = new TextureLoader();
|
|
try {
|
|
for (const [index, source] of graph.textures.entries()) {
|
|
if (!source.url) continue;
|
|
const image = await fetchCombatMediaAsset(source.url);
|
|
if (!image.ok) throw new Error(`Shadowfiend texture request failed: ${image.status}`);
|
|
const objectUrl = URL.createObjectURL(await image.blob());
|
|
try {
|
|
const texture = await loader.loadAsync(objectUrl);
|
|
texture.colorSpace = SRGBColorSpace;
|
|
ownedTextures.push(texture);
|
|
textures.set(index, texture);
|
|
} finally {
|
|
URL.revokeObjectURL(objectUrl);
|
|
}
|
|
}
|
|
preparedShadowfiendMedia = { graph, textures };
|
|
return preparedShadowfiendMedia;
|
|
} catch (error) {
|
|
ownedTextures.forEach((texture) => texture.dispose());
|
|
throw error;
|
|
}
|
|
})().catch((error: unknown) => {
|
|
shadowfiendMediaRequest = null;
|
|
throw error;
|
|
});
|
|
return shadowfiendMediaRequest;
|
|
}
|