Added logging, worked on character type management

This commit is contained in:
Dennis Postma 2024-10-19 02:14:39 +02:00
parent d29420cbf3
commit 4e1e7d95ac
11 changed files with 234 additions and 32 deletions

View File

@ -53,7 +53,7 @@ CREATE TABLE `CharacterType` (
`name` VARCHAR(191) NOT NULL,
`gender` ENUM('MALE', 'FEMALE') NOT NULL,
`race` ENUM('HUMAN', 'ELF', 'DWARF', 'ORC', 'GOBLIN') NOT NULL,
`spriteId` VARCHAR(191) NOT NULL,
`spriteId` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,

View File

@ -25,8 +25,8 @@ model CharacterType {
gender CharacterGender
race CharacterRace
characters Character[]
spriteId String
sprite Sprite @relation(fields: [spriteId], references: [id], onDelete: Cascade)
spriteId String?
sprite Sprite? @relation(fields: [spriteId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

View File

@ -65,4 +65,4 @@ class DateManager {
}
}
export default new DateManager()
export default new DateManager()

View File

@ -0,0 +1,10 @@
import prisma from '../utilities/prisma' // Import the global Prisma instance
import { CharacterType } from '@prisma/client'
class CharacterTypeRepository {
async getAll(): Promise<CharacterType[]> {
return prisma.characterType.findMany()
}
}
export default new CharacterTypeRepository()

View File

@ -0,0 +1,40 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../../utilities/types'
import prisma from '../../../../utilities/prisma'
import characterRepository from '../../../../repositories/characterRepository'
import { CharacterGender, CharacterRace } from '@prisma/client'
export default class CharacterTypeCreateEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
public listen(): void {
this.socket.on('gm:characterType:create', this.handleCharacterTypeCreate.bind(this))
}
private async handleCharacterTypeCreate(data: undefined, callback: (response: boolean, characterType?: any) => void): Promise<void> {
try {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) return callback(false)
if (character.role !== 'gm') {
return callback(false)
}
const newCharacterType = await prisma.characterType.create({
data: {
name: 'New character type',
gender: CharacterGender.MALE,
race: CharacterRace.HUMAN
}
})
callback(true, newCharacterType)
} catch (error) {
console.error('Error creating character type:', error)
callback(false)
}
}
}

View File

@ -0,0 +1,36 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../../utilities/types'
import { CharacterType } from '@prisma/client'
import characterRepository from '../../../../repositories/characterRepository'
import { gameMasterLogger } from '../../../../utilities/logger'
import CharacterTypeRepository from '../../../../repositories/characterTypeRepository'
interface IPayload {}
export default class CharacterTypeListEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
public listen(): void {
this.socket.on('gm:characterType:list', this.handleCharacterTypeList.bind(this))
}
private async handleCharacterTypeList(data: IPayload, callback: (response: CharacterType[]) => void): Promise<void> {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) {
gameMasterLogger.error('gm:characterType:list error', 'Character not found')
return callback([])
}
if (character.role !== 'gm') {
gameMasterLogger.info(`User ${character.id} tried to list character types but is not a game master.`)
return callback([])
}
// get all objects
const items = await CharacterTypeRepository.getAll()
callback(items)
}
}

View File

@ -0,0 +1,56 @@
import fs from 'fs'
import { Server } from 'socket.io'
import { TSocket } from '../../../../utilities/types'
import prisma from '../../../../utilities/prisma'
import characterRepository from '../../../../repositories/characterRepository'
import { getPublicPath } from '../../../../utilities/storage'
interface IPayload {
object: string
}
export default class ObjectRemoveEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
public listen(): void {
this.socket.on('gm:object:remove', this.handleObjectRemove.bind(this))
}
private async handleObjectRemove(data: IPayload, callback: (response: boolean) => void): Promise<void> {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) return callback(false)
if (character.role !== 'gm') {
return callback(false)
}
try {
await prisma.object.delete({
where: {
id: data.object
}
})
// get root path
const public_folder = getPublicPath('objects')
// remove the tile from the disk
const finalFilePath = getPublicPath('objects', data.object + '.png')
fs.unlink(finalFilePath, (err) => {
if (err) {
console.log(err)
callback(false)
return
}
callback(true)
})
} catch (e) {
console.log(e)
callback(false)
}
}
}

View File

@ -0,0 +1,58 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../../utilities/types'
import prisma from '../../../../utilities/prisma'
import characterRepository from '../../../../repositories/characterRepository'
type Payload = {
id: string
name: string
tags: string[]
originX: number
originY: number
isAnimated: boolean
frameSpeed: number
frameWidth: number
frameHeight: number
}
export default class ObjectUpdateEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
public listen(): void {
this.socket.on('gm:object:update', this.handleObjectUpdate.bind(this))
}
private async handleObjectUpdate(data: Payload, callback: (success: boolean) => void): Promise<void> {
const character = await characterRepository.getById(this.socket.characterId as number)
if (!character) return callback(false)
if (character.role !== 'gm') {
return callback(false)
}
try {
const object = await prisma.object.update({
where: {
id: data.id
},
data: {
name: data.name,
tags: data.tags,
originX: data.originX,
originY: data.originY,
isAnimated: data.isAnimated,
frameSpeed: data.frameSpeed,
frameWidth: data.frameWidth,
frameHeight: data.frameHeight
}
})
callback(true)
} catch (error) {
console.error(error)
callback(false)
}
}
}

View File

@ -130,6 +130,8 @@ export default class ZoneUpdateEvent {
return
}
gameMasterLogger.info(`User ${character.id} has updated zone via zone editor.`)
callback(zone)
zoneManager.unloadZone(data.zoneId)

View File

@ -1,49 +1,49 @@
import * as fs from 'fs/promises';
import { appLogger } from './logger';
import * as fs from 'fs/promises'
import { appLogger } from './logger'
export async function readJsonFile<T>(filePath: string): Promise<T> {
try {
const fileContent = await fs.readFile(filePath, 'utf-8');
return JSON.parse(fileContent) as T;
const fileContent = await fs.readFile(filePath, 'utf-8')
return JSON.parse(fileContent) as T
} catch (error) {
appLogger.error(`Error reading JSON file: ${error instanceof Error ? error.message : String(error)}`);
throw error;
appLogger.error(`Error reading JSON file: ${error instanceof Error ? error.message : String(error)}`)
throw error
}
}
export async function writeJsonFile<T>(filePath: string, data: T): Promise<void> {
try {
const jsonString = JSON.stringify(data, null, 2);
await fs.writeFile(filePath, jsonString, 'utf-8');
const jsonString = JSON.stringify(data, null, 2)
await fs.writeFile(filePath, jsonString, 'utf-8')
} catch (error) {
appLogger.error(`Error writing JSON file: ${error instanceof Error ? error.message : String(error)}`);
throw error;
appLogger.error(`Error writing JSON file: ${error instanceof Error ? error.message : String(error)}`)
throw error
}
}
export async function readJsonValue<T>(filePath: string, paramPath: string): Promise<T> {
try {
const jsonContent = await readJsonFile<any>(filePath);
const paramValue = paramPath.split('.').reduce((obj, key) => obj && obj[key], jsonContent);
const jsonContent = await readJsonFile<any>(filePath)
const paramValue = paramPath.split('.').reduce((obj, key) => obj && obj[key], jsonContent)
if (paramValue === undefined) {
throw new Error(`Parameter ${paramPath} not found in the JSON file`);
throw new Error(`Parameter ${paramPath} not found in the JSON file`)
}
return paramValue as T;
return paramValue as T
} catch (error) {
appLogger.error(`Error reading JSON parameter: ${error instanceof Error ? error.message : String(error)}`);
throw error;
appLogger.error(`Error reading JSON parameter: ${error instanceof Error ? error.message : String(error)}`)
throw error
}
}
export async function setJsonValue<T>(filePath: string, key: string, value: any): Promise<void> {
try {
const data = await readJsonFile<T>(filePath);
const updatedData = { ...data, [key]: value };
await writeJsonFile(filePath, updatedData);
const data = await readJsonFile<T>(filePath)
const updatedData = { ...data, [key]: value }
await writeJsonFile(filePath, updatedData)
} catch (error) {
appLogger.error(`Error setting JSON value: ${error instanceof Error ? error.message : String(error)}`);
throw error;
appLogger.error(`Error setting JSON value: ${error instanceof Error ? error.message : String(error)}`)
throw error
}
}
}

View File

@ -17,17 +17,17 @@ export function getPublicPath(folder: string, ...additionalSegments: string[]) {
export function doesPathExist(path: string) {
try {
fs.accessSync(path, fs.constants.F_OK);
return true;
fs.accessSync(path, fs.constants.F_OK)
return true
} catch (e) {
return false;
return false
}
}
export function createDir(path: string) {
try {
fs.mkdirSync(path, { recursive: true });
fs.mkdirSync(path, { recursive: true })
} catch (e) {
console.error(e);
console.error(e)
}
}
}