Files
igncore/core/buddy_service.py
T
Minidodo 43918066a9 Added !orglist cancel
fix for !whois <char_id>
added logging for invalid ORG_MSG_EVENT's
2022-05-09 19:47:26 +02:00

166 lines
6.1 KiB
Python

from core.aochat import client_packets
from core.aochat import server_packets
from core.conn import Conn
from core.decorators import instance
from core.logger import Logger
from core.lookup.character_service import CharacterService
@instance()
class BuddyService:
BUDDY_LOGON_EVENT = "buddy_logon"
BUDDY_LOGOFF_EVENT = "buddy_logoff"
def __init__(self):
self.buddy_list = {}
self.buddy_list_size = 0
self.logger = Logger(__name__)
def inject(self, registry):
self.character_service: CharacterService = registry.get_instance("character_service")
self.bot = registry.get_instance("bot")
self.event_service = registry.get_instance("event_service")
def pre_start(self):
self.bot.register_packet_handler(server_packets.BuddyAdded.id, self.handle_add)
self.bot.register_packet_handler(server_packets.BuddyRemoved.id, self.handle_remove)
self.bot.register_packet_handler(server_packets.LoginOK.id, self.handle_login_ok)
self.event_service.register_event_type(self.BUDDY_LOGON_EVENT)
self.event_service.register_event_type(self.BUDDY_LOGOFF_EVENT)
def handle_add(self, conn: Conn, packet):
buddy = self.buddy_list[conn.id].get(packet.char_id, {"types": [], "conn_id": conn.id})
buddy["online"] = packet.online
self.buddy_list[conn.id][packet.char_id] = buddy
# verify that buddy does not exist on any other conn
for conn_id, conn_buddy_list in self.buddy_list.items():
if conn.id != conn_id:
if buddy := conn_buddy_list.get(packet.char_id, None):
if buddy["online"] is None:
# remove from other conn list
del conn_buddy_list[packet.char_id]
else:
# remove from this conn
self.logger.warning(f"Removing char '{packet.char_id}' from conn '{conn.id}' "
f"since it already exists on another conn")
conn.send_packet(client_packets.BuddyRemove(packet.char_id))
if packet.online == 1:
self.event_service.fire_event(self.BUDDY_LOGON_EVENT, packet)
else:
self.event_service.fire_event(self.BUDDY_LOGOFF_EVENT, packet)
def handle_remove(self, conn: Conn, packet):
conn_buddy_list = self.buddy_list[conn.id]
if packet.char_id in conn_buddy_list:
if len(conn_buddy_list[packet.char_id]["types"]) > 0:
self.logger.warning(f"Removing buddy {packet.char_id} that still has "
f"types {conn_buddy_list[packet.char_id]['types']}")
del conn_buddy_list[packet.char_id]
def handle_login_ok(self, conn: Conn, _):
self.buddy_list_size += 1000
self.buddy_list[conn.id] = {}
self.buddy_list[conn.id][conn.char_id] = {"online": True, "types": [], "conn_id": conn.id}
def add_buddy(self, char_id, _type):
if not char_id:
return False
# check if we are trying to add a conn as a buddy
if self.is_conn_char_id(char_id):
return False
buddy = self.get_buddy(char_id)
if buddy:
buddy["types"].append(_type)
else:
conn = self.get_conn_for_new_buddy()
if conn.char_id != char_id:
conn.send_packet(client_packets.BuddyAdd(char_id, "\1"))
self.buddy_list[conn.id][char_id] = {"online": None, "types": [_type], "conn_id": conn.id}
return True
def is_conn_char_id(self, char_id):
for _id, conn in self.bot.conns.items():
if conn.char_id == char_id:
return True
return False
def remove_buddy(self, char_id, _type, force_remove=False):
if char_id:
buddy = self.get_buddy(char_id)
if not buddy:
return False
if _type in buddy["types"]:
buddy["types"].remove(_type)
if len(buddy["types"]) == 0 or force_remove:
if not self.is_conn_char_id(char_id):
conn = self.bot.conns[buddy["conn_id"]]
conn.send_packet(client_packets.BuddyRemove(char_id))
return True
else:
return False
def remove_buddy_type(self, chars: [], _type: str, force_remove=False):
removed = 0
if len(chars) < 1:
return removed
for bot, buddylist in self.buddy_list.items():
for x in buddylist.keys():
if x not in chars:
continue
if _type not in buddylist[x]['types']:
continue
buddylist[x]["types"].remove(_type)
if len(buddylist[x]["types"]) == 0 or force_remove:
conn = self.bot.conns[buddylist[x]["conn_id"]]
conn.send_packet(client_packets.BuddyRemove(x))
removed += 1
return removed
def get_buddy(self, char_id):
for conn_id, conn_buddy_list in self.buddy_list.items():
if char_id in conn_buddy_list:
return conn_buddy_list[char_id]
return None
def is_online(self, char_id):
buddy = self.get_buddy(char_id)
if buddy is None:
return None
else:
return buddy.get("online", None)
def get_all_buddies(self):
result = {}
for conn_id, conn_buddy_list in self.buddy_list.items():
for char_id, buddy in conn_buddy_list.items():
result[char_id] = buddy
return result
def get_buddy_list_size(self):
count = 0
for conn_id, conn_buddy_list in self.buddy_list.items():
count += len(conn_buddy_list)
return count
def get_conn_for_new_buddy(self):
buddy_list_size = None
_id = None
for conn_id, conn_buddy_list in self.buddy_list.items():
if buddy_list_size is None or len(conn_buddy_list) < buddy_list_size:
buddy_list_size = len(conn_buddy_list)
_id = conn_id
return self.bot.conns.get(_id, None)