From 9107b8c5703c2708a52a673a230cce8082b85c38 Mon Sep 17 00:00:00 2001 From: Zenny Date: Fri, 26 Sep 2025 14:05:05 -0700 Subject: [PATCH] Rework loading maps to be asynchronous, change debug menu so that its not completely pausing the game --- Zennysoft.Game.Ma/src/app/App.cs | 4 +- Zennysoft.Game.Ma/src/game/Game.cs | 8 +-- Zennysoft.Game.Ma/src/map/IMap.cs | 8 +-- Zennysoft.Game.Ma/src/map/Map.cs | 68 +++++++++---------- Zennysoft.Game.Ma/src/map/Map.tscn | 68 ++++++++++++++++++- Zennysoft.Game.Ma/src/map/SceneLoader.cs.uid | 1 + Zennysoft.Game.Ma/src/menu/LoadingScreen.cs | 12 +--- Zennysoft.Game.Ma/src/menu/LoadingScreen.tscn | 18 ++--- .../src/ui/pause_menu/PauseDebugMenu.cs | 31 +-------- Zennysoft.Game.Ma/src/utils/SceneLoader.cs | 41 +++++++++++ 10 files changed, 164 insertions(+), 95 deletions(-) create mode 100644 Zennysoft.Game.Ma/src/map/SceneLoader.cs.uid create mode 100644 Zennysoft.Game.Ma/src/utils/SceneLoader.cs diff --git a/Zennysoft.Game.Ma/src/app/App.cs b/Zennysoft.Game.Ma/src/app/App.cs index 052e3393..72bb8026 100644 --- a/Zennysoft.Game.Ma/src/app/App.cs +++ b/Zennysoft.Game.Ma/src/app/App.cs @@ -24,7 +24,7 @@ public partial class App : Node, IApp [Node] private MainMenu MainMenu { get; set; } = default!; - [Node] private Control LoadingScreen { get; set; } = default!; + [Node] private LoadingScreen LoadingScreen { get; set; } = default!; public IInstantiator Instantiator { get; set; } = default!; @@ -118,6 +118,7 @@ public partial class App : Node, IApp if (_loadingGame) { ResourceLoader.LoadThreadedGetStatus(GAME_SCENE_PATH, _progress); + LoadingScreen.ProgressBar.Value = (double)_progress.Single(); if ((double)_progress.Single() == 1) _loadedScene.OnNext(GAME_SCENE_PATH); } @@ -125,6 +126,7 @@ public partial class App : Node, IApp if (_loadingEnemyViewer) { ResourceLoader.LoadThreadedGetStatus(ENEMY_VIEWER_PATH, _progress); + LoadingScreen.ProgressBar.Value = (double)_progress.Single(); if ((double)_progress.Single() == 1) _loadedScene.OnNext(ENEMY_VIEWER_PATH); } diff --git a/Zennysoft.Game.Ma/src/game/Game.cs b/Zennysoft.Game.Ma/src/game/Game.cs index a8b88906..ab32d751 100644 --- a/Zennysoft.Game.Ma/src/game/Game.cs +++ b/Zennysoft.Game.Ma/src/game/Game.cs @@ -177,13 +177,13 @@ public partial class Game : Node3D, IGame { InGameUI.DebugMenu.Show(); InGameUI.PlayerInfoUI.Hide(); - GameRepo.Pause(); + _player.Deactivate(); }) .Handle((in GameState.Output.CloseDebugMenu _) => { InGameUI.DebugMenu.Hide(); InGameUI.PlayerInfoUI.Show(); - GameRepo.Resume(); + _player.Activate(); }) .Handle((in GameState.Output.OpenTeleportScreen _) => { @@ -199,7 +199,7 @@ public partial class Game : Node3D, IGame .Handle((in GameState.Output.LoadNextFloor _) => { FloorClearMenu.FadeOut(); - _map.SpawnNextFloor(); + _map.LoadFloor(); if (_player.EquippedWeapon.Value.ItemTag == ItemTag.BreaksOnChange) { var itemToDestroy = _player.EquippedWeapon.Value; @@ -247,7 +247,7 @@ public partial class Game : Node3D, IGame public void OnReady() { InitializeGame(); - _map.LoadMap(); + _map.LoadFloor(); GameRepo.Resume(); InGameUI.Show(); InGameUI.PlayerInfoUI.Activate(); diff --git a/Zennysoft.Game.Ma/src/map/IMap.cs b/Zennysoft.Game.Ma/src/map/IMap.cs index 63833f9f..1df5813a 100644 --- a/Zennysoft.Game.Ma/src/map/IMap.cs +++ b/Zennysoft.Game.Ma/src/map/IMap.cs @@ -3,24 +3,20 @@ using Chickensoft.Collections; using Chickensoft.GodotNodeInterfaces; using Chickensoft.SaveFileBuilder; using Godot; -using System.Collections.Generic; using System.Collections.Immutable; +using System.Threading.Tasks; using Zennysoft.Ma.Adapter; namespace Zennysoft.Game.Ma; public interface IMap : INode3D, IProvide> { - void LoadMap(); - - void LoadFloor(); + Task LoadFloor(); ImmutableDictionary FloorScenes { get; } IDungeonFloor CurrentFloor { get; } - void SpawnNextFloor(); - Transform3D GetPlayerSpawnPosition(); IDungeonRoom GetPlayersCurrentRoom(); diff --git a/Zennysoft.Game.Ma/src/map/Map.cs b/Zennysoft.Game.Ma/src/map/Map.cs index 2381e4cd..46118e77 100644 --- a/Zennysoft.Game.Ma/src/map/Map.cs +++ b/Zennysoft.Game.Ma/src/map/Map.cs @@ -1,12 +1,13 @@ using Chickensoft.AutoInject; using Chickensoft.Collections; using Chickensoft.Introspection; -using Chickensoft.LogicBlocks; using Chickensoft.SaveFileBuilder; using Godot; -using System.Collections.Generic; +using Godot.Collections; using System.Collections.Immutable; using System.Linq; +using System.Threading.Tasks; +using Zennysoft.Game.Implementation; using Zennysoft.Ma.Adapter; namespace Zennysoft.Game.Ma; @@ -27,12 +28,15 @@ public partial class Map : Node3D, IMap ISaveChunk IProvide>.Value() => MapChunk; + [Node] + public AnimationPlayer AnimationPlayer { get; set; } = default!; + [Dependency] public ISaveChunk GameChunk => this.DependOn>(); #endregion [Export] - private Godot.Collections.Array Floors { get; set; } = default!; + private Array Floors { get; set; } = default!; public ImmutableDictionary FloorScenes { get; private set; } @@ -51,7 +55,6 @@ public partial class Map : Node3D, IMap public void InitializeMapData() { - ClearMap(); FloorScenes = ImmutableDictionary.Empty .Add(Floor.Overworld, $"res://src/map/overworld/Overworld.tscn") .Add(Floor.Altar, $"res://src/map/dungeon/floors/Floor00.tscn") @@ -68,31 +71,6 @@ public partial class Map : Node3D, IMap CurrentFloorNumber.OnNext(0); } - public void LoadMap() - { - LoadFloor(); - CurrentFloor.InitializeDungeon(); - var transform = GetPlayerSpawnPosition(); - Player.TeleportPlayer(transform); - CurrentFloor.FloorIsLoaded = true; - } - - private void ClearMap() - { - CurrentFloor?.CallDeferred(MethodName.QueueFree, []); - } - - public void SpawnNextFloor() - { - ClearMap(); - LoadFloor(); - CurrentFloor.InitializeDungeon(); - var transform = GetPlayerSpawnPosition(); - Player.TeleportPlayer(transform); - CurrentFloor.FloorIsLoaded = true; - CurrentFloorNumber.OnNext(CurrentFloorNumber.Value + 1); - } - public IDungeonRoom GetPlayersCurrentRoom() { var rooms = CurrentFloor.Rooms; @@ -102,15 +80,33 @@ public partial class Map : Node3D, IMap public Transform3D GetPlayerSpawnPosition() => CurrentFloor.GetPlayerSpawnPoint(); - public void LoadFloor() + public async Task LoadFloor() { - ClearMap(); - FloorScenes.TryGetValue(Floors.First(), out var currentFloorScene); - var instantiator = new Instantiator(GetTree()); - var loadedScene = instantiator.LoadAndInstantiate(currentFloorScene); - AddChild(loadedScene); - CurrentFloor = (IDungeonFloor)loadedScene; + AnimationPlayer.CallDeferred(AnimationPlayer.MethodName.Play, "fade_out"); + FloorScenes.TryGetValue(Floors.First(), out var sceneToLoad); + ClearCurrentMap(); + var sceneLoader = new SceneLoader(); + AddChild(sceneLoader); + sceneLoader.LoadSceneRequest(sceneToLoad); + await ToSignal(sceneLoader, SceneLoader.SignalName.SceneLoaded); + AddChild(sceneLoader.LoadedScene); + CurrentFloor = (IDungeonFloor)sceneLoader.LoadedScene; + SetupDungeonFloor(); + CurrentFloor.FloorIsLoaded = true; + CurrentFloorNumber.OnNext(CurrentFloorNumber.Value + 1); + sceneLoader.QueueFree(); + AnimationPlayer.CallDeferred(AnimationPlayer.MethodName.Play, ("fade_in")); + } + + private void ClearCurrentMap() + { + CurrentFloor?.CallDeferred(MethodName.QueueFree, []); Floors.Remove(Floors.First()); + } + + private void SetupDungeonFloor() + { + CurrentFloor.InitializeDungeon(); var transform = GetPlayerSpawnPosition(); Player.TeleportPlayer(transform); } diff --git a/Zennysoft.Game.Ma/src/map/Map.tscn b/Zennysoft.Game.Ma/src/map/Map.tscn index 51030d6a..8ecfa3f6 100644 --- a/Zennysoft.Game.Ma/src/map/Map.tscn +++ b/Zennysoft.Game.Ma/src/map/Map.tscn @@ -1,7 +1,73 @@ -[gd_scene load_steps=2 format=3 uid="uid://by67pn7fdsg1m"] +[gd_scene load_steps=6 format=3 uid="uid://by67pn7fdsg1m"] [ext_resource type="Script" uid="uid://14e8mu48ed4" path="res://src/map/Map.cs" id="1_bw70o"] +[sub_resource type="Animation" id="Animation_g6eui"] +resource_name = "fade_in" +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("ColorRect:color") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(0, 0, 0, 1), Color(0, 0, 0, 0)] +} + +[sub_resource type="Animation" id="Animation_00xd7"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("ColorRect:color") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(0, 0, 0, 1)] +} + +[sub_resource type="Animation" id="Animation_v14r0"] +resource_name = "fade_out" +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("ColorRect:color") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(-0.0666667, 0), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Color(0, 0, 0, 1), Color(0, 0, 0, 1)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_00xd7"] +_data = { +&"RESET": SubResource("Animation_00xd7"), +&"fade_in": SubResource("Animation_g6eui"), +&"fade_out": SubResource("Animation_v14r0") +} + [node name="Map" type="Node3D"] script = ExtResource("1_bw70o") Floors = Array[int]([3, 2, 0, 4, 1, 5, 6]) + +[node name="ColorRect" type="ColorRect" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0, 0, 0, 1) + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +unique_name_in_owner = true +libraries = { +&"": SubResource("AnimationLibrary_00xd7") +} diff --git a/Zennysoft.Game.Ma/src/map/SceneLoader.cs.uid b/Zennysoft.Game.Ma/src/map/SceneLoader.cs.uid new file mode 100644 index 00000000..4d4ba45e --- /dev/null +++ b/Zennysoft.Game.Ma/src/map/SceneLoader.cs.uid @@ -0,0 +1 @@ +uid://bftr18a1c2gll diff --git a/Zennysoft.Game.Ma/src/menu/LoadingScreen.cs b/Zennysoft.Game.Ma/src/menu/LoadingScreen.cs index 39c8acd7..ca1547d0 100644 --- a/Zennysoft.Game.Ma/src/menu/LoadingScreen.cs +++ b/Zennysoft.Game.Ma/src/menu/LoadingScreen.cs @@ -1,20 +1,12 @@ using Chickensoft.AutoInject; using Chickensoft.Introspection; using Godot; -using Zennysoft.Game.Ma; [Meta(typeof(IAutoNode))] public partial class LoadingScreen : Control { public override void _Notification(int what) => this.Notify(what); - public override void _Process(double delta) - { - if (Input.IsActionJustPressed(GameInputs.Next)) - { - } - if (Input.IsActionJustPressed(GameInputs.Previous)) - { - } - } + [Node] + public ProgressBar ProgressBar { get; set; } = default!; } diff --git a/Zennysoft.Game.Ma/src/menu/LoadingScreen.tscn b/Zennysoft.Game.Ma/src/menu/LoadingScreen.tscn index 1ae2ba9c..ae2a8fb2 100644 --- a/Zennysoft.Game.Ma/src/menu/LoadingScreen.tscn +++ b/Zennysoft.Game.Ma/src/menu/LoadingScreen.tscn @@ -1,12 +1,12 @@ [gd_scene load_steps=4 format=3 uid="uid://cpjlj7kxdhv16"] [ext_resource type="Script" uid="uid://b07ueredevhr3" path="res://src/menu/LoadingScreen.cs" id="1_5uxhf"] -[ext_resource type="FontFile" uid="uid://cm8j5vcdop5x0" path="res://src/ui/fonts/Mrs-Eaves-OT-Roman_31443.ttf" id="2_xfkmi"] -[sub_resource type="LabelSettings" id="LabelSettings_6i7rn"] -font = ExtResource("2_xfkmi") -font_size = 100 -font_color = Color(0.737255, 0.705882, 0.690196, 1) +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5uxhf"] +bg_color = Color(0.670689, 0.67069, 0.670689, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_xfkmi"] +bg_color = Color(0.146349, 0.723509, 0, 1) [node name="LoadingScreen" type="Control"] layout_mode = 3 @@ -28,7 +28,9 @@ grow_vertical = 2 [node name="CenterContainer" type="CenterContainer" parent="PanelContainer"] layout_mode = 2 -[node name="Label" type="Label" parent="PanelContainer/CenterContainer"] +[node name="ProgressBar" type="ProgressBar" parent="PanelContainer/CenterContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(500, 50) layout_mode = 2 -text = "Loading..." -label_settings = SubResource("LabelSettings_6i7rn") +theme_override_styles/background = SubResource("StyleBoxFlat_5uxhf") +theme_override_styles/fill = SubResource("StyleBoxFlat_xfkmi") diff --git a/Zennysoft.Game.Ma/src/ui/pause_menu/PauseDebugMenu.cs b/Zennysoft.Game.Ma/src/ui/pause_menu/PauseDebugMenu.cs index 4ca90575..911defa8 100644 --- a/Zennysoft.Game.Ma/src/ui/pause_menu/PauseDebugMenu.cs +++ b/Zennysoft.Game.Ma/src/ui/pause_menu/PauseDebugMenu.cs @@ -47,25 +47,6 @@ public partial class PauseDebugMenu : Control, IDebugMenu public override void _Ready() { -<<<<<<< HEAD - VisibilityChanged += PauseDebugMenu_VisibilityChanged; - LoadNextFloorButton.Pressed += LoadNextFloorButton_Pressed; - _itemDatabase = new ItemDatabase(); - _spawnableItems = _itemDatabase.Items; - _spawnableEnemies = []; - foreach (var item in _spawnableItems) - SpawnItemDropDown.AddItem(item.ItemName); - - _spawnableEnemies = [.. _enemyDatabase.EnemyList]; - - foreach (var enemy in _spawnableEnemies) - { - var tempEnemy = enemy.Instantiate(); - SpawnEnemyDropDown.AddItem(tempEnemy.Name); - } - SpawnItemDropDown.AllowReselect = true; - SpawnEnemyDropDown.AllowReselect = true; -======= VisibilityChanged += PauseDebugMenu_VisibilityChanged; LoadNextFloorButton.Pressed += LoadNextFloorButton_Pressed; _itemDatabase = new ItemDatabase(); @@ -76,7 +57,6 @@ public partial class PauseDebugMenu : Control, IDebugMenu SpawnItemDropDown.AllowReselect = true; SpawnEnemyDropDown.AllowReselect = true; ->>>>>>> 7e9114bfd1f6c5dd447c4c4e54a2e8ccb9f38e24 SpawnItemDropDown.ItemSelected += SpawnItemDropDown_ItemSelected; SpawnEnemyDropDown.ItemSelected += SpawnEnemyDropDown_ItemSelected; @@ -84,17 +64,10 @@ public partial class PauseDebugMenu : Control, IDebugMenu private void SpawnEnemyDropDown_ItemSelected(long index) { -<<<<<<< HEAD - var enemyToSpawn = _spawnableEnemies.ElementAt((int)index); - var loadedEnemy = enemyToSpawn.Instantiate(); - AddChild(loadedEnemy); - loadedEnemy.GlobalPosition = new Vector3(_player.CurrentPosition.X, _player.CurrentPosition.Y + 1, _player.CurrentPosition.Z) + (-_player.CurrentBasis.Z * 2); -======= var enemyToSpawn = _spawnableEnemies.ElementAt((int)index); var loadedEnemy = GD.Load(enemyToSpawn).Instantiate(); AddChild(loadedEnemy); loadedEnemy.GlobalPosition = new Vector3(_player.CurrentPosition.X, _player.CurrentPosition.Y + 1, _player.CurrentPosition.Z) + (-_player.CurrentBasis.Z * 2); ->>>>>>> 7e9114bfd1f6c5dd447c4c4e54a2e8ccb9f38e24 } private void SpawnItemDropDown_ItemSelected(long index) @@ -105,9 +78,9 @@ public partial class PauseDebugMenu : Control, IDebugMenu duplicated.GlobalPosition = new Vector3(_player.CurrentPosition.X, _player.CurrentPosition.Y + 1, _player.CurrentPosition.Z) + (-_player.CurrentBasis.Z * 2); } - private void LoadNextFloorButton_Pressed() + private async void LoadNextFloorButton_Pressed() { - _map.SpawnNextFloor(); + await _map.LoadFloor(); } private void PauseDebugMenu_VisibilityChanged() diff --git a/Zennysoft.Game.Ma/src/utils/SceneLoader.cs b/Zennysoft.Game.Ma/src/utils/SceneLoader.cs new file mode 100644 index 00000000..765211cd --- /dev/null +++ b/Zennysoft.Game.Ma/src/utils/SceneLoader.cs @@ -0,0 +1,41 @@ +using Godot; +using System.Linq; + +namespace Zennysoft.Game.Ma; + +public partial class SceneLoader : Node +{ + private string _sceneToLoad; + private bool _loading = false; + + [Signal] + public delegate void SceneLoadedEventHandler(); + + public Node LoadedScene { get; private set; } + + public void LoadSceneRequest(string sceneToLoad) + { + ResourceLoader.LoadThreadedRequest(sceneToLoad); + _sceneToLoad = sceneToLoad; + _loading = true; + } + + private void LoadScene() + { + _loading = false; + var scene = (PackedScene)ResourceLoader.LoadThreadedGet(_sceneToLoad); + LoadedScene = scene.Instantiate(); + EmitSignal(SignalName.SceneLoaded); + } + + public override void _Process(double delta) + { + if (!_loading) + return; + + var progress = new Godot.Collections.Array(); + ResourceLoader.LoadThreadedGetStatus(_sceneToLoad, progress); + if ((double)progress.Single() == 1) + LoadScene(); + } +}