code: def converted_observations(
      observations_iterator,
      converter,
      accept_step_fn,
      force_action_fn=get_flat_action,
  ):
      """Generator of transformed observations (incl. action and time delay)."""
      current_observation = next(observations_iterator)
      current_step = current_observation[0].observation.game_loop
      assert current_step == 0
  
      player_obs_queue = collections.deque()
  
      for next_observation in observations_iterator:
          step = next_observation[0].observation.game_loop
  
          if step == 0 or (
              current_step > 0 and not accept_step_fn(step - 1)
          ):
              # Save the observation even if it didn't have any actions. The step
              # stream also yields the observations immediately before the actions
              # are reported to capture the time the player actually issued the
              # action. If actions were reported at time steps t1 and t2
              # subsequently, we need to yield observation at step t2-1 instead of
              # t1 (this is also what is recorded in the action skips dataset).
              current_observation = next_observation
              continue
  
          player_obs_queue.append(
              _unconverted_observation(
                  observation=current_observation,
                  actions=next_observation[0].actions,
              )
          )
  
          while len(player_obs_queue) >= 2:
              # We have saved at least 2 observations in the queue, we can now
              # correctly calculate the true action delay.
              player_obs = player_obs_queue.popleft()
              player_obs_next = player_obs_queue[0]
              converted_observation = _convert_observation(
                  converter,
                  player_obs,
                  force_action_delay=(
                      player_obs_next.player.observation.game_loop
                      - player_obs.player.observation.game_loop
                  ),
                  force_action_fn=force_action_fn,
              )
  
              yield converted_observation
  
          current_step = step
          current_observation = next_observation
  
      # Always use last observation, it contains the player result.
      player_obs_queue.append(
          _unconverted_observation(
              observation=current_observation,
              actions=current_observation[0].actions,
          )
      )
  
      previous_delay = 1
      while player_obs_queue:
          player_obs = player_obs_queue.popleft()
          if len(player_obs_queue) >= 1:
              player_obs_next = player_obs_queue[0]
              force_action_delay = (
                  player_obs_next.player.observation.game_loop
                  - player_obs.player.observation.game_loop
              )
          else:
              # Use previous force action delay, this is only done in the last step.
              # Preserve for reproducibility. In theory the actual delay value
              # shouldn't matter if we retrain checkpoints, since the actions from
              # the last step are never taken.
              force_action_delay = previous_delay
          converted_observation = _convert_observation(
              converter,
              player_obs,
              force_action_delay=force_action_delay,
              force_action_fn=force_action_fn,
          )
          previous_delay = force_action_delay
  
          yield converted_observation
  
file_path: pysc2/pysc2/lib/replay/replay_converter.py
imports: import collections
  from typing import Any, Dict, Iterable, Sequence
  import numpy
  from pysc2.env.converter import converter
  from pysc2.env.converter import derive_interface_options
  from pysc2.env.converter.proto import converter_pb2
  from pysc2.lib.replay import replay_observation_stream
  from pysc2.lib.replay import sc2_replay
  from pysc2.lib.replay import sc2_replay_utils
  import tree
  from s2clientprotocol import sc2api_pb2
label_desc: Use image node_id 4 for calling a global function with example usage: converted_observations(observations_iterator, converter, accept_step_fn, force_action_fn) without return types