forked from noxious/server
Typescript fix, almost finished the sprite generator
This commit is contained in:
parent
e3bafca0ad
commit
fb6e9d2fcc
@ -1,38 +1,80 @@
|
|||||||
import { Server } from 'socket.io'
|
import { Server } from 'socket.io'
|
||||||
import { TSocket } from '../../../utilities/Types'
|
import { TSocket } from '../../../utilities/Types'
|
||||||
import prisma from '../../../utilities/Prisma'
|
import prisma from '../../../utilities/Prisma'
|
||||||
import type { SpriteAction } from '@prisma/client'
|
import type { Prisma, SpriteAction } from '@prisma/client'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { writeFile } from 'node:fs/promises'
|
import { writeFile } from 'node:fs/promises'
|
||||||
import fs from '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 = {
|
type Payload = {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
spriteActions: SpriteAction[]
|
spriteActions: Prisma.JsonValue
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function (socket: TSocket, io: Server) {
|
export default function (socket: TSocket, io: Server) {
|
||||||
socket.on('gm:sprite:update', async (data: Payload, callback: (success: boolean) => void) => {
|
socket.on('gm:sprite:update', async (data: Payload, callback: (success: boolean) => void) => {
|
||||||
if (socket.character?.role !== 'gm') {
|
if (socket.character?.role !== 'gm') {
|
||||||
|
callback(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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({
|
await prisma.sprite.update({
|
||||||
where: {
|
where: { id: data.id },
|
||||||
id: data.id
|
|
||||||
},
|
|
||||||
data: {
|
data: {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
spriteActions: {
|
spriteActions: {
|
||||||
deleteMany: {
|
deleteMany: { spriteId: data.id },
|
||||||
spriteId: data.id
|
create: processedActions.map((spriteAction) => ({
|
||||||
},
|
|
||||||
create: data.spriteActions.map((spriteAction) => ({
|
|
||||||
action: spriteAction.action,
|
action: spriteAction.action,
|
||||||
sprites: spriteAction.sprites as string[],
|
sprites: spriteAction.sprites,
|
||||||
origin_x: spriteAction.origin_x,
|
origin_x: spriteAction.origin_x,
|
||||||
origin_y: spriteAction.origin_y,
|
origin_y: spriteAction.origin_y,
|
||||||
isAnimated: spriteAction.isAnimated,
|
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
|
// Process and save each spriteAction
|
||||||
await fs.mkdir(public_folder, { recursive: true })
|
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) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error('Error updating sprite:', error);
|
||||||
callback(false)
|
callback(false);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import prisma from '../utilities/Prisma' // Import the global Prisma instance
|
import prisma from '../utilities/Prisma' // Import the global Prisma instance
|
||||||
import { Sprite } from '@prisma/client'
|
import { Sprite, SpriteAction } from '@prisma/client'
|
||||||
|
|
||||||
class SpriteRepository {
|
class SpriteRepository {
|
||||||
async getById(id: string): Promise<Sprite | null> {
|
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({
|
return prisma.spriteAction.findMany({
|
||||||
where: {
|
where: {
|
||||||
spriteId
|
spriteId
|
||||||
|
Loading…
x
Reference in New Issue
Block a user