From 36c9522e8a9b94da6fac591cf0b119ec259ae305 Mon Sep 17 00:00:00 2001
From: Dennis Postma <dennis@directonline.io>
Date: Tue, 11 Mar 2025 23:53:27 +0100
Subject: [PATCH] Improvements

---
 .../gameMaster/assetManager/sprite/update.ts  | 136 ++++++++++--------
 src/mikro-orm.config.ts                       |   6 +-
 2 files changed, 77 insertions(+), 65 deletions(-)

diff --git a/src/events/gameMaster/assetManager/sprite/update.ts b/src/events/gameMaster/assetManager/sprite/update.ts
index 995bee4..7b3b319 100644
--- a/src/events/gameMaster/assetManager/sprite/update.ts
+++ b/src/events/gameMaster/assetManager/sprite/update.ts
@@ -76,12 +76,8 @@ export default class SpriteUpdateEvent extends BaseEvent {
         if (actionData.sprites.length === 0) continue
 
         // Generate and save the sprite sheet
-        const frameSize = await this.generateAndSaveSpriteSheet(
-            actionData.sprites,
-            sprite.getId(),
-            actionData.action
-        )
-        if (!frameSize) return false
+        const frameDimensions = await this.generateAndSaveSpriteSheet(actionData.sprites, sprite.getId(), actionData.action)
+        if (!frameDimensions) return false
 
         // Create and save sprite action
         const spriteAction = new SpriteAction()
@@ -89,13 +85,13 @@ export default class SpriteUpdateEvent extends BaseEvent {
         sprite.getSpriteActions().add(spriteAction)
 
         spriteAction
-            .setAction(actionData.action)
-            .setSprites(actionData.sprites)
-            .setOriginX(actionData.originX)
-            .setOriginY(actionData.originY)
-            .setFrameWidth(frameSize.width)
-            .setFrameHeight(frameSize.height)
-            .setFrameRate(actionData.frameRate)
+          .setAction(actionData.action)
+          .setSprites(actionData.sprites)
+          .setOriginX(actionData.originX)
+          .setOriginY(actionData.originY)
+          .setFrameWidth(frameDimensions.frameWidth)
+          .setFrameHeight(frameDimensions.frameHeight)
+          .setFrameRate(actionData.frameRate)
 
         await this.spriteRepository.getEntityManager().persistAndFlush(spriteAction)
       }
@@ -107,80 +103,96 @@ export default class SpriteUpdateEvent extends BaseEvent {
     }
   }
 
-  private async generateAndSaveSpriteSheet(
-      sprites: SpriteImage[],
-      spriteId: string,
-      action: string
-  ): Promise<{ width: number, height: number } | null> {
+  private async generateAndSaveSpriteSheet(sprites: SpriteImage[], spriteId: string, action: string): Promise<{ frameWidth: number; frameHeight: number } | null> {
     try {
-      if (sprites.length === 0) return { width: 0, height: 0 }
+      if (sprites.length === 0) return { frameWidth: 0, frameHeight: 0 }
 
-      // Extract image data from sprites
-      const imageBuffers = await Promise.all(
-          sprites.map(sprite => {
-            const base64Data = sprite.url.split(';base64,').pop()
-            if (!base64Data) throw new Error('Invalid base64 image')
-            return Buffer.from(base64Data, 'base64')
-          })
+      // Extract image data and get image metadata
+      const imagesData = await Promise.all(
+        sprites.map(async (sprite) => {
+          const base64Data = sprite.url.split(';base64,').pop()
+          if (!base64Data) throw new Error('Invalid base64 image')
+          const buffer = Buffer.from(base64Data, 'base64')
+          const metadata = await sharp(buffer).metadata()
+
+          return {
+            buffer,
+            width: metadata.width || 0,
+            height: metadata.height || 0
+          }
+        })
       )
 
-      // Get metadata for all images to find the maximum dimensions
-      const metadataList = await Promise.all(
-          imageBuffers.map(buffer => sharp(buffer).metadata())
-      )
-
-      // Calculate the maximum width and height across all frames
-      const maxWidth = Math.max(...metadataList.map(meta => meta.width || 0))
-      const maxHeight = Math.max(...metadataList.map(meta => meta.height || 0))
-
-      // Skip creation if we couldn't determine dimensions
-      if (maxWidth === 0 || maxHeight === 0) {
-        console.error('Could not determine sprite dimensions')
+      // Skip creation if any image has invalid dimensions
+      if (imagesData.some((data) => data.width === 0 || data.height === 0)) {
+        console.error('One or more sprites have invalid dimensions')
         return null
       }
 
-      // Resize all frames to the same dimensions
-      const resizedFrames = await Promise.all(
-          imageBuffers.map(async (buffer) => {
-            return sharp(buffer)
-                .resize({
-                  width: maxWidth,
-                  height: maxHeight,
-                  fit: 'contain',
-                  background: { r: 0, g: 0, b: 0, alpha: 0 }
-                })
-                .toBuffer()
+      // Calculate the maximum width and height to use for all frames
+      const maxWidth = Math.max(...imagesData.map((data) => data.width))
+      const maxHeight = Math.max(...imagesData.map((data) => data.height))
+
+      // Create frames of uniform size with the original sprites centered
+      const uniformFrames = await Promise.all(
+        imagesData.map(async (imageData) => {
+          // Calculate centering offsets to position the sprite in the middle of the frame
+          const xOffset = Math.floor((maxWidth - imageData.width) / 2)
+          const yOffset = Math.floor((maxHeight - imageData.height) / 2)
+
+          // Create a uniform-sized frame with the sprite centered
+          return sharp({
+            create: {
+              width: maxWidth,
+              height: maxHeight,
+              channels: 4,
+              background: { r: 0, g: 0, b: 0, alpha: 0 }
+            }
           })
+            .composite([
+              {
+                input: imageData.buffer,
+                left: xOffset,
+                top: yOffset
+              }
+            ])
+            .png()
+            .toBuffer()
+        })
       )
 
-      // Create sprite sheet with uniformly sized frames
+      // Create the sprite sheet with uniform frames
       const spriteSheet = await sharp({
         create: {
-          width: maxWidth * resizedFrames.length,
+          width: maxWidth * uniformFrames.length,
           height: maxHeight,
           channels: 4,
           background: { r: 0, g: 0, b: 0, alpha: 0 }
         }
       })
-          .composite(
-              resizedFrames.map((buffer, index) => ({
-                input: buffer,
-                left: index * maxWidth,
-                top: 0
-              }))
-          )
-          .png()
-          .toBuffer()
+        .composite(
+          uniformFrames.map((buffer, index) => ({
+            input: buffer,
+            left: index * maxWidth,
+            top: 0
+          }))
+        )
+        .png()
+        .toBuffer()
 
       // Save sprite sheet
       const dir = `public/sprites/${spriteId}`
       await fs.promises.mkdir(dir, { recursive: true })
       await fs.promises.writeFile(`${dir}/${action}.png`, spriteSheet)
 
-      return { width: maxWidth, height: maxHeight }
+      // Return the uniform frame dimensions
+      return {
+        frameWidth: maxWidth,
+        frameHeight: maxHeight
+      }
     } catch (error) {
       console.error('Error generating sprite sheet:', error)
       return null
     }
   }
-}
\ No newline at end of file
+}
diff --git a/src/mikro-orm.config.ts b/src/mikro-orm.config.ts
index f1844ef..5f21b31 100644
--- a/src/mikro-orm.config.ts
+++ b/src/mikro-orm.config.ts
@@ -1,7 +1,7 @@
 import serverConfig from '@/application/config'
 import { Migrator } from '@mikro-orm/migrations'
-// import { defineConfig, MariaDbDriver } from '@mikro-orm/mariadb'
-import { defineConfig, MySqlDriver } from '@mikro-orm/mysql'
+import { defineConfig, MariaDbDriver } from '@mikro-orm/mariadb'
+// import { defineConfig, MySqlDriver } from '@mikro-orm/mysql'
 import { TsMorphMetadataProvider } from '@mikro-orm/reflection'
 
 export default defineConfig({
@@ -9,7 +9,7 @@ export default defineConfig({
   metadataProvider: TsMorphMetadataProvider,
   entities: ['./src/entities/*.ts'],
   entitiesTs: ['./src/entities/*.ts'],
-  driver: MySqlDriver,
+  driver: MariaDbDriver,
   host: serverConfig.DB_HOST,
   port: serverConfig.DB_PORT,
   user: serverConfig.DB_USER,