#169 : Re-enabled command manager, created extrudeTiles command for testing

This commit is contained in:
Dennis Postma 2024-09-30 19:02:55 +02:00
parent ddeee356b4
commit 3a83f2c1ff
5 changed files with 169 additions and 32 deletions

6
package-lock.json generated
View File

@ -982,9 +982,9 @@
"license": "BSD-3-Clause"
},
"node_modules/bullmq": {
"version": "5.13.2",
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.13.2.tgz",
"integrity": "sha512-McGE8k3mrCvdUHdU0sHkTKDS1xr4pff+hbEKBY51wk5S6Za0gkuejYA620VQTo3Zz37E/NVWMgumwiXPQ3yZcA==",
"version": "5.14.0",
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.14.0.tgz",
"integrity": "sha512-qxZHtRuGEp0oHM1aNokuZ4gA0xr6vcZQPe1OLuQoDTuhaEXB4faxApUoo85v/PHnzrniAAqNT9kqD+UBbmECDQ==",
"license": "MIT",
"dependencies": {
"cron-parser": "^4.6.0",

View File

@ -0,0 +1,136 @@
import { Server } from 'socket.io'
import ZoneManager from '../managers/zoneManager'
import sharp from 'sharp'
import path from 'path'
import fs from 'fs'
import { commandLogger } from '../utilities/logger'
type CommandInput = string[]
/**
* Extrude tiles command
* This command will get all the tiles inside process.cwd() > public > tiles
* And overwrite the existing tiles.
* @param input
* @param io
*/
export default async function extrudeTiles(input: CommandInput, io: Server) {
const [tileWidth, tileHeight, extrusion = '1', color = '0xffffff00'] = input
if (!tileWidth || !tileHeight) {
console.log('Missing tileWidth or tileHeight! Usage: extrudeTiles <tileWidth> <tileHeight> [extrusion] [color]')
return
}
const options = {
tileWidth: parseInt(tileWidth),
tileHeight: parseInt(tileHeight),
extrusion: parseInt(extrusion),
color: parseInt(color, 16)
}
const tilesDir = path.join(process.cwd(), 'public', 'tiles')
const files = fs.readdirSync(tilesDir).filter(file => file.endsWith('.png'))
for (const file of files) {
const inputPath = path.join(tilesDir, file)
const outputPath = path.join(tilesDir, `${path.parse(file).name}.png`)
try {
await extrudeTile(
options.tileWidth,
options.tileHeight,
inputPath,
outputPath,
options.extrusion,
options.color
)
commandLogger.info(`Extruded tile ${file}`)
} catch (error: any) {
console.log(error)
commandLogger.error('Error extruding tile:', error.message)
}
}
}
async function extrudeTile(
tileWidth: number,
tileHeight: number,
inputPath: string,
outputPath: string,
extrusion: number,
backgroundColor: number
) {
const borderWidth = 4; // You can adjust this value to change the border width
const image = sharp(inputPath)
const metadata = await image.metadata()
if (!metadata.width || !metadata.height) {
throw new Error('Unable to get image dimensions')
}
const tilesX = Math.floor(metadata.width / tileWidth)
const tilesY = Math.floor(metadata.height / tileHeight)
// Use borderWidth in the new dimensions calculation
const newWidth = metadata.width + (tilesX + 1) * extrusion + tilesX * borderWidth * 2
const newHeight = metadata.height + (tilesY + 1) * extrusion + tilesY * borderWidth * 2
const background = {
r: (backgroundColor >> 24) & 0xff,
g: (backgroundColor >> 16) & 0xff,
b: (backgroundColor >> 8) & 0xff,
alpha: backgroundColor & 0xff
}
const newImage = sharp({
create: {
width: newWidth,
height: newHeight,
channels: 4,
background
}
})
const compositeOperations = []
for (let y = 0; y < tilesY; y++) {
for (let x = 0; x < tilesX; x++) {
const tileBuffer = await image
.extract({
left: x * tileWidth,
top: y * tileHeight,
width: tileWidth,
height: tileHeight
})
.extend({
top: borderWidth,
bottom: borderWidth,
left: borderWidth,
right: borderWidth,
background: { r: 0, g: 0, b: 0, alpha: 0 }
})
.raw()
.toBuffer()
compositeOperations.push({
input: tileBuffer,
// Use borderWidth in positioning calculation
left: x * (tileWidth + extrusion + borderWidth * 2),
top: y * (tileHeight + extrusion + borderWidth * 2),
raw: {
width: tileWidth + borderWidth * 2,
height: tileHeight + borderWidth * 2,
channels: 4
}
})
}
}
await newImage
// @ts-ignore
.composite(compositeOperations)
.png()
.toFile(outputPath)
}

View File

@ -2,6 +2,7 @@ import * as readline from 'readline'
import * as fs from 'fs'
import * as path from 'path'
import { Server } from 'socket.io'
import { commandLogger } from '../utilities/logger'
class CommandManager {
private commands: Map<string, Function> = new Map()
@ -23,7 +24,7 @@ class CommandManager {
public async boot(io: Server) {
this.io = io
await this.loadCommands()
console.log('[✅] Command manager loaded')
commandLogger.info('Command manager loaded')
this.startPrompt()
}
@ -48,7 +49,6 @@ class CommandManager {
private handleUnknownCommand(command: string) {
switch (command) {
case 'exit':
console.log('Goodbye!')
this.rl.close()
break
default:
@ -58,7 +58,7 @@ class CommandManager {
}
private async loadCommands() {
const commandsDir = path.resolve(__dirname, 'commands')
const commandsDir = path.resolve(process.cwd(), 'src', 'commands')
try {
const files: string[] = await fs.promises.readdir(commandsDir)
@ -66,7 +66,7 @@ class CommandManager {
await this.loadCommand(commandsDir, file)
}
} catch (error) {
console.error('[❌] Failed to read commands directory:', error)
commandLogger.error(`Failed to read commands directory: ${error}`)
}
}
@ -79,16 +79,16 @@ class CommandManager {
this.registerCommand(commandName, module.default)
} catch (error) {
console.error('[❌] Failed to load command:', file, error)
commandLogger.error(`Failed to load command: ${file}: ${error}`)
}
}
private registerCommand(name: string, command: (args: string[], io: Server) => void) {
if (this.commands.has(name)) {
console.warn(`Command '${name}' is already registered. Overwriting...`)
commandLogger.warn(`Command '${name}' is already registered. Overwriting...`)
}
this.commands.set(name, command)
console.log(`Registered command: ${name}`)
commandLogger.info(`Registered command: ${name}`)
}
}

View File

@ -1,19 +1,19 @@
import fs from 'fs'
import path from 'path'
import express, { Application } from 'express'
import config from './utilities/config'
import { createServer as httpServer, Server as HTTPServer } from 'http'
import { addHttpRoutes } from './utilities/http'
import cors from 'cors'
import { Server as SocketServer } from 'socket.io'
import { TSocket } from './utilities/types'
import config from './utilities/config'
import prisma from './utilities/prisma'
import ZoneManager from './managers/zoneManager'
import UserManager from './managers/userManager'
import { Authentication } from './middleware/authentication'
// import CommandManager from './managers/CommandManager'
import { TSocket } from './utilities/types'
import prisma from './utilities/prisma'
import { Dirent } from 'node:fs'
import { appLogger, watchLogs } from './utilities/logger'
import ZoneManager from './managers/zoneManager'
import UserManager from './managers/userManager'
import CommandManager from './managers/commandManager'
import CharacterManager from './managers/characterManager'
import QueueManager from './managers/queueManager'
@ -58,12 +58,12 @@ export class Server {
appLogger.error(`Socket.IO failed to start: ${error.message}`)
}
// Load queue manager
await QueueManager.boot(this.io)
// Add http API routes
await addHttpRoutes(this.app)
// Load queue manager
await QueueManager.boot(this.io)
// Load user manager
await UserManager.boot()
@ -73,8 +73,8 @@ export class Server {
// Load character manager
await CharacterManager.boot()
// Load command manager - Disabled for now
// await CommandManager.boot(this.io);
// Load command manager
await CommandManager.boot(this.io);
// Listen for socket connections
this.io.on('connection', this.handleConnection.bind(this))
@ -106,15 +106,9 @@ export class Server {
try {
const module = await import(fullPath)
if (typeof module.default === 'function') {
if (module.default.prototype && module.default.prototype.listen) {
// This is a class-based event
const EventClass = module.default
const eventInstance = new EventClass(this.io, socket)
eventInstance.listen()
} else {
// This is a function-based event
module.default(this.io, socket)
}
const EventClass = module.default
const eventInstance = new EventClass(this.io, socket)
eventInstance.listen()
} else {
appLogger.warn(`Unrecognized export in ${file.name}`)
}

View File

@ -3,7 +3,7 @@ import fs from 'fs'
import path from 'path'
// Array of log types
const LOG_TYPES = ['http', 'game', 'gameMaster', 'app', 'queue'] as const
const LOG_TYPES = ['http', 'game', 'gameMaster', 'app', 'queue', 'command'] as const
type LogType = (typeof LOG_TYPES)[number]
const createLogger = (name: LogType) =>
@ -43,6 +43,13 @@ const watchLogs = () => {
})
}
export const { http: httpLogger, game: gameLogger, gameMaster: gameMasterLogger, app: appLogger, queue: queueLogger } = loggers
export const {
http: httpLogger,
game: gameLogger,
gameMaster: gameMasterLogger,
app: appLogger,
queue: queueLogger,
command: commandLogger
} = loggers
export { watchLogs }