Initial Release of IGNCore version 2.5
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import re
|
||||
|
||||
from core.aochat import server_packets, client_packets
|
||||
from core.conn import Conn
|
||||
from core.decorators import instance
|
||||
from core.logger import Logger
|
||||
from core.lookup.character_service import CharacterService
|
||||
from core.setting_service import SettingService
|
||||
from core.setting_types import TextSettingType, BooleanSettingType
|
||||
from core.text import Text
|
||||
from core.tyrbot import Tyrbot
|
||||
|
||||
|
||||
# noinspection DuplicatedCode
|
||||
@instance("AllianceRelayController")
|
||||
class AllianceRelayController:
|
||||
relay_channel_id = None
|
||||
MESSAGE_SOURCE = "alliance"
|
||||
|
||||
def __init__(self):
|
||||
self.logger = Logger(__name__)
|
||||
|
||||
def inject(self, registry):
|
||||
self.bot: Tyrbot = registry.get_instance("bot")
|
||||
self.setting_service: SettingService = registry.get_instance("setting_service")
|
||||
self.character_service: CharacterService = registry.get_instance("character_service")
|
||||
self.message_hub_service = registry.get_instance("message_hub_service")
|
||||
self.public_channel_service = registry.get_instance("public_channel_service")
|
||||
self.text: Text = registry.get_instance("text")
|
||||
|
||||
def pre_start(self):
|
||||
self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)
|
||||
|
||||
def start(self):
|
||||
self.setting_service.register_new(self.module_name, "arelay_symbol", "#",
|
||||
TextSettingType(["!", "#", "*", "@", "$", "+", "-"]),
|
||||
"Symbol for external relay")
|
||||
|
||||
self.setting_service.register_new(self.module_name, "arelay_symbol_method", "with_symbol",
|
||||
TextSettingType(["Always", "with_symbol", "unless_symbol"]),
|
||||
"When to relay messages")
|
||||
|
||||
self.setting_service.register_new(self.module_name, "arelaybot", "",
|
||||
TextSettingType(allow_empty=True),
|
||||
"Bot for alliance relay")
|
||||
|
||||
self.setting_service.register_new(self.module_name, "arelay_enabled", False,
|
||||
BooleanSettingType(),
|
||||
"Enable the alliance relay")
|
||||
|
||||
self.setting_service.register_new(self.module_name, "arelay_guild_abbreviation", "",
|
||||
TextSettingType(allow_empty=True),
|
||||
"Abbreviation to use for org name")
|
||||
|
||||
self.message_hub_service.register_message_destination(self.MESSAGE_SOURCE,
|
||||
self.handle_relay_hub_message,
|
||||
["org_channel"],
|
||||
[self.MESSAGE_SOURCE])
|
||||
|
||||
self.bot.register_packet_handler(server_packets.PrivateChannelInvited.id, self.handle_private_channel_invite,
|
||||
100)
|
||||
self.bot.register_packet_handler(server_packets.PrivateChannelMessage.id, self.handle_private_channel_message)
|
||||
|
||||
def handle_private_channel_invite(self, conn: Conn, packet: server_packets.PrivateChannelInvited):
|
||||
if conn.id != "main":
|
||||
return
|
||||
|
||||
if not self.setting_service.get("arelay_enabled").get_value():
|
||||
return
|
||||
|
||||
channel_name = self.character_service.get_char_name(packet.private_channel_id)
|
||||
if self.setting_service.get_value("arelaybot").lower() == channel_name.lower():
|
||||
self.bot.send_packet(client_packets.PrivateChannelJoin(packet.private_channel_id))
|
||||
self.logger.info("Joined private channel {channel}".format(channel=channel_name))
|
||||
self.relay_channel_id = packet.private_channel_id
|
||||
|
||||
def handle_private_channel_message(self, conn: Conn, packet: server_packets.PrivateChannelMessage):
|
||||
if conn.id != "main":
|
||||
return
|
||||
|
||||
if not self.setting_service.get("arelay_enabled").get_value():
|
||||
return
|
||||
|
||||
# ignore packets from the bot's own private channel and from the bot itself
|
||||
if packet.private_channel_id == self.bot.get_char_id() or packet.char_id == self.bot.get_char_id():
|
||||
return
|
||||
|
||||
message = packet.message.lstrip()
|
||||
if message[:6] != "!agcr ":
|
||||
return
|
||||
formatted_message = None
|
||||
message = re.match("!agcr \[(.+)] (.+): (.+)", message)
|
||||
if message:
|
||||
org, name, text = message.groups()
|
||||
formatted_message = self.setting_service.get('alliance_base').format_text(
|
||||
f"[{self.setting_service.get('alliance_org').format_text(org)}] "
|
||||
f"{self.setting_service.get('alliance_sender').format_text(name)}: "
|
||||
f"{self.setting_service.get('alliance_msg').format_text(text)}")
|
||||
# sender is not the bot that sent it, but rather the original char that sent the message
|
||||
# given the format of !agcr messages, it could be possible to parse the sender for the message
|
||||
# but currently this is not done
|
||||
sender = None
|
||||
|
||||
self.message_hub_service.send_message(self.MESSAGE_SOURCE,
|
||||
sender, None,
|
||||
formatted_message or packet.message.lstrip)
|
||||
|
||||
def handle_relay_hub_message(self, ctx):
|
||||
if not self.setting_service.get("arelay_enabled").get_value():
|
||||
return
|
||||
method = self.setting_service.get_value("arelay_symbol_method")
|
||||
symbol = self.setting_service.get_value("arelay_symbol")
|
||||
plain_msg = ctx.message or ctx.formatted_message
|
||||
|
||||
if method == "unless_symbol" and len(plain_msg) > len(symbol) and plain_msg[:len(symbol)] == symbol:
|
||||
return
|
||||
elif method == "with_symbol":
|
||||
if len(plain_msg) < len(symbol) or plain_msg[:len(symbol)] != symbol:
|
||||
return
|
||||
else:
|
||||
# trim symbol from message
|
||||
plain_msg = plain_msg[len(symbol):]
|
||||
|
||||
org = self.setting_service.get_value("arelay_guild_abbreviation") or \
|
||||
self.public_channel_service.get_org_name() or \
|
||||
self.bot.get_char_name()
|
||||
msg = f"[{org + (' - Priv' if ctx.source == 'private_channel' else '')}] {ctx.sender.name}: {plain_msg}"
|
||||
|
||||
self.send_message_to_alliance(msg)
|
||||
|
||||
def send_message_to_alliance(self, msg):
|
||||
if self.relay_channel_id:
|
||||
packet = client_packets.PrivateChannelMessage(self.relay_channel_id,
|
||||
"!agcr " + self.text.format_message(msg, False), "\0")
|
||||
self.bot.conns["main"].send_packet(packet)
|
||||
@@ -0,0 +1,78 @@
|
||||
import time
|
||||
|
||||
from core.buddy_service import BuddyService
|
||||
from core.command_param_types import Character, Int
|
||||
from core.decorators import event, instance, command
|
||||
from core.logger import Logger
|
||||
from core.lookup.character_service import CharacterService
|
||||
from core.text import Text
|
||||
from core.translation_service import TranslationService
|
||||
from core.tyrbot import Tyrbot
|
||||
from modules.core.accounting.services.account_service import AccountService
|
||||
|
||||
|
||||
@instance()
|
||||
class NotifyController:
|
||||
|
||||
def __init__(self):
|
||||
self.logger = Logger(__name__)
|
||||
|
||||
def inject(self, registry):
|
||||
self.bot: Tyrbot = registry.get_instance("bot")
|
||||
self.db = registry.get_instance("db")
|
||||
self.util = registry.get_instance("util")
|
||||
self.text: Text = registry.get_instance("text")
|
||||
self.alts: AccountService = registry.get_instance("account_service")
|
||||
self.buddy_service: BuddyService = registry.get_instance("buddy_service")
|
||||
self.character_service: CharacterService = registry.get_instance("character_service")
|
||||
self.ts: TranslationService = registry.get_instance("translation_service")
|
||||
self.getresp = self.ts.get_response
|
||||
|
||||
def start(self):
|
||||
self.db.exec("CREATE TABLE IF NOT EXISTS notify_log (id INT PRIMARY KEY AUTO_INCREMENT, char_id INT NOT NULL, "
|
||||
"status TINYINT NOT NULL, time INT NOT NULL DEFAULT 0)")
|
||||
|
||||
@event(event_type=BuddyService.BUDDY_LOGON_EVENT, description="Record last seen info", is_hidden=True)
|
||||
def notify_logon_event(self, event_type, event_data):
|
||||
self.update_last_seen(event_data)
|
||||
|
||||
@event(event_type=BuddyService.BUDDY_LOGOFF_EVENT, description="Record last seen info", is_hidden=True)
|
||||
def notify_logoff_event(self, event_type, event_data):
|
||||
self.update_last_seen(event_data)
|
||||
|
||||
@command(command="lastseen",
|
||||
params=[Character("character"), Int("number_of_entries", is_optional=True)],
|
||||
access_level="org_member",
|
||||
description="View when someone was last online")
|
||||
def lastseen_limited_cmd(self, request, char, limit):
|
||||
if not char.char_id:
|
||||
return f"Character {char.name} does not exist."
|
||||
alts = self.alts.get_alts(char.char_id)
|
||||
if not alts:
|
||||
alts = [self.alts.get_main(char.char_id)]
|
||||
logs = self.get_log(alts, limit or 20)
|
||||
blob = ""
|
||||
if len(logs) == 0:
|
||||
return "No data for <highlight>%s<end> recorded." % char.name
|
||||
for log in logs:
|
||||
blob += f"<grey>[{self.util.format_datetime(log.time)}]</grey> <highlight>{log.name}<end> -> " \
|
||||
f"{'<green>logged on</green>' if log.status == 1 else '<red>logged off</red>'}.\n"
|
||||
return f"<highlight>{char.name}<end> was last seen at " \
|
||||
f"{self.util.format_date(logs[0].time)}. {self.text.format_page('More', blob)}"
|
||||
|
||||
def get_log(self, char_list, length=16):
|
||||
query = "SELECT n.*, p.name as name FROM notify_log n LEFT JOIN player p on n.char_id = p.char_id "
|
||||
for toon in char_list:
|
||||
if toon == char_list[0]:
|
||||
query += f"where n.char_id={toon.char_id:d}"
|
||||
else:
|
||||
query += f" or n.char_id={toon.char_id:d}"
|
||||
query += f" ORDER BY time DESC LIMIT {length:d}"
|
||||
return self.db.query(query)
|
||||
|
||||
def update_last_seen(self, packet):
|
||||
if self.bot.is_ready():
|
||||
types = self.buddy_service.get_buddy(packet.char_id)["types"]
|
||||
if "org_member" in types or "track" in types or "member" in types:
|
||||
self.db.exec("INSERT INTO notify_log (char_id, status, time) VALUES (?, ?, ?)",
|
||||
[packet.char_id, packet.online, time.time()])
|
||||
@@ -0,0 +1,122 @@
|
||||
import time
|
||||
|
||||
from core.aochat.server_packets import PublicChannelMessage
|
||||
from core.chat_blob import ChatBlob
|
||||
from core.conn import Conn
|
||||
from core.decorators import instance, command, event, timerevent
|
||||
from core.dict_object import DictObject
|
||||
from core.sender_obj import SenderObj
|
||||
|
||||
|
||||
@instance()
|
||||
class CloakController:
|
||||
MESSAGE_SOURCE = "cloak_reminder"
|
||||
CLOAK_EVENT = "cloak"
|
||||
|
||||
def inject(self, registry):
|
||||
self.bot = registry.get_instance("bot")
|
||||
self.db = registry.get_instance("db")
|
||||
self.util = registry.get_instance("util")
|
||||
self.character_service = registry.get_instance("character_service")
|
||||
self.command_alias_service = registry.get_instance("command_alias_service")
|
||||
self.timer_controller = registry.get_instance("timer_controller", is_optional=True)
|
||||
self.event_service = registry.get_instance("event_service")
|
||||
self.access_service = registry.get_instance("access_service")
|
||||
self.message_hub_service = registry.get_instance("message_hub_service")
|
||||
|
||||
def pre_start(self):
|
||||
self.bot.register_packet_handler(PublicChannelMessage.id, self.handle_public_message)
|
||||
self.event_service.register_event_type(self.CLOAK_EVENT)
|
||||
self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)
|
||||
|
||||
def start(self):
|
||||
self.db.exec("CREATE TABLE IF NOT EXISTS cloak_status ("
|
||||
"char_id INT NOT NULL, "
|
||||
"action VARCHAR(10) NOT NULL,"
|
||||
" created_at INT NOT NULL)")
|
||||
self.command_alias_service.add_alias("city", "cloak")
|
||||
|
||||
@command(command="cloak", params=[], access_level="member",
|
||||
description="Show the current status of the city cloak and the cloak history")
|
||||
def cloak_show_command(self, request):
|
||||
data = self.db.query("SELECT c.*, p.name FROM cloak_status c "
|
||||
"LEFT JOIN player p ON c.char_id = p.char_id "
|
||||
"ORDER BY created_at DESC LIMIT 20")
|
||||
|
||||
if len(data) == 0:
|
||||
return "Unknown status on cloak."
|
||||
else:
|
||||
msg = self.get_cloak_status(data[0])
|
||||
|
||||
request.reply(msg)
|
||||
|
||||
blob = ""
|
||||
for row in data:
|
||||
action = "<green>on</green>" if row.action == "on" else "<orange>off</orange>"
|
||||
blob += f"{row.name} turned the device {action} at {self.util.format_datetime(row.created_at)}.\n"
|
||||
|
||||
return ChatBlob("Cloak History", blob)
|
||||
|
||||
@event(event_type=CLOAK_EVENT, description="Record when the city cloak is turned off and on", is_hidden=True)
|
||||
def city_cloak_event(self, _, event_data):
|
||||
self.db.exec("INSERT INTO cloak_status (char_id, action, created_at) VALUES (?, ?, ?)",
|
||||
[event_data.sender.char_id, event_data.action, int(time.time())])
|
||||
|
||||
@timerevent(budatime="15m", description="Reminds the players to toggle the cloak")
|
||||
def cloak_reminder_event(self, _, _1):
|
||||
data = self.db.query("SELECT c.*, p.name FROM cloak_status c "
|
||||
"LEFT JOIN player p ON c.char_id = p.char_id "
|
||||
"ORDER BY created_at DESC LIMIT 1")
|
||||
|
||||
for row in data:
|
||||
one_hour = 3600
|
||||
t = int(time.time())
|
||||
time_until_change = row.created_at + one_hour - t
|
||||
if row.action == "off" and time_until_change <= 0:
|
||||
time_str = self.util.time_to_readable(t - row.created_at)
|
||||
msg = "The cloaking device is <orange>disabled</orange> but can be enabled. " \
|
||||
"<highlight>%s</highlight> disabled it %s ago." % (row.name, time_str)
|
||||
self.message_hub_service.send_message(self.MESSAGE_SOURCE, None, None, msg)
|
||||
|
||||
@event(event_type=CLOAK_EVENT, description="Set a timer for when cloak can be raised and lowered")
|
||||
def city_cloak_timer_event(self, _, event_data):
|
||||
if event_data.action == "off":
|
||||
timer_name = "Raise City Cloak"
|
||||
elif event_data.action == "on":
|
||||
timer_name = "Lower City Cloak"
|
||||
else:
|
||||
raise Exception(f"Unknown cloak action '{event_data.action}'")
|
||||
|
||||
self.timer_controller.add_timer(timer_name, event_data.sender.char_id, "org", int(time.time()), 3600)
|
||||
|
||||
def get_cloak_status(self, row):
|
||||
one_hour = 3600
|
||||
time_until_change = row.created_at + one_hour - int(time.time())
|
||||
time_string = self.util.time_to_readable(time_until_change)
|
||||
|
||||
if row.action == "off":
|
||||
if time_until_change <= 0:
|
||||
msg = "The cloaking device is <orange>disabled</orange>. It is possible to enable it."
|
||||
else:
|
||||
msg = f"The cloaking device is <orange>disabled</orange>. It is possible to enable it in {time_string}."
|
||||
else:
|
||||
if time_until_change <= 0:
|
||||
msg = "The cloaking device is <green>enabled</green>. It is possible to disable it."
|
||||
else:
|
||||
msg = f"The cloaking device is <green>enabled</green>. It is possible to disable it in {time_string}."
|
||||
|
||||
return msg
|
||||
|
||||
def handle_public_message(self, conn: Conn, packet: PublicChannelMessage):
|
||||
if conn.id != "main":
|
||||
return
|
||||
|
||||
extended_message = packet.extended_message
|
||||
if extended_message and extended_message.category_id == 1001 and extended_message.instance_id == 1:
|
||||
char_name = extended_message.params[0]
|
||||
char_id = self.character_service.resolve_char_to_id(char_name)
|
||||
action = extended_message.params[1]
|
||||
access_level = self.access_service.get_access_level(char_id)
|
||||
self.event_service.fire_event(self.CLOAK_EVENT,
|
||||
DictObject({"sender": SenderObj(char_id, char_name, access_level),
|
||||
"action": action}))
|
||||
@@ -0,0 +1,37 @@
|
||||
from core.command_param_types import Const, Int, Any
|
||||
from core.decorators import instance, command, event
|
||||
from modules.standard.online.online_controller import OnlineController
|
||||
|
||||
|
||||
@instance(name="online_controller", override=True)
|
||||
class OrgOnlineController(OnlineController):
|
||||
|
||||
@event(event_type="org_member_logon", description="Change online channel", is_hidden=True)
|
||||
def org_member_logon(self, _, event_data):
|
||||
self.awaiting_data.put([event_data, 'org', True])
|
||||
|
||||
@event(event_type="org_member_logoff", description="Change online channel", is_hidden=True)
|
||||
def org_member_logoff(self, _, event_data):
|
||||
if self.bot.is_ready():
|
||||
self.awaiting_data.put([event_data, 'org', False])
|
||||
|
||||
@command(command="online", params=[Const('all', is_optional=True),
|
||||
Int("min_level", is_optional=True),
|
||||
Any("profession", is_optional=True)],
|
||||
description="shows online players",
|
||||
access_level="member")
|
||||
def online_all_cmd(self, request, const_all, min_level, profession):
|
||||
query = ""
|
||||
params = [self.bot.name, self.bot.get_char_id()]
|
||||
if const_all:
|
||||
query += "and channel_id IN (1, 2, 3) "
|
||||
else:
|
||||
query += "and channel_id IN (1, 2) "
|
||||
if min_level:
|
||||
query += "and p.level >= ? "
|
||||
params.append(min_level)
|
||||
if profession:
|
||||
query += "and p.profession = ? "
|
||||
params.append(self.util.get_profession(profession))
|
||||
blob = self.online_display.format_by_channel_main(query, params)
|
||||
request.reply(self.online_display.format_blob(blob))
|
||||
@@ -0,0 +1,132 @@
|
||||
from core.chat_blob import ChatBlob
|
||||
from core.db import DB
|
||||
from core.decorators import instance, event
|
||||
from core.dict_object import DictObject
|
||||
from core.logger import Logger
|
||||
from core.public_channel_service import PublicChannelService
|
||||
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.core.accounting.services.account_service import AccountService
|
||||
from modules.orgbot.org.org_roster_controller import OrgRosterController
|
||||
from modules.standard.online.online_display import OnlineDisplay
|
||||
|
||||
|
||||
@instance()
|
||||
class OrgChannelController:
|
||||
MESSAGE_SOURCE = "org_channel"
|
||||
ORG_CHANNEL_PREFIX = "[<cyan>Org</cyan>]"
|
||||
|
||||
def __init__(self):
|
||||
self.logger = Logger(__name__)
|
||||
|
||||
def inject(self, registry):
|
||||
self.bot: Tyrbot = registry.get_instance("bot")
|
||||
self.db: DB = registry.get_instance("db")
|
||||
self.util: Util = registry.get_instance("util")
|
||||
self.character_service = registry.get_instance("character_service")
|
||||
self.message_hub_service = registry.get_instance("message_hub_service")
|
||||
self.setting_service: SettingService = registry.get_instance("setting_service")
|
||||
self.ban_service = registry.get_instance("ban_service")
|
||||
self.log_controller = registry.get_instance("log_controller", is_optional=True)
|
||||
self.online_controller = registry.get_instance("online_controller", is_optional=True)
|
||||
self.text: Text = registry.get_instance("text")
|
||||
self.account_service: AccountService = registry.get_instance("account_service")
|
||||
|
||||
def pre_start(self):
|
||||
self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)
|
||||
|
||||
def start(self):
|
||||
self.message_hub_service.register_message_destination(
|
||||
self.MESSAGE_SOURCE, self.handle_incoming_relay_message,
|
||||
["private_channel", "discord", "websocket_relay", "tell_relay", "broadcast",
|
||||
"raffle", "cloak_reminder", "wave_counter", "shutdown_notice", "raid"],
|
||||
[self.MESSAGE_SOURCE])
|
||||
|
||||
self.setting_service.register_new(self.module_name, "prefix_org_priv", True, BooleanSettingType(),
|
||||
"Should the prefix [org] be displayed in relayed messages")
|
||||
|
||||
def handle_incoming_relay_message(self, ctx):
|
||||
self.bot.send_org_message(ctx.formatted_message, fire_outgoing_event=False)
|
||||
|
||||
@event(event_type=PublicChannelService.ORG_CHANNEL_MESSAGE_EVENT,
|
||||
description="Relay messages from the org channel to the relay hub",
|
||||
is_hidden=True)
|
||||
def handle_org_message_event(self, _, event_data):
|
||||
if event_data.char_id == self.bot.get_char_id() or self.ban_service.get_ban(event_data.char_id):
|
||||
return
|
||||
|
||||
if event_data.extended_message:
|
||||
message = event_data.extended_message.get_message()
|
||||
else:
|
||||
message = event_data.message
|
||||
|
||||
if event_data.char_id == 4294967295 or event_data.char_id == 0:
|
||||
sender = None
|
||||
formatted_message = "{org} {msg}".format(org=self.ORG_CHANNEL_PREFIX,
|
||||
msg=message)
|
||||
else:
|
||||
char_name = self.character_service.resolve_char_to_name(event_data.char_id)
|
||||
sender = DictObject({"char_id": event_data.char_id, "name": char_name})
|
||||
formatted_message = "{org} {char}: {msg}".format(org=self.ORG_CHANNEL_PREFIX,
|
||||
char=self.text.make_charlink(char_name),
|
||||
msg=message)
|
||||
|
||||
self.message_hub_service.send_message(self.MESSAGE_SOURCE, sender, message, formatted_message)
|
||||
|
||||
@event(event_type=OrgRosterController.ORG_MEMBER_LOGON_EVENT, description="Notify when org member logs on")
|
||||
def org_member_logon_event(self, _, event_data):
|
||||
if not self.bot.is_ready():
|
||||
return
|
||||
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 ""
|
||||
if main.char_id == event_data.char_info.char_id:
|
||||
alt = ""
|
||||
logon = f" :: <grey>{event_data.account.logon}<grey>" if event_data.account.logon else ""
|
||||
msg = f"{self.text.format_char_info(event_data.char_info)} {alt}:: logged <green>on</green>.{logon}"
|
||||
self.bot.send_org_message(msg, fire_outgoing_event=False)
|
||||
|
||||
self.message_hub_service.send_message(self.MESSAGE_SOURCE, None, None, "[<cyan>Org</cyan>] " + msg)
|
||||
od = OnlineDisplay(self.text, self.util, self.db)
|
||||
params = [self.bot.name, self.bot.get_char_id()]
|
||||
self.bot.send_mass_message(event_data.packet.char_id,
|
||||
od.format_blob(od.format_by_channel_main("and channel_id IN (1, 2) ", params)))
|
||||
|
||||
@event(event_type=OrgRosterController.ORG_MEMBER_LOGOFF_EVENT, description="Notify when org member logs off")
|
||||
def org_member_logoff_event(self, _, event_data):
|
||||
if not self.bot.is_ready():
|
||||
return
|
||||
char_name = self.character_service.resolve_char_to_name(event_data.packet.char_id)
|
||||
logoff = f" :: <grey>{event_data.account.logon}<grey>" if event_data.account.logon else ""
|
||||
msg = f"{char_name} logged <red>off</red>.{logoff}"
|
||||
self.bot.send_org_message(msg, fire_outgoing_event=False)
|
||||
self.message_hub_service.send_message(self.MESSAGE_SOURCE, None, None, "[<cyan>Org</cyan>] " + msg)
|
||||
|
||||
@event(event_type=Tyrbot.OUTGOING_ORG_MESSAGE_EVENT,
|
||||
description="Relay commands from the org channel to the relay hub",
|
||||
is_hidden=True)
|
||||
def outgoing_org_message_event(self, _, event_data):
|
||||
if isinstance(event_data.message, ChatBlob):
|
||||
pages = self.text.paginate(ChatBlob(event_data.message.title, event_data.message.msg),
|
||||
self.setting_service.get("org_channel_max_page_length").get_value())
|
||||
if len(pages) < 4:
|
||||
for page in pages:
|
||||
message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=page)
|
||||
self.message_hub_service.send_message(self.MESSAGE_SOURCE,
|
||||
None,
|
||||
page,
|
||||
message)
|
||||
else:
|
||||
message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=event_data.message.title)
|
||||
self.message_hub_service.send_message(self.MESSAGE_SOURCE,
|
||||
None,
|
||||
event_data.message.title,
|
||||
message)
|
||||
else:
|
||||
message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=event_data.message)
|
||||
self.message_hub_service.send_message(self.MESSAGE_SOURCE,
|
||||
None,
|
||||
event_data.message,
|
||||
message)
|
||||
@@ -0,0 +1,248 @@
|
||||
import json
|
||||
import time
|
||||
|
||||
import requests
|
||||
from mysql.connector.cursor import CursorBase
|
||||
|
||||
from core.buddy_service import BuddyService
|
||||
from core.cache_service import CacheService
|
||||
from core.chat_blob import ChatBlob
|
||||
from core.command_param_types import Int
|
||||
from core.db import DB
|
||||
from core.decorators import instance, command, event, timerevent
|
||||
from core.dict_object import DictObject
|
||||
from core.event_service import EventService
|
||||
from core.logger import Logger
|
||||
from core.lookup.character_service import CharacterService
|
||||
from core.lookup.org_pork_service import OrgPorkService
|
||||
from core.lookup.pork_service import PorkService
|
||||
from core.public_channel_service import PublicChannelService
|
||||
from core.tyrbot import Tyrbot
|
||||
from core.util import Util
|
||||
from modules.core.accounting.services.account_service import AccountService
|
||||
|
||||
|
||||
@instance()
|
||||
class OrgRosterController:
|
||||
ORG_BUDDY_TYPE = "org_member"
|
||||
ORG_ACCESS_LEVEL = "org_member"
|
||||
|
||||
MODE_ADD_AUTO = "add_auto"
|
||||
MODE_REM_AUTO = "rem_auto"
|
||||
MODE_ADD_MANUAL = "add_manual"
|
||||
MODE_REM_MANUAL = "rem_manual"
|
||||
|
||||
ORG_MEMBER_LOGON_EVENT = "org_member_logon"
|
||||
ORG_MEMBER_LOGOFF_EVENT = "org_member_logoff"
|
||||
ORG_MEMBER_REMOVED_EVENT = "org_member_removed"
|
||||
|
||||
LEFT_ORG = [508, 45978487508, 45978487]
|
||||
KICKED_FROM_ORG = [508, 37093479]
|
||||
INVITED_TO_ORG = [508, 173558247]
|
||||
KICKED_INACTIVE_FROM_ORG = [508, 20908201]
|
||||
KICKED_ALIGNMENT_CHANGED = [501, 181448347]
|
||||
JOINED_ORG = [508, 5146599]
|
||||
|
||||
def __init__(self):
|
||||
self.logger = Logger(__name__)
|
||||
|
||||
def inject(self, registry):
|
||||
self.bot: Tyrbot = registry.get_instance("bot")
|
||||
self.db: DB = registry.get_instance("db")
|
||||
self.text = registry.get_instance("text")
|
||||
self.buddy_service: BuddyService = registry.get_instance("buddy_service")
|
||||
self.public_channel_service: PublicChannelService = registry.get_instance("public_channel_service")
|
||||
self.access_service = registry.get_instance("access_service")
|
||||
self.org_pork_service: OrgPorkService = registry.get_instance("org_pork_service")
|
||||
self.pork: PorkService = registry.get_instance("pork_service")
|
||||
self.util: Util = registry.get_instance("util")
|
||||
self.event_service: EventService = registry.get_instance("event_service")
|
||||
self.character_service: CharacterService = registry.get_instance("character_service")
|
||||
self.cache: CacheService = registry.get_instance("cache_service")
|
||||
self.account_service: AccountService = registry.get_instance("account_service")
|
||||
|
||||
def pre_start(self):
|
||||
self.db.exec("CREATE TABLE IF NOT EXISTS org_activity ("
|
||||
"id int primary key AUTO_INCREMENT, "
|
||||
"message varchar(32) NOT NULL, "
|
||||
"time int not null)")
|
||||
self.event_service.register_event_type(self.ORG_MEMBER_LOGON_EVENT)
|
||||
self.event_service.register_event_type(self.ORG_MEMBER_LOGOFF_EVENT)
|
||||
|
||||
self.access_service.register_access_level(self.ORG_ACCESS_LEVEL, 60, self.check_org_member)
|
||||
|
||||
def check_org_member(self, char_id):
|
||||
return (self.account_service.get_account(char_id) or {}).get("member", 0) == self.public_channel_service.org_id
|
||||
|
||||
@event("connect", "Adds all members to buddylist")
|
||||
def connect(self, _, _1):
|
||||
query = self.db.query("SELECT char_id, member from account where member IN (?, 0)",
|
||||
[self.public_channel_service.org_id])
|
||||
if query:
|
||||
for player in query:
|
||||
if player.member == self.public_channel_service.org_id:
|
||||
self.buddy_service.add_buddy(player.char_id, "org_member")
|
||||
else:
|
||||
self.buddy_service.add_buddy(player.char_id, "member")
|
||||
|
||||
@event("buddy_logon", "fire orgmember logon event")
|
||||
def orgmember_logon(self, _, data):
|
||||
account = self.account_service.get_entry(data.char_id)
|
||||
if not account:
|
||||
return
|
||||
if account.member == self.public_channel_service.org_id:
|
||||
self.event_service.fire_event(self.ORG_MEMBER_LOGON_EVENT, DictObject(
|
||||
{'account': account, 'char_info': self.pork.get_character_info(data.char_id), 'packet': data}))
|
||||
|
||||
@event("buddy_logoff", "fire orgmember logoff event")
|
||||
def orgmember_logoff(self, _, data):
|
||||
account = self.account_service.get_entry(data.char_id)
|
||||
if not account:
|
||||
return
|
||||
if account.member == self.public_channel_service.org_id:
|
||||
self.event_service.fire_event(self.ORG_MEMBER_LOGOFF_EVENT,
|
||||
DictObject({'account': account, 'packet': data}))
|
||||
|
||||
@command(command="orgmembers", params=[], access_level="admin",
|
||||
description="Show the list of org members")
|
||||
def org_members_cmd(self, _):
|
||||
data = self.db.query(
|
||||
"SELECT * from account a left join player p on a.char_id = p.char_id where member=? order by p.name",
|
||||
[self.public_channel_service.org_id])
|
||||
blob = ""
|
||||
for row in data:
|
||||
blob += f"{self.text.zfill(row.level, 220)}/<green>{self.text.zfill(row.ai_level, 30)}</green> " \
|
||||
f"{row.name} ({row.org_rank_name})\n"
|
||||
|
||||
return ChatBlob(f"Orgmembers ({len(data)})", blob)
|
||||
|
||||
@command(command="orgactivity", params=[Int('count', is_optional=True)], access_level="org_member",
|
||||
description="Show the most recent org activity")
|
||||
def org_activity(self, _, count):
|
||||
data = self.db.query("SELECT * from org_activity order by id desc LIMIT ?", [count or 25])
|
||||
|
||||
return ChatBlob(f"Recent Activities ({len(data)})", "\n".join(
|
||||
[f'<grey>[{self.util.format_datetime(x.time)}]</grey> {x.message}' for x in data]))
|
||||
|
||||
@timerevent("24h", "Update the orgroster on changes")
|
||||
def update_roster(self, _, _1):
|
||||
self.bot.send_org_message("Updating roster...")
|
||||
cache = self.cache.retrieve('org_roster', f"{self.public_channel_service.org_id}.5.json")
|
||||
if cache:
|
||||
if cache.last_modified > time.time() - 16 * 60 * 60:
|
||||
result = requests.get(self.org_pork_service.get_pork_url(5, self.public_channel_service.org_id)).json()
|
||||
if result:
|
||||
self.cache.store('org_roster', f"{self.public_channel_service.org_id}.5.json", json.dumps(result))
|
||||
else:
|
||||
result = json.loads(cache.data)
|
||||
else:
|
||||
result = json.loads(cache.data)
|
||||
else:
|
||||
result = requests.get(self.org_pork_service.get_pork_url(5, self.public_channel_service.org_id)).json()
|
||||
if result:
|
||||
self.cache.store('org_roster', f"{self.public_channel_service.org_id}.5.json", json.dumps(result))
|
||||
data = []
|
||||
accounts = []
|
||||
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"], "roster", int(time.time())))
|
||||
|
||||
accounts.append((char_info["CHAR_INSTANCE"], char_info["CHAR_INSTANCE"], result[0]["ORG_INSTANCE"],
|
||||
time.time(), time.time()))
|
||||
if buddy := self.buddy_service.get_buddy(char_info['CHAR_INSTANCE']):
|
||||
if "org_member" in buddy['types']:
|
||||
continue
|
||||
self.buddy_service.add_buddy(char_info['CHAR_INSTANCE'], "org_member")
|
||||
|
||||
with self.db.lock:
|
||||
with self.db.pool.get_connection() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur: CursorBase
|
||||
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)
|
||||
self.account_service.create_users(accounts)
|
||||
users = self.db.query('SELECT * from account where member=? and last_updated < ?',
|
||||
[self.public_channel_service.org_id, time.time() - 23 * 60 * 60])
|
||||
for user in users:
|
||||
self.buddy_service.remove_buddy(user.char_id, 'org_member')
|
||||
cur.execute("UPDATE account set member=-1 where member=? and last_updated < ?",
|
||||
[self.public_channel_service.org_id, time.time() - 23 * 60 * 60])
|
||||
cur.execute("UPDATE account set member=-1 where member NOT IN (0, ?, -1)",
|
||||
[self.public_channel_service.org_id])
|
||||
conn.commit()
|
||||
self.bot.send_org_message('Successfully updated the roster.')
|
||||
|
||||
@event(PublicChannelService.ORG_MSG_EVENT, "Update org roster when characters join or leave", is_hidden=True)
|
||||
def org_msg_event(self, _, event_data):
|
||||
ext_msg = event_data.extended_message
|
||||
if [ext_msg.category_id, ext_msg.instance_id] == self.LEFT_ORG:
|
||||
self.process_org_msg(ext_msg.params[0], self.MODE_REM_MANUAL, ext_msg)
|
||||
elif [ext_msg.category_id, ext_msg.instance_id] == self.KICKED_FROM_ORG:
|
||||
self.process_org_msg(ext_msg.params[1], self.MODE_REM_MANUAL, ext_msg.params[0])
|
||||
elif [ext_msg.category_id, ext_msg.instance_id] == self.INVITED_TO_ORG:
|
||||
self.process_org_msg(ext_msg.params[1], self.MODE_ADD_MANUAL, ext_msg.params[0])
|
||||
elif [ext_msg.category_id, ext_msg.instance_id] == self.KICKED_INACTIVE_FROM_ORG:
|
||||
self.process_org_msg(ext_msg.params[1], self.MODE_REM_MANUAL, ext_msg.params[0])
|
||||
elif [ext_msg.category_id, ext_msg.instance_id] == self.KICKED_ALIGNMENT_CHANGED:
|
||||
self.process_org_msg(ext_msg.params[0], self.MODE_REM_MANUAL)
|
||||
elif [ext_msg.category_id, ext_msg.instance_id] == self.JOINED_ORG:
|
||||
self.process_org_msg(ext_msg.params[0], self.MODE_ADD_MANUAL)
|
||||
# noinspection SqlInsertValues
|
||||
self.db.exec("INSERT INTO org_activity (message, time) VALUES(?, ?)", [ext_msg.get_message(), time.time()])
|
||||
|
||||
def process_org_msg(self, char_name, new_mode, actee=None):
|
||||
char_id = self.character_service.resolve_char_to_id(char_name)
|
||||
org_member = self.get_org_member(char_id)
|
||||
self.process_update(char_id, org_member.member if org_member else None, new_mode, actee)
|
||||
|
||||
def get_org_member(self, char_id):
|
||||
return self.db.query_single("SELECT char_id, member FROM account WHERE char_id = ?", [char_id])
|
||||
|
||||
def process_update(self, char_id, old_mode, new_mode, actee):
|
||||
if old_mode == new_mode:
|
||||
return
|
||||
if new_mode in [self.MODE_REM_MANUAL, self.MODE_REM_AUTO]:
|
||||
self.bot.send_org_message(f"<highlight>{self.character_service.get_char_name(char_id)}</highlight> "
|
||||
f"left the org.")
|
||||
main = self.account_service.get_main(char_id)
|
||||
self.account_service.add_log(main.char_id, "system", f'Left the org '
|
||||
f'{self.public_channel_service.get_org_name()} with '
|
||||
f'{self.character_service.get_char_name(char_id)}',
|
||||
main.char_id)
|
||||
self.account_service.create_users(users=[(char_id, char_id, -1, time.time(), time.time())])
|
||||
self.update_buddylist(char_id, self.MODE_REM_AUTO)
|
||||
if new_mode in [self.MODE_ADD_MANUAL, self.MODE_ADD_AUTO]:
|
||||
self.account_service.create_users(users=[(char_id, char_id,
|
||||
self.public_channel_service.org_id,
|
||||
time.time(),
|
||||
time.time())])
|
||||
main = self.account_service.get_main(char_id)
|
||||
self.account_service.add_log(char_id, "system", f'Joined the org '
|
||||
f'{self.public_channel_service.get_org_name()} with '
|
||||
f'{self.character_service.get_char_name(char_id)}',
|
||||
main.char_id)
|
||||
self.bot.send_org_message(f"Please Welcome "
|
||||
f"<highlight>{self.character_service.get_char_name(char_id)}</highlight>!!! ")
|
||||
self.update_buddylist(char_id, self.MODE_ADD_AUTO)
|
||||
|
||||
def update_buddylist(self, char_id, mode):
|
||||
if mode in [self.MODE_ADD_MANUAL, self.MODE_ADD_AUTO]:
|
||||
self.buddy_service.remove_buddy(char_id, "member")
|
||||
self.buddy_service.add_buddy(char_id, self.ORG_BUDDY_TYPE)
|
||||
else:
|
||||
self.buddy_service.remove_buddy(char_id, self.ORG_BUDDY_TYPE)
|
||||
@@ -0,0 +1,52 @@
|
||||
from core.decorators import instance, event
|
||||
from core.public_channel_service import PublicChannelService
|
||||
|
||||
|
||||
@instance()
|
||||
class WaveCounterController:
|
||||
MESSAGE_SOURCE = "wave_counter"
|
||||
CITY_TARGETED = [1001, 3]
|
||||
|
||||
ALERT_TIMES = [105, 150, 90, 120, 120, 120, 120, 120, 120]
|
||||
|
||||
def __init__(self):
|
||||
self.current_wave = None
|
||||
self.scheduled_job_id = None
|
||||
|
||||
def inject(self, registry):
|
||||
self.job_scheduler = registry.get_instance("job_scheduler")
|
||||
self.message_hub_service = registry.get_instance("message_hub_service")
|
||||
|
||||
def pre_start(self):
|
||||
self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)
|
||||
|
||||
@event(event_type=PublicChannelService.ORG_CHANNEL_MESSAGE_EVENT,
|
||||
description="Start wave counter when city is targeted by aliens")
|
||||
def check_for_city_raid_start(self, _, event_data):
|
||||
ext_msg = event_data.extended_message
|
||||
if ext_msg:
|
||||
if [ext_msg.category_id, ext_msg.instance_id] == self.CITY_TARGETED:
|
||||
self.start_counter()
|
||||
|
||||
def start_counter(self):
|
||||
if self.scheduled_job_id:
|
||||
self.job_scheduler.cancel_job(self.scheduled_job_id)
|
||||
|
||||
self.send_message("Wave counter started. <red>DO NOT enter the city!</red>")
|
||||
self.scheduled_job_id = self.job_scheduler.delayed_job(self.timer_alert, self.ALERT_TIMES[0], 0)
|
||||
|
||||
def timer_alert(self, t, wave_number):
|
||||
wave_number += 1
|
||||
|
||||
if wave_number == 9:
|
||||
self.send_message("General incoming. <red>DO NOT enter the city!</red>")
|
||||
self.scheduled_job_id = None
|
||||
else:
|
||||
self.send_message("Wave <highlight>%d</highlight> incoming. "
|
||||
"<red>DO NOT enter the city!</red>" % wave_number)
|
||||
self.scheduled_job_id = self.job_scheduler.scheduled_job(self.timer_alert,
|
||||
t + self.ALERT_TIMES[wave_number],
|
||||
wave_number)
|
||||
|
||||
def send_message(self, msg):
|
||||
self.message_hub_service.send_message(self.MESSAGE_SOURCE, None, None, msg)
|
||||
@@ -0,0 +1,86 @@
|
||||
import re
|
||||
|
||||
from core.aochat.client_packets import PrivateMessage
|
||||
from core.command_param_types import Const
|
||||
from core.decorators import instance, setting, command, timerevent, event
|
||||
from core.logger import Logger
|
||||
from core.lookup.character_service import CharacterService
|
||||
from core.message_hub_service import MessageHubService
|
||||
from core.public_channel_service import PublicChannelService
|
||||
from core.setting_service import SettingService
|
||||
from core.setting_types import TextSettingType
|
||||
from core.text import Text
|
||||
from core.tyrbot import Tyrbot
|
||||
from core.util import Util
|
||||
|
||||
|
||||
@instance()
|
||||
class RaidSpyController:
|
||||
planned = ""
|
||||
|
||||
def __init__(self):
|
||||
self.logger = Logger(__name__)
|
||||
|
||||
def inject(self, registry):
|
||||
self.bot: Tyrbot = registry.get_instance("bot")
|
||||
self.setting_service: SettingService = registry.get_instance("setting_service")
|
||||
self.character_service: CharacterService = registry.get_instance("character_service")
|
||||
self.public_channel_service: PublicChannelService = registry.get_instance("public_channel_service")
|
||||
self.util: Util = registry.get_instance("util")
|
||||
self.text: Text = registry.get_instance("text")
|
||||
self.relay_hub_service: MessageHubService = registry.get_instance("message_hub_service")
|
||||
|
||||
@setting(name="raidbot-name", value="", description="The Raidbot")
|
||||
def raidbot(self):
|
||||
return TextSettingType(allow_empty=True)
|
||||
|
||||
@event(event_type=Tyrbot.PRIVATE_MSG_EVENT, description="update raidlist", is_enabled=False)
|
||||
def handle_raidbot_msg(self, _, textblob: PrivateMessage):
|
||||
if self.character_service.get_char_name(textblob.char_id) != self.setting_service.get_value("raidbot-name"):
|
||||
return
|
||||
tag = re.search(
|
||||
r"<font color=#.{6}><font color=#.{6}>Planned Raids last updated \w+ \d+\w+, \d+ \d+:\d+:: "
|
||||
r"<a href=\"text://(.+)\">.+</a></font></font>",
|
||||
textblob.message,
|
||||
re.DOTALL)
|
||||
if tag:
|
||||
textblob.message = tag[1]
|
||||
with open("data/latest_raids.txt", "w") as f:
|
||||
f.write(textblob.message)
|
||||
self.planned = textblob.message
|
||||
self.bot.send_org_message("Die Raids wurden geupdatet: " +
|
||||
self.text.format_page("Die Raids der Woche", self.planned), fire_outgoing_event=False)
|
||||
self.bot.send_private_channel_message("Die Raids wurden geupdatet: " +
|
||||
self.text.format_page("Die Raids der Woche", self.planned),
|
||||
fire_outgoing_event=False)
|
||||
|
||||
@event(event_type="connect", description="update raidlist", is_enabled=False)
|
||||
def handle_log_raidlog(self, _, _1):
|
||||
try:
|
||||
with open("data/latest_raids.txt", "r") as f:
|
||||
self.planned = f.read()
|
||||
except FileNotFoundError:
|
||||
self.planned = "<center><font color=#DDDD44>:::: Planned Raids ::::" \
|
||||
"</font></center><br><font color=#66AA66> Es sind mir leider keine Raids bekannt.</font>"
|
||||
|
||||
# @command(command="raids", params=[],
|
||||
# description="Shows planned raids", access_level="org_member")
|
||||
# def raids_list(self, request):
|
||||
# return self.text.format_page("Die Raids der Woche", self.planned)
|
||||
|
||||
@command(command="raids", params=[Const("update")],
|
||||
description="Shows planned raids", access_level="moderator", sub_command="update")
|
||||
def raids_patch(self, request, _):
|
||||
self.bot.send_private_message(self.character_service.resolve_char_to_id(self.raidbot().get_value()),
|
||||
"!raids",
|
||||
add_color=False)
|
||||
return "Das Updaten der Raidliste wurde eingeleitet... Sollte es neues geben, " \
|
||||
"Informiere ich Alle Mitglieder für dich."
|
||||
|
||||
@timerevent(budatime="12h", description="Update Raid list")
|
||||
def check_for_raids(self, _, _2):
|
||||
if self.raidbot().get_value() == "":
|
||||
return
|
||||
self.bot.send_private_message(self.character_service.resolve_char_to_id(self.raidbot().get_value()),
|
||||
"!raids",
|
||||
add_color=False)
|
||||
Reference in New Issue
Block a user