class_docstr: A Starcraft II environment.
  
  The implementation details of the action and observation specs are in
  lib/features.py
code: def _get_observations(self, target_game_loop):
      # Transform in the thread so it runs while waiting for other observations.
      def parallel_observe(c, f):
          obs = c.observe(target_game_loop=target_game_loop)
          agent_obs = f.transform_obs(obs)
          return obs, agent_obs
  
      with self._metrics.measure_observation_time():
          self._obs, self._agent_obs = zip(
              *self._parallel.run(
                  (parallel_observe, c, f)
                  for c, f in zip(self._controllers, self._features)
              )
          )
  
      game_loop = _get_game_loop(self._agent_obs[0])
      if game_loop < target_game_loop and not any(
          o.player_result for o in self._obs
      ):
          raise ValueError(
              (
                  "The game didn't advance to the expected game loop. "
                  "Expected: %s, got: %s"
              )
              % (target_game_loop, game_loop)
          )
      elif game_loop > target_game_loop and target_game_loop > 0:
          logging.warning(
              "Received observation %d step(s) late: %d rather than %d.",
              game_loop - target_game_loop,
              game_loop,
              target_game_loop,
          )
  
      if self._realtime:
          # Track delays on executed actions.
          # Note that this will underestimate e.g. action sent, new observation
          # taken before action executes, action executes, observation taken
          # with action. This is difficult to avoid without changing the SC2
          # binary - e.g. send the observation game loop with each action,
          # return them in the observation action proto.
          if self._last_obs_game_loop is not None:
              for i, obs in enumerate(self._obs):
                  for action in obs.actions:
                      if action.HasField("game_loop"):
                          delay = (
                              action.game_loop
                              - self._last_obs_game_loop
                          )
                          if delay > 0:
                              num_slots = len(self._action_delays[i])
                              delay = min(
                                  delay, num_slots - 1
                              )  # Cap to num buckets.
                              self._action_delays[i][delay] += 1
                              break
          self._last_obs_game_loop = game_loop
  
imports: import collections
  import copy
  import random
  import time
  from absl import logging
  from pysc2 import maps
  from pysc2 import run_configs
  from pysc2.env import enums
  from pysc2.env import environment
  from pysc2.lib import actions
  from pysc2.lib import features
  from pysc2.lib import metrics
  from pysc2.lib import portspicker
  from pysc2.lib import renderer_human
  from pysc2.lib import run_parallel
  from pysc2.lib import stopwatch
  from s2clientprotocol import sc2api_pb2
label_desc: Use image node_id 19 for calling the SC2Env obj's underlying member method code with example usage: obj._get_observations(target_game_loop) and returns: obs,  agent_obs