import asyncio import datetime from typing import Literal import mcstatus from nonebot import on_command from nonebot.adapters import Event from nonebot_plugin_alconna import Alconna, Args, UniMessage, on_alconna from mcstatus.responses import JavaStatusResponse from nonebot_plugin_apscheduler import scheduler from konabot.common.permsys import DepPermManager, require_permission from konabot.plugins.minecraft_servers.simpfun_server import SimpfunServer cmd = on_command( "宾几人", aliases=set(("宾人数", "mcbingo")), rule=require_permission("minecraft.bingo.check"), ) def parse_status(motd: str) -> str: if "[PRE-GAME]" in motd: return "[✨ 空闲]" if "[IN-GAME]" in motd: return "[🕜 游戏中]" if "[POST-GAME]" in motd: return "[🕜 游戏中]" return "[✨ 开放]" def dump_server_status(name: str, status: JavaStatusResponse | BaseException) -> str: if isinstance(status, JavaStatusResponse): motd = status.motd.to_plain() # Bingo Status: [PRE-GAME], [IN-GAME], [POST-GAME] st = parse_status(motd) players_sample = status.players.sample or [] players_sample_suffix = "" if len(players_sample) > 0: player_list = [s.name for s in players_sample] players_sample_suffix = " (" + ", ".join(player_list) + ")" return f"{name}: {st} {status.players.online} 人在线{players_sample_suffix}" else: return f"{name}: 好像没开" @cmd.handle() async def _(evt: Event, pm: DepPermManager): servers = ( (mcstatus.JavaServer("play.simpfun.cn", 11495), "小帕 Bingo"), (mcstatus.JavaServer("bingo.mujica.tech"), "坏枪 Bingo"), (mcstatus.JavaServer("mc.mujica.tech", 11456), "齿轮盛宴"), ) responses = await asyncio.gather( *map(lambda s: s[0].async_status(), servers), return_exceptions=True, ) messages = "\n".join( ( dump_server_status(n, r) for n, r in zip(map(lambda s: s[1], servers), responses) ) ) if await pm.check_has_permission(evt, "minecraft.bingo.manipulate"): messages += "\n\n---\n\n你可以使用 bingoman start 开启小帕的 bingo 服,用 bingoman stop 关闭小帕的 bingo 服" await UniMessage.text(messages).finish(evt, at_sender=False) cmd_bingo_manipulate = on_alconna( Alconna("bingoman", Args["action", str]), aliases=("宾服务器", "bingo服"), rule=require_permission("minecraft.bingo.manipulate"), ) actions: dict[str, Literal["start", "stop", "restart", "kill"]] = { "up": "start", "down": "stop", "start": "start", "stop": "stop", "开机": "start", "关机": "stop", "restart": "restart", "kill": "kill", "重启": "restart", } @cmd_bingo_manipulate.handle() async def _(action: str, event: Event): server = SimpfunServer.new() # 使用默认配置管理服务器 a = actions.get(action.lower().strip()) if a is None: await UniMessage.text(f"操作 {action} 不存在").send(event, at_sender=True) return resp = await server.power(a) if resp.code == 200: await UniMessage.text("好了").send(event, at_sender=True) else: await UniMessage.text(f"不好:{resp}").send(event, at_sender=True) @scheduler.scheduled_job("cron", hour="4,23") async def _(): server = SimpfunServer.new() today = datetime.datetime.now() # 获取服务器当前状态,重试多次以保证不会误判服务器未开启 server_up = False server_players = 0 for _ in range(3): mcs = mcstatus.JavaServer("play.simpfun.cn", 11495) try: resp = await mcs.async_status() server_up = True server_players = resp.players.online except Exception: pass if today.weekday() == 5 and today.hour < 12: # 每周六开机一天,保证可以让服务器不被自动销毁 if not server_up: await server.power("start") else: # 每用一个自然日都会计费,所以要赶在这一天结束之前关服 # 平时如果没人,也自动关上 if server_up and server_players == 0: await server.power("stop")