Commit 6252b3fe authored by nanahira's avatar nanahira

rearrange modules

parent 3ae9ffa2
Pipeline #43330 passed with stages
in 3 minutes and 14 seconds
...@@ -44,3 +44,4 @@ Dockerfile ...@@ -44,3 +44,4 @@ Dockerfile
/ssl /ssl
/ygopro /ygopro
/windbot /windbot
/src/plugins
...@@ -40,3 +40,4 @@ lerna-debug.log* ...@@ -40,3 +40,4 @@ lerna-debug.log*
/ssl /ssl
/ygopro /ygopro
/windbot /windbot
/src/plugins
{
"python-envs.pythonProjects": []
}
...@@ -83,6 +83,7 @@ ...@@ -83,6 +83,7 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.29.0", "@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0", "@babel/generator": "^7.29.0",
...@@ -573,6 +574,7 @@ ...@@ -573,6 +574,7 @@
"resolved": "https://registry.npmjs.org/@cordisjs/core/-/core-3.18.1.tgz", "resolved": "https://registry.npmjs.org/@cordisjs/core/-/core-3.18.1.tgz",
"integrity": "sha512-yRuATOamFxeD1ztE2L3o1SaHuT2zw5DTXijQYxt9azVNeILbvtomfGG6sLZegrynJO9XZbNvXbOlQ7LBJDOlAg==", "integrity": "sha512-yRuATOamFxeD1ztE2L3o1SaHuT2zw5DTXijQYxt9azVNeILbvtomfGG6sLZegrynJO9XZbNvXbOlQ7LBJDOlAg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"cosmokit": "^1.6.2" "cosmokit": "^1.6.2"
} }
...@@ -609,6 +611,7 @@ ...@@ -609,6 +611,7 @@
"resolved": "https://registry.npmjs.org/@cordisjs/plugin-http/-/plugin-http-0.6.3.tgz", "resolved": "https://registry.npmjs.org/@cordisjs/plugin-http/-/plugin-http-0.6.3.tgz",
"integrity": "sha512-kmw4G1t39ZZzFGpBKUNuTv2aefEUtxa1e4qu4+bTrM5Z8uYHTRzPpyJfkj9zuZwopP/Vz271OUr2UfDN5lrJKQ==", "integrity": "sha512-kmw4G1t39ZZzFGpBKUNuTv2aefEUtxa1e4qu4+bTrM5Z8uYHTRzPpyJfkj9zuZwopP/Vz271OUr2UfDN5lrJKQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"cosmokit": "^1.6.3", "cosmokit": "^1.6.3",
"file-type": "^16.5.4", "file-type": "^16.5.4",
...@@ -1464,6 +1467,7 @@ ...@@ -1464,6 +1467,7 @@
"resolved": "https://registry.npmjs.org/@koishijs/core/-/core-4.18.10.tgz", "resolved": "https://registry.npmjs.org/@koishijs/core/-/core-4.18.10.tgz",
"integrity": "sha512-P2dc9EqoMasqqdUz3iKyGbcd0krAG7dMT7Ju6CqrzAobj0w7i548cCE89mD3qTzhvdTKzbf4UBYDRg21lXrb4A==", "integrity": "sha512-P2dc9EqoMasqqdUz3iKyGbcd0krAG7dMT7Ju6CqrzAobj0w7i548cCE89mD3qTzhvdTKzbf4UBYDRg21lXrb4A==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@koishijs/i18n-utils": "^1.0.1", "@koishijs/i18n-utils": "^1.0.1",
"@koishijs/utils": "^7.2.1", "@koishijs/utils": "^7.2.1",
...@@ -2117,6 +2121,7 @@ ...@@ -2117,6 +2121,7 @@
"integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==", "integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/scope-manager": "8.55.0",
"@typescript-eslint/types": "8.55.0", "@typescript-eslint/types": "8.55.0",
...@@ -2622,6 +2627,7 @@ ...@@ -2622,6 +2627,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
...@@ -3017,6 +3023,7 @@ ...@@ -3017,6 +3023,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.9.0", "baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759", "caniuse-lite": "^1.0.30001759",
...@@ -3471,6 +3478,7 @@ ...@@ -3471,6 +3478,7 @@
"resolved": "https://registry.npmjs.org/cordis/-/cordis-3.18.1.tgz", "resolved": "https://registry.npmjs.org/cordis/-/cordis-3.18.1.tgz",
"integrity": "sha512-9IbthFbFBVJ15WBDNPqHdl59TyEAMNWxF1Dxsdi14625ePQkMX35WvcqgGno0BcXlpXDbUaBZgQ+jfBYT+uuSQ==", "integrity": "sha512-9IbthFbFBVJ15WBDNPqHdl59TyEAMNWxF1Dxsdi14625ePQkMX35WvcqgGno0BcXlpXDbUaBZgQ+jfBYT+uuSQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@cordisjs/core": "3.18.1", "@cordisjs/core": "3.18.1",
"@cordisjs/loader": "^0.13.1", "@cordisjs/loader": "^0.13.1",
...@@ -3891,6 +3899,7 @@ ...@@ -3891,6 +3899,7 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
...@@ -3947,6 +3956,7 @@ ...@@ -3947,6 +3956,7 @@
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"eslint-config-prettier": "bin/cli.js" "eslint-config-prettier": "bin/cli.js"
}, },
...@@ -4940,6 +4950,7 @@ ...@@ -4940,6 +4950,7 @@
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.2.tgz", "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.2.tgz",
"integrity": "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==", "integrity": "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@ioredis/commands": "1.5.0", "@ioredis/commands": "1.5.0",
"cluster-key-slot": "^1.1.0", "cluster-key-slot": "^1.1.0",
...@@ -5227,6 +5238,7 @@ ...@@ -5227,6 +5238,7 @@
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@jest/core": "30.2.0", "@jest/core": "30.2.0",
"@jest/types": "30.2.0", "@jest/types": "30.2.0",
...@@ -6020,6 +6032,7 @@ ...@@ -6020,6 +6032,7 @@
"resolved": "https://registry.npmjs.org/koishi/-/koishi-4.18.10.tgz", "resolved": "https://registry.npmjs.org/koishi/-/koishi-4.18.10.tgz",
"integrity": "sha512-rEbF2NuHDAsBJ0+5B12RsRk7QWM/1sZvMnlaSj2TqUP+558Z1+lVZO9HhsyxrEp+r+bheRNfpJDN8aO369/myg==", "integrity": "sha512-rEbF2NuHDAsBJ0+5B12RsRk7QWM/1sZvMnlaSj2TqUP+558Z1+lVZO9HhsyxrEp+r+bheRNfpJDN8aO369/myg==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@koishijs/core": "4.18.10", "@koishijs/core": "4.18.10",
"@koishijs/loader": "4.6.10", "@koishijs/loader": "4.6.10",
...@@ -6689,6 +6702,7 @@ ...@@ -6689,6 +6702,7 @@
"resolved": "https://registry.npmjs.org/pg/-/pg-8.18.0.tgz", "resolved": "https://registry.npmjs.org/pg/-/pg-8.18.0.tgz",
"integrity": "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==", "integrity": "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"pg-connection-string": "^2.11.0", "pg-connection-string": "^2.11.0",
"pg-pool": "^3.11.0", "pg-pool": "^3.11.0",
...@@ -7009,6 +7023,7 @@ ...@@ -7009,6 +7023,7 @@
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"
}, },
...@@ -8252,6 +8267,7 @@ ...@@ -8252,6 +8267,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
...@@ -8516,6 +8532,7 @@ ...@@ -8516,6 +8532,7 @@
"resolved": "https://registry.npmjs.org/typed-struct/-/typed-struct-2.7.1.tgz", "resolved": "https://registry.npmjs.org/typed-struct/-/typed-struct-2.7.1.tgz",
"integrity": "sha512-GluzA9kYlHjATJmzBDA2X9G9237Md5zsJsc8uEkmpvUFeuUvt+e7Sq11/nQnVB2VZIfKNR1CrwTCgpJVz52pAA==", "integrity": "sha512-GluzA9kYlHjATJmzBDA2X9G9237Md5zsJsc8uEkmpvUFeuUvt+e7Sq11/nQnVB2VZIfKNR1CrwTCgpJVz52pAA==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
...@@ -8650,6 +8667,7 @@ ...@@ -8650,6 +8667,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
......
...@@ -16,6 +16,9 @@ import { KoaService } from './services/koa-service'; ...@@ -16,6 +16,9 @@ import { KoaService } from './services/koa-service';
import { FileResourceService } from './file-resource'; import { FileResourceService } from './file-resource';
import { LegacyApiAuthService } from './services/legacy-api-auth-service'; import { LegacyApiAuthService } from './services/legacy-api-auth-service';
import { LegacyApiModule } from './legacy-api/legacy-api-module'; import { LegacyApiModule } from './legacy-api/legacy-api-module';
import { TailModule } from './tail-module';
import { PreJoinModule } from './pre-join';
import { PluginLoader } from './plugin-loader';
const core = createAppContext() const core = createAppContext()
.provide(ConfigService, { .provide(ConfigService, {
...@@ -51,8 +54,11 @@ export type ContextState = AppContextState<Context>; ...@@ -51,8 +54,11 @@ export type ContextState = AppContextState<Context>;
export const app = core export const app = core
.use(TransportModule) .use(TransportModule)
.use(RoomModule)
.use(FeatsModule) .use(FeatsModule)
.use(LegacyApiModule) .use(LegacyApiModule)
.use(RoomModule) .use(PreJoinModule)
.use(PluginLoader())
.use(JoinHandlerModule) .use(JoinHandlerModule)
.use(TailModule)
.define(); .define();
...@@ -20,7 +20,9 @@ import { ...@@ -20,7 +20,9 @@ import {
import { YGOProCtosDisconnect } from '../utility/ygopro-ctos-disconnect'; import { YGOProCtosDisconnect } from '../utility/ygopro-ctos-disconnect';
export class ClientHandler { export class ClientHandler {
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx this.ctx
.middleware(YGOProCtosExternalAddress, async (msg, client, next) => { .middleware(YGOProCtosExternalAddress, async (msg, client, next) => {
if (client.ip) { if (client.ip) {
......
...@@ -8,6 +8,9 @@ export class I18nService extends I18n { ...@@ -8,6 +8,9 @@ export class I18nService extends I18n {
locales: Object.keys(TRANSLATIONS), locales: Object.keys(TRANSLATIONS),
defaultLocale: 'en-US', defaultLocale: 'en-US',
}); });
}
async init() {
this.middleware(I18nLookupMiddleware(TRANSLATIONS)); this.middleware(I18nLookupMiddleware(TRANSLATIONS));
} }
} }
...@@ -42,7 +42,9 @@ export class IpResolver { ...@@ -42,7 +42,9 @@ export class IpResolver {
{ count: this.trustedProxies.length }, { count: this.trustedProxies.length },
'Trusted proxies initialized', 'Trusted proxies initialized',
); );
}
async init() {
this.ctx.middleware(YGOProCtosDisconnect, async (_msg, client, next) => { this.ctx.middleware(YGOProCtosDisconnect, async (_msg, client, next) => {
await this.releaseClientIp(client); await this.releaseClientIp(client);
return next(); return next();
......
...@@ -4,7 +4,9 @@ import { Context } from '../app'; ...@@ -4,7 +4,9 @@ import { Context } from '../app';
export class BlockReplay { export class BlockReplay {
private enabled = this.ctx.config.getBoolean('BLOCK_REPLAY_TO_PLAYER'); private enabled = this.ctx.config.getBoolean('BLOCK_REPLAY_TO_PLAYER');
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
if (!this.enabled) { if (!this.enabled) {
return; return;
} }
......
...@@ -69,7 +69,9 @@ export class ChallongeService { ...@@ -69,7 +69,9 @@ export class ChallongeService {
private challongeApi?: Challonge; private challongeApi?: Challonge;
private challongeApiFingerprint = ''; private challongeApiFingerprint = '';
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.registerLockDeckCheck(); this.registerLockDeckCheck();
this.registerScoreHooks(); this.registerScoreHooks();
this.registerToObserverGuard(); this.registerToObserverGuard();
...@@ -463,10 +465,14 @@ export class ChallongeService { ...@@ -463,10 +465,14 @@ export class ChallongeService {
if (participant0Id == null && participant1Id != null) { if (participant0Id == null && participant1Id != null) {
participant0Id = participant0Id =
participant1Id === match.player1_id ? match.player2_id : match.player1_id; participant1Id === match.player1_id
? match.player2_id
: match.player1_id;
} else if (participant1Id == null && participant0Id != null) { } else if (participant1Id == null && participant0Id != null) {
participant1Id = participant1Id =
participant0Id === match.player1_id ? match.player2_id : match.player1_id; participant0Id === match.player1_id
? match.player2_id
: match.player1_id;
} }
return [participant0Id, participant1Id]; return [participant0Id, participant1Id];
......
...@@ -50,12 +50,13 @@ export class ChatgptService { ...@@ -50,12 +50,13 @@ export class ChatgptService {
private tiktokenUnavailableLogged = false; private tiktokenUnavailableLogged = false;
private tokenizerByModel = new Map<string, TiktokenEncoder>(); private tokenizerByModel = new Map<string, TiktokenEncoder>();
private tiktokenModulePromise?: Promise<any>; private tiktokenModulePromise?: Promise<any>;
private middlewareRegistered = false;
constructor(private ctx: Context) { constructor(private ctx: Context) {}
if (!this.enabled) {
return;
}
async init() {
if (!this.middlewareRegistered) {
if (this.enabled) {
this.ctx.middleware(YGOProCtosChat, async (msg, client, next) => { this.ctx.middleware(YGOProCtosChat, async (msg, client, next) => {
const room = this.resolveChatRoom(client); const room = this.resolveChatRoom(client);
if (!room) { if (!room) {
...@@ -90,8 +91,9 @@ export class ChatgptService { ...@@ -90,8 +91,9 @@ export class ChatgptService {
return next(); return next();
}); });
} }
this.middlewareRegistered = true;
}
async init() {
if ( if (
!this.enabled || !this.enabled ||
this.tiktokenUnavailable || this.tiktokenUnavailable ||
......
...@@ -69,7 +69,9 @@ export class CloudReplayService { ...@@ -69,7 +69,9 @@ export class CloudReplayService {
private clientKeyProvider = this.ctx.get(() => ClientKeyProvider); private clientKeyProvider = this.ctx.get(() => ClientKeyProvider);
private menuManager = this.ctx.get(() => MenuManager); private menuManager = this.ctx.get(() => MenuManager);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(OnRoomWin, async (event, _client, next) => { this.ctx.middleware(OnRoomWin, async (event, _client, next) => {
await this.saveDuelRecord(event); await this.saveDuelRecord(event);
return next(); return next();
......
import { createAppContext } from 'nfkit'; import { createAppContext } from 'nfkit';
import { ClientVersionCheck } from './client-version-check';
import { Welcome } from './welcome'; import { Welcome } from './welcome';
import { PlayerStatusNotify } from './player-status-notify'; import { PlayerStatusNotify } from './player-status-notify';
import { Reconnect, RefreshFieldService } from './reconnect'; import { Reconnect, RefreshFieldService } from './reconnect';
...@@ -20,6 +19,7 @@ import { BlockReplay } from './block-replay'; ...@@ -20,6 +19,7 @@ import { BlockReplay } from './block-replay';
import { RoomDeathService } from './room-death-service'; import { RoomDeathService } from './room-death-service';
import { RoomAutoDeathService } from './room-auto-death-service'; import { RoomAutoDeathService } from './room-auto-death-service';
import { ChallongeService } from './challonge-service'; import { ChallongeService } from './challonge-service';
import { TagSurrenderConfirmMiddleware } from './tag-surrender-confirm-middleware';
export const FeatsModule = createAppContext() export const FeatsModule = createAppContext()
.provide(ClientKeyProvider) .provide(ClientKeyProvider)
...@@ -28,8 +28,7 @@ export const FeatsModule = createAppContext() ...@@ -28,8 +28,7 @@ export const FeatsModule = createAppContext()
.provide(CommandsService) // some chat commands .provide(CommandsService) // some chat commands
.provide(Welcome) .provide(Welcome)
.provide(MenuManager) .provide(MenuManager)
.provide(ClientVersionCheck) .provide(PlayerStatusNotify) // hint meessages when player status changes
.provide(PlayerStatusNotify)
.provide(CloudReplayService) // persist duel records .provide(CloudReplayService) // persist duel records
.provide(BlockReplay) // block replay packets for in-room players .provide(BlockReplay) // block replay packets for in-room players
.provide(ChatgptService) // AI-room chat replies .provide(ChatgptService) // AI-room chat replies
...@@ -38,10 +37,11 @@ export const FeatsModule = createAppContext() ...@@ -38,10 +37,11 @@ export const FeatsModule = createAppContext()
.provide(RoomAutoDeathService) // auto trigger death mode after duel start .provide(RoomAutoDeathService) // auto trigger death mode after duel start
.provide(ChallongeService) // challonge deck lock + score sync .provide(ChallongeService) // challonge deck lock + score sync
.provide(LockDeckService) // srvpro-style tournament deck lock check .provide(LockDeckService) // srvpro-style tournament deck lock check
.provide(RefreshFieldService) .provide(RefreshFieldService) // utility for
.provide(Reconnect) .provide(Reconnect) // allow players to reconnect to ongoing duels without leaving the room
.provide(WaitForPlayerProvider) // chat refresh .provide(WaitForPlayerProvider) // chat refresh
.provide(SideTimeout) .provide(SideTimeout) // side timeout in duel
.provide(TagSurrenderConfirmMiddleware) // teammate-confirm surrender in tag duel
.use(ResourceModule) // chat bad words .use(ResourceModule) // chat bad words
.use(RandomDuelModule) // chat random duel block .use(RandomDuelModule) // chat random duel block
.use(WindbotModule) .use(WindbotModule)
......
...@@ -12,7 +12,9 @@ export class HidePlayerNameProvider { ...@@ -12,7 +12,9 @@ export class HidePlayerNameProvider {
private roomManager = this.ctx.get(() => RoomManager); private roomManager = this.ctx.get(() => RoomManager);
private hidePlayerNameMode = this.resolveMode(); private hidePlayerNameMode = this.resolveMode();
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
if (!this.enabled) { if (!this.enabled) {
return; return;
} }
......
export * from './client-version-check'; export * from '../pre-join/client-version-check';
export * from './client-key-provider'; export * from './client-key-provider';
export * from './chatgpt-service'; export * from './chatgpt-service';
export * from './block-replay'; export * from './block-replay';
......
...@@ -20,7 +20,9 @@ class SrvproDeckBadError extends YGOProLFListError { ...@@ -20,7 +20,9 @@ class SrvproDeckBadError extends YGOProLFListError {
} }
export class LockDeckService { export class LockDeckService {
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
if (!this.ctx.config.getBoolean('TOURNAMENT_MODE_CHECK_DECK')) { if (!this.ctx.config.getBoolean('TOURNAMENT_MODE_CHECK_DECK')) {
return; return;
} }
......
...@@ -10,7 +10,9 @@ import { RoomManager } from '../room'; ...@@ -10,7 +10,9 @@ import { RoomManager } from '../room';
export class LpLowHintService { export class LpLowHintService {
private roomManager = this.ctx.get(() => RoomManager); private roomManager = this.ctx.get(() => RoomManager);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProMsgDamage, async (msg, client, next) => { this.ctx.middleware(YGOProMsgDamage, async (msg, client, next) => {
await this.trySendLowLpHint(msg.player, client, '#{lp_low_opponent}'); await this.trySendLowLpHint(msg.player, client, '#{lp_low_opponent}');
return next(); return next();
......
...@@ -49,7 +49,9 @@ export class MenuManager { ...@@ -49,7 +49,9 @@ export class MenuManager {
private chnroute = this.ctx.get(() => Chnroute); private chnroute = this.ctx.get(() => Chnroute);
private welcome = this.ctx.get(() => Welcome); private welcome = this.ctx.get(() => Welcome);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware( this.ctx.middleware(
YGOProCtosBase, YGOProCtosBase,
async (msg, client, next) => { async (msg, client, next) => {
......
...@@ -4,7 +4,9 @@ import { OnRoomJoinObserver } from '../room/room-event/on-room-join-observer'; ...@@ -4,7 +4,9 @@ import { OnRoomJoinObserver } from '../room/room-event/on-room-join-observer';
import { OnRoomLeave } from '../room/room-event/on-room-leave'; import { OnRoomLeave } from '../room/room-event/on-room-leave';
export class PlayerStatusNotify { export class PlayerStatusNotify {
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
// 观战者加入 // 观战者加入
this.ctx.middleware(OnRoomJoinObserver, async (event, client, next) => { this.ctx.middleware(OnRoomJoinObserver, async (event, client, next) => {
const room = event.room; const room = event.room;
......
...@@ -22,7 +22,7 @@ import { fillRandomString } from '../../utility/fill-random-string'; ...@@ -22,7 +22,7 @@ import { fillRandomString } from '../../utility/fill-random-string';
import { import {
OnClientBadwordViolation, OnClientBadwordViolation,
OnClientWaitTimeout, OnClientWaitTimeout,
} from '../random-duel-events'; } from './random-duel-events';
import { CanReconnectCheck } from '../reconnect'; import { CanReconnectCheck } from '../reconnect';
import { WaitForPlayerProvider } from '../wait-for-player-provider'; import { WaitForPlayerProvider } from '../wait-for-player-provider';
import { ClientKeyProvider } from '../client-key-provider'; import { ClientKeyProvider } from '../client-key-provider';
...@@ -118,22 +118,12 @@ export class RandomDuelProvider { ...@@ -118,22 +118,12 @@ export class RandomDuelProvider {
private blankPassModes = this.resolveBlankPassModes(); private blankPassModes = this.resolveBlankPassModes();
private supportedTypes = this.resolveSupportedTypes(); private supportedTypes = this.resolveSupportedTypes();
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
if (!this.enabled) { if (!this.enabled) {
return; return;
} }
this.registerRandomRoomModes();
this.waitForPlayerProvider.registerTick({
roomFilter: (room) => !!room.randomType,
raadyTimeoutMs: this.waitForPlayerReadyTimeoutMs,
hangTimeoutMs: this.waitForPlayerHangTimeoutMs,
longAgoBackoffMs: this.waitForPlayerLongAgoBackoffMs,
});
if (this.recordMatchScoresConfigured && !this.ctx.database) {
this.logger.warn(
'RANDOM_DUEL_RECORD_MATCH_SCORES is enabled but database is unavailable',
);
}
this.ctx.middleware(CanReconnectCheck, async (msg, _client, next) => { this.ctx.middleware(CanReconnectCheck, async (msg, _client, next) => {
if (msg.room.randomType && this.getDisconnectedCount(msg.room) > 1) { if (msg.room.randomType && this.getDisconnectedCount(msg.room) > 1) {
...@@ -206,6 +196,19 @@ export class RandomDuelProvider { ...@@ -206,6 +196,19 @@ export class RandomDuelProvider {
return next(); return next();
}, },
); );
this.registerRandomRoomModes();
this.waitForPlayerProvider.registerTick({
roomFilter: (room) => !!room.randomType,
raadyTimeoutMs: this.waitForPlayerReadyTimeoutMs,
hangTimeoutMs: this.waitForPlayerHangTimeoutMs,
longAgoBackoffMs: this.waitForPlayerLongAgoBackoffMs,
});
if (this.recordMatchScoresConfigured && !this.ctx.database) {
this.logger.warn(
'RANDOM_DUEL_RECORD_MATCH_SCORES is enabled but database is unavailable',
);
}
} }
get defaultType() { get defaultType() {
......
import { Client } from '../client'; import { Client } from '../../client';
import { Room } from '../room'; import { Room } from '../../room';
export type RandomDuelWaitTimeoutType = 'ready' | 'hang'; export type RandomDuelWaitTimeoutType = 'ready' | 'hang';
......
...@@ -59,7 +59,9 @@ export class Reconnect { ...@@ -59,7 +59,9 @@ export class Reconnect {
private clientKeyProvider = this.ctx.get(() => ClientKeyProvider); private clientKeyProvider = this.ctx.get(() => ClientKeyProvider);
private refreshFieldService = this.ctx.get(() => RefreshFieldService); private refreshFieldService = this.ctx.get(() => RefreshFieldService);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
// 检查是否启用断线重连(默认启用) // 检查是否启用断线重连(默认启用)
if (!this.ctx.config.getBoolean('ENABLE_RECONNECT')) { if (!this.ctx.config.getBoolean('ENABLE_RECONNECT')) {
return; return;
......
...@@ -4,7 +4,7 @@ import { Client } from '../../client'; ...@@ -4,7 +4,7 @@ import { Client } from '../../client';
import { Room, RoomManager } from '../../room'; import { Room, RoomManager } from '../../room';
import { escapeRegExp } from '../../utility/escape-regexp'; import { escapeRegExp } from '../../utility/escape-regexp';
import { ValueContainer } from '../../utility/value-container'; import { ValueContainer } from '../../utility/value-container';
import { OnClientBadwordViolation } from '../random-duel-events'; import { OnClientBadwordViolation } from '../random-duel/random-duel-events';
import { BaseResourceProvider } from './base-resource-provider'; import { BaseResourceProvider } from './base-resource-provider';
import { isObjectRecord } from './resource-util'; import { isObjectRecord } from './resource-util';
import { BadwordsData, EMPTY_BADWORDS_DATA } from './types'; import { BadwordsData, EMPTY_BADWORDS_DATA } from './types';
...@@ -60,11 +60,10 @@ export class BadwordProvider extends BaseResourceProvider<BadwordsData> { ...@@ -60,11 +60,10 @@ export class BadwordProvider extends BaseResourceProvider<BadwordsData> {
resourceName: 'badwords', resourceName: 'badwords',
emptyData: EMPTY_BADWORDS_DATA, emptyData: EMPTY_BADWORDS_DATA,
}); });
if (!this.enabled) {
return;
} }
async init() {
if (this.enabled) {
this.ctx.middleware(YGOProCtosChat, async (msg, client, next) => { this.ctx.middleware(YGOProCtosChat, async (msg, client, next) => {
if (client.isInternal) { if (client.isInternal) {
return next(); return next();
...@@ -82,7 +81,9 @@ export class BadwordProvider extends BaseResourceProvider<BadwordsData> { ...@@ -82,7 +81,9 @@ export class BadwordProvider extends BaseResourceProvider<BadwordsData> {
room, room,
originalMessage, originalMessage,
filtered.level, filtered.level,
filtered.message !== originalMessage ? filtered.message : undefined, filtered.message !== originalMessage
? filtered.message
: undefined,
), ),
client as any, client as any,
); );
...@@ -101,6 +102,8 @@ export class BadwordProvider extends BaseResourceProvider<BadwordsData> { ...@@ -101,6 +102,8 @@ export class BadwordProvider extends BaseResourceProvider<BadwordsData> {
return next(); return next();
}); });
} }
await super.init();
}
async refreshResources() { async refreshResources() {
if (!this.enabled) { if (!this.enabled) {
......
...@@ -38,16 +38,17 @@ export class DialoguesProvider extends BaseResourceProvider<DialoguesData> { ...@@ -38,16 +38,17 @@ export class DialoguesProvider extends BaseResourceProvider<DialoguesData> {
resourceName: 'dialogues', resourceName: 'dialogues',
emptyData: EMPTY_DIALOGUES_DATA, emptyData: EMPTY_DIALOGUES_DATA,
}); });
if (!this.enabled) {
return;
} }
async init() {
if (this.enabled) {
this.ctx.middleware(YGOProMsgBase, async (msg, client, next) => { this.ctx.middleware(YGOProMsgBase, async (msg, client, next) => {
await this.handleDialogueMessage(msg, client); await this.handleDialogueMessage(msg, client);
return next(); return next();
}); });
} }
await super.init();
}
async refreshResources() { async refreshResources() {
if (!this.enabled) { if (!this.enabled) {
......
...@@ -58,14 +58,15 @@ export class TipsProvider extends BaseResourceProvider<TipsData> { ...@@ -58,14 +58,15 @@ export class TipsProvider extends BaseResourceProvider<TipsData> {
} }
await this.sendRandomTip(commandContext.client, commandContext.room); await this.sendRandomTip(commandContext.client, commandContext.room);
}); });
}
async init() {
if (this.enabled) {
this.ctx.middleware(OnRoomDuelStart, async (event, _client, next) => { this.ctx.middleware(OnRoomDuelStart, async (event, _client, next) => {
await this.sendRandomTipToRoom(event.room); await this.sendRandomTipToRoom(event.room);
return next(); return next();
}); });
} }
async init() {
await super.init(); await super.init();
this.registerAutoTipTimers(); this.registerAutoTipTimers();
} }
......
...@@ -24,11 +24,10 @@ export class WordsProvider extends BaseResourceProvider<WordsData> { ...@@ -24,11 +24,10 @@ export class WordsProvider extends BaseResourceProvider<WordsData> {
resourceName: 'words', resourceName: 'words',
emptyData: EMPTY_WORDS_DATA, emptyData: EMPTY_WORDS_DATA,
}); });
if (!this.enabled) {
return;
} }
async init() {
if (this.enabled) {
this.ctx.middleware(OnRoomJoin, async (event, client, next) => { this.ctx.middleware(OnRoomJoin, async (event, client, next) => {
const line = await this.getRandomWords(event.room, client); const line = await this.getRandomWords(event.room, client);
if (line) { if (line) {
...@@ -37,6 +36,8 @@ export class WordsProvider extends BaseResourceProvider<WordsData> { ...@@ -37,6 +36,8 @@ export class WordsProvider extends BaseResourceProvider<WordsData> {
return next(); return next();
}); });
} }
await super.init();
}
async refreshResources() { async refreshResources() {
if (!this.enabled) { if (!this.enabled) {
......
...@@ -32,7 +32,9 @@ export class RoomAutoDeathService { ...@@ -32,7 +32,9 @@ export class RoomAutoDeathService {
Number.isFinite(deathTime) && deathTime > 0 ? deathTime : 40, Number.isFinite(deathTime) && deathTime > 0 ? deathTime : 40,
}; };
}); });
}
async init() {
this.ctx.middleware(OnRoomGameStart, async (event, _client, next) => { this.ctx.middleware(OnRoomGameStart, async (event, _client, next) => {
const scheduled = this.tryScheduleAutoDeath( const scheduled = this.tryScheduleAutoDeath(
event.room.name, event.room.name,
......
...@@ -13,7 +13,9 @@ declare module '../room' { ...@@ -13,7 +13,9 @@ declare module '../room' {
export class RoomDeathService { export class RoomDeathService {
private roomManager = this.ctx.get(() => RoomManager); private roomManager = this.ctx.get(() => RoomManager);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(OnRoomDuelStart, async (event, _client, next) => { this.ctx.middleware(OnRoomDuelStart, async (event, _client, next) => {
const room = event.room; const room = event.room;
if (!room.death) { if (!room.death) {
......
...@@ -6,16 +6,16 @@ import { ...@@ -6,16 +6,16 @@ import {
} from 'ygopro-msg-encode'; } from 'ygopro-msg-encode';
import { Context } from '../app'; import { Context } from '../app';
import { Client } from '../client'; import { Client } from '../client';
import { DuelStage } from './duel-stage';
import { Room } from './room';
import { RoomManager } from './room-manager';
import { YGOProCtosDisconnect } from '../utility/ygopro-ctos-disconnect'; import { YGOProCtosDisconnect } from '../utility/ygopro-ctos-disconnect';
import { Room, DuelStage, RoomManager } from '../room';
export class TagSurrenderConfirmMiddleware { export class TagSurrenderConfirmMiddleware {
// Track per-room pending teammate-confirm surrender by player position. // Track per-room pending teammate-confirm surrender by player position.
private pendingByRoom = new WeakMap<Room, Set<number>>(); private pendingByRoom = new WeakMap<Room, Set<number>>();
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProMsgNewTurn, async (msg, client, next) => { this.ctx.middleware(YGOProMsgNewTurn, async (msg, client, next) => {
const room = this.getRoom(client); const room = this.getRoom(client);
if (room?.isTag && (msg.player & 0x2) === 0) { if (room?.isTag && (msg.player & 0x2) === 0) {
......
...@@ -20,7 +20,7 @@ import { ...@@ -20,7 +20,7 @@ import {
Room, Room,
RoomManager, RoomManager,
} from '../room'; } from '../room';
import { OnClientWaitTimeout } from './random-duel-events'; import { OnClientWaitTimeout } from './random-duel/random-duel-events';
export interface WaitForPlayerConfig { export interface WaitForPlayerConfig {
roomFilter: (room: Room) => boolean; roomFilter: (room: Room) => boolean;
...@@ -55,7 +55,9 @@ export class WaitForPlayerProvider { ...@@ -55,7 +55,9 @@ export class WaitForPlayerProvider {
private tickRuntimes = new Map<number, WaitForPlayerTickRuntime>(); private tickRuntimes = new Map<number, WaitForPlayerTickRuntime>();
private nextTickId = 1; private nextTickId = 1;
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware( this.ctx.middleware(
YGOProMsgResponseBase, YGOProMsgResponseBase,
async (msg, client, next) => { async (msg, client, next) => {
......
...@@ -18,7 +18,9 @@ declare module '../client' { ...@@ -18,7 +18,9 @@ declare module '../client' {
} }
export class Welcome { export class Welcome {
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(OnRoomJoin, async (event, client, next) => { this.ctx.middleware(OnRoomJoin, async (event, client, next) => {
const room = event.room; const room = event.room;
await this.sendConfigWelcome(client); await this.sendConfigWelcome(client);
......
...@@ -15,7 +15,9 @@ export class JoinWindbotAi { ...@@ -15,7 +15,9 @@ export class JoinWindbotAi {
private windbotProvider = this.ctx.get(() => WindBotProvider); private windbotProvider = this.ctx.get(() => WindBotProvider);
private roomManager = this.ctx.get(() => RoomManager); private roomManager = this.ctx.get(() => RoomManager);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
if (!this.windbotProvider.enabled) { if (!this.windbotProvider.enabled) {
return; return;
} }
......
...@@ -9,7 +9,9 @@ export class JoinWindbotToken { ...@@ -9,7 +9,9 @@ export class JoinWindbotToken {
private logger = this.ctx.createLogger(this.constructor.name); private logger = this.ctx.createLogger(this.constructor.name);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
if (!this.windbotProvider.enabled) { if (!this.windbotProvider.enabled) {
return; return;
} }
......
...@@ -94,7 +94,12 @@ export class WindBotProvider { ...@@ -94,7 +94,12 @@ export class WindBotProvider {
} }
await this.requestWindbotJoin(room, botName); await this.requestWindbotJoin(room, botName);
}); });
}
async init() {
if (!this.enabled) {
return;
}
this.ctx this.ctx
.middleware(OnRoomFinalize, async (event, _client, next) => { .middleware(OnRoomFinalize, async (event, _client, next) => {
this.deleteRoomToken(event.room.name); this.deleteRoomToken(event.room.name);
...@@ -110,12 +115,6 @@ export class WindBotProvider { ...@@ -110,12 +115,6 @@ export class WindBotProvider {
}, },
true, true,
); );
}
async init() {
if (!this.enabled) {
return;
}
await this.loadBotList(); await this.loadBotList();
} }
......
...@@ -8,7 +8,9 @@ export class ChallongeJoinHandler { ...@@ -8,7 +8,9 @@ export class ChallongeJoinHandler {
private challongeService = this.ctx.get(() => ChallongeService); private challongeService = this.ctx.get(() => ChallongeService);
private roomManager = this.ctx.get(() => RoomManager); private roomManager = this.ctx.get(() => RoomManager);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
if (!this.challongeService.enabled) { if (!this.challongeService.enabled) {
return next(); return next();
......
...@@ -7,7 +7,9 @@ export class CloudReplayJoinHandler { ...@@ -7,7 +7,9 @@ export class CloudReplayJoinHandler {
private enabled = private enabled =
this.ctx.config.getBoolean('ENABLE_CLOUD_REPLAY') && !!this.ctx.database; this.ctx.config.getBoolean('ENABLE_CLOUD_REPLAY') && !!this.ctx.database;
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
if (!this.enabled) { if (!this.enabled) {
return next(); return next();
......
...@@ -2,7 +2,9 @@ import { YGOProCtosJoinGame } from 'ygopro-msg-encode'; ...@@ -2,7 +2,9 @@ import { YGOProCtosJoinGame } from 'ygopro-msg-encode';
import { Context } from '../app'; import { Context } from '../app';
export class JoinFallback { export class JoinFallback {
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
return client.die('#{blank_room_name}'); return client.die('#{blank_room_name}');
}); });
......
...@@ -13,7 +13,9 @@ export class JoinBlankPassMenu { ...@@ -13,7 +13,9 @@ export class JoinBlankPassMenu {
private enabled = this.ctx.config.getBoolean('ENABLE_MENU'); private enabled = this.ctx.config.getBoolean('ENABLE_MENU');
private rootMenu = this.loadRootMenu(); private rootMenu = this.loadRootMenu();
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
if (!this.enabled) { if (!this.enabled) {
return; return;
} }
......
...@@ -5,7 +5,9 @@ import { RandomDuelProvider } from '../feats'; ...@@ -5,7 +5,9 @@ import { RandomDuelProvider } from '../feats';
export class JoinBlankPassRandomDuel { export class JoinBlankPassRandomDuel {
private randomDuelProvider = this.ctx.get(() => RandomDuelProvider); private randomDuelProvider = this.ctx.get(() => RandomDuelProvider);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
msg.pass = (msg.pass || '').trim(); msg.pass = (msg.pass || '').trim();
if (msg.pass || !this.randomDuelProvider.enabled) { if (msg.pass || !this.randomDuelProvider.enabled) {
......
...@@ -5,7 +5,9 @@ import { JoinWindbotAi } from '../feats/windbot'; ...@@ -5,7 +5,9 @@ import { JoinWindbotAi } from '../feats/windbot';
export class JoinBlankPassWindbotAi { export class JoinBlankPassWindbotAi {
private joinWindbotAi = this.ctx.get(() => JoinWindbotAi); private joinWindbotAi = this.ctx.get(() => JoinWindbotAi);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
msg.pass = (msg.pass || '').trim(); msg.pass = (msg.pass || '').trim();
if (msg.pass) { if (msg.pass) {
......
...@@ -9,7 +9,9 @@ export class JoinBotlist { ...@@ -9,7 +9,9 @@ export class JoinBotlist {
private joinWindbotAi = this.ctx.get(() => JoinWindbotAi); private joinWindbotAi = this.ctx.get(() => JoinWindbotAi);
private windbotProvider = this.ctx.get(() => WindBotProvider); private windbotProvider = this.ctx.get(() => WindBotProvider);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
if (!this.windbotProvider.enabled) { if (!this.windbotProvider.enabled) {
return; return;
} }
......
import { createAppContext } from 'nfkit'; import { createAppContext } from 'nfkit';
import { ContextState } from '../app'; import { ContextState } from '../app';
import { ClientVersionCheck } from '../feats'; import { JoinWindbotAi } from '../feats/windbot';
import { JoinWindbotAi, JoinWindbotToken } from '../feats/windbot';
import { JoinRoom } from './join-room'; import { JoinRoom } from './join-room';
import { JoinRoomIp } from './join-room-ip'; import { JoinRoomIp } from './join-room-ip';
import { CloudReplayJoinHandler } from './cloud-replay-join-handler'; import { CloudReplayJoinHandler } from './cloud-replay-join-handler';
import { JoinFallback } from './fallback';
import { JoinPrechecks } from './join-prechecks';
import { RandomDuelJoinHandler } from './random-duel-join-handler'; import { RandomDuelJoinHandler } from './random-duel-join-handler';
import { BadwordPlayerInfoChecker } from './badword-player-info-checker';
import { JoinBlankPassRandomDuel } from './join-blank-pass-random-duel'; import { JoinBlankPassRandomDuel } from './join-blank-pass-random-duel';
import { JoinBlankPassWindbotAi } from './join-blank-pass-windbot-ai'; import { JoinBlankPassWindbotAi } from './join-blank-pass-windbot-ai';
import { JoinBlankPassMenu } from './join-blank-pass-menu'; import { JoinBlankPassMenu } from './join-blank-pass-menu';
...@@ -17,10 +13,6 @@ import { JoinBotlist } from './join-botlist'; ...@@ -17,10 +13,6 @@ import { JoinBotlist } from './join-botlist';
import { ChallongeJoinHandler } from './challonge-join-handler'; import { ChallongeJoinHandler } from './challonge-join-handler';
export const JoinHandlerModule = createAppContext<ContextState>() export const JoinHandlerModule = createAppContext<ContextState>()
.provide(ClientVersionCheck)
.provide(JoinPrechecks)
.provide(JoinWindbotToken)
.provide(BadwordPlayerInfoChecker)
.provide(JoinRoomIp) // IP .provide(JoinRoomIp) // IP
.provide(CloudReplayJoinHandler) // R, R#, W, W#, YRP# .provide(CloudReplayJoinHandler) // R, R#, W, W#, YRP#
.provide(JoinRoomlist) // L .provide(JoinRoomlist) // L
...@@ -32,5 +24,4 @@ export const JoinHandlerModule = createAppContext<ContextState>() ...@@ -32,5 +24,4 @@ export const JoinHandlerModule = createAppContext<ContextState>()
.provide(JoinBlankPassMenu) // blank pass below .provide(JoinBlankPassMenu) // blank pass below
.provide(JoinBlankPassRandomDuel) .provide(JoinBlankPassRandomDuel)
.provide(JoinBlankPassWindbotAi) .provide(JoinBlankPassWindbotAi)
.provide(JoinFallback)
.define(); .define();
...@@ -2,7 +2,9 @@ import { ChatColor, YGOProCtosJoinGame } from 'ygopro-msg-encode'; ...@@ -2,7 +2,9 @@ import { ChatColor, YGOProCtosJoinGame } from 'ygopro-msg-encode';
import { Context } from '../app'; import { Context } from '../app';
export class JoinRoomIp { export class JoinRoomIp {
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
const pass = (msg.pass || '').trim(); const pass = (msg.pass || '').trim();
if (!pass) { if (!pass) {
......
...@@ -4,7 +4,10 @@ import { RoomManager } from '../room/room-manager'; ...@@ -4,7 +4,10 @@ import { RoomManager } from '../room/room-manager';
export class JoinRoom { export class JoinRoom {
private logger = this.ctx.createLogger(this.constructor.name); private logger = this.ctx.createLogger(this.constructor.name);
constructor(private ctx: Context) {
constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
if (!msg.pass) { if (!msg.pass) {
return next(); return next();
......
...@@ -10,7 +10,9 @@ export class JoinRoomlist { ...@@ -10,7 +10,9 @@ export class JoinRoomlist {
private roomManager = this.ctx.get(() => RoomManager); private roomManager = this.ctx.get(() => RoomManager);
private enabled = this.ctx.config.getBoolean('ENABLE_ROOMLIST'); private enabled = this.ctx.config.getBoolean('ENABLE_ROOMLIST');
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
if (!this.enabled) { if (!this.enabled) {
return next(); return next();
......
...@@ -5,7 +5,9 @@ import { RandomDuelProvider } from '../feats'; ...@@ -5,7 +5,9 @@ import { RandomDuelProvider } from '../feats';
export class RandomDuelJoinHandler { export class RandomDuelJoinHandler {
private randomDuelProvider = this.ctx.get(() => RandomDuelProvider); private randomDuelProvider = this.ctx.get(() => RandomDuelProvider);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
if (!this.randomDuelProvider.enabled) { if (!this.randomDuelProvider.enabled) {
return; return;
} }
......
...@@ -99,10 +99,10 @@ export class KoishiContextService { ...@@ -99,10 +99,10 @@ export class KoishiContextService {
private koishiStarted = false; private koishiStarted = false;
private koishiStartPromise?: Promise<void>; private koishiStartPromise?: Promise<void>;
private chatBridgeRegistered = false;
constructor(private ctx: Context) { constructor(private ctx: Context) {
this.koishi.plugin(koishiHelp); this.koishi.plugin(koishiHelp);
this.registerChatBridge();
} }
get instance() { get instance() {
...@@ -124,6 +124,10 @@ export class KoishiContextService { ...@@ -124,6 +124,10 @@ export class KoishiContextService {
} }
async init() { async init() {
if (!this.chatBridgeRegistered) {
this.registerChatBridge();
this.chatBridgeRegistered = true;
}
if (this.attachI18nTasks.length) { if (this.attachI18nTasks.length) {
await Promise.all(this.attachI18nTasks); await Promise.all(this.attachI18nTasks);
this.attachI18nTasks = []; this.attachI18nTasks = [];
......
...@@ -41,10 +41,13 @@ export class LegacyApiDeckService { ...@@ -41,10 +41,13 @@ export class LegacyApiDeckService {
constructor(private ctx: Context) { constructor(private ctx: Context) {
this.registerRoutes(); this.registerRoutes();
this.registerLockDeckCheck();
void this.ensureBackgroundsFresh(); void this.ensureBackgroundsFresh();
} }
async init() {
this.registerLockDeckCheck();
}
private registerRoutes() { private registerRoutes() {
const router = this.ctx.router; const router = this.ctx.router;
......
...@@ -8,6 +8,15 @@ export class LegacyBanService { ...@@ -8,6 +8,15 @@ export class LegacyBanService {
private logger = this.ctx.createLogger('LegacyBanService'); private logger = this.ctx.createLogger('LegacyBanService');
constructor(private ctx: Context) { constructor(private ctx: Context) {
this.ctx
.get(() => LegacyApiService)
.addApiMessageHandler('ban', 'ban_user', async (value) => {
const result = await this.banUser(value);
return [result ? 'ban ok' : 'ban fail', value];
});
}
async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
if (client.isLocal || client.isInternal) { if (client.isLocal || client.isInternal) {
return next(); return next();
...@@ -36,13 +45,6 @@ export class LegacyBanService { ...@@ -36,13 +45,6 @@ export class LegacyBanService {
} }
return next(); return next();
}); });
this.ctx
.get(() => LegacyApiService)
.addApiMessageHandler('ban', 'ban_user', async (value) => {
const result = await this.banUser(value);
return [result ? 'ban ok' : 'ban fail', value];
});
} }
async banUser(name: string) { async banUser(name: string) {
......
...@@ -10,7 +10,9 @@ export class LegacyRoomIdService { ...@@ -10,7 +10,9 @@ export class LegacyRoomIdService {
private roomNameToRoomId = new Map<string, string>(); private roomNameToRoomId = new Map<string, string>();
private roomIdToRoomName = new Map<string, string>(); private roomIdToRoomName = new Map<string, string>();
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(OnRoomCreate, async (event, client, next) => { this.ctx.middleware(OnRoomCreate, async (event, client, next) => {
this.bindRoom(event.room.name, event.room.identifier); this.bindRoom(event.room.name, event.room.identifier);
return next(); return next();
......
...@@ -10,13 +10,6 @@ export class LegacyStopService { ...@@ -10,13 +10,6 @@ export class LegacyStopService {
private stopText?: string; private stopText?: string;
constructor(private ctx: Context) { constructor(private ctx: Context) {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
if (!this.stopText) {
return next();
}
return client.die(this.stopText, ChatColor.RED);
});
this.ctx this.ctx
.get(() => LegacyApiService) .get(() => LegacyApiService)
.addApiMessageHandler('stop', 'stop', async (value) => { .addApiMessageHandler('stop', 'stop', async (value) => {
...@@ -26,6 +19,13 @@ export class LegacyStopService { ...@@ -26,6 +19,13 @@ export class LegacyStopService {
} }
async init() { async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
if (!this.stopText) {
return next();
}
return client.die(this.stopText, ChatColor.RED);
});
const text = await this.loadStopTextFromDatabase(); const text = await this.loadStopTextFromDatabase();
this.stopText = text; this.stopText = text;
if (text) { if (text) {
......
...@@ -9,14 +9,6 @@ export class LegacyWelcomeService { ...@@ -9,14 +9,6 @@ export class LegacyWelcomeService {
private logger = this.ctx.createLogger('LegacyWelcomeService'); private logger = this.ctx.createLogger('LegacyWelcomeService');
constructor(private ctx: Context) { constructor(private ctx: Context) {
this.ctx.middleware(WelcomeConfigCheck, async (event, client, next) => {
const dbWelcome = await this.getWelcomeFromDatabase();
if (dbWelcome) {
event.use(dbWelcome);
}
return next();
});
this.ctx this.ctx
.get(() => LegacyApiService) .get(() => LegacyApiService)
.addApiMessageHandler('getwelcome', 'change_settings', async () => { .addApiMessageHandler('getwelcome', 'change_settings', async () => {
...@@ -29,6 +21,16 @@ export class LegacyWelcomeService { ...@@ -29,6 +21,16 @@ export class LegacyWelcomeService {
}); });
} }
async init() {
this.ctx.middleware(WelcomeConfigCheck, async (event, client, next) => {
const dbWelcome = await this.getWelcomeFromDatabase();
if (dbWelcome) {
event.use(dbWelcome);
}
return next();
});
}
async getWelcomeText() { async getWelcomeText() {
const dbWelcome = await this.getWelcomeFromDatabase(); const dbWelcome = await this.getWelcomeFromDatabase();
if (dbWelcome) { if (dbWelcome) {
......
import { createAppContext } from 'nfkit';
import { ContextState } from './app';
export const PluginLoader = () => {
const ctx = createAppContext<ContextState>();
return ctx;
};
...@@ -6,7 +6,9 @@ export class BadwordPlayerInfoChecker { ...@@ -6,7 +6,9 @@ export class BadwordPlayerInfoChecker {
private logger = this.ctx.createLogger(this.constructor.name); private logger = this.ctx.createLogger(this.constructor.name);
private badwordProvider = this.ctx.get(() => BadwordProvider); private badwordProvider = this.ctx.get(() => BadwordProvider);
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
if (this.ctx.config.getBoolean('TOURNAMENT_MODE')) { if (this.ctx.config.getBoolean('TOURNAMENT_MODE')) {
return; return;
} }
......
...@@ -10,7 +10,9 @@ export class ClientVersionCheck { ...@@ -10,7 +10,9 @@ export class ClientVersionCheck {
version = this.ctx.config.getInt('YGOPRO_VERSION'); version = this.ctx.config.getInt('YGOPRO_VERSION');
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware( this.ctx.middleware(
YGOProCtosJoinGame, YGOProCtosJoinGame,
async (msg, client, next) => { async (msg, client, next) => {
......
export * from './badword-player-info-checker';
export * from './join-prechecks';
export * from './client-version-check';
export * from './pre-join-module';
...@@ -2,7 +2,9 @@ import { ChatColor, YGOProCtosJoinGame } from 'ygopro-msg-encode'; ...@@ -2,7 +2,9 @@ import { ChatColor, YGOProCtosJoinGame } from 'ygopro-msg-encode';
import { Context } from '../app'; import { Context } from '../app';
export class JoinPrechecks { export class JoinPrechecks {
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => { this.ctx.middleware(YGOProCtosJoinGame, async (msg, client, next) => {
if (!client.name || !client.name.length) { if (!client.name || !client.name.length) {
return client.die('#{bad_user_name}', ChatColor.RED); return client.die('#{bad_user_name}', ChatColor.RED);
......
import { createAppContext } from 'nfkit';
import { ContextState } from '../app';
import { ClientVersionCheck } from './client-version-check';
import { JoinPrechecks } from './join-prechecks';
import { JoinWindbotToken } from '../feats/windbot';
import { BadwordPlayerInfoChecker } from './badword-player-info-checker';
export const PreJoinModule = createAppContext<ContextState>()
.provide(ClientVersionCheck)
.provide(JoinPrechecks)
.provide(JoinWindbotToken) // AIJOIN#
.provide(BadwordPlayerInfoChecker)
.define();
...@@ -3,8 +3,10 @@ import { checkDeck } from '../utility/check-deck'; ...@@ -3,8 +3,10 @@ import { checkDeck } from '../utility/check-deck';
import { RoomCheckDeck } from './room-event/room-check-deck'; import { RoomCheckDeck } from './room-event/room-check-deck';
export class DefaultDeckChecker { export class DefaultDeckChecker {
constructor(private ctx: Context) { constructor(private ctx: Context) {}
ctx.middleware(RoomCheckDeck, (msg, client, next) => {
async init() {
this.ctx.middleware(RoomCheckDeck, (msg, client, next) => {
const { room, deck, cardReader } = msg; const { room, deck, cardReader } = msg;
if (room.hostinfo.no_check_deck) { if (room.hostinfo.no_check_deck) {
return next(); return next();
......
...@@ -11,7 +11,9 @@ import { makeArray } from 'nfkit'; ...@@ -11,7 +11,9 @@ import { makeArray } from 'nfkit';
export class RoomEventRegister { export class RoomEventRegister {
private logger = this.ctx.createLogger('RoomEventRegister'); private logger = this.ctx.createLogger('RoomEventRegister');
constructor(private ctx: Context) { constructor(private ctx: Context) {}
async init() {
this.registerRoomEvents(); this.registerRoomEvents();
} }
......
...@@ -2,15 +2,12 @@ import { createAppContext } from 'nfkit'; ...@@ -2,15 +2,12 @@ import { createAppContext } from 'nfkit';
import { ContextState } from '../app'; import { ContextState } from '../app';
import { YGOProResourceLoader } from './ygopro-resource-loader'; import { YGOProResourceLoader } from './ygopro-resource-loader';
import { DefaultHostInfoProvider } from './default-hostinfo-provder'; import { DefaultHostInfoProvider } from './default-hostinfo-provder';
import { RoomEventRegister } from './room-event-register';
import { RoomManager } from './room-manager'; import { RoomManager } from './room-manager';
import { TagSurrenderConfirmMiddleware } from './tag-surrender-confirm-middleware';
import { DefaultDeckChecker } from './default-deck-checker'; import { DefaultDeckChecker } from './default-deck-checker';
export const RoomModule = createAppContext<ContextState>() export const RoomModule = createAppContext<ContextState>()
.provide(DefaultHostInfoProvider) .provide(DefaultHostInfoProvider)
.provide(YGOProResourceLoader) .provide(YGOProResourceLoader)
.provide(RoomManager) .provide(RoomManager)
.provide(TagSurrenderConfirmMiddleware)
.provide(DefaultDeckChecker) .provide(DefaultDeckChecker)
.provide(RoomEventRegister); .define();
import { createAppContext } from 'nfkit';
import { ContextState } from './app';
import { JoinFallback } from './join-handlers/fallback';
import { RoomEventRegister } from './room/room-event-register';
export const TailModule = createAppContext<ContextState>()
.provide(RoomEventRegister)
.provide(JoinFallback)
.define();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment