Skip to content

Commit d5aedc7

Browse files
committed
Merge remote-tracking branch 'misskey-dev/develop' into merge-upstream
2 parents 3efbd3d + 60156a4 commit d5aedc7

File tree

21 files changed

+531
-433
lines changed

21 files changed

+531
-433
lines changed

locales/index.d.ts

+8
Original file line numberDiff line numberDiff line change
@@ -9807,6 +9807,14 @@ export interface Locale extends ILocale {
98079807
* 相手が設定を変更しました
98089808
*/
98099809
"opponentHasSettingsChanged": string;
9810+
/**
9811+
* 変則許可 (完全フリー)
9812+
*/
9813+
"allowIrregularRules": string;
9814+
/**
9815+
* 変則なし
9816+
*/
9817+
"disallowIrregularRules": string;
98109818
};
98119819
"_offlineScreen": {
98129820
/**

locales/ja-JP.yml

+2
Original file line numberDiff line numberDiff line change
@@ -2614,6 +2614,8 @@ _reversi:
26142614
shareToTlTheGameWhenStart: "開始時に対局をタイムラインに投稿"
26152615
iStartedAGame: "対局を開始しました! #MisskeyReversi"
26162616
opponentHasSettingsChanged: "相手が設定を変更しました"
2617+
allowIrregularRules: "変則許可 (完全フリー)"
2618+
disallowIrregularRules: "変則なし"
26172619

26182620
_offlineScreen:
26192621
title: "オフライン - サーバーに接続できません"

locales/ja-KS.yml

+3
Original file line numberDiff line numberDiff line change
@@ -2482,6 +2482,9 @@ _reversi:
24822482
freeMatch: "フリーマッチ"
24832483
lookingForPlayer: "対戦相手を探してるで"
24842484
gameCanceled: "対局がキャンセルされたわ"
2485+
shareToTlTheGameWhenStart: "初めの時に対局をタイムラインに投稿するで"
2486+
iStartedAGame: "対局し始めたで! #MisskeyReversi"
2487+
opponentHasSettingsChanged: "相手が設定変えたで"
24852488
_offlineScreen:
24862489
title: "オフライン - サーバーに接続できひんで"
24872490
header: "サーバーに接続できへんわ"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* SPDX-FileCopyrightText: syuilo and other misskey contributors
3+
* SPDX-License-Identifier: AGPL-3.0-only
4+
*/
5+
6+
export class Reversi61706081514499 {
7+
name = 'Reversi61706081514499'
8+
9+
async up(queryRunner) {
10+
await queryRunner.query(`ALTER TABLE "reversi_game" ADD "noIrregularRules" boolean NOT NULL DEFAULT false`);
11+
}
12+
13+
async down(queryRunner) {
14+
await queryRunner.query(`ALTER TABLE "reversi_game" DROP COLUMN "noIrregularRules"`);
15+
}
16+
}

packages/backend/package.json

+9-9
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@
8181
"@fastify/view": "8.2.0",
8282
"@misskey-dev/sharp-read-bmp": "^1.1.1",
8383
"@misskey-dev/summaly": "^5.0.3",
84-
"@nestjs/common": "10.2.10",
85-
"@nestjs/core": "10.2.10",
86-
"@nestjs/testing": "10.2.10",
84+
"@nestjs/common": "10.3.1",
85+
"@nestjs/core": "10.3.1",
86+
"@nestjs/testing": "10.3.1",
8787
"@peertube/http-signature": "1.7.0",
8888
"@simplewebauthn/server": "9.0.0",
8989
"@sinonjs/fake-timers": "11.2.2",
90-
"@smithy/node-http-handler": "2.1.10",
91-
"@swc/cli": "0.1.65",
90+
"@smithy/node-http-handler": "2.3.1",
91+
"@swc/cli": "0.2.2",
9292
"@swc/core": "1.3.105",
9393
"@twemoji/parser": "15.0.0",
9494
"accepts": "1.3.8",
@@ -98,7 +98,7 @@
9898
"bcryptjs": "2.4.3",
9999
"blurhash": "2.0.5",
100100
"body-parser": "1.20.2",
101-
"bullmq": "5.1.4",
101+
"bullmq": "5.1.5",
102102
"cacheable-lookup": "7.0.0",
103103
"cbor": "9.0.1",
104104
"chalk": "5.3.0",
@@ -154,7 +154,7 @@
154154
"promise-limit": "2.7.0",
155155
"pug": "3.0.2",
156156
"punycode": "2.3.1",
157-
"pureimage": "0.3.17",
157+
"pureimage": "0.4.13",
158158
"qrcode": "1.5.3",
159159
"random-seed": "0.3.0",
160160
"ratelimiter": "3.4.1",
@@ -186,7 +186,7 @@
186186
"devDependencies": {
187187
"@jest/globals": "29.7.0",
188188
"@misskey-dev/eslint-plugin": "1.0.0",
189-
"@nestjs/platform-express": "10.3.0",
189+
"@nestjs/platform-express": "10.3.1",
190190
"@simplewebauthn/types": "9.0.0",
191191
"@swc/jest": "0.2.31",
192192
"@types/accepts": "1.3.7",
@@ -204,7 +204,7 @@
204204
"@types/jsrsasign": "10.5.12",
205205
"@types/mime-types": "2.1.4",
206206
"@types/ms": "0.7.34",
207-
"@types/node": "20.11.5",
207+
"@types/node": "20.11.6",
208208
"@types/nodemailer": "6.4.14",
209209
"@types/oauth": "0.9.4",
210210
"@types/oauth2orize": "1.11.3",

packages/backend/src/core/ReversiService.ts

+35-20
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { Serialized } from '@/types.js';
2424
import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js';
2525
import type { OnModuleInit } from '@nestjs/common';
2626

27-
const MATCHING_TIMEOUT_MS = 1000 * 20; // 20sec
27+
const INVITATION_TIMEOUT_MS = 1000 * 20; // 20sec
2828

2929
@Injectable()
3030
export class ReversiService implements OnModuleInit {
@@ -85,6 +85,7 @@ export class ReversiService implements OnModuleInit {
8585
map: game.map,
8686
bw: game.bw,
8787
crc32: game.crc32,
88+
noIrregularRules: game.noIrregularRules,
8889
} satisfies Partial<MiReversiGame>;
8990
}
9091

@@ -112,14 +113,16 @@ export class ReversiService implements OnModuleInit {
112113
//#region 相手から既に招待されてないか確認
113114
const invitations = await this.redisClient.zrange(
114115
`reversi:matchSpecific:${me.id}`,
115-
Date.now() - MATCHING_TIMEOUT_MS,
116+
Date.now() - INVITATION_TIMEOUT_MS,
116117
'+inf',
117118
'BYSCORE');
118119

119120
if (invitations.includes(targetUser.id)) {
120121
await this.redisClient.zrem(`reversi:matchSpecific:${me.id}`, targetUser.id);
121122

122-
const game = await this.matched(targetUser.id, me.id);
123+
const game = await this.matched(targetUser.id, me.id, {
124+
noIrregularRules: false,
125+
});
123126

124127
return game;
125128
}
@@ -138,7 +141,7 @@ export class ReversiService implements OnModuleInit {
138141
}
139142

140143
@bindThis
141-
public async matchAnyUser(me: MiUser, multiple = false): Promise<MiReversiGame | null> {
144+
public async matchAnyUser(me: MiUser, options: { noIrregularRules: boolean }, multiple = false): Promise<MiReversiGame | null> {
142145
if (!multiple) {
143146
// 既にマッチしている対局が無いか探す(3分以内)
144147
const games = await this.reversiGamesRepository.find({
@@ -157,41 +160,52 @@ export class ReversiService implements OnModuleInit {
157160
//#region まず自分宛ての招待を探す
158161
const invitations = await this.redisClient.zrange(
159162
`reversi:matchSpecific:${me.id}`,
160-
Date.now() - MATCHING_TIMEOUT_MS,
163+
Date.now() - INVITATION_TIMEOUT_MS,
161164
'+inf',
162165
'BYSCORE');
163166

164167
if (invitations.length > 0) {
165168
const invitorId = invitations[Math.floor(Math.random() * invitations.length)];
166169
await this.redisClient.zrem(`reversi:matchSpecific:${me.id}`, invitorId);
167170

168-
const game = await this.matched(invitorId, me.id);
171+
const game = await this.matched(invitorId, me.id, {
172+
noIrregularRules: false,
173+
});
169174

170175
return game;
171176
}
172177
//#endregion
173178

174179
const matchings = await this.redisClient.zrange(
175180
'reversi:matchAny',
176-
Date.now() - MATCHING_TIMEOUT_MS,
177-
'+inf',
178-
'BYSCORE');
181+
0,
182+
2, // 自分自身のIDが入っている場合もあるので2つ取得
183+
'REV');
179184

180-
const userIds = matchings.filter(id => id !== me.id);
185+
const items = matchings.filter(id => !id.startsWith(me.id));
181186

182-
if (userIds.length > 0) {
183-
// pick random
184-
const matchedUserId = userIds[Math.floor(Math.random() * userIds.length)];
187+
if (items.length > 0) {
188+
const [matchedUserId, option] = items[0].split(':');
185189

186-
await this.redisClient.zrem('reversi:matchAny', me.id, matchedUserId);
190+
await this.redisClient.zrem('reversi:matchAny',
191+
me.id,
192+
matchedUserId,
193+
me.id + ':noIrregularRules',
194+
matchedUserId + ':noIrregularRules');
187195

188-
const game = await this.matched(matchedUserId, me.id);
196+
const game = await this.matched(matchedUserId, me.id, {
197+
noIrregularRules: options.noIrregularRules || option === 'noIrregularRules',
198+
});
189199

190200
return game;
191201
} else {
192202
const redisPipeline = this.redisClient.pipeline();
193-
redisPipeline.zadd('reversi:matchAny', Date.now(), me.id);
194-
redisPipeline.expire('reversi:matchAny', 120, 'NX');
203+
if (options.noIrregularRules) {
204+
redisPipeline.zadd('reversi:matchAny', Date.now(), me.id + ':noIrregularRules');
205+
} else {
206+
redisPipeline.zadd('reversi:matchAny', Date.now(), me.id);
207+
}
208+
redisPipeline.expire('reversi:matchAny', 15, 'NX');
195209
await redisPipeline.exec();
196210
return null;
197211
}
@@ -204,7 +218,7 @@ export class ReversiService implements OnModuleInit {
204218

205219
@bindThis
206220
public async matchAnyUserCancel(user: MiUser) {
207-
await this.redisClient.zrem('reversi:matchAny', user.id);
221+
await this.redisClient.zrem('reversi:matchAny', user.id, user.id + ':noIrregularRules');
208222
}
209223

210224
@bindThis
@@ -266,7 +280,7 @@ export class ReversiService implements OnModuleInit {
266280
}
267281

268282
@bindThis
269-
private async matched(parentId: MiUser['id'], childId: MiUser['id']): Promise<MiReversiGame> {
283+
private async matched(parentId: MiUser['id'], childId: MiUser['id'], options: { noIrregularRules: boolean; }): Promise<MiReversiGame> {
270284
const game = await this.reversiGamesRepository.insert({
271285
id: this.idService.gen(),
272286
user1Id: parentId,
@@ -279,6 +293,7 @@ export class ReversiService implements OnModuleInit {
279293
map: Reversi.maps.eighteight.data,
280294
bw: 'random',
281295
isLlotheo: false,
296+
noIrregularRules: options.noIrregularRules,
282297
}).then(x => this.reversiGamesRepository.findOneOrFail({
283298
where: { id: x.identifiers[0].id },
284299
relations: ['user1', 'user2'],
@@ -380,7 +395,7 @@ export class ReversiService implements OnModuleInit {
380395
public async getInvitations(user: MiUser): Promise<MiUser['id'][]> {
381396
const invitations = await this.redisClient.zrange(
382397
`reversi:matchSpecific:${user.id}`,
383-
Date.now() - MATCHING_TIMEOUT_MS,
398+
Date.now() - INVITATION_TIMEOUT_MS,
384399
'+inf',
385400
'BYSCORE');
386401
return invitations;

packages/backend/src/core/entities/ReversiGameEntityService.ts

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export class ReversiGameEntityService {
6060
canPutEverywhere: game.canPutEverywhere,
6161
loopedBoard: game.loopedBoard,
6262
timeLimitForEachTurn: game.timeLimitForEachTurn,
63+
noIrregularRules: game.noIrregularRules,
6364
logs: game.logs,
6465
map: game.map,
6566
});
@@ -108,6 +109,7 @@ export class ReversiGameEntityService {
108109
canPutEverywhere: game.canPutEverywhere,
109110
loopedBoard: game.loopedBoard,
110111
timeLimitForEachTurn: game.timeLimitForEachTurn,
112+
noIrregularRules: game.noIrregularRules,
111113
});
112114
}
113115

packages/backend/src/models/ReversiGame.ts

+5
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ export class MiReversiGame {
113113
})
114114
public bw: string;
115115

116+
@Column('boolean', {
117+
default: false,
118+
})
119+
public noIrregularRules: boolean;
120+
116121
@Column('boolean', {
117122
default: false,
118123
})

packages/backend/src/models/json-schema/reversi-game.ts

+8
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ export const packedReversiGameLiteSchema = {
8282
type: 'string',
8383
optional: false, nullable: false,
8484
},
85+
noIrregularRules: {
86+
type: 'boolean',
87+
optional: false, nullable: false,
88+
},
8589
isLlotheo: {
8690
type: 'boolean',
8791
optional: false, nullable: false,
@@ -196,6 +200,10 @@ export const packedReversiGameDetailedSchema = {
196200
type: 'string',
197201
optional: false, nullable: false,
198202
},
203+
noIrregularRules: {
204+
type: 'boolean',
205+
optional: false, nullable: false,
206+
},
199207
isLlotheo: {
200208
type: 'boolean',
201209
optional: false, nullable: false,

packages/backend/src/server/api/endpoints/reversi/match.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const paramDef = {
3737
type: 'object',
3838
properties: {
3939
userId: { type: 'string', format: 'misskey:id', nullable: true },
40+
noIrregularRules: { type: 'boolean', default: false },
4041
multiple: { type: 'boolean', default: false },
4142
},
4243
required: [],
@@ -57,7 +58,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
5758
throw err;
5859
}) : null;
5960

60-
const game = target ? await this.reversiService.matchSpecificUser(me, target, ps.multiple) : await this.reversiService.matchAnyUser(me, ps.multiple);
61+
const game = target
62+
? await this.reversiService.matchSpecificUser(me, target, ps.multiple)
63+
: await this.reversiService.matchAnyUser(me, { noIrregularRules: ps.noIrregularRules }, ps.multiple);
6164

6265
if (game == null) return;
6366

packages/frontend/package.json

+4-6
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"chartjs-chart-matrix": "2.0.1",
4141
"chartjs-plugin-gradient": "0.6.1",
4242
"chartjs-plugin-zoom": "2.0.1",
43-
"chromatic": "10.3.1",
43+
"chromatic": "10.5.0",
4444
"compare-versions": "6.1.0",
4545
"cropperjs": "2.0.0-beta.4",
4646
"date-fns": "2.30.0",
@@ -51,7 +51,6 @@
5151
"insert-text-at-cursor": "0.3.0",
5252
"is-file-animated": "1.0.2",
5353
"json5": "2.2.3",
54-
"lodash.defaultsdeep": "4.6.1",
5554
"matter-js": "0.19.0",
5655
"mfm-js": "0.24.0",
5756
"misskey-bubble-game": "workspace:*",
@@ -101,10 +100,9 @@
101100
"@testing-library/vue": "8.0.1",
102101
"@types/escape-regexp": "0.0.3",
103102
"@types/estree": "1.0.5",
104-
"@types/lodash.defaultsdeep": "4.6.9",
105103
"@types/matter-js": "0.19.6",
106104
"@types/micromatch": "4.0.6",
107-
"@types/node": "20.11.5",
105+
"@types/node": "20.11.6",
108106
"@types/punycode": "2.1.3",
109107
"@types/sanitize-html": "2.9.5",
110108
"@types/throttle-debounce": "5.0.2",
@@ -125,7 +123,7 @@
125123
"happy-dom": "10.0.3",
126124
"intersection-observer": "0.12.2",
127125
"micromatch": "4.0.5",
128-
"msw": "2.1.3",
126+
"msw": "2.1.4",
129127
"msw-storybook-addon": "1.10.0",
130128
"nodemon": "3.0.3",
131129
"prettier": "3.2.4",
@@ -137,7 +135,7 @@
137135
"vite-plugin-turbosnap": "1.0.3",
138136
"vitest": "0.34.6",
139137
"vitest-fetch-mock": "0.2.2",
140-
"vue-eslint-parser": "9.4.1",
138+
"vue-eslint-parser": "9.4.2",
141139
"vue-tsc": "1.8.27"
142140
}
143141
}

0 commit comments

Comments
 (0)