Compare commits

...

36 Commits

Author SHA1 Message Date
5680b324b4 Merge remote-tracking branch 'origin/feature/map-refactor' 2025-01-27 01:56:51 +01:00
9771f45e6d Removed isAnimated and isLooping fields 2025-01-27 01:56:04 +01:00
b3ac6d34b8 Merge remote-tracking branch 'origin/feature/#313-effects' into feature/map-refactor 2025-01-25 15:34:40 +01:00
b115181756 Updated README 2025-01-25 14:50:53 +01:00
bf4789b9a8 Added additional installation steps 2025-01-25 14:44:33 +01:00
f004f059f6 Added software requirements to README 2025-01-25 14:39:44 +01:00
e6adb959ba npm run format 2025-01-25 13:24:46 +01:00
85161ab4f6 Added comment 2025-01-25 00:28:23 +01:00
8f4d4fc482 Removed unused functions 2025-01-24 23:53:03 +01:00
a0584c2bb9 Inline checking for less written code; removed unused import 2025-01-24 23:52:56 +01:00
7f4a784915 Removed redundant columns 2025-01-24 23:52:30 +01:00
71fdbd89a4 npm update 2025-01-24 23:46:36 +01:00
5c34ed7286 Fixed error thrown when getArgs called on a command with no arguments 2025-01-23 13:52:32 -06:00
edb7836e55 Weather values randomized if no number is given as a command argument 2025-01-23 13:42:26 -06:00
112559055c Added createdAt and updatedAt fields to character hair to fix cache issue 2025-01-23 20:36:02 +01:00
1546deb811 Removed depth field from placedMapObject as this is calculated automatically 2025-01-23 19:47:33 +01:00
d7ac70662a Accidentally put fog instead of rain 2025-01-23 11:59:23 -06:00
dae0d365d5 Changed toggle functions to set, and refactored the random weather value gen 2025-01-22 20:33:11 -06:00
020f2bd3c5 Removed weather effects booleans, now to disable weather effects, setting the value to 0 is the way 2025-01-22 18:00:04 -06:00
189fd39377 Moved CORS logic into httpManager 2025-01-21 14:58:55 +01:00
0ba79c2299 Teleport fix 2025-01-14 02:18:53 +01:00
74f5214ca3 removed console.log 2025-01-13 15:02:44 +01:00
410d5cb7a8 Disabled Mikro ORM debugging 2025-01-13 14:51:39 +01:00
41e65fc3e9 ? 2025-01-12 22:11:41 +01:00
4b6935c44a npm update 2025-01-11 21:47:29 +01:00
4232042a06 Typo 2025-01-10 23:23:20 +01:00
3869eefaaf frameCount fix 2025-01-10 19:29:28 +01:00
a4437fadce npm run format 2025-01-09 16:02:26 +01:00
458293a5fc Better var. naming 2025-01-09 15:58:16 +01:00
849ef07297 Entirely replaces asset controller with improved ones (textures & cache) 2025-01-08 21:12:33 +01:00
39ec4daa06 More cache stuff 2025-01-07 22:20:27 +01:00
010454914b POC working new caching method - moved controllers folder, renamed assets to textures, fixed HTTP bug, formatted code 2025-01-07 03:58:32 +01:00
f47023dc81 POC working new caching method - moved controllers folder, renamed assets to textures, fixed HTTP bug, formatted code 2025-01-07 03:58:26 +01:00
4397552a86 Merge pull request 'fixed console logging on windows devices.' (#1) from issue/#307-fix-server-console-logging-on-window-based-devices into main
Reviewed-on: #1
2025-01-06 20:40:36 +00:00
7dabed7ff6 Minor change 2025-01-06 21:23:25 +01:00
d91a70be09 Value can't be undefined anymore, is now null by default if no value is set or found 2025-01-06 21:23:17 +01:00
60 changed files with 780 additions and 668 deletions

View File

@ -3,7 +3,7 @@ ENV=development
HOST="0.0.0.0"
PORT=4000
JWT_SECRET="secret"
CLIENT_URL="http://192.168.3.4:5173"
CLIENT_URL="http://localhost:5173"
# Database configuration
REDIS_URL="redis://@127.0.0.1:6379/4"

View File

@ -2,12 +2,22 @@
This is the server for the Noxious game.
## Projects requirements
- NodeJS 20.x or higher
- MySQL 8.x or higher
- Redis 7.x or higher
## Installation
1. Clone the repository
2. Install dependencies with `npm install`
3. Copy the `.env.example` file to `.env` and fill in the required variables
4. Run the server with `npm run dev`
4. Extract assets.zip to the `public` folder
5. After MySQL and Redis are running, run `npx mikro-orm migration:up` to create the database schema
6. Run the server with `npm run dev`
7. Write `init` in the console to import default data and restart the server
8. Write `tiles` in the console to fix tile sizes
## Commands

View File

@ -1,6 +1,6 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20250106170204 extends Migration {
export class Migration20250123193515 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;`);
@ -17,7 +17,7 @@ export class Migration20250106170204 extends Migration {
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(`create table \`placed_map_object\` (\`id\` varchar(255) not null, \`map_id\` varchar(255) not null, \`map_object_id\` varchar(255) not null, \`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\`);`);
@ -29,7 +29,7 @@ export class Migration20250106170204 extends Migration {
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;`);
this.addSql(`alter table \`character_type\` add index \`character_type_sprite_id_index\`(\`sprite_id\`);`);
this.addSql(`create table \`character_hair\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`gender\` varchar(255) not null default 'MALE', \`is_selectable\` tinyint(1) not null default false, \`sprite_id\` varchar(255) null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
this.addSql(`create table \`character_hair\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`gender\` varchar(255) not null default 'MALE', \`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;`);
this.addSql(`alter table \`character_hair\` add index \`character_hair_sprite_id_index\`(\`sprite_id\`);`);
this.addSql(`create table \`sprite_action\` (\`id\` varchar(255) not null, \`sprite_id\` varchar(255) not null, \`action\` varchar(255) not null, \`sprites\` json null, \`origin_x\` int not null default 0, \`origin_y\` int not null default 0, \`is_animated\` tinyint(1) not null default false, \`is_looping\` tinyint(1) not null default false, \`frame_width\` int not null default 0, \`frame_height\` int not null default 0, \`frame_rate\` int not null default 0, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);

View File

@ -0,0 +1,104 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20250127005232 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, \`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, \`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 \`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(`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;`);
this.addSql(`alter table \`character_type\` add index \`character_type_sprite_id_index\`(\`sprite_id\`);`);
this.addSql(`create table \`character_hair\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`gender\` varchar(255) not null default 'MALE', \`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;`);
this.addSql(`alter table \`character_hair\` add index \`character_hair_sprite_id_index\`(\`sprite_id\`);`);
this.addSql(`create table \`sprite_action\` (\`id\` varchar(255) not null, \`sprite_id\` varchar(255) not null, \`action\` varchar(255) not null, \`sprites\` json null, \`origin_x\` int not null default 0, \`origin_y\` int not null default 0, \`frame_width\` int not null default 0, \`frame_height\` int not null default 0, \`frame_rate\` int not null default 0, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
this.addSql(`alter table \`sprite_action\` add index \`sprite_action_sprite_id_index\`(\`sprite_id\`);`);
this.addSql(`create table \`tile\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`tags\` json null, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
this.addSql(`create table \`user\` (\`id\` varchar(255) not null, \`username\` varchar(255) not null, \`email\` varchar(255) not null, \`password\` varchar(255) not null, \`online\` tinyint(1) not null default false, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
this.addSql(`alter table \`user\` add unique \`user_username_unique\`(\`username\`);`);
this.addSql(`alter table \`user\` add unique \`user_email_unique\`(\`email\`);`);
this.addSql(`create table \`password_reset_token\` (\`id\` varchar(255) not null, \`user_id\` varchar(255) not null, \`token\` varchar(255) not null, \`created_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
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(`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_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(`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(`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\`);`);
this.addSql(`alter table \`character_item\` add index \`character_item_item_id_index\`(\`item_id\`);`);
this.addSql(`create table \`character_equipment\` (\`id\` varchar(255) not null, \`slot\` enum('HEAD', 'BODY', 'ARMS', 'LEGS', 'NECK', 'RING') not null, \`character_id\` varchar(255) not null, \`character_item_id\` varchar(255) not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
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, \`rain_percentage\` int not null default 0, \`fog_density\` int not null default 0, primary key (\`date\`)) default character set utf8mb4 engine = InnoDB;`);
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(`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(`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(`alter table \`item\` add constraint \`item_sprite_id_foreign\` foreign key (\`sprite_id\`) references \`sprite\` (\`id\`) on update cascade on delete set null;`);
this.addSql(`alter table \`character_type\` add constraint \`character_type_sprite_id_foreign\` foreign key (\`sprite_id\`) references \`sprite\` (\`id\`) on update cascade on delete set null;`);
this.addSql(`alter table \`character_hair\` add constraint \`character_hair_sprite_id_foreign\` foreign key (\`sprite_id\`) references \`sprite\` (\`id\`) on update cascade on delete set null;`);
this.addSql(`alter table \`sprite_action\` add constraint \`sprite_action_sprite_id_foreign\` foreign key (\`sprite_id\`) references \`sprite\` (\`id\`) on update cascade on delete cascade;`);
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_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 \`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;`);
}
}

View File

@ -16,8 +16,7 @@ export default defineConfig({
user: serverConfig.DB_USER,
password: serverConfig.DB_PASS,
dbName: serverConfig.DB_NAME,
debug: serverConfig.ENV !== 'production',
// allowGlobalContext: true,
debug: false,
driverOptions: {
allowPublicKeyRetrieval: true
},

494
package-lock.json generated
View File

@ -544,9 +544,9 @@
}
},
"node_modules/@eslint/core": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz",
"integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==",
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz",
"integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@ -605,9 +605,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.17.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz",
"integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==",
"version": "9.19.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz",
"integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==",
"dev": true,
"license": "MIT",
"engines": {
@ -625,12 +625,13 @@
}
},
"node_modules/@eslint/plugin-kit": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz",
"integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==",
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz",
"integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/core": "^0.10.0",
"levn": "^0.4.1"
},
"engines": {
@ -1108,16 +1109,16 @@
}
},
"node_modules/@mikro-orm/cli": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.2.tgz",
"integrity": "sha512-aGOpVNNbymdkxIsHt+rD5hU25UlGbcPrd3zMdDVh0H5jttB1kr9MpAT4Jt4SXqZfTc1ff6h479eufUYJP3mZZQ==",
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.4.tgz",
"integrity": "sha512-GgYpwZFLndijNa1YxPtGeHyqQM3uwXxxoXEh7qbG2MDggkpt8VYGMj66NLjykNv25meARCEdijE02DpVZh8eoQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jercle/yargonaut": "1.1.5",
"@mikro-orm/core": "6.4.2",
"@mikro-orm/knex": "6.4.2",
"fs-extra": "11.2.0",
"@mikro-orm/core": "6.4.4",
"@mikro-orm/knex": "6.4.4",
"fs-extra": "11.3.0",
"tsconfig-paths": "4.2.0",
"yargs": "17.7.2"
},
@ -1130,17 +1131,17 @@
}
},
"node_modules/@mikro-orm/core": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.2.tgz",
"integrity": "sha512-sk+rGxZoj8zx9q819CeXLqMMLXF81s7pQZtrdg3XUCBnUVqsaVIsbBj5WpyojQXmCvxgenWqDE/ybM5ftbDP/w==",
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.4.tgz",
"integrity": "sha512-1Ff+fJX7pZFaZt9ebFxPW2w8yDp/uz2VhSMqqop1538VRvTqHseTRI+2Tmm9oX5pm5y5YS7+FdgnyAx6FLWjHg==",
"license": "MIT",
"dependencies": {
"dataloader": "2.2.3",
"dotenv": "16.4.7",
"esprima": "4.0.1",
"fs-extra": "11.2.0",
"fs-extra": "11.3.0",
"globby": "11.1.0",
"mikro-orm": "6.4.2",
"mikro-orm": "6.4.4",
"reflect-metadata": "0.2.2"
},
"engines": {
@ -1151,12 +1152,12 @@
}
},
"node_modules/@mikro-orm/knex": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.2.tgz",
"integrity": "sha512-vA72sVyR+8irrLsTP5f+zh84Q1a2tvzSfVgit4L/G+JOEgltG6F8Sfic/xt/1Wcis1zgNUiUL50ISQSLnhVNAw==",
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.4.tgz",
"integrity": "sha512-lzTce9SrdD3zO9mQP0MXqXTPM1+X7DXP19SgFnhygLEcBfWPgx1iRxjxOWbLjdM6p41p0Fh+5W73bwF/4jrIfQ==",
"license": "MIT",
"dependencies": {
"fs-extra": "11.2.0",
"fs-extra": "11.3.0",
"knex": "3.1.0",
"sqlstring": "2.3.3"
},
@ -1182,12 +1183,12 @@
}
},
"node_modules/@mikro-orm/mariadb": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/@mikro-orm/mariadb/-/mariadb-6.4.2.tgz",
"integrity": "sha512-Ua2dE/Y/ozC5GYxukwaV1k/6nFL71/YNsnI65sOFGVFzxZLeMrgY4fbWBW/EZSZgZWcxvlDefhG9U8228R8cbA==",
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/@mikro-orm/mariadb/-/mariadb-6.4.4.tgz",
"integrity": "sha512-mxTGdOPOyNR7kh18CL2xcFexFkYpyD6jIAQFJlUAmKrXEHpkcOuY8fIHGw8fqJW9eVfBjdNqyDEDjz9iAxFxLA==",
"license": "MIT",
"dependencies": {
"@mikro-orm/knex": "6.4.2",
"@mikro-orm/knex": "6.4.4",
"mariadb": "3.4.0"
},
"engines": {
@ -1198,13 +1199,13 @@
}
},
"node_modules/@mikro-orm/migrations": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/@mikro-orm/migrations/-/migrations-6.4.2.tgz",
"integrity": "sha512-oLAOT+ejduIOb8rO6cJ8B6yr9bM17t22ejLPTxUnw1N093DXb31zWOg6Ptc8cicnB3BbFQGjQVw6Jf2e3vYpbA==",
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/@mikro-orm/migrations/-/migrations-6.4.4.tgz",
"integrity": "sha512-eeN91BjV4RDizWu5r+z2taVhFivbLmj04udkJ4ZGrrYGB+DIH6nb7zqLKiLbKvHUknXkzNX10wEPOuav/wW+Kg==",
"license": "MIT",
"dependencies": {
"@mikro-orm/knex": "6.4.2",
"fs-extra": "11.2.0",
"@mikro-orm/knex": "6.4.4",
"fs-extra": "11.3.0",
"umzug": "3.8.2"
},
"engines": {
@ -1215,13 +1216,13 @@
}
},
"node_modules/@mikro-orm/mysql": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/@mikro-orm/mysql/-/mysql-6.4.2.tgz",
"integrity": "sha512-w6gch2Th/j7JJW1RUjt+naWsatiAJdHpTfrOBzsaYcjeZeW6qT2+igvbcLxq+pfQp+Ea3uZ21CxLKJOGKnVDnA==",
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/@mikro-orm/mysql/-/mysql-6.4.4.tgz",
"integrity": "sha512-OnSsYnr/o8TLjmFXtwI2anuAyNj5Nrgde2uUY5pECGnUkN2jH9+8AdXQmlgljodYNmZrc04QbhbvG65PjL0LsA==",
"license": "MIT",
"dependencies": {
"@mikro-orm/knex": "6.4.2",
"mysql2": "3.11.5"
"@mikro-orm/knex": "6.4.4",
"mysql2": "3.12.0"
},
"engines": {
"node": ">= 18.12.0"
@ -1231,13 +1232,13 @@
}
},
"node_modules/@mikro-orm/reflection": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.4.2.tgz",
"integrity": "sha512-tCqy9xKc97a+6NlOK8xhaJlnj2b7C2dDhu7vhkU0ks/WuCOigHOmg21ikhFPz4VfKbGYPStt2DoZBUU9mCkMmA==",
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.4.4.tgz",
"integrity": "sha512-qNScd9vlQdbu5o34N834QGpXTH0OEgjZKZbZYqDzBbEzvMbz4VByXFiMFo0kw39/y2+RlB+hrH7kPfcAYIYQxA==",
"license": "MIT",
"dependencies": {
"globby": "11.1.0",
"ts-morph": "24.0.0"
"ts-morph": "25.0.0"
},
"engines": {
"node": ">= 18.12.0"
@ -1360,9 +1361,9 @@
}
},
"node_modules/@prisma/client": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.1.0.tgz",
"integrity": "sha512-AbQYc5+EJKm1Ydfq3KxwcGiy7wIbm4/QbjCKWWoNROtvy7d6a3gmAGkKjK0iUCzh+rHV8xDhD5Cge8ke/kiy5Q==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.2.1.tgz",
"integrity": "sha512-msKY2iRLISN8t5X0Tj7hU0UWet1u0KuxSPHWuf3IRkB4J95mCvGpyQBfQ6ufcmvKNOMQSq90O2iUmJEN2e5fiA==",
"hasInstallScript": true,
"license": "Apache-2.0",
"engines": {
@ -1378,53 +1379,53 @@
}
},
"node_modules/@prisma/debug": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.1.0.tgz",
"integrity": "sha512-0himsvcM4DGBTtvXkd2Tggv6sl2JyUYLzEGXXleFY+7Kp6rZeSS3hiTW9mwtUlXrwYbJP6pwlVNB7jYElrjWUg==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.2.1.tgz",
"integrity": "sha512-0KItvt39CmQxWkEw6oW+RQMD6RZ43SJWgEUnzxN8VC9ixMysa7MzZCZf22LCK5DSooiLNf8vM3LHZm/I/Ni7bQ==",
"devOptional": true,
"license": "Apache-2.0"
},
"node_modules/@prisma/engines": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.1.0.tgz",
"integrity": "sha512-GnYJbCiep3Vyr1P/415ReYrgJUjP79fBNc1wCo7NP6Eia0CzL2Ot9vK7Infczv3oK7JLrCcawOSAxFxNFsAERQ==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.2.1.tgz",
"integrity": "sha512-lTBNLJBCxVT9iP5I7Mn6GlwqAxTpS5qMERrhebkUhtXpGVkBNd/jHnNJBZQW4kGDCKaQg/r2vlJYkzOHnAb7ZQ==",
"devOptional": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@prisma/debug": "6.1.0",
"@prisma/engines-version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959",
"@prisma/fetch-engine": "6.1.0",
"@prisma/get-platform": "6.1.0"
"@prisma/debug": "6.2.1",
"@prisma/engines-version": "6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69",
"@prisma/fetch-engine": "6.2.1",
"@prisma/get-platform": "6.2.1"
}
},
"node_modules/@prisma/engines-version": {
"version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959",
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959.tgz",
"integrity": "sha512-PdJqmYM2Fd8K0weOOtQThWylwjsDlTig+8Pcg47/jszMuLL9iLIaygC3cjWJLda69siRW4STlCTMSgOjZzvKPQ==",
"version": "6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69",
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69.tgz",
"integrity": "sha512-7tw1qs/9GWSX6qbZs4He09TOTg1ff3gYsB3ubaVNN0Pp1zLm9NC5C5MZShtkz7TyQjx7blhpknB7HwEhlG+PrQ==",
"devOptional": true,
"license": "Apache-2.0"
},
"node_modules/@prisma/fetch-engine": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.1.0.tgz",
"integrity": "sha512-asdFi7TvPlEZ8CzSZ/+Du5wZ27q6OJbRSXh+S8ISZguu+S9KtS/gP7NeXceZyb1Jv1SM1S5YfiCv+STDsG6rrg==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.2.1.tgz",
"integrity": "sha512-OO7O9d6Mrx2F9i+Gu1LW+DGXXyUFkP7OE5aj9iBfA/2jjDXEJjqa9X0ZmM9NZNo8Uo7ql6zKm6yjDcbAcRrw1A==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"@prisma/debug": "6.1.0",
"@prisma/engines-version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959",
"@prisma/get-platform": "6.1.0"
"@prisma/debug": "6.2.1",
"@prisma/engines-version": "6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69",
"@prisma/get-platform": "6.2.1"
}
},
"node_modules/@prisma/get-platform": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.1.0.tgz",
"integrity": "sha512-ia8bNjboBoHkmKGGaWtqtlgQOhCi7+f85aOkPJKgNwWvYrT6l78KgojLekE8zMhVk0R9lWcifV0Pf8l3/15V0Q==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.2.1.tgz",
"integrity": "sha512-zp53yvroPl5m5/gXYLz7tGCNG33bhG+JYCm74ohxOq1pPnrL47VQYFfF3RbTZ7TzGWCrR3EtoiYMywUBw7UK6Q==",
"devOptional": true,
"license": "Apache-2.0",
"dependencies": {
"@prisma/debug": "6.1.0"
"@prisma/debug": "6.2.1"
}
},
"node_modules/@rtsao/scc": {
@ -1435,9 +1436,9 @@
"license": "MIT"
},
"node_modules/@rushstack/node-core-library": {
"version": "5.10.1",
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.10.1.tgz",
"integrity": "sha512-BSb/KcyBHmUQwINrgtzo6jiH0HlGFmrUy33vO6unmceuVKTEyL2q+P0fQq2oB5hvXVWOEUhxB2QvlkZluvUEmg==",
"version": "5.10.2",
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.10.2.tgz",
"integrity": "sha512-xOF/2gVJZTfjTxbo4BDj9RtQq/HFnrrKdtem4JkyRLnwsRz2UDTg8gA1/et10fBx5RxmZD9bYVGST69W8ME5OQ==",
"license": "MIT",
"dependencies": {
"ajv": "~8.13.0",
@ -1554,12 +1555,12 @@
}
},
"node_modules/@rushstack/terminal": {
"version": "0.14.4",
"resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.14.4.tgz",
"integrity": "sha512-NxACqERW0PHq8Rpq1V6v5iTHEwkRGxenjEW+VWqRYQ8T9puUzgmGHmEZUaUEDHAe9Qyvp0/Ew04sAiQw9XjhJg==",
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.14.5.tgz",
"integrity": "sha512-TEOpNwwmsZVrkp0omnuTUTGZRJKTr6n6m4OITiNjkqzLAkcazVpwR1SOtBg6uzpkIBLgrcNHETqI8rbw3uiUfw==",
"license": "MIT",
"dependencies": {
"@rushstack/node-core-library": "5.10.1",
"@rushstack/node-core-library": "5.10.2",
"supports-color": "~8.1.1"
},
"peerDependencies": {
@ -1587,12 +1588,12 @@
}
},
"node_modules/@rushstack/ts-command-line": {
"version": "4.23.2",
"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.23.2.tgz",
"integrity": "sha512-JJ7XZX5K3ThBBva38aomgsPv1L7FV6XmSOcR6HtM7HDFZJkepqT65imw26h9ggGqMjsY0R9jcl30tzKcVj9aOQ==",
"version": "4.23.3",
"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.23.3.tgz",
"integrity": "sha512-HazKL8fv4HMQMzrKJCrOrhyBPPdzk7iajUXgsASwjQ8ROo1cmgyqxt/k9+SdmrNLGE1zATgRqMUH3s/6smbRMA==",
"license": "MIT",
"dependencies": {
"@rushstack/terminal": "0.14.4",
"@rushstack/terminal": "0.14.5",
"@types/argparse": "1.0.38",
"argparse": "~1.0.9",
"string-argv": "~0.3.1"
@ -1614,14 +1615,14 @@
"license": "MIT"
},
"node_modules/@ts-morph/common": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.25.0.tgz",
"integrity": "sha512-kMnZz+vGGHi4GoHnLmMhGNjm44kGtKUXGnOvrKmMwAuvNjM/PgKVGfUnL7IDvK7Jb2QQ82jq3Zmp04Gy+r3Dkg==",
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.26.0.tgz",
"integrity": "sha512-/RmKAtctStXqM5nECMQ46duT74Hoig/DBzhWXGHcodlDNrgRbsbwwHqSKFNbca6z9Xt/CUWMeXOsC9QEN1+rqw==",
"license": "MIT",
"dependencies": {
"fast-glob": "^3.3.2",
"minimatch": "^9.0.4",
"path-browserify": "^1.0.1",
"tinyglobby": "^0.2.9"
"path-browserify": "^1.0.1"
}
},
"node_modules/@tsconfig/node10": {
@ -1682,12 +1683,6 @@
"@types/node": "*"
}
},
"node_modules/@types/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
"license": "MIT"
},
"node_modules/@types/cors": {
"version": "2.8.17",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
@ -1731,9 +1726,9 @@
}
},
"node_modules/@types/geojson": {
"version": "7946.0.15",
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz",
"integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==",
"version": "7946.0.16",
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
"integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
"license": "MIT"
},
"node_modules/@types/http-errors": {
@ -1767,12 +1762,13 @@
"license": "MIT"
},
"node_modules/@types/jsonwebtoken": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz",
"integrity": "sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==",
"version": "9.0.8",
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.8.tgz",
"integrity": "sha512-7fx54m60nLFUVYlxAB1xpe9CBWX2vSrk50Y6ogRJ1v5xxtba7qXTg5BgYDN5dq+yuQQ9HaVlHJyAAt1/mxryFg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/ms": "*",
"@types/node": "*"
}
},
@ -1783,10 +1779,17 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/ms": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
"dev": true,
"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.16",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.16.tgz",
"integrity": "sha512-vOTpLduLkZXePLxHiHsBLp98mHGnl8RptV4YAO3HfKO5UHjDvySGbxKtpYfy8Sx5+WKcgc45qNreJJRVM3L6mw==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.19.2"
@ -1803,9 +1806,9 @@
}
},
"node_modules/@types/qs": {
"version": "6.9.17",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz",
"integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==",
"version": "6.9.18",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz",
"integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==",
"dev": true,
"license": "MIT"
},
@ -1840,21 +1843,21 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.0.tgz",
"integrity": "sha512-NggSaEZCdSrFddbctrVjkVZvFC6KGfKfNK0CU7mNK/iKHGKbzT4Wmgm08dKpcZECBu9f5FypndoMyRHkdqfT1Q==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.21.0.tgz",
"integrity": "sha512-eTH+UOR4I7WbdQnG4Z48ebIA6Bgi7WO8HvFEneeYBxG8qCOYgTOFPSg6ek9ITIDvGjDQzWHcoWHCDO2biByNzA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.19.0",
"@typescript-eslint/type-utils": "8.19.0",
"@typescript-eslint/utils": "8.19.0",
"@typescript-eslint/visitor-keys": "8.19.0",
"@typescript-eslint/scope-manager": "8.21.0",
"@typescript-eslint/type-utils": "8.21.0",
"@typescript-eslint/utils": "8.21.0",
"@typescript-eslint/visitor-keys": "8.21.0",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
"ts-api-utils": "^1.3.0"
"ts-api-utils": "^2.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -1870,16 +1873,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.0.tgz",
"integrity": "sha512-6M8taKyOETY1TKHp0x8ndycipTVgmp4xtg5QpEZzXxDhNvvHOJi5rLRkLr8SK3jTgD5l4fTlvBiRdfsuWydxBw==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.21.0.tgz",
"integrity": "sha512-Wy+/sdEH9kI3w9civgACwabHbKl+qIOu0uFZ9IMKzX3Jpv9og0ZBJrZExGrPpFAY7rWsXuxs5e7CPPP17A4eYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.19.0",
"@typescript-eslint/types": "8.19.0",
"@typescript-eslint/typescript-estree": "8.19.0",
"@typescript-eslint/visitor-keys": "8.19.0",
"@typescript-eslint/scope-manager": "8.21.0",
"@typescript-eslint/types": "8.21.0",
"@typescript-eslint/typescript-estree": "8.21.0",
"@typescript-eslint/visitor-keys": "8.21.0",
"debug": "^4.3.4"
},
"engines": {
@ -1895,14 +1898,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.0.tgz",
"integrity": "sha512-hkoJiKQS3GQ13TSMEiuNmSCvhz7ujyqD1x3ShbaETATHrck+9RaDdUbt+osXaUuns9OFwrDTTrjtwsU8gJyyRA==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.21.0.tgz",
"integrity": "sha512-G3IBKz0/0IPfdeGRMbp+4rbjfSSdnGkXsM/pFZA8zM9t9klXDnB/YnKOBQ0GoPmoROa4bCq2NeHgJa5ydsQ4mA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.19.0",
"@typescript-eslint/visitor-keys": "8.19.0"
"@typescript-eslint/types": "8.21.0",
"@typescript-eslint/visitor-keys": "8.21.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -1913,16 +1916,16 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.0.tgz",
"integrity": "sha512-TZs0I0OSbd5Aza4qAMpp1cdCYVnER94IziudE3JU328YUHgWu9gwiwhag+fuLeJ2LkWLXI+F/182TbG+JaBdTg==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.21.0.tgz",
"integrity": "sha512-95OsL6J2BtzoBxHicoXHxgk3z+9P3BEcQTpBKriqiYzLKnM2DeSqs+sndMKdamU8FosiadQFT3D+BSL9EKnAJQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/typescript-estree": "8.19.0",
"@typescript-eslint/utils": "8.19.0",
"@typescript-eslint/typescript-estree": "8.21.0",
"@typescript-eslint/utils": "8.21.0",
"debug": "^4.3.4",
"ts-api-utils": "^1.3.0"
"ts-api-utils": "^2.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -1937,9 +1940,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.0.tgz",
"integrity": "sha512-8XQ4Ss7G9WX8oaYvD4OOLCjIQYgRQxO+qCiR2V2s2GxI9AUpo7riNwo6jDhKtTcaJjT8PY54j2Yb33kWtSJsmA==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.21.0.tgz",
"integrity": "sha512-PAL6LUuQwotLW2a8VsySDBwYMm129vFm4tMVlylzdoTybTHaAi0oBp7Ac6LhSrHHOdLM3efH+nAR6hAWoMF89A==",
"dev": true,
"license": "MIT",
"engines": {
@ -1951,20 +1954,20 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.0.tgz",
"integrity": "sha512-WW9PpDaLIFW9LCbucMSdYUuGeFUz1OkWYS/5fwZwTA+l2RwlWFdJvReQqMUMBw4yJWJOfqd7An9uwut2Oj8sLw==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.21.0.tgz",
"integrity": "sha512-x+aeKh/AjAArSauz0GiQZsjT8ciadNMHdkUSwBB9Z6PrKc/4knM4g3UfHml6oDJmKC88a6//cdxnO/+P2LkMcg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.19.0",
"@typescript-eslint/visitor-keys": "8.19.0",
"@typescript-eslint/types": "8.21.0",
"@typescript-eslint/visitor-keys": "8.21.0",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
"ts-api-utils": "^1.3.0"
"ts-api-utils": "^2.0.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -1978,16 +1981,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.0.tgz",
"integrity": "sha512-PTBG+0oEMPH9jCZlfg07LCB2nYI0I317yyvXGfxnvGvw4SHIOuRnQ3kadyyXY6tGdChusIHIbM5zfIbp4M6tCg==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.21.0.tgz",
"integrity": "sha512-xcXBfcq0Kaxgj7dwejMbFyq7IOHgpNMtVuDveK7w3ZGwG9owKzhALVwKpTF2yrZmEwl9SWdetf3fxNzJQaVuxw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "8.19.0",
"@typescript-eslint/types": "8.19.0",
"@typescript-eslint/typescript-estree": "8.19.0"
"@typescript-eslint/scope-manager": "8.21.0",
"@typescript-eslint/types": "8.21.0",
"@typescript-eslint/typescript-estree": "8.21.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@ -2002,13 +2005,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.0.tgz",
"integrity": "sha512-mCFtBbFBJDCNCWUl5y6sZSCHXw1DEFEk3c/M3nRK2a4XUB8StGFtmcEMizdjKuBzB6e/smJAAWYug3VrdLMr1w==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.21.0.tgz",
"integrity": "sha512-BkLMNpdV6prozk8LlyK/SOoWLmUFi+ZD+pcqti9ILCbVvHGk1ui1g4jJOc2WDLaeExz2qWwojxlPce5PljcT3w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.19.0",
"@typescript-eslint/types": "8.21.0",
"eslint-visitor-keys": "^4.2.0"
},
"engines": {
@ -2322,6 +2325,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/async-function": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/atomic-sleep": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
@ -2457,9 +2470,9 @@
"license": "BSD-3-Clause"
},
"node_modules/bullmq": {
"version": "5.34.6",
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.6.tgz",
"integrity": "sha512-pRCYyO9RlkQWxdmKlrNnUthyFwurYXRYLVXD1YIx+nCCdhAOiHatD8FDHbsT/w2I31c0NWoMcfZiIGuipiF7Lg==",
"version": "5.37.0",
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.37.0.tgz",
"integrity": "sha512-h/wf979+9uROyYpB8oTE44Py6JERCluCSd+ZFpCZlPsYh+wxAkqrfHsHHHKBgsNJp9odWLIY4SG+280EXzXiCQ==",
"license": "MIT",
"dependencies": {
"cron-parser": "^4.9.0",
@ -3029,17 +3042,16 @@
}
},
"node_modules/engine.io": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz",
"integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==",
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.3.tgz",
"integrity": "sha512-2hkLItQMBkoYSagneiisupWGvsQlWXqzhSMvsjaM8GYbnfUsX7tzYQq9QARnate5LRedVTX+MbkSZAANAr3NtQ==",
"license": "MIT",
"dependencies": {
"@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.7.2",
"cookie": "~1.0.2",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
@ -3059,12 +3071,12 @@
}
},
"node_modules/engine.io/node_modules/cookie": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
"node": ">=18"
}
},
"node_modules/engine.io/node_modules/debug": {
@ -3169,9 +3181,9 @@
}
},
"node_modules/es-object-atoms": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@ -3293,19 +3305,19 @@
}
},
"node_modules/eslint": {
"version": "9.17.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz",
"integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==",
"version": "9.19.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz",
"integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.19.0",
"@eslint/core": "^0.9.0",
"@eslint/core": "^0.10.0",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "9.17.0",
"@eslint/plugin-kit": "^0.2.3",
"@eslint/js": "9.19.0",
"@eslint/plugin-kit": "^0.2.5",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.1",
@ -3813,9 +3825,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==",
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
"funding": [
{
"type": "github",
@ -3947,13 +3959,19 @@
"license": "ISC"
},
"node_modules/for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz",
"integrity": "sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-callable": "^1.1.3"
"is-callable": "^1.2.7"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/forwarded": {
@ -3975,9 +3993,9 @@
}
},
"node_modules/fs-extra": {
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
"integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
"version": "11.3.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
"integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
@ -4127,9 +4145,9 @@
}
},
"node_modules/get-tsconfig": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz",
"integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==",
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz",
"integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -4492,12 +4510,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.1.1",
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
"integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"async-function": "^1.0.0",
"call-bound": "^1.0.3",
"get-proto": "^1.0.1",
"has-tostringtag": "^1.0.2",
@ -5188,9 +5207,9 @@
"license": "MIT"
},
"node_modules/long": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==",
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz",
"integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==",
"license": "Apache-2.0"
},
"node_modules/lru-cache": {
@ -5246,9 +5265,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.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz",
"integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
@ -5331,9 +5350,9 @@
}
},
"node_modules/mikro-orm": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.2.tgz",
"integrity": "sha512-PyivHOk8wlN16fzFv8fTfMXrTj9nWQ6Cnzi49twsVHVr1HUQuhFKMJUV/n0HlEdYBiQj0UK1pN4wNGo7h3nNGQ==",
"version": "6.4.4",
"resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.4.tgz",
"integrity": "sha512-nHV0lZnPUwidqeVyJwBegKDW9KwTxfH5yNp0aGSud9EI0mFkjK/M4EVfh+vwg/y6gdSIu9UnwDORYP2hJw96dQ==",
"license": "MIT",
"engines": {
"node": ">= 18.12.0"
@ -5435,9 +5454,9 @@
}
},
"node_modules/mysql2": {
"version": "3.11.5",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.5.tgz",
"integrity": "sha512-0XFu8rUmFN9vC0ME36iBvCUObftiMHItrYFhlCRvFWbLgpNqtC4Br/NmZX1HNCszxT0GGy5QtP+k3Q3eCJPaYA==",
"version": "3.12.0",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.12.0.tgz",
"integrity": "sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==",
"license": "MIT",
"dependencies": {
"aws-ssl-profiles": "^1.1.1",
@ -5525,9 +5544,9 @@
}
},
"node_modules/nodemailer": {
"version": "6.9.16",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz",
"integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==",
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz",
"integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==",
"license": "MIT-0",
"engines": {
"node": ">=6.0.0"
@ -5992,14 +6011,14 @@
}
},
"node_modules/prisma": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.1.0.tgz",
"integrity": "sha512-aFI3Yi+ApUxkwCJJwyQSwpyzUX7YX3ihzuHNHOyv4GJg3X5tQsmRaJEnZ+ZyfHpMtnyahhmXVfbTZ+lS8ZtfKw==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.2.1.tgz",
"integrity": "sha512-hhyM0H13pQleQ+br4CkzGizS5I0oInoeTw3JfLw1BRZduBSQxPILlJLwi+46wZzj9Je7ndyQEMGw/n5cN2fknA==",
"devOptional": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@prisma/engines": "6.1.0"
"@prisma/engines": "6.2.1"
},
"bin": {
"prisma": "build/index.js"
@ -7019,45 +7038,6 @@
"node": ">=8"
}
},
"node_modules/tinyglobby": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz",
"integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==",
"license": "MIT",
"dependencies": {
"fdir": "^6.4.2",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/tinyglobby/node_modules/fdir": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz",
"integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==",
"license": "MIT",
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -7090,25 +7070,25 @@
}
},
"node_modules/ts-api-utils": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
"integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz",
"integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=16"
"node": ">=18.12"
},
"peerDependencies": {
"typescript": ">=4.2.0"
"typescript": ">=4.8.4"
}
},
"node_modules/ts-morph": {
"version": "24.0.0",
"resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-24.0.0.tgz",
"integrity": "sha512-2OAOg/Ob5yx9Et7ZX4CvTCc0UFoZHwLEJ+dpDPSUi5TgwwlTlX47w+iFRrEwzUZwYACjq83cgjS/Da50Ga37uw==",
"version": "25.0.0",
"resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-25.0.0.tgz",
"integrity": "sha512-ERPTUVO5qF8cEGJgAejGOsCVlbk8d0SDyiJsucKQT5XgqoZslv0Qml+gnui6Yy6o+uQqw5SestyW2HvlVtT/Sg==",
"license": "MIT",
"dependencies": {
"@ts-morph/common": "~0.25.0",
"@ts-morph/common": "~0.26.0",
"code-block-writer": "^13.0.3"
}
},
@ -7210,9 +7190,9 @@
}
},
"node_modules/type-fest": {
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.31.0.tgz",
"integrity": "sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==",
"version": "4.33.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.33.0.tgz",
"integrity": "sha512-s6zVrxuyKbbAsSAD5ZPTB77q4YIdRctkTbJ2/Dqlinwz+8ooH2gd+YA7VA6Pa93KML9GockVvoxjZ2vHP+mu8g==",
"license": "(MIT OR CC0-1.0)",
"engines": {
"node": ">=16"
@ -7313,9 +7293,9 @@
}
},
"node_modules/typescript": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",

View File

@ -1,4 +1,6 @@
import { Request, Response } from 'express'
import fs from 'fs'
import { Response } from 'express'
import Logger, { LoggerType } from '#application/logger'
@ -19,4 +21,18 @@ export abstract class BaseController {
message
})
}
protected sendFile(res: Response, filePath: string) {
if (!fs.existsSync(filePath)) {
this.logger.error(`File not found: ${filePath}`)
return this.sendError(res, 'Asset not found', 404)
}
res.sendFile(filePath, (error) => {
if (error) {
this.logger.error('Error sending file:' + error)
this.sendError(res, 'Error downloading the asset', 500)
}
})
}
}

View File

@ -61,8 +61,8 @@ export class LogReader {
})
stream.on('data', (data) => {
console.log(`[${filename}]`);
console.log(data.toString()); //
console.log(`[${filename}]`)
console.log(data.toString()) //
})
currentPosition = newPosition

View File

@ -37,7 +37,6 @@ export type AssetData = {
updatedAt: Date
originX?: number
originY?: number
isAnimated?: boolean
frameRate?: number
frameWidth?: number
frameHeight?: number
@ -46,8 +45,11 @@ export type AssetData = {
export type WorldSettings = {
date: Date
isRainEnabled: boolean
isFogEnabled: boolean
weatherState: WeatherState
}
export type WeatherState = {
rainPercentage: number
fogDensity: number
}

View File

@ -89,8 +89,6 @@ export default class InitCommand extends BaseCommand {
])
.setOriginX(0)
.setOriginY(0)
.setIsAnimated(false)
.setIsLooping(false)
.setFrameWidth(64)
.setFrameHeight(94)
.setFrameRate(0)
@ -105,8 +103,6 @@ export default class InitCommand extends BaseCommand {
])
.setOriginX(0)
.setOriginY(0)
.setIsAnimated(false)
.setIsLooping(false)
.setFrameWidth(64)
.setFrameHeight(94)
.setFrameRate(0)
@ -124,8 +120,6 @@ export default class InitCommand extends BaseCommand {
])
.setOriginX(0)
.setOriginY(0)
.setIsAnimated(true)
.setIsLooping(false)
.setFrameWidth(64)
.setFrameHeight(94)
.setFrameRate(7)
@ -143,8 +137,6 @@ export default class InitCommand extends BaseCommand {
])
.setOriginX(0)
.setOriginY(0)
.setIsAnimated(true)
.setIsLooping(false)
.setFrameWidth(64)
.setFrameHeight(94)
.setFrameRate(7)
@ -175,8 +167,6 @@ export default class InitCommand extends BaseCommand {
])
.setOriginX(0.5)
.setOriginY(5.34)
.setIsAnimated(false)
.setIsLooping(false)
.setFrameWidth(64)
.setFrameHeight(18)
.setFrameRate(0)
@ -191,8 +181,6 @@ export default class InitCommand extends BaseCommand {
])
.setOriginX(0.5)
.setOriginY(4.34)
.setIsAnimated(false)
.setIsLooping(false)
.setFrameWidth(64)
.setFrameHeight(22)
.setFrameRate(0)
@ -216,8 +204,6 @@ export default class InitCommand extends BaseCommand {
sprites: ['data:image/png;base64,...'],
originX: 0,
originY: 0,
isAnimated: false,
isLooping: false,
frameWidth: 64,
frameHeight: 94,
frameRate: 0
@ -259,8 +245,8 @@ export default class InitCommand extends BaseCommand {
.setName('root')
.setRole('gm')
.setMap((await this.mapRepository.getFirst())!)
.setCharacterType((await this.characterTypeRepository.getFirst()) ?? undefined)
.setCharacterHair((await this.characterHairRepository.getFirst()) ?? undefined)
.setCharacterType(await this.characterTypeRepository.getFirst())
.setCharacterHair(await this.characterHairRepository.getFirst())
.save()
}
}

119
src/controllers/cache.ts Normal file
View File

@ -0,0 +1,119 @@
import { Request, Response } from 'express'
import { BaseController } from '#application/base/baseController'
import CharacterHairRepository from '#repositories/characterHairRepository'
import CharacterTypeRepository from '#repositories/characterTypeRepository'
import MapObjectRepository from '#repositories/mapObjectRepository'
import MapRepository from '#repositories/mapRepository'
import SpriteRepository from '#repositories/spriteRepository'
import TileRepository from '#repositories/tileRepository'
export class CacheController extends BaseController {
/**
* Serve a list of tiles and send as JSON
* @param req
* @param res
*/
public async tiles(req: Request, res: Response) {
const items: any[] = []
const tileRepository = new TileRepository()
const tiles = await tileRepository.getAll()
for (const tile of tiles) {
items.push(await tile.cache())
}
return this.sendSuccess(res, items)
}
/**
* Serve a list of maps and send as JSON
* @param req
* @param res
*/
public async maps(req: Request, res: Response) {
const items: any[] = []
const mapRepository = new MapRepository()
const maps = await mapRepository.getAll()
for (const map of maps) {
items.push(await map.cache())
}
return this.sendSuccess(res, items)
}
/**
* Serve a list of map objects and send as JSON
* @param req
* @param res
*/
public async mapObjects(req: Request, res: Response) {
const items: any[] = []
const mapObjectRepository = new MapObjectRepository()
const mapObjects = await mapObjectRepository.getAll()
for (const mapObject of mapObjects) {
items.push(await mapObject.cache())
}
return this.sendSuccess(res, items)
}
/**
* Serve a list of character hairs and send as JSON
* @param req
* @param res
*/
public async characterHair(req: Request, res: Response) {
const items: any[] = []
const characterHairRepository = new CharacterHairRepository()
const characterHairs = await characterHairRepository.getAll()
for (const characterHair of characterHairs) {
items.push(await characterHair.cache())
}
return this.sendSuccess(res, items)
}
/**
* Serve a list of character types and send as JSON
* @param req
* @param res
*/
public async characterTypes(req: Request, res: Response) {
const items: any[] = []
const characterTypeRepository = new CharacterTypeRepository()
const characterTypes = await characterTypeRepository.getAll()
for (const characterType of characterTypes) {
items.push(await characterType.cache())
}
return this.sendSuccess(res, items)
}
/**
* Serve a list of sprites and send as JSON
* @param req
* @param res
*/
public async sprites(req: Request, res: Response) {
const items: any[] = []
const spriteRepository = new SpriteRepository()
const sprites = await spriteRepository.getAll()
for (const sprite of sprites) {
items.push(await sprite.cache())
}
return this.sendSuccess(res, items)
}
}

View File

@ -0,0 +1,19 @@
import { Request, Response } from 'express'
import { BaseController } from '#application/base/baseController'
import Storage from '#application/storage'
export class TexturesController extends BaseController {
/**
* Download texture
* @param req
* @param res
*/
public async download(req: Request, res: Response) {
const { type, spriteId, file } = req.params
const texture = type === 'sprites' && spriteId ? Storage.getPublicPath(type, spriteId, file) : Storage.getPublicPath(type, file)
this.sendFile(res, texture)
}
}

View File

@ -12,7 +12,6 @@ import { Chat } from '#entities/chat'
import { Map } from '#entities/map'
import { User } from '#entities/user'
export class BaseCharacter extends BaseEntity {
@PrimaryKey()
id = randomUUID()
@ -47,10 +46,10 @@ export class BaseCharacter extends BaseEntity {
// Customization
@ManyToOne({ deleteRule: 'set null' })
characterType?: CharacterType | null | undefined
characterType: CharacterType | null = null
@ManyToOne({ deleteRule: 'set null' })
characterHair?: CharacterHair | null | undefined
characterHair: CharacterHair | null = null
// Inventory
@OneToMany({ mappedBy: 'character' })
@ -177,7 +176,7 @@ export class BaseCharacter extends BaseEntity {
return this.rotation
}
setCharacterType(characterType: CharacterType | null | undefined) {
setCharacterType(characterType: CharacterType | null) {
this.characterType = characterType
return this
}
@ -186,7 +185,7 @@ export class BaseCharacter extends BaseEntity {
return this.characterType
}
setCharacterHair(characterHair: CharacterHair | null | undefined) {
setCharacterHair(characterHair: CharacterHair | null) {
this.characterHair = characterHair
return this
}

View File

@ -2,7 +2,6 @@ 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'

View File

@ -2,7 +2,6 @@ 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'
@ -25,6 +24,12 @@ export class BaseCharacterHair extends BaseEntity {
@ManyToOne()
sprite?: Sprite
@Property()
createdAt = new Date()
@Property()
updatedAt = new Date()
setId(id: UUID) {
this.id = id
return this
@ -69,4 +74,22 @@ export class BaseCharacterHair extends BaseEntity {
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
}
}

View File

@ -8,7 +8,6 @@ import { Character } from '#entities/character'
import { CharacterEquipment } from '#entities/characterEquipment'
import { Item } from '#entities/item'
export class BaseCharacterItem extends BaseEntity {
@PrimaryKey()
id = randomUUID()

View File

@ -2,7 +2,6 @@ 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'

View File

@ -7,7 +7,6 @@ import { UUID } from '#application/types'
import { Character } from '#entities/character'
import { Map } from '#entities/map'
export class BaseChat extends BaseEntity {
@PrimaryKey()
id = randomUUID()

View File

@ -2,7 +2,6 @@ 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'

View File

@ -2,7 +2,6 @@ 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 { Map } from '#entities/map'

View File

@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto'
import { Entity, Enum, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'
import { BaseEntity } from '#application/base/baseEntity'
import { MapEventTileType } from '#application/enums'
import { UUID } from '#application/types'

View File

@ -7,7 +7,6 @@ import { UUID } from '#application/types'
import { Map } from '#entities/map'
import { MapEventTile } from '#entities/mapEventTile'
export class BaseMapEventTileTeleport extends BaseEntity {
@PrimaryKey()
id = randomUUID()

View File

@ -21,9 +21,6 @@ export class BaseMapObject extends BaseEntity {
@Property({ type: 'decimal', precision: 10, scale: 2 })
originY = 0
@Property()
isAnimated = false
@Property()
frameRate = 0
@ -84,15 +81,6 @@ export class BaseMapObject extends BaseEntity {
return this.originY
}
setIsAnimated(isAnimated: boolean) {
this.isAnimated = isAnimated
return this
}
getIsAnimated() {
return this.isAnimated
}
setFrameRate(frameRate: number) {
this.frameRate = frameRate
return this

View File

@ -2,7 +2,6 @@ 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'

View File

@ -2,7 +2,6 @@ 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 { Map } from '#entities/map'
@ -20,9 +19,6 @@ export class BasePlacedMapObject extends BaseEntity {
@ManyToOne({ deleteRule: 'cascade', eager: true })
mapObject!: MapObject
@Property()
depth = 0
@Property()
isRotated = false
@ -59,15 +55,6 @@ export class BasePlacedMapObject extends BaseEntity {
return this.mapObject
}
setDepth(depth: number) {
this.depth = depth
return this
}
getDepth() {
return this.depth
}
setIsRotated(isRotated: boolean) {
this.isRotated = isRotated
return this

View File

@ -2,7 +2,6 @@ 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'

View File

@ -2,7 +2,6 @@ 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'
@ -26,12 +25,6 @@ export class BaseSpriteAction extends BaseEntity {
@Property()
originY = 0
@Property()
isAnimated = false
@Property()
isLooping = false
@Property()
frameWidth = 0
@ -95,24 +88,6 @@ export class BaseSpriteAction extends BaseEntity {
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

View File

@ -8,7 +8,6 @@ import { UUID } from '#application/types'
import { Character } from '#entities/character'
import { PasswordResetToken } from '#entities/passwordResetToken'
export class BaseUser extends BaseEntity {
@PrimaryKey()
id = randomUUID()

View File

@ -6,15 +6,9 @@ export class BaseWorld extends BaseEntity {
@PrimaryKey()
date = new Date()
@Property()
isRainEnabled = false
@Property()
rainPercentage = 0
@Property()
isFogEnabled = false
@Property()
fogDensity = 0
@ -27,15 +21,6 @@ export class BaseWorld extends BaseEntity {
return this.date
}
setIsRainEnabled(isRainEnabled: boolean) {
this.isRainEnabled = isRainEnabled
return this
}
getIsRainEnabled() {
return this.isRainEnabled
}
setRainPercentage(rainPercentage: number) {
this.rainPercentage = rainPercentage
return this
@ -45,15 +30,6 @@ export class BaseWorld extends BaseEntity {
return this.rainPercentage
}
setIsFogEnabled(isFogEnabled: boolean) {
this.isFogEnabled = isFogEnabled
return this
}
getIsFogEnabled() {
return this.isFogEnabled
}
setFogDensity(fogDensity: number) {
this.fogDensity = fogDensity
return this

View File

@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
import { BaseCharacterHair } from '#entities/base/characterHair'
@Entity()
export class CharacterHair extends BaseCharacterHair {}
export class CharacterHair extends BaseCharacterHair {
public async cache() {
try {
return this
} catch (error) {
console.error(error)
return {}
}
}
}

View File

@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
import { BaseCharacterType } from '#entities/base/characterType'
@Entity()
export class CharacterType extends BaseCharacterType {}
export class CharacterType extends BaseCharacterType {
public async cache() {
try {
return this
} catch (error) {
console.error(error)
return {}
}
}
}

View File

@ -2,5 +2,38 @@ import { Entity } from '@mikro-orm/core'
import { BaseMap } from '#entities/base/map'
export type MapCacheT = ReturnType<Map['cache']> | {}
@Entity()
export class Map extends BaseMap {}
export class Map extends BaseMap {
public async cache() {
try {
await this.getPlacedMapObjects().load()
await this.getMapEffects().load()
return {
id: this.getId(),
name: this.getName(),
width: this.getWidth(),
height: this.getHeight(),
tiles: this.getTiles(),
pvp: this.getPvp(),
updatedAt: this.getUpdatedAt(),
placedMapObjects: this.getPlacedMapObjects().map((placedMapObject) => ({
id: placedMapObject.getId(),
mapObject: placedMapObject.getMapObject().getId(),
isRotated: placedMapObject.getIsRotated(),
positionX: placedMapObject.getPositionX(),
positionY: placedMapObject.getPositionY()
})),
mapEffects: this.getMapEffects().map((mapEffect) => ({
effect: mapEffect.getEffect(),
strength: mapEffect.getStrength()
}))
}
} catch (error) {
console.error(error)
return {}
}
}
}

View File

@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
import { BaseMapObject } from '#entities/base/mapObject'
@Entity()
export class MapObject extends BaseMapObject {}
export class MapObject extends BaseMapObject {
public async cache() {
try {
return this
} catch (error) {
console.error(error)
return {}
}
}
}

View File

@ -3,4 +3,30 @@ import { Entity } from '@mikro-orm/core'
import { BaseSprite } from '#entities/base/sprite'
@Entity()
export class Sprite extends BaseSprite {}
export class Sprite extends BaseSprite {
public async cache() {
await this.getSpriteActions().load()
try {
return {
id: this.getId(),
name: this.getName(),
createdAt: this.getCreatedAt(),
updatedAt: this.getUpdatedAt(),
spriteActions: this.getSpriteActions().map((spriteAction) => ({
id: spriteAction.getId(),
action: spriteAction.getAction(),
originX: spriteAction.getOriginX(),
originY: spriteAction.getOriginY(),
frameWidth: spriteAction.getFrameWidth(),
frameHeight: spriteAction.getFrameHeight(),
frameRate: spriteAction.getFrameRate(),
frameCount: spriteAction.getSprites()?.length
}))
}
} catch (error) {
console.error(error)
return {}
}
}
}

View File

@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
import { BaseTile } from '#entities/base/tile'
@Entity()
export class Tile extends BaseTile {}
export class Tile extends BaseTile {
public async cache() {
try {
return this
} catch (error) {
console.error(error)
return {}
}
}
}

View File

@ -1,23 +0,0 @@
import { BaseEvent } from '#application/base/baseEvent'
import { CharacterHair } from '#entities/characterHair'
import CharacterHairRepository from '#repositories/characterHairRepository'
interface IPayload {}
export default class characterHairListEvent extends BaseEvent {
public listen(): void {
this.socket.on('character:hair:list', this.handleEvent.bind(this))
}
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([])
}
}
}

View File

@ -32,9 +32,6 @@ export default class CharacterConnectEvent extends BaseEvent {
return
}
// Populate character with characterType and characterHair
await this.characterRepository.getEntityManager().populate(character, ['characterType', 'characterHair'])
// Set character id
this.socket.characterId = character.id

View File

@ -12,9 +12,6 @@ export default class CharacterListEvent extends BaseEvent {
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'])
this.socket.emit('character:list', characters)
} catch (error: any) {
this.logger.error('character:list error', error.message)

View File

@ -1,6 +1,5 @@
import { BaseEvent } from '#application/base/baseEvent'
import WeatherManager from '#managers/weatherManager'
import CharacterRepository from '#repositories/characterRepository'
import ChatService from '#services/chatService'
type TypePayload = {
@ -20,7 +19,10 @@ export default class ToggleFogCommand extends BaseEvent {
// Check if character exists and is GM
if (!(await this.isCharacterGM())) return
await WeatherManager.toggleFog()
const args = ChatService.getArgs('fog', data.message)
await WeatherManager.setFogValue(args![0] ? Number(args![0]) : null);
callback(true)
} catch (error: any) {
this.logger.error('command error', error.message)
callback(false)

View File

@ -1,6 +1,5 @@
import { BaseEvent } from '#application/base/baseEvent'
import WeatherManager from '#managers/weatherManager'
import CharacterRepository from '#repositories/characterRepository'
import ChatService from '#services/chatService'
type TypePayload = {
@ -20,7 +19,10 @@ export default class ToggleRainCommand extends BaseEvent {
// Check if character exists and is GM
if (!(await this.isCharacterGM())) return
await WeatherManager.toggleRain()
let args = ChatService.getArgs('rain', data.message)
await WeatherManager.setRainValue(args![0] ? Number(args![0]) : null);
callback(true)
} catch (error: any) {
this.logger.error('command error', error.message)
callback(false)

View File

@ -29,7 +29,8 @@ export default class CharacterHairUpdateEvent extends BaseEvent {
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()
await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite).setUpdatedAt(new Date()).save()
return callback(true)
} catch (error) {
this.logger.error(`Error updating character hair: ${error instanceof Error ? error.message : String(error)}`)

View File

@ -8,7 +8,6 @@ type Payload = {
tags: string[]
originX: number
originY: number
isAnimated: boolean
frameRate: number
frameWidth: number
frameHeight: number
@ -33,7 +32,6 @@ export default class MapObjectUpdateEvent extends BaseEvent {
.setTags(data.tags)
.setOriginX(data.originX)
.setOriginY(data.originY)
.setIsAnimated(data.isAnimated)
.setFrameRate(data.frameRate)
.setFrameWidth(data.frameWidth)
.setFrameHeight(data.frameHeight)

View File

@ -369,8 +369,6 @@ export default class SpriteUpdateEvent extends BaseEvent {
sprites: action.sprites,
originX: action.originX,
originY: action.originY,
isAnimated: action.isAnimated,
isLooping: action.isLooping,
frameWidth: action.frameWidth,
frameHeight: action.frameHeight,
frameRate: action.frameRate

View File

@ -1,6 +1,5 @@
import { BaseEvent } from '#application/base/baseEvent'
import { Map } from '#entities/map'
import MapRepository from '#repositories/mapRepository'
import { Map, MapCacheT } from '#entities/map'
type Payload = {
name: string
@ -13,11 +12,11 @@ export default class MapCreateEvent extends BaseEvent {
this.socket.on('gm:map:create', this.handleEvent.bind(this))
}
private async handleEvent(data: Payload, callback: (response: Map[]) => void): Promise<void> {
private async handleEvent(data: Payload, callback: (response: MapCacheT | false) => 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.`)
this.logger.info(`GM ${(await this.getCharacter())!.getId()} has created a new map via map editor.`)
const map = new Map()
await map
@ -27,14 +26,11 @@ export default class MapCreateEvent extends BaseEvent {
.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)
return callback(await map.cache())
} catch (error: any) {
this.logger.error('gm:map:create error', error.message)
this.socket.emit('notification', { message: 'Failed to create map.' })
return callback([])
return callback(false)
}
}
}

View File

@ -1,27 +0,0 @@
import { BaseEvent } from '#application/base/baseEvent'
import { Map } from '#entities/map'
import MapRepository from '#repositories/mapRepository'
interface IPayload {}
export default class MapListEvent extends BaseEvent {
public listen(): void {
this.socket.on('gm:map:list', this.handleEvent.bind(this))
}
private async handleEvent(data: IPayload, callback: (response: Map[]) => void): Promise<void> {
try {
if (!(await this.isCharacterGM())) return
this.logger.info(`User ${(await this.getCharacter())!.getId()} has listed maps via map editor.`)
const mapRepository = new MapRepository()
const maps = await mapRepository.getAll()
return callback(maps)
} catch (error: any) {
this.logger.error('gm:map:list error', error.message)
return callback([])
}
}
}

View File

@ -68,6 +68,7 @@ export default class MapUpdateEvent extends BaseEvent {
}
}
// Remove map event tiles and placed map objects that are out of bounds
data.mapEventTiles = data.mapEventTiles.filter((tile) => tile.positionX >= 0 && tile.positionX < data.width && tile.positionY >= 0 && tile.positionY < data.height)
data.placedMapObjects = data.placedMapObjects.filter((obj) => obj.positionX >= 0 && obj.positionX < data.width && obj.positionY >= 0 && obj.positionY < data.height)
@ -95,13 +96,7 @@ export default class MapUpdateEvent extends BaseEvent {
// Create and add new map objects
for (const object of data.placedMapObjects) {
const mapObject = new PlacedMapObject()
.setMapObject(object.mapObject)
.setDepth(object.depth)
.setIsRotated(object.isRotated)
.setPositionX(object.positionX)
.setPositionY(object.positionY)
.setMap(map)
const mapObject = new PlacedMapObject().setMapObject(object.mapObject).setIsRotated(object.isRotated).setPositionX(object.positionX).setPositionY(object.positionY).setMap(map)
map.placedMapObjects.add(mapObject)
}
@ -113,8 +108,6 @@ export default class MapUpdateEvent extends BaseEvent {
map.mapEffects.add(mapEffect)
}
console.log(map.getPlacedMapObjects().count())
// Update map properties
await map.setName(data.name).setWidth(data.width).setHeight(data.height).setTiles(data.tiles).setPvp(data.pvp).setUpdatedAt(new Date()).save()

View File

@ -38,7 +38,7 @@ export default class CharacterMove extends BaseEvent {
await this.moveAlongPath(mapCharacter, path)
}
private async moveAlongPath(mapCharacter: MapCharacter, path: Array<{ x: number; y: number }>): Promise<void> {
private async moveAlongPath(mapCharacter: MapCharacter, path: Array<{ positionX: number; positionY: number }>): Promise<void> {
const character = mapCharacter.getCharacter()
for (let i = 0; i < path.length - 1; i++) {
@ -47,19 +47,19 @@ export default class CharacterMove extends BaseEvent {
}
const [start, end] = [path[i], path[i + 1]]
character.setRotation(CharacterService.calculateRotation(start.x, start.y, end.x, end.y))
character.setRotation(CharacterService.calculateRotation(start.positionX, start.positionY, end.positionX, end.positionY))
const mapEventTileRepository = new MapEventTileRepository()
const mapEventTile = await mapEventTileRepository.getEventTileByMapIdAndPosition(character.getMap().getId(), Math.floor(end.x), Math.floor(end.y))
const mapEventTile = await mapEventTileRepository.getEventTileByMapIdAndPosition(character.getMap().getId(), Math.floor(end.positionX), Math.floor(end.positionY))
if (mapEventTile?.type === 'BLOCK') break
if (mapEventTile?.type === 'TELEPORT' && mapEventTile.teleport) {
await this.handleMapEventTile(mapEventTile as MapEventTileWithTeleport)
break
return
}
// Update position first
character.setPositionX(end.x).setPositionY(end.y)
character.setPositionX(end.positionX).setPositionY(end.positionY)
// Then emit with the same properties
this.io.in(character.map.id).emit('map:character:move', {

View File

@ -1,119 +0,0 @@
import fs from 'fs'
import { Request, Response } from 'express'
import { BaseController } from '#application/base/baseController'
import Database from '#application/database'
import Storage from '#application/storage'
import { AssetData, UUID } from '#application/types'
import MapRepository from '#repositories/mapRepository'
import SpriteRepository from '#repositories/spriteRepository'
import TileRepository from '#repositories/tileRepository'
export class AssetsController extends BaseController {
private readonly mapRepository = new MapRepository()
private readonly spriteRepository = new SpriteRepository()
private readonly tileRepository = new TileRepository()
/**
* List tiles
* @param req
* @param res
*/
public async listTiles(req: Request, res: Response) {
const assets: AssetData[] = []
const tiles = await this.tileRepository.getAll()
for (const tile of tiles) {
assets.push({ key: tile.getId(), data: '/assets/tiles/' + tile.getId() + '.png', group: 'tiles', updatedAt: tile.getUpdatedAt() } as AssetData)
}
return this.sendSuccess(res, assets)
}
/**
* List tiles by map
* @param req
* @param res
*/
public async listTilesByMap(req: Request, res: Response) {
const mapId = req.params.mapId as UUID
if (!mapId) {
return this.sendError(res, 'Invalid map ID', 400)
}
const map = await this.mapRepository.getById(mapId)
if (!map) {
return this.sendError(res, 'Map not found', 404)
}
const assets: AssetData[] = []
const tiles = await this.tileRepository.getByMapId(mapId)
for (const tile of tiles) {
assets.push({ key: tile.getId(), data: '/assets/tiles/' + tile.getId() + '.png', group: 'tiles', updatedAt: tile.getUpdatedAt() } as AssetData)
}
return this.sendSuccess(res, assets)
}
/**
* List sprite actions
* @param req
* @param res
*/
public async listSpriteActions(req: Request, res: Response) {
const spriteId = req.params.spriteId as UUID
if (!spriteId) {
return this.sendError(res, 'Invalid sprite ID', 400)
}
const sprite = await this.spriteRepository.getById(spriteId)
if (!sprite) {
return this.sendError(res, 'Sprite not found', 404)
}
await this.spriteRepository.getEntityManager().populate(sprite, ['spriteActions'])
const assets: AssetData[] = sprite.getSpriteActions().map((spriteAction) => ({
key: sprite.getId() + '-' + spriteAction.getAction(),
data: '/assets/sprites/' + sprite.getId() + '/' + spriteAction.getAction() + '.png',
group: spriteAction.getIsAnimated() ? 'sprite_animations' : 'sprites',
updatedAt: sprite.getUpdatedAt(),
originX: Number(spriteAction.getOriginX().toString()),
originY: Number(spriteAction.getOriginY().toString()),
isAnimated: spriteAction.getIsAnimated(),
frameRate: spriteAction.getFrameRate(),
frameWidth: spriteAction.getFrameWidth(),
frameHeight: spriteAction.getFrameHeight(),
frameCount: spriteAction.getSprites()?.length
}))
return this.sendSuccess(res, assets)
}
/**
* Download asset
* @param req
* @param res
*/
public async downloadAsset(req: Request, res: Response) {
const { type, spriteId, file } = req.params
const assetPath = type === 'sprites' && spriteId ? Storage.getPublicPath(type, spriteId, file) : Storage.getPublicPath(type, file)
if (!fs.existsSync(assetPath)) {
this.logger.error(`File not found: ${assetPath}`)
return this.sendError(res, 'Asset not found', 404)
}
res.sendFile(assetPath, (err) => {
if (err) {
this.logger.error('Error sending file:' + err)
this.sendError(res, 'Error downloading the asset', 500)
}
})
}
}

View File

@ -1,21 +1,36 @@
import cors from 'cors'
import { Application } from 'express'
import { AssetsController } from '#http/controllers/assets'
import { AuthController } from '#http/controllers/auth'
import { AvatarController } from '#http/controllers/avatar'
import config from '#application/config'
import { AuthController } from '#controllers/auth'
import { AvatarController } from '#controllers/avatar'
import { CacheController } from '#controllers/cache'
import { TexturesController } from '#controllers/textures'
/**
* HTTP manager
*/
class HttpManager {
private readonly authController: AuthController
private readonly avatarController: AvatarController
private readonly assetsController: AssetsController
constructor() {
this.authController = new AuthController()
this.avatarController = new AvatarController()
this.assetsController = new AssetsController()
}
private readonly authController: AuthController = new AuthController()
private readonly avatarController: AvatarController = new AvatarController()
private readonly texturesController: TexturesController = new TexturesController()
private readonly cacheController: CacheController = new CacheController()
/**
* Initialize HTTP manager
* @param app
*/
public async boot(app: Application) {
// Add CORS middleware
app.use(
cors({
origin: config.CLIENT_URL,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // Add supported methods
allowedHeaders: ['Content-Type', 'Authorization'], // Add allowed headers
credentials: true
})
)
// Add routes
await this.addRoutes(app)
}
@ -31,11 +46,16 @@ class HttpManager {
app.get('/avatar/:characterName', (req, res) => this.avatarController.getByName(req, res))
app.get('/avatar/s/:characterTypeId/:characterHairId?', (req, res) => this.avatarController.getByParams(req, res))
// Assets routes
app.get('/assets/list_tiles', (req, res) => this.assetsController.listTiles(req, res))
app.get('/assets/list_tiles/:mapId', (req, res) => this.assetsController.listTilesByMap(req, res))
app.get('/assets/list_sprite_actions/:spriteId', (req, res) => this.assetsController.listSpriteActions(req, res))
app.get('/assets/:type/:spriteId?/:file', (req, res) => this.assetsController.downloadAsset(req, res))
// Download texture file
app.get('/textures/:type/:spriteId?/:file', (req, res) => this.texturesController.download(req, res))
// Cache routes
app.get('/cache/tiles', (req, res) => this.cacheController.tiles(req, res))
app.get('/cache/maps', (req, res) => this.cacheController.maps(req, res))
app.get('/cache/map_objects', (req, res) => this.cacheController.mapObjects(req, res))
app.get('/cache/sprites', (req, res) => this.cacheController.sprites(req, res))
app.get('/cache/character_types', (req, res) => this.cacheController.characterTypes(req, res))
app.get('/cache/character_hair', (req, res) => this.cacheController.characterHair(req, res))
}
}

View File

@ -5,7 +5,6 @@ import { pathToFileURL } from 'url'
import { Application } from 'express'
import { Server as SocketServer } from 'socket.io'
import config from '#application/config'
import Logger, { LoggerType } from '#application/logger'
import Storage from '#application/storage'
import { TSocket, UUID } from '#application/types'
@ -19,14 +18,7 @@ class SocketManager {
* Initialize Socket.IO server
*/
public async boot(app: Application, http: HTTPServer): Promise<void> {
this.io = new SocketServer(http, {
cors: {
origin: config.CLIENT_URL,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
}
})
this.io = new SocketServer(http)
// Apply authentication middleware
this.io.use(Authentication)

View File

@ -6,9 +6,7 @@ import SocketManager from '#managers/socketManager'
import WorldRepository from '#repositories/worldRepository'
type WeatherState = {
isRainEnabled: boolean
rainPercentage: number
isFogEnabled: boolean
fogDensity: number
}
@ -26,9 +24,7 @@ class WeatherManager {
private intervalId: NodeJS.Timeout | null = null
private weatherState: WeatherState = {
isRainEnabled: false,
rainPercentage: 0,
isFogEnabled: false,
fogDensity: 0
}
@ -43,18 +39,31 @@ class WeatherManager {
return { ...this.weatherState }
}
public async toggleRain(): Promise<void> {
this.updateWeatherProperty('rain')
public randomWeatherValue(type: 'rain' | 'fog' ) {
switch (type) {
case 'rain':
return this.getRandomNumber(WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.min, WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.max)
case 'fog':
return this.getRandomNumber(WeatherManager.CONFIG.FOG_DENSITY_RANGE.min, WeatherManager.CONFIG.FOG_DENSITY_RANGE.max)
}
}
public async setRainValue(value : number | null): Promise<void> {
if (value === null) {
value = this.randomWeatherValue('rain')
}
this.updateWeatherProperty('rain', value)
await this.saveAndEmitWeather()
}
public async toggleFog(): Promise<void> {
this.updateWeatherProperty('fog')
await this.saveAndEmitWeather()
public async setFogValue(value : number | null): Promise<void> {
if (value === null) {
value = this.randomWeatherValue('fog')
}
public cleanup(): void {
this.intervalId && clearInterval(this.intervalId)
this.updateWeatherProperty('fog', value)
await this.saveAndEmitWeather()
}
private async loadWeather(): Promise<void> {
@ -63,9 +72,7 @@ class WeatherManager {
const world = await worldRepository.getFirst()
if (world) {
this.weatherState = {
isRainEnabled: world.isRainEnabled,
rainPercentage: world.rainPercentage,
isFogEnabled: world.isFogEnabled,
fogDensity: world.fogDensity
}
}
@ -83,22 +90,20 @@ class WeatherManager {
private updateRandomWeather(): void {
if (Math.random() < WeatherManager.CONFIG.RAIN_CHANCE) {
this.updateWeatherProperty('rain')
this.updateWeatherProperty('rain', this.randomWeatherValue('rain') )
}
if (Math.random() < WeatherManager.CONFIG.FOG_CHANCE) {
this.updateWeatherProperty('fog')
this.updateWeatherProperty('fog', this.randomWeatherValue('fog'))
}
}
private updateWeatherProperty(type: 'rain' | 'fog'): void {
private updateWeatherProperty(type: 'rain' | 'fog', value: number): void {
if (type === 'rain') {
this.weatherState.isRainEnabled = !this.weatherState.isRainEnabled
this.weatherState.rainPercentage = this.weatherState.isRainEnabled ? this.getRandomNumber(WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.min, WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.max) : 0
this.weatherState.rainPercentage = value
}
if (type === 'fog') {
this.weatherState.isFogEnabled = !this.weatherState.isFogEnabled
this.weatherState.fogDensity = this.weatherState.isFogEnabled ? this.getRandomNumber(WeatherManager.CONFIG.FOG_DENSITY_RANGE.min, WeatherManager.CONFIG.FOG_DENSITY_RANGE.max) : 0
this.weatherState.fogDensity = value
}
}
@ -118,10 +123,9 @@ class WeatherManager {
let world = await worldRepository.getFirst()
if (!world) world = new World()
//the data model still contains the booleans
await world
.setIsRainEnabled(this.weatherState.isRainEnabled)
.setRainPercentage(this.weatherState.rainPercentage)
.setIsFogEnabled(this.weatherState.isFogEnabled)
.setFogDensity(this.weatherState.fogDensity)
.save()
} catch (error) {

View File

@ -35,7 +35,6 @@ class LoadedMap {
}
public getCharactersInMap(): MapCharacter[] {
console.log(this.characters)
return this.characters
}

View File

@ -9,7 +9,7 @@ import TeleportService from '#services/teleportService'
class MapCharacter {
public readonly character: Character
public isMoving: boolean = false
public currentPath: Array<{ x: number; y: number }> | null = null
public currentPath: Array<{ positionX: number; positionY: number }> | null = null
constructor(character: Character) {
this.character = character

View File

@ -19,11 +19,7 @@ class MapEventTileRepository extends BaseRepository {
async getEventTileByMapIdAndPosition(mapId: UUID, positionX: number, positionY: number) {
try {
const repository = this.getEntityManager().getRepository(MapEventTile)
const result = await repository.findOne({
map: mapId,
positionX: positionX,
positionY: positionY
})
const result = await repository.findOne({ map: mapId, positionX: positionX, positionY: positionY })
if (result) result.setEntityManager(this.getEntityManager())
return result

View File

@ -7,7 +7,7 @@ import SocketManager from '#managers/socketManager'
import CharacterRepository from '#repositories/characterRepository'
import MapRepository from '#repositories/mapRepository'
type Position = { x: number; y: number }
type Position = { positionX: number; positionY: number }
export type Node = Position & { parent?: Node; g: number; h: number; f: number }
class CharacterService extends BaseService {
@ -33,13 +33,13 @@ class CharacterService extends BaseService {
}
const start: Position = {
x: Math.floor(character.positionX),
y: Math.floor(character.positionY)
positionX: Math.floor(character.positionX),
positionY: Math.floor(character.positionY)
}
const end: Position = {
x: Math.floor(targetX),
y: Math.floor(targetY)
positionX: Math.floor(targetX),
positionY: Math.floor(targetY)
}
return this.findPath(start, end, grid)
@ -80,24 +80,24 @@ class CharacterService extends BaseService {
private findPath(start: Position, end: Position, grid: number[][]): Node[] {
const openList: Node[] = [{ ...start, g: 0, h: 0, f: 0 }]
const closedSet = new Set<string>()
const getKey = (p: Position) => `${p.x},${p.y}`
const getKey = (p: Position) => `${p.positionX},${p.positionY}`
while (openList.length > 0) {
const current = openList.reduce((min, node) => (node.f < min.f ? node : min))
if (current.x === end.x && current.y === end.y) return this.reconstructPath(current)
if (current.positionX === end.positionX && current.positionY === end.positionY) return this.reconstructPath(current)
openList.splice(openList.indexOf(current), 1)
closedSet.add(getKey(current))
const neighbors = this.DIRECTIONS.slice(0, config.ALLOW_DIAGONAL_MOVEMENT ? 8 : 4)
.map((dir) => ({ x: current.x + dir.x, y: current.y + dir.y }))
.map((dir) => ({ positionX: current.positionX + dir.x, positionY: current.positionY + dir.y }))
.filter((pos) => this.isValidPosition(pos, grid, end))
for (const neighbor of neighbors) {
if (closedSet.has(getKey(neighbor))) continue
const g = current.g + this.getDistance(current, neighbor)
const existing = openList.find((node) => node.x === neighbor.x && node.y === neighbor.y)
const existing = openList.find((node) => node.positionX === neighbor.positionX && node.positionY === neighbor.positionY)
if (!existing || g < existing.g) {
const h = this.getDistance(neighbor, end)
@ -112,12 +112,18 @@ class CharacterService extends BaseService {
}
private isValidPosition(pos: Position, grid: number[][], end: Position): boolean {
return pos.x >= 0 && pos.y >= 0 && pos.x < grid[0].length && pos.y < grid.length && (grid[pos.y][pos.x] === 0 || (pos.x === end.x && pos.y === end.y))
return (
pos.positionX >= 0 &&
pos.positionY >= 0 &&
pos.positionX < grid[0].length &&
pos.positionY < grid.length &&
(grid[pos.positionY][pos.positionX] === 0 || (pos.positionX === end.positionX && pos.positionY === end.positionY))
)
}
private getDistance(a: Position, b: Position): number {
const dx = Math.abs(a.x - b.x),
dy = Math.abs(a.y - b.y)
const dx = Math.abs(a.positionX - b.positionX),
dy = Math.abs(a.positionY - b.positionY)
// Manhattan distance for straight paths, then Euclidean for diagonals
return dx + dy + (Math.sqrt(2) - 2) * Math.min(dx, dy)
}

View File

@ -38,7 +38,7 @@ class ChatService extends BaseService {
public getArgs(command: string, message: string): string[] | undefined {
if (!this.isCommand(message, command)) return
return message.split(`/${command} `)[1].split(' ')
return message.slice(`/${command} `.length).split(' ')
}
}

View File

@ -48,13 +48,6 @@ class TeleportService {
const currentMapId = mapCharacter.character.map?.id
const io = SocketManager.getIO()
// Handle current map cleanup
if (currentMapId) {
socket.leave(currentMapId)
MapManager.removeCharacter(characterId)
io.in(currentMapId).emit('map:character:leave', characterId)
}
// Update character position and map
await mapCharacter
.getCharacter()
@ -64,6 +57,26 @@ class TeleportService {
.setMap(targetMap.getMap())
.save()
// If the current map is the target map and we are not joining, send move event
if (currentMapId === options.targetMapId && !options.isInitialJoin) {
// If the current map is the target map, send move event
io.in(currentMapId).emit('map:character:move', {
characterId: mapCharacter.character.id,
positionX: options.targetX,
positionY: options.targetY,
rotation: options.rotation ?? 0,
isMoving: false
})
return true
}
// Handle current map cleanup
if (currentMapId) {
socket.leave(currentMapId)
MapManager.removeCharacter(characterId)
io.in(currentMapId).emit('map:character:leave', characterId)
}
// Join new map
socket.join(options.targetMapId)
targetMap.addCharacter(mapCharacter.getCharacter())
@ -74,7 +87,7 @@ class TeleportService {
// Notify clients
io.in(options.targetMapId).emit('map:character:join', mapCharacter)
socket.emit('map:character:teleport', {
map: map,
mapId: options.targetMapId,
characters: targetMap.getCharactersInMap()
})

View File

@ -19,7 +19,7 @@
"#application/*": ["./src/application/*"],
"#commands/*": ["./src/commands/*"],
"#entities/*": ["./src/entities/*"],
"#http/*": ["./src/http/*"],
"#controllers/*": ["./src/controllers/*"],
"#jobs/*": ["./src/jobs/*"],
"#managers/*": ["./src/managers/*"],
"#middleware/*": ["./src/middleware/*"],