forked from noxious/server
#161: Set default value for createdAt field, store zone chats into database
This commit is contained in:
parent
3f8f8745eb
commit
460308d555
6
package-lock.json
generated
6
package-lock.json
generated
@ -949,9 +949,9 @@
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/bullmq": {
|
||||
"version": "5.25.6",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.25.6.tgz",
|
||||
"integrity": "sha512-jxpa/DB02V20CqBAgyqpQazT630CJm0r4fky8EchH3mcJAomRtKXLS6tRA0J8tb29BDGlr/LXhlUuZwdBJBSdA==",
|
||||
"version": "5.26.1",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.26.1.tgz",
|
||||
"integrity": "sha512-XuxCGFlC1PQ2i1JHQiB9dqkqKQILMwQpU7ipi+cT/dzJaoXVcS0/IByUz6SsZ3xyOQY3twPt6G7J2d5GrsJuEA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cron-parser": "^4.6.0",
|
||||
|
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE `Chat` MODIFY `createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3);
|
@ -11,7 +11,7 @@
|
||||
// npx prisma migrate deploy
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["prismaSchemaFolder"]
|
||||
}
|
||||
|
||||
@ -27,5 +27,5 @@ model Chat {
|
||||
zoneId Int
|
||||
zone Zone @relation(fields: [zoneId], references: [id], onDelete: Cascade)
|
||||
message String
|
||||
createdAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import prisma from '../utilities/prisma'
|
||||
class ZoneCharacter {
|
||||
public readonly character: Character
|
||||
public isMoving: boolean = false
|
||||
public currentPath: Array<{ x: number; y: number }> | null = null;
|
||||
public currentPath: Array<{ x: number; y: number }> | null = null
|
||||
|
||||
constructor(character: Character) {
|
||||
this.character = character
|
||||
|
@ -0,0 +1,49 @@
|
||||
import prisma from '../utilities/prisma'
|
||||
import { Chat } from '@prisma/client'
|
||||
|
||||
class ChatRepository {
|
||||
async getById(id: number): Promise<Chat | null> {
|
||||
return prisma.chat.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
character: true,
|
||||
zone: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async getAll(): Promise<Chat[]> {
|
||||
return prisma.chat.findMany({
|
||||
include: {
|
||||
character: true,
|
||||
zone: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async getByCharacterId(characterId: number): Promise<Chat[]> {
|
||||
return prisma.chat.findMany({
|
||||
where: {
|
||||
characterId
|
||||
},
|
||||
include: {
|
||||
character: true,
|
||||
zone: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async getByZoneId(zoneId: number): Promise<Chat[]> {
|
||||
return prisma.chat.findMany({
|
||||
where: {
|
||||
zoneId
|
||||
},
|
||||
include: {
|
||||
character: true,
|
||||
zone: true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default new ChatRepository()
|
@ -27,12 +27,14 @@ export class Server {
|
||||
*/
|
||||
constructor() {
|
||||
this.app = express()
|
||||
this.app.use(cors({
|
||||
origin: config.CLIENT_URL,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // Add supported methods
|
||||
allowedHeaders: ['Content-Type', 'Authorization'], // Add allowed headers
|
||||
credentials: true // Enable if you're using cookies/credentials
|
||||
}))
|
||||
this.app.use(
|
||||
cors({
|
||||
origin: config.CLIENT_URL,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // Add supported methods
|
||||
allowedHeaders: ['Content-Type', 'Authorization'], // Add allowed headers
|
||||
credentials: true // Enable if you're using cookies/credentials
|
||||
})
|
||||
)
|
||||
this.app.use(express.json())
|
||||
this.app.use(express.urlencoded({ extended: true }))
|
||||
this.http = httpServer(this.app)
|
||||
|
@ -0,0 +1,30 @@
|
||||
import prisma from '../utilities/prisma'
|
||||
import { gameLogger } from '../utilities/logger'
|
||||
import { Server } from 'socket.io'
|
||||
import { TSocket } from '../utilities/types'
|
||||
import ChatRepository from '../repositories/chatRepository'
|
||||
|
||||
class ChatService {
|
||||
async sendZoneMessage(io: Server, socket: TSocket, message: string, characterId: number, zoneId: number): Promise<boolean> {
|
||||
try {
|
||||
const newChat = await prisma.chat.create({
|
||||
data: {
|
||||
characterId,
|
||||
zoneId,
|
||||
message
|
||||
}
|
||||
})
|
||||
|
||||
const chat = await ChatRepository.getById(newChat.id)
|
||||
if (!chat) return false
|
||||
|
||||
io.to(zoneId.toString()).emit('chat:message', chat)
|
||||
return true
|
||||
} catch (error: any) {
|
||||
gameLogger.error(`Failed to save chat message: ${error instanceof Error ? error.message : String(error)}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ChatService
|
@ -45,7 +45,7 @@ export default class CharacterConnectEvent {
|
||||
|
||||
private async hasActiveCharacter(): Promise<boolean> {
|
||||
const characters = await CharacterRepository.getByUserId(this.socket.userId!)
|
||||
return characters?.some(char => ZoneManager.getCharacter(char.id)) ?? false
|
||||
return characters?.some((char) => ZoneManager.getCharacter(char.id)) ?? false
|
||||
}
|
||||
|
||||
private async connectCharacter(characterId: number) {
|
||||
@ -53,7 +53,7 @@ export default class CharacterConnectEvent {
|
||||
}
|
||||
|
||||
private emitError(message: string): void {
|
||||
this.socket.emit('notification', { title: 'Server message', message})
|
||||
this.socket.emit('notification', { title: 'Server message', message })
|
||||
gameLogger.error('character:connect error', `Player ${this.socket.userId}: ${message}`)
|
||||
}
|
||||
|
||||
@ -62,4 +62,4 @@ export default class CharacterConnectEvent {
|
||||
this.emitError(`${context}: ${errorMessage}`)
|
||||
gameLogger.error('character:connect error', errorMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,30 +17,27 @@ export default class ChatMessageEvent {
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('chat:send_message', this.handleChatMessage.bind(this))
|
||||
this.socket.on('chat:message', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleChatMessage(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!data.message || isCommand(data.message)) {
|
||||
callback(false)
|
||||
return
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const zoneCharacter = ZoneManager.getCharacter(this.socket.characterId!)
|
||||
if (!zoneCharacter) {
|
||||
gameLogger.error('chat:send_message error', 'Character not found')
|
||||
callback(false)
|
||||
return
|
||||
gameLogger.error('chat:message error', 'Character not found')
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const character = zoneCharacter.character
|
||||
|
||||
const zone = await ZoneRepository.getById(character.zoneId)
|
||||
if (!zone) {
|
||||
gameLogger.error('chat:send_message error', 'Zone not found')
|
||||
callback(false)
|
||||
return
|
||||
gameLogger.error('chat:message error', 'Zone not found')
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const chatService = new ChatService()
|
||||
@ -50,7 +47,7 @@ export default class ChatMessageEvent {
|
||||
|
||||
callback(false)
|
||||
} catch (error: any) {
|
||||
gameLogger.error('chat:send_message error', error.message)
|
||||
gameLogger.error('chat:message error', error.message)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export default class ObjectRemoveEvent {
|
||||
const finalFilePath = getPublicPath('objects', data.object + '.png')
|
||||
fs.unlink(finalFilePath, (err) => {
|
||||
if (err) {
|
||||
gameMasterLogger.error(`Error deleting object ${data.object}: ${(err.message)}`)
|
||||
gameMasterLogger.error(`Error deleting object ${data.object}: ${err.message}`)
|
||||
callback(false)
|
||||
return
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ export default class ObjectRemoveEvent {
|
||||
const finalFilePath = getPublicPath('objects', data.object + '.png')
|
||||
fs.unlink(finalFilePath, (err) => {
|
||||
if (err) {
|
||||
gameMasterLogger.error(`Error deleting object ${data.object}: ${(err.message)}`)
|
||||
gameMasterLogger.error(`Error deleting object ${data.object}: ${err.message}`)
|
||||
callback(false)
|
||||
return
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ export default class CharacterMove {
|
||||
// If already moving, cancel current movement and wait for it to fully stop
|
||||
if (zoneCharacter.isMoving) {
|
||||
zoneCharacter.isMoving = false
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||
}
|
||||
|
||||
const path = await this.characterMoveService.calculatePath(zoneCharacter.character, positionX, positionY)
|
||||
|
Loading…
x
Reference in New Issue
Block a user