diff --git a/README.md b/README.md index 91e7121..31f21ab 100644 --- a/README.md +++ b/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 diff --git a/migrations/Migration20250106170204.ts b/migrations/Migration20250123193515.ts similarity index 96% rename from migrations/Migration20250106170204.ts rename to migrations/Migration20250123193515.ts index 1937fb2..a05f0d6 100644 --- a/migrations/Migration20250106170204.ts +++ b/migrations/Migration20250123193515.ts @@ -1,6 +1,6 @@ import { Migration } from '@mikro-orm/migrations'; -export class Migration20250106170204 extends Migration { +export class Migration20250123193515 extends Migration { override async up(): Promise { this.addSql(`create table \`map\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`width\` int not null default 10, \`height\` int not null default 10, \`tiles\` json null, \`pvp\` tinyint(1) not null default false, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`); @@ -17,7 +17,7 @@ export class Migration20250106170204 extends Migration { this.addSql(`create table \`map_object\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`tags\` json null, \`origin_x\` numeric(10,2) not null default 0, \`origin_y\` numeric(10,2) not null default 0, \`is_animated\` tinyint(1) not null default false, \`frame_rate\` int not null default 0, \`frame_width\` int not null default 0, \`frame_height\` int not null default 0, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`); - this.addSql(`create table \`placed_map_object\` (\`id\` varchar(255) not null, \`map_id\` varchar(255) not null, \`map_object_id\` varchar(255) not null, \`depth\` int not null default 0, \`is_rotated\` tinyint(1) not null default false, \`position_x\` int not null default 0, \`position_y\` int not null default 0, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`); + this.addSql(`create table \`placed_map_object\` (\`id\` varchar(255) not null, \`map_id\` varchar(255) not null, \`map_object_id\` varchar(255) not null, \`is_rotated\` tinyint(1) not null default false, \`position_x\` int not null default 0, \`position_y\` int not null default 0, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`); this.addSql(`alter table \`placed_map_object\` add index \`placed_map_object_map_id_index\`(\`map_id\`);`); this.addSql(`alter table \`placed_map_object\` add index \`placed_map_object_map_object_id_index\`(\`map_object_id\`);`); @@ -29,7 +29,7 @@ export class Migration20250106170204 extends Migration { this.addSql(`create table \`character_type\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`gender\` enum('MALE', 'FEMALE') not null, \`race\` enum('HUMAN', 'ELF', 'DWARF', 'ORC', 'GOBLIN') not null, \`is_selectable\` tinyint(1) not null default false, \`sprite_id\` varchar(255) null, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`); this.addSql(`alter table \`character_type\` add index \`character_type_sprite_id_index\`(\`sprite_id\`);`); - this.addSql(`create table \`character_hair\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`gender\` varchar(255) not null default 'MALE', \`is_selectable\` tinyint(1) not null default false, \`sprite_id\` varchar(255) null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`); + this.addSql(`create table \`character_hair\` (\`id\` varchar(255) not null, \`name\` varchar(255) not null, \`gender\` varchar(255) not null default 'MALE', \`is_selectable\` tinyint(1) not null default false, \`sprite_id\` varchar(255) null, \`created_at\` datetime not null, \`updated_at\` datetime not null, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`); this.addSql(`alter table \`character_hair\` add index \`character_hair_sprite_id_index\`(\`sprite_id\`);`); this.addSql(`create table \`sprite_action\` (\`id\` varchar(255) not null, \`sprite_id\` varchar(255) not null, \`action\` varchar(255) not null, \`sprites\` json null, \`origin_x\` int not null default 0, \`origin_y\` int not null default 0, \`is_animated\` tinyint(1) not null default false, \`is_looping\` tinyint(1) not null default false, \`frame_width\` int not null default 0, \`frame_height\` int not null default 0, \`frame_rate\` int not null default 0, primary key (\`id\`)) default character set utf8mb4 engine = InnoDB;`); diff --git a/package-lock.json b/package-lock.json index 4e7de10..861d836 100644 --- a/package-lock.json +++ b/package-lock.json @@ -605,9 +605,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", - "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", + "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": { @@ -1109,16 +1109,16 @@ } }, "node_modules/@mikro-orm/cli": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.3.tgz", - "integrity": "sha512-DWnYNxoyMgU6L90TGBlT0eziTu6yl15ArnnFoq0kyOjp8JEMRjin+8cizSrKyQ3QiQZ5iop5fB0i9Sp+Hbgd8Q==", + "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.3", - "@mikro-orm/knex": "6.4.3", - "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" }, @@ -1131,17 +1131,17 @@ } }, "node_modules/@mikro-orm/core": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.3.tgz", - "integrity": "sha512-UTaqKs1bomYtGmEEZ8sNBOmW2OqT5NcMh+pBV2iJ6WLM5MuiIEuNhDMuvvPE5gNEwUzc1HyRhUV87bRDhDIGRg==", + "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.3", + "mikro-orm": "6.4.4", "reflect-metadata": "0.2.2" }, "engines": { @@ -1152,12 +1152,12 @@ } }, "node_modules/@mikro-orm/knex": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.3.tgz", - "integrity": "sha512-gVkRD/cIn6qxk/P9nR+IufZxJwuCCdv0AtcGvShxXXvaoIrQPJYDV7HRxBOHCEyNygr6M3Fqpph1oPoT6aezTQ==", + "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" }, @@ -1183,12 +1183,12 @@ } }, "node_modules/@mikro-orm/mariadb": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/mariadb/-/mariadb-6.4.3.tgz", - "integrity": "sha512-TLLCp3vVjWyQVm/WRQZhvxqSc9V6JD5UbuoUAyNqh3rT0ud/3BxxOebUv6vqGwGLERdF3z2AwpvOdchAEIDqJg==", + "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.3", + "@mikro-orm/knex": "6.4.4", "mariadb": "3.4.0" }, "engines": { @@ -1199,13 +1199,13 @@ } }, "node_modules/@mikro-orm/migrations": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/migrations/-/migrations-6.4.3.tgz", - "integrity": "sha512-VrsKq95esUBEMhwp9vVX+YUj2+/cNwb8UZ63HfgaqPo+pYj8r1RBSTboFOE9V0Md0n3ol9b5xByfPPa3qHmL0g==", + "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.3", - "fs-extra": "11.2.0", + "@mikro-orm/knex": "6.4.4", + "fs-extra": "11.3.0", "umzug": "3.8.2" }, "engines": { @@ -1216,12 +1216,12 @@ } }, "node_modules/@mikro-orm/mysql": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/mysql/-/mysql-6.4.3.tgz", - "integrity": "sha512-ZkrrzOWE9ouifU331q70K9BfAOD9SFRiNLNnECnzVrvDPWnthMV0ahGium9HyHpG4nev0Ybg6vnvq9IQzW1brg==", + "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.3", + "@mikro-orm/knex": "6.4.4", "mysql2": "3.12.0" }, "engines": { @@ -1232,9 +1232,9 @@ } }, "node_modules/@mikro-orm/reflection": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.4.3.tgz", - "integrity": "sha512-oi9WMO3J7hA9vLZvDW57I3LRtMMZgRqZUgUXoPRuDZihZYQFR7/6SC3b8EKwKP2VLt5v/3/0y6TE4OYq3QeOkQ==", + "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", @@ -1683,12 +1683,6 @@ "@types/node": "*" } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "license": "MIT" - }, "node_modules/@types/cors": { "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", @@ -1732,9 +1726,9 @@ } }, "node_modules/@types/geojson": { - "version": "7946.0.15", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.15.tgz", - "integrity": "sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==", + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, "node_modules/@types/http-errors": { @@ -1768,12 +1762,13 @@ "license": "MIT" }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz", - "integrity": "sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==", + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.8.tgz", + "integrity": "sha512-7fx54m60nLFUVYlxAB1xpe9CBWX2vSrk50Y6ogRJ1v5xxtba7qXTg5BgYDN5dq+yuQQ9HaVlHJyAAt1/mxryFg==", "dev": true, "license": "MIT", "dependencies": { + "@types/ms": "*", "@types/node": "*" } }, @@ -1784,10 +1779,17 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { - "version": "20.17.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.14.tgz", - "integrity": "sha512-w6qdYetNL5KRBiSClK/KWai+2IMEJuAj+EujKCumalFOwXtvOXaEan9AuwcRID2IcOIAWSIfR495hBtgKlx2zg==", + "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" @@ -2323,6 +2325,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/atomic-sleep": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", @@ -2458,9 +2470,9 @@ "license": "BSD-3-Clause" }, "node_modules/bullmq": { - "version": "5.34.10", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.10.tgz", - "integrity": "sha512-ia6EzpQm1ZPq6GUBSLyfvzJrhdBTd1f3Gn2g9pFtLX4hBOob6QHmcmBzGgPlSCyr/i2Qfe4OdjS21bRd02srbw==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.37.0.tgz", + "integrity": "sha512-h/wf979+9uROyYpB8oTE44Py6JERCluCSd+ZFpCZlPsYh+wxAkqrfHsHHHKBgsNJp9odWLIY4SG+280EXzXiCQ==", "license": "MIT", "dependencies": { "cron-parser": "^4.9.0", @@ -3030,17 +3042,16 @@ } }, "node_modules/engine.io": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz", - "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==", + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.3.tgz", + "integrity": "sha512-2hkLItQMBkoYSagneiisupWGvsQlWXqzhSMvsjaM8GYbnfUsX7tzYQq9QARnate5LRedVTX+MbkSZAANAr3NtQ==", "license": "MIT", "dependencies": { - "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", - "cookie": "~0.7.2", + "cookie": "~1.0.2", "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", @@ -3060,12 +3071,12 @@ } }, "node_modules/engine.io/node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" } }, "node_modules/engine.io/node_modules/debug": { @@ -3294,9 +3305,9 @@ } }, "node_modules/eslint": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.18.0.tgz", - "integrity": "sha512-+waTfRWQlSbpt3KWE+CjrPPYnbq9kfZIYUqapc0uBXyjTp8aYXZDsUH16m39Ryq3NjAVP4tjuF7KaukeqoCoaA==", + "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": { @@ -3305,7 +3316,7 @@ "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.10.0", "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.18.0", + "@eslint/js": "9.19.0", "@eslint/plugin-kit": "^0.2.5", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -3948,13 +3959,19 @@ "license": "ISC" }, "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.4.tgz", + "integrity": "sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==", "dev": true, "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/forwarded": { @@ -3976,9 +3993,9 @@ } }, "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", @@ -4493,12 +4510,13 @@ "license": "MIT" }, "node_modules/is-async-function": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.0.tgz", - "integrity": "sha512-GExz9MtyhlZyXYLxzlJRj5WUCE661zhDa1Yna52CN57AJsymh+DvXXjyveSioqSRdxvUrdKdvqB1b5cVKsNpWQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, "license": "MIT", "dependencies": { + "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", @@ -5247,9 +5265,9 @@ } }, "node_modules/mariadb/node_modules/@types/node": { - "version": "22.10.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", - "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", + "version": "22.10.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.10.tgz", + "integrity": "sha512-X47y/mPNzxviAGY5TcYPtYL8JsY3kAq2n8fMmKoRCxq/c4v4pyGNCzM2R6+M5/umG4ZfHuT+sgqDYqWc9rJ6ww==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -5332,9 +5350,9 @@ } }, "node_modules/mikro-orm": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.3.tgz", - "integrity": "sha512-xDNzmLiL4EUTMOu9CbZ2d0sNIaUdH4RzDv4oqw27+u0/FPfvZTIagd+luxx1lWWqe/vg/iNtvqr5OcNQIYYrtQ==", + "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" @@ -5526,9 +5544,9 @@ } }, "node_modules/nodemailer": { - "version": "6.9.16", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz", - "integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.0.tgz", + "integrity": "sha512-SQ3wZCExjeSatLE/HBaXS5vqUOQk6GtBdIIKxiFdmm01mOQZX/POJkO3SUX1wDiYcwUOJwT23scFSC9fY2H8IA==", "license": "MIT-0", "engines": { "node": ">=6.0.0" diff --git a/src/entities/base/characterHair.ts b/src/entities/base/characterHair.ts index 8a924c2..149d2e1 100644 --- a/src/entities/base/characterHair.ts +++ b/src/entities/base/characterHair.ts @@ -24,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 @@ -68,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 + } } diff --git a/src/entities/base/placedMapObject.ts b/src/entities/base/placedMapObject.ts index 3d2e170..8162caa 100644 --- a/src/entities/base/placedMapObject.ts +++ b/src/entities/base/placedMapObject.ts @@ -19,9 +19,6 @@ export class BasePlacedMapObject extends BaseEntity { @ManyToOne({ deleteRule: 'cascade', eager: true }) mapObject!: MapObject - @Property() - depth = 0 - @Property() isRotated = false @@ -58,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 diff --git a/src/entities/map.ts b/src/entities/map.ts index a248485..76cf594 100644 --- a/src/entities/map.ts +++ b/src/entities/map.ts @@ -2,6 +2,8 @@ import { Entity } from '@mikro-orm/core' import { BaseMap } from '#entities/base/map' +export type MapCacheT = ReturnType | {} + @Entity() export class Map extends BaseMap { public async cache() { @@ -20,7 +22,6 @@ export class Map extends BaseMap { placedMapObjects: this.getPlacedMapObjects().map((placedMapObject) => ({ id: placedMapObject.getId(), mapObject: placedMapObject.getMapObject().getId(), - depth: placedMapObject.getDepth(), isRotated: placedMapObject.getIsRotated(), positionX: placedMapObject.getPositionX(), positionY: placedMapObject.getPositionY() diff --git a/src/events/gameMaster/assetManager/characterHair/update.ts b/src/events/gameMaster/assetManager/characterHair/update.ts index aebf6c5..27e1ab8 100644 --- a/src/events/gameMaster/assetManager/characterHair/update.ts +++ b/src/events/gameMaster/assetManager/characterHair/update.ts @@ -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)}`) diff --git a/src/events/gameMaster/mapEditor/create.ts b/src/events/gameMaster/mapEditor/create.ts index e542ebf..3adc851 100644 --- a/src/events/gameMaster/mapEditor/create.ts +++ b/src/events/gameMaster/mapEditor/create.ts @@ -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 { + private async handleEvent(data: Payload, callback: (response: MapCacheT | false) => void): Promise { 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) } } } diff --git a/src/events/gameMaster/mapEditor/list.ts b/src/events/gameMaster/mapEditor/list.ts deleted file mode 100644 index 2b2f672..0000000 --- a/src/events/gameMaster/mapEditor/list.ts +++ /dev/null @@ -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 { - 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([]) - } - } -} diff --git a/src/events/gameMaster/mapEditor/update.ts b/src/events/gameMaster/mapEditor/update.ts index af3fec4..c4adfc1 100644 --- a/src/events/gameMaster/mapEditor/update.ts +++ b/src/events/gameMaster/mapEditor/update.ts @@ -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()