Various Fixes.

generified the Worldboss module; removed the spammy-section as of currently, will be readded at a later stage.
This commit is contained in:
2022-06-24 18:10:45 +02:00
parent e942ac43fa
commit 84a5933490
20 changed files with 274 additions and 176 deletions
+1 -2
View File
@@ -89,8 +89,7 @@ class CommandService:
command_key = self.get_command_key(cmd_name.lower(), sub_command.lower() if sub_command else "") command_key = self.get_command_key(cmd_name.lower(), sub_command.lower() if sub_command else "")
al = access_levels.get(command_key, None) al = access_levels.get(command_key, None)
if al is not None and al != access_level.lower(): if al is not None and al != access_level.lower():
print(handler) raise Exception(f"Different access levels specified for forms of command '{command_key}' with handler '{handler}'")
raise Exception(f"Different access levels specified for forms of command '{command_key}'")
access_levels[command_key] = access_level access_levels[command_key] = access_level
self.register(handler, cmd_name, params, access_level, description, inst.module_name, help_text, self.register(handler, cmd_name, params, access_level, description, inst.module_name, help_text,
+1 -1
View File
@@ -48,7 +48,7 @@ class IgnCore:
self.last_timer_event = 0 self.last_timer_event = 0
self.start_time = int(time.time()) self.start_time = int(time.time())
self.major_version = "IGNCore v2.9" self.major_version = "IGNCore v2.9"
self.minor_version = "4" self.minor_version = "5"
self.incoming_queue = FifoQueue() self.incoming_queue = FifoQueue()
self.mass_message_queue = None self.mass_message_queue = None
self.conns = DictObject() self.conns = DictObject()
+8 -2
View File
@@ -35,6 +35,7 @@ class OrgPorkService:
cache_result = self.cache_service.retrieve(self.CACHE_GROUP, cache_key) cache_result = self.cache_service.retrieve(self.CACHE_GROUP, cache_key)
is_cache = False is_cache = False
result = None
if cache_result and cache_result.last_modified > (t - self.CACHE_MAX_AGE): if cache_result and cache_result.last_modified > (t - self.CACHE_MAX_AGE):
result = json.loads(cache_result.data) result = json.loads(cache_result.data)
is_cache = True is_cache = True
@@ -43,8 +44,13 @@ class OrgPorkService:
try: try:
r = requests.get(url, timeout=5) r = requests.get(url, timeout=5)
result = r.json() d = r.json()
if len(d[1]) > 0:
result = d
elif cache_result:
result = json.loads(cache_result.data)
if not result:
return None
# if data is invalid # if data is invalid
if result[0]["ORG_INSTANCE"] != org_id: if result[0]["ORG_INSTANCE"] != org_id:
result = None result = None
+4 -2
View File
@@ -113,7 +113,8 @@ class Text:
return count return count
def zfill(self, numb, highest_number): def zfill(self, numb, highest_number):
return f"<black>{(self.get_count_digits(highest_number) - self.get_count_digits(numb)) * '0'}</black>{numb}" val = (self.get_count_digits(highest_number) - self.get_count_digits(numb))
return f"{('<black>'+ (val * '0')+'</black>') if val > 0 else ''}{numb}"
def format_pagination(self, data, offset, page, formatter, title, no_data_msg, cmd, page_size=10, headline=""): def format_pagination(self, data, offset, page, formatter, title, no_data_msg, cmd, page_size=10, headline=""):
selected = data[offset:offset + page_size] selected = data[offset:offset + page_size]
@@ -330,7 +331,7 @@ class Text:
def format_message(self, msg, replace_br=True): def format_message(self, msg, replace_br=True):
for t in ["</header>", "</header2>", "</highlight>", "</notice>", "</black>", "</white>", "</yellow>", for t in ["</header>", "</header2>", "</highlight>", "</notice>", "</black>", "</white>", "</yellow>",
"</blue>", "</green>", "</red>", "</orange>", "</grey>", "</cyan>", "</blue>", "</green>", "</red>", "</orange>", "</grey>", "</cyan>",
"</violet>", "</neutral>", "</omni>", "</clan>", "</unknown>"]: "</violet>", "</neutral>", "</omni>", "</clan>", "</unknown>", "</gold>"]:
msg = msg.replace(t, "</font>") msg = msg.replace(t, "</font>")
if replace_br: if replace_br:
msg = msg.replace("<br>", "\n") msg = msg.replace("<br>", "\n")
@@ -344,6 +345,7 @@ class Text:
.replace("<yellow>", "<font color=#FFFF00>") \ .replace("<yellow>", "<font color=#FFFF00>") \
.replace("<blue>", "<font color=#8CB5FF>") \ .replace("<blue>", "<font color=#8CB5FF>") \
.replace("<green>", "<font color=#00DE42>") \ .replace("<green>", "<font color=#00DE42>") \
.replace("<gold>", "<font color=#FFD700>") \
.replace("<red>", "<font color=#FF0000>") \ .replace("<red>", "<font color=#FF0000>") \
.replace("<orange>", "<font color=#FCA712>") \ .replace("<orange>", "<font color=#FCA712>") \
.replace("<grey>", "<font color=#C3C3C3>") \ .replace("<grey>", "<font color=#C3C3C3>") \
@@ -230,7 +230,7 @@ class AccountController:
if len(alts) < 1: if len(alts) < 1:
return "No Account registered for this user." return "No Account registered for this user."
prefs = self.preferences.get_pref_view_small(alts[0]) prefs = self.preferences.get_pref_view_small(alts[0])
response = f"<header>{alts[0].name}'s Account</header>\n\n" \ response = f"" \
f" Owner: <notice>{alts[0].name}</notice> ({alts[0].char_id}) " \ f" Owner: <notice>{alts[0].name}</notice> ({alts[0].char_id}) " \
f"[{self.text.make_tellcmd('W', f'whois {alts[0].name}')}] " \ f"[{self.text.make_tellcmd('W', f'whois {alts[0].name}')}] " \
f"[{self.text.make_tellcmd('Alts', f'alts {alts[0].name}')}] " \ f"[{self.text.make_tellcmd('Alts', f'alts {alts[0].name}')}] " \
+35 -13
View File
@@ -69,7 +69,7 @@ class DiscordCommandHandler(BaseModule):
'discord_handle': 'discord_handle':
f'{ctx.author.name}#{ctx.author.discriminator}'}), f'{ctx.author.name}#{ctx.author.discriminator}'}),
reply, reply) reply, reply)
if type(reply) == ChatBlob: elif type(reply) == ChatBlob:
if reply.embed: if reply.embed:
embeds = Embed(title=self.parseDiscord(f"{reply.page_prefix} {reply.title} {reply.page_postfix}"), embeds = Embed(title=self.parseDiscord(f"{reply.page_prefix} {reply.title} {reply.page_postfix}"),
color=0x00FF00, color=0x00FF00,
@@ -89,22 +89,36 @@ class DiscordCommandHandler(BaseModule):
reply, reply) reply, reply)
if embeds: if embeds:
if len(embeds.description) > 4000: if len(embeds.description) > 4000:
body = self.discord.text.split_by_separators(embeds.description, 4000, 10) body = self.discord.text.split_by_separators(embeds.description, 3000, 10)
tmp1 = embeds tmp1 = embeds
embeds = [] embeds = []
for x, e in enumerate(body): for x, e in enumerate(body):
tmp = tmp1.copy() tmp = tmp1.copy()
tmp.description = e tmp.description = e
tmp.title += f"*Page ({x}/{len(body)})*" tmp.title += f"*Page ({x+1}/{len(body)})*"
embeds.append(tmp) embeds.append(tmp)
else: else:
embeds = [embeds] embeds = [embeds]
if len(rsp) > 2000: # if len(rsp) > 2000:
rsp = self.discord.text.split_by_separators(rsp, 2000) # rsp = self.discord.text.split_by_separators(rsp, 2000)
for page in rsp: # for page in rsp:
self.discord.client.loop.create_task(ctx.reply(page)) # self.discord.client.loop.create_task(ctx.reply(page))
# else:
tmp = []
_len = 0
for x in embeds:
_len += len(x.description)
if _len < 6000:
tmp.append(x)
else:
self.discord.client.loop.create_task(ctx.reply(rsp, embeds=tmp))
tmp = [x]
_len = len(x.description)
if len(tmp) > 0:
self.discord.client.loop.create_task(ctx.reply(rsp, embeds=tmp))
else: else:
self.discord.client.loop.create_task(ctx.reply(rsp, embeds=embeds)) self.discord.client.loop.create_task(ctx.reply(rsp))
def parseDiscord(self, ctx: str, blob=False): def parseDiscord(self, ctx: str, blob=False):
proficon = {1: "sold", 2: "ma", 3: "eng", 4: "fixer", 5: "agent", 6: "adv", 7: "trad", 8: "crat", 9: "enf", proficon = {1: "sold", 2: "ma", 3: "eng", 4: "fixer", 5: "agent", 6: "adv", 7: "trad", 8: "crat", 9: "enf",
@@ -115,8 +129,9 @@ class DiscordCommandHandler(BaseModule):
f"<notice>{self.discord.util.get_profession(proficon.get(int(match)))}</notice>") f"<notice>{self.discord.util.get_profession(proficon.get(int(match)))}</notice>")
for x in ["`", '*', '_', '|']: for x in ["`", '*', '_', '|']:
ctx = ctx.replace(x, f' \\{x.strip()}') ctx = ctx.replace(x, f'\\{x}')
for pattern, sub in [(r"(<br>|\n|</br>)", r"\n"), for pattern, sub in [(r"(<br>|\n|</br>)", r"\n"),
(r"`", "´"),
(r"<highlight>(.*?)</highlight>", r"**\1**"), (r"<highlight>(.*?)</highlight>", r"**\1**"),
(r"<title>(.*?)</title>", r"**__\1__**"), (r"<title>(.*?)</title>", r"**__\1__**"),
(r"<header>(.*?)</header>", r"**__\1__**"), (r"<header>(.*?)</header>", r"**__\1__**"),
@@ -126,8 +141,9 @@ class DiscordCommandHandler(BaseModule):
(r"<myname>", self.bot.get_char_name()), (r"<myname>", self.bot.get_char_name()),
(r"<symbol>", self.discord.setting_service.get_value("symbol")), (r"<symbol>", self.discord.setting_service.get_value("symbol")),
# (r"<a href=(.*?)itemref://\d+/\d+/\d+\1>(.+?)<\/a>", r"`\2`"), # (r"<a href=(.*?)itemref://\d+/\d+/\d+\1>(.+?)<\/a>", r"`\2`"),
(r"<a href=(.*?)itemref://(\d+)/\d+/(\d+)\1>(.+?)<\/a>", r"[\4](https://aoitems.com/item\/\2\/\3/)" if blob else r"`\4`"), (r"<a .+?href=(.*?)chatcmd:///start (.+?)\1>(.+?)</a>", r"[\3](\2)"),
(r"<a href=(.*?)itemid://(\d+)/(\d+)\1>(.+?)<\/a>", r"[\4](https://aoitems.com/item\/\2\/\3/)" if blob else r"`\4`"), (r"<a href=(.*?)itemref://(\d+)/\d+/(\d+)\1>(.+?)<\/a>", r"[\4](https://aoitems.com/item/\2/\3/)" if blob else r"`\4`"),
(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"<(.+?)>\s*?<\1>", ''),
(r"<pagebreak>", ''), (r"<pagebreak>", ''),
(r"<a.+?href=\'.*?\'>(.*?)</a>", r'`\1`'), (r"<a.+?href=\'.*?\'>(.*?)</a>", r'`\1`'),
@@ -147,9 +163,15 @@ class DiscordCommandHandler(BaseModule):
while cnt > 0: while cnt > 0:
ctx, cnt = re.subn(r"<(black|white|yellow|blue|green|red|orange|grey|cyan|violet)>(.*?|\d+?)</\1>", r"\2", ctx, cnt = re.subn(r"<(black|white|yellow|blue|green|red|orange|grey|cyan|violet)>(.*?|\d+?)</\1>", r"\2",
ctx) ctx)
ctx.rstrip().rstrip(">")
y = re.split('(`.+?`)', ctx)
ctx = ""
for x in y:
if x.startswith("`"):
for var in ['*', '_', '|']:
x = x.replace(f"\\{var}", f'{var}')
ctx += x
ctx.rstrip()
ctx.rstrip(">")
return self.discord.text.strip_html_tags(ctx) return self.discord.text.strip_html_tags(ctx)
@command(command="discord", params=[Const("invite")], access_level="member", @command(command="discord", params=[Const("invite")], access_level="member",
+1 -1
View File
@@ -18,7 +18,7 @@ class DiscordData:
return self.db.exec("UPDATE account SET discord_handle = ? WHERE discord_id = ?", [handle, discord_id]) return self.db.exec("UPDATE account SET discord_handle = ? WHERE discord_id = ?", [handle, discord_id])
def get_discord_invite(self, invite): def get_discord_invite(self, invite):
return self.db.query_single("SELECT * FROM account WHERE discord_invite = ? and a.main=a.char_id", [invite]) return self.db.query_single("SELECT * FROM account a WHERE discord_invite = ? and a.main=a.char_id", [invite])
def get_account_discord_id(self, discord_id): def get_account_discord_id(self, discord_id):
return self.db.query_single("SELECT * FROM account a left join player p on a.char_id=p.char_id WHERE a.discord_id = ? and a.main=a.char_id", [discord_id]) return self.db.query_single("SELECT * FROM account a left join player p on a.char_id=p.char_id WHERE a.discord_id = ? and a.main=a.char_id", [discord_id])
@@ -66,7 +66,7 @@ class PrivateChannelController:
@event("connect", "Reinvite previous raiders") @event("connect", "Reinvite previous raiders")
def reinvite_all(self, _, _1): def reinvite_all(self, _, _1):
for user in self.reinvite: for user in set(self.reinvite):
self.bot.send_mass_message(user, "You have been <green>reinvited</green> into my private channel " self.bot.send_mass_message(user, "You have been <green>reinvited</green> into my private channel "
"after a bot restart or crash; Sorry for the inconvenience.") "after a bot restart or crash; Sorry for the inconvenience.")
self.priv.invite(user) self.priv.invite(user)
+1 -1
View File
@@ -203,7 +203,7 @@ class OrgController:
"left join all_orgs a on o.org_id = a.org_id order by lower(a.org_name)") "left join all_orgs a on o.org_id = a.org_id order by lower(a.org_name)")
for org in ours: for org in ours:
result = requests.get(self.single_org_uri % org.org_id).json() result = requests.get(self.single_org_uri % org.org_id).json()
if result: if result and len(result[1]) > 0:
self.cache.store('org_roster', f"{org.org_id}.5.json", json.dumps(result)) self.cache.store('org_roster', f"{org.org_id}.5.json", json.dumps(result))
else: else:
result = json.loads(self.cache.retrieve('org_roster', f"{org.org_id}.5.json").data) result = json.loads(self.cache.retrieve('org_roster', f"{org.org_id}.5.json").data)
@@ -1,4 +1,4 @@
import time #import time
from core.chat_blob import ChatBlob from core.chat_blob import ChatBlob
from core.command_param_types import Const, Character, Options, Any from core.command_param_types import Const, Character, Options, Any
+1 -1
View File
@@ -85,7 +85,7 @@ class OrgChannelController:
if not self.bot.is_ready(): if not self.bot.is_ready():
return return
main = self.account_service.get_account(event_data.char_info.char_id) main = self.account_service.get_account(event_data.char_info.char_id)
alt = f":: Alt of <highlight>{main.name}</highlight> " if event_data.account else "" alt = f":: Alt of <highlight>{main.name}</highlight> " if event_data.account and main.name else ""
if main.char_id == event_data.char_info.char_id: if main.char_id == event_data.char_info.char_id:
alt = "" alt = ""
logon = f" :: <grey>{event_data.account.logon}<grey>" if event_data.account.logon else "" logon = f" :: <grey>{event_data.account.logon}<grey>" if event_data.account.logon else ""
+46 -1
View File
@@ -1,4 +1,5 @@
import time import time
from collections import OrderedDict
from typing import Union from typing import Union
from core.aochat import server_packets from core.aochat import server_packets
@@ -9,6 +10,7 @@ from core.command_param_types import Const, Int, Any, Options, Character
from core.command_request import CommandRequest from core.command_request import CommandRequest
from core.db import DB from core.db import DB
from core.decorators import instance, command, timerevent, event from core.decorators import instance, command, timerevent, event
from core.dict_object import DictObject
from core.event_service import EventService from core.event_service import EventService
from core.lookup.character_service import CharacterService from core.lookup.character_service import CharacterService
from core.lookup.pork_service import PorkService from core.lookup.pork_service import PorkService
@@ -20,6 +22,7 @@ from core.igncore import IgnCore
from core.util import Util from core.util import Util
from modules.core.accounting.services.account_service import AccountService from modules.core.accounting.services.account_service import AccountService
from modules.raidbot.raid.preset_controller import PresetController from modules.raidbot.raid.preset_controller import PresetController
from modules.standard.online.online_controller import OnlineController
from modules.standard.raid.leader_controller import LeaderController from modules.standard.raid.leader_controller import LeaderController
@@ -75,6 +78,7 @@ class RaidbotController(BaseModule):
self.private_channel_service: PrivateChannelService = registry.get_instance("private_channel_service") self.private_channel_service: PrivateChannelService = registry.get_instance("private_channel_service")
self.account_service: AccountService = registry.get_instance("account_service") self.account_service: AccountService = registry.get_instance("account_service")
self.buddy_service: BuddyService = registry.get_instance("buddy_service") self.buddy_service: BuddyService = registry.get_instance("buddy_service")
self.online: OnlineController = registry.get_instance("online_controller")
@event("connect", "Adds all raiders to buddylist") @event("connect", "Adds all raiders to buddylist")
def connect(self, _, _1): def connect(self, _, _1):
@@ -192,7 +196,7 @@ class RaidbotController(BaseModule):
if not char.char_id: if not char.char_id:
return self.getresp("global", "char_not_found", {"char": char.name}) return self.getresp("global", "char_not_found", {"char": char.name})
if not self.private_channel_service.in_private_channel(char.char_id): if not self.private_channel_service.in_private_channel(char.char_id):
return f"The player <highlight>{char.name}</highlight> is not in my private channel. Could not add him." return f"The player <highlight>{char.name}</highlight> is not in my private channel. You cannot add him/her to the raid."
main_id = self.account_service.get_main(char.char_id).char_id main_id = self.account_service.get_main(char.char_id).char_id
in_raid = self.is_in_raid(main_id) in_raid = self.is_in_raid(main_id)
if in_raid is not None: if in_raid is not None:
@@ -365,6 +369,47 @@ class RaidbotController(BaseModule):
raider_names.clear() raider_names.clear()
return ChatBlob("Active check", blob) return ChatBlob("Active check", blob)
@command(command="raid", params=[Const("list")], description="Get a list if (in)active raiders.",
access_level="leader", sub_command="manage")
def raid_check_cmd(self, _1, _):
if not self.raid:
return self.NO_RAID_RUNNING_RESPONSE
raiders = {}
o = self.online.online_display.get_online_players("ORDER BY p.profession, p.name", "", [self.bot.get_char_name(), self.bot.get_char_id()])
users = []
for x in self.raid.raiders:
if x.is_active:
users.append(self.character_service.resolve_char_to_name(x.active_id))
for x in o:
if x.channel_id not in [1, 2, 4] and x.name not in users:
continue
if x.name in raiders.keys():
if raiders[x.name].channel_id < x.channel_id:
continue
raiders[x.name] = x
if x.name in users:
raiders[x.name].update({'in_raid': True})
else:
raiders[x.name].update({'in_raid': False})
raiders = DictObject(raiders)
blob = ""
for name, raider in raiders.items():
if not raider.in_raid and raider.channel_id > 2:
continue
entry = f"{self.util.get_prof_icon(raider.profession)} " \
f"{self.text.zfill(raider.level, 220)}/<green>{self.text.zfill(raider.ai_level, 30)}</green> " \
f"{raider.name} [<highlight>{raider.main_name or raider.name}</highlight>] - " \
f"{'<green>In Raid</green>' if raider.in_raid else '<red>Not in Raid</red>'}"
if raider.in_raid:
entry += f" - [{self.text.make_tellcmd('Kick', f'raid kick {raider.name} <no reason given>')}]"
else:
entry += f" - [{self.text.make_tellcmd('Add', f'raid add {raider.name}')}]"
blob += f"{entry}\n"
return ChatBlob("Raid list", blob)
@command(command="raid", params=[Const("kick"), Character("char"), Any("reason")], @command(command="raid", params=[Const("kick"), Character("char"), Any("reason")],
description="Set raider as kicked with a reason", access_level="leader", sub_command="manage") description="Set raider as kicked with a reason", access_level="leader", sub_command="manage")
def raid_kick_cmd(self, request, _2, char: SenderObj, reason: str): def raid_kick_cmd(self, request, _2, char: SenderObj, reason: str):
@@ -141,4 +141,4 @@ class WhatBuffsController:
return ChatBlob(f"Whatbuffs - {skill.name} {item_type} ({len(data):d})", blob) return ChatBlob(f"Whatbuffs - {skill.name} {item_type} ({len(data):d})", blob)
def get_footer(self): def get_footer(self):
return "\nItem DB Extraction Info provided by Unk" return "\nItem DB Extraction Info provided by IGNCore"
+1 -1
View File
@@ -45,7 +45,7 @@ class LevelController:
@command(command="mission", params=[Int("mission_level")], access_level="member", @command(command="mission", params=[Int("mission_level")], access_level="member",
description="Show what character levels can roll a specified mission level", description="Show what character levels can roll a specified mission level",
extended_description="Updated mission levels provided by Lucier") extended_description="Updated mission levels provided by Zetabyte")
def mission_cmd(self, _, level): def mission_cmd(self, _, level):
if 1 <= level <= 250: if 1 <= level <= 250:
levels = self.get_mission_levels(level) levels = self.get_mission_levels(level)
+1 -4
View File
@@ -134,10 +134,7 @@ hh:mm - DD.MM.YYYY
out += f"[Starts in {self.util.time_to_readable(next_event.start - time.time())}] " \ out += f"[Starts in {self.util.time_to_readable(next_event.start - time.time())}] " \
f"[by <highlight>{name}</highlight>]\n" f"[by <highlight>{name}</highlight>]\n"
for timer in self.worldboss.timer_data: out += self.worldboss.getWBTimer()
msg = self.worldboss.show_user(timer)
if msg != "No timers cached; please try again later.":
out += " " + msg + "\n"
return out return out
def get_next_event(self): def get_next_event(self):
+157 -131
View File
@@ -1,10 +1,10 @@
import time import datetime
from typing import Union
from core.chat_blob import ChatBlob from core.chat_blob import ChatBlob
from core.command_alias_service import CommandAliasService from core.command_alias_service import CommandAliasService
from core.command_param_types import Any from core.command_param_types import Any, Const
from core.decorators import instance, command, event, setting from core.decorators import instance, command, event
from core.dict_object import DictObject
from core.igncore import IgnCore from core.igncore import IgnCore
from core.job_scheduler import JobScheduler from core.job_scheduler import JobScheduler
from core.logger import Logger from core.logger import Logger
@@ -16,17 +16,66 @@ from core.util import Util
from modules.standard.datanet.ws_controller import WebsocketRelayController from modules.standard.datanet.ws_controller import WebsocketRelayController
class TimerObj:
name: str = ""
spawn: int = 0
mortal: int = 0
time: int = 0
spam: int = 0
def __init__(self, obj):
self.name = obj.name
self.spawn = obj.spawn
self.mortal = obj.mortal
self.time = obj.time
def update(self, obj):
self.spawn = obj.spawn
self.time = obj.time
def __str__(self):
return f"{self.name} " \
f"\n\tspawn: {datetime.datetime.fromtimestamp(self.spawn, tz=datetime.timezone.utc).strftime('%H:%M:%S')}" \
f"\n\tmortal delta: {self.mortal}" \
f"\n\tmortal: {datetime.datetime.fromtimestamp(self.time, tz=datetime.timezone.utc).strftime('%H:%M:%S')}" \
f"\n\tImmortal: {self.alive_immortal()}" \
f"\n\tMortal killable: {self.alive_mortal()}"\
f"\n\t{self.name} - {self.spawn} - {self.mortal} - {self.time} - {self.spam} - {self.getTime()}"
def alive_immortal(self, spam=False) -> bool:
if spam:
return self.spam < self.spawn < self.time and self.time > self.getTime()
return self.time > self.getTime()
def alive_mortal(self, spam=False) -> bool:
if spam:
return self.spam < self.time < (self.getTime()) and (self.time+60) > self.getTime()
return self.time < self.getTime()
@classmethod
def getTime(cls) -> int:
return int(datetime.datetime.now().timestamp())
def get_respawn_timer(self):
if self.name in ["Tarasque", "Loren Warr", "The Hollow Reaper", "Cerubin The Reborn"]:
return 9*60*60
elif self.name in ["Vizaresh"]:
return 17*60*60
elif self.name in ["Atma"]:
return 3 * 60 * 60
elif self.name in ["T.A.M.", "Zaal The Immortal"]:
return 6 * 60 * 60
elif self.name in ["Abmouth Indomitus"]:
return 0
@instance() @instance()
class WorldBossController: class WorldBossController:
# Timers are provided through a local websocket relay, which gets fed by an external API.
# example timer data:
# [{"name":"Tarasque","time": <mortal time>},
# {"name":"Vizaresh","time": <mortal time>}]
timer_data = [] timer_data = []
alerts = [480 * 60, 360 * 60, 240 * 60, 120 * 60, 60 * 60, 60 * 15, alerts = [480 * 60, 360 * 60, 240 * 60, 120 * 60, 60 * 60, 60 * 15,
60 * 5, 60 * 3, 60 * 2, 60, 30, 15, 5, 0] 60 * 5, 60 * 3, 60 * 2, 60, 30, 15, 5, 0]
jobs = [] jobs = {}
def inject(self, registry): def inject(self, registry):
self.logger = Logger(__name__) self.logger = Logger(__name__)
@@ -48,80 +97,46 @@ class WorldBossController:
self.command_alias_service.add_alias("loren", "wb loren") self.command_alias_service.add_alias("loren", "wb loren")
self.command_alias_service.add_alias("reaper", "wb reaper") self.command_alias_service.add_alias("reaper", "wb reaper")
def spam_timer(self, time, mob, msg):
self.send_warn(msg)
self.jobs.pop(mob, 0)
@event(WebsocketRelayController.WS_RELAY, "save most current local_timers") @event(WebsocketRelayController.WS_RELAY, "save most current local_timers")
def get_timer(self, _, data): def get_timer(self, _, data):
# print(data)
if data.type != "timer": if data.type != "timer":
return return
local_timers = {} local = {}
spam = True if self.setting_service.get_value("timer_spam") == "1" else False for x in data.payload:
found = False
for y in self.timer_data:
if y.name == x.name and not found:
y.update(x)
found = True
if not found:
self.timer_data.append(TimerObj(x))
# print("-"*50)
for x in self.timer_data: for x in self.timer_data:
local_timers[x['name']] = x['time'] x: TimerObj
for row in data.payload: # print(x.__str__())
spawn = self.get_spawn(row) if x.alive_immortal(True):
if not spawn: x.spam = x.getTime()
continue job = self.jobs.pop(x.name, None)
if row['name'] not in local_timers: if job:
self.timer_data.append(row) self.job_scheduler.cancel_job(job)
if spam: self.send_warn(f"<highlight>{x.name}</highlight> has spawned.")
for x in self.jobs: i = self.job_scheduler.scheduled_job(self.spam_timer, x.time-1, mob=x.name, msg=f"<highlight>{x.name}</highlight> is now mortal.")
if x['name'] == row['name']: self.jobs[x.name] = i
self.job_scheduler.cancel_job(x['id']) elif x.alive_mortal(True):
self.jobs.append( x.spam = x.getTime()
{'name': row['name'], 'id': self.job_scheduler.delayed_job(self.timer_alert, 2, spawn)}) job = self.jobs.pop(x.name, None)
continue if job:
elif (local_timers[row['name']] + 1) < row['time']: self.job_scheduler.cancel_job(job)
for timer in self.timer_data: self.send_warn(f"<highlight>{x.name}</highlight> is now mortal.")
if timer['name'] == row['name']: if x.get_respawn_timer() != 0:
timer['time'] = row['time'] i = self.job_scheduler.scheduled_job(self.spam_timer, x.time+x.get_respawn_timer(), mob=x.name, msg=f"<highlight>{x.name}</highlight> should spawn soon.")
if spam: self.jobs[x.name] = i
for job in self.jobs: # print("-"*50)
if job['name'] == row['name']:
self.job_scheduler.cancel_job(job['id'])
alert_duration = self.get_next_alert(spawn.at - time.time())
job_id = self.job_scheduler.scheduled_job(self.timer_alert, 2,
spawn)
job['id'] = job_id
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)
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): def send_warn(self, msg):
self.relay_hub.send_message("timers", None, f"[<red>WB</red>] {msg}", f"[<red>WB</red>] {msg}") self.relay_hub.send_message("timers", None, f"[<red>WB</red>] {msg}", f"[<red>WB</red>] {msg}")
@@ -135,65 +150,76 @@ class WorldBossController:
@command(command="wb", params=[Any("worldboss", is_optional=True)], @command(command="wb", params=[Any("worldboss", is_optional=True)],
description="Displays the next worldboss spawns", access_level="member") description="Displays the next worldboss spawns", access_level="member")
def show_worldboss(self, request, boss: str): def show_worldboss(self, request, boss: str):
if boss: return ChatBlob("Next Worldboss spawns", self.getWBTimer())
boss = boss.lower()
if boss in ["tara", "tarasque"]: @command(command="wb", params=[Const("settings")],
boss = "Tarasque" description="Worldboss Settings", access_level="moderator", sub_command="mod")
elif boss in ["viza", "vizaresh", "gaunt", "gauntlet"]: def wb_settings_cmd(self, request, boss: str):
boss = "Vizaresh" pass
elif boss in ["loren", "loren warr", "loren war", "lw"]:
boss = "Loren Warr"
elif boss in ["thr", "the hollow", "the hollow reaper", "reaper"]:
boss = "The Hollow Reaper"
for x in self.timer_data:
if x['name'] == boss:
return self.show_user(x)
else:
blob = "\n".join([self.show_user(x) for x in self.timer_data if
self.show_user(x) != "No timers cached; please try again later."])
return ChatBlob("Next Worldboss spawns", blob)
def show_user(self, timer): def show_user(self, timer):
timer = self.get_spawn(timer) timer = self.getWBTimer(timer)
if not timer: if not timer:
return "No timers cached; please try again later." return "No timers cached; please try again later."
if timer.type == "mortal": if timer.spawn < timer.getTime() < timer.time:
return f"<highlight>{timer.name}</highlight> :: mortal in {self.util.format_time(timer.time)}" return f"<highlight>{timer.name}</highlight> :: mortal in {self.util.format_time(timer.time-timer.spawn)}"
elif timer.type == "spawn": elif timer.time < timer.getTime():
return f"<highlight>{timer.name}</highlight> :: spawn in {self.util.format_time(timer.time)}" rt = timer.get_respawn_timer()
return f"<highlight>{timer.name}</highlight> :: spawn in {self.util.format_time(timer.time + timer.get_respawn_timer())}"
def getWBTimer(self, name=None) -> Union[TimerObj, list[TimerObj]]:
if not name:
blob = ""
for x in self.timer_data:
x: TimerObj
if x.alive_immortal():
blob += f" <highlight>{x.name}</highlight> :: mortal in {self.util.format_time(x.time - x.getTime())}\n"
else:
rt = x.get_respawn_timer()
if rt != 0:
if (x.time + rt) < x.getTime() < (x.time + 2 * rt):
blob += f" <highlight>{x.name}</highlight> :: should have spawned <highlight>{self.util.format_time(abs(x.getTime() - (x.time + rt)))}</highlight> ago\n"
continue
blob += f" <highlight>{x.name}</highlight> :: spawn in {self.util.format_time(x.time + rt - x.getTime())}\n"
return blob
for x in self.timer_data:
if x.name == name:
return x
def timer_alert(self, t, timer): def timer_alert(self, t, timer):
if self.setting_service.get_value("timer_spam") == "0": pass
return # if self.setting_service.get_value("timer_spam") == "0":
for row in self.timer_data: # return
if row["name"] == timer.name: # for row in self.timer_data:
timer = self.get_spawn(row) # if row["name"] == timer.name:
if not timer.at: # timer = self.get_spawn(row)
return # if not timer.at:
alert_duration = self.get_next_alert(timer.at - time.time()) # return
if timer.at - time.time() < 1: # alert_duration = self.get_next_alert(timer.at - time.time())
if timer.type == "mortal": # if timer.at - time.time() < 1:
self.send_warn(f"<highlight>{timer.name}</highlight> :: is now mortal") # if timer.type == "mortal":
self.jobs = [x for x in self.jobs if x['name'] != timer.name] # self.send_warn(f"<highlight>{timer.name}</highlight> :: is now mortal")
elif timer.type == "spawn": # self.jobs = [x for x in self.jobs if x['name'] != timer.name]
self.send_warn(f"<highlight>{timer.name}</highlight> :: has just spawned") # elif timer.type == "spawn":
self.jobs = [x for x in self.jobs if x['name'] != timer.name] # self.send_warn(f"<highlight>{timer.name}</highlight> :: has just spawned")
else: # self.jobs = [x for x in self.jobs if x['name'] != timer.name]
if timer.type == "mortal": # else:
self.send_warn(f"<highlight>{timer.name}</highlight> :: mortal in {self.util.format_time(timer.time)}") # if timer.type == "mortal":
elif timer.type == "spawn": # self.send_warn(f"<highlight>{timer.name}</highlight> :: mortal in {self.util.format_time(timer.time)}")
if alert_duration > 60 * 2: # elif timer.type == "spawn":
self.send_warn( # if alert_duration > 60 * 2:
f"<highlight>{timer.name}</highlight> :: spawn in {self.util.format_time(timer.time)}") # self.send_warn(
for row in self.timer_data: # f"<highlight>{timer.name}</highlight> :: spawn in {self.util.format_time(timer.time)}")
if row["name"] == timer.name: # for row in self.timer_data:
timer = self.get_spawn(row) # if row["name"] == timer.name:
job_id = self.job_scheduler.scheduled_job(self.timer_alert, time.time() + alert_duration, timer) # timer = self.get_spawn(row)
for job in self.jobs: # job_id = self.job_scheduler.scheduled_job(self.timer_alert, time.time() + alert_duration, timer)
if job['name'] == timer.name: # for job in self.jobs:
job['id'] = job_id # if job['name'] == timer.name:
return # job['id'] = job_id
self.jobs.append({'name': timer.name, 'id': job_id}) # return
# self.jobs.append({'name': timer.name, 'id': job_id})
# @setting('alert_times', '[480 * 60, 360 * 60, 240 * 60, 120 * 60, 60 * 60, 60 * 15, 60 * 5, 60 * 3, 60 * 2, 60, 30, 15, 5, 0]', 'Worldboss timer spam messages (ETA and actual)') # @setting('alert_times', '[480 * 60, 360 * 60, 240 * 60, 120 * 60, 60 * 60, 60 * 15, 60 * 5, 60 * 3, 60 * 2, 60, 30, 15, 5, 0]', 'Worldboss timer spam messages (ETA and actual)')
# def alert_times(self): # def alert_times(self):
+3 -1
View File
@@ -10,6 +10,7 @@ from core.command_request import CommandRequest
from core.db import DB from core.db import DB
from core.decorators import instance, event, command from core.decorators import instance, event, command
from core.dict_object import DictObject from core.dict_object import DictObject
from core.event_service import EventService
from core.fifo_queue import FifoQueue from core.fifo_queue import FifoQueue
from core.igncore import IgnCore from core.igncore import IgnCore
from core.logger import Logger from core.logger import Logger
@@ -49,6 +50,7 @@ class OnlineController:
self.online_display: OnlineDisplay = OnlineDisplay(self.text, self.util, self.db, self.afk_list) self.online_display: OnlineDisplay = OnlineDisplay(self.text, self.util, self.db, self.afk_list)
self.account_service: AccountService = registry.get_instance("account_service") self.account_service: AccountService = registry.get_instance("account_service")
self.character_service: CharacterService = registry.get_instance("character_service") self.character_service: CharacterService = registry.get_instance("character_service")
self.event_service: EventService = registry.get_instance("event_service")
def pre_start(self): def pre_start(self):
self.db.exec("DROP TABLE IF EXISTS online") self.db.exec("DROP TABLE IF EXISTS online")
@@ -92,7 +94,7 @@ class OnlineController:
while self.bot.status != BotStatus.SHUTDOWN: while self.bot.status != BotStatus.SHUTDOWN:
data, channel, logged = self.awaiting_data.get() data, channel, logged = self.awaiting_data.get()
buddy = (self.buddy_service.get_buddy(data.packet.char_id) or {}).get("types", []) buddy = (self.buddy_service.get_buddy(data.packet.char_id) or {}).get("types", [])
if ("org_member" in buddy) or ("member" in buddy): if ("org_member" in buddy) or ("member" in buddy) or ("darknet" in buddy):
if logged: if logged:
self.db.exec("INSERT IGNORE INTO online VALUES(?, ?, ?)", self.db.exec("INSERT IGNORE INTO online VALUES(?, ?, ?)",
[data.packet.char_id, channel, self.bot.get_char_id()]) [data.packet.char_id, channel, self.bot.get_char_id()])
+4 -5
View File
@@ -5,7 +5,7 @@ from core.command_param_types import Any, Const, Time, Options
from core.decorators import instance, command from core.decorators import instance, command
from core.igncore import IgnCore from core.igncore import IgnCore
from core.registry import Registry from core.registry import Registry
from modules.standard.news.worldboss_controller import WorldBossController from modules.standard.news.worldboss_controller import WorldBossController, TimerObj
class TimerTime(Time): class TimerTime(Time):
@@ -83,10 +83,9 @@ class TimerController:
blob = "" blob = ""
if self.worldboss.timer_data: if self.worldboss.timer_data:
blob += "<header>Automatic Timers</header>\n" blob += "<header>Automatic Timers</header>\n"
for row in self.worldboss.timer_data: blob += self.worldboss.getWBTimer()
msg, cnt = getmsg(self.worldboss.show_user(row)) x: TimerObj = None
blob += msg count += len([x for x in self.worldboss.timer_data if (x.time+x.get_respawn_timer()) < x.getTime()])
count += cnt
blob += "\n\n<header>Manual Timers</header>\n" blob += "\n\n<header>Manual Timers</header>\n"
for timer in data: for timer in data:
repeats = "" repeats = ""
+1 -1
View File
@@ -147,7 +147,7 @@ class TowerHotController(BaseModule):
params.append(min_ql) params.append(min_ql)
params.append(max_ql) params.append(max_ql)
if faction: if faction:
where += " AND c.faction LIKE " where += " AND c.faction LIKE ?"
params.append("%" + faction.capitalize() + "%") params.append("%" + faction.capitalize() + "%")
data = self.db.query("SELECT a.*, f.short_name, c.org_name, b.min_ql, b.max_ql, " data = self.db.query("SELECT a.*, f.short_name, c.org_name, b.min_ql, b.max_ql, "
"(CASE WHEN (a.close_time-?) < 0 THEN a.close_time-? +86400 ELSE a.close_time-? END) " "(CASE WHEN (a.close_time-?) < 0 THEN a.close_time-? +86400 ELSE a.close_time-? END) "
+5 -5
View File
@@ -1,13 +1,13 @@
bbcode==1.1.0 bbcode==1.1.0
beautifulsoup4==4.10.0 beautifulsoup4==4.11.1
cryptography==3.3.2 cryptography==3.3.2
discord.py @ git+https://github.com/Rapptz/discord.py@1bfe6b2bb160ce802a1f08afed73941a19a0a651 discord.py @ git+https://github.com/Rapptz/discord.py@1bfe6b2bb160ce802a1f08afed73941a19a0a651
emojis==0.6.0 emojis==0.6.0
hjson==3.0.2 hjson==3.0.2
mariadb==1.0.7 mariadb==1.0.11
psutil==5.8.0 psutil==5.9.1
pytz==2021.3 pytz==2022.1
requests==2.26.0 requests==2.28.0
torpy==1.1.6 torpy==1.1.6
websock==1.0.4 websock==1.0.4
websocket-client==1.2.1 websocket-client==1.2.1