forked from noxious/server
Typescript fix, almost finished the sprite generator
This commit is contained in:
parent
e3bafca0ad
commit
fb6e9d2fcc
src
@ -1,38 +1,80 @@
|
||||
import { Server } from 'socket.io'
|
||||
import { TSocket } from '../../../utilities/Types'
|
||||
import prisma from '../../../utilities/Prisma'
|
||||
import type { SpriteAction } from '@prisma/client'
|
||||
import type { Prisma, SpriteAction } from '@prisma/client'
|
||||
import path from 'path'
|
||||
import { writeFile } from 'node:fs/promises'
|
||||
import fs from 'fs/promises'
|
||||
import spriteRepository from '../../../repositories/SpriteRepository'
|
||||
import sharp from 'sharp'
|
||||
|
||||
type SpriteActionInput = Omit<SpriteAction, 'id' | 'spriteId' | 'frameWidth' | 'frameHeight'> & {
|
||||
sprites: string[]
|
||||
}
|
||||
|
||||
type Payload = {
|
||||
id: string
|
||||
name: string
|
||||
spriteActions: SpriteAction[]
|
||||
spriteActions: Prisma.JsonValue
|
||||
}
|
||||
|
||||
export default function (socket: TSocket, io: Server) {
|
||||
socket.on('gm:sprite:update', async (data: Payload, callback: (success: boolean) => void) => {
|
||||
if (socket.character?.role !== 'gm') {
|
||||
callback(false)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// Parse and validate spriteActions
|
||||
let parsedSpriteActions: SpriteActionInput[];
|
||||
try {
|
||||
parsedSpriteActions = JSON.parse(JSON.stringify(data.spriteActions)) as SpriteActionInput[];
|
||||
if (!Array.isArray(parsedSpriteActions)) {
|
||||
throw new Error('spriteActions is not an array');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error parsing spriteActions:', error);
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Process the sprites to determine the largest dimensions
|
||||
const processedActions = await Promise.all(parsedSpriteActions.map(async (spriteAction) => {
|
||||
const { action, sprites } = spriteAction;
|
||||
|
||||
if (!Array.isArray(sprites) || sprites.length === 0) {
|
||||
throw new Error(`Invalid sprites array for action: ${action}`);
|
||||
}
|
||||
|
||||
// Convert base64 strings to buffers and get dimensions
|
||||
const buffersWithDimensions = await Promise.all(sprites.map(async (sprite: string) => {
|
||||
const buffer = Buffer.from(sprite.split(',')[1], 'base64');
|
||||
const { width, height } = await sharp(buffer).metadata();
|
||||
return { buffer, width, height };
|
||||
}));
|
||||
|
||||
// Find the largest width and height
|
||||
const frameWidth = Math.max(...buffersWithDimensions.map(b => b.width || 0));
|
||||
const frameHeight = Math.max(...buffersWithDimensions.map(b => b.height || 0));
|
||||
|
||||
return {
|
||||
...spriteAction,
|
||||
frameWidth,
|
||||
frameHeight,
|
||||
buffersWithDimensions
|
||||
};
|
||||
}));
|
||||
|
||||
// Update the database with the new sprite actions (including calculated frame sizes)
|
||||
await prisma.sprite.update({
|
||||
where: {
|
||||
id: data.id
|
||||
},
|
||||
where: { id: data.id },
|
||||
data: {
|
||||
name: data.name,
|
||||
spriteActions: {
|
||||
deleteMany: {
|
||||
spriteId: data.id
|
||||
},
|
||||
create: data.spriteActions.map((spriteAction) => ({
|
||||
deleteMany: { spriteId: data.id },
|
||||
create: processedActions.map((spriteAction) => ({
|
||||
action: spriteAction.action,
|
||||
sprites: spriteAction.sprites as string[],
|
||||
sprites: spriteAction.sprites,
|
||||
origin_x: spriteAction.origin_x,
|
||||
origin_y: spriteAction.origin_y,
|
||||
isAnimated: spriteAction.isAnimated,
|
||||
@ -43,19 +85,43 @@ export default function (socket: TSocket, io: Server) {
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const public_folder = path.join(process.cwd(), 'public', 'sprites', data.id)
|
||||
const public_folder = path.join(process.cwd(), 'public', 'sprites', data.id);
|
||||
await fs.mkdir(public_folder, { recursive: true });
|
||||
|
||||
// Ensure the folder exists
|
||||
await fs.mkdir(public_folder, { recursive: true })
|
||||
// Process and save each spriteAction
|
||||
await Promise.all(processedActions.map(async (spriteAction) => {
|
||||
const { action, buffersWithDimensions, frameWidth, frameHeight } = spriteAction;
|
||||
|
||||
const sprite = await spriteRepository.getById(data.id)
|
||||
// Combine all sprites into a single image
|
||||
const combinedImage = await sharp({
|
||||
create: {
|
||||
width: frameWidth * buffersWithDimensions.length,
|
||||
height: frameHeight,
|
||||
channels: 4,
|
||||
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
||||
}
|
||||
})
|
||||
.composite(
|
||||
buffersWithDimensions.map(({ buffer }, index) => ({
|
||||
input: buffer,
|
||||
left: index * frameWidth,
|
||||
top: 0
|
||||
}))
|
||||
)
|
||||
.png()
|
||||
.toBuffer();
|
||||
|
||||
callback(true)
|
||||
// Save the combined image
|
||||
const filename = path.join(public_folder, `${action}.png`);
|
||||
await writeFile(filename, combinedImage);
|
||||
}));
|
||||
|
||||
callback(true);
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
callback(false)
|
||||
console.error('Error updating sprite:', error);
|
||||
callback(false);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import prisma from '../utilities/Prisma' // Import the global Prisma instance
|
||||
import { Sprite } from '@prisma/client'
|
||||
import { Sprite, SpriteAction } from '@prisma/client'
|
||||
|
||||
class SpriteRepository {
|
||||
async getById(id: string): Promise<Sprite | null> {
|
||||
@ -19,7 +19,7 @@ class SpriteRepository {
|
||||
})
|
||||
}
|
||||
|
||||
async getSpriteActions(spriteId: string) {
|
||||
async getSpriteActions(spriteId: string): Promise<SpriteAction[]> {
|
||||
return prisma.spriteAction.findMany({
|
||||
where: {
|
||||
spriteId
|
||||
|
Loading…
x
Reference in New Issue
Block a user