256 lines
7.9 KiB
GDScript
256 lines
7.9 KiB
GDScript
extends Control
|
|
class_name GL_Node_Map
|
|
|
|
var holder: Control
|
|
var is_panning: bool = false
|
|
var last_mouse_pos: Vector2
|
|
var is_hovered: bool = false
|
|
|
|
#Workspace shenanigans
|
|
var optionsVar:OptionButton
|
|
|
|
#Workspaces
|
|
var _workspace_ID:String
|
|
var save_name: String = "My Save"
|
|
var author_name: String = "Unnamed Author"
|
|
var showtapesPath: String = "user://Showtapes/"
|
|
var version: String = ProjectSettings.get_setting("application/config/version")
|
|
var game_title: String = ProjectSettings.get_setting("application/config/name")
|
|
var time_created: String = ""
|
|
var last_updated: String = ""
|
|
|
|
|
|
func _notification(what):
|
|
if what == NOTIFICATION_EXIT_TREE:
|
|
save_everything()
|
|
|
|
func _ready():
|
|
visible = false
|
|
holder = get_node("Holder")
|
|
optionsVar = get_node("MarginContainer/HBoxContainer/OptionButton")
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
|
|
connect("mouse_entered", _on_mouse_entered)
|
|
connect("mouse_exited", _on_mouse_exited)
|
|
|
|
_workspace_ID = generate_new_workspace_id()
|
|
populate_workspace_options()
|
|
optionsVar.connect("item_selected", Callable(self, "_on_workspace_selected"))
|
|
|
|
|
|
func _on_mouse_entered():
|
|
is_hovered = true
|
|
|
|
func _on_mouse_exited():
|
|
is_hovered = false
|
|
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event is InputEventKey and event.pressed:
|
|
match event.keycode:
|
|
KEY_ESCAPE:
|
|
visible = not visible
|
|
if not visible:
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
else:
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
|
|
if not is_hovered:
|
|
return
|
|
|
|
if event is InputEventMouseButton:
|
|
if event.button_index == MOUSE_BUTTON_MIDDLE:
|
|
is_panning = event.pressed
|
|
if is_panning:
|
|
last_mouse_pos = event.position
|
|
|
|
if event.pressed and (event.button_index == MOUSE_BUTTON_WHEEL_UP or event.button_index == MOUSE_BUTTON_WHEEL_DOWN):
|
|
var mouse_pos = event.position
|
|
var global_xform = holder.get_global_transform()
|
|
var local_mouse_pos = global_xform.affine_inverse().basis_xform(mouse_pos)
|
|
|
|
var zoom_factor := 1.0
|
|
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
|
zoom_factor = 1.1
|
|
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
|
zoom_factor = 0.9
|
|
|
|
holder.scale *= zoom_factor
|
|
|
|
var new_global_xform = holder.get_global_transform()
|
|
var new_local_mouse_pos = new_global_xform.affine_inverse().basis_xform(mouse_pos)
|
|
|
|
var delta = (new_local_mouse_pos - local_mouse_pos)
|
|
holder.position += delta * holder.scale
|
|
|
|
if event is InputEventMouseMotion and is_panning:
|
|
var delta = event.position - last_mouse_pos
|
|
holder.position += delta
|
|
last_mouse_pos = event.position
|
|
|
|
func save_everything():
|
|
var saveDict := {}
|
|
var rng = RandomNumberGenerator.new()
|
|
rng.seed = Time.get_ticks_msec()
|
|
|
|
if holder.get_child_count() == 0:
|
|
return
|
|
|
|
for child in holder.get_children():
|
|
child = child.get_child(0)
|
|
print(child._get_title() + ", " + child.nodePath)
|
|
if child is not GL_Node:
|
|
print(child)
|
|
continue
|
|
|
|
var id = "SAVE_" + str(rng.randi())
|
|
var node_data = {
|
|
"path": child.nodePath,
|
|
"name": child._get_title(),
|
|
"uuid": child.uuid,
|
|
"rows": child.rows.duplicate(true),
|
|
"position": child.position
|
|
}
|
|
|
|
# Save recording if it's a GL_Record and has enough data
|
|
if child is GL_Record and child.recording != null:
|
|
if child.recording.size() >= 3:
|
|
var recording_file_path = showtapesPath + str(_workspace_ID) + "/" + child.uuid + "_recording.tres"
|
|
var recording_config = ConfigFile.new()
|
|
recording_config.set_value("recording", "data", child.recording)
|
|
var err = recording_config.save(recording_file_path)
|
|
if err != OK:
|
|
push_error("Failed to save recording for " + child.uuid + ": " + str(err))
|
|
else:
|
|
print("Saved recording for node ", child.uuid)
|
|
|
|
# Convert connections to uuid references
|
|
for key in node_data["rows"]:
|
|
if node_data["rows"][key].has("connections"):
|
|
var connections = node_data["rows"][key]["connections"]
|
|
for i in range(connections.size()):
|
|
if connections[i]["target"] is GL_Node:
|
|
connections[i]["target"] = connections[i]["target"].uuid
|
|
|
|
saveDict[id] = node_data
|
|
|
|
var save_dir = showtapesPath + str(_workspace_ID)
|
|
DirAccess.make_dir_recursive_absolute(save_dir)
|
|
var file_path = save_dir + "/node_workspace.tres"
|
|
|
|
var resource = ConfigFile.new()
|
|
|
|
# Metadata section
|
|
if time_created == "":
|
|
time_created = Time.get_datetime_string_from_system(true)
|
|
last_updated = Time.get_datetime_string_from_system(true)
|
|
|
|
resource.set_value("meta", "save_name", save_name)
|
|
resource.set_value("meta", "author", author_name)
|
|
resource.set_value("meta", "version", ProjectSettings.get_setting("application/config/version"))
|
|
resource.set_value("meta", "game_title", ProjectSettings.get_setting("application/config/name"))
|
|
resource.set_value("meta", "time_created", time_created)
|
|
resource.set_value("meta", "last_updated", last_updated)
|
|
|
|
# Main save data
|
|
resource.set_value("workspace", "data", saveDict)
|
|
|
|
var err = resource.save(file_path)
|
|
if err != OK:
|
|
push_error("Failed to save workspace: " + str(err))
|
|
else:
|
|
print("Saved workspace to: ", file_path)
|
|
|
|
populate_workspace_options()
|
|
|
|
|
|
|
|
func load_everything():
|
|
var file_path = showtapesPath + str(_workspace_ID) + "/node_workspace.tres"
|
|
var resource = ConfigFile.new()
|
|
var err = resource.load(file_path)
|
|
if err != OK:
|
|
push_error("Failed to load workspace: " + str(err))
|
|
return {}
|
|
|
|
# Load metadata
|
|
save_name = resource.get_value("meta", "save_name", "Unnamed Save")
|
|
author_name = resource.get_value("meta", "author", "Unknown Author")
|
|
version = resource.get_value("meta", "version", "0.0")
|
|
game_title = resource.get_value("meta", "game_title", "Untitled Game")
|
|
time_created = resource.get_value("meta", "time_created", "")
|
|
last_updated = resource.get_value("meta", "last_updated", "")
|
|
|
|
print("Loaded workspace metadata:")
|
|
print("Save Name: ", save_name)
|
|
print("Author: ", author_name)
|
|
print("Version: ", version)
|
|
print("Game Title: ", game_title)
|
|
print("Time Created: ", time_created)
|
|
print("Last Updated: ", last_updated)
|
|
|
|
# Load nodes
|
|
var data = resource.get_value("workspace", "data", {})
|
|
for key in data:
|
|
var packed_scene = load(data[key]["path"])
|
|
if packed_scene == null:
|
|
printerr("Could not load resource at: " + data[key]["path"])
|
|
continue
|
|
var node = packed_scene.instantiate() as Control
|
|
holder.add_child(node)
|
|
node = node.get_child(0) as GL_Node
|
|
node.position = data[key].get("position",Vector2.ZERO)
|
|
node.nodePath = data[key].get("path","ERR")
|
|
node.uuid = data[key].get("uuid","ERR_" + key + str(Time.get_ticks_msec()))
|
|
node._set_title(data[key].get("name","???"))
|
|
node.rows = data[key].get("rows",{})
|
|
node._update_visuals()
|
|
if node is GL_Record:
|
|
var recording_file = showtapesPath + str(_workspace_ID) + "/" + node.uuid + "_recording.tres"
|
|
var config = ConfigFile.new()
|
|
if config.load(recording_file) == OK:
|
|
node.recording = config.get_value("recording", "data", {})
|
|
|
|
|
|
func generate_new_workspace_id() -> String:
|
|
var rng = RandomNumberGenerator.new()
|
|
rng.seed = Time.get_ticks_msec()
|
|
return str(rng.randi())
|
|
|
|
func clear_holder():
|
|
for node in holder.get_children():
|
|
node.queue_free()
|
|
await get_tree().process_frame # ensure all nodes are freed
|
|
|
|
func populate_workspace_options():
|
|
optionsVar.clear()
|
|
optionsVar.add_item("New Workspace")
|
|
|
|
var dir := DirAccess.open(showtapesPath)
|
|
if dir:
|
|
dir.list_dir_begin()
|
|
var name = dir.get_next()
|
|
while name != "":
|
|
if dir.current_is_dir() and name != "." and name != "..":
|
|
optionsVar.add_item(name)
|
|
name = dir.get_next()
|
|
dir.list_dir_end()
|
|
|
|
func _on_workspace_selected(index: int):
|
|
save_everything()
|
|
|
|
if index == 0: # New Workspace
|
|
clear_holder()
|
|
_workspace_ID = generate_new_workspace_id()
|
|
save_name = "My Save"
|
|
author_name = "Unnamed Author"
|
|
version = ProjectSettings.get_setting("application/config/version")
|
|
game_title = ProjectSettings.get_setting("application/config/name")
|
|
time_created = ""
|
|
last_updated = ""
|
|
print("Created new workspace: ", _workspace_ID)
|
|
else:
|
|
var selected_name = optionsVar.get_item_text(index)
|
|
_workspace_ID = selected_name
|
|
clear_holder()
|
|
load_everything()
|