Continue working on spritesheet generator

This commit is contained in:
Dennis Postma 2025-01-28 14:29:45 +01:00
parent d17408acd9
commit dbdc8c9d6e
6 changed files with 122 additions and 77 deletions

112
package-lock.json generated
View File

@ -1843,17 +1843,17 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.21.0.tgz",
"integrity": "sha512-eTH+UOR4I7WbdQnG4Z48ebIA6Bgi7WO8HvFEneeYBxG8qCOYgTOFPSg6ek9ITIDvGjDQzWHcoWHCDO2biByNzA==",
"version": "8.22.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.22.0.tgz",
"integrity": "sha512-4Uta6REnz/xEJMvwf72wdUnC3rr4jAQf5jnTkeRQ9b6soxLxhDEbS/pfMPoJLDfFPNVRdryqWUIV/2GZzDJFZw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.21.0",
"@typescript-eslint/type-utils": "8.21.0",
"@typescript-eslint/utils": "8.21.0",
"@typescript-eslint/visitor-keys": "8.21.0",
"@typescript-eslint/scope-manager": "8.22.0",
"@typescript-eslint/type-utils": "8.22.0",
"@typescript-eslint/utils": "8.22.0",
"@typescript-eslint/visitor-keys": "8.22.0",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
@ -1873,16 +1873,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.21.0.tgz",
"integrity": "sha512-Wy+/sdEH9kI3w9civgACwabHbKl+qIOu0uFZ9IMKzX3Jpv9og0ZBJrZExGrPpFAY7rWsXuxs5e7CPPP17A4eYA==",
"version": "8.22.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.22.0.tgz",
"integrity": "sha512-MqtmbdNEdoNxTPzpWiWnqNac54h8JDAmkWtJExBVVnSrSmi9z+sZUt0LfKqk9rjqmKOIeRhO4fHHJ1nQIjduIQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.21.0",
"@typescript-eslint/types": "8.21.0",
"@typescript-eslint/typescript-estree": "8.21.0",
"@typescript-eslint/visitor-keys": "8.21.0",
"@typescript-eslint/scope-manager": "8.22.0",
"@typescript-eslint/types": "8.22.0",
"@typescript-eslint/typescript-estree": "8.22.0",
"@typescript-eslint/visitor-keys": "8.22.0",
"debug": "^4.3.4"
},
"engines": {
@ -1898,14 +1898,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.21.0.tgz",
"integrity": "sha512-G3IBKz0/0IPfdeGRMbp+4rbjfSSdnGkXsM/pFZA8zM9t9klXDnB/YnKOBQ0GoPmoROa4bCq2NeHgJa5ydsQ4mA==",
"version": "8.22.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.22.0.tgz",
"integrity": "sha512-/lwVV0UYgkj7wPSw0o8URy6YI64QmcOdwHuGuxWIYznO6d45ER0wXUbksr9pYdViAofpUCNJx/tAzNukgvaaiQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.21.0",
"@typescript-eslint/visitor-keys": "8.21.0"
"@typescript-eslint/types": "8.22.0",
"@typescript-eslint/visitor-keys": "8.22.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -1916,14 +1916,14 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.21.0.tgz",
"integrity": "sha512-95OsL6J2BtzoBxHicoXHxgk3z+9P3BEcQTpBKriqiYzLKnM2DeSqs+sndMKdamU8FosiadQFT3D+BSL9EKnAJQ==",
"version": "8.22.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.22.0.tgz",
"integrity": "sha512-NzE3aB62fDEaGjaAYZE4LH7I1MUwHooQ98Byq0G0y3kkibPJQIXVUspzlFOmOfHhiDLwKzMlWxaNv+/qcZurJA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/typescript-estree": "8.21.0",
"@typescript-eslint/utils": "8.21.0",
"@typescript-eslint/typescript-estree": "8.22.0",
"@typescript-eslint/utils": "8.22.0",
"debug": "^4.3.4",
"ts-api-utils": "^2.0.0"
},
@ -1940,9 +1940,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.21.0.tgz",
"integrity": "sha512-PAL6LUuQwotLW2a8VsySDBwYMm129vFm4tMVlylzdoTybTHaAi0oBp7Ac6LhSrHHOdLM3efH+nAR6hAWoMF89A==",
"version": "8.22.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz",
"integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==",
"dev": true,
"license": "MIT",
"engines": {
@ -1954,14 +1954,14 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.21.0.tgz",
"integrity": "sha512-x+aeKh/AjAArSauz0GiQZsjT8ciadNMHdkUSwBB9Z6PrKc/4knM4g3UfHml6oDJmKC88a6//cdxnO/+P2LkMcg==",
"version": "8.22.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.22.0.tgz",
"integrity": "sha512-SJX99NAS2ugGOzpyhMza/tX+zDwjvwAtQFLsBo3GQxiGcvaKlqGBkmZ+Y1IdiSi9h4Q0Lr5ey+Cp9CGWNY/F/w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.21.0",
"@typescript-eslint/visitor-keys": "8.21.0",
"@typescript-eslint/types": "8.22.0",
"@typescript-eslint/visitor-keys": "8.22.0",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
@ -1981,16 +1981,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.21.0.tgz",
"integrity": "sha512-xcXBfcq0Kaxgj7dwejMbFyq7IOHgpNMtVuDveK7w3ZGwG9owKzhALVwKpTF2yrZmEwl9SWdetf3fxNzJQaVuxw==",
"version": "8.22.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.22.0.tgz",
"integrity": "sha512-T8oc1MbF8L+Bk2msAvCUzjxVB2Z2f+vXYfcucE2wOmYs7ZUwco5Ep0fYZw8quNwOiw9K8GYVL+Kgc2pETNTLOg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "8.21.0",
"@typescript-eslint/types": "8.21.0",
"@typescript-eslint/typescript-estree": "8.21.0"
"@typescript-eslint/scope-manager": "8.22.0",
"@typescript-eslint/types": "8.22.0",
"@typescript-eslint/typescript-estree": "8.22.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -2005,13 +2005,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.21.0.tgz",
"integrity": "sha512-BkLMNpdV6prozk8LlyK/SOoWLmUFi+ZD+pcqti9ILCbVvHGk1ui1g4jJOc2WDLaeExz2qWwojxlPce5PljcT3w==",
"version": "8.22.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz",
"integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.21.0",
"@typescript-eslint/types": "8.22.0",
"eslint-visitor-keys": "^4.2.0"
},
"engines": {
@ -2470,9 +2470,9 @@
"license": "BSD-3-Clause"
},
"node_modules/bullmq": {
"version": "5.37.0",
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.37.0.tgz",
"integrity": "sha512-h/wf979+9uROyYpB8oTE44Py6JERCluCSd+ZFpCZlPsYh+wxAkqrfHsHHHKBgsNJp9odWLIY4SG+280EXzXiCQ==",
"version": "5.38.0",
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.38.0.tgz",
"integrity": "sha512-X6ApLQlSmX0LQ58xCpCoXE2nN57y8H9LD4EApJl9+8E6+FNWdKy6gykL8ofB9x4TcZeeGJhZOUZJAuhRV721bw==",
"license": "MIT",
"dependencies": {
"cron-parser": "^4.9.0",
@ -3042,16 +3042,16 @@
}
},
"node_modules/engine.io": {
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.3.tgz",
"integrity": "sha512-2hkLItQMBkoYSagneiisupWGvsQlWXqzhSMvsjaM8GYbnfUsX7tzYQq9QARnate5LRedVTX+MbkSZAANAr3NtQ==",
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
"integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
"license": "MIT",
"dependencies": {
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~1.0.2",
"cookie": "~0.7.2",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
@ -3071,12 +3071,12 @@
}
},
"node_modules/engine.io/node_modules/cookie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT",
"engines": {
"node": ">=18"
"node": ">= 0.6"
}
},
"node_modules/engine.io/node_modules/debug": {
@ -5265,9 +5265,9 @@
}
},
"node_modules/mariadb/node_modules/@types/node": {
"version": "22.10.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz",
"integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==",
"version": "22.12.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.12.0.tgz",
"integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"

View File

@ -46,9 +46,9 @@ export abstract class BaseEntity {
throw error
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message :
error && typeof error === 'object' && 'toString' in error ? error.toString() :
String(error)
const errorMessage = error instanceof Error ? error.message : error && typeof error === 'object' && 'toString' in error ? error.toString() : String(error)
console.log(errorMessage)
this.logger.error(`Failed to ${actionDescription}: ${errorMessage}`)
throw error
}

View File

@ -21,7 +21,7 @@ export default class ToggleFogCommand extends BaseEvent {
const args = ChatService.getArgs('fog', data.message)
await WeatherManager.setFogValue(args![0] ? Number(args![0]) : null);
await WeatherManager.setFogValue(args![0] ? Number(args![0]) : null)
callback(true)
} catch (error: any) {
this.logger.error('command error', error.message)

View File

@ -21,7 +21,7 @@ export default class ToggleRainCommand extends BaseEvent {
let args = ChatService.getArgs('rain', data.message)
await WeatherManager.setRainValue(args![0] ? Number(args![0]) : null);
await WeatherManager.setRainValue(args![0] ? Number(args![0]) : null)
callback(true)
} catch (error: any) {
this.logger.error('command error', error.message)

View File

@ -1,6 +1,8 @@
import { BaseEvent } from '#application/base/baseEvent'
import { UUID } from '#application/types'
import SpriteRepository from '#repositories/spriteRepository'
import { SpriteAction } from '#entities/spriteAction'
import sharp from 'sharp'
type Payload = {
id: UUID
@ -27,13 +29,35 @@ export default class SpriteUpdateEvent extends BaseEvent {
const sprite = await spriteRepository.getById(data.id)
if (!sprite) return callback(false)
await spriteRepository.getEntityManager().populate(sprite, ['spriteActions']);
await spriteRepository.getEntityManager().populate(sprite, ['spriteActions'])
// Update sprite in database
await sprite
.setName(data.name)
.setSpriteActions(data.spriteActions)
.save()
await sprite.setName(data.name).save()
const existingActions = sprite.getSpriteActions()
// Remove all existing actions - we'll recreate the ones we need
for (const existingAction of existingActions) {
await spriteRepository.getEntityManager().removeAndFlush(existingAction)
}
// Create new actions
for (const actionData of data.spriteActions) {
const spriteAction = new SpriteAction()
spriteAction.setSprite(sprite)
sprite.getSpriteActions().add(spriteAction)
spriteAction
.setAction(actionData.action)
.setSprites(actionData.sprites)
.setOriginX(actionData.originX)
.setOriginY(actionData.originY)
.setFrameWidth(await this.calculateWidth(actionData.sprites[0]))
.setFrameHeight(await this.calculateHeight(actionData.sprites[0]))
.setFrameRate(actionData.frameRate)
await spriteRepository.getEntityManager().persistAndFlush(spriteAction)
}
return callback(true)
} catch (error) {
@ -41,4 +65,28 @@ export default class SpriteUpdateEvent extends BaseEvent {
return callback(false)
}
}
private async calculateWidth(base64: string): Promise<number> {
const uri = base64.split(';base64,').pop()
if (!uri) return 0
const imgBuffer = Buffer.from(uri, 'base64')
const image = await sharp(imgBuffer).metadata()
return image.width ?? 0
}
private async calculateHeight(base64: string): Promise<number> {
const uri = base64.split(';base64,').pop()
if (!uri) return 0
const imgBuffer = Buffer.from(uri, 'base64')
const image = await sharp(imgBuffer).metadata()
return image.height ?? 0
}
private generateSpriteSheet(sprites: string[]) {
// In here comes a function that generates a sprite sheet from the given sprites using Sharp.
// This function takes an array of base64 encoded sprites and generates a single png sprite sheet.
// Then proceeds to save ths sprite sheet to the public/sprites/{spriteId}/ directory. The file name is {action}.png.
}
}

View File

@ -39,7 +39,7 @@ class WeatherManager {
return { ...this.weatherState }
}
public randomWeatherValue(type: 'rain' | 'fog' ) {
public randomWeatherValue(type: 'rain' | 'fog') {
switch (type) {
case 'rain':
return this.getRandomNumber(WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.min, WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.max)
@ -48,7 +48,7 @@ class WeatherManager {
}
}
public async setRainValue(value : number | null): Promise<void> {
public async setRainValue(value: number | null): Promise<void> {
if (value === null) {
value = this.randomWeatherValue('rain')
}
@ -57,7 +57,7 @@ class WeatherManager {
await this.saveAndEmitWeather()
}
public async setFogValue(value : number | null): Promise<void> {
public async setFogValue(value: number | null): Promise<void> {
if (value === null) {
value = this.randomWeatherValue('fog')
}
@ -90,7 +90,7 @@ class WeatherManager {
private updateRandomWeather(): void {
if (Math.random() < WeatherManager.CONFIG.RAIN_CHANCE) {
this.updateWeatherProperty('rain', this.randomWeatherValue('rain') )
this.updateWeatherProperty('rain', this.randomWeatherValue('rain'))
}
if (Math.random() < WeatherManager.CONFIG.FOG_CHANCE) {
this.updateWeatherProperty('fog', this.randomWeatherValue('fog'))
@ -124,10 +124,7 @@ class WeatherManager {
if (!world) world = new World()
//the data model still contains the booleans
await world
.setRainPercentage(this.weatherState.rainPercentage)
.setFogDensity(this.weatherState.fogDensity)
.save()
await world.setRainPercentage(this.weatherState.rainPercentage).setFogDensity(this.weatherState.fogDensity).save()
} catch (error) {
this.logError('save', error)
}