#16: Working PoC avatar image generator
This commit is contained in:
parent
68f7db7aa4
commit
bf58fc4944
6
package-lock.json
generated
6
package-lock.json
generated
@ -954,9 +954,9 @@
|
|||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/bullmq": {
|
"node_modules/bullmq": {
|
||||||
"version": "5.34.3",
|
"version": "5.34.4",
|
||||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.3.tgz",
|
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.4.tgz",
|
||||||
"integrity": "sha512-S8/V11w7p6jYAGvv+00skLza/4inTOupWPe0uCD8mZSUiYKzvmW4/YEB+KVjZI2CC2oD3KJ3t7/KkUd31MxMig==",
|
"integrity": "sha512-FPTN5eqsYO5/Blm6vh/bVJ0eADrVLjTBDjMkPCqZN3xx/5GqHov9NwxM6A6M3m6n2Vg+gNAoN98t7bTij5/UEA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cron-parser": "^4.6.0",
|
"cron-parser": "^4.6.0",
|
||||||
|
73
src/http/avatar.ts
Normal file
73
src/http/avatar.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* 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 '../utilities/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?.spriteId) {
|
||||||
|
return res.status(404).json({ message: 'Character type not found' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const bodySpritePath = getPublicPath('sprites', characterType.spriteId, '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)
|
||||||
|
|
||||||
|
if (options.characterHairId) {
|
||||||
|
const characterHair = await CharacterHairRepository.getById(options.characterHairId)
|
||||||
|
if (characterHair?.spriteId) {
|
||||||
|
const hairSpritePath = getPublicPath('sprites', characterHair.spriteId, 'front.png')
|
||||||
|
if (fs.existsSync(hairSpritePath)) {
|
||||||
|
avatar = avatar.composite([{ input: hairSpritePath, gravity: 'north' }])
|
||||||
|
} 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
|
@ -12,6 +12,11 @@ class CharacterHairRepository {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
async getById(id: number): Promise<CharacterHair | null> {
|
||||||
|
return prisma.characterHair.findUnique({
|
||||||
|
where: { id }
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new CharacterHairRepository()
|
export default new CharacterHairRepository()
|
||||||
|
@ -3,7 +3,19 @@ import { CharacterType } from '@prisma/client'
|
|||||||
|
|
||||||
class CharacterTypeRepository {
|
class CharacterTypeRepository {
|
||||||
async getAll(): Promise<CharacterType[]> {
|
async getAll(): Promise<CharacterType[]> {
|
||||||
return prisma.characterType.findMany()
|
return prisma.characterType.findMany({
|
||||||
|
include: {
|
||||||
|
sprite: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
async getById(id: number): Promise<CharacterType | null> {
|
||||||
|
return prisma.characterType.findUnique({
|
||||||
|
where: { id },
|
||||||
|
include: {
|
||||||
|
sprite: true
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user