291 lines
13 KiB
Python
291 lines
13 KiB
Python
from fastapi import HTTPException
|
||
from datetime import datetime
|
||
import json
|
||
from app.services.coins import CoinsService
|
||
from app.models.server.event import PlayerEvent, OnlinePlayersUpdate
|
||
import uuid
|
||
|
||
class EventService:
|
||
def __init__(self):
|
||
self.coins_service = CoinsService()
|
||
|
||
async def process_event(self, event_data):
|
||
"""Обработка событий от сервера Minecraft"""
|
||
try:
|
||
# Проверяем формат ваших событий (event_type вместо type)
|
||
event_type = event_data.get("event_type")
|
||
if not event_type:
|
||
# Для совместимости со старым форматом
|
||
event_type = event_data.get("type")
|
||
|
||
if not event_type:
|
||
raise HTTPException(status_code=400, detail="Missing event type")
|
||
|
||
server_ip = event_data.get("server_ip")
|
||
if not server_ip:
|
||
raise HTTPException(status_code=400, detail="Missing server IP")
|
||
|
||
# Преобразуем ваши типы событий в нужные форматы
|
||
if event_type == "online_players_update":
|
||
# Регистрируем сервер, если его нет
|
||
await self._register_server(server_ip, event_data)
|
||
|
||
# Обновляем данные об онлайн игроках
|
||
players = event_data.get("players", [])
|
||
await self._update_online_players(server_ip, players)
|
||
return {"status": "success"}
|
||
|
||
elif event_type == "player_join":
|
||
player_id = event_data.get("player_id")
|
||
player_name = event_data.get("player_name")
|
||
|
||
if not player_id or not player_name:
|
||
raise HTTPException(status_code=400, detail="Missing player data")
|
||
|
||
# Регистрируем вход игрока
|
||
await self._register_player_login(server_ip, player_id, player_name)
|
||
return {"status": "success"}
|
||
|
||
elif event_type == "player_quit":
|
||
player_id = event_data.get("player_id")
|
||
player_name = event_data.get("player_name")
|
||
|
||
if not player_id or not player_name:
|
||
raise HTTPException(status_code=400, detail="Missing player data")
|
||
|
||
# Регистрируем выход игрока
|
||
await self._register_player_logout(server_ip, player_id, player_name)
|
||
return {"status": "success"}
|
||
|
||
elif event_type == "player_session":
|
||
player_id = event_data.get("player_id")
|
||
player_name = event_data.get("player_name")
|
||
duration = event_data.get("duration", 0)
|
||
|
||
if not player_id or not player_name:
|
||
raise HTTPException(status_code=400, detail="Missing player data")
|
||
|
||
# Обрабатываем информацию о сессии
|
||
await self._process_player_session(server_ip, player_id, player_name, duration)
|
||
return {"status": "success"}
|
||
|
||
# Если тип события не распознан
|
||
print(f"[{datetime.now()}] Неизвестное событие: {event_data}")
|
||
raise HTTPException(status_code=400, detail="Invalid event type")
|
||
|
||
except HTTPException as e:
|
||
print(f"[{datetime.now()}] Ошибка обработки события: {e.status_code}: {e.detail}")
|
||
print(f"Полученные данные: {event_data}")
|
||
raise
|
||
except Exception as e:
|
||
print(f"[{datetime.now()}] Необработанная ошибка: {str(e)}")
|
||
print(f"Полученные данные: {event_data}")
|
||
raise HTTPException(status_code=500, detail=f"Server error: {str(e)}")
|
||
|
||
async def _register_server(self, server_ip, event_data):
|
||
"""Регистрирует сервер, если его нет в базе"""
|
||
from app.db.database import db
|
||
import uuid
|
||
|
||
game_servers_collection = db.game_servers
|
||
|
||
# Проверяем, есть ли уже такой сервер
|
||
existing_server = await game_servers_collection.find_one({"ip": server_ip})
|
||
|
||
if not existing_server:
|
||
# Создаем новую запись сервера
|
||
server_data = {
|
||
"id": str(uuid.uuid4()),
|
||
"name": f"Server {server_ip}", # Можно улучшить название
|
||
"ip": server_ip,
|
||
"port": 25565, # Стандартный порт Minecraft
|
||
"description": f"Minecraft server {server_ip}",
|
||
"max_players": 100,
|
||
"registered_at": datetime.utcnow(),
|
||
"last_activity": datetime.utcnow() # Добавляем поле last_activity
|
||
}
|
||
|
||
await game_servers_collection.insert_one(server_data)
|
||
print(f"[{datetime.utcnow()}] Зарегистрирован новый сервер: {server_ip}")
|
||
else:
|
||
# Обновляем активность существующего сервера
|
||
await game_servers_collection.update_one(
|
||
{"ip": server_ip},
|
||
{"$set": {"last_activity": datetime.utcnow()}}
|
||
)
|
||
|
||
return existing_server or await game_servers_collection.find_one({"ip": server_ip})
|
||
|
||
async def _update_online_players(self, server_ip, players_data):
|
||
"""Обновляет информацию об онлайн игроках"""
|
||
from app.db.database import db
|
||
|
||
online_players_collection = db.online_players
|
||
game_servers_collection = db.game_servers
|
||
|
||
# Получаем ID сервера
|
||
server = await self._register_server(server_ip, {})
|
||
server_id = server["id"]
|
||
|
||
# Обновляем время активности сервера
|
||
await game_servers_collection.update_one(
|
||
{"id": server_id},
|
||
{"$set": {"last_activity": datetime.utcnow()}}
|
||
)
|
||
|
||
# Помечаем всех игроков как оффлайн на этом сервере
|
||
await online_players_collection.update_many(
|
||
{"server_id": server_id},
|
||
{"$set": {"is_online": False}}
|
||
)
|
||
|
||
# Обновляем данные для каждого онлайн игрока
|
||
now = datetime.utcnow()
|
||
for player in players_data:
|
||
player_id = player.get("player_id")
|
||
player_name = player.get("player_name")
|
||
online_time = player.get("online_time", 0)
|
||
|
||
if not player_id or not player_name:
|
||
continue
|
||
|
||
# Проверяем, существует ли уже запись
|
||
existing_player = await online_players_collection.find_one({
|
||
"uuid": player_id,
|
||
"server_id": server_id
|
||
})
|
||
|
||
if existing_player:
|
||
# Обновляем существующую запись
|
||
await online_players_collection.update_one(
|
||
{"_id": existing_player["_id"]},
|
||
{"$set": {
|
||
"username": player_name,
|
||
"is_online": True,
|
||
"last_seen": now,
|
||
"online_duration": online_time
|
||
}}
|
||
)
|
||
else:
|
||
# Создаем новую запись
|
||
await online_players_collection.insert_one({
|
||
"uuid": player_id,
|
||
"username": player_name,
|
||
"server_id": server_id,
|
||
"is_online": True,
|
||
"login_time": now,
|
||
"last_seen": now,
|
||
"online_duration": online_time
|
||
})
|
||
|
||
online_count = len(players_data)
|
||
print(f"[{now}] Обновлена информация о {online_count} игроках на сервере {server_ip}")
|
||
|
||
# Также обновляем информацию о коинах для каждого игрока
|
||
if players_data:
|
||
from app.services.coins import CoinsService
|
||
coins_service = CoinsService()
|
||
|
||
for player in players_data:
|
||
player_id = player.get("player_id")
|
||
player_name = player.get("player_name")
|
||
online_time = player.get("online_time", 0)
|
||
|
||
if player_id and player_name:
|
||
await coins_service.update_player_coins(player_id, player_name, online_time, server_ip)
|
||
|
||
async def _register_player_login(self, server_ip, player_id, player_name):
|
||
"""Регистрирует вход игрока на сервер"""
|
||
from app.db.database import db
|
||
|
||
online_players_collection = db.online_players
|
||
|
||
server = await self._register_server(server_ip, {})
|
||
server_id = server["id"]
|
||
|
||
now = datetime.utcnow()
|
||
|
||
# Проверяем, есть ли уже запись для этого игрока
|
||
existing_player = await online_players_collection.find_one({
|
||
"uuid": player_id,
|
||
"server_id": server_id
|
||
})
|
||
|
||
if existing_player:
|
||
# Обновляем запись
|
||
await online_players_collection.update_one(
|
||
{"_id": existing_player["_id"]},
|
||
{"$set": {
|
||
"username": player_name,
|
||
"is_online": True,
|
||
"login_time": now,
|
||
"last_seen": now
|
||
}}
|
||
)
|
||
else:
|
||
# Создаем новую запись
|
||
await online_players_collection.insert_one({
|
||
"uuid": player_id,
|
||
"username": player_name,
|
||
"server_id": server_id,
|
||
"is_online": True,
|
||
"login_time": now,
|
||
"last_seen": now,
|
||
"online_duration": 0
|
||
})
|
||
|
||
print(f"[{now}] Игрок {player_name} зашел на сервер {server_ip}")
|
||
|
||
async def _register_player_logout(self, server_ip, player_id, player_name):
|
||
"""Регистрирует выход игрока с сервера"""
|
||
from app.db.database import db
|
||
|
||
online_players_collection = db.online_players
|
||
|
||
server = await self._register_server(server_ip, {})
|
||
server_id = server["id"]
|
||
|
||
now = datetime.utcnow()
|
||
|
||
# Ищем запись игрока
|
||
player = await online_players_collection.find_one({
|
||
"uuid": player_id,
|
||
"server_id": server_id
|
||
})
|
||
|
||
if player:
|
||
# Обновляем запись
|
||
await online_players_collection.update_one(
|
||
{"_id": player["_id"]},
|
||
{"$set": {
|
||
"is_online": False,
|
||
"last_seen": now
|
||
}}
|
||
)
|
||
|
||
print(f"[{now}] Игрок {player_name} вышел с сервера {server_ip}")
|
||
|
||
async def _process_player_session(self, server_ip, player_id, player_name, duration):
|
||
"""Обрабатывает информацию о завершенной сессии игрока"""
|
||
from app.db.database import db
|
||
from app.services.coins import CoinsService
|
||
|
||
server = await self._register_server(server_ip, {})
|
||
server_id = server["id"]
|
||
|
||
# Обновляем статистику времени игры
|
||
await db.player_sessions.insert_one({
|
||
"uuid": player_id,
|
||
"username": player_name,
|
||
"server_id": server_id,
|
||
"server_ip": server_ip,
|
||
"duration": duration,
|
||
"session_end": datetime.utcnow()
|
||
})
|
||
|
||
# Начисляем коины за время игры
|
||
coins_service = CoinsService()
|
||
await coins_service.update_player_coins(player_id, player_name, duration, server_ip)
|
||
|
||
print(f"[{datetime.now()}] Сессия игрока {player_name} завершена, длительность: {duration} сек.")
|