Compare commits
105 Commits
feature/#3
...
feature/mo
Author | SHA1 | Date | |
---|---|---|---|
9e55ac7990 | |||
8b51f6e16a | |||
e2ded75017 | |||
0cead14e71 | |||
f2905247ff | |||
e735522d76 | |||
94c619192b | |||
a8a98d0083 | |||
646c40db27 | |||
cfaea6ec7c | |||
9030550c0f | |||
c71c393a51 | |||
4d192bd5ec | |||
f46fff5b69 | |||
f5cae0db9f | |||
c627ea2412 | |||
30145e1662 | |||
778e4402ba | |||
e2bc151881 | |||
2b022ee4e0 | |||
3802b2cf9d | |||
2ee6a72984 | |||
f50e4c75a9 | |||
51cbe87755 | |||
d6aa8da2de | |||
7b4674587a | |||
8e652f8dcb | |||
5349e2ffe5 | |||
66759a87f2 | |||
b7748c254f | |||
ee080b6987 | |||
67021f9ada | |||
3270ea8729 | |||
04710edb73 | |||
d398764b6d | |||
be479b11c5 | |||
45964ba7f3 | |||
e7e187da7c | |||
64c0d82d48 | |||
12292ea4f2 | |||
0c8df9d175 | |||
86cbe3fdcb | |||
62e31c10d7 | |||
35fe0e6faa | |||
bcc5c0bca3 | |||
2de92ca51c | |||
2cdcfa7e56 | |||
ee4eca6db3 | |||
daca3d306d | |||
47d38e36dd | |||
14b4726546 | |||
394ad13341 | |||
fe18f8b54e | |||
11f177c901 | |||
e1f9f8e523 | |||
10c8e493a7 | |||
9a5aa9a53d | |||
2d5a445af0 | |||
af43faf8f2 | |||
cbaadc0c26 | |||
1ed9c2a61f | |||
b46989d3af | |||
30310bf0cf | |||
a28b1b9bee | |||
ccdc39e74b | |||
df860cb7d7 | |||
5e46597e7d | |||
aebe21f140 | |||
d4c1098a5e | |||
8b9afdf956 | |||
5f02aca6e4 | |||
e824f0f558 | |||
13252e056f | |||
50f595f718 | |||
a7726387af | |||
cff5fed4f7 | |||
52b8a9b7ad | |||
f5e7d10fb4 | |||
fae428f239 | |||
37f2cd90e6 | |||
3265bf7823 | |||
209f474575 | |||
733a1c4956 | |||
7e2c5eb529 | |||
b2f7d45a1f | |||
8b0746958e | |||
0c607fe39d | |||
aae125c6c6 | |||
4ace8c1e84 | |||
cf3b274cd3 | |||
10fd2064ba | |||
9ba8be51ab | |||
1686a7a9a0 | |||
b82e2fd0fd | |||
71dd1f240d | |||
f2917e67e3 | |||
9ea12ee458 | |||
67a4c6763b | |||
f0c0456121 | |||
4992ef69d4 | |||
765a0468bc | |||
ba96ae7dd4 | |||
9baffd1327 | |||
a14074afcf | |||
6b03937c39 |
17
.dockerignore
Normal file
17
.dockerignore
Normal file
@ -0,0 +1,17 @@
|
||||
node_modules
|
||||
npm-debug.log
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
.env
|
||||
.env.*
|
||||
docker-compose*
|
||||
*.md
|
||||
coverage
|
||||
.vscode
|
||||
.idea
|
||||
dist
|
||||
build
|
||||
temp
|
14
.env.example
14
.env.example
@ -6,10 +6,10 @@ JWT_SECRET="secret"
|
||||
CLIENT_URL="http://localhost:5173"
|
||||
|
||||
# Database configuration
|
||||
REDIS_URL="redis://@127.0.0.1:6379/4"
|
||||
DB_HOST="localhost"
|
||||
DB_USER="root"
|
||||
DB_PASS=""
|
||||
REDIS_URL="redis://@redis:6379/4"
|
||||
DB_HOST="mariadb"
|
||||
DB_USER="mariadb"
|
||||
DB_PASS="mariadb"
|
||||
DB_PORT="3306"
|
||||
DB_NAME="game"
|
||||
|
||||
@ -25,4 +25,8 @@ DEFAULT_CHARACTER_POS_Y="0"
|
||||
SMTP_HOST=my.directonline.io
|
||||
SMTP_PORT=587
|
||||
SMTP_USER=no-reply@noxious.gg
|
||||
SMTP_PASSWORD=""
|
||||
SMTP_PASSWORD=""
|
||||
|
||||
# SSL
|
||||
#PUBLIC_KEY_PATH=
|
||||
#PRIVATE_KEY_PATH=
|
41
Dockerfile
41
Dockerfile
@ -1,41 +0,0 @@
|
||||
# Use the official Node.js 22.4.1 image
|
||||
FROM node:22.4.1-alpine
|
||||
|
||||
# Install Redis and tmux
|
||||
RUN apk add --no-cache redis tmux
|
||||
|
||||
# Set the working directory in the container
|
||||
WORKDIR /usr/src/
|
||||
|
||||
# Copy package.json and package-lock.json (if available)
|
||||
COPY package*.json ./
|
||||
|
||||
# Install application dependencies
|
||||
RUN npm install
|
||||
|
||||
# Copy prisma schema
|
||||
COPY prisma ./prisma/
|
||||
|
||||
# Generate Prisma client
|
||||
RUN npx prisma generate
|
||||
|
||||
# Copy the rest of your application code to the container
|
||||
COPY . .
|
||||
|
||||
# Build the application
|
||||
RUN npm run build
|
||||
|
||||
# Expose the ports your Node.js application and Redis will listen on
|
||||
EXPOSE 80 6379
|
||||
|
||||
# Create a shell script to run Redis, run migrations, and start the application in a tmux session
|
||||
RUN echo '#!/bin/sh' > /usr/src/start.sh && \
|
||||
echo 'redis-server --daemonize yes' >> /usr/src/start.sh && \
|
||||
echo 'npx prisma migrate deploy' >> /usr/src/start.sh && \
|
||||
echo 'tmux new-session -d -s nodeapp "node dist/server.js"' >> /usr/src/start.sh && \
|
||||
echo 'echo "App is running in tmux session. Attach with: tmux attach-session -t nodeapp"' >> /usr/src/start.sh && \
|
||||
echo 'tail -f /dev/null' >> /usr/src/start.sh && \
|
||||
chmod +x /usr/src/start.sh
|
||||
|
||||
# Use the shell script as the entry point
|
||||
CMD ["/usr/src/start.sh"]
|
10
README.md
10
README.md
@ -5,7 +5,7 @@ This is the server for the Noxious game.
|
||||
## Projects requirements
|
||||
|
||||
- NodeJS 20.x or higher
|
||||
- MySQL 8.x or higher
|
||||
- MariaDB 11.x or higher
|
||||
- Redis 7.x or higher
|
||||
|
||||
## Installation
|
||||
@ -14,7 +14,7 @@ This is the server for the Noxious game.
|
||||
2. Install dependencies with `npm install`
|
||||
3. Copy the `.env.example` file to `.env` and fill in the required variables
|
||||
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
|
||||
5. After MySQL and Redis are running, run `npx mikro-orm-esm 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
|
||||
@ -39,15 +39,15 @@ MikroORM is used as the ORM for the server.
|
||||
|
||||
### Create init. migrations
|
||||
|
||||
Run `npx mikro-orm migration:create --initial` to create a new initial migration.
|
||||
Run `npx mikro-orm-esm migration:create --initial` to create a new initial migration.
|
||||
|
||||
### Create migrations
|
||||
|
||||
Run `npx mikro-orm migration:create` to create a new migration. You do this when you want to add a new table or change an existing one.
|
||||
Run `npx mikro-orm-esm migration:create` to create a new migration. You do this when you want to add a new table or change an existing one.
|
||||
|
||||
### Apply migrations
|
||||
|
||||
Run `npx mikro-orm migration:up` to apply all pending migrations.
|
||||
Run `npx mikro-orm-esm migration:up` to apply all pending migrations.
|
||||
|
||||
### Import default data
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 2,
|
||||
"dockerfilePath" :"./Dockerfile"
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20250128165214 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\` numeric(5,2) not null default 0, \`origin_y\` numeric(5,2) 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;`);
|
||||
}
|
||||
|
||||
}
|
247
package-lock.json
generated
247
package-lock.json
generated
@ -5,6 +5,7 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@mikro-orm/cli": "^6.4.2",
|
||||
"@mikro-orm/core": "^6.4.2",
|
||||
"@mikro-orm/mariadb": "^6.4.2",
|
||||
"@mikro-orm/migrations": "^6.4.2",
|
||||
@ -12,22 +13,25 @@
|
||||
"@mikro-orm/reflection": "^6.4.2",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bufferutil": "^4.0.9",
|
||||
"bullmq": "^5.13.2",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
"https": "^1.0.0",
|
||||
"ioredis": "^5.4.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"nodemailer": "^6.9.15",
|
||||
"pino": "^9.3.2",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"sharp": "^0.33.4",
|
||||
"socket.io": "^4.7.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.5.3",
|
||||
"utf-8-validate": "^6.0.5",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mikro-orm/cli": "^6.4.2",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/jsonwebtoken": "^9.0.6",
|
||||
@ -542,9 +546,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/core": {
|
||||
"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==",
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.11.0.tgz",
|
||||
"integrity": "sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@ -603,9 +607,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz",
|
||||
"integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==",
|
||||
"version": "9.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.20.0.tgz",
|
||||
"integrity": "sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -636,6 +640,19 @@
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
|
||||
"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": {
|
||||
"@types/json-schema": "^7.0.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||
@ -1073,7 +1090,6 @@
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@jercle/yargonaut/-/yargonaut-1.1.5.tgz",
|
||||
"integrity": "sha512-zBp2myVvBHp1UaJsNTyS6q4UDKT7eRiqTS4oNTS6VQMd6mpxYOdbeK4pY279cDCdakGy6hG0J3ejoXZVsPwHqw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.2",
|
||||
@ -1110,7 +1126,6 @@
|
||||
"version": "6.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.5.tgz",
|
||||
"integrity": "sha512-Ujmpy6ZFs//2TYzi0Q1tzmrOjq+SwtkT7Iv1RUsniaF21N6R71qhQnSHdkJgVuaGGE5a6Qyp52mDWSwW4qb9EQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jercle/yargonaut": "1.1.5",
|
||||
@ -1741,17 +1756,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.23.0.tgz",
|
||||
"integrity": "sha512-vBz65tJgRrA1Q5gWlRfvoH+w943dq9K1p1yDBY2pc+a1nbBLZp7fB9+Hk8DaALUbzjqlMfgaqlVPT1REJdkt/w==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.0.tgz",
|
||||
"integrity": "sha512-aFcXEJJCI4gUdXgoo/j9udUYIHgF23MFkg09LFz2dzEmU0+1Plk4rQWv/IYKvPHAtlkkGoB3m5e6oUp+JPsNaQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.23.0",
|
||||
"@typescript-eslint/type-utils": "8.23.0",
|
||||
"@typescript-eslint/utils": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0",
|
||||
"@typescript-eslint/scope-manager": "8.24.0",
|
||||
"@typescript-eslint/type-utils": "8.24.0",
|
||||
"@typescript-eslint/utils": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
@ -1771,16 +1786,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.23.0.tgz",
|
||||
"integrity": "sha512-h2lUByouOXFAlMec2mILeELUbME5SZRN/7R9Cw2RD2lRQQY08MWMM+PmVVKKJNK1aIwqTo9t/0CvOxwPbRIE2Q==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.24.0.tgz",
|
||||
"integrity": "sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.23.0",
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/typescript-estree": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0",
|
||||
"@typescript-eslint/scope-manager": "8.24.0",
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/typescript-estree": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -1796,14 +1811,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.23.0.tgz",
|
||||
"integrity": "sha512-OGqo7+dXHqI7Hfm+WqkZjKjsiRtFUQHPdGMXzk5mYXhJUedO7e/Y7i8AK3MyLMgZR93TX4bIzYrfyVjLC+0VSw==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.24.0.tgz",
|
||||
"integrity": "sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0"
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -1814,14 +1829,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.23.0.tgz",
|
||||
"integrity": "sha512-iIuLdYpQWZKbiH+RkCGc6iu+VwscP5rCtQ1lyQ7TYuKLrcZoeJVpcLiG8DliXVkUxirW/PWlmS+d6yD51L9jvA==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.24.0.tgz",
|
||||
"integrity": "sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.23.0",
|
||||
"@typescript-eslint/utils": "8.23.0",
|
||||
"@typescript-eslint/typescript-estree": "8.24.0",
|
||||
"@typescript-eslint/utils": "8.24.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.0.1"
|
||||
},
|
||||
@ -1838,9 +1853,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.23.0.tgz",
|
||||
"integrity": "sha512-1sK4ILJbCmZOTt9k4vkoulT6/y5CHJ1qUYxqpF1K/DBAd8+ZUL4LlSCxOssuH5m4rUaaN0uS0HlVPvd45zjduQ==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.24.0.tgz",
|
||||
"integrity": "sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -1852,14 +1867,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.23.0.tgz",
|
||||
"integrity": "sha512-LcqzfipsB8RTvH8FX24W4UUFk1bl+0yTOf9ZA08XngFwMg4Kj8A+9hwz8Cr/ZS4KwHrmo9PJiLZkOt49vPnuvQ==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.0.tgz",
|
||||
"integrity": "sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/visitor-keys": "8.23.0",
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/visitor-keys": "8.24.0",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
@ -1879,16 +1894,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.23.0.tgz",
|
||||
"integrity": "sha512-uB/+PSo6Exu02b5ZEiVtmY6RVYO7YU5xqgzTIVZwTHvvK3HsL8tZZHFaTLFtRG3CsV4A5mhOv+NZx5BlhXPyIA==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.24.0.tgz",
|
||||
"integrity": "sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "8.23.0",
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/typescript-estree": "8.23.0"
|
||||
"@typescript-eslint/scope-manager": "8.24.0",
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"@typescript-eslint/typescript-estree": "8.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -1903,13 +1918,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.23.0.tgz",
|
||||
"integrity": "sha512-oWWhcWDLwDfu++BGTZcmXWqpwtkwb5o7fxUIGksMQQDSdPW9prsSnfIOZMlsj4vBOSrcnjIUZMiIjODgGosFhQ==",
|
||||
"version": "8.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.0.tgz",
|
||||
"integrity": "sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.23.0",
|
||||
"@typescript-eslint/types": "8.24.0",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -2040,7 +2055,6 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@ -2050,7 +2064,6 @@
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
@ -2367,10 +2380,23 @@
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/bufferutil": {
|
||||
"version": "4.0.9",
|
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz",
|
||||
"integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.14.2"
|
||||
}
|
||||
},
|
||||
"node_modules/bullmq": {
|
||||
"version": "5.40.0",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.40.0.tgz",
|
||||
"integrity": "sha512-tmrk32EmcbtUOGPSdwlDUcc0w+nAMqCisk8vEFFmG8aOzIehz0BxTNSj6Grh0qoMugRF3VglWk8HGUBnWqU2Fw==",
|
||||
"version": "5.40.2",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.40.2.tgz",
|
||||
"integrity": "sha512-Cn4NUpwGAF4WnuXR2kTZCTAUEUHajSCn/IqiDG9ry1kVvAwwwg1Ati3J5HN2uZjqD5PBfNDXYnsc2+0PzakDwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cron-parser": "^4.9.0",
|
||||
@ -2453,7 +2479,6 @@
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
@ -2508,7 +2533,6 @@
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
@ -2927,7 +2951,6 @@
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
@ -3203,18 +3226,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.19.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz",
|
||||
"integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==",
|
||||
"version": "9.20.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.20.1.tgz",
|
||||
"integrity": "sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g==",
|
||||
"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.10.0",
|
||||
"@eslint/core": "^0.11.0",
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "9.19.0",
|
||||
"@eslint/js": "9.20.0",
|
||||
"@eslint/plugin-kit": "^0.2.5",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
@ -3751,7 +3774,6 @@
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/figlet/-/figlet-1.8.0.tgz",
|
||||
"integrity": "sha512-chzvGjd+Sp7KUvPHZv6EXV5Ir3Q7kYNpCr4aHrRW79qFtTefmQZNny+W1pW9kf5zeE6dikku2W50W/wAH2xWgw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"figlet": "bin/index.js"
|
||||
@ -3857,9 +3879,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz",
|
||||
"integrity": "sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==",
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
||||
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -3972,7 +3994,6 @@
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
@ -4256,6 +4277,12 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/https": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz",
|
||||
"integrity": "sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
@ -4351,9 +4378,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ioredis": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.4.2.tgz",
|
||||
"integrity": "sha512-0SZXGNGZ+WzISQ67QDyZ2x0+wVxjjUndtD8oSeik/4ajifeiRufed8fCb8QW8VMyi4MXcS+UO1k/0NGhvq1PAg==",
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.5.0.tgz",
|
||||
"integrity": "sha512-7CutT89g23FfSa8MDoIFs2GYYa0PaNiW/OrT+nRyjRXHDZd17HmIgy+reOQ/yhh72NznNjGuS8kbCAcA4Ro4mw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ioredis/commands": "^1.1.1",
|
||||
@ -4457,13 +4484,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-boolean-object": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz",
|
||||
"integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
|
||||
"integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"call-bound": "^1.0.3",
|
||||
"has-tostringtag": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
@ -4565,7 +4592,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@ -4850,7 +4876,6 @@
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
@ -5105,9 +5130,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz",
|
||||
"integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==",
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.3.0.tgz",
|
||||
"integrity": "sha512-5vvY5yF1zF/kXk+L94FRiTDa1Znom46UjPCH6/XbSvS8zBKMFBHTJk8KDMqJ+2J6QezQFi7k1k8v21ClJYHPaw==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
@ -5308,7 +5333,6 @@
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@ -5426,6 +5450,17 @@
|
||||
"integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-gyp-build": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
|
||||
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"node-gyp-build": "bin.js",
|
||||
"node-gyp-build-optional": "optional.js",
|
||||
"node-gyp-build-test": "build-test.js"
|
||||
}
|
||||
},
|
||||
"node_modules/node-gyp-build-optional-packages": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
|
||||
@ -5546,9 +5581,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
|
||||
"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@ -5747,7 +5782,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz",
|
||||
"integrity": "sha512-2MXDNZC4aXdkkap+rBBMv0lUsfJqvX5/2FiYYnfCnorZt3Pk06/IOR5KeaoghgS2w07MLWgjbsnyaq6PdHn2LQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
@ -5873,9 +5907,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/possible-typed-array-names": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
|
||||
"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
|
||||
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -5893,9 +5927,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
|
||||
"integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.0.tgz",
|
||||
"integrity": "sha512-quyMrVt6svPS7CjQ9gKb3GLEX/rl3BCL2oa/QkNcXv4YNVBC9olt3s+H7ukto06q7B1Qz46PbrKLO34PR6vXcA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@ -6127,7 +6161,6 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@ -6758,7 +6791,6 @@
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
@ -6832,7 +6864,6 @@
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
@ -6845,7 +6876,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
@ -6868,7 +6898,6 @@
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
@ -7017,7 +7046,6 @@
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
|
||||
"integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"json5": "^2.2.2",
|
||||
@ -7068,9 +7096,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "4.33.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.33.0.tgz",
|
||||
"integrity": "sha512-s6zVrxuyKbbAsSAD5ZPTB77q4YIdRctkTbJ2/Dqlinwz+8ooH2gd+YA7VA6Pa93KML9GockVvoxjZ2vHP+mu8g==",
|
||||
"version": "4.34.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.34.1.tgz",
|
||||
"integrity": "sha512-6kSc32kT0rbwxD6QL1CYe8IqdzN/J/ILMrNK+HMQCKH3insCDRY/3ITb0vcBss0a3t72fzh2YSzj8ko1HgwT3g==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
@ -7258,6 +7286,19 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/utf-8-validate": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.5.tgz",
|
||||
"integrity": "sha512-EYZR+OpIXp9Y1eG1iueg8KRsY8TuT8VNgnanZ0uA3STqhHQTLwbl+WX76/9X5OY12yQubymBpaBSmMPkSTQcKA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.14.2"
|
||||
}
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
@ -7413,7 +7454,6 @@
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
@ -7452,7 +7492,6 @@
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
@ -7468,7 +7507,6 @@
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
@ -7487,7 +7525,6 @@
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
|
25
package.json
25
package.json
@ -1,13 +1,29 @@
|
||||
{
|
||||
"type": "module",
|
||||
"tsNode": true,
|
||||
"scripts": {
|
||||
"start": "node dist/server.js",
|
||||
"start": "tsx src/server.ts",
|
||||
"dev": "nodemon --exec tsx src/server.ts",
|
||||
"build": "tsc",
|
||||
"format": "prettier --write src/",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix"
|
||||
},
|
||||
"imports": {
|
||||
"#root/*": "./src/*.js",
|
||||
"#application/*": "./src/application/*.js",
|
||||
"#commands/*": "./src/commands/*.js",
|
||||
"#entities/*": "./src/entities/*.js",
|
||||
"#controllers/*": "./src/controllers/*.js",
|
||||
"#jobs/*": "./src/jobs/*.js",
|
||||
"#managers/*": "./src/managers/*.js",
|
||||
"#middleware/*": "./src/middleware/*.js",
|
||||
"#models/*": "./src/models/*.js",
|
||||
"#repositories/*": "./src/repositories/*.js",
|
||||
"#services/*": "./src/services/*.js",
|
||||
"#events/*": "./src/events/*.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mikro-orm/cli": "^6.4.2",
|
||||
"@mikro-orm/core": "^6.4.2",
|
||||
"@mikro-orm/mariadb": "^6.4.2",
|
||||
"@mikro-orm/migrations": "^6.4.2",
|
||||
@ -15,22 +31,25 @@
|
||||
"@mikro-orm/reflection": "^6.4.2",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bufferutil": "^4.0.9",
|
||||
"bullmq": "^5.13.2",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
"https": "^1.0.0",
|
||||
"ioredis": "^5.4.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"nodemailer": "^6.9.15",
|
||||
"pino": "^9.3.2",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"sharp": "^0.33.4",
|
||||
"socket.io": "^4.7.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.5.3",
|
||||
"utf-8-validate": "^6.0.5",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mikro-orm/cli": "^6.4.2",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/jsonwebtoken": "^9.0.6",
|
||||
|
@ -1,6 +1,6 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import { Response } from 'express'
|
||||
import type { Response } from 'express'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
|
||||
|
@ -1,18 +1,34 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import type { TSocket } from '#application/types'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import { TSocket } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
|
||||
export abstract class BaseEvent {
|
||||
protected readonly logger = Logger.type(LoggerType.GAME)
|
||||
private lastActionTimes: Map<string, number> = new Map()
|
||||
|
||||
constructor(
|
||||
readonly io: Server,
|
||||
readonly socket: TSocket
|
||||
) {}
|
||||
|
||||
protected isThrottled(actionId: string, throttleTime: number): boolean {
|
||||
const now = Date.now()
|
||||
const lastActionTime = this.lastActionTimes.get(actionId) || 0
|
||||
|
||||
if (now - lastActionTime < throttleTime) {
|
||||
return true
|
||||
}
|
||||
|
||||
this.lastActionTimes.set(actionId, now)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
protected async getCharacter(): Promise<Character | null> {
|
||||
const characterRepository = new CharacterRepository()
|
||||
return characterRepository.getById(this.socket.characterId!)
|
||||
@ -24,13 +40,14 @@ export abstract class BaseEvent {
|
||||
}
|
||||
|
||||
protected emitError(message: string): void {
|
||||
this.socket.emit('notification', { title: 'Server message', message })
|
||||
this.logger.error('character:connect error', `Player ${this.socket.userId}: ${message}`)
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, { title: 'Server message', message })
|
||||
this.logger.error('Base event error', `Player ${this.socket.userId}: ${message}`)
|
||||
}
|
||||
|
||||
protected handleError(context: string, error: unknown): void {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
this.emitError(`${context}: ${errorMessage}`)
|
||||
this.logger.error('character:connect error', errorMessage)
|
||||
console.log(error)
|
||||
const errorMessage = error instanceof Error ? error.message : error && typeof error === 'object' && 'toString' in error ? error.toString() : String(error)
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, { title: 'Server message', message: `Server error occured. Please contact the server administrator.` })
|
||||
this.logger.error('Base event error', errorMessage)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { EntityManager } from '@mikro-orm/core'
|
||||
|
||||
import Database from '../database'
|
||||
|
||||
import Database from '#application/database'
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
|
||||
export abstract class BaseRepository {
|
||||
|
@ -31,6 +31,10 @@ class config {
|
||||
static SMTP_PORT: number = process.env.SMTP_PORT ? parseInt(process.env.SMTP_PORT) : 587
|
||||
static SMTP_USER: string = process.env.SMTP_USER || 'no-reply@noxious.gg'
|
||||
static SMTP_PASSWORD: string = process.env.SMTP_PASSWORD || 'password'
|
||||
|
||||
// SSL
|
||||
static PUBLIC_KEY_PATH: string = process.env.PUBLIC_KEY_PATH || ''
|
||||
static PRIVATE_KEY_PATH: string = process.env.PRIVATE_KEY_PATH || ''
|
||||
}
|
||||
|
||||
export default config
|
||||
|
@ -2,9 +2,10 @@ import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { pathToFileURL } from 'url'
|
||||
|
||||
import type { Command } from '#application/types'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import Storage from '#application/storage'
|
||||
import { Command } from '#application/types'
|
||||
|
||||
export class CommandRegistry {
|
||||
private readonly commands: Map<string, Command> = new Map()
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import * as readline from 'readline'
|
||||
|
||||
export class ConsolePrompt {
|
||||
@ -10,7 +11,7 @@ export class ConsolePrompt {
|
||||
output: process.stdout
|
||||
})
|
||||
|
||||
this.rl.on('close', () => {
|
||||
this.rl.on(SocketEvent.CLOSE, () => {
|
||||
this.isClosed = true
|
||||
})
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
@ -60,7 +61,7 @@ export class LogReader {
|
||||
end: newPosition
|
||||
})
|
||||
|
||||
stream.on('data', (data) => {
|
||||
stream.on(SocketEvent.DATA, (data) => {
|
||||
console.log(`[${filename}]`)
|
||||
console.log(data.toString()) //
|
||||
})
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { MikroORM } from '@mikro-orm/mysql'
|
||||
import { MikroORM } from '@mikro-orm/mariadb'
|
||||
// import { MikroORM } from '@mikro-orm/mysql'
|
||||
|
||||
import Logger, { LoggerType } from './logger'
|
||||
import config from '../../mikro-orm.config'
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import config from '#root/mikro-orm.config'
|
||||
|
||||
class Database {
|
||||
private static orm: MikroORM
|
||||
|
@ -1,17 +1,57 @@
|
||||
export enum SocketEvent {
|
||||
CHARACTER_CONNECT = 1,
|
||||
CHARACTER_MOVE = 2,
|
||||
CHARACTER_MOVE_ERROR = 3,
|
||||
CHARACTER_TELEPORT = 4,
|
||||
ZONE_CHARACTER_LEAVE = 5,
|
||||
ZONE_CHARACTER_JOIN = 6,
|
||||
ZONE_CHARACTER_LIST = 7,
|
||||
ZONE_CHARACTER_DELETE = 8,
|
||||
ZONE_CHARACTER_CREATE = 9,
|
||||
ZONE_CHARACTER_UPDATE = 10,
|
||||
ZONE_CHARACTER_HAIR_UPDATE = 11,
|
||||
ZONE_CHARACTER_HAIR_LIST = 12,
|
||||
ZONE_CHARACTER_TELEPORT = 13
|
||||
CLOSE = '52',
|
||||
DATA = '51',
|
||||
CHARACTER_CONNECT = '50',
|
||||
CHARACTER_CREATE = '49',
|
||||
CHARACTER_DELETE = '48',
|
||||
CHARACTER_LIST = '47',
|
||||
GM_CHARACTERHAIR_CREATE = '46',
|
||||
GM_CHARACTERHAIR_REMOVE = '45',
|
||||
GM_CHARACTERHAIR_LIST = '44',
|
||||
GM_CHARACTERHAIR_UPDATE = '43',
|
||||
GM_CHARACTERTYPE_CREATE = '42',
|
||||
GM_CHARACTERTYPE_REMOVE = '41',
|
||||
GM_CHARACTERTYPE_LIST = '40',
|
||||
GM_CHARACTERTYPE_UPDATE = '39',
|
||||
GM_ITEM_CREATE = '38',
|
||||
GM_ITEM_REMOVE = '37',
|
||||
GM_ITEM_LIST = '36',
|
||||
GM_ITEM_UPDATE = '35',
|
||||
GM_MAPOBJECT_LIST = '34',
|
||||
GM_MAPOBJECT_REMOVE = '33',
|
||||
GM_MAPOBJECT_UPDATE = '32',
|
||||
GM_MAPOBJECT_UPLOAD = '31',
|
||||
GM_SPRITE_COPY = '30',
|
||||
GM_SPRITE_CREATE = '29',
|
||||
GM_SPRITE_DELETE = '28',
|
||||
GM_SPRITE_LIST = '27',
|
||||
GM_SPRITE_UPDATE = '26',
|
||||
GM_TILE_DELETE = '25',
|
||||
GM_TILE_LIST = '24',
|
||||
GM_TILE_UPDATE = '23',
|
||||
GM_TILE_UPLOAD = '22',
|
||||
GM_MAP_CREATE = '21',
|
||||
GM_MAP_DELETE = '20',
|
||||
GM_MAP_REQUEST = '19',
|
||||
GM_MAP_UPDATE = '18',
|
||||
MAP_CHARACTER_MOVEERROR = '17',
|
||||
DISCONNECT = '16',
|
||||
USER_DISCONNECT = '15',
|
||||
LOGIN = '14',
|
||||
LOGGED_IN = '13',
|
||||
NOTIFICATION = '12',
|
||||
DATE = '11',
|
||||
FAILED = '10',
|
||||
COMPLETED = '9',
|
||||
CONNECTION = '8',
|
||||
WEATHER = '7',
|
||||
CHARACTER_DISCONNECT = '6',
|
||||
MAP_CHARACTER_ATTACK = '5',
|
||||
MAP_CHARACTER_TELEPORT = '4',
|
||||
MAP_CHARACTER_JOIN = '3',
|
||||
MAP_CHARACTER_LEAVE = '2',
|
||||
MAP_CHARACTER_MOVE = '1',
|
||||
CHAT_MESSAGE = '0',
|
||||
}
|
||||
|
||||
export enum ItemType {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import pino from 'pino'
|
||||
const logger = pino.pino
|
||||
|
||||
export enum LoggerType {
|
||||
HTTP = 'http',
|
||||
@ -13,13 +14,13 @@ export enum LoggerType {
|
||||
}
|
||||
|
||||
class Logger {
|
||||
private instances: Map<LoggerType, ReturnType<typeof pino>> = new Map()
|
||||
private instances: Map<LoggerType, pino.Logger> = new Map()
|
||||
|
||||
private getLogger(type: LoggerType): ReturnType<typeof pino> {
|
||||
private getLogger(type: LoggerType): pino.Logger {
|
||||
if (!this.instances.has(type)) {
|
||||
this.instances.set(
|
||||
type,
|
||||
pino({
|
||||
logger({
|
||||
level: process.env.LOG_LEVEL || 'debug',
|
||||
transport: {
|
||||
target: 'pino/file',
|
||||
|
@ -9,7 +9,7 @@ class Storage {
|
||||
|
||||
constructor() {
|
||||
this.rootDir = process.cwd()
|
||||
this.baseDir = config.ENV === 'development' ? 'src' : 'dist'
|
||||
this.baseDir = config.ENV === 'development' ? 'src' : 'src'
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import { BaseCommand } from '#application/base/baseCommand'
|
||||
@ -8,6 +9,6 @@ export default class AlertCommand extends BaseCommand {
|
||||
public execute(input: CommandInput): void {
|
||||
const message: string = input.join(' ') ?? null
|
||||
if (!message) return console.log('message is required')
|
||||
this.io.emit('notification', { message: message })
|
||||
this.io.emit(SocketEvent.NOTIFICATION, { message: message })
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import fs from 'fs'
|
||||
wimport fs from 'fs'
|
||||
|
||||
import sharp from 'sharp'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseCommand } from '#application/base/baseCommand'
|
||||
import { CharacterGender, CharacterRace } from '#application/enums'
|
||||
import Storage from '#application/storage'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { CharacterHair } from '#entities/characterHair'
|
||||
import { CharacterType } from '#entities/characterType'
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Request, Response } from 'express'
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
import type { Request, Response } from 'express'
|
||||
|
||||
import { BaseController } from '#application/base/baseController'
|
||||
import config from '#application/config'
|
||||
import { loginAccountSchema, registerAccountSchema, resetPasswordSchema, newPasswordSchema } from '#application/zodTypes'
|
||||
|
@ -1,11 +1,12 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import { Request, Response } from 'express'
|
||||
import sharp from 'sharp'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { Request, Response } from 'express'
|
||||
|
||||
import { BaseController } from '#application/base/baseController'
|
||||
import Storage from '#application/storage'
|
||||
import { UUID } from '#application/types'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
import CharacterTypeRepository from '#repositories/characterTypeRepository'
|
||||
@ -26,7 +27,7 @@ export class AvatarController extends BaseController {
|
||||
* @param res
|
||||
*/
|
||||
public async getByName(req: Request, res: Response) {
|
||||
const character = await this.characterRepository.getByName(req.params.characterName)
|
||||
const character = await this.characterRepository.getByName(req.params.characterName!)
|
||||
if (!character?.characterType) {
|
||||
return this.sendError(res, 'Character or character type not found', 404)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Request, Response } from 'express'
|
||||
import type { Request, Response } from 'express'
|
||||
|
||||
import { BaseController } from '#application/base/baseController'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Request, Response } from 'express'
|
||||
import type { Request, Response } from 'express'
|
||||
|
||||
import { BaseController } from '#application/base/baseController'
|
||||
import Storage from '#application/storage'
|
||||
@ -12,6 +12,10 @@ export class TexturesController extends BaseController {
|
||||
public async download(req: Request, res: Response) {
|
||||
const { type, spriteId, file } = req.params
|
||||
|
||||
if (!type || !file) {
|
||||
return this.sendError(res, 'Invalid request', 400)
|
||||
}
|
||||
|
||||
const texture = type === 'sprites' && spriteId ? Storage.getPublicPath(type, spriteId, file) : Storage.getPublicPath(type, file)
|
||||
|
||||
this.sendFile(res, texture)
|
||||
|
@ -1,16 +1,17 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import { Collection, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { CharacterEquipment } from '#entities/characterEquipment'
|
||||
import type { CharacterHair } from '#entities/characterHair'
|
||||
import type { CharacterItem } from '#entities/characterItem'
|
||||
import type { CharacterType } from '#entities/characterType'
|
||||
import type { Chat } from '#entities/chat'
|
||||
import type { Map } from '#entities/map'
|
||||
import type { User } from '#entities/user'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { CharacterEquipment } from '#entities/characterEquipment'
|
||||
import { CharacterHair } from '#entities/characterHair'
|
||||
import { CharacterItem } from '#entities/characterItem'
|
||||
import { CharacterType } from '#entities/characterType'
|
||||
import { Chat } from '#entities/chat'
|
||||
import { Map } from '#entities/map'
|
||||
import { User } from '#entities/user'
|
||||
|
||||
export class BaseCharacter extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
@ -28,7 +29,7 @@ export class BaseCharacter extends BaseEntity {
|
||||
@Property()
|
||||
role = 'player'
|
||||
|
||||
@OneToMany(() => Chat, (chat) => chat.character)
|
||||
@OneToMany({ mappedBy: 'character' })
|
||||
chats = new Collection<Chat>(this)
|
||||
|
||||
// Position - @TODO: Update to spawn point when current map is not found
|
||||
|
@ -2,11 +2,12 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Enum, ManyToOne, PrimaryKey } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { Character } from '#entities/character'
|
||||
import type { CharacterItem } from '#entities/characterItem'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterEquipmentSlotType } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { CharacterItem } from '#entities/characterItem'
|
||||
|
||||
export class BaseCharacterEquipment extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
|
@ -2,9 +2,10 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterGender } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import { ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { Character } from '#entities/character'
|
||||
import type { Item } from '#entities/item'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { CharacterEquipment } from '#entities/characterEquipment'
|
||||
import { Item } from '#entities/item'
|
||||
|
||||
export class BaseCharacterItem extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
|
@ -2,9 +2,10 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterGender, CharacterRace } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import { ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { Character } from '#entities/character'
|
||||
import type { Map } from '#entities/map'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { Map } from '#entities/map'
|
||||
|
||||
export class BaseChat extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
|
@ -2,9 +2,10 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { ItemType, ItemRarity } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { CharacterItem } from '#entities/characterItem'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import { Collection, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { MapEffect } from '#entities/mapEffect'
|
||||
import type { MapEventTile } from '#entities/mapEventTile'
|
||||
import type { PlacedMapObject } from '#entities/placedMapObject'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { MapEffect } from '#entities/mapEffect'
|
||||
import { MapEventTile } from '#entities/mapEventTile'
|
||||
import { PlacedMapObject } from '#entities/placedMapObject'
|
||||
|
||||
export class BaseMap extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
@ -22,7 +23,7 @@ export class BaseMap extends BaseEntity {
|
||||
height = 10
|
||||
|
||||
@Property({ type: 'json', nullable: true })
|
||||
tiles?: any
|
||||
tiles: Array<Array<string>> = []
|
||||
|
||||
@Property()
|
||||
pvp = false
|
||||
@ -33,13 +34,13 @@ export class BaseMap extends BaseEntity {
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
@OneToMany(() => MapEffect, (effect) => effect.map, { orphanRemoval: true })
|
||||
@OneToMany({ mappedBy: 'map', orphanRemoval: true })
|
||||
mapEffects = new Collection<MapEffect>(this)
|
||||
|
||||
@OneToMany(() => MapEventTile, (tile) => tile.map, { orphanRemoval: true })
|
||||
@OneToMany({ mappedBy: 'map', orphanRemoval: true })
|
||||
mapEventTiles = new Collection<MapEventTile>(this)
|
||||
|
||||
@OneToMany(() => PlacedMapObject, (placedMapObject) => placedMapObject.map, { orphanRemoval: true })
|
||||
@OneToMany({ mappedBy: 'map', orphanRemoval: true })
|
||||
placedMapObjects = new Collection<PlacedMapObject>(this)
|
||||
|
||||
setId(id: UUID) {
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import { ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { Map } from '#entities/map'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
|
||||
export class BaseMapEffect extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
|
@ -1,12 +1,13 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, Enum, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import { Enum, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { Map } from '#entities/map'
|
||||
import type { MapEventTileTeleport } from '#entities/mapEventTileTeleport'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { MapEventTileType } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
import { MapEventTileTeleport } from '#entities/mapEventTileTeleport'
|
||||
|
||||
export class BaseMapEventTile extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
@ -24,7 +25,7 @@ export class BaseMapEventTile extends BaseEntity {
|
||||
@Property()
|
||||
positionY!: number
|
||||
|
||||
@OneToOne(() => MapEventTileTeleport, (teleport) => teleport.mapEventTile, { eager: true })
|
||||
@OneToOne({ eager: true })
|
||||
teleport?: MapEventTileTeleport
|
||||
|
||||
setId(id: UUID) {
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import { ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { Map } from '#entities/map'
|
||||
import type { MapEventTile } from '#entities/mapEventTile'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
import { MapEventTile } from '#entities/mapEventTile'
|
||||
|
||||
export class BaseMapEventTileTeleport extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
|
@ -2,8 +2,9 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
export class BaseMapObject extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import { ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { User } from '#entities/user'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { User } from '#entities/user'
|
||||
|
||||
export class BasePasswordResetToken extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import { ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { Map } from '#entities/map'
|
||||
import type { MapObject } from '#entities/mapObject'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
import { MapObject } from '#entities/mapObject'
|
||||
|
||||
//@TODO : Rename mapObject
|
||||
|
||||
export class BasePlacedMapObject extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
|
@ -2,8 +2,9 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { SpriteAction } from '#entities/spriteAction'
|
||||
|
||||
export class BaseSprite extends BaseEntity {
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import { ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
import type { Sprite } from '#entities/sprite'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
|
||||
export interface SpriteImage {
|
||||
url: string
|
||||
|
@ -2,8 +2,9 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
|
||||
export class BaseTile extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
|
@ -3,8 +3,9 @@ import { randomUUID } from 'node:crypto'
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
import bcrypt from 'bcryptjs'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { PasswordResetToken } from '#entities/passwordResetToken'
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import MapManager from '#managers/mapManager'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
@ -15,7 +17,7 @@ export default class CharacterConnectEvent extends BaseEvent {
|
||||
private readonly characterRepository = new CharacterRepository()
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('character:connect', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.CHARACTER_CONNECT, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: CharacterConnectPayload, callback: (response: any) => void): Promise<void> {
|
||||
|
@ -1,67 +1,85 @@
|
||||
import { ZodError } from 'zod'
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { ZodError, z } from 'zod'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { ZCharacterCreate } from '#application/zodTypes'
|
||||
import { Character } from '#entities/character'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
import CharacterTypeRepository from '#repositories/characterTypeRepository'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
import UserRepository from '#repositories/userRepository'
|
||||
|
||||
const MAX_CHARACTERS = 4
|
||||
|
||||
export default class CharacterCreateEvent extends BaseEvent {
|
||||
private readonly userRepository: UserRepository = new UserRepository()
|
||||
private readonly characterRepository: CharacterRepository = new CharacterRepository()
|
||||
private readonly characterTypeRepository: CharacterTypeRepository = new CharacterTypeRepository()
|
||||
private readonly mapRepository: MapRepository = new MapRepository()
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('character:create', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.CHARACTER_CREATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: any): Promise<any> {
|
||||
// zod validate
|
||||
private async handleEvent(data: z.infer<typeof ZCharacterCreate>, callback: (success: boolean) => void): Promise<void> {
|
||||
try {
|
||||
data = ZCharacterCreate.parse(data)
|
||||
|
||||
const userRepository = new UserRepository()
|
||||
const characterRepository = new CharacterRepository()
|
||||
const mapRepository = new MapRepository()
|
||||
|
||||
const user = await userRepository.getById(this.socket.userId!)
|
||||
|
||||
if (!user) {
|
||||
return this.socket.emit('notification', { message: 'User not found' })
|
||||
}
|
||||
|
||||
// Check if character name already exists
|
||||
const characterExists = await characterRepository.getByName(data.name)
|
||||
|
||||
if (characterExists) {
|
||||
return this.socket.emit('notification', { message: 'Character name already exists' })
|
||||
}
|
||||
|
||||
let characters: Character[] = await characterRepository.getByUserId(user.getId())
|
||||
|
||||
if (characters.length >= 4) {
|
||||
return this.socket.emit('notification', { message: 'You can only have 4 characters' })
|
||||
}
|
||||
|
||||
// @TODO: Change to default location
|
||||
const map = await mapRepository.getFirst()
|
||||
|
||||
const newCharacter = new Character()
|
||||
await newCharacter.setName(data.name).setUser(user).setMap(map!).save()
|
||||
|
||||
if (!newCharacter) {
|
||||
return this.socket.emit('notification', { message: 'Failed to create character. Please try again (later).' })
|
||||
}
|
||||
|
||||
characters = [...characters, newCharacter]
|
||||
|
||||
this.socket.emit('character:create:success')
|
||||
this.socket.emit('character:list', characters)
|
||||
|
||||
this.logger.info('character:create success')
|
||||
} catch (error: any) {
|
||||
this.logger.error(`character:create error: ${error.message}`)
|
||||
if (error instanceof ZodError) {
|
||||
return this.socket.emit('notification', { message: error.issues[0].message })
|
||||
}
|
||||
return this.socket.emit('notification', { message: 'Could not create character. Please try again (later).' })
|
||||
const validatedData = ZCharacterCreate.parse(data)
|
||||
await this.createCharacter(validatedData)
|
||||
callback(true)
|
||||
} catch (error: unknown) {
|
||||
this.returnError(error)
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
|
||||
private async createCharacter(data: z.infer<typeof ZCharacterCreate>): Promise<void> {
|
||||
const user = await this.userRepository.getById(this.socket.userId!)
|
||||
if (!user) {
|
||||
throw new Error('You are not logged in')
|
||||
}
|
||||
|
||||
const characterExists = await this.characterRepository.getByName(data.name)
|
||||
if (characterExists) {
|
||||
throw new Error('Character name already exists')
|
||||
}
|
||||
|
||||
let characters = await this.characterRepository.getByUserId(user.getId())
|
||||
if (characters.length >= MAX_CHARACTERS) {
|
||||
throw new Error(`You can only create ${MAX_CHARACTERS} characters`)
|
||||
}
|
||||
|
||||
const map = await this.mapRepository.getFirst()
|
||||
if (!map) {
|
||||
throw new Error('No default map found')
|
||||
}
|
||||
|
||||
const characterType = await this.characterTypeRepository.getFirst()
|
||||
if (!characterType) {
|
||||
throw new Error('No character type found')
|
||||
}
|
||||
|
||||
const newCharacter = new Character()
|
||||
await newCharacter.setName(data.name).setUser(user).setMap(map).setCharacterType(characterType).save()
|
||||
characters = await this.characterRepository.getByUserId(user.getId())
|
||||
|
||||
this.socket.emit(SocketEvent.CHARACTER_LIST, characters)
|
||||
this.logger.info('character:create success')
|
||||
}
|
||||
|
||||
private returnError(error: unknown): void {
|
||||
this.logger.error(`character:create error: ${error instanceof Error ? error.message : 'Unknown error'}`)
|
||||
|
||||
let errorMessage = 'Could not create character. Please try again later.'
|
||||
|
||||
if (error instanceof ZodError) {
|
||||
errorMessage = error.issues[0]?.message || errorMessage
|
||||
} else if (error instanceof Error) {
|
||||
errorMessage = error.message
|
||||
}
|
||||
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, {
|
||||
title: 'Error',
|
||||
message: errorMessage
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
|
||||
@ -13,7 +15,7 @@ type TypeResponse = {
|
||||
|
||||
export default class CharacterDeleteEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('character:delete', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.CHARACTER_DELETE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: TypeResponse) => void): Promise<any> {
|
||||
@ -22,9 +24,9 @@ export default class CharacterDeleteEvent extends BaseEvent {
|
||||
await (await characterRepository.getByUserAndId(this.socket.userId!, data.characterId))?.delete()
|
||||
const characters: Character[] = await characterRepository.getByUserId(this.socket.userId!)
|
||||
|
||||
this.socket.emit('character:list', characters)
|
||||
this.socket.emit(SocketEvent.CHARACTER_LIST, characters)
|
||||
} catch (error: any) {
|
||||
return this.socket.emit('notification', { message: 'Character delete failed. Please try again.' })
|
||||
return this.socket.emit(SocketEvent.NOTIFICATION, { message: 'Character delete failed. Please try again.' })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Character } from '#entities/character'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
|
||||
export default class CharacterListEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('character:list', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.CHARACTER_LIST, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: any): Promise<void> {
|
||||
@ -12,7 +13,7 @@ export default class CharacterListEvent extends BaseEvent {
|
||||
const characterRepository = new CharacterRepository()
|
||||
let characters: Character[] = await characterRepository.getByUserId(this.socket.userId!)
|
||||
|
||||
this.socket.emit('character:list', characters)
|
||||
this.socket.emit(SocketEvent.CHARACTER_LIST, characters)
|
||||
} catch (error: any) {
|
||||
this.logger.error('character:list error', error.message)
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
import ChatService from '#services/chatService'
|
||||
@ -8,7 +9,7 @@ type TypePayload = {
|
||||
|
||||
export default class AlertCommandEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('chat:message', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.CHAT_MESSAGE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
@ -25,7 +26,7 @@ export default class AlertCommandEvent extends BaseEvent {
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
this.io.emit('notification', { title: 'Message from GM', message: args.join(' ') })
|
||||
this.io.emit(SocketEvent.NOTIFICATION, { title: 'Message from GM', message: args.join(' ') })
|
||||
return callback(true)
|
||||
} catch (error: any) {
|
||||
this.logger.error('chat:alert_command error', error.message)
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import DateManager from '#managers/dateManager'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
@ -9,7 +10,7 @@ type TypePayload = {
|
||||
|
||||
export default class SetTimeCommand extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('chat:message', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.CHAT_MESSAGE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import MapManager from '#managers/mapManager'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
import TeleportService from '#services/characterTeleportService'
|
||||
@ -11,7 +13,7 @@ type TypePayload = {
|
||||
|
||||
export default class TeleportCommandEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('chat:message', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.CHAT_MESSAGE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void) {
|
||||
@ -28,7 +30,7 @@ export default class TeleportCommandEvent extends BaseEvent {
|
||||
const args = ChatService.getArgs('teleport', data.message)
|
||||
|
||||
if (!args || args.length === 0 || args.length > 3) {
|
||||
this.socket.emit('notification', {
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, {
|
||||
title: 'Server message',
|
||||
message: 'Usage: /teleport <mapId> [x] [y]'
|
||||
})
|
||||
@ -40,7 +42,7 @@ export default class TeleportCommandEvent extends BaseEvent {
|
||||
const targetY = args[2] ? parseInt(args[2], 10) : 0
|
||||
|
||||
if (!mapId || isNaN(targetX) || isNaN(targetY)) {
|
||||
this.socket.emit('notification', {
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, {
|
||||
title: 'Server message',
|
||||
message: 'Invalid parameters. X and Y coordinates must be numbers.'
|
||||
})
|
||||
@ -50,7 +52,7 @@ export default class TeleportCommandEvent extends BaseEvent {
|
||||
const mapRepository = new MapRepository()
|
||||
const map = await mapRepository.getById(mapId)
|
||||
if (!map) {
|
||||
this.socket.emit('notification', {
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, {
|
||||
title: 'Server message',
|
||||
message: 'Map not found'
|
||||
})
|
||||
@ -58,7 +60,7 @@ export default class TeleportCommandEvent extends BaseEvent {
|
||||
}
|
||||
|
||||
if (character.map.id === map.id && targetX === character.positionX && targetY === character.positionY) {
|
||||
this.socket.emit('notification', {
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, {
|
||||
title: 'Server message',
|
||||
message: 'You are already at that location'
|
||||
})
|
||||
@ -73,20 +75,20 @@ export default class TeleportCommandEvent extends BaseEvent {
|
||||
})
|
||||
|
||||
if (!success) {
|
||||
return this.socket.emit('notification', {
|
||||
return this.socket.emit(SocketEvent.NOTIFICATION, {
|
||||
title: 'Server message',
|
||||
message: 'Failed to teleport'
|
||||
})
|
||||
}
|
||||
|
||||
this.socket.emit('notification', {
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, {
|
||||
title: 'Server message',
|
||||
message: `Teleported to ${map.name} (${targetX}, ${targetY})`
|
||||
})
|
||||
this.logger.info('teleport', `Character ${character.id} teleported to map ${map.id} at position (${targetX}, ${targetY})`)
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Error in teleport command: ${error.message}`)
|
||||
this.socket.emit('notification', {
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, {
|
||||
title: 'Server message',
|
||||
message: 'An error occurred while teleporting'
|
||||
})
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import WeatherManager from '#managers/weatherManager'
|
||||
import ChatService from '#services/chatService'
|
||||
@ -8,7 +9,7 @@ type TypePayload = {
|
||||
|
||||
export default class ToggleFogCommand extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('chat:message', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.CHAT_MESSAGE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import WeatherManager from '#managers/weatherManager'
|
||||
import ChatService from '#services/chatService'
|
||||
@ -8,7 +9,7 @@ type TypePayload = {
|
||||
|
||||
export default class ToggleRainCommand extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('chat:message', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.CHAT_MESSAGE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import MapManager from '#managers/mapManager'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
@ -9,7 +10,7 @@ type TypePayload = {
|
||||
|
||||
export default class ChatMessageEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('chat:message', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.CHAT_MESSAGE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: TypePayload, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import MapManager from '#managers/mapManager'
|
||||
|
||||
export default class DisconnectEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('disconnect', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.DISCONNECT, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(): Promise<void> {
|
||||
@ -13,7 +14,7 @@ export default class DisconnectEvent extends BaseEvent {
|
||||
return
|
||||
}
|
||||
|
||||
this.io.emit('user:disconnect', this.socket.userId)
|
||||
this.io.emit(SocketEvent.USER_DISCONNECT, this.socket.userId)
|
||||
|
||||
const mapCharacter = MapManager.getCharacterById(this.socket.characterId!)
|
||||
if (!mapCharacter) {
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterHair } from '#entities/characterHair'
|
||||
|
||||
export default class CharacterHairCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterHair:create', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_CHARACTERHAIR_CREATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: undefined, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,27 +1,32 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
|
||||
interface IPayload {
|
||||
id: UUID
|
||||
}
|
||||
|
||||
export default class characterHairDeleteEvent extends BaseEvent {
|
||||
export default class CharacterHairDeleteEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterHair:remove', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_CHARACTERHAIR_REMOVE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const characterHair = await CharacterHairRepository.getById(data.id)
|
||||
await (await CharacterHairRepository.getById(data.id))?.delete()
|
||||
const characterHairRepository = new CharacterHairRepository()
|
||||
const characterHair = await characterHairRepository.getById(data.id)
|
||||
if (!characterHair) return callback(false)
|
||||
|
||||
await characterHair.delete()
|
||||
|
||||
return callback(true)
|
||||
} catch (error) {
|
||||
this.logger.error(`Error deleting character type ${data.id}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
callback(false)
|
||||
this.logger.error(`Error deleting character hair ${data.id}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
return callback(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterHair } from '#entities/characterHair'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
@ -6,7 +7,7 @@ interface IPayload {}
|
||||
|
||||
export default class characterHairListEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterHair:list', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_CHARACTERHAIR_LIST, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise<void> {
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterGender } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
|
||||
@ -14,7 +16,7 @@ type Payload = {
|
||||
|
||||
export default class CharacterHairUpdateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterHair:update', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_CHARACTERHAIR_UPDATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterType } from '#entities/characterType'
|
||||
|
||||
export default class CharacterTypeCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterType:create', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_CHARACTERTYPE_CREATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: undefined, callback: (response: boolean, characterType?: any) => void): Promise<void> {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import CharacterTypeRepository from '#repositories/characterTypeRepository'
|
||||
|
||||
interface IPayload {
|
||||
@ -8,7 +10,7 @@ interface IPayload {
|
||||
|
||||
export default class CharacterTypeDeleteEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterType:remove', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_CHARACTERTYPE_REMOVE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterType } from '#entities/characterType'
|
||||
import CharacterTypeRepository from '#repositories/characterTypeRepository'
|
||||
@ -6,7 +7,7 @@ interface IPayload {}
|
||||
|
||||
export default class CharacterTypeListEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterType:list', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_CHARACTERTYPE_LIST, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: CharacterType[]) => void): Promise<void> {
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterGender, CharacterRace } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import CharacterTypeRepository from '#repositories/characterTypeRepository'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
|
||||
@ -15,7 +17,7 @@ type Payload = {
|
||||
|
||||
export default class CharacterTypeUpdateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:characterType:update', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_CHARACTERTYPE_UPDATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
|
||||
|
@ -1,17 +1,24 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { ItemRarity, ItemType } from '#application/enums'
|
||||
import { Item } from '#entities/item'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
|
||||
export default class ItemCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:item:create', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_ITEM_CREATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: undefined, callback: (response: boolean, item?: any) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const sprite = await spriteRepository.getFirst()
|
||||
if (!sprite) return callback(false)
|
||||
|
||||
const newItem = new Item()
|
||||
await newItem.setName('New Item').setItemType('WEAPON').setStackable(false).setRarity('COMMON').setSprite(null).save()
|
||||
await newItem.setName('New Item').setItemType(ItemType.WEAPON).setStackable(false).setRarity(ItemRarity.COMMON).setSprite(sprite).save()
|
||||
|
||||
return callback(true, newItem)
|
||||
} catch (error) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import ItemRepository from '#repositories/itemRepository'
|
||||
|
||||
interface IPayload {
|
||||
@ -8,7 +10,7 @@ interface IPayload {
|
||||
|
||||
export default class ItemDeleteEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:item:remove', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_ITEM_REMOVE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Item } from '#entities/item'
|
||||
import ItemRepository from '#repositories/itemRepository'
|
||||
@ -6,7 +7,7 @@ interface IPayload {}
|
||||
|
||||
export default class ItemListEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:item:list', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_ITEM_LIST, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Item[]) => void): Promise<void> {
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { ItemType, ItemRarity } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import ItemRepository from '#repositories/itemRepository'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
|
||||
@ -16,7 +18,7 @@ type Payload = {
|
||||
|
||||
export default class ItemUpdateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:item:update', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_ITEM_UPDATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { MapObject } from '#entities/mapObject'
|
||||
import MapObjectRepository from '#repositories/mapObjectRepository'
|
||||
@ -6,7 +7,7 @@ interface IPayload {}
|
||||
|
||||
export default class MapObjectListEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:mapObject:list', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_MAPOBJECT_LIST, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: MapObject[]) => void): Promise<void> {
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import fs from 'fs'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import Storage from '#application/storage'
|
||||
import { UUID } from '#application/types'
|
||||
import MapObjectRepository from '#repositories/mapObjectRepository'
|
||||
|
||||
interface IPayload {
|
||||
@ -11,7 +13,7 @@ interface IPayload {
|
||||
|
||||
export default class MapObjectRemoveEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:mapObject:remove', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_MAPOBJECT_REMOVE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import MapObjectRepository from '#repositories/mapObjectRepository'
|
||||
|
||||
type Payload = {
|
||||
@ -15,7 +17,7 @@ type Payload = {
|
||||
|
||||
export default class MapObjectUpdateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:mapObject:update', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_MAPOBJECT_UPDATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
|
||||
@ -27,19 +29,19 @@ export default class MapObjectUpdateEvent extends BaseEvent {
|
||||
const mapObject = await mapObjectRepository.getById(data.id)
|
||||
if (!mapObject) return callback(false)
|
||||
|
||||
await mapObject
|
||||
.setName(data.name)
|
||||
.setTags(data.tags)
|
||||
.setOriginX(data.originX)
|
||||
.setOriginY(data.originY)
|
||||
.setFrameRate(data.frameRate)
|
||||
.setFrameWidth(data.frameWidth)
|
||||
.setFrameHeight(data.frameHeight)
|
||||
.save()
|
||||
if (data.name !== undefined) mapObject.name = data.name
|
||||
if (data.tags !== undefined) mapObject.tags = data.tags
|
||||
if (data.originX !== undefined) mapObject.originX = data.originX
|
||||
if (data.originY !== undefined) mapObject.originY = data.originY
|
||||
if (data.frameRate !== undefined) mapObject.frameRate = data.frameRate
|
||||
if (data.frameWidth !== undefined) mapObject.frameWidth = data.frameWidth
|
||||
if (data.frameHeight !== undefined) mapObject.frameHeight = data.frameHeight
|
||||
|
||||
await mapObject.save()
|
||||
|
||||
return callback(true)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, { title: 'Error', message: 'Failed to update mapObject.' })
|
||||
return callback(false)
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import fs from 'fs/promises'
|
||||
import { writeFile } from 'node:fs/promises'
|
||||
|
||||
@ -13,7 +14,7 @@ interface IObjectData {
|
||||
|
||||
export default class MapObjectUploadEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:mapObject:upload', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_MAPOBJECT_UPLOAD, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IObjectData, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
|
||||
@ -9,7 +11,7 @@ interface CopyPayload {
|
||||
|
||||
export default class SpriteCopyEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:sprite:copy', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_SPRITE_COPY, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(payload: CopyPayload, callback: (success: boolean) => void): Promise<void> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
@ -6,7 +7,7 @@ import { Sprite } from '#entities/sprite'
|
||||
|
||||
export default class SpriteCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:sprite:create', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_SPRITE_CREATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: undefined, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import fs from 'fs'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import Storage from '#application/storage'
|
||||
import { UUID } from '#application/types'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
|
||||
type Payload = {
|
||||
@ -11,7 +13,7 @@ type Payload = {
|
||||
|
||||
export default class GMSpriteDeleteEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:sprite:delete', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_SPRITE_DELETE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
@ -6,7 +7,7 @@ interface IPayload {}
|
||||
|
||||
export default class SpriteListEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:sprite:list', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_SPRITE_LIST, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Sprite[]) => void): Promise<void> {
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import fs from 'fs'
|
||||
|
||||
import sharp from 'sharp'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import { SpriteAction } from '#entities/spriteAction'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
|
||||
@ -43,7 +45,7 @@ type Payload = {
|
||||
|
||||
export default class SpriteUpdateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:sprite:update', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_SPRITE_UPDATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import Storage from '#application/storage'
|
||||
import { UUID } from '#application/types'
|
||||
import TileRepository from '#repositories/tileRepository'
|
||||
|
||||
type Payload = {
|
||||
@ -11,7 +13,7 @@ type Payload = {
|
||||
|
||||
export default class GMTileDeleteEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:tile:delete', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_TILE_DELETE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Tile } from '#entities/tile'
|
||||
import TileRepository from '#repositories/tileRepository'
|
||||
@ -6,7 +7,7 @@ interface IPayload {}
|
||||
|
||||
export default class TileListEven extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:tile:list', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_TILE_LIST, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Tile[]) => void): Promise<void> {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import TileRepository from '#repositories/tileRepository'
|
||||
|
||||
type Payload = {
|
||||
@ -10,7 +12,7 @@ type Payload = {
|
||||
|
||||
export default class TileUpdateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:tile:update', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_TILE_UPDATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import fs from 'fs/promises'
|
||||
import { writeFile } from 'node:fs/promises'
|
||||
|
||||
@ -11,7 +12,7 @@ interface ITileData {
|
||||
|
||||
export default class TileUploadEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:tile:upload', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_TILE_UPLOAD, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: ITileData, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,5 +1,8 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { MapCacheT } from '#entities/map'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Map, MapCacheT } from '#entities/map'
|
||||
import { Map } from '#entities/map'
|
||||
|
||||
type Payload = {
|
||||
name: string
|
||||
@ -9,7 +12,7 @@ type Payload = {
|
||||
|
||||
export default class MapCreateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:map:create', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_MAP_CREATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (response: MapCacheT | false) => void): Promise<void> {
|
||||
@ -19,12 +22,12 @@ export default class MapCreateEvent extends BaseEvent {
|
||||
this.logger.info(`GM ${(await this.getCharacter())!.getId()} has created a new map via map editor.`)
|
||||
|
||||
if (data.name === '') {
|
||||
this.socket.emit('notification', { message: 'Map name cannot be empty.' })
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, { title: 'Error', message: 'Map name cannot be empty.' })
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
if (data.width < 1 || data.height < 1) {
|
||||
this.socket.emit('notification', { message: 'Map width and height must be greater than 0.' })
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, { title: 'Error', message: 'Map width and height must be greater than 0.' })
|
||||
return callback(false)
|
||||
}
|
||||
|
||||
@ -39,7 +42,7 @@ export default class MapCreateEvent extends BaseEvent {
|
||||
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.' })
|
||||
this.socket.emit(SocketEvent.NOTIFICATION, { message: 'Failed to create map.' })
|
||||
return callback(false)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
|
||||
type Payload = {
|
||||
@ -8,7 +10,7 @@ type Payload = {
|
||||
|
||||
export default class MapDeleteEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:map:delete', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_MAP_DELETE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (response: boolean) => void): Promise<void> {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
|
||||
@ -9,7 +11,7 @@ interface IPayload {
|
||||
|
||||
export default class MapRequestEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:map:request', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_MAP_REQUEST, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Map | null) => void): Promise<void> {
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { MapEventTileType } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
import { MapEffect } from '#entities/mapEffect'
|
||||
import { MapEventTile } from '#entities/mapEventTile'
|
||||
@ -33,7 +35,7 @@ interface IPayload {
|
||||
|
||||
export default class MapUpdateEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:map:update', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.GM_MAP_UPDATE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Map | null) => void): Promise<void> {
|
||||
@ -62,9 +64,11 @@ export default class MapUpdateEvent extends BaseEvent {
|
||||
if (data.tiles.length > data.height) {
|
||||
data.tiles = data.tiles.slice(0, data.height)
|
||||
}
|
||||
|
||||
for (let i = 0; i < data.tiles.length; i++) {
|
||||
if (data.tiles[i].length > data.width) {
|
||||
data.tiles[i] = data.tiles[i].slice(0, data.width)
|
||||
const row = data.tiles[i]
|
||||
if (row !== undefined && row.length > data.width) {
|
||||
data.tiles[i] = row.slice(0, data.width)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import UserRepository from '#repositories/userRepository'
|
||||
|
||||
export default class LoginEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('login', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.LOGIN, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent() {
|
||||
@ -14,7 +15,7 @@ export default class LoginEvent extends BaseEvent {
|
||||
}
|
||||
|
||||
const userRepository = new UserRepository()
|
||||
this.socket.emit('logged_in', { user: userRepository.getById(this.socket.userId) })
|
||||
this.socket.emit(SocketEvent.LOGGED_IN, { user: userRepository.getById(this.socket.userId) })
|
||||
this.logger.info(`User logged in: ${this.socket.userId}`)
|
||||
} catch (error: any) {
|
||||
this.logger.error('login error: ' + error.message)
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import CharacterAttackService from '#services/characterAttackService'
|
||||
|
||||
@ -5,7 +6,7 @@ export default class CharacterMove extends BaseEvent {
|
||||
private readonly characterAttackService = CharacterAttackService
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('map:character:attack', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.MAP_CHARACTER_ATTACK, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: any, callback: (response: any) => void): Promise<void> {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import type { MapEventTileWithTeleport } from '#application/types'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { MapEventTileWithTeleport } from '#application/types'
|
||||
import MapManager from '#managers/mapManager'
|
||||
import MapCharacter from '#models/mapCharacter'
|
||||
import MapEventTileRepository from '#repositories/mapEventTileRepository'
|
||||
@ -8,9 +10,10 @@ import TeleportService from '#services/characterTeleportService'
|
||||
|
||||
export default class CharacterMove extends BaseEvent {
|
||||
private readonly characterService = CharacterService
|
||||
private readonly MOVEMENT_THROTTLE = 230 // Minimum time between movement requests
|
||||
|
||||
public listen(): void {
|
||||
this.socket.on('map:character:move', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.MAP_CHARACTER_MOVE, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent({ positionX, positionY }: { positionX: number; positionY: number }): Promise<void> {
|
||||
@ -20,61 +23,96 @@ export default class CharacterMove extends BaseEvent {
|
||||
return
|
||||
}
|
||||
|
||||
// If already moving, cancel current movement and wait for it to fully stop
|
||||
if (mapCharacter.isMoving) {
|
||||
mapCharacter.isMoving = false
|
||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||
if (this.isThrottled(`movement_${this.socket.characterId}`, this.MOVEMENT_THROTTLE)) {
|
||||
// Only cancel current movement if the new target is different
|
||||
if (mapCharacter.isMoving &&
|
||||
(Math.floor(positionX) !== Math.floor(mapCharacter.character.positionX) ||
|
||||
Math.floor(positionY) !== Math.floor(mapCharacter.character.positionY))) {
|
||||
mapCharacter.isMoving = false
|
||||
mapCharacter.currentPath = null
|
||||
// this.finalizeMovement(mapCharacter)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// If already moving, cancel current movement
|
||||
if (mapCharacter.isMoving && mapCharacter.currentPath && mapCharacter.currentPath.length > 2) {
|
||||
mapCharacter.isMoving = false
|
||||
mapCharacter.currentPath = null
|
||||
}
|
||||
|
||||
// Validate target position is within reasonable range
|
||||
const currentX = mapCharacter.character.positionX
|
||||
const currentY = mapCharacter.character.positionY
|
||||
const distance = Math.sqrt(Math.pow(positionX - currentX, 2) + Math.pow(positionY - currentY, 2))
|
||||
|
||||
const path = await this.characterService.calculatePath(mapCharacter.character, positionX, positionY)
|
||||
if (!path) {
|
||||
this.io.in(mapCharacter.character.map.id).emit('map:character:moveError', 'No valid path found')
|
||||
if (!path?.length) {
|
||||
this.io.in(mapCharacter.character.map.id).emit(SocketEvent.MAP_CHARACTER_MOVEERROR, 'No valid path found')
|
||||
return
|
||||
}
|
||||
|
||||
// Start new movement
|
||||
mapCharacter.isMoving = true
|
||||
mapCharacter.currentPath = path // Add this property to MapCharacter class
|
||||
mapCharacter.currentPath = path
|
||||
await this.moveAlongPath(mapCharacter, path)
|
||||
}
|
||||
|
||||
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++) {
|
||||
if (!mapCharacter.isMoving || mapCharacter.currentPath !== path) {
|
||||
return
|
||||
try {
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
if (!mapCharacter.isMoving || mapCharacter.currentPath !== path) {
|
||||
return
|
||||
}
|
||||
|
||||
const [start, end] = [path[i], path[i + 1]]
|
||||
|
||||
if (!start || !end) {
|
||||
this.logger.error('Invalid path step detected')
|
||||
break
|
||||
}
|
||||
|
||||
if (i !== 0) {
|
||||
await this.characterService.applyMovementDelay()
|
||||
}
|
||||
|
||||
// Validate each step
|
||||
if (Math.abs(end.positionX - start.positionX) > 1 || Math.abs(end.positionY - start.positionY) > 1) {
|
||||
this.logger.error('Invalid path step detected')
|
||||
break
|
||||
}
|
||||
|
||||
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.positionX), Math.floor(end.positionY))
|
||||
|
||||
if (mapEventTile?.type === 'BLOCK') break
|
||||
if (mapEventTile?.type === 'TELEPORT' && mapEventTile.teleport) {
|
||||
await this.handleTeleportMapEventTile(mapEventTile as MapEventTileWithTeleport)
|
||||
return
|
||||
}
|
||||
|
||||
// Update position first
|
||||
character.setPositionX(end.positionX).setPositionY(end.positionY)
|
||||
|
||||
// Then emit with the same properties
|
||||
this.io.in(character.map.id).emit(SocketEvent.MAP_CHARACTER_MOVE, {
|
||||
characterId: character.id,
|
||||
positionX: character.getPositionX(),
|
||||
positionY: character.getPositionY(),
|
||||
rotation: character.getRotation(),
|
||||
isMoving: true
|
||||
})
|
||||
|
||||
await this.characterService.applyMovementDelay()
|
||||
}
|
||||
|
||||
const [start, end] = [path[i], path[i + 1]]
|
||||
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.positionX), Math.floor(end.positionY))
|
||||
|
||||
if (mapEventTile?.type === 'BLOCK') break
|
||||
if (mapEventTile?.type === 'TELEPORT' && mapEventTile.teleport) {
|
||||
await this.handleTeleportMapEventTile(mapEventTile as MapEventTileWithTeleport)
|
||||
return
|
||||
} finally {
|
||||
if (mapCharacter.isMoving && mapCharacter.currentPath === path) {
|
||||
this.finalizeMovement(mapCharacter)
|
||||
}
|
||||
|
||||
// Update position first
|
||||
character.setPositionX(end.positionX).setPositionY(end.positionY)
|
||||
|
||||
// Then emit with the same properties
|
||||
this.io.in(character.map.id).emit('map:character:move', {
|
||||
characterId: character.id,
|
||||
positionX: character.getPositionX(),
|
||||
positionY: character.getPositionY(),
|
||||
rotation: character.getRotation(),
|
||||
isMoving: true
|
||||
})
|
||||
|
||||
await this.characterService.applyMovementDelay()
|
||||
}
|
||||
|
||||
if (mapCharacter.isMoving && mapCharacter.currentPath === path) {
|
||||
this.finalizeMovement(mapCharacter)
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,12 +129,12 @@ export default class CharacterMove extends BaseEvent {
|
||||
|
||||
private finalizeMovement(mapCharacter: MapCharacter): void {
|
||||
mapCharacter.isMoving = false
|
||||
this.io.in(mapCharacter.character.map.id).emit('map:character:move', {
|
||||
this.io.in(mapCharacter.character.map.id).emit(SocketEvent.MAP_CHARACTER_MOVE, {
|
||||
characterId: mapCharacter.character.id,
|
||||
positionX: mapCharacter.character.positionX,
|
||||
positionY: mapCharacter.character.positionY,
|
||||
rotation: mapCharacter.character.rotation,
|
||||
isMoving: false
|
||||
isMoving: mapCharacter.isMoving
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import WeatherManager from '#managers/weatherManager'
|
||||
|
||||
export default class Weather extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('weather', this.handleEvent.bind(this))
|
||||
this.socket.on(SocketEvent.WEATHER, this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(): Promise<void> {
|
||||
try {
|
||||
const weather = WeatherManager.getWeatherState()
|
||||
this.socket.emit('weather', weather)
|
||||
this.socket.emit(SocketEvent.WEATHER, weather)
|
||||
} catch (error: any) {
|
||||
this.logger.error('weather error: ' + error.message)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { Server as SocketServer } from 'socket.io'
|
||||
|
||||
import { TSocket } from '#application/types'
|
||||
import type { TSocket } from '#application/types'
|
||||
|
||||
export default class SomeJob {
|
||||
constructor(private params: any) {}
|
||||
@ -8,9 +9,9 @@ export default class SomeJob {
|
||||
async execute(io: SocketServer, socket?: TSocket) {
|
||||
// Handle the event
|
||||
if (socket) {
|
||||
socket.emit('notification', { message: 'Something happened with socket' })
|
||||
socket.emit(SocketEvent.NOTIFICATION, { message: 'Something happened with socket' })
|
||||
}
|
||||
// Use io for broadcasting if needed
|
||||
io.emit('notification', { message: 'Something happened' })
|
||||
io.emit(SocketEvent.NOTIFICATION, { message: 'Something happened' })
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,11 @@ export class ConsoleManager {
|
||||
private async processCommand(commandLine: string): Promise<void> {
|
||||
const [cmd, ...args] = commandLine.trim().split(' ')
|
||||
|
||||
if (!cmd) {
|
||||
console.log('No command provided')
|
||||
return
|
||||
}
|
||||
|
||||
if (cmd === 'exit') {
|
||||
this.prompt.close()
|
||||
return
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
@ -8,16 +9,14 @@ import WorldRepository from '#repositories/worldRepository'
|
||||
class DateManager {
|
||||
private static readonly CONFIG = {
|
||||
GAME_SPEED: 8, // 24 game hours / 3 real hours
|
||||
UPDATE_INTERVAL: 1000 // 1 second
|
||||
UPDATE_INTERVAL: 1000 // 1 minute
|
||||
} as const
|
||||
|
||||
private io: Server | null = null
|
||||
private intervalId: NodeJS.Timeout | null = null
|
||||
private currentDate = new Date()
|
||||
private readonly logger = Logger.type(LoggerType.APP)
|
||||
private currentDate = new Date()
|
||||
private intervalId: NodeJS.Timeout | null = null
|
||||
|
||||
public async boot(): Promise<void> {
|
||||
this.io = SocketManager.getIO()
|
||||
await this.loadDate()
|
||||
this.startDateLoop()
|
||||
this.logger.info('Date manager loaded')
|
||||
@ -61,6 +60,7 @@ class DateManager {
|
||||
|
||||
if (timeOnlyPattern.test(timeString)) {
|
||||
const [hours, minutes] = timeString.split(':').map(Number)
|
||||
if (!hours || !minutes) return null
|
||||
const newDate = new Date(this.currentDate)
|
||||
newDate.setHours(hours, minutes)
|
||||
return newDate
|
||||
@ -84,7 +84,8 @@ class DateManager {
|
||||
}
|
||||
|
||||
private emitDate(): void {
|
||||
this.io?.emit('date', this.currentDate)
|
||||
const io = SocketManager.getIO()
|
||||
io?.emit(SocketEvent.DATE, this.currentDate)
|
||||
}
|
||||
|
||||
private async saveDate(): Promise<void> {
|
||||
|
@ -1,7 +1,12 @@
|
||||
import fs from 'fs'
|
||||
import { createServer as httpServer, Server as HTTPServer } from 'http'
|
||||
import { createServer as httpsServer, Server as HTTPSServer } from 'https'
|
||||
|
||||
import cors from 'cors'
|
||||
import { Application } from 'express'
|
||||
import express, { type Application } from 'express'
|
||||
|
||||
import config from '#application/config'
|
||||
import Logger, { LoggerType } from '#application/logger.js'
|
||||
import { AuthController } from '#controllers/auth'
|
||||
import { AvatarController } from '#controllers/avatar'
|
||||
import { CacheController } from '#controllers/cache'
|
||||
@ -11,16 +16,40 @@ import { TexturesController } from '#controllers/textures'
|
||||
* HTTP manager
|
||||
*/
|
||||
class HttpManager {
|
||||
private readonly app: Application
|
||||
private readonly server: HTTPServer | HTTPSServer
|
||||
private readonly logger = Logger.type(LoggerType.APP)
|
||||
private readonly authController: AuthController = new AuthController()
|
||||
private readonly avatarController: AvatarController = new AvatarController()
|
||||
private readonly texturesController: TexturesController = new TexturesController()
|
||||
private readonly cacheController: CacheController = new CacheController()
|
||||
|
||||
constructor() {
|
||||
this.app = express()
|
||||
this.app.use(cors())
|
||||
this.app.use(express.json())
|
||||
this.app.use(express.urlencoded({ extended: true }))
|
||||
|
||||
if (config.PUBLIC_KEY_PATH && config.PRIVATE_KEY_PATH) {
|
||||
const credentials = {
|
||||
key: fs.readFileSync(config.PRIVATE_KEY_PATH),
|
||||
cert: fs.readFileSync(config.PUBLIC_KEY_PATH)
|
||||
}
|
||||
this.server = httpsServer(credentials, this.app)
|
||||
this.logger.info('HTTPS server initialized')
|
||||
} else {
|
||||
this.server = httpServer(this.app)
|
||||
this.logger.info('HTTP server initialized')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize HTTP manager
|
||||
* @param app
|
||||
*/
|
||||
public async boot(app: Application) {
|
||||
this.server.listen(config.PORT, config.HOST)
|
||||
|
||||
// Add CORS middleware
|
||||
app.use(
|
||||
cors({
|
||||
@ -33,6 +62,8 @@ class HttpManager {
|
||||
|
||||
// Add routes
|
||||
await this.addRoutes(app)
|
||||
|
||||
this.logger.info(`HTTP running on port ${config.PORT}`)
|
||||
}
|
||||
|
||||
private async addRoutes(app: Application) {
|
||||
@ -57,6 +88,14 @@ class HttpManager {
|
||||
app.get('/cache/character_types', (req, res) => this.cacheController.characterTypes(req, res))
|
||||
app.get('/cache/character_hair', (req, res) => this.cacheController.characterHair(req, res))
|
||||
}
|
||||
|
||||
getAppInstance(): Application {
|
||||
return this.app
|
||||
}
|
||||
|
||||
getServerInstance(): HTTPServer | HTTPSServer {
|
||||
return this.server
|
||||
}
|
||||
}
|
||||
|
||||
export default new HttpManager()
|
||||
|
@ -1,5 +1,6 @@
|
||||
import type { UUID } from '#application/types'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
import LoadedMap from '#models/loadedMap'
|
||||
import MapCharacter from '#models/mapCharacter'
|
||||
|
@ -4,14 +4,15 @@ import { Job, Queue, Worker } from 'bullmq'
|
||||
import IORedis from 'ioredis'
|
||||
import { Server as SocketServer } from 'socket.io'
|
||||
|
||||
import type { TSocket } from '#application/types'
|
||||
|
||||
import config from '#application/config'
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import Storage from '#application/storage'
|
||||
import { TSocket } from '#application/types'
|
||||
import SocketManager from '#managers/socketManager'
|
||||
|
||||
class QueueManager {
|
||||
private connection!: IORedis
|
||||
private connection!: IORedis.Redis
|
||||
private queue!: Queue
|
||||
private worker!: Worker
|
||||
private io!: SocketServer
|
||||
@ -20,7 +21,7 @@ class QueueManager {
|
||||
public async boot() {
|
||||
this.io = SocketManager.getIO()
|
||||
|
||||
this.connection = new IORedis(config.REDIS_URL, {
|
||||
this.connection = new IORedis.Redis(config.REDIS_URL, {
|
||||
maxRetriesPerRequest: null
|
||||
})
|
||||
|
||||
|
@ -2,12 +2,13 @@ import fs from 'fs'
|
||||
import { Server as HTTPServer } from 'http'
|
||||
import { pathToFileURL } from 'url'
|
||||
|
||||
import { Application } from 'express'
|
||||
import { Server as SocketServer } from 'socket.io'
|
||||
|
||||
import type { TSocket, UUID } from '#application/types'
|
||||
import type { Application } from 'express'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import Storage from '#application/storage'
|
||||
import { TSocket, UUID } from '#application/types'
|
||||
import { Authentication } from '#middleware/authentication'
|
||||
|
||||
class SocketManager {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { User } from '@prisma/client'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import { User } from '#entities/user'
|
||||
|
||||
type TLoggedInUsers = {
|
||||
users: User[]
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { SocketEvent } from '#application/enums';
|
||||
import { Server } from 'socket.io'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
@ -20,7 +21,6 @@ class WeatherManager {
|
||||
} as const
|
||||
|
||||
private readonly logger = Logger.type(LoggerType.APP)
|
||||
private io: Server | null = null
|
||||
private intervalId: NodeJS.Timeout | null = null
|
||||
|
||||
private weatherState: WeatherState = {
|
||||
@ -29,7 +29,6 @@ class WeatherManager {
|
||||
}
|
||||
|
||||
public async boot(): Promise<void> {
|
||||
this.io = SocketManager.getIO()
|
||||
await this.loadWeather()
|
||||
this.startWeatherLoop()
|
||||
this.logger.info('Weather manager loaded')
|
||||
@ -113,7 +112,8 @@ class WeatherManager {
|
||||
}
|
||||
|
||||
private emitWeather(): void {
|
||||
this.io?.emit('weather', this.weatherState)
|
||||
const io = SocketManager.getIO()
|
||||
io?.emit(SocketEvent.WEATHER, this.weatherState)
|
||||
}
|
||||
|
||||
private async saveWeather(): Promise<void> {
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { verify } from 'jsonwebtoken'
|
||||
import jwt from 'jsonwebtoken'
|
||||
|
||||
import type { TSocket } from '#application/types'
|
||||
|
||||
import config from '#application/config'
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import { TSocket } from '#application/types'
|
||||
|
||||
class SocketAuthenticator {
|
||||
private socket: TSocket
|
||||
@ -39,7 +40,7 @@ class SocketAuthenticator {
|
||||
}
|
||||
|
||||
private verifyToken(token: string): void {
|
||||
verify(token, config.JWT_SECRET, (err: any, decoded: any) => {
|
||||
jwt.verify(token, config.JWT_SECRET, (err: any, decoded: any) => {
|
||||
if (err) {
|
||||
this.logger.error('Invalid token')
|
||||
return this.next(new Error('Authentication error'))
|
||||
|
2079
src/migrations/.snapshot-game.json
Normal file
2079
src/migrations/.snapshot-game.json
Normal file
File diff suppressed because it is too large
Load Diff
162
src/migrations/Migration20250207212301.ts
Normal file
162
src/migrations/Migration20250207212301.ts
Normal file
@ -0,0 +1,162 @@
|
||||
import { Migration } from '@mikro-orm/migrations'
|
||||
|
||||
export class Migration20250207212301 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, \`teleport_id\` varchar(255) 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(`alter table \`map_event_tile\` add unique \`map_event_tile_teleport_id_unique\`(\`teleport_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\` numeric(5,2) not null default 0, \`origin_y\` numeric(5,2) 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\` add constraint \`map_event_tile_teleport_id_foreign\` foreign key (\`teleport_id\`) references \`map_event_tile_teleport\` (\`id\`) on update cascade on delete set null;`
|
||||
)
|
||||
|
||||
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;`
|
||||
)
|
||||
}
|
||||
}
|
@ -1,16 +1,16 @@
|
||||
// import { defineConfig, MariaDbDriver } from '@mikro-orm/mariadb'
|
||||
import { defineConfig, MariaDbDriver } from '@mikro-orm/mariadb'
|
||||
// import { defineConfig, MySqlDriver } from '@mikro-orm/mysql'
|
||||
import { Migrator } from '@mikro-orm/migrations'
|
||||
import { defineConfig, MySqlDriver } from '@mikro-orm/mysql'
|
||||
import { TsMorphMetadataProvider } from '@mikro-orm/reflection'
|
||||
|
||||
import serverConfig from './src/application/config'
|
||||
import serverConfig from '#application/config'
|
||||
|
||||
export default defineConfig({
|
||||
extensions: [Migrator],
|
||||
metadataProvider: TsMorphMetadataProvider,
|
||||
entities: ['./src/entities/*.js'],
|
||||
entities: ['./dist/entities/*.js'],
|
||||
entitiesTs: ['./src/entities/*.ts'],
|
||||
driver: MySqlDriver,
|
||||
driver: MariaDbDriver,
|
||||
host: serverConfig.DB_HOST,
|
||||
port: serverConfig.DB_PORT,
|
||||
user: serverConfig.DB_USER,
|
||||
@ -21,7 +21,7 @@ export default defineConfig({
|
||||
allowPublicKeyRetrieval: true
|
||||
},
|
||||
migrations: {
|
||||
path: './migrations',
|
||||
pathTs: './migrations',
|
||||
path: './dist/migrations',
|
||||
pathTs: './src/migrations'
|
||||
}
|
||||
})
|
||||
})
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user