code: def _process_msg(self, ident, obs, reward, done, info):
      client = self.clients[ident]
      reward_scale = 1 - GAMMA
      info["shaping_reward"] *= reward_scale
      if len(client.memory) > 0:
          client.memory[-1].reward = reward
          info["target_change_times"] = client.target_change_times
          client.memory[-1].info = info
          if info["target_changed"]:
              client.target_change_times = min(
                  client.target_change_times + 1, 3
              )
              # re-sample model_idx after target was changed
              client.model_idx = np.random.randint(args.ensemble_num)
          if done:
              assert "last_obs" in info
              self._parse_memory(client, ident, info["last_obs"])
      client.memory.append(
          TransitionExperience(
              obs=obs, action=None, reward=None, info=None
          )
      )
      if "target_changed" in info and info["target_changed"]:
          client.update_last_target_changed()
      return False
  
imports: import grpc
  import json
  import numpy
  import os
  import queue
  import simulator_pb2
  import simulator_pb2_grpc
  import six
  import time
  import threading
  from args import get_server_args
  from collections import defaultdict
  from concurrent import futures
  from multi_head_ddpg import MultiHeadDDPG
  from opensim_agent import OpenSimAgent
  from opensim_model import OpenSimModel
  from parl.utils import logger
  from replay_memory import ReplayMemory
  from utils import calc_indicators, ScalarsManager, TransitionExperience
label_desc: Use image node_id 4 for calling the SimulatorServer obj's underlying member method code with example usage: obj._process_msg(ident, obs, reward, done, info) and returns: False