Update GODOT part
0
addons/Todo_Manager/CONTRIBUTING.md
Normal file → Executable file
0
addons/Todo_Manager/ColourPicker.gd
Normal file → Executable file
0
addons/Todo_Manager/Current.gd
Normal file → Executable file
0
addons/Todo_Manager/Dock.gd
Normal file → Executable file
0
addons/Todo_Manager/Pattern.gd
Normal file → Executable file
0
addons/Todo_Manager/Project.gd
Normal file → Executable file
0
addons/Todo_Manager/README.md
Normal file → Executable file
0
addons/Todo_Manager/READMECN.md
Normal file → Executable file
0
addons/Todo_Manager/UI/ColourPicker.tscn
Normal file → Executable file
0
addons/Todo_Manager/UI/Dock.tscn
Normal file → Executable file
0
addons/Todo_Manager/UI/Pattern.tscn
Normal file → Executable file
0
addons/Todo_Manager/doc/example.gd
Normal file → Executable file
0
addons/Todo_Manager/doc/images/Instruct1.png
Normal file → Executable 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
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
0
addons/Todo_Manager/doc/images/Instruct3.png
Normal file → Executable 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
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
0
addons/Todo_Manager/doc/images/Instruct5.png
Normal file → Executable 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
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
0
addons/Todo_Manager/doc/images/TodoExternal.gif
Normal file → Executable 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
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
0
addons/Todo_Manager/doc/images/example2.png
Normal file → Executable file
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
0
addons/Todo_Manager/plugin.cfg
Normal file → Executable file
0
addons/Todo_Manager/plugin.gd
Normal file → Executable file
0
addons/Todo_Manager/todoItem_class.gd
Normal file → Executable file
0
addons/Todo_Manager/todo_class.gd
Normal file → Executable 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
0
addons/godot_rl_agents/godot_rl_agents.gd
Normal file → Executable file
0
addons/godot_rl_agents/icon.png
Normal file → Executable 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
0
addons/godot_rl_agents/onnx/csharp/SessionConfigurator.cs
Normal file → Executable file
0
addons/godot_rl_agents/onnx/csharp/docs/ONNXInference.xml
Normal file → Executable file
0
addons/godot_rl_agents/onnx/csharp/docs/SessionConfigurator.xml
Normal file → Executable file
0
addons/godot_rl_agents/onnx/wrapper/ONNX_wrapper.gd
Normal file → Executable file
0
addons/godot_rl_agents/plugin.cfg
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_2d/ExampleRaycastSensor2D.tscn
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_2d/GridSensor2D.gd
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_2d/ISensor2D.gd
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_2d/RaycastSensor2D.gd
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_2d/RaycastSensor2D.tscn
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_3d/ExampleRaycastSensor3D.tscn
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_3d/GridSensor3D.gd
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_3d/ISensor3D.gd
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_3d/RGBCameraSensor3D.gd
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_3d/RGBCameraSensor3D.tscn
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_3d/RaycastSensor3D.gd
Normal file → Executable file
0
addons/godot_rl_agents/sensors/sensors_3d/RaycastSensor3D.tscn
Normal file → Executable 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
0
assets/audio/attack/claw.wav
Normal file → Executable file
0
assets/audio/attack/fireball.wav
Normal file → Executable file
0
assets/audio/attack/slash.wav
Normal file → Executable file
0
assets/audio/death.wav
Normal file → Executable file
0
assets/audio/heal.wav
Normal file → Executable file
0
assets/audio/hit.wav
Normal file → Executable file
0
assets/audio/main.ogg
Normal file → Executable file
0
assets/audio/sword.wav
Normal file → Executable file
0
assets/graphics/font/joystix.ttf
Normal file → Executable file
0
assets/graphics/grass/grass_1.png
Normal file → Executable file
Before Width: | Height: | Size: 494 B After Width: | Height: | Size: 494 B |
0
assets/graphics/grass/grass_2.png
Normal file → Executable file
Before Width: | Height: | Size: 500 B After Width: | Height: | Size: 500 B |
0
assets/graphics/grass/grass_3.png
Normal file → Executable 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
Before Width: | Height: | Size: 487 B After Width: | Height: | Size: 487 B |
0
assets/graphics/monsters/bamboo/idle/0.png
Normal file → Executable 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
Before Width: | Height: | Size: 517 B After Width: | Height: | Size: 517 B |
0
assets/graphics/monsters/bamboo/idle/2.png
Normal file → Executable 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
Before Width: | Height: | Size: 504 B After Width: | Height: | Size: 504 B |
0
assets/graphics/monsters/bamboo/move/0.png
Normal file → Executable 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
Before Width: | Height: | Size: 517 B After Width: | Height: | Size: 517 B |
0
assets/graphics/monsters/bamboo/move/2.png
Normal file → Executable 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
Before Width: | Height: | Size: 504 B After Width: | Height: | Size: 504 B |
0
assets/graphics/monsters/raccoon/attack/0.png
Normal file → Executable 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Before Width: | Height: | Size: 426 B After Width: | Height: | Size: 426 B |
0
assets/graphics/monsters/spirit/idle/0.png
Normal file → Executable 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
Before Width: | Height: | Size: 417 B After Width: | Height: | Size: 417 B |
0
assets/graphics/monsters/spirit/idle/2.png
Normal file → Executable 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
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 418 B |
0
assets/graphics/monsters/spirit/move/0.png
Normal file → Executable 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
Before Width: | Height: | Size: 425 B After Width: | Height: | Size: 425 B |
0
assets/graphics/monsters/spirit/move/2.png
Normal file → Executable 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
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
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
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
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 463 B |
0
assets/graphics/monsters/squid/attack/0.png
Normal file → Executable 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
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 463 B |
0
assets/graphics/monsters/squid/idle/1.png
Normal file → Executable file
Before Width: | Height: | Size: 461 B After Width: | Height: | Size: 461 B |