Initial Release of IGNCore version 2.5

This commit is contained in:
2021-08-09 13:18:56 +02:00
commit a83d98c47e
910 changed files with 224171 additions and 0 deletions
+225
View File
@@ -0,0 +1,225 @@
import time
from datetime import datetime
from core.buddy_service import BuddyService
from core.chat_blob import ChatBlob
from core.command_param_types import Options, Int, Any, Character, Const
from core.db import DB
from core.decorators import instance, event, command
from core.dict_object import DictObject
from core.job_scheduler import JobScheduler
from core.logger import Logger
from core.text import Text
from core.tyrbot import Tyrbot
from modules.core.accounting.services.account_service import AccountService
from modules.core.ban.ban_service import BanService
@instance()
class MailController:
def inject(self, registry):
self.logger = Logger(__name__)
self.bot: Tyrbot = registry.get_instance("bot")
self.db: DB = registry.get_instance("db")
self.text: Text = registry.get_instance("text")
self.ban: BanService = registry.get_instance("ban_service")
self.buddy_service: BuddyService = registry.get_instance("buddy_service")
self.job_schedule: JobScheduler = registry.get_instance("job_scheduler")
self.account_service: AccountService = registry.get_instance("account_service")
def pre_start(self):
self.db.exec(
"CREATE TABLE IF NOT EXISTS mail("
"id int primary key auto_increment, "
"text text, "
"recipient int not null, "
"sender int not null, "
"sent_at int not null, "
"`read` int not null default 0)")
@event(event_type="connect", description="register players with pending mails")
def connect_event(self, _, _1):
data = self.db.query(
"SELECT a.char_id from mail m "
"left join account a ON a.main = m.recipient "
"WHERE `read` = 0 and (a.disabled = 0 and a.member=1) "
"group by a.char_id")
for row in data:
self.buddy_service.add_buddy(row.char_id, "mail")
@event(event_type="member_logon", description="Send mails on logon")
def logon_event(self, _, data):
if not self.bot.is_ready():
return
if data.account.disabled == 1:
return
if "mail" in self.buddy_service.get_buddy(data.packet.char_id)["types"]:
self.job_schedule.delayed_job(self.send_mail, 16, data.packet.char_id, self.get_mails(data.packet.char_id))
def send_mail(self, _, sender, mail, greeting="Hey, you got some mails!"):
if self.buddy_service.get_buddy(sender)["online"] == 0:
return
# hotfix for
if len(mail) < 10:
self.buddy_service.remove_buddy(sender, "mail")
return
self.bot.send_mass_message(sender, f"<red>{greeting}</red> <yellow>::</yellow> " +
self.text.paginate_single(ChatBlob("Your mails", mail)))
#####################
# Mail Management #
#####################
@command(command="mail", params=[Const('all', is_optional=True)], description="Show your mails",
access_level="member")
def mail_show(self, sender, const_all):
if const_all:
mails = self.get_mails(sender.sender.char_id, True)
if mails:
self.bot.send_private_message(sender.sender.char_id, ChatBlob("All your recent Mails", mails))
else:
return "You dont have any mails."
else:
mails = self.get_mails(sender.sender.char_id)
if mails:
self.bot.send_private_message(sender.sender.char_id, ChatBlob("Your unread mails", mails))
else:
return "You dont have any unread mails."
@command(command="mail", params=[Options(["read"]), Int("ID")],
description="mark a mail as read", access_level="member")
def mail_read(self, sender, _, mail_id):
row = self.db.exec(
"UPDATE mail set `read` = 1 where recipient=(SELECT main from account where char_id=? LIMIT 1) and id=?",
[sender.sender.char_id, mail_id])
if len(self.get_mails(sender.sender.char_id)) < 10:
alts = self.account_service.get_alts(sender.sender.char_id)
for i in alts:
self.buddy_service.remove_buddy(i.char_id, "mail")
if row == 0:
return f"You dont have an unread mail with the ID <highlight>{mail_id}</highlight>."
elif row == 1:
return f"The mail with the ID <highlight>{mail_id}</highlight> has been marked as read."
else:
return "Something went wrong. please contact an administrator."
@command(command="mail", params=[Options(["delete"]), Int("ID")],
description="mark a mail as read", access_level="member")
def mail_delete(self, sender, _, mail_id):
row = self.db.exec(
"DELETE FROM mail where recipient=(SELECT main from account where char_id=? LIMIT 1) and id=?",
[sender.sender.char_id, mail_id])
if len(self.get_mails(sender.sender.char_id)) < 10:
alts = self.account_service.get_alts(sender.sender.char_id)
for i in alts:
self.buddy_service.remove_buddy(i.char_id, "mail")
if row == 0:
return f"You dont have a mail with the ID <highlight>{mail_id}</highlight>."
elif row == 1:
return f"The mail with the ID <highlight>{mail_id}</highlight> has been deleted."
else:
return "Something went wrong. please contact an administrator."
@command(command="mail", params=[Options(["send"]), Character("recipient"), Any("text")],
description="Send a mail to someone", access_level="member")
def mail_send(self, sender, _, receiver, message):
if not receiver.char_id:
return f"Character <highlight>{receiver.name}</highlight> not found."
recipient = self.account_service.get_account(receiver.char_id)
if not recipient:
return f"No account for <highlight>{receiver.name}</highlight> found."
if recipient.member == -1 or recipient.disabled == 1:
return f"The Character <highlight>{recipient.name}</highlight> has " \
f"no active account in <highlight><myname></highlight>."
self.db.exec("INSERT INTO mail(sender, recipient, text, sent_at) VALUES(?, ?, ?, ?)",
[sender.sender.char_id, recipient.main, message, time.time()])
alts = self.account_service.get_alts(recipient.char_id)
for i in alts:
buddy = self.buddy_service.get_buddy(i.char_id) or []
if "mail" not in buddy:
if i.member == -1:
continue
self.buddy_service.add_buddy(i.char_id, "mail")
if self.buddy_service.is_online(i.char_id):
self.send_mail(0, i.char_id, self.get_mails(i.char_id),
f"{sender.sender.name} just sent you a mail, please read it")
return "Mail sent successfully."
@command(command="mail", params=[Const("group"), Any("group"), Any("text")],
description="Send a mail to a group of players", sub_command='sendgroup', access_level="moderator")
def mail_send_group(self, sender, _, recipient, message):
group = self.account_service.get_group_tag(recipient)
users = []
if group:
if group == "all":
if sender.sender.access_level['level'] > 20:
return "This group is unavailable."
users = self.account_service.get_all_members()
else:
users = self.account_service.get_by_group(group)
elif not group:
return f"Sorry, but the group <highlight>{recipient}</highlight> does not exist. " \
f"The following groups are defined: " \
f"<highlight>admin, council, [all - admin only group], moderator</highlight> " \
f"and <highlight>leaders</highlight>."
count = 0
readers = []
if group != "all":
message += f"<br><tab><header>» This mail has been sent to the " \
f"<highlight>{group}</highlight> group.</header>"
else:
message += f"<br><tab><header>» This mail has been sent to <highlight>everyone</highlight>.</header>"
mails = []
for user in users:
if user.main == user.char_id:
mails.append((sender.sender.char_id, user.main, message, time.time()))
count += 1
if user.online == 1:
readers.append(DictObject({"name": user.name, "char_id": user.char_id}))
with self.db.pool.get_connection() as conn:
with conn.cursor() as cur:
cur.executemany("INSERT INTO mail(sender, recipient, text, sent_at) VALUES(?, ?, ?, ?)", mails)
for user in readers:
self.send_mail(0, user.char_id, self.get_mails(user.char_id),
greeting=f"<highlight>{sender.sender.name}</highlight> just sent you a group mail, "
f"please read it!")
return f"I've sent the <highlight>{count}</highlight> mails to the group " \
f"<highlight>{group}</highlight> for you. " \
f"A total of <highlight>{len(readers)}</highlight> characters from this group are online, " \
f"the have been notified."
def get_single_mail(self, char_id, mail_id):
return ChatBlob(f"Your Mail with the ID {mail_id}", self.format_mail(self.db.query_single(
"SELECT * FROM mail where recipient=(SELECT main from account where char_id=?) and id = ?", [char_id, id])))
def get_mails(self, char_id, all_mails=False):
if all_mails:
data = self.db.query(
"SELECT * FROM mail where recipient=(SELECT main from account where char_id=?) order by id desc",
[char_id])
else:
data = self.db.query(
"SELECT * FROM mail where recipient=(SELECT main from account where char_id=?) and `read`=0 "
"order by id desc",
[char_id])
blob = ""
for row in data:
blob += self.format_mail(row) + "<br>"
return blob
def format_mail(self, mail):
# noinspection LongLine
return \
f"""
<notice>{self.bot.character_service.resolve_char_to_name(mail.sender) if mail.sender != 0 else "IGNCOM"}</notice> sent you a mail on <highlight>{datetime.utcfromtimestamp(mail.sent_at).strftime("%d.%m.%Y - %H:%M:%S")}</highlight>:
<white>{mail.text}</white>
- <green>[{self.text.make_tellcmd('Mark as read', f'mail read {mail.id}')}] [{self.text.make_tellcmd('DELETE', f'mail delete {mail.id}')}]</green>
"""
@event(event_type="main_changed", description="Fix mails")
def fix_mails(self, _, data):
self.db.exec("UPDATE mail set recipient=? where recipient=?", [data.new_main_id, data.old_main_id])
+302
View File
@@ -0,0 +1,302 @@
import random
import textwrap
import time
from datetime import datetime, timezone
from queue import Queue
from core.buddy_service import BuddyService
from core.chat_blob import ChatBlob
from core.command_param_types import Options, Int, Const, Any
from core.db import DB
from core.decorators import instance, event, command
from core.dict_object import DictObject
from core.job_scheduler import JobScheduler
from core.logger import Logger
from core.lookup.pork_service import PorkService
from core.setting_service import SettingService
from core.text import Text
from core.tyrbot import Tyrbot
from core.util import Util
from modules.core.accounting.preference_controller import PreferenceController
from modules.core.accounting.services.account_service import AccountService
from modules.onlinebot.online.org_alias_controller import OrgAliasController
from modules.standard.news.weekly_controller import WeeklyController
from modules.standard.news.worldboss_controller import WorldBossController
@instance()
class NewsController:
queue = Queue()
# taken from https://app2brain.com/de/sprachen-lernen/woerter-saetze/hallo/
greetings = ["Welcome", "Greetings", "Hey", "Namaste", "Ahoy", "Salutations", "Hola", "Ahoj", "Hallo", "Hello",
"Hei", "Salut", "Helló", "Halló", "Ciao", "Olá", "Ahoj", "¡Hola"]
layout = \
"""
<header>News</header>
<notice>CURRENT TIME</notice>
hh:mm - DD.MM.YYYY
{time}
<notice>ACCOUNT</notice>
Your main is: <highlight>{main}</highlight>
You have {alts_show} <highlight>alts</highlight> registered
{discord}
Preferences: {prefs}
<notice>NEWS</notice>
{news}
<notice>TIMERS</notice>
{timers}
<notice>POPULAR COMMANDS</notice>
{commands}
"""
def inject(self, registry):
self.logger = Logger(__name__)
self.bot: Tyrbot = registry.get_instance("bot")
self.db: DB = registry.get_instance("db")
self.text: Text = registry.get_instance("text")
self.account_service: AccountService = registry.get_instance("account_service")
self.pork: PorkService = registry.get_instance("pork_service")
self.util: Util = registry.get_instance("util")
self.buddy_service: BuddyService = registry.get_instance("buddy_service")
self.setting_service: SettingService = registry.get_instance("setting_service")
self.job_schedule: JobScheduler = registry.get_instance("job_scheduler")
self.preferences: PreferenceController = registry.get_instance("preference_controller")
self.alias_controller: OrgAliasController = registry.get_instance("org_alias_controller")
self.weekly: WeeklyController = registry.get_instance("weekly_controller")
self.worldboss: WorldBossController = registry.get_instance("world_boss_controller")
def pre_start(self):
self.db.exec(
"CREATE TABLE IF NOT EXISTS news("
"id int primary key auto_increment, "
"text text, "
"added_by int not null, "
"added_at timestamp, "
"headline int not null default 0)")
def start(self):
self.commands = f" [{self.text.make_chatcmd('raids', '/tell <myname> raids')}] " \
f"[{self.text.make_chatcmd('online', '/tell <myname> online')}]\n" \
f" [{self.text.make_chatcmd('rules', '/tell <myname> rules')}] " \
f"[{self.text.make_chatcmd('about', '/tell <myname> about')}]\n" \
f" [{self.text.make_chatcmd('orgs', '/tell <myname> orgs')}] " \
f"[{self.text.make_chatcmd('admins', '/tell <myname> admins')}]\n"
@event("connect", "prepare info msg")
def prepare_info(self, _, _1):
self.INFO = ChatBlob("Welcome", f"<font color=CCInfoText>You're getting this message,\n"
f"because you recently joined the clan alliance\n"
f"<highlight>The New Alliance</highlight> or in short "
f"<highlight>TNA</highlight>.\n"
f"I'm <notice><myname></notice>, a bot with the task to "
f"automate a few workflows around here,\n"
f"while making the life of everyone a bit easier.\n"
f"\n"
f"You can see a list of all my orgs by using "
f"{self.text.make_tellcmd('!orgs', 'orgs')}.\n"
f"Whenever you use {self.text.make_tellcmd('!online', 'online')} "
f"I'll show you who's currently around.\n"
f"We've got regular raids, you can view them by using "
f"{self.text.make_tellcmd('!raids', 'raids')}\n"
f"If you'd like to stay out, thats fine. Just turn all settings off here: "
f"{self.text.make_tellcmd('here', 'prefs')}\n"
f"\n"
f"If you encounter any issues, my administrators will help you. just ask them, "
f"you can find them all here: {self.text.make_tellcmd('!admins', 'admins')}\n"
f"\n"
f"<highlight>Thats it already. "
f"Thank you for taking your time to read this note. See you ingame!</highlight>"
f"</font>")
self.INFO = f"\n<yellow>________________\n\n" \
f" No need to <red>PANIC</red>!\n" \
f" [{self.text.paginate_single(self.INFO)}]\n" \
f" to our alliance!\n" \
f"________________</yellow>"
@event(event_type="member_logon", description="Send news to players logging in")
def logon_event(self, _, data):
if not self.bot.is_ready():
return
if "member" in self.buddy_service.get_buddy(data.packet.char_id)["types"]:
account = data.account
if account.disabled == 1:
return
if self.db.query_single("SELECT * from org_bots where char_id=?", [data.packet.char_id]):
return
if account.news_spam == 1:
if account.discord_joined == 0:
discord = f"Your Account is <highlight>not</highlight> connected to Discord " \
f"[{self.text.make_chatcmd('Join', '/tell <myname> discord invite')}]"
else:
discord = f"Your Account <highlight>is</highlight> connected to Discord as " \
f"<highlight>[{self.alias_controller.get_alias(account.org_id)}] " \
f"{account.name}</highlight>"
user = self.pork.get_character_info(data.packet.char_id)
self.job_schedule.delayed_job(self.send_news, 15, user, self.account_service.get_alts(account.main),
discord,
self.preferences.get_pref_view_small(account))
if account.last_seen == 0 and self.setting_service.get_value('is_alliance_bot') == "1":
self.bot.send_mass_message(data.packet.char_id, self.INFO)
@command(command="raids", params=[], description="Show the Raids", access_level="member")
def show_raids(self, _):
with open("data/latest_raids.txt", "r") as f:
return self.text.format_page("Raidschedule", f.read())
def get_timers(self):
events = [self.weekly.get_next_bs(),
self.weekly.get_next_ai(),
self.weekly.get_next_dio()]
next_event = sorted(events, key=lambda timer_event: timer_event.start)[0]
name = self.bot.get_char_name().upper()
out = f" <highlight>{self.weekly.get_long_name(next_event.type)}</highlight> - "
if next_event.is_running():
out += f"[Ends in {self.util.time_to_readable(next_event.end - time.time())}] " \
f"[by <highlight>{name}</highlight>]\n"
else:
out += f"[Starts in {self.util.time_to_readable(next_event.start - time.time())}] " \
f"[by <highlight>{name}</highlight>]\n"
for timer in self.worldboss.timer_data:
msg = self.worldboss.show_user(timer)
if msg != "No timers cached; please try again later.":
out += " " + msg + "\n"
return out
def get_next_event(self):
events = [self.weekly.get_next_bs(),
self.weekly.get_next_ai(),
self.weekly.get_next_dio()]
return sorted(events, key=lambda timer: timer.start)[0]
def send_news(self, _, sender, alts, discord, prefs, auto=True):
if auto:
if self.buddy_service.get_buddy(sender.char_id)["online"] == 0:
return
timers = self.get_timers()
next_event = self.get_next_event()
news = self.layout.format(time=datetime.now(timezone.utc).strftime("%H:%M - %d.%m.%Y") + " [UTC-0]",
main=alts[0].name,
alts_show=self.text.make_chatcmd(len(alts), "/tell <myname> alts"),
news=self.get_news(),
timers=timers,
commands=self.commands,
prefs=prefs,
discord=discord)
name = self.weekly.get_long_name(next_event.type)
blob = f"<yellow>{random.choice(self.greetings)} {sender.name} :: " \
f"{self.text.format_page('Your News', textwrap.dedent(news))} </yellow> " \
f"{f'<yellow>::</yellow> {name} running' if next_event.is_running() else ''}"
self.bot.send_mass_message(sender.char_id, blob)
#####################
# News Management #
#####################
@command(command="news", params=[], description="Show the news", access_level="member")
def show_news(self, sender):
user = self.db.query_single("SELECT * FROM player where char_id=?", [sender.sender.char_id])
alts = self.account_service.get_alts(sender.sender.char_id)
if not alts:
discord = f"Your Account is <highlight>not</highlight> connected to Discord " \
f"[{self.text.make_chatcmd('Join', '/tell <myname> discord invite')}]"
alts = [self.account_service.get_main(sender.sender.char_id)]
elif alts[0].discord_joined == 0:
discord = f"Your Account is <highlight>not</highlight> connected to Discord " \
f"[{self.text.make_chatcmd('Join', '/tell <myname> discord invite')}]"
else:
prefix = ""
if self.setting_service.get_value('is_alliance_bot') == '1':
prefix = f"[{self.alias_controller.get_alias(alts[0].org_id)}] "
discord = f"Your Account <highlight>is</highlight> connected to Discord as " \
f"<highlight>{prefix}{alts[0].name}</highlight>"
prefs = self.preferences.get_pref_view_small(alts[0]) if alts else ""
self.send_news(0, user, alts, discord, prefs, False)
@command(command="news", params=[Options(["pin", "unpin"]), Int("ID")], description="Set news as headlines",
access_level="moderator", sub_command="moderate")
def news_pin(self, _, option, news_id):
if option == "pin":
row = self.db.exec("UPDATE news set headline=1 where id =?", [news_id])
if row == 0:
return f"There's no entry with the ID <highlight>{news_id}</highlight>, or it is already pinned."
elif row == 1:
return f"The entry with the ID <highlight>{news_id}</highlight> has been pinned."
else:
return "Multiple entries have been pinned... SHIT!"
elif option == "unpin":
row = self.db.exec("UPDATE news set headline=0 where id =?", [news_id])
if row == 0:
return f"There's no entry with the ID <highlight>{news_id}</highlight>, or it is not pinned."
elif row == 1:
return f"The entry with the ID <highlight>{news_id}</highlight> has been unpinned."
else:
return "Multiple entries have been unpinned... SHIT!"
@command(command="news", params=[Options(["remove", "delete", "rem", "del"]), Int("ID")],
description="Set news as headlines", access_level="moderator", sub_command="moderate")
def news_del(self, _, _1, news_id):
row = self.db.exec("DELETE FROM news where id =?", [news_id])
if row == 0:
return f"There's no entry with the ID <highlight>{news_id}</highlight>."
elif row == 1:
return f"The entry with the ID <highlight>{news_id}</highlight> has been removed."
else:
return "Multiple entries have been deleted... SHIT!"
@command(command="news", params=[Const("add"), Any("text")], description="Moderate the news",
access_level="moderator", sub_command="moderate")
def news_add(self, sender, _, text):
self.add_entry(text, sender.sender)
row = DictObject(
{"added_at": datetime.utcfromtimestamp(time.time()), "added_by": sender.sender.char_id, "headline": 0,
"id": self.db.query_single("SELECT id from news order by id desc").id, "text": text})
return ChatBlob(f"News entry with ID {row.id}",
self.format_entry(row, sender.sender, sender.sender.access_level['level'] <= 30))
@command(command="news", params=[Options(["detail", "info", "more"]), Int("ID", is_optional=True)],
description="Moderate the news", access_level="member")
def news_detail(self, sender, _, news_id):
if news_id:
row = self.db.query_single("SELECT * from news where id=?", [news_id])
if row:
return ChatBlob(f"News entry with ID {news_id}",
self.format_entry(row, sender.sender, sender.sender.access_level['level'] <= 30))
else:
return f"There's no entry with the ID <highlight>{news_id}</highlight>."
else:
return ChatBlob("The latest news", self.get_news(10000, sender.sender))
def get_news(self, limit=500, receiver=None):
data = self.db.query("SELECT * from news order by ID desc")
normal = ""
headline = ""
for entry in data:
if entry.headline == 1:
if len(self.text.strip_html_tags(headline) or []) > limit / 2:
continue
headline += self.format_entry(entry, receiver)
else:
if len(self.text.strip_html_tags(normal) or []) > limit / 2:
continue
normal += self.format_entry(entry, receiver)
if len(self.text.strip_html_tags(headline + normal) or []) > limit:
normal += f" There seem to be more news,<br> but they're too long to get shown here. " \
f"[{self.text.make_tellcmd('Display', 'news detail')}]<br>"
return headline + "____________________________<br><br>" + normal if headline != "" else normal
# noinspection LongLine
def format_entry(self, entry, receiver=None, mod=False):
name = self.bot.get_char_name().upper()
base = f"""<font color=#8CB5FF>On {entry.added_at.strftime("%d.%m.%Y - %H:%M:%S")} UTC by <white>{self.bot.character_service.resolve_char_to_name(entry.added_by) if entry.added_by != 0 else f"{name}"}</white> (ID {entry.id}):</font><br><white>{entry.text}</white><br><br>"""
if mod:
base += f"""<br> - <green>Moderate this entry: [{self.text.make_tellcmd('PIN' if entry.headline == 0 else 'UNPIN', f'news {"pin" if entry.headline == 0 else "unpin"} {entry.id}')}] [{self.text.make_tellcmd('DELETE', f'news delete {entry.id}')}]</green>"""
return base
def add_entry(self, text, sender):
self.db.exec("INSERT INTO news(text, added_by, added_at) VALUES(?, ?, ?)",
[text, sender.char_id, datetime.utcfromtimestamp(time.time())])
+121
View File
@@ -0,0 +1,121 @@
import time
from datetime import datetime
from core.buddy_service import BuddyService
from core.chat_blob import ChatBlob
from core.command_alias_service import CommandAliasService
from core.db import DB
from core.decorators import instance, command
from core.job_scheduler import JobScheduler
from core.logger import Logger
from core.lookup.pork_service import PorkService
from core.setting_service import SettingService
from core.text import Text
from core.tyrbot import Tyrbot
from core.util import Util
from modules.core.accounting.preference_controller import PreferenceController
from modules.core.accounting.services.account_service import AccountService
from modules.core.ban.ban_service import BanService
from modules.core.discord.discord_controller import DiscordController
from modules.onlinebot.online.org_alias_controller import OrgAliasController
@instance()
class WeeklyController:
# dates = {"ai": [1618704000, 1619395200],
# "bs": [1619913600, 1620604800],
# "dio": [1621123200, 1621814400],
# }
dates = {"ai": [1627171200, 1627862400],
"bs": [1628380800, 1629072000],
"dio": [1629590400, 1630281600],
}
duration = 60 * 60 * 24 * 42 # 3628800
def inject(self, registry):
self.logger = Logger(__name__)
self.bot: Tyrbot = registry.get_instance("bot")
self.db: DB = registry.get_instance("db")
self.text: Text = registry.get_instance("text")
self.ban: BanService = registry.get_instance("ban_service")
self.util: Util = registry.get_instance("util")
self.account_service: AccountService = registry.get_instance("account_service")
self.pork: PorkService = registry.get_instance("pork_service")
self.org_pork: PorkService = registry.get_instance("org_pork_service")
self.command_alias_service: CommandAliasService = registry.get_instance("command_alias_service")
self.buddy_service: BuddyService = registry.get_instance("buddy_service")
self.setting_service: SettingService = registry.get_instance("setting_service")
self.discord: DiscordController = registry.get_instance("discord_controller")
self.job_schedule: JobScheduler = registry.get_instance("job_scheduler")
self.preferences: PreferenceController = registry.get_instance("preference_controller")
self.alias_controller: OrgAliasController = registry.get_instance("org_alias_controller")
self.account_service: AccountService = registry.get_instance("account_service")
@command(command="icc", params=[], description="ICC Weekly", access_level="member")
def show_raids(self, _):
events = [self.get_next_bs(),
self.get_next_ai(),
self.get_next_dio()]
events = sorted(events, key=lambda event: event.start)
current = "None"
if events[0].is_running():
current = self.get_long_name(events[0].type) + \
f' [Ends in {self.util.time_to_readable(events[0].end - time.time())}]'
blob = "" \
f"Current Mission: {current}\n" \
f"\n" \
f"Planned:\n"
for i in events:
blob += self.format_entry(i)
return ChatBlob("ICC Weekly Missions", blob)
# noinspection PyShadowingNames
def time_to_readable(self, time):
return datetime.utcfromtimestamp(time).strftime("%d.%m.%Y")
def format_entry(self, event):
return f"{self.get_long_name(event.type)}: <highlight>{self.time_to_readable(event.start)}</highlight> " \
f"-> <highlight>{self.time_to_readable(event.end - 1)}</highlight>\n" if not event.is_running() else ""
def get_long_name(self, event_type):
return {"ai": "Alien Weekly",
"bs": "Battlestation Weekly",
"dio": "Dust it Off Weekly"}.get(event_type)
def get_next_event(self, event_type, now):
cycle = (now - self.dates[event_type][0]) / self.duration
cycle = round(cycle)
event = WeeklyEvent(event_type, self.dates[event_type][0] + cycle * self.duration,
self.dates[event_type][1] + cycle * self.duration)
if event.end <= now:
event.start += self.duration
event.end += self.duration
return event
def get_next_dio(self, when=0):
when = time.time() if when == 0 else when
return self.get_next_event("dio", when)
def get_next_bs(self, when=0):
when = time.time() if when == 0 else when
return self.get_next_event("bs", when)
def get_next_ai(self, when=0):
when = time.time() if when == 0 else when
return self.get_next_event("ai", when)
class WeeklyEvent:
start = 0
end = 0
type = ""
def __init__(self, event_type, start, end):
self.start = start
self.end = end
self.type = event_type
def is_running(self, when=0):
when = time.time() if when == 0 else when
return self.start <= when <= self.end
@@ -0,0 +1,172 @@
import sys
import time
from conf.config import BotConfig
from core.command_alias_service import CommandAliasService
from core.decorators import instance, command, event
from core.dict_object import DictObject
from core.job_scheduler import JobScheduler
from core.logger import Logger
from core.setting_service import SettingService
from core.setting_types import BooleanSettingType
from core.text import Text
from core.tyrbot import Tyrbot
from core.util import Util
from modules.standard.datanet.ws_controller import WebsocketRelayController
@instance()
class WorldBossController:
alerts = [480 * 60, 360 * 60, 240 * 60, 120 * 60, 60 * 60, 60 * 15,
60 * 5, 60 * 3, 60 * 2, 60, 30, 15, 10, 5, 4, 3, 2, 1, 0]
jobs = []
timer_data = []
def __init__(self):
mod = __import__(f'conf.{sys.argv[1]}', fromlist=['BotConfig'])
config: BotConfig = getattr(mod, 'BotConfig')
if hasattr(config, "timer_url"):
self.timer_api = config.timer_url
else:
self.timer_api = None
def inject(self, registry):
self.logger = Logger(__name__)
self.bot: Tyrbot = registry.get_instance("bot")
self.text: Text = registry.get_instance("text")
self.util: Util = registry.get_instance("util")
self.command_alias_service: CommandAliasService = registry.get_instance("command_alias_service")
self.job_scheduler: JobScheduler = registry.get_instance("job_scheduler")
self.setting_service: SettingService = registry.get_instance("setting_service")
def pre_start(self):
self.setting_service.register_new(self.module_name, 'timer_spam', True, BooleanSettingType(),
"should timers be spammed")
@event(WebsocketRelayController.WS_RELAY, "save most current timers")
def get_timer(self, _, data):
if data.type == "timer":
self.timer_data = data.payload
def test(test_data):
if test_data:
for job in self.jobs:
if job["name"] == test_data.name:
return
self.job_scheduler.delayed_job(self.timer_alert, 2, test_data)
if self.setting_service.get_value("timer_spam") == "1":
for row in self.timer_data:
data = self.get_spawn(row)
test(data)
def get_spawn(self, timer):
timer = DictObject(timer)
if timer.name == "Loren Warr":
data = self.calc_spawn_mortal(timer.time, 9 * 60 * 60, 15 * 60)
elif timer.name == "Tarasque":
data = self.calc_spawn_mortal(timer.time, 9 * 60 * 60, 30 * 60)
elif timer.name == "The Hollow Reaper":
data = self.calc_spawn_mortal(timer.time, 9 * 60 * 60, 15 * 60)
elif timer.name == "Vizaresh":
data = self.calc_spawn_mortal(timer.time, 17 * 60 * 60, 6 * 60 + 20)
else:
return None
if not data:
return
if data.spawn < time.time():
if data.mortal > time.time():
return DictObject(
{'name': timer.name, 'type': 'mortal', 'time': data.mortal - time.time(), 'at': data.mortal,
'data': data})
return DictObject(
{'name': timer.name, 'type': 'spawn', 'time': data.spawn - time.time(), 'at': data.spawn, 'data': data})
def calc_spawn_mortal(self, last, respawn, immortal):
pop = last + respawn
attackable = pop + immortal
now = time.time()
# Mortal
if immortal > attackable - now > 0:
return DictObject({'spawn': pop, 'mortal': attackable})
elif immortal > attackable + respawn - now > 0:
return DictObject({'spawn': pop + respawn, 'mortal': attackable + respawn})
# Spawn
elif respawn > (pop - now) > 0:
return DictObject({'spawn': pop, 'mortal': pop})
elif respawn > pop + respawn - now > 0:
return DictObject({'spawn': attackable + respawn, 'mortal': attackable + respawn + immortal})
elif last - now > 0:
return DictObject({'spawn': last - immortal, 'mortal': last})
def send_warn(self, msg):
self.bot.send_private_channel_message(f"[<red>WB</red>] {msg}")
def get_next_alert(self, duration):
for alert in self.alerts:
if duration - 1 > alert:
return duration - alert - 1
return duration
@command(command="gaunt", params=[], description="Displays the next Vizaresh pop time", access_level="member")
def show_gaunt(self, _):
for timer in self.timer_data:
if timer['name'] == "Vizaresh":
return self.show_user(timer)
return "Timer not found"
@command(command="loren", params=[], description="Displays the next Loren Warr pop time", access_level="member")
def show_loren(self, _):
for timer in self.timer_data:
if timer['name'] == "Loren Warr":
return self.show_user(timer)
return "Timer not found"
@command(command="tara", params=[], description="Displays the next Tara pop time", access_level="member")
def show_tara(self, _):
for timer in self.timer_data:
if timer['name'] == "Tarasque":
return self.show_user(timer)
return "Timer not found"
def show_user(self, timer):
timer = self.get_spawn(timer)
if not timer:
return "No timers cached; please try again later."
if timer.type == "mortal":
return f"<highlight>{timer.name}</highlight> :: mortal in {self.util.format_time(timer.time)}"
elif timer.type == "spawn":
return f"<highlight>{timer.name}</highlight> :: spawn in {self.util.format_time(timer.time)}"
def timer_alert(self, t, timer):
if self.setting_service.get_value("timer_spam") == "0":
return
for row in self.timer_data:
if row["name"] == timer.name:
timer = self.get_spawn(row)
alert_duration = self.get_next_alert(timer.at - t)
if timer.at - time.time() < 1:
if timer.type == "mortal":
self.send_warn(f"<highlight>{timer.name}</highlight> :: is now mortal")
self.jobs = [x for x in self.jobs if x['name'] != timer.name]
elif timer.type == "spawn":
self.send_warn(f"<highlight>{timer.name}</highlight> :: has just spawned")
self.jobs = [x for x in self.jobs if x['name'] != timer.name]
else: # timer.at > time.time():
if timer.type == "mortal":
self.send_warn(f"<highlight>{timer.name}</highlight> :: mortal in {self.util.format_time(timer.time)}")
elif timer.type == "spawn":
if alert_duration > 60 * 2:
self.send_warn(
f"<highlight>{timer.name}</highlight> :: spawn in {self.util.format_time(timer.time)}")
for row in self.timer_data:
if row["name"] == timer.name:
timer = self.get_spawn(row)
job_id = self.job_scheduler.scheduled_job(self.timer_alert, t + alert_duration, timer)
for job in self.jobs:
if job['name'] == timer.name:
job['id'] = job_id
return
self.jobs.append({'name': timer.name, 'id': job_id})