class_docstr: Vectorized Environment Wrapper for MB-MPO.
  
  Primary change is in the `vector_step` method, which calls the dynamics
  models for next_obs "calculation" (instead of the actual env). Also, the
  actual envs need to have two extra methods implemented: `reward(obs)` and
  (optionally) `done(obs)`. If `done` is not implemented, we will assume
  that episodes in the env do not terminate, ever.
class_docstr_tok: ["Vectorized","Environment","Wrapper","for","MB-MPO",".","Primary","change","is","in","the","`","vector_step","`","method",",","which","calls","the","dynamics","models","for","next_obs","``","calculation","''","(","instead","of","the","actual","env",")",".","Also",",","the","actual","envs","need","to","have","two","extra","methods","implemented",":","`","reward","(","obs",")","`","and","(","optionally",")","`","done","(","obs",")","`",".","If","`","done","`","is","not","implemented",",","we","will","assume","that","episodes","in","the","env","do","not","terminate",",","ever","."]
code: def vector_step(self, actions):
      if self.cur_obs is None:
          raise ValueError("Need to reset env first")
  
      for idx in range(self.num_envs):
          self._timesteps[idx] += 1
  
      # If discrete, need to one-hot actions
      if isinstance(self.action_space, Discrete):
          act = np.array(actions)
          new_act = np.zeros((act.size, act.max() + 1))
          new_act[np.arange(act.size), act] = 1
          actions = new_act.astype("float32")
  
      # Batch the TD-model prediction.
      obs_batch = np.stack(self.cur_obs, axis=0)
      action_batch = np.stack(actions, axis=0)
      # Predict the next observation, given previous a) real obs
      # (after a reset), b) predicted obs (any other time).
      next_obs_batch = self.model.predict_model_batches(
          obs_batch, action_batch, device=self.device
      )
      next_obs_batch = np.clip(next_obs_batch, -1000, 1000)
  
      # Call env's reward function.
      # Note: Each actual env must implement one to output exact rewards.
      rew_batch = self.envs[0].reward(
          obs_batch, action_batch, next_obs_batch
      )
  
      # If env has a `done` method, use it.
      if hasattr(self.envs[0], "done"):
          dones_batch = self.envs[0].done(next_obs_batch)
      # Our sub-environments have timestep limits.
      elif hasattr(self.envs[0], "_max_episode_steps"):
          dones_batch = np.array(
              [
                  self._timesteps[idx]
                  >= self.envs[0]._max_episode_steps
                  for idx in range(self.num_envs)
              ]
          )
      # Otherwise, assume the episode does not end.
      else:
          dones_batch = np.asarray(
              [False for _ in range(self.num_envs)]
          )
      truncateds_batch = [False for _ in range(self.num_envs)]
  
      info_batch = [{} for _ in range(self.num_envs)]
  
      self.cur_obs = next_obs_batch
  
      return (
          list(next_obs_batch),
          list(rew_batch),
          list(dones_batch),
          truncateds_batch,
          info_batch,
      )
  
file_path: ray/rllib/env/wrappers/model_vector_env.py
imports: import logging
  from gymnasium.spaces import Discrete
  import numpy
  from ray.rllib.utils.annotations import override
  from ray.rllib.env.vector_env import VectorEnv
  from ray.rllib.evaluation.rollout_worker import get_global_worker
  from ray.rllib.env.base_env import BaseEnv, convert_to_base_env
  from ray.rllib.utils.typing import EnvType
label_desc: Use image node_id 4 for calling the _VectorizedModelGymEnv obj's underlying member method code with example usage: obj.vector_step(actions) and returns: list,  list,  list,  truncateds_batch,  info_batch