enhance(reversi): some tweaks
This commit is contained in:
parent
67f6157d42
commit
259992c65f
|
@ -42,7 +42,7 @@ class ReversiGameChannel extends Channel {
|
||||||
case 'updateSettings': this.updateSettings(body.key, body.value); break;
|
case 'updateSettings': this.updateSettings(body.key, body.value); break;
|
||||||
case 'cancel': this.cancelGame(); break;
|
case 'cancel': this.cancelGame(); break;
|
||||||
case 'putStone': this.putStone(body.pos, body.id); break;
|
case 'putStone': this.putStone(body.pos, body.id); break;
|
||||||
case 'checkState': this.checkState(body.crc32); break;
|
case 'resync': this.resync(body.crc32); break;
|
||||||
case 'claimTimeIsUp': this.claimTimeIsUp(); break;
|
case 'claimTimeIsUp': this.claimTimeIsUp(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,12 +76,10 @@ class ReversiGameChannel extends Channel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async checkState(crc32: string | number) {
|
private async resync(crc32: string | number) {
|
||||||
if (crc32 != null) return;
|
|
||||||
|
|
||||||
const game = await this.reversiService.checkCrc(this.gameId!, crc32);
|
const game = await this.reversiService.checkCrc(this.gameId!, crc32);
|
||||||
if (game) {
|
if (game) {
|
||||||
this.send('rescue', game);
|
this.send('resynced', game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -163,7 +163,7 @@ const $i = signinRequired();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
game: Misskey.entities.ReversiGameDetailed;
|
game: Misskey.entities.ReversiGameDetailed;
|
||||||
connection: Misskey.ChannelConnection;
|
connection?: Misskey.ChannelConnection | null;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const showBoardLabels = ref<boolean>(false);
|
const showBoardLabels = ref<boolean>(false);
|
||||||
|
@ -240,10 +240,10 @@ watch(logPos, (v) => {
|
||||||
|
|
||||||
if (game.value.isStarted && !game.value.isEnded) {
|
if (game.value.isStarted && !game.value.isEnded) {
|
||||||
useInterval(() => {
|
useInterval(() => {
|
||||||
if (game.value.isEnded) return;
|
if (game.value.isEnded || props.connection == null) return;
|
||||||
const crc32 = CRC32.str(JSON.stringify(game.value.logs)).toString();
|
const crc32 = CRC32.str(JSON.stringify(game.value.logs)).toString();
|
||||||
if (_DEV_) console.log('crc32', crc32);
|
if (_DEV_) console.log('crc32', crc32);
|
||||||
props.connection.send('checkState', {
|
props.connection.send('resync', {
|
||||||
crc32: crc32,
|
crc32: crc32,
|
||||||
});
|
});
|
||||||
}, 10000, { immediate: false, afterMounted: true });
|
}, 10000, { immediate: false, afterMounted: true });
|
||||||
|
@ -267,7 +267,7 @@ function putStone(pos) {
|
||||||
});
|
});
|
||||||
|
|
||||||
const id = Math.random().toString(36).slice(2);
|
const id = Math.random().toString(36).slice(2);
|
||||||
props.connection.send('putStone', {
|
props.connection!.send('putStone', {
|
||||||
pos: pos,
|
pos: pos,
|
||||||
id,
|
id,
|
||||||
});
|
});
|
||||||
|
@ -283,6 +283,7 @@ const myTurnTimerRmain = ref<number>(game.value.timeLimitForEachTurn);
|
||||||
const opTurnTimerRmain = ref<number>(game.value.timeLimitForEachTurn);
|
const opTurnTimerRmain = ref<number>(game.value.timeLimitForEachTurn);
|
||||||
|
|
||||||
const TIMER_INTERVAL_SEC = 3;
|
const TIMER_INTERVAL_SEC = 3;
|
||||||
|
if (!props.game.isEnded) {
|
||||||
useInterval(() => {
|
useInterval(() => {
|
||||||
if (myTurnTimerRmain.value > 0) {
|
if (myTurnTimerRmain.value > 0) {
|
||||||
myTurnTimerRmain.value = Math.max(0, myTurnTimerRmain.value - TIMER_INTERVAL_SEC);
|
myTurnTimerRmain.value = Math.max(0, myTurnTimerRmain.value - TIMER_INTERVAL_SEC);
|
||||||
|
@ -293,12 +294,13 @@ useInterval(() => {
|
||||||
|
|
||||||
if (iAmPlayer.value) {
|
if (iAmPlayer.value) {
|
||||||
if ((isMyTurn.value && myTurnTimerRmain.value === 0) || (!isMyTurn.value && opTurnTimerRmain.value === 0)) {
|
if ((isMyTurn.value && myTurnTimerRmain.value === 0) || (!isMyTurn.value && opTurnTimerRmain.value === 0)) {
|
||||||
props.connection.send('claimTimeIsUp', {});
|
props.connection!.send('claimTimeIsUp', {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, TIMER_INTERVAL_SEC * 1000, { immediate: false, afterMounted: true });
|
}, TIMER_INTERVAL_SEC * 1000, { immediate: false, afterMounted: true });
|
||||||
|
}
|
||||||
|
|
||||||
function onStreamLog(log: Reversi.Serializer.Log & { id: string | null }) {
|
async function onStreamLog(log: Reversi.Serializer.Log & { id: string | null }) {
|
||||||
game.value.logs = Reversi.Serializer.serializeLogs([
|
game.value.logs = Reversi.Serializer.serializeLogs([
|
||||||
...Reversi.Serializer.deserializeLogs(game.value.logs),
|
...Reversi.Serializer.deserializeLogs(game.value.logs),
|
||||||
log,
|
log,
|
||||||
|
@ -309,17 +311,25 @@ function onStreamLog(log: Reversi.Serializer.Log & { id: string | null }) {
|
||||||
if (log.id == null || !appliedOps.includes(log.id)) {
|
if (log.id == null || !appliedOps.includes(log.id)) {
|
||||||
switch (log.operation) {
|
switch (log.operation) {
|
||||||
case 'put': {
|
case 'put': {
|
||||||
|
sound.playUrl('/client-assets/reversi/put.mp3', {
|
||||||
|
volume: 1,
|
||||||
|
playbackRate: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (log.player !== engine.value.turn) { // = desyncが発生している
|
||||||
|
const _game = await misskeyApi('reversi/show-game', {
|
||||||
|
gameId: props.game.id,
|
||||||
|
});
|
||||||
|
restoreGame(_game);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
engine.value.putStone(log.pos);
|
engine.value.putStone(log.pos);
|
||||||
triggerRef(engine);
|
triggerRef(engine);
|
||||||
|
|
||||||
myTurnTimerRmain.value = game.value.timeLimitForEachTurn;
|
myTurnTimerRmain.value = game.value.timeLimitForEachTurn;
|
||||||
opTurnTimerRmain.value = game.value.timeLimitForEachTurn;
|
opTurnTimerRmain.value = game.value.timeLimitForEachTurn;
|
||||||
|
|
||||||
sound.playUrl('/client-assets/reversi/put.mp3', {
|
|
||||||
volume: 1,
|
|
||||||
playbackRate: 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
checkEnd();
|
checkEnd();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -366,9 +376,7 @@ function checkEnd() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStreamRescue(_game) {
|
function restoreGame(_game) {
|
||||||
console.log('rescue');
|
|
||||||
|
|
||||||
game.value = deepClone(_game);
|
game.value = deepClone(_game);
|
||||||
|
|
||||||
engine.value = Reversi.Serializer.restoreGame({
|
engine.value = Reversi.Serializer.restoreGame({
|
||||||
|
@ -384,6 +392,12 @@ function onStreamRescue(_game) {
|
||||||
checkEnd();
|
checkEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onStreamResynced(_game) {
|
||||||
|
console.log('resynced');
|
||||||
|
|
||||||
|
restoreGame(_game);
|
||||||
|
}
|
||||||
|
|
||||||
async function surrender() {
|
async function surrender() {
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
|
@ -434,27 +448,35 @@ function share() {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (props.connection != null) {
|
||||||
props.connection.on('log', onStreamLog);
|
props.connection.on('log', onStreamLog);
|
||||||
props.connection.on('rescue', onStreamRescue);
|
props.connection.on('resynced', onStreamResynced);
|
||||||
props.connection.on('ended', onStreamEnded);
|
props.connection.on('ended', onStreamEnded);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
|
if (props.connection != null) {
|
||||||
props.connection.on('log', onStreamLog);
|
props.connection.on('log', onStreamLog);
|
||||||
props.connection.on('rescue', onStreamRescue);
|
props.connection.on('resynced', onStreamResynced);
|
||||||
props.connection.on('ended', onStreamEnded);
|
props.connection.on('ended', onStreamEnded);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onDeactivated(() => {
|
onDeactivated(() => {
|
||||||
|
if (props.connection != null) {
|
||||||
props.connection.off('log', onStreamLog);
|
props.connection.off('log', onStreamLog);
|
||||||
props.connection.off('rescue', onStreamRescue);
|
props.connection.off('resynced', onStreamResynced);
|
||||||
props.connection.off('ended', onStreamEnded);
|
props.connection.off('ended', onStreamEnded);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
if (props.connection != null) {
|
||||||
props.connection.off('log', onStreamLog);
|
props.connection.off('log', onStreamLog);
|
||||||
props.connection.off('rescue', onStreamRescue);
|
props.connection.off('resynced', onStreamResynced);
|
||||||
props.connection.off('ended', onStreamEnded);
|
props.connection.off('ended', onStreamEnded);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="game == null || connection == null"><MkLoading/></div>
|
<div v-if="game == null || (!game.isEnded && connection == null)"><MkLoading/></div>
|
||||||
<GameSetting v-else-if="!game.isStarted" :game="game" :connection="connection"/>
|
<GameSetting v-else-if="!game.isStarted" :game="game" :connection="connection!"/>
|
||||||
<GameBoard v-else :game="game" :connection="connection"/>
|
<GameBoard v-else :game="game" :connection="connection"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ async function fetchGame() {
|
||||||
if (connection.value) {
|
if (connection.value) {
|
||||||
connection.value.dispose();
|
connection.value.dispose();
|
||||||
}
|
}
|
||||||
|
if (!game.value.isEnded) {
|
||||||
connection.value = useStream().useChannel('reversiGame', {
|
connection.value = useStream().useChannel('reversiGame', {
|
||||||
gameId: game.value.id,
|
gameId: game.value.id,
|
||||||
});
|
});
|
||||||
|
@ -65,6 +66,7 @@ async function fetchGame() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchGame();
|
fetchGame();
|
||||||
|
|
Loading…
Reference in New Issue