fix afk server logic

This commit is contained in:
2025-12-20 12:23:35 +05:00
parent bb74dbbba7
commit 41711d68c8
2 changed files with 37 additions and 30 deletions

View File

@ -1,4 +1,5 @@
from datetime import datetime from datetime import datetime
import re
from app.db.database import users_collection from app.db.database import users_collection
from fastapi import HTTPException from fastapi import HTTPException
from app.db.database import db from app.db.database import db
@ -8,58 +9,67 @@ MAX_MINUTES_PER_UPDATE = 120
coins_sessions_collection = db.coins_sessions coins_sessions_collection = db.coins_sessions
class CoinsService: 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): 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) user = await self._find_user_by_uuid(player_id)
if not user: if not user:
return # Пользователь не найден return
# Находим последнее обновление монет
last_update = await coins_sessions_collection.find_one({ last_update = await coins_sessions_collection.find_one({
"player_id": player_id, "player_id": player_id,
"server_ip": server_ip, "server_ip": server_ip,
"update_type": "coins_update" "update_type": "coins_update"
}, sort=[("timestamp", -1)]) }, 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_coins = user.get("coins", 0)
current_total_time = user.get("total_time_played", 0) current_total_time = user.get("total_time_played", 0)
if last_update: if last_update:
# Время с последнего начисления seconds_since_update = int((now - last_update["timestamp"]).total_seconds())
last_timestamp = last_update["timestamp"]
seconds_since_update = int((now - last_timestamp).total_seconds())
# Начисляем монеты только за полные минуты,
# но не больше 1 минуты за одно событие
minutes_to_reward = seconds_since_update // 60 minutes_to_reward = seconds_since_update // 60
if minutes_to_reward < 1: if minutes_to_reward < 1:
return return
# ВАЖНО: не позволяем начислить больше 1 минуты за один апдейт
minutes_to_reward = min(minutes_to_reward, 1) minutes_to_reward = min(minutes_to_reward, 1)
else: else:
# Первое обновление (ограничиваем для безопасности)
minutes_to_reward = min(online_time // 60, 5) minutes_to_reward = min(online_time // 60, 5)
if minutes_to_reward > 0: if minutes_to_reward > 0:
# Обновляем монеты и время
new_coins = current_coins + minutes_to_reward new_coins = current_coins + minutes_to_reward
new_total_time = current_total_time + (minutes_to_reward * 60) new_total_time = current_total_time + (minutes_to_reward * 60)
# Сохраняем в БД
await users_collection.update_one( await users_collection.update_one(
{"_id": user["_id"]}, {"_id": user["_id"]},
{"$set": { {"$set": {"coins": new_coins, "total_time_played": new_total_time}}
"coins": new_coins,
"total_time_played": new_total_time
}}
) )
# Сохраняем запись о начислении
await coins_sessions_collection.insert_one({ await coins_sessions_collection.insert_one({
"player_id": player_id, "player_id": player_id,
"player_name": player_name, "player_name": player_name,
@ -69,9 +79,6 @@ class CoinsService:
"minutes_added": minutes_to_reward, "minutes_added": minutes_to_reward,
"coins_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): async def _find_user_by_uuid(self, player_id: str):
"""Находит пользователя по UUID с поддержкой разных форматов""" """Находит пользователя по UUID с поддержкой разных форматов"""

View File

@ -39,7 +39,7 @@ class EventService:
for p in players: for p in players:
name = p.get("player_name") 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) await DailyQuestsService().on_active_time_tick(name, tick_seconds)
return {"status": "success"} return {"status": "success"}