feat: add asset import services
This commit is contained in:
1 parent
4b596226e0
commit
3497df9dfd
46 files changed
+5383
No files matched your search
@@ -0,0 +1,64 @@
|
||||
import { cropRgba, decodePng } from '@/lib/services/imager/png-decode'
|
||||
import { encodePng, parseNitroBundle } from '@/lib/services/swf/nitro-builder'
|
||||
|
||||
interface FurniAsset {
|
||||
x?: number
|
||||
y?: number
|
||||
source?: string
|
||||
}
|
||||
interface FurniFrame {
|
||||
frame: { x: number; y: number; w: number; h: number }
|
||||
rotated?: boolean
|
||||
}
|
||||
interface FurniNitroJson {
|
||||
name?: string
|
||||
assets?: Record<string, FurniAsset>
|
||||
spritesheet?: { frames?: Record<string, FurniFrame> }
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the furni catalog icon — the `{name}_icon_a` sprite — from a Nitro
|
||||
* bundle and return it as a standalone PNG, or null if the bundle has no icon
|
||||
* asset / usable frame. Used for sources that embed furni icons inside the
|
||||
* `.nitro` instead of serving a separate `{classname}_icon.png`.
|
||||
*/
|
||||
export function extractFurniIconPng(nitro: Buffer): Buffer | null {
|
||||
let json: FurniNitroJson
|
||||
let png: Buffer
|
||||
try {
|
||||
const parsed = parseNitroBundle(nitro)
|
||||
json = parsed.json as FurniNitroJson
|
||||
png = parsed.png
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
const name = json.name
|
||||
if (!name || !json.assets) return null
|
||||
|
||||
// The icon asset is conventionally `${name}_icon_a`; fall back to any
|
||||
// `${name}_icon*` the bundle exposes.
|
||||
const iconKey = json.assets[`${name}_icon_a`]
|
||||
? `${name}_icon_a`
|
||||
: Object.keys(json.assets).find((k) => k.startsWith(`${name}_icon`))
|
||||
if (!iconKey) return null
|
||||
|
||||
const asset = json.assets[iconKey]
|
||||
// An asset may alias another's pixels via `source`; the frame key is the
|
||||
// bundle name prefixed onto the asset name. Different converters pack the
|
||||
// key with or without a trailing `.png`, so try both.
|
||||
const pixelAsset = asset.source ?? iconKey
|
||||
const frames = json.spritesheet?.frames ?? {}
|
||||
const frame = frames[`${name}_${pixelAsset}`] ?? frames[`${name}_${pixelAsset}.png`]
|
||||
if (!frame || frame.rotated) return null
|
||||
const { x, y, w, h } = frame.frame
|
||||
if (w <= 0 || h <= 0) return null
|
||||
|
||||
try {
|
||||
const sheet = decodePng(png)
|
||||
const px = cropRgba(sheet.rgba, sheet.width, x, y, w, h)
|
||||
return encodePng(w, h, px)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user