Improved folder and file structure, separated prisma schema into multiple ones, removed obsolete functions, worked on dynamic character sprite logics, general enhancements

This commit is contained in:
Dennis Postma 2024-07-23 02:17:46 +02:00
parent 7531385912
commit 4b81d7ff67
17 changed files with 249 additions and 189 deletions

View File

@ -0,0 +1,42 @@
/*
Warnings:
- Added the required column `characterTypeId` to the `Character` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE `Character` ADD COLUMN `characterTypeId` INTEGER NOT NULL;
-- AlterTable
ALTER TABLE `Sprite` ADD COLUMN `isAnimated` BOOLEAN NOT NULL DEFAULT false;
-- CreateTable
CREATE TABLE `CharacterSprite` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`characterTypeId` INTEGER NOT NULL,
`spriteId` VARCHAR(191) NOT NULL,
`action` ENUM('IDLE_LEFT', 'IDLE_DOWN', 'SIT_LEFT', 'SIT_DOWN', 'WALK_LEFT', 'WALK_DOWN', 'ATTACK_LEFT', 'ATTACK_DOWN') NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- CreateTable
CREATE TABLE `CharacterType` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`name` VARCHAR(191) NOT NULL,
`gender` ENUM('MALE', 'FEMALE') NOT NULL,
`race` ENUM('HUMAN', 'ELF', 'DWARF', 'ORC', 'GOBLIN') NOT NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- AddForeignKey
ALTER TABLE `CharacterSprite` ADD CONSTRAINT `CharacterSprite_characterTypeId_fkey` FOREIGN KEY (`characterTypeId`) REFERENCES `CharacterType`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `CharacterSprite` ADD CONSTRAINT `CharacterSprite_spriteId_fkey` FOREIGN KEY (`spriteId`) REFERENCES `Sprite`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE `Character` ADD CONSTRAINT `Character_characterTypeId_fkey` FOREIGN KEY (`characterTypeId`) REFERENCES `CharacterType`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE `Character` MODIFY `characterTypeId` INTEGER NULL;

View File

@ -1,153 +0,0 @@
// CHEAT SHEET
// 1. Create a new Prisma project
// npx prisma init
// 2. Create a new database schema
// npx prisma db push
// 3. Generate Prisma Client and type-safe models based on schema
// npx prisma generate
// 4. Create a new migration
// npx prisma migrate dev --name [migration-name]
// 5. Apply the migration
// npx prisma migrate deploy
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model Sprite {
id String @id @default(uuid())
name String
origin_x Decimal @default(0)
origin_y Decimal @default(0)
frameSpeed Int @default(0)
frameWidth Int @default(0)
frameHeight Int @default(0)
isLooping Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Tile {
id String @id @default(uuid())
name String
tags Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Object {
id String @id @default(uuid())
name String
tags Json?
origin_x Decimal @default(0)
origin_y Decimal @default(0)
isAnimated Boolean @default(false)
frameSpeed Int @default(0)
frameWidth Int @default(0)
frameHeight Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ZoneObject ZoneObject[]
}
model Item {
id String @id @default(uuid())
name String
description String?
stackable Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
characters CharacterItem[]
}
model User {
id Int @id @default(autoincrement())
username String @unique
password String
characters Character[]
}
model Character {
id Int @id @default(autoincrement())
userId Int
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
name String @unique
hitpoints Int @default(100)
mana Int @default(100)
level Int @default(1)
experience Int @default(0)
role String @default("player")
position_x Int @default(0)
position_y Int @default(0)
rotation Int @default(0)
zoneId Int @default(1)
zone Zone @relation(fields: [zoneId], references: [id], onDelete: Cascade)
chats Chat[]
items CharacterItem[]
}
model CharacterItem {
id Int @id @default(autoincrement())
characterId Int
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
itemId String
item Item @relation(fields: [itemId], references: [id], onDelete: Cascade)
quantity Int
}
model Zone {
id Int @id @default(autoincrement())
name String
width Int @default(10)
height Int @default(10)
tiles Json?
pvp Boolean @default(false)
zoneEventTiles ZoneEventTile[]
zoneObjects ZoneObject[]
characters Character[]
chats Chat[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ZoneObject {
id String @id @default(uuid())
zoneId Int
zone Zone @relation(fields: [zoneId], references: [id], onDelete: Cascade)
objectId String
object Object @relation(fields: [objectId], references: [id], onDelete: Cascade)
depth Int @default(0)
position_x Int @default(0)
position_y Int @default(0)
}
enum ZoneEventTileType {
BLOCK
WARP
NPC
ITEM
}
model ZoneEventTile {
id String @id @default(uuid())
zoneId Int
zone Zone @relation(fields: [zoneId], references: [id], onDelete: Cascade)
type ZoneEventTileType
position_x Int
position_y Int
}
model Chat {
id Int @id @default(autoincrement())
characterId Int
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
zoneId Int
zone Zone @relation(fields: [zoneId], references: [id], onDelete: Cascade)
message String
createdAt DateTime
}

View File

@ -0,0 +1,31 @@
// CHEAT SHEET
// 1. Create a new Prisma project
// npx prisma init
// 2. Create a new database schema
// npx prisma db push
// 3. Generate Prisma Client and type-safe models based on schema
// npx prisma generate
// 4. Create a new migration
// npx prisma migrate dev --name [migration-name]
// 5. Apply the migration
// npx prisma migrate deploy
generator client {
provider = "prisma-client-js"
previewFeatures = ["prismaSchemaFolder"]
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model Chat {
id Int @id @default(autoincrement())
characterId Int
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
zoneId Int
zone Zone @relation(fields: [zoneId], references: [id], onDelete: Cascade)
message String
createdAt DateTime
}

View File

@ -0,0 +1,34 @@
model Sprite {
id String @id @default(uuid())
name String
origin_x Decimal @default(0)
origin_y Decimal @default(0)
isAnimated Boolean @default(false)
frameSpeed Int @default(0)
frameWidth Int @default(0)
frameHeight Int @default(0)
isLooping Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
characterSprites CharacterSprite[]
}
enum SpriteAction {
IDLE_LEFT
IDLE_DOWN
SIT_LEFT
SIT_DOWN
WALK_LEFT
WALK_DOWN
ATTACK_LEFT
ATTACK_DOWN
}
model CharacterSprite {
id Int @id @default(autoincrement())
characterTypeId Int
spriteId String
action SpriteAction
characterType CharacterType @relation(fields: [characterTypeId], references: [id], onDelete: Cascade)
sprite Sprite @relation(fields: [spriteId], references: [id], onDelete: Cascade)
}

60
prisma/schema/user.prisma Normal file
View File

@ -0,0 +1,60 @@
model User {
id Int @id @default(autoincrement())
username String @unique
password String
characters Character[]
}
enum CharacterGender {
MALE
FEMALE
}
enum CharacterRace {
HUMAN
ELF
DWARF
ORC
GOBLIN
}
model CharacterType {
id Int @id @default(autoincrement())
name String
gender CharacterGender
race CharacterRace
characters Character[]
characterSprites CharacterSprite[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Character {
id Int @id @default(autoincrement())
userId Int
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
name String @unique
hitpoints Int @default(100)
mana Int @default(100)
level Int @default(1)
experience Int @default(0)
role String @default("player")
position_x Int @default(0)
position_y Int @default(0)
rotation Int @default(0)
zoneId Int @default(1)
zone Zone @relation(fields: [zoneId], references: [id], onDelete: Cascade)
characterTypeId Int?
characterType CharacterType? @relation(fields: [characterTypeId], references: [id], onDelete: Cascade)
chats Chat[]
items CharacterItem[]
}
model CharacterItem {
id Int @id @default(autoincrement())
characterId Int
character Character @relation(fields: [characterId], references: [id], onDelete: Cascade)
itemId String
item Item @relation(fields: [itemId], references: [id], onDelete: Cascade)
quantity Int
}

74
prisma/schema/zone.prisma Normal file
View File

@ -0,0 +1,74 @@
model Tile {
id String @id @default(uuid())
name String
tags Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Object {
id String @id @default(uuid())
name String
tags Json?
origin_x Decimal @default(0)
origin_y Decimal @default(0)
isAnimated Boolean @default(false)
frameSpeed Int @default(0)
frameWidth Int @default(0)
frameHeight Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ZoneObject ZoneObject[]
}
model Item {
id String @id @default(uuid())
name String
description String?
stackable Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
characters CharacterItem[]
}
model Zone {
id Int @id @default(autoincrement())
name String
width Int @default(10)
height Int @default(10)
tiles Json?
pvp Boolean @default(false)
zoneEventTiles ZoneEventTile[]
zoneObjects ZoneObject[]
characters Character[]
chats Chat[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ZoneObject {
id String @id @default(uuid())
zoneId Int
zone Zone @relation(fields: [zoneId], references: [id], onDelete: Cascade)
objectId String
object Object @relation(fields: [objectId], references: [id], onDelete: Cascade)
depth Int @default(0)
position_x Int @default(0)
position_y Int @default(0)
}
enum ZoneEventTileType {
BLOCK
WARP
NPC
ITEM
}
model ZoneEventTile {
id String @id @default(uuid())
zoneId Int
zone Zone @relation(fields: [zoneId], references: [id], onDelete: Cascade)
type ZoneEventTileType
position_x Int
position_y Int
}

View File

@ -29,7 +29,8 @@ export default function (socket: TSocket, io: Server) {
const character: Character = await prisma.character.create({
data: {
name: data.name,
userId: user_id
userId: user_id,
// characterTypeId: 1 // @TODO set to chosen character type
}
})
@ -38,7 +39,8 @@ export default function (socket: TSocket, io: Server) {
socket.emit('character:create:success')
socket.emit('character:list', characters)
} catch (error: any) {
return socket.emit('notification', { message: error.errors[0]?.message ?? 'Invalid data' })
console.log('character:create error', error)
return socket.emit('notification', { message: 'Could not create character. Please try again (later).' })
}
})
}

View File

@ -1,7 +1,7 @@
import { Server } from 'socket.io'
import { TSocket } from '../../../utilities/Types'
import path from 'path'
import fs from 'fs'
import path from 'path'
import prisma from '../../../utilities/Prisma'
type Payload = {

View File

@ -42,7 +42,7 @@ export default function (socket: TSocket, io: Server) {
return
}
console.log(data);
console.log(data)
await prisma.zone.update({
where: {

View File

@ -45,25 +45,6 @@ class CharacterRepository {
}
}
async create(userId: number, name: string, role: 'player'): Promise<Character | null> {
try {
return await prisma.character.create({
data: {
userId,
name,
role,
position_x: 0, // @TODO Set default registration values in the database
position_y: 0, // @TODO Set default registration values in the database
rotation: 0, // @TODO Set default registration values in the database
zoneId: 1 // @TODO Set default registration values in the database
}
})
} catch (error: any) {
// Handle error
throw new Error(`Failed to create character: ${error.message}`)
}
}
async updatePosition(id: number, position_x: number, position_y: number): Promise<Character | null> {
try {
return await prisma.character.update({
@ -81,19 +62,6 @@ class CharacterRepository {
}
}
async delete(id: number): Promise<Character | null> {
try {
return await prisma.character.delete({
where: {
id
}
})
} catch (error: any) {
// Handle error
throw new Error(`Failed to delete character: ${error.message}`)
}
}
async deleteByUserIdAndId(userId: number, characterId: number): Promise<Character | null> {
try {
return await prisma.character.delete({