Skip to content

Commit 70ed770

Browse files
GodotUtils and Visualize moved to DLLs (#187)
* Convert Visualize & GodotUtils to dlls * Update dlls and include missing GodotUtils.dll * Fix incorrect theme paths
1 parent b3b8704 commit 70ed770

File tree

89 files changed

+4819
-6
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+4819
-6
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
using Godot;
2+
using GodotUtils.UI;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Diagnostics;
6+
7+
namespace GodotUtils;
8+
9+
public class AudioManager : IDisposable
10+
{
11+
private const float MinDefaultRandomPitch = 0.8f;
12+
private const float MaxDefaultRandomPitch = 1.2f;
13+
private const float RandomPitchThreshold = 0.1f;
14+
private const int MutedVolume = -80;
15+
private const int MutedVolumeNormalized = -40;
16+
17+
private static AudioManager _instance;
18+
private AudioStreamPlayer _musicPlayer;
19+
private ResourceOptions _options;
20+
private Autoloads _autoloads;
21+
private float _lastPitch;
22+
23+
private List<AudioStreamPlayer2D> _activeSfxPlayers = [];
24+
25+
public AudioManager(Autoloads autoloads)
26+
{
27+
if (_instance != null)
28+
throw new InvalidOperationException($"{nameof(AudioManager)} was initialized already");
29+
30+
_instance = this;
31+
_autoloads = autoloads;
32+
_options = OptionsManager.GetOptions();
33+
34+
_musicPlayer = new AudioStreamPlayer();
35+
autoloads.AddChild(_musicPlayer);
36+
}
37+
38+
public void Dispose()
39+
{
40+
_musicPlayer.QueueFree();
41+
_activeSfxPlayers.Clear();
42+
43+
_instance = null;
44+
}
45+
46+
public static void PlayMusic(AudioStream song, bool instant = true, double fadeOut = 1.5, double fadeIn = 0.5)
47+
{
48+
if (!instant && _instance._musicPlayer.Playing)
49+
{
50+
// Slowly transition to the new song
51+
PlayAudioCrossfade(_instance._musicPlayer, song, _instance._options.MusicVolume, fadeOut, fadeIn);
52+
}
53+
else
54+
{
55+
// Instantly switch to the new song
56+
PlayAudio(_instance._musicPlayer, song, _instance._options.MusicVolume);
57+
}
58+
}
59+
60+
/// <summary>
61+
/// Plays a <paramref name="sound"/> at <paramref name="position"/>.
62+
/// </summary>
63+
/// <param name="parent"></param>
64+
/// <param name="sound"></param>
65+
public static void PlaySFX(AudioStream sound, Vector2 position, float minPitch = MinDefaultRandomPitch, float maxPitch = MaxDefaultRandomPitch)
66+
{
67+
AudioStreamPlayer2D sfxPlayer = new()
68+
{
69+
Stream = sound,
70+
VolumeDb = NormalizeConfigVolume(_instance._options.SFXVolume),
71+
PitchScale = GetRandomPitch(minPitch, maxPitch)
72+
};
73+
74+
sfxPlayer.Finished += () =>
75+
{
76+
sfxPlayer.QueueFree();
77+
_instance._activeSfxPlayers.Remove(sfxPlayer);
78+
};
79+
80+
_instance._autoloads.AddChild(sfxPlayer);
81+
_instance._activeSfxPlayers.Add(sfxPlayer);
82+
83+
sfxPlayer.GlobalPosition = position;
84+
sfxPlayer.Play();
85+
}
86+
87+
public static void FadeOutSFX(double fadeTime = 1)
88+
{
89+
foreach (AudioStreamPlayer2D sfxPlayer in _instance._activeSfxPlayers)
90+
{
91+
new GodotTween(sfxPlayer).Animate(AudioStreamPlayer.PropertyName.VolumeDb, MutedVolume, fadeTime);
92+
}
93+
}
94+
95+
public static void SetMusicVolume(float volume)
96+
{
97+
_instance._musicPlayer.VolumeDb = NormalizeConfigVolume(volume);
98+
_instance._options.MusicVolume = volume;
99+
}
100+
101+
public static void SetSFXVolume(float volume)
102+
{
103+
_instance._options.SFXVolume = volume;
104+
105+
float mappedVolume = NormalizeConfigVolume(volume);
106+
107+
foreach (AudioStreamPlayer2D sfxPlayer in _instance._activeSfxPlayers)
108+
{
109+
sfxPlayer.VolumeDb = mappedVolume;
110+
}
111+
}
112+
113+
private static void PlayAudio(AudioStreamPlayer player, AudioStream song, float volume)
114+
{
115+
player.Stream = song;
116+
player.VolumeDb = NormalizeConfigVolume(volume);
117+
player.Play();
118+
}
119+
120+
private static void PlayAudioCrossfade(AudioStreamPlayer player, AudioStream song, float volume, double fadeOut, double fadeIn)
121+
{
122+
new GodotTween(player)
123+
.SetAnimatingProp(AudioStreamPlayer.PropertyName.VolumeDb)
124+
.AnimateProp(MutedVolume, fadeOut).EaseIn()
125+
.Callback(() => PlayAudio(player, song, volume))
126+
.AnimateProp(NormalizeConfigVolume(volume), fadeIn).EaseIn();
127+
}
128+
129+
private static float NormalizeConfigVolume(float volume)
130+
{
131+
return volume == 0 ? MutedVolume : volume.Remap(0, 100, MutedVolumeNormalized, 0);
132+
}
133+
134+
private static float GetRandomPitch(float min, float max)
135+
{
136+
RandomNumberGenerator rng = new();
137+
rng.Randomize();
138+
139+
float pitch = rng.RandfRange(min, max);
140+
141+
while (Mathf.Abs(pitch - _instance._lastPitch) < RandomPitchThreshold)
142+
{
143+
rng.Randomize();
144+
pitch = rng.RandfRange(min, max);
145+
}
146+
147+
_instance._lastPitch = pitch;
148+
return pitch;
149+
}
150+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://d102rl17730xk

Framework/Autoloads/Autoloads.cs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
using Godot;
2+
using GodotUtils.UI;
3+
using GodotUtils.UI.Console;
4+
#if DEBUG
5+
using GodotUtils.Debugging;
6+
#endif
7+
using System;
8+
using System.Threading.Tasks;
9+
10+
namespace GodotUtils;
11+
12+
// Autoload
13+
// Access this with GetNode<Autoloads>("/root/Autoloads")
14+
public partial class Autoloads : Node
15+
{
16+
[Export] private MenuScenes _scenes;
17+
18+
public event Func<Task> PreQuit;
19+
20+
public static Autoloads Instance { get; private set; }
21+
22+
// Game developers should be able to access each individual manager
23+
public ComponentManager ComponentManager { get; private set; }
24+
public AudioManager AudioManager { get; private set; }
25+
public OptionsManager OptionsManager { get; private set; }
26+
public Services Services { get; private set; }
27+
public MetricsOverlay MetricsOverlay { get; private set; }
28+
public SceneManager SceneManager { get; private set; }
29+
public GameConsole GameConsole { get; private set; }
30+
31+
#if NETCODE_ENABLED
32+
private Logger _logger;
33+
#endif
34+
35+
#if DEBUG
36+
private VisualizeAutoload _visualizeAutoload;
37+
#endif
38+
39+
public override void _EnterTree()
40+
{
41+
if (Instance != null)
42+
throw new InvalidOperationException("Global has been initialized already");
43+
44+
Instance = this;
45+
ComponentManager = GetNode<ComponentManager>("ComponentManager");
46+
GameConsole = GetNode<GameConsole>("%Console");
47+
SceneManager = new SceneManager(this, _scenes);
48+
Services = new Services(this);
49+
MetricsOverlay = new MetricsOverlay();
50+
51+
#if NETCODE_ENABLED
52+
_logger = new Logger(GameConsole);
53+
#endif
54+
}
55+
56+
public override void _Ready()
57+
{
58+
CommandLineArgs.Initialize();
59+
Commands.RegisterAll();
60+
61+
OptionsManager = new OptionsManager(this);
62+
AudioManager = new AudioManager(this);
63+
64+
#if DEBUG
65+
_visualizeAutoload = new VisualizeAutoload();
66+
#endif
67+
}
68+
69+
public override void _Process(double delta)
70+
{
71+
OptionsManager.Update();
72+
MetricsOverlay.Update();
73+
74+
#if DEBUG
75+
_visualizeAutoload.Update();
76+
#endif
77+
78+
#if NETCODE_ENABLED
79+
_logger.Update();
80+
#endif
81+
}
82+
83+
public override void _PhysicsProcess(double delta)
84+
{
85+
MetricsOverlay.UpdatePhysics();
86+
}
87+
88+
public override async void _Notification(int what)
89+
{
90+
if (what == NotificationWMCloseRequest)
91+
{
92+
await QuitAndCleanup();
93+
}
94+
}
95+
96+
public override void _ExitTree()
97+
{
98+
AudioManager.Dispose();
99+
OptionsManager.Dispose();
100+
SceneManager.Dispose();
101+
Services.Dispose();
102+
MetricsOverlay.Dispose();
103+
104+
#if DEBUG
105+
_visualizeAutoload.Dispose();
106+
#endif
107+
108+
#if NETCODE_ENABLED
109+
_logger.Dispose();
110+
#endif
111+
112+
Profiler.Dispose();
113+
114+
Instance = null;
115+
}
116+
117+
// Using deferred is always complicated...
118+
public void DeferredSwitchSceneProxy(string rawName, Variant transTypeVariant)
119+
{
120+
if (SceneManager.Instance == null)
121+
return;
122+
123+
SceneManager.Instance.DeferredSwitchScene(rawName, transTypeVariant);
124+
}
125+
126+
public async Task QuitAndCleanup()
127+
{
128+
GetTree().AutoAcceptQuit = false;
129+
130+
// Wait for cleanup
131+
if (PreQuit != null)
132+
{
133+
// Since the PreQuit event contains a Task only the first subscriber will be invoked
134+
// with await PreQuit?.Invoke(); so need to ensure all subs are invoked.
135+
Delegate[] invocationList = PreQuit.GetInvocationList();
136+
foreach (Func<Task> subscriber in invocationList)
137+
{
138+
await subscriber();
139+
}
140+
}
141+
142+
GetTree().Quit();
143+
}
144+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://cdt2k6s3xm13g

Framework/Autoloads/Autoloads.tscn

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
[gd_scene load_steps=10 format=3 uid="uid://cj4fbh1a1lpq4"]
2+
3+
[ext_resource type="Script" uid="uid://cdt2k6s3xm13g" path="res://Framework/Autoloads/Autoloads.cs" id="1_00yjk"]
4+
[ext_resource type="PackedScene" uid="uid://rbcqvr4snrvn" path="res://Framework/Scenes/MenuUI/Credits/Credits.tscn" id="2_xdmsn"]
5+
[ext_resource type="PackedScene" uid="uid://d4a5xfmaulku1" path="res://Framework/Scenes/MenuUI/MainMenu/MainMenu.tscn" id="3_sv5ok"]
6+
[ext_resource type="Script" uid="uid://ct4og8hi8urvd" path="res://Framework/Components/ComponentManager.cs" id="3_sycog"]
7+
[ext_resource type="PackedScene" uid="uid://jrjqky6ag6gg" path="res://Framework/Console/GameConsole.tscn" id="4_8po21"]
8+
[ext_resource type="PackedScene" uid="uid://d1jo48n2hdkih" path="res://Framework/ModLoader/ModLoader.tscn" id="4_ems5f"]
9+
[ext_resource type="PackedScene" uid="uid://7tfets4irkba" path="res://Framework/Scenes/Options/Options.tscn" id="5_vm4c5"]
10+
[ext_resource type="Script" uid="uid://17yxgcswri77" path="res://Framework/Scenes/MenuScenes.cs" id="6_2fq88"]
11+
12+
[sub_resource type="Resource" id="Resource_xdmsn"]
13+
script = ExtResource("6_2fq88")
14+
MainMenu = ExtResource("3_sv5ok")
15+
ModLoader = ExtResource("4_ems5f")
16+
Options = ExtResource("5_vm4c5")
17+
Credits = ExtResource("2_xdmsn")
18+
metadata/_custom_type_script = "uid://17yxgcswri77"
19+
20+
[node name="Autoloads" type="Node"]
21+
process_mode = 3
22+
script = ExtResource("1_00yjk")
23+
_scenes = SubResource("Resource_xdmsn")
24+
25+
[node name="ComponentManager" type="Node" parent="."]
26+
process_mode = 1
27+
script = ExtResource("3_sycog")
28+
29+
[node name="Debug" type="CanvasLayer" parent="."]
30+
layer = 128
31+
32+
[node name="Console" parent="Debug" instance=ExtResource("4_8po21")]
33+
unique_name_in_owner = true

0 commit comments

Comments
 (0)