Commit 4427068c authored by Chunchi Che's avatar Chunchi Che

support replay

parent 80d19636
Pipeline #22948 passed with stages
in 13 minutes and 37 seconds
...@@ -7,7 +7,7 @@ import { fetchCard, ygopro } from "@/api"; ...@@ -7,7 +7,7 @@ import { fetchCard, ygopro } from "@/api";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import { sleep } from "@/infra"; import { sleep } from "@/infra";
import { cardStore, CardType, matStore } from "@/stores"; import { cardStore, CardType, matStore } from "@/stores";
import { replayStart } from "@/ui/Replay"; import { replayStart } from "@/ui/NewMatch/ReplayModal";
const TOKEN_SIZE = 13; // 每人场上最多就只可能有13个token const TOKEN_SIZE = 13; // 每人场上最多就只可能有13个token
export default async (start: ygopro.StocGameMessage.MsgStart) => { export default async (start: ygopro.StocGameMessage.MsgStart) => {
......
...@@ -17,7 +17,7 @@ import { ...@@ -17,7 +17,7 @@ import {
} from "./Message"; } from "./Message";
import { LifeBar, Mat, Menu } from "./PlayMat"; import { LifeBar, Mat, Menu } from "./PlayMat";
const NeosDuel = () => { export const Component: React.FC = () => {
return ( return (
<> <>
<SelectActionsModal /> <SelectActionsModal />
...@@ -39,5 +39,4 @@ const NeosDuel = () => { ...@@ -39,5 +39,4 @@ const NeosDuel = () => {
</> </>
); );
}; };
Component.displayName = "NeosDuel";
export default NeosDuel;
...@@ -28,6 +28,7 @@ const _router = createBrowserRouter([ ...@@ -28,6 +28,7 @@ const _router = createBrowserRouter([
}, },
{ {
path: "/duel/:ip/:player/:passWd", path: "/duel/:ip/:player/:passWd",
lazy: () => import("./Duel/Main"),
}, },
], ],
}, },
......
...@@ -6,7 +6,7 @@ import { proxy, useSnapshot } from "valtio"; ...@@ -6,7 +6,7 @@ import { proxy, useSnapshot } from "valtio";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import { accountStore, roomStore } from "@/stores"; import { accountStore, roomStore } from "@/stores";
import styles from "./Modal.module.scss"; import styles from "./MatchModal.module.scss";
import { init } from "./util"; import { init } from "./util";
const NeosConfig = useConfig(); const NeosConfig = useConfig();
const serverConfig = NeosConfig.servers; const serverConfig = NeosConfig.servers;
...@@ -24,10 +24,10 @@ const defaultProps: Props = { ...@@ -24,10 +24,10 @@ const defaultProps: Props = {
open: false, open: false,
}; };
export const localStore = proxy<Props>(defaultProps); export const matchStore = proxy<Props>(defaultProps);
export const MatchModal: React.FC = ({}) => { export const MatchModal: React.FC = ({}) => {
const { open } = useSnapshot(localStore); const { open } = useSnapshot(matchStore);
const { user } = useSnapshot(accountStore); const { user } = useSnapshot(accountStore);
const { joined } = useSnapshot(roomStore); const { joined } = useSnapshot(roomStore);
const [player, setPlayer] = useState(user?.name ?? defaultPlayer); const [player, setPlayer] = useState(user?.name ?? defaultPlayer);
...@@ -71,7 +71,7 @@ export const MatchModal: React.FC = ({}) => { ...@@ -71,7 +71,7 @@ export const MatchModal: React.FC = ({}) => {
<Modal <Modal
open={open} open={open}
title="请输入自定义房间信息" title="请输入自定义房间信息"
onCancel={() => (localStore.open = false)} onCancel={() => (matchStore.open = false)}
footer={ footer={
<Button onClick={handleSubmit} loading={confirmLoading}> <Button onClick={handleSubmit} loading={confirmLoading}>
加入房间 加入房间
......
import "../../styles/core.scss";
import { UploadOutlined } from "@ant-design/icons"; import { UploadOutlined } from "@ant-design/icons";
import { Button, message, Modal, Upload, UploadProps } from "antd"; import { Button, message, Modal, Upload, UploadProps } from "antd";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import rustInit from "rust-src";
import { proxy, useSnapshot } from "valtio"; import { proxy, useSnapshot } from "valtio";
import { initStrings } from "@/api";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import socketMiddleWare, { socketCmd } from "@/middleware/socket";
import sqliteMiddleWare, { sqliteCmd } from "@/middleware/sqlite";
import { matStore } from "@/stores"; import { matStore } from "@/stores";
import { init } from "./util";
const NeosConfig = useConfig(); const NeosConfig = useConfig();
const localStore = proxy({ const localStore = proxy({
open: false,
hasStart: false, hasStart: false,
}); });
const ReplayModal: React.FC = () => { export const ReplayModal: React.FC = () => {
const { hasStart } = useSnapshot(localStore); const { open, hasStart } = useSnapshot(localStore);
const [replay, setReplay] = useState<null | ArrayBuffer>(null); const [replay, setReplay] = useState<null | ArrayBuffer>(null);
const [loading, setLoading] = useState(false);
const uploadProps: UploadProps = { const uploadProps: UploadProps = {
name: "replay", name: "replay",
onChange(info) { onChange(info) {
...@@ -35,9 +33,32 @@ const ReplayModal: React.FC = () => { ...@@ -35,9 +33,32 @@ const ReplayModal: React.FC = () => {
}; };
const navigate = useNavigate(); const navigate = useNavigate();
const onSubmit = async () => {
if (replay === null) {
message.error("请先上传录像文件");
} else {
setLoading(true);
// 标记为回放模式
matStore.isReplay = true;
// 初始化额外卡组
// FIXME: 这样写应该不对,有空来修
window.myExtraDeckCodes = [];
await init({
ip: "",
player: "",
passWd: "",
replay: true,
replayData: replay,
});
}
};
useEffect(() => { useEffect(() => {
if (hasStart) { if (hasStart) {
setLoading(false);
// 跳转 // 跳转
navigate(`/duel/neos/replay/${NeosConfig.replayUrl}`); navigate(`/duel/neos/replay/${NeosConfig.replayUrl}`);
} }
...@@ -46,55 +67,16 @@ const ReplayModal: React.FC = () => { ...@@ -46,55 +67,16 @@ const ReplayModal: React.FC = () => {
return ( return (
<Modal <Modal
title="选择回放" title="选择回放"
open={true} open={open}
maskClosable={false} maskClosable={false}
onOk={async () => { confirmLoading={loading}
if (replay === null) { centered
message.error("请先上传录像文件"); footer={
} else { <Button onClick={onSubmit} loading={loading}>
// 标记为回放模式 开始回放
matStore.isReplay = true; </Button>
}
// 初始化wasm onCancel={() => (localStore.open = false)}
const url =
import.meta.env.BASE_URL === "/"
? undefined
: new URL(
"rust_src_bg.wasm",
`${import.meta.env.BASE_URL}assets/`
);
await rustInit(url);
// 初始化额外卡组
// FIXME: 这样写应该不对,有空来修
window.myExtraDeckCodes = [];
// 初始化sqlite
await sqliteMiddleWare({
cmd: sqliteCmd.INIT,
initInfo: { dbUrl: NeosConfig.cardsDbUrl },
});
// 初始化文案
await initStrings();
// 连接回放websocket服务
socketMiddleWare({
cmd: socketCmd.CONNECT,
isReplay: true,
replayInfo: {
Url: NeosConfig.replayUrl,
data: replay,
},
});
}
}}
onCancel={() => {
// 断开websocket连接
socketMiddleWare({ cmd: socketCmd.DISCONNECT });
// 回到初始界面
navigate("/");
}}
> >
<Upload {...uploadProps}> <Upload {...uploadProps}>
<Button icon={<UploadOutlined />}>点击上传录像文件</Button> <Button icon={<UploadOutlined />}>点击上传录像文件</Button>
...@@ -103,8 +85,10 @@ const ReplayModal: React.FC = () => { ...@@ -103,8 +85,10 @@ const ReplayModal: React.FC = () => {
); );
}; };
export const replayOpen = () => {
localStore.open = true;
};
export const replayStart = () => { export const replayStart = () => {
localStore.hasStart = true; localStore.hasStart = true;
}; };
export default ReplayModal;
...@@ -7,7 +7,8 @@ import { accountStore, type User } from "@/stores"; ...@@ -7,7 +7,8 @@ import { accountStore, type User } from "@/stores";
import { Background, IconFont, Select } from "@/ui/Shared"; import { Background, IconFont, Select } from "@/ui/Shared";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
import { localStore, MatchModal } from "./Modal"; import { MatchModal, matchStore } from "./MatchModal";
import { ReplayModal, replayOpen } from "./ReplayModal";
export const loader: LoaderFunction = () => { export const loader: LoaderFunction = () => {
const sso = new URLSearchParams(location.search).get("sso"); const sso = new URLSearchParams(location.search).get("sso");
...@@ -72,12 +73,13 @@ export const Component: React.FC = () => { ...@@ -72,12 +73,13 @@ export const Component: React.FC = () => {
title="自定义房间" title="自定义房间"
desc="创建一个自定义的对战房间,便捷地与好友进行对战,甚至是举办一场竞技比赛。" desc="创建一个自定义的对战房间,便捷地与好友进行对战,甚至是举办一场竞技比赛。"
icon={<SettingFilled />} icon={<SettingFilled />}
onClick={() => (localStore.open = true)} onClick={() => (matchStore.open = true)}
/> />
<Mode <Mode
title="录像回放" title="录像回放"
desc="自由查看进行过的决斗,回味那些精彩的逆转瞬间。" desc="自由查看进行过的决斗,回味那些精彩的逆转瞬间。"
icon={<IconFont type="icon-record" size={24} />} icon={<IconFont type="icon-record" size={24} />}
onClick={replayOpen}
/> />
<Mode <Mode
title="卡组编辑" title="卡组编辑"
...@@ -88,6 +90,7 @@ export const Component: React.FC = () => { ...@@ -88,6 +90,7 @@ export const Component: React.FC = () => {
</div> </div>
</div> </div>
<MatchModal /> <MatchModal />
<ReplayModal />
</> </>
); );
}; };
......
...@@ -7,11 +7,13 @@ import sqliteMiddleWare, { sqliteCmd } from "@/middleware/sqlite"; ...@@ -7,11 +7,13 @@ import sqliteMiddleWare, { sqliteCmd } from "@/middleware/sqlite";
const NeosConfig = useConfig(); const NeosConfig = useConfig();
// 进行进入房间前的一些初始化操作 // 进行进入房间/回放前的一些初始化操作
export const init = async (params: { export const init = async (params: {
ip: string; ip: string;
player: string; player: string;
passWd: string; passWd: string;
replay?: boolean;
replayData?: ArrayBuffer;
}) => { }) => {
// 初始化wasm // 初始化wasm
const url = const url =
...@@ -29,9 +31,21 @@ export const init = async (params: { ...@@ -29,9 +31,21 @@ export const init = async (params: {
// 初始化I18N文案 // 初始化I18N文案
await initStrings(); await initStrings();
// 页面第一次渲染时,通过socket中间件向ygopro服务端请求建立长连接 if (params.replay && params.replayData) {
socketMiddleWare({ // 连接回放websocket服务
cmd: socketCmd.CONNECT, socketMiddleWare({
initInfo: params, cmd: socketCmd.CONNECT,
}); isReplay: true,
replayInfo: {
Url: NeosConfig.replayUrl,
data: params.replayData,
},
});
} else {
// 通过socket中间件向ygopro服务端请求建立长连接
socketMiddleWare({
cmd: socketCmd.CONNECT,
initInfo: params,
});
}
}; };
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