-> !wants
-> !orgs info
-> special cmd's
-> !assist
-> "afk" for players without active account
-> !loot add <item_ref> <count> => nolonger breaks !account
Changes:
-> grouped !tara, !gaunt, .. into !wb
-> Display the most recent news entry on logon (default: enabled)
-> improved grouping of !items
-> Added the option to authentificate WS connections (Datanet module). This is used in special cases, where the Websocket Server requires the clien tto authentificate itself. (Server sends "#auth", client responds with the auth string)
-> Add main name to relaying (priv <-> org) [default: disabled]
-> Added logon/logoff messages back
-> restricted default access to "dangerous" commands to moderator
-> Added optional logging (Private Channel, Org Channel, Tells, ... disabled by default)

Rewrite of the Tower Module.
-> More verbosity, if enabled in config. by default, GAS and Hot timer only.
-> !hot displays currently hot (and in penalty) sites, and these which go hot in < 60 minutes
-> !attacks filterable by PF and Site
-> display current contract QL's grouped by org: !contracts (requires managed cache)
This commit is contained in:
2021-11-25 14:09:43 +01:00
parent 2d7ecf4883
commit 17c776faec
44 changed files with 1669 additions and 1249 deletions
+63 -10
View File
@@ -8,14 +8,15 @@ from core.buddy_service import BuddyService
from core.chat_blob import ChatBlob
from core.command_param_types import Options, Int, Const, Any
from core.db import DB
from core.decorators import instance, event, command
from core.decorators import instance, event, command, setting
from core.dict_object import DictObject
from core.igncore import IgnCore
from core.job_scheduler import JobScheduler
from core.logger import Logger
from core.lookup.pork_service import PorkService
from core.setting_service import SettingService
from core.setting_types import BooleanSettingType
from core.text import Text
from core.igncore import IgnCore
from core.util import Util
from modules.core.accounting.preference_controller import PreferenceController
from modules.core.accounting.services.account_service import AccountService
@@ -76,6 +77,7 @@ hh:mm - DD.MM.YYYY
"added_by int not null, "
"added_at timestamp, "
"headline int not null default 0)")
self.db.exec("CREATE TABLE IF NOT EXISTS news_read(main INT NOT NULL PRIMARY KEY, post_id INT NOT NULL)")
def start(self):
self.commands = f" [{self.text.make_chatcmd('raids', '/tell <myname> raids')}] " \
@@ -89,7 +91,8 @@ hh:mm - DD.MM.YYYY
def logon_event(self, _, data):
if not self.bot.is_ready():
return
if "member" in self.buddy_service.get_buddy(data.packet.char_id)["types"]:
if "member" in self.buddy_service.get_buddy(data.packet.char_id)["types"] \
or "org_member" in self.buddy_service.get_buddy(data.packet.char_id)["types"]:
account = data.account
# Apply standard checks. (User Banned, Account disabled, ...)
if not self.account_service.simple_checks(data.account):
@@ -101,18 +104,21 @@ hh:mm - DD.MM.YYYY
discord = f"Your Account is <highlight>not</highlight> connected to Discord " \
f"[{self.text.make_chatcmd('Join', '/tell <myname> discord invite')}]"
else:
prefix = ""
if self.setting_service.get_value('is_alliance_bot') == '1':
prefix = f"[{self.alias_controller.get_alias(account.org_id)}] "
discord = f"Your Account <highlight>is</highlight> connected to Discord as " \
f"<highlight>[{self.alias_controller.get_alias(account.org_id)}] " \
f"{account.name}</highlight>"
f"<highlight>{prefix}{account.name}</highlight>"
user = self.pork.get_character_info(data.packet.char_id)
self.job_schedule.delayed_job(self.send_news, 15, user, self.account_service.get_alts(account.main),
discord,
self.preferences.get_pref_view_small(account))
@command(command="raids", params=[], description="Show the Raids", access_level="member")
def show_raids(self, _):
with open("data/latest_raids.txt", "r") as f:
return self.text.format_page("Raidschedule", f.read())
# @command(command="raids", params=[], description="Show the Raids", access_level="member")
# def show_raids(self, _):
# with open("data/latest_raids.txt", "r") as f:
# return self.text.format_page("Raidschedule", f.read())
def get_timers(self):
events = [self.weekly.get_next_bs(),
@@ -140,12 +146,21 @@ hh:mm - DD.MM.YYYY
self.weekly.get_next_dio()]
return sorted(events, key=lambda timer: timer.start)[0]
@setting(name="preview_recent", value="true",
description="Sends the newest News entry to the user directly, without wrapping it into a blob")
def preview_recent(self):
return BooleanSettingType()
def send_news(self, _, sender, alts, discord, prefs, auto=True):
if auto:
if self.buddy_service.get_buddy(sender.char_id)["online"] == 0:
return
timers = self.get_timers()
next_event = self.get_next_event()
last_updated: datetime = (self.db.query_single("SELECT added_at FROM news order by ID desc") or {}).get(
"added_at", 0)
if type(last_updated) != int:
last_updated = last_updated.astimezone().timestamp()
news = self.layout.format(time=datetime.now(timezone.utc).strftime("%H:%M - %d.%m.%Y") + " [UTC-0]",
main=alts[0].name,
alts_show=self.text.make_chatcmd(len(alts), "/tell <myname> alts"),
@@ -155,15 +170,38 @@ hh:mm - DD.MM.YYYY
prefs=prefs,
discord=discord)
name = self.weekly.get_long_name(next_event.type)
if last_updated > 0:
last_updated = f"[{self.util.time_to_readable(datetime.utcfromtimestamp(time.time()).timestamp() - last_updated)} ago]"
else:
last_updated = ""
blob = f"<yellow>{random.choice(self.greetings)} {sender.name} :: " \
f"{self.text.format_page('Your News', textwrap.dedent(news))} </yellow> " \
f"{self.text.format_page('Your News', textwrap.dedent(news))} </yellow>{last_updated} " \
f"{f'<yellow>::</yellow> {name} running' if next_event.is_running() else ''}"
self.bot.send_mass_message(sender.char_id, blob)
if self.preview_recent().get_value() and auto:
entry = self.get_newest_entry()
if not entry:
return
if entry.id > self.get_read_id(sender.char_id):
data = f":: <yellow>Your most recent unread news</yellow> :: \n" \
f"{entry.text}\n" \
f"{self.text.format_page('Mark as read', self.text.make_tellcmd('Mark as read', f'news read {entry.id}'))}"
self.bot.send_mass_message(sender.char_id, data)
#####################
# News Management #
#####################
@command(command="news", params=[Const("read"), Int("ID", is_optional=True)],
description="Marks All news until [ID] as read, or all of none specified.",
access_level="member",
extended_description="It is also possible to move the read marker back, i.e. from ID 5 -> 1.\nThis has no effect if the preview_recent setting is off.")
def cmd_news_read(self, sender, _, entry_id):
if not entry_id:
entry_id = (self.db.query_single("SELECT id from news ORDER BY id desc limit 1") or {}).get("id", 0)
self.mark_as_read(sender.sender.char_id, entry_id)
return f"Your News Read marker has been moved to ID <highlight>{entry_id}</highlight>."
@command(command="news", params=[], description="Show the news", access_level="member")
def show_news(self, sender):
user = self.db.query_single("SELECT * FROM player where char_id=?", [sender.sender.char_id])
@@ -243,6 +281,8 @@ hh:mm - DD.MM.YYYY
normal = ""
headline = ""
for entry in data:
if len(self.text.strip_html_tags(headline + normal) or []) > limit:
break
if entry.headline == 1:
if len(self.text.strip_html_tags(headline) or []) > limit / 2:
continue
@@ -268,3 +308,16 @@ hh:mm - DD.MM.YYYY
def add_entry(self, text, sender):
self.db.exec("INSERT INTO news(text, added_by, added_at) VALUES(?, ?, ?)",
[text, sender.char_id, datetime.utcfromtimestamp(time.time())])
def get_newest_entry(self):
return self.db.query_single("SELECT * from news order by id desc")
def get_read_id(self, char_id):
return (self.db.query_single(
"SELECT post_id from news_read where main = (SELECT main from account where char_id=?)",
[char_id]) or {}).get('post_id', 0)
def mark_as_read(self, char_id, post_id):
self.db.exec(
"INSERT INTO news_read(main, post_id) VALUES((SELECT main from account where char_id=? LIMIT 1), ?) ON DUPLICATE KEY UPDATE post_id=?",
[char_id, post_id, post_id])