From d9e00e9a88b47557b6d09468b9753b13503148ae Mon Sep 17 00:00:00 2001 From: rk1a Date: Thu, 12 Jan 2023 13:52:48 +0100 Subject: [PATCH 1/2] Restructure reward mods * define global reward and reset in base rewards mod * custom reward mods can * overwrite at each step (e.g. random reward mod) * or modify reward based on events (e.g. treechop) --- .gitignore | 3 ++- clientmods/mods.conf | 6 +++--- clientmods/random/init.lua | 4 ++++ clientmods/random/mod.conf | 1 + clientmods/rewards/init.lua | 26 +++++--------------------- clientmods/treechop/init.lua | 8 -------- 6 files changed, 15 insertions(+), 33 deletions(-) create mode 100644 clientmods/random/init.lua create mode 100644 clientmods/random/mod.conf diff --git a/.gitignore b/.gitignore index 8e9ba910e735..3a3ceecae7db 100644 --- a/.gitignore +++ b/.gitignore @@ -68,7 +68,8 @@ newworld/ /worlds /world/ /clientmods/* -!/clientmods/preview/ +!/clientmods/rewards/ +!/clientmods/random/ !/clientmods/treechop/ !/clientmods/mods.conf /client/mod_storage/ diff --git a/clientmods/mods.conf b/clientmods/mods.conf index c1459d3b62b8..07fa7076faa0 100644 --- a/clientmods/mods.conf +++ b/clientmods/mods.conf @@ -1,4 +1,4 @@ -load_mod_rewards = false +load_mod_rewards = true +load_mod_random = false +load_mod_treechop = false load_mod_preview = false -load_mod_rewards_client = false -load_mod_treechop = true diff --git a/clientmods/random/init.lua b/clientmods/random/init.lua new file mode 100644 index 000000000000..03f204b71897 --- /dev/null +++ b/clientmods/random/init.lua @@ -0,0 +1,4 @@ +-- set random reward at every step +minetest.register_globalstep(function(dtime) + reward = math.random() +end) \ No newline at end of file diff --git a/clientmods/random/mod.conf b/clientmods/random/mod.conf new file mode 100644 index 000000000000..213c6773c5a4 --- /dev/null +++ b/clientmods/random/mod.conf @@ -0,0 +1 @@ +name = random \ No newline at end of file diff --git a/clientmods/rewards/init.lua b/clientmods/rewards/init.lua index 572a623d12f5..4d04875c8fc5 100644 --- a/clientmods/rewards/init.lua +++ b/clientmods/rewards/init.lua @@ -1,23 +1,7 @@ --- https://github.com/minetest/minetest/issues/10682 -local function register_globalstep_on_mods_loaded(func) - local function wrapper_func(dtime) - if not minetest.localplayer then return end - func(dtime) - for i, globalstep in pairs(minetest.registered_globalsteps) do - if globalstep == wrapper_func then - minetest.registered_globalsteps[i] = func - end - end - end - minetest.register_globalstep(wrapper_func) -end +-- define global reward variable reward = 0.0 --- local loaded = false -register_globalstep_on_mods_loaded(function() - -- if(loaded) then return end - -- loaded = true - -- local channel_name = "rewards_"..minetest.localplayer:get_name() - -- minetest.mod_channel_join(channel_name) - -- minetest.register_on_modchannel_message(function(channel_name, sender, message) end) - reward = math.random() + +-- reset reward every step +minetest.register_globalstep(function(dtime) + reward = 0.0 end) \ No newline at end of file diff --git a/clientmods/treechop/init.lua b/clientmods/treechop/init.lua index 305b4056dade..da99df2d2190 100644 --- a/clientmods/treechop/init.lua +++ b/clientmods/treechop/init.lua @@ -1,11 +1,3 @@ - -reward = 0.0 - --- reset reward every step -minetest.register_globalstep(function(dtime) - reward = 0.0 -end) - -- reward chopping tree nodes minetest.register_on_dignode(function(pos, node) if string.find(node["name"], "tree") then From 07bbe71ac5d5d07edb8092b910e8b9845c66461c Mon Sep 17 00:00:00 2001 From: rk1a Date: Thu, 12 Jan 2023 13:59:24 +0100 Subject: [PATCH 2/2] Add clientmod configuration pass list of clientsmods to be enabled --- hacking_testing/minetest_env.py | 45 ++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/hacking_testing/minetest_env.py b/hacking_testing/minetest_env.py index 0c0914156397..22515336fcbd 100644 --- a/hacking_testing/minetest_env.py +++ b/hacking_testing/minetest_env.py @@ -5,7 +5,7 @@ import shutil import subprocess import uuid -from typing import Any, Dict, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple import gym import matplotlib.pyplot as plt @@ -167,15 +167,15 @@ def __init__( fov: int = 72, seed: Optional[int] = None, start_minetest: Optional[bool] = True, + clientmods: List[str] = [], ): # Graphics settings self.display_size = display_size self.fov_y = fov self.fov_x = self.fov_y * self.display_size[0] / self.display_size[1] - self.max_mouse_move_x = 180 / self.fov_x * self.display_size[0] - self.max_mouse_move_y = 180 / self.fov_y * self.display_size[1] - # Define action and observation space + self.max_mouse_move_x = self.display_size[0] + self.max_mouse_move_y = self.display_size[1] self.action_space = gym.spaces.Dict( { **{key: gym.spaces.Discrete(2) for key in KEY_MAP.keys()}, @@ -198,6 +198,7 @@ def __init__( # Define Minetest paths self.root_dir = os.path.dirname(os.path.dirname(__file__)) + self.minetest_executable = minetest_executable if minetest_executable is None: self.minetest_executable = os.path.join(self.root_dir, "bin", "minetest") if log_dir is None: @@ -241,18 +242,37 @@ def __init__( # Seed the environment self.unique_env_id = str(uuid.uuid4()) # fallback UUID when no seed is provided - if seed: + if seed is not None: self.seed(seed) # Configure logging logging.basicConfig( filename=os.path.join(self.log_dir, f"env_{self.unique_env_id}.log"), filemode="a", - format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s', - datefmt='%H:%M:%S', + format="%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s", + datefmt="%H:%M:%S", level=logging.DEBUG, ) + # Configure mods + self.clientmods = clientmods + ["rewards"] # require the base rewards mod + clientmods_folder = os.path.realpath( + os.path.join(os.path.dirname(self.minetest_executable), "../clientmods"), + ) + if not os.path.exists(clientmods_folder): + raise ValueError(f"Clientmods must be located at {clientmods_folder}!") + # Write mods.conf + with open(os.path.join(clientmods_folder, "mods.conf"), "w") as mods_config: + for clientmod in self.clientmods: + clientmod_folder = os.path.join(clientmods_folder, clientmod) + if not os.path.exists(clientmod_folder): + logging.warning( + f"Clientmod {clientmod} was not found!" + " It must be located at {clientmod_folder}.", + ) + else: + mods_config.write(f"load_mod_{clientmod} = true\n") + def _reset_zmq(self): if self.socket: self.socket.close() @@ -264,7 +284,8 @@ def _reset_minetest(self): # Determine log paths reset_timestamp = datetime.datetime.now().strftime("%m-%d-%Y,%H:%M:%S") log_path = os.path.join( - self.log_dir, f"{{}}_{reset_timestamp}_{self.unique_env_id}.log", + self.log_dir, + f"{{}}_{reset_timestamp}_{self.unique_env_id}.log", ) # (Re)start Minetest server @@ -296,7 +317,7 @@ def _delete_world(self): shutil.rmtree(self.world_dir) else: raise RuntimeError( - "World directory was not set. Please, provide a world directory" + "World directory was not set. Please, provide a world directory " "in the constructor or seed the environment!", ) @@ -306,7 +327,7 @@ def _delete_config(self): os.remove(self.config_path) else: raise RuntimeError( - "Minetest config path was not set. Please, provide a config path" + "Minetest config path was not set. Please, provide a config path " "in the constructor or seed the environment!", ) @@ -342,7 +363,6 @@ def seed(self, seed: int): if self.config_path is None: self.config_path = os.path.join(self.root_dir, f"{self.unique_env_id}.conf") self._write_config() - # TODO seed used libraries, like numpy, pytorch etc. def reset(self): if self.start_minetest: @@ -361,7 +381,8 @@ def reset(self): def step(self, action: Dict[str, Any]): # Send action - action["MOUSE"] = action["MOUSE"].tolist() + if isinstance(action["MOUSE"], np.ndarray): + action["MOUSE"] = action["MOUSE"].tolist() logging.debug("Sending action: {}".format(action)) pb_action = pack_pb_action(action) self.socket.send(pb_action.SerializeToString())