| @ -0,0 +1,32 @@ | |||||
| ## Performs the actual Saving[br][br] | |||||
| ## | |||||
| ## Below is a basic definition of various components and resources for reference:[br] | |||||
| ## * SaveLevelDataComponent - The root save component that performs saving and loading of the actual data from disk | |||||
| ## * SaveDataComponent - Attached to a node that has properties that need to be saved | |||||
| ## * Node Type Resources - Each type of node that requires saving, such as a TileMapLayer, needs a resource created | |||||
| extends Node | |||||
| func _unhandled_input(event: InputEvent) -> void: | |||||
| if event.is_action_pressed("quick_save"): | |||||
| save_game() | |||||
| if event.is_action_pressed("quick_load"): | |||||
| load_game() | |||||
| func save_game() -> void: | |||||
| var save_level_data_component: SaveLevelDataComponent = get_tree().get_first_node_in_group("save_level_data_component") | |||||
| if save_level_data_component == null: | |||||
| push_error("Could not find SaveLevelDataComponent node in level") | |||||
| return | |||||
| save_level_data_component.save_game() | |||||
| func load_game() -> void: | |||||
| var save_level_data_component: SaveLevelDataComponent = get_tree().get_first_node_in_group("save_level_data_component") | |||||
| if save_level_data_component == null: # Nothing to load | |||||
| return | |||||
| save_level_data_component.load_game() | |||||
| @ -0,0 +1 @@ | |||||
| uid://dau7tp2xpp0w | |||||
| @ -0,0 +1,26 @@ | |||||
| ## Add to any node that has data we need to save | |||||
| ## Each node type, such as TileMapLayer, will need a resource created for it | |||||
| ## See `res://save_load/resources/node_types/` | |||||
| class_name SaveDataComponent | |||||
| extends Node | |||||
| @export var save_data_resource: NodeDataResource ## The resource describing the type of object being saved | |||||
| @onready var parent_node: Node3D = get_parent() | |||||
| func _ready() -> void: | |||||
| add_to_group("save_data_component") | |||||
| func _save_data() -> Resource: | |||||
| if parent_node == null: | |||||
| return | |||||
| if save_data_resource == null: | |||||
| push_error("save_data_resource not defined on node ", parent_node.name) | |||||
| return | |||||
| save_data_resource._save_data(parent_node) | |||||
| return save_data_resource | |||||
| @ -0,0 +1 @@ | |||||
| uid://b0400fjcqflgh | |||||
| @ -0,0 +1,6 @@ | |||||
| [gd_scene load_steps=2 format=3 uid="uid://baki8rbf1ti0r"] | |||||
| [ext_resource type="Script" uid="uid://b0400fjcqflgh" path="res://save_load/components/save_data_component.gd" id="1_nm1vf"] | |||||
| [node name="SaveDataComponent" type="Node"] | |||||
| script = ExtResource("1_nm1vf") | |||||
| @ -0,0 +1,66 @@ | |||||
| ## Performs the actual saving and loading of data related to this level/scene | |||||
| ## Utilized by the SaveGameManager | |||||
| class_name SaveLevelDataComponent | |||||
| extends Node | |||||
| ## See documentation to where this path is: https://docs.godotengine.org/en/stable/tutorials/io/data_paths.html#accessing-persistent-user-data-user[br][br] | |||||
| ## Default Paths:[br] | |||||
| ## * Windows: %APPDATA%\Godot\app_userdata\[project_name][br] | |||||
| ## * macOS: ~/Library/Application Support/Godot/app_userdata/[project_name][br] | |||||
| ## * Linux: ~/.local/share/godot/app_userdata/[project_name][br] | |||||
| @export var save_game_data_path: String = "user://game_data/" | |||||
| @export var save_file_name: String = "save_%s_game_data.tres" | |||||
| var level_scene_name: String | |||||
| var game_data_resource: SaveGameDataResource | |||||
| var level_save_file_name: String | |||||
| var save_game_file_path: String | |||||
| func _ready() -> void: | |||||
| add_to_group("save_level_data_component") | |||||
| level_scene_name = get_parent().name | |||||
| level_save_file_name = save_file_name % level_scene_name | |||||
| save_game_file_path = save_game_data_path + level_save_file_name | |||||
| func save_node_data() -> void: | |||||
| var nodes: Array = get_tree().get_nodes_in_group("save_data_component") | |||||
| if nodes == null: return | |||||
| game_data_resource = SaveGameDataResource.new() | |||||
| for node: Node in nodes: | |||||
| if node is SaveDataComponent: | |||||
| @warning_ignore("unsafe_method_access") | |||||
| var save_data_resource: NodeDataResource = node._save_data() | |||||
| var save_final_resource: NodeDataResource = save_data_resource.duplicate() | |||||
| game_data_resource.save_data_nodes.append(save_final_resource) | |||||
| func save_game() -> void: | |||||
| if !DirAccess.dir_exists_absolute(save_game_data_path): | |||||
| DirAccess.make_dir_absolute(save_game_data_path) | |||||
| save_node_data() | |||||
| var result: int = ResourceSaver.save(game_data_resource, save_game_file_path) | |||||
| print("Save Result: ", result) | |||||
| func load_game() -> void: | |||||
| if !FileAccess.file_exists(save_game_file_path): | |||||
| #push_error("Save file does not exist: ", save_game_file_path) | |||||
| return | |||||
| game_data_resource = ResourceLoader.load(save_game_file_path) | |||||
| if game_data_resource == null: | |||||
| push_error("Could not load save file: ", save_game_file_path) | |||||
| return | |||||
| var root_node: Window = get_tree().root | |||||
| for resource: Resource in game_data_resource.save_data_nodes: | |||||
| if resource is NodeDataResource: | |||||
| (resource as NodeDataResource)._load_data(root_node) | |||||
| @ -0,0 +1 @@ | |||||
| uid://c7x2qvyu62230 | |||||
| @ -0,0 +1,6 @@ | |||||
| [gd_scene load_steps=2 format=3 uid="uid://c3pqilb6yh5kc"] | |||||
| [ext_resource type="Script" uid="uid://c7x2qvyu62230" path="res://save_load/components/save_level_data_component.gd" id="1_exguq"] | |||||
| [node name="SaveLevelDataComponent" type="Node"] | |||||
| script = ExtResource("1_exguq") | |||||
| @ -0,0 +1,13 @@ | |||||
| ## Basically just load any saved data for the scene that already exists | |||||
| ## Attach this to any test scene to automatically load any data found | |||||
| class_name TestSceneSaveDataManagerComponent | |||||
| extends Node | |||||
| func _ready() -> void: | |||||
| call_deferred("load_test_scene") | |||||
| func load_test_scene() -> void: | |||||
| SaveGameManager.load_game() | |||||
| print("Save Game Data Loaded") | |||||
| @ -0,0 +1 @@ | |||||
| uid://b763cjyd7t2ju | |||||
| @ -0,0 +1,6 @@ | |||||
| [gd_scene load_steps=2 format=3 uid="uid://dftxu6qsgxyjb"] | |||||
| [ext_resource type="Script" uid="uid://b763cjyd7t2ju" path="res://save_load/components/test_scene_save_data_manager_component.gd" id="1_toc0k"] | |||||
| [node name="TestSceneSaveDataManagerComponent" type="Node"] | |||||
| script = ExtResource("1_toc0k") | |||||
| @ -0,0 +1,23 @@ | |||||
| ## The resource utilized for saving a Block | |||||
| class_name BlockDataResource | |||||
| extends NodeDataResource | |||||
| @export var block_id: String = "001" | |||||
| func _save_data(node: Node3D) -> void: | |||||
| super._save_data(node) | |||||
| block_id = node.id | |||||
| func _load_data(window: Window) -> void: | |||||
| var scene_node: Node = window.get_node_or_null(node_path) | |||||
| if scene_node == null: return | |||||
| var block: Block = scene_node | |||||
| block.transform = transform | |||||
| block.set_id(block_id) | |||||
| print("Loaded Block: ", block.name) | |||||
| @ -0,0 +1 @@ | |||||
| uid://syaia0l6vjt1 | |||||
| @ -0,0 +1,12 @@ | |||||
| [gd_resource type="Resource" script_class="BlockDataResource" load_steps=2 format=3 uid="uid://dfos8np8agysk"] | |||||
| [ext_resource type="Script" uid="uid://syaia0l6vjt1" path="res://save_load/resources/node_types/block_data_resource.gd" id="1_a06et"] | |||||
| [resource] | |||||
| script = ExtResource("1_a06et") | |||||
| block_id = "001" | |||||
| block_position = Vector3(0, 0, 0) | |||||
| transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) | |||||
| node_path = NodePath("") | |||||
| parent_node_path = NodePath("") | |||||
| metadata/_custom_type_script = "uid://syaia0l6vjt1" | |||||
| @ -0,0 +1,21 @@ | |||||
| ## The base resource for saving a specific Node | |||||
| class_name NodeDataResource | |||||
| extends Resource | |||||
| @export var transform: Transform3D | |||||
| @export var node_path: NodePath | |||||
| @export var parent_node_path: NodePath | |||||
| func _load_data(_window: Window) -> void: | |||||
| pass | |||||
| func _save_data(node: Node3D) -> void: | |||||
| transform = node.transform | |||||
| node_path = node.get_path() | |||||
| var parent_node: Node3D = node.get_parent() | |||||
| if parent_node != null: | |||||
| parent_node_path = parent_node.get_path() | |||||
| @ -0,0 +1 @@ | |||||
| uid://drj0sfem1gmsk | |||||
| @ -0,0 +1,9 @@ | |||||
| [gd_resource type="Resource" script_class="NodeDataResource" load_steps=2 format=3 uid="uid://dald1lud7ktsj"] | |||||
| [ext_resource type="Script" uid="uid://drj0sfem1gmsk" path="res://save_load/resources/node_types/node_data_resource.gd" id="1_b70a7"] | |||||
| [resource] | |||||
| script = ExtResource("1_b70a7") | |||||
| transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) | |||||
| node_path = NodePath("") | |||||
| parent_node_path = NodePath("") | |||||
| @ -0,0 +1,16 @@ | |||||
| ## The resource utilized for saving a Player | |||||
| class_name PlayerDataResource | |||||
| extends NodeDataResource | |||||
| func _save_data(node: Node3D) -> void: | |||||
| super._save_data(node) | |||||
| # TODO: Save inventory or any other data | |||||
| func _load_data(window: Window) -> void: | |||||
| var scene_node: Node = window.get_node_or_null(node_path) | |||||
| if scene_node == null: return | |||||
| #var player: Player = scene_node | |||||
| @ -0,0 +1 @@ | |||||
| uid://dodqpooodtguo | |||||
| @ -0,0 +1,10 @@ | |||||
| [gd_resource type="Resource" script_class="PlayerDataResource" load_steps=2 format=3 uid="uid://bvsurbn5xgchr"] | |||||
| [ext_resource type="Script" uid="uid://dodqpooodtguo" path="res://save_load/resources/node_types/player_data_resource.gd" id="1_scty6"] | |||||
| [resource] | |||||
| script = ExtResource("1_scty6") | |||||
| transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0) | |||||
| node_path = NodePath("") | |||||
| parent_node_path = NodePath("") | |||||
| metadata/_custom_type_script = "uid://dodqpooodtguo" | |||||
| @ -0,0 +1,7 @@ | |||||
| ## The entire save structure that contains all NodeDataResources | |||||
| ## NodeDataResources will be located by the SaveLevelDataComponent | |||||
| class_name SaveGameDataResource | |||||
| extends Resource | |||||
| @export var save_data_nodes: Array[NodeDataResource] | |||||
| @ -0,0 +1 @@ | |||||
| uid://di6ov7tpewhft | |||||
| @ -0,0 +1,9 @@ | |||||
| [gd_resource type="Resource" script_class="SaveGameDataResource" load_steps=3 format=3 uid="uid://dkniygoky2jcx"] | |||||
| [ext_resource type="Script" uid="uid://drj0sfem1gmsk" path="res://save_load/resources/node_types/node_data_resource.gd" id="1_7yx7n"] | |||||
| [ext_resource type="Script" uid="uid://di6ov7tpewhft" path="res://save_load/resources/save_game_data_resource.gd" id="1_sbw5t"] | |||||
| [resource] | |||||
| script = ExtResource("1_sbw5t") | |||||
| save_data_nodes = Array[ExtResource("1_7yx7n")]([]) | |||||
| metadata/_custom_type_script = "uid://di6ov7tpewhft" | |||||
| @ -0,0 +1,30 @@ | |||||
| ## Used with the SaveDataComponent for defining node and scene_file_path | |||||
| class_name SceneDataResource | |||||
| extends NodeDataResource | |||||
| @export var node_name: String | |||||
| @export var scene_file_path: String | |||||
| func _save_data(node: Node3D) -> void: | |||||
| super._save_data(node) | |||||
| node_name = node.name | |||||
| scene_file_path = node.scene_file_path | |||||
| func _load_data(window: Window) -> void: | |||||
| var parent_node: Node3D | |||||
| if parent_node_path != null: | |||||
| parent_node = window.get_node_or_null(parent_node_path) | |||||
| var scene_node: Node3D | |||||
| if node_path != null: | |||||
| var scene_file_resource: Resource = load(scene_file_path) | |||||
| scene_node = scene_file_resource.instantiate() | |||||
| if parent_node != null and scene_node != null: | |||||
| #scene_node.position = position | |||||
| print("Loading Child: ", scene_node.name) | |||||
| parent_node.add_child(scene_node) | |||||
| @ -0,0 +1 @@ | |||||
| uid://bxr74kmjt6heh | |||||
| @ -0,0 +1,10 @@ | |||||
| [gd_resource type="Resource" script_class="SceneDataResource" load_steps=2 format=3 uid="uid://duqhhi2nlic6n"] | |||||
| [ext_resource type="Script" uid="uid://bxr74kmjt6heh" path="res://save_load/resources/scene_data_resource.gd" id="1_ihw72"] | |||||
| [resource] | |||||
| script = ExtResource("1_ihw72") | |||||
| global_position = Vector2(0, 0) | |||||
| node_path = NodePath("") | |||||
| parent_node_path = NodePath("") | |||||
| metadata/_custom_type_script = "uid://bxr74kmjt6heh" | |||||