Compare commits
1 Commits
issue/#307
...
feature/im
Author | SHA1 | Date | |
---|---|---|---|
5ac056bb8a |
@ -3,6 +3,6 @@
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 200,
|
||||
"printWidth": 300,
|
||||
"trailingComma": "none"
|
||||
}
|
@ -33,12 +33,8 @@ Run `npx mikro-orm migration:create --initial` to create a new initial migration
|
||||
|
||||
### Create migrations
|
||||
|
||||
Run `npx mikro-orm migration:create` to create a new migration. You do this when you want to add a new table or change an existing one.
|
||||
Run `npx mikro-orm migration:create` to create a new migration.
|
||||
|
||||
### Apply migrations
|
||||
|
||||
Run `npx mikro-orm migration:up` to apply all pending migrations.
|
||||
|
||||
### Import default data
|
||||
|
||||
After running the server, write `init` in the console to import default data.
|
||||
Run `npx mikro-orm migration:up` to apply all pending migrations.
|
@ -1,29 +1,13 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20250106170204 extends Migration {
|
||||
export class Migration20250101224501 extends Migration {
|
||||
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(`create table \`map\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`width\` int not null default 10, \`height\` int not null default 10, \`tiles\` json null, \`pvp\` tinyint(1) not null default false, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
|
||||
this.addSql(`create table \`map_effect\` (\`id\` varchar(255) not null, \`map_id\` varchar(255) not null, \`effect\` varchar(255) not null, \`strength\` int not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`map_effect\` add index \`map_effect_map_id_index\`(\`map_id\`);`);
|
||||
|
||||
this.addSql(`create table \`map_event_tile\` (\`id\` varchar(255) not null, \`map_id\` varchar(255) not null, \`type\` enum('BLOCK', 'TELEPORT', 'NPC', 'ITEM') not null, \`position_x\` int not null, \`position_y\` int not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`map_event_tile\` add index \`map_event_tile_map_id_index\`(\`map_id\`);`);
|
||||
|
||||
this.addSql(`create table \`map_event_tile_teleport\` (\`id\` varchar(255) not null, \`map_event_tile_id\` varchar(255) not null, \`to_map_id\` varchar(255) not null, \`to_rotation\` int not null, \`to_position_x\` int not null, \`to_position_y\` int not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`map_event_tile_teleport\` add unique \`map_event_tile_teleport_map_event_tile_id_unique\`(\`map_event_tile_id\`);`);
|
||||
this.addSql(`alter table \`map_event_tile_teleport\` add index \`map_event_tile_teleport_to_map_id_index\`(\`to_map_id\`);`);
|
||||
|
||||
this.addSql(`create table \`map_object\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`tags\` json null, \`origin_x\` numeric(10,2) not null default 0, \`origin_y\` numeric(10,2) not null default 0, \`is_animated\` tinyint(1) not null default false, \`frame_rate\` int not null default 0, \`frame_width\` int not null default 0, \`frame_height\` int not null default 0, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
|
||||
this.addSql(`create table \`placed_map_object\` (\`id\` varchar(255) not null, \`map_id\` varchar(255) not null, \`map_object_id\` varchar(255) not null, \`depth\` int not null default 0, \`is_rotated\` tinyint(1) not null default false, \`position_x\` int not null default 0, \`position_y\` int not null default 0, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`placed_map_object\` add index \`placed_map_object_map_id_index\`(\`map_id\`);`);
|
||||
this.addSql(`alter table \`placed_map_object\` add index \`placed_map_object_map_object_id_index\`(\`map_object_id\`);`);
|
||||
this.addSql(`create table \`map_object\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`tags\` json null, \`origin_x\` int not null default 0, \`origin_y\` int not null default 0, \`is_animated\` tinyint(1) not null default false, \`frame_rate\` int not null default 0, \`frame_width\` int not null default 0, \`frame_height\` int not null default 0, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
|
||||
this.addSql(`create table \`sprite\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
|
||||
this.addSql(`create table \`item\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`description\` varchar(255) not null default '', \`item_type\` enum('WEAPON', 'HELMET', 'CHEST', 'LEGS', 'BOOTS', 'GLOVES', 'RING', 'NECKLACE') not null, \`stackable\` tinyint(1) not null default false, \`rarity\` enum('COMMON', 'UNCOMMON', 'RARE', 'EPIC', 'LEGENDARY') not null default 'COMMON', \`sprite_id\` varchar(255) null, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`create table \`item\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`description\` varchar(255) null, \`item_type\` enum('WEAPON', 'HELMET', 'CHEST', 'LEGS', 'BOOTS', 'GLOVES', 'RING', 'NECKLACE') not null, \`stackable\` tinyint(1) not null default false, \`rarity\` enum('COMMON', 'UNCOMMON', 'RARE', 'EPIC', 'LEGENDARY') not null default 'COMMON', \`sprite_id\` varchar(255) null, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`item\` add index \`item_sprite_id_index\`(\`sprite_id\`);`);
|
||||
|
||||
this.addSql(`create table \`character_type\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`gender\` enum('MALE', 'FEMALE') not null, \`race\` enum('HUMAN', 'ELF', 'DWARF', 'ORC', 'GOBLIN') not null, \`is_selectable\` tinyint(1) not null default false, \`sprite_id\` varchar(255) null, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
@ -45,16 +29,20 @@ export class Migration20250106170204 extends Migration {
|
||||
this.addSql(`alter table \`password_reset_token\` add index \`password_reset_token_user_id_index\`(\`user_id\`);`);
|
||||
this.addSql(`alter table \`password_reset_token\` add unique \`password_reset_token_token_unique\`(\`token\`);`);
|
||||
|
||||
this.addSql(`create table \`character\` (\`id\` varchar(255) not null, \`user_id\` varchar(255) not null, \`name\` varchar(255) not null, \`online\` tinyint(1) not null default false, \`role\` varchar(255) not null default 'player', \`map_id\` varchar(255) not null, \`position_x\` int not null default 0, \`position_y\` int not null default 0, \`rotation\` int not null default 0, \`character_type_id\` varchar(255) null, \`character_hair_id\` varchar(255) null, \`alignment\` int not null default 50, \`hitpoints\` int not null default 100, \`mana\` int not null default 100, \`level\` int not null default 1, \`experience\` int not null default 0, \`strength\` int not null default 10, \`dexterity\` int not null default 10, \`intelligence\` int not null default 10, \`wisdom\` int not null default 10, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`create table \`world\` (\`date\` datetime not null, \`is_rain_enabled\` tinyint(1) not null default false, \`rain_percentage\` int not null default 0, \`is_fog_enabled\` tinyint(1) not null default false, \`fog_density\` int not null default 0, primary key (\`date\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
|
||||
this.addSql(`create table \`zone\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`width\` int not null default 10, \`height\` int not null default 10, \`tiles\` json null, \`pvp\` tinyint(1) not null default false, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
|
||||
this.addSql(`create table \`character\` (\`id\` varchar(255) not null, \`user_id\` varchar(255) not null, \`name\` varchar(255) not null, \`online\` tinyint(1) not null default false, \`role\` varchar(255) not null default 'player', \`zone_id\` varchar(255) not null, \`position_x\` int not null default 0, \`position_y\` int not null default 0, \`rotation\` int not null default 0, \`character_type_id\` varchar(255) null, \`character_hair_id\` varchar(255) null, \`alignment\` int not null default 50, \`hitpoints\` int not null default 100, \`mana\` int not null default 100, \`level\` int not null default 1, \`experience\` int not null default 0, \`strength\` int not null default 10, \`dexterity\` int not null default 10, \`intelligence\` int not null default 10, \`wisdom\` int not null default 10, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`character\` add index \`character_user_id_index\`(\`user_id\`);`);
|
||||
this.addSql(`alter table \`character\` add unique \`character_name_unique\`(\`name\`);`);
|
||||
this.addSql(`alter table \`character\` add index \`character_map_id_index\`(\`map_id\`);`);
|
||||
this.addSql(`alter table \`character\` add index \`character_zone_id_index\`(\`zone_id\`);`);
|
||||
this.addSql(`alter table \`character\` add index \`character_character_type_id_index\`(\`character_type_id\`);`);
|
||||
this.addSql(`alter table \`character\` add index \`character_character_hair_id_index\`(\`character_hair_id\`);`);
|
||||
|
||||
this.addSql(`create table \`chat\` (\`id\` varchar(255) not null, \`character_id\` varchar(255) not null, \`map_id\` varchar(255) not null, \`message\` varchar(255) not null, \`created_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`create table \`chat\` (\`id\` varchar(255) not null, \`character_id\` varchar(255) not null, \`zone_id\` varchar(255) not null, \`message\` varchar(255) not null, \`created_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`chat\` add index \`chat_character_id_index\`(\`character_id\`);`);
|
||||
this.addSql(`alter table \`chat\` add index \`chat_map_id_index\`(\`map_id\`);`);
|
||||
this.addSql(`alter table \`chat\` add index \`chat_zone_id_index\`(\`zone_id\`);`);
|
||||
|
||||
this.addSql(`create table \`character_item\` (\`id\` varchar(255) not null, \`character_id\` varchar(255) not null, \`item_id\` varchar(255) not null, \`quantity\` int not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`character_item\` add index \`character_item_character_id_index\`(\`character_id\`);`);
|
||||
@ -64,17 +52,19 @@ export class Migration20250106170204 extends Migration {
|
||||
this.addSql(`alter table \`character_equipment\` add index \`character_equipment_character_id_index\`(\`character_id\`);`);
|
||||
this.addSql(`alter table \`character_equipment\` add index \`character_equipment_character_item_id_index\`(\`character_item_id\`);`);
|
||||
|
||||
this.addSql(`create table \`world\` (\`date\` datetime not null, \`is_rain_enabled\` tinyint(1) not null default false, \`rain_percentage\` int not null default 0, \`is_fog_enabled\` tinyint(1) not null default false, \`fog_density\` int not null default 0, primary key (\`date\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`create table \`zone_effect\` (\`id\` varchar(255) not null, \`zone_id\` varchar(255) not null, \`effect\` varchar(255) not null, \`strength\` int not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`zone_effect\` add index \`zone_effect_zone_id_index\`(\`zone_id\`);`);
|
||||
|
||||
this.addSql(`alter table \`map_effect\` add constraint \`map_effect_map_id_foreign\` foreign key (\`map_id\`) references \`map\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`create table \`zone_event_tile\` (\`id\` varchar(255) not null, \`zone_id\` varchar(255) not null, \`type\` enum('BLOCK', 'TELEPORT', 'NPC', 'ITEM') not null, \`position_x\` int not null, \`position_y\` int not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`zone_event_tile\` add index \`zone_event_tile_zone_id_index\`(\`zone_id\`);`);
|
||||
|
||||
this.addSql(`alter table \`map_event_tile\` add constraint \`map_event_tile_map_id_foreign\` foreign key (\`map_id\`) references \`map\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`create table \`zone_event_tile_teleport\` (\`id\` varchar(255) not null, \`zone_event_tile_id\` varchar(255) not null, \`to_zone_id\` varchar(255) not null, \`to_rotation\` int not null, \`to_position_x\` int not null, \`to_position_y\` int not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`zone_event_tile_teleport\` add unique \`zone_event_tile_teleport_zone_event_tile_id_unique\`(\`zone_event_tile_id\`);`);
|
||||
this.addSql(`alter table \`zone_event_tile_teleport\` add index \`zone_event_tile_teleport_to_zone_id_index\`(\`to_zone_id\`);`);
|
||||
|
||||
this.addSql(`alter table \`map_event_tile_teleport\` add constraint \`map_event_tile_teleport_map_event_tile_id_foreign\` foreign key (\`map_event_tile_id\`) references \`map_event_tile\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`alter table \`map_event_tile_teleport\` add constraint \`map_event_tile_teleport_to_map_id_foreign\` foreign key (\`to_map_id\`) references \`map\` (\`id\`) on update cascade on delete cascade;`);
|
||||
|
||||
this.addSql(`alter table \`placed_map_object\` add constraint \`placed_map_object_map_id_foreign\` foreign key (\`map_id\`) references \`map\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`alter table \`placed_map_object\` add constraint \`placed_map_object_map_object_id_foreign\` foreign key (\`map_object_id\`) references \`map_object\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`create table \`zone_object\` (\`id\` varchar(255) not null, \`zone_id\` varchar(255) not null, \`map_object_id\` varchar(255) not null, \`depth\` int not null default 0, \`is_rotated\` tinyint(1) not null default false, \`position_x\` int not null default 0, \`position_y\` int not null default 0, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`zone_object\` add index \`zone_object_zone_id_index\`(\`zone_id\`);`);
|
||||
this.addSql(`alter table \`zone_object\` add index \`zone_object_map_object_id_index\`(\`map_object_id\`);`);
|
||||
|
||||
this.addSql(`alter table \`item\` add constraint \`item_sprite_id_foreign\` foreign key (\`sprite_id\`) references \`sprite\` (\`id\`) on update cascade on delete set null;`);
|
||||
|
||||
@ -87,18 +77,28 @@ export class Migration20250106170204 extends Migration {
|
||||
this.addSql(`alter table \`password_reset_token\` add constraint \`password_reset_token_user_id_foreign\` foreign key (\`user_id\`) references \`user\` (\`id\`) on update cascade on delete cascade;`);
|
||||
|
||||
this.addSql(`alter table \`character\` add constraint \`character_user_id_foreign\` foreign key (\`user_id\`) references \`user\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`alter table \`character\` add constraint \`character_map_id_foreign\` foreign key (\`map_id\`) references \`map\` (\`id\`) on update cascade;`);
|
||||
this.addSql(`alter table \`character\` add constraint \`character_zone_id_foreign\` foreign key (\`zone_id\`) references \`zone\` (\`id\`) on update cascade;`);
|
||||
this.addSql(`alter table \`character\` add constraint \`character_character_type_id_foreign\` foreign key (\`character_type_id\`) references \`character_type\` (\`id\`) on update cascade on delete set null;`);
|
||||
this.addSql(`alter table \`character\` add constraint \`character_character_hair_id_foreign\` foreign key (\`character_hair_id\`) references \`character_hair\` (\`id\`) on update cascade on delete set null;`);
|
||||
|
||||
this.addSql(`alter table \`chat\` add constraint \`chat_character_id_foreign\` foreign key (\`character_id\`) references \`character\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`alter table \`chat\` add constraint \`chat_map_id_foreign\` foreign key (\`map_id\`) references \`map\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`alter table \`chat\` add constraint \`chat_zone_id_foreign\` foreign key (\`zone_id\`) references \`zone\` (\`id\`) on update cascade on delete cascade;`);
|
||||
|
||||
this.addSql(`alter table \`character_item\` add constraint \`character_item_character_id_foreign\` foreign key (\`character_id\`) references \`character\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`alter table \`character_item\` add constraint \`character_item_item_id_foreign\` foreign key (\`item_id\`) references \`item\` (\`id\`) on update cascade on delete cascade;`);
|
||||
|
||||
this.addSql(`alter table \`character_equipment\` add constraint \`character_equipment_character_id_foreign\` foreign key (\`character_id\`) references \`character\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`alter table \`character_equipment\` add constraint \`character_equipment_character_item_id_foreign\` foreign key (\`character_item_id\`) references \`character_item\` (\`id\`) on update cascade on delete cascade;`);
|
||||
|
||||
this.addSql(`alter table \`zone_effect\` add constraint \`zone_effect_zone_id_foreign\` foreign key (\`zone_id\`) references \`zone\` (\`id\`) on update cascade on delete cascade;`);
|
||||
|
||||
this.addSql(`alter table \`zone_event_tile\` add constraint \`zone_event_tile_zone_id_foreign\` foreign key (\`zone_id\`) references \`zone\` (\`id\`) on update cascade on delete cascade;`);
|
||||
|
||||
this.addSql(`alter table \`zone_event_tile_teleport\` add constraint \`zone_event_tile_teleport_zone_event_tile_id_foreign\` foreign key (\`zone_event_tile_id\`) references \`zone_event_tile\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`alter table \`zone_event_tile_teleport\` add constraint \`zone_event_tile_teleport_to_zone_id_foreign\` foreign key (\`to_zone_id\`) references \`zone\` (\`id\`) on update cascade on delete cascade;`);
|
||||
|
||||
this.addSql(`alter table \`zone_object\` add constraint \`zone_object_zone_id_foreign\` foreign key (\`zone_id\`) references \`zone\` (\`id\`) on update cascade on delete cascade;`);
|
||||
this.addSql(`alter table \`zone_object\` add constraint \`zone_object_map_object_id_foreign\` foreign key (\`map_object_id\`) references \`map_object\` (\`id\`) on update cascade on delete cascade;`);
|
||||
}
|
||||
|
||||
}
|
@ -8,16 +8,15 @@ import serverConfig from './src/application/config'
|
||||
export default defineConfig({
|
||||
extensions: [Migrator],
|
||||
metadataProvider: TsMorphMetadataProvider,
|
||||
entities: ['./src/entities/*.js'],
|
||||
entitiesTs: ['./src/entities/*.ts'],
|
||||
entities: ['./src/entities/**/*.js'],
|
||||
entitiesTs: ['./src/entities/**/*.ts'],
|
||||
driver: MySqlDriver,
|
||||
host: serverConfig.DB_HOST,
|
||||
port: serverConfig.DB_PORT,
|
||||
user: serverConfig.DB_USER,
|
||||
password: serverConfig.DB_PASS,
|
||||
dbName: serverConfig.DB_NAME,
|
||||
debug: serverConfig.ENV !== 'production',
|
||||
// allowGlobalContext: true,
|
||||
// debug: serverConfig.ENV !== 'production',
|
||||
driverOptions: {
|
||||
allowPublicKeyRetrieval: true
|
||||
},
|
||||
|
184
package-lock.json
generated
184
package-lock.json
generated
@ -11,8 +11,10 @@
|
||||
"@mikro-orm/mysql": "^6.4.2",
|
||||
"@mikro-orm/reflection": "^6.4.2",
|
||||
"@prisma/client": "^6.1.0",
|
||||
"@types/blessed": "^0.1.25",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"blessed": "^0.1.81",
|
||||
"bullmq": "^5.13.2",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
@ -1661,6 +1663,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/blessed": {
|
||||
"version": "0.1.25",
|
||||
"resolved": "https://registry.npmjs.org/@types/blessed/-/blessed-0.1.25.tgz",
|
||||
"integrity": "sha512-kQsjBgtsbJLmG6CJA+Z6Nujj+tq1fcSE3UIowbDvzQI4wWmoTV7djUDhSo5lDjgwpIN0oRvks0SA5mMdKE5eFg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/body-parser": {
|
||||
"version": "1.19.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
|
||||
@ -1784,9 +1795,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.17.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.12.tgz",
|
||||
"integrity": "sha512-vo/wmBgMIiEA23A/knMfn/cf37VnuF52nZh5ZoW0GWt4e4sxNquibrMRJ7UQsA06+MBx9r/H1jsI9grYjQCQlw==",
|
||||
"version": "20.17.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.11.tgz",
|
||||
"integrity": "sha512-Ept5glCK35R8yeyIeYlRIZtX6SLRyqMhOFTgj5SOkMpLTdw3SEHI9fHx60xaUZ+V1aJxQJODE+7/j5ocZydYTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
@ -2390,6 +2401,18 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/blessed": {
|
||||
"version": "0.1.81",
|
||||
"resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz",
|
||||
"integrity": "sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"blessed": "bin/tput.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
@ -3085,9 +3108,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-abstract": {
|
||||
"version": "1.23.9",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz",
|
||||
"integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==",
|
||||
"version": "1.23.8",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.8.tgz",
|
||||
"integrity": "sha512-lfab8IzDn6EpI1ibZakcgS6WsfEBiB+43cuJo+wgylx1xKXf+Sp+YR3vFuQwC/u3sxYwV8Cxe3B0DpVUu/WiJQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -3102,11 +3125,10 @@
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"es-set-tostringtag": "^2.0.3",
|
||||
"es-to-primitive": "^1.3.0",
|
||||
"function.prototype.name": "^1.1.8",
|
||||
"get-intrinsic": "^1.2.7",
|
||||
"get-proto": "^1.0.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"get-symbol-description": "^1.1.0",
|
||||
"globalthis": "^1.0.4",
|
||||
"gopd": "^1.2.0",
|
||||
@ -3127,12 +3149,11 @@
|
||||
"object-inspect": "^1.13.3",
|
||||
"object-keys": "^1.1.1",
|
||||
"object.assign": "^4.1.7",
|
||||
"own-keys": "^1.0.1",
|
||||
"own-keys": "^1.0.0",
|
||||
"regexp.prototype.flags": "^1.5.3",
|
||||
"safe-array-concat": "^1.1.3",
|
||||
"safe-push-apply": "^1.0.0",
|
||||
"safe-regex-test": "^1.1.0",
|
||||
"set-proto": "^1.0.0",
|
||||
"string.prototype.trim": "^1.2.10",
|
||||
"string.prototype.trimend": "^1.0.9",
|
||||
"string.prototype.trimstart": "^1.0.8",
|
||||
@ -3181,16 +3202,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
|
||||
"integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
"hasown": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@ -3762,16 +3782,16 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
|
||||
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
|
||||
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
"glob-parent": "^5.1.2",
|
||||
"merge2": "^1.3.0",
|
||||
"micromatch": "^4.0.8"
|
||||
"micromatch": "^4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6.0"
|
||||
@ -3813,19 +3833,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.5.tgz",
|
||||
"integrity": "sha512-5JnBCWpFlMo0a3ciDy/JckMzzv1U9coZrIhedq+HXxxUfDTAiS0LA8OKVao4G9BxmCVck/jtA5r3KAtRWEyD8Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz",
|
||||
"integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/fastq": {
|
||||
@ -4063,21 +4073,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
|
||||
"integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz",
|
||||
"integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"dunder-proto": "^1.0.0",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.0",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
"math-intrinsics": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@ -4095,19 +4105,6 @@
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/get-symbol-description": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
|
||||
@ -4492,16 +4489,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-async-function": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.0.tgz",
|
||||
"integrity": "sha512-GExz9MtyhlZyXYLxzlJRj5WUCE661zhDa1Yna52CN57AJsymh+DvXXjyveSioqSRdxvUrdKdvqB1b5cVKsNpWQ==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
|
||||
"integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
"get-proto": "^1.0.1",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"safe-regex-test": "^1.1.0"
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@ -4655,16 +4649,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-generator-function": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz",
|
||||
"integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==",
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
|
||||
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.3",
|
||||
"get-proto": "^1.0.0",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"safe-regex-test": "^1.1.0"
|
||||
"has-tostringtag": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@ -5246,9 +5237,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mariadb/node_modules/@types/node": {
|
||||
"version": "22.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz",
|
||||
"integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==",
|
||||
"version": "22.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.3.tgz",
|
||||
"integrity": "sha512-DifAyw4BkrufCILvD3ucnuN8eydUfc/C1GlyrnI+LK6543w5/L3VeVgf05o3B4fqSXP1dKYLOZsKfutpxPzZrw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.20.0"
|
||||
@ -6012,19 +6003,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/process-warning": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz",
|
||||
"integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fastify"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fastify"
|
||||
}
|
||||
],
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.0.tgz",
|
||||
"integrity": "sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
@ -6183,19 +6164,19 @@
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/reflect.getprototypeof": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
|
||||
"integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz",
|
||||
"integrity": "sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-abstract": "^1.23.9",
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-abstract": "^1.23.6",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"get-intrinsic": "^1.2.7",
|
||||
"get-proto": "^1.0.1",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"gopd": "^1.2.0",
|
||||
"which-builtin-type": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
@ -6206,17 +6187,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/regexp.prototype.flags": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
|
||||
"integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz",
|
||||
"integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.8",
|
||||
"call-bind": "^1.0.7",
|
||||
"define-properties": "^1.2.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"set-function-name": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
@ -6522,21 +6501,6 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/set-proto": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
|
||||
"integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
|
@ -1,4 +1,6 @@
|
||||
{
|
||||
"useTsNode": true,
|
||||
"alwaysAllowTs": true,
|
||||
"scripts": {
|
||||
"start": "node dist/server.js",
|
||||
"dev": "nodemon --exec tsx src/server.ts",
|
||||
@ -14,8 +16,10 @@
|
||||
"@mikro-orm/mysql": "^6.4.2",
|
||||
"@mikro-orm/reflection": "^6.4.2",
|
||||
"@prisma/client": "^6.1.0",
|
||||
"@types/blessed": "^0.1.25",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"blessed": "^0.1.81",
|
||||
"bullmq": "^5.13.2",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
|
Binary file not shown.
@ -5,32 +5,23 @@ import Logger, { LoggerType } from '#application/logger'
|
||||
|
||||
export abstract class BaseEntity {
|
||||
protected readonly logger = Logger.type(LoggerType.ENTITY)
|
||||
protected entityManager?: EntityManager
|
||||
|
||||
private getEntityManager(): EntityManager {
|
||||
if (!this.entityManager) {
|
||||
this.entityManager = Database.getORM().em.fork()
|
||||
}
|
||||
return this.entityManager
|
||||
}
|
||||
|
||||
public setEntityManager(entityManager: EntityManager) {
|
||||
this.entityManager = entityManager
|
||||
return this
|
||||
return Database.getEntityManager()
|
||||
}
|
||||
|
||||
async save(): Promise<this> {
|
||||
return this.execute('persist', 'save entity')
|
||||
}
|
||||
|
||||
async delete(): Promise<this> {
|
||||
return this.execute('remove', 'remove entity')
|
||||
}
|
||||
|
||||
async update(): Promise<this> {
|
||||
return this.execute('merge', 'update entity')
|
||||
}
|
||||
|
||||
async delete(): Promise<this> {
|
||||
return this.execute('remove', 'remove entity')
|
||||
}
|
||||
|
||||
private async execute(method: 'persist' | 'merge' | 'remove', actionDescription: string): Promise<this> {
|
||||
try {
|
||||
const em = this.getEntityManager()
|
||||
|
@ -2,8 +2,6 @@ import { Server } from 'socket.io'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import { TSocket } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
|
||||
export abstract class BaseEvent {
|
||||
protected readonly logger = Logger.type(LoggerType.GAME)
|
||||
@ -13,16 +11,6 @@ export abstract class BaseEvent {
|
||||
readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
protected async getCharacter(): Promise<Character | null> {
|
||||
const characterRepository = new CharacterRepository()
|
||||
return characterRepository.getById(this.socket.characterId!)
|
||||
}
|
||||
|
||||
protected async isCharacterGM(): Promise<boolean> {
|
||||
const character = await this.getCharacter()
|
||||
return character?.getRole() === 'gm'
|
||||
}
|
||||
|
||||
protected emitError(message: string): void {
|
||||
this.socket.emit('notification', { title: 'Server message', message })
|
||||
this.logger.error('character:connect error', `Player ${this.socket.userId}: ${message}`)
|
||||
|
@ -6,12 +6,8 @@ import Logger, { LoggerType } from '#application/logger'
|
||||
|
||||
export abstract class BaseRepository {
|
||||
protected readonly logger = Logger.type(LoggerType.REPOSITORY)
|
||||
private entityManager?: EntityManager
|
||||
|
||||
getEntityManager(): EntityManager {
|
||||
if (!this.entityManager) {
|
||||
this.entityManager = Database.getORM().em.fork()
|
||||
}
|
||||
return this.entityManager
|
||||
protected get em(): EntityManager {
|
||||
return Database.getEntityManager()
|
||||
}
|
||||
}
|
||||
|
@ -1,57 +0,0 @@
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { pathToFileURL } from 'url'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import Storage from '#application/storage'
|
||||
import { Command } from '#application/types'
|
||||
|
||||
export class CommandRegistry {
|
||||
private readonly commands: Map<string, Command> = new Map()
|
||||
private readonly logger = Logger.type(LoggerType.COMMAND)
|
||||
|
||||
public getCommand(name: string): Command | undefined {
|
||||
return this.commands.get(name)
|
||||
}
|
||||
|
||||
public async loadCommands(): Promise<void> {
|
||||
const directory = Storage.getAppPath('commands')
|
||||
this.logger.info(`Loading commands from: ${directory}`)
|
||||
|
||||
try {
|
||||
const files = await fs.promises.readdir(directory, { withFileTypes: true })
|
||||
await Promise.all(files.filter((file) => this.isValidCommandFile(file)).map((file) => this.loadCommandFile(file)))
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to read commands directory: ${error instanceof Error ? error.message : String(error)}`)
|
||||
}
|
||||
}
|
||||
|
||||
private isValidCommandFile(file: fs.Dirent): boolean {
|
||||
return file.isFile() && (file.name.endsWith('.ts') || file.name.endsWith('.js'))
|
||||
}
|
||||
|
||||
private async loadCommandFile(file: fs.Dirent): Promise<void> {
|
||||
try {
|
||||
const filePath = Storage.getAppPath('commands', file.name)
|
||||
const commandName = path.basename(file.name, path.extname(file.name))
|
||||
|
||||
const module = await import(pathToFileURL(filePath).href)
|
||||
if (typeof module.default !== 'function') {
|
||||
this.logger.warn(`Unrecognized export in ${file.name}`)
|
||||
return
|
||||
}
|
||||
|
||||
this.registerCommand(commandName, module.default)
|
||||
} catch (error) {
|
||||
this.logger.error(`Error loading command ${file.name}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
}
|
||||
}
|
||||
|
||||
private registerCommand(name: string, CommandClass: Command): void {
|
||||
if (this.commands.has(name)) {
|
||||
this.logger.warn(`Command '${name}' is already registered. Overwriting...`)
|
||||
}
|
||||
this.commands.set(name, CommandClass)
|
||||
this.logger.info(`Registered command: ${name}`)
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
import * as readline from 'readline'
|
||||
|
||||
export class ConsolePrompt {
|
||||
private readonly rl: readline.Interface
|
||||
private isClosed: boolean = false
|
||||
|
||||
constructor(private readonly commandHandler: (command: string) => void) {
|
||||
this.rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
})
|
||||
|
||||
this.rl.on('close', () => {
|
||||
this.isClosed = true
|
||||
})
|
||||
}
|
||||
|
||||
public start(): void {
|
||||
if (this.isClosed) return
|
||||
this.promptCommand()
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.rl.close()
|
||||
}
|
||||
|
||||
private promptCommand(): void {
|
||||
this.rl.question('> ', (command: string) => {
|
||||
this.commandHandler(command)
|
||||
this.promptCommand()
|
||||
})
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
|
||||
export class LogReader {
|
||||
private logger = Logger.type(LoggerType.CONSOLE)
|
||||
private watchers: fs.FSWatcher[] = []
|
||||
private readonly logsDirectory: string
|
||||
|
||||
constructor(rootPath: string) {
|
||||
this.logsDirectory = path.join(rootPath, 'logs')
|
||||
}
|
||||
|
||||
public start(): void {
|
||||
this.logger.info('Starting log reader...')
|
||||
this.watchLogs()
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
this.watchers.forEach((watcher) => watcher.close())
|
||||
this.watchers = []
|
||||
}
|
||||
|
||||
private watchLogs(): void {
|
||||
// Watch directory for new files
|
||||
const directoryWatcher = fs.watch(this.logsDirectory, (_, filename) => {
|
||||
if (filename?.endsWith('.log')) {
|
||||
this.watchLogFile(filename)
|
||||
}
|
||||
})
|
||||
this.watchers.push(directoryWatcher)
|
||||
|
||||
// Watch existing files
|
||||
try {
|
||||
fs.readdirSync(this.logsDirectory)
|
||||
.filter((file) => file.endsWith('.log'))
|
||||
.forEach((file) => this.watchLogFile(file))
|
||||
} catch (error) {
|
||||
this.logger.error(`Error reading logs directory: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
private watchLogFile(filename: string): void {
|
||||
const filePath = path.join(this.logsDirectory, filename)
|
||||
let currentPosition = fs.existsSync(filePath) ? fs.statSync(filePath).size : 0
|
||||
|
||||
const watcher = fs.watch(filePath, () => {
|
||||
try {
|
||||
const stat = fs.statSync(filePath)
|
||||
const newPosition = stat.size
|
||||
|
||||
if (newPosition < currentPosition) {
|
||||
currentPosition = 0
|
||||
}
|
||||
|
||||
if (newPosition > currentPosition) {
|
||||
const stream = fs.createReadStream(filePath, {
|
||||
start: currentPosition,
|
||||
end: newPosition
|
||||
})
|
||||
|
||||
stream.on('data', (data) => {
|
||||
console.log(`[${filename}]`);
|
||||
console.log(data.toString()); //
|
||||
})
|
||||
|
||||
currentPosition = newPosition
|
||||
}
|
||||
} catch {
|
||||
watcher.close()
|
||||
}
|
||||
})
|
||||
|
||||
this.watchers.push(watcher)
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
import { EntityManager } from '@mikro-orm/core'
|
||||
import { MikroORM } from '@mikro-orm/mysql'
|
||||
|
||||
import Logger, { LoggerType } from './logger'
|
||||
@ -5,11 +6,13 @@ import config from '../../mikro-orm.config'
|
||||
|
||||
class Database {
|
||||
private static orm: MikroORM
|
||||
private static em: EntityManager
|
||||
private static logger = Logger.type(LoggerType.APP)
|
||||
|
||||
public static async initialize(): Promise<void> {
|
||||
try {
|
||||
this.orm = await MikroORM.init(config)
|
||||
Database.orm = await MikroORM.init(config)
|
||||
Database.em = Database.orm.em.fork()
|
||||
this.logger.info('Database connection initialized')
|
||||
} catch (error) {
|
||||
this.logger.error(`MikroORM connection failed: ${error}`)
|
||||
@ -18,7 +21,17 @@ class Database {
|
||||
}
|
||||
|
||||
public static getORM(): MikroORM {
|
||||
return this.orm
|
||||
if (!Database.orm) {
|
||||
throw new Error('Database not initialized. Call Database.initialize() first.')
|
||||
}
|
||||
return Database.orm
|
||||
}
|
||||
|
||||
public static getEntityManager(): EntityManager {
|
||||
if (!Database.em) {
|
||||
throw new Error('Database not initialized. Call Database.initialize() first.')
|
||||
}
|
||||
return Database.em
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ export enum CharacterEquipmentSlotType {
|
||||
RING = 'RING'
|
||||
}
|
||||
|
||||
export enum MapEventTileType {
|
||||
export enum ZoneEventTileType {
|
||||
BLOCK = 'BLOCK',
|
||||
TELEPORT = 'TELEPORT',
|
||||
NPC = 'NPC',
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { Server, Socket } from 'socket.io'
|
||||
|
||||
import { Character } from '#entities/character'
|
||||
import { MapEventTile } from '#entities/mapEventTile'
|
||||
import { MapEventTileTeleport } from '#entities/mapEventTileTeleport'
|
||||
import { ZoneEventTile } from '#entities/zoneEventTile'
|
||||
import { ZoneEventTileTeleport } from '#entities/zoneEventTileTeleport'
|
||||
|
||||
export type UUID = `${string}-${string}-${string}-${string}-${string}`
|
||||
|
||||
@ -26,8 +26,8 @@ export type ExtendedCharacter = Character & {
|
||||
resetMovement?: boolean
|
||||
}
|
||||
|
||||
export type MapEventTileWithTeleport = MapEventTile & {
|
||||
teleport: MapEventTileTeleport
|
||||
export type ZoneEventTileWithTeleport = ZoneEventTile & {
|
||||
teleport: ZoneEventTileTeleport
|
||||
}
|
||||
|
||||
export type AssetData = {
|
||||
|
@ -9,35 +9,31 @@ import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { CharacterHair } from '#entities/characterHair'
|
||||
import { CharacterType } from '#entities/characterType'
|
||||
import { Map } from '#entities/map'
|
||||
import { MapEffect } from '#entities/mapEffect'
|
||||
import { MapObject } from '#entities/mapObject'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
import { SpriteAction } from '#entities/spriteAction'
|
||||
import { Tile } from '#entities/tile'
|
||||
import { User } from '#entities/user'
|
||||
import { Zone } from '#entities/zone'
|
||||
import { ZoneEffect } from '#entities/zoneEffect'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
import CharacterTypeRepository from '#repositories/characterTypeRepository'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
import ZoneRepository from '#repositories/zoneRepository'
|
||||
|
||||
// @TODO : Replace this with seeding
|
||||
// https://mikro-orm.io/docs/seeding
|
||||
|
||||
export default class InitCommand extends BaseCommand {
|
||||
private readonly mapRepository = new MapRepository()
|
||||
private readonly characterTypeRepository = new CharacterTypeRepository()
|
||||
private readonly characterHairRepository = new CharacterHairRepository()
|
||||
|
||||
public async execute(): Promise<void> {
|
||||
// Assets
|
||||
await this.importTiles()
|
||||
await this.importMapObjects()
|
||||
await this.importObjects()
|
||||
await this.createCharacterType()
|
||||
await this.createCharacterHair()
|
||||
// await this.createCharacterEquipment()
|
||||
|
||||
// Map
|
||||
await this.createMap()
|
||||
// Zone
|
||||
await this.createZone()
|
||||
|
||||
// User
|
||||
await this.createUser()
|
||||
@ -55,19 +51,19 @@ export default class InitCommand extends BaseCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private async importMapObjects(): Promise<void> {
|
||||
for (const mapObject of fs.readdirSync(Storage.getPublicPath('map_objects'))) {
|
||||
private async importObjects(): Promise<void> {
|
||||
for (const object of fs.readdirSync(Storage.getPublicPath('objects'))) {
|
||||
const newMapObject = new MapObject()
|
||||
newMapObject
|
||||
.setId(mapObject.split('.')[0] as UUID)
|
||||
.setName('New map object')
|
||||
.setId(object.split('.')[0] as UUID)
|
||||
.setName('New object')
|
||||
.setFrameWidth(
|
||||
(await sharp(Storage.getPublicPath('map_objects', mapObject))
|
||||
(await sharp(Storage.getPublicPath('objects', object))
|
||||
.metadata()
|
||||
.then((metadata) => metadata.height)) ?? 0
|
||||
)
|
||||
.setFrameHeight(
|
||||
(await sharp(Storage.getPublicPath('map_objects', mapObject))
|
||||
(await sharp(Storage.getPublicPath('objects', object))
|
||||
.metadata()
|
||||
.then((metadata) => metadata.width)) ?? 0
|
||||
)
|
||||
@ -152,14 +148,7 @@ export default class InitCommand extends BaseCommand {
|
||||
.save()
|
||||
|
||||
const characterType = new CharacterType()
|
||||
await characterType
|
||||
.setId('75b70c78-17f0-44c0-a4fa-15043cb95be0')
|
||||
.setName('New character type')
|
||||
.setGender(CharacterGender.MALE)
|
||||
.setRace(CharacterRace.HUMAN)
|
||||
.setIsSelectable(true)
|
||||
.setSprite(characterSprite)
|
||||
.save()
|
||||
await characterType.setId('75b70c78-17f0-44c0-a4fa-15043cb95be0').setName('New character type').setGender(CharacterGender.MALE).setRace(CharacterRace.HUMAN).setIsSelectable(true).setSprite(characterSprite).save()
|
||||
}
|
||||
|
||||
private async createCharacterHair(): Promise<void> {
|
||||
@ -235,17 +224,17 @@ export default class InitCommand extends BaseCommand {
|
||||
await equipmentSprite.save()
|
||||
}
|
||||
|
||||
private async createMap(): Promise<void> {
|
||||
const map = new Map()
|
||||
await map
|
||||
.setName('New map')
|
||||
private async createZone(): Promise<void> {
|
||||
const zone = new Zone()
|
||||
await zone
|
||||
.setName('New zone')
|
||||
.setWidth(100)
|
||||
.setHeight(100)
|
||||
.setTiles(Array.from({ length: 100 }, () => Array.from({ length: 100 }, () => 'a2fd8d6f-5042-437a-9c1e-c66b91ecc35b')))
|
||||
.save()
|
||||
|
||||
const effect = new MapEffect()
|
||||
await effect.setEffect('light').setStrength(100).setMap(map).save()
|
||||
const effect = new ZoneEffect()
|
||||
await effect.setEffect('light').setStrength(100).setZone(zone).save()
|
||||
}
|
||||
|
||||
private async createUser(): Promise<void> {
|
||||
@ -258,9 +247,9 @@ export default class InitCommand extends BaseCommand {
|
||||
.setUser(user)
|
||||
.setName('root')
|
||||
.setRole('gm')
|
||||
.setMap((await this.mapRepository.getFirst())!)
|
||||
.setCharacterType((await this.characterTypeRepository.getFirst()) ?? undefined)
|
||||
.setCharacterHair((await this.characterHairRepository.getFirst()) ?? undefined)
|
||||
.setZone((await ZoneRepository.getFirst())!)
|
||||
.setCharacterType((await CharacterTypeRepository.getFirst()) ?? undefined)
|
||||
.setCharacterHair((await CharacterHairRepository.getFirst()) ?? undefined)
|
||||
.save()
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { BaseCommand } from '#application/base/baseCommand'
|
||||
import MapManager from '#managers/mapManager'
|
||||
|
||||
type CommandInput = string[]
|
||||
|
||||
export default class ListMapsCommand extends BaseCommand {
|
||||
public execute(input: CommandInput): void {
|
||||
console.log(MapManager.getLoadedMaps())
|
||||
}
|
||||
}
|
12
src/commands/listZones.ts
Normal file
12
src/commands/listZones.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { BaseCommand } from '#application/base/baseCommand'
|
||||
import ZoneManager from '#managers/zoneManager'
|
||||
|
||||
type CommandInput = string[]
|
||||
|
||||
export default class ListZonesCommand extends BaseCommand {
|
||||
public execute(input: CommandInput): void {
|
||||
console.log(ZoneManager.getLoadedZones())
|
||||
}
|
||||
}
|
@ -1,296 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { CharacterEquipment } from '#entities/characterEquipment'
|
||||
import { CharacterHair } from '#entities/characterHair'
|
||||
import { CharacterItem } from '#entities/characterItem'
|
||||
import { CharacterType } from '#entities/characterType'
|
||||
import { Chat } from '#entities/chat'
|
||||
import { Map } from '#entities/map'
|
||||
import { User } from '#entities/user'
|
||||
|
||||
|
||||
export class BaseCharacter extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
user!: User
|
||||
|
||||
@Property({ unique: true })
|
||||
name!: string
|
||||
|
||||
@Property()
|
||||
online = false
|
||||
|
||||
@Property()
|
||||
role = 'player'
|
||||
|
||||
@OneToMany(() => Chat, (chat) => chat.character)
|
||||
chats = new Collection<Chat>(this)
|
||||
|
||||
// Position - @TODO: Update to spawn point when current map is not found
|
||||
@ManyToOne()
|
||||
map!: Map
|
||||
|
||||
@Property()
|
||||
positionX = 0
|
||||
|
||||
@Property()
|
||||
positionY = 0
|
||||
|
||||
@Property()
|
||||
rotation = 0
|
||||
|
||||
// Customization
|
||||
@ManyToOne({ deleteRule: 'set null' })
|
||||
characterType?: CharacterType | null | undefined
|
||||
|
||||
@ManyToOne({ deleteRule: 'set null' })
|
||||
characterHair?: CharacterHair | null | undefined
|
||||
|
||||
// Inventory
|
||||
@OneToMany({ mappedBy: 'character' })
|
||||
items = new Collection<CharacterItem>(this)
|
||||
|
||||
@OneToMany({ mappedBy: 'character' })
|
||||
equipment = new Collection<CharacterEquipment>(this)
|
||||
|
||||
// Stats
|
||||
@Property()
|
||||
alignment = 50
|
||||
|
||||
@Property()
|
||||
hitpoints = 100
|
||||
|
||||
@Property()
|
||||
mana = 100
|
||||
|
||||
@Property()
|
||||
level = 1
|
||||
|
||||
@Property()
|
||||
experience = 0
|
||||
|
||||
@Property()
|
||||
strength = 10
|
||||
|
||||
@Property()
|
||||
dexterity = 10
|
||||
|
||||
@Property()
|
||||
intelligence = 10
|
||||
|
||||
@Property()
|
||||
wisdom = 10
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setUser(user: User) {
|
||||
this.user = user
|
||||
return this
|
||||
}
|
||||
|
||||
getUser() {
|
||||
return this.user
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setOnline(online: boolean) {
|
||||
this.online = online
|
||||
return this
|
||||
}
|
||||
|
||||
getOnline() {
|
||||
return this.online
|
||||
}
|
||||
|
||||
setRole(role: string) {
|
||||
this.role = role
|
||||
return this
|
||||
}
|
||||
|
||||
getRole() {
|
||||
return this.role
|
||||
}
|
||||
|
||||
setChats(chats: Collection<Chat>) {
|
||||
this.chats = chats
|
||||
return this
|
||||
}
|
||||
|
||||
getChats() {
|
||||
return this.chats
|
||||
}
|
||||
|
||||
setMap(map: Map) {
|
||||
this.map = map
|
||||
return this
|
||||
}
|
||||
|
||||
getMap() {
|
||||
return this.map
|
||||
}
|
||||
|
||||
setPositionX(positionX: number) {
|
||||
this.positionX = positionX
|
||||
return this
|
||||
}
|
||||
|
||||
getPositionX() {
|
||||
return this.positionX
|
||||
}
|
||||
|
||||
setPositionY(positionY: number) {
|
||||
this.positionY = positionY
|
||||
return this
|
||||
}
|
||||
|
||||
getPositionY() {
|
||||
return this.positionY
|
||||
}
|
||||
|
||||
setRotation(rotation: number) {
|
||||
this.rotation = rotation
|
||||
return this
|
||||
}
|
||||
|
||||
getRotation() {
|
||||
return this.rotation
|
||||
}
|
||||
|
||||
setCharacterType(characterType: CharacterType | null | undefined) {
|
||||
this.characterType = characterType
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacterType() {
|
||||
return this.characterType
|
||||
}
|
||||
|
||||
setCharacterHair(characterHair: CharacterHair | null | undefined) {
|
||||
this.characterHair = characterHair
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacterHair() {
|
||||
return this.characterHair
|
||||
}
|
||||
|
||||
setItems(items: Collection<CharacterItem>) {
|
||||
this.items = items
|
||||
return this
|
||||
}
|
||||
|
||||
getItems() {
|
||||
return this.items
|
||||
}
|
||||
|
||||
setEquipment(equipment: Collection<CharacterEquipment>) {
|
||||
this.equipment = equipment
|
||||
return this
|
||||
}
|
||||
|
||||
getEquipment() {
|
||||
return this.equipment
|
||||
}
|
||||
|
||||
setAlignment(alignment: number) {
|
||||
this.alignment = alignment
|
||||
return this
|
||||
}
|
||||
|
||||
getAlignment() {
|
||||
return this.alignment
|
||||
}
|
||||
|
||||
setHitpoints(hitpoints: number) {
|
||||
this.hitpoints = hitpoints
|
||||
return this
|
||||
}
|
||||
|
||||
getHitpoints() {
|
||||
return this.hitpoints
|
||||
}
|
||||
|
||||
setMana(mana: number) {
|
||||
this.mana = mana
|
||||
return this
|
||||
}
|
||||
|
||||
getMana() {
|
||||
return this.mana
|
||||
}
|
||||
|
||||
setLevel(level: number) {
|
||||
this.level = level
|
||||
return this
|
||||
}
|
||||
|
||||
getLevel() {
|
||||
return this.level
|
||||
}
|
||||
|
||||
setExperience(experience: number) {
|
||||
this.experience = experience
|
||||
return this
|
||||
}
|
||||
|
||||
getExperience() {
|
||||
return this.experience
|
||||
}
|
||||
|
||||
setStrength(strength: number) {
|
||||
this.strength = strength
|
||||
return this
|
||||
}
|
||||
|
||||
getStrength() {
|
||||
return this.strength
|
||||
}
|
||||
|
||||
setDexterity(dexterity: number) {
|
||||
this.dexterity = dexterity
|
||||
return this
|
||||
}
|
||||
|
||||
getDexterity() {
|
||||
return this.dexterity
|
||||
}
|
||||
|
||||
setIntelligence(intelligence: number) {
|
||||
this.intelligence = intelligence
|
||||
return this
|
||||
}
|
||||
|
||||
getIntelligence() {
|
||||
return this.intelligence
|
||||
}
|
||||
|
||||
setWisdom(wisdom: number) {
|
||||
this.wisdom = wisdom
|
||||
return this
|
||||
}
|
||||
|
||||
getWisdom() {
|
||||
return this.wisdom
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Enum, ManyToOne, PrimaryKey } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterEquipmentSlotType } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { CharacterItem } from '#entities/characterItem'
|
||||
|
||||
export class BaseCharacterEquipment extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Enum(() => CharacterEquipmentSlotType)
|
||||
slot!: CharacterEquipmentSlotType
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
character!: Character
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
characterItem!: CharacterItem
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setSlot(slot: CharacterEquipmentSlotType) {
|
||||
this.slot = slot
|
||||
return this
|
||||
}
|
||||
|
||||
getSlot() {
|
||||
return this.slot
|
||||
}
|
||||
|
||||
setCharacter(character: Character) {
|
||||
this.character = character
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacter() {
|
||||
return this.character
|
||||
}
|
||||
|
||||
setCharacterItem(characterItem: CharacterItem) {
|
||||
this.characterItem = characterItem
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacterItem() {
|
||||
return this.characterItem
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterGender } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
|
||||
export class BaseCharacterHair extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Property()
|
||||
gender: CharacterGender = CharacterGender.MALE
|
||||
|
||||
@Property()
|
||||
isSelectable = false
|
||||
|
||||
@ManyToOne()
|
||||
sprite?: Sprite
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setGender(gender: CharacterGender) {
|
||||
this.gender = gender
|
||||
return this
|
||||
}
|
||||
|
||||
getGender() {
|
||||
return this.gender
|
||||
}
|
||||
|
||||
setIsSelectable(isSelectable: boolean) {
|
||||
this.isSelectable = isSelectable
|
||||
return this
|
||||
}
|
||||
|
||||
getIsSelectable() {
|
||||
return this.isSelectable
|
||||
}
|
||||
|
||||
setSprite(sprite: Sprite) {
|
||||
this.sprite = sprite
|
||||
return this
|
||||
}
|
||||
|
||||
getSprite() {
|
||||
return this.sprite
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { CharacterEquipment } from '#entities/characterEquipment'
|
||||
import { Item } from '#entities/item'
|
||||
|
||||
|
||||
export class BaseCharacterItem extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
character!: Character
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
item!: Item
|
||||
|
||||
@Property()
|
||||
quantity!: number
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setCharacter(character: Character) {
|
||||
this.character = character
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacter() {
|
||||
return this.character
|
||||
}
|
||||
|
||||
setItem(item: Item) {
|
||||
this.item = item
|
||||
return this
|
||||
}
|
||||
|
||||
getItem() {
|
||||
return this.item
|
||||
}
|
||||
|
||||
setQuantity(quantity: number) {
|
||||
this.quantity = quantity
|
||||
return this
|
||||
}
|
||||
|
||||
getQuantity() {
|
||||
return this.quantity
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterGender, CharacterRace } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
|
||||
export class BaseCharacterType extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Enum(() => CharacterGender)
|
||||
gender!: CharacterGender
|
||||
|
||||
@Enum(() => CharacterRace)
|
||||
race!: CharacterRace
|
||||
|
||||
@Property()
|
||||
isSelectable = false
|
||||
|
||||
@ManyToOne()
|
||||
sprite?: Sprite
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setGender(gender: CharacterGender) {
|
||||
this.gender = gender
|
||||
return this
|
||||
}
|
||||
|
||||
getGender() {
|
||||
return this.gender
|
||||
}
|
||||
|
||||
setRace(race: CharacterRace) {
|
||||
this.race = race
|
||||
return this
|
||||
}
|
||||
|
||||
getRace() {
|
||||
return this.race
|
||||
}
|
||||
|
||||
setIsSelectable(isSelectable: boolean) {
|
||||
this.isSelectable = isSelectable
|
||||
return this
|
||||
}
|
||||
|
||||
getIsSelectable() {
|
||||
return this.isSelectable
|
||||
}
|
||||
|
||||
setSprite(sprite: Sprite) {
|
||||
this.sprite = sprite
|
||||
return this
|
||||
}
|
||||
|
||||
getSprite() {
|
||||
return this.sprite
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { Map } from '#entities/map'
|
||||
|
||||
|
||||
export class BaseChat extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
character!: Character
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
map!: Map
|
||||
|
||||
@Property()
|
||||
message!: string
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setCharacter(character: Character) {
|
||||
this.character = character
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacter() {
|
||||
return this.character
|
||||
}
|
||||
|
||||
setMap(map: Map) {
|
||||
this.map = map
|
||||
return this
|
||||
}
|
||||
|
||||
getMap() {
|
||||
return this.map
|
||||
}
|
||||
|
||||
setMessage(message: string) {
|
||||
this.message = message
|
||||
return this
|
||||
}
|
||||
|
||||
getMessage() {
|
||||
return this.message
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { ItemType, ItemRarity } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { CharacterItem } from '#entities/characterItem'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
|
||||
export class BaseItem extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Property()
|
||||
description: string = ''
|
||||
|
||||
@Enum(() => ItemType)
|
||||
itemType!: ItemType
|
||||
|
||||
@Property()
|
||||
stackable = false
|
||||
|
||||
@Enum(() => ItemRarity)
|
||||
rarity: ItemRarity = ItemRarity.COMMON
|
||||
|
||||
@ManyToOne(() => Sprite)
|
||||
sprite?: Sprite
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setDescription(description: string) {
|
||||
this.description = description
|
||||
return this
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return this.description
|
||||
}
|
||||
|
||||
setItemType(itemType: ItemType) {
|
||||
this.itemType = itemType
|
||||
return this
|
||||
}
|
||||
|
||||
getItemType() {
|
||||
return this.itemType
|
||||
}
|
||||
|
||||
setStackable(stackable: boolean) {
|
||||
this.stackable = stackable
|
||||
return this
|
||||
}
|
||||
|
||||
getStackable() {
|
||||
return this.stackable
|
||||
}
|
||||
|
||||
setRarity(rarity: ItemRarity) {
|
||||
this.rarity = rarity
|
||||
return this
|
||||
}
|
||||
|
||||
getRarity() {
|
||||
return this.rarity
|
||||
}
|
||||
|
||||
setSprite(sprite: Sprite) {
|
||||
this.sprite = sprite
|
||||
return this
|
||||
}
|
||||
|
||||
getSprite() {
|
||||
return this.sprite
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { MapEffect } from '#entities/mapEffect'
|
||||
import { MapEventTile } from '#entities/mapEventTile'
|
||||
import { PlacedMapObject } from '#entities/placedMapObject'
|
||||
|
||||
export class BaseMap extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Property()
|
||||
width = 10
|
||||
|
||||
@Property()
|
||||
height = 10
|
||||
|
||||
@Property({ type: 'json', nullable: true })
|
||||
tiles?: any
|
||||
|
||||
@Property()
|
||||
pvp = false
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
@OneToMany(() => MapEffect, (effect) => effect.map, { orphanRemoval: true })
|
||||
mapEffects = new Collection<MapEffect>(this)
|
||||
|
||||
@OneToMany(() => MapEventTile, (tile) => tile.map, { orphanRemoval: true })
|
||||
mapEventTiles = new Collection<MapEventTile>(this)
|
||||
|
||||
@OneToMany(() => PlacedMapObject, (placedMapObject) => placedMapObject.map, { orphanRemoval: true })
|
||||
placedMapObjects = new Collection<PlacedMapObject>(this)
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setWidth(width: number) {
|
||||
this.width = width
|
||||
return this
|
||||
}
|
||||
|
||||
getWidth() {
|
||||
return this.width
|
||||
}
|
||||
|
||||
setHeight(height: number) {
|
||||
this.height = height
|
||||
return this
|
||||
}
|
||||
|
||||
getHeight() {
|
||||
return this.height
|
||||
}
|
||||
|
||||
setTiles(tiles: any) {
|
||||
this.tiles = tiles
|
||||
return this
|
||||
}
|
||||
|
||||
getTiles() {
|
||||
return this.tiles
|
||||
}
|
||||
|
||||
setPvp(pvp: boolean) {
|
||||
this.pvp = pvp
|
||||
return this
|
||||
}
|
||||
|
||||
getPvp() {
|
||||
return this.pvp
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
|
||||
setMapEffects(mapEffects: Collection<MapEffect>) {
|
||||
this.mapEffects = mapEffects
|
||||
return this
|
||||
}
|
||||
|
||||
getMapEffects() {
|
||||
return this.mapEffects
|
||||
}
|
||||
|
||||
setMapEventTiles(mapEventTiles: Collection<MapEventTile>) {
|
||||
this.mapEventTiles = mapEventTiles
|
||||
return this
|
||||
}
|
||||
|
||||
getMapEventTiles() {
|
||||
return this.mapEventTiles
|
||||
}
|
||||
|
||||
setPlacedMapObjects(placedMapObjects: Collection<PlacedMapObject>) {
|
||||
this.placedMapObjects = placedMapObjects
|
||||
return this
|
||||
}
|
||||
|
||||
getPlacedMapObjects() {
|
||||
return this.placedMapObjects
|
||||
}
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
export class BaseMapObject extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Property({ type: 'json', nullable: true })
|
||||
tags?: any
|
||||
|
||||
@Property({ type: 'decimal', precision: 10, scale: 2 })
|
||||
originX = 0
|
||||
|
||||
@Property({ type: 'decimal', precision: 10, scale: 2 })
|
||||
originY = 0
|
||||
|
||||
@Property()
|
||||
isAnimated = false
|
||||
|
||||
@Property()
|
||||
frameRate = 0
|
||||
|
||||
@Property()
|
||||
frameWidth = 0
|
||||
|
||||
@Property()
|
||||
frameHeight = 0
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setTags(tags: any) {
|
||||
this.tags = tags
|
||||
return this
|
||||
}
|
||||
|
||||
getTags() {
|
||||
return this.tags
|
||||
}
|
||||
|
||||
setOriginX(originX: number) {
|
||||
this.originX = originX
|
||||
return this
|
||||
}
|
||||
|
||||
getOriginX() {
|
||||
return this.originX
|
||||
}
|
||||
|
||||
setOriginY(originY: number) {
|
||||
this.originY = originY
|
||||
return this
|
||||
}
|
||||
|
||||
getOriginY() {
|
||||
return this.originY
|
||||
}
|
||||
|
||||
setIsAnimated(isAnimated: boolean) {
|
||||
this.isAnimated = isAnimated
|
||||
return this
|
||||
}
|
||||
|
||||
getIsAnimated() {
|
||||
return this.isAnimated
|
||||
}
|
||||
|
||||
setFrameRate(frameRate: number) {
|
||||
this.frameRate = frameRate
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameRate() {
|
||||
return this.frameRate
|
||||
}
|
||||
|
||||
setFrameWidth(frameWidth: number) {
|
||||
this.frameWidth = frameWidth
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameWidth() {
|
||||
return this.frameWidth
|
||||
}
|
||||
|
||||
setFrameHeight(frameHeight: number) {
|
||||
this.frameHeight = frameHeight
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameHeight() {
|
||||
return this.frameHeight
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { User } from '#entities/user'
|
||||
|
||||
export class BasePasswordResetToken extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
user!: User
|
||||
|
||||
@Property({ unique: true })
|
||||
token!: string
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setUser(user: User) {
|
||||
this.user = user
|
||||
return this
|
||||
}
|
||||
|
||||
getUser() {
|
||||
return this.user
|
||||
}
|
||||
|
||||
setToken(token: string) {
|
||||
this.token = token
|
||||
return this
|
||||
}
|
||||
|
||||
getToken() {
|
||||
return this.token
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { SpriteAction } from '#entities/spriteAction'
|
||||
|
||||
export class BaseSprite extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@OneToMany(() => SpriteAction, (action) => action.sprite)
|
||||
spriteActions = new Collection<SpriteAction>(this)
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setSpriteActions(spriteActions: Collection<SpriteAction>) {
|
||||
this.spriteActions = spriteActions
|
||||
return this
|
||||
}
|
||||
|
||||
getSpriteActions() {
|
||||
return this.spriteActions
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
|
||||
export class BaseSpriteAction extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
sprite!: Sprite
|
||||
|
||||
@Property()
|
||||
action!: string
|
||||
|
||||
@Property({ type: 'json', nullable: true })
|
||||
sprites?: string[]
|
||||
|
||||
@Property()
|
||||
originX = 0
|
||||
|
||||
@Property()
|
||||
originY = 0
|
||||
|
||||
@Property()
|
||||
isAnimated = false
|
||||
|
||||
@Property()
|
||||
isLooping = false
|
||||
|
||||
@Property()
|
||||
frameWidth = 0
|
||||
|
||||
@Property()
|
||||
frameHeight = 0
|
||||
|
||||
@Property()
|
||||
frameRate = 0
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setSprite(sprite: Sprite) {
|
||||
this.sprite = sprite
|
||||
return this
|
||||
}
|
||||
|
||||
getSprite() {
|
||||
return this.sprite
|
||||
}
|
||||
|
||||
setAction(action: string) {
|
||||
this.action = action
|
||||
return this
|
||||
}
|
||||
|
||||
getAction() {
|
||||
return this.action
|
||||
}
|
||||
|
||||
setSprites(sprites: string[]) {
|
||||
this.sprites = sprites
|
||||
return this
|
||||
}
|
||||
|
||||
getSprites() {
|
||||
return this.sprites
|
||||
}
|
||||
|
||||
setOriginX(originX: number) {
|
||||
this.originX = originX
|
||||
return this
|
||||
}
|
||||
|
||||
getOriginX() {
|
||||
return this.originX
|
||||
}
|
||||
|
||||
setOriginY(originY: number) {
|
||||
this.originY = originY
|
||||
return this
|
||||
}
|
||||
|
||||
getOriginY() {
|
||||
return this.originY
|
||||
}
|
||||
|
||||
setIsAnimated(isAnimated: boolean) {
|
||||
this.isAnimated = isAnimated
|
||||
return this
|
||||
}
|
||||
|
||||
getIsAnimated() {
|
||||
return this.isAnimated
|
||||
}
|
||||
|
||||
setIsLooping(isLooping: boolean) {
|
||||
this.isLooping = isLooping
|
||||
return this
|
||||
}
|
||||
|
||||
getIsLooping() {
|
||||
return this.isLooping
|
||||
}
|
||||
|
||||
setFrameWidth(frameWidth: number) {
|
||||
this.frameWidth = frameWidth
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameWidth() {
|
||||
return this.frameWidth
|
||||
}
|
||||
|
||||
setFrameHeight(frameHeight: number) {
|
||||
this.frameHeight = frameHeight
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameHeight() {
|
||||
return this.frameHeight
|
||||
}
|
||||
|
||||
setFrameRate(frameRate: number) {
|
||||
this.frameRate = frameRate
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameRate() {
|
||||
return this.frameRate
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
export class BaseTile extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Property({ type: 'json', nullable: true })
|
||||
tags?: any
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setTags(tags: any) {
|
||||
this.tags = tags
|
||||
return this
|
||||
}
|
||||
|
||||
getTags() {
|
||||
return this.tags
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import bcrypt from 'bcryptjs'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { PasswordResetToken } from '#entities/passwordResetToken'
|
||||
|
||||
|
||||
export class BaseUser extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property({ unique: true })
|
||||
username!: string
|
||||
|
||||
@Property({ unique: true })
|
||||
email!: string
|
||||
|
||||
@Property()
|
||||
password!: string
|
||||
|
||||
@Property()
|
||||
online = false
|
||||
|
||||
@OneToMany(() => Character, (character) => character.user)
|
||||
characters = new Collection<Character>(this)
|
||||
|
||||
@OneToMany(() => PasswordResetToken, (token) => token.user)
|
||||
passwordResetTokens = new Collection<PasswordResetToken>(this)
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setUsername(username: string) {
|
||||
this.username = username
|
||||
return this
|
||||
}
|
||||
|
||||
getUsername() {
|
||||
return this.username
|
||||
}
|
||||
|
||||
setEmail(email: string) {
|
||||
this.email = email
|
||||
return this
|
||||
}
|
||||
|
||||
getEmail() {
|
||||
return this.email
|
||||
}
|
||||
|
||||
setPassword(password: string) {
|
||||
this.password = bcrypt.hashSync(password, 10)
|
||||
return this
|
||||
}
|
||||
|
||||
getPassword() {
|
||||
return this.password
|
||||
}
|
||||
|
||||
setOnline(online: boolean) {
|
||||
this.online = online
|
||||
return this
|
||||
}
|
||||
|
||||
getOnline() {
|
||||
return this.online
|
||||
}
|
||||
|
||||
setCharacters(characters: Collection<Character>) {
|
||||
this.characters = characters
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacters() {
|
||||
return this.characters
|
||||
}
|
||||
|
||||
setPasswordResetTokens(passwordResetTokens: Collection<PasswordResetToken>) {
|
||||
this.passwordResetTokens = passwordResetTokens
|
||||
return this
|
||||
}
|
||||
|
||||
getPasswordResetTokens() {
|
||||
return this.passwordResetTokens
|
||||
return this
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
import { Entity, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
|
||||
export class BaseWorld extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
date = new Date()
|
||||
|
||||
@Property()
|
||||
isRainEnabled = false
|
||||
|
||||
@Property()
|
||||
rainPercentage = 0
|
||||
|
||||
@Property()
|
||||
isFogEnabled = false
|
||||
|
||||
@Property()
|
||||
fogDensity = 0
|
||||
|
||||
setDate(date: Date) {
|
||||
this.date = date
|
||||
return this
|
||||
}
|
||||
|
||||
getDate() {
|
||||
return this.date
|
||||
}
|
||||
|
||||
setIsRainEnabled(isRainEnabled: boolean) {
|
||||
this.isRainEnabled = isRainEnabled
|
||||
return this
|
||||
}
|
||||
|
||||
getIsRainEnabled() {
|
||||
return this.isRainEnabled
|
||||
}
|
||||
|
||||
setRainPercentage(rainPercentage: number) {
|
||||
this.rainPercentage = rainPercentage
|
||||
return this
|
||||
}
|
||||
|
||||
getRainPercentage() {
|
||||
return this.rainPercentage
|
||||
}
|
||||
|
||||
setIsFogEnabled(isFogEnabled: boolean) {
|
||||
this.isFogEnabled = isFogEnabled
|
||||
return this
|
||||
}
|
||||
|
||||
getIsFogEnabled() {
|
||||
return this.isFogEnabled
|
||||
}
|
||||
|
||||
setFogDensity(fogDensity: number) {
|
||||
this.fogDensity = fogDensity
|
||||
return this
|
||||
}
|
||||
|
||||
getFogDensity() {
|
||||
return this.fogDensity
|
||||
}
|
||||
}
|
@ -1,6 +1,297 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseCharacter } from '#entities/base/character'
|
||||
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { CharacterEquipment } from './characterEquipment'
|
||||
import { CharacterHair } from './characterHair'
|
||||
import { CharacterItem } from './characterItem'
|
||||
import { CharacterType } from './characterType'
|
||||
import { Chat } from './chat'
|
||||
import { User } from './user'
|
||||
import { Zone } from './zone'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class Character extends BaseCharacter {}
|
||||
export class Character extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
user!: User
|
||||
|
||||
@Property({ unique: true })
|
||||
name!: string
|
||||
|
||||
@Property()
|
||||
online = false
|
||||
|
||||
@Property()
|
||||
role = 'player'
|
||||
|
||||
@OneToMany(() => Chat, (chat) => chat.character)
|
||||
chats = new Collection<Chat>(this)
|
||||
|
||||
// Position
|
||||
@ManyToOne()
|
||||
zone!: Zone // @TODO: Update to spawn point when current zone is not found
|
||||
|
||||
@Property()
|
||||
positionX = 0
|
||||
|
||||
@Property()
|
||||
positionY = 0
|
||||
|
||||
@Property()
|
||||
rotation = 0
|
||||
|
||||
// Customization
|
||||
@ManyToOne({ deleteRule: 'set null' })
|
||||
characterType?: CharacterType | null | undefined
|
||||
|
||||
@ManyToOne({ deleteRule: 'set null' })
|
||||
characterHair?: CharacterHair | null | undefined
|
||||
|
||||
// Inventory
|
||||
@OneToMany({ mappedBy: 'character' })
|
||||
items = new Collection<CharacterItem>(this)
|
||||
|
||||
@OneToMany({ mappedBy: 'character' })
|
||||
equipment = new Collection<CharacterEquipment>(this)
|
||||
|
||||
// Stats
|
||||
@Property()
|
||||
alignment = 50
|
||||
|
||||
@Property()
|
||||
hitpoints = 100
|
||||
|
||||
@Property()
|
||||
mana = 100
|
||||
|
||||
@Property()
|
||||
level = 1
|
||||
|
||||
@Property()
|
||||
experience = 0
|
||||
|
||||
@Property()
|
||||
strength = 10
|
||||
|
||||
@Property()
|
||||
dexterity = 10
|
||||
|
||||
@Property()
|
||||
intelligence = 10
|
||||
|
||||
@Property()
|
||||
wisdom = 10
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setUser(user: User) {
|
||||
this.user = user
|
||||
return this
|
||||
}
|
||||
|
||||
getUser() {
|
||||
return this.user
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setOnline(online: boolean) {
|
||||
this.online = online
|
||||
return this
|
||||
}
|
||||
|
||||
getOnline() {
|
||||
return this.online
|
||||
}
|
||||
|
||||
setRole(role: string) {
|
||||
this.role = role
|
||||
return this
|
||||
}
|
||||
|
||||
getRole() {
|
||||
return this.role
|
||||
}
|
||||
|
||||
setChats(chats: Collection<Chat>) {
|
||||
this.chats = chats
|
||||
return this
|
||||
}
|
||||
|
||||
getChats() {
|
||||
return this.chats
|
||||
}
|
||||
|
||||
setZone(zone: Zone) {
|
||||
this.zone = zone
|
||||
return this
|
||||
}
|
||||
|
||||
getZone() {
|
||||
return this.zone
|
||||
}
|
||||
|
||||
setPositionX(positionX: number) {
|
||||
this.positionX = positionX
|
||||
return this
|
||||
}
|
||||
|
||||
getPositionX() {
|
||||
return this.positionX
|
||||
}
|
||||
|
||||
setPositionY(positionY: number) {
|
||||
this.positionY = positionY
|
||||
return this
|
||||
}
|
||||
|
||||
getPositionY() {
|
||||
return this.positionY
|
||||
}
|
||||
|
||||
setRotation(rotation: number) {
|
||||
this.rotation = rotation
|
||||
return this
|
||||
}
|
||||
|
||||
getRotation() {
|
||||
return this.rotation
|
||||
}
|
||||
|
||||
setCharacterType(characterType: CharacterType | null | undefined) {
|
||||
this.characterType = characterType
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacterType() {
|
||||
return this.characterType
|
||||
}
|
||||
|
||||
setCharacterHair(characterHair: CharacterHair | null | undefined) {
|
||||
this.characterHair = characterHair
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacterHair() {
|
||||
return this.characterHair
|
||||
}
|
||||
|
||||
setItems(items: Collection<CharacterItem>) {
|
||||
this.items = items
|
||||
return this
|
||||
}
|
||||
|
||||
getItems() {
|
||||
return this.items
|
||||
}
|
||||
|
||||
setEquipment(equipment: Collection<CharacterEquipment>) {
|
||||
this.equipment = equipment
|
||||
return this
|
||||
}
|
||||
|
||||
getEquipment() {
|
||||
return this.equipment
|
||||
}
|
||||
|
||||
setAlignment(alignment: number) {
|
||||
this.alignment = alignment
|
||||
return this
|
||||
}
|
||||
|
||||
getAlignment() {
|
||||
return this.alignment
|
||||
}
|
||||
|
||||
setHitpoints(hitpoints: number) {
|
||||
this.hitpoints = hitpoints
|
||||
return this
|
||||
}
|
||||
|
||||
getHitpoints() {
|
||||
return this.hitpoints
|
||||
}
|
||||
|
||||
setMana(mana: number) {
|
||||
this.mana = mana
|
||||
return this
|
||||
}
|
||||
|
||||
getMana() {
|
||||
return this.mana
|
||||
}
|
||||
|
||||
setLevel(level: number) {
|
||||
this.level = level
|
||||
return this
|
||||
}
|
||||
|
||||
getLevel() {
|
||||
return this.level
|
||||
}
|
||||
|
||||
setExperience(experience: number) {
|
||||
this.experience = experience
|
||||
return this
|
||||
}
|
||||
|
||||
getExperience() {
|
||||
return this.experience
|
||||
}
|
||||
|
||||
setStrength(strength: number) {
|
||||
this.strength = strength
|
||||
return this
|
||||
}
|
||||
|
||||
getStrength() {
|
||||
return this.strength
|
||||
}
|
||||
|
||||
setDexterity(dexterity: number) {
|
||||
this.dexterity = dexterity
|
||||
return this
|
||||
}
|
||||
|
||||
getDexterity() {
|
||||
return this.dexterity
|
||||
}
|
||||
|
||||
setIntelligence(intelligence: number) {
|
||||
this.intelligence = intelligence
|
||||
return this
|
||||
}
|
||||
|
||||
getIntelligence() {
|
||||
return this.intelligence
|
||||
}
|
||||
|
||||
setWisdom(wisdom: number) {
|
||||
this.wisdom = wisdom
|
||||
return this
|
||||
}
|
||||
|
||||
getWisdom() {
|
||||
return this.wisdom
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,61 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseCharacterEquipment } from '#entities/base/characterEquipment'
|
||||
import { Entity, Enum, ManyToOne, PrimaryKey } from '@mikro-orm/core'
|
||||
|
||||
import { Character } from './character'
|
||||
import { CharacterItem } from './characterItem'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterEquipmentSlotType } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class CharacterEquipment extends BaseCharacterEquipment {}
|
||||
export class CharacterEquipment extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Enum(() => CharacterEquipmentSlotType)
|
||||
slot!: CharacterEquipmentSlotType
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
character!: Character
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
characterItem!: CharacterItem
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setSlot(slot: CharacterEquipmentSlotType) {
|
||||
this.slot = slot
|
||||
return this
|
||||
}
|
||||
|
||||
getSlot() {
|
||||
return this.slot
|
||||
}
|
||||
|
||||
setCharacter(character: Character) {
|
||||
this.character = character
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacter() {
|
||||
return this.character
|
||||
}
|
||||
|
||||
setCharacterItem(characterItem: CharacterItem) {
|
||||
this.characterItem = characterItem
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacterItem() {
|
||||
return this.characterItem
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,73 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseCharacterHair } from '#entities/base/characterHair'
|
||||
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { Character } from './character'
|
||||
import { Sprite } from './sprite'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterGender } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class CharacterHair extends BaseCharacterHair {}
|
||||
export class CharacterHair extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Property()
|
||||
gender: CharacterGender = CharacterGender.MALE
|
||||
|
||||
@Property()
|
||||
isSelectable = false
|
||||
|
||||
@ManyToOne({ nullable: true })
|
||||
sprite?: Sprite
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setGender(gender: CharacterGender) {
|
||||
this.gender = gender
|
||||
return this
|
||||
}
|
||||
|
||||
getGender() {
|
||||
return this.gender
|
||||
}
|
||||
|
||||
setIsSelectable(isSelectable: boolean) {
|
||||
this.isSelectable = isSelectable
|
||||
return this
|
||||
}
|
||||
|
||||
getIsSelectable() {
|
||||
return this.isSelectable
|
||||
}
|
||||
|
||||
setSprite(sprite: Sprite) {
|
||||
this.sprite = sprite
|
||||
return this
|
||||
}
|
||||
|
||||
getSprite() {
|
||||
return this.sprite
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,61 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseCharacterItem } from '#entities/base/characterItem'
|
||||
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { Character } from './character'
|
||||
import { CharacterEquipment } from './characterEquipment'
|
||||
import { Item } from './item'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class CharacterItem extends BaseCharacterItem {}
|
||||
export class CharacterItem extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
character!: Character
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
item!: Item
|
||||
|
||||
@Property()
|
||||
quantity!: number
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setCharacter(character: Character) {
|
||||
this.character = character
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacter() {
|
||||
return this.character
|
||||
}
|
||||
|
||||
setItem(item: Item) {
|
||||
this.item = item
|
||||
return this
|
||||
}
|
||||
|
||||
getItem() {
|
||||
return this.item
|
||||
}
|
||||
|
||||
setQuantity(quantity: number) {
|
||||
this.quantity = quantity
|
||||
return this
|
||||
}
|
||||
|
||||
getQuantity() {
|
||||
return this.quantity
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,121 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseCharacterType } from '#entities/base/characterType'
|
||||
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { Character } from './character'
|
||||
import { Sprite } from './sprite'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterGender, CharacterRace } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class CharacterType extends BaseCharacterType {}
|
||||
export class CharacterType extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Enum(() => CharacterGender)
|
||||
gender!: CharacterGender
|
||||
|
||||
@Enum(() => CharacterRace)
|
||||
race!: CharacterRace
|
||||
|
||||
@Property()
|
||||
isSelectable = false
|
||||
|
||||
@OneToMany(() => Character, (character) => character.characterType)
|
||||
characters = new Collection<Character>(this)
|
||||
|
||||
@ManyToOne(() => Sprite, { nullable: true })
|
||||
sprite?: Sprite
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setGender(gender: CharacterGender) {
|
||||
this.gender = gender
|
||||
return this
|
||||
}
|
||||
|
||||
getGender() {
|
||||
return this.gender
|
||||
}
|
||||
|
||||
setRace(race: CharacterRace) {
|
||||
this.race = race
|
||||
return this
|
||||
}
|
||||
|
||||
getRace() {
|
||||
return this.race
|
||||
}
|
||||
|
||||
setIsSelectable(isSelectable: boolean) {
|
||||
this.isSelectable = isSelectable
|
||||
return this
|
||||
}
|
||||
|
||||
getIsSelectable() {
|
||||
return this.isSelectable
|
||||
}
|
||||
|
||||
setSprite(sprite: Sprite) {
|
||||
this.sprite = sprite
|
||||
return this
|
||||
}
|
||||
|
||||
getSprite() {
|
||||
return this.sprite
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
|
||||
setCharacters(characters: Collection<Character>) {
|
||||
this.characters = characters
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacters() {
|
||||
return this.characters
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,72 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseChat } from '#entities/base/chat'
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { Character } from './character'
|
||||
import { Zone } from './zone'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class Chat extends BaseChat {}
|
||||
export class Chat extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
character!: Character
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
zone!: Zone
|
||||
|
||||
@Property()
|
||||
message!: string
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setCharacter(character: Character) {
|
||||
this.character = character
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacter() {
|
||||
return this.character
|
||||
}
|
||||
|
||||
setZone(zone: Zone) {
|
||||
this.zone = zone
|
||||
return this
|
||||
}
|
||||
|
||||
getZone() {
|
||||
return this.zone
|
||||
}
|
||||
|
||||
setMessage(message: string) {
|
||||
this.message = message
|
||||
return this
|
||||
}
|
||||
|
||||
getMessage() {
|
||||
return this.message
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,121 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseItem } from '#entities/base/item'
|
||||
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { CharacterItem } from './characterItem'
|
||||
import { Sprite } from './sprite'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { ItemType, ItemRarity } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class Item extends BaseItem {}
|
||||
export class Item extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Property({ nullable: true })
|
||||
description?: string
|
||||
|
||||
@Enum(() => ItemType)
|
||||
itemType!: ItemType
|
||||
|
||||
@Property()
|
||||
stackable = false
|
||||
|
||||
@Enum(() => ItemRarity)
|
||||
rarity: ItemRarity = ItemRarity.COMMON
|
||||
|
||||
@ManyToOne(() => Sprite, { nullable: true })
|
||||
sprite?: Sprite
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setDescription(description: string) {
|
||||
this.description = description
|
||||
return this
|
||||
}
|
||||
|
||||
getDescription() {
|
||||
return this.description
|
||||
}
|
||||
|
||||
setItemType(itemType: ItemType) {
|
||||
this.itemType = itemType
|
||||
return this
|
||||
}
|
||||
|
||||
getItemType() {
|
||||
return this.itemType
|
||||
}
|
||||
|
||||
setStackable(stackable: boolean) {
|
||||
this.stackable = stackable
|
||||
return this
|
||||
}
|
||||
|
||||
getStackable() {
|
||||
return this.stackable
|
||||
}
|
||||
|
||||
setRarity(rarity: ItemRarity) {
|
||||
this.rarity = rarity
|
||||
return this
|
||||
}
|
||||
|
||||
getRarity() {
|
||||
return this.rarity
|
||||
}
|
||||
|
||||
setSprite(sprite: Sprite) {
|
||||
this.sprite = sprite
|
||||
return this
|
||||
}
|
||||
|
||||
getSprite() {
|
||||
return this.sprite
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
|
||||
import { BaseMap } from '#entities/base/map'
|
||||
|
||||
@Entity()
|
||||
export class Map extends BaseMap {}
|
@ -1,6 +0,0 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
|
||||
import { BaseMapEffect } from '#entities/base/mapEffect'
|
||||
|
||||
@Entity()
|
||||
export class MapEffect extends BaseMapEffect {}
|
@ -1,6 +0,0 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
|
||||
import { BaseMapEventTile } from '#entities/base/mapEventTile'
|
||||
|
||||
@Entity()
|
||||
export class MapEventTile extends BaseMapEventTile {}
|
@ -1,6 +0,0 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
|
||||
import { BaseMapEventTileTeleport } from '#entities/base/mapEventTileTeleport'
|
||||
|
||||
@Entity()
|
||||
export class MapEventTileTeleport extends BaseMapEventTileTeleport {}
|
@ -1,6 +1,143 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseMapObject } from '#entities/base/mapObject'
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { ZoneObject } from './zoneObject'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class MapObject extends BaseMapObject {}
|
||||
export class MapObject extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Property({ type: 'json', nullable: true })
|
||||
tags?: any
|
||||
|
||||
@Property()
|
||||
originX = 0
|
||||
|
||||
@Property()
|
||||
originY = 0
|
||||
|
||||
@Property()
|
||||
isAnimated = false
|
||||
|
||||
@Property()
|
||||
frameRate = 0
|
||||
|
||||
@Property()
|
||||
frameWidth = 0
|
||||
|
||||
@Property()
|
||||
frameHeight = 0
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setTags(tags: any) {
|
||||
this.tags = tags
|
||||
return this
|
||||
}
|
||||
|
||||
getTags() {
|
||||
return this.tags
|
||||
}
|
||||
|
||||
setOriginX(originX: number) {
|
||||
this.originX = originX
|
||||
return this
|
||||
}
|
||||
|
||||
getOriginX() {
|
||||
return this.originX
|
||||
}
|
||||
|
||||
setOriginY(originY: number) {
|
||||
this.originY = originY
|
||||
return this
|
||||
}
|
||||
|
||||
getOriginY() {
|
||||
return this.originY
|
||||
}
|
||||
|
||||
setIsAnimated(isAnimated: boolean) {
|
||||
this.isAnimated = isAnimated
|
||||
return this
|
||||
}
|
||||
|
||||
getIsAnimated() {
|
||||
return this.isAnimated
|
||||
}
|
||||
|
||||
setFrameRate(frameRate: number) {
|
||||
this.frameRate = frameRate
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameRate() {
|
||||
return this.frameRate
|
||||
}
|
||||
|
||||
setFrameWidth(frameWidth: number) {
|
||||
this.frameWidth = frameWidth
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameWidth() {
|
||||
return this.frameWidth
|
||||
}
|
||||
|
||||
setFrameHeight(frameHeight: number) {
|
||||
this.frameHeight = frameHeight
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameHeight() {
|
||||
return this.frameHeight
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,59 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BasePasswordResetToken } from '#entities/base/passwordResetToken'
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { User } from './user'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class PasswordResetToken extends BasePasswordResetToken {}
|
||||
export class PasswordResetToken extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
user!: User
|
||||
|
||||
@Property({ unique: true })
|
||||
token!: string
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setUser(user: User) {
|
||||
this.user = user
|
||||
return this
|
||||
}
|
||||
|
||||
getUser() {
|
||||
return this.user
|
||||
}
|
||||
|
||||
setToken(token: string) {
|
||||
this.token = token
|
||||
return this
|
||||
}
|
||||
|
||||
getToken() {
|
||||
return this.token
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
|
||||
import { BasePlacedMapObject } from '#entities/base/placedMapObject'
|
||||
|
||||
@Entity()
|
||||
export class PlacedMapObject extends BasePlacedMapObject {}
|
@ -1,6 +1,71 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseSprite } from '#entities/base/sprite'
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { SpriteAction } from './spriteAction'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class Sprite extends BaseSprite {}
|
||||
export class Sprite extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@OneToMany(() => SpriteAction, (action) => action.sprite)
|
||||
spriteActions = new Collection<SpriteAction>(this)
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setSpriteActions(spriteActions: Collection<SpriteAction>) {
|
||||
this.spriteActions = spriteActions
|
||||
return this
|
||||
}
|
||||
|
||||
getSpriteActions() {
|
||||
return this.spriteActions
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,143 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseSpriteAction } from '#entities/base/spriteAction'
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { Sprite } from './sprite'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class SpriteAction extends BaseSpriteAction {}
|
||||
export class SpriteAction extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
sprite!: Sprite
|
||||
|
||||
@Property()
|
||||
action!: string
|
||||
|
||||
@Property({ type: 'json', nullable: true })
|
||||
sprites?: string[]
|
||||
|
||||
@Property()
|
||||
originX = 0
|
||||
|
||||
@Property()
|
||||
originY = 0
|
||||
|
||||
@Property()
|
||||
isAnimated = false
|
||||
|
||||
@Property()
|
||||
isLooping = false
|
||||
|
||||
@Property()
|
||||
frameWidth = 0
|
||||
|
||||
@Property()
|
||||
frameHeight = 0
|
||||
|
||||
@Property()
|
||||
frameRate = 0
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setSprite(sprite: Sprite) {
|
||||
this.sprite = sprite
|
||||
return this
|
||||
}
|
||||
|
||||
getSprite() {
|
||||
return this.sprite
|
||||
}
|
||||
|
||||
setAction(action: string) {
|
||||
this.action = action
|
||||
return this
|
||||
}
|
||||
|
||||
getAction() {
|
||||
return this.action
|
||||
}
|
||||
|
||||
setSprites(sprites: string[]) {
|
||||
this.sprites = sprites
|
||||
return this
|
||||
}
|
||||
|
||||
getSprites() {
|
||||
return this.sprites
|
||||
}
|
||||
|
||||
setOriginX(originX: number) {
|
||||
this.originX = originX
|
||||
return this
|
||||
}
|
||||
|
||||
getOriginX() {
|
||||
return this.originX
|
||||
}
|
||||
|
||||
setOriginY(originY: number) {
|
||||
this.originY = originY
|
||||
return this
|
||||
}
|
||||
|
||||
getOriginY() {
|
||||
return this.originY
|
||||
}
|
||||
|
||||
setIsAnimated(isAnimated: boolean) {
|
||||
this.isAnimated = isAnimated
|
||||
return this
|
||||
}
|
||||
|
||||
getIsAnimated() {
|
||||
return this.isAnimated
|
||||
}
|
||||
|
||||
setIsLooping(isLooping: boolean) {
|
||||
this.isLooping = isLooping
|
||||
return this
|
||||
}
|
||||
|
||||
getIsLooping() {
|
||||
return this.isLooping
|
||||
}
|
||||
|
||||
setFrameWidth(frameWidth: number) {
|
||||
this.frameWidth = frameWidth
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameWidth() {
|
||||
return this.frameWidth
|
||||
}
|
||||
|
||||
setFrameHeight(frameHeight: number) {
|
||||
this.frameHeight = frameHeight
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameHeight() {
|
||||
return this.frameHeight
|
||||
}
|
||||
|
||||
setFrameRate(frameRate: number) {
|
||||
this.frameRate = frameRate
|
||||
return this
|
||||
}
|
||||
|
||||
getFrameRate() {
|
||||
return this.frameRate
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,69 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseTile } from '#entities/base/tile'
|
||||
import { Entity, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class Tile extends BaseTile {}
|
||||
export class Tile extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Property({ type: 'json', nullable: true })
|
||||
tags?: any
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setTags(tags: any) {
|
||||
this.tags = tags
|
||||
return this
|
||||
}
|
||||
|
||||
getTags() {
|
||||
return this.tags
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,98 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { BaseUser } from '#entities/base/user'
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import bcrypt from 'bcryptjs'
|
||||
|
||||
import { Character } from './character'
|
||||
import { PasswordResetToken } from './passwordResetToken'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class User extends BaseUser {}
|
||||
export class User extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property({ unique: true })
|
||||
username!: string
|
||||
|
||||
@Property({ unique: true })
|
||||
email!: string
|
||||
|
||||
@Property()
|
||||
password!: string
|
||||
|
||||
@Property()
|
||||
online = false
|
||||
|
||||
@OneToMany(() => Character, (character) => character.user)
|
||||
characters = new Collection<Character>(this)
|
||||
|
||||
@OneToMany(() => PasswordResetToken, (token) => token.user)
|
||||
passwordResetTokens = new Collection<PasswordResetToken>(this)
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setUsername(username: string) {
|
||||
this.username = username
|
||||
return this
|
||||
}
|
||||
|
||||
getUsername() {
|
||||
return this.username
|
||||
}
|
||||
|
||||
setEmail(email: string) {
|
||||
this.email = email
|
||||
return this
|
||||
}
|
||||
|
||||
getEmail() {
|
||||
return this.email
|
||||
}
|
||||
|
||||
setPassword(password: string) {
|
||||
this.password = bcrypt.hashSync(password, 10)
|
||||
return this
|
||||
}
|
||||
|
||||
getPassword() {
|
||||
return this.password
|
||||
}
|
||||
|
||||
setOnline(online: boolean) {
|
||||
this.online = online
|
||||
return this
|
||||
}
|
||||
|
||||
getOnline() {
|
||||
return this.online
|
||||
}
|
||||
|
||||
setCharacters(characters: Collection<Character>) {
|
||||
this.characters = characters
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacters() {
|
||||
return this.characters
|
||||
}
|
||||
|
||||
setPasswordResetTokens(passwordResetTokens: Collection<PasswordResetToken>) {
|
||||
this.passwordResetTokens = passwordResetTokens
|
||||
return this
|
||||
}
|
||||
|
||||
getPasswordResetTokens() {
|
||||
return this.passwordResetTokens
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,66 @@
|
||||
import { Entity } from '@mikro-orm/core'
|
||||
import { Entity, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { BaseWorld } from '#entities/base/world'
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
|
||||
@Entity()
|
||||
export class World extends BaseWorld {}
|
||||
export class World extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
date = new Date()
|
||||
|
||||
@Property()
|
||||
isRainEnabled = false
|
||||
|
||||
@Property()
|
||||
rainPercentage = 0
|
||||
|
||||
@Property()
|
||||
isFogEnabled = false
|
||||
|
||||
@Property()
|
||||
fogDensity = 0
|
||||
|
||||
setDate(date: Date) {
|
||||
this.date = date
|
||||
return this
|
||||
}
|
||||
|
||||
getDate() {
|
||||
return this.date
|
||||
}
|
||||
|
||||
setIsRainEnabled(isRainEnabled: boolean) {
|
||||
this.isRainEnabled = isRainEnabled
|
||||
return this
|
||||
}
|
||||
|
||||
getIsRainEnabled() {
|
||||
return this.isRainEnabled
|
||||
}
|
||||
|
||||
setRainPercentage(rainPercentage: number) {
|
||||
this.rainPercentage = rainPercentage
|
||||
return this
|
||||
}
|
||||
|
||||
getRainPercentage() {
|
||||
return this.rainPercentage
|
||||
}
|
||||
|
||||
setIsFogEnabled(isFogEnabled: boolean) {
|
||||
this.isFogEnabled = isFogEnabled
|
||||
return this
|
||||
}
|
||||
|
||||
getIsFogEnabled() {
|
||||
return this.isFogEnabled
|
||||
}
|
||||
|
||||
setFogDensity(fogDensity: number) {
|
||||
this.fogDensity = fogDensity
|
||||
return this
|
||||
}
|
||||
|
||||
getFogDensity() {
|
||||
return this.fogDensity
|
||||
}
|
||||
}
|
||||
|
184
src/entities/zone.ts
Normal file
184
src/entities/zone.ts
Normal file
@ -0,0 +1,184 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { Character } from './character'
|
||||
import { Chat } from './chat'
|
||||
import { ZoneEffect } from './zoneEffect'
|
||||
import { ZoneEventTile } from './zoneEventTile'
|
||||
import { ZoneEventTileTeleport } from './zoneEventTileTeleport'
|
||||
import { ZoneObject } from './zoneObject'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
@Entity()
|
||||
export class Zone extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@Property()
|
||||
name!: string
|
||||
|
||||
@Property()
|
||||
width = 10
|
||||
|
||||
@Property()
|
||||
height = 10
|
||||
|
||||
@Property({ type: 'json', nullable: true })
|
||||
tiles?: any
|
||||
|
||||
@Property()
|
||||
pvp = false
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
@OneToMany(() => ZoneEffect, (effect) => effect.zone)
|
||||
zoneEffects = new Collection<ZoneEffect>(this)
|
||||
|
||||
@OneToMany(() => ZoneEventTile, (tile) => tile.zone)
|
||||
zoneEventTiles = new Collection<ZoneEventTile>(this)
|
||||
|
||||
@OneToMany(() => ZoneEventTileTeleport, (teleport) => teleport.toZone)
|
||||
zoneEventTileTeleports = new Collection<ZoneEventTileTeleport>(this)
|
||||
|
||||
@OneToMany(() => ZoneObject, (object) => object.zone)
|
||||
zoneObjects = new Collection<ZoneObject>(this)
|
||||
|
||||
@OneToMany(() => Character, (character) => character.zone)
|
||||
characters = new Collection<Character>(this)
|
||||
|
||||
@OneToMany(() => Chat, (chat) => chat.zone)
|
||||
chats = new Collection<Chat>(this)
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setName(name: string) {
|
||||
this.name = name
|
||||
return this
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name
|
||||
}
|
||||
|
||||
setWidth(width: number) {
|
||||
this.width = width
|
||||
return this
|
||||
}
|
||||
|
||||
getWidth() {
|
||||
return this.width
|
||||
}
|
||||
|
||||
setHeight(height: number) {
|
||||
this.height = height
|
||||
return this
|
||||
}
|
||||
|
||||
getHeight() {
|
||||
return this.height
|
||||
}
|
||||
|
||||
setTiles(tiles: any) {
|
||||
this.tiles = tiles
|
||||
return this
|
||||
}
|
||||
|
||||
getTiles() {
|
||||
return this.tiles
|
||||
}
|
||||
|
||||
setPvp(pvp: boolean) {
|
||||
this.pvp = pvp
|
||||
return this
|
||||
}
|
||||
|
||||
getPvp() {
|
||||
return this.pvp
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
|
||||
setZoneEffects(zoneEffects: Collection<ZoneEffect>) {
|
||||
this.zoneEffects = zoneEffects
|
||||
return this
|
||||
}
|
||||
|
||||
getZoneEffects() {
|
||||
return this.zoneEffects
|
||||
}
|
||||
|
||||
setZoneEventTiles(zoneEventTiles: Collection<ZoneEventTile>) {
|
||||
this.zoneEventTiles = zoneEventTiles
|
||||
return this
|
||||
}
|
||||
|
||||
getZoneEventTiles() {
|
||||
return this.zoneEventTiles
|
||||
}
|
||||
|
||||
setZoneEventTileTeleports(zoneEventTileTeleports: Collection<ZoneEventTileTeleport>) {
|
||||
this.zoneEventTileTeleports = zoneEventTileTeleports
|
||||
return this
|
||||
}
|
||||
|
||||
getZoneEventTileTeleports() {
|
||||
return this.zoneEventTileTeleports
|
||||
}
|
||||
|
||||
setZoneObjects(zoneObjects: Collection<ZoneObject>) {
|
||||
this.zoneObjects = zoneObjects
|
||||
return this
|
||||
}
|
||||
|
||||
getZoneObjects() {
|
||||
return this.zoneObjects
|
||||
}
|
||||
|
||||
setCharacters(characters: Collection<Character>) {
|
||||
this.characters = characters
|
||||
return this
|
||||
}
|
||||
|
||||
getCharacters() {
|
||||
return this.characters
|
||||
}
|
||||
|
||||
setChats(chats: Collection<Chat>) {
|
||||
this.chats = chats
|
||||
return this
|
||||
}
|
||||
|
||||
getChats() {
|
||||
return this.chats
|
||||
}
|
||||
}
|
@ -2,17 +2,18 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { Zone } from './zone'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
|
||||
export class BaseMapEffect extends BaseEntity {
|
||||
@Entity()
|
||||
export class ZoneEffect extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
map!: Map
|
||||
zone!: Zone
|
||||
|
||||
@Property()
|
||||
effect!: string
|
||||
@ -29,13 +30,13 @@ export class BaseMapEffect extends BaseEntity {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setMap(map: Map) {
|
||||
this.map = map
|
||||
setZone(zone: Zone) {
|
||||
this.zone = zone
|
||||
return this
|
||||
}
|
||||
|
||||
getMap() {
|
||||
return this.map
|
||||
getZone() {
|
||||
return this.zone
|
||||
}
|
||||
|
||||
setEffect(effect: string) {
|
@ -2,22 +2,23 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, Enum, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { Zone } from './zone'
|
||||
import { ZoneEventTileTeleport } from './zoneEventTileTeleport'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { MapEventTileType } from '#application/enums'
|
||||
import { ZoneEventTileType } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
import { MapEventTileTeleport } from '#entities/mapEventTileTeleport'
|
||||
|
||||
export class BaseMapEventTile extends BaseEntity {
|
||||
@Entity()
|
||||
export class ZoneEventTile extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
map!: Map
|
||||
zone!: Zone
|
||||
|
||||
@Enum(() => MapEventTileType)
|
||||
type!: MapEventTileType
|
||||
@Enum(() => ZoneEventTileType)
|
||||
type!: ZoneEventTileType
|
||||
|
||||
@Property()
|
||||
positionX!: number
|
||||
@ -25,8 +26,8 @@ export class BaseMapEventTile extends BaseEntity {
|
||||
@Property()
|
||||
positionY!: number
|
||||
|
||||
@OneToOne(() => MapEventTileTeleport, (teleport) => teleport.mapEventTile, { eager: true })
|
||||
teleport?: MapEventTileTeleport
|
||||
@OneToOne(() => ZoneEventTileTeleport, (teleport) => teleport.zoneEventTile)
|
||||
teleport?: ZoneEventTileTeleport
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
@ -37,16 +38,16 @@ export class BaseMapEventTile extends BaseEntity {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setMap(map: Map) {
|
||||
this.map = map
|
||||
setZone(zone: Zone) {
|
||||
this.zone = zone
|
||||
return this
|
||||
}
|
||||
|
||||
getMap() {
|
||||
return this.map
|
||||
getZone() {
|
||||
return this.zone
|
||||
}
|
||||
|
||||
setType(type: MapEventTileType) {
|
||||
setType(type: ZoneEventTileType) {
|
||||
this.type = type
|
||||
return this
|
||||
}
|
||||
@ -73,7 +74,7 @@ export class BaseMapEventTile extends BaseEntity {
|
||||
return this.positionY
|
||||
}
|
||||
|
||||
setTeleport(teleport: MapEventTileTeleport) {
|
||||
setTeleport(teleport: ZoneEventTileTeleport) {
|
||||
this.teleport = teleport
|
||||
return this
|
||||
}
|
@ -2,21 +2,22 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { Zone } from './zone'
|
||||
import { ZoneEventTile } from './zoneEventTile'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
import { MapEventTile } from '#entities/mapEventTile'
|
||||
|
||||
|
||||
export class BaseMapEventTileTeleport extends BaseEntity {
|
||||
@Entity()
|
||||
export class ZoneEventTileTeleport extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@OneToOne({ deleteRule: 'cascade' })
|
||||
mapEventTile!: MapEventTile
|
||||
zoneEventTile!: ZoneEventTile
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade', eager: true })
|
||||
toMap!: Map
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
toZone!: Zone
|
||||
|
||||
@Property()
|
||||
toRotation!: number
|
||||
@ -36,22 +37,22 @@ export class BaseMapEventTileTeleport extends BaseEntity {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setMapEventTile(mapEventTile: MapEventTile) {
|
||||
this.mapEventTile = mapEventTile
|
||||
setZoneEventTile(zoneEventTile: ZoneEventTile) {
|
||||
this.zoneEventTile = zoneEventTile
|
||||
return this
|
||||
}
|
||||
|
||||
getMapEventTile() {
|
||||
return this.mapEventTile
|
||||
getZoneEventTile() {
|
||||
return this.zoneEventTile
|
||||
}
|
||||
|
||||
setToMap(toMap: Map) {
|
||||
this.toMap = toMap
|
||||
setToZone(toZone: Zone) {
|
||||
this.toZone = toZone
|
||||
return this
|
||||
}
|
||||
|
||||
getToMap() {
|
||||
return this.toMap
|
||||
getToZone() {
|
||||
return this.toZone
|
||||
}
|
||||
|
||||
setToRotation(toRotation: number) {
|
@ -2,22 +2,22 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import { Zone } from './zone'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
import { MapObject } from '#entities/mapObject'
|
||||
|
||||
//@TODO : Rename mapObject
|
||||
|
||||
export class BasePlacedMapObject extends BaseEntity {
|
||||
@Entity()
|
||||
export class ZoneObject extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
map!: Map
|
||||
zone!: Zone
|
||||
|
||||
@ManyToOne({ deleteRule: 'cascade', eager: true })
|
||||
@ManyToOne({ deleteRule: 'cascade' })
|
||||
mapObject!: MapObject
|
||||
|
||||
@Property()
|
||||
@ -41,13 +41,13 @@ export class BasePlacedMapObject extends BaseEntity {
|
||||
return this.id
|
||||
}
|
||||
|
||||
setMap(map: Map) {
|
||||
this.map = map
|
||||
setZone(zone: Zone) {
|
||||
this.zone = zone
|
||||
return this
|
||||
}
|
||||
|
||||
getMap() {
|
||||
return this.map
|
||||
getZone() {
|
||||
return this.zone
|
||||
}
|
||||
|
||||
setMapObject(mapObject: MapObject) {
|
@ -1,6 +1,7 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import Database from '#application/database'
|
||||
import { CharacterHair } from '#entities/characterHair'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
import characterHairRepository from '#repositories/characterHairRepository'
|
||||
|
||||
interface IPayload {}
|
||||
|
||||
@ -10,14 +11,8 @@ export default class characterHairListEvent extends BaseEvent {
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise<void> {
|
||||
try {
|
||||
const characterHairRepository = new CharacterHairRepository()
|
||||
const items: CharacterHair[] = await characterHairRepository.getAllSelectable(['sprite'])
|
||||
|
||||
return callback(items)
|
||||
} catch (error) {
|
||||
this.logger.error('character:hair:list error', error)
|
||||
return callback([])
|
||||
}
|
||||
const items: CharacterHair[] = await characterHairRepository.getAllSelectable()
|
||||
await Database.getEntityManager().populate(items, ['sprite'])
|
||||
callback(items)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import MapManager from '#managers/mapManager'
|
||||
import ZoneManager from '#managers/zoneManager'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
import TeleportService from '#services/teleportService'
|
||||
@ -11,47 +11,57 @@ interface CharacterConnectPayload {
|
||||
}
|
||||
|
||||
export default class CharacterConnectEvent extends BaseEvent {
|
||||
private readonly characterHairRepository = new CharacterHairRepository()
|
||||
private readonly characterRepository = new CharacterRepository()
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('character:connect', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle character connect event
|
||||
* @TODO:
|
||||
* 1. Check if character is already connected
|
||||
* 2. Update character hair if provided
|
||||
* 3. Emit character connect event
|
||||
* 4. Let other clients know of new character
|
||||
* @param data
|
||||
* @param callback
|
||||
* @private
|
||||
*/
|
||||
private async handleEvent(data: CharacterConnectPayload, callback: (response: any) => void): Promise<void> {
|
||||
if (!this.socket.userId) {
|
||||
this.emitError('User not authenticated')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
if (await this.checkForActiveCharacters()) {
|
||||
this.emitError('You are already connected to another character')
|
||||
return
|
||||
}
|
||||
|
||||
const character = await this.characterRepository.getByUserAndId(this.socket.userId!, data.characterId)
|
||||
const character = await CharacterRepository.getByUserAndId(this.socket.userId, data.characterId)
|
||||
|
||||
if (!character) {
|
||||
this.emitError('Character not found or does not belong to this user')
|
||||
return
|
||||
}
|
||||
|
||||
// Populate character with characterType and characterHair
|
||||
await this.characterRepository.getEntityManager().populate(character, ['characterType', 'characterHair'])
|
||||
|
||||
// Set character id
|
||||
this.socket.characterId = character.id
|
||||
|
||||
// Set character hair
|
||||
if (data.characterHairId !== undefined && data.characterHairId !== null) {
|
||||
const characterHair = await this.characterHairRepository.getById(data.characterHairId)
|
||||
await character.setCharacterHair(characterHair).save()
|
||||
const characterHair = await CharacterHairRepository.getById(data.characterHairId)
|
||||
await character.setCharacterHair(characterHair).update()
|
||||
}
|
||||
|
||||
// Emit character connect event
|
||||
callback({ character })
|
||||
|
||||
// wait 300 ms, @TODO: Find a better way to do this, race condition
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
// wait 300 ms, @TODO: Find a better way to do this
|
||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||
|
||||
await TeleportService.teleportCharacter(character.id, {
|
||||
targetMapId: character.map.id,
|
||||
targetZoneId: character.zone.id,
|
||||
targetX: character.positionX,
|
||||
targetY: character.positionY,
|
||||
rotation: character.rotation,
|
||||
@ -64,7 +74,7 @@ export default class CharacterConnectEvent extends BaseEvent {
|
||||
}
|
||||
|
||||
private async checkForActiveCharacters(): Promise<boolean> {
|
||||
const characters = await this.characterRepository.getByUserId(this.socket.userId!)
|
||||
return characters?.some((char) => MapManager.getCharacterById(char.id)) ?? false
|
||||
const characters = await CharacterRepository.getByUserId(this.socket.userId!)
|
||||
return characters?.some((char) => ZoneManager.getCharacterById(char.id)) ?? false
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { ZCharacterCreate } from '#application/zodTypes'
|
||||
import { Character } from '#entities/character'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
import UserRepository from '#repositories/userRepository'
|
||||
import ZoneRepository from '#repositories/zoneRepository'
|
||||
|
||||
export default class CharacterCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
@ -17,34 +17,30 @@ export default class CharacterCreateEvent extends BaseEvent {
|
||||
try {
|
||||
data = ZCharacterCreate.parse(data)
|
||||
|
||||
const userRepository = new UserRepository()
|
||||
const characterRepository = new CharacterRepository()
|
||||
const mapRepository = new MapRepository()
|
||||
|
||||
const user = await userRepository.getById(this.socket.userId!)
|
||||
const user = await UserRepository.getById(this.socket.userId!)
|
||||
|
||||
if (!user) {
|
||||
return this.socket.emit('notification', { message: 'User not found' })
|
||||
}
|
||||
|
||||
// Check if character name already exists
|
||||
const characterExists = await characterRepository.getByName(data.name)
|
||||
const characterExists = await CharacterRepository.getByName(data.name)
|
||||
|
||||
if (characterExists) {
|
||||
return this.socket.emit('notification', { message: 'Character name already exists' })
|
||||
}
|
||||
|
||||
let characters: Character[] = await characterRepository.getByUserId(user.getId())
|
||||
let characters: Character[] = await CharacterRepository.getByUserId(user.getId())
|
||||
|
||||
if (characters.length >= 4) {
|
||||
return this.socket.emit('notification', { message: 'You can only have 4 characters' })
|
||||
}
|
||||
|
||||
// @TODO: Change to default location
|
||||
const map = await mapRepository.getFirst()
|
||||
const zone = await ZoneRepository.getFirst()
|
||||
|
||||
const newCharacter = new Character()
|
||||
await newCharacter.setName(data.name).setUser(user).setMap(map!).save()
|
||||
await newCharacter.setName(data.name).setUser(user).setZone(zone!).save()
|
||||
|
||||
if (!newCharacter) {
|
||||
return this.socket.emit('notification', { message: 'Failed to create character. Please try again (later).' })
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { Zone } from '#entities/zone'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
|
||||
type TypePayload = {
|
||||
@ -8,6 +9,7 @@ type TypePayload = {
|
||||
}
|
||||
|
||||
type TypeResponse = {
|
||||
zone: Zone
|
||||
characters: Character[]
|
||||
}
|
||||
|
||||
@ -18,9 +20,12 @@ export default class CharacterDeleteEvent extends BaseEvent {
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: TypeResponse) => void): Promise<any> {
|
||||
try {
|
||||
const characterRepository = new CharacterRepository()
|
||||
await (await characterRepository.getByUserAndId(this.socket.userId!, data.characterId))?.delete()
|
||||
const characters: Character[] = await characterRepository.getByUserId(this.socket.userId!)
|
||||
const character = await CharacterRepository.getByUserAndId(this.socket.userId!, data.characterId)
|
||||
if (character) {
|
||||
await character.delete()
|
||||
}
|
||||
|
||||
const characters: Character[] = await CharacterRepository.getByUserId(this.socket.userId!)
|
||||
|
||||
this.socket.emit('character:list', characters)
|
||||
} catch (error: any) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import Database from '#application/database'
|
||||
import { Character } from '#entities/character'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
|
||||
@ -9,11 +10,8 @@ export default class CharacterListEvent extends BaseEvent {
|
||||
|
||||
private async handleEvent(data: any): Promise<void> {
|
||||
try {
|
||||
const characterRepository = new CharacterRepository()
|
||||
let characters: Character[] = await characterRepository.getByUserId(this.socket.userId!)
|
||||
|
||||
// Populate characters with characterType and characterHair
|
||||
await characterRepository.getEntityManager().populate(characters, ['characterType', 'characterHair'])
|
||||
const characters: Character[] = await CharacterRepository.getByUserId(this.socket.userId!)
|
||||
await Database.getEntityManager().populate(characters, ['characterType', 'characterHair'])
|
||||
|
||||
this.socket.emit('character:list', characters)
|
||||
} catch (error: any) {
|
||||
|
@ -13,11 +13,22 @@ export default class AlertCommandEvent extends BaseEvent {
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
// Check if command is alert
|
||||
if (!ChatService.isCommand(data.message, 'alert')) return
|
||||
if (!ChatService.isCommand(data.message, 'alert')) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if character exists
|
||||
if (!(await this.isCharacterGM())) return
|
||||
const character = await CharacterRepository.getByUserAndId(this.socket.userId!, this.socket.characterId!)
|
||||
if (!character) {
|
||||
this.logger.error('chat:alert_command error', 'Character not found')
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
// Check if the user is the GM
|
||||
if (character.role !== 'gm') {
|
||||
this.logger.info(`User ${character.id} tried to set time but is not a game master.`)
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const args = ChatService.getArgs('alert', data.message)
|
||||
|
||||
|
@ -14,11 +14,22 @@ export default class SetTimeCommand extends BaseEvent {
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
// Check if command is time
|
||||
if (!ChatService.isCommand(data.message, 'time')) return
|
||||
if (!ChatService.isCommand(data.message, 'time')) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if character exists and is GM
|
||||
if (!(await this.isCharacterGM())) return
|
||||
// Check if character exists
|
||||
const character = await CharacterRepository.getByUserAndId(this.socket.userId!, this.socket.characterId!)
|
||||
if (!character) {
|
||||
this.logger.error('chat:alert_command error', 'Character not found')
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the user is the GM
|
||||
if (character.role !== 'gm') {
|
||||
this.logger.info(`User ${character.id} tried to set time but is not a game master.`)
|
||||
return
|
||||
}
|
||||
|
||||
// Get arguments
|
||||
const args = ChatService.getArgs('time', data.message)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import MapManager from '#managers/mapManager'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
import ZoneManager from '#managers/zoneManager'
|
||||
import ZoneRepository from '#repositories/zoneRepository'
|
||||
import ChatService from '#services/chatService'
|
||||
import TeleportService from '#services/teleportService'
|
||||
|
||||
@ -16,30 +16,36 @@ export default class TeleportCommandEvent extends BaseEvent {
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void) {
|
||||
try {
|
||||
// Check if command is teleport
|
||||
const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!)
|
||||
if (!zoneCharacter) {
|
||||
this.logger.error('chat:message error', 'Character not found')
|
||||
return
|
||||
}
|
||||
|
||||
const character = zoneCharacter.character
|
||||
|
||||
if (character.role !== 'gm') {
|
||||
this.logger.info(`User ${character.id} tried to set time but is not a game master.`)
|
||||
return
|
||||
}
|
||||
|
||||
if (!ChatService.isCommand(data.message, 'teleport')) return
|
||||
|
||||
// Check if character exists and is GM
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const character = await this.getCharacter()
|
||||
if (!character) return
|
||||
|
||||
const args = ChatService.getArgs('teleport', data.message)
|
||||
|
||||
if (!args || args.length === 0 || args.length > 3) {
|
||||
this.socket.emit('notification', {
|
||||
title: 'Server message',
|
||||
message: 'Usage: /teleport <mapId> [x] [y]'
|
||||
message: 'Usage: /teleport <zoneId> [x] [y]'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const mapId = args[0] as UUID
|
||||
const zoneId = args[0] as UUID
|
||||
const targetX = args[1] ? parseInt(args[1], 10) : 0
|
||||
const targetY = args[2] ? parseInt(args[2], 10) : 0
|
||||
|
||||
if (!mapId || isNaN(targetX) || isNaN(targetY)) {
|
||||
if (!zoneId || isNaN(targetX) || isNaN(targetY)) {
|
||||
this.socket.emit('notification', {
|
||||
title: 'Server message',
|
||||
message: 'Invalid parameters. X and Y coordinates must be numbers.'
|
||||
@ -47,17 +53,16 @@ export default class TeleportCommandEvent extends BaseEvent {
|
||||
return
|
||||
}
|
||||
|
||||
const mapRepository = new MapRepository()
|
||||
const map = await mapRepository.getById(mapId)
|
||||
if (!map) {
|
||||
const zone = await ZoneRepository.getById(zoneId)
|
||||
if (!zone) {
|
||||
this.socket.emit('notification', {
|
||||
title: 'Server message',
|
||||
message: 'Map not found'
|
||||
message: 'Zone not found'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (character.map.id === map.id && targetX === character.positionX && targetY === character.positionY) {
|
||||
if (character.zone.id === zone.id && targetX === character.positionX && targetY === character.positionY) {
|
||||
this.socket.emit('notification', {
|
||||
title: 'Server message',
|
||||
message: 'You are already at that location'
|
||||
@ -66,7 +71,7 @@ export default class TeleportCommandEvent extends BaseEvent {
|
||||
}
|
||||
|
||||
const success = await TeleportService.teleportCharacter(character.id, {
|
||||
targetMapId: map.id,
|
||||
targetZoneId: zone.id,
|
||||
targetX,
|
||||
targetY,
|
||||
rotation: character.rotation
|
||||
@ -81,9 +86,9 @@ export default class TeleportCommandEvent extends BaseEvent {
|
||||
|
||||
this.socket.emit('notification', {
|
||||
title: 'Server message',
|
||||
message: `Teleported to ${map.name} (${targetX}, ${targetY})`
|
||||
message: `Teleported to ${zone.name} (${targetX}, ${targetY})`
|
||||
})
|
||||
this.logger.info('teleport', `Character ${character.id} teleported to map ${map.id} at position (${targetX}, ${targetY})`)
|
||||
this.logger.info('teleport', `Character ${character.id} teleported to zone ${zone.id} at position (${targetX}, ${targetY})`)
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Error in teleport command: ${error.message}`)
|
||||
this.socket.emit('notification', {
|
||||
|
@ -14,11 +14,22 @@ export default class ToggleFogCommand extends BaseEvent {
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
// Check if command is fog
|
||||
if (!ChatService.isCommand(data.message, 'fog')) return
|
||||
if (!ChatService.isCommand(data.message, 'fog')) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if character exists and is GM
|
||||
if (!(await this.isCharacterGM())) return
|
||||
// Check if character exists
|
||||
const character = await CharacterRepository.getByUserAndId(this.socket.userId!, this.socket.characterId!)
|
||||
if (!character) {
|
||||
this.logger.error('chat:alert_command error', 'Character not found')
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the user is the GM
|
||||
if (character.role !== 'gm') {
|
||||
this.logger.info(`User ${character.id} tried to set time but is not a game master.`)
|
||||
return
|
||||
}
|
||||
|
||||
await WeatherManager.toggleFog()
|
||||
} catch (error: any) {
|
||||
|
@ -14,11 +14,22 @@ export default class ToggleRainCommand extends BaseEvent {
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
// Check if command is rain
|
||||
if (!ChatService.isCommand(data.message, 'rain')) return
|
||||
if (!ChatService.isCommand(data.message, 'rain')) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check if character exists and is GM
|
||||
if (!(await this.isCharacterGM())) return
|
||||
// Check if character exists
|
||||
const character = await CharacterRepository.getByUserAndId(this.socket.userId!, this.socket.characterId!)
|
||||
if (!character) {
|
||||
this.logger.error('chat:alert_command error', 'Character not found')
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the user is the GM
|
||||
if (character.role !== 'gm') {
|
||||
this.logger.info(`User ${character.id} tried to set time but is not a game master.`)
|
||||
return
|
||||
}
|
||||
|
||||
await WeatherManager.toggleRain()
|
||||
} catch (error: any) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import MapManager from '#managers/mapManager'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
import ZoneManager from '#managers/zoneManager'
|
||||
import ZoneRepository from '#repositories/zoneRepository'
|
||||
import ChatService from '#services/chatService'
|
||||
|
||||
type TypePayload = {
|
||||
@ -18,22 +18,21 @@ export default class ChatMessageEvent extends BaseEvent {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const mapCharacter = MapManager.getCharacterById(this.socket.characterId!)
|
||||
if (!mapCharacter) {
|
||||
const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!)
|
||||
if (!zoneCharacter) {
|
||||
this.logger.error('chat:message error', 'Character not found')
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const character = mapCharacter.character
|
||||
const character = zoneCharacter.character
|
||||
|
||||
const mapRepository = new MapRepository()
|
||||
const map = await mapRepository.getById(character.map.id)
|
||||
if (!map) {
|
||||
this.logger.error('chat:message error', 'Map not found')
|
||||
const zone = await ZoneRepository.getById(character.zone.id)
|
||||
if (!zone) {
|
||||
this.logger.error('chat:message error', 'Zone not found')
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
if (await ChatService.sendMapMessage(character.getId(), map.getId(), data.message)) {
|
||||
if (await ChatService.sendZoneMessage(character.getId(), zone.getId(), data.message)) {
|
||||
return callback(true)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import MapManager from '#managers/mapManager'
|
||||
import ZoneManager from '#managers/zoneManager'
|
||||
|
||||
export default class DisconnectEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
@ -15,13 +15,13 @@ export default class DisconnectEvent extends BaseEvent {
|
||||
|
||||
this.io.emit('user:disconnect', this.socket.userId)
|
||||
|
||||
const mapCharacter = MapManager.getCharacterById(this.socket.characterId!)
|
||||
if (!mapCharacter) {
|
||||
const zoneCharacter = ZoneManager.getCharacterById(this.socket.characterId!)
|
||||
if (!zoneCharacter) {
|
||||
this.logger.info('User disconnected but had no character set')
|
||||
return
|
||||
}
|
||||
|
||||
await mapCharacter.disconnect(this.socket, this.io)
|
||||
await zoneCharacter.disconnect(this.socket, this.io)
|
||||
this.logger.info('User disconnected along with their character')
|
||||
} catch (error: any) {
|
||||
this.logger.error('disconnect error: ' + error.message)
|
||||
|
@ -1,22 +1,28 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterHair } from '#entities/characterHair'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
export default class CharacterHairCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterHair:create', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: undefined, callback: (response: boolean) => void): Promise<void> {
|
||||
private async handleEvent(data: undefined, callback: (response: boolean, characterType?: any) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
const character = await characterRepository.getById(this.socket.characterId!)
|
||||
if (!character) return callback(false)
|
||||
|
||||
if (character.role !== 'gm') {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const newCharacterHair = new CharacterHair()
|
||||
await newCharacterHair.setName('New hair').save()
|
||||
|
||||
return callback(true)
|
||||
callback(true, newCharacterHair)
|
||||
} catch (error) {
|
||||
console.error('Error creating character hair:', error)
|
||||
return callback(false)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
interface IPayload {
|
||||
id: UUID
|
||||
id: number
|
||||
}
|
||||
|
||||
export default class characterHairDeleteEvent extends BaseEvent {
|
||||
@ -12,13 +12,20 @@ export default class characterHairDeleteEvent extends BaseEvent {
|
||||
}
|
||||
|
||||
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 {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const characterHair = await CharacterHairRepository.getById(data.id)
|
||||
await (await CharacterHairRepository.getById(data.id))?.delete()
|
||||
if (characterHair) {
|
||||
await characterHair.delete()
|
||||
}
|
||||
|
||||
return callback(true)
|
||||
callback(true)
|
||||
} catch (error) {
|
||||
this.logger.error(`Error deleting character type ${data.id}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
callback(false)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterHair } from '#entities/characterHair'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
import characterHairRepository from '#repositories/characterHairRepository'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
interface IPayload {}
|
||||
|
||||
@ -10,17 +11,19 @@ export default class characterHairListEvent extends BaseEvent {
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const characterHairRepository = new CharacterHairRepository()
|
||||
const items = await characterHairRepository.getAll()
|
||||
await characterHairRepository.getEntityManager().populate(items, ['sprite'])
|
||||
|
||||
return callback(items)
|
||||
} catch (error) {
|
||||
this.logger.error('gm:characterHair:list error', error)
|
||||
const character = await characterRepository.getById(this.socket.characterId as number)
|
||||
if (!character) {
|
||||
this.logger.error('gm:characterHair:list error', 'Character not found')
|
||||
return callback([])
|
||||
}
|
||||
|
||||
if (character.role !== 'gm') {
|
||||
this.logger.info(`User ${character.id} tried to list character hair but is not a game master.`)
|
||||
return callback([])
|
||||
}
|
||||
|
||||
// get all objects
|
||||
const items = await characterHairRepository.getAll()
|
||||
callback(items)
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterGender } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
|
||||
type Payload = {
|
||||
id: UUID
|
||||
id: number
|
||||
name: string
|
||||
gender: CharacterGender
|
||||
isSelectable: boolean
|
||||
@ -18,18 +19,21 @@ export default class CharacterHairUpdateEvent extends BaseEvent {
|
||||
}
|
||||
|
||||
private async handleEvent(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 {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
const sprite = await SpriteRepository.getById(data.spriteId)
|
||||
const characterHair = await CharacterHairRepository.getById(data.id)
|
||||
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const sprite = await spriteRepository.getById(data.spriteId)
|
||||
if (!sprite) return callback(false)
|
||||
if (characterHair) {
|
||||
await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite!).update()
|
||||
}
|
||||
|
||||
const characterHairRepository = new CharacterHairRepository()
|
||||
const characterHair = await characterHairRepository.getById(data.id)
|
||||
if (!characterHair) return callback(false)
|
||||
|
||||
await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite).save()
|
||||
return callback(true)
|
||||
} catch (error) {
|
||||
this.logger.error(`Error updating character hair: ${error instanceof Error ? error.message : String(error)}`)
|
||||
|
@ -1,22 +1,41 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterType } from '#entities/characterType'
|
||||
import { CharacterGender, CharacterRace } from '@prisma/client'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import prisma from '#application/prisma'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
export default class CharacterTypeCreateEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
export default class CharacterTypeCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterType:create', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: undefined, callback: (response: boolean, characterType?: any) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
const character = await characterRepository.getById(this.socket.characterId as number)
|
||||
if (!character) return callback(false)
|
||||
|
||||
const newCharacterType = new CharacterType()
|
||||
await newCharacterType.setName('New character type').save()
|
||||
if (character.role !== 'gm') {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
return callback(true, newCharacterType)
|
||||
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)
|
||||
return callback(false)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,41 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
import CharacterTypeRepository from '#repositories/characterTypeRepository'
|
||||
|
||||
interface IPayload {
|
||||
id: UUID
|
||||
id: number
|
||||
}
|
||||
|
||||
export default class CharacterTypeDeleteEvent extends BaseEvent {
|
||||
export default class CharacterTypeDeleteEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterType:remove', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
const character = await characterRepository.getById(this.socket.characterId!)
|
||||
if (!character) return callback(false)
|
||||
|
||||
const characterTypeRepository = new CharacterTypeRepository()
|
||||
const characterType = await characterTypeRepository.getById(data.id)
|
||||
if (character.role !== 'gm') {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
try {
|
||||
const characterType = await CharacterTypeRepository.getById(data.id)
|
||||
if (!characterType) return callback(false)
|
||||
|
||||
await characterType.delete()
|
||||
return callback(true)
|
||||
callback(true)
|
||||
} catch (error) {
|
||||
this.logger.error(`Error deleting character type ${data.id}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
return callback(false)
|
||||
gameMasterLogger.error(`Error deleting character type ${data.id}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,37 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterType } from '#entities/characterType'
|
||||
import { CharacterType } from '@prisma/client'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
import CharacterTypeRepository from '#repositories/characterTypeRepository'
|
||||
|
||||
interface IPayload {}
|
||||
|
||||
export default class CharacterTypeListEvent extends BaseEvent {
|
||||
export default class CharacterTypeListEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterType:list', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: CharacterType[]) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const characterTypeRepository = new CharacterTypeRepository()
|
||||
const items = await characterTypeRepository.getAll()
|
||||
await characterTypeRepository.getEntityManager().populate(items, ['sprite'])
|
||||
|
||||
return callback(items)
|
||||
} catch (error) {
|
||||
this.logger.error('gm:characterType:list error', error)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -1,41 +1,53 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterGender, CharacterRace } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import CharacterTypeRepository from '#repositories/characterTypeRepository'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
import { CharacterGender, CharacterRace } from '@prisma/client'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import prisma from '#application/prisma'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
type Payload = {
|
||||
id: UUID
|
||||
id: number
|
||||
name: string
|
||||
gender: CharacterGender
|
||||
race: CharacterRace
|
||||
isSelectable: boolean
|
||||
spriteId: UUID
|
||||
spriteId: string
|
||||
}
|
||||
|
||||
export default class CharacterTypeUpdateEvent extends BaseEvent {
|
||||
export default class CharacterTypeUpdateEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterType:update', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
|
||||
const character = await characterRepository.getById(this.socket.characterId!)
|
||||
if (!character) return callback(false)
|
||||
|
||||
if (character.role !== 'gm') {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
await prisma.characterType.update({
|
||||
where: { id: data.id },
|
||||
data: {
|
||||
name: data.name,
|
||||
gender: data.gender,
|
||||
race: data.race,
|
||||
isSelectable: data.isSelectable,
|
||||
spriteId: data.spriteId
|
||||
}
|
||||
})
|
||||
|
||||
const characterTypeRepository = new CharacterTypeRepository()
|
||||
const characterType = await characterTypeRepository.getById(data.id)
|
||||
if (!characterType) return callback(false)
|
||||
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const sprite = await spriteRepository.getById(data.spriteId)
|
||||
if (!sprite) return callback(false)
|
||||
|
||||
await characterType.setName(data.name).setGender(data.gender).setRace(data.race).setIsSelectable(data.isSelectable).setSprite(sprite).save()
|
||||
|
||||
return callback(true)
|
||||
callback(true)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return callback(false)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,42 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Item } from '#entities/item'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import prisma from '#application/prisma'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
export default class ItemCreateEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
export default class ItemCreateEvent extends BaseEvent {
|
||||
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 {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
const character = await characterRepository.getById(this.socket.characterId as number)
|
||||
if (!character) return callback(false)
|
||||
|
||||
const newItem = new Item()
|
||||
await newItem.setName('New Item').setItemType('WEAPON').setStackable(false).setRarity('COMMON').setSprite(null).save()
|
||||
if (character.role !== 'gm') {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
return callback(true, newItem)
|
||||
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)
|
||||
return callback(false)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,41 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import ItemRepository from '#repositories/itemRepository'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import prisma from '#application/prisma'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
interface IPayload {
|
||||
id: UUID
|
||||
id: string
|
||||
}
|
||||
|
||||
export default class ItemDeleteEvent extends BaseEvent {
|
||||
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> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
const character = await characterRepository.getById(this.socket.characterId as number)
|
||||
if (!character) return callback(false)
|
||||
|
||||
const itemRepository = new ItemRepository()
|
||||
const item = await itemRepository.getById(data.id)
|
||||
if (!item) return callback(false)
|
||||
|
||||
await item.delete()
|
||||
|
||||
return callback(true)
|
||||
} catch (error) {
|
||||
this.logger.error(`Error deleting item ${data.id}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,37 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Item } from '#entities/item'
|
||||
import ItemRepository from '#repositories/itemRepository'
|
||||
import { Item } from '@prisma/client'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
import itemRepository from '#repositories/itemRepository'
|
||||
|
||||
interface IPayload {}
|
||||
|
||||
export default class ItemListEvent extends BaseEvent {
|
||||
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> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const itemRepository = new ItemRepository()
|
||||
const items = await itemRepository.getAll()
|
||||
|
||||
return callback(items)
|
||||
} catch (error) {
|
||||
this.logger.error('gm:item:list error', error)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -1,41 +1,55 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { ItemType, ItemRarity } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import ItemRepository from '#repositories/itemRepository'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
import { ItemType, ItemRarity } from '@prisma/client'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import prisma from '#application/prisma'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
type Payload = {
|
||||
id: UUID
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
description: string | null
|
||||
itemType: ItemType
|
||||
stackable: boolean
|
||||
rarity: ItemRarity
|
||||
spriteId: UUID
|
||||
spriteId: string | null
|
||||
}
|
||||
|
||||
export default class ItemUpdateEvent extends BaseEvent {
|
||||
export default class ItemUpdateEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:item:update', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(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 {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const itemRepository = new ItemRepository()
|
||||
const item = await itemRepository.getById(data.id)
|
||||
if (!item) return callback(false)
|
||||
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const sprite = await spriteRepository.getById(data.spriteId)
|
||||
if (!sprite) return callback(false)
|
||||
|
||||
await item.setName(data.name).setDescription(data.description).setItemType(data.itemType).setStackable(data.stackable).setRarity(data.rarity).setSprite(sprite).save()
|
||||
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) {
|
||||
console.error(error)
|
||||
gameMasterLogger.error(`Error updating item: ${error instanceof Error ? error.message : String(error)}`)
|
||||
return callback(false)
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { MapObject } from '#entities/mapObject'
|
||||
import MapObjectRepository from '#repositories/mapObjectRepository'
|
||||
|
||||
interface IPayload {}
|
||||
|
||||
export default class MapObjectListEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:mapObject:list', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: MapObject[]) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
// Get all map objects
|
||||
const mapObjectRepository = new MapObjectRepository()
|
||||
const mapObjects = await mapObjectRepository.getAll()
|
||||
|
||||
return callback(mapObjects)
|
||||
} catch (error) {
|
||||
this.logger.error('gm:mapObject:list error', error)
|
||||
return callback([])
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import Storage from '#application/storage'
|
||||
import { UUID } from '#application/types'
|
||||
import MapObjectRepository from '#repositories/mapObjectRepository'
|
||||
|
||||
interface IPayload {
|
||||
mapObjectId: UUID
|
||||
}
|
||||
|
||||
export default class MapObjectRemoveEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:mapObject:remove', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
// remove the tile from the disk
|
||||
const finalFilePath = Storage.getPublicPath('map_objects', data.mapObjectId + '.png')
|
||||
fs.unlink(finalFilePath, async (err) => {
|
||||
if (err) {
|
||||
this.logger.error(`Error deleting object ${data.mapObjectId}: ${err.message}`)
|
||||
callback(false)
|
||||
return
|
||||
}
|
||||
|
||||
const mapObjectRepository = new MapObjectRepository()
|
||||
await (await mapObjectRepository.getById(data.mapObjectId))?.delete()
|
||||
|
||||
return callback(true)
|
||||
})
|
||||
} catch (error) {
|
||||
this.logger.error(`Error deleting object ${data.mapObjectId}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
return callback(false)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import MapObjectRepository from '#repositories/mapObjectRepository'
|
||||
|
||||
type Payload = {
|
||||
id: UUID
|
||||
name: string
|
||||
tags: string[]
|
||||
originX: number
|
||||
originY: number
|
||||
isAnimated: boolean
|
||||
frameRate: number
|
||||
frameWidth: number
|
||||
frameHeight: number
|
||||
}
|
||||
|
||||
export default class MapObjectUpdateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:mapObject:update', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const mapObjectRepository = new MapObjectRepository()
|
||||
|
||||
const mapObject = await mapObjectRepository.getById(data.id)
|
||||
if (!mapObject) return callback(false)
|
||||
|
||||
await mapObject
|
||||
.setName(data.name)
|
||||
.setTags(data.tags)
|
||||
.setOriginX(data.originX)
|
||||
.setOriginY(data.originY)
|
||||
.setIsAnimated(data.isAnimated)
|
||||
.setFrameRate(data.frameRate)
|
||||
.setFrameWidth(data.frameWidth)
|
||||
.setFrameHeight(data.frameHeight)
|
||||
.save()
|
||||
|
||||
return callback(true)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return callback(false)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
import fs from 'fs/promises'
|
||||
import { writeFile } from 'node:fs/promises'
|
||||
|
||||
import sharp from 'sharp'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import Storage from '#application/storage'
|
||||
import { MapObject } from '#entities/mapObject'
|
||||
|
||||
interface IObjectData {
|
||||
[key: string]: Buffer
|
||||
}
|
||||
|
||||
export default class MapObjectUploadEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:mapObject:upload', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IObjectData, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const public_folder = Storage.getPublicPath('map_objects')
|
||||
|
||||
// Ensure the folder exists
|
||||
await fs.mkdir(public_folder, { recursive: true })
|
||||
|
||||
const uploadPromises = Object.entries(data).map(async ([key, objectData]) => {
|
||||
// Get image dimensions
|
||||
const metadata = await sharp(objectData).metadata()
|
||||
const width = metadata.width || 0
|
||||
const height = metadata.height || 0
|
||||
|
||||
// Create new map object and save it to database
|
||||
const mapObject = new MapObject()
|
||||
await mapObject.setName('New map object').setTags([]).setOriginX(0).setOriginY(0).setFrameWidth(width).setFrameHeight(height).save()
|
||||
|
||||
// Save image to disk
|
||||
const uuid = mapObject.getId()
|
||||
const filename = `${uuid}.png`
|
||||
const finalFilePath = Storage.getPublicPath('map_objects', filename)
|
||||
await writeFile(finalFilePath, objectData)
|
||||
|
||||
this.logger.info('gm:mapObject:upload', `Object ${key} uploaded with id ${uuid}`)
|
||||
})
|
||||
|
||||
await Promise.all(uploadPromises)
|
||||
return callback(true)
|
||||
} catch (error: any) {
|
||||
this.logger.error('gm:mapObject:upload error', error.message)
|
||||
return callback(false)
|
||||
}
|
||||
}
|
||||
}
|
32
src/events/gameMaster/assetManager/object/list.ts
Normal file
32
src/events/gameMaster/assetManager/object/list.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { Object } from '@prisma/client'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
import ObjectRepository from '#repositories/objectRepository'
|
||||
|
||||
interface IPayload {}
|
||||
|
||||
export default class ObjectListEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:object:list', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Object[]) => void): Promise<void> {
|
||||
const character = await characterRepository.getById(this.socket.characterId as number)
|
||||
if (!character) return callback([])
|
||||
|
||||
if (character.role !== 'gm') {
|
||||
return callback([])
|
||||
}
|
||||
|
||||
// get all objects
|
||||
const objects = await ObjectRepository.getAll()
|
||||
callback(objects)
|
||||
}
|
||||
}
|
59
src/events/gameMaster/assetManager/object/remove.ts
Normal file
59
src/events/gameMaster/assetManager/object/remove.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { gameLogger, gameMasterLogger } from '#application/logger'
|
||||
import prisma from '#application/prisma'
|
||||
import Storage from '#application/storage'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
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.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.object.delete({
|
||||
where: {
|
||||
id: data.object
|
||||
}
|
||||
})
|
||||
|
||||
// get root path
|
||||
const public_folder = Storage.getPublicPath('objects')
|
||||
|
||||
// remove the tile from the disk
|
||||
const finalFilePath = Storage.getPublicPath('objects', data.object + '.png')
|
||||
fs.unlink(finalFilePath, (err) => {
|
||||
if (err) {
|
||||
gameMasterLogger.error(`Error deleting object ${data.object}: ${err.message}`)
|
||||
callback(false)
|
||||
return
|
||||
}
|
||||
|
||||
callback(true)
|
||||
})
|
||||
} catch (error) {
|
||||
gameLogger.error(`Error deleting object ${data.object}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
59
src/events/gameMaster/assetManager/object/update.ts
Normal file
59
src/events/gameMaster/assetManager/object/update.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import prisma from '#application/prisma'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
type Payload = {
|
||||
id: string
|
||||
name: string
|
||||
tags: string[]
|
||||
originX: number
|
||||
originY: number
|
||||
isAnimated: boolean
|
||||
frameRate: 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.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(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,
|
||||
frameRate: data.frameRate,
|
||||
frameWidth: data.frameWidth,
|
||||
frameHeight: data.frameHeight
|
||||
}
|
||||
})
|
||||
callback(true)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
73
src/events/gameMaster/assetManager/object/upload.ts
Normal file
73
src/events/gameMaster/assetManager/object/upload.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import fs from 'fs/promises'
|
||||
import { writeFile } from 'node:fs/promises'
|
||||
|
||||
import sharp from 'sharp'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import prisma from '#application/prisma'
|
||||
import Storage from '#application/storage'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
interface IObjectData {
|
||||
[key: string]: Buffer
|
||||
}
|
||||
|
||||
export default class ObjectUploadEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:object:upload', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IObjectData, callback: (response: boolean) => 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 public_folder = Storage.getPublicPath('objects')
|
||||
|
||||
// Ensure the folder exists
|
||||
await fs.mkdir(public_folder, { recursive: true })
|
||||
|
||||
const uploadPromises = Object.entries(data).map(async ([key, objectData]) => {
|
||||
// Get image dimensions
|
||||
const metadata = await sharp(objectData).metadata()
|
||||
const width = metadata.width || 0
|
||||
const height = metadata.height || 0
|
||||
|
||||
const object = await prisma.object.create({
|
||||
data: {
|
||||
name: key,
|
||||
tags: [],
|
||||
originX: 0,
|
||||
originY: 0,
|
||||
frameWidth: width,
|
||||
frameHeight: height
|
||||
}
|
||||
})
|
||||
|
||||
const uuid = object.id
|
||||
const filename = `${uuid}.png`
|
||||
const finalFilePath = Storage.getPublicPath('objects', filename)
|
||||
await writeFile(finalFilePath, objectData)
|
||||
|
||||
gameMasterLogger.info('gm:object:upload', `Object ${key} uploaded with id ${uuid}`)
|
||||
})
|
||||
|
||||
await Promise.all(uploadPromises)
|
||||
|
||||
callback(true)
|
||||
} catch (error: any) {
|
||||
gameMasterLogger.error('gm:object:upload error', error.message)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +1,79 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import type { Prisma } from '@prisma/client'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import prisma from '#application/prisma'
|
||||
import { TSocket } from '#application/types'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
|
||||
interface CopyPayload {
|
||||
id: UUID
|
||||
id: string
|
||||
}
|
||||
|
||||
export default class SpriteCopyEvent extends BaseEvent {
|
||||
export default class SpriteCopyEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:sprite:copy', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(payload: CopyPayload, callback: (success: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const sourceSprite = await spriteRepository.getById(payload.id)
|
||||
|
||||
if (!sourceSprite) {
|
||||
this.logger.error('gm:sprite:copy error', 'Source sprite not found')
|
||||
if (!(await this.validateGameMasterAccess())) {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
// Populate source sprite with spriteActions
|
||||
await spriteRepository.getEntityManager().populate(sourceSprite, ['spriteActions'])
|
||||
const sourceSprite = await prisma.sprite.findUnique({
|
||||
where: { id: payload.id },
|
||||
include: {
|
||||
spriteActions: true
|
||||
}
|
||||
})
|
||||
|
||||
const newSprite = new Sprite()
|
||||
await newSprite.setName(`${sourceSprite.getName()} (Copy)`).setSpriteActions(sourceSprite.getSpriteActions()).save()
|
||||
if (!sourceSprite) {
|
||||
throw new Error('Source sprite not found')
|
||||
}
|
||||
|
||||
return callback(true)
|
||||
const newSprite = await prisma.sprite.create({
|
||||
data: {
|
||||
name: `${sourceSprite.name} (Copy)`,
|
||||
spriteActions: {
|
||||
create: sourceSprite.spriteActions.map((action) => ({
|
||||
action: action.action,
|
||||
sprites: action.sprites as Prisma.InputJsonValue,
|
||||
originX: action.originX,
|
||||
originY: action.originY,
|
||||
isAnimated: action.isAnimated,
|
||||
isLooping: action.isLooping,
|
||||
frameWidth: action.frameWidth,
|
||||
frameHeight: action.frameHeight,
|
||||
frameRate: action.frameRate
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
callback(true)
|
||||
} catch (error) {
|
||||
this.logger.error(`Error copying sprite:`, String(error))
|
||||
return callback(false)
|
||||
this.handleError(error, payload.id, callback)
|
||||
}
|
||||
}
|
||||
|
||||
private async validateGameMasterAccess(): Promise<boolean> {
|
||||
const character = await CharacterRepository.getById(this.socket.characterId!)
|
||||
return character?.role === 'gm'
|
||||
}
|
||||
|
||||
private handleError(error: unknown, spriteId: string, callback: (success: boolean) => void): void {
|
||||
gameMasterLogger.error(`Error copying sprite ${spriteId}: ${this.getErrorMessage(error)}`)
|
||||
callback(false)
|
||||
}
|
||||
|
||||
private getErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error)
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,51 @@
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import Storage from '#application/storage'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import prisma from '#application/prisma'
|
||||
import Storage from '#application/storage'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
export default class SpriteCreateEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
export default class SpriteCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:sprite:create', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: undefined, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
const character = await characterRepository.getById(this.socket.characterId!)
|
||||
if (!character) return callback(false)
|
||||
|
||||
if (character.role !== 'gm') {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const public_folder = Storage.getPublicPath('sprites')
|
||||
|
||||
// Ensure the folder exists
|
||||
await fs.mkdir(public_folder, { recursive: true })
|
||||
|
||||
const sprite = new Sprite()
|
||||
await sprite.setName('New sprite').save()
|
||||
|
||||
const sprite = await prisma.sprite.create({
|
||||
data: {
|
||||
name: 'New sprite'
|
||||
}
|
||||
})
|
||||
const uuid = sprite.id
|
||||
|
||||
// Create folder with uuid
|
||||
const sprite_folder = Storage.getPublicPath('sprites', uuid)
|
||||
await fs.mkdir(sprite_folder, { recursive: true })
|
||||
|
||||
return callback(true)
|
||||
callback(true)
|
||||
} catch (error) {
|
||||
console.error('Error creating sprite:', error)
|
||||
return callback(false)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,47 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import prisma from '#application/prisma'
|
||||
import Storage from '#application/storage'
|
||||
import { UUID } from '#application/types'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
import { TSocket } from '#application/types'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
|
||||
type Payload = {
|
||||
id: UUID
|
||||
id: string
|
||||
}
|
||||
|
||||
export default class GMSpriteDeleteEvent extends BaseEvent {
|
||||
export default class GMSpriteDeleteEvent {
|
||||
private readonly public_folder: string
|
||||
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {
|
||||
this.public_folder = Storage.getPublicPath('sprites')
|
||||
}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:sprite:delete', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
await this.deleteSpriteFolder(data.id)
|
||||
|
||||
const spriteRepository = new SpriteRepository()
|
||||
await (await spriteRepository.getById(data.id))?.delete()
|
||||
|
||||
this.logger.info(`Sprite ${data.id} deleted.`)
|
||||
return callback(true)
|
||||
} catch (error: any) {
|
||||
this.logger.error('gm:sprite:delete error', error.message)
|
||||
const character = await CharacterRepository.getById(this.socket.characterId!)
|
||||
if (character?.role !== 'gm') {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
try {
|
||||
await this.deleteSpriteFolder(data.id)
|
||||
await this.deleteSpriteFromDatabase(data.id)
|
||||
|
||||
gameMasterLogger.info(`Sprite ${data.id} deleted.`)
|
||||
callback(true)
|
||||
} catch (error: any) {
|
||||
gameMasterLogger.error('gm:sprite:delete error', error.message)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
|
||||
private async deleteSpriteFolder(spriteId: string): Promise<void> {
|
||||
@ -38,4 +51,12 @@ export default class GMSpriteDeleteEvent extends BaseEvent {
|
||||
await fs.promises.rmdir(finalFilePath, { recursive: true })
|
||||
}
|
||||
}
|
||||
|
||||
private async deleteSpriteFromDatabase(spriteId: string): Promise<void> {
|
||||
await prisma.sprite.delete({
|
||||
where: {
|
||||
id: spriteId
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,32 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
import { Sprite } from '@prisma/client'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
|
||||
interface IPayload {}
|
||||
|
||||
export default class SpriteListEvent extends BaseEvent {
|
||||
export default class SpriteListEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:sprite:list', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Sprite[]) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
private async handleEvent(data: any, callback: (response: Sprite[]) => void): Promise<void> {
|
||||
const character = await characterRepository.getById(this.socket.characterId!)
|
||||
if (!character) return callback([])
|
||||
|
||||
// Get all sprites
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const sprites = await spriteRepository.getAll()
|
||||
await spriteRepository.getEntityManager().populate(sprites, ['spriteActions'])
|
||||
|
||||
return callback(sprites)
|
||||
} catch (error) {
|
||||
this.logger.error('gm:sprite:list error', error)
|
||||
if (character.role !== 'gm') {
|
||||
return callback([])
|
||||
}
|
||||
|
||||
// get all sprites
|
||||
const sprites = await SpriteRepository.getAll()
|
||||
callback(sprites)
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
import { writeFile, mkdir } from 'node:fs/promises'
|
||||
|
||||
import sharp from 'sharp'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import type { Prisma, SpriteAction } from '@prisma/client'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import prisma from '#application/prisma'
|
||||
import Storage from '#application/storage'
|
||||
import { SpriteAction } from '#entities/spriteAction'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
import { TSocket } from '#application/types'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
|
||||
// Constants
|
||||
const ISOMETRIC_CONFIG = {
|
||||
@ -37,7 +41,7 @@ interface SpriteActionInput extends Omit<SpriteAction, 'id' | 'spriteId' | 'fram
|
||||
interface UpdatePayload {
|
||||
id: string
|
||||
name: string
|
||||
spriteActions: SpriteAction[]
|
||||
spriteActions: Prisma.JsonValue
|
||||
}
|
||||
|
||||
interface ProcessedSpriteAction extends SpriteActionInput {
|
||||
@ -58,14 +62,21 @@ interface SpriteAnalysis {
|
||||
contentBounds: ContentBounds
|
||||
}
|
||||
|
||||
export default class SpriteUpdateEvent extends BaseEvent {
|
||||
export default class SpriteUpdateEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:sprite:update', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(payload: UpdatePayload, callback: (success: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
if (!(await this.validateGameMasterAccess())) {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
const parsedActions = this.validateSpriteActions(payload.spriteActions)
|
||||
|
||||
@ -100,6 +111,11 @@ export default class SpriteUpdateEvent extends BaseEvent {
|
||||
}
|
||||
}
|
||||
|
||||
private async validateGameMasterAccess(): Promise<boolean> {
|
||||
const character = await CharacterRepository.getById(this.socket.characterId!)
|
||||
return character?.role === 'gm'
|
||||
}
|
||||
|
||||
private validateSpriteActions(actions: Prisma.JsonValue): SpriteActionInput[] {
|
||||
try {
|
||||
const parsed = JSON.parse(JSON.stringify(actions)) as SpriteActionInput[]
|
||||
@ -359,8 +375,6 @@ export default class SpriteUpdateEvent extends BaseEvent {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await (await SpriteRepository.getById(id))?.setName(name).setSpriteActions(actions).update()
|
||||
}
|
||||
|
||||
private mapActionToDatabase(action: ProcessedSpriteAction) {
|
||||
@ -378,7 +392,7 @@ export default class SpriteUpdateEvent extends BaseEvent {
|
||||
}
|
||||
|
||||
private handleError(error: unknown, spriteId: string, callback: (success: boolean) => void): void {
|
||||
this.logger.error(`Error updating sprite ${spriteId}: ${this.getErrorMessage(error)}`)
|
||||
gameMasterLogger.error(`Error updating sprite ${spriteId}: ${this.getErrorMessage(error)}`)
|
||||
callback(false)
|
||||
}
|
||||
|
||||
|
@ -1,38 +1,60 @@
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import prisma from '#application/prisma'
|
||||
import Storage from '#application/storage'
|
||||
import { UUID } from '#application/types'
|
||||
import TileRepository from '#repositories/tileRepository'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
type Payload = {
|
||||
id: UUID
|
||||
id: string
|
||||
}
|
||||
|
||||
export default class GMTileDeleteEvent extends BaseEvent {
|
||||
export default class GMTileDeleteEvent {
|
||||
private readonly public_folder: string
|
||||
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {
|
||||
this.public_folder = Storage.getPublicPath('tiles')
|
||||
}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:tile:delete', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, 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
|
||||
}
|
||||
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
this.logger.info(`Deleting tile ${data.id}`)
|
||||
|
||||
gameMasterLogger.info(`Deleting tile ${data.id}`)
|
||||
await this.deleteTileFromDatabase(data.id)
|
||||
await this.deleteTileFile(data.id)
|
||||
|
||||
const tileRepository = new TileRepository()
|
||||
await (await tileRepository.getById(data.id))?.delete()
|
||||
|
||||
this.logger.info(`Tile ${data.id} deleted successfully.`)
|
||||
return callback(true)
|
||||
} catch (error: unknown) {
|
||||
this.logger.error('gm:tile:delete error', error)
|
||||
return callback(false)
|
||||
gameMasterLogger.info(`Tile ${data.id} deleted successfully.`)
|
||||
callback(true)
|
||||
} catch (error: any) {
|
||||
gameMasterLogger.error('gm:tile:delete error', error.message)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
|
||||
private async deleteTileFromDatabase(tileId: string): Promise<void> {
|
||||
await prisma.tile.delete({
|
||||
where: {
|
||||
id: tileId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private async deleteTileFile(tileId: string): Promise<void> {
|
||||
const finalFilePath = Storage.getPublicPath('tiles', `${tileId}.png`)
|
||||
try {
|
||||
@ -41,7 +63,7 @@ export default class GMTileDeleteEvent extends BaseEvent {
|
||||
if (error.code !== 'ENOENT') {
|
||||
throw error
|
||||
}
|
||||
this.logger.warn(`File ${finalFilePath} does not exist.`)
|
||||
gameMasterLogger.warn(`File ${finalFilePath} does not exist.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,32 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Tile } from '#entities/tile'
|
||||
import { Tile } from '@prisma/client'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
import TileRepository from '#repositories/tileRepository'
|
||||
|
||||
interface IPayload {}
|
||||
|
||||
export default class TileListEven extends BaseEvent {
|
||||
export default class TileListEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:tile:list', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Tile[]) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
private async handleEvent(data: any, callback: (response: Tile[]) => void): Promise<void> {
|
||||
const character = await characterRepository.getById(this.socket.characterId as number)
|
||||
if (!character) return
|
||||
|
||||
// Get all tiles
|
||||
const tileRepository = new TileRepository()
|
||||
const tiles = await tileRepository.getAll()
|
||||
return callback(tiles)
|
||||
} catch (error) {
|
||||
this.logger.error('gm:tile:list error', error)
|
||||
return callback([])
|
||||
if (character.role !== 'gm') {
|
||||
return
|
||||
}
|
||||
|
||||
// get all tiles
|
||||
const tiles = await TileRepository.getAll()
|
||||
callback(tiles)
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,48 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import TileRepository from '#repositories/tileRepository'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import prisma from '#application/prisma'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
type Payload = {
|
||||
id: UUID
|
||||
id: string
|
||||
name: string
|
||||
tags: string[]
|
||||
}
|
||||
|
||||
export default class TileUpdateEvent extends BaseEvent {
|
||||
export default class TileUpdateEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:tile:update', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(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
|
||||
}
|
||||
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
const Tile = await prisma.tile.update({
|
||||
where: {
|
||||
id: data.id
|
||||
},
|
||||
data: {
|
||||
name: data.name,
|
||||
tags: data.tags
|
||||
}
|
||||
})
|
||||
|
||||
const tileRepository = new TileRepository()
|
||||
|
||||
const tile = await tileRepository.getById(data.id)
|
||||
if (!tile) return callback(false)
|
||||
|
||||
await tile.setName(data.name).setTags(data.tags).save()
|
||||
|
||||
return callback(true)
|
||||
callback(true)
|
||||
} catch (error) {
|
||||
return callback(false)
|
||||
console.error(error)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,36 @@
|
||||
import fs from 'fs/promises'
|
||||
import { writeFile } from 'node:fs/promises'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { gameMasterLogger } from '#application/logger'
|
||||
import prisma from '#application/prisma'
|
||||
import Storage from '#application/storage'
|
||||
import { Tile } from '#entities/tile'
|
||||
import { TSocket } from '#application/types'
|
||||
import characterRepository from '#repositories/characterRepository'
|
||||
|
||||
interface ITileData {
|
||||
[key: string]: Buffer
|
||||
}
|
||||
|
||||
export default class TileUploadEvent extends BaseEvent {
|
||||
export default class TileUploadEvent {
|
||||
constructor(
|
||||
private readonly io: Server,
|
||||
private readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('gm:tile:upload', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: ITileData, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
const character = await characterRepository.getById(this.socket.characterId as number)
|
||||
if (!character) return callback(false)
|
||||
|
||||
if (character.role !== 'gm') {
|
||||
return
|
||||
}
|
||||
|
||||
const public_folder = Storage.getPublicPath('tiles')
|
||||
|
||||
@ -24,9 +38,12 @@ export default class TileUploadEvent extends BaseEvent {
|
||||
await fs.mkdir(public_folder, { recursive: true })
|
||||
|
||||
const uploadPromises = Object.entries(data).map(async ([key, tileData]) => {
|
||||
const tile = new Tile()
|
||||
await tile.setName('New tile').save()
|
||||
const uuid = tile.getId()
|
||||
const tile = await prisma.tile.create({
|
||||
data: {
|
||||
name: 'New tile'
|
||||
}
|
||||
})
|
||||
const uuid = tile.id
|
||||
const filename = `${uuid}.png`
|
||||
const finalFilePath = Storage.getPublicPath('tiles', filename)
|
||||
await writeFile(finalFilePath, tileData)
|
||||
@ -34,10 +51,10 @@ export default class TileUploadEvent extends BaseEvent {
|
||||
|
||||
await Promise.all(uploadPromises)
|
||||
|
||||
return callback(true)
|
||||
callback(true)
|
||||
} catch (error) {
|
||||
this.logger.error('Error uploading tile:', error)
|
||||
return callback(false)
|
||||
gameMasterLogger.error('Error uploading tile:', error)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Map } from '#entities/map'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
|
||||
type Payload = {
|
||||
name: string
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
export default class MapCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:map:create', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (response: Map[]) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
this.logger.info(`User ${(await this.getCharacter())!.getId()} has created a new map via map editor.`)
|
||||
|
||||
const map = new Map()
|
||||
await map
|
||||
.setName(data.name)
|
||||
.setWidth(data.width)
|
||||
.setHeight(data.height)
|
||||
.setTiles(Array.from({ length: data.height }, () => Array.from({ length: data.width }, () => 'blank_tile')))
|
||||
.save()
|
||||
|
||||
const mapRepository = new MapRepository()
|
||||
const mapList = await mapRepository.getAll()
|
||||
|
||||
return callback(mapList)
|
||||
} catch (error: any) {
|
||||
this.logger.error('gm:map:create error', error.message)
|
||||
this.socket.emit('notification', { message: 'Failed to create map.' })
|
||||
return callback([])
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user