diff --git a/core/buddy_service.py b/core/buddy_service.py index f79675f..5b5aa79 100644 --- a/core/buddy_service.py +++ b/core/buddy_service.py @@ -109,6 +109,23 @@ class BuddyService: else: return False + def remove_buddy_type(self, chars: [], _type: str, force_remove=False): + removed = 0 + if len(chars) < 1: + return removed + for bot, buddylist in self.buddy_list.items(): + for x in buddylist.keys(): + if x not in chars: + continue + if _type not in buddylist[x]['types']: + continue + buddylist[x]["types"].remove(_type) + if len(buddylist[x]["types"]) == 0 or force_remove: + conn = self.bot.conns[buddylist[x]["conn_id"]] + conn.send_packet(client_packets.BuddyRemove(x)) + removed += 1 + return removed + def get_buddy(self, char_id): for conn_id, conn_buddy_list in self.buddy_list.items(): if char_id in conn_buddy_list: diff --git a/core/igncore.py b/core/igncore.py index 69c8fc9..ce8ad91 100644 --- a/core/igncore.py +++ b/core/igncore.py @@ -48,7 +48,7 @@ class IgnCore: self.last_timer_event = 0 self.start_time = int(time.time()) self.major_version = "IGNCore v2.9" - self.minor_version = "2" + self.minor_version = "3" self.incoming_queue = FifoQueue() self.mass_message_queue = None self.conns = DictObject() diff --git a/modules/core/discord/discord_command_handler.py b/modules/core/discord/discord_command_handler.py index a2752e4..073bf23 100644 --- a/modules/core/discord/discord_command_handler.py +++ b/modules/core/discord/discord_command_handler.py @@ -112,9 +112,9 @@ class DiscordCommandHandler(BaseModule): m = re.findall(r"", ctx) for match in m: ctx = ctx.replace(f"", - f"#_#{self.discord.util.get_profession(proficon.get(int(match)))}#_#") + f"{self.discord.util.get_profession(proficon.get(int(match)))}") - for x in ["`", ' *', ' _', ' |']: + for x in ["`", '*', '_', '|']: ctx = ctx.replace(x, f' \\{x.strip()}') for pattern, sub in [(r"(
|\n|
)", r"\n"), (r"(.*?)", r"**\1**"), @@ -138,7 +138,6 @@ class DiscordCommandHandler(BaseModule): (r"", "\t"), (r"\n\n", ''), (r"(.+?)", r'\1'), - ('#(.+?)#', r'\1'), ('<', '<'), ('>', '>'), (r"", ''), @@ -156,7 +155,7 @@ class DiscordCommandHandler(BaseModule): @command(command="discord", params=[Const("invite")], access_level="member", description="Get a personal Discord invite", sub_command="invite") def discord_invite_cmd(self, request, _): - if not self.discord.client: + if not self.discord.client or not self.discord.client.loop: return "Discord module has not been initiated yet. Please try again later." account = self.discord.account_service.get_account(request.sender.char_id) if account is None: @@ -262,14 +261,14 @@ class DiscordCommandHandler(BaseModule): account = self.discord.data.get_account_discord_id(member.id) if not account: - log = '**%s** has left discord (**%s**)' % (member.nick or member.name, handle) + log = '%s has left discord (%s)' % (member.nick or member.name, handle) self.relay_hub_service.send_message("system_logger", 0, log, log) self.logger.info(log) continue main = self.discord.account_service.get_main(account.char_id) if account is None: continue - log = '**%s** has left discord (**%s**)' % (main.name, handle) + log = '%s has left discord (%s)' % (main.name, handle) self.relay_hub_service.send_message("system_logger", 0, log, log) self.logger.info(log) # self.bot.send_private_channel_message("%s has left Discord (%s)" % (main.name, handle)) @@ -281,7 +280,7 @@ class DiscordCommandHandler(BaseModule): invite_used = obj.invite handle = member.name + "#" + member.discriminator if invite_used is None: - log = '**%s** joined discord with unknown invite' % handle + log = '%s joined discord with unknown invite' % handle self.relay_hub_service. \ send_message("system_logger", 0, log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, " @@ -293,13 +292,13 @@ class DiscordCommandHandler(BaseModule): self.discord.guild = self.discord.client.get_guild(self.discord.client.guilds[0].id) account = self.discord.data.get_discord_invite(invite_used.code) if account is None: - log = '**%s** joined discord with invite **%s** but couldnt find account!' % ( + log = '%s joined discord with invite %s but couldnt find account!' % ( handle, invite_used.code) self.relay_hub_service. \ send_message("system_logger", 0, - log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, " + log + f" {self.discord.get_role('Administrator', self.discord.guild.roles).mention}'s, " f"check that!", - log + f" {self.get_role('Administrator', self.guild.roles).mention}'s, " + log + f" {self.discord.get_role('Administrator', self.discord.guild.roles).mention}'s, " f"check that!") self.logger.info(log) asyncio.run_coroutine_threadsafe(self.discord.discord_member_roles(member, None, None), @@ -319,7 +318,7 @@ class DiscordCommandHandler(BaseModule): self.discord.discord_member_roles(member, account, access_level), self.discord.loop) # noinspection LongLine - log = '**%s** joined discord with invite **%s** and matches account **%s**' \ + log = '%s joined discord with invite %s and matches account %s' \ % (handle, invite_used.code, f"{f'[{self.discord.alias_controller.get_alias(main.org_id)}] ' if self.discord.setting_service.get_value('is_alliance_bot') == '1' else ''}{main.name}") self.relay_hub_service.send_message("system_logger", account.main, log, log) diff --git a/modules/orgbot/org/org_roster_controller.py b/modules/orgbot/org/org_roster_controller.py index 4c7459a..b9b6774 100644 --- a/modules/orgbot/org/org_roster_controller.py +++ b/modules/orgbot/org/org_roster_controller.py @@ -1,10 +1,10 @@ import json import time +import typing import requests from core.aochat import server_packets -from core.buddy_service import BuddyService from core.cache_service import CacheService from core.chat_blob import ChatBlob from core.command_param_types import Int @@ -14,12 +14,15 @@ from core.dict_object import DictObject from core.event_service import EventService from core.igncore import IgnCore from core.logger import Logger -from core.lookup.character_service import CharacterService -from core.lookup.org_pork_service import OrgPorkService -from core.lookup.pork_service import PorkService -from core.public_channel_service import PublicChannelService from core.util import Util -from modules.core.accounting.services.account_service import AccountService +from core.public_channel_service import PublicChannelService + +if typing.TYPE_CHECKING: + from modules.core.accounting.services.account_service import AccountService + from core.lookup.character_service import CharacterService + from core.lookup.org_pork_service import OrgPorkService + from core.lookup.pork_service import PorkService + from core.buddy_service import BuddyService @instance() @@ -129,6 +132,11 @@ class OrgRosterController: @timerevent("24h", "Update the orgroster on changes") def update_roster(self, _, _1): self.bot.send_org_message("Updating roster...") + handlers = self.event_service.get_handlers("connect", "") + conn = False + for x in handlers: + if "orgbot" in x.handler and "connect" in x.handler: + conn = True cache = self.cache.retrieve('org_roster', f"{self.public_channel_service.org_id}.5.json") if cache: if cache.last_modified < time.time() - 16 * 60 * 60: @@ -159,7 +167,8 @@ class OrgRosterController: if buddy := self.buddy_service.get_buddy(char_info['CHAR_INSTANCE']): if "org_member" in buddy['types']: continue - self.buddy_service.add_buddy(char_info['CHAR_INSTANCE'], "org_member") + if conn: + self.buddy_service.add_buddy(char_info['CHAR_INSTANCE'], "org_member") with self.db.lock: with self.db.pool.get_connection() as conn: @@ -192,6 +201,9 @@ class OrgRosterController: def org_msg_event(self, _, event_data): ext_msg = event_data.extended_message log = False + if not ext_msg: + self.logger.error(f"--UKN-- {_} -- {event_data}") + return if [ext_msg.category_id, ext_msg.instance_id] == self.LEFT_ORG: log = True self.process_org_msg(ext_msg.params[0], self.MODE_REM_MANUAL, ext_msg) diff --git a/modules/standard/helpbot/overequipped_controller.py b/modules/standard/helpbot/overequipped_controller.py index 92ddcdb..7033ec1 100644 --- a/modules/standard/helpbot/overequipped_controller.py +++ b/modules/standard/helpbot/overequipped_controller.py @@ -19,19 +19,19 @@ class OverequippedController: def oe_command(self, _, skill_level): oe = self.get_oe_vals(skill_level) - blob = "With a skill requirement of %s, you will be\n" % skill_level - blob += "Out of OE: %d or higher\n" % oe.oe100low - blob += "75%%: %d to %d\n" % (oe.oe75low, oe.oe100low - 1) - blob += "50%%: %d to %d\n" % (oe.oe50low, oe.oe75low - 1) - blob += "25%%: %d to %d\n" % (oe.oe25low, oe.oe50low - 1) - blob += "0%%: %d or lower\n\n" % (oe.oe25low - 1) + blob = f"With a skill requirement of {skill_level}, you will be\n" + blob += f"Out of OE: {oe.oe100low} or higher\n" + blob += f"75%: {oe.oe75low} to {oe.oe100low - 1}\n" + blob += f"50%: {oe.oe50low} to {oe.oe75low - 1}\n" + blob += f"25%: {oe.oe25low} to {oe.oe50low - 1}\n" + blob += f"0%: {oe.oe25low - 1} or lower\n\n" - blob += "With a personal skill of %s, you can use up to\n" % skill_level - blob += "Out of OE: %d or lower\n" % oe.oe100 - blob += "75%%: %d to %d\n" % (oe.oe100 + 1, oe.oe75) - blob += "50%%: %d to %d\n" % (oe.oe75 + 1, oe.oe50) - blob += "25%%: %d to %d\n" % (oe.oe50 + 1, oe.oe25) - blob += "0%%: %d or higher\n" % (oe.oe25 - 1) + blob += f"With a personal skill of {skill_level}, you can use up to\n" + blob += f"Out of OE: {oe.oe100} or lower\n" + blob += f"75%: {oe.oe100 + 1} to {oe.oe75}\n" + blob += f"50%: {oe.oe75 + 1} to {oe.oe50}\n" + blob += f"25%: {oe.oe50 + 1} to {oe.oe25}\n" + blob += f"0%: {oe.oe25 - 1} or higher\n" return ChatBlob("%d - %d - %d" % (oe.oe100low, skill_level, oe.oe100), blob) diff --git a/modules/standard/tower/land_controller.py b/modules/standard/tower/land_controller.py index 041d0b5..3516d38 100644 --- a/modules/standard/tower/land_controller.py +++ b/modules/standard/tower/land_controller.py @@ -217,6 +217,9 @@ class LandController: blob += f"Dist: {cond} Conductors and {turret} Turrets\n" blob += "\n Towers:\n" blob += towers + else: + blob += f"Dist: {data.guards} Conductors and {data.turrets} Turrets\n" + else: if not row.enabled: blob += "Disabled\n" @@ -264,16 +267,21 @@ class LandController: else: return self.db.query("""SELECT d.playfield_id AS pf_id, d.site_number, d.site_name, d.min_ql, d.max_ql, d.x_coord, d.y_coord, d.timing, d.enabled, a.tower_id, a.ql, - a.close_time, a.penalty_until, a.planted, b.*, c.*, e.* + a.close_time, a.penalty_until, a.planted, b.*, c.*, e.*, t2.turrets, t2.guards FROM tower_sites d LEFT JOIN towers a on a.pf_id = d.playfield_id and a.site_number = d.site_number AND a.close_time IS NOT NULL LEFT JOIN aodb b ON a.high_id = b.highid LEFT JOIN playfields c on d.playfield_id = c.id LEFT JOIN all_orgs e on a.org_id = e.org_id + LEFT JOIN (SELECT COUNT(CASE WHEN name LIKE '%Turret%' THEN 1 WHEN name LIKE '%SAM Battery%' THEN 1 END) turrets, + COUNT(CASE WHEN name LIKE '%Guard%' THEN 1 END) guards, site_number AS site + FROM towers a LEFT JOIN aodb b ON a.high_id = b.highid WHERE a.pf_id=? GROUP BY site_number) t2 + + ON d.site_number = t2.site WHERE playfield_id=? GROUP BY playfield_id, site_number ORDER BY site_number, ql DESC - """, [pf]) + """, [pf, pf]) def get_towers_by_org(self, org_id): return self.db.query("""SELECT * FROM (SELECT COUNT(CASE WHEN name LIKE '%Turret%' THEN 1 WHEN name LIKE '%SAM Battery%' THEN 1 END) turrets, diff --git a/modules/standard/whois/character_info_controller.py b/modules/standard/whois/character_info_controller.py index 6302945..6551824 100644 --- a/modules/standard/whois/character_info_controller.py +++ b/modules/standard/whois/character_info_controller.py @@ -1,4 +1,5 @@ import time +import typing from functools import partial from core.aochat.server_packets import BuddyAdded, CharacterName @@ -8,10 +9,11 @@ from core.command_request import CommandRequest from core.db import DB from core.decorators import instance, command, timerevent from core.dict_object import DictObject -from core.lookup.pork_service import PorkService -from core.text import Text -from core.igncore import IgnCore - +if typing.TYPE_CHECKING: + from core.job_scheduler import JobScheduler + from core.lookup.pork_service import PorkService + from core.text import Text + from core.igncore import IgnCore @instance() class CharacterInfoController: @@ -31,6 +33,7 @@ class CharacterInfoController: self.account_service = registry.get_instance("account_service") self.buddy_service = registry.get_instance("buddy_service") self.alts_controller = registry.get_instance("alts_controller") + self.jobs: JobScheduler = registry.get_instance("job_scheduler") def pre_start(self): self.bot.register_packet_handler(CharacterName.id, self.character_name_update) @@ -60,6 +63,16 @@ class CharacterInfoController: if dimension == self.bot.dimension and char.char_id: online_status = self.buddy_service.is_online(char.char_id) if online_status is None: + if str(char.char_id) == char.name: + def a(_): + if char.char_id in self.waiting_for_update.keys(): + del self.waiting_for_update[char.char_id] + if not self.waiting_for_update: + self.bot.remove_packet_handler(BuddyAdded.id, self.handle_buddy_status) + self.buddy_service.remove_buddy(char.char_id, self.BUDDY_IS_ONLINE_TYPE) + request.reply(f"Could not find character {char.name} on RK{dimension}. Lookup failed.") + + self.jobs.delayed_job(a, 5) self.bot.register_packet_handler(BuddyAdded.id, self.handle_buddy_status) self.waiting_for_update[char.char_id] = \ DictObject({"char_id": char.char_id, "name": char.name, diff --git a/modules/standard/whois/org_list_controller.py b/modules/standard/whois/org_list_controller.py index 3253002..a47ed43 100644 --- a/modules/standard/whois/org_list_controller.py +++ b/modules/standard/whois/org_list_controller.py @@ -2,7 +2,7 @@ import requests from core.buddy_service import BuddyService from core.chat_blob import ChatBlob -from core.command_param_types import Int, Any, Options +from core.command_param_types import Int, Any, Options, Const from core.decorators import instance, command, event from core.dict_object import DictObject from core.registry import Registry @@ -41,6 +41,16 @@ class OrgListController: def orglist_cmd(self, request, org_id): self.start_orglist_lookup(request.reply, org_id) + @command(command="orglist", params=[Const("cancel")], access_level="member", + description="Cancel a running orgroster") + def orglist_cancel_cmd(self, request, _): + if not self.orglist: + return "There's currently no orglist running, or the download of the orgroster has not been finished yes." + org = self.orglist + self.orglist = None + self.buddy_service.remove_buddy_type(org.finished_org_members, self.ORGLIST_BUDDY_TYPE) + request.reply(f"Running orglist has been aborted.") + @command(command="orglist", params=[Any("character|org_name|org_id")], access_level="member", description="Show online status of characters in an org") def orglist_character_cmd(self, request, search): @@ -124,7 +134,7 @@ class OrgListController: def start_orglist_lookup(self, reply, org_id): if self.orglist: - reply("There is an orglist already in progress.") + reply("There is an orglist already in progress. You can abort the running one like this: orglist cancel.") return reply(f"Downloading org roster for org id {org_id:d}...") @@ -148,7 +158,10 @@ class OrgListController: while self.bot.iterate(1): pass - self.check_for_orglist_end() + try: + self.check_for_orglist_end() + except AttributeError: + pass @event(event_type=BuddyService.BUDDY_LOGON_EVENT, description="Detect online buddies for orglist command", is_hidden=True) @@ -165,14 +178,17 @@ class OrgListController: self.check_for_orglist_end() def update_online_status(self, char_id, status): + if not self.orglist: + return self.orglist.finished_org_members[char_id] = self.orglist.waiting_org_members[char_id] self.orglist.finished_org_members[char_id].online = status del self.orglist.waiting_org_members[char_id] def check_for_orglist_end(self): + if not self.orglist: + return if self.orglist.org_members: self.iterate_org_members() - if not self.orglist.waiting_org_members: self.orglist.reply(self.format_result()) self.orglist = None @@ -229,7 +245,7 @@ class OrgListController: def iterate_org_members(self): # add org_members that we don't have online status for as buddies - while self.orglist.org_members and self.buddy_list_has_available_slots(): + while self.orglist and self.orglist.org_members and self.buddy_list_has_available_slots(): org_member = self.orglist.org_members.pop() char_id = org_member.char_id self.orglist.waiting_org_members[char_id] = org_member