Unified settings management and sound fixes

- fix: speech was not paused during pause menu
- fix: allow sound levels to reach min value 0.0 (=muted)
- fix: crash was happening when switch language during the game
This commit is contained in:
Julian Murgia
2022-08-11 22:59:21 +02:00
committed by Duncan Brown
parent 4ef86c6cc3
commit 04348147b9
18 changed files with 286 additions and 95 deletions

View File

@@ -564,6 +564,8 @@ func perform_inputevent_on_object(
# Manage exits
if obj.node.is_exit and current_action in ["", ACTION_WALK]:
escoria.event_manager.interrupt_running_event()
escoria.event_manager.clear_event_queue()
_activate(ACTION_EXIT_SCENE, obj)
else:
# Manage movements towards object before activating it

View File

@@ -89,7 +89,7 @@ func _exit_tree():
# Ready function
func _ready():
escoria.apply_settings(escoria.settings)
escoria.settings_manager.apply_settings()
connect("crash_popup_confirmed", escoria, "quit",
[], CONNECT_ONESHOT)

View File

@@ -42,7 +42,7 @@ export var speech_volume: float = ProjectSettings.get_setting(
export var fullscreen: bool = false
# True if skipping dialogs is allowed
export var skip_dialog: bool = true
export var skip_dialogs: bool = true
# Dictionary containing all user-defined settings.
export var custom_settings: Dictionary

View File

@@ -0,0 +1,181 @@
# Manages settings
class_name ESCSettingsManager
# Template for settings filename
const SETTINGS_TEMPLATE: String = "settings.tres"
# Variable containing the settings folder obtained from Project Settings
var settings_folder: String
# Dictionary containing specific settings that gamedev wants to save in settings
# This variable is access-free. Getting its content is gamedev's duty.
# It is saved with other Escoria settings data when save_settings() is called.
var custom_settings: Dictionary
# Constructor of ESCSaveManager object.
func _init():
# We leave the calls to ProjectSettings as-is since this constructor can be
# called from escoria.gd's own.
settings_folder = ProjectSettings.get_setting("escoria/main/settings_path")
# Apply the loaded settings
func apply_settings() -> void:
if not Engine.is_editor_hint():
escoria.logger.info(
self,
"******* settings loaded"
)
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(escoria.BUS_MASTER),
linear2db(
ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.MASTER_VOLUME
)
)
)
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(escoria.BUS_SFX),
linear2db(
ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.SFX_VOLUME
)
)
)
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(escoria.BUS_MUSIC),
linear2db(
ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.MUSIC_VOLUME
)
)
)
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(escoria.BUS_SPEECH),
linear2db(
ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.SPEECH_VOLUME
)
)
)
TranslationServer.set_locale(
ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.TEXT_LANG
)
)
escoria.game_scene.apply_custom_settings(custom_settings)
func save_settings_resource_to_project_settings(settings: ESCSaveSettings):
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.TEXT_LANG,
settings.text_lang
)
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.VOICE_LANG,
settings.voice_lang
)
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.SPEECH_ENABLED,
settings.speech_enabled
)
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.MASTER_VOLUME,
settings.master_volume
)
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.MUSIC_VOLUME,
settings.music_volume
)
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.SFX_VOLUME,
settings.sfx_volume
)
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.SPEECH_VOLUME,
settings.speech_volume
)
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.FULLSCREEN,
settings.fullscreen
)
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.SKIP_DIALOGS,
settings.skip_dialogs
)
custom_settings = settings.custom_settings
# Load the game settings from the settings file
func load_settings():
var save_settings_path: String = \
settings_folder.plus_file(SETTINGS_TEMPLATE)
var file: File = File.new()
if not file.file_exists(save_settings_path):
escoria.logger.warn(
self,
"Settings file %s doesn't exist" % save_settings_path
+ "Setting default settings."
)
save_settings()
var settings: ESCSaveSettings = load(save_settings_path)
save_settings_resource_to_project_settings(settings)
func get_settings() -> ESCSaveSettings:
var settings: ESCSaveSettings = ESCSaveSettings.new()
var plugin_config = ConfigFile.new()
plugin_config.load("res://addons/escoria-core/plugin.cfg")
settings.escoria_version = plugin_config.get_value("plugin", "version")
settings.text_lang = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.TEXT_LANG
)
settings.voice_lang = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.VOICE_LANG
)
settings.speech_enabled = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.SPEECH_ENABLED
)
settings.master_volume = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.MASTER_VOLUME
)
settings.music_volume = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.MUSIC_VOLUME
)
settings.sfx_volume = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.SFX_VOLUME
)
settings.speech_volume = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.SPEECH_VOLUME
)
settings.fullscreen = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.FULLSCREEN
)
settings.skip_dialogs = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.SKIP_DIALOGS
)
settings.custom_settings = custom_settings
return settings
# Save the game settings in the settings file.
func save_settings():
var settings = get_settings()
var directory: Directory = Directory.new()
if not directory.dir_exists(settings_folder):
directory.make_dir_recursive(settings_folder)
var save_path = settings_folder.plus_file(SETTINGS_TEMPLATE)
var error: int = ResourceSaver.save(save_path, settings)
if error != OK:
escoria.logger.error(
self,
"There was an issue writing settings %s" % save_path
)

View File

@@ -66,6 +66,9 @@ var globals_manager: ESCGlobalsManager
# ESC command registry instance
var command_registry: ESCCommandRegistry
# Manager of game settings (resolution, sound, etc)
var settings_manager: ESCSettingsManager
# Resource cache handler
var resource_cache: ESCResourceCache
@@ -75,9 +78,6 @@ var dialog_player: ESCDialogPlayer
# Inventory scene
var inventory
# These are settings that the player can affect and save/load later
var settings: ESCSaveSettings
# The main scene
var main
@@ -149,40 +149,6 @@ func set_game_paused(p_paused: bool):
scene_tree.paused = p_paused
# Apply the loaded settings
#
# #### Parameters
#
# * p_settings: Loaded settings
func apply_settings(p_settings: ESCSaveSettings) -> void:
if not Engine.is_editor_hint():
escoria.logger.info(self, "******* settings loaded")
if p_settings != null:
settings = p_settings
else:
settings = ESCSaveSettings.new()
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(BUS_MASTER),
linear2db(settings.master_volume)
)
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(BUS_SFX),
linear2db(settings.sfx_volume)
)
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(BUS_MUSIC),
linear2db(settings.music_volume)
)
AudioServer.set_bus_volume_db(
AudioServer.get_bus_index(BUS_SPEECH),
linear2db(settings.speech_volume)
)
TranslationServer.set_locale(settings.text_lang)
game_scene.apply_custom_settings(settings.custom_settings)
# Called from main menu's "new game" button
func new_game():
get_escoria().new_game()

View File

@@ -16,6 +16,7 @@ const GAME_SCENE = "%s/%s/game_scene" % [_ESCORIA_SETTINGS_ROOT, _UI_ROOT]
const INVENTORY_ITEM_SIZE = "%s/%s/inventory_item_size" % [_ESCORIA_SETTINGS_ROOT, _UI_ROOT]
const INVENTORY_ITEMS_PATH = "%s/%s/inventory_items_path" % [_ESCORIA_SETTINGS_ROOT, _UI_ROOT]
const TRANSITION_PATHS = "%s/%s/transition_paths" % [_ESCORIA_SETTINGS_ROOT, _UI_ROOT]
const SKIP_DIALOGS = "%s/%s/skip_dialogs" % [_ESCORIA_SETTINGS_ROOT, _UI_ROOT]
# Main Escoria project settings
const _MAIN_ROOT = "main"
@@ -67,6 +68,12 @@ const TEXT_SPEED_PER_CHARACTER = "%s/%s/text_speed_per_character" % [_ESCORIA_SE
const FAST_TEXT_SPEED_PER_CHARACTER = "%s/%s/fast_text_speed_per_character" % [_ESCORIA_SETTINGS_ROOT, _SIMPLE_DIALOG_ROOT]
const MAX_TIME_TO_DISAPPEAR = "%s/%s/max_time_to_disappear" % [_ESCORIA_SETTINGS_ROOT, _SIMPLE_DIALOG_ROOT]
# Godot Windows project settings
const DISPLAY = "display"
const WINDOW = "window"
const SIZE = "size"
const FULLSCREEN = "%s/%s/%s/fullscreen" % [DISPLAY, WINDOW, SIZE]
# Register a new project setting if it hasn't been defined already
#

View File

@@ -28,7 +28,7 @@ func _init():
escoria.resource_cache.start()
escoria.save_manager = ESCSaveManager.new()
escoria.inputs_manager = ESCInputsManager.new()
escoria.settings = ESCSaveSettings.new()
escoria.settings_manager = ESCSettingsManager.new()
if ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.GAME_SCENE
@@ -47,8 +47,9 @@ func _init():
func _ready():
_handle_direct_scene_run()
escoria.settings = escoria.save_manager.load_settings()
escoria.apply_settings(escoria.settings)
escoria.settings_manager.load_settings()
escoria.settings_manager.apply_settings()
escoria.room_manager.register_reserved_globals()
escoria.inputs_manager.register_core()
if ESCProjectSettingsManager.get_setting(

View File

@@ -44,10 +44,6 @@ func set_state(p_state: String, p_force: bool = false) -> void:
resource.loop_end = resource.mix_rate * resource.get_length()
elif "loop" in resource:
resource.loop = true
if ESCProjectSettingsManager.has_setting(ESCProjectSettingsManager.MUSIC_VOLUME):
stream.volume_db = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.MUSIC_VOLUME
)
stream.play()

View File

@@ -3,15 +3,13 @@
[ext_resource path="res://addons/escoria-core/game/scenes/sound/esc_music_player.gd" type="Script" id=1]
[node name="bg_music" type="Control"]
pause_mode = 2
anchor_right = 1.0
anchor_bottom = 1.0
margin_right = -1680.0
margin_bottom = -1050.0
mouse_filter = 2
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
bus = "Music"

View File

@@ -43,10 +43,6 @@ func set_state(p_state: String, p_force: bool = false):
resource.loop_mode = AudioStreamSample.LOOP_DISABLED
elif "loop" in resource:
resource.loop = false
if ESCProjectSettingsManager.has_setting(ESCProjectSettingsManager.SFX_VOLUME):
stream.volume_db = ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.SFX_VOLUME
)
stream.play()

View File

@@ -3,6 +3,7 @@
[ext_resource path="res://addons/escoria-core/game/scenes/sound/esc_sound_player.gd" type="Script" id=1]
[node name="bg_sound" type="Control"]
pause_mode = 2
anchor_right = 1.0
anchor_bottom = 1.0
margin_right = -1680.0

View File

@@ -6,6 +6,9 @@ class_name ESCSpeechPlayer
# Global id of the background music player
export var global_id: String = "_speech"
# Reference to the audio player
onready var stream: AudioStreamPlayer = $AudioStreamPlayer
# Set the state of this player
#
@@ -15,20 +18,21 @@ export var global_id: String = "_speech"
# - p_force: Override the existing state even if the stream is still playing
func set_state(p_state: String, p_force: bool = false) -> void:
# If speech is disabled, return
if not escoria.settings.speech_enabled:
if not ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.SPEECH_ENABLED
):
return
# If state is "off"/"default", turn off speech
if p_state in ["off", "default"]:
$AudioStreamPlayer.stream = null
stream.stream = null
return
var resource = load(p_state)
stream.stream = resource
$AudioStreamPlayer.stream = resource
if $AudioStreamPlayer.stream:
resource.set_loop(false)
if stream.stream:
stream.stream.set_loop(false)
$AudioStreamPlayer.play()
@@ -42,5 +46,16 @@ func _ready():
)
# Callback called when the audio stream player finished playing.
func _on_AudioStreamPlayer_finished() -> void:
set_state("off")
# Pause the speech player
func pause():
stream.stream_paused = true
# Unpause the speech player
func resume():
stream.stream_paused = false

View File

@@ -3,6 +3,7 @@
[ext_resource path="res://addons/escoria-core/game/scenes/sound/esc_speech_player.gd" type="Script" id=1]
[node name="Control" type="Control"]
pause_mode = 2
anchor_right = 1.0
anchor_bottom = 1.0
mouse_filter = 2

View File

@@ -6,6 +6,10 @@ extends Control
signal back_button_pressed
# Custom setting key
const CUSTOM_SETTING: String = "a_custom_setting"
# The current settings
var backup_settings
@@ -39,10 +43,11 @@ func _ready() -> void:
_flags_container.add_child(_lang)
_lang.connect("gui_input", self, "_on_language_input", [lang])
# Show the options
func show():
backup_settings = escoria.settings.duplicate()
initialize_options(escoria.settings)
backup_settings = escoria.settings_manager.get_settings()
initialize_options(backup_settings)
visible = true
@@ -66,7 +71,10 @@ func initialize_options(p_settings):
func _on_language_input(event: InputEvent, language: String):
if event.is_pressed():
TranslationServer.set_locale(language)
escoria.settings["text_lang"] = language
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.TEXT_LANG,
language
)
settings_changed = true
@@ -75,9 +83,15 @@ func _on_language_input(event: InputEvent, language: String):
# #### Parameters
# - value: The new volume level
func _on_sound_volume_changed(value):
escoria.settings["sfx_volume"] = value
escoria.apply_settings(escoria.settings)
settings_changed = true
if ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.SFX_VOLUME
) != value:
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.SFX_VOLUME,
value
)
escoria.settings_manager.apply_settings()
settings_changed = true
# Music volume was changed
@@ -85,9 +99,15 @@ func _on_sound_volume_changed(value):
# #### Parameters
# - value: The new volume level
func _on_music_volume_changed(value):
escoria.settings["music_volume"] = value
escoria.apply_settings(escoria.settings)
settings_changed = true
if ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.MUSIC_VOLUME
) != value:
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.MUSIC_VOLUME,
value
)
escoria.settings_manager.apply_settings()
settings_changed = true
# General volume was changed
@@ -95,9 +115,15 @@ func _on_music_volume_changed(value):
# #### Parameters
# - value: The new volume level
func _on_general_volume_changed(value):
escoria.settings["master_volume"] = value
escoria.apply_settings(escoria.settings)
settings_changed = true
if ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.MASTER_VOLUME
) != value:
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.MASTER_VOLUME,
value
)
escoria.settings_manager.apply_settings()
settings_changed = true
# Speech volume was changed
@@ -105,21 +131,27 @@ func _on_general_volume_changed(value):
# #### Parameters
# - value: The new volume level
func _on_speech_volume_value_changed(value: float) -> void:
escoria.settings["speech_volume"] = value
escoria.apply_settings(escoria.settings)
settings_changed = true
if ESCProjectSettingsManager.get_setting(
ESCProjectSettingsManager.SPEECH_VOLUME
) != value:
ESCProjectSettingsManager.set_setting(
ESCProjectSettingsManager.SPEECH_VOLUME,
value
)
escoria.settings_manager.apply_settings()
settings_changed = true
# Save the settings
func _on_apply_pressed():
escoria.settings.custom_settings["a_custom_setting"] = 100
escoria.save_manager.save_settings()
escoria.settings_manager.custom_settings[CUSTOM_SETTING] = 100
escoria.settings_manager.save_settings()
settings_changed = false
emit_signal("back_button_pressed")
# The back button was pressed
func _on_back_pressed():
escoria.settings = backup_settings
escoria.apply_settings(escoria.settings)
escoria.settings_manager.save_settings_resource_to_project_settings(backup_settings)
escoria.settings_manager.apply_settings()
emit_signal("back_button_pressed")

View File

@@ -7,9 +7,6 @@
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource( 4 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Panel" type="Panel" parent="."]
anchor_right = 1.0
@@ -86,10 +83,8 @@ margin_top = 79.0
margin_right = 457.0
margin_bottom = 95.0
size_flags_horizontal = 3
min_value = 0.001
max_value = 1.0
step = 0.001
value = 0.001
[node name="label3" type="Label" parent="VBoxContainer/MarginContainer/options"]
margin_top = 100.0
@@ -103,10 +98,8 @@ margin_top = 99.0
margin_right = 457.0
margin_bottom = 115.0
size_flags_horizontal = 3
min_value = 0.001
max_value = 1.0
step = 0.001
value = 0.001
[node name="label4" type="Label" parent="VBoxContainer/MarginContainer/options"]
margin_top = 120.0
@@ -120,10 +113,8 @@ margin_top = 119.0
margin_right = 457.0
margin_bottom = 135.0
size_flags_horizontal = 3
min_value = 0.001
max_value = 1.0
step = 0.001
value = 0.001
[node name="label5" type="Label" parent="VBoxContainer/MarginContainer/options"]
margin_top = 140.0
@@ -137,10 +128,8 @@ margin_top = 139.0
margin_right = 457.0
margin_bottom = 155.0
size_flags_horizontal = 3
min_value = 0.001
max_value = 1.0
step = 0.001
value = 0.001
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 539.0

View File

@@ -329,7 +329,8 @@ func show_main_menu():
func unpause_game():
if get_node(pause_menu).visible:
get_node(pause_menu).hide()
escoria.object_manager.get_object("_camera").node.current = true
escoria.object_manager.get_object(ESCObjectManager.CAMERA).node.current = true
escoria.object_manager.get_object(ESCObjectManager.SPEECH).node.resume()
escoria.main.current_scene.game.show_ui()
escoria.main.current_scene.show()
escoria.set_game_paused(false)
@@ -339,7 +340,8 @@ func pause_game():
get_node(pause_menu).reset()
get_node(pause_menu).set_save_enabled(escoria.save_manager.save_enabled)
get_node(pause_menu).show()
escoria.object_manager.get_object("_camera").node.current = false
escoria.object_manager.get_object(ESCObjectManager.CAMERA).node.current = false
escoria.object_manager.get_object(ESCObjectManager.SPEECH).node.pause()
escoria.main.current_scene.game.hide_ui()
escoria.main.current_scene.hide()
escoria.set_game_paused(true)

View File

@@ -372,7 +372,8 @@ func show_main_menu():
func unpause_game():
if get_node(pause_menu).visible:
get_node(pause_menu).hide()
escoria.object_manager.get_object("_camera").node.current = true
escoria.object_manager.get_object(ESCObjectManager.CAMERA).node.current = true
escoria.object_manager.get_object(ESCObjectManager.SPEECH).node.resume()
escoria.main.current_scene.game.show_ui()
escoria.main.current_scene.show()
escoria.set_game_paused(false)
@@ -382,7 +383,8 @@ func pause_game():
get_node(pause_menu).reset()
get_node(pause_menu).set_save_enabled(escoria.save_manager.save_enabled)
get_node(pause_menu).show()
escoria.object_manager.get_object("_camera").node.current = false
escoria.object_manager.get_object(ESCObjectManager.CAMERA).node.current = false
escoria.object_manager.get_object(ESCObjectManager.SPEECH).node.pause()
escoria.main.current_scene.game.hide_ui()
escoria.main.current_scene.hide()
escoria.set_game_paused(true)

View File

@@ -312,7 +312,8 @@ func show_main_menu():
func unpause_game():
if get_node(pause_menu).visible:
get_node(pause_menu).hide()
escoria.object_manager.get_object(escoria.object_manager.CAMERA).node.current = true
escoria.object_manager.get_object(ESCObjectManager.CAMERA).node.current = true
escoria.object_manager.get_object(ESCObjectManager.SPEECH).node.resume()
escoria.main.current_scene.game.show_ui()
escoria.main.current_scene.show()
@@ -324,7 +325,8 @@ func pause_game():
escoria.save_manager.save_enabled
)
get_node(pause_menu).show()
escoria.object_manager.get_object(escoria.object_manager.CAMERA).node.current = false
escoria.object_manager.get_object(ESCObjectManager.CAMERA).node.current = false
escoria.object_manager.get_object(ESCObjectManager.SPEECH).node.pause()
escoria.main.current_scene.game.hide_ui()
escoria.main.current_scene.hide()