Improved entities, ran formatting, utilise getters and setters

This commit is contained in:
Dennis Postma 2024-12-26 16:45:00 +01:00
parent 691abb7c4f
commit 4a963b4359
18 changed files with 68 additions and 97 deletions

View File

@ -1,6 +1,6 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20241226031358 extends Migration {
export class Migration20241226153149 extends Migration {
override async up(): Promise<void> {
this.addSql(`create table \`map_object\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`tags\` json null, \`origin_x\` int not null default 0, \`origin_y\` int not null default 0, \`is_animated\` tinyint(1) not null default false, \`frame_rate\` int not null default 0, \`frame_width\` int not null default 0, \`frame_height\` int not null default 0, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);

View File

@ -42,17 +42,17 @@ export class Character extends BaseEntity {
rotation = 0
// Customization
@ManyToOne(() => CharacterType, { nullable: true })
@ManyToOne()
characterType?: CharacterType
@ManyToOne(() => CharacterHair, { nullable: true })
@ManyToOne()
characterHair?: CharacterHair
// Inventory
@OneToMany(() => CharacterItem, (item) => item.character)
@OneToMany({ mappedBy: 'character' })
items = new Collection<CharacterItem>(this)
@OneToMany(() => CharacterEquipment, (equipment) => equipment.character)
@OneToMany({ mappedBy: 'character' })
equipment = new Collection<CharacterEquipment>(this)
// Stats

View File

@ -2,9 +2,6 @@ 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'
import { UUID } from '#application/types'
@Entity()
@ -15,24 +12,15 @@ export class Sprite extends BaseEntity {
@Property()
name!: string
@OneToMany(() => SpriteAction, (action) => action.sprite)
spriteActions = new Collection<SpriteAction>(this)
@Property()
createdAt = new Date()
@Property()
updatedAt = new Date()
@OneToMany(() => SpriteAction, (action) => action.sprite)
spriteActions = new Collection<SpriteAction>(this)
@OneToMany(() => CharacterType, (type) => type.sprite)
characterTypes = new Collection<CharacterType>(this)
@OneToMany(() => CharacterHair, (hair) => hair.sprite)
characterHairs = new Collection<CharacterHair>(this)
@OneToMany(() => Item, (item) => item.sprite)
items = new Collection<Item>(this)
setId(id: UUID) {
this.id = id
return this
@ -51,6 +39,15 @@ export class Sprite extends BaseEntity {
return this.name
}
setSpriteActions(spriteActions: Collection<SpriteAction>) {
this.spriteActions = spriteActions
return this
}
getSpriteActions() {
return this.spriteActions
}
setCreatedAt(createdAt: Date) {
this.createdAt = createdAt
return this

View File

@ -20,7 +20,7 @@ router.post('/login', async (req: Request, res: Response) => {
const user = await userService.login(username, password)
if (user && typeof user !== 'boolean') {
const token = jwt.sign({ id: user.id }, config.JWT_SECRET, { expiresIn: '4h' })
const token = jwt.sign({ id: user.getId() }, config.JWT_SECRET, { expiresIn: '4h' })
return res.status(200).json({ token })
}

View File

@ -6,7 +6,7 @@ class CharacterHairRepository extends BaseRepository {
async getFirst() {
try {
const repository = this.em.getRepository(CharacterHair)
return await repository.findOne({ id: { $exists: true } })
return await repository.findOne({ id: { $exists: true } }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get first character hair: ${error instanceof Error ? error.message : String(error)}`)
return null
@ -16,7 +16,7 @@ class CharacterHairRepository extends BaseRepository {
async getAll() {
try {
const repository = this.em.getRepository(CharacterHair)
return await repository.findAll()
return await repository.findAll({ populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get all character hair: ${error instanceof Error ? error.message : String(error)}`)
return null
@ -26,9 +26,7 @@ class CharacterHairRepository extends BaseRepository {
async getAllSelectable() {
try {
const repository = this.em.getRepository(CharacterHair)
return await repository.find({
isSelectable: true
})
return await repository.find({ isSelectable: true }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get selectable character hair: ${error instanceof Error ? error.message : String(error)}`)
return null
@ -38,12 +36,7 @@ class CharacterHairRepository extends BaseRepository {
async getById(id: number) {
try {
const repository = this.em.getRepository(CharacterHair)
return await repository.findOne(
{ id },
{
populate: ['sprite.spriteActions']
}
)
return await repository.findOne({ id }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get character hair by ID: ${error instanceof Error ? error.message : String(error)}`)
return null

View File

@ -6,9 +6,7 @@ class CharacterRepository extends BaseRepository {
async getByUserId(userId: number): Promise<Character[]> {
try {
const repository = this.em.getRepository(Character)
return await repository.find({
user: userId
})
return await repository.find({ user: userId }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get character by user ID: ${error instanceof Error ? error.message : String(error)}`)
return []
@ -18,10 +16,7 @@ class CharacterRepository extends BaseRepository {
async getByUserAndId(userId: number, characterId: number): Promise<Character | null> {
try {
const repository = this.em.getRepository(Character)
return await repository.findOne({
user: userId,
id: characterId
})
return await repository.findOne({ user: userId, id: characterId }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get character by user ID and character ID: ${error instanceof Error ? error.message : String(error)}`)
return null
@ -31,7 +26,7 @@ class CharacterRepository extends BaseRepository {
async getById(id: number): Promise<Character | null> {
try {
const repository = this.em.getRepository(Character)
return await repository.findOne({ id })
return await repository.findOne({ id }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get character by ID: ${error instanceof Error ? error.message : String(error)}`)
return null
@ -41,7 +36,7 @@ class CharacterRepository extends BaseRepository {
async getByName(name: string): Promise<Character | null> {
try {
const repository = this.em.getRepository(Character)
return await repository.findOne({ name })
return await repository.findOne({ name }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get character by name: ${error instanceof Error ? error.message : String(error)}`)
return null

View File

@ -6,7 +6,7 @@ class CharacterTypeRepository extends BaseRepository {
async getFirst() {
try {
const repository = this.em.getRepository(CharacterType)
return await repository.findOne({ id: { $exists: true } })
return await repository.findOne({ id: { $exists: true } }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get first character type: ${error instanceof Error ? error.message : String(error)}`)
return null
@ -16,7 +16,7 @@ class CharacterTypeRepository extends BaseRepository {
async getAll() {
try {
const repository = this.em.getRepository(CharacterType)
return await repository.findAll()
return await repository.findAll({ populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get all character types: ${error instanceof Error ? error.message : String(error)}`)
return null
@ -26,7 +26,7 @@ class CharacterTypeRepository extends BaseRepository {
async getById(id: number) {
try {
const repository = this.em.getRepository(CharacterType)
return await repository.findOne({ id })
return await repository.findOne({ id }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get character type by ID: ${error instanceof Error ? error.message : String(error)}`)
return null

View File

@ -6,9 +6,12 @@ class ChatRepository extends BaseRepository {
async getById(id: number): Promise<Chat[]> {
try {
const repository = this.em.getRepository(Chat)
return await repository.find({
id
})
return await repository.find(
{
id
},
{ populate: ['*'] }
)
} catch (error: any) {
appLogger.error(`Failed to get chat by ID: ${error instanceof Error ? error.message : String(error)}`)
return []
@ -18,7 +21,7 @@ class ChatRepository extends BaseRepository {
async getAll(): Promise<Chat[]> {
try {
const repository = this.em.getRepository(Chat)
return await repository.findAll()
return await repository.findAll({ populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get all chats: ${error instanceof Error ? error.message : String(error)}`)
return []
@ -28,9 +31,7 @@ class ChatRepository extends BaseRepository {
async getByCharacterId(characterId: number): Promise<Chat[]> {
try {
const repository = this.em.getRepository(Chat)
return await repository.find({
character: characterId
})
return await repository.find({ character: characterId }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get chats by character ID: ${error instanceof Error ? error.message : String(error)}`)
return []
@ -40,9 +41,7 @@ class ChatRepository extends BaseRepository {
async getByZoneId(zoneId: number): Promise<Chat[]> {
try {
const repository = this.em.getRepository(Chat)
return await repository.find({
zone: zoneId
})
return await repository.find({ zone: zoneId }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get chats by zone ID: ${error instanceof Error ? error.message : String(error)}`)
return []

View File

@ -6,7 +6,7 @@ class SpriteRepository extends BaseRepository {
async getById(id: FilterValue<`${string}-${string}-${string}-${string}-${string}`>) {
try {
const repository = this.em.getRepository(Sprite)
return await repository.findOne({ id })
return await repository.findOne({ id }, { populate: ['*'] })
} catch (error: any) {
return null
}
@ -15,7 +15,7 @@ class SpriteRepository extends BaseRepository {
async getAll(): Promise<any> {
try {
const repository = this.em.getRepository(Sprite)
return await repository.findAll()
return await repository.findAll({ populate: ['*'] })
} catch (error: any) {
return null
}

View File

@ -6,7 +6,7 @@ class UserRepository extends BaseRepository {
async getById(id: number) {
try {
const repository = this.em.getRepository(User)
return await repository.findOne({ id })
return await repository.findOne({ id }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get user by ID: ${error instanceof Error ? error.message : String(error)}`)
return null
@ -16,7 +16,7 @@ class UserRepository extends BaseRepository {
async getByUsername(username: string) {
try {
const repository = this.em.getRepository(User)
return await repository.findOne({ username })
return await repository.findOne({ username }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get user by username: ${error instanceof Error ? error.message : String(error)}`)
return null
@ -26,7 +26,7 @@ class UserRepository extends BaseRepository {
async getByEmail(email: string) {
try {
const repository = this.em.getRepository(User)
return await repository.findOne({ email })
return await repository.findOne({ email }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get user by email: ${error instanceof Error ? error.message : String(error)}`)
return null

View File

@ -8,7 +8,7 @@ class ZoneRepository extends BaseRepository {
async getFirst(): Promise<Zone | null> {
try {
const repository = this.em.getRepository(Zone)
return await repository.findOne({ id: { $exists: true } })
return await repository.findOne({ id: { $exists: true } }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get first zone: ${error instanceof Error ? error.message : String(error)}`)
return null
@ -18,7 +18,7 @@ class ZoneRepository extends BaseRepository {
async getAll(): Promise<Zone[]> {
try {
const repository = this.em.getRepository(Zone)
return await repository.findAll()
return await repository.findAll({ populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get all zone: ${error.message}`)
return []
@ -28,7 +28,7 @@ class ZoneRepository extends BaseRepository {
async getById(id: number) {
try {
const repository = this.em.getRepository(Zone)
return await repository.findOne({ id })
return await repository.findOne({ id }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get zone by id: ${error.message}`)
return null
@ -38,9 +38,7 @@ class ZoneRepository extends BaseRepository {
async getEventTiles(id: number): Promise<ZoneEventTile[]> {
try {
const repository = this.em.getRepository(ZoneEventTile)
return await repository.find({
zone: id
})
return await repository.find({ zone: id }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get zone event tiles: ${error.message}`)
return []
@ -50,11 +48,14 @@ class ZoneRepository extends BaseRepository {
async getFirstEventTile(zoneId: number, positionX: number, positionY: number): Promise<ZoneEventTile | null> {
try {
const repository = this.em.getRepository(ZoneEventTile)
return await repository.findOne({
zone: zoneId,
positionX: positionX,
positionY: positionY
})
return await repository.findOne(
{
zone: zoneId,
positionX: positionX,
positionY: positionY
},
{ populate: ['*'] }
)
} catch (error: any) {
appLogger.error(`Failed to get zone event tile: ${error.message}`)
return null
@ -64,9 +65,7 @@ class ZoneRepository extends BaseRepository {
async getZoneObjects(id: number): Promise<ZoneObject[]> {
try {
const repository = this.em.getRepository(ZoneObject)
return await repository.find({
zone: id
})
return await repository.find({ zone: id }, { populate: ['*'] })
} catch (error: any) {
appLogger.error(`Failed to get zone objects: ${error.message}`)
return []

View File

@ -74,7 +74,7 @@ export class Server {
await UserManager.boot()
// Load date manager
await DateManager.boot(this.io)
// await DateManager.boot(this.io)
// Load weather manager
await WeatherManager.boot(this.io)

View File

@ -17,10 +17,7 @@ class ChatService {
const newChat = new Chat()
newChat
.setCharacter(character)
.setZone(zone)
.setMessage(message)
newChat.setCharacter(character).setZone(zone).setMessage(message)
await newChat.save()

View File

@ -48,10 +48,7 @@ class UserService {
const hashedPassword = await bcrypt.hash(password, 10)
const newUser = new User()
newUser
.setUsername(username)
.setEmail(email)
.setPassword(hashedPassword)
newUser.setUsername(username).setEmail(email).setPassword(hashedPassword)
await newUser.save()
return newUser
@ -82,9 +79,7 @@ class UserService {
// Create new token using MikroORM
const passwordResetToken = new PasswordResetToken()
passwordResetToken
.setUser(user)
.setToken(token)
passwordResetToken.setUser(user).setToken(token)
await passwordResetToken.save()
const transporter = NodeMailer.createTransport({

View File

@ -21,11 +21,7 @@ export class ZoneEventTileService {
character.isMoving = false
// Update local character object
character
.setZone(teleport.toZone)
.setRotation(teleport.toRotation)
.setPositionX(teleport.toPositionX)
.setPositionY(teleport.toPositionY)
character.setZone(teleport.toZone).setRotation(teleport.toRotation).setPositionX(teleport.toPositionX).setPositionY(teleport.toPositionY)
await character.save()

View File

@ -16,7 +16,7 @@ export default class CharacterListEvent {
private async handleCharacterList(data: any): Promise<void> {
try {
const characters: Character[] = (await CharacterRepository.getByUserId(this.socket.userId!)) as Character[]
const characters: Character[] = await CharacterRepository.getByUserId(this.socket.userId!)
this.socket.emit('character:list', characters)
} catch (error: any) {
gameLogger.error('character:list error', error.message)

View File

@ -1,12 +1,12 @@
import { Server } from 'socket.io'
import { TSocket } from '#application/types'
import ZoneRepository from '#repositories/zoneRepository'
import { Zone } from '@prisma/client'
import { gameLogger } from '#application/logger'
import CharacterRepository from '#repositories/characterRepository'
import ZoneManager from '#managers/zoneManager'
import zoneCharacter from '#models/zoneCharacter'
import zoneManager from '#managers/zoneManager'
import { Zone } from '#entities/zone'
interface IResponse {
zone: Zone
@ -39,7 +39,7 @@ export default class CharacterJoinEvent {
/**
* @TODO: If zone is not found, spawn back to the start
*/
const zone = await ZoneRepository.getById(character.zoneId)
const zone = await ZoneRepository.getById(character.zone!.id)
if (!zone) {
gameLogger.error('zone:character:join error', 'Zone not found')
return

View File

@ -36,7 +36,7 @@ export default class CharacterMove {
const path = await this.characterService.calculatePath(zoneCharacter.character, positionX, positionY)
if (!path) {
this.io.in(zoneCharacter.character.zoneId.toString()).emit('character:moveError', 'No valid path found')
this.io.in(zoneCharacter.character.zone!.id.toString()).emit('character:moveError', 'No valid path found')
return
}
@ -58,7 +58,7 @@ export default class CharacterMove {
const [start, end] = [path[i], path[i + 1]]
character.rotation = Rotation.calculate(start.x, start.y, end.x, end.y)
const zoneEventTile = await zoneEventTileRepository.getEventTileByZoneIdAndPosition(character.zoneId, Math.floor(end.x), Math.floor(end.y))
const zoneEventTile = await zoneEventTileRepository.getEventTileByZoneIdAndPosition(character.zone!.id, Math.floor(end.x), Math.floor(end.y))
if (zoneEventTile?.type === 'BLOCK') break
if (zoneEventTile?.type === 'TELEPORT' && zoneEventTile.teleport) {
@ -67,7 +67,7 @@ export default class CharacterMove {
}
this.characterService.updatePosition(character, end)
this.io.in(character.zoneId.toString()).emit('character:move', zoneCharacter)
this.io.in(character.zone!.id.toString()).emit('character:move', zoneCharacter)
await this.characterService.applyMovementDelay()
}
@ -91,6 +91,6 @@ export default class CharacterMove {
private finalizeMovement(zoneCharacter: ZoneCharacter): void {
zoneCharacter.isMoving = false
this.io.in(zoneCharacter.character.zoneId.toString()).emit('character:move', zoneCharacter)
this.io.in(zoneCharacter.character.zone!.id.toString()).emit('character:move', zoneCharacter)
}
}