npm update, http asset endpoint changes

This commit is contained in:
Dennis Postma 2024-10-25 22:21:06 +02:00
parent 5631930bf5
commit 9d08073fa8
4 changed files with 128 additions and 116 deletions

18
package-lock.json generated
View File

@ -719,9 +719,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.16.13", "version": "20.17.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.13.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.1.tgz",
"integrity": "sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==", "integrity": "sha512-j2VlPv1NnwPJbaCNv69FO/1z4lId0QmGvpT41YxitRtWlg96g/j8qcv2RKsLKe2F6OJgyXhupN1Xo17b2m139Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~6.19.2" "undici-types": "~6.19.2"
@ -926,9 +926,9 @@
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/bullmq": { "node_modules/bullmq": {
"version": "5.21.1", "version": "5.21.2",
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.21.1.tgz", "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.21.2.tgz",
"integrity": "sha512-+yvsd5LkbWkTW2K5C/1s8h1+gGK4F9wVfKM6AJUBSWGsbfWHXnni0Se7xHj1dieVkx6XEsfCzFtO6kZnD+mtHQ==", "integrity": "sha512-LPuNoGaDc5CON2X6h4cJ2iVfd+B+02xubFU+IB/fyJHd+/HqUZRqnlYryUCAuhVHBhUKtA6oyVdJxqSa62i+og==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cron-parser": "^4.6.0", "cron-parser": "^4.6.0",
@ -2479,9 +2479,9 @@
} }
}, },
"node_modules/socket.io": { "node_modules/socket.io": {
"version": "4.8.0", "version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
"integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==", "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"accepts": "~1.3.4", "accepts": "~1.3.4",

View File

@ -2,8 +2,7 @@ import { Zone } from '@prisma/client'
import ZoneRepository from '../repositories/zoneRepository' import ZoneRepository from '../repositories/zoneRepository'
import ZoneService from '../services/zoneService' import ZoneService from '../services/zoneService'
import LoadedZone from '../models/loadedZone' import LoadedZone from '../models/loadedZone'
import zoneRepository from '../repositories/zoneRepository' import { gameLogger } from '../utilities/logger'
import { gameMasterLogger } from '../utilities/logger'
class ZoneManager { class ZoneManager {
private loadedZones: LoadedZone[] = [] private loadedZones: LoadedZone[] = []
@ -21,36 +20,20 @@ class ZoneManager {
await this.loadZone(zone) await this.loadZone(zone)
} }
gameMasterLogger.info('Zone manager loaded') gameLogger.info('Zone manager loaded')
}
public async getZoneAssets(zone: Zone): Promise<ZoneAssets> {
const tiles: string[] = this.getUnique((JSON.parse(JSON.stringify(zone.tiles)) as string[][]).reduce((acc, val) => [...acc, ...val]))
const objects = await zoneRepository.getObjects(zone.id)
const mappedObjects = this.getUnique(objects.map((x) => x.objectId))
return {
tiles: tiles,
objects: mappedObjects
} as ZoneAssets
}
private getUnique<T>(array: T[]) {
return [...new Set<T>(array)]
} }
// Method to handle individual zoneEditor loading // Method to handle individual zoneEditor loading
public async loadZone(zone: Zone) { public async loadZone(zone: Zone) {
const loadedZone = new LoadedZone(zone) const loadedZone = new LoadedZone(zone)
this.loadedZones.push(loadedZone) this.loadedZones.push(loadedZone)
await this.getZoneAssets(zone) gameLogger.info(`Zone ID ${zone.id} loaded`)
gameMasterLogger.info(`Zone ID ${zone.id} loaded`)
} }
// Method to handle individual zoneEditor unloading // Method to handle individual zoneEditor unloading
public unloadZone(zoneId: number) { public unloadZone(zoneId: number) {
this.loadedZones = this.loadedZones.filter((loadedZone) => loadedZone.getZone().id !== zoneId) this.loadedZones = this.loadedZones.filter((loadedZone) => loadedZone.getZone().id !== zoneId)
gameMasterLogger.info(`Zone ID ${zoneId} unloaded`) gameLogger.info(`Zone ID ${zoneId} unloaded`)
} }
// Getter for loaded zones // Getter for loaded zones

View File

@ -2,6 +2,8 @@ import { Zone, ZoneEventTile, ZoneEventTileType, ZoneObject } from '@prisma/clie
import prisma from '../utilities/prisma' import prisma from '../utilities/prisma'
import { ZoneEventTileWithTeleport } from '../socketEvents/zone/characterMove' import { ZoneEventTileWithTeleport } from '../socketEvents/zone/characterMove'
import { appLogger } from '../utilities/logger' import { appLogger } from '../utilities/logger'
import { TAsset } from '../utilities/types'
import tileRepository from './tileRepository'
class ZoneRepository { class ZoneRepository {
async getFirst(): Promise<Zone | null> { async getFirst(): Promise<Zone | null> {
@ -22,7 +24,7 @@ class ZoneRepository {
} }
} }
async getById(id: number): Promise<Zone | null> { async getById(id: number) {
try { try {
return await prisma.zone.findUnique({ return await prisma.zone.findUnique({
where: { where: {
@ -77,7 +79,7 @@ class ZoneRepository {
} }
} }
async getObjects(id: number): Promise<ZoneObject[]> { async getZoneObjects(id: number): Promise<ZoneObject[]> {
try { try {
return await prisma.zoneObject.findMany({ return await prisma.zoneObject.findMany({
where: { where: {
@ -89,6 +91,52 @@ class ZoneRepository {
return [] return []
} }
} }
async getZoneAssets(zone_id: number): Promise<TAsset[]> {
const zone = await this.getById(zone_id)
if (!zone) return []
const assets: TAsset[] = []
// zone.tiles is prisma jsonvalue
let tiles = JSON.parse(JSON.stringify(zone.tiles))
tiles = [...new Set(tiles.flat())]
// Add tile assets
for (const tile of tiles) {
const tileInfo = await tileRepository.getById(tile)
if (!tileInfo) continue
assets.push({
key: tileInfo.id,
url: '/assets/tiles/' + tileInfo.id + '.png',
group: 'tiles',
updatedAt: tileInfo?.updatedAt || new Date()
})
}
// Add object assets
for (const zoneObject of zone.zoneObjects) {
if (!zoneObject.object) continue
assets.push({
key: zoneObject.object.id,
url: '/assets/objects/' + zoneObject.object.id + '.png',
group: 'objects',
updatedAt: zoneObject.object.updatedAt || new Date()
})
}
// Filter out duplicate assets
return assets.reduce((acc: TAsset[], current) => {
const x = acc.find((item) => item.key === current.key && item.group === current.group)
if (!x) {
return acc.concat([current])
} else {
return acc
}
}, [])
}
} }
export default new ZoneRepository() export default new ZoneRepository()

View File

@ -3,95 +3,12 @@ import UserService from '../services/userService'
import jwt from 'jsonwebtoken' import jwt from 'jsonwebtoken'
import config from './config' import config from './config'
import { loginAccountSchema, registerAccountSchema } from './zodTypes' import { loginAccountSchema, registerAccountSchema } from './zodTypes'
import { TAsset } from './types'
import tileRepository from '../repositories/tileRepository'
import objectRepository from '../repositories/objectRepository'
import spriteRepository from '../repositories/spriteRepository'
import fs from 'fs' import fs from 'fs'
import { httpLogger } from './logger' import { httpLogger } from './logger'
import { getPublicPath } from './storage' import { getPublicPath } from './storage'
import zoneRepository from '../repositories/zoneRepository'
async function addHttpRoutes(app: Application) { async function addHttpRoutes(app: Application) {
/**
* Get all base sprite, assets
* @param req
* @param res
*/
app.get('/assets', async (req: Request, res: Response) => {
let assets: TAsset[] = []
const sprites = await spriteRepository.getAll()
const tiles = await tileRepository.getAll()
const objects = await objectRepository.getAll()
// sprites all contain spriteActions, loop through these
sprites.forEach((sprite) => {
sprite.spriteActions.forEach((spriteAction) => {
assets.push({
key: sprite.id + '-' + spriteAction.action,
url: '/assets/sprites/' + sprite.id + '/' + spriteAction.action + '.png',
group: spriteAction.isAnimated ? 'sprite_animations' : 'sprites',
updatedAt: sprite.updatedAt,
frameCount: JSON.parse(JSON.stringify(spriteAction.sprites)).length,
frameWidth: spriteAction.frameWidth,
frameHeight: spriteAction.frameHeight,
})
})
})
// Get all tiles
tiles.forEach((tile) => {
assets.push({
key: tile.id,
url: '/assets/tiles/' + tile.id + '.png',
group: 'tiles',
updatedAt: tile.updatedAt
})
})
// Get all objects
objects.forEach((object) => {
assets.push({
key: object.id,
url: '/assets/objects/' + object.id + '.png',
group: 'objects',
updatedAt: object.updatedAt
})
})
res.json(assets)
})
/**
* Get a specific asset
* @param req
* @param res
*/
app.get('/assets/:type/:spriteId?/:file', (req: Request, res: Response) => {
const assetType = req.params.type
const spriteId = req.params.spriteId
const fileName = req.params.file
let assetPath
if (assetType === 'sprites' && spriteId) {
assetPath = getPublicPath(assetType, spriteId, fileName)
} else {
assetPath = getPublicPath(assetType, fileName)
}
if (!fs.existsSync(assetPath)) {
httpLogger.error(`File not found: ${assetPath}`)
return res.status(404).send('Asset not found')
}
res.sendFile(assetPath, (err) => {
if (err) {
httpLogger.error('Error sending file:', err)
res.status(500).send('Error downloading the asset')
}
})
})
/** /**
* Login * Login
* @param req * @param req
@ -141,6 +58,70 @@ async function addHttpRoutes(app: Application) {
return res.status(400).json({ message: 'Failed to register user' }) return res.status(400).json({ message: 'Failed to register user' })
}) })
/**
* Get all tiles from a zone as an array of ids
* @param req
* @param res
*/
app.get('/assets/tiles/:zoneId', async (req: Request, res: Response) => {
const zoneId = req.params.zoneId
// Check if zoneId is valid number
if (!zoneId || parseInt(zoneId) === 0) {
return res.status(400).json({ message: 'Invalid zone ID' })
}
// Get zone by id
const zone = await zoneRepository.getById(parseInt(zoneId))
if (!zone) {
return res.status(404).json({ message: 'Zone not found' })
}
let tiles = zone.tiles;
// Convert to array
tiles = JSON.parse(JSON.stringify(tiles)) as string[]
// Flatten the array
tiles = [...new Set(tiles.flat())]
// Remove duplicates
tiles = tiles.filter((value, index, self) => self.indexOf(value) === index);
// Return the array
res.json(tiles)
})
/**
* Get a specific asset
* @param req
* @param res
*/
app.get('/assets/:type/:spriteId?/:file', (req: Request, res: Response) => {
const assetType = req.params.type
const spriteId = req.params.spriteId
const fileName = req.params.file
let assetPath
if (assetType === 'sprites' && spriteId) {
assetPath = getPublicPath(assetType, spriteId, fileName)
} else {
assetPath = getPublicPath(assetType, fileName)
}
if (!fs.existsSync(assetPath)) {
httpLogger.error(`File not found: ${assetPath}`)
return res.status(404).send('Asset not found')
}
res.sendFile(assetPath, (err) => {
if (err) {
httpLogger.error('Error sending file:', err)
res.status(500).send('Error downloading the asset')
}
})
})
httpLogger.info('Web routes added') httpLogger.info('Web routes added')
} }