From a750a5914c356dc044941e4b69919ffd9a1f3b51 Mon Sep 17 00:00:00 2001 From: plun1331 Date: Fri, 14 Aug 2026 00:12:10 -0700 Subject: [PATCH 1/4] Return data from Hypixel API response Return the JSON data from the response instead of None. --- extensions/game_commands/game_commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/game_commands/game_commands.py b/extensions/game_commands/game_commands.py index 78a7504..55ab5d7 100644 --- a/extensions/game_commands/game_commands.py +++ b/extensions/game_commands/game_commands.py @@ -183,7 +183,7 @@ async def hypixel_request(self, *args, **kwargs): data = await resp.json() if resp.status not in (200, 404): print(f"{Color.MAGENTA}Game Commands{Color.RESET} > {Color.RED}[ERROR]{Color.RESET} Non-OK response from Hypixel: {data}") - return + return data async def cog_unload(self) -> None: if self.session is not None: From 532bb2c98c24085d6d2b636791896a0915abc9a5 Mon Sep 17 00:00:00 2001 From: plun1331 Date: Sat, 15 Aug 2026 15:20:11 -0700 Subject: [PATCH 2/4] feat: keep track of guild members, do not mess with people not in the guild --- extensions/mute_sync.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/extensions/mute_sync.py b/extensions/mute_sync.py index db81594..a9a9ec7 100644 --- a/extensions/mute_sync.py +++ b/extensions/mute_sync.py @@ -27,6 +27,7 @@ class MuteSync(commands.Cog): def __init__(self, bot): self.bot = bot self.mutes = {} # (discord id, uuid): datetime + self.guild_members: set[str] = set() self._sess: aiohttp.ClientSession | None = None self.mute_task: tuple[asyncio.Task, datetime] | None = None self._syncing = False @@ -98,6 +99,20 @@ async def get_discord_user(self, uuid): return int(data["data"]["userid"]) return None + async def get_minecraft_uuid(self, userid): + session = await self.get_session() + async with session.get( + f"{self.skykings_api_url}/user/info?userid={userid}", + headers={"Authorization": self.skykings_api_key}, + ) as resp: + if resp.status == 404: + return None + if resp.status != 200: + resp.raise_for_status() + data = await resp.json() + return int(data["data"]["uuid"]) + return None + async def get_guild_mutes(self): # wait for this to be populated while self.bot.mineflayer_bot.bot.username is None: @@ -115,6 +130,7 @@ async def get_guild_mutes(self): guild = data["guild"] if guild is None: return [] + self.guild_members = set(member["uuid"] for member in guild["members"]) for member in guild["members"]: uuid = member["uuid"] discord_id = await self.get_discord_user(uuid) @@ -236,6 +252,17 @@ async def on_hypixel_guild_member_unmuted(self, _, player): # hypixel does not allow specific durations (e.g. 1d 1h, only 1h or 1d) await self.process_new_unmute(player) + @commands.Cog.listener() + async def on_hypixel_guild_member_join(self, player): + uuid = await self.get_uuid(player) + self.guild_members.add(uuid) + + @commands.Cog.listener() + async def on_hypixel_guild_member_leave(self, player): + uuid = await self.get_uuid(player) + if uuid in self.guild_members: + self.guild_members.remove(uuid) + @tasks.loop(hours=12) async def sync_task(self): print("waiting for ready") @@ -258,6 +285,9 @@ async def on_sync_task_error(self, exc): async def on_member_join(self, member): if member.id is None: return + # is the user in our guild? + if member.guild.id != MuteSyncConfig.guild_id: + return # find the mute for (discord_id, uuid), expiry in dict(self.mutes).items(): if discord_id == member.id: @@ -272,6 +302,7 @@ async def on_member_update(self, before, after): return # check if mute is still valid valid = False + # if they have a current mute, they are obviously in our guild for (discord_id, uuid), expiry in dict(self.mutes).items(): if discord_id == after.id: if expiry > datetime.datetime.now(): @@ -280,9 +311,18 @@ async def on_member_update(self, before, after): role = after.guild.get_role(MuteSyncConfig.mute_role) await after.add_roles(role, reason="UPDATE: User has an active guild mute") break + # if they do not, they might be in a different guild. check if they are in our guild if not valid: if MuteSyncConfig.mute_role in [role.id for role in after.roles]: role = after.guild.get_role(MuteSyncConfig.mute_role) + uuid = await self.get_minecraft_uuid(after.id) + if uuid is None: + # not even verified, shouldn't have role + await after.remove_roles(role, reason="UPDATE: User has no active guild mute") + return + if uuid not in self.guild_members: + # not in our guild + return await after.remove_roles(role, reason="UPDATE: User has no active guild mute") From 46737d2dde08250c4cbb85332ed15aa9efa9fc1b Mon Sep 17 00:00:00 2001 From: plun1331 Date: Sat, 15 Aug 2026 15:20:47 -0700 Subject: [PATCH 3/4] chore: remove debugging prints --- extensions/mute_sync.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/extensions/mute_sync.py b/extensions/mute_sync.py index a9a9ec7..6816aeb 100644 --- a/extensions/mute_sync.py +++ b/extensions/mute_sync.py @@ -265,13 +265,10 @@ async def on_hypixel_guild_member_leave(self, player): @tasks.loop(hours=12) async def sync_task(self): - print("waiting for ready") await self.bot.wait_until_ready() - print("bot ready") guild = self.bot.get_channel(DiscordConfig.channel).guild if self.bot.mineflayer_bot is None or not self.bot.mineflayer_bot.is_ready(): await asyncio.sleep(.5) - print("mc ready") if not self._syncing: self._syncing = True await self.sync_mutes() From 6a6a07c3a3e3f118bb01ebd1a34574c184301f2b Mon Sep 17 00:00:00 2001 From: plun1331 Date: Sat, 15 Aug 2026 16:27:08 -0700 Subject: [PATCH 4/4] Return UUID as string instead of integer --- extensions/mute_sync.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/mute_sync.py b/extensions/mute_sync.py index 6816aeb..cfdaf65 100644 --- a/extensions/mute_sync.py +++ b/extensions/mute_sync.py @@ -110,7 +110,7 @@ async def get_minecraft_uuid(self, userid): if resp.status != 200: resp.raise_for_status() data = await resp.json() - return int(data["data"]["uuid"]) + return data["data"]["uuid"] return None async def get_guild_mutes(self):