Renamed folder utilities > application, added baseEntity class, updated baseRepo class, removed prisma helper

This commit is contained in:
Dennis Postma 2024-12-25 16:50:01 +01:00
parent f5a7a348e0
commit f4746722af
120 changed files with 423 additions and 378 deletions

View File

@ -3,7 +3,7 @@ ENV=development
HOST="0.0.0.0"
PORT=4000
JWT_SECRET="secret"
CLIENT_URL="http://192.168.3.4:5173"
CLIENT_URL="http://192.168.2.34:5173"
# Database configuration
REDIS_URL="redis://@127.0.0.1:6379/4"

View File

@ -2,7 +2,7 @@
import { defineConfig, MySqlDriver } from '@mikro-orm/mysql'
import { Migrator } from '@mikro-orm/migrations'
import { TsMorphMetadataProvider } from '@mikro-orm/reflection'
import serverConfig from './src/utilities/config'
import serverConfig from './src/application/config'
export default defineConfig({
extensions: [Migrator],

View File

@ -0,0 +1,67 @@
import { Database } from '#application/database'
import { appLogger } from '#application/logger'
export abstract class BaseEntity {
async save(): Promise<this> {
try {
const orm = await Database.getInstance()
const em = orm.em.fork()
await em.begin()
try {
em.persist(this)
await em.flush()
await em.commit()
return this
} catch (error) {
await em.rollback()
throw error
}
} catch (error) {
appLogger.error(`Failed to save entity: ${error instanceof Error ? error.message : String(error)}`)
throw error
}
}
async update(): Promise<this> {
try {
const orm = await Database.getInstance()
const em = orm.em.fork()
await em.begin()
try {
em.merge(this)
await em.flush()
await em.commit()
return this
} catch (error) {
await em.rollback()
throw error
}
} catch (error) {
appLogger.error(`Failed to update entity: ${error instanceof Error ? error.message : String(error)}`)
throw error
}
}
async delete(): Promise<this> {
try {
const orm = await Database.getInstance()
const em = orm.em.fork()
await em.begin()
try {
em.remove(this)
await em.flush()
await em.commit()
return this
} catch (error) {
await em.rollback()
throw error
}
} catch (error) {
appLogger.error(`Failed to remove entity: ${error instanceof Error ? error.message : String(error)}`)
throw error
}
}
}

View File

@ -1,5 +1,5 @@
import { appLogger } from '#utilities/logger'
import { Database } from '#utilities/database'
import { appLogger } from '../logger'
import { Database } from '../database'
import { EntityManager, MikroORM } from '@mikro-orm/core'
export abstract class BaseRepository {

View File

@ -0,0 +1,27 @@
import config from '../../mikro-orm.config'
// import { MikroORM } from '@mikro-orm/mariadb'
import { MikroORM } from '@mikro-orm/mysql'
import { appLogger } from './logger'
/**
* Singleton class for initializing and managing the database connection
*/
export class Database {
private static instance: MikroORM | undefined
private static async init(): Promise<MikroORM> {
try {
return await MikroORM.init(config)
} catch (error) {
appLogger.error(`MikroORM connection failed: ${error}`)
throw error
}
}
public static async getInstance(): Promise<MikroORM> {
if (!Database.instance) {
Database.instance = await Database.init()
}
return Database.instance
}
}

View File

@ -1,7 +1,7 @@
import { Server } from 'socket.io'
import prisma from '#utilities/prisma'
import prisma from '#application/prisma'
import fs from 'fs'
import { getPublicPath, getRootPath } from '#utilities/storage'
import { getPublicPath, getRootPath } from '#application/storage'
import sharp from 'sharp'
import { CharacterEquipmentSlotType, CharacterGender, CharacterRace } from '@prisma/client'
import bcrypt from 'bcryptjs'

View File

@ -1,8 +1,8 @@
import fs from 'fs'
import sharp from 'sharp'
import { commandLogger } from '#utilities/logger'
import { commandLogger } from '#application/logger'
import { Server } from 'socket.io'
import { getPublicPath } from '#utilities/storage'
import { getPublicPath } from '#application/storage'
import path from 'path'
export default class TilesCommand {

View File

@ -1,4 +1,5 @@
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { User } from './user'
import { Zone } from './zone'
import { CharacterType } from './characterType'
@ -8,7 +9,7 @@ import { CharacterEquipment } from './characterEquipment'
import { Chat } from './chat'
@Entity()
export class Character {
export class Character extends BaseEntity {
@PrimaryKey()
id!: number

View File

@ -1,10 +1,11 @@
import { Entity, Enum, ManyToOne, PrimaryKey } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Character } from './character'
import { CharacterItem } from './characterItem'
import { CharacterEquipmentSlotType } from '#utilities/enums'
import { CharacterEquipmentSlotType } from '#application/enums'
@Entity()
export class CharacterEquipment {
export class CharacterEquipment extends BaseEntity {
@PrimaryKey()
id!: number

View File

@ -1,10 +1,11 @@
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Character } from './character'
import { Sprite } from './sprite'
import { CharacterGender } from '#utilities/enums'
import { CharacterGender } from '#application/enums'
@Entity()
export class CharacterHair {
export class CharacterHair extends BaseEntity {
@PrimaryKey()
id!: number

View File

@ -1,10 +1,11 @@
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Character } from './character'
import { Item } from './item'
import { CharacterEquipment } from './characterEquipment'
@Entity()
export class CharacterItem {
export class CharacterItem extends BaseEntity {
@PrimaryKey()
id!: number

View File

@ -1,10 +1,11 @@
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Character } from './character'
import { Sprite } from './sprite'
import { CharacterGender, CharacterRace } from '#utilities/enums'
import { CharacterGender, CharacterRace } from '#application/enums'
@Entity()
export class CharacterType {
export class CharacterType extends BaseEntity {
@PrimaryKey()
id!: number

View File

@ -1,9 +1,10 @@
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Character } from './character'
import { Zone } from './zone'
@Entity()
export class Chat {
export class Chat extends BaseEntity {
@PrimaryKey()
id!: number

View File

@ -1,10 +1,11 @@
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Sprite } from './sprite'
import { CharacterItem } from './characterItem'
import { ItemType, ItemRarity } from '#utilities/enums'
import { ItemType, ItemRarity } from '#application/enums'
@Entity()
export class Item {
export class Item extends BaseEntity {
@PrimaryKey()
id!: string

View File

@ -1,9 +1,10 @@
import { randomUUID } from 'node:crypto'
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { ZoneObject } from './zoneObject'
@Entity()
export class MapObject {
export class MapObject extends BaseEntity {
@PrimaryKey()
id = randomUUID()

View File

@ -1,8 +1,9 @@
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { User } from './user'
@Entity()
export class PasswordResetToken {
export class PasswordResetToken extends BaseEntity {
@PrimaryKey()
id!: number

View File

@ -1,12 +1,13 @@
import { randomUUID } from 'node:crypto'
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { SpriteAction } from './spriteAction'
import { CharacterType } from './characterType'
import { CharacterHair } from './characterHair'
import { Item } from './item'
@Entity()
export class Sprite {
export class Sprite extends BaseEntity {
@PrimaryKey()
id = randomUUID()

View File

@ -1,9 +1,10 @@
import { randomUUID } from 'node:crypto'
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Sprite } from './sprite'
@Entity()
export class SpriteAction {
export class SpriteAction extends BaseEntity {
@PrimaryKey()
id = randomUUID()

View File

@ -1,8 +1,9 @@
import { randomUUID } from 'node:crypto'
import { Entity, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
@Entity()
export class Tile {
export class Tile extends BaseEntity {
@PrimaryKey()
id = randomUUID()

View File

@ -1,9 +1,10 @@
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Character } from './character'
import { PasswordResetToken } from './passwordResetToken'
@Entity()
export class User {
export class User extends BaseEntity {
@PrimaryKey()
id!: number

View File

@ -1,7 +1,8 @@
import { Entity, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
@Entity()
export class World {
export class World extends BaseEntity {
@PrimaryKey()
date = new Date()

View File

@ -1,4 +1,5 @@
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { ZoneEffect } from './zoneEffect'
import { ZoneEventTile } from './zoneEventTile'
import { ZoneEventTileTeleport } from './zoneEventTileTeleport'
@ -7,7 +8,7 @@ import { Character } from './character'
import { Chat } from './chat'
@Entity()
export class Zone {
export class Zone extends BaseEntity {
@PrimaryKey()
id!: number

View File

@ -1,8 +1,9 @@
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Zone } from './zone'
@Entity()
export class ZoneEffect {
export class ZoneEffect extends BaseEntity {
@PrimaryKey()
id!: string

View File

@ -1,10 +1,11 @@
import { Entity, Enum, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Zone } from './zone'
import { ZoneEventTileType } from '#utilities/enums'
import { ZoneEventTileType } from '#application/enums'
import { ZoneEventTileTeleport } from './zoneEventTileTeleport'
@Entity()
export class ZoneEventTile {
export class ZoneEventTile extends BaseEntity {
@PrimaryKey()
id!: string

View File

@ -1,10 +1,11 @@
import { randomUUID } from 'node:crypto'
import { Entity, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Zone } from './zone'
import { ZoneEventTile } from './ZoneEventTile'
import { ZoneEventTile } from './zoneEventTile'
@Entity()
export class ZoneEventTileTeleport {
export class ZoneEventTileTeleport extends BaseEntity {
@PrimaryKey()
id = randomUUID()

View File

@ -1,10 +1,11 @@
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/bases/baseEntity'
import { Zone } from './zone'
import { MapObject } from '#entities/mapObject'
//@TODO : Rename mapObject
@Entity()
export class ZoneObject {
export class ZoneObject extends BaseEntity {
@PrimaryKey()
id!: string

View File

@ -1,11 +1,11 @@
import { Router, Request, Response } from 'express'
import fs from 'fs'
import { httpLogger } from '#utilities/logger'
import { getPublicPath } from '#utilities/storage'
import { httpLogger } from '#application/logger'
import { getPublicPath } from '#application/storage'
import TileRepository from '#repositories/tileRepository'
import ZoneRepository from '#repositories/zoneRepository'
import SpriteRepository from '#repositories/spriteRepository'
import { AssetData } from '#utilities/types'
import { AssetData } from '#application/types'
import { FilterValue } from '@mikro-orm/core'
const router = Router()

View File

@ -1,8 +1,8 @@
import { Router, Request, Response } from 'express'
import UserService from '#services/userService'
import jwt from 'jsonwebtoken'
import config from '#utilities/config'
import { loginAccountSchema, registerAccountSchema, resetPasswordSchema, newPasswordSchema } from '#utilities/zodTypes'
import config from '#application/config'
import { loginAccountSchema, registerAccountSchema, resetPasswordSchema, newPasswordSchema } from '#application/zodTypes'
const router = Router()

View File

@ -7,7 +7,7 @@ import fs from 'fs'
import CharacterRepository from '#repositories/characterRepository'
import CharacterHairRepository from '#repositories/characterHairRepository'
import CharacterTypeRepository from '#repositories/characterTypeRepository'
import { getPublicPath } from '#utilities/storage'
import { getPublicPath } from '#application/storage'
const router = Router()

View File

@ -1,8 +1,8 @@
import { Application } from 'express'
import { httpLogger } from '#utilities/logger'
import { httpLogger } from '#application/logger'
import fs from 'fs'
import path from 'path'
import { getAppPath } from '#utilities/storage'
import { getAppPath } from '#application/storage'
async function addHttpRoutes(app: Application) {
const routeFiles = fs.readdirSync(__dirname).filter((file) => {

View File

@ -1,4 +1,4 @@
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import { Server as SocketServer } from 'socket.io'
export default class SomeJob {

View File

@ -2,8 +2,8 @@ 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'
import { getAppPath } from '#utilities/storage'
import { commandLogger } from '#application/logger'
import { getAppPath } from '#application/storage'
class CommandManager {
private commands: Map<string, any> = new Map()

View File

@ -1,5 +1,5 @@
import { Server } from 'socket.io'
import { appLogger } from '#utilities/logger'
import { appLogger } from '#application/logger'
import worldService from '#services/worldService'
import worldRepository from '#repositories/worldRepository'
@ -64,6 +64,9 @@ class DateManager {
}
private advanceGameTime(): void {
if (!this.currentDate) {
this.currentDate = new Date()
}
const advanceMilliseconds = DateManager.GAME_SPEED * DateManager.UPDATE_INTERVAL
this.currentDate = new Date(this.currentDate.getTime() + advanceMilliseconds)
}

View File

@ -1,11 +1,11 @@
import IORedis from 'ioredis'
import { Job, Queue, Worker } from 'bullmq'
import config from '#utilities/config'
import config from '#application/config'
import { Server as SocketServer } from 'socket.io'
import { TSocket } from '#utilities/types'
import { queueLogger } from '#utilities/logger'
import { TSocket } from '#application/types'
import { queueLogger } from '#application/logger'
import fs from 'fs'
import { getAppPath } from '#utilities/storage'
import { getAppPath } from '#application/storage'
class QueueManager {
private connection!: IORedis

View File

@ -1,5 +1,5 @@
import { User } from '@prisma/client'
import { appLogger } from '#utilities/logger'
import { appLogger } from '#application/logger'
type TLoggedInUsers = {
users: User[]

View File

@ -1,5 +1,5 @@
import { Server } from 'socket.io'
import { appLogger } from '#utilities/logger'
import { appLogger } from '#application/logger'
import worldService from '#services/worldService'
import worldRepository from '#repositories/worldRepository'
@ -25,9 +25,9 @@ class WeatherManager {
}
public async boot(io: Server): Promise<void> {
this.io = io
await this.loadWeather()
this.startWeatherLoop()
// this.io = io
// await this.loadWeather()
// this.startWeatherLoop()
appLogger.info('Weather manager loaded')
}

View File

@ -2,7 +2,7 @@ import { Zone } from '@prisma/client'
import ZoneRepository from '#repositories/zoneRepository'
import ZoneService from '#services/zoneService'
import LoadedZone from '#models/loadedZone'
import { gameLogger } from '#utilities/logger'
import { gameLogger } from '#application/logger'
import ZoneCharacter from '#models/zoneCharacter'
class ZoneManager {

View File

@ -1,9 +1,9 @@
import { verify } from 'jsonwebtoken'
import { TSocket } from '#utilities/types'
import config from '#utilities/config'
import { TSocket } from '#application/types'
import config from '#application/config'
import UserRepository from '#repositories/userRepository'
import { User } from '@prisma/client'
import { gameLogger } from '#utilities/logger'
import { gameLogger } from '#application/logger'
/**
* Socket io jwt auth middleware

View File

@ -1,5 +1,5 @@
import { appLogger } from '#utilities/logger'
import { BaseRepository } from './baseRepository'
import { appLogger } from '#application/logger'
import { BaseRepository } from '#application/bases/baseRepository'
import { CharacterHair } from '#entities/characterHair'
class CharacterHairRepository extends BaseRepository {

View File

@ -1,5 +1,5 @@
import { appLogger } from '#utilities/logger'
import { BaseRepository } from '#repositories/baseRepository'
import { appLogger } from '#application/logger'
import { BaseRepository } from '#application/bases/baseRepository'
import { Character } from '#entities/character'
class CharacterRepository extends BaseRepository {

View File

@ -1,5 +1,5 @@
import { appLogger } from '#utilities/logger'
import { BaseRepository } from '#repositories/baseRepository'
import { appLogger } from '#application/logger'
import { BaseRepository } from '#application/bases/baseRepository'
import { CharacterType } from '#entities/characterType'
class CharacterTypeRepository extends BaseRepository {

View File

@ -1,5 +1,5 @@
import { appLogger } from '#utilities/logger'
import { BaseRepository } from '#repositories/baseRepository'
import { appLogger } from '#application/logger'
import { BaseRepository } from '#application/bases/baseRepository'
import { Chat } from '#entities/chat'
class ChatRepository extends BaseRepository {

View File

@ -1,5 +1,5 @@
import { appLogger } from '#utilities/logger'
import { BaseRepository } from '#repositories/baseRepository'
import { appLogger } from '#application/logger'
import { BaseRepository } from '#application/bases/baseRepository'
import { Item } from '#entities/item'
class ItemRepository extends BaseRepository {

View File

@ -1,4 +1,4 @@
import { BaseRepository } from '#repositories/baseRepository'
import { BaseRepository } from '#application/bases/baseRepository'
class ObjectRepository extends BaseRepository {
async getById(id: string): Promise<any> {

View File

@ -1,5 +1,5 @@
import { appLogger } from '#utilities/logger'
import { BaseRepository } from '#repositories/baseRepository' // Import the global Prisma instance
import { appLogger } from '#application/logger'
import { BaseRepository } from '#application/bases/baseRepository' // Import the global Prisma instance
import { PasswordResetToken } from '#entities/passwordResetToken'
class PasswordResetTokenRepository extends BaseRepository {

View File

@ -1,5 +1,5 @@
import { FilterValue } from '@mikro-orm/core'
import { BaseRepository } from '#repositories/baseRepository'
import { BaseRepository } from '#application/bases/baseRepository'
import { Sprite } from '#entities/sprite'
class SpriteRepository extends BaseRepository {

View File

@ -1,9 +1,9 @@
import { FilterValue } from '@mikro-orm/core'
import { BaseRepository } from '#repositories/baseRepository'
import { BaseRepository } from '#application/bases/baseRepository'
import { Tile } from '#entities/tile'
import { Zone } from '#entities/zone'
import { unduplicateArray } from '#utilities/utilities'
import { FlattenZoneArray } from '#utilities/zone'
import { unduplicateArray } from '#application/utilities'
import { FlattenZoneArray } from '#application/zone'
class TileRepository extends BaseRepository {
async getById(id: FilterValue<`${string}-${string}-${string}-${string}-${string}`>): Promise<any> {

View File

@ -1,5 +1,5 @@
import { appLogger } from '#utilities/logger'
import { BaseRepository } from './baseRepository'
import { appLogger } from '#application/logger'
import { BaseRepository } from '#application/bases/baseRepository'
import { User } from '#entities/user'
class UserRepository extends BaseRepository {

View File

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

View File

@ -1,5 +1,5 @@
import { appLogger } from '#utilities/logger'
import { BaseRepository } from '#repositories/baseRepository'
import { appLogger } from '#application/logger'
import { BaseRepository } from '#application/bases/baseRepository'
import { ZoneEventTile } from '#entities/zoneEventTile'
class ZoneEventTileRepository extends BaseRepository {

View File

@ -1,5 +1,5 @@
import { appLogger } from '#utilities/logger'
import { BaseRepository } from '#repositories/baseRepository'
import { appLogger } from '#application/logger'
import { BaseRepository } from '#application/bases/baseRepository'
import { ZoneEventTile } from '#entities/zoneEventTile'
import { ZoneObject } from '#entities/zoneObject'
import { Zone } from '#entities/zone'

View File

@ -1,16 +1,15 @@
import fs from 'fs'
import express, { Application } from 'express'
import config from '#utilities/config'
import { getAppPath } from '#utilities/storage'
import config from '#application/config'
import { getAppPath } from '#application/storage'
import { createServer as httpServer, Server as HTTPServer } from 'http'
import { addHttpRoutes } from './http'
import cors from 'cors'
import { Server as SocketServer } from 'socket.io'
import { Authentication } from '#middleware/authentication'
import { TSocket } from '#utilities/types'
import { Database } from '#utilities/database'
import prisma from '#utilities/prisma' // @TODO: Remove this
import { appLogger, watchLogs } from '#utilities/logger'
import { TSocket } from '#application/types'
import { Database } from '#application/database'
import { appLogger, watchLogs } from '#application/logger'
import ZoneManager from '#managers/zoneManager'
import UserManager from '#managers/userManager'
import CommandManager from '#managers/commandManager'
@ -50,19 +49,11 @@ export class Server {
// Read log file and print to console for debugging
watchLogs()
// Check prisma connection
try {
await prisma.$connect()
appLogger.info('Database connected')
} catch (error: any) {
appLogger.error(`Database connection failed: ${error.message}`)
}
// MikroORM
// Connect to database
try {
await Database.getInstance()
} catch (error: any) {
appLogger.error(`Database 2 connection failed: ${error.message}`)
appLogger.error(`Database connection failed: ${error.message}`)
}
// Start the server

View File

@ -1,9 +1,14 @@
import { AStar } from '#utilities/character/aStar'
import { AStar } from '#application/character/aStar'
import ZoneManager from '#managers/zoneManager'
import prisma from '#utilities/prisma'
import Rotation from '#utilities/character/rotation'
import { appLogger, gameLogger } from '#utilities/logger'
import { Character } from '@prisma/client'
import Rotation from '#application/character/rotation'
import { appLogger, gameLogger } from '#application/logger'
import { Database } from '#application/database'
import { Character } from '#entities/character'
import UserRepository from '#repositories/userRepository'
import CharacterRepository from '#repositories/characterRepository'
import CharacterHairRepository from '#repositories/characterHairRepository'
import ZoneRepository from '#repositories/zoneRepository'
import { Zone } from '#entities/zone'
interface Position {
x: number
@ -14,32 +19,41 @@ export class CharacterService {
private readonly MOVEMENT_DELAY_MS = 250
async create(name: string, userId: number) {
return prisma.character.create({
data: {
name,
userId
// characterTypeId: 1 // @TODO set to chosen character type
}
})
const user = await UserRepository.getById(userId)
if (!user) return null
const character = new Character()
character.name = name
character.user = user
await Database.save(character)
return character
}
async updateHair(characterId: number, characterHairId: number | null) {
await prisma.character.update({
where: { id: characterId },
data: {
characterHairId
const character = await CharacterRepository.getById(characterId)
if (!character) return null
if (characterHairId === null) {
character.characterHair = undefined
await Database.save(character)
return character
}
})
const characterHair = await CharacterHairRepository.getById(characterHairId)
character.characterHair = characterHair ?? undefined
await Database.save(character)
return character
}
async deleteByUserIdAndId(userId: number, characterId: number): Promise<Character | null> {
try {
return await prisma.character.delete({
where: {
userId,
id: characterId
}
})
const character = await CharacterRepository.getByUserAndId(userId, characterId)
if (!character) return null
await Database.delete(character)
return character
} catch (error: any) {
// Handle error
appLogger.error(`Failed to delete character by user ID and character ID: ${error instanceof Error ? error.message : String(error)}`)
@ -48,15 +62,16 @@ export class CharacterService {
}
async updateCharacterPosition(id: number, positionX: number, positionY: number, rotation: number, zoneId: number) {
await prisma.character.update({
where: { id },
data: {
positionX,
positionY,
rotation,
zoneId
}
})
const character = await CharacterRepository.getById(id)
if (!character) return null
character.positionX = positionX
character.positionY = positionY
character.rotation = rotation
character.zone = await ZoneRepository.getById(zoneId) as Zone
await Database.save(character)
return character
}
public updatePosition(character: Character, position: Position, newZoneId?: number): void {
@ -68,12 +83,12 @@ export class CharacterService {
positionX: position.x,
positionY: position.y,
rotation: Rotation.calculate(character.positionX, character.positionY, position.x, position.y),
zoneId: newZoneId ?? character.zoneId
zoneId: newZoneId ?? character.zone.id
})
}
public async calculatePath(character: Character, targetX: number, targetY: number): Promise<Position[] | null> {
const zone = ZoneManager.getZoneById(character.zoneId)
const zone = ZoneManager.getZoneById(character.zone.id)
const grid = await zone?.getGrid()
if (!grid?.length) {

View File

@ -1,7 +1,7 @@
import prisma from '#utilities/prisma'
import { gameLogger } from '#utilities/logger'
import prisma from '#application/prisma'
import { gameLogger } from '#application/logger'
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import ChatRepository from '#repositories/chatRepository'
class ChatService {

View File

@ -1,6 +1,6 @@
import prisma from '#utilities/prisma'
import prisma from '#application/prisma'
import passwordResetTokenRepository from '#repositories/passwordResetTokenRepository'
import { appLogger } from '#utilities/logger'
import { appLogger } from '#application/logger'
class PasswordResetTokenService {
/**

View File

@ -1,12 +1,12 @@
import bcrypt from 'bcryptjs'
import UserRepository from '#repositories/userRepository'
import PasswordResetTokenRepository from '#repositories/passwordResetTokenRepository'
import config from '#utilities/config'
import config from '#application/config'
import NodeMailer from 'nodemailer'
import { httpLogger } from '#utilities/logger'
import { httpLogger } from '#application/logger'
import PasswordResetTokenService from './passwordResetTokenService' // @TODO: Correctly implement this
import { User } from '#entities/user'
import { Database } from '#utilities/database'
import { Database } from '#application/database'
import { PasswordResetToken } from '#entities/passwordResetToken'
/**

View File

@ -1,30 +1,35 @@
import prisma from '#utilities/prisma'
import { gameLogger } from '#utilities/logger'
import { World } from '@prisma/client'
import { gameLogger } from '#application/logger'
import WorldRepository from '#repositories/worldRepository'
import { World } from '#entities/world'
class WorldService {
async update(worldData: Partial<World>): Promise<boolean> {
try {
const currentWorld = await WorldRepository.getFirst()
if (!currentWorld) {
// If no world exists, create first record
await prisma.world.create({
data: {
...worldData,
date: worldData.date || new Date()
}
})
return true
let world = await WorldRepository.getFirst()
if (!world) {
world = new World()
await world.save()
}
// Update existing world using its date as unique identifier
await prisma.world.update({
where: {
date: currentWorld.date
},
data: worldData
})
world.date = worldData.date || new Date()
if (worldData.isRainEnabled) {
world.isRainEnabled = worldData.isRainEnabled
}
if (worldData.rainPercentage) {
world.rainPercentage = worldData.rainPercentage
}
if (worldData.isFogEnabled) {
world.isFogEnabled = worldData.isFogEnabled
}
if (worldData.fogDensity) {
world.fogDensity = worldData.fogDensity
}
console.log(world.date)
await world.update()
return true
} catch (error: any) {

View File

@ -1,9 +1,9 @@
import { ExtendedCharacter, TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { ExtendedCharacter, TSocket } from '#application/types'
import prisma from '#application/prisma'
import { ZoneEventTileTeleport } from '@prisma/client'
import { Server } from 'socket.io'
import ZoneManager from '#managers/zoneManager'
import { gameLogger } from '#utilities/logger'
import { gameLogger } from '#application/logger'
export class ZoneEventTileService {
public async handleTeleport(io: Server, socket: TSocket, character: ExtendedCharacter, teleport: ZoneEventTileTeleport): Promise<void> {

View File

@ -1,5 +1,5 @@
import prisma from '#utilities/prisma'
import { gameLogger } from '#utilities/logger'
import prisma from '#application/prisma'
import { gameLogger } from '#application/logger'
class ZoneService {}

View File

@ -1,7 +1,7 @@
import { Server } from 'socket.io'
import { CharacterHair } from '@prisma/client'
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import characterHairRepository from '#repositories/characterHairRepository'
import { CharacterHair } from '#entities/characterHair'
interface IPayload {}
@ -15,7 +15,7 @@ export default class characterHairListEvent {
this.socket.on('character:hair:list', this.handleEvent.bind(this))
}
private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise<void> {
private async handleEvent(data: IPayload, callback: (response: CharacterHair[] | null) => void): Promise<void> {
const items = await characterHairRepository.getAllSelectable()
callback(items)
}

View File

@ -1,7 +1,7 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import CharacterRepository from '#repositories/characterRepository'
import { gameLogger } from '#utilities/logger'
import { gameLogger } from '#application/logger'
import ZoneManager from '#managers/zoneManager'
import { CharacterService } from '#services/characterService'

View File

@ -1,10 +1,10 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { Character } from '@prisma/client'
import { TSocket } from '#application/types'
import { Character } from '#entities/character'
import CharacterRepository from '#repositories/characterRepository'
import { CharacterService } from '#services/characterService'
import { ZCharacterCreate } from '#utilities/zodTypes'
import { gameLogger } from '#utilities/logger'
import { ZCharacterCreate } from '#application/zodTypes'
import { gameLogger } from '#application/logger'
import { ZodError } from 'zod'
export default class CharacterCreateEvent {

View File

@ -1,8 +1,9 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { Character, Zone } from '@prisma/client'
import { TSocket } from '#application/types'
import CharacterRepository from '#repositories/characterRepository'
import { CharacterService } from '#services/characterService'
import { Character } from '#entities/character'
import { Zone } from '#entities/zone'
type TypePayload = {
characterId: number

View File

@ -1,8 +1,8 @@
import { Socket, Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { Character } from '@prisma/client'
import { TSocket } from '#application/types'
import CharacterRepository from '#repositories/characterRepository'
import { gameLogger } from '#utilities/logger'
import { gameLogger } from '#application/logger'
import { Character } from '#entities/character'
export default class CharacterListEvent {
constructor(

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { getArgs, isCommand } from '#utilities/chat'
import { TSocket } from '#application/types'
import { getArgs, isCommand } from '#application/chat'
import CharacterRepository from '#repositories/characterRepository'
import { gameLogger } from '#utilities/logger'
import { gameLogger } from '#application/logger'
type TypePayload = {
message: string

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { getArgs, isCommand } from '#utilities/chat'
import { TSocket } from '#application/types'
import { getArgs, isCommand } from '#application/chat'
import CharacterRepository from '#repositories/characterRepository'
import { gameLogger } from '#utilities/logger'
import { gameLogger } from '#application/logger'
import DateManager from '#managers/dateManager'
type TypePayload = {

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { getArgs, isCommand } from '#utilities/chat'
import { TSocket } from '#application/types'
import { getArgs, isCommand } from '#application/chat'
import ZoneRepository from '#repositories/zoneRepository'
import { gameLogger, gameMasterLogger } from '#utilities/logger'
import { gameLogger, gameMasterLogger } from '#application/logger'
import ZoneManager from '#managers/zoneManager'
import ZoneCharacter from '#models/zoneCharacter'
import zoneManager from '#managers/zoneManager'

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { isCommand } from '#utilities/chat'
import { TSocket } from '#application/types'
import { isCommand } from '#application/chat'
import CharacterRepository from '#repositories/characterRepository'
import { gameLogger } from '#utilities/logger'
import { gameLogger } from '#application/logger'
import WeatherManager from '#managers/weatherManager'
type TypePayload = {

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { isCommand } from '#utilities/chat'
import { TSocket } from '#application/types'
import { isCommand } from '#application/chat'
import CharacterRepository from '#repositories/characterRepository'
import { gameLogger } from '#utilities/logger'
import { gameLogger } from '#application/logger'
import WeatherManager from '#managers/weatherManager'
type TypePayload = {

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import ZoneRepository from '#repositories/zoneRepository'
import { isCommand } from '#utilities/chat'
import { gameLogger } from '#utilities/logger'
import { isCommand } from '#application/chat'
import { gameLogger } from '#application/logger'
import ZoneManager from '#managers/zoneManager'
import ChatService from '#services/chatService'

View File

@ -1,6 +1,6 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { gameLogger } from '#utilities/logger'
import { TSocket } from '#application/types'
import { gameLogger } from '#application/logger'
import ZoneManager from '#managers/zoneManager'
export default class DisconnectEvent {

View File

@ -1,6 +1,6 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
export default class CharacterHairCreateEvent {

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
import { gameMasterLogger } from '#utilities/logger'
import { gameMasterLogger } from '#application/logger'
interface IPayload {
id: number

View File

@ -1,7 +1,7 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import { CharacterHair } from '@prisma/client'
import { gameMasterLogger } from '#utilities/logger'
import { gameMasterLogger } from '#application/logger'
import characterRepository from '#repositories/characterRepository'
import characterHairRepository from '#repositories/characterHairRepository'

View File

@ -1,9 +1,9 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
import { CharacterGender, CharacterRace } from '@prisma/client'
import { gameMasterLogger } from '#utilities/logger'
import { gameMasterLogger } from '#application/logger'
type Payload = {
id: number

View File

@ -1,6 +1,6 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
import { CharacterGender, CharacterRace } from '@prisma/client'

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
import { gameMasterLogger } from '#utilities/logger'
import { gameMasterLogger } from '#application/logger'
interface IPayload {
id: number

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import { CharacterType } from '@prisma/client'
import characterRepository from '#repositories/characterRepository'
import { gameMasterLogger } from '#utilities/logger'
import { gameMasterLogger } from '#application/logger'
import CharacterTypeRepository from '#repositories/characterTypeRepository'
interface IPayload {}

View File

@ -1,6 +1,6 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
import { CharacterGender, CharacterRace } from '@prisma/client'

View File

@ -1,6 +1,6 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
export default class ItemCreateEvent {

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
import { gameMasterLogger } from '#utilities/logger'
import { gameMasterLogger } from '#application/logger'
interface IPayload {
id: string

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import { Item } from '@prisma/client'
import characterRepository from '#repositories/characterRepository'
import { gameMasterLogger } from '#utilities/logger'
import { gameMasterLogger } from '#application/logger'
import itemRepository from '#repositories/itemRepository'
interface IPayload {}

View File

@ -1,9 +1,9 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
import { ItemType, ItemRarity } from '@prisma/client'
import { gameMasterLogger } from '#utilities/logger'
import { gameMasterLogger } from '#application/logger'
type Payload = {
id: string

View File

@ -1,5 +1,5 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import { Object } from '@prisma/client'
import ObjectRepository from '#repositories/objectRepository'
import characterRepository from '#repositories/characterRepository'

View File

@ -1,10 +1,10 @@
import fs from 'fs'
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
import { getPublicPath } from '#utilities/storage'
import { gameLogger, gameMasterLogger } from '#utilities/logger'
import { getPublicPath } from '#application/storage'
import { gameLogger, gameMasterLogger } from '#application/logger'
interface IPayload {
object: string

View File

@ -1,6 +1,6 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
type Payload = {

View File

@ -1,12 +1,12 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import { writeFile } from 'node:fs/promises'
import fs from 'fs/promises'
import prisma from '#utilities/prisma'
import prisma from '#application/prisma'
import sharp from 'sharp'
import characterRepository from '#repositories/characterRepository'
import { gameMasterLogger } from '#utilities/logger'
import { getPublicPath } from '#utilities/storage'
import { gameMasterLogger } from '#application/logger'
import { getPublicPath } from '#application/storage'
interface IObjectData {
[key: string]: Buffer

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import prisma from '#utilities/prisma'
import { TSocket } from '#application/types'
import prisma from '#application/prisma'
import CharacterRepository from '#repositories/characterRepository'
import { gameMasterLogger } from '#utilities/logger'
import { gameMasterLogger } from '#application/logger'
import type { Prisma } from '@prisma/client'
interface CopyPayload {

View File

@ -1,9 +1,9 @@
import { Server } from 'socket.io'
import { TSocket } from '#utilities/types'
import { TSocket } from '#application/types'
import fs from 'fs/promises'
import prisma from '#utilities/prisma'
import prisma from '#application/prisma'
import characterRepository from '#repositories/characterRepository'
import { getPublicPath } from '#utilities/storage'
import { getPublicPath } from '#application/storage'
export default class SpriteCreateEvent {
constructor(

Some files were not shown because too many files have changed in this diff Show More