Update GODOT part

This commit is contained in:
Vasilis Valatsos 2024-06-13 18:44:02 +02:00
parent 9499204ec8
commit dd3c7c814b
346 changed files with 682 additions and 683 deletions

0
addons/Todo_Manager/CONTRIBUTING.md Normal file → Executable file
View file

0
addons/Todo_Manager/ColourPicker.gd Normal file → Executable file
View file

0
addons/Todo_Manager/Current.gd Normal file → Executable file
View file

0
addons/Todo_Manager/Dock.gd Normal file → Executable file
View file

0
addons/Todo_Manager/Pattern.gd Normal file → Executable file
View file

0
addons/Todo_Manager/Project.gd Normal file → Executable file
View file

0
addons/Todo_Manager/README.md Normal file → Executable file
View file

0
addons/Todo_Manager/READMECN.md Normal file → Executable file
View file

0
addons/Todo_Manager/UI/ColourPicker.tscn Normal file → Executable file
View file

0
addons/Todo_Manager/UI/Dock.tscn Normal file → Executable file
View file

0
addons/Todo_Manager/UI/Pattern.tscn Normal file → Executable file
View file

0
addons/Todo_Manager/doc/example.gd Normal file → Executable file
View file

0
addons/Todo_Manager/doc/images/Instruct1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

0
addons/Todo_Manager/doc/images/Instruct2.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

0
addons/Todo_Manager/doc/images/Instruct3.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

0
addons/Todo_Manager/doc/images/Instruct4.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

0
addons/Todo_Manager/doc/images/Instruct5.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

0
addons/Todo_Manager/doc/images/TODO_Manager_Logo.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

0
addons/Todo_Manager/doc/images/TodoExternal.gif Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 243 KiB

0
addons/Todo_Manager/doc/images/example1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

0
addons/Todo_Manager/doc/images/example2.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

0
addons/Todo_Manager/plugin.cfg Normal file → Executable file
View file

0
addons/Todo_Manager/plugin.gd Normal file → Executable file
View file

0
addons/Todo_Manager/todoItem_class.gd Normal file → Executable file
View file

0
addons/Todo_Manager/todo_class.gd Normal file → Executable file
View file

View file

@ -34,37 +34,37 @@ var _player: Node2D
func _ready(): func _ready():
add_to_group("AGENT") add_to_group("AGENT")
func init(player: Node2D): func init(player: Node2D):
_player = player _player = player
#-- Methods that need implementing using the "extend script" option in Godot --# #-- Methods that need implementing using the "extend script" option in Godot --#
func get_obs() -> Dictionary: func get_obs() -> Dictionary:
assert(false, "the get_obs method is not implemented when extending from ai_controller") assert(false, "the get_obs method is not implemented when extending from ai_controller")
return {"obs": []} return {"obs": []}
func get_reward() -> float: func get_reward() -> float:
assert(false, "the get_reward method is not implemented when extending from ai_controller") assert(false, "the get_reward method is not implemented when extending from ai_controller")
return 0.0 return 0.0
func get_action_space() -> Dictionary: func get_action_space() -> Dictionary:
assert( assert(
false, false,
"the get get_action_space method is not implemented when extending from ai_controller" "the get get_action_space method is not implemented when extending from ai_controller"
) )
return { return {
"example_actions_continous": {"size": 2, "action_type": "continuous"}, "example_actions_continous": {"size": 2, "action_type": "continuous"},
"example_actions_discrete": {"size": 2, "action_type": "discrete"}, "example_actions_discrete": {"size": 2, "action_type": "discrete"},
} }
func set_action(action) -> void: func set_action(action) -> void:
assert(false, "the set_action method is not implemented when extending from ai_controller") assert(false, "the set_action method is not implemented when extending from ai_controller")
#-----------------------------------------------------------------------------# #-----------------------------------------------------------------------------#
@ -73,47 +73,47 @@ func set_action(action) -> void:
#-- Methods that sometimes need implementing using the "extend script" option in Godot --# #-- Methods that sometimes need implementing using the "extend script" option in Godot --#
# Only needed if you are recording expert demos with this AIController # Only needed if you are recording expert demos with this AIController
func get_action() -> Array: func get_action() -> Array:
assert(false, "the get_action method is not implemented in extended AIController but demo_recorder is used") assert(false, "the get_action method is not implemented in extended AIController but demo_recorder is used")
return [] return []
# -----------------------------------------------------------------------------# # -----------------------------------------------------------------------------#
func _physics_process(delta): func _physics_process(delta):
n_steps += 1 n_steps += 1
if n_steps > reset_after: if n_steps > reset_after:
needs_reset = true needs_reset = true
func get_obs_space(): func get_obs_space():
# may need overriding if the obs space is complex # may need overriding if the obs space is complex
var obs = get_obs() var obs = get_obs()
return { return {
"obs": {"size": [len(obs["obs"])], "space": "box"}, "obs": {"size": [len(obs["obs"])], "space": "box"},
} }
func reset(): func reset():
n_steps = 0 n_steps = 0
needs_reset = false needs_reset = false
func reset_if_done(): func reset_if_done():
if done: if done:
reset() reset()
func set_heuristic(h): func set_heuristic(h):
# sets the heuristic from "human" or "model" nothing to change here # sets the heuristic from "human" or "model" nothing to change here
heuristic = h heuristic = h
func get_done(): func get_done():
return done return done
func set_done_false(): func set_done_false():
done = false done = false
func zero_reward(): func zero_reward():
reward = 0.0 reward = 0.0

0
addons/godot_rl_agents/controller/ai_controller_3d.gd Normal file → Executable file
View file

0
addons/godot_rl_agents/godot_rl_agents.gd Normal file → Executable file
View file

0
addons/godot_rl_agents/icon.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 198 B

0
addons/godot_rl_agents/onnx/csharp/ONNXInference.cs Normal file → Executable file
View file

View file

View file

View file

0
addons/godot_rl_agents/onnx/wrapper/ONNX_wrapper.gd Normal file → Executable file
View file

0
addons/godot_rl_agents/plugin.cfg Normal file → Executable file
View file

View file

View file

0
addons/godot_rl_agents/sensors/sensors_2d/ISensor2D.gd Normal file → Executable file
View file

View file

View file

View file

View file

0
addons/godot_rl_agents/sensors/sensors_3d/ISensor3D.gd Normal file → Executable file
View file

View file

View file

View file

View file

View file

@ -51,430 +51,430 @@ var _obs_space_training: Array[Dictionary] = []
# Called when the node enters the scene tree for the first time. # Called when the node enters the scene tree for the first time.
func _ready(): func _ready():
await get_tree().root.ready await get_tree().root.ready
get_tree().set_pause(true) get_tree().set_pause(true)
_initialize() _initialize()
await get_tree().create_timer(1.0).timeout await get_tree().create_timer(1.0).timeout
get_tree().set_pause(false) get_tree().set_pause(false)
func _initialize(): func _initialize():
_get_agents() _get_agents()
args = _get_args() args = _get_args()
Engine.physics_ticks_per_second = _get_speedup() * 60 # Replace with function body. Engine.physics_ticks_per_second = _get_speedup() * 60 # Replace with function body.
Engine.time_scale = _get_speedup() * 1.0 Engine.time_scale = _get_speedup() * 1.0
prints( prints(
"physics ticks", "physics ticks",
Engine.physics_ticks_per_second, Engine.physics_ticks_per_second,
Engine.time_scale, Engine.time_scale,
_get_speedup(), _get_speedup(),
speed_up speed_up
) )
_set_heuristic("human", all_agents) _set_heuristic("human", all_agents)
_initialize_training_agents() _initialize_training_agents()
_initialize_inference_agents() _initialize_inference_agents()
_initialize_demo_recording() _initialize_demo_recording()
_set_seed() _set_seed()
_set_action_repeat() _set_action_repeat()
initialized = true initialized = true
func _initialize_training_agents(): func _initialize_training_agents():
if agents_training.size() > 0: if agents_training.size() > 0:
_obs_space_training.resize(agents_training.size()) _obs_space_training.resize(agents_training.size())
_action_space_training.resize(agents_training.size()) _action_space_training.resize(agents_training.size())
for agent_idx in range(0, agents_training.size()): for agent_idx in range(0, agents_training.size()):
_obs_space_training[agent_idx] = agents_training[agent_idx].get_obs_space() _obs_space_training[agent_idx] = agents_training[agent_idx].get_obs_space()
_action_space_training[agent_idx] = agents_training[agent_idx].get_action_space() _action_space_training[agent_idx] = agents_training[agent_idx].get_action_space()
connected = connect_to_server() connected = connect_to_server()
if connected: if connected:
_set_heuristic("model", agents_training) _set_heuristic("model", agents_training)
_handshake() _handshake()
_send_env_info() _send_env_info()
else: else:
push_warning( push_warning(
"Couldn't connect to Python server, using human controls instead. ", "Couldn't connect to Python server, using human controls instead. ",
"Did you start the training server using e.g. `gdrl` from the console?" "Did you start the training server using e.g. `gdrl` from the console?"
) )
func _initialize_inference_agents(): func _initialize_inference_agents():
if agents_inference.size() > 0: if agents_inference.size() > 0:
if control_mode == ControlModes.ONNX_INFERENCE: if control_mode == ControlModes.ONNX_INFERENCE:
assert( assert(
FileAccess.file_exists(onnx_model_path), FileAccess.file_exists(onnx_model_path),
"Onnx Model Path set on Sync node does not exist: %s" % onnx_model_path "Onnx Model Path set on Sync node does not exist: %s" % onnx_model_path
) )
onnx_models[onnx_model_path] = ONNXModel.new(onnx_model_path, 1) onnx_models[onnx_model_path] = ONNXModel.new(onnx_model_path, 1)
for agent in agents_inference: for agent in agents_inference:
var action_space = agent.get_action_space() var action_space = agent.get_action_space()
_action_space_inference.append(action_space) _action_space_inference.append(action_space)
var agent_onnx_model: ONNXModel var agent_onnx_model: ONNXModel
if agent.onnx_model_path.is_empty(): if agent.onnx_model_path.is_empty():
assert( assert(
onnx_models.has(onnx_model_path), onnx_models.has(onnx_model_path),
( (
"Node %s has no onnx model path set " % agent.get_path() "Node %s has no onnx model path set " % agent.get_path()
+ "and sync node's control mode is not set to OnnxInference. " + "and sync node's control mode is not set to OnnxInference. "
+ "Either add the path to the AIController, " + "Either add the path to the AIController, "
+ "or if you want to use the path set on sync node instead, " + "or if you want to use the path set on sync node instead, "
+ "set control mode to OnnxInference." + "set control mode to OnnxInference."
) )
) )
prints( prints(
"Info: AIController %s" % agent.get_path(), "Info: AIController %s" % agent.get_path(),
"has no onnx model path set.", "has no onnx model path set.",
"Using path set on the sync node instead." "Using path set on the sync node instead."
) )
agent_onnx_model = onnx_models[onnx_model_path] agent_onnx_model = onnx_models[onnx_model_path]
else: else:
if not onnx_models.has(agent.onnx_model_path): if not onnx_models.has(agent.onnx_model_path):
assert( assert(
FileAccess.file_exists(agent.onnx_model_path), FileAccess.file_exists(agent.onnx_model_path),
( (
"Onnx Model Path set on %s node does not exist: %s" "Onnx Model Path set on %s node does not exist: %s"
% [agent.get_path(), agent.onnx_model_path] % [agent.get_path(), agent.onnx_model_path]
) )
) )
onnx_models[agent.onnx_model_path] = ONNXModel.new(agent.onnx_model_path, 1) onnx_models[agent.onnx_model_path] = ONNXModel.new(agent.onnx_model_path, 1)
agent_onnx_model = onnx_models[agent.onnx_model_path] agent_onnx_model = onnx_models[agent.onnx_model_path]
agent.onnx_model = agent_onnx_model agent.onnx_model = agent_onnx_model
if not agent_onnx_model.action_means_only_set: if not agent_onnx_model.action_means_only_set:
agent_onnx_model.set_action_means_only(action_space) agent_onnx_model.set_action_means_only(action_space)
_set_heuristic("model", agents_inference) _set_heuristic("model", agents_inference)
func _initialize_demo_recording(): func _initialize_demo_recording():
if agent_demo_record: if agent_demo_record:
expert_demo_save_path = agent_demo_record.expert_demo_save_path expert_demo_save_path = agent_demo_record.expert_demo_save_path
assert( assert(
not expert_demo_save_path.is_empty(), not expert_demo_save_path.is_empty(),
"Expert demo save path set in %s is empty." % agent_demo_record.get_path() "Expert demo save path set in %s is empty." % agent_demo_record.get_path()
) )
InputMap.add_action("RemoveLastDemoEpisode") InputMap.add_action("RemoveLastDemoEpisode")
InputMap.action_add_event( InputMap.action_add_event(
"RemoveLastDemoEpisode", agent_demo_record.remove_last_episode_key "RemoveLastDemoEpisode", agent_demo_record.remove_last_episode_key
) )
current_demo_trajectory.resize(2) current_demo_trajectory.resize(2)
current_demo_trajectory[0] = [] current_demo_trajectory[0] = []
current_demo_trajectory[1] = [] current_demo_trajectory[1] = []
agent_demo_record.heuristic = "demo_record" agent_demo_record.heuristic = "demo_record"
func _physics_process(_delta): func _physics_process(_delta):
# two modes, human control, agent control # two modes, human control, agent control
# pause tree, send obs, get actions, set actions, unpause tree # pause tree, send obs, get actions, set actions, unpause tree
_demo_record_process() _demo_record_process()
if n_action_steps % action_repeat != 0: if n_action_steps % action_repeat != 0:
n_action_steps += 1 n_action_steps += 1
return return
n_action_steps += 1 n_action_steps += 1
_training_process() _training_process()
_inference_process() _inference_process()
_heuristic_process() _heuristic_process()
func _training_process(): func _training_process():
if connected: if connected:
get_tree().set_pause(true) get_tree().set_pause(true)
if just_reset: if just_reset:
just_reset = false just_reset = false
var obs = _get_obs_from_agents(agents_training) var obs = _get_obs_from_agents(agents_training)
var reply = {"type": "reset", "obs": obs} var reply = {"type": "reset", "obs": obs}
_send_dict_as_json_message(reply) _send_dict_as_json_message(reply)
# this should go straight to getting the action and setting it checked the agent, no need to perform one phyics tick # this should go straight to getting the action and setting it checked the agent, no need to perform one phyics tick
get_tree().set_pause(false) get_tree().set_pause(false)
return return
if need_to_send_obs: if need_to_send_obs:
need_to_send_obs = false need_to_send_obs = false
var reward = _get_reward_from_agents() var reward = _get_reward_from_agents()
var done = _get_done_from_agents() var done = _get_done_from_agents()
#_reset_agents_if_done() # this ensures the new observation is from the next env instance : NEEDS REFACTOR #_reset_agents_if_done() # this ensures the new observation is from the next env instance : NEEDS REFACTOR
var obs = _get_obs_from_agents(agents_training) var obs = _get_obs_from_agents(agents_training)
var reply = {"type": "step", "obs": obs, "reward": reward, "done": done} var reply = {"type": "step", "obs": obs, "reward": reward, "done": done}
_send_dict_as_json_message(reply) _send_dict_as_json_message(reply)
var handled = handle_message() var handled = handle_message()
func _inference_process(): func _inference_process():
if agents_inference.size() > 0: if agents_inference.size() > 0:
var obs: Array = _get_obs_from_agents(agents_inference) var obs: Array = _get_obs_from_agents(agents_inference)
var actions = [] var actions = []
for agent_id in range(0, agents_inference.size()): for agent_id in range(0, agents_inference.size()):
var model: ONNXModel = agents_inference[agent_id].onnx_model var model: ONNXModel = agents_inference[agent_id].onnx_model
var action = model.run_inference( var action = model.run_inference(
obs[agent_id]["obs"], 1.0 obs[agent_id]["obs"], 1.0
) )
var action_dict = _extract_action_dict( var action_dict = _extract_action_dict(
action["output"], _action_space_inference[agent_id], model.action_means_only action["output"], _action_space_inference[agent_id], model.action_means_only
) )
actions.append(action_dict) actions.append(action_dict)
_set_agent_actions(actions, agents_inference) _set_agent_actions(actions, agents_inference)
_reset_agents_if_done(agents_inference) _reset_agents_if_done(agents_inference)
get_tree().set_pause(false) get_tree().set_pause(false)
func _demo_record_process(): func _demo_record_process():
if not agent_demo_record: if not agent_demo_record:
return return
if Input.is_action_just_pressed("RemoveLastDemoEpisode"): if Input.is_action_just_pressed("RemoveLastDemoEpisode"):
print("[Sync script][Demo recorder] Removing last recorded episode.") print("[Sync script][Demo recorder] Removing last recorded episode.")
demo_trajectories.remove_at(demo_trajectories.size() - 1) demo_trajectories.remove_at(demo_trajectories.size() - 1)
print("Remaining episode count: %d" % demo_trajectories.size()) print("Remaining episode count: %d" % demo_trajectories.size())
if n_action_steps % agent_demo_record.action_repeat != 0: if n_action_steps % agent_demo_record.action_repeat != 0:
return return
var obs_dict: Dictionary = agent_demo_record.get_obs() var obs_dict: Dictionary = agent_demo_record.get_obs()
# Get the current obs from the agent # Get the current obs from the agent
assert( assert(
obs_dict.has("obs"), obs_dict.has("obs"),
"Demo recorder needs an 'obs' key in get_obs() returned dictionary to record obs from." "Demo recorder needs an 'obs' key in get_obs() returned dictionary to record obs from."
) )
current_demo_trajectory[0].append(obs_dict.obs) current_demo_trajectory[0].append(obs_dict.obs)
# Get the action applied for the current obs from the agent # Get the action applied for the current obs from the agent
agent_demo_record.set_action() agent_demo_record.set_action()
var acts = agent_demo_record.get_action() var acts = agent_demo_record.get_action()
var terminal = agent_demo_record.get_done() var terminal = agent_demo_record.get_done()
# Record actions only for non-terminal states # Record actions only for non-terminal states
if terminal: if terminal:
agent_demo_record.set_done_false() agent_demo_record.set_done_false()
else: else:
current_demo_trajectory[1].append(acts) current_demo_trajectory[1].append(acts)
if terminal: if terminal:
#current_demo_trajectory[2].append(true) #current_demo_trajectory[2].append(true)
demo_trajectories.append(current_demo_trajectory.duplicate(true)) demo_trajectories.append(current_demo_trajectory.duplicate(true))
print("[Sync script][Demo recorder] Recorded episode count: %d" % demo_trajectories.size()) print("[Sync script][Demo recorder] Recorded episode count: %d" % demo_trajectories.size())
current_demo_trajectory[0].clear() current_demo_trajectory[0].clear()
current_demo_trajectory[1].clear() current_demo_trajectory[1].clear()
func _heuristic_process(): func _heuristic_process():
for agent in agents_heuristic: for agent in agents_heuristic:
_reset_agents_if_done(agents_heuristic) _reset_agents_if_done(agents_heuristic)
func _extract_action_dict(action_array: Array, action_space: Dictionary, action_means_only: bool): func _extract_action_dict(action_array: Array, action_space: Dictionary, action_means_only: bool):
var index = 0 var index = 0
var result = {} var result = {}
for key in action_space.keys(): for key in action_space.keys():
var size = action_space[key]["size"] var size = action_space[key]["size"]
var action_type = action_space[key]["action_type"] var action_type = action_space[key]["action_type"]
if action_type == "discrete": if action_type == "discrete":
var largest_logit: float # Value of the largest logit for this action in the actions array var largest_logit: float # Value of the largest logit for this action in the actions array
var largest_logit_idx: int # Index of the largest logit for this action in the actions array var largest_logit_idx: int # Index of the largest logit for this action in the actions array
for logit_idx in range(0, size): for logit_idx in range(0, size):
var logit_value = action_array[index + logit_idx] var logit_value = action_array[index + logit_idx]
if logit_value > largest_logit: if logit_value > largest_logit:
largest_logit = logit_value largest_logit = logit_value
largest_logit_idx = logit_idx largest_logit_idx = logit_idx
result[key] = largest_logit_idx # Index of the largest logit is the discrete action value result[key] = largest_logit_idx # Index of the largest logit is the discrete action value
index += size index += size
elif action_type == "continuous": elif action_type == "continuous":
# For continous actions, we only take the action mean values # For continous actions, we only take the action mean values
result[key] = clamp_array(action_array.slice(index, index + size), -1.0, 1.0) result[key] = clamp_array(action_array.slice(index, index + size), -1.0, 1.0)
if action_means_only: if action_means_only:
index += size # model only outputs action means, so we move index by size index += size # model only outputs action means, so we move index by size
else: else:
index += size * 2 # model outputs logstd after action mean, we skip the logstd part index += size * 2 # model outputs logstd after action mean, we skip the logstd part
else: else:
assert(false, 'Only "discrete" and "continuous" action types supported. Found: %s action type set.' % action_type) assert(false, 'Only "discrete" and "continuous" action types supported. Found: %s action type set.' % action_type)
return result return result
## For AIControllers that inherit mode from sync, sets the correct mode. ## For AIControllers that inherit mode from sync, sets the correct mode.
func _set_agent_mode(agent: Node): func _set_agent_mode(agent: Node):
var agent_inherits_mode: bool = agent.control_mode == agent.ControlModes.INHERIT_FROM_SYNC var agent_inherits_mode: bool = agent.control_mode == agent.ControlModes.INHERIT_FROM_SYNC
if agent_inherits_mode: if agent_inherits_mode:
match control_mode: match control_mode:
ControlModes.HUMAN: ControlModes.HUMAN:
agent.control_mode = agent.ControlModes.HUMAN agent.control_mode = agent.ControlModes.HUMAN
ControlModes.TRAINING: ControlModes.TRAINING:
agent.control_mode = agent.ControlModes.TRAINING agent.control_mode = agent.ControlModes.TRAINING
ControlModes.ONNX_INFERENCE: ControlModes.ONNX_INFERENCE:
agent.control_mode = agent.ControlModes.ONNX_INFERENCE agent.control_mode = agent.ControlModes.ONNX_INFERENCE
func _get_agents(): func _get_agents():
all_agents = get_tree().get_nodes_in_group("AGENT") all_agents = get_tree().get_nodes_in_group("AGENT")
for agent in all_agents: for agent in all_agents:
_set_agent_mode(agent) _set_agent_mode(agent)
if agent.control_mode == agent.ControlModes.TRAINING: if agent.control_mode == agent.ControlModes.TRAINING:
agents_training.append(agent) agents_training.append(agent)
elif agent.control_mode == agent.ControlModes.ONNX_INFERENCE: elif agent.control_mode == agent.ControlModes.ONNX_INFERENCE:
agents_inference.append(agent) agents_inference.append(agent)
elif agent.control_mode == agent.ControlModes.HUMAN: elif agent.control_mode == agent.ControlModes.HUMAN:
agents_heuristic.append(agent) agents_heuristic.append(agent)
elif agent.control_mode == agent.ControlModes.RECORD_EXPERT_DEMOS: elif agent.control_mode == agent.ControlModes.RECORD_EXPERT_DEMOS:
assert( assert(
not agent_demo_record, not agent_demo_record,
"Currently only a single AIController can be used for recording expert demos." "Currently only a single AIController can be used for recording expert demos."
) )
agent_demo_record = agent agent_demo_record = agent
var training_agent_count = agents_training.size() var training_agent_count = agents_training.size()
agents_training_policy_names.resize(training_agent_count) agents_training_policy_names.resize(training_agent_count)
for i in range(0, training_agent_count): for i in range(0, training_agent_count):
agents_training_policy_names[i] = agents_training[i].policy_name agents_training_policy_names[i] = agents_training[i].policy_name
func _set_heuristic(heuristic, agents: Array): func _set_heuristic(heuristic, agents: Array):
for agent in agents: for agent in agents:
agent.set_heuristic(heuristic) agent.set_heuristic(heuristic)
func _handshake(): func _handshake():
print("performing handshake") print("performing handshake")
var json_dict = _get_dict_json_message() var json_dict = _get_dict_json_message()
assert(json_dict["type"] == "handshake") assert(json_dict["type"] == "handshake")
var major_version = json_dict["major_version"] var major_version = json_dict["major_version"]
var minor_version = json_dict["minor_version"] var minor_version = json_dict["minor_version"]
if major_version != MAJOR_VERSION: if major_version != MAJOR_VERSION:
print("WARNING: major verison mismatch ", major_version, " ", MAJOR_VERSION) print("WARNING: major verison mismatch ", major_version, " ", MAJOR_VERSION)
if minor_version != MINOR_VERSION: if minor_version != MINOR_VERSION:
print("WARNING: minor verison mismatch ", minor_version, " ", MINOR_VERSION) print("WARNING: minor verison mismatch ", minor_version, " ", MINOR_VERSION)
print("handshake complete") print("handshake complete")
func _get_dict_json_message(): func _get_dict_json_message():
# returns a dictionary from of the most recent message # returns a dictionary from of the most recent message
# this is not waiting # this is not waiting
while stream.get_available_bytes() == 0: while stream.get_available_bytes() == 0:
stream.poll() stream.poll()
if stream.get_status() != 2: if stream.get_status() != 2:
print("server disconnected status, closing") print("server disconnected status, closing")
get_tree().quit() get_tree().quit()
return null return null
OS.delay_usec(10) OS.delay_usec(10)
var message = stream.get_string() var message = stream.get_string()
var json_data = JSON.parse_string(message) var json_data = JSON.parse_string(message)
return json_data return json_data
func _send_dict_as_json_message(dict): func _send_dict_as_json_message(dict):
stream.put_string(JSON.stringify(dict, "", false)) stream.put_string(JSON.stringify(dict, "", false))
func _send_env_info(): func _send_env_info():
var json_dict = _get_dict_json_message() var json_dict = _get_dict_json_message()
assert(json_dict["type"] == "env_info") assert(json_dict["type"] == "env_info")
var message = { var message = {
"type": "env_info", "type": "env_info",
"observation_space": _obs_space_training, "observation_space": _obs_space_training,
"action_space": _action_space_training, "action_space": _action_space_training,
"n_agents": len(agents_training), "n_agents": len(agents_training),
"agent_policy_names": agents_training_policy_names "agent_policy_names": agents_training_policy_names
} }
_send_dict_as_json_message(message) _send_dict_as_json_message(message)
func connect_to_server(): func connect_to_server():
print("Waiting for one second to allow server to start") print("Waiting for one second to allow server to start")
OS.delay_msec(1000) OS.delay_msec(1000)
print("trying to connect to server") print("trying to connect to server")
stream = StreamPeerTCP.new() stream = StreamPeerTCP.new()
# "localhost" was not working on windows VM, had to use the IP # "localhost" was not working on windows VM, had to use the IP
var ip = "127.0.0.1" var ip = "127.0.0.1"
var port = _get_port() var port = _get_port()
var connect = stream.connect_to_host(ip, port) var connect = stream.connect_to_host(ip, port)
stream.set_no_delay(true) # TODO check if this improves performance or not stream.set_no_delay(true) # TODO check if this improves performance or not
stream.poll() stream.poll()
# Fetch the status until it is either connected (2) or failed to connect (3) # Fetch the status until it is either connected (2) or failed to connect (3)
while stream.get_status() < 2: while stream.get_status() < 2:
stream.poll() stream.poll()
return stream.get_status() == 2 return stream.get_status() == 2
func _get_args(): func _get_args():
print("getting command line arguments") print("getting command line arguments")
var arguments = {} var arguments = {}
for argument in OS.get_cmdline_args(): for argument in OS.get_cmdline_args():
print(argument) print(argument)
if argument.find("=") > -1: if argument.find("=") > -1:
var key_value = argument.split("=") var key_value = argument.split("=")
arguments[key_value[0].lstrip("--")] = key_value[1] arguments[key_value[0].lstrip("--")] = key_value[1]
else: else:
# Options without an argument will be present in the dictionary, # Options without an argument will be present in the dictionary,
# with the value set to an empty string. # with the value set to an empty string.
arguments[argument.lstrip("--")] = "" arguments[argument.lstrip("--")] = ""
return arguments return arguments
func _get_speedup(): func _get_speedup():
print(args) print(args)
return args.get("speedup", str(speed_up)).to_float() return args.get("speedup", str(speed_up)).to_float()
func _get_port(): func _get_port():
return args.get("port", DEFAULT_PORT).to_int() return args.get("port", DEFAULT_PORT).to_int()
func _set_seed(): func _set_seed():
var _seed = args.get("env_seed", DEFAULT_SEED).to_int() var _seed = args.get("env_seed", DEFAULT_SEED).to_int()
seed(_seed) seed(_seed)
func _set_action_repeat(): func _set_action_repeat():
action_repeat = args.get("action_repeat", str(action_repeat)).to_int() action_repeat = args.get("action_repeat", str(action_repeat)).to_int()
func disconnect_from_server(): func disconnect_from_server():
stream.disconnect_from_host() stream.disconnect_from_host()
func handle_message() -> bool: func handle_message() -> bool:
# get json message: reset, step, close # get json message: reset, step, close
var message = _get_dict_json_message() var message = _get_dict_json_message()
if message["type"] == "close": if message["type"] == "close":
print("received close message, closing game") print("received close message, closing game")
get_tree().quit() get_tree().quit()
get_tree().set_pause(false) get_tree().set_pause(false)
return true return true
if message["type"] == "reset": if message["type"] == "reset":
print("resetting all agents") print("resetting all agents")
_reset_agents() _reset_agents()
just_reset = true just_reset = true
get_tree().set_pause(false) get_tree().set_pause(false)
#print("resetting forcing draw") #print("resetting forcing draw")
# RenderingServer.force_draw() # RenderingServer.force_draw()
# var obs = _get_obs_from_agents() # var obs = _get_obs_from_agents()
# print("obs ", obs) # print("obs ", obs)
@ -483,97 +483,97 @@ func handle_message() -> bool:
# "obs": obs # "obs": obs
# } # }
# _send_dict_as_json_message(reply) # _send_dict_as_json_message(reply)
return true return true
if message["type"] == "call": if message["type"] == "call":
var method = message["method"] var method = message["method"]
var returns = _call_method_on_agents(method) var returns = _call_method_on_agents(method)
var reply = {"type": "call", "returns": returns} var reply = {"type": "call", "returns": returns}
print("calling method from Python") print("calling method from Python")
_send_dict_as_json_message(reply) _send_dict_as_json_message(reply)
return handle_message() return handle_message()
if message["type"] == "action": if message["type"] == "action":
var action = message["action"] var action = message["action"]
_set_agent_actions(action, agents_training) _set_agent_actions(action, agents_training)
need_to_send_obs = true need_to_send_obs = true
get_tree().set_pause(false) get_tree().set_pause(false)
return true return true
print("message was not handled") print("message was not handled")
return false return false
func _call_method_on_agents(method): func _call_method_on_agents(method):
var returns = [] var returns = []
for agent in all_agents: for agent in all_agents:
returns.append(agent.call(method)) returns.append(agent.call(method))
return returns return returns
func _reset_agents_if_done(agents = all_agents): func _reset_agents_if_done(agents = all_agents):
for agent in agents: for agent in agents:
if agent.get_done(): if agent.get_done():
agent.set_done_false() agent.set_done_false()
func _reset_agents(agents = all_agents): func _reset_agents(agents = all_agents):
for agent in agents: for agent in agents:
agent.needs_reset = true agent.needs_reset = true
#agent.reset() #agent.reset()
func _get_obs_from_agents(agents: Array = all_agents): func _get_obs_from_agents(agents: Array = all_agents):
var obs = [] var obs = []
for agent in agents: for agent in agents:
obs.append(agent.get_obs()) obs.append(agent.get_obs())
return obs return obs
func _get_reward_from_agents(agents: Array = agents_training): func _get_reward_from_agents(agents: Array = agents_training):
var rewards = [] var rewards = []
for agent in agents: for agent in agents:
rewards.append(agent.get_reward()) rewards.append(agent.get_reward())
agent.zero_reward() agent.zero_reward()
return rewards return rewards
func _get_done_from_agents(agents: Array = agents_training): func _get_done_from_agents(agents: Array = agents_training):
var dones = [] var dones = []
for agent in agents: for agent in agents:
var done = agent.get_done() var done = agent.get_done()
if done: if done:
agent.set_done_false() agent.set_done_false()
dones.append(done) dones.append(done)
return dones return dones
func _set_agent_actions(actions, agents: Array = all_agents): func _set_agent_actions(actions, agents: Array = all_agents):
for i in range(len(actions)): for i in range(len(actions)):
agents[i].set_action(actions[i]) agents[i].set_action(actions[i])
func clamp_array(arr: Array, min: float, max: float): func clamp_array(arr: Array, min: float, max: float):
var output: Array = [] var output: Array = []
for a in arr: for a in arr:
output.append(clamp(a, min, max)) output.append(clamp(a, min, max))
return output return output
## Save recorded export demos on window exit (Close game window instead of "Stop" button in Godot Editor) ## Save recorded export demos on window exit (Close game window instead of "Stop" button in Godot Editor)
func _notification(what): func _notification(what):
if demo_trajectories.size() == 0 or expert_demo_save_path.is_empty(): if demo_trajectories.size() == 0 or expert_demo_save_path.is_empty():
return return
if what == NOTIFICATION_PREDELETE: if what == NOTIFICATION_PREDELETE:
var json_string = JSON.stringify(demo_trajectories, "", false) var json_string = JSON.stringify(demo_trajectories, "", false)
var file = FileAccess.open(expert_demo_save_path, FileAccess.WRITE) var file = FileAccess.open(expert_demo_save_path, FileAccess.WRITE)
if not file: if not file:
var error: Error = FileAccess.get_open_error() var error: Error = FileAccess.get_open_error()
assert(not error, "There was an error opening the file: %d" % error) assert(not error, "There was an error opening the file: %d" % error)
file.store_line(json_string) file.store_line(json_string)
var error = file.get_error() var error = file.get_error()
assert(not error, "There was an error after trying to write to the file: %d" % error) assert(not error, "There was an error after trying to write to the file: %d" % error)

0
assets/audio/Fire.wav Normal file → Executable file
View file

0
assets/audio/attack/claw.wav Normal file → Executable file
View file

0
assets/audio/attack/fireball.wav Normal file → Executable file
View file

0
assets/audio/attack/slash.wav Normal file → Executable file
View file

0
assets/audio/death.wav Normal file → Executable file
View file

0
assets/audio/heal.wav Normal file → Executable file
View file

0
assets/audio/hit.wav Normal file → Executable file
View file

0
assets/audio/main.ogg Normal file → Executable file
View file

0
assets/audio/sword.wav Normal file → Executable file
View file

0
assets/graphics/font/joystix.ttf Normal file → Executable file
View file

0
assets/graphics/grass/grass_1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 494 B

0
assets/graphics/grass/grass_2.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 500 B

After

Width:  |  Height:  |  Size: 500 B

0
assets/graphics/grass/grass_3.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 575 B

After

Width:  |  Height:  |  Size: 575 B

0
assets/graphics/monsters/bamboo/attack/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 487 B

0
assets/graphics/monsters/bamboo/idle/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 487 B

0
assets/graphics/monsters/bamboo/idle/1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 517 B

After

Width:  |  Height:  |  Size: 517 B

0
assets/graphics/monsters/bamboo/idle/2.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 487 B

0
assets/graphics/monsters/bamboo/idle/3.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 504 B

After

Width:  |  Height:  |  Size: 504 B

0
assets/graphics/monsters/bamboo/move/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 487 B

0
assets/graphics/monsters/bamboo/move/1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 517 B

After

Width:  |  Height:  |  Size: 517 B

0
assets/graphics/monsters/bamboo/move/2.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 487 B

0
assets/graphics/monsters/bamboo/move/3.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 504 B

After

Width:  |  Height:  |  Size: 504 B

0
assets/graphics/monsters/raccoon/attack/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

0
assets/graphics/monsters/raccoon/attack/1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

0
assets/graphics/monsters/raccoon/attack/2.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

0
assets/graphics/monsters/raccoon/attack/3.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

0
assets/graphics/monsters/raccoon/idle/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

0
assets/graphics/monsters/raccoon/idle/1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

0
assets/graphics/monsters/raccoon/idle/2.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

0
assets/graphics/monsters/raccoon/idle/3.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

0
assets/graphics/monsters/raccoon/idle/4.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

0
assets/graphics/monsters/raccoon/idle/5.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

0
assets/graphics/monsters/raccoon/move/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
assets/graphics/monsters/raccoon/move/1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
assets/graphics/monsters/raccoon/move/2.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

0
assets/graphics/monsters/raccoon/move/3.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

0
assets/graphics/monsters/raccoon/move/4.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
assets/graphics/monsters/spirit/attack/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 426 B

0
assets/graphics/monsters/spirit/idle/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 420 B

0
assets/graphics/monsters/spirit/idle/1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 417 B

After

Width:  |  Height:  |  Size: 417 B

0
assets/graphics/monsters/spirit/idle/2.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 406 B

0
assets/graphics/monsters/spirit/idle/3.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 418 B

After

Width:  |  Height:  |  Size: 418 B

0
assets/graphics/monsters/spirit/move/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 426 B

0
assets/graphics/monsters/spirit/move/1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 425 B

After

Width:  |  Height:  |  Size: 425 B

0
assets/graphics/monsters/spirit/move/2.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 414 B

After

Width:  |  Height:  |  Size: 414 B

0
assets/graphics/monsters/spirit/move/3.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 413 B

After

Width:  |  Height:  |  Size: 413 B

0
assets/graphics/monsters/squid/attack/0 - Copy (2).png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 463 B

0
assets/graphics/monsters/squid/attack/0 - Copy (3).png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 463 B

0
assets/graphics/monsters/squid/attack/0 - Copy.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 463 B

0
assets/graphics/monsters/squid/attack/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 463 B

0
assets/graphics/monsters/squid/idle/0.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 463 B

0
assets/graphics/monsters/squid/idle/1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 461 B

After

Width:  |  Height:  |  Size: 461 B

Some files were not shown because too many files have changed in this diff Show more