UPDATE: Add Worker, pending map to fix bug missing data
All checks were successful
Gitea Auto Deploy / Deploy-Container (push) Successful in 59s
All checks were successful
Gitea Auto Deploy / Deploy-Container (push) Successful in 59s
This commit is contained in:
@@ -47,7 +47,7 @@ export default function Home() {
|
||||
}, [expandedCharts]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col px-2 h-full w-full mt-5 min-h-[74vh] bg-base-100 font-[family-name:var(--font-geist-sans)]">
|
||||
<div className="flex flex-col px-2 h-full w-full mt-5 min-h-[74vh] bg-base-100 font-(family-name:--font-geist-sans)">
|
||||
<div className="h-full ">
|
||||
<div className="grid grid-cols-12 gap-2 lg:gap-3 h-full min-h-full">
|
||||
<div className="col-span-12 md:col-span-3 lg:col-span-2 xl:col-span-2 h-full">
|
||||
@@ -76,7 +76,7 @@ export default function Home() {
|
||||
</div>
|
||||
{enemyDetail && <EnemyBar />}
|
||||
|
||||
<div className="rounded-lg p-2 shadow-md flex-grow">
|
||||
<div className="rounded-lg p-2 shadow-md grow">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
|
||||
<div
|
||||
|
||||
@@ -71,7 +71,7 @@ export default function ActionBar() {
|
||||
return (
|
||||
<div className="p-4 md:p-1 rounded-lg shadow-lg w-full h-full">
|
||||
<motion.h2
|
||||
className="text-center text-xl lg:text-2xl mb-2 font-bold text-transparent bg-clip-text bg-gradient-to-r from-pink-500 via-purple-500 to-cyan-500"
|
||||
className="text-center text-xl lg:text-2xl mb-2 font-bold text-transparent bg-clip-text bg-linear-to-r from-pink-500 via-purple-500 to-cyan-500"
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
@@ -171,7 +171,7 @@ export default function ActionBar() {
|
||||
</div>
|
||||
|
||||
<div className="border-b border-purple-500/30 px-6 py-4 mb-4">
|
||||
<h3 className="font-bold text-2xl text-transparent bg-clip-text bg-gradient-to-r from-pink-400 to-cyan-400">
|
||||
<h3 className="font-bold text-2xl text-transparent bg-clip-text bg-linear-to-r from-pink-400 to-cyan-400">
|
||||
{transI18n("turnDetail").toUpperCase()}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
@@ -19,9 +19,9 @@ export default function CharacterCard({ data }: CharacterCardProps) {
|
||||
const { avatarDetail } = useBattleDataStore()
|
||||
|
||||
return (
|
||||
<li className="z-10 flex flex-col w-28 items-center p-1 rounded-md shadow-lg bg-gradient-to-b from-customStart to-customEnd transform transition-transform duration-300 hover:scale-105 m-1">
|
||||
<li className="z-10 flex flex-col w-28 items-center p-1 rounded-md shadow-lg bg-linear-to-b from-customStart to-customEnd transform transition-transform duration-300 hover:scale-105 m-1">
|
||||
<div
|
||||
className={`w-[80px] rounded-md p-[2px] bg-gradient-to-br ${data.rank === "CombatPowerAvatarRarityType5"
|
||||
className={`w-20 rounded-md p-0.5 bg-linear-to-br ${data.rank === "CombatPowerAvatarRarityType5"
|
||||
? "from-yellow-400 via-yellow-300 to-yellow-500"
|
||||
: "from-purple-300 via-purple-200 to-purple-400"
|
||||
}`}
|
||||
|
||||
@@ -18,7 +18,7 @@ export default function EnemyBar() {
|
||||
<div className="flex gap-3 overflow-x-auto pb-2">
|
||||
{enemyDetail && Object.values(enemyDetail).filter((enemy) => (enemy.stats?.AV > 0
|
||||
&& enemy.stats.HP <= enemy.maxHP)).map((enemy, uid) => (
|
||||
<div key={uid} className="bg-base-200 rounded-lg p-3 border border-gray-700 w-52 flex-shrink-0">
|
||||
<div key={uid} className="bg-base-200 rounded-lg p-3 border border-gray-700 w-52 shrink-0">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
{listEnemy.find((monster) => monster.child.includes(enemy.id))?.icon?.split("/")?.pop()?.replace(".png", "") && (
|
||||
|
||||
@@ -86,7 +86,7 @@ export default function Header() {
|
||||
return () => {
|
||||
disconnectSocket()
|
||||
};
|
||||
}, [setStatus]);
|
||||
}, []);
|
||||
|
||||
const handleConnect = () => {
|
||||
if (!host || !port) {
|
||||
@@ -217,7 +217,7 @@ export default function Header() {
|
||||
<div className="flex flex-col justify-center items-start">
|
||||
<h1 className="text-xl font-bold">
|
||||
<span className="text-emerald-500">Firefly Analy</span>
|
||||
<span className="bg-clip-text text-transparent bg-gradient-to-r from-emerald-400 via-orange-500 to-red-500">
|
||||
<span className="bg-clip-text text-transparent bg-linear-to-r from-emerald-400 via-orange-500 to-red-500">
|
||||
sis
|
||||
</span>
|
||||
</h1>
|
||||
@@ -227,7 +227,7 @@ export default function Header() {
|
||||
</a>
|
||||
{version && (
|
||||
<div className="px-2">
|
||||
<div className="inline-flex items-center space-x-2 px-3 py-1.5 bg-gradient-to-r from-blue-500 to-purple-600 rounded-full shadow-md hover:shadow-lg transition-all duration-200">
|
||||
<div className="inline-flex items-center space-x-2 px-3 py-1.5 bg-linear-to-r from-blue-500 to-purple-600 rounded-full shadow-md hover:shadow-lg transition-all duration-200">
|
||||
<div className="w-1.5 h-1.5 bg-white rounded-full animate-pulse"></div>
|
||||
<div className="text-xs font-semibold text-white">
|
||||
{version}
|
||||
@@ -380,7 +380,7 @@ export default function Header() {
|
||||
|
||||
{/* GitHub Link */}
|
||||
<Link
|
||||
className='hidden sm:flex btn btn-ghost btn-sm btn-circle bg-white/20 hover:bg-white/100 transition-all duration-200 items-center justify-center'
|
||||
className='hidden sm:flex btn btn-ghost btn-sm btn-circle bg-white/20 hover:bg-white transition-all duration-200 items-center justify-center'
|
||||
href={"https://github.com/AzenKain/SR-Analysis"}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
@@ -405,7 +405,7 @@ export default function Header() {
|
||||
</div>
|
||||
|
||||
<div className="border-b border-purple-500/30 px-6 py-4 mb-4">
|
||||
<h3 className="font-bold text-2xl text-transparent bg-clip-text bg-gradient-to-r from-pink-400 to-cyan-400">
|
||||
<h3 className="font-bold text-2xl text-transparent bg-clip-text bg-linear-to-r from-pink-400 to-cyan-400">
|
||||
{transI18n("socketConnection").toUpperCase()}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
@@ -67,7 +67,7 @@ export default function LineupBar() {
|
||||
return (
|
||||
<div className="p-4 md:p-1 rounded-lg shadow-lg w-full h-full">
|
||||
<motion.h2
|
||||
className="text-center text-xl lg:text-2xl pb-2 font-bold text-transparent bg-clip-text bg-gradient-to-r from-pink-500 via-purple-500 to-cyan-500"
|
||||
className="text-center text-xl lg:text-2xl pb-2 font-bold text-transparent bg-clip-text bg-linear-to-r from-pink-500 via-purple-500 to-cyan-500"
|
||||
initial={{ opacity: 0, y: -20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
@@ -115,7 +115,7 @@ export default function LineupBar() {
|
||||
transition={{ duration: 0.3, delay: index * 0.1 }}
|
||||
whileHover={{ scale: 1.05 }}
|
||||
onClick={() => handleShow("character_detail_modal", item)}
|
||||
className={`cursor-pointer flex-shrink-0 justify-items-center ${isLastTurn ? "shadow-[inset_0_0_10px_2px_rgba(59,130,246,0.7),_0_0_20px_5px_rgba(59,130,246,0.3)]" : ""
|
||||
className={`cursor-pointer shrink-0 justify-items-center ${isLastTurn ? "shadow-[inset_0_0_10px_2px_rgba(59,130,246,0.7),0_0_20px_5px_rgba(59,130,246,0.3)]" : ""
|
||||
}`}
|
||||
>
|
||||
<CharacterCard data={item} />
|
||||
@@ -129,7 +129,7 @@ export default function LineupBar() {
|
||||
|
||||
{/* Character Detail Modal */}
|
||||
<dialog id="character_detail_modal" className="modal backdrop-blur-sm">
|
||||
<div className="modal-box w-11/12 max-w-7xl bg-gradient-to-b bg-base-100 text-base-content border-purple-500 shadow-lg shadow-purple-500/20">
|
||||
<div className="modal-box w-11/12 max-w-7xl bg-linear-to-b bg-base-100 text-base-content border-purple-500 shadow-lg shadow-purple-500/20">
|
||||
<div className="sticky top-0 z-10">
|
||||
<motion.button
|
||||
whileHover={{ scale: 1.1, rotate: 90 }}
|
||||
@@ -146,7 +146,7 @@ export default function LineupBar() {
|
||||
<NameAvatar
|
||||
locale={locale}
|
||||
text={getNameChar(locale, selectedCharacter).toUpperCase()}
|
||||
className={"font-bold text-2xl text-transparent bg-clip-text bg-gradient-to-r from-pink-400 to-cyan-400"}
|
||||
className={"font-bold text-2xl text-transparent bg-clip-text bg-linear-to-r from-pink-400 to-cyan-400"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
4
src/global.d.ts
vendored
Normal file
4
src/global.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
declare module '*.css' {
|
||||
const content: { [className: string]: string };
|
||||
export default content;
|
||||
}
|
||||
@@ -1,59 +1,149 @@
|
||||
// File: socket-client.ts
|
||||
|
||||
import { io, Socket } from "socket.io-client";
|
||||
import useSocketStore from "@/stores/socketSettingStore";
|
||||
import { toast } from 'react-toastify';
|
||||
import { toast } from "react-toastify";
|
||||
import useBattleDataStore from "@/stores/battleDataStore";
|
||||
import { BattleBeginType } from "@/types";
|
||||
import type {
|
||||
AvatarAnalysisJson,
|
||||
BattleBeginType,
|
||||
BattleEndType,
|
||||
DamageType,
|
||||
EntityDefeatedType,
|
||||
InitializeEnemyType,
|
||||
SetBattleLineupType,
|
||||
StatChangeType,
|
||||
TurnBeginType,
|
||||
TurnEndType,
|
||||
UpdateCycleType,
|
||||
UpdateTeamFormationType,
|
||||
UpdateWaveType,
|
||||
UseSkillType,
|
||||
VersionType,
|
||||
} from "@/types";
|
||||
|
||||
let socket: Socket | null = null;
|
||||
|
||||
|
||||
const notify = (msg: string, type: 'info' | 'success' | 'error' = 'info') => {
|
||||
if (type === 'success') toast.success(msg);
|
||||
else if (type === 'error') toast.error(msg);
|
||||
const notify = (msg: string, type: "info" | "success" | "error" = "info") => {
|
||||
if (type === "success") toast.success(msg);
|
||||
else if (type === "error") toast.error(msg);
|
||||
else toast.info(msg);
|
||||
};
|
||||
|
||||
function safeParse(json: unknown | string) {
|
||||
try {
|
||||
return typeof json === "string" ? JSON.parse(json) : json;
|
||||
} catch (e) {
|
||||
console.error("JSON parse error:", e, json);
|
||||
return null;
|
||||
}
|
||||
interface SocketEvents {
|
||||
Connected: VersionType;
|
||||
OnBattleBegin: BattleBeginType;
|
||||
OnSetBattleLineup: SetBattleLineupType;
|
||||
OnDamage: DamageType;
|
||||
OnTurnBegin: TurnBeginType;
|
||||
OnTurnEnd: TurnEndType;
|
||||
OnEntityDefeated: EntityDefeatedType;
|
||||
OnUseSkill: UseSkillType;
|
||||
OnUpdateWave: UpdateWaveType;
|
||||
OnUpdateCycle: UpdateCycleType;
|
||||
OnStatChange: StatChangeType;
|
||||
OnUpdateTeamFormation: UpdateTeamFormationType;
|
||||
OnInitializeEnemy: InitializeEnemyType;
|
||||
OnBattleEnd: BattleEndType;
|
||||
OnCreateBattle: AvatarAnalysisJson[];
|
||||
Error: string;
|
||||
}
|
||||
|
||||
type ListenerMap = {
|
||||
[K in keyof SocketEvents]: (payload: SocketEvents[K]) => void;
|
||||
};
|
||||
|
||||
export const connectSocket = (): Socket => {
|
||||
let listeners: ListenerMap | null = null;
|
||||
|
||||
let workerPool: Worker[] | null = null;
|
||||
let nextWorker = 0;
|
||||
let reqId = 1;
|
||||
const pendingMap = new Map<number, (res: { parsed: unknown | null; err?: string }) => void>();
|
||||
|
||||
const createWorkerPool = (size = Math.max(1, (navigator.hardwareConcurrency || 4) - 1)) => {
|
||||
if (workerPool) return workerPool;
|
||||
const code = `self.onmessage = function(e) { try { const { id, raw } = e.data; const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw; self.postMessage({ id, parsed }); } catch (err) { self.postMessage({ id, err: err && err.message ? err.message : String(err) }); } }`;
|
||||
const blob = new Blob([code], { type: 'application/javascript' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
workerPool = Array.from({ length: size }).map(() => new Worker(url));
|
||||
workerPool.forEach((w) => {
|
||||
w.onmessage = (ev) => {
|
||||
const { id, parsed, err } = ev.data as { id: number; parsed: unknown; err?: string };
|
||||
const cb = pendingMap.get(id);
|
||||
if (cb) {
|
||||
cb({ parsed: parsed ?? null, err });
|
||||
pendingMap.delete(id);
|
||||
}
|
||||
};
|
||||
w.onerror = (ev) => {
|
||||
console.error('worker error', ev.message);
|
||||
};
|
||||
});
|
||||
return workerPool;
|
||||
};
|
||||
|
||||
const parseWithWorker = (raw: unknown): Promise<{ parsed: unknown | null; err?: string }> => {
|
||||
if (!workerPool) createWorkerPool();
|
||||
if (!workerPool) return Promise.resolve({ parsed: null, err: 'no worker' });
|
||||
const id = reqId++;
|
||||
return new Promise((resolve) => {
|
||||
pendingMap.set(id, resolve);
|
||||
const w = workerPool![nextWorker];
|
||||
nextWorker = (nextWorker + 1) % workerPool!.length;
|
||||
try {
|
||||
w.postMessage({ id, raw });
|
||||
} catch (err) {
|
||||
pendingMap.delete(id);
|
||||
resolve({ parsed: null, err: err && (err as Error).message ? (err as Error).message : String(err) });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let eventQueue: { name: keyof SocketEvents; data: unknown }[] = [];
|
||||
let rafScheduled = false;
|
||||
const MAX_QUEUE = 5000;
|
||||
|
||||
const flushQueue = () => {
|
||||
const items = eventQueue.splice(0, eventQueue.length);
|
||||
if (items.length === 0) return;
|
||||
const l = listeners;
|
||||
if (!l) return;
|
||||
for (const it of items) {
|
||||
try {
|
||||
l[it.name](it.data as never);
|
||||
} catch (err) {
|
||||
console.error('listener handler error', err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const scheduleFlush = () => {
|
||||
if (rafScheduled) return;
|
||||
rafScheduled = true;
|
||||
requestAnimationFrame(() => {
|
||||
rafScheduled = false;
|
||||
flushQueue();
|
||||
});
|
||||
};
|
||||
|
||||
const safeEnqueue = (name: keyof SocketEvents, data: unknown) => {
|
||||
if (eventQueue.length > MAX_QUEUE) {
|
||||
eventQueue.shift();
|
||||
console.warn('eventQueue overflow, dropping oldest');
|
||||
}
|
||||
eventQueue.push({ name, data });
|
||||
scheduleFlush();
|
||||
};
|
||||
|
||||
export const connectSocket = async (): Promise<Socket> => {
|
||||
const { host, port, connectionType, setStatus } = useSocketStore.getState();
|
||||
const {
|
||||
onConnectedService,
|
||||
onBattleBeginService,
|
||||
onSetBattleLineupService,
|
||||
onDamageService,
|
||||
onTurnBeginService,
|
||||
onTurnEndService,
|
||||
onEntityDefeatedService,
|
||||
onUseSkillService,
|
||||
onUpdateWaveService,
|
||||
onUpdateCycleService,
|
||||
onStatChange,
|
||||
onUpdateTeamFormation,
|
||||
onInitializeEnemyService,
|
||||
onBattleEndService,
|
||||
onCreateBattleService,
|
||||
} = useBattleDataStore.getState();
|
||||
const battle = useBattleDataStore.getState();
|
||||
|
||||
let url = `${host}:${port}`;
|
||||
if (connectionType === "Native") {
|
||||
url = "http://localhost:1305"
|
||||
}
|
||||
else if (connectionType === "PS") {
|
||||
url = "http://localhost:21000"
|
||||
}
|
||||
if (connectionType === "Native") url = "http://localhost:1305";
|
||||
else if (connectionType === "PS") url = "http://localhost:21000";
|
||||
|
||||
if (socket) {
|
||||
socket.disconnect();
|
||||
}
|
||||
if (socket) socket.disconnect();
|
||||
|
||||
socket = io(url, {
|
||||
reconnectionAttempts: 5,
|
||||
@@ -62,156 +152,91 @@ export const connectSocket = (): Socket => {
|
||||
});
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log("Socket connected");
|
||||
setStatus(true);
|
||||
notify(`Connected: ${socket?.id}`, "success");
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
console.log("Socket disconnected");
|
||||
setStatus(false);
|
||||
});
|
||||
socket.on("disconnect", () => setStatus(false));
|
||||
socket.on("connect_error", () => setStatus(false));
|
||||
socket.on("connect_timeout", () => setStatus(false));
|
||||
socket.on("reconnect_failed", () => setStatus(false));
|
||||
|
||||
socket.on("connect_error", (err) => {
|
||||
console.error("Connection error:", err);
|
||||
setStatus(false);
|
||||
});
|
||||
|
||||
socket.on("connect_timeout", () => {
|
||||
console.warn("Connection timeout");
|
||||
setStatus(false);
|
||||
});
|
||||
|
||||
socket.on("reconnect_failed", () => {
|
||||
console.error("Reconnect failed");
|
||||
setStatus(false);
|
||||
});
|
||||
|
||||
const onConnect = () => {
|
||||
setStatus(true);
|
||||
notify(`Kết nối thành công với Socket ID: ${socket?.id}`, 'success');
|
||||
listeners = {
|
||||
Connected: (payload) => battle.onConnectedService(payload),
|
||||
OnBattleBegin: (payload) => {
|
||||
notify("Battle Started!", "info");
|
||||
battle.onBattleBeginService(payload);
|
||||
},
|
||||
OnSetBattleLineup: (payload) => battle.onSetBattleLineupService(payload),
|
||||
OnDamage: (payload) => battle.onDamageService(payload),
|
||||
OnTurnBegin: (payload) => battle.onTurnBeginService(payload),
|
||||
OnTurnEnd: (payload) => battle.onTurnEndService(payload),
|
||||
OnEntityDefeated: (payload) => battle.onEntityDefeatedService(payload),
|
||||
OnUseSkill: (payload) => battle.onUseSkillService(payload),
|
||||
OnUpdateWave: (payload) => battle.onUpdateWaveService(payload),
|
||||
OnUpdateCycle: (payload) => battle.onUpdateCycleService(payload),
|
||||
OnStatChange: (payload) => battle.onStatChange(payload),
|
||||
OnUpdateTeamFormation: (payload) => battle.onUpdateTeamFormation(payload),
|
||||
OnInitializeEnemy: (payload) => battle.onInitializeEnemyService(payload),
|
||||
OnBattleEnd: (payload) => battle.onBattleEndService(payload),
|
||||
OnCreateBattle: (payload) => battle.onCreateBattleService(payload),
|
||||
Error: (msg) => console.error("Server Error:", msg),
|
||||
};
|
||||
|
||||
const onBattleBegin = (data: BattleBeginType) => {
|
||||
notify("Battle Started!", "info")
|
||||
onBattleBeginService(data)
|
||||
}
|
||||
const register = (eventName: string) => {
|
||||
socket?.on(eventName, async (raw: unknown) => {
|
||||
if (!listeners) return;
|
||||
if (workerPool) {
|
||||
const res = await parseWithWorker(raw);
|
||||
if (res.err) {
|
||||
safeEnqueue("Error", `Worker parse error for ${eventName}: ${res.err}`);
|
||||
} else if (res.parsed !== null) {
|
||||
safeEnqueue(eventName as keyof SocketEvents, res.parsed);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const parsed = typeof raw === 'string' ? JSON.parse(raw) : raw;
|
||||
safeEnqueue(eventName as keyof SocketEvents, parsed);
|
||||
} catch (err) {
|
||||
safeEnqueue("Error", `Parse error for ${eventName}: ${err && (err as Error).message ? (err as Error).message : String(err)}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (isSocketConnected()) onConnect();
|
||||
socket.on("Connected", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onConnectedService(data);
|
||||
});
|
||||
socket.on("OnBattleBegin", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onBattleBegin(data);
|
||||
});
|
||||
socket.on("OnSetBattleLineup", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onSetBattleLineupService(data);
|
||||
});
|
||||
socket.on("OnDamage", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onDamageService(data);
|
||||
});
|
||||
socket.on("OnTurnBegin", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onTurnBeginService(data);
|
||||
});
|
||||
socket.on("OnTurnEnd", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onTurnEndService(data);
|
||||
});
|
||||
socket.on("OnEntityDefeated", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onEntityDefeatedService(data);
|
||||
});
|
||||
socket.on("OnUseSkill", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onUseSkillService(data);
|
||||
});
|
||||
socket.on("OnUpdateWave", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onUpdateWaveService(data);
|
||||
});
|
||||
socket.on("OnUpdateCycle", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onUpdateCycleService(data);
|
||||
});
|
||||
socket.on("OnStatChange", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onStatChange(data);
|
||||
});
|
||||
socket.on("OnUpdateTeamFormation", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onUpdateTeamFormation(data);
|
||||
});
|
||||
socket.on("OnInitializeEnemy", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onInitializeEnemyService(data);
|
||||
});
|
||||
socket.on("OnBattleEnd", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onBattleEndService(data);
|
||||
});
|
||||
socket.on("OnCreateBattle", (json) => {
|
||||
const data = safeParse(json);
|
||||
if (data) onCreateBattleService(data);
|
||||
});
|
||||
socket.on("Error", (msg: string) => {
|
||||
console.error("Server Error:", msg);
|
||||
});
|
||||
Object.keys(listeners).forEach((k) => register(k));
|
||||
|
||||
createWorkerPool();
|
||||
|
||||
return socket;
|
||||
};
|
||||
|
||||
export const disconnectSocket = (): void => {
|
||||
const {
|
||||
onConnectedService,
|
||||
onBattleBeginService,
|
||||
onSetBattleLineupService,
|
||||
onDamageService,
|
||||
onTurnBeginService,
|
||||
onTurnEndService,
|
||||
onEntityDefeatedService,
|
||||
onUseSkillService,
|
||||
onUpdateWaveService,
|
||||
onUpdateCycleService,
|
||||
onStatChange,
|
||||
onUpdateTeamFormation,
|
||||
onInitializeEnemyService,
|
||||
onBattleEndService,
|
||||
onCreateBattleService,
|
||||
} = useBattleDataStore.getState();
|
||||
const onBattleBegin = (data: BattleBeginType) => {
|
||||
notify("Battle Started!", "info")
|
||||
onBattleBeginService(data)
|
||||
if (!socket) return;
|
||||
if (listeners) {
|
||||
Object.keys(listeners).forEach((eventName) => {
|
||||
socket?.off(eventName);
|
||||
});
|
||||
}
|
||||
if (socket) {
|
||||
socket.off("Connected", (json) => onConnectedService(JSON.parse(json)));
|
||||
socket.off("OnBattleBegin", (json) => onBattleBegin(JSON.parse(json)));
|
||||
socket.off("OnSetBattleLineup", (json) => onSetBattleLineupService(JSON.parse(json)));
|
||||
socket.off("OnTurnEnd", (json) => onTurnEndService(JSON.parse(json)));
|
||||
socket.off("OnUseSkill", (json) => onUseSkillService(JSON.parse(json)));
|
||||
socket.off("OnEntityDefeated", (json) => onEntityDefeatedService(JSON.parse(json)));
|
||||
socket.off("OnDamage", (json) => onDamageService(JSON.parse(json)));
|
||||
socket.off('OnTurnBegin', (json) => onTurnBeginService(JSON.parse(json)));
|
||||
socket.off('OnBattleEnd', (json) => onBattleEndService(JSON.parse(json)));
|
||||
socket.off('OnUpdateCycle', (json) => onUpdateCycleService(JSON.parse(json)));
|
||||
socket.off('OnUpdateWave', (json) => onUpdateWaveService(JSON.parse(json)));
|
||||
socket.off('OnCreateBattle', (json) => onCreateBattleService(JSON.parse(json)));
|
||||
socket.off('OnStatChange', (json) => onStatChange(JSON.parse(json)));
|
||||
socket.off('OnUpdateTeamFormation', (json) => onUpdateTeamFormation(JSON.parse(json)));
|
||||
socket.off('OnInitializeEnemy', (json) => onInitializeEnemyService(JSON.parse(json)));
|
||||
socket.offAny();
|
||||
socket.disconnect();
|
||||
useSocketStore.getState().setStatus(false);
|
||||
socket.disconnect();
|
||||
useSocketStore.getState().setStatus(false);
|
||||
listeners = null;
|
||||
if (workerPool) {
|
||||
workerPool.forEach((w) => w.terminate());
|
||||
workerPool = null;
|
||||
}
|
||||
pendingMap.clear();
|
||||
eventQueue = [];
|
||||
};
|
||||
|
||||
export const isSocketConnected = (): boolean => {
|
||||
return socket?.connected || false;
|
||||
export const isSocketConnected = (): boolean => socket?.connected || false;
|
||||
export const getSocket = (): Socket | null => socket;
|
||||
|
||||
export const setWorkerPoolSize = (size: number) => {
|
||||
if (workerPool) {
|
||||
workerPool.forEach((w) => w.terminate());
|
||||
workerPool = null;
|
||||
}
|
||||
createWorkerPool(Math.max(1, size));
|
||||
};
|
||||
|
||||
export const getSocket = (): Socket | null => {
|
||||
return socket;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user