diff --git a/app/services/coins.py b/app/services/coins.py index ce92496..1e941b8 100644 --- a/app/services/coins.py +++ b/app/services/coins.py @@ -1,4 +1,5 @@ from datetime import datetime +import re from app.db.database import users_collection from fastapi import HTTPException from app.db.database import db @@ -8,58 +9,67 @@ MAX_MINUTES_PER_UPDATE = 120 coins_sessions_collection = db.coins_sessions class CoinsService: + _AFK_PREFIX_RE = re.compile(r"^\s*\[\s*AFK\s*\]", re.IGNORECASE) + + @classmethod + def _is_afk_name(cls, player_name: str) -> bool: + if not player_name: + return False + return bool(cls._AFK_PREFIX_RE.match(player_name)) + async def update_player_coins(self, player_id: str, player_name: str, online_time: int, server_ip: str): """Обновляет монеты игрока на основе времени онлайн""" - - # Находим пользователя + user = await self._find_user_by_uuid(player_id) if not user: - return # Пользователь не найден - - # Находим последнее обновление монет + return + last_update = await coins_sessions_collection.find_one({ "player_id": player_id, "server_ip": server_ip, "update_type": "coins_update" }, sort=[("timestamp", -1)]) - - now = datetime.now() + + now = datetime.utcnow() + + # AFK: монеты не начисляем, но обязательно фиксируем тик, + # чтобы AFK-время не накопилось и не начислилось потом. + if self._is_afk_name(player_name): + await coins_sessions_collection.insert_one({ + "player_id": player_id, + "player_name": player_name, + "server_ip": server_ip, + "update_type": "coins_update", + "timestamp": now, + "minutes_added": 0, + "coins_added": 0, + "note": "afk_skip" + }) + return + current_coins = user.get("coins", 0) current_total_time = user.get("total_time_played", 0) - + if last_update: - # Время с последнего начисления - last_timestamp = last_update["timestamp"] - seconds_since_update = int((now - last_timestamp).total_seconds()) - - # Начисляем монеты только за полные минуты, - # но не больше 1 минуты за одно событие + seconds_since_update = int((now - last_update["timestamp"]).total_seconds()) minutes_to_reward = seconds_since_update // 60 if minutes_to_reward < 1: return - # ВАЖНО: не позволяем начислить больше 1 минуты за один апдейт minutes_to_reward = min(minutes_to_reward, 1) else: - # Первое обновление (ограничиваем для безопасности) minutes_to_reward = min(online_time // 60, 5) - + if minutes_to_reward > 0: - # Обновляем монеты и время new_coins = current_coins + minutes_to_reward new_total_time = current_total_time + (minutes_to_reward * 60) - - # Сохраняем в БД + await users_collection.update_one( {"_id": user["_id"]}, - {"$set": { - "coins": new_coins, - "total_time_played": new_total_time - }} + {"$set": {"coins": new_coins, "total_time_played": new_total_time}} ) - - # Сохраняем запись о начислении + await coins_sessions_collection.insert_one({ "player_id": player_id, "player_name": player_name, @@ -69,9 +79,6 @@ class CoinsService: "minutes_added": minutes_to_reward, "coins_added": minutes_to_reward }) - - print(f"[{now}] Игроку {user.get('username')} начислено {minutes_to_reward} монет. " - f"Всего монет: {new_coins}") async def _find_user_by_uuid(self, player_id: str): """Находит пользователя по UUID с поддержкой разных форматов""" diff --git a/app/services/server/event.py b/app/services/server/event.py index 3956e7e..25163d7 100644 --- a/app/services/server/event.py +++ b/app/services/server/event.py @@ -39,7 +39,7 @@ class EventService: for p in players: name = p.get("player_name") - if name: + if name and not self.coins_service._is_afk_name(name): await DailyQuestsService().on_active_time_tick(name, tick_seconds) return {"status": "success"}