Lots of stuff I forgot to commit because Holidays

- D&D dice engine (see README)
- Markdown support
- Phantom camera
This commit is contained in:
Tony Bark 2023-12-24 20:39:57 -05:00
parent 9589acd877
commit 2b41f84b05
125 changed files with 13170 additions and 23 deletions

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present Nathan Hoad
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,178 @@
using Godot;
using Godot.Collections;
namespace NathanHoad
{
public partial class SoundManager : Node
{
private static Node instance;
public static Node Instance
{
get
{
if (instance == null)
{
instance = (Node)Engine.GetSingleton("SoundManager");
}
return instance;
}
}
#region Sounds
public static float GetSoundVolume()
{
return (float)Instance.Call("get_sound_volume");
}
public static float GetUISoundVolume()
{
return (float)Instance.Call("get_ui_sound_volume");
}
public static void SetSoundVolume(float volume)
{
Instance.Call("set_sound_volume", volume);
}
public static AudioStreamPlayer PlaySound(AudioStream resource, string overrideBus = "")
{
return (AudioStreamPlayer)Instance.Call("play_sound", resource, overrideBus);
}
public static AudioStreamPlayer PlaySoundWithPitch(AudioStream resource, float pitch, string overrideBus = "")
{
return (AudioStreamPlayer)Instance.Call("play_sound_with_pitch", resource, pitch, overrideBus);
}
public static AudioStreamPlayer PlayUISound(AudioStream resource, string overrideBus = "")
{
return (AudioStreamPlayer)Instance.Call("play_ui_sound", resource, overrideBus);
}
public static AudioStreamPlayer PlayUISoundWithPitch(AudioStream resource, float pitch, string overrideBus = "")
{
return (AudioStreamPlayer)Instance.Call("play_ui_sound_with_pitch", resource, pitch, overrideBus);
}
public static void SetDefaultSoundBus(string bus)
{
Instance.Call("set_default_sound_bus", bus);
}
public static void SetDefaultUISoundBus(string bus)
{
Instance.Call("set_default_ui_sound_bus", bus);
}
#endregion
#region Music
public static float GetMusicVolume()
{
return (float)Instance.Call("get_music_volume");
}
public static void SetMusicVolume(float volume)
{
Instance.Call("set_music_volume", volume);
}
public static AudioStreamPlayer PlayMusic(AudioStream resource, float crossFadeDuration = 0.0f, string overrideBus = "")
{
return (AudioStreamPlayer)Instance.Call("play_music", resource, crossFadeDuration, overrideBus);
}
public static AudioStreamPlayer PlayMusicFromPosition(AudioStream resource, float position, float crossFadeDuration = 0.0f, string overrideBus = "")
{
return (AudioStreamPlayer)Instance.Call("play_music_from_position", resource, position, crossFadeDuration, overrideBus);
}
public static AudioStreamPlayer PlayMusicAtVolume(AudioStream resource, float volume, float crossFadeDuration = 0.0f, string overrideBus = "")
{
return (AudioStreamPlayer)Instance.Call("play_music_at_volume", resource, volume, crossFadeDuration, overrideBus);
}
public static AudioStreamPlayer PlayMusicFromPositionAtVolume(AudioStream resource, float position, float volume, float crossFadeDuration = 0.0f, string overrideBus = "")
{
return (AudioStreamPlayer)Instance.Call("play_music_from_position_at_volume", resource, position, volume, crossFadeDuration, overrideBus);
}
public static Array<string> GetMusicTrackHistory()
{
return (Array<string>)Instance.Call("get_music_track_history");
}
public static string GetLastPlayedMusicTrack()
{
return (string)Instance.Call("get_last_played_music_track");
}
public static bool IsMusicPlaying(AudioStream resource = null)
{
return (bool)Instance.Call("is_music_playing", resource);
}
public static bool IsMusicTrackPlaying(string resource_path)
{
return (bool)Instance.Call("is_music_track_playing", resource_path);
}
public static Array<AudioStream> GetCurrentlyPlayingMusic()
{
return (Array<AudioStream>)Instance.Call("get_currently_playing_music");
}
public static Array<string> GetCurrentlyPlayingTracks()
{
return (Array<string>)Instance.Call("get_currently_playing_tracks");
}
public static void PauseMusic(AudioStream resource = null)
{
Instance.Call("pause_music", resource);
}
public static void ResumeMusic(AudioStream resource = null)
{
Instance.Call("resume_music", resource);
}
public static void StopMusic(float fadeOutDuration = 0.0f)
{
Instance.Call("stop_music", fadeOutDuration);
}
public static void SetDefaultMusicBus(string bus)
{
Instance.Call("set_default_music_bus", bus);
}
#endregion
}
}

View file

@ -0,0 +1,84 @@
extends Node
@export var default_busses := []
@export var default_pool_size := 8
var available_players: Array[AudioStreamPlayer] = []
var busy_players: Array[AudioStreamPlayer] = []
var bus: String = "Master"
func _init(possible_busses: PackedStringArray = default_busses, pool_size: int = default_pool_size) -> void:
bus = get_possible_bus(possible_busses)
for i in pool_size:
increase_pool()
func get_possible_bus(possible_busses: PackedStringArray) -> String:
for possible_bus in possible_busses:
var cases: PackedStringArray = [
possible_bus,
possible_bus.to_lower(),
possible_bus.to_camel_case(),
possible_bus.to_pascal_case(),
possible_bus.to_snake_case()
]
for case in cases:
if AudioServer.get_bus_index(case) > -1:
return case
return "Master"
func prepare(resource: AudioStream, override_bus: String = "") -> AudioStreamPlayer:
var player: AudioStreamPlayer
if resource is AudioStreamRandomizer:
player = get_player_with_resource(resource)
if player == null:
player = get_available_player()
player.stream = resource
player.bus = override_bus if override_bus != "" else bus
player.volume_db = linear_to_db(1.0)
player.pitch_scale = 1
return player
func get_available_player() -> AudioStreamPlayer:
if available_players.size() == 0:
increase_pool()
var player = available_players.pop_front()
busy_players.append(player)
return player
func get_player_with_resource(resource: AudioStream) -> AudioStreamPlayer:
for player in busy_players + available_players:
if player.stream == resource:
return player
return null
func mark_player_as_available(player: AudioStreamPlayer) -> void:
if busy_players.has(player):
busy_players.erase(player)
if not available_players.has(player):
available_players.append(player)
func increase_pool() -> void:
var player := AudioStreamPlayer.new()
add_child(player)
available_players.append(player)
player.bus = bus
player.finished.connect(_on_player_finished.bind(player))
### SIGNALS
func _on_player_finished(player: AudioStreamPlayer) -> void:
mark_player_as_available(player)

View file

@ -0,0 +1,133 @@
extends "res://addons/sound_manager/abstract_audio_player_pool.gd"
var tweens: Dictionary = {}
var track_history: PackedStringArray = []
func play(resource: AudioStream, position: float = 0.0, volume: float = 0.0, crossfade_duration: float = 0.0, override_bus: String = "") -> AudioStreamPlayer:
stop(crossfade_duration * 2)
var player = _get_player_with_music(resource)
# If the player already exists then just make sure the volume is right (it might have just been fading in or out)
if player != null:
fade_volume(player, player.volume_db, volume, crossfade_duration)
return player
# Otherwise we need to prep another player and handle its introduction
player = prepare(resource, override_bus)
fade_volume(player, -80.0, volume, crossfade_duration)
# Remember this track name
track_history.insert(0, resource.resource_path)
if track_history.size() > 50:
track_history.remove_at(50)
player.call_deferred("play", position)
return player
func is_playing(resource: AudioStream) -> bool:
if resource != null:
return _get_player_with_music(resource) != null
else:
return busy_players.size() > 0
func stop(fade_out_duration: float = 0.0) -> void:
for player in busy_players:
if fade_out_duration <= 0.0:
fade_out_duration = 0.01
fade_volume(player, player.volume_db, -80, fade_out_duration)
func pause(resource: AudioStream = null) -> void:
if resource != null:
var player = _get_player_with_music(resource)
if is_instance_valid(player):
player.stream_paused = true
else:
for player in busy_players:
player.stream_paused = true
func resume(resource: AudioStream = null) -> void:
if resource != null:
var player = _get_player_with_music(resource)
if is_instance_valid(player):
player.stream_paused = false
else:
for player in busy_players:
player.stream_paused = false
func is_track_playing(resource_path: String) -> bool:
for player in busy_players:
if player.stream.resource_path == resource_path:
return true
return false
func get_currently_playing() -> Array[AudioStream]:
var tracks: Array[AudioStream] = []
for player in busy_players:
tracks.append(player.stream)
return tracks
func get_currently_playing_tracks() -> PackedStringArray:
var tracks: PackedStringArray = []
for player in busy_players:
tracks.append(player.stream.resource_path)
return tracks
func fade_volume(player: AudioStreamPlayer, from_volume: float, to_volume: float, duration: float) -> AudioStreamPlayer:
# Remove any tweens that might already be on this player
_remove_tween(player)
# Start a new tween
var tween: Tween = get_tree().create_tween().bind_node(self)
player.volume_db = from_volume
if from_volume > to_volume:
# Fade out
tween.tween_property(player, "volume_db", to_volume, duration).set_trans(Tween.TRANS_CIRC).set_ease(Tween.EASE_IN)
else:
# Fade in
tween.tween_property(player, "volume_db", to_volume, duration).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
tweens[player] = tween
tween.finished.connect(_on_fade_completed.bind(player, tween, from_volume, to_volume, duration))
return player
### Helpers
func _get_player_with_music(resource: AudioStream) -> AudioStreamPlayer:
for player in busy_players:
if player.stream.resource_path == resource.resource_path:
return player
return null
func _remove_tween(player: AudioStreamPlayer) -> void:
if tweens.has(player):
var fade: Tween = tweens.get(player)
fade.kill()
tweens.erase(player)
### Signals
func _on_fade_completed(player: AudioStreamPlayer, tween: Tween, from_volume: float, to_volume: float, duration: float):
_remove_tween(player)
# If we just faded out then our player is now available
if to_volume <= -79.0:
player.stop()
mark_player_as_available(player)

View file

@ -0,0 +1,7 @@
[plugin]
name="SoundManager"
description="Manage your sounds and music"
author="Nathan Hoad"
version="2.5.0"
script="plugin.gd"

View file

@ -0,0 +1,10 @@
@tool
extends EditorPlugin
func _enter_tree():
add_autoload_singleton("SoundManager", "res://addons/sound_manager/sound_manager.gd")
func _exit_tree():
remove_autoload_singleton("SoundManager")

View file

@ -0,0 +1,7 @@
extends "res://addons/sound_manager/abstract_audio_player_pool.gd"
func play(resource: AudioStream, override_bus: String = "") -> AudioStreamPlayer:
var player = prepare(resource, override_bus)
player.call_deferred("play")
return player

View file

@ -0,0 +1,154 @@
extends Node
const SoundEffectsPlayer = preload("res://addons/sound_manager/sound_effects.gd")
const MusicPlayer = preload("res://addons/sound_manager/music.gd")
var sound_effects: SoundEffectsPlayer = SoundEffectsPlayer.new(["Sounds", "SFX"], 8)
var ui_sound_effects: SoundEffectsPlayer = SoundEffectsPlayer.new(["UI", "Interface", "Sounds", "SFX"], 8)
var music: MusicPlayer = MusicPlayer.new(["Music"], 2)
var sound_process_mode: ProcessMode:
set(value):
sound_effects.process_mode = value
get:
return sound_effects.process_mode
var ui_sound_process_mode: ProcessMode:
set(value):
ui_sound_effects.process_mode = value
get:
return ui_sound_effects.process_mode
var music_process_mode: ProcessMode:
set(value):
music.process_mode = value
get:
return music.process_mode
func _init() -> void:
Engine.register_singleton("SoundManager", self)
add_child(sound_effects)
add_child(ui_sound_effects)
add_child(music)
self.sound_process_mode = PROCESS_MODE_PAUSABLE
self.ui_sound_process_mode = PROCESS_MODE_ALWAYS
self.music_process_mode = PROCESS_MODE_ALWAYS
func get_sound_volume() -> float:
return db_to_linear(AudioServer.get_bus_volume_db(AudioServer.get_bus_index(sound_effects.bus)))
func get_ui_sound_volume() -> float:
return db_to_linear(AudioServer.get_bus_volume_db(AudioServer.get_bus_index(ui_sound_effects.bus)))
func set_sound_volume(volume_between_0_and_1) -> void:
_show_shared_bus_warning()
AudioServer.set_bus_volume_db(AudioServer.get_bus_index(sound_effects.bus), linear_to_db(volume_between_0_and_1))
AudioServer.set_bus_volume_db(AudioServer.get_bus_index(ui_sound_effects.bus), linear_to_db(volume_between_0_and_1))
func play_sound(resource: AudioStream, override_bus: String = "") -> AudioStreamPlayer:
return sound_effects.play(resource, override_bus)
func play_sound_with_pitch(resource: AudioStream, pitch: float = 1.0, override_bus: String = "") -> AudioStreamPlayer:
var player = sound_effects.play(resource, override_bus)
player.pitch_scale = pitch
return player
func play_ui_sound(resource: AudioStream, override_bus: String = "") -> AudioStreamPlayer:
return ui_sound_effects.play(resource, override_bus)
func play_ui_sound_with_pitch(resource: AudioStream, pitch: float = 1.0, override_bus: String = "") -> AudioStreamPlayer:
var player = ui_sound_effects.play(resource, override_bus)
player.pitch_scale = pitch
return player
func set_default_sound_bus(bus: String) -> void:
sound_effects.bus = bus
func set_default_ui_sound_bus(bus: String) -> void:
ui_sound_effects.bus = bus
func get_music_volume() -> float:
return db_to_linear(AudioServer.get_bus_volume_db(AudioServer.get_bus_index(music.bus)))
func set_music_volume(volume_between_0_and_1: float) -> void:
_show_shared_bus_warning()
AudioServer.set_bus_volume_db(AudioServer.get_bus_index(music.bus), linear_to_db(volume_between_0_and_1))
func play_music(resource: AudioStream, crossfade_duration: float = 0.0, override_bus: String = "") -> AudioStreamPlayer:
return music.play(resource, 0.0, 0.0, crossfade_duration, override_bus)
func play_music_from_position(resource: AudioStream, position: float = 0.0, crossfade_duration: float = 0.0, override_bus: String = "") -> AudioStreamPlayer:
return music.play(resource, position, 0.0, crossfade_duration, override_bus)
func play_music_at_volume(resource: AudioStream, volume: float = 0.0, crossfade_duration: float = 0.0, override_bus: String = "") -> AudioStreamPlayer:
return music.play(resource, 0.0, volume, crossfade_duration, override_bus)
func play_music_from_position_at_volume(resource: AudioStream, position: float = 0.0, volume: float = 0.0, crossfade_duration: float = 0.0, override_bus: String = "") -> AudioStreamPlayer:
return music.play(resource, position, volume, crossfade_duration, override_bus)
func get_music_track_history() -> Array:
return music.track_history
func get_last_played_music_track() -> String:
return music.track_history[0]
func is_music_playing(resource: AudioStream = null) -> bool:
return music.is_playing(resource)
func is_music_track_playing(resource_path: String) -> bool:
return music.is_track_playing(resource_path)
func get_currently_playing_music() -> Array:
return music.get_currently_playing()
func get_currently_playing_music_tracks() -> Array:
return music.get_current_tracks()
func pause_music(resource: AudioStream = null) -> void:
music.pause(resource)
func resume_music(resource: AudioStream = null) -> void:
music.resume(resource)
func stop_music(fade_out_duration: float = 0.0) -> void:
music.stop(fade_out_duration)
func set_default_music_bus(bus: String) -> void:
music.bus = bus
### Helpers
func _show_shared_bus_warning() -> void:
if music.bus == sound_effects.bus or music.bus == ui_sound_effects.bus:
push_warning("Both music and sounds are using the same bus: %s" % music.bus)