Improved achievement logic #268_achievements

This commit is contained in:
2023-07-13 13:54:13 +02:00
parent cab65477b0
commit 184d241695
17 changed files with 375 additions and 112 deletions

View File

@@ -0,0 +1,78 @@
from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_discord.service import DiscordBotServiceABC
from cpl_translation import TranslatePipe
from bot_core.configuration.server_settings import ServerSettings
from bot_core.service.message_service import MessageService
from bot_data.abc.achievement_repository_abc import AchievementRepositoryABC
from bot_data.model.achievement import Achievement
from bot_data.model.user import User
from bot_data.model.user_got_achievement import UserGotAchievement
class AchievementService:
def __init__(
self,
config: ConfigurationABC,
logger: LoggerABC,
bot: DiscordBotServiceABC,
achievements: AchievementRepositoryABC,
db: DatabaseContextABC,
message_service: MessageService,
t: TranslatePipe,
):
self._config = config
self._logger = logger
self._bot = bot
self._achievements = achievements
self._db = db
self._message_service = message_service
self._t = t
def _match(self, value: str, operator: str, expected_value: str) -> bool:
match operator:
case "==":
return value == expected_value
case "!=":
return value != expected_value
case "<=":
return value <= expected_value
case ">=":
return value >= expected_value
case "<":
return value < expected_value
case ">":
return value > expected_value
case _:
raise ValueError(f"Invalid operator: ${operator}")
def has_user_achievement_already(self, user: User, achievement: Achievement) -> bool:
user_achievements = self._achievements.get_achievements_by_user_id(user.id)
return user_achievements.where(lambda x: x.name == achievement.name).count() > 0
def has_user_achievement(self, user: User, achievement: Achievement) -> bool:
return self._match(str(getattr(user, achievement.attribute)), achievement.operator, achievement.value)
async def validate_achievements_for_user(self, user: User):
achievements = self._achievements.get_achievements_by_server_id(user.server.id)
for achievement in achievements:
if self.has_user_achievement_already(user, achievement) and not self.has_user_achievement(
user, achievement
):
continue
self._achievements.add_user_got_achievement(UserGotAchievement(user, achievement, user.server))
self._db.save_changes()
await self._send_achievement_notification(user.server.discord_id, user.discord_id, achievement.name)
async def _send_achievement_notification(self, guild_id: int, member_id: int, achievement_name: str):
member = self._bot.get_guild(guild_id).get_member(member_id)
settings: ServerSettings = self._config.get_configuration(f"ServerSettings_{guild_id}")
await self._message_service.send_channel_message(
self._bot.get_channel(settings.notification_chat_id),
self._t.transform("modules.achievements.got_new_achievement").format(member.mention, achievement_name),
is_persistent=True,
)

View File

@@ -1,10 +1,13 @@
from cpl_core.configuration import ConfigurationABC
from cpl_core.dependency_injection import ServiceCollectionABC
from cpl_core.environment import ApplicationEnvironmentABC
from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum
from cpl_discord.service.discord_collection_abc import DiscordCollectionABC
from bot_core.abc.module_abc import ModuleABC
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from modules.achievements.achievement_service import AchievementService
from modules.achievements.events.achievement_on_message_event import AchievementOnMessageEvent
class AchievementsModule(ModuleABC):
@@ -15,4 +18,5 @@ class AchievementsModule(ModuleABC):
pass
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
pass
services.add_transient(AchievementService)
self._dc.add_event(DiscordEventTypesEnum.on_message.value, AchievementOnMessageEvent)

View File

@@ -0,0 +1 @@
# imports

View File

@@ -0,0 +1,43 @@
import discord
from cpl_core.database.context import DatabaseContextABC
from cpl_core.logging import LoggerABC
from cpl_discord.events import OnMessageABC
from cpl_discord.service import DiscordBotServiceABC
from bot_core.helper.event_checks import EventChecks
from bot_data.abc.server_repository_abc import ServerRepositoryABC
from bot_data.abc.user_repository_abc import UserRepositoryABC
from modules.achievements.achievement_service import AchievementService
class AchievementOnMessageEvent(OnMessageABC):
def __init__(
self,
logger: LoggerABC,
bot: DiscordBotServiceABC,
achievements: AchievementService,
db: DatabaseContextABC,
servers: ServerRepositoryABC,
users: UserRepositoryABC,
):
OnMessageABC.__init__(self)
self._logger = logger
self._bot = bot
self._achievements = achievements
self._db = db
self._servers = servers
self._users = users
@EventChecks.check_is_ready()
async def on_message(self, message: discord.Message):
if message.author.bot:
return
server = self._servers.get_server_by_discord_id(message.guild.id)
user = self._users.get_user_by_discord_id_and_server_id(message.author.id, server.id)
user.message_count += 1
self._db.save_changes()
await self._achievements.validate_achievements_for_user(user)