add: store pranks
This commit is contained in:
55
app/api/pranks.py
Normal file
55
app/api/pranks.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
from fastapi import APIRouter, HTTPException
|
||||||
|
from app.services.server.prank import PrankService
|
||||||
|
from app.models.server.prank import PrankCommandCreate, PrankCommandUpdate, PrankExecute
|
||||||
|
|
||||||
|
router = APIRouter(
|
||||||
|
prefix="/api/pranks",
|
||||||
|
tags=["Pranks"]
|
||||||
|
)
|
||||||
|
|
||||||
|
prank_service = PrankService()
|
||||||
|
|
||||||
|
@router.get("/commands")
|
||||||
|
async def get_all_prank_commands():
|
||||||
|
"""Получение всех доступных команд-пакостей"""
|
||||||
|
return await prank_service.get_all_prank_commands()
|
||||||
|
|
||||||
|
@router.get("/commands/{command_id}")
|
||||||
|
async def get_prank_command(command_id: str):
|
||||||
|
"""Получение команды-пакости по ID"""
|
||||||
|
return await prank_service.get_prank_command(command_id)
|
||||||
|
|
||||||
|
@router.post("/commands")
|
||||||
|
async def add_prank_command(command: PrankCommandCreate):
|
||||||
|
"""Добавление новой команды-пакости"""
|
||||||
|
return await prank_service.add_prank_command(command)
|
||||||
|
|
||||||
|
@router.put("/commands/{command_id}")
|
||||||
|
async def update_prank_command(command_id: str, update_data: PrankCommandUpdate):
|
||||||
|
"""Обновление команды-пакости"""
|
||||||
|
return await prank_service.update_prank_command(command_id, update_data)
|
||||||
|
|
||||||
|
@router.delete("/commands/{command_id}")
|
||||||
|
async def delete_prank_command(command_id: str):
|
||||||
|
"""Удаление команды-пакости"""
|
||||||
|
return await prank_service.delete_prank_command(command_id)
|
||||||
|
|
||||||
|
@router.get("/servers")
|
||||||
|
async def get_all_servers():
|
||||||
|
"""Получение списка всех доступных серверов"""
|
||||||
|
return await prank_service.get_all_servers()
|
||||||
|
|
||||||
|
@router.get("/servers/{server_id}/players")
|
||||||
|
async def get_server_online_players(server_id: str):
|
||||||
|
"""Получение списка онлайн игроков на сервере"""
|
||||||
|
return await prank_service.get_server_online_players(server_id)
|
||||||
|
|
||||||
|
@router.post("/execute")
|
||||||
|
async def execute_prank(username: str, prank_data: PrankExecute):
|
||||||
|
"""Выполнение пакости (списание монет и выполнение команды)"""
|
||||||
|
return await prank_service.execute_prank(
|
||||||
|
username,
|
||||||
|
prank_data.command_id,
|
||||||
|
prank_data.target_player,
|
||||||
|
prank_data.server_id
|
||||||
|
)
|
@ -5,3 +5,5 @@ class ServerCommand(BaseModel):
|
|||||||
command: str
|
command: str
|
||||||
server_ip: str
|
server_ip: str
|
||||||
require_online_player: Optional[bool] = False
|
require_online_player: Optional[bool] = False
|
||||||
|
target_message: Optional[str] = None # Сообщение для цели
|
||||||
|
global_message: Optional[str] = None # Сообщение для остальных
|
||||||
|
36
app/models/server/prank.py
Normal file
36
app/models/server/prank.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from typing import Optional, List
|
||||||
|
|
||||||
|
class PrankCommandCreate(BaseModel):
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
price: int
|
||||||
|
command_template: str
|
||||||
|
server_ids: List[str] = Field(
|
||||||
|
default=[],
|
||||||
|
description='Список серверов, где доступна команда. Использование ["*"] означает доступность на всех серверах'
|
||||||
|
)
|
||||||
|
targetDescription: Optional[str] = None # Сообщение для целевого игрока
|
||||||
|
globalDescription: Optional[str] = None # Сообщение для всех остальных
|
||||||
|
|
||||||
|
class PrankCommandUpdate(BaseModel):
|
||||||
|
name: Optional[str] = None
|
||||||
|
description: Optional[str] = None
|
||||||
|
price: Optional[int] = None
|
||||||
|
command_template: Optional[str] = None
|
||||||
|
server_ids: Optional[List[str]] = None
|
||||||
|
targetDescription: Optional[str] = None
|
||||||
|
globalDescription: Optional[str] = None
|
||||||
|
|
||||||
|
class PrankCommand(BaseModel):
|
||||||
|
id: str
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
price: int
|
||||||
|
command_template: str
|
||||||
|
server_ids: List[str] = []
|
||||||
|
|
||||||
|
class PrankExecute(BaseModel):
|
||||||
|
command_id: str
|
||||||
|
target_player: str
|
||||||
|
server_id: str
|
@ -14,6 +14,8 @@ class CommandService:
|
|||||||
"command": command_data.command,
|
"command": command_data.command,
|
||||||
"server_ip": command_data.server_ip,
|
"server_ip": command_data.server_ip,
|
||||||
"require_online_player": command_data.require_online_player,
|
"require_online_player": command_data.require_online_player,
|
||||||
|
"target_message": command_data.target_message if hasattr(command_data, 'target_message') else None,
|
||||||
|
"global_message": command_data.global_message if hasattr(command_data, 'global_message') else None,
|
||||||
"created_at": datetime.now().isoformat()
|
"created_at": datetime.now().isoformat()
|
||||||
}
|
}
|
||||||
print(f"[{datetime.now()}] Добавлена команда: {command_data.command} "
|
print(f"[{datetime.now()}] Добавлена команда: {command_data.command} "
|
||||||
@ -26,7 +28,13 @@ class CommandService:
|
|||||||
try:
|
try:
|
||||||
# Получаем команды для указанного сервера
|
# Получаем команды для указанного сервера
|
||||||
commands = [
|
commands = [
|
||||||
{"id": cmd_id, "command": cmd["command"], "require_online_player": cmd["require_online_player"]}
|
{
|
||||||
|
"id": cmd_id,
|
||||||
|
"command": cmd["command"],
|
||||||
|
"require_online_player": cmd["require_online_player"],
|
||||||
|
"target_message": cmd.get("target_message"),
|
||||||
|
"global_message": cmd.get("global_message")
|
||||||
|
}
|
||||||
for cmd_id, cmd in pending_commands.items()
|
for cmd_id, cmd in pending_commands.items()
|
||||||
if cmd["server_ip"] == server_ip
|
if cmd["server_ip"] == server_ip
|
||||||
]
|
]
|
||||||
|
@ -3,68 +3,274 @@ from datetime import datetime
|
|||||||
import json
|
import json
|
||||||
from app.services.coins import CoinsService
|
from app.services.coins import CoinsService
|
||||||
from app.models.server.event import PlayerEvent, OnlinePlayersUpdate
|
from app.models.server.event import PlayerEvent, OnlinePlayersUpdate
|
||||||
|
import uuid
|
||||||
|
|
||||||
class EventService:
|
class EventService:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.coins_service = CoinsService()
|
self.coins_service = CoinsService()
|
||||||
|
|
||||||
async def process_event(self, event_data: dict):
|
async def process_event(self, event_data):
|
||||||
|
"""Обработка событий от сервера Minecraft"""
|
||||||
try:
|
try:
|
||||||
|
# Проверяем формат ваших событий (event_type вместо type)
|
||||||
event_type = event_data.get("event_type")
|
event_type = event_data.get("event_type")
|
||||||
server_ip = event_data.get("server_ip", "unknown")
|
if not event_type:
|
||||||
|
# Для совместимости со старым форматом
|
||||||
|
event_type = event_data.get("type")
|
||||||
|
|
||||||
|
if not event_type:
|
||||||
|
raise HTTPException(status_code=400, detail="Missing event type")
|
||||||
|
|
||||||
if event_type == "player_join":
|
server_ip = event_data.get("server_ip")
|
||||||
player_name = event_data["player_name"]
|
if not server_ip:
|
||||||
player_id = event_data["player_id"]
|
raise HTTPException(status_code=400, detail="Missing server IP")
|
||||||
print(f"[{datetime.now()}] Игрок вошел: {player_name} (ID: {player_id}) "
|
|
||||||
f"IP сервера: {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":
|
elif event_type == "player_quit":
|
||||||
player_name = event_data["player_name"]
|
player_id = event_data.get("player_id")
|
||||||
player_id = event_data["player_id"]
|
player_name = event_data.get("player_name")
|
||||||
print(f"[{datetime.now()}] Игрок вышел: {player_name} (ID: {player_id}) "
|
|
||||||
f"IP сервера: {server_ip}")
|
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":
|
elif event_type == "player_session":
|
||||||
player_name = event_data["player_name"]
|
player_id = event_data.get("player_id")
|
||||||
player_id = event_data["player_id"]
|
player_name = event_data.get("player_name")
|
||||||
duration = event_data["duration"]
|
duration = event_data.get("duration", 0)
|
||||||
|
|
||||||
# Обновляем монеты через выделенный сервис
|
if not player_id or not player_name:
|
||||||
await self.coins_service.update_player_coins(player_id, player_name, duration, server_ip)
|
raise HTTPException(status_code=400, detail="Missing player data")
|
||||||
|
|
||||||
print(f"[{datetime.now()}] Игрок {player_name} провел на сервере: {duration} секунд "
|
|
||||||
f"IP сервера: {server_ip}")
|
|
||||||
|
|
||||||
elif event_type == "online_players_update":
|
|
||||||
players = event_data["players"]
|
|
||||||
print(f"\n[{datetime.now()}] Текущие онлайн-игроки ({len(players)}): "
|
|
||||||
f"IP сервера: {server_ip}")
|
|
||||||
|
|
||||||
# Обрабатываем каждого игрока
|
|
||||||
for player in players:
|
|
||||||
player_id = player["player_id"]
|
|
||||||
player_name = player["player_name"]
|
|
||||||
online_time = player["online_time"]
|
|
||||||
|
|
||||||
# Обновляем монеты через выделенный сервис
|
# Обрабатываем информацию о сессии
|
||||||
await self.coins_service.update_player_coins(
|
await self._process_player_session(server_ip, player_id, player_name, duration)
|
||||||
player_id, player_name, online_time, server_ip
|
return {"status": "success"}
|
||||||
)
|
|
||||||
|
|
||||||
hours, remainder = divmod(online_time, 3600)
|
|
||||||
minutes, seconds = divmod(remainder, 60)
|
|
||||||
print(f" - {player_name} (ID: {player_id}) "
|
|
||||||
f"Онлайн: {hours}ч {minutes}м {seconds}с")
|
|
||||||
print()
|
|
||||||
|
|
||||||
else:
|
|
||||||
print(f"[{datetime.now()}] Неизвестное событие: {json.dumps(event_data, indent=2)}")
|
|
||||||
raise HTTPException(status_code=400, detail="Invalid event type")
|
|
||||||
|
|
||||||
return {"status": "success", "message": "Event processed"}
|
|
||||||
|
|
||||||
|
# Если тип события не распознан
|
||||||
|
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:
|
except Exception as e:
|
||||||
print(f"[{datetime.now()}] Ошибка обработки события: {str(e)}")
|
print(f"[{datetime.now()}] Необработанная ошибка: {str(e)}")
|
||||||
print(f"Полученные данные: {json.dumps(event_data, indent=2)}")
|
print(f"Полученные данные: {event_data}")
|
||||||
raise HTTPException(status_code=400, detail=str(e))
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
await game_servers_collection.insert_one(server_data)
|
||||||
|
print(f"[{datetime.utcnow()}] Зарегистрирован новый сервер: {server_ip}")
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# Получаем ID сервера
|
||||||
|
server = await self._register_server(server_ip, {})
|
||||||
|
server_id = server["id"]
|
||||||
|
|
||||||
|
# Помечаем всех игроков как оффлайн на этом сервере
|
||||||
|
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} сек.")
|
||||||
|
264
app/services/server/prank.py
Normal file
264
app/services/server/prank.py
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
from fastapi import HTTPException
|
||||||
|
from app.db.database import db, users_collection
|
||||||
|
from app.models.server.prank import PrankCommand, PrankCommandUpdate
|
||||||
|
from datetime import datetime
|
||||||
|
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):
|
||||||
|
"""Получение списка всех доступных серверов"""
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
|
||||||
|
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"]
|
||||||
|
}
|
3
main.py
3
main.py
@ -1,6 +1,6 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from app.api import users, skins, capes, meta, server, store
|
from app.api import users, skins, capes, meta, server, store, pranks
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
@ -11,6 +11,7 @@ app.include_router(skins.router)
|
|||||||
app.include_router(capes.router)
|
app.include_router(capes.router)
|
||||||
app.include_router(server.router)
|
app.include_router(server.router)
|
||||||
app.include_router(store.router)
|
app.include_router(store.router)
|
||||||
|
app.include_router(pranks.router)
|
||||||
|
|
||||||
# Монтируем статику
|
# Монтируем статику
|
||||||
app.mount("/skins", StaticFiles(directory="app/static/skins"), name="skins")
|
app.mount("/skins", StaticFiles(directory="app/static/skins"), name="skins")
|
||||||
|
Reference in New Issue
Block a user