import React, { useState, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
import { Users, Clock, Circle, ServerOff } from 'lucide-react';
import { motion } from 'framer-motion';
import { io } from 'socket.io-client';
import { formatPlayTimeMs } from '../utils/formatters';
// 스티브 머리 기본 이미지 (로딩 전/실패 시 사용)
const STEVE_HEAD_BASE64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABWUlEQVRoge2ZPUsDQRCGk7DeGU1ysTDYpIuFjYUasMpHaZFKhJDWxj7gjwjYK/Y2wcJKsAppxEYkTcCU1oGcubt8gv6Bd4oBk3FhnvLZvb17GW7YvYsfF3Z+YgxSjuFMZxPMl9BPCZ9Y5cOsAw0gjQaQxvjBBA54qST0VJfgdqe/Wsf6CmgAaTSANMZ1NuDAVfkU+r3cLl5oKw39MhpDP5ktoPf9EfR33Tfora+ABpBGA0gTv788gycyz8vCC5Iu7loUVLfhQnUn6yugAaTRANIYqttc3DxAf15qQV8vfkBPdY/nzwr0j91r6NvNBvTWV0ADSKMBpGHvhSg6733W/MrRAWu+7oX+KxpAGusDmDCK4ECwCKF/ee1Bf5jfZ934tv0Efa16Av13iE921ldAA0ijAaQxxsU/6odj/NbPpnPoe18D1nx304Ge6jaZbfw9yvoKaABpNIA0v2NsVwyhlV0PAAAAAElFTkSuQmCC';
// 플레이어 아바타 컴포넌트 - 스킨 캐싱 API 사용
const PlayerAvatar = ({ uuid, name }) => {
const [src, setSrc] = useState(STEVE_HEAD_BASE64);
useEffect(() => {
// 스킨 캐싱 API 호출 (avatar/uuid/size)
fetch(`/link/skin/avatar/${uuid}/48`)
.then(res => res.json())
.then(data => {
if (data.url) {
const img = new Image();
img.onload = () => setSrc(data.url);
img.onerror = () => setSrc(`https://mc-heads.net/avatar/${uuid}/48`);
img.src = data.url;
}
})
.catch(() => {
// 폴백: mc-heads 직접 사용
setSrc(`https://mc-heads.net/avatar/${uuid}/48`);
});
}, [uuid]);
return (
);
};
// 전체 플레이어 목록 페이지
const PlayersPage = ({ isMobile = false }) => {
const [players, setPlayers] = useState([]);
const [loading, setLoading] = useState(true);
const [serverOnline, setServerOnline] = useState(null);
const socketRef = useRef(null);
useEffect(() => {
// 소켓 연결
const socket = io('/', {
path: '/socket.io',
transports: ['websocket', 'polling']
});
socketRef.current = socket;
socket.on('status', (data) => {
setServerOnline(data.online);
if (!data.online) {
setLoading(false);
}
});
socket.on('players', (data) => {
setPlayers(data);
setLoading(false);
});
// 1초마다 갱신
const interval = setInterval(() => {
socket.emit('get_players');
}, 1000);
// 초기 요청
socket.emit('get_players');
return () => {
clearInterval(interval);
socket.disconnect();
};
}, []);
// 온라인 플레이어 먼저, 그 다음 이름순 정렬
const sortedPlayers = [...players].sort((a, b) => {
if (a.isOnline !== b.isOnline) return b.isOnline ? 1 : -1;
return a.name.localeCompare(b.name, 'ko');
});
const onlineCount = players.filter(p => p.isOnline).length;
// 서버 오프라인 상태 - 전체 화면 가운데 정렬
if (serverOnline === false) {
return (
마인크래프트 서버가 현재 오프라인 상태입니다.
서버가 시작되면 플레이어 정보를 확인할 수 있습니다.
전체 플레이어 {players.length}명 • 온라인 {onlineCount}명
등록된 플레이어가 없습니다.