|
|
|
|
|
|
# If true, this means the environment was successfully loaded |
|
|
|
self._loaded = False |
|
|
|
# The process that is started. If None, no process was started |
|
|
|
self._proc1 = None |
|
|
|
self._process: Optional[subprocess.Popen] = None |
|
|
|
self._timeout_wait: int = timeout_wait |
|
|
|
self._communicator = self._get_communicator(worker_id, base_port, timeout_wait) |
|
|
|
self._worker_id = worker_id |
|
|
|
|
|
|
) |
|
|
|
if file_name is not None: |
|
|
|
try: |
|
|
|
self._proc1 = env_utils.launch_executable( |
|
|
|
self._process = env_utils.launch_executable( |
|
|
|
file_name, self._executable_args() |
|
|
|
) |
|
|
|
except UnityEnvironmentException: |
|
|
|
|
|
|
if self._no_graphics: |
|
|
|
args += ["-nographics", "-batchmode"] |
|
|
|
args += [UnityEnvironment._PORT_COMMAND_LINE_ARG, str(self._port)] |
|
|
|
if self._log_folder: |
|
|
|
|
|
|
|
# If the logfile arg isn't already set in the env args, |
|
|
|
# try to set it to an output directory |
|
|
|
logfile_set = "-logfile" in (arg.lower() for arg in self._additional_args) |
|
|
|
if self._log_folder and not logfile_set: |
|
|
|
log_file_path = os.path.join( |
|
|
|
self._log_folder, f"Player-{self._worker_id}.log" |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
def reset(self) -> None: |
|
|
|
if self._loaded: |
|
|
|
outputs = self._communicator.exchange(self._generate_reset_input()) |
|
|
|
outputs = self._communicator.exchange( |
|
|
|
self._generate_reset_input(), self._poll_process |
|
|
|
) |
|
|
|
if outputs is None: |
|
|
|
raise UnityCommunicatorStoppedException("Communicator has exited.") |
|
|
|
self._update_behavior_specs(outputs) |
|
|
|
|
|
|
].action_spec.empty_action(n_agents) |
|
|
|
step_input = self._generate_step_input(self._env_actions) |
|
|
|
with hierarchical_timer("communicator.exchange"): |
|
|
|
outputs = self._communicator.exchange(step_input) |
|
|
|
outputs = self._communicator.exchange(step_input, self._poll_process) |
|
|
|
if outputs is None: |
|
|
|
raise UnityCommunicatorStoppedException("Communicator has exited.") |
|
|
|
self._update_behavior_specs(outputs) |
|
|
|
|
|
|
self._assert_behavior_exists(behavior_name) |
|
|
|
return self._env_state[behavior_name] |
|
|
|
|
|
|
|
def _poll_process(self) -> None: |
|
|
|
""" |
|
|
|
Check the status of the subprocess. If it has exited, raise a UnityEnvironmentException |
|
|
|
:return: None |
|
|
|
""" |
|
|
|
if not self._process: |
|
|
|
return |
|
|
|
poll_res = self._process.poll() |
|
|
|
if poll_res is not None: |
|
|
|
exc_msg = self._returncode_to_env_message(self._process.returncode) |
|
|
|
raise UnityEnvironmentException(exc_msg) |
|
|
|
|
|
|
|
def close(self): |
|
|
|
""" |
|
|
|
Sends a shutdown signal to the unity environment, and closes the socket connection. |
|
|
|
|
|
|
timeout = self._timeout_wait |
|
|
|
self._loaded = False |
|
|
|
self._communicator.close() |
|
|
|
if self._proc1 is not None: |
|
|
|
if self._process is not None: |
|
|
|
self._proc1.wait(timeout=timeout) |
|
|
|
signal_name = self._returncode_to_signal_name(self._proc1.returncode) |
|
|
|
signal_name = f" ({signal_name})" if signal_name else "" |
|
|
|
return_info = f"Environment shut down with return code {self._proc1.returncode}{signal_name}." |
|
|
|
logger.info(return_info) |
|
|
|
self._process.wait(timeout=timeout) |
|
|
|
logger.info(self._returncode_to_env_message(self._process.returncode)) |
|
|
|
self._proc1.kill() |
|
|
|
self._process.kill() |
|
|
|
self._proc1 = None |
|
|
|
self._process = None |
|
|
|
|
|
|
|
@timed |
|
|
|
def _generate_step_input( |
|
|
|
|
|
|
) -> UnityOutputProto: |
|
|
|
inputs = UnityInputProto() |
|
|
|
inputs.rl_initialization_input.CopyFrom(init_parameters) |
|
|
|
return self._communicator.initialize(inputs) |
|
|
|
return self._communicator.initialize(inputs, self._poll_process) |
|
|
|
|
|
|
|
@staticmethod |
|
|
|
def _wrap_unity_input(rl_input: UnityRLInputProto) -> UnityInputProto: |
|
|
|
|
|
|
except Exception: |
|
|
|
# Should generally be a ValueError, but catch everything just in case. |
|
|
|
return None |
|
|
|
|
|
|
|
@staticmethod |
|
|
|
def _returncode_to_env_message(returncode: int) -> str: |
|
|
|
signal_name = UnityEnvironment._returncode_to_signal_name(returncode) |
|
|
|
signal_name = f" ({signal_name})" if signal_name else "" |
|
|
|
return f"Environment shut down with return code {returncode}{signal_name}." |