diff --git a/db.py b/db.py
index af32d39c..9e74aa2b 100644
--- a/db.py
+++ b/db.py
@@ -1234,14 +1234,16 @@ class Match(Base):
def active_players_count(self):
count = 0
for player in self.players:
- if player.status == MatchmakingStatus.READY or player.status == MatchmakingStatus.WAIT_FOR_ME:
+ if player.status == MatchmakingStatus.READY \
+ or player.status == MatchmakingStatus.WAIT_FOR_ME \
+ or player.status == MatchmakingStatus.SOMEONE_ELSE:
count += 1
return count
def generate_text(self, session):
player_list = session.query(MatchPartecipation).filter_by(match=self).all()
title = f"{self.match_title}"
- description = self.match_desc if self.match_desc else ""
+ description = f"{self.match_desc}\n" if self.match_desc else ""
if self.min_players:
minimum = f" (minimo {self.min_players})"
else:
@@ -1264,14 +1266,14 @@ class Match(Base):
continue
plist += f"{icon} {player.user.royal.username}\n"
if ignore_count:
- ignored = f"β {ignore_count} persone non ne hanno voglia.\n"
+ ignored = f"β {ignore_count} persone non sono interessate.\n"
else:
ignored = ""
if self.max_players:
players = f"[{self.active_players_count()}/{self.max_players}]"
else:
players = f"[{self.active_players_count()}]"
- close = f"[matchmaking concluso]\n" if self.closed else ""
+ close = f"[matchmaking terminato]\n" if self.closed else ""
message = f"{title} {players}\n" \
f"{description}\n" \
f"{plist}\n" \
@@ -1282,6 +1284,20 @@ class Match(Base):
def __repr__(self):
return f""
+ def format_dict(self) -> typing.Dict[str, str]:
+ return {
+ "id": self.id,
+ "timestamp": self.timestamp.isoformat(),
+ "creator_id": self.creator_id,
+ "creator_name": self.creator.mention(),
+ "match_title": self.match_title,
+ "match_desc": self.match_desc,
+ "min_players": self.min_players,
+ "max_players": self.max_players,
+ "active_players": self.active_players_count(),
+ "players": len(self.active_players_count())
+ }
+
class MatchmakingStatus(enum.IntEnum):
WAIT_FOR_ME = 1
diff --git a/strings.py b/strings.py
new file mode 100644
index 00000000..c6fcbf9e
--- /dev/null
+++ b/strings.py
@@ -0,0 +1,50 @@
+from db import MatchmakingStatus
+
+
+class SafeDict(dict):
+ def __missing__(self, key):
+ return '' + key + '
'
+
+
+def safely_format_string(string, **kwargs):
+ return string.format_map(SafeDict(**kwargs))
+
+
+class ROYALNET:
+ class ERRORS:
+ TELEGRAM_NOT_LINKED = "β Il tuo account Telegram non Γ¨ registrato a Royalnet! Registrati con `/register@royalgamesbot `."
+
+
+# Matchmaking service strings
+class MATCHMAKING:
+ TICKER_TEXT = {
+ "match_ready": "π΅ Hai detto che sei pronto per giocare!",
+ "match_wait_for_me": "π Hai chiesto agli altri di aspettarti.",
+ "match_maybe": "β Hai detto che forse ci sarai.",
+ "match_someone_else": "π¬ Hai detto che vuoi aspettare che venga qualcun altro.",
+ "match_ignore": "β Non hai intenzione di partecipare.",
+ "match_close": "π© Hai notificato tutti che la partita sta iniziando.",
+ "match_cancel": "π Hai annullato la partita."
+ }
+
+ GAME_START = {
+ MatchmakingStatus.READY: "π΅ Che {match_title} abbia inizio!",
+ MatchmakingStatus.WAIT_FOR_ME: "π Sbrigati! {match_title} sta per iniziare!",
+ MatchmakingStatus.SOMEONE_ELSE: "β {match_title} sta iniziando. Se vuoi partecipare, fai in fretta!",
+ MatchmakingStatus.MAYBE: "π¬ {match_title} sta per iniziare, e ci sono {active_players} giocatori."
+ }
+
+ BUTTONS = {
+ "match_ready": "π΅ Sono pronto per iniziare!",
+ "match_wait_for_me": "π Ci sarΓ², aspettatemi!",
+ "match_maybe": "β Forse vengo, se non ci sono fate senza di me.",
+ "match_someone_else": "π¬ Solo se viene anche qualcun altro...",
+ "match_ignore": "β Non ci sarΓ².",
+ "match_close": "π© ADMIN: Avvia la partita",
+ "match_cancel": "π ADMIN: Annulla la partita"
+ }
+
+ class ERRORS:
+ INVALID_SYNTAX = "β Sintassi del comando errata.\n Sintassi: `/mm [minplayers-][maxplayers] per \\n [descrizione]`"
+ NOT_ADMIN = "β Non sei il creatore di questo match!"
+ MATCH_CLOSED = "β Il matchmaking per questa partita Γ¨ terminato!"
diff --git a/telegrambot.py b/telegrambot.py
index 5b49cd58..f9c0445c 100644
--- a/telegrambot.py
+++ b/telegrambot.py
@@ -9,6 +9,7 @@ import stagismo
from telegram import Bot, Update, InlineKeyboardMarkup, InlineKeyboardButton
# noinspection PyPackageRequirements
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
+from telegram.error import TimedOut
import dice
import sys
import os
@@ -19,6 +20,8 @@ import configparser
import markovify
import raven
import coloredlogs
+import strings
+s = strings.safely_format_string
# Markov model
try:
@@ -50,6 +53,8 @@ def catch_and_report(func: "function"):
# noinspection PyBroadException
try:
return func(bot, update)
+ except TimedOut:
+ logger.warning(f"Telegram timed out in {update}")
except Exception:
logger.error(f"Critical error: {sys.exc_info()}")
# noinspection PyBroadException
@@ -293,16 +298,13 @@ def cmd_mm(bot: Bot, update: Update):
try:
user = session.query(db.Telegram).filter_by(telegram_id=update.message.from_user.id).one_or_none()
if user is None:
- bot.send_message(update.message.chat.id,
- "β Il tuo account Telegram non Γ¨ registrato a Royalnet!"
- " Registrati con `/register@royalgamesbot `.", parse_mode="Markdown")
+ bot.send_message(update.message.chat.id, strings.ROYALNET.ERRORS.TELEGRAM_NOT_LINKED, parse_mode="Markdown")
return
match = re.match(r"/(?:mm|matchmaking)(?:@royalgamesbot)?(?: (?:([0-9]+)-)?([0-9]+))? (?:per )?([A-Za-z0-9!\-_\. ]+)(?:.*\n(.+))?",
update.message.text)
if match is None:
bot.send_message(update.message.chat.id,
- "β Sintassi del comando errata.\n"
- "Sintassi: `/matchmaking@royalgamesbot [minplayers]-[maxplayers] per \\n [descrizione]`")
+ "")
return
min_players, max_players, match_name, match_desc = match.group(1, 2, 3, 4)
db_match = db.Match(timestamp=datetime.datetime.now(),
@@ -313,20 +315,9 @@ def cmd_mm(bot: Bot, update: Update):
creator=user)
session.add(db_match)
session.flush()
- inline_keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("π΅ Possiamo iniziare!",
- callback_data="match_ready")],
- [InlineKeyboardButton("π Ci sarΓ², aspettatemi!",
- callback_data="match_wait_for_me")],
- [InlineKeyboardButton("β Forse vengo, se non ci sono fate senza di me.",
- callback_data="match_maybe")],
- [InlineKeyboardButton("π¬ Solo se viene anche qualcun altro...",
- callback_data="match_someone_else")],
- [InlineKeyboardButton("β Non ci sarΓ².",
- callback_data="match_ignore")],
- [InlineKeyboardButton("π [annulla la partita]",
- callback_data="match_delete")],
- [InlineKeyboardButton("π© [avvia la partita]",
- callback_data="match_close")]])
+ inline_keyboard = InlineKeyboardMarkup([([InlineKeyboardButton(strings.MATCHMAKING.BUTTONS[key],
+ callback_data=key)])
+ for key in strings.MATCHMAKING.BUTTONS])
message = bot.send_message(config["Telegram"]["announcement_group"], db_match.generate_text(session=session),
parse_mode="HTML",
reply_markup=inline_keyboard)
@@ -393,55 +384,32 @@ def on_callback_query(bot: Bot, update: Update):
try:
user = session.query(db.Telegram).filter_by(telegram_id=update.callback_query.from_user.id).one_or_none()
if user is None:
- bot.answer_callback_query(update.callback_query.id, show_alert=True,
- text="β Il tuo account Telegram non Γ¨ registrato a Royalnet!"
- " Registrati con `/register@royalgamesbot `.",
+ bot.answer_callback_query(update.callback_query.id,
+ show_alert=True,
+ text=strings.ROYALNET.ERRORS.TELEGRAM_NOT_LINKED,
parse_mode="Markdown")
return
match = session.query(db.Match).filter_by(message_id=update.callback_query.message.message_id).one()
- if update.callback_query.data == "match_ready":
- status = db.MatchmakingStatus.READY
- text = "π΅ Hai detto che sei pronto per giocare!"
- elif update.callback_query.data == "match_wait_for_me":
- status = db.MatchmakingStatus.WAIT_FOR_ME
- text = "π Hai chiesto agli altri di aspettarti."
- elif update.callback_query.data == "match_ignore":
- status = db.MatchmakingStatus.IGNORED
- text = "β Non ti interessa questa partita."
- elif update.callback_query.data == "match_maybe":
- status = db.MatchmakingStatus.MAYBE
- text = "β Hai detto che forse ci sarai."
- elif update.callback_query.data == "match_someone_else":
- status = db.MatchmakingStatus.SOMEONE_ELSE
- text = "π¬ Hai detto che vuoi aspettare che venga qualcun altro."
- elif update.callback_query.data == "match_close" or update.callback_query.data == "match_delete":
+ if update.callback_query.data == "match_close":
status = None
- if match.creator == user:
- match.closed = True
- text = "π© Matchmaking chiuso!"
- if update.callback_query.data == "match_close":
- for player in match.players:
- if player.status == db.MatchmakingStatus.READY or player.status == db.MatchmakingStatus.WAIT_FOR_ME:
- try:
- bot.send_message(player.user.telegram_id,
- f"π© Sei pronto? {match.match_title} sta iniziando!",
- parse_mode="HTML")
- except Exception as e:
- logger.warning(f"Failed to notify {player.user.username}: {e}")
- else:
- bot.answer_callback_query(update.callback_query.id, show_alert=True,
- text="β Non sei il creatore di questo match!")
+ if match.creator != user:
+ bot.answer_callback_query(update.callback_query.id,
+ show_alert=True,
+ text=strings.MATCHMAKING.ERRORS.NOT_ADMIN)
return
+ match.closed = True
+ for player in match.players:
+ if player.status >= 1:
+ bot.send_message(player.user.telegram_id,
+ s(strings.MATCHMAKING.GAME_START[player.status],
+ **match.format_dict()))
else:
raise NotImplementedError()
if status:
if match.closed:
- bot.answer_callback_query(update.callback_query.id, show_alert=True,
- text="β Il matchmaking Γ¨ terminato!")
- return
- if match.max_players and match.active_players_count() >= match.max_players:
- bot.answer_callback_query(update.callback_query.id, show_alert=True,
- text="β La partita Γ¨ piena.")
+ bot.answer_callback_query(update.callback_query.id,
+ show_alert=True,
+ text=strings.MATCHMAKING.ERRORS.MATCH_CLOSED)
return
player = session.query(db.MatchPartecipation).filter_by(match=match, user=user).one_or_none()
if player is None:
@@ -450,22 +418,13 @@ def on_callback_query(bot: Bot, update: Update):
else:
player.status = status.value
session.commit()
- bot.answer_callback_query(update.callback_query.id, text=text, cache_time=1)
+ bot.answer_callback_query(update.callback_query.id,
+ text=s(strings.MATCHMAKING.TICKER_TEXT[update.callback_query.data]),
+ cache_time=1)
if not match.closed:
- inline_keyboard = InlineKeyboardMarkup([[InlineKeyboardButton("π΅ Possiamo iniziare!",
- callback_data="match_ready")],
- [InlineKeyboardButton("π Ci sarΓ², aspettatemi!",
- callback_data="match_wait_for_me")],
- [InlineKeyboardButton("β Forse vengo, se non ci sono fate senza di me.",
- callback_data="match_maybe")],
- [InlineKeyboardButton("π¬ Solo se viene anche qualcun altro...",
- callback_data="match_someone_else")],
- [InlineKeyboardButton("β Non ci sarΓ².",
- callback_data="match_ignore")],
- [InlineKeyboardButton("π [annulla la partita]",
- callback_data="match_delete")],
- [InlineKeyboardButton("π© [avvia la partita]",
- callback_data="match_close")]])
+ inline_keyboard = InlineKeyboardMarkup([([InlineKeyboardButton(strings.MATCHMAKING.BUTTONS[key],
+ callback_data=key)])
+ for key in strings.MATCHMAKING.BUTTONS])
else:
inline_keyboard = None
bot.edit_message_text(message_id=update.callback_query.message.message_id,