diff --git a/BasaltTrainer/cmd_server.py b/BasaltTrainer/cmd_server.py index 5da2b9d..5f03fe0 100644 --- a/BasaltTrainer/cmd_server.py +++ b/BasaltTrainer/cmd_server.py @@ -26,9 +26,18 @@ class PixelKind(IntEnum): @dataclass class HandshakePayload: + headless: bool pixel_kind: PixelKind width: int height: int + engine_name: str + engine_device: int + deliver_name: str + deliver_device: int + object_loader_name: str + object_loader_file: str + anime_loader_name: str + anime_loader_file: str class ServerStatus(Enum): @@ -38,7 +47,9 @@ class ServerStatus(Enum): CODE_PACKER: struct.Struct = struct.Struct("=B") -HANDSHAKE_REQUEST_PACKER: struct.Struct = struct.Struct("=BII") +U8_PACKER: struct.Struct = struct.Struct("=B") +U32_PACKER: struct.Struct = struct.Struct("=I") +USIZE_PACKER: struct.Struct = struct.Struct("=N") class CmdServer: @@ -66,17 +77,23 @@ class CmdServer: raise RuntimeError("unexpected server status") # Send handshake request to Presenter - self.__pipe_operator.write(CODE_PACKER.pack(ProtocolCode.HANDSHAKE_REQUEST)) + self.__pipe_operator.write_pod(CODE_PACKER, ProtocolCode.HANDSHAKE_REQUEST) # And the payload data - self.__pipe_operator.write( - HANDSHAKE_REQUEST_PACKER.pack( - payload.pixel_kind, payload.width, payload.height - ) - ) + self.__pipe_operator.write_pod(U8_PACKER, 1 if payload.headless else 0) + self.__pipe_operator.write_pod(U8_PACKER, payload.pixel_kind) + self.__pipe_operator.write_pod(U32_PACKER, payload.width) + self.__pipe_operator.write_pod(U32_PACKER, payload.height) + self.__pipe_operator.write_bsstring(payload.engine_name) + self.__pipe_operator.write_pod(USIZE_PACKER, payload.engine_device) + self.__pipe_operator.write_bsstring(payload.deliver_name) + self.__pipe_operator.write_pod(USIZE_PACKER, payload.deliver_device) + self.__pipe_operator.write_bsstring(payload.object_loader_name) + self.__pipe_operator.write_bsstring(payload.object_loader_file) + self.__pipe_operator.write_bsstring(payload.anime_loader_name) + self.__pipe_operator.write_bsstring(payload.anime_loader_file) # Wait for handshake response from Presenter (code 0x62) - code_bytes = self.__pipe_operator.read(CODE_PACKER.size) - (code,) = CODE_PACKER.unpack(code_bytes) + (code,) = self.__pipe_operator.read_pod(CODE_PACKER) if ProtocolCode(code) != ProtocolCode.HANDSHAKE_RESPONSE: raise RuntimeError("expect handshake response code, but got another") @@ -95,12 +112,11 @@ class CmdServer: # If there is stop requested from us, # we order Presenter exit and enter next step. if request_stop: - self.__pipe_operator.write(CODE_PACKER.pack(ProtocolCode.STOP_REQUEST)) + self.__pipe_operator.write_pod(CODE_PACKER, ProtocolCode.STOP_REQUEST) while True: # Wait for code from Presenter - code_bytes = self.__pipe_operator.read(CODE_PACKER.size) - (code,) = CODE_PACKER.unpack(code_bytes) + (code,) = self.__pipe_operator.read_pod(CODE_PACKER) # Analyse code match ProtocolCode(code): @@ -108,15 +124,15 @@ class CmdServer: # Receive data data_receiver() # Send data received symbol - self.__pipe_operator.write( - CODE_PACKER.pack(ProtocolCode.DATA_RECEIVED) + self.__pipe_operator.write_pod( + CODE_PACKER, ProtocolCode.DATA_RECEIVED ) return False case ProtocolCode.ACTIVELY_STOP: # Presenter requested stop. # Agree with it, send code and wait response - self.__pipe_operator.write( - CODE_PACKER.pack(ProtocolCode.STOP_REQUEST) + self.__pipe_operator.write_pod( + CODE_PACKER, ProtocolCode.STOP_REQUEST ) case ProtocolCode.STOP_RESPONSE: # Set self status and return diff --git a/BasaltTrainer/main.py b/BasaltTrainer/main.py index 3fd2635..ffbd224 100644 --- a/BasaltTrainer/main.py +++ b/BasaltTrainer/main.py @@ -15,7 +15,20 @@ def main(): input() logging.info("Waiting BasaltPresenter...") - server.wait_handshake(HandshakePayload(PixelKind.GRAY_U8, 600, 600)) + server.wait_handshake(HandshakePayload( + headless=False, + pixel_kind=PixelKind.GRAY_U8, + width=600, + height=600, + engine_name="BasaltDirectX11Engine", + engine_device=0, + deliver_name="BasaltPipeDeliver", + deliver_device=0, + object_loader_name="BasaltObjObjectLoader", + object_loader_file="", + anime_loader_name="BasaltChickenNuggetAnimeLoader", + anime_loader_file="", + )) logging.info("Start to running.") STOPPER.register() diff --git a/BasaltTrainer/pipe_operator.py b/BasaltTrainer/pipe_operator.py index 1236b67..4b7fe74 100644 --- a/BasaltTrainer/pipe_operator.py +++ b/BasaltTrainer/pipe_operator.py @@ -1,8 +1,10 @@ import os import sys -from typing import Optional, Any +import struct +from typing import Optional, Any, ClassVar IS_WINDOWS: bool = sys.platform == "win32" +IS_LITTLE_ENDIAN: bool = sys.byteorder == "little" if IS_WINDOWS: import win32pipe @@ -151,3 +153,43 @@ class PipeOperator: total_written += bytes_written except OSError as e: raise RuntimeError(f"Failed to write to named pipe: {e}") + + def read_pod(self, pattern: struct.Struct) -> tuple[Any, ...]: + return pattern.unpack(self.read(pattern.size)) + + def write_pod(self, pattern: struct.Struct, *args) -> None: + self.write(pattern.pack(*args)) + + STR_LEN_PACKER: ClassVar[struct.Struct] = struct.Struct("=N") + + def read_string(self) -> str: + (length,) = self.read_pod(PipeOperator.STR_LEN_PACKER) + str_bytes = self.read(length) + return str_bytes.decode("utf-8") + + def write_string(self, s: str) -> None: + str_bytes = s.encode("utf-8") + self.write_pod(PipeOperator.STR_LEN_PACKER, len(str_bytes)) + self.write(str_bytes) + + def read_bsstring(self) -> str: + (length,) = self.read_pod(PipeOperator.STR_LEN_PACKER) + str_bytes = self.read(length) + return self.__decode_bsstring(str_bytes) + + def write_bsstring(self, s: str) -> None: + str_bytes = self.__encode_bsstring(s) + self.write_pod(PipeOperator.STR_LEN_PACKER, len(str_bytes)) + self.write(str_bytes) + + def __encode_bsstring(self, s: str) -> bytes: + if IS_LITTLE_ENDIAN: + return s.encode("utf_16_le") + else: + return s.encode("utf_16_be") + + def __decode_bsstring(self, b: bytes) -> str: + if IS_LITTLE_ENDIAN: + return b.decode("utf_16_le") + else: + return b.decode("utf_16_be")