@ -0,0 +1,41 @@ | |||
## 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 | |||
signal game_saved | |||
signal game_loaded | |||
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() | |||
game_saved.emit() | |||
func _load_game() -> void: | |||
EntityManager.reset_world.emit() | |||
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.load_game() | |||
game_loaded.emit() |
@ -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: Node3DDataResource ## 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,64 @@ | |||
## 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: Node3DDataResource = node._save_data() | |||
var save_final_resource: Node3DDataResource = 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) | |||
if result != OK: | |||
printerr("Failed to save game: ", result) | |||
func load_game() -> void: | |||
if !FileAccess.file_exists(save_game_file_path): | |||
printerr("Failed to load save. File does not exist: ", save_game_file_path) | |||
return | |||
game_data_resource = ResourceLoader.load(save_game_file_path) | |||
if game_data_resource == null: | |||
printerr("Failed to load save. Unknown format? ", 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 Node3DDataResource: | |||
(resource as Node3DDataResource)._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,16 @@ | |||
## The resource utilized for saving a Block | |||
class_name BlockDataResource | |||
extends Node3DDataResource | |||
@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: | |||
EntityManager.create_block.emit(block_id, transform.origin) |
@ -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,20 @@ | |||
## The base resource for saving a specific Node | |||
class_name Node3DDataResource | |||
extends Resource | |||
@export var transform: Transform3D | |||
@export var node_path: NodePath | |||
@export var parent_node_path: NodePath | |||
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() | |||
func _load_data(_window: Window) -> void: | |||
pass |
@ -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/node3d_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 Node3DDataResource | |||
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 | |||
EntityManager.spawn_player.emit(transform) |
@ -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,8 @@ | |||
## The entire save structure that contains all Node3DDataResources | |||
## Node3DDataResources will be located by the SaveLevelDataComponent | |||
class_name SaveGameDataResource | |||
extends Resource | |||
@export var game_version: String = ProjectSettings.get_setting("application/config/version") | |||
@export var save_data_nodes: Array[Node3DDataResource] |
@ -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/node3d_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,28 @@ | |||
## Used with the SaveDataComponent for defining node and scene_file_path | |||
class_name SceneDataResource | |||
extends Node3DDataResource | |||
@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: | |||
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" |