@ -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" |