CRUD for items

This commit is contained in:
Dennis Postma 2024-12-22 20:09:14 +01:00
parent 1facd2d641
commit dd9e039649
8 changed files with 220 additions and 2 deletions

View File

@ -55,6 +55,7 @@ CREATE TABLE `Item` (
`itemType` ENUM('WEAPON', 'HELMET', 'CHEST', 'LEGS', 'BOOTS', 'GLOVES', 'RING', 'NECKLACE') NOT NULL,
`stackable` BOOLEAN NOT NULL DEFAULT false,
`rarity` ENUM('COMMON', 'UNCOMMON', 'RARE', 'EPIC', 'LEGENDARY') NOT NULL DEFAULT 'COMMON',
`spriteId` VARCHAR(191) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
@ -256,6 +257,9 @@ ALTER TABLE `Chat` ADD CONSTRAINT `Chat_zoneId_fkey` FOREIGN KEY (`zoneId`) REFE
-- AddForeignKey
ALTER TABLE `SpriteAction` ADD CONSTRAINT `SpriteAction_spriteId_fkey` FOREIGN KEY (`spriteId`) REFERENCES `Sprite`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Item` ADD CONSTRAINT `Item_spriteId_fkey` FOREIGN KEY (`spriteId`) REFERENCES `Sprite`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `PasswordResetToken` ADD CONSTRAINT `PasswordResetToken_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `User`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -1,3 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
# It should be added in your version-control system (e.g., Git)
provider = "mysql"

View File

@ -24,6 +24,7 @@ model Sprite {
spriteActions SpriteAction[]
characterTypes CharacterType[]
characterHairs CharacterHair[]
Item Item[]
}
model SpriteAction {
@ -48,6 +49,8 @@ model Item {
itemType ItemType
stackable Boolean @default(false)
rarity ItemRarity @default(COMMON)
spriteId String?
sprite Sprite? @relation(fields: [spriteId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
characters CharacterItem[]

View File

@ -0,0 +1,39 @@
import prisma from '../utilities/prisma' // Import the global Prisma instance
import { Tile } from '@prisma/client'
import zoneRepository from './zoneRepository'
import { unduplicateArray } from '../utilities/utilities'
import { FlattenZoneArray } from '../utilities/zone'
class ItemRepository {
async getById(id: string) {
return prisma.item.findUnique({
where: { id },
include: {
sprite: true
}
})
}
async getByIds(ids: string[]) {
return prisma.item.findMany({
where: {
id: {
in: ids
}
},
include: {
sprite: true
}
})
}
async getAll() {
return prisma.item.findMany({
include: {
sprite: true
}
})
}
}
export default new ItemRepository()

View File

@ -0,0 +1,41 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../../utilities/types'
import prisma from '../../../../utilities/prisma'
import characterRepository from '../../../../repositories/characterRepository'
export default class ItemCreateEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
public listen(): void {
this.socket.on('gm:item:create', this.handleEvent.bind(this))
}
private async handleEvent(data: undefined, callback: (response: boolean, item?: 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 newItem = await prisma.item.create({
data: {
name: 'New Item',
itemType: 'WEAPON',
stackable: false,
rarity: 'COMMON',
spriteId: null
}
})
callback(true, newItem)
} catch (error) {
console.error('Error creating item:', error)
callback(false)
}
}
}

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 { gameMasterLogger } from '../../../../utilities/logger'
interface IPayload {
id: string
}
export default class ItemDeleteEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
public listen(): void {
this.socket.on('gm:item:remove', this.handleEvent.bind(this))
}
private async handleEvent(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.item.delete({
where: { id: data.id }
})
callback(true)
} catch (error) {
gameMasterLogger.error(`Error deleting item ${data.id}: ${error instanceof Error ? error.message : String(error)}`)
callback(false)
}
}
}

View File

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

View File

@ -0,0 +1,55 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../../utilities/types'
import prisma from '../../../../utilities/prisma'
import characterRepository from '../../../../repositories/characterRepository'
import { ItemType, ItemRarity } from '@prisma/client'
import { gameMasterLogger } from '../../../../utilities/logger'
type Payload = {
id: string
name: string
description: string | null
itemType: ItemType
stackable: boolean
rarity: ItemRarity
spriteId: string | null
}
export default class ItemUpdateEvent {
constructor(
private readonly io: Server,
private readonly socket: TSocket
) {}
public listen(): void {
this.socket.on('gm:item: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 {
await prisma.item.update({
where: { id: data.id },
data: {
name: data.name,
description: data.description,
itemType: data.itemType,
stackable: data.stackable,
rarity: data.rarity,
spriteId: data.spriteId
}
})
return callback(true)
} catch (error) {
gameMasterLogger.error(`Error updating item: ${error instanceof Error ? error.message : String(error)}`)
return callback(false)
}
}
}