Files

289 lines
13 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import HTTPException
from app.db.database import db, users_collection
from app.models.server.prank import PrankCommand, PrankCommandUpdate
from datetime import datetime, timedelta
import uuid
from app.services.server.command import CommandService
# Создаем коллекции для хранения пакостей и серверов
prank_commands_collection = db.prank_commands
game_servers_collection = db.game_servers
online_players_collection = db.online_players
class PrankService:
async def add_prank_command(self, command_data):
"""Добавление новой команды-пакости"""
# Проверяем корректность шаблона команды
if "{targetPlayer}" not in command_data.command_template:
raise HTTPException(status_code=400,
detail="Шаблон команды должен содержать {targetPlayer} для подстановки имени цели")
prank_id = str(uuid.uuid4())
# Создаем новую команду в БД
prank_command = {
"id": prank_id,
"name": command_data.name,
"description": command_data.description,
"price": command_data.price,
"command_template": command_data.command_template,
"server_ids": command_data.server_ids,
"targetDescription": command_data.targetDescription,
"globalDescription": command_data.globalDescription, # Добавить это поле
"created_at": datetime.utcnow()
}
await prank_commands_collection.insert_one(prank_command)
return {"status": "success", "id": prank_id}
async def get_all_prank_commands(self):
"""Получение списка всех команд-пакостей"""
commands = await prank_commands_collection.find().to_list(1000)
result = []
for cmd in commands:
result.append({
"id": cmd["id"],
"name": cmd["name"],
"description": cmd["description"],
"price": cmd["price"],
"command_template": cmd["command_template"],
"server_ids": cmd.get("server_ids", []),
"targetDescription": cmd.get("targetDescription"),
"globalDescription": cmd.get("globalDescription") # Добавить это поле
})
return result
async def get_prank_command(self, command_id: str):
"""Получение конкретной команды по ID"""
command = await prank_commands_collection.find_one({"id": command_id})
if not command:
raise HTTPException(status_code=404, detail="Команда не найдена")
return {
"id": command["id"],
"name": command["name"],
"description": command["description"],
"price": command["price"],
"command_template": command["command_template"],
"server_ids": command.get("server_ids", []),
"targetDescription": command.get("targetDescription"),
"globalDescription": command.get("globalDescription") # Добавить это поле
}
async def update_prank_command(self, command_id: str, update_data: PrankCommandUpdate):
"""Обновление команды-пакости"""
command = await prank_commands_collection.find_one({"id": command_id})
if not command:
raise HTTPException(status_code=404, detail="Команда не найдена")
# Готовим данные для обновления
update = {}
if update_data.name is not None:
update["name"] = update_data.name
if update_data.description is not None:
update["description"] = update_data.description
if update_data.price is not None:
update["price"] = update_data.price
if update_data.command_template is not None:
if "{targetPlayer}" not in update_data.command_template:
raise HTTPException(status_code=400,
detail="Шаблон команды должен содержать {targetPlayer} для подстановки имени цели")
update["command_template"] = update_data.command_template
if update_data.server_ids is not None:
update["server_ids"] = update_data.server_ids
if update_data.targetDescription is not None:
update["targetDescription"] = update_data.targetDescription
if update_data.globalDescription is not None: # Добавить эту проверку
update["globalDescription"] = update_data.globalDescription
if update:
result = await prank_commands_collection.update_one(
{"id": command_id},
{"$set": update}
)
if result.modified_count == 0:
raise HTTPException(status_code=500, detail="Ошибка при обновлении команды")
return {"status": "success"}
async def delete_prank_command(self, command_id: str):
"""Удаление команды-пакости"""
command = await prank_commands_collection.find_one({"id": command_id})
if not command:
raise HTTPException(status_code=404, detail="Команда не найдена")
result = await prank_commands_collection.delete_one({"id": command_id})
if result.deleted_count == 0:
raise HTTPException(status_code=500, detail="Ошибка при удалении команды")
return {"status": "success"}
async def get_all_servers(self):
"""Получение списка всех доступных серверов"""
# Проверяем и удаляем неактивные серверы (более 5 минут без данных)
current_time = datetime.utcnow()
inactive_threshold = 5 * 60 # 5 минут в секундах
# Находим серверы, которые не отправляли данные больше 5 минут
# Учитываем, что у некоторых серверов может не быть поля last_activity
inactive_servers = await game_servers_collection.find({
"last_activity": {
"$exists": True,
"$lt": current_time - timedelta(seconds=inactive_threshold)
}
}).to_list(100)
# Удаляем неактивные серверы
if inactive_servers:
server_ids = [server["id"] for server in inactive_servers]
await game_servers_collection.delete_many({"id": {"$in": server_ids}})
# Опционально: логирование удаленных серверов
for server in inactive_servers:
print(f"Удален неактивный сервер: {server['name']} (ID: {server['id']})")
# Получаем актуальный список серверов
servers = await game_servers_collection.find().to_list(100)
# Если нет зарегистрированных серверов, вернем пустой список
if not servers:
return []
result = []
for server in servers:
# Получаем количество онлайн игроков
online_count = await online_players_collection.count_documents(
{"server_id": server["id"], "is_online": True}
)
result.append({
"id": server["id"],
"name": server["name"],
"ip": server.get("ip"),
"port": server.get("port"),
"description": server.get("description", ""),
"online_players": online_count,
"max_players": server.get("max_players", 0),
"last_activity": server.get("last_activity")
})
return result
async def get_server_online_players(self, server_id: str):
"""Получение списка онлайн игроков на конкретном сервере"""
server = await game_servers_collection.find_one({"id": server_id})
if not server:
raise HTTPException(status_code=404, detail="Сервер не найден")
players = await online_players_collection.find(
{"server_id": server_id, "is_online": True}
).to_list(1000)
result = []
for player in players:
result.append({
"username": player["username"],
"uuid": player.get("uuid", ""),
"online_since": player.get("login_time")
})
return {
"server": {
"id": server["id"],
"name": server["name"]
},
"online_players": result,
"count": len(result)
}
async def execute_prank(self, username: str, command_id: str, target_player: str, server_id: str):
"""Выполнение пакости (покупка и выполнение команды)"""
# Проверяем пользователя
user = await users_collection.find_one({"username": username})
if not user:
raise HTTPException(status_code=404, detail="Пользователь не найден")
# Проверяем команду
command = await prank_commands_collection.find_one({"id": command_id})
if not command:
raise HTTPException(status_code=404, detail="Команда не найдена")
# Проверяем сервер
server = await game_servers_collection.find_one({"id": server_id})
if not server:
raise HTTPException(status_code=404, detail="Сервер не найден")
# Проверяем, доступна ли команда на данном сервере
if (command.get("server_ids") and
"*" not in command.get("server_ids", []) and
server_id not in command.get("server_ids", [])):
raise HTTPException(status_code=400, detail="Команда недоступна на выбранном сервере")
# Проверяем, онлайн ли целевой игрок
target_online = await online_players_collection.find_one({
"username": target_player,
"server_id": server_id,
"is_online": True
})
if not target_online:
raise HTTPException(status_code=400, detail=f"Игрок {target_player} не в сети на этом сервере")
# Проверяем достаточно ли монет
user_coins = user.get("coins", 0)
if user_coins < command["price"]:
raise HTTPException(status_code=400,
detail=f"Недостаточно монет. Требуется: {command['price']}, имеется: {user_coins}")
# Формируем команду для выполнения
actual_command = command["command_template"].replace("{targetPlayer}", target_player)
# Обрабатываем оба типа сообщений
target_desc = None
global_desc = None
if command.get("targetDescription"):
target_desc = command.get("targetDescription").replace("{username}", username).replace("{targetPlayer}", target_player)
if command.get("globalDescription"):
global_desc = command.get("globalDescription").replace("{username}", username).replace("{targetPlayer}", target_player)
# Отправляем команду с обоими сообщениями
command_service = CommandService()
from app.models.server.command import ServerCommand
server_command = ServerCommand(
command=actual_command,
server_ip=server.get("ip", ""),
require_online_player=True,
target_message=target_desc, # Сообщение для цели
global_message=global_desc # Сообщение для всех остальных
)
command_result = await command_service.add_command(server_command)
# Логируем выполнение пакости
log_entry = {
"user_id": user["_id"],
"username": username,
"target_player": target_player,
"command_id": command_id,
"command_name": command["name"],
"server_id": server_id,
"price": command["price"],
"executed_command": actual_command,
"executed_at": datetime.utcnow()
}
await db.prank_executions.insert_one(log_entry)
return {
"status": "success",
"message": f"Команда '{command['name']}' успешно выполнена на игроке {target_player}",
"remaining_coins": user_coins - command["price"]
}