diff --git a/tooldelta/frame.py b/tooldelta/frame.py index 4a4c22d9..5d3675a3 100755 --- a/tooldelta/frame.py +++ b/tooldelta/frame.py @@ -12,9 +12,11 @@ import signal import traceback import json +import uuid from . import constants, extend_functions, game_utils, utils from .constants import SysStatus, TextType +from .constants.netease import PYRPC_OP_SEND from .internal.config_loader import ConfigLoader from .internal.launch_config import LaunchConfig from .internal.packet_handler import PacketHandler @@ -359,11 +361,49 @@ def bot_name(self) -> str: f"此启动器 ({self.launcher.__class__.__name__}) 框架无法产生机器人名" ) + def sendwocmd(self, cmd: str) -> None: + """ + 以控制台身份发送命令。 + + Args: + cmd (str): Minecraft 命令 + """ + self.launcher.sendwocmd(cmd) + + def sendwscmd( + self, cmd: str, waitForResp: bool = False, timeout: float = 30 + ) -> Packet_CommandOutput | None: + """ + 以 WebSocket 身份发送命令。 + + Args: + cmd (str): Minecraft 命令 + waitForResp (bool, optional): 是否等待返回。默认为 False + timeout (float, optional): 超时时间, 超时则引发 TimeoutError + """ + return self.launcher.sendwscmd(cmd, waitForResp, timeout) + + def sendwscmd_with_resp( + self, cmd: str, timeout: float = 30 + ) -> Packet_CommandOutput: + """ + 以 WebSocket 身份发送命令并获取返回。 + + Args: + cmd (str): Minecraft 命令 + timeout (float, optional): 超时时间, 超时则引发 TimeoutError + + Returns: + Packet_CommandOutput: 命令返回类 + """ + resp: Packet_CommandOutput = self.sendwscmd(cmd, True, timeout) # type: ignore + return resp + def sendcmd( self, cmd: str, waitForResp: bool = False, timeout: float = 30 ) -> Packet_CommandOutput | None: """ - 以机器人玩家身份发送指令。 + 以机器人玩家身份发送命令。 Args: cmd (str): Minecraft 命令 @@ -374,55 +414,79 @@ def sendcmd( def sendcmd_with_resp(self, cmd: str, timeout: float = 30) -> Packet_CommandOutput: """ - 以机器人玩家身份发送指令并获取返回。 + 以机器人玩家身份发送命令并获取返回。 Args: - cmd (str): Minecraft 指令 + cmd (str): Minecraft 命令 timeout (float, optional): 超时时间, 超时则引发 TimeoutError Returns: - Packet_CommandOutput: 指令返回类 + Packet_CommandOutput: 命令返回类 """ resp: Packet_CommandOutput = self.sendcmd(cmd, True, timeout) # type: ignore return resp - def sendwscmd( + # TODO: 当 omega 接入点支持 sendaicmd_with_resp 方法后, 请删除以下的保护性代码 + def sendaicmd( self, cmd: str, waitForResp: bool = False, timeout: float = 30 ) -> Packet_CommandOutput | None: """ - 以 WebSocket 身份发送指令。 + 发送魔法命令。 Args: cmd (str): Minecraft 命令 waitForResp (bool, optional): 是否等待返回。默认为 False timeout (float, optional): 超时时间, 超时则引发 TimeoutError """ - return self.launcher.sendwscmd(cmd, waitForResp, timeout) - - def sendwscmd_with_resp( + if hasattr(self.launcher, "sendaicmd"): + return self.launcher.sendaicmd(cmd, waitForResp, timeout) # type: ignore + if not waitForResp: + self.sendaicmdonly(cmd) + return None + raise AttributeError("此接入点尚未实现 sendaicmd_with_resp 方法") + + def sendaicmd_with_resp( self, cmd: str, timeout: float = 30 ) -> Packet_CommandOutput: """ - 发送 WebSocket 指令并获取返回。 + 发送魔法命令并获取返回。 Args: - cmd (str): MC WebSocket 指令 + cmd (str): Minecraft 命令 timeout (float, optional): 超时时间, 超时则引发 TimeoutError Returns: - Packet_CommandOutput: 指令返回类 + Packet_CommandOutput: 命令返回类 """ - resp: Packet_CommandOutput = self.sendwscmd(cmd, True, timeout) # type: ignore + resp: Packet_CommandOutput = self.sendaicmd(cmd, True, timeout) # type: ignore return resp - def sendwocmd(self, cmd: str) -> None: + def sendaicmdonly(self, cmd: str) -> None: """ - 发送 SettingsCommand 指令。 + 仅发送魔法命令, 不获取返回。 Args: cmd (str): Minecraft 命令 """ - self.launcher.sendwocmd(cmd) + my_runtimeid = self.players.getBotInfo().runtime_id + pk = { + "Value": [ + "ModEventC2S", + [ + "Minecraft", + "aiCommand", + "ExecuteCommandEvent", + { + "playerId": str(my_runtimeid), + "cmd": cmd, + "uuid": str(uuid.uuid4()), + }, + ], + None, + ], + "OperationType": PYRPC_OP_SEND, + } + self.sendPacket(constants.PacketIDS.PyRpc, pk) def say_to(self, target: str, text: str) -> None: """向玩家发送消息 diff --git a/tooldelta/internal/cmd_executor.py b/tooldelta/internal/cmd_executor.py index d7d7f3a4..7b58a009 100644 --- a/tooldelta/internal/cmd_executor.py +++ b/tooldelta/internal/cmd_executor.py @@ -2,6 +2,8 @@ from dataclasses import dataclass from typing import Any, TYPE_CHECKING from collections.abc import Callable +import json +import textwrap from .. import plugin_market from ..constants import SysStatus from ..utils import fmts, mc_translator, thread_func, ToolDeltaThread @@ -138,50 +140,149 @@ def command_readline_proc(self): fmts.print_err("§6虽然出现了问题, 但是您仍然可以继续使用控制台菜单") def prepare_internal_cmds(self): - @thread_func("控制台执行指令并获取回调", ToolDeltaThread.SYSTEM) - def _execute_mc_command_and_get_callback(cmds: list[str]) -> None: - """执行 Minecraft 指令并获取回调结果。 + @thread_func("控制台执行WO命令", ToolDeltaThread.SYSTEM) + def _execute_wo_command(cmds: list[str]) -> None: + """以控制台身份发送命令。 Args: - cmd (str): 要执行的 Minecraft 指令。 + cmds (list[str]): Minecraft 命令 + """ + if not cmds: + fmts.print_err("命令参数为空") + return + cmd = " ".join(cmds) + self.frame.get_game_control().sendwocmd(cmd) + + @thread_func("控制台执行WS命令并获取返回", ToolDeltaThread.SYSTEM) + def _execute_ws_command_and_get_callback(cmds: list[str]) -> None: + """以 WebSocket 身份发送命令并获取返回。 + + Args: + cmds (list[str]): Minecraft 命令 + """ + if not cmds: + fmts.print_err("命令参数为空") + return + cmd = " ".join(cmds) + try: + result = self.frame.get_game_control().sendwscmd_with_resp(cmd, 5) + msgs_output = [ + mc_translator.translate(o.Message, o.Parameters) + for o in result.OutputMessages + ] + pkt_output = json.dumps(result.as_dict, indent=2, ensure_ascii=False) + msgs_formatted = textwrap.indent("\n".join(msgs_output), " ") + pkt_formatted = textwrap.indent(pkt_output, " ") + if result.SuccessCount: + fmts.print_suc( + f"命令执行成功:\n{msgs_formatted}\n\n命令返回数据包:\n{pkt_formatted}" + ) + else: + if len(result.OutputMessages) > 0 and ( + result.OutputMessages[0].Message + in ("commands.generic.syntax", "commands.generic.unknown") + ): + fmts.print_err( + f"命令执行错误:\n{msgs_formatted}\n\n命令返回数据包:\n{pkt_formatted}" + ) + else: + fmts.print_war( + f"命令执行失败:\n{msgs_formatted}\n\n命令返回数据包:\n{pkt_formatted}" + ) + except TimeoutError: + fmts.print_err(f"获取命令 {cmd} 返回超时") + except Exception as err: + fmts.print_err(f"解析命令 {cmd} 返回时出现未知的错误: {err}") + + @thread_func("控制台执行玩家命令并获取返回", ToolDeltaThread.SYSTEM) + def _execute_command_and_get_callback(cmds: list[str]) -> None: + """以机器人玩家身份发送命令并获取返回。 + + Args: + cmds (list[str]): Minecraft 命令 + """ + if not cmds: + fmts.print_err("命令参数为空") + return + cmd = " ".join(cmds) + try: + result = self.frame.get_game_control().sendcmd_with_resp(cmd, 5) + msgs_output = [ + mc_translator.translate(o.Message, o.Parameters) + for o in result.OutputMessages + ] + pkt_output = json.dumps(result.as_dict, indent=2, ensure_ascii=False) + msgs_formatted = textwrap.indent("\n".join(msgs_output), " ") + pkt_formatted = textwrap.indent(pkt_output, " ") + if result.SuccessCount: + fmts.print_suc( + f"命令执行成功:\n{msgs_formatted}\n\n命令返回数据包:\n{pkt_formatted}" + ) + else: + if len(result.OutputMessages) > 0 and ( + result.OutputMessages[0].Message + in ("commands.generic.syntax", "commands.generic.unknown") + ): + fmts.print_err( + f"命令执行错误:\n{msgs_formatted}\n\n命令返回数据包:\n{pkt_formatted}" + ) + else: + fmts.print_war( + f"命令执行失败:\n{msgs_formatted}\n\n命令返回数据包:\n{pkt_formatted}" + ) + except TimeoutError: + fmts.print_err(f"获取命令 {cmd} 返回超时") + except Exception as err: + fmts.print_err(f"解析命令 {cmd} 返回时出现未知的错误: {err}") - Raises: - ValueError: 当指令执行失败时抛出。 + @thread_func("控制台执行魔法命令并获取返回", ToolDeltaThread.SYSTEM) + def _execute_ai_command_and_get_callback(cmds: list[str]) -> None: + """发送魔法命令并获取返回。 + + Args: + cmds (list[str]): Minecraft 命令 """ + if not cmds: + fmts.print_err("命令参数为空") + return cmd = " ".join(cmds) try: - result = self.frame.get_game_control().sendcmd_with_resp(cmd, 10) - if (result.OutputMessages[0].Message == "commands.generic.syntax") | ( - result.OutputMessages[0].Message == "commands.generic.unknown" - ): - fmts.print_err(f'未知的 MC 指令, 可能是指令格式有误: "{cmd}"') + gc = self.frame.get_game_control() + if hasattr(gc.launcher, "sendaicmd"): + result = gc.sendaicmd_with_resp(cmd, 5) else: - msgs_output = [ - mc_translator.translate(o.Message, o.Parameters) - for o in result.OutputMessages - ] - # if ( - # game_text_handler - # := self.frame.get_game_control().game_data_handler - # ): - # msgs_output = " ".join( - # json.loads(i) - # for i in game_text_handler.Handle_Text_Class1( - # result.as_dict["OutputMessages"] - # ) - # ) - # else: - # msgs_output = json.dumps( - # result.as_dict["OutputMessages"], - # indent=2, - # ensure_ascii=False, - # ) - if result.SuccessCount: - fmts.print_suc("指令执行成功: \n " + "\n ".join(msgs_output)) + fmts.print_war( + "此接入点尚未实现 sendaicmd_with_resp 方法, 无法获取返回结果" + ) + gc.sendaicmd(cmd) + return + msgs_output = [ + mc_translator.translate(o.Message, o.Parameters) + for o in result.OutputMessages + ] + pkt_output = json.dumps(result.as_dict, indent=2, ensure_ascii=False) + msgs_formatted = textwrap.indent("\n".join(msgs_output), " ") + pkt_formatted = textwrap.indent(pkt_output, " ") + if result.SuccessCount: + fmts.print_suc( + f"命令执行成功:\n{msgs_formatted}\n\n命令返回数据包:\n{pkt_formatted}" + ) + else: + if len(result.OutputMessages) > 0 and ( + result.OutputMessages[0].Message + in ("commands.generic.syntax", "commands.generic.unknown") + ): + fmts.print_err( + f"命令执行错误:\n{msgs_formatted}\n\n命令返回数据包:\n{pkt_formatted}" + ) else: - fmts.print_war("指令执行失败: \n " + "\n ".join(msgs_output)) + fmts.print_war( + f"命令执行失败:\n{msgs_formatted}\n\n命令返回数据包:\n{pkt_formatted}" + ) except TimeoutError: - fmts.print_err(f"[超时] 指令获取结果返回超时: {cmd}") + fmts.print_err(f"获取命令 {cmd} 返回超时") + except Exception as err: + fmts.print_err(f"解析命令 {cmd} 返回时出现未知的错误: {err}") def _send_to_neomega(cmds: list[str]): # 仅当启动模式为 neomega 并行模式才生效 @@ -236,23 +337,41 @@ def _exit(_): "进入插件市场", lambda _: plugin_market.market.enter_plugin_market(in_game=True), ) + self.add_console_cmd_trigger( + ["wo/"], + "[命令]", + "以控制台身份发送命令", + lambda args: _execute_wo_command(args) and None, + ) + self.add_console_cmd_trigger( + ["ws/"], + "[命令]", + "以 WebSocket 身份发送命令并获取返回", + lambda args: _execute_ws_command_and_get_callback(args) and None, + ) self.add_console_cmd_trigger( ["/"], - "[指令]", - "执行 MC 指令", - lambda args: _execute_mc_command_and_get_callback(args) and None, + "[命令]", + "以机器人玩家身份发送命令并获取返回", + lambda args: _execute_command_and_get_callback(args) and None, + ) + self.add_console_cmd_trigger( + ["ai/"], + "[命令]", + "发送魔法命令并获取返回", + lambda args: _execute_ai_command_and_get_callback(args) and None, ) self.add_console_cmd_trigger(["list"], None, "查询在线玩家", _list) self.add_console_cmd_trigger( ["reload"], None, - "浅重载插件 (重载插件的__init__.py, 可能有部分特殊插件无法重载)", + "浅重载插件 (重载插件的__init__.py, 可能有部分特殊插件无法重载, 建议一般情况时使用)", lambda _: self.frame.reload(deep_reload=False), ) self.add_console_cmd_trigger( ["deepreload"], None, - "深重载插件 (重载整个插件模块, 可能导致某些进程被强制清除, 建议开发时使用)", + "深重载插件 (重载整个插件模块, 可能导致某些进程被强制清除, 建议插件开发时使用)", lambda _: self.frame.reload(deep_reload=True), ) if isinstance(self.frame.launcher, FrameNeOmegaLauncher): diff --git a/tooldelta/internal/launch_cli/fateark_access_point.py b/tooldelta/internal/launch_cli/fateark_access_point.py index 5a9bc336..a01bfeb5 100644 --- a/tooldelta/internal/launch_cli/fateark_access_point.py +++ b/tooldelta/internal/launch_cli/fateark_access_point.py @@ -1,12 +1,11 @@ import os import subprocess -from collections.abc import Callable import time from grpc import RpcError import grpc from ... import utils -from ...constants import SysStatus, PacketIDS +from ...constants import SysStatus from ...internal.types import Packet_CommandOutput from ...mc_bytes_packet import base_bytes_packet, pool from ...utils import fmts, urlmethod, sys_args @@ -20,7 +19,6 @@ class FrameFateArk(StandardFrame): def __init__(self) -> None: super().__init__() self.bot_name = "" - self.command_output_cbs: dict[str, Callable] = {} def init(self) -> None: if "no-download-libs" not in sys_args.sys_args_to_dict().keys(): @@ -187,17 +185,8 @@ def _packets_handler(self, pkID: int, pk: dict | base_bytes_packet.BaseBytesPack if isinstance(pk, base_bytes_packet.BaseBytesPacket): self.bytes_packet_handler(pkID, pk) else: - if pkID == PacketIDS.CommandOutput: - self._command_output_handler(pk) self.dict_packet_handler(pkID, pk) - def _command_output_handler(self, pk: dict): - pkUUID = utils.basic.validate_uuid(pk["CommandOrigin"]["UUID"]) - if pkUUID in self.command_output_cbs: - self.command_output_cbs[pkUUID](pk) - # else: - # fmts.print_war(f"命令没有对应回调: {pkUUID}") - def _safe_exit(self): self.kill_proc() @@ -208,41 +197,51 @@ def check_avaliable(self): if self.status != SysStatus.RUNNING: raise ValueError("未连接到游戏") - def sendcmd( + def sendwocmd(self, cmd: str): + self.check_avaliable() + fateark_core.send_wo_command(cmd) + + def sendwscmd( self, cmd: str, waitForResp: bool = False, timeout: float = 30 ) -> Packet_CommandOutput | None: self.check_avaliable() if waitForResp: - ud = fateark_core.sendcmd_and_get_uuid(cmd) - getter, setter = utils.create_result_cb(dict) - self.command_output_cbs[ud] = setter - res = getter(timeout) - if res is None: - raise TimeoutError("指令超时", ud) - return Packet_CommandOutput(res) - else: - fateark_core.sendcmd_and_get_uuid(cmd) - return None + co, err = fateark_core.send_ws_command_with_response(cmd, timeout) + if err == "timeout": + raise TimeoutError(f"获取命令 {cmd} 返回超时") + elif err != "": + raise Exception(f"执行命令 {cmd} 时出现未知的错误: {err}") + return Packet_CommandOutput(co) + fateark_core.send_ws_command(cmd) + return None - def sendwscmd( + def sendcmd( self, cmd: str, waitForResp: bool = False, timeout: float = 30 ) -> Packet_CommandOutput | None: self.check_avaliable() if waitForResp: - ud = fateark_core.sendwscmd_and_get_uuid(cmd) - getter, setter = utils.create_result_cb(dict) - self.command_output_cbs[ud] = setter - res = getter(timeout) - if res is None: - raise TimeoutError("指令超时", ud) - return Packet_CommandOutput(res) - else: - fateark_core.sendwscmd_and_get_uuid(cmd) - return None + co, err = fateark_core.send_player_command_with_response(cmd, timeout) + if err == "timeout": + raise TimeoutError(f"获取命令 {cmd} 返回超时") + elif err != "": + raise Exception(f"执行命令 {cmd} 时出现未知的错误: {err}") + return Packet_CommandOutput(co) + fateark_core.send_player_command(cmd) + return None - def sendwocmd(self, cmd: str): + def sendaicmd( + self, cmd: str, waitForResp: bool = False, timeout: float = 30 + ) -> Packet_CommandOutput | None: self.check_avaliable() - fateark_core.sendwocmd(cmd) + if waitForResp: + co, err = fateark_core.send_ai_command_with_response(cmd, timeout) + if err == "timeout": + raise TimeoutError(f"获取命令 {cmd} 返回超时") + elif err != "": + raise Exception(f"执行命令 {cmd} 时出现未知的错误: {err}") + return Packet_CommandOutput(co) + fateark_core.send_ai_command(cmd) + return None def sendPacket( self, pkID: int, pk: dict | base_bytes_packet.BaseBytesPacket diff --git a/tooldelta/internal/launch_cli/fateark_libs/core_conn.py b/tooldelta/internal/launch_cli/fateark_libs/core_conn.py index 869e7531..850b546b 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/core_conn.py +++ b/tooldelta/internal/launch_cli/fateark_libs/core_conn.py @@ -7,22 +7,25 @@ from ....internal.types import UnreadyPlayer, Abilities from ....mc_bytes_packet.pool import is_bytes_packet -utils_pb2 = importlib.import_module(".proto.utils_pb2", package=__package__) -reversaler_pb2 = importlib.import_module(".proto.reversaler_pb2", package=__package__) +command_pb2 = importlib.import_module(".proto.command_pb2", package=__package__) listener_pb2 = importlib.import_module(".proto.listener_pb2", package=__package__) playerkit_pb2 = importlib.import_module(".proto.playerkit_pb2", package=__package__) +reversaler_pb2 = importlib.import_module(".proto.reversaler_pb2", package=__package__) +utils_pb2 = importlib.import_module(".proto.utils_pb2", package=__package__) +from .proto.command_pb2_grpc import CommandServiceStub from .proto.listener_pb2_grpc import ListenerServiceStub +from .proto.playerkit_pb2_grpc import PlayerKitServiceStub from .proto.reversaler_pb2_grpc import FateReversalerServiceStub from .proto.utils_pb2_grpc import UtilsServiceStub -from .proto.playerkit_pb2_grpc import PlayerKitServiceStub grpc_con: grpc.Channel | None = None -utils_stub: UtilsServiceStub | None = None +command_stub: CommandServiceStub | None = None listener_stub: ListenerServiceStub | None = None playerkit_stub: PlayerKitServiceStub | None = None core_stub: FateReversalerServiceStub | None = None +utils_stub: UtilsServiceStub | None = None listen_packets: set[int] = set() @@ -34,17 +37,11 @@ def get_grpc_con(): return grpc_con -def get_core_stub(): - global core_stub - if core_stub is None: +def get_command_stub(): + global command_stub + if command_stub is None: raise Exception("在建立连接前调用") - return core_stub - -def get_utils_stub(): - global utils_stub - if utils_stub is None: - raise Exception("在建立连接前调用") - return utils_stub + return command_stub def get_listener_stub(): @@ -61,22 +58,40 @@ def get_playerkit_stub(): return playerkit_stub +def get_core_stub(): + global core_stub + if core_stub is None: + raise Exception("在建立连接前调用") + return core_stub + + +def get_utils_stub(): + global utils_stub + if utils_stub is None: + raise Exception("在建立连接前调用") + return utils_stub + + def connect(address: str) -> None: - global grpc_con, listener_stub, playerkit_stub, utils_stub, core_stub + global grpc_con, command_stub, listener_stub, playerkit_stub, core_stub, utils_stub grpc_con = grpc.insecure_channel(address) - utils_stub = UtilsServiceStub(grpc_con) + command_stub = CommandServiceStub(grpc_con) listener_stub = ListenerServiceStub(grpc_con) playerkit_stub = PlayerKitServiceStub(grpc_con) core_stub = FateReversalerServiceStub(grpc_con) + utils_stub = UtilsServiceStub(grpc_con) + def wait_dead(): wait_dead_request = reversaler_pb2.WaitDeadRequest() res = next(get_core_stub().WaitDead(wait_dead_request)) return res.reason + def ping(): return get_core_stub().Ping(reversaler_pb2.PingRequest()).success + def login( auth_server: str, fbtoken: str, @@ -109,7 +124,8 @@ def read_packet(): pk_payload: str = packet.payload if pk_payload == "": continue - yield packet.id, json.loads(packet.payload) + yield packet.id, json.loads(pk_payload) + def read_bytes_packet(): for packet in get_listener_stub().ListenBytesPackets( @@ -120,6 +136,7 @@ def read_bytes_packet(): continue yield packet.id, pk_payload + def sendPacket(pkID: int, pk: dict): get_utils_stub().SendPacket( utils_pb2.SendPacketRequest( @@ -147,51 +164,56 @@ def set_listen_packets(pkIDs: set[int]): listen_packets.add(i) -def sendcmd_and_get_uuid(cmd: str): - ud = str(uuid.uuid4()) - sendPacket( - constants.PacketIDS.CommandRequest, - { - "CommandLine": cmd, - "CommandOrigin": { - "Origin": 0, - "UUID": ud, - "RequestID": ud, - "PlayerUniqueID": 0, - }, - "Internal": False, - "Version": constants.minecraft.COMMAND_VERSION, - "UnLimited": False, - }, +def send_wo_command(cmd: str): + get_command_stub().SendWOCommand(command_pb2.SendWOCommandRequest(cmd=cmd)) + + +def send_ws_command(cmd: str): + get_command_stub().SendWSCommand(command_pb2.SendWSCommandRequest(cmd=cmd)) + + +def send_player_command(cmd: str): + get_command_stub().SendPlayerCommand(command_pb2.SendPlayerCommandRequest(cmd=cmd)) + + +def send_ai_command(cmd: str): + get_command_stub().SendAICommand(command_pb2.SendAICommandRequest(cmd=cmd)) + + +def send_ws_command_with_response(cmd: str, timeout: float): + res = get_command_stub().SendWSCommandWithResponse( + command_pb2.SendWSCommandWithResponseRequest(cmd=cmd, timeout=timeout) ) - return ud - - -def sendwscmd_and_get_uuid(cmd: str): - ud = str(uuid.uuid4()) - sendPacket( - constants.PacketIDS.CommandRequest, - { - "CommandLine": cmd, - "CommandOrigin": { - "Origin": 5, - "UUID": ud, - "RequestID": ud, - "PlayerUniqueID": 0, - }, - "Internal": False, - "Version": constants.minecraft.COMMAND_VERSION, - "UnLimited": False, - }, + res_status: int = res.status + res_payload: str = res.payload + res_error_msg: str = res.error_msg + if res_status == 0: + return json.loads(res_payload), "" + return {}, res_error_msg + + +def send_player_command_with_response(cmd: str, timeout: float): + res = get_command_stub().SendPlayerCommandWithResponse( + command_pb2.SendPlayerCommandWithResponseRequest(cmd=cmd, timeout=timeout) ) - return ud + res_status: int = res.status + res_payload: str = res.payload + res_error_msg: str = res.error_msg + if res_status == 0: + return json.loads(res_payload), "" + return {}, res_error_msg -def sendwocmd(cmd: str): - sendPacket( - constants.PacketIDS.SettingsCommand, - {"CommandLine": cmd, "SuppressOutput": False}, +def send_ai_command_with_response(cmd: str, timeout: float): + res = get_command_stub().SendAICommandWithResponse( + command_pb2.SendAICommandWithResponseRequest(cmd=cmd, timeout=timeout) ) + res_status: int = res.status + res_payload: str = res.payload + res_error_msg: str = res.error_msg + if res_status == 0: + return json.loads(res_payload), "" + return {}, res_error_msg def get_online_player_uuids() -> list[str]: diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/builder.py b/tooldelta/internal/launch_cli/fateark_libs/proto/builder.py index 2008589b..62a2ad12 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/builder.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/builder.py @@ -1,18 +1,23 @@ +import subprocess import os import sys from pathlib import Path -PROTOC_PATH = Path( - "C:/Users/25286/AppData/Local/Programs/Python/Python311/Lib/site-packages/grpc_tools/protoc.py" -) +PYTHON_ROOT_PATH = Path(sys.prefix) +PROTOC_PATH = PYTHON_ROOT_PATH / Path("Lib/site-packages/grpc_tools/protoc.py") this_dir = Path(os.path.dirname(__file__)) for file in os.listdir(this_dir / "proto"): if file.endswith(".proto"): - os.system( - f"{sys.executable} {PROTOC_PATH} --python_out={os.path.dirname(this_dir)} --grpc_python_out={os.path.dirname(this_dir)} -I {this_dir} {this_dir / 'proto' / file}" - ) + subprocess.run([ + sys.executable, + str(PROTOC_PATH), + f"--python_out={this_dir.parent}", + f"--grpc_python_out={this_dir.parent}", + "-I", str(this_dir), + str(this_dir / "proto" / file) + ], check=True) for file in os.listdir(this_dir): if file.endswith(".py") and file != "builder.py": diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/command_pb2.py b/tooldelta/internal/launch_cli/fateark_libs/proto/command_pb2.py index 0026327b..23059449 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/command_pb2.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/command_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: proto/command.proto -# Protobuf Python Version: 6.31.0 +# Protobuf Python Version: 6.31.1 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 6, 31, - 0, + 1, '', 'proto/command.proto' ) @@ -25,7 +25,7 @@ from . import response_pb2 as proto_dot_response__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13proto/command.proto\x12\x15\x66\x61teark.proto.command\x1a\x14proto/response.proto\"#\n\x14SendWOCommandRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\"#\n\x14SendWSCommandRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\"\'\n\x18SendPlayerCommandRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\"7\n\x14SendAICommandRequest\x12\x12\n\nruntime_id\x18\x01 \x01(\t\x12\x0b\n\x03\x63md\x18\x02 \x01(\t\"/\n SendWSCommandWithResponseRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\"3\n$SendPlayerCommandWithResponseRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\"C\n SendAICommandWithResponseRequest\x12\x12\n\nruntime_id\x18\x01 \x01(\t\x12\x0b\n\x03\x63md\x18\x02 \x01(\t2\xba\x06\n\x0e\x43ommandService\x12\x65\n\rSendWOCommand\x12+.fateark.proto.command.SendWOCommandRequest\x1a\'.fateark.proto.response.GeneralResponse\x12\x65\n\rSendWSCommand\x12+.fateark.proto.command.SendWSCommandRequest\x1a\'.fateark.proto.response.GeneralResponse\x12m\n\x11SendPlayerCommand\x12/.fateark.proto.command.SendPlayerCommandRequest\x1a\'.fateark.proto.response.GeneralResponse\x12\x65\n\rSendAICommand\x12+.fateark.proto.command.SendAICommandRequest\x1a\'.fateark.proto.response.GeneralResponse\x12}\n\x19SendWSCommandWithResponse\x12\x37.fateark.proto.command.SendWSCommandWithResponseRequest\x1a\'.fateark.proto.response.GeneralResponse\x12\x85\x01\n\x1dSendPlayerCommandWithResponse\x12;.fateark.proto.command.SendPlayerCommandWithResponseRequest\x1a\'.fateark.proto.response.GeneralResponse\x12}\n\x19SendAICommandWithResponse\x12\x37.fateark.proto.command.SendAICommandWithResponseRequest\x1a\'.fateark.proto.response.GeneralResponseB\x1fZ\x1dnetwork_api/command;commandpbb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13proto/command.proto\x12\x15\x66\x61teark.proto.command\x1a\x14proto/response.proto\"#\n\x14SendWOCommandRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\"#\n\x14SendWSCommandRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\"\'\n\x18SendPlayerCommandRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\"#\n\x14SendAICommandRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\"@\n SendWSCommandWithResponseRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\x12\x0f\n\x07timeout\x18\x02 \x01(\x01\"D\n$SendPlayerCommandWithResponseRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\x12\x0f\n\x07timeout\x18\x02 \x01(\x01\"@\n SendAICommandWithResponseRequest\x12\x0b\n\x03\x63md\x18\x01 \x01(\t\x12\x0f\n\x07timeout\x18\x02 \x01(\x01\x32\xba\x06\n\x0e\x43ommandService\x12\x65\n\rSendWOCommand\x12+.fateark.proto.command.SendWOCommandRequest\x1a\'.fateark.proto.response.GeneralResponse\x12\x65\n\rSendWSCommand\x12+.fateark.proto.command.SendWSCommandRequest\x1a\'.fateark.proto.response.GeneralResponse\x12m\n\x11SendPlayerCommand\x12/.fateark.proto.command.SendPlayerCommandRequest\x1a\'.fateark.proto.response.GeneralResponse\x12\x65\n\rSendAICommand\x12+.fateark.proto.command.SendAICommandRequest\x1a\'.fateark.proto.response.GeneralResponse\x12}\n\x19SendWSCommandWithResponse\x12\x37.fateark.proto.command.SendWSCommandWithResponseRequest\x1a\'.fateark.proto.response.GeneralResponse\x12\x85\x01\n\x1dSendPlayerCommandWithResponse\x12;.fateark.proto.command.SendPlayerCommandWithResponseRequest\x1a\'.fateark.proto.response.GeneralResponse\x12}\n\x19SendAICommandWithResponse\x12\x37.fateark.proto.command.SendAICommandWithResponseRequest\x1a\'.fateark.proto.response.GeneralResponseB\x1fZ\x1dnetwork_api/command;commandpbb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -40,13 +40,13 @@ _globals['_SENDPLAYERCOMMANDREQUEST']._serialized_start=142 _globals['_SENDPLAYERCOMMANDREQUEST']._serialized_end=181 _globals['_SENDAICOMMANDREQUEST']._serialized_start=183 - _globals['_SENDAICOMMANDREQUEST']._serialized_end=238 - _globals['_SENDWSCOMMANDWITHRESPONSEREQUEST']._serialized_start=240 - _globals['_SENDWSCOMMANDWITHRESPONSEREQUEST']._serialized_end=287 - _globals['_SENDPLAYERCOMMANDWITHRESPONSEREQUEST']._serialized_start=289 - _globals['_SENDPLAYERCOMMANDWITHRESPONSEREQUEST']._serialized_end=340 - _globals['_SENDAICOMMANDWITHRESPONSEREQUEST']._serialized_start=342 - _globals['_SENDAICOMMANDWITHRESPONSEREQUEST']._serialized_end=409 - _globals['_COMMANDSERVICE']._serialized_start=412 - _globals['_COMMANDSERVICE']._serialized_end=1238 + _globals['_SENDAICOMMANDREQUEST']._serialized_end=218 + _globals['_SENDWSCOMMANDWITHRESPONSEREQUEST']._serialized_start=220 + _globals['_SENDWSCOMMANDWITHRESPONSEREQUEST']._serialized_end=284 + _globals['_SENDPLAYERCOMMANDWITHRESPONSEREQUEST']._serialized_start=286 + _globals['_SENDPLAYERCOMMANDWITHRESPONSEREQUEST']._serialized_end=354 + _globals['_SENDAICOMMANDWITHRESPONSEREQUEST']._serialized_start=356 + _globals['_SENDAICOMMANDWITHRESPONSEREQUEST']._serialized_end=420 + _globals['_COMMANDSERVICE']._serialized_start=423 + _globals['_COMMANDSERVICE']._serialized_end=1249 # @@protoc_insertion_point(module_scope) diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/command_pb2_grpc.py b/tooldelta/internal/launch_cli/fateark_libs/proto/command_pb2_grpc.py index a8ceb0a1..903583c9 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/command_pb2_grpc.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/command_pb2_grpc.py @@ -6,7 +6,7 @@ from . import command_pb2 as proto_dot_command__pb2 from . import response_pb2 as proto_dot_response__pb2 -GRPC_GENERATED_VERSION = '1.73.0' +GRPC_GENERATED_VERSION = '1.78.1' GRPC_VERSION = grpc.__version__ _version_not_supported = False @@ -19,7 +19,7 @@ if _version_not_supported: raise RuntimeError( f'The grpc package installed is at version {GRPC_VERSION},' - + f' but the generated code in proto/command_pb2_grpc.py depends on' + + ' but the generated code in proto/command_pb2_grpc.py depends on' + f' grpcio>={GRPC_GENERATED_VERSION}.' + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/listener_pb2.py b/tooldelta/internal/launch_cli/fateark_libs/proto/listener_pb2.py index 54856a9d..82d4403c 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/listener_pb2.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/listener_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: proto/listener.proto -# Protobuf Python Version: 6.31.0 +# Protobuf Python Version: 6.31.1 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 6, 31, - 0, + 1, '', 'proto/listener.proto' ) diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/listener_pb2_grpc.py b/tooldelta/internal/launch_cli/fateark_libs/proto/listener_pb2_grpc.py index 35d52fe2..cf32d848 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/listener_pb2_grpc.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/listener_pb2_grpc.py @@ -6,7 +6,7 @@ from . import listener_pb2 as proto_dot_listener__pb2 from . import response_pb2 as proto_dot_response__pb2 -GRPC_GENERATED_VERSION = '1.73.0' +GRPC_GENERATED_VERSION = '1.78.1' GRPC_VERSION = grpc.__version__ _version_not_supported = False @@ -19,7 +19,7 @@ if _version_not_supported: raise RuntimeError( f'The grpc package installed is at version {GRPC_VERSION},' - + f' but the generated code in proto/listener_pb2_grpc.py depends on' + + ' but the generated code in proto/listener_pb2_grpc.py depends on' + f' grpcio>={GRPC_GENERATED_VERSION}.' + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/playerkit_pb2.py b/tooldelta/internal/launch_cli/fateark_libs/proto/playerkit_pb2.py index dfc69c39..d5a385a3 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/playerkit_pb2.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/playerkit_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: proto/playerkit.proto -# Protobuf Python Version: 6.31.0 +# Protobuf Python Version: 6.31.1 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 6, 31, - 0, + 1, '', 'proto/playerkit.proto' ) diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/playerkit_pb2_grpc.py b/tooldelta/internal/launch_cli/fateark_libs/proto/playerkit_pb2_grpc.py index 79e60df1..6f234ae9 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/playerkit_pb2_grpc.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/playerkit_pb2_grpc.py @@ -6,7 +6,7 @@ from . import playerkit_pb2 as proto_dot_playerkit__pb2 from . import response_pb2 as proto_dot_response__pb2 -GRPC_GENERATED_VERSION = '1.73.0' +GRPC_GENERATED_VERSION = '1.78.1' GRPC_VERSION = grpc.__version__ _version_not_supported = False @@ -19,7 +19,7 @@ if _version_not_supported: raise RuntimeError( f'The grpc package installed is at version {GRPC_VERSION},' - + f' but the generated code in proto/playerkit_pb2_grpc.py depends on' + + ' but the generated code in proto/playerkit_pb2_grpc.py depends on' + f' grpcio>={GRPC_GENERATED_VERSION}.' + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/proto/command.proto b/tooldelta/internal/launch_cli/fateark_libs/proto/proto/command.proto index 4fb8ac92..ec9cf9c0 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/proto/command.proto +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/proto/command.proto @@ -12,18 +12,21 @@ message SendWSCommandRequest { string cmd = 1; } message SendPlayerCommandRequest { string cmd = 1; } -message SendAICommandRequest { - string runtime_id = 1; - string cmd = 2; -} +message SendAICommandRequest { string cmd = 1; } -message SendWSCommandWithResponseRequest { string cmd = 1; } +message SendWSCommandWithResponseRequest { + string cmd = 1; + double timeout = 2; +} -message SendPlayerCommandWithResponseRequest { string cmd = 1; } +message SendPlayerCommandWithResponseRequest { + string cmd = 1; + double timeout = 2; +} message SendAICommandWithResponseRequest { - string runtime_id = 1; - string cmd = 2; + string cmd = 1; + double timeout = 2; } service CommandService { diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/response_pb2.py b/tooldelta/internal/launch_cli/fateark_libs/proto/response_pb2.py index 4302a893..e13d662b 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/response_pb2.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/response_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: proto/response.proto -# Protobuf Python Version: 6.31.0 +# Protobuf Python Version: 6.31.1 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 6, 31, - 0, + 1, '', 'proto/response.proto' ) diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/response_pb2_grpc.py b/tooldelta/internal/launch_cli/fateark_libs/proto/response_pb2_grpc.py index 86d4c9f4..5b1773d8 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/response_pb2_grpc.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/response_pb2_grpc.py @@ -4,7 +4,7 @@ import warnings -GRPC_GENERATED_VERSION = '1.73.0' +GRPC_GENERATED_VERSION = '1.78.1' GRPC_VERSION = grpc.__version__ _version_not_supported = False @@ -17,7 +17,7 @@ if _version_not_supported: raise RuntimeError( f'The grpc package installed is at version {GRPC_VERSION},' - + f' but the generated code in proto/response_pb2_grpc.py depends on' + + ' but the generated code in proto/response_pb2_grpc.py depends on' + f' grpcio>={GRPC_GENERATED_VERSION}.' + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/reversaler_pb2.py b/tooldelta/internal/launch_cli/fateark_libs/proto/reversaler_pb2.py index 4ac66483..4f5b69d9 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/reversaler_pb2.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/reversaler_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: proto/reversaler.proto -# Protobuf Python Version: 6.31.0 +# Protobuf Python Version: 6.31.1 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 6, 31, - 0, + 1, '', 'proto/reversaler.proto' ) diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/reversaler_pb2_grpc.py b/tooldelta/internal/launch_cli/fateark_libs/proto/reversaler_pb2_grpc.py index 40b6a80e..32c7e3b4 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/reversaler_pb2_grpc.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/reversaler_pb2_grpc.py @@ -6,7 +6,7 @@ from . import response_pb2 as proto_dot_response__pb2 from . import reversaler_pb2 as proto_dot_reversaler__pb2 -GRPC_GENERATED_VERSION = '1.73.0' +GRPC_GENERATED_VERSION = '1.78.1' GRPC_VERSION = grpc.__version__ _version_not_supported = False @@ -19,7 +19,7 @@ if _version_not_supported: raise RuntimeError( f'The grpc package installed is at version {GRPC_VERSION},' - + f' but the generated code in proto/reversaler_pb2_grpc.py depends on' + + ' but the generated code in proto/reversaler_pb2_grpc.py depends on' + f' grpcio>={GRPC_GENERATED_VERSION}.' + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/utils_pb2.py b/tooldelta/internal/launch_cli/fateark_libs/proto/utils_pb2.py index 88e0db33..c7581547 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/utils_pb2.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/utils_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: proto/utils.proto -# Protobuf Python Version: 6.31.0 +# Protobuf Python Version: 6.31.1 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -13,7 +13,7 @@ _runtime_version.Domain.PUBLIC, 6, 31, - 0, + 1, '', 'proto/utils.proto' ) diff --git a/tooldelta/internal/launch_cli/fateark_libs/proto/utils_pb2_grpc.py b/tooldelta/internal/launch_cli/fateark_libs/proto/utils_pb2_grpc.py index 15fd4dcd..00a6010e 100644 --- a/tooldelta/internal/launch_cli/fateark_libs/proto/utils_pb2_grpc.py +++ b/tooldelta/internal/launch_cli/fateark_libs/proto/utils_pb2_grpc.py @@ -6,7 +6,7 @@ from . import response_pb2 as proto_dot_response__pb2 from . import utils_pb2 as proto_dot_utils__pb2 -GRPC_GENERATED_VERSION = '1.73.0' +GRPC_GENERATED_VERSION = '1.78.1' GRPC_VERSION = grpc.__version__ _version_not_supported = False @@ -19,7 +19,7 @@ if _version_not_supported: raise RuntimeError( f'The grpc package installed is at version {GRPC_VERSION},' - + f' but the generated code in proto/utils_pb2_grpc.py depends on' + + ' but the generated code in proto/utils_pb2_grpc.py depends on' + f' grpcio>={GRPC_GENERATED_VERSION}.' + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'