From db7bd0e94e0bf98fe49bdd7ea0937c491c562db5 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 28 Jan 2024 17:31:32 +0900 Subject: [PATCH] wip --- .../backend/src/core/GlobalEventService.ts | 11 +++-- packages/backend/src/core/MahjongService.ts | 19 ++++++++ .../api/stream/channels/mahjong-room.ts | 8 ++++ .../frontend/assets/mahjong/tile-top-h.png | Bin 0 -> 5076 bytes .../frontend/assets/mahjong/tile-top-v.png | Bin 0 -> 5049 bytes packages/frontend/assets/mahjong/tile-top.png | Bin 5956 -> 0 bytes .../frontend/src/pages/mahjong/room.game.vue | 33 ++++++++----- packages/frontend/src/pages/mahjong/tile.vue | 45 ++++++++++++++++++ packages/misskey-mahjong/src/engine.ts | 29 ++++++++++- 9 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 packages/frontend/assets/mahjong/tile-top-h.png create mode 100644 packages/frontend/assets/mahjong/tile-top-v.png delete mode 100644 packages/frontend/assets/mahjong/tile-top.png create mode 100644 packages/frontend/src/pages/mahjong/tile.vue diff --git a/packages/backend/src/core/GlobalEventService.ts b/packages/backend/src/core/GlobalEventService.ts index 57c1b3da40..d7318a43ad 100644 --- a/packages/backend/src/core/GlobalEventService.ts +++ b/packages/backend/src/core/GlobalEventService.ts @@ -205,18 +205,23 @@ export interface MahjongRoomEventTypes { room: Packed<'MahjongRoomDetailed'>; }; tsumo: { - house: Mahjong.Engine.House; + house: Mahjong.Common.House; tile: Mahjong.Common.Tile; }; dahai: { - house: Mahjong.Engine.House; + house: Mahjong.Common.House; tile: Mahjong.Common.Tile; }; dahaiAndTsumo: { - house: Mahjong.Engine.House; + dahaiHouse: Mahjong.Common.House; dahaiTile: Mahjong.Common.Tile; tsumoTile: Mahjong.Common.Tile; }; + ponned: { + source: Mahjong.Common.House; + target: Mahjong.Common.House; + tile: Mahjong.Common.Tile; + }; } //#endregion diff --git a/packages/backend/src/core/MahjongService.ts b/packages/backend/src/core/MahjongService.ts index 82bd7e8818..3e8b20a5a1 100644 --- a/packages/backend/src/core/MahjongService.ts +++ b/packages/backend/src/core/MahjongService.ts @@ -412,6 +412,25 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit { await this.dahai(room, engine, myHouse, tile); } + @bindThis + public async op_ron(roomId: MiMahjongGame['id'], user: MiUser) { + const room = await this.getRoom(roomId); + if (room == null) return; + if (room.gameState == null) return; + + const engine = new Mahjong.Engine.MasterGameEngine(room.gameState); + const myHouse = user.id === room.user1Id ? engine.state.user1House : user.id === room.user2Id ? engine.state.user2House : user.id === room.user3Id ? engine.state.user3House : engine.state.user4House; + + // TODO: 自分にロン回答する権利がある状態かバリデーション + + // TODO: この辺の処理はアトミックに行いたいけどJSONサポートはRedis Stackが必要 + const current = await this.redisClient.get(`mahjong:gameCallAndRonAsking:${room.id}`); + if (current == null) throw new Error('no asking found'); + const currentAnswers = JSON.parse(current) as CallAndRonAnswers; + currentAnswers.ron[myHouse] = true; + await this.redisClient.set(`mahjong:gameCallAndRonAsking:${room.id}`, JSON.stringify(currentAnswers)); + } + @bindThis public async op_pon(roomId: MiMahjongGame['id'], user: MiUser) { const room = await this.getRoom(roomId); diff --git a/packages/backend/src/server/api/stream/channels/mahjong-room.ts b/packages/backend/src/server/api/stream/channels/mahjong-room.ts index 1472a7013a..e3556fbc8b 100644 --- a/packages/backend/src/server/api/stream/channels/mahjong-room.ts +++ b/packages/backend/src/server/api/stream/channels/mahjong-room.ts @@ -39,6 +39,7 @@ class MahjongRoomChannel extends Channel { case 'updateSettings': this.updateSettings(body.key, body.value); break; case 'addAi': this.addAi(); break; case 'dahai': this.dahai(body.tile); break; + case 'ron': this.ron(); break; case 'pon': this.pon(); break; case 'nop': this.nop(); break; case 'claimTimeIsUp': this.claimTimeIsUp(); break; @@ -73,6 +74,13 @@ class MahjongRoomChannel extends Channel { this.mahjongService.op_dahai(this.roomId!, this.user, tile); } + @bindThis + private async ron() { + if (this.user == null) return; + + this.mahjongService.op_ron(this.roomId!, this.user); + } + @bindThis private async pon() { if (this.user == null) return; diff --git a/packages/frontend/assets/mahjong/tile-top-h.png b/packages/frontend/assets/mahjong/tile-top-h.png new file mode 100644 index 0000000000000000000000000000000000000000..a575deca27e1071baa582b05a4592510798ff3ae GIT binary patch literal 5076 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 CNoGX= literal 0 HcmV?d00001 diff --git a/packages/frontend/assets/mahjong/tile-top-v.png b/packages/frontend/assets/mahjong/tile-top-v.png new file mode 100644 index 0000000000000000000000000000000000000000..d087d195b445b2e88a8f850a76bba3437245004d GIT binary patch literal 5049 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 H_t^gcTM#!) literal 0 HcmV?d00001 diff --git a/packages/frontend/assets/mahjong/tile-top.png b/packages/frontend/assets/mahjong/tile-top.png deleted file mode 100644 index 861608a43d7b49b215905964ccf9fe7ac27d221d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5956 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 diff --git a/packages/frontend/src/pages/mahjong/room.game.vue b/packages/frontend/src/pages/mahjong/room.game.vue index ab4572e508..a38df8025e 100644 --- a/packages/frontend/src/pages/mahjong/room.game.vue +++ b/packages/frontend/src/pages/mahjong/room.game.vue @@ -28,28 +28,28 @@ SPDX-License-Identifier: AGPL-3.0-only
- +
- +
- +
- +
@@ -69,16 +69,17 @@ SPDX-License-Identifier: AGPL-3.0-only
- - - + + +
- Pon - Skip pon - Hora + Ron + Pon + Skip + Tsumo @@ -86,6 +87,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, onActivated, onDeactivated, onMounted, onUnmounted, ref, shallowRef, triggerRef, watch } from 'vue'; import * as Misskey from 'misskey-js'; import * as Mahjong from 'misskey-mahjong'; +import XTile from './tile.vue'; import MkButton from '@/components/MkButton.vue'; import MkFolder from '@/components/MkFolder.vue'; import MkSwitch from '@/components/MkSwitch.vue'; @@ -190,6 +192,14 @@ function dahai(tile: Mahjong.Common.Tile, ev: MouseEvent) { }); } +function ron() { + engine.value.op_ron(engine.value.state.canRonSource, engine.value.myHouse); + triggerRef(engine); + + props.connection!.send('ron', { + }); +} + function pon() { engine.value.op_pon(engine.value.state.canPonSource, engine.value.myHouse); triggerRef(engine); @@ -464,9 +474,6 @@ onUnmounted(() => { .hoTile { position: relative; display: inline-block; - width: 32px; - aspect-ratio: 0.7; - background: #fff; margin-bottom: -8px; } diff --git a/packages/frontend/src/pages/mahjong/tile.vue b/packages/frontend/src/pages/mahjong/tile.vue new file mode 100644 index 0000000000..a86c5f8463 --- /dev/null +++ b/packages/frontend/src/pages/mahjong/tile.vue @@ -0,0 +1,45 @@ + + + + + + + diff --git a/packages/misskey-mahjong/src/engine.ts b/packages/misskey-mahjong/src/engine.ts index 01e37b1a64..a71dca8e14 100644 --- a/packages/misskey-mahjong/src/engine.ts +++ b/packages/misskey-mahjong/src/engine.ts @@ -365,8 +365,9 @@ export class MasterGameEngine { const horaSets = Utils.getHoraSets(this.getHandTilesOf(house).concat(tile)); if (horaSets.length === 0) return false; // 完成形じゃない - const yakus = YAKU_DEFINITIONS.filter(yaku => yaku.calc(this.state, { tsumoTile: null, ronTile: tile })); - if (yakus.length === 0) return false; // 役がない + // TODO + //const yakus = YAKU_DEFINITIONS.filter(yaku => yaku.calc(this.state, { tsumoTile: null, ronTile: tile })); + //if (yakus.length === 0) return false; // 役がない return true; } @@ -494,6 +495,9 @@ export type PlayerState = { latestDahaiedTile: Tile | null; turn: House | null; canPonSource: House | null; + canCiiSource: House | null; + canKanSource: House | null; + canRonSource: House | null; canCiiTo: House | null; canKanTo: House | null; canRonTo: House | null; @@ -596,14 +600,34 @@ export class PlayerGameEngine { if (house === this.myHouse) { } else { + const canRon = Utils.getHoraSets(this.myHandTiles.concat(tile)).length > 0; const canPon = this.myHandTiles.filter(t => t === tile).length === 2; // TODO: canCii + if (canRon) this.state.canRonSource = house; if (canPon) this.state.canPonSource = house; } } + /** + * ロンします + * @param source 牌を捨てた人 + * @param target ロンした人 + */ + public op_ron(source: House, target: House) { + this.state.canRonSource = null; + + const lastTile = this.getHoTilesOf(source).pop(); + if (lastTile == null) throw new PlayerGameEngine.InvalidOperationError(); + if (target === this.myHouse) { + this.myHandTiles.push(lastTile); + } else { + this.getHandTilesOf(target).push(null); + } + this.state.turn = null; + } + /** * ポンします * @param source 牌を捨てた人 @@ -627,6 +651,7 @@ export class PlayerGameEngine { } public op_nop() { + this.state.canRonSource = null; this.state.canPonSource = null; } }