Major refractor, cleaning and improvements.

This commit is contained in:
Dennis Postma 2024-08-24 03:08:43 +02:00
parent e0b376cb83
commit 39f4e79a88
30 changed files with 123 additions and 69 deletions

6
package-lock.json generated
View File

@ -2546,9 +2546,9 @@
}
},
"node_modules/tslib": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
"license": "0BSD",
"optional": true
},

View File

@ -20,7 +20,7 @@ export default function (socket: TSocket, io: Server) {
ZoneManager.removeCharacterFromZone(socket.character.zoneId, socket.character)
io.in(socket.character.zoneId.toString()).emit('zone:character:leave', socket.character.id)
io.in(socket.character.zoneId.toString()).emit('zoneEditor:character:leave', socket.character.id)
io.emit('character:disconnect', socket.character.id)
})
}

View File

@ -1,7 +1,7 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types'
import { TSocket } from '../../../../utilities/types'
import { Object } from '@prisma/client'
import ObjectRepository from '../../../repositories/objectRepository'
import ObjectRepository from '../../../../repositories/objectRepository'
interface IPayload {}

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types'
import { TSocket } from '../../../../utilities/types'
import path from 'path'
import fs from 'fs'
import prisma from '../../../utilities/prisma'
import prisma from '../../../../utilities/prisma'
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 '../../../../utilities/types'
import prisma from '../../../../utilities/prisma'
type Payload = {
id: string

View File

@ -1,9 +1,9 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types'
import { TSocket } from '../../../../utilities/types'
import { writeFile } from 'node:fs/promises'
import path from 'path'
import fs from 'fs/promises'
import prisma from '../../../utilities/prisma'
import prisma from '../../../../utilities/prisma'
interface IObjectData {
[key: string]: Buffer

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types'
import { TSocket } from '../../../../utilities/types'
import path from 'path'
import fs from 'fs/promises'
import prisma from '../../../utilities/prisma'
import prisma from '../../../../utilities/prisma'
/**
* Handle game master new sprite event

View File

@ -1,7 +1,7 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types'
import { TSocket } from '../../../../utilities/types'
import { Sprite } from '@prisma/client'
import SpriteRepository from '../../../repositories/spriteRepository'
import SpriteRepository from '../../../../repositories/spriteRepository'
interface IPayload {}

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types'
import { TSocket } from '../../../../utilities/types'
import fs from 'fs'
import path from 'path'
import prisma from '../../../utilities/prisma'
import prisma from '../../../../utilities/prisma'
type Payload = {
id: 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 '../../../../utilities/types'
import prisma from '../../../../utilities/prisma'
import type { Prisma, SpriteAction } from '@prisma/client'
import path from 'path'
import { writeFile, mkdir } from 'node:fs/promises'

View File

@ -1,7 +1,7 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types'
import { TSocket } from '../../../../utilities/types'
import { Tile } from '@prisma/client'
import TileRepository from '../../../repositories/tileRepository'
import TileRepository from '../../../../repositories/tileRepository'
interface IPayload {}

View File

@ -1,8 +1,8 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types'
import { TSocket } from '../../../../utilities/types'
import path from 'path'
import fs from 'fs'
import prisma from '../../../utilities/prisma'
import prisma from '../../../../utilities/prisma'
type Payload = {
id: 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 '../../../../utilities/types'
import prisma from '../../../../utilities/prisma'
type Payload = {
id: string

View File

@ -1,9 +1,9 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/types'
import { TSocket } from '../../../../utilities/types'
import { writeFile } from 'node:fs/promises'
import path from 'path'
import fs from 'fs/promises'
import prisma from '../../../utilities/prisma'
import prisma from '../../../../utilities/prisma'
interface ITileData {
[key: string]: Buffer

View File

@ -11,7 +11,7 @@ type Payload = {
}
/**
* Handle game master zone create event
* Handle game master zoneEditor create event
* @param socket
* @param io
*/
@ -36,10 +36,10 @@ export default function (socket: TSocket, io: Server) {
zoneList = await ZoneRepository.getAll()
callback(zoneList)
// send over zone and characters to socket
// send over zoneEditor and characters to socket
} catch (e) {
console.error(e)
socket.emit('notification', { message: 'Failed to create zone.' })
socket.emit('notification', { message: 'Failed to create zoneEditor.' })
callback(zoneList)
}
})

View File

@ -8,7 +8,7 @@ type Payload = {
}
/**
* Handle game master zone delete event
* Handle game master zoneEditor delete event
* @param socket
* @param io
*/

View File

@ -8,7 +8,7 @@ interface IPayload {
}
/**
* Handle game master zone request event
* Handle game master zoneEditor request event
* @param socket
* @param io
*/

View File

@ -26,7 +26,7 @@ interface IPayload {
}
/**
* Handle game master zone update event
* Handle game master zoneEditor update event
* @param socket
* @param io
*/
@ -66,9 +66,9 @@ export default function (socket: TSocket, io: Server) {
pvp: data.pvp,
zoneEventTiles: {
deleteMany: {
zoneId: data.zoneId // Ensure only event tiles related to the zone are deleted
zoneId: data.zoneId // Ensure only event tiles related to the zoneEditor are deleted
},
// Save new zone event tiles
// Save new zoneEditor event tiles
create: data.zoneEventTiles.map((zoneEventTile) => ({
type: zoneEventTile.type,
positionX: zoneEventTile.positionX,
@ -86,9 +86,9 @@ export default function (socket: TSocket, io: Server) {
},
zoneObjects: {
deleteMany: {
zoneId: data.zoneId // Ensure only objects related to the zone are deleted
zoneId: data.zoneId // Ensure only objects related to the zoneEditor are deleted
},
// Save new zone objects
// Save new zoneEditor objects
create: data.zoneObjects.map((zoneObject) => ({
objectId: zoneObject.objectId,
depth: zoneObject.depth,
@ -106,7 +106,7 @@ export default function (socket: TSocket, io: Server) {
return
}
// send over zone and characters to socket
// send over zoneEditor and characters to socket
socket.emit('gm:zone_editor:zone:load', zone)
zoneManager.unloadZone(data.zoneId)

View File

@ -1,5 +1,5 @@
import { Server } from 'socket.io'
import { TSocket } from '../../utilities/types'
import { ExtendedCharacter, TSocket } from '../../utilities/types'
import ZoneRepository from '../../repositories/zoneRepository'
import ZoneManager from '../../managers/zoneManager'
import { Character, Zone } from '@prisma/client'
@ -20,7 +20,7 @@ interface IResponse {
* @param io
*/
export default function (socket: TSocket, io: Server) {
socket.on('character:zone:request', async (data: IPayload, callback: (response: IResponse) => void) => {
socket.on('zone:characterJoin', async (data: IPayload, callback: (response: IResponse) => void) => {
try {
console.log(`---User ${socket.character?.id} has requested zone.`)
@ -43,11 +43,10 @@ export default function (socket: TSocket, io: Server) {
io.to(socket.character.zoneId.toString()).emit('zone:character:leave', socket.character)
}
socket.character.zoneId = zone.id
socket.join(zone.id.toString())
// let other clients know of new character
io.to(zone.id.toString()).emit('zone:character:join', socket.character)
io.to(zone.id.toString()).emit('zone:characterJoin', socket.character)
// add character to zone manager
ZoneManager.addCharacterToZone(zone.id, socket.character as Character)
@ -55,8 +54,8 @@ export default function (socket: TSocket, io: Server) {
// send over zone and characters to socket
callback({ zone, characters: ZoneManager.getCharactersInZone(zone.id) })
} catch (error: any) {
console.log(`Error requesting zone: ${error.message}`)
logger.error(`Error requesting zone: ${error.message}`)
socket.disconnect();
}
})
}

View File

@ -10,7 +10,7 @@ import { Character, Zone } from '@prisma/client'
* @param io
*/
export default function (socket: TSocket, io: Server) {
socket.on('character:zone:leave', async () => {
socket.on('zone:characterLeave', async () => {
console.log(`---Socket ${socket.character?.id} has leaved zone.`)
if (!socket.character) {

View File

@ -13,7 +13,7 @@ type TLoadedZone = {
class ZoneManager {
private loadedZones: TLoadedZone[] = []
// Method to initialize zone manager
// Method to initialize zoneEditor manager
public async boot() {
if (!(await ZoneRepository.getById(1))) {
const zoneService = new ZoneService()
@ -29,9 +29,9 @@ class ZoneManager {
logger.info('Zone manager loaded')
}
// Method to handle individual zone loading
// Method to handle individual zoneEditor loading
public async loadZone(zone: Zone) {
const grid = await this.getGrid(zone.id) // Create the grid for the zone
const grid = await this.getGrid(zone.id) // Create the grid for the zoneEditor
this.loadedZones.push({
zone,
characters: [],
@ -40,7 +40,7 @@ class ZoneManager {
logger.info(`Zone ID ${zone.id} loaded`)
}
// Method to handle individual zone unloading
// Method to handle individual zoneEditor unloading
public unloadZone(zoneId: number) {
this.loadedZones = this.loadedZones.filter((loadedZone) => {
return loadedZone.zone.id !== zoneId
@ -56,15 +56,43 @@ class ZoneManager {
// Check if position is walkable
private isPositionWalkable(zoneId: number, x: number, y: number): boolean {
const loadedZone = this.loadedZones.find((lz) => lz.zone.id === zoneId)
return loadedZone ? loadedZone.grid[y][x] === 0 : false
if (!loadedZone) {
console.log(`Zone ${zoneId} not found in loadedZones`);
return false;
}
if (!loadedZone.grid) {
console.log(`Grid for zone ${zoneId} is undefined`);
return false;
}
if (!loadedZone.grid[y]) {
console.log(`Row ${y} in grid for zone ${zoneId} is undefined`);
return false;
}
return loadedZone.grid[y][x] === 0;
}
public addCharacterToZone(zoneId: number, character: Character) {
console.log(`Adding character ${character.id} to zone ${zoneId}`);
console.log(`Character position: x=${character.positionX}, y=${character.positionY}`);
const loadedZone = this.loadedZones.find((loadedZone) => {
return loadedZone.zone.id === zoneId
})
if (loadedZone && this.isPositionWalkable(zoneId, character.positionX, character.positionY)) {
if (!loadedZone) {
console.log(`Zone ${zoneId} not found in loadedZones`);
return;
}
if (this.isPositionWalkable(zoneId, character.positionX, character.positionY)) {
loadedZone.characters.push(character)
console.log(`Character ${character.id} added to zone ${zoneId}`);
} else {
// set position to 0,0 if not walkable
console.log(`Position (${character.positionX}, ${character.positionY}) is not walkable in zone ${zoneId}`);
character.positionX = 0;
character.positionY = 0;
loadedZone.characters.push(character);
}
}

View File

@ -1,16 +1,23 @@
// socket io jwt auth middleware
import { verify } from 'jsonwebtoken'
import { TSocket } from '../utilities/types'
import config from '../utilities/config'
import UserRepository from '../repositories/userRepository'
import { User } from '@prisma/client'
/**
* Socket io jwt auth middleware
* @param socket
* @param next
*/
export async function Authentication(socket: TSocket, next: any) {
if (!socket.request.headers.cookie) {
console.log('No cookie provided')
return next(new Error('Authentication error'))
}
/**
* Parse cookies
*/
const cookies = socket.request.headers.cookie.split('; ').reduce((prev: any, current: any) => {
const [name, value] = current.split('=')
prev[name] = value
@ -19,6 +26,9 @@ export async function Authentication(socket: TSocket, next: any) {
const token = cookies['token']
/**
* Verify token, if valid, set user on socket and continue
*/
if (token) {
verify(token, config.JWT_SECRET, async (err: any, decoded: any) => {
if (err) {

View File

@ -14,6 +14,7 @@ class UserRepository {
throw new Error(`Failed to get user by ID: ${error.message}`)
}
}
async getByUsername(username: string): Promise<User | null> {
try {
return await prisma.user.findUnique({

View File

@ -1,13 +1,14 @@
import { Zone } from '@prisma/client'
import prisma from '../utilities/prisma' // Import the global Prisma instance
import { Zone, ZoneEventTile, ZoneObject } from '@prisma/client'
import prisma from '../utilities/prisma'
import logger from '../utilities/logger'
class ZoneRepository {
async getFirst(): Promise<Zone | null> {
try {
return await prisma.zone.findFirst()
} catch (error: any) {
// Handle error
throw new Error(`Failed to get first zone: ${error.message}`)
logger.error(`Failed to get first zone: ${error.message}`)
return null
}
}
@ -15,12 +16,12 @@ class ZoneRepository {
try {
return await prisma.zone.findMany()
} catch (error: any) {
// Handle error
throw new Error(`Failed to get all zone: ${error.message}`)
logger.error(`Failed to get all zone: ${error.message}`)
return []
}
}
async getById(id: number) {
async getById(id: number): Promise<Zone | null> {
try {
return await prisma.zone.findUnique({
where: {
@ -41,12 +42,12 @@ class ZoneRepository {
}
})
} catch (error: any) {
// Handle error
throw new Error(`Failed to get zone by id: ${error.message}`)
logger.error(`Failed to get zone by id: ${error.message}`)
return null
}
}
async getEventTiles(id: number) {
async getEventTiles(id: number): Promise<ZoneEventTile[]> {
try {
return await prisma.zoneEventTile.findMany({
where: {
@ -54,12 +55,12 @@ class ZoneRepository {
}
})
} catch (error: any) {
// Handle error
throw new Error(`Failed to get zone event tiles: ${error.message}`)
logger.error(`Failed to get zone event tiles: ${error.message}`)
return []
}
}
async getObjects(id: number) {
async getObjects(id: number): Promise<ZoneObject[]> {
try {
return await prisma.zoneObject.findMany({
where: {
@ -67,8 +68,8 @@ class ZoneRepository {
}
})
} catch (error: any) {
// Handle error
throw new Error(`Failed to get zone objects: ${error.message}`)
logger.error(`Failed to get zone objects: ${error.message}`)
return []
}
}
}

View File

@ -59,7 +59,7 @@ export class Server {
// Load user manager
await UserManager.boot()
// Load zone manager
// Load zoneEditor manager
await ZoneManager.boot()
// Load command manager - Disabled for now

View File

@ -3,7 +3,17 @@ import UserRepository from '../repositories/userRepository'
import prisma from '../utilities/prisma'
import { User } from '@prisma/client'
/**
* User service
* Handles user login and registration
* @class UserService
*/
class UserService {
/**
* Login user
* @param username
* @param password
*/
async login(username: string, password: string): Promise<boolean | User> {
const user = await UserRepository.getByUsername(username)
if (!user) {
@ -18,6 +28,11 @@ class UserService {
return user
}
/**
* Register user
* @param username
* @param password
*/
async register(username: string, password: string): Promise<boolean | User> {
const user = await UserRepository.getByUsername(username)
if (user) {

View File

@ -24,7 +24,7 @@ class ZoneService {
}
})
console.log('Demo zone created.')
console.log('Demo zoneEditor created.')
return true
}
}