1
0
forked from noxious/server
This commit is contained in:
Dennis Postma 2025-01-31 01:03:33 +01:00
parent eaa7385acc
commit c400e868af

View File

@ -5,12 +5,20 @@ import { SpriteAction } from '#entities/spriteAction'
import sharp from 'sharp'
import fs from 'fs'
interface SpriteImage {
url: string
offset: {
x: number
y: number
}
}
type Payload = {
id: UUID
name: string
spriteActions: Array<{
action: string
sprites: string[]
sprites: SpriteImage[]
originX: number
originY: number
frameRate: number
@ -74,12 +82,12 @@ export default class SpriteUpdateEvent extends BaseEvent {
}
}
private async calculateMaxWidth(sprites: string[]): Promise<number> {
private async calculateMaxWidth(sprites: SpriteImage[]): Promise<number> {
if (!sprites.length) return 0
const widths = await Promise.all(
sprites.map(async (base64) => {
const uri = base64.split(';base64,').pop()
const uri = base64.url.split(';base64,').pop()
if (!uri) return 0
const imgBuffer = Buffer.from(uri, 'base64')
@ -91,12 +99,12 @@ export default class SpriteUpdateEvent extends BaseEvent {
return Math.max(...widths)
}
private async calculateMaxHeight(sprites: string[]): Promise<number> {
private async calculateMaxHeight(sprites: SpriteImage[]): Promise<number> {
if (!sprites.length) return 0
const heights = await Promise.all(
sprites.map(async (base64) => {
const uri = base64.split(';base64,').pop()
const uri = base64.url.split(';base64,').pop()
if (!uri) return 0
const imgBuffer = Buffer.from(uri, 'base64')
@ -108,46 +116,69 @@ export default class SpriteUpdateEvent extends BaseEvent {
return Math.max(...heights)
}
private async generateSpriteSheet(sprites: string[], spriteId: string, action: string): Promise<boolean> {
private async generateSpriteSheet(sprites: SpriteImage[], spriteId: string, action: string): Promise<boolean> {
try {
// Skip if no sprites
if (!sprites.length) return true
// Process all base64 images to buffers and get their dimensions
const imageData = await Promise.all(
sprites.map(async (base64) => {
const uri = base64.split(';base64,').pop()
sprites.map(async (sprite) => {
const uri = sprite.url.split(';base64,').pop()
if (!uri) throw new Error('Invalid base64 image')
const buffer = Buffer.from(uri, 'base64')
const metadata = await sharp(buffer).metadata()
return { buffer, width: metadata.width ?? 0, height: metadata.height ?? 0 }
return {
buffer,
width: metadata.width ?? 0,
height: metadata.height ?? 0,
offsetX: sprite.offset?.x ?? 0,
offsetY: sprite.offset?.y ?? 0
}
})
)
// Find the largest dimensions
const maxWidth = Math.max(...imageData.map((data) => data.width))
const maxHeight = Math.max(...imageData.map((data) => data.height))
// Find the largest dimensions including offsets
const effectiveDimensions = imageData.map(({ width, height, offsetX, offsetY }) => ({
width: width + Math.abs(offsetX),
height: height + Math.abs(offsetY),
top: offsetY >= 0 ? offsetY : 0,
bottom: offsetY < 0 ? Math.abs(offsetY) : 0
}))
const maxWidth = Math.max(...effectiveDimensions.map(d => d.width))
const maxHeight = Math.max(...effectiveDimensions.map(d => d.height))
const maxTop = Math.max(...effectiveDimensions.map(d => d.top))
const maxBottom = Math.max(...effectiveDimensions.map(d => d.bottom))
console.log(maxWidth, maxHeight)
// Calculate total height needed to accommodate all sprites with their offsets
const totalHeight = maxHeight + maxTop + maxBottom
// Extend all images to match the largest dimensions without resizing
const resizedBuffers = await Promise.all(
imageData.map(async ({ buffer, width, height }) => {
// Calculate padding to center the sprite
const topPadding = 0 // This is always 0. We don't need to calculate it
const bottomPadding = Math.ceil((maxHeight - height) / 2)
const leftPadding = Math.ceil((maxWidth - width) / 2)
const rightPadding = Math.ceil((maxWidth - width) / 2)
imageData.map(async ({ buffer, width, height, offsetX, offsetY }) => {
// Calculate the position of the image within the frame
const left = offsetX >= 0 ? offsetX : 0
// Position from bottom edge while respecting offsetY
const verticalOffset = totalHeight - height - (offsetY >= 0 ? offsetY : 0)
return await sharp(buffer)
.extend({
top: topPadding,
bottom: bottomPadding,
left: leftPadding,
right: rightPadding,
// Create a blank canvas of the maximum size
return await sharp({
create: {
width: maxWidth,
height: totalHeight,
channels: 4,
background: { r: 0, g: 0, b: 0, alpha: 0 }
})
.toBuffer()
}
})
.composite([
{
input: buffer,
left: left,
top: verticalOffset
}
])
.png()
.toBuffer()
})
)
@ -155,7 +186,7 @@ export default class SpriteUpdateEvent extends BaseEvent {
const spriteSheet = await sharp({
create: {
width: maxWidth * sprites.length,
height: maxHeight,
height: totalHeight,
channels: 4,
background: { r: 0, g: 0, b: 0, alpha: 0 }
}