Commit d7fab496 authored by timel's avatar timel

Merge branch 'refactor/forbidden' into 'main'

Refactor/forbidden

See merge request mycard/Neos!266
parents f28f8e94 ec305a4e
Pipeline #23151 passed with stages
in 11 minutes and 7 seconds
//! 禁限卡表
import { clear, createStore, get, setMany } from "idb-keyval";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import { initStore } from "@/stores";
const { lflistUrl } = useConfig(); const { lflistUrl } = useConfig();
type Forbiddens = Map<number, number>; class Forbidden {
private data: Map<number, number> = new Map<number, number>();
const IDB_NAME = "forbiddens"; public time: string = "?";
// 禁限卡表的时间,比如 [2023.4] - 2023年4月表
export let forbiddenTime = "?";
const idb = createStore(IDB_NAME, IDB_NAME);
export async function initForbiddens(): Promise<void> { public async init(): Promise<void> {
const text = await (await fetch(lflistUrl)).text(); const text = await (await fetch(lflistUrl)).text();
const { time, forbiddens } = extractForbiddensFromText(text); const { time, forbiddens } = this.extractForbiddensFromText(text);
forbiddenTime = time; this.time = time;
this.setForbiddens(forbiddens);
// 先清掉之前的记录 initStore.forbidden = true;
clear(idb); }
// 设置新记录
await setMany(Array.from(forbiddens));
}
// 获取禁限信息
export async function getForbiddenInfo(
id: number,
): Promise<number | undefined> {
return await get(id, idb);
}
// 解析函数,提取卡片编号和限制张数 public set(cardId: number, limitCount: number): void {
function parseCardInfo( this.data.set(cardId, limitCount);
input: string,
): { cardId: number; limitCount: number } | null {
const match = input.match(/^(\d+)\s+(\d+)\s+--/);
if (match) {
const cardId = parseInt(match[1]);
const limitCount = parseInt(match[2]);
return { cardId, limitCount };
} }
return null;
}
// 分割文本为行,并提取每行的限制信息 public get(id: number): number | undefined {
function extractForbiddensFromText(text: string): { return this.data.get(id);
time: string; }
forbiddens: Forbiddens;
} {
const lines = text.split("\n");
const forbiddens = new Map<number, number>([]);
// remove first line private setForbiddens(forbiddens: Map<number, number>): void {
lines.shift(); this.data.clear();
for (const [cardId, limitCount] of forbiddens) {
this.data.set(cardId, limitCount);
}
}
let time = "?"; private extractForbiddensFromText(text: string): {
time: string;
forbiddens: Map<number, number>;
} {
// 解析文本行中的卡片信息
function parseCardInfo(
input: string,
): { cardId: number; limitCount: number } | null {
const match = input.match(/^(\d+)\s+(\d+)\s+--/);
if (match) {
const cardId = parseInt(match[1]);
const limitCount = parseInt(match[2]);
return { cardId, limitCount };
}
return null;
}
for (const line of lines) { const lines = text.split("\n");
if (line.startsWith("#")) { const forbiddens = new Map<number, number>();
// do nothing let time = "?";
} else if (line.startsWith("!")) {
if (time !== "?") { // 移除第一行标题
// 已经读取完第一个禁限表的信息了,退出循环 lines.shift();
break;
for (const line of lines) {
if (line.startsWith("#")) {
// 忽略注释行
} else if (line.startsWith("!")) {
// 如果时间已经设置,退出循环
if (time !== "?") {
break;
} else {
// 提取时间信息
time = line.substring(1).trim();
}
} else { } else {
time = line.substring(1).trim(); const cardInfo = parseCardInfo(line);
} if (cardInfo) {
} else { // 将卡片信息添加到禁限表
const cardInfo = parseCardInfo(line); forbiddens.set(cardInfo.cardId, cardInfo.limitCount);
if (cardInfo) { }
forbiddens.set(cardInfo.cardId, cardInfo.limitCount);
} }
} }
}
return { time, forbiddens }; // 返回时间和禁限表
return { time, forbiddens };
}
} }
export const forbidden = new Forbidden();
...@@ -5,10 +5,11 @@ import { type NeosStore } from "./shared"; ...@@ -5,10 +5,11 @@ import { type NeosStore } from "./shared";
export const initStore = proxy({ export const initStore = proxy({
sqlite: { sqlite: {
progress: 0, // 0 -> 1 progress: 0, // 0 -> 1
}, }, // ygodb
decks: false, decks: false,
i18n: false, i18n: false,
wasm: false, wasm: false,
forbidden: false, // 禁卡表
// ... // ...
reset() {}, reset() {},
} satisfies NeosStore); } satisfies NeosStore);
...@@ -8,9 +8,9 @@ import { ...@@ -8,9 +8,9 @@ import {
extraCardTypes, extraCardTypes,
isLinkMonster, isLinkMonster,
isMonster, isMonster,
isPendulumMonster,
Race2StringCodeMap, Race2StringCodeMap,
Type2StringCodeMap, Type2StringCodeMap,
isPendulumMonster,
} from "@/common"; } from "@/common";
import { CardEffectText, IconFont, ScrollableArea, YgoCard } from "@/ui/Shared"; import { CardEffectText, IconFont, ScrollableArea, YgoCard } from "@/ui/Shared";
......
...@@ -26,7 +26,7 @@ import { LoaderFunction } from "react-router-dom"; ...@@ -26,7 +26,7 @@ import { LoaderFunction } from "react-router-dom";
import { proxy, useSnapshot } from "valtio"; import { proxy, useSnapshot } from "valtio";
import { subscribeKey } from "valtio/utils"; import { subscribeKey } from "valtio/utils";
import { type CardMeta, initForbiddens, searchCards } from "@/api"; import { type CardMeta, searchCards } from "@/api";
import { isToken } from "@/common"; import { isToken } from "@/common";
import { FtsConditions } from "@/middleware/sqlite/fts"; import { FtsConditions } from "@/middleware/sqlite/fts";
import { deckStore, type IDeck, initStore } from "@/stores"; import { deckStore, type IDeck, initStore } from "@/stores";
...@@ -59,8 +59,13 @@ export const loader: LoaderFunction = async () => { ...@@ -59,8 +59,13 @@ export const loader: LoaderFunction = async () => {
}); });
} }
// 更新禁限卡表 // 同时,等待禁卡表的加载
await initForbiddens(); if (!initStore.forbidden) {
await new Promise<void>((rs) => {
subscribeKey(initStore, "forbidden", (done) => done && rs());
});
}
return null; return null;
}; };
......
...@@ -9,6 +9,7 @@ import { ...@@ -9,6 +9,7 @@ import {
} from "react-router-dom"; } from "react-router-dom";
import { useSnapshot } from "valtio"; import { useSnapshot } from "valtio";
import { forbidden } from "@/api";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import { accountStore } from "@/stores"; import { accountStore } from "@/stores";
...@@ -28,6 +29,7 @@ export const loader: LoaderFunction = async () => { ...@@ -28,6 +29,7 @@ export const loader: LoaderFunction = async () => {
initDeck(); initDeck();
initSqlite(); initSqlite();
initWASM(); initWASM();
forbidden.init();
return null; return null;
}; };
......
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