import { resolveGordonBuildUrl } from '@/lib/services/import/core/gordon' import { siteSettings } from '@/lib/services/site-settings' import type { EffectMapEntry } from '@/types/effects' // Defaults to VALIDATE against a live fetch (spec Open Item #2). Override the // SWF source with the `effect_swf_base_url` site setting if these drift. const OFFICIAL_EFFECTMAP_URL = 'https://www.habbo.com/gamedata/effectmap/1' const CACHE_TTL = 30 * 60 * 1000 let effectCache: { list: EffectMapEntry[]; ts: number } | null = null export function __clearEffectSourceCache(): void { effectCache = null } function parseEffectMapXml(xml: string): EffectMapEntry[] { const out: EffectMapEntry[] = [] const re = /]*)\/?>/g for (const m of xml.matchAll(re)) { const attrs = m[1] const id = /\bid="([^"]*)"/.exec(attrs)?.[1] const lib = /\blib="([^"]*)"/.exec(attrs)?.[1] const type = /\btype="([^"]*)"/.exec(attrs)?.[1] ?? 'fx' const revision = Number(/\brevision="([^"]*)"/.exec(attrs)?.[1] ?? '0') if (id && lib) out.push({ id, lib, type, revision: Number.isFinite(revision) ? revision : 0 }) } return out } export async function listOfficialEffects(): Promise { const now = Date.now() if (effectCache && now - effectCache.ts < CACHE_TTL) return effectCache.list const res = await fetch(OFFICIAL_EFFECTMAP_URL, { signal: AbortSignal.timeout(20000) }) if (!res.ok) { console.warn(`[effect-source] effectmap fetch failed: ${res.status}`) return effectCache?.list ?? [] } const list = parseEffectMapXml(await res.text()) effectCache = { list, ts: now } return list } export async function resolveEffectSwfUrl(lib: string): Promise { const override = ((await siteSettings.get('effect_swf_base_url', '')) ?? '').trim() if (override) return `${override.replace(/\/+$/, '')}/${lib}.swf` const gordon = await resolveGordonBuildUrl() return `${gordon}${lib}.swf` }