# A slightly redundant proxy to ProjectSettings # This is mostly used so that signals can be used to respond to settings changes extends Node signal config_loaded signal subsampling_changed(xy) # Newer Android versions require storage access permissions to be requested at runtime. # There is no way around this, so this code needs to be updated to work. var android_permissions_granted := false const REQUIRED_ANDROID_PERMISSIONS := PoolStringArray(['MANAGE_EXTERNAL_FILES', 'READ_EXTERNAL_FILES', 'WRITE_EXTERNAL_FILES']) func check_android_permissions() -> bool: if self.android_permissions_granted: return true var permissions_granted := OS.get_granted_permissions() for perm in REQUIRED_ANDROID_PERMISSIONS: if not (perm in permissions_granted): return false self.android_permissions_granted = true return true func update_android_permissions() -> void: if not OS.has_feature('Android'): return if self.check_android_permissions(): return OS.request_permissions() func _on_request_permissions_result(permission: String, granted: bool) -> void: print('_on_request_permissions_result: %s = %s' % [permission, granted]) # if granted and (permission in REQUIRED_ANDROID_PERMISSIONS): # self.call_deferred('update_view') const ANDROID_USERDIR := '/storage/emulated/0/RhythmGame/' # The following would probably work. One huge caveat is that permission needs to be manually granted by the user in app settings as we can't use OS.request_permission('WRITE_EXTERNAL_STORAGE') # '/storage/emulated/0/Android/data/au.ufeff.rhythmgame/' # '/sdcard/Android/data/au.ufeff.rhythmgame/' var user_data_dir := OS.get_user_data_dir().rstrip('/')+'/' if OS.get_name() != 'Android' else ANDROID_USERDIR var SETTINGS_FILENAME = user_data_dir + 'settings.cfg' var config : ConfigFile var subsampling: Vector2 setget SSXY_set, SSXY_get var subsampling_x: float setget SSX_set, SSX_get var subsampling_y: float setget SSY_set, SSY_get func SSX_set(x: float): ProjectSettings.set_setting('rendering/quality/subsampling/x', x) emit_signal('subsampling_changed', self.subsampling) func SSY_set(y: float): ProjectSettings.set_setting('rendering/quality/subsampling/y', y) emit_signal('subsampling_changed', self.subsampling) func SSXY_set(xy: Vector2): ProjectSettings.set_setting('rendering/quality/subsampling/x', xy.x) ProjectSettings.set_setting('rendering/quality/subsampling/y', xy.y) emit_signal('subsampling_changed', self.subsampling) func SSX_get() -> float: return ProjectSettings.get_setting('rendering/quality/subsampling/x') func SSY_get() -> float: return ProjectSettings.get_setting('rendering/quality/subsampling/y') func SSXY_get() -> Vector2: return Vector2(self.subsampling_x, self.subsampling_y) func get_library_paths() -> PoolStringArray: var paths = [user_data_dir] var additional_paths = config.get_value('libraries', 'additional_paths', []) # Ensure paths are valid and have trailing slash for p in additional_paths: if p is String: paths.append(p.rstrip('/')+'/') return PoolStringArray(paths) func set_additional_library_paths(entries): config.set_value('libraries', 'additional_paths', PoolStringArray(entries)) save_settings() func load_settings(): config = ConfigFile.new() config.set_value('libraries', 'additional_paths', []) match config.load(SETTINGS_FILENAME): OK: self.subsampling = Vector2( config.get_value('rendering', 'subsampling_x', self.subsampling_x), config.get_value('rendering', 'subsampling_y', self.subsampling_y) ) emit_signal('config_loaded') ERR_FILE_NOT_FOUND: save_settings() print('Loaded settings from ' + SETTINGS_FILENAME) func save_settings(): config.save(SETTINGS_FILENAME) print('Saved settings to ' + SETTINGS_FILENAME) func _ready(): load_settings() get_tree().connect('on_request_permissions_result', self, '_on_request_permissions_result') self.update_android_permissions()