OOP is my passion ( ͡° ͜ʖ ͡°)

This commit is contained in:
Dennis Postma 2025-01-04 18:35:53 +01:00
parent 0b4420f956
commit 067976c54a
46 changed files with 165 additions and 164 deletions

View File

@ -6,8 +6,12 @@ import Logger, { LoggerType } from '#application/logger'
export abstract class BaseRepository { export abstract class BaseRepository {
protected readonly logger = Logger.type(LoggerType.REPOSITORY) protected readonly logger = Logger.type(LoggerType.REPOSITORY)
private entityManager?: EntityManager
protected get em(): EntityManager { getEntityManager(): EntityManager {
return Database.getEntityManager() if (!this.entityManager) {
this.entityManager = Database.getORM().em.fork()
}
return this.entityManager
} }
} }

View File

@ -10,7 +10,7 @@ class Database {
public static async initialize(): Promise<void> { public static async initialize(): Promise<void> {
try { try {
Database.orm = await MikroORM.init(config) this.orm = await MikroORM.init(config)
this.logger.info('Database connection initialized') this.logger.info('Database connection initialized')
} catch (error) { } catch (error) {
this.logger.error(`MikroORM connection failed: ${error}`) this.logger.error(`MikroORM connection failed: ${error}`)
@ -18,8 +18,8 @@ class Database {
} }
} }
public static getEntityManager(): EntityManager { public static getORM(): MikroORM {
return Database.orm.em.fork() return this.orm
} }
} }

View File

@ -9,13 +9,13 @@ import { UUID } from '#application/types'
import { Character } from '#entities/character' import { Character } from '#entities/character'
import { CharacterHair } from '#entities/characterHair' import { CharacterHair } from '#entities/characterHair'
import { CharacterType } from '#entities/characterType' import { CharacterType } from '#entities/characterType'
import { Map } from '#entities/map'
import { MapEffect } from '#entities/mapEffect'
import { MapObject } from '#entities/mapObject' import { MapObject } from '#entities/mapObject'
import { Sprite } from '#entities/sprite' import { Sprite } from '#entities/sprite'
import { SpriteAction } from '#entities/spriteAction' import { SpriteAction } from '#entities/spriteAction'
import { Tile } from '#entities/tile' import { Tile } from '#entities/tile'
import { User } from '#entities/user' import { User } from '#entities/user'
import { Map } from '#entities/map'
import { MapEffect } from '#entities/mapEffect'
import CharacterHairRepository from '#repositories/characterHairRepository' import CharacterHairRepository from '#repositories/characterHairRepository'
import CharacterTypeRepository from '#repositories/characterTypeRepository' import CharacterTypeRepository from '#repositories/characterTypeRepository'
import MapRepository from '#repositories/mapRepository' import MapRepository from '#repositories/mapRepository'
@ -24,6 +24,10 @@ import MapRepository from '#repositories/mapRepository'
// https://mikro-orm.io/docs/seeding // https://mikro-orm.io/docs/seeding
export default class InitCommand extends BaseCommand { export default class InitCommand extends BaseCommand {
private readonly mapRepository = new MapRepository()
private readonly characterTypeRepository = new CharacterTypeRepository()
private readonly characterHairRepository = new CharacterHairRepository()
public async execute(): Promise<void> { public async execute(): Promise<void> {
// Assets // Assets
await this.importTiles() await this.importTiles()
@ -247,9 +251,9 @@ export default class InitCommand extends BaseCommand {
.setUser(user) .setUser(user)
.setName('root') .setName('root')
.setRole('gm') .setRole('gm')
.setMap((await MapRepository.getFirst())!) .setMap((await this.mapRepository.getFirst())!)
.setCharacterType((await CharacterTypeRepository.getFirst()) ?? undefined) .setCharacterType((await this.characterTypeRepository.getFirst()) ?? undefined)
.setCharacterHair((await CharacterHairRepository.getFirst()) ?? undefined) .setCharacterHair((await this.characterHairRepository.getFirst()) ?? undefined)
.save() .save()
} }
} }

View File

@ -1,5 +1,3 @@
import { Server } from 'socket.io'
import { BaseCommand } from '#application/base/baseCommand' import { BaseCommand } from '#application/base/baseCommand'
import MapManager from '#managers/mapManager' import MapManager from '#managers/mapManager'

View File

@ -7,8 +7,8 @@ import { CharacterHair } from './characterHair'
import { CharacterItem } from './characterItem' import { CharacterItem } from './characterItem'
import { CharacterType } from './characterType' import { CharacterType } from './characterType'
import { Chat } from './chat' import { Chat } from './chat'
import { User } from './user'
import { Map } from './map' import { Map } from './map'
import { User } from './user'
import { BaseEntity } from '#application/base/baseEntity' import { BaseEntity } from '#application/base/baseEntity'
import { UUID } from '#application/types' import { UUID } from '#application/types'

View File

@ -29,7 +29,7 @@ export class Item extends BaseEntity {
@Enum(() => ItemRarity) @Enum(() => ItemRarity)
rarity: ItemRarity = ItemRarity.COMMON rarity: ItemRarity = ItemRarity.COMMON
@ManyToOne(() => Sprite, ) @ManyToOne(() => Sprite)
sprite?: Sprite sprite?: Sprite
@Property() @Property()

View File

@ -1,6 +1,6 @@
import { BaseEvent } from '#application/base/baseEvent' import { BaseEvent } from '#application/base/baseEvent'
import { CharacterHair } from '#entities/characterHair' import { CharacterHair } from '#entities/characterHair'
import characterHairRepository from '#repositories/characterHairRepository' import CharacterHairRepository from '#repositories/characterHairRepository'
interface IPayload {} interface IPayload {}
@ -11,6 +11,7 @@ export default class characterHairListEvent extends BaseEvent {
private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise<void> { private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise<void> {
try { try {
const characterHairRepository = new CharacterHairRepository()
const items: CharacterHair[] = await characterHairRepository.getAllSelectable(['sprite']) const items: CharacterHair[] = await characterHairRepository.getAllSelectable(['sprite'])
return callback(items) return callback(items)

View File

@ -11,6 +11,9 @@ interface CharacterConnectPayload {
} }
export default class CharacterConnectEvent extends BaseEvent { export default class CharacterConnectEvent extends BaseEvent {
private readonly characterHairRepository = new CharacterHairRepository()
private readonly characterRepository = new CharacterRepository()
public listen(): void { public listen(): void {
this.socket.on('character:connect', this.handleEvent.bind(this)) this.socket.on('character:connect', this.handleEvent.bind(this))
} }
@ -22,10 +25,7 @@ export default class CharacterConnectEvent extends BaseEvent {
return return
} }
const character = await CharacterRepository.getByUserAndId(this.socket.userId!, data.characterId, [ const character = await this.characterRepository.getByUserAndId(this.socket.userId!, data.characterId, ['characterType', 'characterHair'])
'characterType',
'characterHair'
])
if (!character) { if (!character) {
this.emitError('Character not found or does not belong to this user') this.emitError('Character not found or does not belong to this user')
@ -37,7 +37,7 @@ export default class CharacterConnectEvent extends BaseEvent {
// Set character hair // Set character hair
if (data.characterHairId !== undefined && data.characterHairId !== null) { if (data.characterHairId !== undefined && data.characterHairId !== null) {
const characterHair = await CharacterHairRepository.getById(data.characterHairId) const characterHair = await this.characterHairRepository.getById(data.characterHairId)
await character.setCharacterHair(characterHair).update() await character.setCharacterHair(characterHair).update()
} }
@ -61,7 +61,7 @@ export default class CharacterConnectEvent extends BaseEvent {
} }
private async checkForActiveCharacters(): Promise<boolean> { private async checkForActiveCharacters(): Promise<boolean> {
const characters = await CharacterRepository.getByUserId(this.socket.userId!) const characters = await this.characterRepository.getByUserId(this.socket.userId!)
return characters?.some((char) => MapManager.getCharacterById(char.id)) ?? false return characters?.some((char) => MapManager.getCharacterById(char.id)) ?? false
} }
} }

View File

@ -4,8 +4,8 @@ import { BaseEvent } from '#application/base/baseEvent'
import { ZCharacterCreate } from '#application/zodTypes' import { ZCharacterCreate } from '#application/zodTypes'
import { Character } from '#entities/character' import { Character } from '#entities/character'
import CharacterRepository from '#repositories/characterRepository' import CharacterRepository from '#repositories/characterRepository'
import UserRepository from '#repositories/userRepository'
import MapRepository from '#repositories/mapRepository' import MapRepository from '#repositories/mapRepository'
import UserRepository from '#repositories/userRepository'
export default class CharacterCreateEvent extends BaseEvent { export default class CharacterCreateEvent extends BaseEvent {
public listen(): void { public listen(): void {
@ -17,27 +17,31 @@ export default class CharacterCreateEvent extends BaseEvent {
try { try {
data = ZCharacterCreate.parse(data) data = ZCharacterCreate.parse(data)
const user = await UserRepository.getById(this.socket.userId!) const userRepository = new UserRepository()
const characterRepository = new CharacterRepository()
const mapRepository = new MapRepository()
const user = await userRepository.getById(this.socket.userId!)
if (!user) { if (!user) {
return this.socket.emit('notification', { message: 'User not found' }) return this.socket.emit('notification', { message: 'User not found' })
} }
// Check if character name already exists // Check if character name already exists
const characterExists = await CharacterRepository.getByName(data.name) const characterExists = await characterRepository.getByName(data.name)
if (characterExists) { if (characterExists) {
return this.socket.emit('notification', { message: 'Character name already exists' }) return this.socket.emit('notification', { message: 'Character name already exists' })
} }
let characters: Character[] = await CharacterRepository.getByUserId(user.getId()) let characters: Character[] = await characterRepository.getByUserId(user.getId())
if (characters.length >= 4) { if (characters.length >= 4) {
return this.socket.emit('notification', { message: 'You can only have 4 characters' }) return this.socket.emit('notification', { message: 'You can only have 4 characters' })
} }
// @TODO: Change to default location // @TODO: Change to default location
const map = await MapRepository.getFirst() const map = await mapRepository.getFirst()
const newCharacter = new Character() const newCharacter = new Character()
await newCharacter.setName(data.name).setUser(user).setMap(map!).save() await newCharacter.setName(data.name).setUser(user).setMap(map!).save()

View File

@ -9,11 +9,12 @@ export default class CharacterListEvent extends BaseEvent {
private async handleEvent(data: any): Promise<void> { private async handleEvent(data: any): Promise<void> {
try { try {
let characters: Character[] = await CharacterRepository.getByUserId(this.socket.userId!, [ const characterRepository = new CharacterRepository()
'characterType', let characters: Character[] = await characterRepository.getByUserId(this.socket.userId!)
'characterHair'
])
await characterRepository.getEntityManager().populate(characters, ['characterType', 'characterHair'])
console.log(characters)
this.socket.emit('character:list', characters) this.socket.emit('character:list', characters)
} catch (error: any) { } catch (error: any) {
this.logger.error('character:list error', error.message) this.logger.error('character:list error', error.message)

View File

@ -1,6 +1,6 @@
import { BaseEvent } from '#application/base/baseEvent' import { BaseEvent } from '#application/base/baseEvent'
import CharacterHairRepository from '#repositories/characterHairRepository'
import { UUID } from '#application/types' import { UUID } from '#application/types'
import CharacterHairRepository from '#repositories/characterHairRepository'
interface IPayload { interface IPayload {
id: UUID id: UUID

View File

@ -29,7 +29,7 @@ export default class CharacterHairUpdateEvent extends BaseEvent {
return callback(false) return callback(false)
} }
await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite!).update() await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite).update()
return callback(true) return callback(true)
} catch (error) { } catch (error) {
this.logger.error(`Error updating character hair: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Error updating character hair: ${error instanceof Error ? error.message : String(error)}`)

View File

@ -1,6 +1,6 @@
import { BaseEvent } from '#application/base/baseEvent'
import { UUID } from '#application/types' import { UUID } from '#application/types'
import CharacterTypeRepository from '#repositories/characterTypeRepository' import CharacterTypeRepository from '#repositories/characterTypeRepository'
import { BaseEvent } from '#application/base/baseEvent'
interface IPayload { interface IPayload {
id: UUID id: UUID

View File

@ -1,6 +1,6 @@
import CharacterTypeRepository from '#repositories/characterTypeRepository'
import { BaseEvent } from '#application/base/baseEvent' import { BaseEvent } from '#application/base/baseEvent'
import { CharacterType } from '#entities/characterType' import { CharacterType } from '#entities/characterType'
import CharacterTypeRepository from '#repositories/characterTypeRepository'
interface IPayload {} interface IPayload {}

View File

@ -1,6 +1,6 @@
import ObjectRepository from '#repositories/mapObjectRepository'
import { BaseEvent } from '#application/base/baseEvent' import { BaseEvent } from '#application/base/baseEvent'
import { MapObject } from '#entities/mapObject' import { MapObject } from '#entities/mapObject'
import ObjectRepository from '#repositories/mapObjectRepository'
interface IPayload {} interface IPayload {}

View File

@ -1,8 +1,9 @@
import fs from 'fs' import fs from 'fs'
import Storage from '#application/storage'
import { BaseEvent } from '#application/base/baseEvent' import { BaseEvent } from '#application/base/baseEvent'
import MapObjectRepository from '#repositories/mapObjectRepository' import Storage from '#application/storage'
import { UUID } from '#application/types' import { UUID } from '#application/types'
import MapObjectRepository from '#repositories/mapObjectRepository'
interface IPayload { interface IPayload {
mapObjectId: UUID mapObjectId: UUID

View File

@ -1,5 +1,5 @@
import { UUID } from '#application/types'
import { BaseEvent } from '#application/base/baseEvent' import { BaseEvent } from '#application/base/baseEvent'
import { UUID } from '#application/types'
import MapObjectRepository from '#repositories/mapObjectRepository' import MapObjectRepository from '#repositories/mapObjectRepository'
type Payload = { type Payload = {
@ -26,16 +26,7 @@ export default class MapObjectUpdateEvent extends BaseEvent {
const mapObject = await MapObjectRepository.getById(data.id) const mapObject = await MapObjectRepository.getById(data.id)
if (!mapObject) return callback(false) if (!mapObject) return callback(false)
await mapObject await mapObject.setName(data.name).setTags(data.tags).setOriginX(data.originX).setOriginY(data.originY).setIsAnimated(data.isAnimated).setFrameRate(data.frameRate).setFrameWidth(data.frameWidth).setFrameHeight(data.frameHeight).update()
.setName(data.name)
.setTags(data.tags)
.setOriginX(data.originX)
.setOriginY(data.originY)
.setIsAnimated(data.isAnimated)
.setFrameRate(data.frameRate)
.setFrameWidth(data.frameWidth)
.setFrameHeight(data.frameHeight)
.update()
return callback(true) return callback(true)
} catch (error) { } catch (error) {

View File

@ -2,8 +2,9 @@ import fs from 'fs/promises'
import { writeFile } from 'node:fs/promises' import { writeFile } from 'node:fs/promises'
import sharp from 'sharp' import sharp from 'sharp'
import Storage from '#application/storage'
import { BaseEvent } from '#application/base/baseEvent' import { BaseEvent } from '#application/base/baseEvent'
import Storage from '#application/storage'
import { MapObject } from '#entities/mapObject' import { MapObject } from '#entities/mapObject'
interface IObjectData { interface IObjectData {

View File

@ -1,8 +1,8 @@
import { BaseEvent } from '#application/base/baseEvent' import { BaseEvent } from '#application/base/baseEvent'
import Database from '#application/database'
import { UUID } from '#application/types' import { UUID } from '#application/types'
import { Map } from '#entities/map' import { Map } from '#entities/map'
import MapRepository from '#repositories/mapRepository' import MapRepository from '#repositories/mapRepository'
import Database from '#application/database'
interface IPayload { interface IPayload {
mapId: UUID mapId: UUID
@ -26,14 +26,13 @@ export default class MapRequestEvent extends BaseEvent {
const map = await MapRepository.getById(data.mapId) const map = await MapRepository.getById(data.mapId)
if (!map) { if (!map) {
this.logger.info(`User ${(await this.getCharacter())!.getId()} tried to request map ${data.mapId} but it does not exist.`) this.logger.info(`User ${(await this.getCharacter())!.getId()} tried to request map ${data.mapId} but it does not exist.`)
return callback(null) return callback(null)
} }
console.log(map) console.log(map)
await Database.getEntityManager().populate(map, ['mapEventTiles', 'placedMapObjects']) // await Database.getEntityManager().populate(map, ['mapEventTiles', 'placedMapObjects'])
return callback(map) return callback(map)
} catch (error: any) { } catch (error: any) {

View File

@ -5,9 +5,9 @@ import { Map } from '#entities/map'
import { MapEffect } from '#entities/mapEffect' import { MapEffect } from '#entities/mapEffect'
import { MapEventTile } from '#entities/mapEventTile' import { MapEventTile } from '#entities/mapEventTile'
import { MapEventTileTeleport } from '#entities/mapEventTileTeleport' import { MapEventTileTeleport } from '#entities/mapEventTileTeleport'
import { PlacedMapObject } from '#entities/placedMapObject'
import mapManager from '#managers/mapManager' import mapManager from '#managers/mapManager'
import MapRepository from '#repositories/mapRepository' import MapRepository from '#repositories/mapRepository'
import { PlacedMapObject } from '#entities/placedMapObject'
interface IPayload { interface IPayload {
mapId: UUID mapId: UUID
@ -83,7 +83,7 @@ export default class MapUpdateEvent extends BaseEvent {
if (tile.teleport) { if (tile.teleport) {
const teleport = new MapEventTileTeleport() const teleport = new MapEventTileTeleport()
.setToMap((await MapRepository.getById(tile.teleport.toMapId))!) .setToMap(await MapRepository.getById(tile.teleport.toMapId))
.setToPositionX(tile.teleport.toPositionX) .setToPositionX(tile.teleport.toPositionX)
.setToPositionY(tile.teleport.toPositionY) .setToPositionY(tile.teleport.toPositionY)
.setToRotation(tile.teleport.toRotation) .setToRotation(tile.teleport.toRotation)

View File

@ -6,14 +6,15 @@ export default class LoginEvent extends BaseEvent {
this.socket.on('login', this.handleEvent.bind(this)) this.socket.on('login', this.handleEvent.bind(this))
} }
private handleEvent(): void { private async handleEvent() {
try { try {
if (!this.socket.userId) { if (!this.socket.userId) {
this.logger.warn('Login attempt without user data') this.logger.warn('Login attempt without user data')
return return
} }
this.socket.emit('logged_in', { user: UserRepository.getById(this.socket.userId) }) const userRepository = new UserRepository()
this.socket.emit('logged_in', { user: userRepository.getById(this.socket.userId) })
this.logger.info(`User logged in: ${this.socket.userId}`) this.logger.info(`User logged in: ${this.socket.userId}`)
} catch (error: any) { } catch (error: any) {
this.logger.error('login error: ' + error.message) this.logger.error('login error: ' + error.message)

View File

@ -51,11 +51,7 @@ export default class CharacterMove extends BaseEvent {
const [start, end] = [path[i], path[i + 1]] const [start, end] = [path[i], path[i + 1]]
character.rotation = CharacterService.calculateRotation(start.x, start.y, end.x, end.y) character.rotation = CharacterService.calculateRotation(start.x, start.y, end.x, end.y)
const zoneEventTile = await zoneEventTileRepository.getEventTileByZoneIdAndPosition( const zoneEventTile = await zoneEventTileRepository.getEventTileByZoneIdAndPosition(character.zone.id, Math.floor(end.x), Math.floor(end.y))
character.zone.id,
Math.floor(end.x),
Math.floor(end.y)
)
if (zoneEventTile?.type === 'BLOCK') break if (zoneEventTile?.type === 'BLOCK') break
if (zoneEventTile?.type === 'TELEPORT' && zoneEventTile.teleport) { if (zoneEventTile?.type === 'TELEPORT' && zoneEventTile.teleport) {

View File

@ -6,11 +6,15 @@ import { BaseController } from '#application/base/baseController'
import Database from '#application/database' import Database from '#application/database'
import Storage from '#application/storage' import Storage from '#application/storage'
import { AssetData, UUID } from '#application/types' import { AssetData, UUID } from '#application/types'
import MapRepository from '#repositories/mapRepository'
import SpriteRepository from '#repositories/spriteRepository' import SpriteRepository from '#repositories/spriteRepository'
import TileRepository from '#repositories/tileRepository' import TileRepository from '#repositories/tileRepository'
import MapRepository from '#repositories/mapRepository'
export class AssetsController extends BaseController { export class AssetsController extends BaseController {
private readonly mapRepository = new MapRepository()
private readonly spriteRepository = new SpriteRepository()
private readonly tileRepository = new TileRepository()
/** /**
* List tiles * List tiles
* @param req * @param req
@ -18,7 +22,7 @@ export class AssetsController extends BaseController {
*/ */
public async listTiles(req: Request, res: Response) { public async listTiles(req: Request, res: Response) {
const assets: AssetData[] = [] const assets: AssetData[] = []
const tiles = await TileRepository.getAll() const tiles = await this.tileRepository.getAll()
for (const tile of tiles) { for (const tile of tiles) {
assets.push({ key: tile.getId(), data: '/assets/tiles/' + tile.getId() + '.png', group: 'tiles', updatedAt: tile.getUpdatedAt() } as AssetData) assets.push({ key: tile.getId(), data: '/assets/tiles/' + tile.getId() + '.png', group: 'tiles', updatedAt: tile.getUpdatedAt() } as AssetData)
@ -39,13 +43,13 @@ export class AssetsController extends BaseController {
return this.sendError(res, 'Invalid map ID', 400) return this.sendError(res, 'Invalid map ID', 400)
} }
const map = await MapRepository.getById(mapId) const map = await this.mapRepository.getById(mapId)
if (!map) { if (!map) {
return this.sendError(res, 'Map not found', 404) return this.sendError(res, 'Map not found', 404)
} }
const assets: AssetData[] = [] const assets: AssetData[] = []
const tiles = await TileRepository.getByMapId(mapId) const tiles = await this.tileRepository.getByMapId(mapId)
for (const tile of tiles) { for (const tile of tiles) {
assets.push({ key: tile.getId(), data: '/assets/tiles/' + tile.getId() + '.png', group: 'tiles', updatedAt: tile.getUpdatedAt() } as AssetData) assets.push({ key: tile.getId(), data: '/assets/tiles/' + tile.getId() + '.png', group: 'tiles', updatedAt: tile.getUpdatedAt() } as AssetData)
@ -66,12 +70,12 @@ export class AssetsController extends BaseController {
return this.sendError(res, 'Invalid sprite ID', 400) return this.sendError(res, 'Invalid sprite ID', 400)
} }
const sprite = await SpriteRepository.getById(spriteId) const sprite = await this.spriteRepository.getById(spriteId)
if (!sprite) { if (!sprite) {
return this.sendError(res, 'Sprite not found', 404) return this.sendError(res, 'Sprite not found', 404)
} }
await Database.getEntityManager().populate(sprite, ['spriteActions']) // await Database.getEntityManager().populate(sprite, ['spriteActions'])
const assets: AssetData[] = sprite.spriteActions.getItems().map((spriteAction) => ({ const assets: AssetData[] = sprite.spriteActions.getItems().map((spriteAction) => ({
key: sprite.getId() + '-' + spriteAction.getAction(), key: sprite.getId() + '-' + spriteAction.getAction(),

View File

@ -16,13 +16,17 @@ interface AvatarOptions {
} }
export class AvatarController extends BaseController { export class AvatarController extends BaseController {
private readonly characterTypeRepository = new CharacterTypeRepository()
private readonly characterHairRepository = new CharacterHairRepository()
private readonly characterRepository = new CharacterRepository()
/** /**
* Get avatar by character * Get avatar by character
* @param req * @param req
* @param res * @param res
*/ */
public async getByName(req: Request, res: Response) { public async getByName(req: Request, res: Response) {
const character = await CharacterRepository.getByName(req.params.characterName) const character = await this.characterRepository.getByName(req.params.characterName)
if (!character?.characterType) { if (!character?.characterType) {
return this.sendError(res, 'Character or character type not found', 404) return this.sendError(res, 'Character or character type not found', 404)
} }
@ -53,7 +57,7 @@ export class AvatarController extends BaseController {
*/ */
private async generateAvatar(res: Response, options: AvatarOptions) { private async generateAvatar(res: Response, options: AvatarOptions) {
try { try {
const characterType = await CharacterTypeRepository.getById(options.characterTypeId) const characterType = await this.characterTypeRepository.getById(options.characterTypeId)
if (!characterType?.sprite?.id) { if (!characterType?.sprite?.id) {
return this.sendError(res, 'Character type not found', 404) return this.sendError(res, 'Character type not found', 404)
} }
@ -70,7 +74,7 @@ export class AvatarController extends BaseController {
}) })
if (options.characterHairId) { if (options.characterHairId) {
const characterHair = await CharacterHairRepository.getById(options.characterHairId) const characterHair = await this.characterHairRepository.getById(options.characterHairId)
if (characterHair?.sprite?.id) { if (characterHair?.sprite?.id) {
const hairSpritePath = Storage.getPublicPath('sprites', characterHair.sprite.id, 'front.png') const hairSpritePath = Storage.getPublicPath('sprites', characterHair.sprite.id, 'front.png')
if (fs.existsSync(hairSpritePath)) { if (fs.existsSync(hairSpritePath)) {

View File

@ -1,5 +1,3 @@
import { Server } from 'socket.io'
import { CommandRegistry } from '#application/console/commandRegistry' import { CommandRegistry } from '#application/console/commandRegistry'
import { ConsolePrompt } from '#application/console/consolePrompt' import { ConsolePrompt } from '#application/console/consolePrompt'
import { LogReader } from '#application/console/logReader' import { LogReader } from '#application/console/logReader'

View File

@ -2,8 +2,8 @@ import { Server } from 'socket.io'
import Logger, { LoggerType } from '#application/logger' import Logger, { LoggerType } from '#application/logger'
import SocketManager from '#managers/socketManager' import SocketManager from '#managers/socketManager'
import worldRepository from '#repositories/worldRepository' import WorldRepository from '#repositories/worldRepository'
import worldService from '#services/worldService' import WorldService from '#services/worldService'
class DateManager { class DateManager {
private static readonly CONFIG = { private static readonly CONFIG = {
@ -47,6 +47,7 @@ class DateManager {
private async loadDate(): Promise<void> { private async loadDate(): Promise<void> {
try { try {
const worldRepository = new WorldRepository()
const world = await worldRepository.getFirst() const world = await worldRepository.getFirst()
this.currentDate = world?.date ?? new Date() this.currentDate = world?.date ?? new Date()
} catch (error) { } catch (error) {
@ -88,7 +89,7 @@ class DateManager {
private async saveDate(): Promise<void> { private async saveDate(): Promise<void> {
try { try {
await worldService.update({ date: this.currentDate }) await WorldService.update({ date: this.currentDate })
} catch (error) { } catch (error) {
this.handleError('Failed to save date', error) this.handleError('Failed to save date', error)
} }

View File

@ -10,7 +10,8 @@ class MapManager {
private logger = Logger.type(LoggerType.GAME) private logger = Logger.type(LoggerType.GAME)
public async boot(): Promise<void> { public async boot(): Promise<void> {
const maps = await MapRepository.getAll() const mapRepository = new MapRepository()
const maps = await mapRepository.getAll()
await Promise.all(maps.map((map) => this.loadMap(map))) await Promise.all(maps.map((map) => this.loadMap(map)))
this.logger.info(`Map manager loaded with ${Object.keys(this.maps).length} maps`) this.logger.info(`Map manager loaded with ${Object.keys(this.maps).length} maps`)

View File

@ -2,8 +2,8 @@ import { Server } from 'socket.io'
import Logger, { LoggerType } from '#application/logger' import Logger, { LoggerType } from '#application/logger'
import SocketManager from '#managers/socketManager' import SocketManager from '#managers/socketManager'
import worldRepository from '#repositories/worldRepository' import WorldRepository from '#repositories/worldRepository'
import worldService from '#services/worldService' import WorldService from '#services/worldService'
type WeatherState = { type WeatherState = {
isRainEnabled: boolean isRainEnabled: boolean
@ -59,6 +59,7 @@ class WeatherManager {
private async loadWeather(): Promise<void> { private async loadWeather(): Promise<void> {
try { try {
const worldRepository = new WorldRepository()
const world = await worldRepository.getFirst() const world = await worldRepository.getFirst()
if (world) { if (world) {
this.weatherState = { this.weatherState = {
@ -112,7 +113,7 @@ class WeatherManager {
private async saveWeather(): Promise<void> { private async saveWeather(): Promise<void> {
try { try {
await worldService.update(this.weatherState) await WorldService.update(this.weatherState)
} catch (error) { } catch (error) {
this.logError('save', error) this.logError('save', error)
} }

View File

@ -2,8 +2,8 @@ import { Server } from 'socket.io'
import { TSocket } from '#application/types' import { TSocket } from '#application/types'
import { Character } from '#entities/character' import { Character } from '#entities/character'
import SocketManager from '#managers/socketManager'
import MapManager from '#managers/mapManager' import MapManager from '#managers/mapManager'
import SocketManager from '#managers/socketManager'
import TeleportService from '#services/teleportService' import TeleportService from '#services/teleportService'
class MapCharacter { class MapCharacter {

View File

@ -5,7 +5,7 @@ import { CharacterHair } from '#entities/characterHair'
class CharacterHairRepository extends BaseRepository { class CharacterHairRepository extends BaseRepository {
async getFirst() { async getFirst() {
try { try {
const repository = this.em.getRepository(CharacterHair) const repository = this.getEntityManager().getRepository(CharacterHair)
return await repository.findOne({ id: { $exists: true } }) return await repository.findOne({ id: { $exists: true } })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get first character hair: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get first character hair: ${error instanceof Error ? error.message : String(error)}`)
@ -15,7 +15,7 @@ class CharacterHairRepository extends BaseRepository {
async getAll(): Promise<CharacterHair[]> { async getAll(): Promise<CharacterHair[]> {
try { try {
const repository = this.em.getRepository(CharacterHair) const repository = this.getEntityManager().getRepository(CharacterHair)
return await repository.findAll() return await repository.findAll()
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get all character hair: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get all character hair: ${error instanceof Error ? error.message : String(error)}`)
@ -25,7 +25,7 @@ class CharacterHairRepository extends BaseRepository {
async getAllSelectable(populate?: any): Promise<CharacterHair[]> { async getAllSelectable(populate?: any): Promise<CharacterHair[]> {
try { try {
const repository = this.em.getRepository(CharacterHair) const repository = this.getEntityManager().getRepository(CharacterHair)
return await repository.find({ isSelectable: true }, { populate }) return await repository.find({ isSelectable: true }, { populate })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get selectable character hair: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get selectable character hair: ${error instanceof Error ? error.message : String(error)}`)
@ -35,7 +35,7 @@ class CharacterHairRepository extends BaseRepository {
async getById(id: UUID): Promise<CharacterHair | null> { async getById(id: UUID): Promise<CharacterHair | null> {
try { try {
const repository = this.em.getRepository(CharacterHair) const repository = this.getEntityManager().getRepository(CharacterHair)
return await repository.findOne({ id }) return await repository.findOne({ id })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get character hair by ID: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get character hair by ID: ${error instanceof Error ? error.message : String(error)}`)
@ -44,4 +44,4 @@ class CharacterHairRepository extends BaseRepository {
} }
} }
export default new CharacterHairRepository() export default CharacterHairRepository

View File

@ -3,20 +3,20 @@ import { UUID } from '#application/types'
import { Character } from '#entities/character' import { Character } from '#entities/character'
class CharacterRepository extends BaseRepository { class CharacterRepository extends BaseRepository {
async getByUserId(userId: UUID, populate?: any): Promise<Character[]> { async getByUserId(userId: UUID): Promise<Character[]> {
try { try {
const repository = this.em.getRepository(Character) const repository = this.getEntityManager().getRepository(Character)
return await repository.find({ user: userId }, { populate }) return await repository.find({ user: userId })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get character by user ID: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get character by user ID: ${error instanceof Error ? error.message : String(error)}`)
return [] return []
} }
} }
async getByUserAndId(userId: UUID, characterId: UUID, populate?: any): Promise<Character | null> { async getByUserAndId(userId: UUID, characterId: UUID): Promise<Character | null> {
try { try {
const repository = this.em.getRepository(Character) const repository = this.getEntityManager().getRepository(Character)
return await repository.findOne({ user: userId, id: characterId }, { populate }) return await repository.findOne({ user: userId, id: characterId })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get character by user ID and character ID: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get character by user ID and character ID: ${error instanceof Error ? error.message : String(error)}`)
return null return null
@ -25,7 +25,7 @@ class CharacterRepository extends BaseRepository {
async getById(id: UUID, populate?: any): Promise<Character | null> { async getById(id: UUID, populate?: any): Promise<Character | null> {
try { try {
const repository = this.em.getRepository(Character) const repository = this.getEntityManager().getRepository(Character)
return await repository.findOne({ id }, { populate }) return await repository.findOne({ id }, { populate })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get character by ID: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get character by ID: ${error instanceof Error ? error.message : String(error)}`)
@ -35,7 +35,7 @@ class CharacterRepository extends BaseRepository {
async getByName(name: string, populate?: any): Promise<Character | null> { async getByName(name: string, populate?: any): Promise<Character | null> {
try { try {
const repository = this.em.getRepository(Character) const repository = this.getEntityManager().getRepository(Character)
return await repository.findOne({ name }, { populate }) return await repository.findOne({ name }, { populate })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get character by name: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get character by name: ${error instanceof Error ? error.message : String(error)}`)
@ -44,4 +44,4 @@ class CharacterRepository extends BaseRepository {
} }
} }
export default new CharacterRepository() export default CharacterRepository

View File

@ -5,7 +5,7 @@ import { CharacterType } from '#entities/characterType'
class CharacterTypeRepository extends BaseRepository { class CharacterTypeRepository extends BaseRepository {
async getFirst() { async getFirst() {
try { try {
const repository = this.em.getRepository(CharacterType) const repository = this.getEntityManager().getRepository(CharacterType)
return await repository.findOne({ id: { $exists: true } }) return await repository.findOne({ id: { $exists: true } })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get first character type: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get first character type: ${error instanceof Error ? error.message : String(error)}`)
@ -15,7 +15,7 @@ class CharacterTypeRepository extends BaseRepository {
async getAll() { async getAll() {
try { try {
const repository = this.em.getRepository(CharacterType) const repository = this.getEntityManager().getRepository(CharacterType)
return await repository.findAll() return await repository.findAll()
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get all character types: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get all character types: ${error instanceof Error ? error.message : String(error)}`)
@ -25,7 +25,7 @@ class CharacterTypeRepository extends BaseRepository {
async getById(id: UUID) { async getById(id: UUID) {
try { try {
const repository = this.em.getRepository(CharacterType) const repository = this.getEntityManager().getRepository(CharacterType)
return await repository.findOne({ id }) return await repository.findOne({ id })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get character type by ID: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get character type by ID: ${error instanceof Error ? error.message : String(error)}`)
@ -34,4 +34,4 @@ class CharacterTypeRepository extends BaseRepository {
} }
} }
export default new CharacterTypeRepository() export default CharacterTypeRepository

View File

@ -5,7 +5,7 @@ import { Chat } from '#entities/chat'
class ChatRepository extends BaseRepository { class ChatRepository extends BaseRepository {
async getById(id: UUID): Promise<Chat[]> { async getById(id: UUID): Promise<Chat[]> {
try { try {
const repository = this.em.getRepository(Chat) const repository = this.getEntityManager().getRepository(Chat)
return await repository.find({ return await repository.find({
id id
}) })
@ -17,7 +17,7 @@ class ChatRepository extends BaseRepository {
async getAll(): Promise<Chat[]> { async getAll(): Promise<Chat[]> {
try { try {
const repository = this.em.getRepository(Chat) const repository = this.getEntityManager().getRepository(Chat)
return await repository.findAll() return await repository.findAll()
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get all chats: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get all chats: ${error instanceof Error ? error.message : String(error)}`)
@ -27,7 +27,7 @@ class ChatRepository extends BaseRepository {
async getByCharacterId(characterId: UUID): Promise<Chat[]> { async getByCharacterId(characterId: UUID): Promise<Chat[]> {
try { try {
const repository = this.em.getRepository(Chat) const repository = this.getEntityManager().getRepository(Chat)
return await repository.find({ character: characterId }) return await repository.find({ character: characterId })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get chats by character ID: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get chats by character ID: ${error instanceof Error ? error.message : String(error)}`)
@ -37,7 +37,7 @@ class ChatRepository extends BaseRepository {
async getByMapId(mapId: UUID): Promise<Chat[]> { async getByMapId(mapId: UUID): Promise<Chat[]> {
try { try {
const repository = this.em.getRepository(Chat) const repository = this.getEntityManager().getRepository(Chat)
return await repository.find({ map: mapId }) return await repository.find({ map: mapId })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get chats by map ID: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get chats by map ID: ${error instanceof Error ? error.message : String(error)}`)
@ -46,4 +46,4 @@ class ChatRepository extends BaseRepository {
} }
} }
export default new ChatRepository() export default ChatRepository

View File

@ -5,7 +5,7 @@ import { Item } from '#entities/item'
class ItemRepository extends BaseRepository { class ItemRepository extends BaseRepository {
async getById(id: UUID): Promise<any> { async getById(id: UUID): Promise<any> {
try { try {
const repository = this.em.getRepository(Item) const repository = this.getEntityManager().getRepository(Item)
return await repository.findOne({ id }) return await repository.findOne({ id })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get item by ID: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get item by ID: ${error instanceof Error ? error.message : String(error)}`)
@ -15,7 +15,7 @@ class ItemRepository extends BaseRepository {
async getByIds(ids: UUID[]): Promise<any> { async getByIds(ids: UUID[]): Promise<any> {
try { try {
const repository = this.em.getRepository(Item) const repository = this.getEntityManager().getRepository(Item)
return await repository.find({ return await repository.find({
id: ids id: ids
}) })
@ -27,7 +27,7 @@ class ItemRepository extends BaseRepository {
async getAll(): Promise<any> { async getAll(): Promise<any> {
try { try {
const repository = this.em.getRepository(Item) const repository = this.getEntityManager().getRepository(Item)
return await repository.findAll() return await repository.findAll()
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get all items: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get all items: ${error instanceof Error ? error.message : String(error)}`)
@ -36,4 +36,4 @@ class ItemRepository extends BaseRepository {
} }
} }
export default new ItemRepository() export default ItemRepository

View File

@ -5,7 +5,7 @@ import { MapEventTile } from '#entities/mapEventTile'
class MapEventTileRepository extends BaseRepository { class MapEventTileRepository extends BaseRepository {
async getAll(id: UUID): Promise<MapEventTile[]> { async getAll(id: UUID): Promise<MapEventTile[]> {
try { try {
const repository = this.em.getRepository(MapEventTile) const repository = this.getEntityManager().getRepository(MapEventTile)
return await repository.find({ return await repository.find({
map: id map: id
}) })
@ -17,7 +17,7 @@ class MapEventTileRepository extends BaseRepository {
async getEventTileByMapIdAndPosition(mapId: UUID, positionX: number, positionY: number) { async getEventTileByMapIdAndPosition(mapId: UUID, positionX: number, positionY: number) {
try { try {
const repository = this.em.getRepository(MapEventTile) const repository = this.getEntityManager().getRepository(MapEventTile)
return await repository.findOne({ return await repository.findOne({
map: mapId, map: mapId,
positionX: positionX, positionX: positionX,
@ -30,4 +30,4 @@ class MapEventTileRepository extends BaseRepository {
} }
} }
export default new MapEventTileRepository() export default MapEventTileRepository

View File

@ -5,7 +5,7 @@ import { MapObject } from '#entities/mapObject'
class MapObjectRepository extends BaseRepository { class MapObjectRepository extends BaseRepository {
async getById(id: UUID): Promise<MapObject | null> { async getById(id: UUID): Promise<MapObject | null> {
try { try {
const repository = this.em.getRepository(MapObject) const repository = this.getEntityManager().getRepository(MapObject)
return await repository.findOne({ id }) return await repository.findOne({ id })
} catch (error: any) { } catch (error: any) {
return null return null
@ -14,7 +14,7 @@ class MapObjectRepository extends BaseRepository {
async getAll(): Promise<MapObject[]> { async getAll(): Promise<MapObject[]> {
try { try {
const repository = this.em.getRepository(MapObject) const repository = this.getEntityManager().getRepository(MapObject)
return await repository.findAll() return await repository.findAll()
} catch (error: any) { } catch (error: any) {
return [] return []
@ -22,4 +22,4 @@ class MapObjectRepository extends BaseRepository {
} }
} }
export default new MapObjectRepository() export default MapObjectRepository

View File

@ -7,7 +7,7 @@ import { MapObject } from '#entities/mapObject'
class MapRepository extends BaseRepository { class MapRepository extends BaseRepository {
async getFirst(): Promise<Map | null> { async getFirst(): Promise<Map | null> {
try { try {
const repository = this.em.getRepository(Map) const repository = this.getEntityManager().getRepository(Map)
return await repository.findOne({ id: { $exists: true } }) return await repository.findOne({ id: { $exists: true } })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get first map: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get first map: ${error instanceof Error ? error.message : String(error)}`)
@ -17,7 +17,7 @@ class MapRepository extends BaseRepository {
async getAll(): Promise<Map[]> { async getAll(): Promise<Map[]> {
try { try {
const repository = this.em.getRepository(Map) const repository = this.getEntityManager().getRepository(Map)
return await repository.findAll() return await repository.findAll()
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get all map: ${error.message}`) this.logger.error(`Failed to get all map: ${error.message}`)
@ -27,7 +27,7 @@ class MapRepository extends BaseRepository {
async getById(id: UUID) { async getById(id: UUID) {
try { try {
const repository = this.em.getRepository(Map) const repository = this.getEntityManager().getRepository(Map)
return await repository.findOne({ id }) return await repository.findOne({ id })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get map by id: ${error.message}`) this.logger.error(`Failed to get map by id: ${error.message}`)
@ -37,7 +37,7 @@ class MapRepository extends BaseRepository {
async getEventTiles(id: UUID): Promise<MapEventTile[]> { async getEventTiles(id: UUID): Promise<MapEventTile[]> {
try { try {
const repository = this.em.getRepository(MapEventTile) const repository = this.getEntityManager().getRepository(MapEventTile)
return await repository.find({ map: id }) return await repository.find({ map: id })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get map event tiles: ${error.message}`) this.logger.error(`Failed to get map event tiles: ${error.message}`)
@ -47,7 +47,7 @@ class MapRepository extends BaseRepository {
async getFirstEventTile(mapId: UUID, positionX: number, positionY: number): Promise<MapEventTile | null> { async getFirstEventTile(mapId: UUID, positionX: number, positionY: number): Promise<MapEventTile | null> {
try { try {
const repository = this.em.getRepository(MapEventTile) const repository = this.getEntityManager().getRepository(MapEventTile)
return await repository.findOne({ return await repository.findOne({
map: mapId, map: mapId,
positionX: positionX, positionX: positionX,
@ -61,7 +61,7 @@ class MapRepository extends BaseRepository {
async getMapObjects(id: UUID): Promise<MapObject[]> { async getMapObjects(id: UUID): Promise<MapObject[]> {
try { try {
const repository = this.em.getRepository(MapObject) const repository = this.getEntityManager().getRepository(MapObject)
return await repository.find({ map: id }) return await repository.find({ map: id })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get map objects: ${error.message}`) this.logger.error(`Failed to get map objects: ${error.message}`)
@ -70,4 +70,4 @@ class MapRepository extends BaseRepository {
} }
} }
export default new MapRepository() export default MapRepository

View File

@ -5,7 +5,7 @@ import { PasswordResetToken } from '#entities/passwordResetToken'
class PasswordResetTokenRepository extends BaseRepository { class PasswordResetTokenRepository extends BaseRepository {
async getById(id: UUID): Promise<any> { async getById(id: UUID): Promise<any> {
try { try {
const repository = this.em.getRepository(PasswordResetToken) const repository = this.getEntityManager().getRepository(PasswordResetToken)
return await repository.findOne({ id }) return await repository.findOne({ id })
} catch (error: any) { } catch (error: any) {
// Handle error // Handle error
@ -15,7 +15,7 @@ class PasswordResetTokenRepository extends BaseRepository {
async getByUserId(userId: UUID): Promise<any> { async getByUserId(userId: UUID): Promise<any> {
try { try {
const repository = this.em.getRepository(PasswordResetToken) const repository = this.getEntityManager().getRepository(PasswordResetToken)
return await repository.findOne({ return await repository.findOne({
user: userId user: userId
}) })
@ -27,7 +27,7 @@ class PasswordResetTokenRepository extends BaseRepository {
async getByToken(token: string): Promise<any> { async getByToken(token: string): Promise<any> {
try { try {
const repository = this.em.getRepository(PasswordResetToken) const repository = this.getEntityManager().getRepository(PasswordResetToken)
return await repository.findOne({ token }) return await repository.findOne({ token })
} catch (error: any) { } catch (error: any) {
// Handle error // Handle error
@ -36,4 +36,4 @@ class PasswordResetTokenRepository extends BaseRepository {
} }
} }
export default new PasswordResetTokenRepository() export default PasswordResetTokenRepository

View File

@ -5,7 +5,7 @@ import { Sprite } from '#entities/sprite'
class SpriteRepository extends BaseRepository { class SpriteRepository extends BaseRepository {
async getById(id: UUID, populate?: any) { async getById(id: UUID, populate?: any) {
try { try {
const repository = this.em.getRepository(Sprite) const repository = this.getEntityManager().getRepository(Sprite)
return await repository.findOne({ id }, { populate }) return await repository.findOne({ id }, { populate })
} catch (error: any) { } catch (error: any) {
return null return null
@ -14,7 +14,7 @@ class SpriteRepository extends BaseRepository {
async getAll(populate?: any): Promise<Sprite[]> { async getAll(populate?: any): Promise<Sprite[]> {
try { try {
const repository = this.em.getRepository(Sprite) const repository = this.getEntityManager().getRepository(Sprite)
return await repository.findAll({ populate }) return await repository.findAll({ populate })
} catch (error: any) { } catch (error: any) {
return [] return []
@ -22,4 +22,4 @@ class SpriteRepository extends BaseRepository {
} }
} }
export default new SpriteRepository() export default SpriteRepository

View File

@ -3,14 +3,14 @@ import { FilterValue } from '@mikro-orm/core'
import { BaseRepository } from '#application/base/baseRepository' import { BaseRepository } from '#application/base/baseRepository'
import { UUID } from '#application/types' import { UUID } from '#application/types'
import { unduplicateArray } from '#application/utilities' import { unduplicateArray } from '#application/utilities'
import { Tile } from '#entities/tile'
import { Map } from '#entities/map' import { Map } from '#entities/map'
import { Tile } from '#entities/tile'
import MapService from '#services/mapService' import MapService from '#services/mapService'
class TileRepository extends BaseRepository { class TileRepository extends BaseRepository {
async getById(id: UUID) { async getById(id: UUID) {
try { try {
const repository = this.em.getRepository(Tile) const repository = this.getEntityManager().getRepository(Tile)
return await repository.findOne({ id }) return await repository.findOne({ id })
} catch (error: any) { } catch (error: any) {
return null return null
@ -19,7 +19,7 @@ class TileRepository extends BaseRepository {
async getByIds(ids: UUID[]) { async getByIds(ids: UUID[]) {
try { try {
const repository = this.em.getRepository(Tile) const repository = this.getEntityManager().getRepository(Tile)
return await repository.find({ return await repository.find({
id: ids id: ids
}) })
@ -30,7 +30,7 @@ class TileRepository extends BaseRepository {
async getAll() { async getAll() {
try { try {
const repository = this.em.getRepository(Tile) const repository = this.getEntityManager().getRepository(Tile)
return await repository.findAll() return await repository.findAll()
} catch (error: any) { } catch (error: any) {
return [] return []
@ -39,8 +39,8 @@ class TileRepository extends BaseRepository {
async getByMapId(mapId: UUID) { async getByMapId(mapId: UUID) {
try { try {
const repository = this.em.getRepository(Map) const repository = this.getEntityManager().getRepository(Map)
const tileRepository = this.em.getRepository(Tile) const tileRepository = this.getEntityManager().getRepository(Tile)
const map = await repository.findOne({ id: mapId }) const map = await repository.findOne({ id: mapId })
if (!map) return [] if (!map) return []
@ -56,4 +56,4 @@ class TileRepository extends BaseRepository {
} }
} }
export default new TileRepository() export default TileRepository

View File

@ -5,7 +5,7 @@ import { User } from '#entities/user'
class UserRepository extends BaseRepository { class UserRepository extends BaseRepository {
async getById(id: UUID) { async getById(id: UUID) {
try { try {
const repository = this.em.getRepository(User) const repository = this.getEntityManager().getRepository(User)
return await repository.findOne({ id }) return await repository.findOne({ id })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get user by ID: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get user by ID: ${error instanceof Error ? error.message : String(error)}`)
@ -15,7 +15,7 @@ class UserRepository extends BaseRepository {
async getByUsername(username: string) { async getByUsername(username: string) {
try { try {
const repository = this.em.getRepository(User) const repository = this.getEntityManager().getRepository(User)
return await repository.findOne({ username }) return await repository.findOne({ username })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get user by username: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get user by username: ${error instanceof Error ? error.message : String(error)}`)
@ -25,7 +25,7 @@ class UserRepository extends BaseRepository {
async getByEmail(email: string) { async getByEmail(email: string) {
try { try {
const repository = this.em.getRepository(User) const repository = this.getEntityManager().getRepository(User)
return await repository.findOne({ email }) return await repository.findOne({ email })
} catch (error: any) { } catch (error: any) {
this.logger.error(`Failed to get user by email: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get user by email: ${error instanceof Error ? error.message : String(error)}`)
@ -34,4 +34,4 @@ class UserRepository extends BaseRepository {
} }
} }
export default new UserRepository() export default UserRepository

View File

@ -1,16 +1,15 @@
import { BaseRepository } from '#application/base/baseRepository' import { BaseRepository } from '#application/base/baseRepository'
import { gameLogger } from '#application/logger'
import { World } from '#entities/world' import { World } from '#entities/world'
class WorldRepository extends BaseRepository { class WorldRepository extends BaseRepository {
async getFirst() { async getFirst() {
try { try {
const repository = this.em.getRepository(World) const repository = this.getEntityManager().getRepository(World)
return await repository.findOne({ date: { $exists: true } }) return await repository.findOne({ date: { $exists: true } })
} catch (error: any) { } catch (error: any) {
gameLogger.error(`Failed to get first world: ${error instanceof Error ? error.message : String(error)}`) this.logger.error(`Failed to get first world: ${error instanceof Error ? error.message : String(error)}`)
} }
} }
} }
export default new WorldRepository() export default WorldRepository

View File

@ -7,13 +7,11 @@ import config from '#application/config'
import Database from '#application/database' import Database from '#application/database'
import Logger, { LoggerType } from '#application/logger' import Logger, { LoggerType } from '#application/logger'
import ConsoleManager from '#managers/consoleManager' import ConsoleManager from '#managers/consoleManager'
import DateManager from '#managers/dateManager'
import HttpManager from '#managers/httpManager' import HttpManager from '#managers/httpManager'
import MapManager from '#managers/mapManager'
import QueueManager from '#managers/queueManager' import QueueManager from '#managers/queueManager'
import SocketManager from '#managers/socketManager' import SocketManager from '#managers/socketManager'
import UserManager from '#managers/userManager' import UserManager from '#managers/userManager'
import WeatherManager from '#managers/weatherManager'
import MapManager from '#managers/mapManager'
export class Server { export class Server {
private readonly app: Application private readonly app: Application
@ -38,16 +36,7 @@ export class Server {
this.logger.info(`Server running on port ${config.PORT}`) this.logger.info(`Server running on port ${config.PORT}`)
// Initialize managers // Initialize managers
await Promise.all([ await Promise.all([HttpManager.boot(this.app), SocketManager.boot(this.app, this.http), QueueManager.boot(), UserManager.boot(), MapManager.boot(), ConsoleManager.boot()])
HttpManager.boot(this.app),
SocketManager.boot(this.app, this.http),
QueueManager.boot(),
UserManager.boot(),
// DateManager.boot(),
// WeatherManager.boot(),
MapManager.boot(),
ConsoleManager.boot()
])
} catch (error: any) { } catch (error: any) {
this.logger.error(`Server failed to start: ${error.message}`) this.logger.error(`Server failed to start: ${error.message}`)
process.exit(1) process.exit(1)

View File

@ -2,8 +2,8 @@ import { BaseService } from '#application/base/baseService'
import config from '#application/config' import config from '#application/config'
import { Character } from '#entities/character' import { Character } from '#entities/character'
import { Map } from '#entities/map' import { Map } from '#entities/map'
import SocketManager from '#managers/socketManager'
import MapManager from '#managers/mapManager' import MapManager from '#managers/mapManager'
import SocketManager from '#managers/socketManager'
import CharacterRepository from '#repositories/characterRepository' import CharacterRepository from '#repositories/characterRepository'
import MapRepository from '#repositories/mapRepository' import MapRepository from '#repositories/mapRepository'

View File

@ -1,8 +1,8 @@
import Logger, { LoggerType } from '#application/logger' import Logger, { LoggerType } from '#application/logger'
import { UUID } from '#application/types' import { UUID } from '#application/types'
import { Character } from '#entities/character' import { Character } from '#entities/character'
import SocketManager from '#managers/socketManager'
import MapManager from '#managers/mapManager' import MapManager from '#managers/mapManager'
import SocketManager from '#managers/socketManager'
import MapCharacter from '#models/mapCharacter' import MapCharacter from '#models/mapCharacter'
interface TeleportOptions { interface TeleportOptions {

View File

@ -16,9 +16,12 @@ import UserRepository from '#repositories/userRepository'
* @class UserService * @class UserService
*/ */
class UserService extends BaseService { class UserService extends BaseService {
protected readonly userRepository = new UserRepository()
protected readonly passwordResetTokenRepository = new PasswordResetTokenRepository()
async login(username: string, password: string): Promise<boolean | User> { async login(username: string, password: string): Promise<boolean | User> {
try { try {
const user = await UserRepository.getByUsername(username) const user = await this.userRepository.getByUsername(username)
if (!user) { if (!user) {
return false return false
} }
@ -39,7 +42,7 @@ class UserService extends BaseService {
async register(username: string, email: string, password: string): Promise<boolean | User> { async register(username: string, email: string, password: string): Promise<boolean | User> {
try { try {
// Check existing users // Check existing users
const [userByName, userByEmail] = await Promise.all([UserRepository.getByUsername(username), UserRepository.getByEmail(email)]) const [userByName, userByEmail] = await Promise.all([this.userRepository.getByUsername(username), this.userRepository.getByEmail(email)])
if (userByName || userByEmail) { if (userByName || userByEmail) {
this.logger.error(`User already exists: ${userByEmail ? email : username}`) this.logger.error(`User already exists: ${userByEmail ? email : username}`)
@ -59,11 +62,11 @@ class UserService extends BaseService {
async requestPasswordReset(email: string): Promise<boolean> { async requestPasswordReset(email: string): Promise<boolean> {
try { try {
const user = await UserRepository.getByEmail(email) const user = await this.userRepository.getByEmail(email)
if (!user) return false if (!user) return false
const token = await bcrypt.hash(new Date().getTime().toString(), 10) const token = await bcrypt.hash(new Date().getTime().toString(), 10)
const latestToken = await PasswordResetTokenRepository.getByUserId(user.id) const latestToken = await this.passwordResetTokenRepository.getByUserId(user.id)
// Check if password reset has been requested recently // Check if password reset has been requested recently
if (latestToken) { if (latestToken) {
@ -108,12 +111,12 @@ class UserService extends BaseService {
async resetPassword(urlToken: string, password: string): Promise<boolean> { async resetPassword(urlToken: string, password: string): Promise<boolean> {
try { try {
const tokenData = await PasswordResetTokenRepository.getByToken(urlToken) const tokenData = await this.passwordResetTokenRepository.getByToken(urlToken)
if (!tokenData) { if (!tokenData) {
return false return false
} }
const user = await UserRepository.getById(tokenData.userId) const user = await this.userRepository.getById(tokenData.userId)
if (!user) { if (!user) {
return false return false
} }