diff --git a/prisma/migrations/20240722235323_separate_prisma_schemes/migration.sql b/prisma/migrations/20240722235323_separate_prisma_schemes/migration.sql new file mode 100644 index 0000000..f568c37 --- /dev/null +++ b/prisma/migrations/20240722235323_separate_prisma_schemes/migration.sql @@ -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; diff --git a/prisma/migrations/20240723001610_made_field_optional/migration.sql b/prisma/migrations/20240723001610_made_field_optional/migration.sql new file mode 100644 index 0000000..39342f4 --- /dev/null +++ b/prisma/migrations/20240723001610_made_field_optional/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `Character` MODIFY `characterTypeId` INTEGER NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma deleted file mode 100644 index 642239d..0000000 --- a/prisma/schema.prisma +++ /dev/null @@ -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 -} diff --git a/prisma/schema/schema.prisma b/prisma/schema/schema.prisma new file mode 100644 index 0000000..7916015 --- /dev/null +++ b/prisma/schema/schema.prisma @@ -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 +} diff --git a/prisma/schema/sprite.prisma b/prisma/schema/sprite.prisma new file mode 100644 index 0000000..d68ed04 --- /dev/null +++ b/prisma/schema/sprite.prisma @@ -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) +} diff --git a/prisma/schema/user.prisma b/prisma/schema/user.prisma new file mode 100644 index 0000000..aef12f3 --- /dev/null +++ b/prisma/schema/user.prisma @@ -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 +} diff --git a/prisma/schema/zone.prisma b/prisma/schema/zone.prisma new file mode 100644 index 0000000..772c8d2 --- /dev/null +++ b/prisma/schema/zone.prisma @@ -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 +} diff --git a/src/events/character/CharacterConnect.ts b/src/events/character/Connect.ts similarity index 100% rename from src/events/character/CharacterConnect.ts rename to src/events/character/Connect.ts diff --git a/src/events/character/CharacterCreate.ts b/src/events/character/Create.ts similarity index 83% rename from src/events/character/CharacterCreate.ts rename to src/events/character/Create.ts index 3d83667..80ea3b5 100644 --- a/src/events/character/CharacterCreate.ts +++ b/src/events/character/Create.ts @@ -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).' }) } }) } diff --git a/src/events/character/CharacterDelete.ts b/src/events/character/Delete.ts similarity index 100% rename from src/events/character/CharacterDelete.ts rename to src/events/character/Delete.ts diff --git a/src/events/character/CharacterList.ts b/src/events/character/List.ts similarity index 100% rename from src/events/character/CharacterList.ts rename to src/events/character/List.ts diff --git a/src/events/character/CharacterMove.ts b/src/events/character/Move.ts similarity index 100% rename from src/events/character/CharacterMove.ts rename to src/events/character/Move.ts diff --git a/src/events/character/CharacterZoneLeave.ts b/src/events/character/ZoneLeave.ts similarity index 100% rename from src/events/character/CharacterZoneLeave.ts rename to src/events/character/ZoneLeave.ts diff --git a/src/events/character/CharacterZoneRequest.ts b/src/events/character/ZoneRequest.ts similarity index 100% rename from src/events/character/CharacterZoneRequest.ts rename to src/events/character/ZoneRequest.ts diff --git a/src/events/gm/sprite/Remove.ts b/src/events/gm/sprite/Remove.ts index 54f62e2..190d891 100644 --- a/src/events/gm/sprite/Remove.ts +++ b/src/events/gm/sprite/Remove.ts @@ -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 = { diff --git a/src/events/gm/zone/Update.ts b/src/events/gm/zone/Update.ts index 34974f9..9430ebd 100644 --- a/src/events/gm/zone/Update.ts +++ b/src/events/gm/zone/Update.ts @@ -42,7 +42,7 @@ export default function (socket: TSocket, io: Server) { return } - console.log(data); + console.log(data) await prisma.zone.update({ where: { diff --git a/src/repositories/CharacterRepository.ts b/src/repositories/CharacterRepository.ts index 6d93381..9234fa1 100644 --- a/src/repositories/CharacterRepository.ts +++ b/src/repositories/CharacterRepository.ts @@ -45,25 +45,6 @@ class CharacterRepository { } } - async create(userId: number, name: string, role: 'player'): Promise { - 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 { try { return await prisma.character.update({ @@ -81,19 +62,6 @@ class CharacterRepository { } } - async delete(id: number): Promise { - 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 { try { return await prisma.character.delete({