godot-plateformer/__settings/input/InputSettingModel.gd

122 lines
3.3 KiB
GDScript3
Raw Permalink Normal View History

2026-01-15 17:43:58 +08:00
extends Node
class_name InputSettingsModel
## ===============================
## Dependencies
## ===============================
const InputSchema = preload("res://__settings/input/InputSchema.gd")
const SettingsStorage = preload("res://__settings/SettingStorage.gd")
## ===============================
## Signals
## ===============================
signal binding_changed(action: String)
signal bindings_applied
signal bindings_reverted
## ===============================
## Internal State
## ===============================
var _bindings_committed : Dictionary = {}
var _bindings_working : Dictionary = {}
var _storage := SettingsStorage.new()
const SECTION := "input"
## ===============================
## Lifecycle
## ===============================
func _ready() -> void:
_load()
## ===============================
## Public API (Read)
## ===============================
func get_bindings(action: String) -> Array:
return _bindings_working.get(action, []).duplicate(true)
func get_all_bindings() -> Dictionary:
return _bindings_working.duplicate(true)
## ===============================
## Public API (Write)
## ===============================
func set_bindings(action: String, bindings: Array) -> void:
_bindings_working[action] = bindings
emit_signal("binding_changed", action)
func add_binding(action: String, binding: Dictionary) -> void:
if not _bindings_working.has(action):
_bindings_working[action] = []
_bindings_working[action].append(binding)
emit_signal("binding_changed", action)
func clear_bindings(action: String) -> void:
_bindings_working[action] = []
emit_signal("binding_changed", action)
## ===============================
## Transaction
## ===============================
func apply() -> void:
_bindings_committed = _bindings_working.duplicate(true)
_save_to_storage()
_apply_to_input_map()
emit_signal("bindings_applied")
func revert() -> void:
_bindings_working = _bindings_committed.duplicate(true)
emit_signal("bindings_reverted")
func has_unsaved_changes() -> bool:
return _bindings_working != _bindings_committed
## ===============================
## Internal
## ===============================
func _load() -> void:
_storage.load()
# 1. defaults
_bindings_committed = InputSchema.defaults().duplicate(true)
# 2. override from storage
for action in _bindings_committed.keys():
var saved = _storage.get_value(SECTION, action, null)
if saved != null:
_bindings_committed[action] = saved
_bindings_working = _bindings_committed.duplicate(true)
# 3. apply to engine at startup
_apply_to_input_map()
func _save_to_storage() -> void:
for action in _bindings_committed.keys():
_storage.set_value(SECTION, action, _bindings_committed[action])
_storage.save()
func _apply_to_input_map() -> void:
for action in _bindings_committed.keys():
if not InputMap.has_action(action):
InputMap.add_action(action)
InputMap.action_erase_events(action)
for binding in _bindings_committed[action]:
var event = _binding_to_event(binding)
if event:
InputMap.action_add_event(action, event)
func _binding_to_event(binding: Dictionary) -> InputEvent:
match binding.get("type"):
"key":
var e := InputEventKey.new()
e.keycode = binding.get("keycode", 0)
return e
"mouse":
var e := InputEventMouseButton.new()
e.button_index = binding.get("button", 0)
return e
return null