From 55ef79d4a9b956095cf66c0e138db55b7dcec919 Mon Sep 17 00:00:00 2001 From: Jerry Date: Sun, 29 Dec 2019 18:07:16 +0800 Subject: [PATCH] new feature: list_games --- data.py | 4 ++-- data_ram.py | 3 +++ tgmsbot.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/data.py b/data.py index ef4882a..310b99e 100644 --- a/data.py +++ b/data.py @@ -4,8 +4,8 @@ from peewee import * SQLITE_MAX_INT: int = 2**63 -1 SQLITE_MIN_INT: int = -2**63 -SQLITE_MAX_INT = int(SQLITE_MAX_INT/2) -SQLITE_MIN_INT = int(SQLITE_MIN_INT/2) +SQLITE_MAX_INT = SQLITE_MAX_INT // 2 +SQLITE_MIN_INT = SQLITE_MIN_INT // 2 db = SqliteDatabase('tgmsbot.db', pragmas={ 'journal_mode': 'wal', diff --git a/data_ram.py b/data_ram.py index 345c8a5..f9017b4 100644 --- a/data_ram.py +++ b/data_ram.py @@ -16,6 +16,9 @@ class Player(): self.restricted_until = restricted_until self.immunity_cards = immunity_cards self.permission = permission + @staticmethod + def save(): + pass def get_player(user_id): player = pool.get(user_id, None) diff --git a/tgmsbot.py b/tgmsbot.py index feb89a5..a0bf504 100644 --- a/tgmsbot.py +++ b/tgmsbot.py @@ -6,8 +6,6 @@ from telegram import InlineKeyboardMarkup, InlineKeyboardButton from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, run_async from telegram.error import TimedOut as TimedOutError from numpy import array_equal -# If no peewee orm is installed, try `from data_ram import get_player, db` -from data import get_player, db from random import randint, choice, randrange from math import log from threading import Lock @@ -19,6 +17,12 @@ import logging logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger('tgmsbot') +try: + from data import get_player, db +except ModuleNotFoundError: + logger.warning('using data_ram instead of data') + from data_ram import get_player, db + token = "token_here" updater = Updater(token, workers=8, use_context=True) job_queue = updater.job_queue @@ -29,6 +33,7 @@ PICKLE_FILE = 'tgmsbot.pickle' KBD_MIN_INTERVAL = 0.5 KBD_DELAY_SECS = 0.5 GARBAGE_COLLECTION_INTERVAL = 86400 +MAX_GAMES_PER_USER = 10 HEIGHT = 8 WIDTH = 8 @@ -80,6 +85,7 @@ class Saved_Game(): self.board = board self.group = group self.creator = creator + self.msgid = None self.__actions = dict() self.last_player = None self.start_time = time.time() @@ -118,16 +124,22 @@ class Saved_Game(): class Game(): def __init__(self, *args, **kwargs): + self.__dict__['__sg'] = None if 'unpickle' in args: assert len(args) == 2 and args[0] == 'unpickle' self.__sg = args[1] else: self.__sg = Saved_Game(*args, **kwargs) - self.lock = Lock() + self.__dict__['lock'] = Lock() def pickle(self): return self.__sg def __getattr__(self, name): return getattr(self.__sg, name, None) + def __setattr__(self, name, val): + if name != '_Game__sg': + return setattr(self.__sg, name, val) + else: + self.__dict__[name] = val class GameManager: def __init__(self): @@ -159,6 +171,14 @@ class GameManager: return False def get_game_from_hash(self, board_hash): return self.__games.get(board_hash, None) + def iter_game_from_user(self, user_id): + for g in self.__games.copy().values(): + if g.creator.id == user_id: + yield g + def iter_game_from_chat(self, chat_id): + for g in self.__games.copy().values(): + if g.group.id == chat_id: + yield g def count(self): return len(self.__games) @run_async @@ -175,7 +195,7 @@ class GameManager: g_checked: int = 0 g_freed: int = 0 games = self.__games - for board_hash in games: + for board_hash in games.copy(): g_checked += 1 gm = games[board_hash] start_time = getattr(gm, 'start_time', 0.0) @@ -188,6 +208,31 @@ class GameManager: game_manager = GameManager() +@run_async +def list_games(update, context): + logger.info("List from {0}".format(update.message.from_user.id)) + if not update.effective_chat or update.effective_chat.type in ('private', 'channel'): + if update.message: + update.message.reply_text('本功能仅在群聊中可用') + return + games_avail = list() + for (gid, gm) in enumerate(game_manager.iter_game_from_chat(update.effective_chat.id)): + if gid + 1 > 10: + break + elif gm.group and gm.creator and gm.msgid: + games_avail.append(gm) + if not games_avail: + update.message.reply_text("本群没有正在进行的游戏") + return + links = list() + def gen_link(chat, msgid, text): + chat = int(chat) + if chat < -1000000000000: + chat = (-chat) - 1000000000000 + return f"[{text}](https://t.me/c/{chat}/{msgid})" + for gm in games_avail: + links.append(gen_link(gm.group.id, gm.msgid, f"{gm.creator.first_name} created on {time.ctime(gm.start_time)}")) + update.message.reply_text("\n".join(links), parse_mode="Markdown") @run_async def send_keyboard(update, context): @@ -197,6 +242,11 @@ def send_keyboard(update, context): if check_restriction(update.message.from_user): update.message.reply_text("爆炸这么多次还想扫雷?") return + for (_gid, _) in enumerate(game_manager.iter_game_from_user(update.message.from_user.id)): + if _gid + 1 > MAX_GAMES_PER_USER: + update.message.reply_text((f"汝已经创建了超过{MAX_GAMES_PER_USER}个游戏了\n" + "请结束一个先前创建的游戏并继续")) + return # create a game board if args is None: args = list() @@ -240,8 +290,9 @@ def send_keyboard(update, context): current_row.append(cell) keyboard.append(current_row) # send the keyboard - bot.send_message(chat_id=msg.chat.id, text="路过的大爷~来扫个雷嘛~", reply_to_message_id=msg.message_id, - parse_mode="Markdown", reply_markup=InlineKeyboardMarkup(keyboard)) + gmsg = bot.send_message(chat_id=msg.chat.id, text="路过的大爷~来扫个雷嘛~", reply_to_message_id=msg.message_id, + parse_mode="Markdown", reply_markup=InlineKeyboardMarkup(keyboard)) + game_manager.get_game_from_hash(bhash).msgid = gmsg.message_id def send_help(update, context): logger.debug("Start from {0}".format(update.message.from_user.id)) @@ -491,6 +542,7 @@ updater.dispatcher.add_handler(CallbackQueryHandler(cards.dist_cards_btn_click, updater.dispatcher.add_handler(CommandHandler('start', send_help)) +updater.dispatcher.add_handler(CommandHandler('list', list_games)) updater.dispatcher.add_handler(CommandHandler('mine', send_keyboard)) updater.dispatcher.add_handler(CommandHandler('status', send_status)) updater.dispatcher.add_handler(CommandHandler('stats', player_statistics))