Commit 190e558d authored by timel's avatar timel

refactor: eventbus(register/call)

parent bb9cecc2
Pipeline #22032 passed with stages
in 18 minutes and 50 seconds
......@@ -16,12 +16,7 @@ import { EventEmitter } from "eventemitter3";
/* eslint no-var: 0 */
declare global {
var eventBus: EventEmitter;
var myExtraDeckCodes: number[];
enum Report {
Move = "move",
Chaining = "chaining",
}
interface Console {
color: (
color: string,
......
import { EventEmitter } from "eventemitter3";
import { v4 as v4uuid } from "uuid";
window.eventBus = new EventEmitter();
const eventEmitter = new EventEmitter();
enum Report {
export enum Task {
Move = "move",
Chaining = "chaining",
}
// @ts-ignore
window.Report = Report;
const getEnd = (task: Task) => `${task}-end`;
export {};
const register = (task: Task, fn: (...args: any[]) => Promise<any>) => {
eventEmitter.on(
task,
async ({ taskId, args }: { taskId: string; args: any[] }) => {
await fn(...args);
eventEmitter.emit(getEnd(task), taskId);
}
);
};
const call = (task: Task, ...args: any[]) =>
new Promise<void>((rs) => {
const taskId = v4uuid();
const cb = (respTaskId: string) => {
if (respTaskId === taskId) {
eventEmitter.removeListener(getEnd(task), cb);
rs();
}
};
eventEmitter.emit(task, { taskId, args });
eventEmitter.on(getEnd(task), cb);
});
export const eventbus = {
call,
register,
};
import { ygopro } from "@/api";
import { useConfig } from "@/config";
import { sleep } from "@/infra";
import { sleep, eventbus, Task } from "@/infra";
import { cardStore, fetchEsHintMeta, matStore } from "@/stores";
export default async (chaining: ygopro.StocGameMessage.MsgChaining) => {
......@@ -22,7 +22,7 @@ export default async (chaining: ygopro.StocGameMessage.MsgChaining) => {
const target = cardStore.find(location);
if (target) {
target.chainIndex = matStore.chains.length;
eventBus.emit(Report.Chaining, target.uuid);
await eventbus.call(Task.Chaining, target.uuid);
console.color("blue")(`${target.meta.text.name} chaining`);
} else {
console.warn(`<Chaining>target from ${location} is null`);
......
import { fetchCard, ygopro } from "@/api";
import { cardStore, fetchEsHintMeta } from "@/stores";
import { eventbus, Task } from "@/infra";
let cnt = 0;
export default async (draw: ygopro.StocGameMessage.MsgDraw) => {
fetchEsHintMeta({ originMsg: "玩家抽卡时" });
......@@ -22,8 +25,15 @@ export default async (draw: ygopro.StocGameMessage.MsgDraw) => {
card.sequence = Number(idx) + handsLength;
}
if (cnt++ < 2) {
// FIXME 暂时性的解决方案,头两回抽卡(双方各自初始手卡)先屏蔽掉
// 不然会出现一些问题...
return;
}
// 抽卡动画
cardStore
.at(ygopro.CardZone.HAND, draw.player)
.forEach((card) => eventBus.emit(Report.Move, card.uuid));
await Promise.all(
cardStore
.at(ygopro.CardZone.HAND, draw.player)
.map((card) => eventbus.call(Task.Move, card.uuid))
);
};
......@@ -60,7 +60,14 @@ const ActiveList = [
"select_yes_no",
];
let animation: Promise<unknown> = new Promise<void>((rs) => rs());
export default async function handleGameMsg(pb: ygopro.YgoStocMsg) {
animation = animation.then(() => _handleGameMsg(pb));
// _handleGameMsg(pb);
}
async function _handleGameMsg(pb: ygopro.YgoStocMsg) {
const msg = pb.stoc_game_msg;
if (ActiveList.includes(msg.gameMsg)) {
......
import { fetchCard, ygopro } from "@/api";
import { cardStore, CardType } from "@/stores";
type MsgMove = ygopro.StocGameMessage.MsgMove;
import { REASON_MATERIAL } from "../../common";
import { eventbus, Task } from "@/infra";
type MsgMove = ygopro.StocGameMessage.MsgMove;
const { HAND, GRAVE, REMOVED, DECK, EXTRA, MZONE, TZONE, OVERLAY } =
ygopro.CardZone;
......@@ -109,13 +111,17 @@ export default async (move: MsgMove) => {
target.position = to.position;
// 维护完了之后,开始动画
eventBus.emit(Report.Move, target.uuid);
const promises: Promise<unknown>[] = [];
promises.push(eventbus.call(Task.Move, target.uuid));
// 如果from或者to是手卡,那么需要刷新除了这张卡之外,这个玩家的所有手卡
if ([fromZone, toZone].includes(HAND)) {
cardStore.at(HAND, target.controller).forEach((card) => {
if (card.uuid !== target.uuid) eventBus.emit(Report.Move, card.uuid);
if (card.uuid !== target.uuid)
promises.push(eventbus.call(Task.Move, card.uuid));
});
}
await Promise.all(promises);
// TODO: 如果涉及了有超量素材的怪兽的移动,那么这个怪兽的移动应该也会带动超量素材的移动
// 注意,一个monster的overlayMaterials中的每一项都是一个cardType,
......
......@@ -18,6 +18,8 @@ import {
moveToOutside,
} from "./springs";
import { eventbus, Task } from "@/infra";
const NeosConfig = useConfig();
const { HAND, GRAVE, REMOVED, DECK, EXTRA, MZONE, SZONE, TZONE, OVERLAY } =
......@@ -67,25 +69,26 @@ export const Card: FC<{ idx: number }> = React.memo(({ idx }) => {
}, []);
const [highlight, setHighlight] = useState(false);
const [shadowOpacity, setShadowOpacity] = useState(0);
const [shadowOpacity, setShadowOpacity] = useState(0); // TODO 透明度
// >>> 动画 >>>
/** 动画序列的promise */
let animation: Promise<unknown> = new Promise<void>((rs) => rs());
let animationQueue: Promise<unknown> = new Promise<void>((rs) => rs());
const addToAnimation = (p: () => Promise<unknown>) => {
animation = animation.then(p);
};
const addToAnimation = (p: () => Promise<void>) =>
new Promise((rs) => {
animationQueue = animationQueue.then(p).then(rs);
});
eventBus.on(Report.Move, (uuid: string) => {
eventbus.register(Task.Move, async (uuid: string) => {
if (uuid === state.uuid) {
addToAnimation(() => move(state.zone));
await addToAnimation(() => move(state.zone));
}
});
eventBus.on(Report.Chaining, (uuid: string) => {
eventbus.register(Task.Chaining, async (uuid: string) => {
if (uuid === state.uuid) {
addToAnimation(() => chaining({ card: state, api }));
await addToAnimation(() => chaining({ card: state, api }));
}
});
// <<< 动画 <<<
......
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