diff --git a/project.godot b/project.godot index 4862c51..f156776 100644 --- a/project.godot +++ b/project.godot @@ -18,16 +18,20 @@ config/icon="res://icon.svg" [autoload] -AsyncResourceHandler="*res://src/async_resource_handler.ts" +AsyncResourceHandler="*res://src/global/async_resource_handler.ts" Console="*res://addons/dev_console/console.tscn" -DebugDraw="*res://src/debug_draw.ts" -MessageBus="*res://src/message_bus.ts" -SaveSerializer="*res://src/save_serializer.ts" +DebugDraw="*res://src/global/debug_draw.ts" +MessageBus="*res://src/global/message_bus.ts" +SaveSerializer="*res://src/save_system/save_serializer.ts" [editor] script/search_in_file_extensions=PackedStringArray("gd", "gdshader", "ts") +[global_group] + +save="" + [input] move_left={ diff --git a/resources/items/handgun.tres b/resources/items/handgun.tres index 5c31277..123073e 100644 --- a/resources/items/handgun.tres +++ b/resources/items/handgun.tres @@ -1,6 +1,6 @@ [gd_resource type="Resource" script_class="Weapon" load_steps=2 format=3 uid="uid://c15pu3ela0g6k"] -[ext_resource type="Script" uid="uid://tv71bu1y658n" path="res://src/weapon.ts" id="1_bp18i"] +[ext_resource type="Script" uid="uid://tv71bu1y658n" path="res://src/item/weapon.ts" id="1_bp18i"] [resource] script = ExtResource("1_bp18i") @@ -8,8 +8,8 @@ name = &"Handgun" description = "" max_quantity = 99 scene = "uid://ddgak6clk2i2p" -range = 100.0 +damage = 1.0 +range = 25.0 fire_rate = 0.5 capacity = 9 -damage = 1.0 metadata/_custom_type_script = "uid://tv71bu1y658n" diff --git a/resources/items/key.tres b/resources/items/key.tres index 7217c31..58df4ad 100644 --- a/resources/items/key.tres +++ b/resources/items/key.tres @@ -1,6 +1,6 @@ [gd_resource type="Resource" script_class="Item" load_steps=2 format=3 uid="uid://5odv3n0dp2nn"] -[ext_resource type="Script" uid="uid://tgca2vcp2tt4" path="res://src/item.ts" id="1_bbxre"] +[ext_resource type="Script" uid="uid://tgca2vcp2tt4" path="res://src/item/item.ts" id="1_bbxre"] [resource] script = ExtResource("1_bbxre") diff --git a/scenes/node_3d.tscn b/scenes/node_3d.tscn index d4874c0..b32a143 100644 --- a/scenes/node_3d.tscn +++ b/scenes/node_3d.tscn @@ -3,11 +3,11 @@ [ext_resource type="PackedScene" uid="uid://cersx8w4ps2sr" path="res://scenes/player.tscn" id="1_uum5p"] [ext_resource type="Script" uid="uid://cgbd6grygtxvj" path="res://src/main_camera.ts" id="2_0n32s"] [ext_resource type="PackedScene" uid="uid://cwrgvwx3lfwf6" path="res://assets/level.glb" id="2_i3oty"] -[ext_resource type="Script" uid="uid://cyll634iylhqg" path="res://src/interactable.ts" id="3_dt0nx"] +[ext_resource type="Script" uid="uid://cyll634iylhqg" path="res://src/interactable/interactable.ts" id="3_dt0nx"] [ext_resource type="Script" uid="uid://1w0aiix6vgbc" path="res://src/interactable/door.ts" id="3_imxmk"] [ext_resource type="Resource" uid="uid://5odv3n0dp2nn" path="res://resources/items/key.tres" id="4_3rynd"] -[ext_resource type="Script" uid="uid://c7s3k1qy8pg3s" path="res://src/item_pickup.ts" id="6_qe67v"] -[ext_resource type="Script" uid="uid://bccrrtp3mlw5i" path="res://src/health.ts" id="8_cptob"] +[ext_resource type="Script" uid="uid://c7s3k1qy8pg3s" path="res://src/item/item_pickup.ts" id="6_qe67v"] +[ext_resource type="Script" uid="uid://bccrrtp3mlw5i" path="res://src/entity/health.ts" id="8_cptob"] [sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_y41n8"] diff --git a/scenes/player.tscn b/scenes/player.tscn index 64f0831..d4c0667 100644 --- a/scenes/player.tscn +++ b/scenes/player.tscn @@ -1,12 +1,13 @@ -[gd_scene load_steps=34 format=3 uid="uid://cersx8w4ps2sr"] +[gd_scene load_steps=35 format=3 uid="uid://cersx8w4ps2sr"] -[ext_resource type="Script" uid="uid://dxiv1svdeoxg2" path="res://src/player.ts" id="2_pdrhn"] -[ext_resource type="Script" uid="uid://hm6oqbvcmigk" path="res://src/player_animation.ts" id="3_26yay"] -[ext_resource type="Script" uid="uid://ny0p0jkmlrv8" path="res://src/player_input.ts" id="3_x6527"] -[ext_resource type="Script" uid="uid://kjthk4tj8qof" path="res://src/interactor.ts" id="5_uk7c1"] -[ext_resource type="Script" uid="uid://dkvbawcldnok5" path="res://src/equipped_weapon.ts" id="6_fjrip"] -[ext_resource type="Script" uid="uid://dbrjcvaqkca21" path="res://src/inventory.ts" id="6_jscba"] +[ext_resource type="Script" uid="uid://dxiv1svdeoxg2" path="res://src/entity/player.ts" id="2_pdrhn"] +[ext_resource type="Script" uid="uid://hm6oqbvcmigk" path="res://src/entity/player_animation.ts" id="3_26yay"] +[ext_resource type="Script" uid="uid://ny0p0jkmlrv8" path="res://src/entity/player_input.ts" id="3_x6527"] +[ext_resource type="Script" uid="uid://kjthk4tj8qof" path="res://src/entity/interactor.ts" id="5_uk7c1"] +[ext_resource type="Script" uid="uid://dkvbawcldnok5" path="res://src/entity/equipped_weapon.ts" id="6_fjrip"] +[ext_resource type="Script" uid="uid://dbrjcvaqkca21" path="res://src/entity/inventory.ts" id="6_jscba"] [ext_resource type="PackedScene" uid="uid://sgc1gxq4osag" path="res://scenes/player_mesh3.tscn" id="7_fjrip"] +[ext_resource type="Script" uid="uid://bccrrtp3mlw5i" path="res://src/entity/health.ts" id="8_smehm"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1kx10"] @@ -126,13 +127,144 @@ states/Unarmed/node = SubResource("AnimationNodeBlendSpace1D_7bso7") states/Unarmed/position = Vector2(405, 89) transitions = ["Start", "Unarmed", SubResource("AnimationNodeStateMachineTransition_cqw7m"), "Unarmed", "Handgun", SubResource("AnimationNodeStateMachineTransition_fjrip"), "Handgun", "Unarmed", SubResource("AnimationNodeStateMachineTransition_smehm"), "Start", "Handgun", SubResource("AnimationNodeStateMachineTransition_ur7pv")] -[node name="Player" type="CharacterBody3D"] +[node name="Player" type="CharacterBody3D" groups=["save"]] script = ExtResource("2_pdrhn") +metadata/_custom_type_script = "uid://dxiv1svdeoxg2" [node name="Mesh" parent="." instance=ExtResource("7_fjrip")] +[node name="Skeleton3D" parent="Mesh/AuxScene/Scene/Armature" index="0"] +bones/0/position = Vector3(-1.74887, 91.964, -0.714319) +bones/0/rotation = Quaternion(0.165541, -0.00688532, -0.0607779, 0.984304) +bones/1/position = Vector3(-5.73688e-07, -9.14512e-06, -1.26241e-06) +bones/2/rotation = Quaternion(-0.05258, -0.0688082, 0.0497405, 0.995001) +bones/3/position = Vector3(9.31323e-07, 4.82425e-06, 3.63451e-07) +bones/4/rotation = Quaternion(0.0222017, -0.0213405, 0.0167214, 0.999386) +bones/5/position = Vector3(-1.93715e-07, -5.33462e-06, -3.29316e-06) +bones/6/rotation = Quaternion(0.0349434, -0.0206503, 0.0167813, 0.999035) +bones/7/position = Vector3(7.1526e-07, -1.93864e-05, -4.64916e-06) +bones/8/rotation = Quaternion(-0.51501, 0.549661, -0.50159, -0.425494) +bones/9/position = Vector3(4.03821e-06, 2.32458e-06, -8.17219e-06) +bones/10/position = Vector3(-1.57305e-06, 10.8382, 6.06992e-05) +bones/10/rotation = Quaternion(0.394962, -0.363464, -0.0296416, 0.84322) +bones/11/position = Vector3(4.29218e-06, -5.19505e-06, 6.01416e-06) +bones/12/rotation = Quaternion(-1.62516e-07, 3.07216e-08, -0.699315, 0.714814) +bones/13/position = Vector3(-8.38905e-06, 3.33295e-06, 2.61253e-06) +bones/14/position = Vector3(-3.8591e-06, 28.3289, 4.04304e-06) +bones/14/rotation = Quaternion(-0.136096, 0.156416, -0.0262674, 0.977917) +bones/15/position = Vector3(3.578e-06, -5.33786e-07, -1.20217e-06) +bones/16/rotation = Quaternion(0.585477, -0.0341162, 0.207056, 0.783058) +bones/17/position = Vector3(-5.2056e-06, -2.74507e-06, 2.17486e-07) +bones/18/position = Vector3(-4.54572e-06, 3.60001, -4.16853e-05) +bones/18/rotation = Quaternion(0.507655, 1.75089e-07, 0.0413582, 0.860568) +bones/19/position = Vector3(5.70967e-07, -7.07246e-06, -9.18487e-06) +bones/20/rotation = Quaternion(0.413244, -3.11702e-08, 0.0336662, 0.909998) +bones/21/position = Vector3(-6.99836e-06, -7.14697e-06, -2.1594e-05) +bones/22/position = Vector3(6.30171e-07, 2.11579, -2.0168e-05) +bones/23/position = Vector3(2.23517e-06, -3.43425e-06, -5.65971e-06) +bones/24/position = Vector3(-2.38966e-05, 9.5325, 4.5051e-05) +bones/24/rotation = Quaternion(0.668999, -0.000171639, 0.0840584, 0.738495) +bones/25/position = Vector3(-6.4569e-06, 7.69735e-06, 1.93997e-05) +bones/26/position = Vector3(-1.6476e-05, 3.70001, -1.55696e-05) +bones/26/rotation = Quaternion(0.496633, -8.3819e-09, 0.0404601, 0.867017) +bones/27/position = Vector3(-1.2354e-05, -8.65261e-06, -1.28768e-05) +bones/28/position = Vector3(-4.24592e-06, 2.95001, -9.53893e-06) +bones/28/rotation = Quaternion(0.411496, 1.23197e-07, 0.033524, 0.910795) +bones/31/position = Vector3(-7.56234e-07, 7.47032e-06, -1.1809e-05) +bones/32/rotation = Quaternion(0.665959, -0.0134166, 0.0985026, 0.739335) +bones/33/position = Vector3(-6.06578e-06, 1.30555e-07, 1.69121e-05) +bones/34/position = Vector3(-4.23319e-06, 3.37928, 2.18956e-06) +bones/34/rotation = Quaternion(0.505618, -7.26432e-08, 0.0411921, 0.861774) +bones/36/position = Vector3(-1.18398e-05, 2.88968, 7.61242e-06) +bones/36/rotation = Quaternion(0.404281, -1.18074e-07, 0.032936, 0.914042) +bones/37/position = Vector3(-6.88349e-06, -1.37002e-05, 1.28552e-05) +bones/38/position = Vector3(2.56333e-07, 2.63883, -1.43249e-05) +bones/39/position = Vector3(-4.24683e-07, 1.26579e-05, -1.86824e-05) +bones/40/position = Vector3(2.25984, 9.10828, 0.517869) +bones/40/rotation = Quaternion(0.664054, 0.0213635, 0.0331529, 0.746644) +bones/41/position = Vector3(1.06017e-06, 7.42728e-06, 1.53654e-05) +bones/42/rotation = Quaternion(0.495834, 1.76951e-08, 0.040395, 0.867477) +bones/43/position = Vector3(-7.02744e-06, 7.93018e-06, 5.25886e-07) +bones/44/rotation = Quaternion(0.412061, -1.75642e-08, 0.0335699, 0.910538) +bones/45/position = Vector3(-2.85069e-06, 1.82002e-06, -3.29077e-06) +bones/48/position = Vector3(2.68185, 2.4648, 1.57399) +bones/48/rotation = Quaternion(0.269242, 0.0131664, -0.225248, 0.936269) +bones/49/position = Vector3(-9.0003e-06, -5.24521e-06, 4.05612e-06) +bones/50/position = Vector3(-1.37213e-05, 4.18898, 1.30866e-06) +bones/50/rotation = Quaternion(-0.0573431, -0.0228523, 0.23602, 0.969786) +bones/52/position = Vector3(-1.33398e-07, 3.41628, -7.38503e-06) +bones/52/rotation = Quaternion(-0.0951258, 0.0335536, -0.103347, 0.989517) +bones/53/position = Vector3(-1.13845e-05, 6.58631e-06, -2.40871e-06) +bones/56/rotation = Quaternion(-0.0477065, -0.00417029, 0.0378131, 0.998137) +bones/57/position = Vector3(-1.43051e-06, -1.90437e-05, -4.97699e-06) +bones/58/rotation = Quaternion(-0.0436575, 0.0735426, -0.040091, 0.995529) +bones/59/position = Vector3(3.57626e-07, -2.48402e-05, -4.05312e-06) +bones/61/rotation = Quaternion(-0.583618, -0.494192, 0.510115, -0.393634) +bones/62/position = Vector3(-9.28342e-06, -1.90735e-06, -1.25186e-05) +bones/63/position = Vector3(-6.21295e-06, 10.8377, 3.97934e-05) +bones/63/rotation = Quaternion(0.347965, 0.00733927, 0.168363, 0.922237) +bones/64/position = Vector3(-6.81842e-07, 2.49492e-06, -4.24376e-06) +bones/65/position = Vector3(9.00633e-07, 27.8415, 2.65277e-05) +bones/65/rotation = Quaternion(-1.72295e-07, -8.69017e-09, 0.856711, 0.515797) +bones/66/position = Vector3(1.81322e-06, -7.35846e-06, -1.91975e-06) +bones/67/rotation = Quaternion(-0.00529397, 0.0445442, 0.140527, 0.98906) +bones/68/position = Vector3(-2.66702e-06, 6.75935e-06, 1.82044e-06) +bones/69/rotation = Quaternion(0.247973, -0.0477907, 0.214491, 0.943514) +bones/70/position = Vector3(1.54972e-06, 1.10865e-05, 1.50938e-05) +bones/71/position = Vector3(-9.48468e-06, 4.18709, 6.46207e-06) +bones/71/rotation = Quaternion(-0.0402928, 0.0170358, -0.189645, 0.980878) +bones/72/position = Vector3(4.76837e-06, -6.58631e-06, -1.79932e-05) +bones/73/position = Vector3(3.41813e-06, 3.41839, -3.61406e-05) +bones/73/rotation = Quaternion(-0.150634, 0.0196685, -0.0384138, 0.987647) +bones/74/position = Vector3(6.76513e-06, 4.05312e-06, -9.94626e-07) +bones/75/position = Vector3(1.19018e-05, 2.58059, -2.38419e-06) +bones/77/rotation = Quaternion(0.348536, -0.00216019, 0.00770235, 0.937261) +bones/78/position = Vector3(1.02476e-05, 1.25725e-06, -3.09773e-06) +bones/79/position = Vector3(1.16544e-05, 3.7, -2.38235e-06) +bones/79/rotation = Quaternion(0.316306, -4.82716e-07, -0.0324142, 0.948103) +bones/80/position = Vector3(-4.95017e-06, 2.76518e-06, -1.62069e-05) +bones/81/rotation = Quaternion(0.316011, -2.94298e-07, -0.0323837, 0.948203) +bones/84/position = Vector3(2.00886e-06, -1.55707e-05, 1.65336e-05) +bones/85/rotation = Quaternion(0.3862, -0.00842687, -0.0564331, 0.920648) +bones/86/position = Vector3(-1.63967e-06, 3.17085e-06, -1.61075e-05) +bones/87/rotation = Quaternion(0.360214, -3.91738e-07, -0.0369136, 0.932139) +bones/88/position = Vector3(1.00015e-05, -1.164e-05, -9.66649e-07) +bones/89/rotation = Quaternion(0.359928, -5.00586e-07, -0.0368843, 0.932251) +bones/90/position = Vector3(1.66535e-06, -8.3745e-06, -2.99188e-06) +bones/92/position = Vector3(7.46036e-06, 4.84443e-06, -1.74526e-06) +bones/93/rotation = Quaternion(0.430639, 0.00721853, -0.0951741, 0.897463) +bones/94/position = Vector3(8.98751e-07, 5.35152e-06, -6.46659e-07) +bones/95/rotation = Quaternion(0.410222, -5.0664e-07, -0.0420382, 0.911016) +bones/96/position = Vector3(4.96211e-06, -1.72045e-06, 3.28761e-06) +bones/97/position = Vector3(6.86945e-06, 2.95, 1.36588e-05) +bones/97/rotation = Quaternion(0.408306, -5.79283e-07, -0.0418419, 0.911886) +bones/98/position = Vector3(-3.15467e-07, 5.01274e-06, 4.26586e-07) +bones/99/position = Vector3(-2.55906e-05, 2.64431, 3.08781e-07) +bones/100/position = Vector3(-1.24937e-06, -5.10697e-06, 1.54605e-05) +bones/101/position = Vector3(3.80626, 8.0778, 0.486897) +bones/101/rotation = Quaternion(0.453869, -0.00504631, -0.172035, 0.874289) +bones/102/position = Vector3(-3.4095e-06, 9.84711e-06, 2.19628e-05) +bones/103/rotation = Quaternion(0.441888, -4.63799e-07, -0.0452826, 0.895927) +bones/104/position = Vector3(2.55811e-06, 3.79583e-06, -1.0634e-05) +bones/105/rotation = Quaternion(0.441703, -4.99189e-07, -0.0452642, 0.896019) +bones/106/position = Vector3(-6.14417e-06, -1.13954e-05, 1.6547e-05) +bones/107/position = Vector3(-5.6429e-06, 2.12554, -1.44594e-05) +bones/108/position = Vector3(-9.07481e-06, 9.92674e-06, -5.45842e-07) +bones/109/rotation = Quaternion(0.00912616, 0.499102, 0.859827, -0.107291) +bones/110/position = Vector3(-8.46157e-07, 2.16948e-05, -6.41459e-07) +bones/111/rotation = Quaternion(-0.422236, 0.017693, 0.0133394, 0.906215) +bones/112/position = Vector3(-6.62415e-08, 3.47755e-06, 3.22101e-06) +bones/113/rotation = Quaternion(0.540386, -0.024196, -0.0396063, 0.840136) +bones/115/rotation = Quaternion(0.351334, 3.47398e-05, 1.17676e-05, 0.93625) +bones/119/rotation = Quaternion(0.102035, 0.0420148, 0.992102, -0.0596471) +bones/120/position = Vector3(-1.94257e-07, 7.09908e-06, -4.76177e-06) +bones/121/rotation = Quaternion(-0.339418, 0.0221456, -0.00134624, 0.940374) +bones/122/position = Vector3(-4.23867e-07, -3.05474e-06, -1.07518e-06) +bones/123/rotation = Quaternion(0.426336, -0.0330713, -0.134284, 0.89393) +bones/125/rotation = Quaternion(0.631409, 0.0537683, 0.0373258, 0.772682) + [node name="RightHand" parent="Mesh/AuxScene/Scene/Armature/Skeleton3D" index="2"] -transform = Transform3D(0.678924, 0.327226, -0.657255, 0.571861, 0.325755, 0.752899, 0.460473, -0.88702, 0.0340353, -5.60212, 89.2255, 32.2557) +transform = Transform3D(0.339146, 0.643904, -0.685833, 0.44957, 0.529466, 0.71941, 0.826357, -0.552315, -0.109914, -21.7915, 84.1795, 2.81691) [node name="Node3D" type="Node3D" parent="Mesh/AuxScene/Scene/Armature/Skeleton3D/RightHand" index="0"] @@ -143,12 +275,14 @@ shape = SubResource("CapsuleShape3D_1kx10") [node name="Input" type="Node3D" parent="."] script = ExtResource("3_x6527") min_range = 0.5 +metadata/_custom_type_script = "uid://ny0p0jkmlrv8" [node name="Interactor" type="Area3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 1) input_ray_pickable = false script = ExtResource("5_uk7c1") _root_node = NodePath("..") +metadata/_custom_type_script = "uid://kjthk4tj8qof" [node name="CollisionShape3D" type="CollisionShape3D" parent="Interactor"] shape = SubResource("SphereShape3D_64co4") @@ -177,4 +311,8 @@ metadata/_custom_type_script = "uid://dkvbawcldnok5" [node name="FireRate" type="Timer" parent="EquippedWeapon"] one_shot = true +[node name="Health" type="Node" parent="."] +script = ExtResource("8_smehm") +metadata/_custom_type_script = "uid://bccrrtp3mlw5i" + [editable path="Mesh"] diff --git a/src/input_buffer.ts b/src/collection/input_buffer.ts similarity index 100% rename from src/input_buffer.ts rename to src/collection/input_buffer.ts diff --git a/src/input_buffer.ts.uid b/src/collection/input_buffer.ts.uid similarity index 100% rename from src/input_buffer.ts.uid rename to src/collection/input_buffer.ts.uid diff --git a/src/damage_source.ts b/src/damage_source.ts index 50b9770..7fbf55d 100644 --- a/src/damage_source.ts +++ b/src/damage_source.ts @@ -1,5 +1,5 @@ -import { float64, Node, Node3D, NodePath, PackedStringArray, Variant } from 'godot' -import { Damageable } from './health' +import { float64, Node, Node3D, NodePath, Variant } from 'godot' +import { Damageable } from './entity/health' import { export_ } from 'godot.annotations' export default class DamageSource extends Node3D { diff --git a/src/equipped_weapon.ts b/src/entity/equipped_weapon.ts similarity index 81% rename from src/equipped_weapon.ts rename to src/entity/equipped_weapon.ts index 380a5aa..458fc5e 100644 --- a/src/equipped_weapon.ts +++ b/src/entity/equipped_weapon.ts @@ -1,11 +1,11 @@ -import { Color, GArray, Node, Node3D, PackedScene, PackedStringArray, PhysicsBody3D, PhysicsRayQueryParameters3D, Signal1, Timer, Vector3 } from 'godot' +import { Color, GArray, Node, Node3D, PackedScene, PhysicsBody3D, PhysicsRayQueryParameters3D, Signal1, Timer, Vector3 } from 'godot' import { export_file, signal } from 'godot.annotations' -import { export_node, onready } from './annotations' -import Weapon from './weapon' -import AsyncResourceHandler from './async_resource_handler' -import { forward } from './vec' -import DebugDraw from './debug_draw' -import { find_in_anscestors, find_in_descendents, has_method } from './node' +import { export_node, onready } from '../extension/annotations' +import Weapon from '../item/weapon' +import AsyncResourceHandler from '../global/async_resource_handler' +import { forward } from '../extension/vec' +import DebugDraw from '../global/debug_draw' +import { find_in_ancestors, find_in_descendents, has_method } from '../extension/node' import { Damageable } from './health' const { MULTIPLY: mul, ADD: add } = Vector3 @@ -85,7 +85,7 @@ export default class EquippedWeapon extends Node3D { if (!result.is_empty()) { DebugDraw.draw_ray(query, Color.DARK_RED) - const root = find_in_anscestors(result.get('collider'), n => n instanceof PhysicsBody3D) + const root = find_in_ancestors(result.get('collider'), n => n instanceof PhysicsBody3D) const health = find_in_descendents(root, n => has_method('apply_damage', n)) if (health != null) { health.apply_damage(this, this._equipped_weapon.damage) diff --git a/src/equipped_weapon.ts.uid b/src/entity/equipped_weapon.ts.uid similarity index 100% rename from src/equipped_weapon.ts.uid rename to src/entity/equipped_weapon.ts.uid diff --git a/src/health.ts b/src/entity/health.ts similarity index 85% rename from src/health.ts rename to src/entity/health.ts index b47c086..ee6e581 100644 --- a/src/health.ts +++ b/src/entity/health.ts @@ -16,6 +16,14 @@ export default class Health extends Node implements Damageable, Recoverable { @export_(Variant.Type.TYPE_FLOAT) private _current_health: number = 0 + get current_health() { + return this._current_health + } + + set current_health(value: number) { + this._current_health = value + } + _ready() { this._current_health = this._max_health } diff --git a/src/health.ts.uid b/src/entity/health.ts.uid similarity index 100% rename from src/health.ts.uid rename to src/entity/health.ts.uid diff --git a/src/interactor.ts b/src/entity/interactor.ts similarity index 96% rename from src/interactor.ts rename to src/entity/interactor.ts index 767047b..75a78b5 100644 --- a/src/interactor.ts +++ b/src/entity/interactor.ts @@ -1,6 +1,6 @@ import { Area3D, Callable, Node, NodePath, Variant } from 'godot' -import Interactable from './interactable' import { export_ } from 'godot.annotations' +import Interactable from '../interactable/interactable' class InteractableDistance { static Empty = new InteractableDistance(Infinity) diff --git a/src/interactor.ts.uid b/src/entity/interactor.ts.uid similarity index 100% rename from src/interactor.ts.uid rename to src/entity/interactor.ts.uid diff --git a/src/inventory.ts b/src/entity/inventory.ts similarity index 79% rename from src/inventory.ts rename to src/entity/inventory.ts index 704aa71..38c8502 100644 --- a/src/inventory.ts +++ b/src/entity/inventory.ts @@ -1,11 +1,9 @@ import { clampi, Node, StringName } from 'godot' -import ItemData from './item' -import { GArrayEnumerator } from './collection/enumerable' -import { Enumerable } from '../addons/enumerable-ts/src/index' -import { find_in_descendents } from './node' +import Item from '../item/item' +import { find_in_descendents } from '../extension/node' class ItemInstance { - readonly resource: ItemData + readonly resource: Item get name() { return this.resource.name @@ -17,7 +15,7 @@ class ItemInstance { quantity: number - constructor(resource: ItemData, quantity: number = 1) { + constructor(resource: Item, quantity: number = 1) { this.resource = resource this.quantity = quantity } @@ -58,7 +56,7 @@ export default class Inventory extends Node { return inventory } - add(item: ItemData, quantity: number = 1) { + add(item: Item, quantity: number = 1) { const existing_item = this.items.get(item.name) if (!existing_item) { @@ -68,7 +66,7 @@ export default class Inventory extends Node { } } - has(item: ItemData): boolean { + has(item: Item): boolean { return this.items.has(item.name) } } diff --git a/src/inventory.ts.uid b/src/entity/inventory.ts.uid similarity index 100% rename from src/inventory.ts.uid rename to src/entity/inventory.ts.uid diff --git a/src/player.ts b/src/entity/player.ts similarity index 85% rename from src/player.ts rename to src/entity/player.ts index f3b3158..e671516 100644 --- a/src/player.ts +++ b/src/entity/player.ts @@ -1,12 +1,16 @@ import { Callable, Callable0, Callable1, CharacterBody3D, Color, float64, ProjectSettings, Variant, Vector2, Vector3 } from 'godot' import { export_, help, onready } from 'godot.annotations' import PlayerInput from './player_input' -import DebugDraw from './debug_draw' +import DebugDraw from '../global/debug_draw' import Interactor from './interactor' +import Health from './health' import PlayerAnimation, { PlayerAnimationName } from './player_animation' import EquippedWeapon from './equipped_weapon' +import GameState, { Savable } from '../save_system/game_state' +import PlayerState from '../save_system/player_state' +import SaveState from '../save_system/save_state' -export default class Player extends CharacterBody3D { +export default class Player extends CharacterBody3D implements Savable { readonly gravity = ProjectSettings.get_setting('physics/3d/default_gravity') @onready('Input') @@ -18,6 +22,9 @@ export default class Player extends CharacterBody3D { @onready('Interactor') readonly interactor!: Interactor + @onready('Health') + readonly health!: Health + @onready('EquippedWeapon') readonly equipped_weapon!: EquippedWeapon @@ -109,6 +116,25 @@ export default class Player extends CharacterBody3D { this.player_animation.animation_finished.connect(this._enable_action_callable) } + on_save_game(save_data: GameState): void { + const state = new PlayerState() + state.position = this.global_position + state.condition = 100 + state.scene = this.scene_file_path + save_data.world.push(state) + } + + on_before_load_game?(): void { + this.get_parent().remove_child(this) + this.queue_free() + } + + on_load_game(state: T): void { + const player_state = state as unknown as PlayerState + this.global_position = player_state.position + this.health.current_health = player_state.condition + } + private _disable_action(value: string) { if (PlayerAnimationName.Fire === value) { this._can_act = false diff --git a/src/player.ts.uid b/src/entity/player.ts.uid similarity index 100% rename from src/player.ts.uid rename to src/entity/player.ts.uid diff --git a/src/player_animation.ts b/src/entity/player_animation.ts similarity index 96% rename from src/player_animation.ts rename to src/entity/player_animation.ts index b3e7f10..1bbd910 100644 --- a/src/player_animation.ts +++ b/src/entity/player_animation.ts @@ -1,7 +1,7 @@ import { AnimationTree, Expression, float64, GArray, GError, Node } from 'godot' import Player from './player' import PlayerInput from './player_input' -import { export_expression, onready } from './annotations' +import { export_expression, onready } from '../extension/annotations' export const PlayerAnimationName = Object.freeze({ Idle: 'Idle', diff --git a/src/player_animation.ts.uid b/src/entity/player_animation.ts.uid similarity index 100% rename from src/player_animation.ts.uid rename to src/entity/player_animation.ts.uid diff --git a/src/player_input.ts b/src/entity/player_input.ts similarity index 98% rename from src/player_input.ts rename to src/entity/player_input.ts index 5b95a63..b1d759b 100644 --- a/src/player_input.ts +++ b/src/entity/player_input.ts @@ -1,8 +1,8 @@ import { Callable, Callable1, Camera3D, float64, Input, InputEvent, InputEventJoypadButton, InputEventJoypadMotion, InputEventKey, InputEventMouse, InputEventMouseMotion, int32, Node3D, PhysicsRayQueryParameters3D, Signal0, Signal1, Variant, Vector2, Vector3, World3D } from 'godot' import { export_, signal } from 'godot.annotations' -import InputBuffer from './input_buffer' -import MainCamera from './main_camera' -import MessageBus from './message_bus' +import InputBuffer from '../collection/input_buffer' +import MainCamera from '../main_camera' +import MessageBus from '../global/message_bus' export const PlayerMovement = Object.freeze({ MoveLeft: 'move_left', diff --git a/src/player_input.ts.uid b/src/entity/player_input.ts.uid similarity index 100% rename from src/player_input.ts.uid rename to src/entity/player_input.ts.uid diff --git a/src/annotations.ts b/src/extension/annotations.ts similarity index 100% rename from src/annotations.ts rename to src/extension/annotations.ts diff --git a/src/annotations.ts.uid b/src/extension/annotations.ts.uid similarity index 100% rename from src/annotations.ts.uid rename to src/extension/annotations.ts.uid diff --git a/src/godot_error.ts b/src/extension/godot_error.ts similarity index 84% rename from src/godot_error.ts rename to src/extension/godot_error.ts index d11fe1e..6ad94db 100644 --- a/src/godot_error.ts +++ b/src/extension/godot_error.ts @@ -1,4 +1,4 @@ -import { GError } from "godot"; +import { GError } from 'godot' export class GodotError extends Error { error: GError diff --git a/src/godot_error.ts.uid b/src/extension/godot_error.ts.uid similarity index 100% rename from src/godot_error.ts.uid rename to src/extension/godot_error.ts.uid diff --git a/src/node.ts b/src/extension/node.ts similarity index 58% rename from src/node.ts rename to src/extension/node.ts index aa500bb..bcbb081 100644 --- a/src/node.ts +++ b/src/extension/node.ts @@ -11,17 +11,24 @@ export function queue_free_children(node: T) { } } -type RequiredField = Omit & Required> +type RequiredField = Omit & Required>; -export function has_method(name: StringName, obj: Object): boolean { - return obj.has_method(name) +export function has_methods]>( + keys: U, + obj: T +): obj is Object & RequiredField { + return keys.every(key => obj.has_method(key as string)) +} + +export function has_method(name: StringName, obj: Object): obj is Object & RequiredField { + return has_methods([name as keyof Object], obj) } export function implements_interface(method_names: StringName[], obj: Object): obj is Object & T { return method_names.every(name => has_method(name, obj)) } -export function find_in_anscestors(root: T | null | undefined, predicate: Predicate, height: number = Infinity): T | null | undefined { +export function find_in_ancestors(root: T | null | undefined, predicate: Predicate, height: number = Infinity): T | null | undefined { if (height < 0 || root == null) { return } @@ -30,7 +37,7 @@ export function find_in_anscestors(root: T | null | undefined, p return root } - return find_in_anscestors(root.get_parent(), predicate, height - 1) as T + return find_in_ancestors(root.get_parent(), predicate, height - 1) as T } export function find_in_descendents(root: T, predicate: Predicate, depth: number = Infinity): T | null | undefined { diff --git a/src/node.ts.uid b/src/extension/node.ts.uid similarity index 100% rename from src/node.ts.uid rename to src/extension/node.ts.uid diff --git a/src/vec.ts b/src/extension/vec.ts similarity index 100% rename from src/vec.ts rename to src/extension/vec.ts diff --git a/src/vec.ts.uid b/src/extension/vec.ts.uid similarity index 100% rename from src/vec.ts.uid rename to src/extension/vec.ts.uid diff --git a/src/async_resource_handler.ts b/src/global/async_resource_handler.ts similarity index 90% rename from src/async_resource_handler.ts rename to src/global/async_resource_handler.ts index 64c4142..42921b5 100644 --- a/src/async_resource_handler.ts +++ b/src/global/async_resource_handler.ts @@ -1,5 +1,5 @@ import { GArray, GError, Node, Resource, ResourceLoader, ResourceSaver } from 'godot' -import { GodotError } from './godot_error' +import { GodotError } from '../extension/godot_error' export class ResourceLoadError extends Error { } @@ -16,11 +16,11 @@ export default class AsyncResourceHandler extends Node { AsyncResourceHandler._instance = this } - static save(path: string, data: T, flags: ResourceSaver.SaverFlags): Promise { + static save(path: string, data: T, flags?: ResourceSaver.SaverFlags): Promise { return this._instance.save(path, data, flags) } - save(path: string, data: T, flags: ResourceSaver.SaverFlags): Promise { + save(path: string, data: T, flags: ResourceSaver.SaverFlags = ResourceSaver.SaverFlags.FLAG_NONE): Promise { return new Promise((resolve, reject) => { const err = ResourceSaver.save(data, path, flags) diff --git a/src/async_resource_handler.ts.uid b/src/global/async_resource_handler.ts.uid similarity index 100% rename from src/async_resource_handler.ts.uid rename to src/global/async_resource_handler.ts.uid diff --git a/src/async_resource_loader.ts.uid b/src/global/async_resource_loader.ts.uid similarity index 100% rename from src/async_resource_loader.ts.uid rename to src/global/async_resource_loader.ts.uid diff --git a/src/debug_draw.ts b/src/global/debug_draw.ts similarity index 100% rename from src/debug_draw.ts rename to src/global/debug_draw.ts diff --git a/src/debug_draw.ts.uid b/src/global/debug_draw.ts.uid similarity index 100% rename from src/debug_draw.ts.uid rename to src/global/debug_draw.ts.uid diff --git a/src/message_bus.ts b/src/global/message_bus.ts similarity index 100% rename from src/message_bus.ts rename to src/global/message_bus.ts diff --git a/src/message_bus.ts.uid b/src/global/message_bus.ts.uid similarity index 100% rename from src/message_bus.ts.uid rename to src/global/message_bus.ts.uid diff --git a/src/interactable/door.ts b/src/interactable/door.ts index 87a4d05..8ba75ca 100644 --- a/src/interactable/door.ts +++ b/src/interactable/door.ts @@ -1,8 +1,8 @@ import { Node3D, Variant } from 'godot' import { export_ } from 'godot.annotations' -import Interactor from '../interactor' -import Item from '../item' -import Inventory from '../inventory' +import Interactor from '../entity/interactor' +import Item from '../item/item' +import Inventory from '../entity/inventory' export default class Door extends Node3D { @export_(Variant.Type.TYPE_BOOL) diff --git a/src/interactable.ts b/src/interactable/interactable.ts similarity index 85% rename from src/interactable.ts rename to src/interactable/interactable.ts index bc59001..e5308b0 100644 --- a/src/interactable.ts +++ b/src/interactable/interactable.ts @@ -1,5 +1,5 @@ import { Area3D, Signal1 } from 'godot' -import Interactor from './interactor' +import Interactor from '../entity/interactor' import { signal } from 'godot.annotations' export default class Interactable extends Area3D { diff --git a/src/interactable.ts.uid b/src/interactable/interactable.ts.uid similarity index 100% rename from src/interactable.ts.uid rename to src/interactable/interactable.ts.uid diff --git a/src/item.ts b/src/item.ts deleted file mode 100644 index 04c216b..0000000 --- a/src/item.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Resource, StringName, Variant } from 'godot' -import { export_, export_enum, export_multiline } from 'godot.annotations' - -export type ItemType = number - -export default class Item extends Resource { - @export_(Variant.Type.TYPE_STRING_NAME) - readonly name: StringName = '' - - @export_multiline() - readonly description: string = '' - - @export_(Variant.Type.TYPE_INT) - readonly max_quantity: number = 99 -} - diff --git a/src/item_data.ts b/src/item/item.ts similarity index 100% rename from src/item_data.ts rename to src/item/item.ts diff --git a/src/item.ts.uid b/src/item/item.ts.uid similarity index 100% rename from src/item.ts.uid rename to src/item/item.ts.uid diff --git a/src/item_pickup.ts b/src/item/item_pickup.ts similarity index 87% rename from src/item_pickup.ts rename to src/item/item_pickup.ts index 437766e..c78a189 100644 --- a/src/item_pickup.ts +++ b/src/item/item_pickup.ts @@ -1,8 +1,8 @@ import { Node, Variant } from 'godot' import { export_, export_range } from 'godot.annotations' import ItemData from './item' -import Interactor from './interactor' -import Inventory from './inventory' +import Interactor from '../entity/interactor' +import Inventory from '../entity/inventory' export default class ItemPickup extends Node { @export_(Variant.Type.TYPE_OBJECT, { class_: ItemData }) diff --git a/src/item_pickup.ts.uid b/src/item/item_pickup.ts.uid similarity index 100% rename from src/item_pickup.ts.uid rename to src/item/item_pickup.ts.uid diff --git a/src/weapon.ts b/src/item/weapon.ts similarity index 83% rename from src/weapon.ts rename to src/item/weapon.ts index 1fd5866..795cd27 100644 --- a/src/weapon.ts +++ b/src/item/weapon.ts @@ -1,5 +1,5 @@ import { Variant } from 'godot' -import { export_scene } from './annotations' +import { export_scene } from '../extension/annotations' import Item from './item' import { export_ } from 'godot.annotations' @@ -11,7 +11,7 @@ export default class Weapon extends Item { readonly damage: number = 1 @export_(Variant.Type.TYPE_FLOAT) - readonly range: number = 100 + readonly range: number = 25 @export_(Variant.Type.TYPE_FLOAT) readonly fire_rate!: number diff --git a/src/weapon.ts.uid b/src/item/weapon.ts.uid similarity index 100% rename from src/weapon.ts.uid rename to src/item/weapon.ts.uid diff --git a/src/item_data.ts.uid b/src/item_data.ts.uid deleted file mode 100644 index 0b8866b..0000000 --- a/src/item_data.ts.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cglbkbhvgksc diff --git a/src/main_camera.ts b/src/main_camera.ts index 852db6f..473e709 100644 --- a/src/main_camera.ts +++ b/src/main_camera.ts @@ -1,5 +1,5 @@ import { Camera3D } from 'godot' -import MessageBus from './message_bus' +import MessageBus from './global/message_bus' export default class MainCamera extends Camera3D { private static _instance: MainCamera diff --git a/src/resource_loader.ts b/src/resource_loader.ts deleted file mode 100644 index 1b521af..0000000 --- a/src/resource_loader.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { GError, Node, Resource, ResourceLoader } from 'godot' - -export default class AsyncResourceLoader extends Node { - private static _instance: AsyncResourceLoader - - static get instance() { - return this._instance - } - - _ready(): void { - AsyncResourceLoader._instance = this - } - - load(path: string, hint_string: string = ''): Promise { - return new Promise(async (resolve, reject) => { - const err = ResourceLoader.load_threaded_request(path, hint_string) - - if (err != GError.OK) { - return reject(new Error(`failed to load ${path}`)) - } - - const get_status = () => ResourceLoader.load_threaded_get_status(path) - - let status = get_status() - while (status === ResourceLoader.ThreadLoadStatus.THREAD_LOAD_IN_PROGRESS) { - await this.get_tree().process_frame.as_promise() - status = get_status() - } - - if (get_status() === ResourceLoader.ThreadLoadStatus.THREAD_LOAD_LOADED) { - return resolve(ResourceLoader.load_threaded_get(path) as T) - } else { - return reject(new Error(`failed to load ${path}`)) - } - }) - } -} - diff --git a/src/resource_loader.ts.uid b/src/resource_loader.ts.uid deleted file mode 100644 index c95ef98..0000000 --- a/src/resource_loader.ts.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dhl3jsf2be316 diff --git a/src/save_serializer.ts b/src/save_serializer.ts deleted file mode 100644 index 4608478..0000000 --- a/src/save_serializer.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { GDictionary, Node, PackedScene, Resource, ResourceLoader, ResourceSaver } from 'godot' -import AsyncResourceHandler from './async_resource_handler' -import { has_method } from './node' - -interface Serializable { - on_save_game(save_data: GameState): void - on_before_load_game?(): void - on_load_game(state: T): void -} - -interface SaveState extends Resource { - scene: string -} - -class PlayerState extends Resource implements SaveState { - condition: undefined = undefined - inventory: undefined = undefined - scene: string = '' -} - -class ProgressState extends Resource { - variables?: GDictionary -} - -export class GameState extends Resource { - player?: PlayerState - progress?: ProgressState - world?: SaveState[] -} - -const StateMethod = { - Save: 'on_save_game', - BeforeLoad: 'on_before_load_game', - Load: 'on_load_game' -} as const - -type StateMethod = typeof StateMethod[keyof typeof StateMethod] - -export default class SaveSerializer extends Node { - private static _save_group: string = 'save' - - private static _instance: SaveSerializer - - _ready() { - SaveSerializer._instance = this - } - - static save() { - this._instance.save() - } - - private _announce(method: StateMethod, ...args: any) { - this.get_tree().call_group( - SaveSerializer._save_group, - method, - ...args - ) - } - - save() { - const game_state: GameState = new GameState() - - this._announce(StateMethod.Save, game_state) - - ResourceSaver.save(game_state, 'user://save1.tres') - } - - private async _restore_node(state: T, parent: Node) { - const scene: PackedScene = await AsyncResourceHandler.load(state.scene, 'PackedScene') - const node = scene.instantiate() - parent.add_child(node) - - if (has_method(StateMethod.Load, node)) { - // TODO: type check for state method - } - - } - - async load() { - const loaded_state: GameState = await AsyncResourceHandler.load('user://save1.tres') - this._announce(StateMethod.BeforeLoad) - // TODO: pass world root as 2nd param - const node_promises = loaded_state.world?.map(state => this._restore_node(state, this)) ?? [] - return Promise.all(node_promises) - } -} - diff --git a/src/save_system/game_state.ts b/src/save_system/game_state.ts new file mode 100644 index 0000000..7d49474 --- /dev/null +++ b/src/save_system/game_state.ts @@ -0,0 +1,19 @@ +import { GArray, PropertyHint, Resource, Variant } from 'godot' +import SaveState from './save_state' +import ProgressState from './progress_state' +import { export_, export_array, export_object } from 'godot.annotations' + +export default class GameState extends Resource { + //@export_object(ProgressState) + //progress: ProgressState = new ProgressState() + + @export_(Variant.Type.TYPE_ARRAY, { class_: SaveState, hint: PropertyHint.PROPERTY_HINT_RESOURCE_TYPE }) + world: SaveState[] = [] +} + +export interface Savable { + on_save_game(save_data: GameState): void + on_before_load_game?(): void + on_load_game(state: T): void +} + diff --git a/src/save_system/game_state.ts.uid b/src/save_system/game_state.ts.uid new file mode 100644 index 0000000..9b94056 --- /dev/null +++ b/src/save_system/game_state.ts.uid @@ -0,0 +1 @@ +uid://c0c2ne0y277od diff --git a/src/save_system/item_state.ts b/src/save_system/item_state.ts new file mode 100644 index 0000000..84dd6b9 --- /dev/null +++ b/src/save_system/item_state.ts @@ -0,0 +1,12 @@ +import { Resource, Variant } from 'godot' +import Item from '../item/item' +import { export_, export_object } from 'godot.annotations' + +export default class ItemState extends Resource { + @export_object(Item) + item?: Item + + @export_(Variant.Type.TYPE_INT) + quantity?: number +} + diff --git a/src/save_system/item_state.ts.uid b/src/save_system/item_state.ts.uid new file mode 100644 index 0000000..9c5dda7 --- /dev/null +++ b/src/save_system/item_state.ts.uid @@ -0,0 +1 @@ +uid://monf53dokbkn diff --git a/src/save_system/player_state.ts b/src/save_system/player_state.ts new file mode 100644 index 0000000..31beebc --- /dev/null +++ b/src/save_system/player_state.ts @@ -0,0 +1,19 @@ +import { Resource, Variant, Vector3 } from 'godot' +import SaveState from './save_state' +import ItemState from './item_state' +import { export_, export_array } from 'godot.annotations' + +export default class PlayerState extends Resource implements SaveState { + @export_(Variant.Type.TYPE_VECTOR3) + position!: Vector3 + + @export_(Variant.Type.TYPE_FLOAT) + condition!: number + + //@export_array(ItemState) + //inventory: ItemState[] = [] + + @export_(Variant.Type.TYPE_STRING_NAME) + scene!: string +} + diff --git a/src/save_system/player_state.ts.uid b/src/save_system/player_state.ts.uid new file mode 100644 index 0000000..1f804ae --- /dev/null +++ b/src/save_system/player_state.ts.uid @@ -0,0 +1 @@ +uid://sgqrfg7r58fl diff --git a/src/save_system/progress_state.ts b/src/save_system/progress_state.ts new file mode 100644 index 0000000..0fc890c --- /dev/null +++ b/src/save_system/progress_state.ts @@ -0,0 +1,4 @@ +export default class ProgressState { + variables: Map = new Map() +} + diff --git a/src/save_system/progress_state.ts.uid b/src/save_system/progress_state.ts.uid new file mode 100644 index 0000000..fd93b73 --- /dev/null +++ b/src/save_system/progress_state.ts.uid @@ -0,0 +1 @@ +uid://dbvn54hy25am5 diff --git a/src/save_system/save_serializer.ts b/src/save_system/save_serializer.ts new file mode 100644 index 0000000..2eddd0c --- /dev/null +++ b/src/save_system/save_serializer.ts @@ -0,0 +1,91 @@ +import { FileAccess, GArray, Node, PackedScene } from 'godot' +import AsyncResourceHandler from '../global/async_resource_handler' +import { implements_interface } from '../extension/node' +import GameState, { Savable } from './game_state' +import SaveState from './save_state' +import { Enumerable } from '../../addons/enumerable-ts/src' +import { GArrayEnumerator } from '../collection/enumerable' + +interface FileHandler { + (file: FileAccess): void +} + +const open = (path: string, mode: FileAccess.ModeFlags, fn: FileHandler) => { + const fd = FileAccess.open(path, mode) + const result = fn(fd) + fd.flush() + fd.close() + return result +} + +const read = (path: string, handler: FileHandler) => open(path, FileAccess.ModeFlags.READ, handler) + +const write = (path: string, handler: FileHandler) => open(path, FileAccess.ModeFlags.WRITE, handler) + +const StateMethod = { + Save: 'on_save_game', + BeforeLoad: 'on_before_load_game', + Load: 'on_load_game' +} as const + +type StateMethod = typeof StateMethod[keyof typeof StateMethod] + +export default class SaveSerializer extends Node { + private static _save_group: string = 'save' + + private static _instance: SaveSerializer + + _ready() { + SaveSerializer._instance = this + this.save() + this.load(this) + } + + static save() { + this._instance.save() + } + + private _announce(method: StateMethod, ...args: any) { + this.get_tree().call_group( + SaveSerializer._save_group, + method, + ...args + ) + } + + save() { + write('user://save1.save', file => { + const game_state = new GameState() + this._announce(StateMethod.Save, game_state) + //const json = JSON.stringify(game_state) + file.store_var(game_state) + }) + } + + private async _restore_node(state: T, parent: Node) { + const scene: PackedScene = await AsyncResourceHandler.load(state.scene, 'PackedScene') + const node = scene.instantiate() + parent.add_child(node) + + if (implements_interface(Object.values(StateMethod), node)) { + node.on_load_game(state) + } + } + + async load(world_root: Node) { + read('user://save1.save', file => { + //const state = JSON.parse(file.get_line()) as GameState + const state = file.get_var() as GameState + console.log(state) + this._announce(StateMethod.BeforeLoad) + const promises = [] + + for (const obj of state.world) { + promises.push(this._restore_node(obj, world_root)) + } + + return Promise.all(promises) + }) + } +} + diff --git a/src/save_serializer.ts.uid b/src/save_system/save_serializer.ts.uid similarity index 100% rename from src/save_serializer.ts.uid rename to src/save_system/save_serializer.ts.uid diff --git a/src/save_system/save_state.ts b/src/save_system/save_state.ts new file mode 100644 index 0000000..668812b --- /dev/null +++ b/src/save_system/save_state.ts @@ -0,0 +1,4 @@ +export default class SaveState { + scene!: string +} + diff --git a/src/save_system/save_state.ts.uid b/src/save_system/save_state.ts.uid new file mode 100644 index 0000000..056597a --- /dev/null +++ b/src/save_system/save_state.ts.uid @@ -0,0 +1 @@ +uid://y7hjjte8tykg diff --git a/typings/scenes/node_3d.nodes.gen.d.ts b/typings/scenes/node_3d.nodes.gen.d.ts index faa7911..7099e6f 100644 --- a/typings/scenes/node_3d.nodes.gen.d.ts +++ b/typings/scenes/node_3d.nodes.gen.d.ts @@ -58,6 +58,7 @@ declare module "godot" { FireRate: Timer<{}>, } >, + Health: Node<{}>, } >, DirectionalLight3D: DirectionalLight3D<{}>, diff --git a/typings/scenes/player.nodes.gen.d.ts b/typings/scenes/player.nodes.gen.d.ts index 1505286..ad66f32 100644 --- a/typings/scenes/player.nodes.gen.d.ts +++ b/typings/scenes/player.nodes.gen.d.ts @@ -43,6 +43,7 @@ declare module "godot" { FireRate: Timer<{}>, } >, + Health: Node<{}>, }, } }