1
0
forked from noxious/server
noxious_server/src/http/avatar.ts

86 lines
2.9 KiB
TypeScript

/**
* Avatar generator API routes
*/
import { Router, Request, Response } from 'express'
import sharp from 'sharp'
import fs from 'fs'
import CharacterRepository from '#repositories/characterRepository'
import CharacterHairRepository from '#repositories/characterHairRepository'
import CharacterTypeRepository from '#repositories/characterTypeRepository'
import { getPublicPath } from '#application/storage'
const router = Router()
interface AvatarOptions {
characterTypeId: number
characterHairId?: number
}
async function generateAvatar(res: Response, options: AvatarOptions) {
try {
const characterType = await CharacterTypeRepository.getById(options.characterTypeId)
if (!characterType?.sprite?.id) {
return res.status(404).json({ message: 'Character type not found' })
}
const bodySpritePath = getPublicPath('sprites', characterType.sprite.id, 'idle_right_down.png')
if (!fs.existsSync(bodySpritePath)) {
console.error(`Body sprite file not found: ${bodySpritePath}`)
return res.status(404).json({ message: 'Body sprite file not found' })
}
let avatar = sharp(bodySpritePath).extend({
top: 2,
bottom: 2,
background: { r: 0, g: 0, b: 0, alpha: 0 }
})
if (options.characterHairId) {
const characterHair = await CharacterHairRepository.getById(options.characterHairId)
if (characterHair?.sprite?.id) {
const hairSpritePath = getPublicPath('sprites', characterHair.sprite.id, 'front.png')
if (fs.existsSync(hairSpritePath)) {
avatar = avatar.composite([
{
input: hairSpritePath,
gravity: 'north'
// Top is originY in min @TODO finish me #287
// top: Math.round(Number(characterHair.sprite!.spriteActions.find((action) => action.action === 'front')?.originY ?? 0)),
// left: 0
}
])
} else {
console.error(`Hair sprite file not found: ${hairSpritePath}`)
}
}
}
res.setHeader('Content-Type', 'image/png')
return avatar.pipe(res)
} catch (error) {
console.error('Error generating avatar:', error)
return res.status(500).json({ message: 'Error generating avatar' })
}
}
router.get('/avatar/:characterName', async (req: Request, res: Response) => {
const character = await CharacterRepository.getByName(req.params.characterName)
if (!character?.characterType) {
return res.status(404).json({ message: 'Character or character type not found' })
}
return generateAvatar(res, {
characterTypeId: character.characterType.id,
characterHairId: character.characterHair?.id
})
})
router.get('/avatar/s/:characterTypeId/:characterHairId?', async (req: Request, res: Response) => {
return generateAvatar(res, {
characterTypeId: parseInt(req.params.characterTypeId),
characterHairId: req.params.characterHairId ? parseInt(req.params.characterHairId) : undefined
})
})
export default router