Commit c74ffee8 authored by timel's avatar timel

refactor: valtio

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