Renamed utilities to files, added datetimeManager, npm update

This commit is contained in:
2024-10-13 12:15:29 +02:00
parent 2008646a3f
commit 049b9de2b3
20 changed files with 157 additions and 43 deletions

View File

@ -2,7 +2,7 @@ import fs from 'fs'
import sharp from 'sharp'
import { commandLogger } from '../utilities/logger'
import { Server } from 'socket.io'
import { getPublicPath } from '../utilities/utilities'
import { getPublicPath } from '../utilities/files'
import path from 'path'
export default class TilesCommand {

View File

@ -3,7 +3,7 @@ import * as fs from 'fs'
import * as path from 'path'
import { Server } from 'socket.io'
import { commandLogger } from '../utilities/logger'
import { getAppPath } from '../utilities/utilities'
import { getAppPath } from '../utilities/files'
class CommandManager {
private commands: Map<string, any> = new Map()

View File

@ -0,0 +1,84 @@
// src/managers/datetimeManager.ts
import fs from 'fs/promises'
import { Server } from 'socket.io'
import { appLogger } from '../utilities/logger'
import { createDir, doesPathExist, getRootPath } from '../utilities/files'
class DatetimeManager {
private static readonly GAME_SPEED = 24 / 3 // 24 hours / 3 hours = 8x speed
private static readonly UPDATE_INTERVAL = 1000 // Update every second for smooth second transitions
private io: Server | null = null
private intervalId: NodeJS.Timeout | null = null
public async boot(io: Server): Promise<void> {
this.io = io
this.startDateTimeLoop()
appLogger.info('Datetime manager loaded')
}
public stop(): void {
if (this.intervalId) {
clearInterval(this.intervalId)
this.intervalId = null
}
}
public async loadDateTime(): Promise<Date> {
try {
const datetimeFilePath = this.getDatetimeFilePath()
const content = await fs.readFile(datetimeFilePath, 'utf-8')
return new Date(content.trim())
} catch (error) {
appLogger.error(`Failed to load datetime: ${error instanceof Error ? error.message : String(error)}`)
return new Date() // Use current date as fallback
}
}
private startDateTimeLoop(): void {
this.intervalId = setInterval(async () => {
const currentDateTime = await this.loadDateTime()
this.advanceGameTime(currentDateTime)
this.emitDateTime(currentDateTime)
this.saveDateTimeIfNeeded(currentDateTime)
}, DatetimeManager.UPDATE_INTERVAL)
}
private advanceGameTime(currentDateTime: Date): void {
const advanceTime = (DatetimeManager.GAME_SPEED * DatetimeManager.UPDATE_INTERVAL) / 1000 * 1000
currentDateTime.setTime(currentDateTime.getTime() + advanceTime)
}
private emitDateTime(currentDateTime: Date): void {
this.io?.emit('datetime', this.formatDateTime(currentDateTime))
}
private formatDateTime(date: Date): string {
return date.toISOString().slice(0, 19).replace('T', ' ')
}
private saveDateTimeIfNeeded(currentDateTime: Date): void {
if (currentDateTime.getMilliseconds() < DatetimeManager.UPDATE_INTERVAL) {
this.saveDateTime(currentDateTime)
}
}
private async saveDateTime(currentDateTime: Date): Promise<void> {
try {
const datetimeFilePath = this.getDatetimeFilePath()
await fs.writeFile(datetimeFilePath, this.formatDateTime(currentDateTime))
} catch (error) {
appLogger.error(`Failed to save datetime: ${error instanceof Error ? error.message : String(error)}`)
}
}
private getDatetimeFilePath(): string {
if (!doesPathExist(getRootPath('data'))) {
createDir(getRootPath('data'))
}
return getRootPath('data', 'datetime.txt')
}
}
export default new DatetimeManager()

View File

@ -5,7 +5,7 @@ import { Server as SocketServer } from 'socket.io'
import { TSocket } from '../utilities/types'
import { queueLogger } from '../utilities/logger'
import fs from 'fs'
import { getAppPath } from '../utilities/utilities'
import { getAppPath } from '../utilities/files'
class QueueManager {
private connection!: IORedis

View File

View File

@ -1,6 +1,7 @@
import fs from 'fs'
import express, { Application } from 'express'
import config from './utilities/config'
import { getAppPath } from './utilities/files'
import { createServer as httpServer, Server as HTTPServer } from 'http'
import { addHttpRoutes } from './utilities/http'
import cors from 'cors'
@ -14,7 +15,7 @@ import UserManager from './managers/userManager'
import CommandManager from './managers/commandManager'
import CharacterManager from './managers/characterManager'
import QueueManager from './managers/queueManager'
import { getAppPath } from './utilities/utilities'
import DatetimeManager from './managers/datetimeManager'
export class Server {
private readonly app: Application
@ -66,6 +67,9 @@ export class Server {
// Load user manager
await UserManager.boot()
// Load datetime manager
await DatetimeManager.boot(this.io)
// Load zoneEditor manager
await ZoneManager.boot()

View File

@ -29,6 +29,8 @@ export default class DisconnectEvent {
return
}
character.resetMovement = true
gameLogger.info('User disconnected along with their character')
await CharacterManager.removeCharacter(character)

View File

@ -3,7 +3,7 @@ import { Server } from 'socket.io'
import { TSocket } from '../../../../utilities/types'
import prisma from '../../../../utilities/prisma'
import characterRepository from '../../../../repositories/characterRepository'
import { getPublicPath } from '../../../../utilities/utilities'
import { getPublicPath } from '../../../../utilities/files'
interface IPayload {
object: string

View File

@ -6,7 +6,7 @@ import prisma from '../../../../utilities/prisma'
import sharp from 'sharp'
import characterRepository from '../../../../repositories/characterRepository'
import { gameMasterLogger } from '../../../../utilities/logger'
import { getPublicPath } from '../../../../utilities/utilities'
import { getPublicPath } from '../../../../utilities/files'
interface IObjectData {
[key: string]: Buffer

View File

@ -3,7 +3,7 @@ import { TSocket } from '../../../../utilities/types'
import fs from 'fs/promises'
import prisma from '../../../../utilities/prisma'
import characterRepository from '../../../../repositories/characterRepository'
import { getPublicPath } from '../../../../utilities/utilities'
import { getPublicPath } from '../../../../utilities/files'
export default class SpriteCreateEvent {
constructor(

View File

@ -4,7 +4,7 @@ import fs from 'fs'
import prisma from '../../../../utilities/prisma'
import CharacterManager from '../../../../managers/characterManager'
import { gameMasterLogger } from '../../../../utilities/logger'
import { getPublicPath } from '../../../../utilities/utilities'
import { getPublicPath } from '../../../../utilities/files'
type Payload = {
id: string

View File

@ -5,7 +5,7 @@ import type { Prisma, SpriteAction } from '@prisma/client'
import { writeFile, mkdir } from 'node:fs/promises'
import sharp from 'sharp'
import CharacterManager from '../../../../managers/characterManager'
import { getPublicPath } from '../../../../utilities/utilities'
import { getPublicPath } from '../../../../utilities/files'
type SpriteActionInput = Omit<SpriteAction, 'id' | 'spriteId' | 'frameWidth' | 'frameHeight'> & {
sprites: string[]

View File

@ -4,7 +4,7 @@ import { TSocket } from '../../../../utilities/types'
import prisma from '../../../../utilities/prisma'
import characterRepository from '../../../../repositories/characterRepository'
import { gameMasterLogger } from '../../../../utilities/logger'
import { getPublicPath } from '../../../../utilities/utilities'
import { getPublicPath } from '../../../../utilities/files'
type Payload = {
id: string

View File

@ -5,7 +5,7 @@ import fs from 'fs/promises'
import prisma from '../../../../utilities/prisma'
import characterRepository from '../../../../repositories/characterRepository'
import { gameMasterLogger } from '../../../../utilities/logger'
import { getPublicPath } from '../../../../utilities/utilities'
import { getPublicPath } from '../../../../utilities/files'
interface ITileData {
[key: string]: Buffer

View File

@ -1,5 +1,6 @@
import config from './config'
import path from 'path'
import fs from 'fs'
export function getRootPath(folder: string, ...additionalSegments: string[]) {
return path.join(process.cwd(), folder, ...additionalSegments)
@ -13,3 +14,20 @@ export function getAppPath(folder: string, ...additionalSegments: string[]) {
export function getPublicPath(folder: string, ...additionalSegments: string[]) {
return path.join(process.cwd(), 'public', folder, ...additionalSegments)
}
export function doesPathExist(path: string) {
try {
fs.accessSync(path, fs.constants.F_OK);
return true;
} catch (e) {
return false;
}
}
export function createDir(path: string) {
try {
fs.mkdirSync(path, { recursive: true });
} catch (e) {
console.error(e);
}
}

View File

@ -12,7 +12,7 @@ import fs from 'fs'
import zoneRepository from '../repositories/zoneRepository'
import zoneManager from '../managers/zoneManager'
import { httpLogger } from './logger'
import { getPublicPath } from './utilities'
import { getPublicPath } from './files'
async function addHttpRoutes(app: Application) {
/**

View File

@ -1,6 +1,6 @@
import pino from 'pino'
import fs from 'fs'
import { getRootPath } from './utilities'
import { getRootPath } from './files'
// Array of log types
const LOG_TYPES = ['http', 'game', 'gameMaster', 'app', 'queue', 'command'] as const