feature/save_and_loaaaaaad #32

Merged
kziolkowski merged 18 commits from feature/save_and_loaaaaaad into develop 2 months ago

@ -1,7 +1,8 @@
[gd_scene load_steps=24 format=3 uid="uid://muuxxgvx33fp"]
[gd_scene load_steps=25 format=3 uid="uid://muuxxgvx33fp"]
[ext_resource type="Script" uid="uid://7m1rt7agb6rm" path="res://scripts/CSharp/Common/Temp/MVPDuck.cs" id="1_54k4r"]
[ext_resource type="Texture2D" uid="uid://hvchk6t0xe7j" path="res://art/animals/Ente.png" id="1_cgxhx"]
[ext_resource type="Resource" uid="uid://tt3d166mntmi" path="res://resources/low code/farming/var_sceneNameProvider.tres" id="2_fdf3t"]
[ext_resource type="AudioStream" uid="uid://qv0aubjeyi0u" path="res://audio/sfx/Animals/SFX_Duck_Quack_01.wav" id="3_kjie1"]
[ext_resource type="Script" uid="uid://cfnrd5k1k0gxw" path="res://scripts/CSharp/Common/AudioPlayer2D.cs" id="3_rdn2q"]
[ext_resource type="AudioStream" uid="uid://da84l8e44scwh" path="res://audio/sfx/Animals/SFX_Duck_Quack_02.wav" id="4_54k4r"]
@ -138,10 +139,11 @@ radius = 200.0
[sub_resource type="ViewportTexture" id="ViewportTexture_4830j"]
viewport_path = NodePath("SubViewport")
[node name="Duck" type="Node2D" node_paths=PackedStringArray("_animationPlayer")]
[node name="Duck" type="Node2D" node_paths=PackedStringArray("_animationPlayer") groups=["Saveable"]]
z_index = 1
y_sort_enabled = true
script = ExtResource("1_54k4r")
_sceneKeyProvider = ExtResource("2_fdf3t")
_transferDelayMs = 1000
_animationPlayer = NodePath("AnimationPlayer")
@ -160,11 +162,11 @@ libraries = {
&"": SubResource("AnimationLibrary_54k4r")
}
[node name="InteractionArea" parent="." node_paths=PackedStringArray("_spritesToOutline") instance=ExtResource("15_uo3dh")]
[node name="duck interaction" parent="." node_paths=PackedStringArray("_spritesToOutline") instance=ExtResource("15_uo3dh")]
position = Vector2(18, -250)
_spritesToOutline = [NodePath("../Duck rendered")]
[node name="CollisionShape3D" parent="InteractionArea/Area2D" index="0"]
[node name="CollisionShape3D" parent="duck interaction/Area2D" index="0"]
shape = SubResource("CircleShape2D_uo3dh")
[node name="Duck rendered" type="Sprite2D" parent="."]
@ -321,7 +323,7 @@ offset = Vector2(40, 40)
region_enabled = true
region_rect = Rect2(246, 393, 111, 111)
[connection signal="Interacted" from="InteractionArea" to="." method="TransferToTargetAfterDelay"]
[connection signal="Interacted" from="InteractionArea" to="Audio/NakNak" method="PlayOneShot"]
[connection signal="Interacted" from="duck interaction" to="." method="TransferToTargetAfterDelay"]
[connection signal="Interacted" from="duck interaction" to="Audio/NakNak" method="PlayOneShot"]
[editable path="InteractionArea"]
[editable path="duck interaction"]

@ -28,7 +28,7 @@
resource_local_to_scene = true
radius = 325.2599
[node name="BaseField" type="Node2D"]
[node name="BaseField" type="Node2D" groups=["Saveable"]]
script = ExtResource("1_4mg73")
Payload = 0
@ -38,13 +38,13 @@ z_index = 1
scale = Vector2(1.3499999, 1.5)
texture = ExtResource("9_wx561")
[node name="FieldBehaviour" type="Sprite2D" parent="." node_paths=PackedStringArray("_fieldIndex", "_fieldSprite", "_maskSprite", "_outlineSprite", "PlantingInteraction", "FieldInteractionArea", "PlantingPlaceholder", "_wateringParticles")]
[node name="FieldBehaviour" type="Sprite2D" parent="." node_paths=PackedStringArray("_fieldIndex", "_saveIdHolder", "_fieldSprite", "_maskSprite", "_outlineSprite", "PlantingInteraction", "FieldInteractionArea", "PlantingPlaceholder", "_wateringParticles")]
visible = false
z_index = -1
scale = Vector2(0.9, 1)
script = ExtResource("1_qa01x")
SaveId = "field"
_fieldIndex = NodePath("..")
_saveIdHolder = NodePath("..")
_sceneKeyProvider = ExtResource("11_cjahb")
FieldState = 0
_fieldSprite = NodePath("MaskedField/FieldTexture")

@ -30,10 +30,11 @@ stream_1/stream = ExtResource("7_edjam")
stream_2/stream = ExtResource("8_kflfw")
stream_3/stream = ExtResource("9_dltn0")
[node name="GenericItemOnGround" type="Node2D"]
[node name="GenericItemOnGround" type="Node2D" groups=["Saveable"]]
z_index = 1
y_sort_enabled = true
script = ExtResource("1_tlhp6")
metadata/SaveID = ""
[node name="SpawnWithItem" type="Node" parent="."]
script = ExtResource("3_xu8me")

@ -32,8 +32,8 @@ InputService="*res://scripts/CSharp/Common/Services/InputService.cs"
QuestManager="*res://prefabs/quests/quest_manager_autoload.tscn"
Signal_Debugger="*res://addons/SignalVisualizer/Debugger/SignalDebugger.gd"
FightWorldAutoload="*res://prefabs/fight/fight_world_autoload.tscn"
FieldService="*res://scripts/CSharp/Common/Farming/FieldService.cs"
SaveGameManager="*res://scripts/CSharp/Common/Savegame/SaveGameManager.cs"
SettingsSaveController="*res://scripts/CSharp/Common/Savegame/SettingsSaveController.cs"
[dialogic]
@ -220,6 +220,10 @@ folder_colors={
"res://shader/": "pink"
}
[global_group]
Saveable=""
[input]
move_left={

@ -13,4 +13,5 @@ name = "Hoe"
color = Color(0.751421, 0.329615, 0.570911, 1)
icon = SubResource("AtlasTexture_i5wdx")
maxStack = 1
isUnique = true
metadata/_custom_type_script = "uid://cbskymrxs6ksu"

@ -13,4 +13,5 @@ name = "Can"
color = Color(0.336269, 0.489145, 0.825324, 1)
icon = SubResource("AtlasTexture_tqw18")
maxStack = 1
isUnique = true
metadata/_custom_type_script = "uid://cbskymrxs6ksu"

@ -1,10 +1,13 @@
[gd_scene load_steps=2 format=3 uid="uid://bopv10dqm1knc"]
[gd_scene load_steps=3 format=3 uid="uid://bopv10dqm1knc"]
[ext_resource type="PackedScene" uid="uid://c6wnoif01ltld" path="res://scenes/Babushka_scene_startMenu.tscn" id="1_15ton"]
[ext_resource type="Script" uid="uid://bbp0dyddwdbl8" path="res://scripts/CSharp/Common/Savegame/WindowSettingsSync.cs" id="2_d3jfo"]
[node name="BabushkaSceneBootstrap" type="Node2D"]
[node name="BabushkaSceneStartMenu" parent="." instance=ExtResource("1_15ton")]
_sceneNamesToLoad = PackedStringArray("res://scenes/Babushka_scene_farm_outside_2d.tscn")
[node name="SceneParent" type="Node" parent="."]
[node name="WindowSettings" type="Node" parent="."]
script = ExtResource("2_d3jfo")

@ -1,4 +1,4 @@
[gd_scene load_steps=116 format=3 uid="uid://gigb28qk8t12"]
[gd_scene load_steps=118 format=3 uid="uid://gigb28qk8t12"]
[ext_resource type="PackedScene" uid="uid://c25udixd5m6l0" path="res://prefabs/characters/Player2D.tscn" id="1_7wfwe"]
[ext_resource type="Texture2D" uid="uid://8sr11ex30n0m" path="res://art/mockups/Kenney_Backgrounds/Samples/uncolored_hills.png" id="2_7b2ri"]
@ -38,7 +38,6 @@
[ext_resource type="Resource" uid="uid://d1uuxp1lp4aro" path="res://resources/items/tomato_seed.tres" id="35_64mdn"]
[ext_resource type="Texture2D" uid="uid://65e44yde224q" path="res://art/farm/Babushka_house_01.png" id="36_e5b7x"]
[ext_resource type="Resource" uid="uid://duq7tshxv6uhp" path="res://resources/items/beet_seed.tres" id="36_fv1t2"]
[ext_resource type="Texture2D" uid="uid://cyyxqmphcrjj" path="res://art/farm/farming/farmobjekte/tomaten/tomaten_template.png" id="36_l7ekk"]
[ext_resource type="AudioStream" uid="uid://cfqg50am0swb7" path="res://audio/Music/Farming_90BPM_69Bars_Loop.wav" id="37_8ey8m"]
[ext_resource type="AudioStream" uid="uid://dku1rq5cocisg" path="res://audio/Music/Farming_90BPM_69Bars.wav" id="37_di1ed"]
[ext_resource type="Shader" uid="uid://braevmqauoek7" path="res://shader/swaying_plant.gdshader" id="37_taxvr"]
@ -79,6 +78,8 @@
[ext_resource type="Script" uid="uid://dih1b0opgc3f7" path="res://scripts/GdScript/dialogic_start_specific.gd" id="77_l7ekk"]
[ext_resource type="Resource" uid="uid://tt3d166mntmi" path="res://resources/low code/farming/var_sceneNameProvider.tres" id="77_xcwle"]
[ext_resource type="PackedScene" uid="uid://b1d2e7ely6hyw" path="res://prefabs/farm/base_field.tscn" id="78_xcwle"]
[ext_resource type="Script" uid="uid://iquhbkr7pqeg" path="res://scripts/CSharp/Common/Savegame/SaveCheats.cs" id="79_065st"]
[ext_resource type="Script" uid="uid://ca4s0algeij1h" path="res://scripts/CSharp/Common/Savegame/SaveIDProviderTool.cs" id="80_w1kgo"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_wtdui"]
shader = ExtResource("13_7p0hq")
@ -1059,9 +1060,8 @@ collision_mask = 4
position = Vector2(145.5, -224)
shape = SubResource("RectangleShape2D_0sfl7")
[node name="InteractionArea" parent="YSorted/Well" node_paths=PackedStringArray("_spritesToOutline") instance=ExtResource("27_klb81")]
_spritesToOutline = [NodePath("..")]
_id = 1
[node name="InteractionArea" parent="YSorted/Well" instance=ExtResource("27_klb81")]
metadata/SaveID = "b8f7b7fe-e057-4974-ba12-9134722998de"
[node name="CollisionShape3D" parent="YSorted/Well/InteractionArea/Area2D" index="0"]
position = Vector2(146, -130)
@ -1069,10 +1069,16 @@ shape = SubResource("CircleShape2D_p6n74")
[node name="CanGenericPickup" parent="YSorted" instance=ExtResource("25_hukxv")]
position = Vector2(8192, 3507)
metadata/SaveID = "5a823507-8107-40ce-8b32-6d0f81a3c44e"
[node name="SpawnWithItem" parent="YSorted/CanGenericPickup" index="0"]
_blueprint = ExtResource("28_ipqaa")
[node name="PickupInteractionArea" parent="YSorted/CanGenericPickup" index="3" node_paths=PackedStringArray("_spritesToOutline")]
_outlineMaterial = null
_spritesToOutline = []
metadata/SaveID = "0c006f5c-c472-4f89-908b-d8f34503ba37"
[node name="CollisionShape3D" parent="YSorted/CanGenericPickup/PickupInteractionArea/Area2D" index="0"]
shape = SubResource("CircleShape2D_2065p")
@ -1081,21 +1087,30 @@ offset = Vector2(0, -50)
[node name="RakeGenericPickup" parent="YSorted" instance=ExtResource("25_hukxv")]
position = Vector2(8391, 2060)
metadata/SaveID = "e13886b1-2131-4072-bc06-7d8abb19357b"
[node name="SpawnWithItem" parent="YSorted/RakeGenericPickup" index="0"]
_blueprint = ExtResource("28_6b2nr")
[node name="PickupInteractionArea" parent="YSorted/RakeGenericPickup" index="3" node_paths=PackedStringArray("_spritesToOutline")]
_outlineMaterial = null
_spritesToOutline = []
metadata/SaveID = "c148aa78-114b-4770-a040-8498483edb1d"
[node name="CollisionShape3D" parent="YSorted/RakeGenericPickup/PickupInteractionArea/Area2D" index="0"]
shape = SubResource("CircleShape2D_tm0yg")
[node name="SeedPickup" parent="YSorted" instance=ExtResource("25_hukxv")]
position = Vector2(9927, 2257)
_infiniteSupply = true
_finiteSupply = 3
metadata/SaveID = "e1bbe13f-0622-42b8-97f3-87a8af369dc0"
[node name="SpawnWithItem" parent="YSorted/SeedPickup" index="0"]
_blueprint = ExtResource("35_64mdn")
[node name="PickupInteractionArea" parent="YSorted/SeedPickup" index="3"]
metadata/SaveID = "ad152c51-3631-42c1-9aa4-4df896b35d8c"
[node name="CollisionShape3D" parent="YSorted/SeedPickup/PickupInteractionArea/Area2D" index="0"]
shape = SubResource("CircleShape2D_tm0yg")
@ -1105,10 +1120,14 @@ scale = Vector2(1, 1)
[node name="SeedPickup2" parent="YSorted" instance=ExtResource("25_hukxv")]
position = Vector2(10705, 2257)
_finiteSupply = 3
metadata/SaveID = "77972c50-63a7-461a-bc7d-6fa46333bc5c"
[node name="SpawnWithItem" parent="YSorted/SeedPickup2" index="0"]
_blueprint = ExtResource("36_fv1t2")
[node name="PickupInteractionArea" parent="YSorted/SeedPickup2" index="3"]
metadata/SaveID = "09e115e7-1d21-485a-be3e-b3fff9c83e78"
[node name="CollisionShape3D" parent="YSorted/SeedPickup2/PickupInteractionArea/Area2D" index="0"]
shape = SubResource("CircleShape2D_tm0yg")
@ -1122,58 +1141,72 @@ position = Vector2(0, -200)
[node name="BaseField" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(8807, 3061)
metadata/SaveID = "533e356b-386b-49c9-beb1-4484f2a5164f"
[node name="BaseField2" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(9335, 3562)
Payload = 1
metadata/SaveID = "79084490-9e12-4153-9ae8-6162b5348c37"
[node name="BaseField3" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(9854, 3071)
Payload = 2
metadata/SaveID = "7332aadf-2583-468b-889c-ccbad96137f8"
[node name="BaseField4" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(10361, 3536)
Payload = 3
metadata/SaveID = "493f7b1f-3d01-4d66-b668-6014ef9b3c15"
[node name="BaseField5" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(10948, 3025)
Payload = 4
metadata/SaveID = "ba9d21eb-7c31-4459-bd90-ae23e9a09eb1"
[node name="BaseField6" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(11296, 3607)
Payload = 5
metadata/SaveID = "e6a3367e-afe1-4c5d-abd9-153cc365dce0"
[node name="BaseField7" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(11869, 3026)
Payload = 6
metadata/SaveID = "08de526f-e22f-42a4-a3f9-549d2dc15b5d"
[node name="BaseField8" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(12353, 3554)
Payload = 7
metadata/SaveID = "9fd46633-8028-48e6-9176-ffe8c7a26a2e"
[node name="BaseField9" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(12828, 2999)
Payload = 8
metadata/SaveID = "82e139eb-47f4-4ce4-962f-f72d22f9fe45"
[node name="BaseField10" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(13285, 3536)
Payload = 9
metadata/SaveID = "03ff923a-614a-4fc9-8865-f5290ec16169"
[node name="BaseField11" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(13733, 2990)
Payload = 10
metadata/SaveID = "1347c031-e8c0-44f9-9d42-80084ae9bc29"
[node name="BaseField12" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(14261, 3474)
Payload = 11
metadata/SaveID = "c0b02859-bd5c-4780-8ca7-80b4234ee1d7"
[node name="BaseField13" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(14753, 2982)
Payload = 12
metadata/SaveID = "bee82b2a-a437-4d3a-b003-dac55dfd24aa"
[node name="BaseField14" parent="YSorted/FieldParent/right" instance=ExtResource("78_xcwle")]
position = Vector2(15201, 3519)
Payload = 13
metadata/SaveID = "4750a191-6902-46d4-9b2e-964c1aa0a29c"
[node name="left" type="Node2D" parent="YSorted/FieldParent"]
position = Vector2(-8661, -143)
@ -1181,50 +1214,62 @@ position = Vector2(-8661, -143)
[node name="BaseField" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(8807, 3061)
Payload = 14
metadata/SaveID = "b44ef2e7-898a-40d0-975b-ba75d7df4601"
[node name="BaseField2" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(9227, 3562)
Payload = 15
metadata/SaveID = "5705ba02-f444-4f2b-b527-b95578132b87"
[node name="BaseField3" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(9756, 3111)
Payload = 16
metadata/SaveID = "bca9073b-0b2f-4371-a645-a37aa04f4e23"
[node name="BaseField4" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(10322, 3536)
Payload = 17
metadata/SaveID = "f636a1ef-016d-4361-9b6e-1d59262a8c04"
[node name="BaseField5" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(10810, 3055)
Payload = 18
metadata/SaveID = "d074a30d-3f52-4788-879a-4ea8c5818c32"
[node name="BaseField6" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(11266, 3607)
Payload = 19
metadata/SaveID = "8296a15c-be4a-4127-b0f7-8a330dd2a843"
[node name="BaseField7" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(11741, 3026)
Payload = 20
metadata/SaveID = "02468d9f-0120-42ff-806d-0aaa351f055c"
[node name="BaseField8" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(12255, 3593)
Payload = 21
metadata/SaveID = "803f7df5-23a8-424a-8389-08371ea80101"
[node name="BaseField9" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(12690, 3019)
Payload = 22
metadata/SaveID = "88efb617-5e57-4b16-8ceb-c45c56463690"
[node name="BaseField10" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(13216, 3556)
Payload = 23
metadata/SaveID = "ca6c1e3d-2c4e-4977-a89e-55d265f65faf"
[node name="BaseField11" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(13684, 3000)
Payload = 24
metadata/SaveID = "262fbec5-597d-432e-8dd0-50d53fd51b59"
[node name="BaseField12" parent="YSorted/FieldParent/left" instance=ExtResource("78_xcwle")]
position = Vector2(14143, 3523)
Payload = 25
metadata/SaveID = "05389ea3-d19b-42fc-8bf0-b0755437ec10"
[node name="Farm visuals" type="Node2D" parent="YSorted"]
position = Vector2(-60, 122)
@ -1247,11 +1292,10 @@ collision_mask = 6
position = Vector2(-252.56, 231.32)
polygon = PackedVector2Array(247.227, 43.5123, 44.7822, 43.5123, -87.2178, 45.123, -104.329, -55.2797, -154.107, -73.5347, -160.107, -380.38, -175.44, -400.783, -63.44, -512.461, 97.8934, -541.991, 261.671, -599.172, 374.782, -526.421, 502.338, -526.421, 637.893, -396.488, 598.56, -360.783, 596.338, -58.2327, 528.782, -58.2327, 501.449, 45.9283)
[node name="EnterHouseInteraction" parent="YSorted/Farm visuals/Static" node_paths=PackedStringArray("_spritesToOutline") instance=ExtResource("27_klb81")]
[node name="EnterHouseInteraction" parent="YSorted/Farm visuals/Static" instance=ExtResource("27_klb81")]
position = Vector2(5834, 2354)
scale = Vector2(2.425, 2.425)
_spritesToOutline = [NodePath("DoorSprite")]
_id = 0
metadata/SaveID = "5a93071f-c1ab-4b4b-b74e-a6324d44ddf8"
[node name="DoorSprite" type="Sprite2D" parent="YSorted/Farm visuals/Static/EnterHouseInteraction"]
position = Vector2(0.412364, -33.1959)
@ -2223,6 +2267,7 @@ shape = SubResource("RectangleShape2D_ycj14")
position = Vector2(11234, 1850)
_spritesToOutline = [NodePath("Fence Door")]
_id = 1
metadata/SaveID = "6ee77256-42af-49c9-a3f2-cf167853f6fb"
[node name="CollisionShape3D" parent="YSorted/Blocker/InteractionArea/Area2D" index="0"]
shape = SubResource("CircleShape2D_l7ekk")
@ -2243,7 +2288,6 @@ position = Vector2(-113.561, 193.035)
shape = SubResource("RectangleShape2D_2vojv")
[node name="ducks" type="Node2D" parent="YSorted"]
visible = false
z_index = 1
y_sort_enabled = true
script = ExtResource("49_uxa2m")
@ -2254,12 +2298,14 @@ z_index = 0
y_sort_enabled = false
position = Vector2(4374, 2652)
_penTarget = NodePath("../../pen/penSlot1")
metadata/SaveID = "348bd0e3-1da5-4f10-84ab-b0444e99d541"
[node name="Duck3" parent="YSorted/ducks" node_paths=PackedStringArray("_penTarget") instance=ExtResource("62_i36hd")]
z_index = 0
y_sort_enabled = false
position = Vector2(9259, 3194)
_penTarget = NodePath("../../pen/penSlot2")
metadata/SaveID = "94c8a740-2745-4162-91e7-66f36b8681e0"
[node name="Duck4" parent="YSorted/ducks" node_paths=PackedStringArray("_penTarget") instance=ExtResource("62_i36hd")]
z_index = 0
@ -2268,6 +2314,7 @@ position = Vector2(13441, 3612)
rotation = 3.14159
scale = Vector2(1, -1)
_penTarget = NodePath("../../pen/penSlot3")
metadata/SaveID = "b3508312-eb61-4520-8349-e49e0e5328d3"
[node name="Duck5" parent="YSorted/ducks" node_paths=PackedStringArray("_penTarget") instance=ExtResource("62_i36hd")]
z_index = 0
@ -2276,12 +2323,14 @@ position = Vector2(15330, 2487)
rotation = 3.14159
scale = Vector2(1, -1)
_penTarget = NodePath("../../pen/penSlot4")
metadata/SaveID = "b73895c2-6366-4c7e-b5e2-23f3dc9485f2"
[node name="Duck6" parent="YSorted/ducks" node_paths=PackedStringArray("_penTarget") instance=ExtResource("62_i36hd")]
z_index = 0
y_sort_enabled = false
position = Vector2(232, 2862)
_penTarget = NodePath("../../pen/penSlot5")
metadata/SaveID = "a963b9d2-862f-458b-be2c-9a54ec1bde90"
[node name="Duck7" parent="YSorted/ducks" node_paths=PackedStringArray("_penTarget") instance=ExtResource("62_i36hd")]
z_index = 0
@ -2290,6 +2339,7 @@ position = Vector2(2409, 3958)
rotation = 3.14159
scale = Vector2(1, -1)
_penTarget = NodePath("../../pen/penSlot6")
metadata/SaveID = "748aff78-10eb-4a4e-bb6d-a8ee25d472d1"
[node name="DialogicToggle" type="Node2D" parent="YSorted/ducks"]
script = ExtResource("51_uxa2m")
@ -2336,8 +2386,10 @@ position = Vector2(3183, 2369)
offset = Vector2(1, -50)
region_rect = Rect2(207, 1184, 149, 142)
[node name="InteractionArea" parent="YSorted/trash/trashObject2" index="0"]
[node name="InteractionArea" parent="YSorted/trash/trashObject2" index="0" node_paths=PackedStringArray("_spritesToOutline")]
position = Vector2(-9, -46)
_spritesToOutline = []
metadata/SaveID = "549bbcf4-ea57-4b8f-80b1-b13ca648559b"
[node name="trashObject3" parent="YSorted/trash" instance=ExtResource("53_ycj14")]
z_index = 0
@ -2346,8 +2398,10 @@ position = Vector2(4724, 3519)
offset = Vector2(1, -50)
region_rect = Rect2(400, 1053, 163, 141)
[node name="InteractionArea" parent="YSorted/trash/trashObject3" index="0"]
[node name="InteractionArea" parent="YSorted/trash/trashObject3" index="0" node_paths=PackedStringArray("_spritesToOutline")]
position = Vector2(-13, -53)
_spritesToOutline = []
metadata/SaveID = "29874314-50c1-4a21-9494-18f936d6e097"
[node name="trashObject4" parent="YSorted/trash" instance=ExtResource("53_ycj14")]
z_index = 0
@ -2356,8 +2410,10 @@ position = Vector2(5385, 3391)
offset = Vector2(1, -50)
region_rect = Rect2(1048, 1092, 348, 106)
[node name="InteractionArea" parent="YSorted/trash/trashObject4" index="0"]
[node name="InteractionArea" parent="YSorted/trash/trashObject4" index="0" node_paths=PackedStringArray("_spritesToOutline")]
position = Vector2(0, -59)
_spritesToOutline = []
metadata/SaveID = "7ccaa831-5526-40ed-8ca3-31ba2ad929a6"
[node name="trashObject5" parent="YSorted/trash" instance=ExtResource("53_ycj14")]
z_index = 0
@ -2393,8 +2449,10 @@ rotation = 1.77025
offset = Vector2(0, 0)
region_rect = Rect2(1048, 1092, 348, 106)
[node name="InteractionArea" parent="YSorted/trash/trashObject9" index="0"]
[node name="InteractionArea" parent="YSorted/trash/trashObject9" index="0" node_paths=PackedStringArray("_spritesToOutline")]
position = Vector2(22.40873, 25.05658)
_spritesToOutline = []
metadata/SaveID = "7bf227d6-3844-41e9-a9cd-524052aced3b"
[node name="CanvasLayer" parent="." instance=ExtResource("32_2nee2")]
@ -2509,6 +2567,14 @@ script = ExtResource("76_l7ekk")
_variableResource = ExtResource("77_xcwle")
_payloadToSet = "farmOutside"
[node name="SaveSystem" type="Node" parent="."]
[node name="SaveGameCheat" type="Node" parent="SaveSystem"]
script = ExtResource("79_065st")
[node name="SaveIDProvider" type="Node" parent="SaveSystem"]
script = ExtResource("80_w1kgo")
[connection signal="FilledWateringCan" from="YSorted/Vesna" to="Audio/SFX/FillWater SFX2" method="PlayOneShot"]
[connection signal="InteractedTool" from="YSorted/Well/InteractionArea" to="YSorted/Vesna" method="TryFillWateringCan"]
[connection signal="SuccessfulPickUp" from="YSorted/CanGenericPickup" to="YSorted/Vesna" method="HandlePickUp"]

@ -1,4 +1,4 @@
[gd_scene load_steps=96 format=3 uid="uid://b3ibx4resa1f3"]
[gd_scene load_steps=98 format=3 uid="uid://b3ibx4resa1f3"]
[ext_resource type="Script" uid="uid://cssdu8viimwm6" path="res://scripts/CSharp/Common/SceneTransition.cs" id="1_6krrk"]
[ext_resource type="Script" uid="uid://bqomwxclsbhd3" path="res://scripts/CSharp/Common/Camera/CameraController.cs" id="2_4ktoi"]
@ -52,7 +52,9 @@
[ext_resource type="AudioStream" uid="uid://bxh5m04vdo0sr" path="res://audio/sfx/Farming/SFX_Harke_04_Solo.wav" id="57_euap5"]
[ext_resource type="Resource" uid="uid://tt3d166mntmi" path="res://resources/low code/farming/var_sceneNameProvider.tres" id="57_hpgl7"]
[ext_resource type="Script" uid="uid://cfnrd5k1k0gxw" path="res://scripts/CSharp/Common/AudioPlayer2D.cs" id="58_m3hs4"]
[ext_resource type="Script" uid="uid://iquhbkr7pqeg" path="res://scripts/CSharp/Common/Savegame/SaveCheats.cs" id="58_qavgq"]
[ext_resource type="AudioStream" uid="uid://dapsknn486aee" path="res://audio/sfx/Farming/SFX_WateringPlants_01.wav" id="59_km2vg"]
[ext_resource type="Script" uid="uid://ca4s0algeij1h" path="res://scripts/CSharp/Common/Savegame/SaveIDProviderTool.cs" id="59_njxly"]
[ext_resource type="AudioStream" uid="uid://dnyne8wov50so" path="res://audio/sfx/Farming/SFX_WateringPlants_02.wav" id="60_qi2gu"]
[ext_resource type="AudioStream" uid="uid://fsiypqhql67w" path="res://audio/sfx/Farming/SFX_GettingWater_01.wav" id="61_wy1mx"]
[ext_resource type="AudioStream" uid="uid://foyw26hq1qp5" path="res://audio/sfx/Farming/SFX_GettingWater_02.wav" id="62_kmjnt"]
@ -1749,9 +1751,11 @@ scale = Vector2(1, 0.993819)
[node name="BaseField" parent="YSorted/Farm visuals/FieldParent" instance=ExtResource("40_efblm")]
position = Vector2(651, 2630.26)
scale = Vector2(1, 1.00622)
metadata/SaveID = "b3b47e69-6115-4405-8da6-508b783823d2"
[node name="FieldBehaviour" parent="YSorted/Farm visuals/FieldParent/BaseField" index="1"]
visible = true
metadata/SaveID = "7a8210bf-479d-4b4c-9758-98d23e59d5d7"
[node name="Beet2" parent="YSorted/Farm visuals/FieldParent/BaseField/FieldBehaviour/PlantPlaceholder" index="0" node_paths=PackedStringArray("_field") instance=ExtResource("41_vyqmy")]
_state = 2
@ -1767,9 +1771,11 @@ shape = SubResource("CircleShape2D_qavgq")
position = Vector2(1226, 3098.15)
scale = Vector2(1, 1.00622)
Payload = 1
metadata/SaveID = "f536efd3-3da8-4ef5-a520-570220e6c19f"
[node name="FieldBehaviour" parent="YSorted/Farm visuals/FieldParent/BaseField2" index="1"]
visible = true
metadata/SaveID = "a1d8a0a2-c51c-4410-83c3-0edb31cbf2de"
[node name="Beet2" parent="YSorted/Farm visuals/FieldParent/BaseField2/FieldBehaviour/PlantPlaceholder" index="0" node_paths=PackedStringArray("_field") instance=ExtResource("41_vyqmy")]
_state = 2
@ -1785,9 +1791,11 @@ shape = SubResource("CircleShape2D_njxly")
position = Vector2(1782, 2606.11)
scale = Vector2(1, 1.00622)
Payload = 2
metadata/SaveID = "14ce64d5-8a4d-43b9-a8ff-3a57725c4dc8"
[node name="FieldBehaviour" parent="YSorted/Farm visuals/FieldParent/BaseField3" index="1"]
visible = true
metadata/SaveID = "79a65532-cb2b-4268-8eb0-8c41a3935cbb"
[node name="Beet2" parent="YSorted/Farm visuals/FieldParent/BaseField3/FieldBehaviour/PlantPlaceholder" index="0" node_paths=PackedStringArray("_field") instance=ExtResource("41_vyqmy")]
_state = 2
@ -1803,10 +1811,12 @@ shape = SubResource("CircleShape2D_54ty3")
position = Vector2(2559, 2624.22)
scale = Vector2(1, 1.00622)
Payload = 3
metadata/SaveID = "6872ce5d-6f42-47d7-97e2-a7214ff3b08c"
[node name="FieldBehaviour" parent="YSorted/Farm visuals/FieldParent/BaseField4" index="1"]
visible = true
FieldState = 3
metadata/SaveID = "13fa64a3-01dc-4fd8-822e-0839c0da3163"
[node name="Beet2" parent="YSorted/Farm visuals/FieldParent/BaseField4/FieldBehaviour/PlantPlaceholder" index="0" node_paths=PackedStringArray("_field") instance=ExtResource("41_vyqmy")]
_state = 2
@ -1822,10 +1832,12 @@ shape = SubResource("CircleShape2D_gbxtf")
position = Vector2(3305, 2624.22)
scale = Vector2(1, 1.00622)
Payload = 4
metadata/SaveID = "f163c38d-9ee0-4844-9def-479833febb4e"
[node name="FieldBehaviour" parent="YSorted/Farm visuals/FieldParent/BaseField5" index="1"]
visible = true
FieldState = 3
metadata/SaveID = "414ecdb9-f3c4-4fb9-81bd-6ca575784f78"
[node name="Beet2" parent="YSorted/Farm visuals/FieldParent/BaseField5/FieldBehaviour/PlantPlaceholder" index="0" node_paths=PackedStringArray("_field") instance=ExtResource("41_vyqmy")]
_state = 2
@ -1841,10 +1853,12 @@ shape = SubResource("CircleShape2D_6krrk")
position = Vector2(4033, 2618.18)
scale = Vector2(1, 1.00622)
Payload = 5
metadata/SaveID = "da691381-ee82-4f86-abf3-dda2c9f19337"
[node name="FieldBehaviour" parent="YSorted/Farm visuals/FieldParent/BaseField6" index="1"]
visible = true
FieldState = 3
metadata/SaveID = "b235febb-b231-4f8c-94e9-1f9d9f115b08"
[node name="Beet2" parent="YSorted/Farm visuals/FieldParent/BaseField6/FieldBehaviour/PlantPlaceholder" index="0" node_paths=PackedStringArray("_field") instance=ExtResource("41_vyqmy")]
_state = 1
@ -1860,10 +1874,12 @@ shape = SubResource("CircleShape2D_4ktoi")
position = Vector2(4755, 2630.26)
scale = Vector2(1, 1.00622)
Payload = 6
metadata/SaveID = "8116fa8b-b164-4d39-a1ed-6cd476d18f94"
[node name="FieldBehaviour" parent="YSorted/Farm visuals/FieldParent/BaseField7" index="1"]
visible = true
FieldState = 3
metadata/SaveID = "9ccdba91-812a-4c13-9ee0-12472e174fc9"
[node name="Beet2" parent="YSorted/Farm visuals/FieldParent/BaseField7/FieldBehaviour/PlantPlaceholder" index="0" node_paths=PackedStringArray("_field") instance=ExtResource("41_vyqmy")]
_state = 2
@ -1879,10 +1895,12 @@ shape = SubResource("CircleShape2D_aaup4")
position = Vector2(4418, 3226.95)
scale = Vector2(1, 1.00622)
Payload = 7
metadata/SaveID = "5298f423-4c3b-45b5-94fb-d4aef36bac21"
[node name="FieldBehaviour" parent="YSorted/Farm visuals/FieldParent/BaseField8" index="1"]
visible = true
FieldState = 3
metadata/SaveID = "da44e54a-0b76-4888-ad8b-782a9d146fa3"
[node name="Beet2" parent="YSorted/Farm visuals/FieldParent/BaseField8/FieldBehaviour/PlantPlaceholder" index="0" node_paths=PackedStringArray("_field") instance=ExtResource("41_vyqmy")]
_state = 2
@ -1898,9 +1916,11 @@ shape = SubResource("CircleShape2D_v10dc")
position = Vector2(5317, 3208.83)
scale = Vector2(1, 1.00622)
Payload = 8
metadata/SaveID = "0de8dc13-5851-4471-be35-309cd6687ebc"
[node name="FieldBehaviour" parent="YSorted/Farm visuals/FieldParent/BaseField9" index="1"]
visible = true
metadata/SaveID = "9919b294-04a1-4a16-9783-38c8aa0e291c"
[node name="FieldActivator" parent="YSorted/Farm visuals/FieldParent/BaseField9" index="7"]
visible = false
@ -2031,6 +2051,14 @@ script = ExtResource("56_34r5t")
_variableResource = ExtResource("57_hpgl7")
_payloadToSet = "beetRootScene"
[node name="SaveSystem" type="Node" parent="."]
[node name="SaveGameCheat" type="Node" parent="SaveSystem"]
script = ExtResource("58_qavgq")
[node name="SaveIDProvider" type="Node" parent="SaveSystem"]
script = ExtResource("59_njxly")
[connection signal="FilledWateringCan" from="YSorted/Vesna" to="Audio/SFX/FillWater SFX2" method="PlayOneShot"]
[connection signal="InteractedTool" from="YSorted/Brünnen/InteractionArea" to="YSorted/Vesna" method="TryFillWateringCan"]
[connection signal="InteractedTool" from="YSorted/Blocker/BackToFarm" to="." method="LoadSceneAtIndex"]

@ -1,4 +1,3 @@
using System;
using System.Linq;
using Babushka.scripts.CSharp.Common.Services;
using Godot;
@ -7,7 +6,7 @@ namespace Babushka.scripts.CSharp.Common.CharacterControls;
public partial class InteractionArea2D : Node2D
{
[ExportGroup("Settings")]
[Export] private Area2D _area;
[Export] private Label _label;
[Export] private bool _active = true;
@ -18,6 +17,7 @@ public partial class InteractionArea2D : Node2D
[Export] private int _id = -1; // TODO: remove
private Material[] _backupMaterials;
private int _interactionCounter;
kziolkowski marked this conversation as resolved
Review

Is this ever used?

Is this ever used?
Review

good catch, this is residue from an attempt at serializing the InteractionArea, which we won't do. So I'm deleting this now.

good catch, this is residue from an attempt at serializing the InteractionArea, which we won't do. So I'm deleting this now.
[Signal] public delegate void InteractedToolEventHandler(int id); // TODO: remove
@ -42,7 +42,6 @@ public partial class InteractionArea2D : Node2D
}
}
public void OnPlayerEntered(Node2D player)
{
if (!_active || !InputService.Instance.InputEnabled)
@ -104,12 +103,17 @@ public partial class InteractionArea2D : Node2D
sprite.Material = _backupMaterials[i];
}
}
EmitSignal(SignalName.InteractedTool, _id);
EmitSignal(SignalName.Interacted);
Interact();
}
}
private void Interact()
{
EmitSignal(SignalName.InteractedTool, _id);
EmitSignal(SignalName.Interacted);
_interactionCounter++;
}
public void SetSpriteActiveState(bool success, int id) // TODO: remove
{
if (!_active)
@ -121,4 +125,5 @@ public partial class InteractionArea2D : Node2D
_active = !_active;
_label.Hide();
}
}

@ -13,11 +13,11 @@ namespace Babushka.scripts.CSharp.Common.Farming;
/// Defines the behaviour of the field, i.e. interactions, states and effects.
/// </summary>
[GlobalClass]
public partial class FieldBehaviour2D : Sprite2D
public partial class FieldBehaviour2D : Sprite2D, ISaveable
{
[ExportGroup("Persistence")]
[Export] public string SaveId = "";
[Export] private VariableNode _fieldIndex;
[Export] private Node _saveIdHolder;
[Export] public VariableResource _sceneKeyProvider;
[Export] public FieldState FieldState = FieldState.Tilled;
@ -78,8 +78,6 @@ public partial class FieldBehaviour2D : Sprite2D
_currentPlant = PlantingPlaceholder.GetChild<PlantBehaviour2D>(0);
UpdateFieldState(FieldState);
FieldService.Instance.TryAddEntry(_sceneKeyProvider.Payload.AsString(),_fieldIndex.Payload.AsInt32(), this);
int randomIndex = new Random().Next(0, _maskTexture.Length);
_maskSprite.Texture = _maskTexture[randomIndex];
_outlineSprite.Texture = _maskOutlineTextures[randomIndex];
@ -185,10 +183,6 @@ public partial class FieldBehaviour2D : Sprite2D
public void UpdateSaveData()
{
var saveData = new SaveData();
saveData.SceneName = _sceneKeyProvider.Payload.AsString();
saveData.Id = SaveId + _fieldIndex.Payload.AsString();
var payloadData = new Dictionary<string, Variant>
{
{ "field_state", (int)FieldState }
@ -206,17 +200,15 @@ public partial class FieldBehaviour2D : Sprite2D
);
}
saveData.JsonPayload = Json.Stringify(payloadData, indent: "\t");
SavegameService.AppendSave(saveData);
string id = _saveIdHolder.GetMeta("SaveID").AsString();
SavegameService.AppendDataToSave(id, payloadData);
}
public void LoadFromSaveData()
{
var sceneName = _sceneKeyProvider.Payload.AsString();
var id = SaveId + _fieldIndex.Payload.AsString();
string jsonPayload = SavegameService.GetSaveData(sceneName, id);
Dictionary<string, Variant> save = Json.ParseString(jsonPayload).AsGodotDictionary<string, Variant>();
string id = _saveIdHolder.GetMeta("SaveID").AsString();
Dictionary<string, Variant> save = SavegameService.GetSaveData(id);
if (save.Count > 0)
{

@ -1,100 +0,0 @@
using System.Collections.Generic;
using Godot;
namespace Babushka.scripts.CSharp.Common.Farming;
public partial class FieldService : Node
{
private Dictionary<string, FieldsInScene>? _outerDict = null!;
public static FieldService Instance { get; private set; } = null!;
public override void _EnterTree()
{
Instance = this;
_outerDict = new Dictionary<string, FieldsInScene>();
}
public override void _ExitTree()
{
Instance = null;
_outerDict = null;
}
//Create
public bool TryAddEntry(string sceneName, int fieldIndex, FieldBehaviour2D field)
{
if (_outerDict != null )
{
FieldsInScene innerDict;
bool outerDictEntryExists = _outerDict.TryGetValue(sceneName, out innerDict);
if (!outerDictEntryExists)
{
innerDict = new FieldsInScene();
_outerDict.Add(sceneName, innerDict);
}
if (!innerDict.fields.ContainsKey(fieldIndex))
{
innerDict.fields.Add(fieldIndex, field);
return true;
}
}
return false;
}
// Read
public FieldBehaviour2D? TryGet(string key, int fieldIndex)
{
if (_outerDict != null && _outerDict.TryGetValue(key, out FieldsInScene? field))
{
if (field.fields.TryGetValue(fieldIndex, out FieldBehaviour2D? fieldInstance))
{
return fieldInstance;
}
}
return null;
}
//Update
public void UpdateEntry(string key, int fieldIndex, FieldBehaviour2D state)
{
if (_outerDict != null && _outerDict.TryGetValue(key, out FieldsInScene? field))
{
if (field.fields.ContainsKey(fieldIndex))
{
field.fields[fieldIndex] = state;
}
else
{
TryAddEntry(key, fieldIndex, state);
}
}
}
//Delete
public void RemoveEntry(string key, int fieldIndex)
{
if (_outerDict != null && _outerDict.TryGetValue(key, out FieldsInScene? field))
{
if (field.fields.ContainsKey(fieldIndex))
{
field.fields.Remove(fieldIndex);
}
}
}
}
internal class FieldsInScene
{
public Dictionary<int, FieldBehaviour2D?> fields;
public FieldsInScene()
{
fields = new Dictionary<int, FieldBehaviour2D?>();
}
}

@ -3,10 +3,11 @@ using System;
using Godot;
using System.Collections.Generic;
using System.Linq;
using Babushka.scripts.CSharp.Common.Savegame;
namespace Babushka.scripts.CSharp.Common.Inventory;
public partial class InventoryInstance : Node
public partial class InventoryInstance : Node, ISaveable
{
private List<InventorySlot> _slots = new();
public IReadOnlyList<InventorySlot> Slots => _slots;
@ -17,6 +18,8 @@ public partial class InventoryInstance : Node
[Signal]
public delegate void InventoryContentsChangedEventHandler();
public static string ID = "inventoryInstance";
/// <summary>
/// The total amount of Inventoryslots in the inventory (empty and occupied).
/// </summary>
@ -42,6 +45,19 @@ public partial class InventoryInstance : Node
}
}
public override void _EnterTree()
{
LoadFromSaveData();
InventoryContentsChanged += UpdateSaveData;
SlotAmountChanged += UpdateSaveData;
}
public override void _ExitTree()
{
InventoryContentsChanged -= UpdateSaveData;
SlotAmountChanged -= UpdateSaveData;
}
public InventoryActionResult AddItem(ItemInstance newItem)
{
var result = AddItemAndStackRecursive(newItem, 0);
@ -156,4 +172,49 @@ public partial class InventoryInstance : Node
{
return items.All(HasItems);
}
#region SAVE AND LOAD
public void UpdateSaveData()
{
var payloadData = new Godot.Collections.Dictionary<string, Variant>();
for (int i = 0; i < _slots.Count; i++)
{
if (!_slots[i].IsEmpty())
{
string key = i.ToString();
string[] value = new string[2];
value[0] = _slots[i].itemInstance.blueprint.ResourcePath;
value[1] = _slots[i].itemInstance.amount.ToString();
payloadData.Add(key,value);
}
}
SavegameService.AppendDataToSave(ID, payloadData);
}
public void LoadFromSaveData()
{
var id = ID;
Godot.Collections.Dictionary<string, Variant> save = SavegameService.GetSaveData(id);
if (save.Count > 0)
{
for (int i = 0; i < _slots.Count; i++)
{
if (save.TryGetValue(i.ToString(), out Variant inventoryItemData))
{
string[] savePayload = inventoryItemData.AsStringArray();
ItemResource resource = ResourceLoader.Load<ItemResource>(savePayload[0]);
int _amount = int.Parse(savePayload[1]);
ItemInstance instance = new ItemInstance { blueprint = resource, amount = _amount };
AddItem(instance);
}
}
}
}
#endregion
}

@ -23,7 +23,7 @@ public partial class InventoryManager : Node
}
}
public InventoryInstance playerInventory = new InventoryInstance();
public InventoryInstance? playerInventory;
private int _currentSelectedSlotIndex = 0;
@ -34,7 +34,9 @@ public partial class InventoryManager : Node
public override void _Ready()
{
playerInventory = new InventoryInstance();
playerInventory.SlotAmount = 37;
AddChild(playerInventory);
}
public InventoryActionResult CreateItem(

@ -18,7 +18,6 @@ public partial class InventoryUi : Control
public override void _Ready()
{
GD.Print("Ready inventory ui");
_playerInventory = InventoryManager.Instance.playerInventory;
//PopulateSlots();
SubscribeSlots();

@ -1,8 +1,10 @@
using Babushka.scripts.CSharp.Common.Savegame;
using Godot;
using Godot.Collections;
namespace Babushka.scripts.CSharp.Common.Inventory;
public partial class ItemOnGround2D : Node
public partial class ItemOnGround2D : Node, ISaveable
{
private ItemInstance _itemInstance;
@ -30,6 +32,7 @@ public partial class ItemOnGround2D : Node
public override void _Ready()
{
LoadFromSaveData();
UpdateVisuals();
_pickupErrorLabel.Text = "";
}
@ -43,24 +46,36 @@ public partial class ItemOnGround2D : Node
EmitSignal(SignalName.SuccessfulPickUp);
if (result == InventoryActionResult.Success)
{
if (!_infiniteSupply)
{
pickUpCounter++;
if (pickUpCounter >= _finiteSupply)
{
QueueFree();
}
}
Pickup();
}
else
{
_pickupErrorLabel.Text = "Inventory Full";
var tween = GetTree().CreateTween();
tween.TweenInterval(2);
tween.TweenCallback(Callable.From(() => _pickupErrorLabel.Text = ""));
FailToPickup();
}
}
private void Pickup()
{
if (!_infiniteSupply)
{
pickUpCounter++;
if (pickUpCounter >= _finiteSupply)
{
QueueFree();
}
UpdateSaveData();
}
}
private void FailToPickup()
{
_pickupErrorLabel.Text = "Inventory Full";
var tween = GetTree().CreateTween();
tween.TweenInterval(2);
tween.TweenCallback(Callable.From(() => _pickupErrorLabel.Text = ""));
}
public void UpdateVisuals()
{
if (!IsActive)
@ -76,4 +91,62 @@ public partial class ItemOnGround2D : Node
_itemLabel.Text = "";
}
}
public void UpdateSaveData()
{
var payloadData = new Dictionary<string, Variant>
{
{"pickupCounter", pickUpCounter}
};
string id = GetMeta("SaveID").AsString();
SavegameService.AppendDataToSave( id, payloadData);
}
public void LoadFromSaveData()
{
if (_infiniteSupply)
return;
// standard check: how many times has this item been collected?
string id = GetMeta("SaveID").AsString();
Dictionary<string, Variant> save = SavegameService.GetSaveData(id);
if (save.Count > 0)
{
if(save.TryGetValue("pickupCounter", out Variant countVar))
{
int count = countVar.AsInt32();
for (int i = 0; i < count; i++)
{
Pickup();
}
}
}
//separate check for unique items: If already in inventory, delete this instance.
ItemResource itemResource = itemInstance.blueprint;
Dictionary<string, Variant> savegameData = SavegameService.GetSaveData(InventoryInstance.ID);
if (savegameData.Count > 0)
{
foreach (var kvp in savegameData)
{
// if it's a unique item, then it can only exist once in the world (either as a pickup OR in the inventory)
if (itemInstance.blueprint.isUnique)
{
//comparing resource path to identify the item
string[] valuePair = kvp.Value.AsStringArray();
if (valuePair[0] == itemResource.ResourcePath)
{
int amountInInventory = int.Parse(valuePair[1]);
// comparing amount to see if it's all in the inventory now.
if (amountInInventory > 0)
{
Pickup();
}
}
}
}
}
}
}

@ -17,6 +17,9 @@ public partial class ItemResource : Resource
[Export]
public int maxStack;
[Export]
public bool isUnique;
public ItemResource()
{
name = "";

@ -12,8 +12,6 @@ public partial class QuestTrigger : Node
public void Trigger()
{
GD.Print("trigger");
if (questResource == null)
throw new Exception("QuestResource is not set on QuestTrigger node.");

@ -0,0 +1,19 @@
namespace Babushka.scripts.CSharp.Common.Savegame;
/// <summary>
/// Defines the behaviour of Nodes that have fields that should save / load to disk.
/// When implementing new Saveable objects, please beware: Please check if object instances need to be identified separately.
/// If so, make sure to give them a proper ID. You can use the <see cref="SaveIDProvider"/> tool for that.
/// </summary>
public interface ISaveable
{
/// <summary>
/// Adds or updates the field data that shall be stored to disk.
/// </summary>
public void UpdateSaveData();
/// <summary>
/// Loads the field data from disk.
/// </summary>
public void LoadFromSaveData();
}

@ -0,0 +1,15 @@
using Godot;
namespace Babushka.scripts.CSharp.Common.Savegame;
[Tool]
public partial class SaveCheats : Node
{
[ExportToolButton("ResetSave")] Callable _raiseAction => Callable.From(Reset);
public void Reset()
{
SavegameService.Reset();
}
}

@ -9,12 +9,20 @@ namespace Babushka.scripts.CSharp.Common.Savegame;
[Serializable]
public class SaveData
{
public string SceneName;
// for future use in case the structure changes.
public const int VERSION = 1;
public int version { get; set; } = VERSION;
public bool IsVersionValid()
{
return VERSION == version;
}
public string Id;
public string JsonPayload;
public string ToString()
{
return SceneName + " " + Id + " " + JsonPayload;
return Id + " " + JsonPayload;
}
}

@ -7,12 +7,15 @@ namespace Babushka.scripts.CSharp.Common.Savegame;
/// </summary>
public partial class SaveGameManager : Node
{
public static string USER_DATA_FILE_PATH = "user://save_data/userData.json";
public static SaveGameManager? Instance { get; private set; } = null!;
public override void _EnterTree()
{
Instance = this;
USER_DATA_FILE_PATH = ProjectSettings.GlobalizePath(USER_DATA_FILE_PATH);
SavegameService.SavePath = USER_DATA_FILE_PATH;
SavegameService.Load();
}

@ -0,0 +1,34 @@
using System;
using Godot;
using Godot.Collections;
namespace Babushka.scripts.CSharp.Common.Savegame;
/// <summary>
/// And editor tool that lives in the scene scope and iterates over saveable nodes and assigns them unique IDs where necessary.
/// It only works if the object (prefab) in question has been added to the "Saveable"-group beforehand.
/// </summary>
[Tool]
public partial class SaveIDProviderTool : Node
{
/// <summary>
/// Creates an inspector button that calls the AssignIDs method.
/// </summary>
[ExportToolButton("Assign IDs")] private Callable assignIDs => Callable.From(AssignIDs);
private void AssignIDs()
{
Array<Node> saveables = GetTree().GetNodesInGroup("Saveable");
foreach (var node in saveables)
{
GD.Print($"Checking {node.Name}.");
if (!node.HasMeta("SaveID") || string.IsNullOrEmpty(node.GetMeta("SaveID").AsString()))
{
string saveID = Guid.NewGuid().ToString();
node.SetMeta("SaveID", saveID);
GD.Print($"Setting Save ID for node {node.Name}: " + saveID);
}
}
}
}

@ -9,31 +9,38 @@ namespace Babushka.scripts.CSharp.Common.Savegame;
/// Handles the saving and loading of game states.
/// Holds the central SaveData object that serves as a temporary SaveFile.
/// Automatically writes to disk on every scene change.
/// Uses the Godot Json Serializer, which may implicitly convert integers to floats, so be careful when extending!
/// </summary>
public static class SavegameService
{
public static readonly string SavePath = "user://babushka_savegame.json";
public static string SavePath = "";
public static Dictionary<string, string> SaveDatas = new ();
public static bool _loaded = false;
public static void AppendDataToSave( string id, Dictionary<string, Variant> payload)
{
var saveData = new SaveData();
saveData.Id = id;
saveData.JsonPayload = Json.Stringify(payload, indent: "\t");
AppendSave(saveData);
}
/// <summary>
/// Adds or overwrites an entry in the SaveData dictionary.
/// </summary>
/// <param name="saveData"></param>
public static void AppendSave(SaveData saveData)
private static void AppendSave(SaveData saveData)
{
string key = string.Concat(saveData.SceneName, "_", saveData.Id);
if (SaveDatas.TryGetValue(key, out var value))
if (SaveDatas.TryGetValue(saveData.Id, out var value))
{
SaveDatas[key] = saveData.JsonPayload;
SaveDatas[saveData.Id] = saveData.JsonPayload;
}
else
{
SaveDatas.Add(key, saveData.JsonPayload);
SaveDatas.Add(saveData.Id, saveData.JsonPayload);
}
}
@ -45,21 +52,21 @@ public static class SavegameService
/// <param name="sceneName"></param>
/// <param name="id"></param>
/// <returns></returns>
public static string GetSaveData(string sceneName, string id)
public static Dictionary<string, Variant> GetSaveData(string id)
{
string saveData = "";
Dictionary<string, Variant> saveData = new();
string key = string.Concat(sceneName, "_", id);
string saveDataString = "";
if (!_loaded)
{
GD.Print("SavegameService: SaveFile not loaded.");
return saveData;
}
if (SaveDatas.ContainsKey(key))
if (SaveDatas.ContainsKey(id))
{
saveData = SaveDatas[key];
saveDataString = SaveDatas[id];
saveData = Json.ParseString(saveDataString).AsGodotDictionary<string, Variant>();
}
return saveData;
@ -72,8 +79,24 @@ public static class SavegameService
public static void Save()
{
string json = Json.Stringify(SaveDatas, indent: "\t");
using var file = FileAccess.Open(SavePath, FileAccess.ModeFlags.Write);
file.StoreString(json);
// create cloud directory
CreateSaveDirectory();
try
{
using var file = FileAccess.Open(SavePath, FileAccess.ModeFlags.Write);
file.StoreString(json);
}
catch (Exception e)
{
GD.Print(e.Message);
}
}
private static void CreateSaveDirectory()
{
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(SavePath) ?? "");
}
/// <summary>
@ -83,8 +106,16 @@ public static class SavegameService
{
try
{
if (!System.IO.File.Exists(SavePath))
{
SaveDatas = new();
CreateSaveDirectory();
}
string saveDataJson = FileAccess.GetFileAsString(SavePath);
SaveDatas = Json.ParseString(saveDataJson).AsGodotDictionary<string, string>();
if(!string.IsNullOrEmpty(saveDataJson))
SaveDatas = Json.ParseString(saveDataJson).AsGodotDictionary<string, string>();
}
catch(Exception e)
{
@ -94,4 +125,10 @@ public static class SavegameService
_loaded = true;
}
public static void Reset()
{
SaveDatas = new ();
Save();
}
}

@ -0,0 +1,31 @@
namespace Babushka.scripts.CSharp.Common.Savegame;
/// <summary>
/// Data structure for device-specific settings that should be saved / loaded to disk.
/// Will not be synced across devices.
/// </summary>
public class SettingsData
{
/// <summary>
/// To be incremented (and migrated) on modification.
/// </summary>
public const int VERSION = 1;
public int version { get; set; } = VERSION;
public bool IsVersionValid()
{
return VERSION == version;
}
public double runtimeSeconds { get; set; }
public int windowSizeX { get; set; } = 800;
public int windowSizeY { get; set; } = 600;
public int windowPositionX { get; set; } = 100;
public int windowPositionY { get; set; } = 100;
public bool windowBorderless { get; set; }
public float volumeMaster { get; set; } = 1.0f;
public float volumeFx { get; set; } = 1.0f;
public float volumeMusic { get; set; } = 1.0f;
}

@ -0,0 +1,108 @@
using System;
using System.Text.Json;
using Godot;
namespace Babushka.scripts.CSharp.Common.Savegame;
/// <summary>
/// Handles the saving and loading of local settings data.
/// </summary>
[GlobalClass]
public partial class SettingsSaveController : Node
{
public static string SETTINGS_FILE_PATH = "user://userSettings.json";
public static SettingsSaveController Instance;
public SettingsData? settings = new SettingsData();
public SettingsData settingsDefault = new SettingsData();
public event Action OnSettingsReloaded;
private bool _loadedData;
private DateTime _readyTime;
public bool LoadedData => _loadedData;
public override void _EnterTree()
{
SETTINGS_FILE_PATH = ProjectSettings.GlobalizePath(SETTINGS_FILE_PATH);
_readyTime = DateTime.Now;
Instance = this;
LoadSettings();
}
public override void _ExitTree()
{
if (settings != null)
settings.runtimeSeconds += (DateTime.Now - _readyTime).TotalSeconds;
SaveSettings();
Instance = null;
}
/// <summary>
/// Saves Settings Data onto disk.
/// </summary>
public void SaveSettings()
{
try
{
string jsonString = JsonSerializer.Serialize(
settings,
new JsonSerializerOptions() { WriteIndented = true}
);
System.IO.File.WriteAllText(SETTINGS_FILE_PATH, jsonString);
}
catch (Exception e)
{
GD.PrintErr("Error Saving Settings:", e);
Console.WriteLine(e);
}
}
/// <summary>
/// Loads Settings data from disk.
/// </summary>
public void LoadSettings()
{
_loadedData = false;
try
{
if (!System.IO.File.Exists(SETTINGS_FILE_PATH))
{
settings = new SettingsData();
}
else
{
string jsonString = System.IO.File.ReadAllText(SETTINGS_FILE_PATH);
SettingsData? loadedSettings = JsonSerializer.Deserialize<SettingsData>(jsonString);
if (loadedSettings != null && !loadedSettings.IsVersionValid())
{
_loadedData = false;
}
else
{
settings = loadedSettings;
_loadedData = true;
}
}
}
catch (Exception e)
{
GD.PrintErr("Loading Error:", e);
Console.WriteLine(e);
}
}
/// <summary>
/// Resets Settings to default.
/// </summary>
public void ResetSettings()
{
settings = JsonSerializer.Deserialize<SettingsData>(JsonSerializer.Serialize<SettingsData>(settingsDefault));
OnSettingsReloaded?.Invoke();
}
}

@ -0,0 +1,101 @@
using Godot;
namespace Babushka.scripts.CSharp.Common.Savegame;
/// <summary>
/// Tracks important window settings and communicates with the <see cref="SettingsSaveController"/> to save/load them.
/// </summary>
public partial class WindowSettingsSync : Node
{
private Window window;
public override void _Ready()
{
window = GetWindow();
window.SizeChanged += SaveWindowSize;
SyncSettings();
SettingsSaveController.Instance.OnSettingsReloaded += SyncSettings;
}
public override void _ExitTree()
{
SaveWindowPosition();
SaveWindowBorderless();
SaveWindowSize();
SettingsSaveController.Instance.SaveSettings();
}
/// <summary>
/// Tries to get previous settings from settings-savefile, if available.
/// </summary>
public void SyncSettings()
{
if (!SettingsSaveController.Instance.LoadedData)
{
SaveWindowPosition();
SaveWindowSize();
SaveWindowBorderless();
return;
}
SettingsData? settingsData = SettingsSaveController.Instance.settings;
if (settingsData != null)
{
window.Position = new Vector2I(settingsData.windowPositionX, settingsData.windowPositionY);
ValidateWindowPosition();
window.Size = new Vector2I(settingsData.windowSizeX, settingsData.windowSizeY);
window.Borderless = settingsData.windowBorderless;
}
}
private void ValidateWindowPosition()
{
bool validWindowPosition = false;
foreach (Rect2I displayRect in DisplayServer.GetDisplayCutouts())
{
if (displayRect.HasPoint(window.Position))
{
validWindowPosition = true;
break;
}
}
if (!validWindowPosition)
{
window.MoveToCenter();
SaveWindowPosition();
}
}
private void SaveWindowPosition()
{
SettingsData? settingsData = SettingsSaveController.Instance.settings;
if (settingsData != null)
{
settingsData.windowPositionX = window.Position.X;
settingsData.windowPositionY = window.Position.Y;
}
}
private void SaveWindowSize()
{
SettingsData? settingsData = SettingsSaveController.Instance.settings;
if (settingsData != null)
{
settingsData.windowSizeX = window.Size.X;
settingsData.windowSizeY = window.Size.Y;
}
}
private void SaveWindowBorderless()
{
SettingsData? settingsData = SettingsSaveController.Instance.settings;
if (settingsData != null)
settingsData.windowBorderless = window.Borderless;
}
}

@ -34,6 +34,7 @@ public partial class SceneTransition : Node
public void Quit()
{
SettingsSaveController.Instance.SaveSettings();
GetTree().Quit();
}

@ -1,13 +1,17 @@
using System.Threading.Tasks;
using Babushka.scripts.CSharp.Common.Savegame;
using Babushka.scripts.CSharp.Low_Code.Variables;
using Godot;
using Godot.Collections;
namespace Babushka.scripts.CSharp.Common.Temp;
/// <summary>
/// Temporary Duck behaviour to make sure we can use them in the first showcase
/// </summary>
public partial class MVPDuck : Node2D
public partial class MVPDuck : Node2D, ISaveable
{
[ExportGroup("Animation")]
[Export] private Node2D _penTarget;
[Export] private int _transferDelayMs;
[Export] private AnimationPlayer _animationPlayer;
@ -17,6 +21,11 @@ public partial class MVPDuck : Node2D
[Signal] public delegate void DuckCollectedEventHandler();
public override void _Ready()
{
LoadFromSaveData();
}
public void TransferToTargetAfterDelay()
{
if (!_collected)
@ -25,7 +34,6 @@ public partial class MVPDuck : Node2D
PlayAnimation();
_collected = true;
}
}
private void PlayAnimation()
@ -40,7 +48,51 @@ public partial class MVPDuck : Node2D
if(!_penTarget.Equals(null))
Position = _penTarget.GlobalPosition;
EmitSignal(SignalName.DuckCollected);
UpdateSaveData();
}
#region SAVE AND LOAD
/// <summary>
// Saves duck position.
/// </summary>
public void UpdateSaveData()
{
var payloadData = new Dictionary<string, Variant>
{
{ "globalPositionX", GlobalPosition.X },
{ "globalPositionY", GlobalPosition.Y },
};
string id = GetMeta("SaveID").AsString();
SavegameService.AppendDataToSave( id, payloadData);
}
/// <summary>
/// Loads duck position.
/// </summary>
public void LoadFromSaveData()
{
string id = GetMeta("SaveID").AsString();
Dictionary<string, Variant> save = SavegameService.GetSaveData(id);
if (save.Count > 0)
{
float xPos = 0;
float yPos = 0;
if (save.TryGetValue("globalPositionX", out Variant xPosVar))
{
xPos = xPosVar.AsSingle();
}
if (save.TryGetValue("globalPositionY", out Variant yPosVar))
{
yPos = yPosVar.AsSingle();
}
GlobalPosition = new Vector2(xPos, yPos);
}
}
#endregion
}

@ -56,7 +56,7 @@ public static class NodeExtension
/// <param name="node"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T GetComponent<T>(Node node)
public static T? GetComponent<T>(Node node)
{
if (node is T)
{

Loading…
Cancel
Save