aboutsummaryrefslogtreecommitdiff
path: root/game
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2023-02-26 17:12:07 +0100
committer GitHub <noreply@github.com>2023-02-26 17:12:07 +0100
commit93c6b207c11fdaba484410eb53fc11b35fbbb3bd (patch)
tree911753c663adb3955ab15cc8b5ac37498c2fda6e /game
parenta37c5085c3b7ee515789d681c8c18d71071fb771 (diff)
Add Setting Sanatization (#21)
Diffstat (limited to 'game')
-rw-r--r--game/src/Autoload/Events/Options.gd7
-rw-r--r--game/src/Autoload/Resolution.gd101
-rw-r--r--game/src/LocaleButton.gd44
-rw-r--r--game/src/OptionMenu/MonitorDisplaySelector.gd18
-rw-r--r--game/src/OptionMenu/OptionsMenu.gd16
-rw-r--r--game/src/OptionMenu/ResolutionSelector.gd69
-rw-r--r--game/src/OptionMenu/ScreenModeSelector.gd12
-rw-r--r--game/src/OptionMenu/SettingNodes/SettingHSlider.gd13
-rw-r--r--game/src/OptionMenu/SettingNodes/SettingOptionButton.gd40
-rw-r--r--game/src/OptionMenu/VideoTab.tscn1
-rw-r--r--game/src/OptionMenu/VolumeGrid.gd20
11 files changed, 215 insertions, 126 deletions
diff --git a/game/src/Autoload/Events/Options.gd b/game/src/Autoload/Events/Options.gd
index 0acaa63..8af620d 100644
--- a/game/src/Autoload/Events/Options.gd
+++ b/game/src/Autoload/Events/Options.gd
@@ -7,14 +7,17 @@ signal reset_settings()
func load_settings_from_file() -> void:
load_settings.emit(_settings_file)
-func save_settings_from_file() -> void:
+func save_settings_to_file() -> void:
save_settings.emit(_settings_file)
_settings_file.save(_settings_file_path)
func try_reset_settings() -> void:
reset_settings.emit()
-var _settings_file_path := ProjectSettings.get_setting("openvic2/settings/settings_file_path", "user://settings.cfg") as String
+const settings_file_path_setting : String = "openvic2/settings/settings_file_path"
+const settings_file_path_default : String = "user://settings.cfg"
+
+var _settings_file_path : String = ProjectSettings.get_setting(settings_file_path_setting, settings_file_path_default)
var _settings_file := ConfigFile.new()
func _init():
diff --git a/game/src/Autoload/Resolution.gd b/game/src/Autoload/Resolution.gd
index ac54c0d..e1e788b 100644
--- a/game/src/Autoload/Resolution.gd
+++ b/game/src/Autoload/Resolution.gd
@@ -1,36 +1,72 @@
extends Node
-var _resolutions : Array[Dictionary]= [
- { "name": &"", "value": Vector2i(3840,2160) },
- { "name": &"", "value": Vector2i(2560,1080) },
- { "name": &"", "value": Vector2i(1920,1080) },
- { "name": &"", "value": Vector2i(1366,768) },
- { "name": &"", "value": Vector2i(1536,864) },
- { "name": &"", "value": Vector2i(1280,720) },
- { "name": &"", "value": Vector2i(1440,900) },
- { "name": &"", "value": Vector2i(1600,900) },
- { "name": &"", "value": Vector2i(1024,600) },
- { "name": &"", "value": Vector2i(800,600) }
-]
+const error_resolution : Vector2i = Vector2i(-1,-1)
+
+@export
+var minimum_resolution : Vector2i = Vector2i(1,1)
+
+const _starting_resolutions : Dictionary = {
+ Vector2i(3840,2160): &"4K",
+ Vector2i(2560,1080): &"UW1080p",
+ Vector2i(1920,1080): &"1080p",
+ Vector2i(1366,768): &"",
+ Vector2i(1536,864): &"",
+ Vector2i(1280,720): &"720p",
+ Vector2i(1440,900): &"",
+ Vector2i(1600,900): &"",
+ Vector2i(1024,600): &"",
+ Vector2i(800,600): &""
+}
+
+var _resolutions : Dictionary
+
+const _regex_pattern : String = "(\\d+)\\s*[xX,]\\s*(\\d+)"
+var _regex : RegEx
func _ready():
- for resolution in _resolutions:
- resolution["tag"] = _get_name_of_resolution(resolution["name"], resolution["value"])
+ assert(minimum_resolution.x > 0 and minimum_resolution.y > 0, "Minimum resolution must be positive!")
+ for resolution_value in _starting_resolutions:
+ add_resolution(resolution_value, _starting_resolutions[resolution_value])
+ assert(not _resolutions.is_empty(), "No valid starting resolutions!")
+
+ _regex = RegEx.new()
+ var err := _regex.compile(_regex_pattern)
+ assert(err == OK, "Resolution RegEx failed to compile!")
-func has_resolution(resolution_name : StringName) -> bool:
- return resolution_name in _resolutions
-func get_resolution(resolution_name : StringName, default : Vector2i = Vector2i(1920, 1080)) -> Vector2i:
- var resolution := _get_resolution_by_name(resolution_name)
- if resolution.x < 0 and resolution.y < 0:
- return default
- return resolution
+func has_resolution(resolution_value : Vector2i) -> bool:
+ return resolution_value in _resolutions
-func get_resolution_name_list() -> Array[StringName]:
- var result : Array[StringName] = []
- for resolution in _resolutions:
- result.append(resolution["tag"])
- return result
+func add_resolution(resolution_value : Vector2i, resolution_name : StringName = &"") -> bool:
+ if has_resolution(resolution_value): return true
+ var res_dict := { value = resolution_value }
+ var display_name := "%sx%s" % [resolution_value.x, resolution_value.y]
+ if not resolution_name.is_empty():
+ res_dict.name = resolution_name
+ display_name = "%s (%s)" % [display_name, resolution_name]
+ res_dict.display_name = StringName(display_name)
+ if resolution_value.x < minimum_resolution.x or resolution_value.y < minimum_resolution.y:
+ push_error("Resolution %s is smaller than minimum (%sx%s)" % [res_dict.display_name, minimum_resolution.x, minimum_resolution.y])
+ return false
+ _resolutions[resolution_value] = res_dict
+ return true
+
+func get_resolution_value_list() -> Array:
+ var list := _resolutions.keys()
+ list.sort_custom(func(a, b): return a > b)
+ return list
+
+func get_resolution_display_name(resolution_value : Vector2i) -> StringName:
+ return _resolutions.get(resolution_value, { display_name = &"unknown resolution" }).display_name
+
+func get_resolution_value_from_string(resolution_string : String) -> Vector2i:
+ if not resolution_string.is_empty():
+ for resolution in _resolutions.values():
+ if resolution_string == resolution.get(name) or resolution_string == resolution.display_name:
+ return resolution.value
+ var result := _regex.search(resolution_string)
+ if result: return Vector2i(result.get_string(1).to_int(), result.get_string(2).to_int())
+ return error_resolution
func get_current_resolution() -> Vector2i:
var window := get_viewport().get_window()
@@ -41,6 +77,8 @@ func get_current_resolution() -> Vector2i:
return window.size
func set_resolution(resolution : Vector2i) -> void:
+ if not has_resolution(resolution):
+ push_warning("Setting resolution to non-standard value %sx%s" % [resolution.x, resolution.y])
var window := get_viewport().get_window()
match window.mode:
Window.MODE_EXCLUSIVE_FULLSCREEN, Window.MODE_FULLSCREEN:
@@ -51,14 +89,3 @@ func set_resolution(resolution : Vector2i) -> void:
func reset_resolution() -> void:
set_resolution(get_current_resolution())
-
-func _get_name_of_resolution(resolution_name : StringName, resolution_value : Vector2i) -> StringName:
- if resolution_name != null and not resolution_name.is_empty():
- return "%s (%sx%s)" % [resolution_name, resolution_value.x, resolution_value.y]
- return "%sx%s" % [resolution_value.x, resolution_value.y]
-
-func _get_resolution_by_name(resolution_name : StringName) -> Vector2i:
- for resolution in _resolutions:
- if resolution["name"] == resolution_name or resolution["tag"] == resolution_name:
- return resolution["value"]
- return Vector2i(-1, -1)
diff --git a/game/src/LocaleButton.gd b/game/src/LocaleButton.gd
index 32807d0..9f499b8 100644
--- a/game/src/LocaleButton.gd
+++ b/game/src/LocaleButton.gd
@@ -1,5 +1,8 @@
extends OptionButton
+const section_name : String = "Localization"
+const setting_name : String = "Locale"
+
var _locales_country_rename : Dictionary
var _locales_list : Array[String]
@@ -21,15 +24,32 @@ func _ready():
Events.Options.load_settings.connect(load_setting)
Events.Options.save_settings.connect(save_setting)
-
-func load_setting(file : ConfigFile):
- var locale_index := _locales_list.find(file.get_value("Localization", "Locale", "") as String)
- if locale_index != -1:
- selected = locale_index
-
-func save_setting(file : ConfigFile):
- file.set_value("Localization", "Locale", _locales_list[selected])
-
-func _on_item_selected(index):
- TranslationServer.set_locale(_locales_list[index])
- Events.Options.save_settings_from_file.call_deferred()
+func _valid_index(index : int) -> bool:
+ return 0 <= index and index < _locales_list.size()
+
+func load_setting(file : ConfigFile) -> void:
+ if file == null: return
+ var load_value = file.get_value(section_name, setting_name, TranslationServer.get_locale())
+ match typeof(load_value):
+ TYPE_STRING, TYPE_STRING_NAME:
+ var locale_index := _locales_list.find(load_value as String)
+ if locale_index != -1:
+ selected = locale_index
+ return
+ push_error("Setting value '%s' invalid for setting [%s] %s" % [load_value, section_name, setting_name])
+ reset_setting()
+
+func save_setting(file : ConfigFile) -> void:
+ if file == null: return
+ file.set_value(section_name, setting_name, _locales_list[selected])
+
+func reset_setting() -> void:
+ selected = _locales_list.find(TranslationServer.get_locale())
+
+func _on_item_selected(index : int) -> void:
+ if _valid_index(index):
+ TranslationServer.set_locale(_locales_list[index])
+ Events.Options.save_settings_to_file.call_deferred()
+ else:
+ push_error("Invalid LocaleButton index: %d" % index)
+ reset_setting()
diff --git a/game/src/OptionMenu/MonitorDisplaySelector.gd b/game/src/OptionMenu/MonitorDisplaySelector.gd
index f2f0dc8..b665658 100644
--- a/game/src/OptionMenu/MonitorDisplaySelector.gd
+++ b/game/src/OptionMenu/MonitorDisplaySelector.gd
@@ -2,13 +2,17 @@ extends SettingOptionButton
func _setup_button():
clear()
- for screen_index in range(DisplayServer.get_screen_count()):
+ for screen_index in DisplayServer.get_screen_count():
add_item("Monitor %d" % (screen_index + 1))
default_selected = get_viewport().get_window().current_screen
-func _on_item_selected(index):
- var window := get_viewport().get_window()
- var mode := window.mode
- window.mode = Window.MODE_WINDOWED
- get_viewport().get_window().set_current_screen(index)
- window.mode = mode
+func _on_item_selected(index : int):
+ if _valid_index(index):
+ var window := get_viewport().get_window()
+ var mode := window.mode
+ window.mode = Window.MODE_WINDOWED
+ get_viewport().get_window().set_current_screen(index)
+ window.mode = mode
+ else:
+ push_error("Invalid MonitorDisplaySelector index: %d" % index)
+ reset_setting()
diff --git a/game/src/OptionMenu/OptionsMenu.gd b/game/src/OptionMenu/OptionsMenu.gd
index 5aba7f2..c25c3b8 100644
--- a/game/src/OptionMenu/OptionsMenu.gd
+++ b/game/src/OptionMenu/OptionsMenu.gd
@@ -38,21 +38,23 @@ func toggle_locale_button_visibility(locale_visible : bool):
$LocaleVBox/LocaleHBox/LocaleButton.visible = locale_visible
func _on_back_button_pressed():
- Events.Options.save_settings_from_file()
+ Events.Options.save_settings_to_file()
back_button_pressed.emit()
func _on_window_close_requested() -> void:
if visible:
- Events.Options.save_settings_from_file()
+ Events.Options.save_settings_to_file()
func _save_overrides() -> void:
- var override_path := ProjectSettings.get_setting("application/config/project_settings_override") as String
- if override_path == null or override_path.is_empty():
- override_path = ProjectSettings.get_setting("openvic2/settings/settings_file_path") as String
+ var override_path : String = ProjectSettings.get_setting("application/config/project_settings_override", "")
+ if override_path.is_empty():
+ override_path = ProjectSettings.get_setting(Events.Options.settings_file_path_setting, Events.Options.settings_file_path_default)
var file := ConfigFile.new()
- file.load(override_path)
+ var err_ret := file.load(override_path)
+ if err_ret != OK: push_error("Failed to load overrides from %s" % override_path)
file.set_value("display", "window/size/mode", get_viewport().get_window().mode)
var resolution : Vector2i = Resolution.get_current_resolution()
file.set_value("display", "window/size/viewport_width", resolution.x)
file.set_value("display", "window/size/viewport_height", resolution.y)
- file.save(override_path)
+ err_ret = file.save(override_path)
+ if err_ret != OK: push_error("Failed to save overrides to %s" % override_path)
diff --git a/game/src/OptionMenu/ResolutionSelector.gd b/game/src/OptionMenu/ResolutionSelector.gd
index e602bab..6cdaca8 100644
--- a/game/src/OptionMenu/ResolutionSelector.gd
+++ b/game/src/OptionMenu/ResolutionSelector.gd
@@ -1,58 +1,65 @@
extends SettingOptionButton
@export
-var default_value : Vector2i = Vector2i(-1, -1)
+var default_value : Vector2i = Resolution.error_resolution
-func add_resolution(value : Vector2i, selection_name : String = "") -> void:
- if selection_name.is_empty():
- selection_name = "%sx%s" % [value.x, value.y]
- add_item(selection_name)
- set_item_metadata(item_count - 1, value)
-
-func find_resolution_value(value : Vector2i) -> int:
- for item_index in range(item_count):
+func _find_resolution_index_by_value(value : Vector2i) -> int:
+ for item_index in item_count:
if get_item_metadata(item_index) == value:
return item_index
return -1
-func _setup_button():
- if default_value.x < 0:
- default_value.x = ProjectSettings.get_setting("display/window/size/viewport_width")
-
- if default_value.y < 0:
- default_value.y = ProjectSettings.get_setting("display/window/size/viewport_height")
-
+func _sync_resolutions(to_select : Vector2i = Resolution.get_current_resolution()) -> void:
clear()
default_selected = -1
selected = -1
- for resolution in Resolution.get_resolution_name_list():
- var resolution_value := Resolution.get_resolution(resolution)
- add_resolution(resolution_value, resolution)
+ for resolution_value in Resolution.get_resolution_value_list():
+ add_item(Resolution.get_resolution_display_name(resolution_value))
+ set_item_metadata(item_count - 1, resolution_value)
if resolution_value == default_value:
default_selected = item_count - 1
- if resolution_value == Resolution.get_current_resolution():
+ if resolution_value == to_select:
selected = item_count - 1
if default_selected == -1:
- add_resolution(default_value)
default_selected = item_count - 1
if selected == -1:
selected = default_selected
+func _setup_button():
+ if default_value.x <= 0:
+ default_value.x = ProjectSettings.get_setting("display/window/size/viewport_width")
+ if default_value.y <= 0:
+ default_value.y = ProjectSettings.get_setting("display/window/size/viewport_height")
+ Resolution.add_resolution(default_value, &"default")
+ _sync_resolutions()
+
func _get_value_for_file(select_value : int):
- return get_item_metadata(select_value)
+ if _valid_index(select_value):
+ return get_item_metadata(select_value)
+ else:
+ return null
func _set_value_from_file(load_value):
- var resolution_value := load_value as Vector2i
- selected = find_resolution_value(resolution_value)
- if selected == -1:
- if add_nonstandard_value:
- add_resolution(resolution_value)
- selected = item_count - 1
- else: push_error("Setting value '%s' invalid for setting [%s] %s" % [load_value, section_name, setting_name])
+ var target_resolution := Resolution.error_resolution
+ match typeof(load_value):
+ TYPE_VECTOR2I: target_resolution = load_value
+ TYPE_STRING, TYPE_STRING_NAME: target_resolution = Resolution.get_resolution_value_from_string(load_value)
+ if target_resolution != Resolution.error_resolution:
+ selected = _find_resolution_index_by_value(target_resolution)
+ if selected != -1: return
+ if Resolution.add_resolution(target_resolution):
+ _sync_resolutions(target_resolution)
+ return
+ push_error("Setting value '%s' invalid for setting [%s] %s" % [load_value, section_name, setting_name])
+ selected = default_selected
-func _on_item_selected(index):
- Resolution.set_resolution(get_item_metadata(index))
+func _on_item_selected(index : int):
+ if _valid_index(index):
+ Resolution.set_resolution(get_item_metadata(index))
+ else:
+ push_error("Invalid ResolutionSelector index: %d" % index)
+ reset_setting()
diff --git a/game/src/OptionMenu/ScreenModeSelector.gd b/game/src/OptionMenu/ScreenModeSelector.gd
index 92c5d60..b4fc5ab 100644
--- a/game/src/OptionMenu/ScreenModeSelector.gd
+++ b/game/src/OptionMenu/ScreenModeSelector.gd
@@ -29,7 +29,11 @@ func _setup_button():
selected = default_selected
func _on_item_selected(index : int):
- var window := get_viewport().get_window()
- var current_resolution := Resolution.get_current_resolution()
- window.mode = get_window_mode_from_screen_mode(index)
- Resolution.set_resolution(current_resolution)
+ if _valid_index(index):
+ var window := get_viewport().get_window()
+ var current_resolution := Resolution.get_current_resolution()
+ window.mode = get_window_mode_from_screen_mode(index)
+ Resolution.set_resolution(current_resolution)
+ else:
+ push_error("Invalid ScreenModeSelector index: %d" % index)
+ reset_setting()
diff --git a/game/src/OptionMenu/SettingNodes/SettingHSlider.gd b/game/src/OptionMenu/SettingNodes/SettingHSlider.gd
index cf2adf4..6a0e5ed 100644
--- a/game/src/OptionMenu/SettingNodes/SettingHSlider.gd
+++ b/game/src/OptionMenu/SettingNodes/SettingHSlider.gd
@@ -17,7 +17,18 @@ func _ready():
func load_setting(file : ConfigFile):
if file == null: return
- value = file.get_value(section_name, setting_name, default_value)
+ var load_value = file.get_value(section_name, setting_name, default_value)
+ match typeof(load_value):
+ TYPE_FLOAT, TYPE_INT:
+ value = load_value
+ return
+ TYPE_STRING, TYPE_STRING_NAME:
+ var load_string := load_value as String
+ if load_string.is_valid_float():
+ value = load_string.to_float()
+ return
+ push_error("Setting value '%s' invalid for setting [%s] \"%s\"" % [load_value, section_name, setting_name])
+ value = default_value
func save_setting(file : ConfigFile):
if file == null: return
diff --git a/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd b/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd
index 3a5c979..c7b760d 100644
--- a/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd
+++ b/game/src/OptionMenu/SettingNodes/SettingOptionButton.gd
@@ -11,30 +11,39 @@ var setting_name : String = "SettingOptionMenu"
var default_selected : int = -1:
get: return default_selected
set(v):
- if v == -1:
+ if v < 0 or item_count == 0:
default_selected = -1
return
default_selected = v % item_count
-@export
-var add_nonstandard_value := false
+func _valid_index(index : int) -> bool:
+ return 0 <= index and index < item_count
func _get_value_for_file(select_value : int):
- if select_value > -1:
- return get_item_text(select_value)
+ if _valid_index(select_value):
+ return select_value
else:
return null
func _set_value_from_file(load_value) -> void:
- selected = -1
- for item_index in range(item_count):
- if load_value == get_item_text(item_index):
- selected = item_index
- if selected == -1:
- if add_nonstandard_value:
- add_item(load_value)
- selected = item_count - 1
- else: push_error("Setting value '%s' invalid for setting [%s] \"%s\"" % [load_value, section_name, setting_name])
+ match typeof(load_value):
+ TYPE_INT:
+ if _valid_index(load_value):
+ selected = load_value
+ return
+ TYPE_STRING, TYPE_STRING_NAME:
+ var load_string := load_value as String
+ if load_string.is_valid_int():
+ var load_int := load_string.to_int()
+ if _valid_index(load_int):
+ selected = load_int
+ return
+ for item_index in item_count:
+ if load_string == get_item_text(item_index):
+ selected = item_index
+ return
+ push_error("Setting value '%s' invalid for setting [%s] \"%s\"" % [load_value, section_name, setting_name])
+ selected = default_selected
func _setup_button() -> void:
pass
@@ -44,6 +53,9 @@ func _ready():
Events.Options.save_settings.connect(save_setting)
Events.Options.reset_settings.connect(reset_setting)
_setup_button()
+ if not _valid_index(default_selected) or selected == -1:
+ OS.alert("Failed to generate %s %s options." % [setting_name, section_name], "%s Options Error" % section_name)
+ get_tree().quit()
func load_setting(file : ConfigFile) -> void:
if file == null: return
diff --git a/game/src/OptionMenu/VideoTab.tscn b/game/src/OptionMenu/VideoTab.tscn
index d46f056..f14f757 100644
--- a/game/src/OptionMenu/VideoTab.tscn
+++ b/game/src/OptionMenu/VideoTab.tscn
@@ -34,7 +34,6 @@ popup/item_0/id = 0
script = ExtResource("1_i8nro")
section_name = "Video"
setting_name = "Resolution"
-add_nonstandard_value = true
[node name="ScreenModeLabel" type="Label" parent="VBoxContainer/GridContainer"]
layout_mode = 2
diff --git a/game/src/OptionMenu/VolumeGrid.gd b/game/src/OptionMenu/VolumeGrid.gd
index fae5ff6..8d5a016 100644
--- a/game/src/OptionMenu/VolumeGrid.gd
+++ b/game/src/OptionMenu/VolumeGrid.gd
@@ -1,8 +1,8 @@
extends GridContainer
-const RATIO_FOR_LINEAR = 100
+const RATIO_FOR_LINEAR : float = 100
-var _slider_dictionary := {}
+var _slider_dictionary : Dictionary
func get_db_as_volume_value(db : float) -> float:
# db_to_linear produces a float between 0 and 1 from a db value
@@ -12,7 +12,7 @@ func get_volume_value_as_db(value : float) -> float:
# linear_to_db consumes a float between 0 and 1 to produce the db value
return linear_to_db(value / RATIO_FOR_LINEAR)
-func add_volume_column(bus_name : StringName, bus_index : int) -> HSlider:
+func add_volume_row(bus_name : StringName, bus_index : int) -> HSlider:
var volume_label := Label.new()
volume_label.text = bus_name + " Volume"
add_child(volume_label)
@@ -33,22 +33,22 @@ func add_volume_column(bus_name : StringName, bus_index : int) -> HSlider:
func _ready():
for bus_index in AudioServer.bus_count:
- add_volume_column(AudioServer.get_bus_name(bus_index), bus_index)
+ add_volume_row(AudioServer.get_bus_name(bus_index), bus_index)
func _on_slider_value_changed(value : float, bus_index : int) -> void:
AudioServer.set_bus_volume_db(bus_index, get_volume_value_as_db(value))
func _on_options_menu_load_settings(load_file : ConfigFile):
- for volume_label_text in _slider_dictionary:
- _slider_dictionary[volume_label_text].load_setting(load_file)
+ for volume_slider in _slider_dictionary.values():
+ volume_slider.load_setting(load_file)
func _on_options_menu_save_settings(save_file : ConfigFile):
- for volume_label_text in _slider_dictionary:
- _slider_dictionary[volume_label_text].save_setting(save_file)
+ for volume_slider in _slider_dictionary.values():
+ volume_slider.save_setting(save_file)
func _on_options_menu_reset_settings():
- for volume_label_text in _slider_dictionary:
- _slider_dictionary[volume_label_text].reset_setting()
+ for volume_slider in _slider_dictionary.values():
+ volume_slider.reset_setting()