Commit c74ffee8 authored by timel's avatar timel

refactor: valtio

parent 33e986dd
......@@ -66,9 +66,6 @@ export async function fetchCard(
return res.data;
}
// 挂到全局 以便 debug
window.fetchCard = fetchCard;
export function getCardStr(meta: CardMeta, idx: number): string | undefined {
switch (idx) {
case 0: {
......
......@@ -2,7 +2,6 @@ import { ygopro } from "@/api/ocgcore/idl/ocgcore";
import { fetchHandsMeta } from "@/reducers/duel/handsSlice";
import { fetchEsHintMeta } from "@/reducers/duel/hintSlice";
import { AppDispatch } from "@/store";
import { valtioStore } from "@/valtioStores";
export default (
......@@ -12,7 +11,7 @@ export default (
dispatch(fetchEsHintMeta({ originMsg: "玩家抽卡时" }));
dispatch(fetchHandsMeta({ controler: draw.player, codes: draw.cards }));
const playMat = valtioStore.duelStore.playMat;
const matStore = valtioStore.matStore;
playMat.hands.add(draw.player, draw.cards);
matStore.hands.add(draw.player, draw.cards);
};
......@@ -19,12 +19,11 @@ import {
fetchOverlayMeta,
} from "@/reducers/duel/monstersSlice";
import { AppDispatch } from "@/store";
import { valtioStore } from "@/valtioStores";
import { REASON_MATERIAL } from "../../common";
const { playMat: playMatStore } = valtioStore.duelStore;
const matStore = valtioStore.matStore;
const OVERLAY_STACK: { code: number; sequence: number }[] = [];
......@@ -37,7 +36,7 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
switch (from.location) {
case ygopro.CardZone.HAND: {
dispatch(removeHand([from.controler, from.sequence]));
playMatStore.hands.remove(from.controler, from.sequence);
matStore.hands.remove(from.controler, from.sequence);
break;
}
case ygopro.CardZone.MZONE: {
......@@ -58,7 +57,7 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
dispatch(
removeGraveyard({ controler: from.controler, sequence: from.sequence })
);
playMatStore.graveyards.remove(from.controler, from.sequence);
matStore.graveyards.remove(from.controler, from.sequence);
break;
}
......@@ -69,7 +68,7 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
sequence: from.sequence,
})
);
playMatStore.banishedZones.remove(from.controler, from.sequence);
matStore.banishedZones.remove(from.controler, from.sequence);
break;
}
......@@ -77,7 +76,7 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
dispatch(
removeExtraDeck({ controler: from.controler, sequence: from.sequence })
);
playMatStore.extraDecks.remove(from.controler, from.sequence);
matStore.extraDecks.remove(from.controler, from.sequence);
break;
}
......@@ -151,7 +150,7 @@ export default (move: MsgMove, dispatch: AppDispatch) => {
dispatch(
insertHandMeta({ controler: to.controler, sequence: to.sequence, code })
);
playMatStore.hands.insert(to.controler, to.sequence, code);
matStore.hands.insert(to.controler, to.sequence, code);
break;
}
......
......@@ -10,10 +10,9 @@ import {
setSelfType,
} from "@/reducers/duel/mod";
import { AppDispatch } from "@/store";
import { valtioStore } from "@/valtioStores";
const playMatStore = valtioStore.duelStore.playMat;
const matStore = valtioStore.matStore;
export default (
start: ygopro.StocGameMessage.MsgStart,
......@@ -21,13 +20,14 @@ export default (
) => {
dispatch(setSelfType(start.playerType));
playMatStore.selfType = start.playerType;
playMatStore.initInfo.set(0, {
matStore.selfType = start.playerType;
matStore.initInfo.set(0, {
life: start.life1,
deckSize: start.deckSize1,
extraSize: start.extraSize1,
});
playMatStore.initInfo.set(1, {
matStore.initInfo.set(1, {
life: start.life2,
deckSize: start.deckSize2,
extraSize: start.extraSize2,
......@@ -59,8 +59,13 @@ export default (
dispatch(initMagics(1));
dispatch(initGraveyard(0));
dispatch(initGraveyard(1));
dispatch(initDeck({ player: 0, deskSize: start.deckSize1 }));
dispatch(initDeck({ player: 1, deskSize: start.deckSize2 }));
matStore.decks.add(0, Array(start.deckSize1).fill(0));
matStore.decks.add(1, Array(start.deckSize2).fill(0));
dispatch(initBanishedZone(0));
dispatch(initBanishedZone(1));
dispatch(initHint());
......
import { proxy } from "valtio";
import { playMat } from "./playMat";
import { modal } from "./modal";
export const duelStore = proxy({
playMat,
modal,
});
import { proxy } from "valtio";
import type { ModalState } from "./types";
export const modal = proxy<ModalState>({
cardModal: { isOpen: false, interactivies: [], counters: {} },
cardListModal: { isOpen: false, list: [] },
checkCardModal: { isOpen: false, cancelAble: false, tags: [] },
yesNoModal: { isOpen: false },
positionModal: { isOpen: false, positions: [] },
optionModal: { isOpen: false, options: [] },
checkCardModalV2: {
isOpen: false,
cancelAble: false,
finishAble: false,
responseable: false,
selectableOptions: [],
selectedOptions: [],
},
checkCardModalV3: {
isOpen: false,
overflow: false,
allLevel: 0,
mustSelectList: [],
selectAbleList: [],
},
checkCounterModal: {
isOpen: false,
options: [],
},
sortCardModal: {
isOpen: false,
options: [],
},
});
import { ygopro } from "@/api/ocgcore/idl/ocgcore";
/**
* 生成一个指定长度的卡片数组
*/
function genBlock(location: ygopro.CardZone, n: number = 5) {
return {
me: Array(n)
.fill(null)
.map((_) => ({
location: {
location,
},
idleInteractivities: [],
counters: {},
})),
op: Array(n)
.fill(null)
.map((_) => ({
location: {
location,
},
idleInteractivities: [],
counters: {},
})),
};
}
......@@ -2,7 +2,8 @@ export * from "./chatStore";
export * from "./joinStore";
export * from "./moraStore";
export * from "./playerStore";
export * from "./duelStore";
export * from "./matStore";
export * from "./messageStore";
import { createContext, type ReactNode, useRef } from "react";
import { proxy } from "valtio";
......@@ -12,14 +13,16 @@ import { chatStore } from "./chatStore";
import { joinStore } from "./joinStore";
import { moraStore } from "./moraStore";
import { playerStore } from "./playerStore";
import { duelStore } from "./duelStore";
import { matStore } from "./matStore";
import { messageStore } from "./messageStore";
export const valtioStore = proxy({
playerStore,
chatStore,
joinStore,
moraStore,
duelStore,
matStore, // 决斗盘
messageStore, // 决斗的信息,包括模态框
});
devtools(valtioStore, { name: "valtio store", enabled: true });
......
import { proxy } from "valtio";
import { ygopro } from "@/api/ocgcore/idl/ocgcore";
import { fetchCard } from "@/api/cards";
import { ygopro } from "@/api/ocgcore/idl/ocgcore";
import type {
PlayMatState,
DuelFieldState,
CardsBothSide,
BothSide,
CardsBothSide,
DuelFieldState,
InitInfo,
PlayMatState,
} from "./types";
/**
* 生成一个指定长度的卡片数组
*/
function genBlock(location: ygopro.CardZone, n: number = 5) {
const genBlock = (
location: ygopro.CardZone,
n: number = 5
): BothSide<DuelFieldState> => {
return {
me: Array(n)
.fill(null)
......@@ -34,7 +38,7 @@ function genBlock(location: ygopro.CardZone, n: number = 5) {
counters: {},
})),
};
}
};
const initInfo: PlayMatState["initInfo"] = proxy({
me: {
......@@ -59,7 +63,8 @@ const initInfo: PlayMatState["initInfo"] = proxy({
/**
* 在决斗盘仓库之中,
* 给 `{me: [...], op: [...]}` 这种类型的对象添加一些方法
* 给 `{me: [...], op: [...]}` 这种类型的对象添加一些方法。
* 具体的方法可以看`CardsBothSide`的类型定义
*/
const wrap = <T extends DuelFieldState>(
entity: BothSide<T>,
......@@ -121,7 +126,7 @@ const wrap = <T extends DuelFieldState>(
* 💡 决斗盘状态仓库,本文件核心,
* 具体介绍可以点进`PlayMatState`去看
*/
export const playMat = proxy<PlayMatState>({
export const matStore = proxy<PlayMatState>({
magics: wrap(genBlock(ygopro.CardZone.SZONE), ygopro.CardZone.SZONE),
monsters: wrap(genBlock(ygopro.CardZone.MZONE), ygopro.CardZone.MZONE),
graveyards: wrap({ me: [], op: [] }, ygopro.CardZone.GRAVE),
......@@ -156,9 +161,10 @@ export const playMat = proxy<PlayMatState>({
/**
* 根据controller判断是自己还是对方
* 不要往外export,尽量逻辑收拢在store内部
*/
const getWhom = (controller: number) =>
judgeSelf(controller, playMat.selfType) ? "me" : "op";
judgeSelf(controller, matStore.selfType) ? "me" : "op";
export function judgeSelf(player: number, selfType: number): boolean {
switch (selfType) {
......
......@@ -3,10 +3,10 @@ import type { ygopro } from "@/api/ocgcore/idl/ocgcore";
// >>> play mat state >>>
export type BothSide<T> = {
export interface BothSide<T> {
me: T;
op: T;
};
}
export interface CardsBothSide<T extends DuelFieldState> extends BothSide<T> {
remove: (player: number, sequence: number) => void; // 移除特定位置的卡片
......@@ -76,7 +76,6 @@ export interface CardState {
controler?: number; // 控制这个位置的玩家,0或1
location: ygopro.CardZone; // 怪兽区/魔法陷阱区/手牌/卡组/墓地/除外区
position?: ygopro.CardPosition; // 卡片的姿势:攻击还是守备
overlay_sequence?: number;
}; // 位置信息,叫location的原因是为了和ygo对齐
idleInteractivities: Interactivity<number>[]; // IDLE状态下的互动信息
placeInteractivities?: Interactivity<{
......@@ -146,119 +145,3 @@ export interface PhaseState {
enableEp: boolean; // 允许回合结束
}
// <<< play mat state <<<
// >>> modal types >>>
type CardLocation = ReturnType<typeof ygopro.CardLocation.prototype.toObject>;
export interface ModalState {
// 卡牌弹窗
cardModal: {
isOpen: boolean;
meta?: CardMeta;
interactivies: { desc: string; response: number }[];
counters: { [type: number]: number };
};
// 卡牌列表弹窗
cardListModal: {
isOpen: boolean;
list: {
meta?: CardMeta;
interactivies: { desc: string; response: number }[];
}[];
};
// 卡牌选择弹窗
checkCardModal: {
isOpen: boolean;
onSubmit?: string;
selectMin?: number;
selectMax?: number;
cancelAble: boolean;
cancelResponse?: number;
tags: {
tagName: string;
options: {
meta: CardMeta;
location?: CardLocation;
effectDescCode?: number;
effectDesc?: string;
response: number;
}[];
}[];
};
// Yes or No弹窗
yesNoModal: {
isOpen: boolean;
msg?: string;
};
// 表示形式选择弹窗
positionModal: {
isOpen: boolean;
positions: ygopro.CardPosition[];
};
// 选项选择弹窗
optionModal: {
isOpen: boolean;
options: { msg: string; response: number }[];
};
// 卡牌选择弹窗V2
checkCardModalV2: {
isOpen: boolean;
cancelAble: boolean;
finishAble: boolean;
selectMin?: number;
selectMax?: number;
responseable?: boolean;
selectableOptions: {
code: number;
name?: string;
desc?: string;
response: number;
}[];
selectedOptions: {
code: number;
name?: string;
desc?: string;
response: number;
}[];
};
// 卡牌选择弹窗V3
checkCardModalV3: {
isOpen: boolean;
overflow: boolean;
allLevel: number;
selectMin?: number;
selectMax?: number;
responseable?: boolean;
mustSelectList: {
meta: CardMeta;
level1: number;
level2: number;
response: number;
}[];
selectAbleList: {
meta: CardMeta;
level1: number;
level2: number;
response: number;
}[];
};
// 指示器选择弹窗
checkCounterModal: {
isOpen: boolean;
counterType?: number;
min?: number;
options: {
code: number;
max: number;
}[];
};
// 卡牌排序弹窗
sortCardModal: {
isOpen: boolean;
options: {
meta: CardMeta;
response: number;
}[];
};
}
// <<< modal types <<<
import type { CardMeta } from "@/api/cards";
import { ygopro } from "@/api/ocgcore/idl/ocgcore";
import { proxy } from "valtio";
export const messageStore = proxy<ModalState>({
cardModal: { isOpen: false, interactivies: [], counters: {} },
cardListModal: { isOpen: false, list: [] },
checkCardModal: { isOpen: false, cancelAble: false, tags: [] },
yesNoModal: { isOpen: false },
positionModal: { isOpen: false, positions: [] },
optionModal: { isOpen: false, options: [] },
checkCardModalV2: {
isOpen: false,
cancelAble: false,
finishAble: false,
responseable: false,
selectableOptions: [],
selectedOptions: [],
},
checkCardModalV3: {
isOpen: false,
overflow: false,
allLevel: 0,
mustSelectList: [],
selectAbleList: [],
},
checkCounterModal: {
isOpen: false,
options: [],
},
sortCardModal: {
isOpen: false,
options: [],
},
});
// >>> modal types >>>
type CardLocation = ReturnType<typeof ygopro.CardLocation.prototype.toObject>;
export interface ModalState {
// 卡牌弹窗
cardModal: {
isOpen: boolean;
meta?: CardMeta;
interactivies: { desc: string; response: number }[];
counters: { [type: number]: number };
};
// 卡牌列表弹窗
cardListModal: {
isOpen: boolean;
list: {
meta?: CardMeta;
interactivies: { desc: string; response: number }[];
}[];
};
// 卡牌选择弹窗
checkCardModal: {
isOpen: boolean;
onSubmit?: string;
selectMin?: number;
selectMax?: number;
cancelAble: boolean;
cancelResponse?: number;
tags: {
tagName: string;
options: {
meta: CardMeta;
location?: CardLocation;
effectDescCode?: number;
effectDesc?: string;
response: number;
}[];
}[];
};
// Yes or No弹窗
yesNoModal: {
isOpen: boolean;
msg?: string;
};
// 表示形式选择弹窗
positionModal: {
isOpen: boolean;
positions: ygopro.CardPosition[];
};
// 选项选择弹窗
optionModal: {
isOpen: boolean;
options: { msg: string; response: number }[];
};
// 卡牌选择弹窗V2
checkCardModalV2: {
isOpen: boolean;
cancelAble: boolean;
finishAble: boolean;
selectMin?: number;
selectMax?: number;
responseable?: boolean;
selectableOptions: {
code: number;
name?: string;
desc?: string;
response: number;
}[];
selectedOptions: {
code: number;
name?: string;
desc?: string;
response: number;
}[];
};
// 卡牌选择弹窗V3
checkCardModalV3: {
isOpen: boolean;
overflow: boolean;
allLevel: number;
selectMin?: number;
selectMax?: number;
responseable?: boolean;
mustSelectList: {
meta: CardMeta;
level1: number;
level2: number;
response: number;
}[];
selectAbleList: {
meta: CardMeta;
level1: number;
level2: number;
response: number;
}[];
};
// 指示器选择弹窗
checkCounterModal: {
isOpen: boolean;
counterType?: number;
min?: number;
options: {
code: number;
max: number;
}[];
};
// 卡牌排序弹窗
sortCardModal: {
isOpen: boolean;
options: {
meta: CardMeta;
response: number;
}[];
};
}
// <<< modal types <<<
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