From 9fcd24f8b55f33cd045efbd13d35e8059f074463 Mon Sep 17 00:00:00 2001 From: cgandeg Date: Thu, 19 Mar 2026 14:26:57 -0500 Subject: [PATCH] Create persistence manager and connectors for chests and gates --- .../Chests/Scripts/Bases/chest_base.gd | 6 +++ .../Chests/Scripts/item_chest_01.gd | 5 ++ .../Gates/Spike Gate/Scripts/spike_gate.gd | 4 ++ .../Gates/Spike Gate/spike_gate.tscn | 2 +- .../path_to_dungeon_01.tscn | 26 +++++++--- .../Scripts/chest_persistence_connector.gd | 21 ++++++++ .../chest_persistence_connector.gd.uid | 1 + .../Scripts/gate_persistence_connector.gd | 40 +++++++++++++++ .../Scripts/gate_persistence_connector.gd.uid | 1 + .../chest_persistence_connector.tscn | 6 +++ .../gate_persistence_connector.tscn | 6 +++ Persistence/persistence_manager.gd | 51 +++++++++++++++++++ Persistence/persistence_manager.gd.uid | 1 + project.godot | 2 + 14 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 Persistence/Connectors/Scripts/chest_persistence_connector.gd create mode 100644 Persistence/Connectors/Scripts/chest_persistence_connector.gd.uid create mode 100644 Persistence/Connectors/Scripts/gate_persistence_connector.gd create mode 100644 Persistence/Connectors/Scripts/gate_persistence_connector.gd.uid create mode 100644 Persistence/Connectors/chest_persistence_connector.tscn create mode 100644 Persistence/Connectors/gate_persistence_connector.tscn create mode 100644 Persistence/persistence_manager.gd create mode 100644 Persistence/persistence_manager.gd.uid diff --git a/Entities/Map Objects/Chests/Scripts/Bases/chest_base.gd b/Entities/Map Objects/Chests/Scripts/Bases/chest_base.gd index 215736d..3aee472 100644 --- a/Entities/Map Objects/Chests/Scripts/Bases/chest_base.gd +++ b/Entities/Map Objects/Chests/Scripts/Bases/chest_base.gd @@ -1,6 +1,7 @@ extends StaticBody2D class_name BaseChest +signal ChestOpened signal OpeningAnimationStarted @export var is_open := false @@ -8,7 +9,12 @@ signal OpeningAnimationStarted # Public Methods func Open() -> void: is_open = true + ChestOpened.emit() func OpenAlreadyOpened() -> void: pass + + +func SetOpenedFromLoad() -> void: + is_open = true diff --git a/Entities/Map Objects/Chests/Scripts/item_chest_01.gd b/Entities/Map Objects/Chests/Scripts/item_chest_01.gd index 48a8e6d..6200fb6 100644 --- a/Entities/Map Objects/Chests/Scripts/item_chest_01.gd +++ b/Entities/Map Objects/Chests/Scripts/item_chest_01.gd @@ -27,6 +27,11 @@ func OpenAlreadyOpened() -> void: already_opened_message_dialogue_trigger.Trigger() +func SetOpenedFromLoad() -> void: + super.SetOpenedFromLoad() + chest_01_sprite.play("opened") + + # Private Methods func _ready() -> void: if is_open: diff --git a/Entities/Map Objects/Gates/Spike Gate/Scripts/spike_gate.gd b/Entities/Map Objects/Gates/Spike Gate/Scripts/spike_gate.gd index ba9a7e8..7e9de6c 100644 --- a/Entities/Map Objects/Gates/Spike Gate/Scripts/spike_gate.gd +++ b/Entities/Map Objects/Gates/Spike Gate/Scripts/spike_gate.gd @@ -1,5 +1,7 @@ extends StaticBody2D +signal Opened + @onready var sprite: AnimatedSprite2D = $AnimatedSprite2D @onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D @@ -15,3 +17,5 @@ func OpenGate() -> void: collision_shape_2d.set_deferred("disabled", true) sprite.play("open") + + Opened.emit() diff --git a/Entities/Map Objects/Gates/Spike Gate/spike_gate.tscn b/Entities/Map Objects/Gates/Spike Gate/spike_gate.tscn index a069542..6d5fc63 100644 --- a/Entities/Map Objects/Gates/Spike Gate/spike_gate.tscn +++ b/Entities/Map Objects/Gates/Spike Gate/spike_gate.tscn @@ -395,6 +395,6 @@ shape = SubResource("RectangleShape2D_5ttkm") y_sort_enabled = true position = Vector2(0, 15) sprite_frames = SubResource("SpriteFrames_pki7h") -animation = &"closed" +animation = &"open" autoplay = "closed" offset = Vector2(0, -15) diff --git a/Maps/Forest Dungeon Entrance/path_to_dungeon_01.tscn b/Maps/Forest Dungeon Entrance/path_to_dungeon_01.tscn index 015849f..7b14875 100644 --- a/Maps/Forest Dungeon Entrance/path_to_dungeon_01.tscn +++ b/Maps/Forest Dungeon Entrance/path_to_dungeon_01.tscn @@ -11,6 +11,8 @@ [ext_resource type="PackedScene" uid="uid://byp273amg5ji8" path="res://Entities/Map Objects/Chests/Item Chests/item_chest_01 (Wooden).tscn" id="5_bnsbe"] [ext_resource type="Texture2D" uid="uid://bf6llktwqhs8l" path="res://Assets/Sprites/Door Fade.png" id="5_jett5"] [ext_resource type="PackedScene" uid="uid://did853bh5xeic" path="res://Maps/Connectors/spawn_marker_connector.tscn" id="5_lphfo"] +[ext_resource type="PackedScene" uid="uid://w4mh31se58f4" path="res://Persistence/Connectors/chest_persistence_connector.tscn" id="6_l5trr"] +[ext_resource type="PackedScene" uid="uid://c5ymu08jotbfp" path="res://Persistence/Connectors/gate_persistence_connector.tscn" id="7_0w1de"] [ext_resource type="PackedScene" uid="uid://be6xfndyj4ckx" path="res://Entities/Map Objects/Trees/tree_02.tscn" id="7_ycf72"] [ext_resource type="PackedScene" uid="uid://cc3qat6un2323" path="res://Entities/Map Objects/Trees/tree_01.tscn" id="8_yab5j"] [ext_resource type="PackedScene" uid="uid://bcx1d8kvp7o0h" path="res://Entities/Map Objects/Trees/tree_03.tscn" id="9_lwurn"] @@ -63,25 +65,33 @@ size = Vector2(10, 7) [node name="Map 01" type="Node2D" unique_id=411453136] y_sort_enabled = true -[node name="Connectors" type="Node" parent="." unique_id=1365901208] +[node name="Map Connectors" type="Node" parent="." unique_id=1365901208] -[node name="Chest Interaction Connector" parent="Connectors" unique_id=625804018 node_paths=PackedStringArray("player") instance=ExtResource("1_jtncl")] +[node name="Chest Interaction Connector" parent="Map Connectors" unique_id=625804018 node_paths=PackedStringArray("player") instance=ExtResource("1_jtncl")] player = NodePath("../../Player") -[node name="Arrow Spawner" parent="Connectors" unique_id=627092886 node_paths=PackedStringArray("player", "arrow_parent") instance=ExtResource("2_jtncl")] +[node name="Arrow Spawner" parent="Map Connectors" unique_id=627092886 node_paths=PackedStringArray("player", "arrow_parent") instance=ExtResource("2_jtncl")] player = NodePath("../../Player") arrow_parent = NodePath("../../Objects/Projectiles") -[node name="Bench Interaction Connector" parent="Connectors" unique_id=541204437 node_paths=PackedStringArray("player") instance=ExtResource("3_x6da4")] +[node name="Bench Interaction Connector" parent="Map Connectors" unique_id=541204437 node_paths=PackedStringArray("player") instance=ExtResource("3_x6da4")] player = NodePath("../../Player") -[node name="Interactive Loading Zone Connector" parent="Connectors" unique_id=833475826 node_paths=PackedStringArray("player") instance=ExtResource("4_4lnhp")] +[node name="Interactive Loading Zone Connector" parent="Map Connectors" unique_id=833475826 node_paths=PackedStringArray("player") instance=ExtResource("4_4lnhp")] player = NodePath("../../Player") -[node name="Spawn Marker Connector" parent="Connectors" unique_id=807187299 node_paths=PackedStringArray("player", "markers") instance=ExtResource("5_lphfo")] +[node name="Spawn Marker Connector" parent="Map Connectors" unique_id=807187299 node_paths=PackedStringArray("player", "markers") instance=ExtResource("5_lphfo")] player = NodePath("../../Player") markers = NodePath("../../Spawn Markers") +[node name="Persistence Connectors" type="Node" parent="." unique_id=1245900932] + +[node name="Chest Persistence Connector" parent="Persistence Connectors" unique_id=281805027 instance=ExtResource("6_l5trr")] +chests = Array[NodePath]([NodePath("../../Objects/Chests/Item Chest 01 - 1"), NodePath("../../Objects/Chests/Item Chest 01 - 2"), NodePath("../../Objects/Chests/Item Chest 01 - 3")]) + +[node name="GatePersistenceConnector" parent="Persistence Connectors" unique_id=1082904286 instance=ExtResource("7_0w1de")] +gates = Array[NodePath]([NodePath("../../Objects/Spike Gate"), NodePath("../../Objects/Spike Gate2")]) + [node name="Camera Limit Connector" type="Area2D" parent="." unique_id=1290795384 node_paths=PackedStringArray("camera_to_limit")] collision_layer = 0 collision_mask = 0 @@ -340,7 +350,7 @@ destination_marker_name = "Entrance" position = Vector2(278, 474) [node name="Player" parent="." unique_id=1502234578 instance=ExtResource("4_4igim")] -position = Vector2(89, 450) +position = Vector2(656, 498) [node name="Camera2D" type="Camera2D" parent="Player" unique_id=1115720225] position = Vector2(0, 1) @@ -385,7 +395,7 @@ position = Vector2(760, 312) [node name="Under Construction Block12" parent="Debug" unique_id=1005752992 instance=ExtResource("26_4lnhp")] position = Vector2(760, 328) -[connection signal="SitOnBenchTriggered" from="Connectors/Bench Interaction Connector" to="Player" method="OnSitOnFurnitureTriggered"] +[connection signal="SitOnBenchTriggered" from="Map Connectors/Bench Interaction Connector" to="Player" method="OnSitOnFurnitureTriggered"] [connection signal="TargetHit" from="Objects/ArrowTarget" to="Objects/Spike Gate" method="OpenGate"] [connection signal="TargetHit" from="Objects/ArrowTarget" to="Objects/Spike Gate2" method="OpenGate"] [connection signal="PressurePlateTripped" from="Objects/PressurePlate" to="Objects/Spike Gate" method="OpenGate"] diff --git a/Persistence/Connectors/Scripts/chest_persistence_connector.gd b/Persistence/Connectors/Scripts/chest_persistence_connector.gd new file mode 100644 index 0000000..ff306d7 --- /dev/null +++ b/Persistence/Connectors/Scripts/chest_persistence_connector.gd @@ -0,0 +1,21 @@ +extends Node + +@export var chests: Array[NodePath] + +# Private Methods +func _ready() -> void: + for relative_node_path in chests: + var chest: BaseChest = get_node(relative_node_path) + var node_path := chest.get_path() + chest.ChestOpened.connect(func(): _on_chest_opened(chest)) + + if PersistenceManager.HasData(node_path): + var chest_opened: bool = PersistenceManager.GetData(node_path) + if chest_opened: + chest.call_deferred("SetOpenedFromLoad") + + +func _on_chest_opened(chest: BaseChest) -> void: + var node_path := chest.get_path() + PersistenceManager.UpdateData(node_path, true) + PersistenceManager.SaveToDisk() diff --git a/Persistence/Connectors/Scripts/chest_persistence_connector.gd.uid b/Persistence/Connectors/Scripts/chest_persistence_connector.gd.uid new file mode 100644 index 0000000..69a3c3c --- /dev/null +++ b/Persistence/Connectors/Scripts/chest_persistence_connector.gd.uid @@ -0,0 +1 @@ +uid://75g2fysjrqji diff --git a/Persistence/Connectors/Scripts/gate_persistence_connector.gd b/Persistence/Connectors/Scripts/gate_persistence_connector.gd new file mode 100644 index 0000000..3769aed --- /dev/null +++ b/Persistence/Connectors/Scripts/gate_persistence_connector.gd @@ -0,0 +1,40 @@ +extends Node + +@export var gates: Array[NodePath] + +# Private Methods +func _ready() -> void: + for node_path in gates: + _handle_spike_gate(node_path) + + +func _handle_spike_gate(node_path: NodePath) -> bool: + var node := get_node(node_path) + node_path = node.get_path() + if not node.name.begins_with("Spike Gate"): + return false + + # Connect Signal + node.connect("Opened", func(): _on_spike_gate_opened(node)) + + if not PersistenceManager.HasData(node_path): + return true + + var is_open: bool = PersistenceManager.GetData(node_path) + if not is_open: + return true + + var collision_shape: CollisionShape2D = node.get_node("CollisionShape2D") + var animated_sprite: AnimatedSprite2D = node.get_node("AnimatedSprite2D") + + node.set_deferred("is_open", true) + collision_shape.set_deferred("disabled", true) + animated_sprite.call_deferred("play", "open") + + return true + + +func _on_spike_gate_opened(node: Node) -> void: + var path := node.get_path() + PersistenceManager.UpdateData(path, true) + PersistenceManager.SaveToDisk() diff --git a/Persistence/Connectors/Scripts/gate_persistence_connector.gd.uid b/Persistence/Connectors/Scripts/gate_persistence_connector.gd.uid new file mode 100644 index 0000000..b048cfd --- /dev/null +++ b/Persistence/Connectors/Scripts/gate_persistence_connector.gd.uid @@ -0,0 +1 @@ +uid://brsiegtrne15y diff --git a/Persistence/Connectors/chest_persistence_connector.tscn b/Persistence/Connectors/chest_persistence_connector.tscn new file mode 100644 index 0000000..f52da8e --- /dev/null +++ b/Persistence/Connectors/chest_persistence_connector.tscn @@ -0,0 +1,6 @@ +[gd_scene format=3 uid="uid://w4mh31se58f4"] + +[ext_resource type="Script" uid="uid://75g2fysjrqji" path="res://Persistence/Connectors/Scripts/chest_persistence_connector.gd" id="1_hytou"] + +[node name="Chest Persistence Connector" type="Node" unique_id=281805027] +script = ExtResource("1_hytou") diff --git a/Persistence/Connectors/gate_persistence_connector.tscn b/Persistence/Connectors/gate_persistence_connector.tscn new file mode 100644 index 0000000..69aa900 --- /dev/null +++ b/Persistence/Connectors/gate_persistence_connector.tscn @@ -0,0 +1,6 @@ +[gd_scene format=3 uid="uid://c5ymu08jotbfp"] + +[ext_resource type="Script" uid="uid://brsiegtrne15y" path="res://Persistence/Connectors/Scripts/gate_persistence_connector.gd" id="1_0smsr"] + +[node name="GatePersistenceConnector" type="Node" unique_id=1082904286] +script = ExtResource("1_0smsr") diff --git a/Persistence/persistence_manager.gd b/Persistence/persistence_manager.gd new file mode 100644 index 0000000..5421910 --- /dev/null +++ b/Persistence/persistence_manager.gd @@ -0,0 +1,51 @@ +extends Node + +var _save_dictionary: Dictionary[NodePath, Variant] = {} + +# Public Methods +func UpdateData(node_path: NodePath, value: Variant) -> void: + _save_dictionary[node_path] = value + + +func GetData(node_path: NodePath) -> Variant: + if not _save_dictionary.has(node_path): + return null + return _save_dictionary[node_path] + + +func HasData(node_path: NodePath) -> bool: + return _save_dictionary.has(node_path) + + +func SaveToDisk() -> void: + var save_file := FileAccess.open("user://savegame.save", FileAccess.WRITE) + var json := JSON.stringify(_save_dictionary) + + save_file.store_line(json) + + +func LoadFromDisk() -> void: + if not FileAccess.file_exists("user://savegame.save"): + return + var save_file = FileAccess.open("user://savegame.save", FileAccess.READ) + print("Loading save file from path: %s" % save_file.get_path_absolute()) + var line := save_file.get_line() + var json = JSON.new() + var parse_result := json.parse(line) + if parse_result != OK: + print("Parsing result when loading file: [%s] in %s at line %d" % [json.get_error_message(), line, json.get_error_line()]) + return + + var data_dict: Dictionary = json.data + var node_dict: Dictionary[NodePath, Variant] + for key in data_dict: + var value: Variant = data_dict[key] + var node_path := NodePath(key) + node_dict[node_path] = value + + _save_dictionary = node_dict + + +# Private Methods +func _ready() -> void: + LoadFromDisk() diff --git a/Persistence/persistence_manager.gd.uid b/Persistence/persistence_manager.gd.uid new file mode 100644 index 0000000..0bad277 --- /dev/null +++ b/Persistence/persistence_manager.gd.uid @@ -0,0 +1 @@ +uid://dl2kg1qu0ymi7 diff --git a/project.godot b/project.godot index 7e9e461..1b732f1 100644 --- a/project.godot +++ b/project.godot @@ -23,6 +23,7 @@ GameManager="*uid://cb4tuxriixfqs" GroupUtils="*uid://bk7o4drbfh24p" MapLoader="*uid://c4jogxtdi3m13" InputManager="*uid://dnbg1dpjcq6vk" +PersistenceManager="*uid://dl2kg1qu0ymi7" [dotnet] @@ -37,6 +38,7 @@ folder_colors={ "res://Global Managers/": "red", "res://Main/": "gray", "res://Maps/": "green", +"res://Persistence/": "blue", "res://Resources/": "orange", "res://Scripts/": "red", "res://UI/": "yellow"