fix afk server logic
This commit is contained in:
@ -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 с поддержкой разных форматов"""
|
||||||
|
|||||||
@ -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"}
|
||||||
|
|||||||
Reference in New Issue
Block a user