From 16a2ba3b1fdb6ea11b7e0f4a35e99372e3744b7e Mon Sep 17 00:00:00 2001 From: SimolZimol <70102430+SimolZimol@users.noreply.github.com> Date: Mon, 27 Oct 2025 18:50:57 +0100 Subject: [PATCH] modified: app.py --- app.py | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/app.py b/app.py index e78dcf2..c6889d5 100644 --- a/app.py +++ b/app.py @@ -136,6 +136,81 @@ TEAM_EMOTE_OVERRIDES: Dict[str, str] = { "default": "<:neutrality:1432391681059197102>", } +# Role mapping for ELO tiers (IDs provided by user) +# Assumption: Top tier is >= 900 ELO rather than strictly >900, +# to avoid leaving 900 unassigned. Adjust if you want 900 handled differently. +STANDARD_ELO_ROLE_IDS = { + "gte_900": 1432368177014374497, + "851_899": 1432368177014374496, + "801_850": 1432368177014374495, + "eq_800": 1432368177014374494, + "751_799": 1432368177014374493, + "701_750": 1432368177014374492, + "lt_700": 1432368177014374491, +} + +COMPETITIVE_ELO_ROLE_IDS = { + "gte_900": 1432368177030893672, + "851_899": 1432368177030893671, + "801_850": 1432368177030893670, + "eq_800": 1432368177030893669, + "751_799": 1432368177030893668, + "701_750": 1432368177014374499, + "lt_700": 1432368177014374498, +} + +def _role_id_for_elo(elo: int, category: str) -> Optional[int]: + """Return the role ID for the given ELO and category ('standard'|'competitive').""" + ids = STANDARD_ELO_ROLE_IDS if category == "standard" else COMPETITIVE_ELO_ROLE_IDS + if elo >= 900: + return ids["gte_900"] + if 851 <= elo <= 899: + return ids["851_899"] + if 801 <= elo <= 850: + return ids["801_850"] + if elo == 800: + return ids["eq_800"] + if 751 <= elo <= 799: + return ids["751_799"] + if 701 <= elo <= 750: + return ids["701_750"] + # < 700 + return ids["lt_700"] + +def _category_role_ids(category: str) -> List[int]: + ids = STANDARD_ELO_ROLE_IDS if category == "standard" else COMPETITIVE_ELO_ROLE_IDS + return list(ids.values()) + +async def update_member_elo_role(member: discord.Member, elo: int, category: str, reason: Optional[str] = None): + """Ensure the member has exactly one rank role for the given category matching their ELO. + - category: 'standard' or 'competitive' + """ + if member is None or member.guild is None: + return + try: + guild = member.guild + target_role_id = _role_id_for_elo(elo, category) + if not target_role_id: + return + target_role = guild.get_role(int(target_role_id)) + if not target_role: + return # Role not found in this guild + + # Remove any other roles from the same category + category_ids = set(_category_role_ids(category)) + roles_to_remove = [r for r in member.roles if r.id in category_ids and r.id != target_role.id] + if roles_to_remove: + await member.remove_roles(*roles_to_remove, reason=reason) + + # Add the target role if missing + if target_role not in member.roles: + await member.add_roles(target_role, reason=reason) + except discord.Forbidden: + # Missing permissions or role hierarchy issue + logging.warning(f"Insufficient permissions to modify roles for {member} in category {category}") + except discord.HTTPException as e: + logging.warning(f"Failed to update roles for {member}: {e}") + # Emoji and formatting helpers def _all_accessible_emojis(ctx: commands.Context) -> List[discord.Emoji]: """Return emojis from current guild plus all guilds the bot is in.""" @@ -777,6 +852,27 @@ async def hoi4end(ctx, game_name: str, winner_team: str): "UPDATE games SET status = 'finished', winner_team = %s, finished_at = CURRENT_TIMESTAMP WHERE id = %s", (final_result, game['id']) ) + + # After DB updates, try to sync Discord roles for affected players (only for this game's category) + try: + guild = ctx.guild + if guild: + for change in elo_changes: + member = guild.get_member(change['discord_id']) + if member is None: + try: + member = await guild.fetch_member(change['discord_id']) + except Exception: + member = None + if member: + await update_member_elo_role( + member, + change['new_elo'], + game['game_type'], + reason=f"HOI4 {game['game_type']} ELO updated in '{game_name}'" + ) + except Exception as e: + logging.warning(f"Role sync after game end failed: {e}") # Create result embed if is_draw: @@ -963,6 +1059,16 @@ async def hoi4stats(ctx, user: Optional[discord.Member] = None): ) await ctx.send(embed=embed) + + # Try to keep user's roles in sync for both categories when stats are viewed + try: + if ctx.guild and isinstance(target_user, discord.Member): + await update_member_elo_role( + target_user, player['standard_elo'], 'standard', reason='HOI4 stats viewed: role sync') + await update_member_elo_role( + target_user, player['competitive_elo'], 'competitive', reason='HOI4 stats viewed: role sync') + except Exception as e: + logging.warning(f"Role sync on stats failed: {e}") except Exception as e: await ctx.send(f"❌ Error getting stats: {str(e)}")