Compare commits
51 Commits
issue/#307
...
feature/sp
Author | SHA1 | Date | |
---|---|---|---|
60753cb2db | |||
c400e868af | |||
eaa7385acc | |||
da2df6ace6 | |||
6f87c3f3c5 | |||
876c96e2c6 | |||
7fd33aa36b | |||
e57c19defd | |||
caf0e5c2f4 | |||
c8728ba83a | |||
b33b9cc29f | |||
3b65cae631 | |||
9d7cee2334 | |||
dbdc8c9d6e | |||
d17408acd9 | |||
5680b324b4 | |||
9771f45e6d | |||
b3ac6d34b8 | |||
b115181756 | |||
bf4789b9a8 | |||
f004f059f6 | |||
e6adb959ba | |||
85161ab4f6 | |||
8f4d4fc482 | |||
a0584c2bb9 | |||
7f4a784915 | |||
71fdbd89a4 | |||
5c34ed7286 | |||
edb7836e55 | |||
112559055c | |||
1546deb811 | |||
d7ac70662a | |||
dae0d365d5 | |||
020f2bd3c5 | |||
189fd39377 | |||
0ba79c2299 | |||
74f5214ca3 | |||
410d5cb7a8 | |||
41e65fc3e9 | |||
4b6935c44a | |||
4232042a06 | |||
3869eefaaf | |||
a4437fadce | |||
458293a5fc | |||
849ef07297 | |||
39ec4daa06 | |||
010454914b | |||
f47023dc81 | |||
4397552a86 | |||
7dabed7ff6 | |||
d91a70be09 |
@ -3,7 +3,7 @@ ENV=development
|
||||
HOST="0.0.0.0"
|
||||
PORT=4000
|
||||
JWT_SECRET="secret"
|
||||
CLIENT_URL="http://192.168.3.4:5173"
|
||||
CLIENT_URL="http://localhost:5173"
|
||||
|
||||
# Database configuration
|
||||
REDIS_URL="redis://@127.0.0.1:6379/4"
|
||||
|
12
README.md
12
README.md
@ -2,12 +2,22 @@
|
||||
|
||||
This is the server for the Noxious game.
|
||||
|
||||
## Projects requirements
|
||||
|
||||
- NodeJS 20.x or higher
|
||||
- MySQL 8.x or higher
|
||||
- Redis 7.x or higher
|
||||
|
||||
## Installation
|
||||
|
||||
1. Clone the repository
|
||||
2. Install dependencies with `npm install`
|
||||
3. Copy the `.env.example` file to `.env` and fill in the required variables
|
||||
4. Run the server with `npm run dev`
|
||||
4. Extract assets.zip to the `public` folder
|
||||
5. After MySQL and Redis are running, run `npx mikro-orm migration:up` to create the database schema
|
||||
6. Run the server with `npm run dev`
|
||||
7. Write `init` in the console to import default data and restart the server
|
||||
8. Write `tiles` in the console to fix tile sizes
|
||||
|
||||
## Commands
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20250106170204 extends Migration {
|
||||
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;`);
|
||||
@ -15,9 +15,9 @@ export class Migration20250106170204 extends Migration {
|
||||
this.addSql(`alter table \`map_event_tile_teleport\` add unique \`map_event_tile_teleport_map_event_tile_id_unique\`(\`map_event_tile_id\`);`);
|
||||
this.addSql(`alter table \`map_event_tile_teleport\` add index \`map_event_tile_teleport_to_map_id_index\`(\`to_map_id\`);`);
|
||||
|
||||
this.addSql(`create table \`map_object\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`tags\` json null, \`origin_x\` numeric(10,2) not null default 0, \`origin_y\` numeric(10,2) not null default 0, \`is_animated\` tinyint(1) not null default false, \`frame_rate\` int not null default 0, \`frame_width\` int not null default 0, \`frame_height\` int not null default 0, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`create table \`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, \`depth\` int not null default 0, \`is_rotated\` tinyint(1) not null default false, \`position_x\` int not null default 0, \`position_y\` int not null default 0, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`create table \`placed_map_object\` (\`id\` varchar(255) not null, \`map_id\` varchar(255) not null, \`map_object_id\` varchar(255) not null, \`is_rotated\` tinyint(1) not null default false, \`position_x\` int not null default 0, \`position_y\` int not null default 0, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`placed_map_object\` add index \`placed_map_object_map_id_index\`(\`map_id\`);`);
|
||||
this.addSql(`alter table \`placed_map_object\` add index \`placed_map_object_map_object_id_index\`(\`map_object_id\`);`);
|
||||
|
||||
@ -29,10 +29,10 @@ export class Migration20250106170204 extends Migration {
|
||||
this.addSql(`create table \`character_type\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`gender\` enum('MALE', 'FEMALE') not null, \`race\` enum('HUMAN', 'ELF', 'DWARF', 'ORC', 'GOBLIN') not null, \`is_selectable\` tinyint(1) not null default false, \`sprite_id\` varchar(255) null, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`character_type\` add index \`character_type_sprite_id_index\`(\`sprite_id\`);`);
|
||||
|
||||
this.addSql(`create table \`character_hair\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`gender\` varchar(255) not null default 'MALE', \`is_selectable\` tinyint(1) not null default false, \`sprite_id\` varchar(255) null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`create table \`character_hair\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`gender\` varchar(255) not null default 'MALE', \`is_selectable\` tinyint(1) not null default false, \`sprite_id\` varchar(255) null, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`alter table \`character_hair\` add index \`character_hair_sprite_id_index\`(\`sprite_id\`);`);
|
||||
|
||||
this.addSql(`create table \`sprite_action\` (\`id\` varchar(255) not null, \`sprite_id\` varchar(255) not null, \`action\` varchar(255) not null, \`sprites\` json null, \`origin_x\` int not null default 0, \`origin_y\` int not null default 0, \`is_animated\` tinyint(1) not null default false, \`is_looping\` tinyint(1) not null default false, \`frame_width\` int not null default 0, \`frame_height\` int not null default 0, \`frame_rate\` int not null default 0, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
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;`);
|
||||
@ -64,7 +64,7 @@ export class Migration20250106170204 extends Migration {
|
||||
this.addSql(`alter table \`character_equipment\` add index \`character_equipment_character_id_index\`(\`character_id\`);`);
|
||||
this.addSql(`alter table \`character_equipment\` add index \`character_equipment_character_item_id_index\`(\`character_item_id\`);`);
|
||||
|
||||
this.addSql(`create table \`world\` (\`date\` datetime not null, \`is_rain_enabled\` tinyint(1) not null default false, \`rain_percentage\` int not null default 0, \`is_fog_enabled\` tinyint(1) not null default false, \`fog_density\` int not null default 0, primary key (\`date\`)) default character set utf8mb4 engine = InnoDB;`);
|
||||
this.addSql(`create table \`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;`);
|
||||
|
@ -16,8 +16,7 @@ export default defineConfig({
|
||||
user: serverConfig.DB_USER,
|
||||
password: serverConfig.DB_PASS,
|
||||
dbName: serverConfig.DB_NAME,
|
||||
debug: serverConfig.ENV !== 'production',
|
||||
// allowGlobalContext: true,
|
||||
debug: false,
|
||||
driverOptions: {
|
||||
allowPublicKeyRetrieval: true
|
||||
},
|
||||
|
520
package-lock.json
generated
520
package-lock.json
generated
@ -10,7 +10,6 @@
|
||||
"@mikro-orm/migrations": "^6.4.2",
|
||||
"@mikro-orm/mysql": "^6.4.2",
|
||||
"@mikro-orm/reflection": "^6.4.2",
|
||||
"@prisma/client": "^6.1.0",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bullmq": "^5.13.2",
|
||||
@ -41,7 +40,6 @@
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"nodemon": "^3.1.4",
|
||||
"prettier": "^3.3.3",
|
||||
"prisma": "^6.1.0",
|
||||
"tsx": "^4.19.2"
|
||||
}
|
||||
},
|
||||
@ -544,9 +542,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/core": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz",
|
||||
"integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==",
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.10.0.tgz",
|
||||
"integrity": "sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@ -605,9 +603,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz",
|
||||
"integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==",
|
||||
"version": "9.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz",
|
||||
"integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -625,12 +623,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/plugin-kit": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz",
|
||||
"integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==",
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz",
|
||||
"integrity": "sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/core": "^0.10.0",
|
||||
"levn": "^0.4.1"
|
||||
},
|
||||
"engines": {
|
||||
@ -1108,16 +1107,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mikro-orm/cli": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.2.tgz",
|
||||
"integrity": "sha512-aGOpVNNbymdkxIsHt+rD5hU25UlGbcPrd3zMdDVh0H5jttB1kr9MpAT4Jt4SXqZfTc1ff6h479eufUYJP3mZZQ==",
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.4.tgz",
|
||||
"integrity": "sha512-GgYpwZFLndijNa1YxPtGeHyqQM3uwXxxoXEh7qbG2MDggkpt8VYGMj66NLjykNv25meARCEdijE02DpVZh8eoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jercle/yargonaut": "1.1.5",
|
||||
"@mikro-orm/core": "6.4.2",
|
||||
"@mikro-orm/knex": "6.4.2",
|
||||
"fs-extra": "11.2.0",
|
||||
"@mikro-orm/core": "6.4.4",
|
||||
"@mikro-orm/knex": "6.4.4",
|
||||
"fs-extra": "11.3.0",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"yargs": "17.7.2"
|
||||
},
|
||||
@ -1130,17 +1129,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mikro-orm/core": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.2.tgz",
|
||||
"integrity": "sha512-sk+rGxZoj8zx9q819CeXLqMMLXF81s7pQZtrdg3XUCBnUVqsaVIsbBj5WpyojQXmCvxgenWqDE/ybM5ftbDP/w==",
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.4.tgz",
|
||||
"integrity": "sha512-1Ff+fJX7pZFaZt9ebFxPW2w8yDp/uz2VhSMqqop1538VRvTqHseTRI+2Tmm9oX5pm5y5YS7+FdgnyAx6FLWjHg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dataloader": "2.2.3",
|
||||
"dotenv": "16.4.7",
|
||||
"esprima": "4.0.1",
|
||||
"fs-extra": "11.2.0",
|
||||
"fs-extra": "11.3.0",
|
||||
"globby": "11.1.0",
|
||||
"mikro-orm": "6.4.2",
|
||||
"mikro-orm": "6.4.4",
|
||||
"reflect-metadata": "0.2.2"
|
||||
},
|
||||
"engines": {
|
||||
@ -1151,12 +1150,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mikro-orm/knex": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.2.tgz",
|
||||
"integrity": "sha512-vA72sVyR+8irrLsTP5f+zh84Q1a2tvzSfVgit4L/G+JOEgltG6F8Sfic/xt/1Wcis1zgNUiUL50ISQSLnhVNAw==",
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.4.tgz",
|
||||
"integrity": "sha512-lzTce9SrdD3zO9mQP0MXqXTPM1+X7DXP19SgFnhygLEcBfWPgx1iRxjxOWbLjdM6p41p0Fh+5W73bwF/4jrIfQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fs-extra": "11.2.0",
|
||||
"fs-extra": "11.3.0",
|
||||
"knex": "3.1.0",
|
||||
"sqlstring": "2.3.3"
|
||||
},
|
||||
@ -1182,12 +1181,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mikro-orm/mariadb": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/mariadb/-/mariadb-6.4.2.tgz",
|
||||
"integrity": "sha512-Ua2dE/Y/ozC5GYxukwaV1k/6nFL71/YNsnI65sOFGVFzxZLeMrgY4fbWBW/EZSZgZWcxvlDefhG9U8228R8cbA==",
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/mariadb/-/mariadb-6.4.4.tgz",
|
||||
"integrity": "sha512-mxTGdOPOyNR7kh18CL2xcFexFkYpyD6jIAQFJlUAmKrXEHpkcOuY8fIHGw8fqJW9eVfBjdNqyDEDjz9iAxFxLA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mikro-orm/knex": "6.4.2",
|
||||
"@mikro-orm/knex": "6.4.4",
|
||||
"mariadb": "3.4.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -1198,13 +1197,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mikro-orm/migrations": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/migrations/-/migrations-6.4.2.tgz",
|
||||
"integrity": "sha512-oLAOT+ejduIOb8rO6cJ8B6yr9bM17t22ejLPTxUnw1N093DXb31zWOg6Ptc8cicnB3BbFQGjQVw6Jf2e3vYpbA==",
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/migrations/-/migrations-6.4.4.tgz",
|
||||
"integrity": "sha512-eeN91BjV4RDizWu5r+z2taVhFivbLmj04udkJ4ZGrrYGB+DIH6nb7zqLKiLbKvHUknXkzNX10wEPOuav/wW+Kg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mikro-orm/knex": "6.4.2",
|
||||
"fs-extra": "11.2.0",
|
||||
"@mikro-orm/knex": "6.4.4",
|
||||
"fs-extra": "11.3.0",
|
||||
"umzug": "3.8.2"
|
||||
},
|
||||
"engines": {
|
||||
@ -1215,13 +1214,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mikro-orm/mysql": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/mysql/-/mysql-6.4.2.tgz",
|
||||
"integrity": "sha512-w6gch2Th/j7JJW1RUjt+naWsatiAJdHpTfrOBzsaYcjeZeW6qT2+igvbcLxq+pfQp+Ea3uZ21CxLKJOGKnVDnA==",
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/mysql/-/mysql-6.4.4.tgz",
|
||||
"integrity": "sha512-OnSsYnr/o8TLjmFXtwI2anuAyNj5Nrgde2uUY5pECGnUkN2jH9+8AdXQmlgljodYNmZrc04QbhbvG65PjL0LsA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@mikro-orm/knex": "6.4.2",
|
||||
"mysql2": "3.11.5"
|
||||
"@mikro-orm/knex": "6.4.4",
|
||||
"mysql2": "3.12.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18.12.0"
|
||||
@ -1231,13 +1230,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mikro-orm/reflection": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.4.2.tgz",
|
||||
"integrity": "sha512-tCqy9xKc97a+6NlOK8xhaJlnj2b7C2dDhu7vhkU0ks/WuCOigHOmg21ikhFPz4VfKbGYPStt2DoZBUU9mCkMmA==",
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.4.4.tgz",
|
||||
"integrity": "sha512-qNScd9vlQdbu5o34N834QGpXTH0OEgjZKZbZYqDzBbEzvMbz4VByXFiMFo0kw39/y2+RlB+hrH7kPfcAYIYQxA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"globby": "11.1.0",
|
||||
"ts-morph": "24.0.0"
|
||||
"ts-morph": "25.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18.12.0"
|
||||
@ -1359,74 +1358,6 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/client": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.1.0.tgz",
|
||||
"integrity": "sha512-AbQYc5+EJKm1Ydfq3KxwcGiy7wIbm4/QbjCKWWoNROtvy7d6a3gmAGkKjK0iUCzh+rHV8xDhD5Cge8ke/kiy5Q==",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=18.18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prisma": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"prisma": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/debug": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.1.0.tgz",
|
||||
"integrity": "sha512-0himsvcM4DGBTtvXkd2Tggv6sl2JyUYLzEGXXleFY+7Kp6rZeSS3hiTW9mwtUlXrwYbJP6pwlVNB7jYElrjWUg==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@prisma/engines": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.1.0.tgz",
|
||||
"integrity": "sha512-GnYJbCiep3Vyr1P/415ReYrgJUjP79fBNc1wCo7NP6Eia0CzL2Ot9vK7Infczv3oK7JLrCcawOSAxFxNFsAERQ==",
|
||||
"devOptional": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@prisma/debug": "6.1.0",
|
||||
"@prisma/engines-version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959",
|
||||
"@prisma/fetch-engine": "6.1.0",
|
||||
"@prisma/get-platform": "6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/engines-version": {
|
||||
"version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959.tgz",
|
||||
"integrity": "sha512-PdJqmYM2Fd8K0weOOtQThWylwjsDlTig+8Pcg47/jszMuLL9iLIaygC3cjWJLda69siRW4STlCTMSgOjZzvKPQ==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@prisma/fetch-engine": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.1.0.tgz",
|
||||
"integrity": "sha512-asdFi7TvPlEZ8CzSZ/+Du5wZ27q6OJbRSXh+S8ISZguu+S9KtS/gP7NeXceZyb1Jv1SM1S5YfiCv+STDsG6rrg==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@prisma/debug": "6.1.0",
|
||||
"@prisma/engines-version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959",
|
||||
"@prisma/get-platform": "6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/get-platform": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.1.0.tgz",
|
||||
"integrity": "sha512-ia8bNjboBoHkmKGGaWtqtlgQOhCi7+f85aOkPJKgNwWvYrT6l78KgojLekE8zMhVk0R9lWcifV0Pf8l3/15V0Q==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@prisma/debug": "6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rtsao/scc": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
|
||||
@ -1435,9 +1366,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rushstack/node-core-library": {
|
||||
"version": "5.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.10.1.tgz",
|
||||
"integrity": "sha512-BSb/KcyBHmUQwINrgtzo6jiH0HlGFmrUy33vO6unmceuVKTEyL2q+P0fQq2oB5hvXVWOEUhxB2QvlkZluvUEmg==",
|
||||
"version": "5.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.10.2.tgz",
|
||||
"integrity": "sha512-xOF/2gVJZTfjTxbo4BDj9RtQq/HFnrrKdtem4JkyRLnwsRz2UDTg8gA1/et10fBx5RxmZD9bYVGST69W8ME5OQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ajv": "~8.13.0",
|
||||
@ -1554,12 +1485,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rushstack/terminal": {
|
||||
"version": "0.14.4",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.14.4.tgz",
|
||||
"integrity": "sha512-NxACqERW0PHq8Rpq1V6v5iTHEwkRGxenjEW+VWqRYQ8T9puUzgmGHmEZUaUEDHAe9Qyvp0/Ew04sAiQw9XjhJg==",
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.14.5.tgz",
|
||||
"integrity": "sha512-TEOpNwwmsZVrkp0omnuTUTGZRJKTr6n6m4OITiNjkqzLAkcazVpwR1SOtBg6uzpkIBLgrcNHETqI8rbw3uiUfw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rushstack/node-core-library": "5.10.1",
|
||||
"@rushstack/node-core-library": "5.10.2",
|
||||
"supports-color": "~8.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@ -1587,12 +1518,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rushstack/ts-command-line": {
|
||||
"version": "4.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.23.2.tgz",
|
||||
"integrity": "sha512-JJ7XZX5K3ThBBva38aomgsPv1L7FV6XmSOcR6HtM7HDFZJkepqT65imw26h9ggGqMjsY0R9jcl30tzKcVj9aOQ==",
|
||||
"version": "4.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.23.3.tgz",
|
||||
"integrity": "sha512-HazKL8fv4HMQMzrKJCrOrhyBPPdzk7iajUXgsASwjQ8ROo1cmgyqxt/k9+SdmrNLGE1zATgRqMUH3s/6smbRMA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rushstack/terminal": "0.14.4",
|
||||
"@rushstack/terminal": "0.14.5",
|
||||
"@types/argparse": "1.0.38",
|
||||
"argparse": "~1.0.9",
|
||||
"string-argv": "~0.3.1"
|
||||
@ -1614,14 +1545,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@ts-morph/common": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.25.0.tgz",
|
||||
"integrity": "sha512-kMnZz+vGGHi4GoHnLmMhGNjm44kGtKUXGnOvrKmMwAuvNjM/PgKVGfUnL7IDvK7Jb2QQ82jq3Zmp04Gy+r3Dkg==",
|
||||
"version": "0.26.0",
|
||||
"resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.26.0.tgz",
|
||||
"integrity": "sha512-/RmKAtctStXqM5nECMQ46duT74Hoig/DBzhWXGHcodlDNrgRbsbwwHqSKFNbca6z9Xt/CUWMeXOsC9QEN1+rqw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-glob": "^3.3.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"path-browserify": "^1.0.1",
|
||||
"tinyglobby": "^0.2.9"
|
||||
"path-browserify": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
@ -1682,12 +1613,6 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
|
||||
@ -1731,9 +1656,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/geojson": {
|
||||
"version": "7946.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz",
|
||||
"integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==",
|
||||
"version": "7946.0.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
|
||||
"integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/http-errors": {
|
||||
@ -1767,12 +1692,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/jsonwebtoken": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz",
|
||||
"integrity": "sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==",
|
||||
"version": "9.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.8.tgz",
|
||||
"integrity": "sha512-7fx54m60nLFUVYlxAB1xpe9CBWX2vSrk50Y6ogRJ1v5xxtba7qXTg5BgYDN5dq+yuQQ9HaVlHJyAAt1/mxryFg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/ms": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
@ -1783,10 +1709,17 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/ms": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
|
||||
"integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.17.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.12.tgz",
|
||||
"integrity": "sha512-vo/wmBgMIiEA23A/knMfn/cf37VnuF52nZh5ZoW0GWt4e4sxNquibrMRJ7UQsA06+MBx9r/H1jsI9grYjQCQlw==",
|
||||
"version": "20.17.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.16.tgz",
|
||||
"integrity": "sha512-vOTpLduLkZXePLxHiHsBLp98mHGnl8RptV4YAO3HfKO5UHjDvySGbxKtpYfy8Sx5+WKcgc45qNreJJRVM3L6mw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
@ -1803,9 +1736,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz",
|
||||
"integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==",
|
||||
"version": "6.9.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.18.tgz",
|
||||
"integrity": "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@ -1840,21 +1773,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.0.tgz",
|
||||
"integrity": "sha512-NggSaEZCdSrFddbctrVjkVZvFC6KGfKfNK0CU7mNK/iKHGKbzT4Wmgm08dKpcZECBu9f5FypndoMyRHkdqfT1Q==",
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.22.0.tgz",
|
||||
"integrity": "sha512-4Uta6REnz/xEJMvwf72wdUnC3rr4jAQf5jnTkeRQ9b6soxLxhDEbS/pfMPoJLDfFPNVRdryqWUIV/2GZzDJFZw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.19.0",
|
||||
"@typescript-eslint/type-utils": "8.19.0",
|
||||
"@typescript-eslint/utils": "8.19.0",
|
||||
"@typescript-eslint/visitor-keys": "8.19.0",
|
||||
"@typescript-eslint/scope-manager": "8.22.0",
|
||||
"@typescript-eslint/type-utils": "8.22.0",
|
||||
"@typescript-eslint/utils": "8.22.0",
|
||||
"@typescript-eslint/visitor-keys": "8.22.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
"ts-api-utils": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -1870,16 +1803,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.0.tgz",
|
||||
"integrity": "sha512-6M8taKyOETY1TKHp0x8ndycipTVgmp4xtg5QpEZzXxDhNvvHOJi5rLRkLr8SK3jTgD5l4fTlvBiRdfsuWydxBw==",
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.22.0.tgz",
|
||||
"integrity": "sha512-MqtmbdNEdoNxTPzpWiWnqNac54h8JDAmkWtJExBVVnSrSmi9z+sZUt0LfKqk9rjqmKOIeRhO4fHHJ1nQIjduIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.19.0",
|
||||
"@typescript-eslint/types": "8.19.0",
|
||||
"@typescript-eslint/typescript-estree": "8.19.0",
|
||||
"@typescript-eslint/visitor-keys": "8.19.0",
|
||||
"@typescript-eslint/scope-manager": "8.22.0",
|
||||
"@typescript-eslint/types": "8.22.0",
|
||||
"@typescript-eslint/typescript-estree": "8.22.0",
|
||||
"@typescript-eslint/visitor-keys": "8.22.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -1895,14 +1828,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.0.tgz",
|
||||
"integrity": "sha512-hkoJiKQS3GQ13TSMEiuNmSCvhz7ujyqD1x3ShbaETATHrck+9RaDdUbt+osXaUuns9OFwrDTTrjtwsU8gJyyRA==",
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.22.0.tgz",
|
||||
"integrity": "sha512-/lwVV0UYgkj7wPSw0o8URy6YI64QmcOdwHuGuxWIYznO6d45ER0wXUbksr9pYdViAofpUCNJx/tAzNukgvaaiQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.19.0",
|
||||
"@typescript-eslint/visitor-keys": "8.19.0"
|
||||
"@typescript-eslint/types": "8.22.0",
|
||||
"@typescript-eslint/visitor-keys": "8.22.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -1913,16 +1846,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.0.tgz",
|
||||
"integrity": "sha512-TZs0I0OSbd5Aza4qAMpp1cdCYVnER94IziudE3JU328YUHgWu9gwiwhag+fuLeJ2LkWLXI+F/182TbG+JaBdTg==",
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.22.0.tgz",
|
||||
"integrity": "sha512-NzE3aB62fDEaGjaAYZE4LH7I1MUwHooQ98Byq0G0y3kkibPJQIXVUspzlFOmOfHhiDLwKzMlWxaNv+/qcZurJA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.19.0",
|
||||
"@typescript-eslint/utils": "8.19.0",
|
||||
"@typescript-eslint/typescript-estree": "8.22.0",
|
||||
"@typescript-eslint/utils": "8.22.0",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
"ts-api-utils": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -1937,9 +1870,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.0.tgz",
|
||||
"integrity": "sha512-8XQ4Ss7G9WX8oaYvD4OOLCjIQYgRQxO+qCiR2V2s2GxI9AUpo7riNwo6jDhKtTcaJjT8PY54j2Yb33kWtSJsmA==",
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.22.0.tgz",
|
||||
"integrity": "sha512-0S4M4baNzp612zwpD4YOieP3VowOARgK2EkN/GBn95hpyF8E2fbMT55sRHWBq+Huaqk3b3XK+rxxlM8sPgGM6A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -1951,20 +1884,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.0.tgz",
|
||||
"integrity": "sha512-WW9PpDaLIFW9LCbucMSdYUuGeFUz1OkWYS/5fwZwTA+l2RwlWFdJvReQqMUMBw4yJWJOfqd7An9uwut2Oj8sLw==",
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.22.0.tgz",
|
||||
"integrity": "sha512-SJX99NAS2ugGOzpyhMza/tX+zDwjvwAtQFLsBo3GQxiGcvaKlqGBkmZ+Y1IdiSi9h4Q0Lr5ey+Cp9CGWNY/F/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.19.0",
|
||||
"@typescript-eslint/visitor-keys": "8.19.0",
|
||||
"@typescript-eslint/types": "8.22.0",
|
||||
"@typescript-eslint/visitor-keys": "8.22.0",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
"ts-api-utils": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -1978,16 +1911,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.0.tgz",
|
||||
"integrity": "sha512-PTBG+0oEMPH9jCZlfg07LCB2nYI0I317yyvXGfxnvGvw4SHIOuRnQ3kadyyXY6tGdChusIHIbM5zfIbp4M6tCg==",
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.22.0.tgz",
|
||||
"integrity": "sha512-T8oc1MbF8L+Bk2msAvCUzjxVB2Z2f+vXYfcucE2wOmYs7ZUwco5Ep0fYZw8quNwOiw9K8GYVL+Kgc2pETNTLOg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "8.19.0",
|
||||
"@typescript-eslint/types": "8.19.0",
|
||||
"@typescript-eslint/typescript-estree": "8.19.0"
|
||||
"@typescript-eslint/scope-manager": "8.22.0",
|
||||
"@typescript-eslint/types": "8.22.0",
|
||||
"@typescript-eslint/typescript-estree": "8.22.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -2002,13 +1935,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.0.tgz",
|
||||
"integrity": "sha512-mCFtBbFBJDCNCWUl5y6sZSCHXw1DEFEk3c/M3nRK2a4XUB8StGFtmcEMizdjKuBzB6e/smJAAWYug3VrdLMr1w==",
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.22.0.tgz",
|
||||
"integrity": "sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.19.0",
|
||||
"@typescript-eslint/types": "8.22.0",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -2322,6 +2255,16 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/async-function": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
|
||||
"integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/atomic-sleep": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
|
||||
@ -2457,9 +2400,9 @@
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/bullmq": {
|
||||
"version": "5.34.6",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.6.tgz",
|
||||
"integrity": "sha512-pRCYyO9RlkQWxdmKlrNnUthyFwurYXRYLVXD1YIx+nCCdhAOiHatD8FDHbsT/w2I31c0NWoMcfZiIGuipiF7Lg==",
|
||||
"version": "5.39.0",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.39.0.tgz",
|
||||
"integrity": "sha512-aS+wtZsjW4/9mv2iZRynkSvEXCFS5h3Ko+OgArJco5rEgTE7v/TehDKv6gYEsKVbavOgiNlUNjgEhWhrzDSLBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cron-parser": "^4.9.0",
|
||||
@ -3029,12 +2972,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io": {
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz",
|
||||
"integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==",
|
||||
"version": "6.6.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
|
||||
"integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
@ -3169,9 +3111,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
|
||||
"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
@ -3293,19 +3235,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.17.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz",
|
||||
"integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==",
|
||||
"version": "9.19.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.19.0.tgz",
|
||||
"integrity": "sha512-ug92j0LepKlbbEv6hD911THhoRHmbdXt2gX+VDABAW/Ir7D3nqKdv5Pf5vtlyY6HQMTEP2skXY43ueqTCWssEA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
"@eslint/config-array": "^0.19.0",
|
||||
"@eslint/core": "^0.9.0",
|
||||
"@eslint/core": "^0.10.0",
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "9.17.0",
|
||||
"@eslint/plugin-kit": "^0.2.3",
|
||||
"@eslint/js": "9.19.0",
|
||||
"@eslint/plugin-kit": "^0.2.5",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@humanwhocodes/retry": "^0.4.1",
|
||||
@ -3813,9 +3755,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.5.tgz",
|
||||
"integrity": "sha512-5JnBCWpFlMo0a3ciDy/JckMzzv1U9coZrIhedq+HXxxUfDTAiS0LA8OKVao4G9BxmCVck/jtA5r3KAtRWEyD8Q==",
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
|
||||
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@ -3947,13 +3889,19 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
||||
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz",
|
||||
"integrity": "sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-callable": "^1.1.3"
|
||||
"is-callable": "^1.2.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
@ -3975,9 +3923,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "11.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
|
||||
"integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
|
||||
"version": "11.3.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
|
||||
"integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
@ -4127,9 +4075,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/get-tsconfig": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz",
|
||||
"integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==",
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz",
|
||||
"integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -4492,12 +4440,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/is-async-function": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.0.tgz",
|
||||
"integrity": "sha512-GExz9MtyhlZyXYLxzlJRj5WUCE661zhDa1Yna52CN57AJsymh+DvXXjyveSioqSRdxvUrdKdvqB1b5cVKsNpWQ==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
|
||||
"integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"async-function": "^1.0.0",
|
||||
"call-bound": "^1.0.3",
|
||||
"get-proto": "^1.0.1",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
@ -5188,9 +5137,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
|
||||
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==",
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz",
|
||||
"integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
@ -5246,9 +5195,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mariadb/node_modules/@types/node": {
|
||||
"version": "22.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz",
|
||||
"integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==",
|
||||
"version": "22.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.12.0.tgz",
|
||||
"integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.20.0"
|
||||
@ -5331,9 +5280,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mikro-orm": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.2.tgz",
|
||||
"integrity": "sha512-PyivHOk8wlN16fzFv8fTfMXrTj9nWQ6Cnzi49twsVHVr1HUQuhFKMJUV/n0HlEdYBiQj0UK1pN4wNGo7h3nNGQ==",
|
||||
"version": "6.4.4",
|
||||
"resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.4.tgz",
|
||||
"integrity": "sha512-nHV0lZnPUwidqeVyJwBegKDW9KwTxfH5yNp0aGSud9EI0mFkjK/M4EVfh+vwg/y6gdSIu9UnwDORYP2hJw96dQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 18.12.0"
|
||||
@ -5435,9 +5384,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mysql2": {
|
||||
"version": "3.11.5",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.5.tgz",
|
||||
"integrity": "sha512-0XFu8rUmFN9vC0ME36iBvCUObftiMHItrYFhlCRvFWbLgpNqtC4Br/NmZX1HNCszxT0GGy5QtP+k3Q3eCJPaYA==",
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.12.0.tgz",
|
||||
"integrity": "sha512-C8fWhVysZoH63tJbX8d10IAoYCyXy4fdRFz2Ihrt9jtPILYynFEKUUzpp1U7qxzDc3tMbotvaBH+sl6bFnGZiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"aws-ssl-profiles": "^1.1.1",
|
||||
@ -5525,9 +5474,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "6.9.16",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz",
|
||||
"integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==",
|
||||
"version": "6.10.0",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz",
|
||||
"integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==",
|
||||
"license": "MIT-0",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
@ -5991,26 +5940,6 @@
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/prisma": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.1.0.tgz",
|
||||
"integrity": "sha512-aFI3Yi+ApUxkwCJJwyQSwpyzUX7YX3ihzuHNHOyv4GJg3X5tQsmRaJEnZ+ZyfHpMtnyahhmXVfbTZ+lS8ZtfKw==",
|
||||
"devOptional": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@prisma/engines": "6.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"prisma": "build/index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/process-warning": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz",
|
||||
@ -6409,9 +6338,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.6.3",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
|
||||
"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz",
|
||||
"integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
@ -7019,45 +6948,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.10",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz",
|
||||
"integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.4.2",
|
||||
"picomatch": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/fdir": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz",
|
||||
"integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
|
||||
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@ -7090,25 +6980,25 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
|
||||
"integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.2.0"
|
||||
"typescript": ">=4.8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-morph": {
|
||||
"version": "24.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-24.0.0.tgz",
|
||||
"integrity": "sha512-2OAOg/Ob5yx9Et7ZX4CvTCc0UFoZHwLEJ+dpDPSUi5TgwwlTlX47w+iFRrEwzUZwYACjq83cgjS/Da50Ga37uw==",
|
||||
"version": "25.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-25.0.0.tgz",
|
||||
"integrity": "sha512-ERPTUVO5qF8cEGJgAejGOsCVlbk8d0SDyiJsucKQT5XgqoZslv0Qml+gnui6Yy6o+uQqw5SestyW2HvlVtT/Sg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ts-morph/common": "~0.25.0",
|
||||
"@ts-morph/common": "~0.26.0",
|
||||
"code-block-writer": "^13.0.3"
|
||||
}
|
||||
},
|
||||
@ -7210,9 +7100,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "4.31.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.31.0.tgz",
|
||||
"integrity": "sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ==",
|
||||
"version": "4.33.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.33.0.tgz",
|
||||
"integrity": "sha512-s6zVrxuyKbbAsSAD5ZPTB77q4YIdRctkTbJ2/Dqlinwz+8ooH2gd+YA7VA6Pa93KML9GockVvoxjZ2vHP+mu8g==",
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
@ -7313,9 +7203,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
|
||||
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
|
||||
"version": "5.7.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
|
||||
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
|
@ -13,7 +13,6 @@
|
||||
"@mikro-orm/migrations": "^6.4.2",
|
||||
"@mikro-orm/mysql": "^6.4.2",
|
||||
"@mikro-orm/reflection": "^6.4.2",
|
||||
"@prisma/client": "^6.1.0",
|
||||
"@types/ioredis": "^4.28.10",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bullmq": "^5.13.2",
|
||||
@ -44,7 +43,6 @@
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"nodemon": "^3.1.4",
|
||||
"prettier": "^3.3.3",
|
||||
"prisma": "^6.1.0",
|
||||
"tsx": "^4.19.2"
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { Request, Response } from 'express'
|
||||
import fs from 'fs'
|
||||
|
||||
import { Response } from 'express'
|
||||
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
|
||||
@ -19,4 +21,18 @@ export abstract class BaseController {
|
||||
message
|
||||
})
|
||||
}
|
||||
|
||||
protected sendFile(res: Response, filePath: string) {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
this.logger.error(`File not found: ${filePath}`)
|
||||
return this.sendError(res, 'Asset not found', 404)
|
||||
}
|
||||
|
||||
res.sendFile(filePath, (error) => {
|
||||
if (error) {
|
||||
this.logger.error('Error sending file:' + error)
|
||||
this.sendError(res, 'Error downloading the asset', 500)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,10 @@ export abstract class BaseEntity {
|
||||
throw error
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to ${actionDescription}: ${error instanceof Error ? error.message : String(error)}`)
|
||||
const errorMessage = error instanceof Error ? error.message : error && typeof error === 'object' && 'toString' in error ? error.toString() : String(error)
|
||||
|
||||
console.log(errorMessage)
|
||||
this.logger.error(`Failed to ${actionDescription}: ${errorMessage}`)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
@ -61,8 +61,8 @@ export class LogReader {
|
||||
})
|
||||
|
||||
stream.on('data', (data) => {
|
||||
console.log(`[${filename}]`);
|
||||
console.log(data.toString()); //
|
||||
console.log(`[${filename}]`)
|
||||
console.log(data.toString()) //
|
||||
})
|
||||
|
||||
currentPosition = newPosition
|
||||
|
@ -37,7 +37,6 @@ export type AssetData = {
|
||||
updatedAt: Date
|
||||
originX?: number
|
||||
originY?: number
|
||||
isAnimated?: boolean
|
||||
frameRate?: number
|
||||
frameWidth?: number
|
||||
frameHeight?: number
|
||||
@ -46,8 +45,11 @@ export type AssetData = {
|
||||
|
||||
export type WorldSettings = {
|
||||
date: Date
|
||||
isRainEnabled: boolean
|
||||
isFogEnabled: boolean
|
||||
weatherState: WeatherState
|
||||
}
|
||||
|
||||
export type WeatherState = {
|
||||
rainPercentage: number
|
||||
fogDensity: number
|
||||
}
|
||||
|
||||
|
@ -85,12 +85,16 @@ export default class InitCommand extends BaseCommand {
|
||||
await idleRightDownAction
|
||||
.setAction('idle_right_down')
|
||||
.setSprites([
|
||||
'data:image/png;base64,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'
|
||||
{
|
||||
url: 'data:image/png;base64,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',
|
||||
offset: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
])
|
||||
.setOriginX(0)
|
||||
.setOriginY(0)
|
||||
.setIsAnimated(false)
|
||||
.setIsLooping(false)
|
||||
.setFrameWidth(64)
|
||||
.setFrameHeight(94)
|
||||
.setFrameRate(0)
|
||||
@ -101,12 +105,16 @@ export default class InitCommand extends BaseCommand {
|
||||
await idleLeftUpAction
|
||||
.setAction('idle_left_up')
|
||||
.setSprites([
|
||||
'data:image/png;base64,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'
|
||||
{
|
||||
url: 'data:image/png;base64,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',
|
||||
offset: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
])
|
||||
.setOriginX(0)
|
||||
.setOriginY(0)
|
||||
.setIsAnimated(false)
|
||||
.setIsLooping(false)
|
||||
.setFrameWidth(64)
|
||||
.setFrameHeight(94)
|
||||
.setFrameRate(0)
|
||||
@ -117,15 +125,37 @@ export default class InitCommand extends BaseCommand {
|
||||
await walkRightDownAction
|
||||
.setAction('walk_right_down')
|
||||
.setSprites([
|
||||
'data:image/png;base64,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',
|
||||
'data:image/png;base64,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',
|
||||
'data:image/png;base64,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',
|
||||
'data:image/png;base64,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'
|
||||
{
|
||||
url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAABWCAYAAAA+Eu3nAAAGmElEQVR4nLVaTWgbRxh92gjF2BYG25VsalhDvOyhEji9hPSQiyv3UnxI2kOpU3xKTBowsSHQQ00w9NCDDIWWNjeT+pLSk482vvgSfGkcZChCKWghkFo4IkK1kA2Re9h8o5nZmdldNX0g8M7OzJtv5vuddWLmm4cwYXhr7VzVXp9bTRgHKpAMI1mYnsTlmWuB90tF/30cUiXZ8Nba+cL0JIYzWdh5F31ODv2jA0Kfh7/k0K4cYqm4dh6V0NIRXZ65JhBdGHGEX//oAPqcHH5Y+Uq71aFkADCcyQIA+pycdmAvhAIZSWXn3SgLZTAtSkumQ+v4BG9eVYx9okin1UYVYT8qgbY4iEzWy+QyAtt4dfEOvFIZANBpNCNPtFR8FJ+sXTmEe/0Gnu7u4azmCe9uL97H7cX7gUluL97HXm4qPhlJdXXxDp7u7gUmfPysGiB8/KwaSqQkq9eO0K4cAvDtjbaSJhz/8uPIkxvJ6nOriY2DKpPOzrs4q3noNJp4/eQ31o//m56ffvJRKJlSG0k6r1RmhCnY+PPuLaEf7y/bZjMEoNpGTrp67Yi1k7L0jw6wHyGqSSg9SH1uNbG+vQ8AgpJ0Gk20jk8Cv06jiaXio9BwY3RXGwdVgZDOT/7JJqKD0YMsTE8yQoI6kIZLFUpGhEBXSpkciB6tQ8lIkssz15jSUASPKpGRjE8LeNh5Fza6sW559grWt6LnIgKZLsmh1KB1fMK8S5+Tg+vksAzfLjcikCYoleNzj1TGZh14TeNtj6SmqE7vNg6qWsKkimjw0hiTgg/5rpNjkpF3ofc2AJQAoKoTrGtntNLBS2O4MOKwrQKAtDvNfu99Oo9UxhbyFGoH/CPQpQcWn+T0OTlGFBXktihHkZWKB1OQVMYOJKKdRhPWUNqY7FBuEsU/WrQaayjNpJIn5/3gP3/9rSQkmNJAS9WBHyz7QcDXUIp57cohOo0mUxwTkgCEXJ6kIgerMgNS8/puNwRtHFTx6+8/of5k30ymkqqyu80CJ0FlZwBYm38MIWT+FuRYEtppNAMrB3z/6GRmhbazmhfoZyTzSmW4inydHC7ga6s1lAYA5roAIAU7MM5IRtK0ACEYykRUOgFAesQ/31ZkKk2k9kplFrd4iWSDl5/Dig+m+jThWc0TEh2CbPCq9jDDtmj1uslUePOqwqSIU2zEqmKIiBEcHwAgM6iGGnakYhCIJgF5FSMZnRcN2DioskSnF1IjGRDULB7kE3lt022Zqb6OvI0ywrZMhSQgVpgqtac+vAG712+w9lhkhDD1D5u4XjsyzmEB0ObqXqkcOY/noctDLJpUt1Ii1JGqPI4uD0nSpICokcWXF/0/Xr4Gnu1jZfyUTSTnisWXF4GsC8DvY+ddYDsY17QepFAoCM/FnR2BvIuLKBQK2KH30Kt/klZLINcDANlst31+fl63LhwdiduoU5IkYM6ICFNT/j3HxMSE0P7ixQvhuXV8grQ7rZyDef1eiKhtamoKhUKBnbMurjEPQh3iXv/JaFcOtf4z4K76nBwWpifxx+aPgc60ZfLWAWAK4pXKWr+Z+PyD989//v5boaB486qCm599jQ/n7zIloa18/vw5G0xtDx48wMr4qVACq8qmJOAbZmsojfQIsH3vFhu0s7ODQqGAbDYrkAC+Bm5ubgIAs0Eq+I31mQp+PDvt2pcCK+OnASM31Wcsb3QydkCLhjNZfJfpPpOnoeBKRKTNdh5YeFvyqqSzaBLZ9/FlLK3cVHtZQ2mkMra5j3wTx0Nctcuk0mHw0hjsvGv2+iSdXGdRgkqEtI20QN7bU6wzSWfxg9uVQ2WywydEbHHcjtARtI5PjNJZ/OCwS2WVWseRLnCTqiNSnWlc6XrOrnhCupukK0JALV0kMioOTeAvQXnpQsloRbTSs5pndEOy+fDSLc9eYVup/MoEdM+IvxkIg+wcZOmMVQy/Ne8CATI5Hwm7aVPBT+98CfkFMzJ+C0UvHh38QuWreoGMwBftdh6h13oqpDI2nBkbZzVPkMyo+mGJUBRSHv/ZqAHxCGTw5/1OyKLifyHTFSGxbwtMqNeOgBICF2wEo2RxazNSfZ3JaMniEKkit1cqwyuVhTAjfkSQjLIX0OcTFbSS9Zrzk4vjnwlGBXFm/ItMUy4og/8wRFgGsL61dq6VjLf+K1/cNH4cALrnJhPxEHOQtwU7ICpIZXc7TCDlHIB/9uvb+6jPrSYS/P/w8G5HdeEcJdSopKcxCfkfhsK2ykQUhn8BlrgX3yO5OYgAAAAASUVORK5CYII=',
|
||||
offset: {
|
||||
x: 7,
|
||||
y: 8
|
||||
}
|
||||
},
|
||||
{
|
||||
url: 'data:image/png;base64,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',
|
||||
offset: {
|
||||
x: 7,
|
||||
y: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
url: 'data:image/png;base64,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',
|
||||
offset: {
|
||||
x: 2,
|
||||
y: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
url: 'data:image/png;base64,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',
|
||||
offset: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
])
|
||||
.setOriginX(0)
|
||||
.setOriginY(0)
|
||||
.setIsAnimated(true)
|
||||
.setIsLooping(false)
|
||||
.setFrameWidth(64)
|
||||
.setFrameHeight(94)
|
||||
.setFrameRate(7)
|
||||
@ -136,15 +166,37 @@ export default class InitCommand extends BaseCommand {
|
||||
await walkLeftUpAction
|
||||
.setAction('walk_left_up')
|
||||
.setSprites([
|
||||
'data:image/png;base64,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',
|
||||
'data:image/png;base64,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',
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAABZCAYAAADVeL+8AAAFcElEQVR4nLVZzUtbWRT/JUqURAkkIWlBeIUmuDHQrqQI3Ygu/Qtk6LLMUldDqYtAF10ozKrMLjDC7LNsEMSdm7GQboIRfBDQ99BHxQ/aQM0sknM9971z33upmQOB5H78zu/ee+75uEks//EXoiTXqPWldm9tKxE2bzIO6MbqIqzqvNZ3tHeA+rDfpMQInmvU+huri6gsr2Lm+ROt7+bkHC+XXyNXLMFzHdQbtb6kQATPNWr9Pzd/w3RlAelCBhP5itY/A+AGgFUFLAxWJClImhinipYIrCZmZ5EqWoM5xZI8RmqsLK8imZ0VJ0hiVefx5sWzwMFr4MQ6TH5eHuPu4nYwOYJAYM+t6ryadHdxizSOtX4CjiOhphgFdn91DQCwW22xX9xzmhRXPNfBq7e/R4ObWJgIHO0diMAiuH9yWN/hP38r4O/HXwPjAnvuuU4sBYBu39KKReY91w4FpTHkb74ff9VIkWjMvbWtRL1R6+eKJVhVfWCqaAWU2q02LANrI3PPdSIPlvrtVltkLYJ7a1uJ+pfTgAJ+G6ndcx0jsJn5UAEHkoC51L+cBvy60RS9ta3EzudDIysOKgGHgo8ipkgUG3xUlwAACX+A5j6Z3K8/fpIc7R0AkPc7AJ5r1PpvXjxTN8+qzgfsm6IPtZEpkgFwJZMSMDFNFa1BOMNAAf1OFzK4Gc6jOCoFa+2GSsDpQgZ3AOAOxqQLGQADu7+/ulYrkYJ1krPmwCQT+YoC5G1cZp4/Qe7VoiJIoqyFGqVrz8Ek4Il8BRP5CqYrC1qwVuDcIvgB/rzUY6i/7ebkXP1OFzLaqjU7t1tt7Hw+DLDnYH5lPdfGzcm5WlUyO6t2QYFzjaMIEZFWOJbr7xfa4kjwuHnK3cVtgH0s5mEKRvbnJCZnZVLmb49kblLA200BfeQDlVhHBuieaxv3z88+rm8fmymSQu6HjOCmfZRYe66DnmurSoQu5KOYR2VmY9kWikIjgcfJGcPEmM5xBaSEK+u5dmTKZ2RumsiVRUkA/LI0j+2zqchkNCwBJRELrpWVFWw3m8DZN3xAUAGBbp9NAQDyQ2UUR2llxmpufX0djuPgXbMp9E4pEgDw7+4DAe52RfBSqYRyuYxyuYylpSUAQKfTEUk4jnlrRPByuSwO9rd3Oh2USnLdD7AD9R/e3Nyc+pgUmkgQlmiKBOj/7VcYJQo8yqyiCJBwf58EHsoUk48g6Xa7xj7Pdcxhjqe++/v7AVCylm63qz4mCyIJWMvm0x/Y3t0F8HBgBCKB+U2RF7xifv6hCLwbKiChC0OmR6DNZhN5BmxkzvPz3apeNYgXdbjSOiNvt9qqjNHA+dvW/dX1oERvAcApNp/+UAQAPSvmNSu3Os3OqZKg78CDiXJL4kUCT2BplWQcGjgFWH8lAehlOwEns7NIZmfx6eN7VezyV7rINy7OxP+qMZ1dUKv89PE9i06nD9tClsJLElPiQ2W73Wor6+BjxbKFREriRSXD7SFgKiUBBCsLXoXRNTaFOdp/u9VWMZUXw6RYYx6XtZ89MfcTCmwLdz6jekoSMgINnIDjZrH+1+fQS3R/da0dUFwxVYKhT3+mpw5ezoeVmGIF/RgxXn8uUXmgsuWQN/SxpNB+JxcA/5Xy3D8nVyxpjivgcklGtXGJ3CSdPAGTZzNZCpeeayMF/c1LA6cv6UJmpP8jPNcZRqm23uYH99+0qC0hv05+W+pX4L9i41FbBvxP7y2h4Ka/w8YCPi4RwcflZ4zMpT/yHgWeLmQwXVlAqmjh5fJrbKwuPkqBAh/lAsUVdUPvr64HD8LjBrdbbVhVaH4iToUcCe6tbSV2GrX+BgDyE6bH9lFFvfz7D+4xoCT/AaNCPNJBtKgMAAAAAElFTkSuQmCC',
|
||||
'data:image/png;base64,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'
|
||||
{
|
||||
url: 'data:image/png;base64,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',
|
||||
offset: {
|
||||
x: 3,
|
||||
y: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
url: 'data:image/png;base64,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',
|
||||
offset: {
|
||||
x: 0,
|
||||
y: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAABZCAYAAADVeL+8AAAFcElEQVR4nLVZzUtbWRT/JUqURAkkIWlBeIUmuDHQrqQI3Ygu/Qtk6LLMUldDqYtAF10ozKrMLjDC7LNsEMSdm7GQboIRfBDQ99BHxQ/aQM0sknM9971z33upmQOB5H78zu/ee+75uEks//EXoiTXqPWldm9tKxE2bzIO6MbqIqzqvNZ3tHeA+rDfpMQInmvU+huri6gsr2Lm+ROt7+bkHC+XXyNXLMFzHdQbtb6kQATPNWr9Pzd/w3RlAelCBhP5itY/A+AGgFUFLAxWJClImhinipYIrCZmZ5EqWoM5xZI8RmqsLK8imZ0VJ0hiVefx5sWzwMFr4MQ6TH5eHuPu4nYwOYJAYM+t6ryadHdxizSOtX4CjiOhphgFdn91DQCwW22xX9xzmhRXPNfBq7e/R4ObWJgIHO0diMAiuH9yWN/hP38r4O/HXwPjAnvuuU4sBYBu39KKReY91w4FpTHkb74ff9VIkWjMvbWtRL1R6+eKJVhVfWCqaAWU2q02LANrI3PPdSIPlvrtVltkLYJ7a1uJ+pfTgAJ+G6ndcx0jsJn5UAEHkoC51L+cBvy60RS9ta3EzudDIysOKgGHgo8ipkgUG3xUlwAACX+A5j6Z3K8/fpIc7R0AkPc7AJ5r1PpvXjxTN8+qzgfsm6IPtZEpkgFwJZMSMDFNFa1BOMNAAf1OFzK4Gc6jOCoFa+2GSsDpQgZ3AOAOxqQLGQADu7+/ulYrkYJ1krPmwCQT+YoC5G1cZp4/Qe7VoiJIoqyFGqVrz8Ek4Il8BRP5CqYrC1qwVuDcIvgB/rzUY6i/7ebkXP1OFzLaqjU7t1tt7Hw+DLDnYH5lPdfGzcm5WlUyO6t2QYFzjaMIEZFWOJbr7xfa4kjwuHnK3cVtgH0s5mEKRvbnJCZnZVLmb49kblLA200BfeQDlVhHBuieaxv3z88+rm8fmymSQu6HjOCmfZRYe66DnmurSoQu5KOYR2VmY9kWikIjgcfJGcPEmM5xBaSEK+u5dmTKZ2RumsiVRUkA/LI0j+2zqchkNCwBJRELrpWVFWw3m8DZN3xAUAGBbp9NAQDyQ2UUR2llxmpufX0djuPgXbMp9E4pEgDw7+4DAe52RfBSqYRyuYxyuYylpSUAQKfTEUk4jnlrRPByuSwO9rd3Oh2USnLdD7AD9R/e3Nyc+pgUmkgQlmiKBOj/7VcYJQo8yqyiCJBwf58EHsoUk48g6Xa7xj7Pdcxhjqe++/v7AVCylm63qz4mCyIJWMvm0x/Y3t0F8HBgBCKB+U2RF7xifv6hCLwbKiChC0OmR6DNZhN5BmxkzvPz3apeNYgXdbjSOiNvt9qqjNHA+dvW/dX1oERvAcApNp/+UAQAPSvmNSu3Os3OqZKg78CDiXJL4kUCT2BplWQcGjgFWH8lAehlOwEns7NIZmfx6eN7VezyV7rINy7OxP+qMZ1dUKv89PE9i06nD9tClsJLElPiQ2W73Wor6+BjxbKFREriRSXD7SFgKiUBBCsLXoXRNTaFOdp/u9VWMZUXw6RYYx6XtZ89MfcTCmwLdz6jekoSMgINnIDjZrH+1+fQS3R/da0dUFwxVYKhT3+mpw5ezoeVmGIF/RgxXn8uUXmgsuWQN/SxpNB+JxcA/5Xy3D8nVyxpjivgcklGtXGJ3CSdPAGTZzNZCpeeayMF/c1LA6cv6UJmpP8jPNcZRqm23uYH99+0qC0hv05+W+pX4L9i41FbBvxP7y2h4Ka/w8YCPi4RwcflZ4zMpT/yHgWeLmQwXVlAqmjh5fJrbKwuPkqBAh/lAsUVdUPvr64HD8LjBrdbbVhVaH4iToUcCe6tbSV2GrX+BgDyE6bH9lFFvfz7D+4xoCT/AaNCPNJBtKgMAAAAAElFTkSuQmCC',
|
||||
offset: {
|
||||
x: 5,
|
||||
y: 6
|
||||
}
|
||||
},
|
||||
{
|
||||
url: 'data:image/png;base64,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',
|
||||
offset: {
|
||||
x: 2,
|
||||
y: 6
|
||||
}
|
||||
}
|
||||
])
|
||||
.setOriginX(0)
|
||||
.setOriginY(0)
|
||||
.setIsAnimated(true)
|
||||
.setIsLooping(false)
|
||||
.setFrameWidth(64)
|
||||
.setFrameHeight(94)
|
||||
.setFrameRate(7)
|
||||
@ -171,12 +223,16 @@ export default class InitCommand extends BaseCommand {
|
||||
await frontAction
|
||||
.setAction('front')
|
||||
.setSprites([
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAASCAYAAABB7B6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA5ElEQVR4nK2VMQ7DIAxFc4AulViysTBUldgqReoGp+pReloqIhx9LOy4IoOVYBw//DFkyZ/vUs3db2Vkuc1rMTwOrRvUwPjwZXs9S0rv/d1BkuDXYx4N41SABAl+7ZJXPzcEqQALJApmroAnC22smbQPw5WPkjoAE7w++X6JAJSF9JRWS3EWiEnzwCrBWPJLkA4gdU1sPvoQIdjGGE+xp8mTULr1IO5Orjlt9NkGaif4kIgqwC6hSarMkkgFoLZ8hVvTeQoglXwJQNMV5bsUUJNKnZJnAHhVWO76vwCjH8hs8gr4ARPESmbfQUg4AAAAAElFTkSuQmCC'
|
||||
{
|
||||
url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAASCAYAAABB7B6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA5ElEQVR4nK2VMQ7DIAxFc4AulViysTBUldgqReoGp+pReloqIhx9LOy4IoOVYBw//DFkyZ/vUs3db2Vkuc1rMTwOrRvUwPjwZXs9S0rv/d1BkuDXYx4N41SABAl+7ZJXPzcEqQALJApmroAnC22smbQPw5WPkjoAE7w++X6JAJSF9JRWS3EWiEnzwCrBWPJLkA4gdU1sPvoQIdjGGE+xp8mTULr1IO5Orjlt9NkGaif4kIgqwC6hSarMkkgFoLZ8hVvTeQoglXwJQNMV5bsUUJNKnZJnAHhVWO76vwCjH8hs8gr4ARPESmbfQUg4AAAAAElFTkSuQmCC',
|
||||
offset: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
])
|
||||
.setOriginX(0.5)
|
||||
.setOriginY(5.34)
|
||||
.setIsAnimated(false)
|
||||
.setIsLooping(false)
|
||||
.setFrameWidth(64)
|
||||
.setFrameHeight(18)
|
||||
.setFrameRate(0)
|
||||
@ -187,12 +243,16 @@ export default class InitCommand extends BaseCommand {
|
||||
await backAction
|
||||
.setAction('back')
|
||||
.setSprites([
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAWCAYAAADafVyIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABHUlEQVR4nJ1VuwrDMAzMB3QpZOmWxUMpdCsYsrlflU/p16YIrCJfTrLTQZCHfSflLufpvX0mVvP1sns1sk7fu8DP+7Ln16MpeZaWWwMkz0pZf++xgQO4AssmLEsi1QN3J5DFXqUT4JRASRQoBYWkpybQ7lIFssCsASUb0gDBM3x7Bm6NQF3EwKWYuBa4p8nBPbgpB+CeqxoC9pPoBgau99ixR+I6yAPPRhtLwCZ3CbzPkquQVh9Zp3uty8IJLHgpa9OV3ishyyYbOeFPhnZFh0UEeu0SoIC5dm8JoojoRgXqUCq4JcB4GIoKpkMiE2EGDUUFngnoILQiOx+6Bw46IZFYQMJIB1ccL7pn+BH/EtkjsZONgA8TMIeMgAvBF10K1sbmijzuAAAAAElFTkSuQmCC'
|
||||
{
|
||||
url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAWCAYAAADafVyIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABHUlEQVR4nJ1VuwrDMAzMB3QpZOmWxUMpdCsYsrlflU/p16YIrCJfTrLTQZCHfSflLufpvX0mVvP1sns1sk7fu8DP+7Ln16MpeZaWWwMkz0pZf++xgQO4AssmLEsi1QN3J5DFXqUT4JRASRQoBYWkpybQ7lIFssCsASUb0gDBM3x7Bm6NQF3EwKWYuBa4p8nBPbgpB+CeqxoC9pPoBgau99ixR+I6yAPPRhtLwCZ3CbzPkquQVh9Zp3uty8IJLHgpa9OV3ishyyYbOeFPhnZFh0UEeu0SoIC5dm8JoojoRgXqUCq4JcB4GIoKpkMiE2EGDUUFngnoILQiOx+6Bw46IZFYQMJIB1ccL7pn+BH/EtkjsZONgA8TMIeMgAvBF10K1sbmijzuAAAAAElFTkSuQmCC',
|
||||
offset: {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
])
|
||||
.setOriginX(0.5)
|
||||
.setOriginY(4.34)
|
||||
.setIsAnimated(false)
|
||||
.setIsLooping(false)
|
||||
.setFrameWidth(64)
|
||||
.setFrameHeight(22)
|
||||
.setFrameRate(0)
|
||||
@ -203,38 +263,6 @@ export default class InitCommand extends BaseCommand {
|
||||
await characterHair.setId('a2471230-d238-4ffb-9eca-9eab869f1b67').setName('Hair 1').setGender(CharacterGender.MALE).setIsSelectable(true).setSprite(hairSprite).save()
|
||||
}
|
||||
|
||||
private async createCharacterEquipment(): Promise<void> {
|
||||
const equipmentSprite = new Sprite()
|
||||
equipmentSprite.id = '5b3932dd-0791-4bb7-bb1e-da9833c3cc50'
|
||||
equipmentSprite.name = 'Male shirt'
|
||||
|
||||
// Create actions similar to createCharacterSprite()
|
||||
// with appropriate sprite data and parameters
|
||||
const actions = [
|
||||
{
|
||||
action: 'idle_right_down',
|
||||
sprites: ['data:image/png;base64,...'],
|
||||
originX: 0,
|
||||
originY: 0,
|
||||
isAnimated: false,
|
||||
isLooping: false,
|
||||
frameWidth: 64,
|
||||
frameHeight: 94,
|
||||
frameRate: 0
|
||||
}
|
||||
// Add other actions...
|
||||
]
|
||||
|
||||
for (const actionData of actions) {
|
||||
const action = new SpriteAction()
|
||||
Object.assign(action, actionData)
|
||||
action.sprite = equipmentSprite
|
||||
await action.save()
|
||||
}
|
||||
|
||||
await equipmentSprite.save()
|
||||
}
|
||||
|
||||
private async createMap(): Promise<void> {
|
||||
const map = new Map()
|
||||
await map
|
||||
@ -259,8 +287,8 @@ export default class InitCommand extends BaseCommand {
|
||||
.setName('root')
|
||||
.setRole('gm')
|
||||
.setMap((await this.mapRepository.getFirst())!)
|
||||
.setCharacterType((await this.characterTypeRepository.getFirst()) ?? undefined)
|
||||
.setCharacterHair((await this.characterHairRepository.getFirst()) ?? undefined)
|
||||
.setCharacterType(await this.characterTypeRepository.getFirst())
|
||||
.setCharacterHair(await this.characterHairRepository.getFirst())
|
||||
.save()
|
||||
}
|
||||
}
|
||||
|
119
src/controllers/cache.ts
Normal file
119
src/controllers/cache.ts
Normal file
@ -0,0 +1,119 @@
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
import { BaseController } from '#application/base/baseController'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
import CharacterTypeRepository from '#repositories/characterTypeRepository'
|
||||
import MapObjectRepository from '#repositories/mapObjectRepository'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
import TileRepository from '#repositories/tileRepository'
|
||||
|
||||
export class CacheController extends BaseController {
|
||||
/**
|
||||
* Serve a list of tiles and send as JSON
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async tiles(req: Request, res: Response) {
|
||||
const items: any[] = []
|
||||
|
||||
const tileRepository = new TileRepository()
|
||||
const tiles = await tileRepository.getAll()
|
||||
|
||||
for (const tile of tiles) {
|
||||
items.push(await tile.cache())
|
||||
}
|
||||
|
||||
return this.sendSuccess(res, items)
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve a list of maps and send as JSON
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async maps(req: Request, res: Response) {
|
||||
const items: any[] = []
|
||||
|
||||
const mapRepository = new MapRepository()
|
||||
const maps = await mapRepository.getAll()
|
||||
|
||||
for (const map of maps) {
|
||||
items.push(await map.cache())
|
||||
}
|
||||
|
||||
return this.sendSuccess(res, items)
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve a list of map objects and send as JSON
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async mapObjects(req: Request, res: Response) {
|
||||
const items: any[] = []
|
||||
|
||||
const mapObjectRepository = new MapObjectRepository()
|
||||
const mapObjects = await mapObjectRepository.getAll()
|
||||
|
||||
for (const mapObject of mapObjects) {
|
||||
items.push(await mapObject.cache())
|
||||
}
|
||||
|
||||
return this.sendSuccess(res, items)
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve a list of character hairs and send as JSON
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async characterHair(req: Request, res: Response) {
|
||||
const items: any[] = []
|
||||
|
||||
const characterHairRepository = new CharacterHairRepository()
|
||||
const characterHairs = await characterHairRepository.getAll()
|
||||
|
||||
for (const characterHair of characterHairs) {
|
||||
items.push(await characterHair.cache())
|
||||
}
|
||||
|
||||
return this.sendSuccess(res, items)
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve a list of character types and send as JSON
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async characterTypes(req: Request, res: Response) {
|
||||
const items: any[] = []
|
||||
|
||||
const characterTypeRepository = new CharacterTypeRepository()
|
||||
const characterTypes = await characterTypeRepository.getAll()
|
||||
|
||||
for (const characterType of characterTypes) {
|
||||
items.push(await characterType.cache())
|
||||
}
|
||||
|
||||
return this.sendSuccess(res, items)
|
||||
}
|
||||
|
||||
/**
|
||||
* Serve a list of sprites and send as JSON
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async sprites(req: Request, res: Response) {
|
||||
const items: any[] = []
|
||||
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const sprites = await spriteRepository.getAll()
|
||||
|
||||
for (const sprite of sprites) {
|
||||
items.push(await sprite.cache())
|
||||
}
|
||||
|
||||
return this.sendSuccess(res, items)
|
||||
}
|
||||
}
|
19
src/controllers/textures.ts
Normal file
19
src/controllers/textures.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
import { BaseController } from '#application/base/baseController'
|
||||
import Storage from '#application/storage'
|
||||
|
||||
export class TexturesController extends BaseController {
|
||||
/**
|
||||
* Download texture
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async download(req: Request, res: Response) {
|
||||
const { type, spriteId, file } = req.params
|
||||
|
||||
const texture = type === 'sprites' && spriteId ? Storage.getPublicPath(type, spriteId, file) : Storage.getPublicPath(type, file)
|
||||
|
||||
this.sendFile(res, texture)
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@ import { Chat } from '#entities/chat'
|
||||
import { Map } from '#entities/map'
|
||||
import { User } from '#entities/user'
|
||||
|
||||
|
||||
export class BaseCharacter extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
@ -47,10 +46,10 @@ export class BaseCharacter extends BaseEntity {
|
||||
|
||||
// Customization
|
||||
@ManyToOne({ deleteRule: 'set null' })
|
||||
characterType?: CharacterType | null | undefined
|
||||
characterType: CharacterType | null = null
|
||||
|
||||
@ManyToOne({ deleteRule: 'set null' })
|
||||
characterHair?: CharacterHair | null | undefined
|
||||
characterHair: CharacterHair | null = null
|
||||
|
||||
// Inventory
|
||||
@OneToMany({ mappedBy: 'character' })
|
||||
@ -177,7 +176,7 @@ export class BaseCharacter extends BaseEntity {
|
||||
return this.rotation
|
||||
}
|
||||
|
||||
setCharacterType(characterType: CharacterType | null | undefined) {
|
||||
setCharacterType(characterType: CharacterType | null) {
|
||||
this.characterType = characterType
|
||||
return this
|
||||
}
|
||||
@ -186,7 +185,7 @@ export class BaseCharacter extends BaseEntity {
|
||||
return this.characterType
|
||||
}
|
||||
|
||||
setCharacterHair(characterHair: CharacterHair | null | undefined) {
|
||||
setCharacterHair(characterHair: CharacterHair | null) {
|
||||
this.characterHair = characterHair
|
||||
return this
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Enum, ManyToOne, PrimaryKey } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterEquipmentSlotType } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
|
@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterGender } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
@ -25,6 +24,12 @@ export class BaseCharacterHair extends BaseEntity {
|
||||
@ManyToOne()
|
||||
sprite?: Sprite
|
||||
|
||||
@Property()
|
||||
createdAt = new Date()
|
||||
|
||||
@Property()
|
||||
updatedAt = new Date()
|
||||
|
||||
setId(id: UUID) {
|
||||
this.id = id
|
||||
return this
|
||||
@ -69,4 +74,22 @@ export class BaseCharacterHair extends BaseEntity {
|
||||
getSprite() {
|
||||
return this.sprite
|
||||
}
|
||||
|
||||
setCreatedAt(createdAt: Date) {
|
||||
this.createdAt = createdAt
|
||||
return this
|
||||
}
|
||||
|
||||
getCreatedAt() {
|
||||
return this.createdAt
|
||||
}
|
||||
|
||||
setUpdatedAt(updatedAt: Date) {
|
||||
this.updatedAt = updatedAt
|
||||
return this
|
||||
}
|
||||
|
||||
getUpdatedAt() {
|
||||
return this.updatedAt
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import { Character } from '#entities/character'
|
||||
import { CharacterEquipment } from '#entities/characterEquipment'
|
||||
import { Item } from '#entities/item'
|
||||
|
||||
|
||||
export class BaseCharacterItem extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { CharacterGender, CharacterRace } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
|
@ -7,7 +7,6 @@ import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { Map } from '#entities/map'
|
||||
|
||||
|
||||
export class BaseChat extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { ItemType, ItemRarity } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
|
@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
|
@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, Enum, ManyToOne, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { MapEventTileType } from '#application/enums'
|
||||
import { UUID } from '#application/types'
|
||||
|
@ -7,7 +7,6 @@ import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
import { MapEventTile } from '#entities/mapEventTile'
|
||||
|
||||
|
||||
export class BaseMapEventTileTeleport extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
@ -21,9 +21,6 @@ export class BaseMapObject extends BaseEntity {
|
||||
@Property({ type: 'decimal', precision: 10, scale: 2 })
|
||||
originY = 0
|
||||
|
||||
@Property()
|
||||
isAnimated = false
|
||||
|
||||
@Property()
|
||||
frameRate = 0
|
||||
|
||||
@ -84,15 +81,6 @@ export class BaseMapObject extends BaseEntity {
|
||||
return this.originY
|
||||
}
|
||||
|
||||
setIsAnimated(isAnimated: boolean) {
|
||||
this.isAnimated = isAnimated
|
||||
return this
|
||||
}
|
||||
|
||||
getIsAnimated() {
|
||||
return this.isAnimated
|
||||
}
|
||||
|
||||
setFrameRate(frameRate: number) {
|
||||
this.frameRate = frameRate
|
||||
return this
|
||||
|
@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { User } from '#entities/user'
|
||||
|
@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Map } from '#entities/map'
|
||||
@ -20,9 +19,6 @@ export class BasePlacedMapObject extends BaseEntity {
|
||||
@ManyToOne({ deleteRule: 'cascade', eager: true })
|
||||
mapObject!: MapObject
|
||||
|
||||
@Property()
|
||||
depth = 0
|
||||
|
||||
@Property()
|
||||
isRotated = false
|
||||
|
||||
@ -59,15 +55,6 @@ export class BasePlacedMapObject extends BaseEntity {
|
||||
return this.mapObject
|
||||
}
|
||||
|
||||
setDepth(depth: number) {
|
||||
this.depth = depth
|
||||
return this
|
||||
}
|
||||
|
||||
getDepth() {
|
||||
return this.depth
|
||||
}
|
||||
|
||||
setIsRotated(isRotated: boolean) {
|
||||
this.isRotated = isRotated
|
||||
return this
|
||||
|
@ -2,7 +2,6 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Collection, Entity, OneToMany, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { SpriteAction } from '#entities/spriteAction'
|
||||
|
@ -2,11 +2,18 @@ import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'
|
||||
|
||||
|
||||
import { BaseEntity } from '#application/base/baseEntity'
|
||||
import { UUID } from '#application/types'
|
||||
import { Sprite } from '#entities/sprite'
|
||||
|
||||
export interface SpriteImage {
|
||||
url: string
|
||||
offset: {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
}
|
||||
|
||||
export class BaseSpriteAction extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
@ -18,19 +25,13 @@ export class BaseSpriteAction extends BaseEntity {
|
||||
action!: string
|
||||
|
||||
@Property({ type: 'json', nullable: true })
|
||||
sprites?: string[]
|
||||
sprites?: SpriteImage[]
|
||||
|
||||
@Property()
|
||||
originX = 0
|
||||
@Property({ type: 'decimal', precision: 5, scale: 2 })
|
||||
originX = 0.0
|
||||
|
||||
@Property()
|
||||
originY = 0
|
||||
|
||||
@Property()
|
||||
isAnimated = false
|
||||
|
||||
@Property()
|
||||
isLooping = false
|
||||
@Property({ type: 'decimal', precision: 5, scale: 2 })
|
||||
originY = 0.0
|
||||
|
||||
@Property()
|
||||
frameWidth = 0
|
||||
@ -68,7 +69,7 @@ export class BaseSpriteAction extends BaseEntity {
|
||||
return this.action
|
||||
}
|
||||
|
||||
setSprites(sprites: string[]) {
|
||||
setSprites(sprites: SpriteImage[]) {
|
||||
this.sprites = sprites
|
||||
return this
|
||||
}
|
||||
@ -95,24 +96,6 @@ export class BaseSpriteAction extends BaseEntity {
|
||||
return this.originY
|
||||
}
|
||||
|
||||
setIsAnimated(isAnimated: boolean) {
|
||||
this.isAnimated = isAnimated
|
||||
return this
|
||||
}
|
||||
|
||||
getIsAnimated() {
|
||||
return this.isAnimated
|
||||
}
|
||||
|
||||
setIsLooping(isLooping: boolean) {
|
||||
this.isLooping = isLooping
|
||||
return this
|
||||
}
|
||||
|
||||
getIsLooping() {
|
||||
return this.isLooping
|
||||
}
|
||||
|
||||
setFrameWidth(frameWidth: number) {
|
||||
this.frameWidth = frameWidth
|
||||
return this
|
||||
|
@ -8,7 +8,6 @@ import { UUID } from '#application/types'
|
||||
import { Character } from '#entities/character'
|
||||
import { PasswordResetToken } from '#entities/passwordResetToken'
|
||||
|
||||
|
||||
export class BaseUser extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
id = randomUUID()
|
||||
|
@ -6,15 +6,9 @@ export class BaseWorld extends BaseEntity {
|
||||
@PrimaryKey()
|
||||
date = new Date()
|
||||
|
||||
@Property()
|
||||
isRainEnabled = false
|
||||
|
||||
@Property()
|
||||
rainPercentage = 0
|
||||
|
||||
@Property()
|
||||
isFogEnabled = false
|
||||
|
||||
@Property()
|
||||
fogDensity = 0
|
||||
|
||||
@ -27,15 +21,6 @@ export class BaseWorld extends BaseEntity {
|
||||
return this.date
|
||||
}
|
||||
|
||||
setIsRainEnabled(isRainEnabled: boolean) {
|
||||
this.isRainEnabled = isRainEnabled
|
||||
return this
|
||||
}
|
||||
|
||||
getIsRainEnabled() {
|
||||
return this.isRainEnabled
|
||||
}
|
||||
|
||||
setRainPercentage(rainPercentage: number) {
|
||||
this.rainPercentage = rainPercentage
|
||||
return this
|
||||
@ -45,15 +30,6 @@ export class BaseWorld extends BaseEntity {
|
||||
return this.rainPercentage
|
||||
}
|
||||
|
||||
setIsFogEnabled(isFogEnabled: boolean) {
|
||||
this.isFogEnabled = isFogEnabled
|
||||
return this
|
||||
}
|
||||
|
||||
getIsFogEnabled() {
|
||||
return this.isFogEnabled
|
||||
}
|
||||
|
||||
setFogDensity(fogDensity: number) {
|
||||
this.fogDensity = fogDensity
|
||||
return this
|
||||
|
@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
|
||||
import { BaseCharacterHair } from '#entities/base/characterHair'
|
||||
|
||||
@Entity()
|
||||
export class CharacterHair extends BaseCharacterHair {}
|
||||
export class CharacterHair extends BaseCharacterHair {
|
||||
public async cache() {
|
||||
try {
|
||||
return this
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
|
||||
import { BaseCharacterType } from '#entities/base/characterType'
|
||||
|
||||
@Entity()
|
||||
export class CharacterType extends BaseCharacterType {}
|
||||
export class CharacterType extends BaseCharacterType {
|
||||
public async cache() {
|
||||
try {
|
||||
return this
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,5 +2,38 @@ import { Entity } from '@mikro-orm/core'
|
||||
|
||||
import { BaseMap } from '#entities/base/map'
|
||||
|
||||
export type MapCacheT = ReturnType<Map['cache']> | {}
|
||||
|
||||
@Entity()
|
||||
export class Map extends BaseMap {}
|
||||
export class Map extends BaseMap {
|
||||
public async cache() {
|
||||
try {
|
||||
await this.getPlacedMapObjects().load()
|
||||
await this.getMapEffects().load()
|
||||
|
||||
return {
|
||||
id: this.getId(),
|
||||
name: this.getName(),
|
||||
width: this.getWidth(),
|
||||
height: this.getHeight(),
|
||||
tiles: this.getTiles(),
|
||||
pvp: this.getPvp(),
|
||||
updatedAt: this.getUpdatedAt(),
|
||||
placedMapObjects: this.getPlacedMapObjects().map((placedMapObject) => ({
|
||||
id: placedMapObject.getId(),
|
||||
mapObject: placedMapObject.getMapObject().getId(),
|
||||
isRotated: placedMapObject.getIsRotated(),
|
||||
positionX: placedMapObject.getPositionX(),
|
||||
positionY: placedMapObject.getPositionY()
|
||||
})),
|
||||
mapEffects: this.getMapEffects().map((mapEffect) => ({
|
||||
effect: mapEffect.getEffect(),
|
||||
strength: mapEffect.getStrength()
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
|
||||
import { BaseMapObject } from '#entities/base/mapObject'
|
||||
|
||||
@Entity()
|
||||
export class MapObject extends BaseMapObject {}
|
||||
export class MapObject extends BaseMapObject {
|
||||
public async cache() {
|
||||
try {
|
||||
return this
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,4 +3,30 @@ import { Entity } from '@mikro-orm/core'
|
||||
import { BaseSprite } from '#entities/base/sprite'
|
||||
|
||||
@Entity()
|
||||
export class Sprite extends BaseSprite {}
|
||||
export class Sprite extends BaseSprite {
|
||||
public async cache() {
|
||||
await this.getSpriteActions().load()
|
||||
|
||||
try {
|
||||
return {
|
||||
id: this.getId(),
|
||||
name: this.getName(),
|
||||
createdAt: this.getCreatedAt(),
|
||||
updatedAt: this.getUpdatedAt(),
|
||||
spriteActions: this.getSpriteActions().map((spriteAction) => ({
|
||||
id: spriteAction.getId(),
|
||||
action: spriteAction.getAction(),
|
||||
originX: spriteAction.getOriginX(),
|
||||
originY: spriteAction.getOriginY(),
|
||||
frameWidth: spriteAction.getFrameWidth(),
|
||||
frameHeight: spriteAction.getFrameHeight(),
|
||||
frameRate: spriteAction.getFrameRate(),
|
||||
frameCount: spriteAction.getSprites()?.length
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
|
||||
import { BaseTile } from '#entities/base/tile'
|
||||
|
||||
@Entity()
|
||||
export class Tile extends BaseTile {}
|
||||
export class Tile extends BaseTile {
|
||||
public async cache() {
|
||||
try {
|
||||
return this
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { CharacterHair } from '#entities/characterHair'
|
||||
import CharacterHairRepository from '#repositories/characterHairRepository'
|
||||
|
||||
interface IPayload {}
|
||||
|
||||
export default class characterHairListEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('character:hair:list', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise<void> {
|
||||
try {
|
||||
const characterHairRepository = new CharacterHairRepository()
|
||||
const items: CharacterHair[] = await characterHairRepository.getAllSelectable(['sprite'])
|
||||
|
||||
return callback(items)
|
||||
} catch (error) {
|
||||
this.logger.error('character:hair:list error', error)
|
||||
return callback([])
|
||||
}
|
||||
}
|
||||
}
|
@ -32,9 +32,6 @@ export default class CharacterConnectEvent extends BaseEvent {
|
||||
return
|
||||
}
|
||||
|
||||
// Populate character with characterType and characterHair
|
||||
await this.characterRepository.getEntityManager().populate(character, ['characterType', 'characterHair'])
|
||||
|
||||
// Set character id
|
||||
this.socket.characterId = character.id
|
||||
|
||||
|
@ -12,9 +12,6 @@ export default class CharacterListEvent extends BaseEvent {
|
||||
const characterRepository = new CharacterRepository()
|
||||
let characters: Character[] = await characterRepository.getByUserId(this.socket.userId!)
|
||||
|
||||
// Populate characters with characterType and characterHair
|
||||
await characterRepository.getEntityManager().populate(characters, ['characterType', 'characterHair'])
|
||||
|
||||
this.socket.emit('character:list', characters)
|
||||
} catch (error: any) {
|
||||
this.logger.error('character:list error', error.message)
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import WeatherManager from '#managers/weatherManager'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
import ChatService from '#services/chatService'
|
||||
|
||||
type TypePayload = {
|
||||
@ -20,7 +19,10 @@ export default class ToggleFogCommand extends BaseEvent {
|
||||
// Check if character exists and is GM
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
await WeatherManager.toggleFog()
|
||||
const args = ChatService.getArgs('fog', data.message)
|
||||
|
||||
await WeatherManager.setFogValue(args![0] ? Number(args![0]) : null)
|
||||
callback(true)
|
||||
} catch (error: any) {
|
||||
this.logger.error('command error', error.message)
|
||||
callback(false)
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import WeatherManager from '#managers/weatherManager'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
import ChatService from '#services/chatService'
|
||||
|
||||
type TypePayload = {
|
||||
@ -20,7 +19,10 @@ export default class ToggleRainCommand extends BaseEvent {
|
||||
// Check if character exists and is GM
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
await WeatherManager.toggleRain()
|
||||
let args = ChatService.getArgs('rain', data.message)
|
||||
|
||||
await WeatherManager.setRainValue(args![0] ? Number(args![0]) : null)
|
||||
callback(true)
|
||||
} catch (error: any) {
|
||||
this.logger.error('command error', error.message)
|
||||
callback(false)
|
||||
|
@ -29,7 +29,8 @@ export default class CharacterHairUpdateEvent extends BaseEvent {
|
||||
const characterHair = await characterHairRepository.getById(data.id)
|
||||
if (!characterHair) return callback(false)
|
||||
|
||||
await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite).save()
|
||||
await characterHair.setName(data.name).setGender(data.gender).setIsSelectable(data.isSelectable).setSprite(sprite).setUpdatedAt(new Date()).save()
|
||||
|
||||
return callback(true)
|
||||
} catch (error) {
|
||||
this.logger.error(`Error updating character hair: ${error instanceof Error ? error.message : String(error)}`)
|
||||
|
@ -8,7 +8,6 @@ type Payload = {
|
||||
tags: string[]
|
||||
originX: number
|
||||
originY: number
|
||||
isAnimated: boolean
|
||||
frameRate: number
|
||||
frameWidth: number
|
||||
frameHeight: number
|
||||
@ -33,7 +32,6 @@ export default class MapObjectUpdateEvent extends BaseEvent {
|
||||
.setTags(data.tags)
|
||||
.setOriginX(data.originX)
|
||||
.setOriginY(data.originY)
|
||||
.setIsAnimated(data.isAnimated)
|
||||
.setFrameRate(data.frameRate)
|
||||
.setFrameWidth(data.frameWidth)
|
||||
.setFrameHeight(data.frameHeight)
|
||||
|
@ -1,61 +1,42 @@
|
||||
import { writeFile, mkdir } from 'node:fs/promises'
|
||||
|
||||
import sharp from 'sharp'
|
||||
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import Storage from '#application/storage'
|
||||
import { SpriteAction } from '#entities/spriteAction'
|
||||
import { UUID } from '#application/types'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
import { SpriteAction } from '#entities/spriteAction'
|
||||
import sharp from 'sharp'
|
||||
import fs from 'fs'
|
||||
|
||||
// Constants
|
||||
const ISOMETRIC_CONFIG = {
|
||||
tileWidth: 64,
|
||||
tileHeight: 32,
|
||||
centerOffset: 32,
|
||||
bodyRatios: {
|
||||
topStart: 0.15,
|
||||
topEnd: 0.45,
|
||||
weightUpper: 0.7,
|
||||
weightLower: 0.3
|
||||
interface SpriteImage {
|
||||
url: string
|
||||
offset: {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
} as const
|
||||
}
|
||||
|
||||
// Types
|
||||
interface ContentBounds {
|
||||
left: number
|
||||
right: number
|
||||
interface ImageDimensions {
|
||||
width: number
|
||||
height: number
|
||||
offsetX: number
|
||||
offsetY: number
|
||||
}
|
||||
|
||||
interface EffectiveDimensions {
|
||||
width: number
|
||||
height: number
|
||||
top: number
|
||||
bottom: number
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
interface SpriteActionInput extends Omit<SpriteAction, 'id' | 'spriteId' | 'frameWidth' | 'frameHeight'> {
|
||||
sprites: string[]
|
||||
}
|
||||
|
||||
interface UpdatePayload {
|
||||
id: string
|
||||
type Payload = {
|
||||
id: UUID
|
||||
name: string
|
||||
spriteActions: SpriteAction[]
|
||||
}
|
||||
|
||||
interface ProcessedSpriteAction extends SpriteActionInput {
|
||||
frameWidth: number
|
||||
frameHeight: number
|
||||
buffersWithDimensions: ProcessedFrame[]
|
||||
}
|
||||
|
||||
interface ProcessedFrame {
|
||||
buffer: Buffer
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
interface SpriteAnalysis {
|
||||
massCenter: number
|
||||
spinePosition: number
|
||||
contentBounds: ContentBounds
|
||||
spriteActions: Array<{
|
||||
action: string
|
||||
sprites: SpriteImage[]
|
||||
originX: number
|
||||
originY: number
|
||||
frameRate: number
|
||||
}>
|
||||
}
|
||||
|
||||
export default class SpriteUpdateEvent extends BaseEvent {
|
||||
@ -63,326 +44,173 @@ export default class SpriteUpdateEvent extends BaseEvent {
|
||||
this.socket.on('gm:sprite:update', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(payload: UpdatePayload, callback: (success: boolean) => void): Promise<void> {
|
||||
private async handleEvent(data: Payload, callback: (success: boolean) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
const parsedActions = this.validateSpriteActions(payload.spriteActions)
|
||||
const spriteRepository = new SpriteRepository()
|
||||
const sprite = await spriteRepository.getById(data.id)
|
||||
if (!sprite) return callback(false)
|
||||
|
||||
// Process sprites
|
||||
const processedActions = await Promise.all(
|
||||
parsedActions.map(async (action) => {
|
||||
const spriteBuffers = await this.convertBase64ToBuffers(action.sprites)
|
||||
const frameWidth = ISOMETRIC_CONFIG.tileWidth
|
||||
const frameHeight = await this.calculateOptimalHeight(spriteBuffers)
|
||||
const processedFrames = await this.normalizeFrames(spriteBuffers, frameWidth, frameHeight)
|
||||
await spriteRepository.getEntityManager().populate(sprite, ['spriteActions'])
|
||||
|
||||
return {
|
||||
...action,
|
||||
frameWidth,
|
||||
frameHeight,
|
||||
buffersWithDimensions: processedFrames
|
||||
// Update sprite in database
|
||||
await sprite.setName(data.name).save()
|
||||
|
||||
// First verify all sprite sheets can be generated
|
||||
for (const actionData of data.spriteActions) {
|
||||
if (!await this.generateSpriteSheet(actionData.sprites, sprite.getId(), actionData.action)) {
|
||||
return callback(false)
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
await Promise.all([
|
||||
this.updateDatabase(payload.id, payload.name, processedActions),
|
||||
this.saveSpritesToDisk(
|
||||
payload.id,
|
||||
processedActions.filter((a) => a.buffersWithDimensions.length > 0)
|
||||
)
|
||||
])
|
||||
const existingActions = sprite.getSpriteActions()
|
||||
|
||||
callback(true)
|
||||
// Remove existing actions only after confirming sprite sheets generated successfully
|
||||
for (const existingAction of existingActions) {
|
||||
await spriteRepository.getEntityManager().removeAndFlush(existingAction)
|
||||
}
|
||||
|
||||
// Create new actions
|
||||
for (const actionData of data.spriteActions) {
|
||||
// Process images and calculate dimensions
|
||||
const imageData = await Promise.all(actionData.sprites.map(sprite => this.processImage(sprite)))
|
||||
const effectiveDimensions = imageData.map(dimensions => this.calculateEffectiveDimensions(dimensions))
|
||||
|
||||
// Calculate total height needed for the sprite sheet
|
||||
const maxHeight = Math.max(...effectiveDimensions.map(d => d.height))
|
||||
const maxTop = Math.max(...effectiveDimensions.map(d => d.top))
|
||||
const maxBottom = Math.max(...effectiveDimensions.map(d => d.bottom))
|
||||
const totalHeight = maxHeight + maxTop + maxBottom
|
||||
|
||||
const spriteAction = new SpriteAction()
|
||||
spriteAction.setSprite(sprite)
|
||||
sprite.getSpriteActions().add(spriteAction)
|
||||
|
||||
spriteAction
|
||||
.setAction(actionData.action)
|
||||
.setSprites(actionData.sprites)
|
||||
.setOriginX(actionData.originX)
|
||||
.setOriginY(actionData.originY)
|
||||
.setFrameWidth(await this.calculateMaxWidth(actionData.sprites))
|
||||
.setFrameHeight(totalHeight)
|
||||
.setFrameRate(actionData.frameRate)
|
||||
|
||||
await spriteRepository.getEntityManager().persistAndFlush(spriteAction)
|
||||
}
|
||||
|
||||
return callback(true)
|
||||
} catch (error) {
|
||||
this.handleError(error, payload.id, callback)
|
||||
console.error(`Error updating sprite ${data.id}:`, error)
|
||||
return callback(false)
|
||||
}
|
||||
}
|
||||
|
||||
private validateSpriteActions(actions: Prisma.JsonValue): SpriteActionInput[] {
|
||||
private async generateSpriteSheet(sprites: SpriteImage[], spriteId: string, action: string): Promise<boolean> {
|
||||
try {
|
||||
const parsed = JSON.parse(JSON.stringify(actions)) as SpriteActionInput[]
|
||||
if (!Array.isArray(parsed)) {
|
||||
throw new Error('Sprite actions must be an array')
|
||||
}
|
||||
return parsed
|
||||
} catch (error) {
|
||||
throw new Error(`Invalid sprite actions format: ${this.getErrorMessage(error)}`)
|
||||
}
|
||||
}
|
||||
if (!sprites.length) return true
|
||||
|
||||
private async convertBase64ToBuffers(sprites: string[]): Promise<Buffer[]> {
|
||||
return sprites.map((sprite) => Buffer.from(sprite.split(',')[1], 'base64'))
|
||||
}
|
||||
// Process all images and get their dimensions
|
||||
const imageData = await Promise.all(sprites.map(sprite => this.processImage(sprite)))
|
||||
const effectiveDimensions = imageData.map(dimensions => this.calculateEffectiveDimensions(dimensions))
|
||||
|
||||
private async normalizeFrames(buffers: Buffer[], frameWidth: number, frameHeight: number): Promise<ProcessedFrame[]> {
|
||||
return Promise.all(
|
||||
buffers.map(async (buffer) => {
|
||||
const normalizedBuffer = await this.normalizeIsometricSprite(buffer, frameWidth, frameHeight)
|
||||
return {
|
||||
buffer: normalizedBuffer,
|
||||
width: frameWidth,
|
||||
height: frameHeight
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
// Calculate maximum dimensions
|
||||
const maxWidth = Math.max(...effectiveDimensions.map(d => d.width))
|
||||
const maxHeight = Math.max(...effectiveDimensions.map(d => d.height))
|
||||
const maxTop = Math.max(...effectiveDimensions.map(d => d.top))
|
||||
const maxBottom = Math.max(...effectiveDimensions.map(d => d.bottom))
|
||||
|
||||
private async calculateOptimalHeight(buffers: Buffer[]): Promise<number> {
|
||||
if (!buffers.length) return ISOMETRIC_CONFIG.tileHeight // Return default height if no buffers
|
||||
// Calculate total height needed
|
||||
const totalHeight = maxHeight + maxTop + maxBottom
|
||||
|
||||
const heights = await Promise.all(
|
||||
buffers.map(async (buffer) => {
|
||||
const bounds = await this.findContentBounds(buffer)
|
||||
return bounds.height
|
||||
})
|
||||
)
|
||||
return Math.ceil(Math.max(...heights) / 2) * 2
|
||||
}
|
||||
// Process images and create sprite sheet
|
||||
const processedImages = await Promise.all(
|
||||
sprites.map(async (sprite, index) => {
|
||||
const { width, height, offsetX, offsetY } = await this.processImage(sprite)
|
||||
const uri = sprite.url.split(';base64,').pop()
|
||||
if (!uri) throw new Error('Invalid base64 image')
|
||||
const buffer = Buffer.from(uri, 'base64')
|
||||
|
||||
private async normalizeIsometricSprite(buffer: Buffer, frameWidth: number, frameHeight: number): Promise<Buffer> {
|
||||
const analysis = await this.analyzeIsometricSprite(buffer)
|
||||
const idealCenter = Math.floor(frameWidth / 2)
|
||||
const offset = Math.round(idealCenter - analysis.massCenter)
|
||||
|
||||
// Process the input sprite
|
||||
const processedInput = await sharp(buffer)
|
||||
.ensureAlpha()
|
||||
.resize({
|
||||
width: frameWidth, // Set maximum width
|
||||
height: frameHeight, // Set maximum height
|
||||
fit: 'inside', // Ensure image fits within dimensions
|
||||
kernel: sharp.kernel.nearest,
|
||||
position: 'center',
|
||||
withoutEnlargement: true // Don't enlarge smaller images
|
||||
})
|
||||
.png({
|
||||
compressionLevel: 9,
|
||||
adaptiveFiltering: false,
|
||||
palette: true,
|
||||
quality: 100,
|
||||
colors: 256
|
||||
})
|
||||
.toBuffer()
|
||||
|
||||
// Create the final composition
|
||||
// Create individual frame
|
||||
const left = offsetX >= 0 ? offsetX : 0
|
||||
const verticalOffset = totalHeight - height - (offsetY >= 0 ? offsetY : 0)
|
||||
return sharp({
|
||||
create: {
|
||||
width: frameWidth,
|
||||
height: frameHeight,
|
||||
width: maxWidth,
|
||||
height: totalHeight,
|
||||
channels: 4,
|
||||
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
||||
}
|
||||
})
|
||||
.composite([
|
||||
{
|
||||
input: processedInput,
|
||||
left: offset,
|
||||
top: 0,
|
||||
blend: 'over'
|
||||
}
|
||||
])
|
||||
.png({
|
||||
compressionLevel: 9,
|
||||
adaptiveFiltering: false,
|
||||
palette: true,
|
||||
quality: 100,
|
||||
colors: 256
|
||||
})
|
||||
.composite([{ input: buffer, left, top: verticalOffset }])
|
||||
.png()
|
||||
.toBuffer()
|
||||
}
|
||||
|
||||
private async analyzeIsometricSprite(buffer: Buffer): Promise<SpriteAnalysis> {
|
||||
const { data, info } = await sharp(buffer).raw().ensureAlpha().toBuffer({ resolveWithObject: true })
|
||||
const { width, height } = info
|
||||
const upperStart = Math.floor(height * ISOMETRIC_CONFIG.bodyRatios.topStart)
|
||||
const upperEnd = Math.floor(height * ISOMETRIC_CONFIG.bodyRatios.topEnd)
|
||||
|
||||
const { columnDensity, upperBodyDensity, bounds } = this.calculatePixelDistribution(data, width, height, upperStart, upperEnd)
|
||||
const spinePosition = this.findSpinePosition(upperBodyDensity)
|
||||
const massCenter = this.calculateWeightedMassCenter(columnDensity, upperBodyDensity)
|
||||
|
||||
return {
|
||||
massCenter,
|
||||
spinePosition,
|
||||
contentBounds: bounds
|
||||
}
|
||||
}
|
||||
|
||||
private calculatePixelDistribution(data: Buffer, width: number, height: number, upperStart: number, upperEnd: number) {
|
||||
const columnDensity = new Array(width).fill(0)
|
||||
const upperBodyDensity = new Array(width).fill(0)
|
||||
const bounds = { left: width, right: 0, top: height, bottom: 0 }
|
||||
|
||||
for (let y = 0; y < height; y++) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
if (data[(y * width + x) * 4 + 3] > 0) {
|
||||
columnDensity[x]++
|
||||
if (y >= upperStart && y <= upperEnd) {
|
||||
upperBodyDensity[x]++
|
||||
}
|
||||
this.updateBounds(bounds, x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
columnDensity,
|
||||
upperBodyDensity,
|
||||
bounds: {
|
||||
...bounds,
|
||||
width: bounds.right - bounds.left + 1,
|
||||
height: bounds.bottom - bounds.top + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private updateBounds(bounds: { left: number; right: number; top: number; bottom: number }, x: number, y: number): void {
|
||||
bounds.left = Math.min(bounds.left, x)
|
||||
bounds.right = Math.max(bounds.right, x)
|
||||
bounds.top = Math.min(bounds.top, y)
|
||||
bounds.bottom = Math.max(bounds.bottom, y)
|
||||
}
|
||||
|
||||
private findSpinePosition(density: number[]): number {
|
||||
return density.reduce((maxIdx, curr, idx, arr) => (curr > arr[maxIdx] ? idx : maxIdx), 0)
|
||||
}
|
||||
|
||||
private calculateWeightedMassCenter(columnDensity: number[], upperBodyDensity: number[]): number {
|
||||
const upperMassCenter = this.calculateMassCenter(upperBodyDensity)
|
||||
const lowerMassCenter = this.calculateMassCenter(columnDensity)
|
||||
|
||||
return Math.round(upperMassCenter * ISOMETRIC_CONFIG.bodyRatios.weightUpper + lowerMassCenter * ISOMETRIC_CONFIG.bodyRatios.weightLower)
|
||||
}
|
||||
|
||||
private calculateMassCenter(density: number[]): number {
|
||||
const totalMass = density.reduce((sum, mass) => sum + mass, 0)
|
||||
if (!totalMass) return 0
|
||||
|
||||
const weightedSum = density.reduce((sum, mass, position) => sum + position * mass, 0)
|
||||
return Math.round(weightedSum / totalMass)
|
||||
}
|
||||
|
||||
private async findContentBounds(buffer: Buffer) {
|
||||
const { data, info } = await sharp(buffer).raw().ensureAlpha().toBuffer({ resolveWithObject: true })
|
||||
|
||||
const width = info.width
|
||||
const height = info.height
|
||||
|
||||
let left = width
|
||||
let right = 0
|
||||
let top = height
|
||||
let bottom = 0
|
||||
|
||||
// Find actual content boundaries by checking alpha channel
|
||||
for (let y = 0; y < height; y++) {
|
||||
for (let x = 0; x < width; x++) {
|
||||
const idx = (y * width + x) * 4
|
||||
if (data[idx + 3] > 0) {
|
||||
// If pixel is not transparent
|
||||
left = Math.min(left, x)
|
||||
right = Math.max(right, x)
|
||||
top = Math.min(top, y)
|
||||
bottom = Math.max(bottom, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
width: right - left + 1,
|
||||
height: bottom - top + 1,
|
||||
leftOffset: left,
|
||||
topOffset: top
|
||||
}
|
||||
}
|
||||
|
||||
private async saveSpritesToDisk(id: string, actions: ProcessedSpriteAction[]): Promise<void> {
|
||||
const publicFolder = Storage.getPublicPath('sprites', id)
|
||||
await mkdir(publicFolder, { recursive: true })
|
||||
|
||||
await Promise.all(
|
||||
actions.map(async (action) => {
|
||||
const spritesheet = await this.createSpritesheet(action.buffersWithDimensions)
|
||||
await writeFile(Storage.getPublicPath('sprites', id, `${action.action}.png`), spritesheet)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
private async createSpritesheet(frames: ProcessedFrame[]): Promise<Buffer> {
|
||||
const background = await sharp({
|
||||
// Combine frames into sprite sheet
|
||||
const spriteSheet = await sharp({
|
||||
create: {
|
||||
width: ISOMETRIC_CONFIG.tileWidth * frames.length,
|
||||
height: frames[0].height,
|
||||
width: maxWidth * sprites.length,
|
||||
height: totalHeight,
|
||||
channels: 4,
|
||||
background: { r: 0, g: 0, b: 0, alpha: 0 }
|
||||
}
|
||||
})
|
||||
.png({
|
||||
compressionLevel: 9,
|
||||
adaptiveFiltering: false,
|
||||
palette: true,
|
||||
quality: 100,
|
||||
colors: 256,
|
||||
dither: 0
|
||||
})
|
||||
.toBuffer()
|
||||
|
||||
return sharp(background)
|
||||
.composite(
|
||||
frames.map((frame, index) => ({
|
||||
input: frame.buffer,
|
||||
left: index * ISOMETRIC_CONFIG.tileWidth,
|
||||
top: 0,
|
||||
blend: 'over'
|
||||
processedImages.map((buffer, index) => ({
|
||||
input: buffer,
|
||||
left: index * maxWidth,
|
||||
top: 0
|
||||
}))
|
||||
)
|
||||
.png({
|
||||
compressionLevel: 9,
|
||||
adaptiveFiltering: false,
|
||||
palette: true,
|
||||
quality: 100,
|
||||
colors: 256,
|
||||
dither: 0
|
||||
})
|
||||
.png()
|
||||
.toBuffer()
|
||||
|
||||
// Ensure directory exists
|
||||
const dir = `public/sprites/${spriteId}`
|
||||
await fs.promises.mkdir(dir, { recursive: true })
|
||||
|
||||
// Save the sprite sheet
|
||||
await fs.promises.writeFile(`${dir}/${action}.png`, spriteSheet)
|
||||
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('Error generating sprite sheet:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private async updateDatabase(id: string, name: string, actions: ProcessedSpriteAction[]): Promise<void> {
|
||||
await prisma.sprite.update({
|
||||
where: { id },
|
||||
data: {
|
||||
name,
|
||||
spriteActions: {
|
||||
deleteMany: { spriteId: id },
|
||||
create: actions.map(this.mapActionToDatabase)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await (await SpriteRepository.getById(id))?.setName(name).setSpriteActions(actions).update()
|
||||
}
|
||||
|
||||
private mapActionToDatabase(action: ProcessedSpriteAction) {
|
||||
private async processImage(sprite: SpriteImage): Promise<ImageDimensions> {
|
||||
const uri = sprite.url.split(';base64,').pop()
|
||||
if (!uri) throw new Error('Invalid base64 image')
|
||||
const buffer = Buffer.from(uri, 'base64')
|
||||
const metadata = await sharp(buffer).metadata()
|
||||
return {
|
||||
action: action.action,
|
||||
sprites: action.sprites,
|
||||
originX: action.originX,
|
||||
originY: action.originY,
|
||||
isAnimated: action.isAnimated,
|
||||
isLooping: action.isLooping,
|
||||
frameWidth: action.frameWidth,
|
||||
frameHeight: action.frameHeight,
|
||||
frameRate: action.frameRate
|
||||
width: metadata.width ?? 0,
|
||||
height: metadata.height ?? 0,
|
||||
offsetX: sprite.offset?.x ?? 0,
|
||||
offsetY: sprite.offset?.y ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
private handleError(error: unknown, spriteId: string, callback: (success: boolean) => void): void {
|
||||
this.logger.error(`Error updating sprite ${spriteId}: ${this.getErrorMessage(error)}`)
|
||||
callback(false)
|
||||
private calculateEffectiveDimensions(imageDimensions: ImageDimensions): EffectiveDimensions {
|
||||
return {
|
||||
width: imageDimensions.width + Math.abs(imageDimensions.offsetX),
|
||||
height: imageDimensions.height + Math.abs(imageDimensions.offsetY),
|
||||
top: imageDimensions.offsetY >= 0 ? imageDimensions.offsetY : 0,
|
||||
bottom: imageDimensions.offsetY < 0 ? Math.abs(imageDimensions.offsetY) : 0
|
||||
}
|
||||
}
|
||||
|
||||
private getErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error)
|
||||
private async calculateMaxWidth(sprites: SpriteImage[]): Promise<number> {
|
||||
if (!sprites.length) return 0
|
||||
|
||||
// Process all images and get their dimensions
|
||||
const imageData = await Promise.all(sprites.map(sprite => this.processImage(sprite)))
|
||||
const effectiveDimensions = imageData.map(dimensions => this.calculateEffectiveDimensions(dimensions))
|
||||
|
||||
// Calculate maximum width needed
|
||||
return Math.max(...effectiveDimensions.map(d => d.width))
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Map } from '#entities/map'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
import { Map, MapCacheT } from '#entities/map'
|
||||
|
||||
type Payload = {
|
||||
name: string
|
||||
@ -13,11 +12,11 @@ export default class MapCreateEvent extends BaseEvent {
|
||||
this.socket.on('gm:map:create', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: Payload, callback: (response: Map[]) => void): Promise<void> {
|
||||
private async handleEvent(data: Payload, callback: (response: MapCacheT | false) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
this.logger.info(`User ${(await this.getCharacter())!.getId()} has created a new map via map editor.`)
|
||||
this.logger.info(`GM ${(await this.getCharacter())!.getId()} has created a new map via map editor.`)
|
||||
|
||||
const map = new Map()
|
||||
await map
|
||||
@ -27,14 +26,11 @@ export default class MapCreateEvent extends BaseEvent {
|
||||
.setTiles(Array.from({ length: data.height }, () => Array.from({ length: data.width }, () => 'blank_tile')))
|
||||
.save()
|
||||
|
||||
const mapRepository = new MapRepository()
|
||||
const mapList = await mapRepository.getAll()
|
||||
|
||||
return callback(mapList)
|
||||
return callback(await map.cache())
|
||||
} catch (error: any) {
|
||||
this.logger.error('gm:map:create error', error.message)
|
||||
this.socket.emit('notification', { message: 'Failed to create map.' })
|
||||
return callback([])
|
||||
return callback(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { BaseEvent } from '#application/base/baseEvent'
|
||||
import { Map } from '#entities/map'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
|
||||
interface IPayload {}
|
||||
|
||||
export default class MapListEvent extends BaseEvent {
|
||||
public listen(): void {
|
||||
this.socket.on('gm:map:list', this.handleEvent.bind(this))
|
||||
}
|
||||
|
||||
private async handleEvent(data: IPayload, callback: (response: Map[]) => void): Promise<void> {
|
||||
try {
|
||||
if (!(await this.isCharacterGM())) return
|
||||
|
||||
this.logger.info(`User ${(await this.getCharacter())!.getId()} has listed maps via map editor.`)
|
||||
|
||||
const mapRepository = new MapRepository()
|
||||
const maps = await mapRepository.getAll()
|
||||
|
||||
return callback(maps)
|
||||
} catch (error: any) {
|
||||
this.logger.error('gm:map:list error', error.message)
|
||||
return callback([])
|
||||
}
|
||||
}
|
||||
}
|
@ -68,6 +68,7 @@ export default class MapUpdateEvent extends BaseEvent {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove map event tiles and placed map objects that are out of bounds
|
||||
data.mapEventTiles = data.mapEventTiles.filter((tile) => tile.positionX >= 0 && tile.positionX < data.width && tile.positionY >= 0 && tile.positionY < data.height)
|
||||
data.placedMapObjects = data.placedMapObjects.filter((obj) => obj.positionX >= 0 && obj.positionX < data.width && obj.positionY >= 0 && obj.positionY < data.height)
|
||||
|
||||
@ -95,13 +96,7 @@ export default class MapUpdateEvent extends BaseEvent {
|
||||
|
||||
// Create and add new map objects
|
||||
for (const object of data.placedMapObjects) {
|
||||
const mapObject = new PlacedMapObject()
|
||||
.setMapObject(object.mapObject)
|
||||
.setDepth(object.depth)
|
||||
.setIsRotated(object.isRotated)
|
||||
.setPositionX(object.positionX)
|
||||
.setPositionY(object.positionY)
|
||||
.setMap(map)
|
||||
const mapObject = new PlacedMapObject().setMapObject(object.mapObject).setIsRotated(object.isRotated).setPositionX(object.positionX).setPositionY(object.positionY).setMap(map)
|
||||
|
||||
map.placedMapObjects.add(mapObject)
|
||||
}
|
||||
@ -113,8 +108,6 @@ export default class MapUpdateEvent extends BaseEvent {
|
||||
map.mapEffects.add(mapEffect)
|
||||
}
|
||||
|
||||
console.log(map.getPlacedMapObjects().count())
|
||||
|
||||
// Update map properties
|
||||
await map.setName(data.name).setWidth(data.width).setHeight(data.height).setTiles(data.tiles).setPvp(data.pvp).setUpdatedAt(new Date()).save()
|
||||
|
||||
|
@ -38,7 +38,7 @@ export default class CharacterMove extends BaseEvent {
|
||||
await this.moveAlongPath(mapCharacter, path)
|
||||
}
|
||||
|
||||
private async moveAlongPath(mapCharacter: MapCharacter, path: Array<{ x: number; y: number }>): Promise<void> {
|
||||
private async moveAlongPath(mapCharacter: MapCharacter, path: Array<{ positionX: number; positionY: number }>): Promise<void> {
|
||||
const character = mapCharacter.getCharacter()
|
||||
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
@ -47,19 +47,19 @@ export default class CharacterMove extends BaseEvent {
|
||||
}
|
||||
|
||||
const [start, end] = [path[i], path[i + 1]]
|
||||
character.setRotation(CharacterService.calculateRotation(start.x, start.y, end.x, end.y))
|
||||
character.setRotation(CharacterService.calculateRotation(start.positionX, start.positionY, end.positionX, end.positionY))
|
||||
|
||||
const mapEventTileRepository = new MapEventTileRepository()
|
||||
const mapEventTile = await mapEventTileRepository.getEventTileByMapIdAndPosition(character.getMap().getId(), Math.floor(end.x), Math.floor(end.y))
|
||||
const mapEventTile = await mapEventTileRepository.getEventTileByMapIdAndPosition(character.getMap().getId(), Math.floor(end.positionX), Math.floor(end.positionY))
|
||||
|
||||
if (mapEventTile?.type === 'BLOCK') break
|
||||
if (mapEventTile?.type === 'TELEPORT' && mapEventTile.teleport) {
|
||||
await this.handleMapEventTile(mapEventTile as MapEventTileWithTeleport)
|
||||
break
|
||||
return
|
||||
}
|
||||
|
||||
// Update position first
|
||||
character.setPositionX(end.x).setPositionY(end.y)
|
||||
character.setPositionX(end.positionX).setPositionY(end.positionY)
|
||||
|
||||
// Then emit with the same properties
|
||||
this.io.in(character.map.id).emit('map:character:move', {
|
||||
|
@ -1,119 +0,0 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
import { BaseController } from '#application/base/baseController'
|
||||
import Database from '#application/database'
|
||||
import Storage from '#application/storage'
|
||||
import { AssetData, UUID } from '#application/types'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
import SpriteRepository from '#repositories/spriteRepository'
|
||||
import TileRepository from '#repositories/tileRepository'
|
||||
|
||||
export class AssetsController extends BaseController {
|
||||
private readonly mapRepository = new MapRepository()
|
||||
private readonly spriteRepository = new SpriteRepository()
|
||||
private readonly tileRepository = new TileRepository()
|
||||
|
||||
/**
|
||||
* List tiles
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async listTiles(req: Request, res: Response) {
|
||||
const assets: AssetData[] = []
|
||||
const tiles = await this.tileRepository.getAll()
|
||||
|
||||
for (const tile of tiles) {
|
||||
assets.push({ key: tile.getId(), data: '/assets/tiles/' + tile.getId() + '.png', group: 'tiles', updatedAt: tile.getUpdatedAt() } as AssetData)
|
||||
}
|
||||
|
||||
return this.sendSuccess(res, assets)
|
||||
}
|
||||
|
||||
/**
|
||||
* List tiles by map
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async listTilesByMap(req: Request, res: Response) {
|
||||
const mapId = req.params.mapId as UUID
|
||||
|
||||
if (!mapId) {
|
||||
return this.sendError(res, 'Invalid map ID', 400)
|
||||
}
|
||||
|
||||
const map = await this.mapRepository.getById(mapId)
|
||||
if (!map) {
|
||||
return this.sendError(res, 'Map not found', 404)
|
||||
}
|
||||
|
||||
const assets: AssetData[] = []
|
||||
const tiles = await this.tileRepository.getByMapId(mapId)
|
||||
|
||||
for (const tile of tiles) {
|
||||
assets.push({ key: tile.getId(), data: '/assets/tiles/' + tile.getId() + '.png', group: 'tiles', updatedAt: tile.getUpdatedAt() } as AssetData)
|
||||
}
|
||||
|
||||
return this.sendSuccess(res, assets)
|
||||
}
|
||||
|
||||
/**
|
||||
* List sprite actions
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async listSpriteActions(req: Request, res: Response) {
|
||||
const spriteId = req.params.spriteId as UUID
|
||||
|
||||
if (!spriteId) {
|
||||
return this.sendError(res, 'Invalid sprite ID', 400)
|
||||
}
|
||||
|
||||
const sprite = await this.spriteRepository.getById(spriteId)
|
||||
if (!sprite) {
|
||||
return this.sendError(res, 'Sprite not found', 404)
|
||||
}
|
||||
|
||||
await this.spriteRepository.getEntityManager().populate(sprite, ['spriteActions'])
|
||||
|
||||
const assets: AssetData[] = sprite.getSpriteActions().map((spriteAction) => ({
|
||||
key: sprite.getId() + '-' + spriteAction.getAction(),
|
||||
data: '/assets/sprites/' + sprite.getId() + '/' + spriteAction.getAction() + '.png',
|
||||
group: spriteAction.getIsAnimated() ? 'sprite_animations' : 'sprites',
|
||||
updatedAt: sprite.getUpdatedAt(),
|
||||
originX: Number(spriteAction.getOriginX().toString()),
|
||||
originY: Number(spriteAction.getOriginY().toString()),
|
||||
isAnimated: spriteAction.getIsAnimated(),
|
||||
frameRate: spriteAction.getFrameRate(),
|
||||
frameWidth: spriteAction.getFrameWidth(),
|
||||
frameHeight: spriteAction.getFrameHeight(),
|
||||
frameCount: spriteAction.getSprites()?.length
|
||||
}))
|
||||
|
||||
return this.sendSuccess(res, assets)
|
||||
}
|
||||
|
||||
/**
|
||||
* Download asset
|
||||
* @param req
|
||||
* @param res
|
||||
*/
|
||||
public async downloadAsset(req: Request, res: Response) {
|
||||
const { type, spriteId, file } = req.params
|
||||
|
||||
const assetPath = type === 'sprites' && spriteId ? Storage.getPublicPath(type, spriteId, file) : Storage.getPublicPath(type, file)
|
||||
|
||||
if (!fs.existsSync(assetPath)) {
|
||||
this.logger.error(`File not found: ${assetPath}`)
|
||||
return this.sendError(res, 'Asset not found', 404)
|
||||
}
|
||||
|
||||
res.sendFile(assetPath, (err) => {
|
||||
if (err) {
|
||||
this.logger.error('Error sending file:' + err)
|
||||
this.sendError(res, 'Error downloading the asset', 500)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,21 +1,36 @@
|
||||
import cors from 'cors'
|
||||
import { Application } from 'express'
|
||||
|
||||
import { AssetsController } from '#http/controllers/assets'
|
||||
import { AuthController } from '#http/controllers/auth'
|
||||
import { AvatarController } from '#http/controllers/avatar'
|
||||
import config from '#application/config'
|
||||
import { AuthController } from '#controllers/auth'
|
||||
import { AvatarController } from '#controllers/avatar'
|
||||
import { CacheController } from '#controllers/cache'
|
||||
import { TexturesController } from '#controllers/textures'
|
||||
|
||||
/**
|
||||
* HTTP manager
|
||||
*/
|
||||
class HttpManager {
|
||||
private readonly authController: AuthController
|
||||
private readonly avatarController: AvatarController
|
||||
private readonly assetsController: AssetsController
|
||||
|
||||
constructor() {
|
||||
this.authController = new AuthController()
|
||||
this.avatarController = new AvatarController()
|
||||
this.assetsController = new AssetsController()
|
||||
}
|
||||
private readonly authController: AuthController = new AuthController()
|
||||
private readonly avatarController: AvatarController = new AvatarController()
|
||||
private readonly texturesController: TexturesController = new TexturesController()
|
||||
private readonly cacheController: CacheController = new CacheController()
|
||||
|
||||
/**
|
||||
* Initialize HTTP manager
|
||||
* @param app
|
||||
*/
|
||||
public async boot(app: Application) {
|
||||
// Add CORS middleware
|
||||
app.use(
|
||||
cors({
|
||||
origin: config.CLIENT_URL,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // Add supported methods
|
||||
allowedHeaders: ['Content-Type', 'Authorization'], // Add allowed headers
|
||||
credentials: true
|
||||
})
|
||||
)
|
||||
|
||||
// Add routes
|
||||
await this.addRoutes(app)
|
||||
}
|
||||
@ -31,11 +46,16 @@ class HttpManager {
|
||||
app.get('/avatar/:characterName', (req, res) => this.avatarController.getByName(req, res))
|
||||
app.get('/avatar/s/:characterTypeId/:characterHairId?', (req, res) => this.avatarController.getByParams(req, res))
|
||||
|
||||
// Assets routes
|
||||
app.get('/assets/list_tiles', (req, res) => this.assetsController.listTiles(req, res))
|
||||
app.get('/assets/list_tiles/:mapId', (req, res) => this.assetsController.listTilesByMap(req, res))
|
||||
app.get('/assets/list_sprite_actions/:spriteId', (req, res) => this.assetsController.listSpriteActions(req, res))
|
||||
app.get('/assets/:type/:spriteId?/:file', (req, res) => this.assetsController.downloadAsset(req, res))
|
||||
// Download texture file
|
||||
app.get('/textures/:type/:spriteId?/:file', (req, res) => this.texturesController.download(req, res))
|
||||
|
||||
// Cache routes
|
||||
app.get('/cache/tiles', (req, res) => this.cacheController.tiles(req, res))
|
||||
app.get('/cache/maps', (req, res) => this.cacheController.maps(req, res))
|
||||
app.get('/cache/map_objects', (req, res) => this.cacheController.mapObjects(req, res))
|
||||
app.get('/cache/sprites', (req, res) => this.cacheController.sprites(req, res))
|
||||
app.get('/cache/character_types', (req, res) => this.cacheController.characterTypes(req, res))
|
||||
app.get('/cache/character_hair', (req, res) => this.cacheController.characterHair(req, res))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@ import { pathToFileURL } from 'url'
|
||||
import { Application } from 'express'
|
||||
import { Server as SocketServer } from 'socket.io'
|
||||
|
||||
import config from '#application/config'
|
||||
import Logger, { LoggerType } from '#application/logger'
|
||||
import Storage from '#application/storage'
|
||||
import { TSocket, UUID } from '#application/types'
|
||||
@ -19,14 +18,7 @@ class SocketManager {
|
||||
* Initialize Socket.IO server
|
||||
*/
|
||||
public async boot(app: Application, http: HTTPServer): Promise<void> {
|
||||
this.io = new SocketServer(http, {
|
||||
cors: {
|
||||
origin: config.CLIENT_URL,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization'],
|
||||
credentials: true
|
||||
}
|
||||
})
|
||||
this.io = new SocketServer(http)
|
||||
|
||||
// Apply authentication middleware
|
||||
this.io.use(Authentication)
|
||||
|
@ -6,9 +6,7 @@ import SocketManager from '#managers/socketManager'
|
||||
import WorldRepository from '#repositories/worldRepository'
|
||||
|
||||
type WeatherState = {
|
||||
isRainEnabled: boolean
|
||||
rainPercentage: number
|
||||
isFogEnabled: boolean
|
||||
fogDensity: number
|
||||
}
|
||||
|
||||
@ -26,9 +24,7 @@ class WeatherManager {
|
||||
private intervalId: NodeJS.Timeout | null = null
|
||||
|
||||
private weatherState: WeatherState = {
|
||||
isRainEnabled: false,
|
||||
rainPercentage: 0,
|
||||
isFogEnabled: false,
|
||||
fogDensity: 0
|
||||
}
|
||||
|
||||
@ -43,18 +39,31 @@ class WeatherManager {
|
||||
return { ...this.weatherState }
|
||||
}
|
||||
|
||||
public async toggleRain(): Promise<void> {
|
||||
this.updateWeatherProperty('rain')
|
||||
public randomWeatherValue(type: 'rain' | 'fog') {
|
||||
switch (type) {
|
||||
case 'rain':
|
||||
return this.getRandomNumber(WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.min, WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.max)
|
||||
case 'fog':
|
||||
return this.getRandomNumber(WeatherManager.CONFIG.FOG_DENSITY_RANGE.min, WeatherManager.CONFIG.FOG_DENSITY_RANGE.max)
|
||||
}
|
||||
}
|
||||
|
||||
public async setRainValue(value: number | null): Promise<void> {
|
||||
if (value === null) {
|
||||
value = this.randomWeatherValue('rain')
|
||||
}
|
||||
|
||||
this.updateWeatherProperty('rain', value)
|
||||
await this.saveAndEmitWeather()
|
||||
}
|
||||
|
||||
public async toggleFog(): Promise<void> {
|
||||
this.updateWeatherProperty('fog')
|
||||
await this.saveAndEmitWeather()
|
||||
public async setFogValue(value: number | null): Promise<void> {
|
||||
if (value === null) {
|
||||
value = this.randomWeatherValue('fog')
|
||||
}
|
||||
|
||||
public cleanup(): void {
|
||||
this.intervalId && clearInterval(this.intervalId)
|
||||
this.updateWeatherProperty('fog', value)
|
||||
await this.saveAndEmitWeather()
|
||||
}
|
||||
|
||||
private async loadWeather(): Promise<void> {
|
||||
@ -63,9 +72,7 @@ class WeatherManager {
|
||||
const world = await worldRepository.getFirst()
|
||||
if (world) {
|
||||
this.weatherState = {
|
||||
isRainEnabled: world.isRainEnabled,
|
||||
rainPercentage: world.rainPercentage,
|
||||
isFogEnabled: world.isFogEnabled,
|
||||
fogDensity: world.fogDensity
|
||||
}
|
||||
}
|
||||
@ -83,22 +90,20 @@ class WeatherManager {
|
||||
|
||||
private updateRandomWeather(): void {
|
||||
if (Math.random() < WeatherManager.CONFIG.RAIN_CHANCE) {
|
||||
this.updateWeatherProperty('rain')
|
||||
this.updateWeatherProperty('rain', this.randomWeatherValue('rain'))
|
||||
}
|
||||
if (Math.random() < WeatherManager.CONFIG.FOG_CHANCE) {
|
||||
this.updateWeatherProperty('fog')
|
||||
this.updateWeatherProperty('fog', this.randomWeatherValue('fog'))
|
||||
}
|
||||
}
|
||||
|
||||
private updateWeatherProperty(type: 'rain' | 'fog'): void {
|
||||
private updateWeatherProperty(type: 'rain' | 'fog', value: number): void {
|
||||
if (type === 'rain') {
|
||||
this.weatherState.isRainEnabled = !this.weatherState.isRainEnabled
|
||||
this.weatherState.rainPercentage = this.weatherState.isRainEnabled ? this.getRandomNumber(WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.min, WeatherManager.CONFIG.RAIN_PERCENTAGE_RANGE.max) : 0
|
||||
this.weatherState.rainPercentage = value
|
||||
}
|
||||
|
||||
if (type === 'fog') {
|
||||
this.weatherState.isFogEnabled = !this.weatherState.isFogEnabled
|
||||
this.weatherState.fogDensity = this.weatherState.isFogEnabled ? this.getRandomNumber(WeatherManager.CONFIG.FOG_DENSITY_RANGE.min, WeatherManager.CONFIG.FOG_DENSITY_RANGE.max) : 0
|
||||
this.weatherState.fogDensity = value
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,12 +123,8 @@ class WeatherManager {
|
||||
let world = await worldRepository.getFirst()
|
||||
if (!world) world = new World()
|
||||
|
||||
await world
|
||||
.setIsRainEnabled(this.weatherState.isRainEnabled)
|
||||
.setRainPercentage(this.weatherState.rainPercentage)
|
||||
.setIsFogEnabled(this.weatherState.isFogEnabled)
|
||||
.setFogDensity(this.weatherState.fogDensity)
|
||||
.save()
|
||||
//the data model still contains the booleans
|
||||
await world.setRainPercentage(this.weatherState.rainPercentage).setFogDensity(this.weatherState.fogDensity).save()
|
||||
} catch (error) {
|
||||
this.logError('save', error)
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ class LoadedMap {
|
||||
}
|
||||
|
||||
public getCharactersInMap(): MapCharacter[] {
|
||||
console.log(this.characters)
|
||||
return this.characters
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import TeleportService from '#services/teleportService'
|
||||
class MapCharacter {
|
||||
public readonly character: Character
|
||||
public isMoving: boolean = false
|
||||
public currentPath: Array<{ x: number; y: number }> | null = null
|
||||
public currentPath: Array<{ positionX: number; positionY: number }> | null = null
|
||||
|
||||
constructor(character: Character) {
|
||||
this.character = character
|
||||
|
@ -19,11 +19,7 @@ class MapEventTileRepository extends BaseRepository {
|
||||
async getEventTileByMapIdAndPosition(mapId: UUID, positionX: number, positionY: number) {
|
||||
try {
|
||||
const repository = this.getEntityManager().getRepository(MapEventTile)
|
||||
const result = await repository.findOne({
|
||||
map: mapId,
|
||||
positionX: positionX,
|
||||
positionY: positionY
|
||||
})
|
||||
const result = await repository.findOne({ map: mapId, positionX: positionX, positionY: positionY })
|
||||
if (result) result.setEntityManager(this.getEntityManager())
|
||||
|
||||
return result
|
||||
|
@ -7,7 +7,7 @@ import SocketManager from '#managers/socketManager'
|
||||
import CharacterRepository from '#repositories/characterRepository'
|
||||
import MapRepository from '#repositories/mapRepository'
|
||||
|
||||
type Position = { x: number; y: number }
|
||||
type Position = { positionX: number; positionY: number }
|
||||
export type Node = Position & { parent?: Node; g: number; h: number; f: number }
|
||||
|
||||
class CharacterService extends BaseService {
|
||||
@ -33,13 +33,13 @@ class CharacterService extends BaseService {
|
||||
}
|
||||
|
||||
const start: Position = {
|
||||
x: Math.floor(character.positionX),
|
||||
y: Math.floor(character.positionY)
|
||||
positionX: Math.floor(character.positionX),
|
||||
positionY: Math.floor(character.positionY)
|
||||
}
|
||||
|
||||
const end: Position = {
|
||||
x: Math.floor(targetX),
|
||||
y: Math.floor(targetY)
|
||||
positionX: Math.floor(targetX),
|
||||
positionY: Math.floor(targetY)
|
||||
}
|
||||
|
||||
return this.findPath(start, end, grid)
|
||||
@ -80,24 +80,24 @@ class CharacterService extends BaseService {
|
||||
private findPath(start: Position, end: Position, grid: number[][]): Node[] {
|
||||
const openList: Node[] = [{ ...start, g: 0, h: 0, f: 0 }]
|
||||
const closedSet = new Set<string>()
|
||||
const getKey = (p: Position) => `${p.x},${p.y}`
|
||||
const getKey = (p: Position) => `${p.positionX},${p.positionY}`
|
||||
|
||||
while (openList.length > 0) {
|
||||
const current = openList.reduce((min, node) => (node.f < min.f ? node : min))
|
||||
if (current.x === end.x && current.y === end.y) return this.reconstructPath(current)
|
||||
if (current.positionX === end.positionX && current.positionY === end.positionY) return this.reconstructPath(current)
|
||||
|
||||
openList.splice(openList.indexOf(current), 1)
|
||||
closedSet.add(getKey(current))
|
||||
|
||||
const neighbors = this.DIRECTIONS.slice(0, config.ALLOW_DIAGONAL_MOVEMENT ? 8 : 4)
|
||||
.map((dir) => ({ x: current.x + dir.x, y: current.y + dir.y }))
|
||||
.map((dir) => ({ positionX: current.positionX + dir.x, positionY: current.positionY + dir.y }))
|
||||
.filter((pos) => this.isValidPosition(pos, grid, end))
|
||||
|
||||
for (const neighbor of neighbors) {
|
||||
if (closedSet.has(getKey(neighbor))) continue
|
||||
|
||||
const g = current.g + this.getDistance(current, neighbor)
|
||||
const existing = openList.find((node) => node.x === neighbor.x && node.y === neighbor.y)
|
||||
const existing = openList.find((node) => node.positionX === neighbor.positionX && node.positionY === neighbor.positionY)
|
||||
|
||||
if (!existing || g < existing.g) {
|
||||
const h = this.getDistance(neighbor, end)
|
||||
@ -112,12 +112,18 @@ class CharacterService extends BaseService {
|
||||
}
|
||||
|
||||
private isValidPosition(pos: Position, grid: number[][], end: Position): boolean {
|
||||
return pos.x >= 0 && pos.y >= 0 && pos.x < grid[0].length && pos.y < grid.length && (grid[pos.y][pos.x] === 0 || (pos.x === end.x && pos.y === end.y))
|
||||
return (
|
||||
pos.positionX >= 0 &&
|
||||
pos.positionY >= 0 &&
|
||||
pos.positionX < grid[0].length &&
|
||||
pos.positionY < grid.length &&
|
||||
(grid[pos.positionY][pos.positionX] === 0 || (pos.positionX === end.positionX && pos.positionY === end.positionY))
|
||||
)
|
||||
}
|
||||
|
||||
private getDistance(a: Position, b: Position): number {
|
||||
const dx = Math.abs(a.x - b.x),
|
||||
dy = Math.abs(a.y - b.y)
|
||||
const dx = Math.abs(a.positionX - b.positionX),
|
||||
dy = Math.abs(a.positionY - b.positionY)
|
||||
// Manhattan distance for straight paths, then Euclidean for diagonals
|
||||
return dx + dy + (Math.sqrt(2) - 2) * Math.min(dx, dy)
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class ChatService extends BaseService {
|
||||
|
||||
public getArgs(command: string, message: string): string[] | undefined {
|
||||
if (!this.isCommand(message, command)) return
|
||||
return message.split(`/${command} `)[1].split(' ')
|
||||
return message.slice(`/${command} `.length).split(' ')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,13 +48,6 @@ class TeleportService {
|
||||
const currentMapId = mapCharacter.character.map?.id
|
||||
const io = SocketManager.getIO()
|
||||
|
||||
// Handle current map cleanup
|
||||
if (currentMapId) {
|
||||
socket.leave(currentMapId)
|
||||
MapManager.removeCharacter(characterId)
|
||||
io.in(currentMapId).emit('map:character:leave', characterId)
|
||||
}
|
||||
|
||||
// Update character position and map
|
||||
await mapCharacter
|
||||
.getCharacter()
|
||||
@ -64,6 +57,26 @@ class TeleportService {
|
||||
.setMap(targetMap.getMap())
|
||||
.save()
|
||||
|
||||
// If the current map is the target map and we are not joining, send move event
|
||||
if (currentMapId === options.targetMapId && !options.isInitialJoin) {
|
||||
// If the current map is the target map, send move event
|
||||
io.in(currentMapId).emit('map:character:move', {
|
||||
characterId: mapCharacter.character.id,
|
||||
positionX: options.targetX,
|
||||
positionY: options.targetY,
|
||||
rotation: options.rotation ?? 0,
|
||||
isMoving: false
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
// Handle current map cleanup
|
||||
if (currentMapId) {
|
||||
socket.leave(currentMapId)
|
||||
MapManager.removeCharacter(characterId)
|
||||
io.in(currentMapId).emit('map:character:leave', characterId)
|
||||
}
|
||||
|
||||
// Join new map
|
||||
socket.join(options.targetMapId)
|
||||
targetMap.addCharacter(mapCharacter.getCharacter())
|
||||
@ -74,7 +87,7 @@ class TeleportService {
|
||||
// Notify clients
|
||||
io.in(options.targetMapId).emit('map:character:join', mapCharacter)
|
||||
socket.emit('map:character:teleport', {
|
||||
map: map,
|
||||
mapId: options.targetMapId,
|
||||
characters: targetMap.getCharactersInMap()
|
||||
})
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
"#application/*": ["./src/application/*"],
|
||||
"#commands/*": ["./src/commands/*"],
|
||||
"#entities/*": ["./src/entities/*"],
|
||||
"#http/*": ["./src/http/*"],
|
||||
"#controllers/*": ["./src/controllers/*"],
|
||||
"#jobs/*": ["./src/jobs/*"],
|
||||
"#managers/*": ["./src/managers/*"],
|
||||
"#middleware/*": ["./src/middleware/*"],
|
||||
|
Reference in New Issue
Block a user