This repository has been archived on 2025-02-16. You can view files and clone it, but cannot push or open issues or pull requests.
Spiffo/cogs/players.py
Corban-Lee Jones 77cb214276
All checks were successful
Build and Push Docker Image / build (push) Successful in 23s
debug mode var and ingame_channel shorthand getter
2024-12-11 15:37:19 +00:00

160 lines
5.2 KiB
Python

"""
Handles tasks related to in-game players, such as connect/disconnect alerts.
"""
import re
import logging
from os import getenv
from pathlib import Path
from datetime import datetime
from discord import Colour
from discord.ext import commands, tasks
from utils.reader import LogFileReader
from utils.models import Player
ZOMBOID_FOLDER_PATH = Path(getenv("SPIFFO__ZOMBOID_FOLDER_PATH"))
LOGS_FOLDER_PATH = ZOMBOID_FOLDER_PATH / "Logs"
USER_LOG_FILE_PATH = next(LOGS_FOLDER_PATH.glob("*_user.txt"), None)
log = logging.getLogger(__name__)
class PlayersCog(commands.Cog):
"""
Handles tasks related to in-game players.
"""
file_handler: LogFileReader
def __init__(self, bot: commands.Bot):
self.bot = bot
self.file_handler = LogFileReader(USER_LOG_FILE_PATH)
self.listen_for_changes.start()
@tasks.loop(seconds=3)
async def listen_for_changes(self):
"""
"""
log.debug("listening for changes")
for line in await self.file_handler.read():
await self.process_log_line(line)
async def process_log_line(self, line: str):
log.debug("processing log line")
if "died" in line:
await self.process_player_death(line)
elif "fully connected" in line:
await self.process_connected_player(line)
elif "disconnected player" in line:
await self.process_disconnected_player(line)
async def process_player_death(self, line: str, alert: bool = False):
log.debug("processing player death")
re_pattern = r"\[(?P<timestamp>[\d\- :\.]+)\] user (?P<username>.+?) died at \((?P<x>\d+),(?P<y>\d+),(?P<z>\d+)\) \((?P<cause>.+?)\)"
re_match = re.search(re_pattern, line)
if not re_match:
log.warning("failed to parse player death log: %s", line)
return
username = re_match.group("username")
player = await Player.get_or_none(username=username)
if not player:
log.warning("Player returned none, cannot add death: %s", username)
return
await player.add_death(
coord_x=re_match.group("x"),
coord_y=re_match.group("y"),
coord_z=re_match.group("z"),
cause=re_match.group("cause"),
timestamp=datetime.strptime(
re_match.group("timestamp"),
"%m-%d-%y %H:%M:%S.%f"
)
)
await player.save()
log.debug("successfully registered player death to %s", re_match.group("username"))
if not alert:
return
channel = await self.bot.get_ingame_channel()
embed = await player.get_embed()
embed.title = "Player Has Died"
embed.colour = Colour.dark_orange()
await channel.send(embed=embed)
async def process_connected_player(self, line: str, alert: bool = False):
"""
"""
log.debug("processing connected player")
re_pattern = r'\[(?P<timestamp>.*?)\] (?P<steam_id>\d+) "(?P<username>.*?)" fully connected \((?P<coordinates>\d+,\d+,\d+)\)'
re_match = re.search(re_pattern, line)
if not re_match:
log.warning("Failed to parse player data: %s", line)
return
player, created = await Player.get_or_create(username=re_match.group("username"))
player.last_connection = datetime.strptime(
re_match.group("timestamp"),
"%m-%d-%y %H:%M:%S.%f"
)
await player.update_steam_summary(re_match.group("steam_id"), self.bot.steam_api_key)
await player.save()
# This connection method is called when the player respawns
if player.is_dead:
player.is_dead = False # player must be alive if fully connected
await player.save()
return
if not alert:
return
channel = await self.bot.get_ingame_channel()
embed = await player.get_embed()
embed.title = "Player Has Connected"
embed.colour = Colour.brand_green()
await channel.send(embed=embed)
async def process_disconnected_player(self, line: str, alert: bool = False):
"""
"""
log.debug("processing disconnected player")
re_pattern = r'\[(?P<timestamp>.*?)\] (?P<steam_id>\d+) "(?P<username>.*?)" disconnected player \((?P<coordinates>\d+,\d+,\d+)\)'
re_match = re.search(re_pattern, line)
if not re_match:
log.warning("Failed to parse player data: %s", line)
return
player, created = await Player.get_or_create(username=re_match.group("username"))
player.last_disconnection = datetime.strptime(
re_match.group("timestamp"),
"%m-%d-%y %H:%M:%S.%f"
)
await player.update_steam_summary(re_match.group("steam_id"), self.bot.steam_api_key)
await player.save()
if player.is_dead or not alert:
return
channel = await self.bot.get_ingame_channel()
embed = await player.get_embed()
embed.title = "Player Has Disconnected"
embed.colour = Colour.brand_red()
await channel.send(embed=embed)
async def setup(bot: commands.Bot):
cog = PlayersCog(bot)
await bot.add_cog(cog)
log.info("Added %s cog", cog.__class__.__name__)