class_docstr: A trajectory recording wrapper. Supports both standard gym envs and BaseEnvs, as well as environments
  that provide more access -- SerializableEnvMixin for access to environment components
  and RecordableEnvMixin for access to MazeState and MazeExecution objects.
  
  :param env: the environment to wrap.
class_docstr_tok: ["A","trajectory","recording","wrapper",".","Supports","both","standard","gym","envs","and","BaseEnvs",",","as","well","as","environments","that","provide","more","access","--","SerializableEnvMixin","for","access","to","environment","components","and","RecordableEnvMixin","for","access","to","MazeState","and","MazeExecution","objects",".",":","param","env",":","the","environment","to","wrap","."]
docstr: Record available step-level data.
docstr_tok: ["Record","available","step-level","data","."]
code: def step(self, action: Any) -> Tuple[Any, Any, bool, Dict[Any, Any]]:
      """Record available step-level data."""
      assert (
          self.episode_record is not None
      ), "Environment must be reset before stepping."
  
      self._maze_action_recorded = False
      observation, reward, done, info = self.env.step(action)
  
      # Recording of event logs and stats happens:
      #  - for TimeEnvs:   Only if the env time changed, so that we record once per time step
      #  - for other envs: Every step
      if (
          not isinstance(self.env, TimeEnvMixin)
          or self.env.get_env_time() != self.last_env_time
      ):
          # Record maze action: In case no step-skipping was done and the action has not been recorded yet, do it here
          self._record_last_action()
  
          # Collect step events
          event_collection = EventCollection(
              self.env.get_step_events()
              if isinstance(self.env, EventEnvMixin)
              else []
          )
          step_event_log = StepEventLog(
              self.last_env_time, events=event_collection
          )
  
          # Record trajectory data
          step_record = StateRecord(
              env_time=self.last_env_time,
              maze_state=self.last_maze_state,
              maze_action=self._last_maze_action_before_skipping,
              step_event_log=step_event_log,
              reward=reward,
              done=done,
              info=info,
              serializable_components=self.last_serializable_components,
          )
          self.episode_record.step_records.append(step_record)
  
          # Collect state and components for the next step
          self._collect_state_and_components()
          self.last_env_time = (
              self.env.get_env_time()
              if isinstance(self.env, TimeEnvMixin)
              else self.last_env_time + 1
          )
  
      return observation, reward, done, info
  
imports: import uuid
  from copy import deepcopy
  from typing import Union, Any, Tuple, Dict, Optional
  from maze.core.annotations import override
  from maze.core.env.base_env import BaseEnv
  from maze.core.env.event_env_mixin import EventEnvMixin
  from maze.core.env.maze_action import MazeActionType
  from maze.core.env.maze_env import MazeEnv
  from maze.core.env.maze_state import MazeStateType
  from maze.core.env.recordable_env_mixin import RecordableEnvMixin
  from maze.core.env.serializable_env_mixin import SerializableEnvMixin
  from maze.core.env.simulated_env_mixin import SimulatedEnvMixin
  from maze.core.env.time_env_mixin import TimeEnvMixin
  from maze.core.events.event_collection import EventCollection
  from maze.core.log_events.step_event_log import StepEventLog
  from maze.core.rendering.keyboard_controlled_trajectory_viewer import KeyboardControlledTrajectoryViewer
  from maze.core.trajectory_recording.records.raw_maze_state import RawState, RawMazeAction
  from maze.core.trajectory_recording.records.state_record import StateRecord
  from maze.core.trajectory_recording.records.trajectory_record import StateTrajectoryRecord
  from maze.core.trajectory_recording.writers.trajectory_writer_registry import TrajectoryWriterRegistry
  from maze.core.wrappers.wrapper import Wrapper
label_desc: Use image node_id 3 for calling the TrajectoryRecordingWrapper obj's underlying member method code with example usage: obj.step(action) and returns: observation,  reward,  done,  info