diff --git a/.gitignore b/.gitignore index d5a9f07ce..258f5e161 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ var/ tests/logs/ .vscode/settings.json +*/performance diff --git a/docs/source/environments/index.rst b/docs/source/environments/index.rst index fb3361f9a..a7aadab7d 100644 --- a/docs/source/environments/index.rst +++ b/docs/source/environments/index.rst @@ -7,7 +7,7 @@ General Information The :code:`minerl` package includes several environments as follows. This page describes each of the incldued environments, provides usage samples, and describes the exact action and observation space provided by each -environment. +environment! @@ -17,7 +17,7 @@ environment. be evaluated in :code:`MineRLObtainDiamond-v0` which has **sparse** rewards. See `MineRLObtainDiamond-v0`_. .. note:: - Al environments offer a default no-op action via :code:`env.action_space.noop()` + All environments offer a default no-op action via :code:`env.action_space.noop()` and a random action via :code:`env.action_space.sample()` .. include:: handlers.rst diff --git a/minerl/env/Malmo b/minerl/env/Malmo index fea1bc006..6c53ca4df 160000 --- a/minerl/env/Malmo +++ b/minerl/env/Malmo @@ -1 +1 @@ -Subproject commit fea1bc00616ad671f54d0cadd6e0519de3574cfc +Subproject commit 6c53ca4df0e10cbdf9653603c926c41accc8118f diff --git a/minerl/env/comms.py b/minerl/env/comms.py index 4644e16c9..470c51b72 100644 --- a/minerl/env/comms.py +++ b/minerl/env/comms.py @@ -75,3 +75,17 @@ def recvall(sock, count): buf += newbuf count -= len(newbuf) return buf + + +class QueueLogger(logging.StreamHandler): + def __init__(self, queue): + self._queue = queue + return super().__init__(None) + + def flush(self): + pass + + + def emit(self, record): + self._queue.append((self.level, record)) + diff --git a/minerl/env/core.py b/minerl/env/core.py index 2d8b29285..b680dc82e 100644 --- a/minerl/env/core.py +++ b/minerl/env/core.py @@ -18,6 +18,7 @@ # ------------------------------------------------------------------------------------------------ import collections + import copy import json import logging @@ -38,13 +39,14 @@ from lxml import etree from minerl.env import comms from minerl.env.comms import retry -from minerl.env.malmo import InstanceManager, malmo_version +from minerl.env.malmo import InstanceManager, malmo_version, launch_queue_logger_thread logger = logging.getLogger(__name__) missions_dir = os.path.join(os.path.dirname(__file__), 'missions') + class EnvException(Exception): """A special exception thrown in the creation of an environment's Malmo mission XML. @@ -113,6 +115,7 @@ def __init__(self, xml, observation_space, action_space, port=None, noop_action= self.ns = '{http://ProjectMalmo.microsoft.com}' self.client_socket = None + self.exp_uid = "" self.done = True self.synchronous = True @@ -123,14 +126,62 @@ def __init__(self, xml, observation_space, action_space, port=None, noop_action= self.xml_file = xml self.has_init = False - self.instance = None self.had_to_clean = False self._already_closed = False + self.instance = self._get_new_instance(port) + + + self._setup_spaces(observation_space, action_space) + + + self.resets = 0 + self.done = True + + def _get_new_instance(self, port=None): + """ + Gets a new instance and sets up a logger if need be. + """ + + if not port is None: + instance = InstanceManager.add_existing_instance(port) + else: + instance = InstanceManager.get_instance(os.getpid()) + + if InstanceManager.is_remote(): + launch_queue_logger_thread(instance, self.is_closed) + + instance.launch() + return instance + + + def _setup_spaces(self, observation_space, action_space): + self.action_space = action_space + self.observation_space = observation_space + + def map_space(space): + if isinstance(space, gym.spaces.Discrete) or isinstance(space, minerl.env.spaces.Enum): + return 0 + elif isinstance(space, gym.spaces.Box): + return np.zeros(shape=space.shape, dtype=space.dtype) + else: + try: + return space.default() + except NameError: + raise ValueError( + 'Specify non-None default_action in gym.register or extend all action spaces with default() method') + if self._default_action is None: + self._default_action = {key: map_space( + space) for key, space in action_space.spaces.items()} + + def noop_func(a): + return deepcopy(self._default_action) - self.init(observation_space, action_space, port=port) + boundmethd = _bind(self.action_space, noop_func) + self.action_space.noop = boundmethd - def init(self, observation_space, action_space, port=None): + + def init(self): """Initializes the MineRL Environment. Note: @@ -146,18 +197,14 @@ def init(self, observation_space, action_space, port=None): ValueError: The space specified for this environment does not have a default action. NotImplementedError: When multiagent environments are attempted to be used. """ - episode = 0 exp_uid = None - if self.instance == None: - if not port is None: - self.instance = InstanceManager.add_existing_instance(port) - else: - self.instance = InstanceManager.get_instance() + # Parse XML file with open(self.xml_file, 'r') as f: - xml_text = f.read() - xml = xml_text.replace('$(MISSIONS_DIR)', missions_dir) - + xml = f.read() + # Todo: This will fail when using a remote instance manager. + xml = xml.replace('$(MISSIONS_DIR)', missions_dir) + xml = xml.replace('$(ENV_NAME)', self.spec.id) # Bootstrap the environment if it hasn't been. role = 0 @@ -174,30 +221,7 @@ def init(self, observation_space, action_space, port=None): else: self.exp_uid = exp_uid - self.action_space = action_space - self.observation_space = observation_space - - def map_space(space): - if isinstance(space, gym.spaces.Discrete) or isinstance(space, minerl.env.spaces.Enum): - return 0 - elif isinstance(space, gym.spaces.Box): - return np.zeros(shape=space.shape, dtype=space.dtype) - else: - try: - return space.default() - except NameError: - raise ValueError( - 'Specify non-None default_action in gym.register or extend all action spaces with default() method') - if self._default_action is None: - self._default_action = {key: map_space( - space) for key, space in action_space.spaces.items()} - - def noop_func(a): - return deepcopy(self._default_action) - - boundmethd = _bind(self.action_space, noop_func) - self.action_space.noop = boundmethd - + # Force single agent self.agent_count = 1 turn_based = self.xml.find( @@ -206,10 +230,6 @@ def noop_func(a): raise NotImplementedError( "Turn based or multi-agent environments not supported.") - self.done = True - - self.resets = episode - e = etree.fromstring(""" self.maxwidth: + scale = self.maxwidth / width + width = int(scale * width) + height = int(scale * height) + self.window = pyglet.window.Window(width=width, height=height, + display=self.display, vsync=False, resizable=True) + self.width = width + self.height = height + self.isopen = True + + @self.window.event + def on_resize(width, height): + self.width = width + self.height = height + + @self.window.event + def on_close(): + self.isopen = False + + self.viewer = ScaledWindowImageViewer(self.width*4, self.height*4) self.viewer.imshow(obs) return self.viewer.isopen @@ -544,6 +589,9 @@ def render(self, mode='human'): self._renderObs(self._last_pov) return self._last_pov + def is_closed(self): + return self._already_closed + def close(self): """gym api close""" if self.viewer is not None: diff --git a/minerl/env/malmo.py b/minerl/env/malmo.py index 5724c98dc..2b087e249 100644 --- a/minerl/env/malmo.py +++ b/minerl/env/malmo.py @@ -22,10 +22,15 @@ import logging import multiprocessing import os -import pathlib +import traceback +import pathlib +import Pyro4.core + + import shutil import socket import struct +import collections import subprocess import sys import tempfile @@ -35,6 +40,7 @@ # from exceptions import NotImplementedError from multiprocessing import process +import uuid import psutil import Pyro4 from minerl.env import comms @@ -61,7 +67,11 @@ class InstanceManager: """ MINECRAFT_DIR = os.path.join(os.path.dirname(__file__), 'Malmo', 'Minecraft') SCHEMAS_DIR = os.path.join(os.path.dirname(__file__), 'Malmo', 'Schemas') + STATUS_DIR = os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'performance') MAXINSTANCES = 10 + KEEP_ALIVE_PYRO_FREQUENCY = 5 + REMOTE = False + DEFAULT_IP = "localhost" _instance_pool = [] ninstances = 0 @@ -70,7 +80,7 @@ class InstanceManager: managed = True @classmethod - def get_instance(cls): + def get_instance(cls, pid): """ Gets an instance from the instance manager. This method is a context manager and therefore when the context is entered the method yields a InstanceManager.Instance @@ -86,24 +96,33 @@ def get_instance(cls): # Find an available instance. for inst in cls._instance_pool: if not inst.locked: - inst._acquire_lock() + inst._acquire_lock(pid) + if hasattr(cls, "_pyroDaemon"): cls._pyroDaemon.register(inst) - Pyro4.current_context.track_resource(inst) + return inst # Otherwise make a new instance if possible if cls.managed: if len(cls._instance_pool) < cls.MAXINSTANCES: cls.ninstances += 1 - inst = cls.Instance(cls._get_valid_port()) + # Make the status directory. + + if hasattr(cls, "_pyroDaemon"): + status_dir = os.path.join(cls.STATUS_DIR, 'mc_{}'.format(cls.ninstances)) + if not os.path.exists(status_dir): + os.makedirs(status_dir) + else: + status_dir = None + + inst = cls.Instance(cls._get_valid_port(), status_dir=status_dir) cls._instance_pool.append(inst) - inst._acquire_lock() + inst._acquire_lock(pid) if hasattr(cls, "_pyroDaemon"): cls._pyroDaemon.register(inst) - Pyro4.current_context.track_resource(inst) return inst @@ -133,11 +152,31 @@ def allocate_pool(cls, num): @classmethod def add_existing_instance(cls, port): assert cls._is_port_taken(port), "No Malmo mod utilizing the port specified." - instance = InstanceManager.Instance(port=port, existing=True) + instance = InstanceManager.Instance(port=port, existing=True, status_dir=status_dir) cls._instance_pool.append(instance) cls.ninstances += 1 return instance + @classmethod + def add_keep_alive(cls,_pid, _callback): + logger.debug("Recieved keep-alive callback from client {}. Starting thread.".format(_pid)) + def check_client_connected(client_pid, keep_alive_proxy): + logger.debug("Client keep-alive connection monitor started for {}.".format(client_pid)) + while True: + time.sleep(InstanceManager.KEEP_ALIVE_PYRO_FREQUENCY) + try: + keep_alive_proxy.call() + except: + bad_insts = [inst for inst in cls._instance_pool if inst.owner == client_pid] + for inst in bad_insts: + inst.close() + + keep_alive_thread = threading.Thread( + target=check_client_connected, + args=(_pid, _callback) + ) + keep_alive_thread.setDaemon(True) + keep_alive_thread.start() @staticmethod def _is_port_taken(port, address='0.0.0.0'): @@ -265,6 +304,10 @@ def on_terminate(proc): logger.info("Minecraft process {} survived SIGKILL; giving up".format(p.pid)) + @classmethod + def is_remote(cls): + return cls.REMOTE + @Pyro4.expose class Instance(object): """ @@ -279,27 +322,34 @@ class Instance(object): This scheme has a single failure point of the process dying before the watcher process is launched. """ + MAX_PIPE_LENGTH = 500 - def __init__(self, port=None, existing=False): + def __init__(self, port=None, existing=False, status_dir=None): """ Launches the subprocess. """ self.running = False + self._starting = True self.minecraft_process = None self.watcher_process = None self._port = None self._host = InstanceManager.DEFAULT_IP self.locked = False + self.uuid = str(uuid.uuid4()).replace("-","")[:6] self.existing = existing self.minecraft_dir = None self.instance_dir = None + self._status_dir = status_dir + self.owner = None - # Launch the instance! - self.launch(port, existing) - + self._setup_logging() + self._target_port = port + + def launch(self): + port = self._target_port + self._starting = True - def launch(self, port=None, existing=False): - if not existing: + if not self.existing: if not port: port = InstanceManager._get_valid_port() @@ -341,13 +391,13 @@ def launch(self, port=None, existing=False): error_str = "" for l in lines: spline = "\n".join(l.split("\n")[:-1]) - logger.error(spline) + self._logger.error(spline) error_str += spline +"\n" # Throw an exception! raise EOFError(error_str + "\n\nMinecraft process finished unexpectedly. There was an error with Malmo.") lines.append(line) - logger.debug("\n".join(line.split("\n")[:-1])) + self._logger.debug("\n".join(line.split("\n")[:-1])) MALMOENVPORTSTR = "***** Start MalmoEnvServer on port " @@ -362,12 +412,14 @@ def launch(self, port=None, existing=False): if client_ready: break - - - logger.info("Minecraft process ready") + + if not self.port: + raise RuntimeError("Malmo failed to start the MalmoEnv server! Check the logs from the Minecraft process."); + self._logger.info("Minecraft process ready") + if not port == self._port: - logger.warning("Tried to launch Minecraft on port {} but that port was taken, instead Minecraft is using port {}.".format(port, self.port)) + self._logger.warning("Tried to launch Minecraft on port {} but that port was taken, instead Minecraft is using port {}.".format(port, self.port)) # supress entire output, otherwise the subprocess will block # NB! there will be still logs under Malmo/Minecraft/run/logs # FNULL = open(os.devnull, 'w') @@ -376,7 +428,7 @@ def log_to_file(logdir): if not os.path.exists(os.path.join(logdir, 'logs')): os.makedirs((os.path.join(logdir, 'logs'))) - file_path = os.path.join(logdir, 'logs', 'minecraft_proc_{}.log'.format(self._port)) + file_path = os.path.join(logdir, 'logs', 'mc_{}.log'.format(self._target_port - 9000)) logger.info("Logging output of Minecraft to {}".format(file_path)) @@ -400,11 +452,11 @@ def log_to_file(logdir): if 'STDERR' in linestr or 'ERROR' in linestr: # Opportune place to suppress harmless MC errors. if not ('hitResult' in linestr): - logger.error(linestr) + self._logger.error(linestr) elif 'LOGTOPY' in linestr: - logger.info(linestr) + self._logger.info(linestr) else: - logger.debug(linestr) + self._logger.debug(linestr) mine_log.write(line) mine_log.flush() finally: @@ -422,6 +474,8 @@ def log_to_file(logdir): self.running = True + self._starting = False + # Make a hook to kill atexit.register(lambda: self._destruct()) @@ -435,8 +489,11 @@ def kill(self): def close(self): """Closes the object. """ - self._destruct() + self._destruct(should_close=True) + @property + def status_dir(self): + return self._status_dir @property def host(self): @@ -446,6 +503,26 @@ def host(self): def port(self): return self._port + def get_output(self): + while self.running or self._starting: + try: + level, line = self._output_stream.pop() + # print("didnt' get it") + return (line.levelno, line.getMessage(), line.name), self.running or self._starting + except IndexError: + time.sleep(0.1) + else: + return None, False + + def _setup_logging(self): + # Set up an output stream handler. + self._logger = logging.getLogger(__name__ + ".instance.{}".format(str(self.uuid))) + self._output_stream = collections.deque(maxlen=self.MAX_PIPE_LENGTH) + for level in [logging.DEBUG]: + handler = comms.QueueLogger(self._output_stream) + handler.setLevel(level) + self._logger.addHandler(handler) + ########################### ##### PRIVATE METHODS ##### ########################### @@ -469,9 +546,10 @@ def _launch_minecraft(self, port, headless, minecraft_dir): rundir = os.path.join(minecraft_dir, 'run') cmd = [launch_script, '-port', str(port), '-env', '-runDir', rundir] + if self.status_dir: + cmd += ['-performanceDir', self.status_dir] - - logger.info("Starting Minecraft process: " + str(cmd)) + self._logger.info("Starting Minecraft process: " + str(cmd)) # print(cmd) if replaceable: @@ -492,7 +570,7 @@ def _launch_process_watcher(self, parent_pid, child_pid, child_host, child_port, Launches the process watcher for the parent and minecraft process. """ parent_conn, child_conn = multiprocessing.Pipe() - logger.info("Starting process watcher for process {} @ {}:{}".format(child_pid, child_host, child_port)) + self._logger.info("Starting process watcher for process {} @ {}:{}".format(child_pid, child_host, child_port)) p = multiprocessing.Process( target=InstanceManager._process_watcher, args=( parent_pid, child_pid, @@ -522,7 +600,6 @@ def _kill_minecraft_via_malmoenv(host, port): sock.close() return ok == 1 except Exception as e: - print(e) logger.error("Attempted to send kill command to minecraft process and failed.") return False @@ -532,11 +609,15 @@ def __del__(self): """ self._destruct() - def _destruct(self): + def _destruct(self, should_close=False): """ Do our best as the parent process to destruct and kill the child + watcher. """ - if self.running and not self.existing: + if (self.running or should_close) and not self.existing: + self.running = False + self._starting = False + + # Wait for the process to start. time.sleep(1) # kill the minecraft process and its subprocesses @@ -560,24 +641,25 @@ def _destruct(self): if self in InstanceManager._instance_pool: InstanceManager._instance_pool.remove(self) self.release_lock() - - self.running = False pass def __repr__(self): - return ("Malmo[proc={}, addr={}:{}, locked={}]".format( + return ("Malmo[{}, proc={}, addr={}:{}, locked={}]".format( + self.uuid, self.minecraft_process.pid if not self.existing else "EXISTING", self.ip, self.port, self.locked )) - def _acquire_lock(self): + def _acquire_lock(self, owner=None): self.locked = True + self.owner = owner def release_lock(self): self.locked = False + self.owner = None def _check_for_launch_errors(line): @@ -618,15 +700,51 @@ def _check_for_launch_errors(line): "If all else fails, JUST PUT THIS IN A DOCKER CONTAINER! :)") + +def launch_queue_logger_thread(output_producer, should_end): + def queue_logger_thread(out_prod, should_end): + while not should_end(): + try: + line, running = out_prod.get_output() + if not running: + break + if line: + level = line[0] + record = line[1] + name = line[2] + lgr = logging.getLogger(name) + lgr.log(level, record) + except Exception as e: + print(e) + break + + + thread = threading.Thread( + target=queue_logger_thread, + args=(output_producer, should_end)) + thread.setDaemon(True) + thread.start() + + + def launch_instance_manager(): """Defines the entry point for the remote procedure call server. """ # Todo: Use name servers in the docker contexct (set up a docker compose?) # pyro4-ns try: - + print("Removing the performance directory!") + try: + shutil.rmtree(InstanceManager.STATUS_DIR) + except: + pass + finally: + if not os.path.exists(InstanceManager.STATUS_DIR): + os.makedirs(InstanceManager.STATUS_DIR) print("autoproxy?",Pyro4.config.AUTOPROXY) - # TODO: Share logger! + InstanceManager.REMOTE = True + Pyro4.config.COMMTIMEOUT = InstanceManager.KEEP_ALIVE_PYRO_FREQUENCY + Pyro4.Daemon.serveSimple( { @@ -638,6 +756,43 @@ def launch_instance_manager(): print(e) print("Start the Pyro name server with pyro4-ns and re-run this script.") + +class CustomAsyncRemoteMethod(Pyro4.core._AsyncRemoteMethod): + def __call__(self, *args, **kwargs): + res = super().__call__(*args, **kwargs) + val = res.value + if isinstance(val, Pyro4.Proxy): + val._pyroAsync(asynchronous=True) + + return val + + if os.getenv(MINERL_INSTANCE_MANAGER_REMOTE): - sys.excepthook = Pyro4.util.excepthook + sys.excepthook = Pyro4.util.excepthook + Pyro4.core._AsyncRemoteMethod = CustomAsyncRemoteMethod InstanceManager = Pyro4.Proxy("PYRONAME:" + INSTANCE_MANAGER_PYRO ) + InstanceManager._pyroAsync(asynchronous=True) + + # Set up the keep alive signal. + logger.debug("Starting client keep-alive server...") + def keep_alive_pyro(): + class KeepAlive(object): + @Pyro4.expose + @Pyro4.callback + def call(self): + return True + + daemon = Pyro4.core.Daemon() + callback = KeepAlive() + daemon.register(callback) + + InstanceManager.add_keep_alive(os.getpid(), callback) + + logger.debug("Client keep-alive server started.") + daemon.requestLoop() + + thread = threading.Thread(target=keep_alive_pyro) + thread.setDaemon(True) + thread.start() + + diff --git a/minerl/env/missions/navigation.xml b/minerl/env/missions/navigation.xml index 9292d0e72..bc067b5e6 100644 --- a/minerl/env/missions/navigation.xml +++ b/minerl/env/missions/navigation.xml @@ -1,7 +1,7 @@ - Navigation through survival world. + $(ENV_NAME) @@ -48,7 +48,7 @@ 64 64 - + diff --git a/minerl/env/missions/navigationDense.xml b/minerl/env/missions/navigationDense.xml index 5b7ab3655..cf6fc04f4 100644 --- a/minerl/env/missions/navigationDense.xml +++ b/minerl/env/missions/navigationDense.xml @@ -1,7 +1,7 @@ - Navigation through survival world. + $(ENV_NAME) @@ -49,6 +49,7 @@ 64 64 + diff --git a/minerl/env/missions/navigationDenseFixedMap.xml b/minerl/env/missions/navigationDenseFixedMap.xml index 6c808085a..3105c3076 100644 --- a/minerl/env/missions/navigationDenseFixedMap.xml +++ b/minerl/env/missions/navigationDenseFixedMap.xml @@ -1,7 +1,7 @@ - Navigation through survival world. + $(ENV_NAME) @@ -52,6 +52,7 @@ 64 64 + diff --git a/minerl/env/missions/navigationExtreme.xml b/minerl/env/missions/navigationExtreme.xml index e51cd43fe..81e751f18 100644 --- a/minerl/env/missions/navigationExtreme.xml +++ b/minerl/env/missions/navigationExtreme.xml @@ -1,7 +1,7 @@ - Navigation through survival world. + $(ENV_NAME) @@ -49,6 +49,7 @@ 64 64 + diff --git a/minerl/env/missions/navigationExtremeDense.xml b/minerl/env/missions/navigationExtremeDense.xml index 255396fb7..fa8962cba 100644 --- a/minerl/env/missions/navigationExtremeDense.xml +++ b/minerl/env/missions/navigationExtremeDense.xml @@ -1,7 +1,7 @@ - Navigation through survival world. + $(ENV_NAME) @@ -49,6 +49,7 @@ 64 64 + diff --git a/minerl/env/missions/obtainDebug.xml b/minerl/env/missions/obtainDebug.xml index 9231cc423..8445bfe0a 100644 --- a/minerl/env/missions/obtainDebug.xml +++ b/minerl/env/missions/obtainDebug.xml @@ -1,7 +1,7 @@ - Obtain iron pickaxe experiment + $(ENV_NAME) @@ -42,6 +42,7 @@ 640 640 + diff --git a/minerl/env/missions/obtainDiamond.xml b/minerl/env/missions/obtainDiamond.xml index 066f609db..a59fb0c94 100644 --- a/minerl/env/missions/obtainDiamond.xml +++ b/minerl/env/missions/obtainDiamond.xml @@ -1,7 +1,7 @@ - Obtain iron pickaxe experiment + $(ENV_NAME) @@ -31,6 +31,7 @@ 64 64 + diff --git a/minerl/env/missions/obtainDiamondDense.xml b/minerl/env/missions/obtainDiamondDense.xml index 8505fba18..b65c11aaa 100644 --- a/minerl/env/missions/obtainDiamondDense.xml +++ b/minerl/env/missions/obtainDiamondDense.xml @@ -1,7 +1,7 @@ - Obtain iron pickaxe experiment + $(ENV_NAME) @@ -31,6 +31,7 @@ 64 64 + diff --git a/minerl/env/missions/obtainIronPickaxe.xml b/minerl/env/missions/obtainIronPickaxe.xml index 91e063fcf..173ed6dfc 100644 --- a/minerl/env/missions/obtainIronPickaxe.xml +++ b/minerl/env/missions/obtainIronPickaxe.xml @@ -1,7 +1,7 @@ - Obtain iron pickaxe experiment + $(ENV_NAME) @@ -31,6 +31,7 @@ 64 64 + diff --git a/minerl/env/missions/obtainIronPickaxeDense.xml b/minerl/env/missions/obtainIronPickaxeDense.xml index 0ae2e9c46..7ee78533b 100644 --- a/minerl/env/missions/obtainIronPickaxeDense.xml +++ b/minerl/env/missions/obtainIronPickaxeDense.xml @@ -1,7 +1,7 @@ - Obtain iron pickaxe experiment + $(ENV_NAME) @@ -31,6 +31,7 @@ 64 64 + diff --git a/minerl/env/missions/treechop.xml b/minerl/env/missions/treechop.xml index 22c67a8cf..8d40edcff 100644 --- a/minerl/env/missions/treechop.xml +++ b/minerl/env/missions/treechop.xml @@ -1,8 +1,8 @@ - - Survival Treechop experiment - + + $(ENV_NAME) + 50 @@ -56,6 +56,7 @@ 64 64 + diff --git a/tests/excluded/simple_env_test.py b/tests/excluded/simple_env_test.py index 0d8edac7e..322015ce6 100644 --- a/tests/excluded/simple_env_test.py +++ b/tests/excluded/simple_env_test.py @@ -17,7 +17,7 @@ #import minerl.env.bootstrap #minerl.env.bootstrap._check_port_avail = lambda _,__: True -NUM_EPISODES=5 +NUM_EPISODES=1 def main(): """ @@ -44,7 +44,7 @@ def main(): random_act) # print(obs["compassAngle"]) netr += reward - print(netr) + print(reward, netr) env.render()