Commit c61bcaba authored by Chunchi Che's avatar Chunchi Che

support observer

parent ece99eb0
Pipeline #22940 failed with stages
in 12 minutes and 51 seconds
...@@ -49,6 +49,11 @@ export default class TypeChangeAdapter implements StocAdapter { ...@@ -49,6 +49,11 @@ export default class TypeChangeAdapter implements StocAdapter {
case 5: { case 5: {
selfType = ygopro.StocTypeChange.SelfType.PLAYER6; selfType = ygopro.StocTypeChange.SelfType.PLAYER6;
break;
}
case 7: {
selfType = ygopro.StocTypeChange.SelfType.OBSERVER;
break; break;
} }
} }
......
...@@ -27,12 +27,11 @@ export default function handleHsPlayerChange(pb: ygopro.YgoStocMsg) { ...@@ -27,12 +27,11 @@ export default function handleHsPlayerChange(pb: ygopro.YgoStocMsg) {
break; break;
} }
case ygopro.StocHsPlayerChange.State.READY: case ygopro.StocHsPlayerChange.State.READY:
case ygopro.StocHsPlayerChange.State.NO_READY: { case ygopro.StocHsPlayerChange.State.NO_READY:
roomStore.players[change.pos].state = change.state;
break;
}
case ygopro.StocHsPlayerChange.State.LEAVE: { case ygopro.StocHsPlayerChange.State.LEAVE: {
roomStore.players.splice(change.pos, 1); // 因为某种原因,当state为`LEAVE`的时候不能把它从`players`中去掉,
// 只能修改状态然后UI上做特化处理
roomStore.players[change.pos].state = change.state;
break; break;
} }
case ygopro.StocHsPlayerChange.State.TO_OBSERVER: { case ygopro.StocHsPlayerChange.State.TO_OBSERVER: {
......
...@@ -11,9 +11,11 @@ export default function handleTypeChange(pb: ygopro.YgoStocMsg) { ...@@ -11,9 +11,11 @@ export default function handleTypeChange(pb: ygopro.YgoStocMsg) {
if (assertHost) { if (assertHost) {
switch (selfType) { switch (selfType) {
case SelfType.UNKNOWN: case SelfType.UNKNOWN: {
console.warn("<HandleTypeChange>selfType is UNKNOWN");
break;
}
case SelfType.OBSERVER: { case SelfType.OBSERVER: {
console.warn("<HandleTypeChange>selfType is UNKNOWN or OBSERVER");
break; break;
} }
default: { default: {
......
...@@ -48,7 +48,6 @@ export const MatchModal: React.FC = ({}) => { ...@@ -48,7 +48,6 @@ export const MatchModal: React.FC = ({}) => {
setPasswd(event.target.value); setPasswd(event.target.value);
}; };
// 因为萌卡服务器的房间密码会有`#`等特殊字符,因此这里用`encodeURIComponent`做下转义
const handleSubmit = async () => { const handleSubmit = async () => {
setConfirmLoading(true); setConfirmLoading(true);
await init({ player, ip: server, passWd: passwd }); await init({ player, ip: server, passWd: passwd });
......
...@@ -81,6 +81,15 @@ ...@@ -81,6 +81,15 @@
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.5); box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.5);
} }
.uncheck {
position: absolute;
bottom: 0;
right: 0;
z-index: 99;
color: red;
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.5);
}
.btn-join { .btn-join {
margin-left: auto; margin-left: auto;
} }
......
import { CheckCircleFilled } from "@ant-design/icons"; import { CheckCircleFilled } from "@ant-design/icons";
import { sendHsNotReady, sendHsReady, sendUpdateDeck, ygopro } from "@/api"; import {
sendHsNotReady,
sendHsReady,
sendHsToDuelList,
sendHsToObserver,
sendUpdateDeck,
ygopro,
} from "@/api";
import socketMiddleWare, { socketCmd } from "@/middleware/socket";
import PlayerState = ygopro.StocHsPlayerChange.State; import PlayerState = ygopro.StocHsPlayerChange.State;
import SelfType = ygopro.StocTypeChange.SelfType;
import { Avatar, Button, ConfigProvider, Popover, Skeleton, Space } from "antd"; import { Avatar, Button, ConfigProvider, Popover, Skeleton, Space } from "antd";
import classNames from "classnames"; import classNames from "classnames";
import { import {
...@@ -11,6 +20,7 @@ import { ...@@ -11,6 +20,7 @@ import {
useRef, useRef,
useState, useState,
} from "react"; } from "react";
import { useNavigate } from "react-router-dom";
import { useSnapshot } from "valtio"; import { useSnapshot } from "valtio";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
...@@ -236,9 +246,9 @@ const PlayerZone: React.FC<{ ...@@ -236,9 +246,9 @@ const PlayerZone: React.FC<{
<div style={{ position: "relative" }}> <div style={{ position: "relative" }}>
<Avatar <Avatar
src={ src={
avatar avatar && player
? avatar ? avatar
: player : player && player.state != PlayerState.LEAVE
? `${NeosConfig.assetsPath}/default-avatar.png` ? `${NeosConfig.assetsPath}/default-avatar.png`
: "" : ""
} }
...@@ -250,7 +260,11 @@ const PlayerZone: React.FC<{ ...@@ -250,7 +260,11 @@ const PlayerZone: React.FC<{
</div> </div>
</OrderPopup> </OrderPopup>
<div className={styles.name}> <div className={styles.name}>
{player ? player.name : <Skeleton.Input size="small" />} {player && player.state != PlayerState.LEAVE ? (
player.name
) : (
<Skeleton.Input size="small" />
)}
</div> </div>
{btn} {btn}
</div> </div>
...@@ -260,15 +274,17 @@ const PlayerZone: React.FC<{ ...@@ -260,15 +274,17 @@ const PlayerZone: React.FC<{
const Controller: React.FC<{ onDeckChange: (deckName: string) => void }> = ({ const Controller: React.FC<{ onDeckChange: (deckName: string) => void }> = ({
onDeckChange, onDeckChange,
}) => { }) => {
const snap = useSnapshot(deckStore); const snapDeck = useSnapshot(deckStore);
const snapRoom = useSnapshot(roomStore);
const navigate = useNavigate();
return ( return (
<Space> <Space>
<Select <Select
title="卡组" title="卡组"
showSearch showSearch
style={{ width: 300 }} style={{ width: 300 }}
defaultValue={snap.decks[0].deckName} defaultValue={snapDeck.decks[0].deckName}
options={snap.decks.map((deck) => ({ options={snapDeck.decks.map((deck) => ({
value: deck.deckName, value: deck.deckName,
title: deck.deckName, title: deck.deckName,
}))} }))}
...@@ -277,22 +293,43 @@ const Controller: React.FC<{ onDeckChange: (deckName: string) => void }> = ({ ...@@ -277,22 +293,43 @@ const Controller: React.FC<{ onDeckChange: (deckName: string) => void }> = ({
(value) => onDeckChange(value) (value) => onDeckChange(value)
} }
/> />
<Button size="large" icon={<IconFont type="icon-record" size={18} />}> <Button
加入观战 size="large"
icon={<IconFont type="icon-record" size={18} />}
onClick={() => {
if (snapRoom.selfType != SelfType.OBSERVER) {
sendHsToObserver();
} else {
sendHsToDuelList();
}
}}
>
{snapRoom.selfType == SelfType.OBSERVER ? "加入决斗者" : "加入观战"}
<Avatar.Group className={styles["avatars-watch"]}> <Avatar.Group className={styles["avatars-watch"]}>
{Array.from({ length: snapRoom.observerCount }).map((_, idx) => (
<Avatar <Avatar
src="https://xsgames.co/randomusers/avatar.php?g=pixel&key=1" key={idx}
src={`${NeosConfig.assetsPath}/default-avatar.png`}
size="small" size="small"
/> />
<Avatar style={{ backgroundColor: "#f56a00" }} size="small"> ))}
K
</Avatar>
<Avatar style={{ backgroundColor: "#87d068" }} size="small" />
</Avatar.Group> </Avatar.Group>
</Button> </Button>
<Button size="large" icon={<IconFont type="icon-play" size={12} />}> <Button size="large" icon={<IconFont type="icon-play" size={12} />}>
开始游戏 开始游戏
</Button> </Button>
<Button
size="large"
danger
onClick={() => {
// 断开websocket🔗,
socketMiddleWare({ cmd: socketCmd.DISCONNECT });
// 返回上一个路由
navigate("..");
}}
>
退出房间
</Button>
</Space> </Space>
); );
}; };
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