140 lines
3.8 KiB
JavaScript
140 lines
3.8 KiB
JavaScript
import React, { useState, useEffect, useRef } from "react";
|
|
import "./Console.css";
|
|
import { useSocket } from "../../hooks/useSocket";
|
|
import ConsoleManager from "../../services/ConsoleManager";
|
|
import PlayerManager from "../../services/PlayerManager"; // Імпортуємо менеджер гравців
|
|
|
|
const Console = () => {
|
|
const { socket } = useSocket();
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [input, setInput] = useState("");
|
|
const [suggestions, setSuggestions] = useState([]);
|
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
const [logs, setLogs] = useState(ConsoleManager.logs);
|
|
|
|
const [playerNames, setPlayerNames] = useState([]);
|
|
|
|
const inputRef = useRef(null);
|
|
const scrollRef = useRef(null);
|
|
|
|
useEffect(() => {
|
|
ConsoleManager.init(socket, setLogs);
|
|
}, [socket]);
|
|
|
|
useEffect(() => {
|
|
const updatePlayers = (data) => {
|
|
setPlayerNames([...data.online, ...data.offline]);
|
|
};
|
|
|
|
const unsubscribe = PlayerManager.subscribe(updatePlayers);
|
|
|
|
setPlayerNames([
|
|
...PlayerManager.onlinePlayers,
|
|
...PlayerManager.offlinePlayers,
|
|
]);
|
|
|
|
return () => unsubscribe();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (scrollRef.current) {
|
|
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
|
}
|
|
}, [logs]);
|
|
|
|
useEffect(() => {
|
|
const handleGlobalKeyDown = (e) => {
|
|
if (e.key === "F9") {
|
|
e.preventDefault();
|
|
setIsOpen((prev) => !prev);
|
|
}
|
|
};
|
|
window.addEventListener("keydown", handleGlobalKeyDown);
|
|
return () => window.removeEventListener("keydown", handleGlobalKeyDown);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
setSuggestions(ConsoleManager.getSuggestions(input, playerNames));
|
|
setSelectedIndex(0);
|
|
}, [input, playerNames]);
|
|
|
|
const handleKeyDown = (e) => {
|
|
if (e.key === "Tab" && suggestions.length > 0) {
|
|
e.preventDefault();
|
|
const parts = input.split(" ");
|
|
parts[parts.length - 1] = suggestions[selectedIndex];
|
|
setInput(parts.join(" ") + (parts.length < 3 ? " " : ""));
|
|
}
|
|
|
|
if (e.key === "ArrowDown") {
|
|
if (suggestions.length > 0) {
|
|
setSelectedIndex((prev) => (prev + 1) % suggestions.length);
|
|
} else {
|
|
const hist = ConsoleManager.getHistory("down");
|
|
if (hist !== null) setInput(hist);
|
|
}
|
|
}
|
|
|
|
if (e.key === "ArrowUp") {
|
|
if (suggestions.length > 0) {
|
|
setSelectedIndex(
|
|
(prev) => (prev - 1 + suggestions.length) % suggestions.length,
|
|
);
|
|
} else {
|
|
const hist = ConsoleManager.getHistory("up");
|
|
if (hist !== null) setInput(hist);
|
|
}
|
|
}
|
|
|
|
if (e.key === "Escape") setIsOpen(false);
|
|
};
|
|
|
|
const handleSubmit = (e) => {
|
|
e.preventDefault();
|
|
if (!input.trim()) return;
|
|
ConsoleManager.execute(input);
|
|
setInput("");
|
|
};
|
|
|
|
if (!isOpen) return null;
|
|
|
|
return (
|
|
<div className="game-console-bottom">
|
|
<div className="console-scroll-area" ref={scrollRef}>
|
|
{logs.map((line, i) => (
|
|
<div key={i} className="console-line">
|
|
{line}
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{suggestions.length > 0 && (
|
|
<div className="console-suggestions-upward">
|
|
{suggestions.map((s, i) => (
|
|
<div
|
|
key={i}
|
|
className={`suggestion-item ${i === selectedIndex ? "selected" : ""}`}
|
|
>
|
|
{s}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
<form className="console-input-form" onSubmit={handleSubmit}>
|
|
<span className="console-prompt">#</span>
|
|
<input
|
|
ref={inputRef}
|
|
autoFocus
|
|
value={input}
|
|
onKeyDown={handleKeyDown}
|
|
onChange={(e) => setInput(e.target.value)}
|
|
placeholder="Type /command..."
|
|
/>
|
|
</form>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Console;
|