Compare commits
No commits in common. "40cfb8c36e2db5060b06b9c33dcc404094056db3" and "a304e66e75d2df088b94325f4cc1ab1e4051b8c6" have entirely different histories.
40cfb8c36e
...
a304e66e75
@ -50,13 +50,6 @@
|
|||||||
>
|
>
|
||||||
<text class="enter-btn-text">{{ entering ? '正在进入...' : (ticketCount > 0 ? '立即开局' : '资格不足') }}</text>
|
<text class="enter-btn-text">{{ entering ? '正在进入...' : (ticketCount > 0 ? '立即开局' : '资格不足') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view
|
|
||||||
class="btn-secondary"
|
|
||||||
style="margin-top: 24rpx; background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); border-radius: 55rpx; height: 110rpx; display: flex; align-items: center; justify-content: center;"
|
|
||||||
@tap="goRoomList"
|
|
||||||
>
|
|
||||||
<text style="color: #94a3b8; font-size: 32rpx; font-weight: 600;">📡 对战列表 / 围观</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@ -127,28 +120,6 @@ export default {
|
|||||||
this.entering = false
|
this.entering = false
|
||||||
this.loadTickets()
|
this.loadTickets()
|
||||||
}
|
}
|
||||||
},
|
|
||||||
async goRoomList() {
|
|
||||||
// 获取配置以拿到 nakama 参数,虽然 room-list 也会尝试连接,但通过 URL 传参更稳妥
|
|
||||||
try {
|
|
||||||
const res = await authRequest({
|
|
||||||
url: '/api/app/games/enter',
|
|
||||||
method: 'POST',
|
|
||||||
data: {
|
|
||||||
game_code: this.gameCode
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const gameToken = encodeURIComponent(res.game_token)
|
|
||||||
const nakamaServer = encodeURIComponent(res.nakama_server)
|
|
||||||
const nakamaKey = encodeURIComponent(res.nakama_key)
|
|
||||||
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `/pages-game/game/minesweeper/room-list?game_token=${gameToken}&nakama_server=${nakamaServer}&nakama_key=${nakamaKey}`
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
uni.showToast({ title: '无法获取对战列表', icon: 'none' })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -901,16 +901,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.spectator-badge {
|
|
||||||
padding: $spacing-sm $spacing-md;
|
|
||||||
background: rgba($brand-secondary, 0.2);
|
|
||||||
border: 1px solid rgba($brand-secondary, 0.4);
|
|
||||||
border-radius: $radius-round;
|
|
||||||
font-size: $font-sm;
|
|
||||||
font-weight: 700;
|
|
||||||
color: $brand-secondary;
|
|
||||||
}
|
|
||||||
|
|
||||||
.timer-progress-bg {
|
.timer-progress-bg {
|
||||||
width: 660rpx;
|
width: 660rpx;
|
||||||
height: 6rpx;
|
height: 6rpx;
|
||||||
@ -1182,258 +1172,285 @@
|
|||||||
font-size: 16rpx;
|
font-size: 16rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// =====================================
|
// =====================================
|
||||||
// 底部面板
|
// 底部面板
|
||||||
// =====================================
|
// =====================================
|
||||||
.bottom-panel {
|
.bottom-panel {
|
||||||
padding: $spacing-sm;
|
padding: $spacing-sm;
|
||||||
padding-bottom: calc($spacing-sm + env(safe-area-inset-bottom));
|
padding-bottom: calc($spacing-sm + env(safe-area-inset-bottom));
|
||||||
background: rgba(0, 0, 0, 0.4);
|
background: rgba(0, 0, 0, 0.4);
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: $spacing-md;
|
gap: $spacing-md;
|
||||||
border-top: 1px solid $border-dark;
|
border-top: 1px solid $border-dark;
|
||||||
height: 180rpx; // 减小高度
|
height: 180rpx; // 减小高度
|
||||||
}
|
|
||||||
|
|
||||||
.game-logs {
|
|
||||||
flex: 1;
|
|
||||||
height: 100%;
|
|
||||||
padding: $spacing-sm;
|
|
||||||
background: rgba(0, 0, 0, 0.3);
|
|
||||||
border-radius: $radius-md;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log-line {
|
|
||||||
font-size: $font-xxs;
|
|
||||||
line-height: 1.6;
|
|
||||||
color: $text-dark-sub;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
|
||||||
&.log-system {
|
|
||||||
color: $accent-cyan;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.log-effect {
|
.game-logs {
|
||||||
color: $brand-primary;
|
flex: 1;
|
||||||
}
|
height: 100%;
|
||||||
}
|
padding: $spacing-sm;
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: $radius-md;
|
||||||
// =====================================
|
|
||||||
// 弹窗 (全屏遮罩)
|
|
||||||
// =====================================
|
|
||||||
.modal-overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background: rgba(0, 0, 0, 0.85);
|
|
||||||
backdrop-filter: blur(12rpx);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
z-index: 10000; // 确保在最厚层
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
width: 560rpx;
|
|
||||||
padding: $spacing-xxl $spacing-xl;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: $spacing-lg;
|
|
||||||
animation: zoomIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes zoomIn {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
.log-line {
|
||||||
opacity: 1;
|
font-size: $font-xxs;
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-emoji {
|
|
||||||
font-size: 110rpx;
|
|
||||||
filter: drop-shadow(0 0 20rpx rgba(255, 255, 255, 0.2));
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-title {
|
|
||||||
font-size: 44rpx;
|
|
||||||
font-weight: 900;
|
|
||||||
color: $text-dark-main;
|
|
||||||
text-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-details {
|
|
||||||
margin: $spacing-lg 0;
|
|
||||||
padding: $spacing-md;
|
|
||||||
background: rgba(255, 255, 255, 0.05);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
border-radius: $radius-md;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.detail-text {
|
|
||||||
font-size: $font-md;
|
|
||||||
color: $text-dark-sub;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
color: $text-dark-sub;
|
||||||
}
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
// =====================================
|
&.log-system {
|
||||||
// 玩法说明弹窗
|
color: $accent-cyan;
|
||||||
// =====================================
|
}
|
||||||
.guide-modal {
|
|
||||||
width: 90%;
|
|
||||||
max-width: 640rpx;
|
|
||||||
max-height: 85vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
animation: slideUp 0.4s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes slideUp {
|
&.log-effect {
|
||||||
from {
|
color: $brand-primary;
|
||||||
opacity: 0;
|
}
|
||||||
transform: translateY(100rpx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
// =====================================
|
||||||
opacity: 1;
|
// 弹窗
|
||||||
transform: translateY(0);
|
// =====================================
|
||||||
}
|
.modal-overlay {
|
||||||
}
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
.guide-header {
|
background: rgba(0, 0, 0, 0.8);
|
||||||
display: flex;
|
backdrop-filter: blur(10rpx);
|
||||||
justify-content: space-between;
|
display: flex;
|
||||||
align-items: center;
|
justify-content: center;
|
||||||
padding: $spacing-lg;
|
align-items: center;
|
||||||
border-bottom: 1px solid $border-dark;
|
z-index: 1000;
|
||||||
}
|
|
||||||
|
|
||||||
.guide-title {
|
|
||||||
font-size: $font-lg;
|
|
||||||
font-weight: 800;
|
|
||||||
color: $text-dark-main;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-btn {
|
|
||||||
width: 64rpx;
|
|
||||||
height: 64rpx;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
font-size: $font-lg;
|
|
||||||
color: $text-dark-sub;
|
|
||||||
background: rgba(255, 255, 255, 0.08);
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.guide-body {
|
|
||||||
padding: $spacing-lg;
|
|
||||||
max-height: 65vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
display: block;
|
|
||||||
font-size: $font-md;
|
|
||||||
font-weight: 700;
|
|
||||||
color: $brand-primary;
|
|
||||||
margin-bottom: $spacing-md;
|
|
||||||
}
|
|
||||||
|
|
||||||
.guide-grid {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: $spacing-md;
|
|
||||||
}
|
|
||||||
|
|
||||||
.guide-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
gap: $spacing-md;
|
|
||||||
padding: $spacing-md;
|
|
||||||
background: rgba(255, 255, 255, 0.04);
|
|
||||||
border-radius: $radius-md;
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
font-size: 36rpx;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.desc {
|
.modal-content {
|
||||||
|
width: 520rpx;
|
||||||
|
padding: $spacing-xxl $spacing-xl;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 6rpx;
|
align-items: center;
|
||||||
|
gap: $spacing-lg;
|
||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.modal-emoji {
|
||||||
font-size: $font-sm;
|
font-size: 100rpx;
|
||||||
font-weight: 600;
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
font-size: 40rpx;
|
||||||
|
font-weight: 900;
|
||||||
|
color: $text-dark-main;
|
||||||
|
margin-top: $spacing-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-details {
|
||||||
|
margin: $spacing-lg 0;
|
||||||
|
padding: $spacing-md;
|
||||||
|
background: rgba($bg-dark-card, 0.5);
|
||||||
|
border-radius: $radius-md;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.detail-text {
|
||||||
|
font-size: $font-md;
|
||||||
|
color: $text-dark-sub;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================
|
||||||
|
// 玩法说明弹窗
|
||||||
|
// =====================================
|
||||||
|
.guide-modal {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 640rpx;
|
||||||
|
max-height: 80vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: $spacing-lg;
|
||||||
|
border-bottom: 1px solid $border-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-title {
|
||||||
|
font-size: $font-lg;
|
||||||
|
font-weight: 800;
|
||||||
color: $text-dark-main;
|
color: $text-dark-main;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail {
|
.close-btn {
|
||||||
font-size: $font-xs;
|
width: 56rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: $font-lg;
|
||||||
color: $text-dark-sub;
|
color: $text-dark-sub;
|
||||||
line-height: 1.5;
|
background: rgba(255, 255, 255, 0.05);
|
||||||
}
|
border-radius: 50%;
|
||||||
}
|
|
||||||
|
|
||||||
// 通用辅助类 (全局可用)
|
|
||||||
.fadeInUp {
|
|
||||||
animation: fadeInUp 0.5s ease-out both;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInUp {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(40rpx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
.guide-body {
|
||||||
opacity: 1;
|
padding: $spacing-lg;
|
||||||
transform: translateY(0);
|
max-height: 60vh;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.pulse {
|
|
||||||
animation: pulse 2s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse {
|
|
||||||
|
|
||||||
0%,
|
|
||||||
100% {
|
|
||||||
transform: scale(1);
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
50% {
|
.section-title {
|
||||||
transform: scale(1.03);
|
display: block;
|
||||||
opacity: 1;
|
font-size: $font-md;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $brand-primary;
|
||||||
|
margin-bottom: $spacing-md;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.bg-red {
|
.guide-grid {
|
||||||
background-color: $color-error !important;
|
display: flex;
|
||||||
}
|
flex-direction: column;
|
||||||
|
gap: $spacing-md;
|
||||||
|
}
|
||||||
|
|
||||||
.bg-yellow {
|
.guide-item {
|
||||||
background-color: $color-warning !important;
|
display: flex;
|
||||||
}
|
align-items: flex-start;
|
||||||
|
gap: $spacing-md;
|
||||||
|
padding: $spacing-sm;
|
||||||
|
background: rgba(255, 255, 255, 0.03);
|
||||||
|
border-radius: $radius-md;
|
||||||
|
|
||||||
.bg-green {
|
.icon {
|
||||||
background-color: $color-success !important;
|
font-size: 32rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: $font-sm;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $text-dark-main;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail {
|
||||||
|
font-size: $font-xs;
|
||||||
|
color: $text-dark-sub;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================
|
||||||
|
// 飘字动画
|
||||||
|
// =====================================
|
||||||
|
.float-label {
|
||||||
|
position: absolute;
|
||||||
|
font-size: $font-md;
|
||||||
|
font-weight: 900;
|
||||||
|
pointer-events: none;
|
||||||
|
animation: floatUp 1s ease-out forwards;
|
||||||
|
z-index: 100;
|
||||||
|
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.8);
|
||||||
|
|
||||||
|
&.global {
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.text-damage {
|
||||||
|
color: $color-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.text-heal {
|
||||||
|
color: $color-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.text-effect {
|
||||||
|
color: $accent-cyan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes floatUp {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0) scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-60rpx) scale(0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =====================================
|
||||||
|
// 屏幕震动 & 通用动画
|
||||||
|
// =====================================
|
||||||
|
.screen-shake {
|
||||||
|
animation: screenShake 0.4s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes screenShake {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
20% {
|
||||||
|
transform: translateX(-8rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: translateX(8rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
60% {
|
||||||
|
transform: translateX(-4rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
transform: translateX(4rpx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fadeInUp {
|
||||||
|
animation: fadeInUp 0.5s ease-out both;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(40rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pulse {
|
||||||
|
animation: pulse 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1.03);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -98,7 +98,7 @@
|
|||||||
:key="p.userId"
|
:key="p.userId"
|
||||||
class="player-card opponent"
|
class="player-card opponent"
|
||||||
:class="{
|
:class="{
|
||||||
'active-turn': gameState.gameStarted && gameState.turnOrder[gameState.currentTurnIndex] === p.userId,
|
'active-turn': gameState.turnOrder[gameState.currentTurnIndex] === p.userId,
|
||||||
'damaged': damagedPlayers.includes(p.userId),
|
'damaged': damagedPlayers.includes(p.userId),
|
||||||
'healed': healedPlayers.includes(p.userId)
|
'healed': healedPlayers.includes(p.userId)
|
||||||
}"
|
}"
|
||||||
@ -141,7 +141,6 @@
|
|||||||
<view class="timer-badge" :class="{ urgent: turnTimer < 5 }">
|
<view class="timer-badge" :class="{ urgent: turnTimer < 5 }">
|
||||||
⏱️ {{ turnTimer }}s
|
⏱️ {{ turnTimer }}s
|
||||||
</view>
|
</view>
|
||||||
<view v-if="isSpectator" class="spectator-badge">围观中</view>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="timer-progress-bg" v-if="gameState.gameStarted">
|
<view class="timer-progress-bg" v-if="gameState.gameStarted">
|
||||||
@ -232,12 +231,12 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 结算弹窗 - 移至根级,确保不被 game-screen 的销毁影响 -->
|
<!-- 结算弹窗 -->
|
||||||
<view v-if="showResultModal" class="modal-overlay" style="z-index: 9999;">
|
<view v-if="shouldShowResultModal" class="modal-overlay">
|
||||||
<view class="modal-content glass-card">
|
<view class="modal-content glass-card">
|
||||||
<text class="modal-emoji">{{ getGameResultEmoji() }}</text>
|
<text class="modal-emoji">{{ getGameResultEmoji() }}</text>
|
||||||
<text class="modal-title">{{ getGameResultTitle() }}</text>
|
<text class="modal-title">{{ getGameResultTitle() }}</text>
|
||||||
<view class="result-details" v-if="gameState && gameState.players">
|
<view class="result-details" v-if="gameState.players">
|
||||||
<text class="detail-text">{{ getResultMessage() }}</text>
|
<text class="detail-text">{{ getResultMessage() }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
@ -250,8 +249,6 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 玩法说明弹窗 -->
|
<!-- 玩法说明弹窗 -->
|
||||||
<view v-if="showGuide" class="modal-overlay" @tap="showGuide = false">
|
<view v-if="showGuide" class="modal-overlay" @tap="showGuide = false">
|
||||||
<view class="guide-modal glass-card" @tap.stop>
|
<view class="guide-modal glass-card" @tap.stop>
|
||||||
@ -316,10 +313,6 @@ export default {
|
|||||||
healedPlayers: [],
|
healedPlayers: [],
|
||||||
isRefreshing: false,
|
isRefreshing: false,
|
||||||
logsScrollTop: 0,
|
logsScrollTop: 0,
|
||||||
isSpectator: false,
|
|
||||||
showSettlement: false,
|
|
||||||
settlementWinnerId: '',
|
|
||||||
showResultModal: false,
|
|
||||||
// Timers
|
// Timers
|
||||||
matchInterval: null,
|
matchInterval: null,
|
||||||
turnInterval: null,
|
turnInterval: null,
|
||||||
@ -386,12 +379,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
shouldShowResultModal(newVal) {
|
|
||||||
console.log('[WATCH] shouldShowResultModal changed:', newVal);
|
|
||||||
if (newVal) {
|
|
||||||
this.showResultModal = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
logs() {
|
logs() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.logsScrollTop = 99999 + Math.random();
|
this.logsScrollTop = 99999 + Math.random();
|
||||||
@ -406,10 +393,7 @@ export default {
|
|||||||
},
|
},
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
this.fetchGameConfig();
|
this.fetchGameConfig();
|
||||||
const { game_token, nakama_server, nakama_key, match_id, is_spectator } = options;
|
const { game_token, nakama_server, nakama_key } = options;
|
||||||
if (is_spectator) this.isSpectator = true;
|
|
||||||
if (match_id) this.matchId = match_id;
|
|
||||||
|
|
||||||
if (game_token) {
|
if (game_token) {
|
||||||
this.initNakama(game_token, decodeURIComponent(nakama_server || ''), decodeURIComponent(nakama_key || ''));
|
this.initNakama(game_token, decodeURIComponent(nakama_server || ''), decodeURIComponent(nakama_key || ''));
|
||||||
} else {
|
} else {
|
||||||
@ -471,20 +455,6 @@ export default {
|
|||||||
this.addLog('system', '✅ 已连接到远程节点');
|
this.addLog('system', '✅ 已连接到远程节点');
|
||||||
// 先设置监听器,再继续后续操作
|
// 先设置监听器,再继续后续操作
|
||||||
this.setupSocketListeners();
|
this.setupSocketListeners();
|
||||||
|
|
||||||
// 如果是直连模式(加入指定房间或围观)
|
|
||||||
if (this.matchId) {
|
|
||||||
this.addLog('system', this.isSpectator ? '🔭 正在切入观察视角...' : '🚪 正在进入指定战局...');
|
|
||||||
try {
|
|
||||||
await nakamaManager.joinMatch(this.matchId);
|
|
||||||
this.addLog('system', '✅ 接入成功');
|
|
||||||
setTimeout(() => {
|
|
||||||
nakamaManager.sendMatchState(this.matchId, 100, JSON.stringify({ action: 'getState' }));
|
|
||||||
}, 100);
|
|
||||||
} catch(err) {
|
|
||||||
this.addLog('system', '❌ 接入失败: ' + err.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.addLog('system', '❌ 通讯异常: ' + e.message);
|
this.addLog('system', '❌ 通讯异常: ' + e.message);
|
||||||
}
|
}
|
||||||
@ -659,51 +629,45 @@ export default {
|
|||||||
// 游戏结束 - 确保正确设置游戏状态
|
// 游戏结束 - 确保正确设置游戏状态
|
||||||
console.log('[游戏结束] 接收到游戏结束数据:', data);
|
console.log('[游戏结束] 接收到游戏结束数据:', data);
|
||||||
|
|
||||||
const winnerId = data.winnerId || (data.gameState && data.gameState.winnerId) || '';
|
|
||||||
this.settlementWinnerId = winnerId;
|
|
||||||
this.showSettlement = !!winnerId;
|
|
||||||
|
|
||||||
if (data.gameState) {
|
if (data.gameState) {
|
||||||
// 更新游戏状态并标记为已结束
|
// 更新游戏状态并标记为已结束
|
||||||
this.gameState = {
|
this.gameState = {
|
||||||
...data.gameState,
|
...data.gameState,
|
||||||
gameStarted: false, // 明确标记游戏已结束
|
gameStarted: false, // 明确标记游戏已结束
|
||||||
winnerId: winnerId
|
winnerId: data.winnerId || data.gameState.winnerId
|
||||||
};
|
};
|
||||||
} else if (this.gameState) {
|
|
||||||
this.gameState.gameStarted = false;
|
|
||||||
if (winnerId) this.gameState.winnerId = winnerId;
|
|
||||||
} else {
|
} else {
|
||||||
this.gameState = {
|
this.gameState = {
|
||||||
...data,
|
...data,
|
||||||
gameStarted: false,
|
gameStarted: false // 明确标记游戏已结束
|
||||||
winnerId: winnerId
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保 winnerId 存在于全局状态中以便计算属性使用
|
// 确保 winnerId 存在
|
||||||
if (this.gameState && !this.gameState.winnerId && winnerId) {
|
if (!this.gameState.winnerId && data.winnerId) {
|
||||||
this.gameState.winnerId = winnerId;
|
this.gameState.winnerId = data.winnerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[游戏结束] 最终游戏状态:', this.gameState);
|
console.log('[游戏结束] 最终游戏状态:', this.gameState);
|
||||||
console.log('[游戏结束] winnerId:', winnerId);
|
console.log('[游戏结束] winnerId:', this.gameState.winnerId);
|
||||||
|
console.log('[游戏结束] gameStarted:', this.gameState.gameStarted);
|
||||||
|
console.log('[游戏结束] 是否显示弹窗:', !this.gameState.gameStarted && !!this.gameState.winnerId);
|
||||||
|
|
||||||
// 根据结果显示不同的日志消息
|
// 根据结果显示不同的日志消息
|
||||||
let endMsg = '';
|
let endMsg = '';
|
||||||
if (winnerId === 'draw') {
|
if (this.gameState.winnerId === 'draw') {
|
||||||
endMsg = '平局:无人幸存';
|
endMsg = '平局:无人幸存';
|
||||||
} else if (winnerId === this.myUserId) {
|
} else if (this.gameState.winnerId === this.myUserId) {
|
||||||
endMsg = '🎉 您获得了胜利!';
|
endMsg = '🎉 您获得了胜利!';
|
||||||
} else {
|
} else {
|
||||||
endMsg = '💀 很遗憾失败了';
|
endMsg = '💀 很遗憾失败了';
|
||||||
}
|
}
|
||||||
this.addLog('system', endMsg);
|
this.addLog('system', `战局结束:${endMsg}`);
|
||||||
|
|
||||||
// 添加震动反馈
|
// 添加震动反馈
|
||||||
if (winnerId === this.myUserId) {
|
if (this.gameState.winnerId === this.myUserId) {
|
||||||
uni.vibrateShort({ type: 'success' });
|
uni.vibrateShort({ type: 'success' });
|
||||||
} else if (winnerId === 'draw') {
|
} else if (this.gameState.winnerId === 'draw') {
|
||||||
uni.vibrateShort({ type: 'warning' });
|
uni.vibrateShort({ type: 'warning' });
|
||||||
} else {
|
} else {
|
||||||
uni.vibrateShort({ type: 'fail' });
|
uni.vibrateShort({ type: 'fail' });
|
||||||
@ -767,7 +731,6 @@ export default {
|
|||||||
this.addLog('system', '已切断匹配信号');
|
this.addLog('system', '已切断匹配信号');
|
||||||
},
|
},
|
||||||
handleCellClick(idx) {
|
handleCellClick(idx) {
|
||||||
if (this.isSpectator) return;
|
|
||||||
if (!this.gameState || !this.gameState.gameStarted) return;
|
if (!this.gameState || !this.gameState.gameStarted) return;
|
||||||
if (!this.isMyTurn) return;
|
if (!this.isMyTurn) return;
|
||||||
if (this.gameState.grid[idx].revealed) return;
|
if (this.gameState.grid[idx].revealed) return;
|
||||||
|
|||||||
@ -1,319 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="page">
|
|
||||||
<view class="bg-decoration"></view>
|
|
||||||
|
|
||||||
<view class="header">
|
|
||||||
<text class="title">实时对战信号</text>
|
|
||||||
<view class="refresh-text-btn" :class="{ loading: loading }" @tap="loadRooms">
|
|
||||||
{{ loading ? '同步中...' : '刷新信号' }}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<scroll-view scroll-y class="content" @refresherrefresh="loadRooms" :refresher-enabled="true" :refresher-triggered="isRefreshing">
|
|
||||||
<view v-if="rooms.length > 0" class="room-list">
|
|
||||||
<view v-for="room in rooms" :key="room.match_id" class="room-card glass-card fadeInUp">
|
|
||||||
<view class="room-main">
|
|
||||||
<view class="room-info">
|
|
||||||
<view class="room-header">
|
|
||||||
<text class="room-id">房间 #{{ room.match_id.split('.')[0].substring(0, 6) }}</text>
|
|
||||||
<view class="status-badge" :class="room.started ? 'started' : 'waiting'">
|
|
||||||
{{ room.started ? '进行中' : '等待中' }}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="room-stats">
|
|
||||||
<view class="stat-item">
|
|
||||||
<text class="stat-icon">👥</text>
|
|
||||||
<text class="stat-text">{{ room.player_count }}/{{ room.max_players }} 玩家</text>
|
|
||||||
</view>
|
|
||||||
<view class="stat-item">
|
|
||||||
<text class="stat-icon">📡</text>
|
|
||||||
<text class="stat-text">延迟: {{ Math.floor(Math.random() * 50) + 20 }}ms</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="room-actions">
|
|
||||||
<view v-if="!room.started && room.player_count < room.max_players" class="btn-action join" @tap="joinRoom(room)">
|
|
||||||
<text class="action-text">加入</text>
|
|
||||||
</view>
|
|
||||||
<view class="btn-action watch" @tap="watchRoom(room)">
|
|
||||||
<text class="action-text">围观</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view v-else-if="!loading" class="empty-box">
|
|
||||||
<view class="empty-icon">🛰️</view>
|
|
||||||
<text class="empty-text">未监测到活跃战局</text>
|
|
||||||
<view class="btn-primary start-new" @tap="goBack">去发起匹配</view>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { nakamaManager } from '../../../utils/nakamaManager.js';
|
|
||||||
import { authRequest } from '../../../utils/request.js';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
rooms: [],
|
|
||||||
loading: false,
|
|
||||||
isRefreshing: false,
|
|
||||||
gameToken: '',
|
|
||||||
nakamaServer: '',
|
|
||||||
nakamaKey: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onLoad(options) {
|
|
||||||
this.gameToken = options.game_token;
|
|
||||||
this.nakamaServer = decodeURIComponent(options.nakama_server || '');
|
|
||||||
this.nakamaKey = decodeURIComponent(options.nakama_key || '');
|
|
||||||
this.initAndLoad();
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async initAndLoad() {
|
|
||||||
this.loading = true;
|
|
||||||
try {
|
|
||||||
if (!nakamaManager.isConnected) {
|
|
||||||
nakamaManager.initClient(this.nakamaServer || 'wss://game.1024tool.vip', this.nakamaKey || 'defaultkey');
|
|
||||||
await nakamaManager.authenticateWithGameToken(this.gameToken);
|
|
||||||
}
|
|
||||||
await this.loadRooms();
|
|
||||||
} catch (e) {
|
|
||||||
uni.showToast({ title: '连接通讯中心失败', icon: 'none' });
|
|
||||||
} finally {
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async loadRooms() {
|
|
||||||
this.isRefreshing = true;
|
|
||||||
try {
|
|
||||||
const res = await nakamaManager.rpc('list_matches', {});
|
|
||||||
this.rooms = res || [];
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Failed to load rooms', e);
|
|
||||||
} finally {
|
|
||||||
this.isRefreshing = false;
|
|
||||||
this.loading = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
goBack() {
|
|
||||||
uni.navigateBack();
|
|
||||||
},
|
|
||||||
joinRoom(room) {
|
|
||||||
// 通过 MatchID 传参给 play.vue
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `/pages-game/game/minesweeper/play?match_id=${room.match_id}&game_token=${encodeURIComponent(this.gameToken)}&nakama_server=${encodeURIComponent(this.nakamaServer)}&nakama_key=${encodeURIComponent(this.nakamaKey)}`
|
|
||||||
});
|
|
||||||
},
|
|
||||||
watchRoom(room) {
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `/pages-game/game/minesweeper/play?match_id=${room.match_id}&is_spectator=1&game_token=${encodeURIComponent(this.gameToken)}&nakama_server=${encodeURIComponent(this.nakamaServer)}&nakama_key=${encodeURIComponent(this.nakamaKey)}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
@import '@/uni.scss';
|
|
||||||
|
|
||||||
.page {
|
|
||||||
min-height: 100vh;
|
|
||||||
background-color: #0f172a;
|
|
||||||
color: #f8fafc;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-decoration {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 400rpx;
|
|
||||||
background: radial-gradient(circle at 50% 0%, rgba(59, 130, 246, 0.15) 0%, transparent 70%);
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
position: relative;
|
|
||||||
z-index: 10;
|
|
||||||
padding: 100rpx 40rpx 40rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 38rpx;
|
|
||||||
font-weight: 800;
|
|
||||||
letter-spacing: 2rpx;
|
|
||||||
color: #f8fafc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.refresh-text-btn {
|
|
||||||
padding: 12rpx 24rpx;
|
|
||||||
background: rgba(255, 255, 255, 0.05);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
border-radius: 12rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #94a3b8;
|
|
||||||
transition: all 0.2s;
|
|
||||||
|
|
||||||
&.loading {
|
|
||||||
opacity: 0.6;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
transform: scale(0.95);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
flex: 1;
|
|
||||||
padding: 0 30rpx;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-list {
|
|
||||||
padding-bottom: 60rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-card {
|
|
||||||
margin-bottom: 24rpx;
|
|
||||||
padding: 32rpx;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-main {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-id {
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #94a3b8;
|
|
||||||
margin-right: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-badge {
|
|
||||||
padding: 4rpx 16rpx;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
font-size: 20rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
|
|
||||||
&.waiting {
|
|
||||||
background: rgba(34, 197, 94, 0.2);
|
|
||||||
color: #4ade80;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.started {
|
|
||||||
background: rgba(59, 130, 246, 0.2);
|
|
||||||
color: #60a5fa;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-stats {
|
|
||||||
display: flex;
|
|
||||||
gap: 24rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stat-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stat-icon {
|
|
||||||
font-size: 24rpx;
|
|
||||||
margin-right: 8rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stat-text {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #cbd5e1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-action {
|
|
||||||
padding: 16rpx 32rpx;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
font-weight: 700;
|
|
||||||
transition: all 0.2s;
|
|
||||||
|
|
||||||
&.join {
|
|
||||||
background: #3b82f6;
|
|
||||||
color: white;
|
|
||||||
box-shadow: 0 4rpx 12rpx rgba(59, 130, 246, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.watch {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
color: #f8fafc;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
transform: scale(0.95);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-box {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding-top: 200rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-icon {
|
|
||||||
font-size: 120rpx;
|
|
||||||
margin-bottom: 40rpx;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-text {
|
|
||||||
font-size: 32rpx;
|
|
||||||
color: #64748b;
|
|
||||||
margin-bottom: 60rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.start-new {
|
|
||||||
width: 320rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInUp {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(20rpx);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fadeInUp {
|
|
||||||
animation: fadeInUp 0.4s ease-out both;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -189,14 +189,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"path": "game/minesweeper/room-list",
|
|
||||||
"style": {
|
|
||||||
"navigationStyle": "default",
|
|
||||||
"navigationBarTitleText": "对战列表",
|
|
||||||
"disableScroll": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "game/webview",
|
"path": "game/webview",
|
||||||
"style": {
|
"style": {
|
||||||
|
|||||||
@ -282,16 +282,12 @@ class NakamaManager {
|
|||||||
await this.authenticateWithGameToken(this.gameToken);
|
await this.authenticateWithGameToken(this.gameToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.gameToken) {
|
|
||||||
throw new Error('Missing game token in manager');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[Nakama] Adding to matchmaker:', minCount, '-', maxCount);
|
console.log('[Nakama] Adding to matchmaker:', minCount, '-', maxCount);
|
||||||
const response = await this._send({
|
const response = await this._send({
|
||||||
matchmaker_add: {
|
matchmaker_add: {
|
||||||
min_count: minCount || 2,
|
min_count: minCount || 2,
|
||||||
max_count: maxCount || 2,
|
max_count: maxCount || 2,
|
||||||
query: '+properties.game_token:*',
|
query: '*',
|
||||||
string_properties: { game_token: this.gameToken }
|
string_properties: { game_token: this.gameToken }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -319,28 +315,6 @@ class NakamaManager {
|
|||||||
return response.match;
|
return response.match;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用 RPC
|
|
||||||
*/
|
|
||||||
async rpc(id, payload) {
|
|
||||||
console.log('[Nakama] RPC call:', id);
|
|
||||||
const response = await this._send({
|
|
||||||
rpc: {
|
|
||||||
id: id,
|
|
||||||
payload: typeof payload === 'string' ? payload : JSON.stringify(payload)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.rpc && response.rpc.payload) {
|
|
||||||
try {
|
|
||||||
return JSON.parse(response.rpc.payload);
|
|
||||||
} catch (e) {
|
|
||||||
return response.rpc.payload;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送游戏状态
|
* 发送游戏状态
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user