Initial Release of IGNCore version 2.5
This commit is contained in:
@@ -0,0 +1,395 @@
|
||||
import math
|
||||
|
||||
from core.buddy_service import BuddyService
|
||||
from core.chat_blob import ChatBlob
|
||||
from core.command_param_types import Const, Character, Any, NamedParameters
|
||||
from core.decorators import instance, command, event
|
||||
from core.dict_object import DictObject
|
||||
from core.logger import Logger
|
||||
from core.lookup.character_service import CharacterService
|
||||
from core.lookup.pork_service import PorkService
|
||||
from core.private_channel_service import PrivateChannelService
|
||||
from core.setting_service import SettingService
|
||||
from core.setting_types import TextSettingType
|
||||
from core.text import Text
|
||||
from core.translation_service import TranslationService
|
||||
from core.tyrbot import Tyrbot
|
||||
|
||||
|
||||
# noinspection SqlCaseVsIf,SqlCaseVsCoalesce
|
||||
@instance()
|
||||
class RIAdminController:
|
||||
PAGE_SIZE = 20
|
||||
UNASSIGNED_RAID_INSTANCE_ID = 0
|
||||
|
||||
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.text: Text = registry.get_instance("text")
|
||||
self.setting_service: SettingService = registry.get_instance("setting_service")
|
||||
self.util = registry.get_instance("util")
|
||||
self.character_service: CharacterService = registry.get_instance("character_service")
|
||||
self.private_channel_service: PrivateChannelService = registry.get_instance("private_channel_service")
|
||||
self.ts: TranslationService = registry.get_instance("translation_service")
|
||||
self.getresp = self.ts.get_response
|
||||
self.buddy_service: BuddyService = registry.get_instance("buddy_service")
|
||||
self.pork: PorkService = registry.get_instance("pork_service")
|
||||
|
||||
def start(self):
|
||||
self.db.exec(
|
||||
"CREATE TABLE IF NOT EXISTS raid_instance (id INT PRIMARY KEY AUTO_INCREMENT, "
|
||||
"name VARCHAR(255) NOT NULL, "
|
||||
"bot varchar(32)) ENGINE MEMORY")
|
||||
self.db.exec(
|
||||
"CREATE TABLE IF NOT EXISTS raid_instance_char ("
|
||||
"raid_instance_id INT NOT NULL, "
|
||||
"char_id INT PRIMARY KEY, "
|
||||
"is_leader TINYINT NOT NULL) ENGINE MEMORY")
|
||||
self.setting_service.register_new(self.module_name, "riadmin_network",
|
||||
"[905848882, 272234, 1923370, 313107, 1217210821, 1134420908]",
|
||||
TextSettingType(), "Allowed bots (charID's)",
|
||||
extended_description="This setting is *NOT* synchronized across the network;"
|
||||
" this needs to be done manually!")
|
||||
|
||||
@event(event_type="buddy_logoff", description="Track raiders")
|
||||
def raider_logoff(self, _, event_data):
|
||||
if self.bot.is_ready():
|
||||
buddy = self.buddy_service.get_buddy(event_data.char_id)
|
||||
if not buddy:
|
||||
return
|
||||
if "raider" in buddy.get('types', []):
|
||||
user = self.db.query_single("SELECT * from player where char_id=?", [event_data.char_id])
|
||||
raid = self.get_raid_instance_by_char(event_data.char_id)
|
||||
if user and raid:
|
||||
if raid.bot != 0:
|
||||
self.bot.send_private_channel_message(f'[<red>RI</red>] Raider logged off: '
|
||||
f'{user.name} - {user.profession} [{raid.name}]')
|
||||
self.db.exec("DELETE FROM raid_instance_char WHERE char_id = ?", [event_data.char_id])
|
||||
self.buddy_service.remove_buddy(event_data.char_id, 'raider')
|
||||
|
||||
@event(event_type=PrivateChannelService.LEFT_PRIVATE_CHANNEL_EVENT, description="Track Raiders")
|
||||
def raider_leave(self, _, event_data):
|
||||
if self.bot.is_ready():
|
||||
buddy = self.buddy_service.get_buddy(event_data.char_id)
|
||||
if not buddy:
|
||||
return
|
||||
if "raider" in buddy.get('types', []):
|
||||
user = self.pork.get_character_info(event_data.char_id)
|
||||
raid = self.get_raid_instance_by_char(event_data.char_id)
|
||||
part = int(raid.bot) if raid else 0
|
||||
if part in [self.bot.get_char_id(), 0]:
|
||||
if part != 0:
|
||||
self.bot.send_private_channel_message(
|
||||
f'[<red>RI</red>] Raider left: {user.name} - {user.profession} '
|
||||
f'[{raid.name if raid else "UNASSIGNED"}]')
|
||||
self.db.exec("DELETE FROM raid_instance_char WHERE char_id = ?", [event_data.char_id])
|
||||
self.buddy_service.remove_buddy(event_data.char_id, 'raider')
|
||||
|
||||
@event(event_type="connect", description="Init raider tracking on startup")
|
||||
def connect(self, _, _1):
|
||||
for user in self.get_raid_instance_chars():
|
||||
self.buddy_service.add_buddy(user.char_id, 'raider')
|
||||
|
||||
@command(command="riadmin", params=[NamedParameters(['page'])], access_level="leader",
|
||||
description="Show the current RIs")
|
||||
def riadmin(self, _, named_params):
|
||||
refresh = self.text.make_tellcmd("Refresh", "riadmin")
|
||||
send = self.text.make_tellcmd("Apply", "riadmin send")
|
||||
clear = self.text.make_tellcmd("Clear All", "riadmin clear")
|
||||
blob = f"[{refresh}] - Update the RI List\n" \
|
||||
f"[{send}] - Send all RI's to their bots\n" \
|
||||
f"[{clear}] - Clear all RI's, and delete them"
|
||||
blob += "\n\n"
|
||||
|
||||
page = int(named_params.page or "1")
|
||||
offset = (page - 1) * self.PAGE_SIZE
|
||||
data = self.get_raid_instance_chars()
|
||||
return self.format_pagination(data, offset, page, self.compact_char_display, 'Raid Instances',
|
||||
'No Raidinstances found.', 'riadmin ', self.PAGE_SIZE, blob)
|
||||
|
||||
def format_pagination(self, data, offset, page, formatter, title, nullmsg, cmd, page_size=10, headline=""):
|
||||
raid_instances = self.get_raid_instances()
|
||||
blob = ""
|
||||
if page == 1:
|
||||
blob = headline
|
||||
selected = data[offset:offset + page_size]
|
||||
if len(data) == 0:
|
||||
return nullmsg
|
||||
num_assigned = 0
|
||||
num_unassigned = 0
|
||||
pages = ""
|
||||
|
||||
if page > 1:
|
||||
pages += "Pages: " + self.text.make_tellcmd("«« Page %d" % (page - 1), f'{cmd} --page={page - 1}')
|
||||
if offset + page_size < len(data):
|
||||
pages += f" Page {page}/{math.ceil(len(data) / page_size)}"
|
||||
pages += " " + self.text.make_tellcmd("Page %d »»" % (page + 1), f'{cmd} --page={page + 1}')
|
||||
pages += "\n"
|
||||
current_raid_instance_id = None
|
||||
for row in data:
|
||||
if row.raid_instance_id == self.UNASSIGNED_RAID_INSTANCE_ID:
|
||||
num_unassigned += 1
|
||||
else:
|
||||
if row.name:
|
||||
num_assigned += 1
|
||||
blob += "" + pages
|
||||
for row in selected:
|
||||
if row.raid_instance_id != current_raid_instance_id:
|
||||
name = ""
|
||||
if row.bot:
|
||||
bot = self.pork.get_character_info(row.bot)
|
||||
name = f"[{bot.name}]" if bot else ""
|
||||
blob += f"\n<header2>{row.raid_instance_name} {name}</header2>\n"
|
||||
current_raid_instance_id = row.raid_instance_id
|
||||
|
||||
if not row.char_id:
|
||||
continue
|
||||
|
||||
blob += formatter(row)
|
||||
add_leader_link = (row.raid_instance_id != self.UNASSIGNED_RAID_INSTANCE_ID and not row.is_leader)
|
||||
blob += " " + self.get_assignment_links(raid_instances, row.name, add_leader_link)
|
||||
blob += "\n"
|
||||
blob += "\n" + pages
|
||||
out = ChatBlob(title, blob)
|
||||
out.page_postfix = f" (<highlight>{num_assigned}</highlight> Players)"
|
||||
if num_unassigned > 0:
|
||||
out.page_postfix = f" (Assigned: <highlight>{num_assigned}</highlight>, " \
|
||||
f"Unassigned: <highlight>{num_unassigned}</highlight>)"
|
||||
return out
|
||||
|
||||
@command(command="ritake", params=[Any("raiders")],
|
||||
access_level="all",
|
||||
description="take the RI from another bot")
|
||||
def ritake(self, request, raiders: str):
|
||||
users = raiders.split(",")
|
||||
if request.sender.char_id not in eval(self.setting_service.get_value('riadmin_network')):
|
||||
return
|
||||
for user in users:
|
||||
char = self.character_service.resolve_char_to_id(user.strip())
|
||||
if not char:
|
||||
continue
|
||||
if self.private_channel_service.in_private_channel(char):
|
||||
self.buddy_service.add_buddy(char, 'raider')
|
||||
continue
|
||||
self.bot.send_mass_message(char, 'You have been assigned to my RI :: <red>accept the invite!</red>')
|
||||
self.private_channel_service.invite(char)
|
||||
|
||||
@command(command="riadmin",
|
||||
params=[Const("add"), Any("raid_instance"), Character("char")],
|
||||
access_level="leader",
|
||||
description="Add a character to a RI", sub_command="leader")
|
||||
def riadmin_add(self, _, _1, raid_instance_name, char):
|
||||
if not char.char_id:
|
||||
return self.getresp("global", "char_not_found", {"char": char.name})
|
||||
raid_instance = self.get_raid_instance(raid_instance_name)
|
||||
if not raid_instance:
|
||||
return f"Raid instance <highlight>{raid_instance_name}</highlight> does not exist."
|
||||
|
||||
self.refresh_raid_instance_chars()
|
||||
|
||||
row = self.db.query_single("SELECT raid_instance_id FROM raid_instance_char WHERE char_id = ?", [char.char_id])
|
||||
if row:
|
||||
if raid_instance.id == row.raid_instance_id:
|
||||
if 'raider' not in (
|
||||
self.buddy_service.get_buddy(char.char_id) or DictObject({'types': []}).get('types', [])):
|
||||
self.buddy_service.add_buddy(char.char_id, 'raider')
|
||||
return f"Character <highlight>{char.name}</highlight> is already assigned to " \
|
||||
f"raid instance <highlight>{raid_instance.name}</highlight>."
|
||||
else:
|
||||
if 'raider' not in (
|
||||
self.buddy_service.get_buddy(char.char_id) or DictObject({'types': []}).get('types', [])):
|
||||
self.buddy_service.add_buddy(char.char_id, 'raider')
|
||||
self.update_char_raid_instance(char.char_id, raid_instance.id)
|
||||
return f"Character <highlight>{char.name}</highlight> has been assigned to " \
|
||||
f"raid instance <highlight>{raid_instance.name}</highlight>."
|
||||
else:
|
||||
return f"Character <highlight>{char.name}</highlight> is not in the private channel."
|
||||
|
||||
@command(command="riadmin", params=[Const("clear")], access_level="leader",
|
||||
description="Remove all raids and their players", sub_command="leader")
|
||||
def riadmin_clear(self, _, _1):
|
||||
query = self.db.query("SELECT * FROM raid_instance_char")
|
||||
for user in query:
|
||||
self.buddy_service.remove_buddy(user.char_id, 'raider')
|
||||
self.db.exec("DELETE FROM raid_instance_char where 1")
|
||||
self.db.exec("DELETE FROM raid_instance where 1")
|
||||
return f"All characters have been removed from raid instances."
|
||||
|
||||
@command(command="riadmin", params=[Const("rem"), Character("char")], access_level="leader",
|
||||
description="remove a character from the RI", sub_command="leader")
|
||||
def riadmin_rem(self, _, _2, char):
|
||||
if not char.char_id:
|
||||
return self.getresp("global", "char_not_found", {"char": char.name})
|
||||
|
||||
self.refresh_raid_instance_chars()
|
||||
|
||||
row = self.db.query_single(
|
||||
"SELECT r2.name FROM raid_instance_char r1 "
|
||||
"JOIN raid_instance r2 ON r1.raid_instance_id = r2.id WHERE r1.char_id = ?",
|
||||
[char.char_id])
|
||||
if row:
|
||||
self.update_char_raid_instance(char.char_id, self.UNASSIGNED_RAID_INSTANCE_ID)
|
||||
return f"Character <highlight>{char.name}</highlight> has been removed from " \
|
||||
f"raid instance <highlight>{row.name}</highlight>."
|
||||
else:
|
||||
return f"Character <highlight>{char.name}</highlight> is not assigned to any raid instances."
|
||||
|
||||
@command(command="riadmin", params=[Const("leader"), Character("char")], access_level="leader",
|
||||
description="Set the leader for a RI", sub_command="leader")
|
||||
def riadmin_leader(self, _, _2, char):
|
||||
if not char.char_id:
|
||||
return self.getresp("global", "char_not_found", {"char": char.name})
|
||||
|
||||
raid_instance = self.get_raid_instance_by_char(char.char_id)
|
||||
if not raid_instance:
|
||||
return f"Character <highlight>{char.name}</highlight> does not belong to a raid instance."
|
||||
|
||||
self.set_leader(char.char_id, raid_instance.id)
|
||||
|
||||
return f"Character <highlight>{char.name}</highlight> has been set as the leader for " \
|
||||
f"raid instance <highlight>{raid_instance.name}</highlight>."
|
||||
|
||||
@command(command="riadmin", params=[Const("send")], access_level="leader",
|
||||
description="Send the RIs to their preset bots", sub_command="leader")
|
||||
def riadmin_send(self, _, _2):
|
||||
self.bot.send_private_channel_message("Exporting raids..")
|
||||
for raid_instance in self.get_raid_instances():
|
||||
data = self.db.query(
|
||||
"SELECT r.char_id, p.name, r.is_leader FROM raid_instance_char r "
|
||||
"left join player p on r.char_id=p.char_id WHERE raid_instance_id = ?",
|
||||
[raid_instance.id])
|
||||
if int(raid_instance.bot) == self.bot.get_char_id() or raid_instance.bot == "0" or not raid_instance.bot:
|
||||
continue
|
||||
self.bot.send_private_message(int(raid_instance.bot), "ritake " + ", ".join([k['name'] for k in data]),
|
||||
add_color=False)
|
||||
for char in data:
|
||||
if char.is_leader == 0:
|
||||
self.private_channel_service.kick(char.char_id)
|
||||
|
||||
return "Raid instance configuration has been applied."
|
||||
|
||||
@command(command="riadmin", params=[Const("create"), Any("Raid_name"), Character("bot")],
|
||||
access_level="leader",
|
||||
description="Create or change a raid instance", sub_command="leader")
|
||||
def riadmin_create(self, _, _2, raid_instance_name, bot):
|
||||
if not bot.char_id:
|
||||
return self.getresp("global", "char_not_found", {"char": bot.name})
|
||||
if bot.char_id not in eval(self.setting_service.get_value('riadmin_network')):
|
||||
return "Bot not valid: please ask an Administrator to verify it first."
|
||||
raid_instance = self.get_raid_instance(raid_instance_name)
|
||||
if raid_instance:
|
||||
if raid_instance.name == raid_instance_name and raid_instance.bot == bot.char_id:
|
||||
return f"Raid instance <highlight>{raid_instance_name}</highlight> already exists."
|
||||
else:
|
||||
self.db.exec("UPDATE raid_instance SET name = ?, bot = ? WHERE id = ?",
|
||||
[raid_instance_name, bot.char_id, raid_instance.id])
|
||||
return f"Raid instance <highlight>{raid_instance_name}</highlight> has been updated."
|
||||
else:
|
||||
self.db.exec("INSERT INTO raid_instance (name, bot) VALUES (?, ?)", [raid_instance_name, bot.char_id])
|
||||
return f"Raid instance <highlight>{raid_instance_name}</highlight> [<highlight>{bot.name}</highlight>] " \
|
||||
f"has been created."
|
||||
|
||||
@command(command="riadmin", params=[Const("delete"), Any("raid_instance_name")], access_level="leader",
|
||||
description="Remove a RI", sub_command="leader")
|
||||
def raid_instance_delete_cmd(self, _, _1, raid_instance_name):
|
||||
raid_instance = self.get_raid_instance(raid_instance_name)
|
||||
if not raid_instance:
|
||||
return f"Raid instance <highlight>{raid_instance_name}</highlight> does not exist."
|
||||
query = self.db.query("SELECT char_id from raid_instance_char where raid_instance_id=?", [raid_instance.id])
|
||||
for user in query:
|
||||
self.buddy_service.remove_buddy(user.char_id, 'raider')
|
||||
self.db.exec("DELETE FROM raid_instance_char WHERE raid_instance_id = ?", [raid_instance.id])
|
||||
self.db.exec("DELETE FROM raid_instance WHERE id = ?", [raid_instance.id])
|
||||
|
||||
return f"Raid instance <highlight>{raid_instance_name}</highlight> has been deleted."
|
||||
|
||||
def get_raid_instance_chars(self):
|
||||
self.refresh_raid_instance_chars()
|
||||
|
||||
data = self.db.query("SELECT * FROM ("
|
||||
"SELECT p.*, r2.id AS raid_instance_id, "
|
||||
"r1.is_leader, r2.name AS raid_instance_name, r2.bot "
|
||||
"FROM raid_instance r2 "
|
||||
"LEFT JOIN raid_instance_char r1 ON r1.raid_instance_id = r2.id "
|
||||
"LEFT JOIN player p ON r1.char_id = p.char_id "
|
||||
"UNION "
|
||||
"SELECT p.*, r3.raid_instance_id, "
|
||||
"r3.is_leader, 'Unassigned' AS raid_instance_name, '' AS bot "
|
||||
"FROM raid_instance_char r3 "
|
||||
"LEFT JOIN player p ON r3.char_id = p.char_id "
|
||||
"WHERE r3.raid_instance_id = ?) as r2r1pr3p "
|
||||
"ORDER BY raid_instance_id != ? DESC, "
|
||||
"raid_instance_name, "
|
||||
"is_leader desc, "
|
||||
"profession, level desc, "
|
||||
"name",
|
||||
[self.UNASSIGNED_RAID_INSTANCE_ID, self.UNASSIGNED_RAID_INSTANCE_ID])
|
||||
|
||||
return data
|
||||
|
||||
def refresh_raid_instance_chars(self):
|
||||
users = self.db.query('SELECT * from online o '
|
||||
'left join player p on o.char_id=p.char_id '
|
||||
'where o.channel = ?', [self.bot.name])
|
||||
for user in users:
|
||||
self.db.exec(
|
||||
"INSERT IGNORE INTO raid_instance_char (char_id, raid_instance_id, is_leader) VALUES (?, ?, 0)",
|
||||
[user.char_id, self.UNASSIGNED_RAID_INSTANCE_ID])
|
||||
self.buddy_service.add_buddy(user.char_id, 'raider')
|
||||
|
||||
def update_char_raid_instance(self, char_id, raid_instance_id):
|
||||
return self.db.exec("UPDATE raid_instance_char SET raid_instance_id = ?, is_leader = 0 WHERE char_id = ?",
|
||||
[raid_instance_id, char_id])
|
||||
|
||||
def set_leader(self, char_id, raid_instance_id):
|
||||
self.db.exec("UPDATE raid_instance_char SET is_leader = 0 WHERE raid_instance_id = ?", [raid_instance_id])
|
||||
self.db.exec("UPDATE raid_instance_char SET is_leader = 1 WHERE raid_instance_id = ? AND char_id = ?",
|
||||
[raid_instance_id, char_id])
|
||||
|
||||
def compact_char_display(self, char_info):
|
||||
if char_info.level:
|
||||
msg = f" {self.util.get_prof_icon(char_info.profession)} " \
|
||||
f"{self.text.zfill(char_info.level, 220)}/<green>{self.text.zfill(char_info.ai_level, 30)}</green> " \
|
||||
f"{char_info.name: <13}"
|
||||
elif char_info.name:
|
||||
msg = " <highlight>%s</highlight>" % char_info.name
|
||||
else:
|
||||
msg = " <highlight>Unknown(%d)</highlight>" % char_info.char_id
|
||||
|
||||
if char_info.is_leader:
|
||||
msg += " [<highlight>Leader</highlight>]"
|
||||
|
||||
return msg
|
||||
|
||||
def get_assignment_links(self, raid_instances, char_name, add_leader_link):
|
||||
links = list(map(lambda x: self.text.make_tellcmd(x.name, f"riadmin add {x.name} {char_name}"), raid_instances))
|
||||
links.insert(0, self.text.make_tellcmd("Rem", f"riadmin rem {char_name}"))
|
||||
if add_leader_link:
|
||||
links.insert(0, self.text.make_tellcmd("L", f"riadmin leader {char_name}"))
|
||||
return f'[{"|".join(links)}]'
|
||||
|
||||
def get_raid_instances(self):
|
||||
data = self.db.query("SELECT id, name, bot FROM raid_instance ORDER BY name")
|
||||
return data
|
||||
|
||||
def get_raid_instance(self, raid_instance_name):
|
||||
return self.db.query_single("SELECT id, name, bot FROM raid_instance WHERE name LIKE ?", [raid_instance_name])
|
||||
|
||||
def get_raid_instance_by_char(self, char_id):
|
||||
return self.db.query_single("SELECT id, name, CASE WHEN bot IS NOT NULL THEN bot else 0 END as bot "
|
||||
"FROM raid_instance r1 JOIN raid_instance_char r2 ON r1.id = r2.raid_instance_id "
|
||||
"WHERE r2.char_id = ?", [char_id])
|
||||
|
||||
def get_conn_by_id(self, bot):
|
||||
conn = self.bot.conns.get(bot)
|
||||
if conn:
|
||||
return conn
|
||||
|
||||
conns = self.bot.get_conns(lambda x: x.char_name.lower() == bot.lower())
|
||||
if conns:
|
||||
return conns[0][1]
|
||||
|
||||
return None
|
||||
Reference in New Issue
Block a user