This should get us back on track (tested on ARCH Linux)
This commit is contained in:
@@ -69,6 +69,8 @@ class DiscordCommandHandler(BaseModule):
|
||||
if type(reply) == str:
|
||||
reply = self.discord.text.format_message(reply)
|
||||
rsp = f"> {self.parseDiscord(reply)}"
|
||||
|
||||
# Sender == init? Should be Sender == bot
|
||||
self.discord.relay_hub_service.send_message(f"Discord_({ctx.channel.name})",
|
||||
DictObject({'char_id': 0, 'name': ctx.author.name,
|
||||
'discord_handle':
|
||||
@@ -87,6 +89,8 @@ class DiscordCommandHandler(BaseModule):
|
||||
rsp += f"**__{reply.title}__**\n"
|
||||
rsp += self.parseDiscord(reply.msg, blob=True)
|
||||
rsp += f"\n {self.parseDiscord(reply.page_postfix)}"
|
||||
|
||||
# Sender == init? Should be Sender == bot
|
||||
self.discord.relay_hub_service.send_message(f"Discord_({ctx.channel.name})",
|
||||
DictObject({'char_id': 0, 'name': ctx.author.name,
|
||||
'discord_handle':
|
||||
@@ -151,6 +155,7 @@ class DiscordCommandHandler(BaseModule):
|
||||
(r"<a href=(.*?)itemid://(\d+)/(\d+)\1>(.+?)<\/a>", r"[\4](https://aoitems.com/item/\2/\3/)" if blob else r"`\4`"),
|
||||
(r"<(.+?)>\s*?<\1>", ''),
|
||||
(r"<pagebreak>", ''),
|
||||
(r"<a.+?href=\'.*?\'><img.+?></a>", r''),
|
||||
(r"<a.+?href=\'.*?\'>(.*?)</a>", r'`\1`'),
|
||||
(r"<clan>(.*?)</clan>", r":yellow_circle: \1"),
|
||||
(r"<omni>(.*?)</omni>", r":blue_circle: \1"),
|
||||
@@ -229,14 +234,15 @@ class DiscordCommandHandler(BaseModule):
|
||||
if not self.discord.client:
|
||||
return "Discord module has not been initiated yet. Please try again later."
|
||||
blob = ""
|
||||
for member in self.discord.guild.members:
|
||||
for member in sorted(self.discord.guild.members, key=lambda x: x.display_name):
|
||||
member_roles = []
|
||||
for role in member.roles:
|
||||
if role.name == "@everyone": # Skip @everyone as everyone has it.
|
||||
continue
|
||||
member_roles.append(f"{role.name}")
|
||||
member_roles.sort(key=str.lower)
|
||||
blob += f"{member.name + '#' + member.discriminator} ({', '.join(member_roles)})\n"
|
||||
# blob += f"{member.name + '#' + member.discriminator} ({', '.join(member_roles)})\n"
|
||||
blob += f"- <highlight>{member.display_name}</highlight> [{member.name + '#' + member.discriminator}] ({', '.join(member_roles)})<br>"
|
||||
return ChatBlob(f"Discord Members ({len(self.discord.guild.members):d})", blob)
|
||||
|
||||
@event(event_type="connect", description="Connects the Discord client automatically on startup, if a token exists")
|
||||
|
||||
@@ -47,7 +47,6 @@ class PrivateChannelController:
|
||||
self.online_controller = registry.get_instance("online_controller", is_optional=True)
|
||||
|
||||
def pre_start(self):
|
||||
self.db.create_view("online")
|
||||
self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)
|
||||
|
||||
try:
|
||||
@@ -58,6 +57,8 @@ class PrivateChannelController:
|
||||
self.reinvite = []
|
||||
|
||||
def start(self):
|
||||
self.db.create_view("online")
|
||||
|
||||
self.message_hub_service.register_message_destination(self.MESSAGE_SOURCE,
|
||||
self.handle_incoming_relay_message,
|
||||
["registration"],
|
||||
|
||||
@@ -182,7 +182,7 @@ class OrgController:
|
||||
"member_count=VALUE(member_count), "
|
||||
"last_seen=VALUE(last_seen)",
|
||||
data)
|
||||
self.db.exec("DELETE FROM all_orgs where last_seen < ?", [time.time() - 2 * 24 * 60 * 60])
|
||||
# self.db.exec("DELETE FROM all_orgs where last_seen < ?", [time.time() - 2 * 24 * 60 * 60])
|
||||
self.logger.info(f"Successfully fetched {count} orgs in {time.time() - start:.2f} seconds.")
|
||||
self.threads.pop('orgdiscover', None)
|
||||
|
||||
|
||||
@@ -414,16 +414,30 @@ class AllianceRelay:
|
||||
if self.discord.guild and self.discord.bot:
|
||||
name = f"<header2>DC Server: <highlight>{self.discord.guild.name}</highlight> - " \
|
||||
f"Bot: <highlight><myname></highlight></header2>"
|
||||
blob = self.text.format_page('Info',
|
||||
f"<header>::: Information :::</header><br><br>"
|
||||
f"This message has been sent to you by:<br><br>"
|
||||
f"{name}<br>"
|
||||
f"<tab>Sender: <notice>{ctx.sender.name}</notice><br>"
|
||||
f"<tab>Tag: <highlight>{ctx.sender.discord_nick}</highlight><br><br>"
|
||||
f"To reply, either respond in the relay or "
|
||||
f"contact them directly at the provided handles.<br><br>"
|
||||
f"<header2>Have you joined our Discord Server yet? "
|
||||
f"If not <highlight>{invite}</highlight> to receive an invite.</header2>")
|
||||
nick = ctx.sender.discord_nick if ctx.sender.get('discord_nick', None) \
|
||||
else self.discord.client.user.display_name if ctx.sender.char_id == self.bot.get_char_id() else None
|
||||
if nick:
|
||||
blob = self.text.format_page('Info',
|
||||
f"<header>::: Information :::</header><br><br>"
|
||||
f"This message has been sent to you by:<br><br>"
|
||||
f"{name}<br>"
|
||||
f"<tab>Sender: <notice>{ctx.sender.name}</notice><br>"
|
||||
f"<tab>Tag: <highlight>{nick}</highlight><br><br>" # Bot ha sno nick!!
|
||||
f"To reply, either respond in the relay or "
|
||||
f"contact them directly at the provided handles.<br><br>"
|
||||
f"<header2>Have you joined our Discord Server yet? "
|
||||
f"If not <highlight>{invite}</highlight> to receive an invite.</header2>")
|
||||
else:
|
||||
blob = self.text.format_page('Info',
|
||||
f"<header>::: Information :::</header><br><br>"
|
||||
f"This message has been sent to you by:<br><br>"
|
||||
f"{name}<br>"
|
||||
f"<tab>Sender: <notice><myname></notice><br>"
|
||||
f"<tab>Tag: <highlight>{self.discord.client.user.display_name}</highlight><br><br>" # Bot has no nick!!
|
||||
f"To reply, either respond in the relay or "
|
||||
f"contact them directly at the provided handles.<br><br>"
|
||||
f"<header2>Have you joined our Discord Server yet? "
|
||||
f"If not <highlight>{invite}</highlight> to receive an invite.</header2>")
|
||||
blob = f"<yellow>[{blob}]</yellow>"
|
||||
# msg = f"{cmd} [{self.discord.alias_controller.get_alias(ctx.sender.org_id)}] {ctx.message} <yellow>[{blob}]</yellow>"
|
||||
msg = f"{cmd} [{abbrv}] {sender}: {message} {blob}"
|
||||
|
||||
@@ -81,7 +81,7 @@ class AOUController:
|
||||
obj.profession = guide_info.profession
|
||||
obj.faction = guide_info.faction
|
||||
obj.level = guide_info.level
|
||||
obj.author = self.format_bbcode_code(guide_info.author)
|
||||
obj.author = self.format_bbcode_code(guide_info.author or "Author Unknown")
|
||||
obj.aou = self.text.make_chatcmd("AO-Universe.com", "/start https://www.ao-universe.com")
|
||||
obj.text = self.format_bbcode_code(guide_info.text)
|
||||
|
||||
|
||||
@@ -15,12 +15,14 @@ class RandomController:
|
||||
self.character_service = registry.get_instance("character_service")
|
||||
self.command_alias_service = registry.get_instance("command_alias_service")
|
||||
|
||||
def pre_start(self):
|
||||
self.db.shared.exec("CREATE TABLE IF NOT EXISTS roll (id INT PRIMARY KEY AUTO_INCREMENT, "
|
||||
"created_at INT NOT NULL, "
|
||||
"char_id INT NOT NULL, "
|
||||
"options VARCHAR(2048), "
|
||||
"result VARCHAR(255))")
|
||||
|
||||
def start(self):
|
||||
self.db.exec("CREATE TABLE IF NOT EXISTS roll (id INT PRIMARY KEY AUTO_INCREMENT, "
|
||||
"created_at INT NOT NULL, "
|
||||
"char_id INT NOT NULL, "
|
||||
"options VARCHAR(2048), "
|
||||
"result VARCHAR(255))")
|
||||
self.db.create_view("roll")
|
||||
self.command_alias_service.add_alias("verify", "roll verify")
|
||||
self.command_alias_service.add_alias("lootorder", "random")
|
||||
|
||||
@@ -81,7 +81,7 @@ class ItemsController:
|
||||
blob += self.format_items(items, ql)
|
||||
blob += head_foot
|
||||
# noinspection LongLine
|
||||
blob += f"\nItem DB rips created using the {self.text.make_chatcmd('Budabot Items Extractor', '/start https://github.com/Budabot/ItemsExtractor')} tool."
|
||||
blob += f"\nItem DB rips created using a modified version of the {self.text.make_chatcmd('Items Extractor', '/start https://github.com/Budabot/ItemsExtractor')} tool."
|
||||
|
||||
return ChatBlob(
|
||||
f"Item Search Results ({offset + 1:d} - {min(offset + self.PAGE_SIZE, len(all_items)):d} "
|
||||
|
||||
@@ -231,7 +231,7 @@ class LootController:
|
||||
f"{loot_item.get_item_str()}",
|
||||
request.sender.char_id)
|
||||
blob += f"{i:d}. {loot_item.get_item_str()}\n"
|
||||
blob += f" | Winners: <red>{'</red>, <red>'.join(winners)}</red>\n\n"
|
||||
blob += f" | Winners: <yellow>{'</yellow>, <yellow>'.join(winners)}</yellow>\n\n"
|
||||
if loot_item.count == 0:
|
||||
remove.append(i)
|
||||
for i in remove:
|
||||
|
||||
@@ -164,7 +164,7 @@ class NanoController:
|
||||
profession = "Martial Artist"
|
||||
strain = strain[7:]
|
||||
nanoline = self.db.query_single(
|
||||
"SELECT * FROM nanos n WHERE n.strain LIKE ? AND profession =? and type='Crystal' LIMIT 1",
|
||||
"SELECT * FROM nanos n WHERE n.strain LIKE ? AND profession =? and type in ('Crystal', 'Misc') LIMIT 1",
|
||||
[strain, profession])
|
||||
|
||||
if not nanoline:
|
||||
@@ -174,7 +174,7 @@ class NanoController:
|
||||
"SELECT n.* FROM nanos n "
|
||||
"where n.strain LIKE ? "
|
||||
"and n.profession = ? "
|
||||
"and type='Crystal' "
|
||||
"and type in ('Crystal', 'Misc') "
|
||||
"group by nano_id "
|
||||
"ORDER BY n.strain, n.ql DESC, n.nano_name",
|
||||
["%" + strain.replace(" ", "%") + "%", profession])
|
||||
@@ -193,6 +193,10 @@ class NanoController:
|
||||
|
||||
return ChatBlob("%s %s Nanos" % (nanoline.profession, str(nanoline.strain).replace("_", " ")), blob)
|
||||
|
||||
# @command(command='disc', params=[Any("search")], access_level="member",
|
||||
# description="Search for the disc to a Crystal, or the other way around.")
|
||||
# def disc_search_command(self, req, search):
|
||||
# pass
|
||||
@command(command="nanolines", params=[Any("profession")], access_level="member",
|
||||
description="Show nanolines by profession")
|
||||
def nanolines_profession_cmd(self, _, prof_name):
|
||||
@@ -204,7 +208,7 @@ class NanoController:
|
||||
"SELECT CASE WHEN strain = 'Composite' THEN 'Composite' ELSE school END as school, strain, profession "
|
||||
"FROM nanos WHERE Profession = ? "
|
||||
"and location not like 'No%longer%drops' "
|
||||
"and type not in ('Tainted', 'Misc') "
|
||||
"and type not in ('Tainted') "
|
||||
"GROUP by strain ORDER BY school, strain='Composite', strain", [profession])
|
||||
|
||||
blob = ""
|
||||
|
||||
@@ -33,8 +33,6 @@ class NewsController:
|
||||
"Hei", "Salut", "Helló", "Halló", "Ciao", "Olá", "Ahoj", "¡Hola"]
|
||||
layout = \
|
||||
"""
|
||||
<header>News</header>
|
||||
|
||||
<notice>CURRENT TIME</notice>
|
||||
hh:mm - DD.MM.YYYY
|
||||
{time}
|
||||
@@ -173,9 +171,9 @@ hh:mm - DD.MM.YYYY
|
||||
last_updated = f"[{self.util.time_to_readable(datetime.utcfromtimestamp(time.time()).timestamp() - last_updated)} ago]"
|
||||
else:
|
||||
last_updated = ""
|
||||
blob = f"<yellow>{random.choice(self.greetings)} {sender.name} :: " \
|
||||
f"{self.text.format_page('Your News', textwrap.dedent(news))} </yellow>{last_updated} " \
|
||||
f"{f'<yellow>::</yellow> {name} running' if next_event.is_running() else ''}"
|
||||
blob = ChatBlob('Your News', textwrap.dedent(news),
|
||||
prefix=f"<yellow>{random.choice(self.greetings)} {sender.name} :: ",
|
||||
suffix=f"</yellow> {last_updated} {f'<yellow>::</yellow> {name} running' if next_event.is_running() else ''}")
|
||||
self.bot.send_mass_message(sender.char_id, blob)
|
||||
if self.preview_recent().get_value() and auto:
|
||||
entry = self.get_newest_entry()
|
||||
|
||||
@@ -23,16 +23,19 @@ class RecipeController:
|
||||
self.items_controller = registry.get_instance("items_controller")
|
||||
self.command_alias_service = registry.get_instance("command_alias_service")
|
||||
|
||||
def pre_start(self):
|
||||
self.db.shared.exec("CREATE TABLE IF NOT EXISTS recipe ("
|
||||
"id INT NOT NULL PRIMARY KEY, "
|
||||
"name VARCHAR(50) NOT NULL, "
|
||||
"author VARCHAR(50) NOT NULL, "
|
||||
"recipe TEXT NOT NULL, "
|
||||
"dt INT NOT NULL DEFAULT 0)")
|
||||
|
||||
def start(self):
|
||||
self.command_alias_service.add_alias("r", "recipe")
|
||||
self.command_alias_service.add_alias("tradeskill", "recipe")
|
||||
|
||||
self.db.exec("CREATE TABLE IF NOT EXISTS recipe ("
|
||||
"id INT NOT NULL PRIMARY KEY, "
|
||||
"name VARCHAR(50) NOT NULL, "
|
||||
"author VARCHAR(50) NOT NULL, "
|
||||
"recipe TEXT NOT NULL, "
|
||||
"dt INT NOT NULL DEFAULT 0)")
|
||||
|
||||
self.db.create_view("recipe")
|
||||
recipe_dir = os.path.dirname(os.path.realpath(__file__)) + "/recipes/"
|
||||
recipes = self.db.query("SELECT id, dt FROM recipe")
|
||||
|
||||
@@ -467,7 +467,7 @@ class SpecialsController:
|
||||
result.hard_cap = weapon_attack + 5
|
||||
result.skill_cap = ((weapon_attack * 16) - result.hard_cap) * 100
|
||||
|
||||
recharge = (weapon_attack * 16) - (fast_attack_skill / 100)
|
||||
recharge = (weapon_attack * 16) - (fast_attack_skill / 100) # same
|
||||
if recharge < result.hard_cap:
|
||||
recharge = result.hard_cap
|
||||
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
import datetime
|
||||
import json
|
||||
import math
|
||||
import time
|
||||
from threading import Thread
|
||||
|
||||
import requests
|
||||
|
||||
from core.aochat.BaseModule import BaseModule
|
||||
from core.aochat.server_packets import BuddyAdded
|
||||
from core.buddy_service import BuddyService
|
||||
from core.cache_service import CacheService
|
||||
from core.chat_blob import ChatBlob
|
||||
from core.command_param_types import Character, Options, Const, Any, NamedParameters
|
||||
from core.db import DB
|
||||
from core.decorators import instance, command, event
|
||||
from core.decorators import instance, command, event, timerevent
|
||||
from core.dict_object import DictObject
|
||||
from core.event_service import EventService
|
||||
from core.igncore import IgnCore
|
||||
from core.job_scheduler import JobScheduler
|
||||
from core.logger import Logger
|
||||
from core.lookup.org_pork_service import OrgPorkService
|
||||
from core.lookup.pork_service import PorkService
|
||||
from core.message_hub_service import MessageHubService
|
||||
from core.private_channel_service import PrivateChannelService
|
||||
@@ -25,11 +34,14 @@ from modules.standard.tower.tower_events import TowerEventController
|
||||
# noinspection DuplicatedCode,SqlCaseVsIf
|
||||
@instance()
|
||||
class TrackController(BaseModule):
|
||||
threads = {}
|
||||
single_org_uri = "https://people.anarchy-online.com/org/stats/d/5/name/%d/basicstats.xml?data_type=json"
|
||||
PRIVATE_CHANNEL_PREFIX = "[Priv]"
|
||||
PAGE_SIZE = 20
|
||||
MESSAGE_SOURCE = "track_log"
|
||||
|
||||
def inject(self, registry):
|
||||
self.logger = Logger("TRACK")
|
||||
self.bot: IgnCore = registry.get_instance("bot")
|
||||
self.util: Util = registry.get_instance("util")
|
||||
self.pork: PorkService = registry.get_instance("pork_service")
|
||||
@@ -43,6 +55,10 @@ class TrackController(BaseModule):
|
||||
self.priv: PrivateChannelService = registry.get_instance("private_channel_service")
|
||||
self.tower: TowerEventController = registry.get_instance("tower_controller")
|
||||
self.message_hub_service: MessageHubService = registry.get_instance("message_hub_service")
|
||||
self.org_pork: OrgPorkService = registry.get_instance("org_pork_service")
|
||||
self.cache: CacheService = registry.get_instance("cache_service")
|
||||
self.relay_hub_service: MessageHubService = registry.get_instance("message_hub_service")
|
||||
|
||||
|
||||
def pre_start(self):
|
||||
self.event_service.register_event_type("track_logon")
|
||||
@@ -59,18 +75,22 @@ class TrackController(BaseModule):
|
||||
"char_id int not null primary key, "
|
||||
"initiator int not null, "
|
||||
"reason varchar(255))")
|
||||
self.db.exec("CREATE TABLE IF NOT EXISTS track_orgs(org_id int not null primary key, initiator int not null)")
|
||||
self.db.exec("CREATE TABLE IF NOT EXISTS track_org_members(char_id int not null, org_id int not null)")
|
||||
self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)
|
||||
|
||||
@event(event_type="connect", description="Autoadd tracked players on connect", is_hidden=True)
|
||||
def connect_add(self, _1, _2):
|
||||
query = self.db.query("SELECT * from track")
|
||||
for user in query:
|
||||
for user in self.db.query("SELECT * from track"):
|
||||
self.buddy_service.add_buddy(user.char_id, "track")
|
||||
for user in self.db.query("SELECT char_id FROM track_org_members"):
|
||||
self.buddy_service.add_buddy(user.char_id, "track")
|
||||
|
||||
@event(event_type="buddy_logon", description="Fire tracker events", is_hidden=True)
|
||||
def track_fire_logon(self, _, event_data):
|
||||
if self.bot.is_ready():
|
||||
if "track" in (self.buddy_service.get_buddy(event_data.char_id) or {'types': []})["types"]:
|
||||
print("Login: ", event_data.char_id)
|
||||
if type(event_data) == BuddyAdded:
|
||||
self.event_service.fire_event("track_logon",
|
||||
self.db.query_single("SELECT * from player where char_id=?",
|
||||
@@ -144,6 +164,59 @@ class TrackController(BaseModule):
|
||||
self.db.exec("INSERT IGNORE INTO track VALUES(?, ?, ?)",
|
||||
[user.char_id, acc.main, reason])
|
||||
|
||||
@command(command="orgtrack", params=[Const('add'), Any("Organisation")], access_level="moderator",
|
||||
description="Initiate tracking for an Organisation", sub_command="add")
|
||||
def track_addorg(self, request, _, search):
|
||||
orgs = self.org_pork.find_org(search)
|
||||
if len(orgs) == 1:
|
||||
orgs = orgs[0]
|
||||
if self.db.exec("REPLACE INTO track_orgs(org_id, initiator) VALUES(?, ?)",
|
||||
[orgs.org_id, request.sender.char_id]) == 1:
|
||||
request.reply(f"Adding the organisation <highlight>{orgs.org_name}</highlight> to the tracking...")
|
||||
org_adder = Thread(name=orgs.org_id, target=self.fetch_single,
|
||||
args=(orgs.org_id, orgs.org_name, request))
|
||||
self.threads[orgs.org_id] = org_adder
|
||||
org_adder.start()
|
||||
else:
|
||||
return f"The organisation <highlight>{orgs.org_name}</highlight> is already being tracked."
|
||||
elif len(orgs) == 0:
|
||||
return f"No org with the name <highlight>{search}</highlight> was found on PoRK."
|
||||
else:
|
||||
blob = "Your search had multiple results; please pick an org:<br>"
|
||||
for org in orgs:
|
||||
blob += f'[{self.text.make_chatcmd("Add", f"/tell <myname> orgtrack add {org.org_id}")}]' \
|
||||
f'[{self.text.make_chatcmd("More", f"/tell <myname> org info {org.org_id}")}]' \
|
||||
f' <highlight>{org.org_name}</highlight> (<highlight>{org.org_id}</highlight>) ' \
|
||||
f'<{org.faction.lower()}>{org.faction}</{org.faction.lower()}> [<highlight>{org.member_count}</highlight> members]' \
|
||||
f'<br><pagebreak>'
|
||||
return ChatBlob("Pick an Org", blob)
|
||||
|
||||
@command(command="orgtrack", params=[Const("rem"), Any("Organisation")], access_level="moderator",
|
||||
description="Add an organisation to the tracking", sub_command="rem")
|
||||
def orgtrack_rem(self, request, _, search):
|
||||
orgs = self.org_pork.find_org(search)
|
||||
orgs = [x for x in orgs if x.org_name.lower().startswith(search.lower()) or (x.org_id == int(search) if search.isdigit() else False)]
|
||||
if len(orgs) == 1:
|
||||
orgs = orgs[0]
|
||||
if self.db.exec("DELETE FROM track_orgs where org_id = ?", [orgs.org_id]) == 1:
|
||||
org_remover = Thread(name=orgs.org_id, target=self.remove_single, args=(orgs.org_id, orgs.org_name))
|
||||
self.threads[orgs.org_id] = org_remover
|
||||
org_remover.start()
|
||||
return f"Removed the organisation <highlight>{orgs.org_name}</highlight> from the roster."
|
||||
else:
|
||||
return f"The organisation <highlight>{orgs.org_name}</highlight> is not on the roster list."
|
||||
elif len(orgs) == 0:
|
||||
return f"The organisation <highlight>{search}</highlight> is not on the roster list."
|
||||
else:
|
||||
blob = "Your search had multiple results; please pick an org:<br>"
|
||||
for org in orgs:
|
||||
blob += f'[{self.text.make_chatcmd("Remove", f"/tell <myname> orgtrack rem {org.org_id}")}]' \
|
||||
f'[{self.text.make_chatcmd("More", f"/tell <myname> org info {org.org_id}")}]' \
|
||||
f' <highlight>{org.org_name}</highlight> (<highlight>{org.org_id}</highlight>) ' \
|
||||
f'<{org.faction.lower()}>{org.faction}</{org.faction.lower()}> [<highlight>{org.member_count}</highlight> members]' \
|
||||
f'<br><pagebreak>'
|
||||
return ChatBlob("Pick an Org", blob)
|
||||
|
||||
@command(command="track", params=[Const('rem'), Character("character")], access_level="moderator",
|
||||
description="Remove character from the tracking", sub_command="rem")
|
||||
def track_rem(self, request, _, user):
|
||||
@@ -180,14 +253,40 @@ class TrackController(BaseModule):
|
||||
players = self.get_tracked('p.level desc, p.profession, p.name', False if const else True)
|
||||
return self.format_page(players, "tl", offset, page, f"Tracklist by Titlelevel ({len(players)})",
|
||||
'No tracked users online', f"track {const or ''} {group or ''}")
|
||||
@command(command="orgtrack",
|
||||
params=[Const('info')],
|
||||
access_level="member",
|
||||
description="Shows tracked orgs")
|
||||
def orgtrack_info(self, _, const):
|
||||
blob = ""
|
||||
for org in self.db.query("SELECT a.*, o.* from track_orgs o LEFT JOIN all_orgs a on o.org_id = a.org_id"):
|
||||
blob += f"- [{self.text.make_tellcmd('Info', f'orgs info {org.org_id}')}] " \
|
||||
f"[{self.text.make_tellcmd('Remove', f'orgtrack rem {org.org_id}')}]" \
|
||||
f" {self.text.get_formatted_faction(org.faction, org.org_name)} ({org.org_id}) with <highlight>{org.member_count}</highlight> memebrs"
|
||||
return ChatBlob("Currently Tracked Organisations", blob)
|
||||
@command(command="orgtrack",
|
||||
params=[Const('list', is_optional=True), NamedParameters(["page"])],
|
||||
access_level="member",
|
||||
description="Shows tracked orgmembers")
|
||||
def track_listorg(self, _, const, named_params):
|
||||
|
||||
page = int(named_params.page or "1")
|
||||
offset = (page - 1) * self.PAGE_SIZE
|
||||
where = "where o.char_id IS NOT NULL" if not const else ""
|
||||
players = self.db.query(f"SELECT p.name, p.level, p.ai_level, p.org_name, p.profession, p.faction, "
|
||||
f"CASE WHEN o.char_id IS NOT NULL THEN 1 ELSE 0 END AS online from track_org_members t "
|
||||
f"left join player p on p.char_id = t.char_id "
|
||||
f"left join online o on o.char_id = t.char_id {where} group by t.char_id order by p.org_name, p.profession, p.level desc, p.name")
|
||||
|
||||
return self.format_page_org(players, "org", offset, page, f"Tracklist by Organisation ({len(players)})",
|
||||
'No tracked users online', f"orgtrack {const or ''} ")
|
||||
|
||||
def format_row(self, user):
|
||||
org = f"[<{user.faction.lower()}>{user.org_name}</{user.faction.lower()}>] " if user.org_name else ""
|
||||
return f"<tab>{self.util.get_prof_icon(user.profession)} " \
|
||||
f"{self.text.zfill(user.level, 220)}:<green>{self.text.zfill(user.ai_level, 220)}</green> " \
|
||||
f"<{user.faction.lower()}>{user.name}</{user.faction.lower()}>" \
|
||||
f" {org}init by <highlight>{user.initiator}</highlight>: {user.reason} " \
|
||||
f"{'[<red>ONLINE</red>]' if user.online == 1 else ''}\n"
|
||||
f" {org} {'[<red>ONLINE</red>]' if user.online == 1 else ''}\n"
|
||||
|
||||
def format_page(self, tracked, order, offset, page, title, nullmsg, cmd):
|
||||
selected = tracked[offset:offset + self.PAGE_SIZE]
|
||||
@@ -228,3 +327,210 @@ class TrackController(BaseModule):
|
||||
|
||||
blob += "</font>\n" + pages
|
||||
return ChatBlob(title, blob)
|
||||
|
||||
def format_page_org(self, tracked, order, offset, page, title, nullmsg, cmd):
|
||||
selected = tracked[offset:offset + self.PAGE_SIZE]
|
||||
count = len(selected)
|
||||
pages = ""
|
||||
if page > 1:
|
||||
pages += "Pages: " + self.text.make_tellcmd("«« Page %d" % (page - 1), f'{cmd} --page={page - 1}')
|
||||
if offset + self.PAGE_SIZE < len(tracked):
|
||||
pages += f" Page {page}/{math.ceil(len(tracked) / self.PAGE_SIZE)}"
|
||||
pages += " " + self.text.make_tellcmd("Page %d »»" % (page + 1), f'{cmd} --page={page + 1}')
|
||||
pages += "\n"
|
||||
if count == 0:
|
||||
return nullmsg
|
||||
else:
|
||||
blob = "\n\n" + pages + "<font color=CCInfoText>"
|
||||
if order == "org":
|
||||
org_name = ""
|
||||
for player in selected:
|
||||
if player.org_name != org_name:
|
||||
org_name = player.org_name
|
||||
blob += f"\n<pagebreak><header>{player.org_name}</header>\n"
|
||||
blob += self.format_row(player)
|
||||
|
||||
blob += "</font>\n" + pages
|
||||
return ChatBlob(title, blob)
|
||||
|
||||
def format_row_org(self, user):
|
||||
org = f"[<{user.faction.lower()}>{user.org_name}</{user.faction.lower()}>] " if user.org_name else ""
|
||||
return f"<tab>{self.util.get_prof_icon(user.profession)} " \
|
||||
f"{self.text.zfill(user.level, 220)}:<green>{self.text.zfill(user.ai_level, 220)}</green> " \
|
||||
f"<{user.faction.lower()}>{user.name}</{user.faction.lower()}>" \
|
||||
f" {org}init by <highlight>{user.initiator}</highlight>: {user.reason} " \
|
||||
f"{'[<red>ONLINE</red>]' if user.online == 1 else ''}\n"
|
||||
|
||||
@timerevent(budatime="24h", description="Update Tracked Orgs")
|
||||
def fetch_orgs(self, _, _1):
|
||||
def discover():
|
||||
start = time.time()
|
||||
self.logger.info("Fetching orgdata..")
|
||||
output = []
|
||||
data = []
|
||||
data2 = []
|
||||
timestamp = 0
|
||||
ours = self.db.query("SELECT * FROM track_orgs t LEFT JOIN all_orgs a ON t.org_id = a.org_id")
|
||||
for org in ours:
|
||||
result = requests.get(self.single_org_uri % org.org_id).json()
|
||||
if result and len(result[1]) > 0:
|
||||
self.cache.store('org_roster', f"{org.org_id}.5.json", json.dumps(result))
|
||||
else:
|
||||
result = json.loads(self.cache.retrieve('org_roster', f"{org.org_id}.5.json").data)
|
||||
d = datetime.datetime.strptime(result[2] + " +0000", '%Y/%m/%d %H:%M:%S %z').timestamp()
|
||||
if d > timestamp:
|
||||
timestamp = d
|
||||
|
||||
for char_info in result[1]:
|
||||
data.append((char_info["CHAR_INSTANCE"], char_info["NAME"], char_info["FIRSTNAME"],
|
||||
char_info["LASTNAME"], char_info["LEVELX"], char_info["BREED"],
|
||||
char_info["SEX"], result[0]["SIDE_NAME"], char_info["PROF"],
|
||||
char_info["PROF_TITLE"], char_info["DEFENDER_RANK_TITLE"], char_info["ALIENLEVEL"],
|
||||
result[0]["ORG_INSTANCE"], result[0]["NAME"], char_info["RANK_TITLE"],
|
||||
char_info["RANK"], char_info["CHAR_DIMENSION"], char_info["HEADID"],
|
||||
0, char_info["PVPTITLE"] or "", "roster", int(time.time())))
|
||||
data2.append((char_info['CHAR_INSTANCE'], result[0]['ORG_INSTANCE']))
|
||||
|
||||
if not self.buddy_service.get_buddy(char_info["CHAR_INSTANCE"]):
|
||||
self.buddy_service.add_buddy(char_info["CHAR_INSTANCE"], "track")
|
||||
output.append(DictObject({"action": "JOIN",
|
||||
"name": char_info['NAME'],
|
||||
"org_name": result[0]["NAME"],
|
||||
"org_id": result[0]["ORG_INSTANCE"],
|
||||
"level": char_info["LEVELX"],
|
||||
"ai_level": char_info["ALIENLEVEL"],
|
||||
"ranks": 0}))
|
||||
self.logger.info(f"[TRACK] Organisation {org.org_name} has been updated.")
|
||||
if len(data) > 1:
|
||||
with self.db.lock:
|
||||
with self.db.pool.get_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.executemany("INSERT INTO player(char_id, name, first_name, last_name, "
|
||||
"level, breed, gender, faction, profession, profession_title, "
|
||||
"ai_rank, ai_level, org_id, org_name, org_rank_name, "
|
||||
"org_rank_id, dimension, head_id, pvp_rating, pvp_title, "
|
||||
"source, last_updated) VALUES "
|
||||
"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "
|
||||
"ON DUPLICATE KEY UPDATE first_name=VALUE(first_name), "
|
||||
"last_name=VALUE(last_name), level=VALUE(level), "
|
||||
"breed=VALUE(breed), gender=VALUE(gender), "
|
||||
"faction=VALUE(faction), profession=VALUE(profession), "
|
||||
"profession_title=VALUE(profession_title),ai_rank=VALUE(ai_rank), "
|
||||
"ai_level=VALUE(ai_level), org_name=VALUE(org_name), "
|
||||
"org_id=VALUE(org_id), org_rank_name=VALUE(org_rank_name), "
|
||||
"org_rank_id=VALUE(org_rank_id), source=VALUE(source), "
|
||||
"last_updated=VALUE(last_updated)", data)
|
||||
cur.executemany("INSERT INTO track_org_members (char_id, org_id) VALUES(?,?)", data2)
|
||||
conn.commit()
|
||||
for org in ours:
|
||||
left = self.db.query("SELECT p.* FROM track_org_members t LEFT JOIN player p on t.char_id = p.char_id where t.org_id=? and (p.last_updated < ? OR t.org_id != p.org_id)", [org.org_id, time.time()-25*60*60, org.org_id])
|
||||
for player in left:
|
||||
bonus = None
|
||||
player = DictObject(player)
|
||||
if self.buddy_service.remove_buddy(player.char_id, "track"):
|
||||
bonus = "LEAVE"
|
||||
new_data = self.pork.request_char_info(player.name, player.dimension)
|
||||
if new_data and new_data.char_id == player.char_id:
|
||||
self.pork.save_character_info(new_data)
|
||||
else:
|
||||
bonus = "DEL"
|
||||
if bonus:
|
||||
output.append(DictObject({"action": bonus,
|
||||
"name": player.name,
|
||||
"org_name": player.org_name,
|
||||
"org_id": player.org_id,
|
||||
"level": player.level,
|
||||
"ai_level": player.ai_level}))
|
||||
|
||||
self.db.exec("DELETE FROM track_org_members where char_id not in (SELECT char_id from player where org_id=?)", [org.org_id])
|
||||
|
||||
self.log(output, time.time() - start)
|
||||
self.logger.info(
|
||||
f"Successfully fetched {len(data)} players from {len(ours)} orgs "
|
||||
f"in {time.time() - start:.2f} seconds. - ")
|
||||
while (timestamp + 24 * 60 * 60) < datetime.datetime.now().timestamp():
|
||||
timestamp += 24 * 60 * 60
|
||||
self.db.exec("UPDATE timer_event SET next_run=? WHERE handler=? AND event_sub_type=?", [
|
||||
int(timestamp +24*60*60 + 10*60),
|
||||
"modules.standard.track.track_controller.TrackController.fetch_orgs",
|
||||
86400
|
||||
])
|
||||
del self.threads['roster']
|
||||
|
||||
if "roster" not in self.threads.keys():
|
||||
thread = Thread(name="roster", target=discover, daemon=True)
|
||||
self.threads["roster"] = thread
|
||||
thread.start()
|
||||
|
||||
def fetch_single(self, org_id, org_name, sender: object):
|
||||
start = time.time()
|
||||
data = []
|
||||
data2 = []
|
||||
accounts = []
|
||||
self.logger.info("Fetching orgdata..")
|
||||
count = 0
|
||||
result = requests.get(self.single_org_uri % org_id).json()
|
||||
for char_info in result[1]:
|
||||
data.append((char_info["CHAR_INSTANCE"], char_info["NAME"], char_info["FIRSTNAME"],
|
||||
char_info["LASTNAME"],
|
||||
char_info["LEVELX"], char_info["BREED"],
|
||||
char_info["SEX"], result[0]["SIDE_NAME"], char_info["PROF"],
|
||||
char_info["PROF_TITLE"], char_info["DEFENDER_RANK_TITLE"], char_info["ALIENLEVEL"],
|
||||
result[0]["ORG_INSTANCE"], result[0]["NAME"], char_info["RANK_TITLE"],
|
||||
char_info["RANK"], char_info["CHAR_DIMENSION"], char_info["HEADID"],
|
||||
0, char_info["PVPTITLE"] or "", "roster", int(time.time())))
|
||||
data2.append((char_info['CHAR_INSTANCE'], result[0]['ORG_INSTANCE']))
|
||||
|
||||
accounts.append((char_info["CHAR_INSTANCE"], char_info["CHAR_INSTANCE"], result[0]["ORG_INSTANCE"],
|
||||
start, start))
|
||||
self.buddy_service.add_buddy(char_info['CHAR_INSTANCE'], "track")
|
||||
count += 1
|
||||
with self.db.pool.get_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.executemany("REPLACE INTO player(char_id, name, first_name, last_name, level, breed, "
|
||||
"gender, faction, profession, profession_title, ai_rank, ai_level, "
|
||||
"org_id, org_name, org_rank_name, org_rank_id, dimension, head_id, "
|
||||
"pvp_rating, pvp_title, source, last_updated) VALUES "
|
||||
"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", data)
|
||||
cur.executemany("REPLACE INTO track_org_members(char_id, org_id) VALUES (?, ?)", data2)
|
||||
|
||||
self.logger.info(f"Organisation {org_name} is now being tracked!")
|
||||
sender.reply(f"<highlight>{org_name}</highlight> is now being tracked. "
|
||||
f"Runtime: {time.time() - start:.2f} seconds.")
|
||||
|
||||
self.logger.info(f"Successfully fetched {count} players in {time.time() - start} seconds.")
|
||||
del self.threads[org_id]
|
||||
|
||||
def remove_single(self, org_id, org_name):
|
||||
members = self.db.query("SELECT * from track_org_members where org_id=?", [org_id])
|
||||
for member in members:
|
||||
self.buddy_service.remove_buddy(member.char_id, "member")
|
||||
self.db.exec("DELETE FROM track_org_members where org_id=?", [org_id])
|
||||
self.db.exec("DELETE FROM online where char_id in (SELECT char_id from player where org_id=?)", [org_id])
|
||||
self.logger.info(f"Organisation {org_name} removed!")
|
||||
del self.threads[org_id]
|
||||
|
||||
def log(self, blob, duration):
|
||||
out = []
|
||||
s = []
|
||||
current = ""
|
||||
|
||||
for entry in blob:
|
||||
s.append(f"[{entry.org_name}] [{entry.action}] {entry.name} "
|
||||
f"({entry.level}/{entry.ai_level})\n")
|
||||
s = sorted(s)
|
||||
if len(s) > 0:
|
||||
s.append(f"\nRuntime: {duration:.2f} seconds.")
|
||||
for entry in s:
|
||||
if len(current) > 1500:
|
||||
out.append(current)
|
||||
current = ""
|
||||
current += entry
|
||||
if len(current) > 10:
|
||||
out.append(current)
|
||||
if len(out) > 0:
|
||||
y = 0
|
||||
for x in out:
|
||||
y += 1
|
||||
blob = ChatBlob(f"Recent changes - {datetime.date.today()} - ({y}/{len(out)})", x, embed=True)
|
||||
self.relay_hub_service.send_message("member_logger", None, blob, blob)
|
||||
@@ -38,12 +38,14 @@ class CharacterInfoController:
|
||||
def pre_start(self):
|
||||
self.bot.register_packet_handler(CharacterName.id, self.character_name_update)
|
||||
|
||||
self.db.shared.exec("CREATE TABLE IF NOT EXISTS name_history ("
|
||||
"char_id INT NOT NULL, "
|
||||
"name VARCHAR(20) NOT NULL, "
|
||||
"created_at INT NOT NULL, "
|
||||
"PRIMARY KEY (char_id, name))")
|
||||
|
||||
def start(self):
|
||||
self.db.exec("CREATE TABLE IF NOT EXISTS name_history ("
|
||||
"char_id INT NOT NULL, "
|
||||
"name VARCHAR(20) NOT NULL, "
|
||||
"created_at INT NOT NULL, "
|
||||
"PRIMARY KEY (char_id, name))")
|
||||
|
||||
self.db.create_view("name_history")
|
||||
self.command_alias_service.add_alias("w", "whois")
|
||||
self.command_alias_service.add_alias("lookup", "whois")
|
||||
@@ -155,7 +157,7 @@ class CharacterInfoController:
|
||||
with self.db.pool.get_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.executemany("INSERT IGNORE INTO name_history (char_id, name, created_at) "
|
||||
"VALUES (?, ?, ?)",
|
||||
"VALUES (%s, %s, %s)",
|
||||
self.name_history)
|
||||
self.name_history = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user