diff options
| author | 2023-03-07 21:36:42 -0500 | |
|---|---|---|
| committer | 2023-06-03 00:05:38 -0700 | |
| commit | 0e4256651a1f082216b9fb8e4ecd6ebd2d4931f2 (patch) | |
| tree | 1ff3bc8292d256138282f3260dbd37115ada1f60 | |
| parent | android: Convert SettingsFrameLayout to Kotlin (diff) | |
| download | yuzu-0e4256651a1f082216b9fb8e4ecd6ebd2d4931f2.tar.gz yuzu-0e4256651a1f082216b9fb8e4ecd6ebd2d4931f2.tar.xz yuzu-0e4256651a1f082216b9fb8e4ecd6ebd2d4931f2.zip | |
android: Convert SettingsFile to Kotlin
2 files changed, 245 insertions, 272 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java deleted file mode 100644 index 2b3d257a3..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java +++ /dev/null | |||
| @@ -1,272 +0,0 @@ | |||
| 1 | package org.yuzu.yuzu_emu.features.settings.utils; | ||
| 2 | |||
| 3 | import androidx.annotation.NonNull; | ||
| 4 | |||
| 5 | import org.yuzu.yuzu_emu.YuzuApplication; | ||
| 6 | import org.yuzu.yuzu_emu.NativeLibrary; | ||
| 7 | import org.yuzu.yuzu_emu.R; | ||
| 8 | import org.yuzu.yuzu_emu.features.settings.model.FloatSetting; | ||
| 9 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting; | ||
| 10 | import org.yuzu.yuzu_emu.features.settings.model.Setting; | ||
| 11 | import org.yuzu.yuzu_emu.features.settings.model.SettingSection; | ||
| 12 | import org.yuzu.yuzu_emu.features.settings.model.Settings; | ||
| 13 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting; | ||
| 14 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivityView; | ||
| 15 | import org.yuzu.yuzu_emu.utils.BiMap; | ||
| 16 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization; | ||
| 17 | import org.yuzu.yuzu_emu.utils.Log; | ||
| 18 | import org.ini4j.Wini; | ||
| 19 | |||
| 20 | import java.io.BufferedReader; | ||
| 21 | import java.io.File; | ||
| 22 | import java.io.FileNotFoundException; | ||
| 23 | import java.io.FileReader; | ||
| 24 | import java.io.IOException; | ||
| 25 | import java.util.HashMap; | ||
| 26 | import java.util.Set; | ||
| 27 | import java.util.TreeMap; | ||
| 28 | import java.util.TreeSet; | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Contains static methods for interacting with .ini files in which settings are stored. | ||
| 32 | */ | ||
| 33 | public final class SettingsFile { | ||
| 34 | public static final String FILE_NAME_CONFIG = "config"; | ||
| 35 | |||
| 36 | public static final String KEY_DESIGN = "design"; | ||
| 37 | |||
| 38 | // CPU | ||
| 39 | public static final String KEY_CPU_ACCURACY = "cpu_accuracy"; | ||
| 40 | // System | ||
| 41 | public static final String KEY_USE_DOCKED_MODE = "use_docked_mode"; | ||
| 42 | public static final String KEY_REGION_INDEX = "region_index"; | ||
| 43 | public static final String KEY_LANGUAGE_INDEX = "language_index"; | ||
| 44 | public static final String KEY_RENDERER_BACKEND = "backend"; | ||
| 45 | // Renderer | ||
| 46 | public static final String KEY_RENDERER_RESOLUTION = "resolution_setup"; | ||
| 47 | public static final String KEY_RENDERER_ASPECT_RATIO = "aspect_ratio"; | ||
| 48 | public static final String KEY_RENDERER_ACCURACY = "gpu_accuracy"; | ||
| 49 | public static final String KEY_RENDERER_ASYNCHRONOUS_SHADERS = "use_asynchronous_shaders"; | ||
| 50 | public static final String KEY_RENDERER_FORCE_MAX_CLOCK = "force_max_clock"; | ||
| 51 | public static final String KEY_RENDERER_USE_SPEED_LIMIT = "use_speed_limit"; | ||
| 52 | public static final String KEY_RENDERER_DEBUG = "debug"; | ||
| 53 | public static final String KEY_RENDERER_SPEED_LIMIT = "speed_limit"; | ||
| 54 | // Audio | ||
| 55 | public static final String KEY_AUDIO_VOLUME = "volume"; | ||
| 56 | |||
| 57 | private static BiMap<String, String> sectionsMap = new BiMap<>(); | ||
| 58 | |||
| 59 | static { | ||
| 60 | //TODO: Add members to sectionsMap when game-specific settings are added | ||
| 61 | } | ||
| 62 | |||
| 63 | |||
| 64 | private SettingsFile() { | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * Reads a given .ini file from disk and returns it as a HashMap of Settings, themselves | ||
| 69 | * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it | ||
| 70 | * failed. | ||
| 71 | * | ||
| 72 | * @param ini The ini file to load the settings from | ||
| 73 | * @param isCustomGame | ||
| 74 | * @param view The current view. | ||
| 75 | * @return An Observable that emits a HashMap of the file's contents, then completes. | ||
| 76 | */ | ||
| 77 | static HashMap<String, SettingSection> readFile(final File ini, boolean isCustomGame, SettingsActivityView view) { | ||
| 78 | HashMap<String, SettingSection> sections = new Settings.SettingsSectionMap(); | ||
| 79 | |||
| 80 | BufferedReader reader = null; | ||
| 81 | |||
| 82 | try { | ||
| 83 | reader = new BufferedReader(new FileReader(ini)); | ||
| 84 | |||
| 85 | SettingSection current = null; | ||
| 86 | for (String line; (line = reader.readLine()) != null; ) { | ||
| 87 | if (line.startsWith("[") && line.endsWith("]")) { | ||
| 88 | current = sectionFromLine(line, isCustomGame); | ||
| 89 | sections.put(current.getName(), current); | ||
| 90 | } else if ((current != null)) { | ||
| 91 | Setting setting = settingFromLine(current, line); | ||
| 92 | if (setting != null) { | ||
| 93 | current.putSetting(setting); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | } catch (FileNotFoundException e) { | ||
| 98 | Log.error("[SettingsFile] File not found: " + e.getMessage()); | ||
| 99 | if (view != null) | ||
| 100 | view.onSettingsFileNotFound(); | ||
| 101 | } catch (IOException e) { | ||
| 102 | Log.error("[SettingsFile] Error reading from: " + e.getMessage()); | ||
| 103 | if (view != null) | ||
| 104 | view.onSettingsFileNotFound(); | ||
| 105 | } finally { | ||
| 106 | if (reader != null) { | ||
| 107 | try { | ||
| 108 | reader.close(); | ||
| 109 | } catch (IOException e) { | ||
| 110 | Log.error("[SettingsFile] Error closing: " + e.getMessage()); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | return sections; | ||
| 116 | } | ||
| 117 | |||
| 118 | public static HashMap<String, SettingSection> readFile(final String fileName, SettingsActivityView view) { | ||
| 119 | return readFile(getSettingsFile(fileName), false, view); | ||
| 120 | } | ||
| 121 | |||
| 122 | /** | ||
| 123 | * Reads a given .ini file from disk and returns it as a HashMap of SettingSections, themselves | ||
| 124 | * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it | ||
| 125 | * failed. | ||
| 126 | * | ||
| 127 | * @param gameId the id of the game to load it's settings. | ||
| 128 | * @param view The current view. | ||
| 129 | */ | ||
| 130 | public static HashMap<String, SettingSection> readCustomGameSettings(final String gameId, SettingsActivityView view) { | ||
| 131 | return readFile(getCustomGameSettingsFile(gameId), true, view); | ||
| 132 | } | ||
| 133 | |||
| 134 | /** | ||
| 135 | * Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error | ||
| 136 | * telling why it failed. | ||
| 137 | * | ||
| 138 | * @param fileName The target filename without a path or extension. | ||
| 139 | * @param sections The HashMap containing the Settings we want to serialize. | ||
| 140 | * @param view The current view. | ||
| 141 | */ | ||
| 142 | public static void saveFile(final String fileName, TreeMap<String, SettingSection> sections, | ||
| 143 | SettingsActivityView view) { | ||
| 144 | File ini = getSettingsFile(fileName); | ||
| 145 | |||
| 146 | try { | ||
| 147 | Wini writer = new Wini(ini); | ||
| 148 | |||
| 149 | Set<String> keySet = sections.keySet(); | ||
| 150 | for (String key : keySet) { | ||
| 151 | SettingSection section = sections.get(key); | ||
| 152 | writeSection(writer, section); | ||
| 153 | } | ||
| 154 | writer.store(); | ||
| 155 | } catch (IOException e) { | ||
| 156 | Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage()); | ||
| 157 | view.showToastMessage(YuzuApplication.getAppContext().getString(R.string.error_saving, fileName, e.getMessage()), false); | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | |||
| 162 | public static void saveCustomGameSettings(final String gameId, final HashMap<String, SettingSection> sections) { | ||
| 163 | Set<String> sortedSections = new TreeSet<>(sections.keySet()); | ||
| 164 | |||
| 165 | for (String sectionKey : sortedSections) { | ||
| 166 | SettingSection section = sections.get(sectionKey); | ||
| 167 | |||
| 168 | HashMap<String, Setting> settings = section.getSettings(); | ||
| 169 | Set<String> sortedKeySet = new TreeSet<>(settings.keySet()); | ||
| 170 | |||
| 171 | for (String settingKey : sortedKeySet) { | ||
| 172 | Setting setting = settings.get(settingKey); | ||
| 173 | NativeLibrary.SetUserSetting(gameId, mapSectionNameFromIni(section.getName()), setting.getKey(), setting.getValueAsString()); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | private static String mapSectionNameFromIni(String generalSectionName) { | ||
| 179 | if (sectionsMap.getForward(generalSectionName) != null) { | ||
| 180 | return sectionsMap.getForward(generalSectionName); | ||
| 181 | } | ||
| 182 | |||
| 183 | return generalSectionName; | ||
| 184 | } | ||
| 185 | |||
| 186 | private static String mapSectionNameToIni(String generalSectionName) { | ||
| 187 | if (sectionsMap.getBackward(generalSectionName) != null) { | ||
| 188 | return sectionsMap.getBackward(generalSectionName); | ||
| 189 | } | ||
| 190 | |||
| 191 | return generalSectionName; | ||
| 192 | } | ||
| 193 | |||
| 194 | @NonNull | ||
| 195 | private static File getSettingsFile(String fileName) { | ||
| 196 | return new File( | ||
| 197 | DirectoryInitialization.getUserDirectory() + "/config/" + fileName + ".ini"); | ||
| 198 | } | ||
| 199 | |||
| 200 | private static File getCustomGameSettingsFile(String gameId) { | ||
| 201 | return new File(DirectoryInitialization.getUserDirectory() + "/GameSettings/" + gameId + ".ini"); | ||
| 202 | } | ||
| 203 | |||
| 204 | private static SettingSection sectionFromLine(String line, boolean isCustomGame) { | ||
| 205 | String sectionName = line.substring(1, line.length() - 1); | ||
| 206 | if (isCustomGame) { | ||
| 207 | sectionName = mapSectionNameToIni(sectionName); | ||
| 208 | } | ||
| 209 | return new SettingSection(sectionName); | ||
| 210 | } | ||
| 211 | |||
| 212 | /** | ||
| 213 | * For a line of text, determines what type of data is being represented, and returns | ||
| 214 | * a Setting object containing this data. | ||
| 215 | * | ||
| 216 | * @param current The section currently being parsed by the consuming method. | ||
| 217 | * @param line The line of text being parsed. | ||
| 218 | * @return A typed Setting containing the key/value contained in the line. | ||
| 219 | */ | ||
| 220 | private static Setting settingFromLine(SettingSection current, String line) { | ||
| 221 | String[] splitLine = line.split("="); | ||
| 222 | |||
| 223 | if (splitLine.length != 2) { | ||
| 224 | Log.warning("Skipping invalid config line \"" + line + "\""); | ||
| 225 | return null; | ||
| 226 | } | ||
| 227 | |||
| 228 | String key = splitLine[0].trim(); | ||
| 229 | String value = splitLine[1].trim(); | ||
| 230 | |||
| 231 | if (value.isEmpty()) { | ||
| 232 | Log.warning("Skipping null value in config line \"" + line + "\""); | ||
| 233 | return null; | ||
| 234 | } | ||
| 235 | |||
| 236 | try { | ||
| 237 | int valueAsInt = Integer.parseInt(value); | ||
| 238 | |||
| 239 | return new IntSetting(key, current.getName(), valueAsInt); | ||
| 240 | } catch (NumberFormatException ex) { | ||
| 241 | } | ||
| 242 | |||
| 243 | try { | ||
| 244 | float valueAsFloat = Float.parseFloat(value); | ||
| 245 | |||
| 246 | return new FloatSetting(key, current.getName(), valueAsFloat); | ||
| 247 | } catch (NumberFormatException ex) { | ||
| 248 | } | ||
| 249 | |||
| 250 | return new StringSetting(key, current.getName(), value); | ||
| 251 | } | ||
| 252 | |||
| 253 | /** | ||
| 254 | * Writes the contents of a Section HashMap to disk. | ||
| 255 | * | ||
| 256 | * @param parser A Wini pointed at a file on disk. | ||
| 257 | * @param section A section containing settings to be written to the file. | ||
| 258 | */ | ||
| 259 | private static void writeSection(Wini parser, SettingSection section) { | ||
| 260 | // Write the section header. | ||
| 261 | String header = section.getName(); | ||
| 262 | |||
| 263 | // Write this section's values. | ||
| 264 | HashMap<String, Setting> settings = section.getSettings(); | ||
| 265 | Set<String> keySet = settings.keySet(); | ||
| 266 | |||
| 267 | for (String key : keySet) { | ||
| 268 | Setting setting = settings.get(key); | ||
| 269 | parser.put(header, setting.getKey(), setting.getValueAsString()); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt new file mode 100644 index 000000000..8e21c65f0 --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt | |||
| @@ -0,0 +1,245 @@ | |||
| 1 | package org.yuzu.yuzu_emu.features.settings.utils | ||
| 2 | |||
| 3 | import org.ini4j.Wini | ||
| 4 | import org.yuzu.yuzu_emu.NativeLibrary | ||
| 5 | import org.yuzu.yuzu_emu.R | ||
| 6 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 7 | import org.yuzu.yuzu_emu.features.settings.model.* | ||
| 8 | import org.yuzu.yuzu_emu.features.settings.model.Settings.SettingsSectionMap | ||
| 9 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivityView | ||
| 10 | import org.yuzu.yuzu_emu.utils.BiMap | ||
| 11 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization | ||
| 12 | import org.yuzu.yuzu_emu.utils.Log | ||
| 13 | import java.io.* | ||
| 14 | import java.util.* | ||
| 15 | |||
| 16 | /** | ||
| 17 | * Contains static methods for interacting with .ini files in which settings are stored. | ||
| 18 | */ | ||
| 19 | object SettingsFile { | ||
| 20 | const val FILE_NAME_CONFIG = "config" | ||
| 21 | const val KEY_DESIGN = "design" | ||
| 22 | |||
| 23 | // CPU | ||
| 24 | const val KEY_CPU_ACCURACY = "cpu_accuracy" | ||
| 25 | |||
| 26 | // System | ||
| 27 | const val KEY_USE_DOCKED_MODE = "use_docked_mode" | ||
| 28 | const val KEY_REGION_INDEX = "region_index" | ||
| 29 | const val KEY_LANGUAGE_INDEX = "language_index" | ||
| 30 | const val KEY_RENDERER_BACKEND = "backend" | ||
| 31 | |||
| 32 | // Renderer | ||
| 33 | const val KEY_RENDERER_RESOLUTION = "resolution_setup" | ||
| 34 | const val KEY_RENDERER_ASPECT_RATIO = "aspect_ratio" | ||
| 35 | const val KEY_RENDERER_ACCURACY = "gpu_accuracy" | ||
| 36 | const val KEY_RENDERER_ASYNCHRONOUS_SHADERS = "use_asynchronous_shaders" | ||
| 37 | const val KEY_RENDERER_FORCE_MAX_CLOCK = "force_max_clock" | ||
| 38 | const val KEY_RENDERER_USE_SPEED_LIMIT = "use_speed_limit" | ||
| 39 | const val KEY_RENDERER_DEBUG = "debug" | ||
| 40 | const val KEY_RENDERER_SPEED_LIMIT = "speed_limit" | ||
| 41 | |||
| 42 | // Audio | ||
| 43 | const val KEY_AUDIO_VOLUME = "volume" | ||
| 44 | private val sectionsMap = BiMap<String?, String?>() | ||
| 45 | |||
| 46 | /** | ||
| 47 | * Reads a given .ini file from disk and returns it as a HashMap of Settings, themselves | ||
| 48 | * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it | ||
| 49 | * failed. | ||
| 50 | * | ||
| 51 | * @param ini The ini file to load the settings from | ||
| 52 | * @param isCustomGame | ||
| 53 | * @param view The current view. | ||
| 54 | * @return An Observable that emits a HashMap of the file's contents, then completes. | ||
| 55 | */ | ||
| 56 | private fun readFile( | ||
| 57 | ini: File?, | ||
| 58 | isCustomGame: Boolean, | ||
| 59 | view: SettingsActivityView? | ||
| 60 | ): HashMap<String, SettingSection?> { | ||
| 61 | val sections: HashMap<String, SettingSection?> = SettingsSectionMap() | ||
| 62 | var reader: BufferedReader? = null | ||
| 63 | try { | ||
| 64 | reader = BufferedReader(FileReader(ini)) | ||
| 65 | var current: SettingSection? = null | ||
| 66 | var line: String? | ||
| 67 | while (reader.readLine().also { line = it } != null) { | ||
| 68 | if (line!!.startsWith("[") && line!!.endsWith("]")) { | ||
| 69 | current = sectionFromLine(line!!, isCustomGame) | ||
| 70 | sections[current.name] = current | ||
| 71 | } else if (current != null) { | ||
| 72 | val setting = settingFromLine(current, line!!) | ||
| 73 | if (setting != null) { | ||
| 74 | current.putSetting(setting) | ||
| 75 | } | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } catch (e: FileNotFoundException) { | ||
| 79 | Log.error("[SettingsFile] File not found: " + e.message) | ||
| 80 | view?.onSettingsFileNotFound() | ||
| 81 | } catch (e: IOException) { | ||
| 82 | Log.error("[SettingsFile] Error reading from: " + e.message) | ||
| 83 | view?.onSettingsFileNotFound() | ||
| 84 | } finally { | ||
| 85 | if (reader != null) { | ||
| 86 | try { | ||
| 87 | reader.close() | ||
| 88 | } catch (e: IOException) { | ||
| 89 | Log.error("[SettingsFile] Error closing: " + e.message) | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | return sections | ||
| 94 | } | ||
| 95 | |||
| 96 | fun readFile(fileName: String, view: SettingsActivityView): HashMap<String, SettingSection?> { | ||
| 97 | return readFile(getSettingsFile(fileName), false, view) | ||
| 98 | } | ||
| 99 | |||
| 100 | /** | ||
| 101 | * Reads a given .ini file from disk and returns it as a HashMap of SettingSections, themselves | ||
| 102 | * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it | ||
| 103 | * failed. | ||
| 104 | * | ||
| 105 | * @param gameId the id of the game to load it's settings. | ||
| 106 | * @param view The current view. | ||
| 107 | */ | ||
| 108 | fun readCustomGameSettings( | ||
| 109 | gameId: String, | ||
| 110 | view: SettingsActivityView | ||
| 111 | ): HashMap<String, SettingSection?> { | ||
| 112 | return readFile(getCustomGameSettingsFile(gameId), true, view) | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error | ||
| 117 | * telling why it failed. | ||
| 118 | * | ||
| 119 | * @param fileName The target filename without a path or extension. | ||
| 120 | * @param sections The HashMap containing the Settings we want to serialize. | ||
| 121 | * @param view The current view. | ||
| 122 | */ | ||
| 123 | fun saveFile( | ||
| 124 | fileName: String, | ||
| 125 | sections: TreeMap<String, SettingSection>, | ||
| 126 | view: SettingsActivityView | ||
| 127 | ) { | ||
| 128 | val ini = getSettingsFile(fileName) | ||
| 129 | try { | ||
| 130 | val writer = Wini(ini) | ||
| 131 | val keySet: Set<String> = sections.keys | ||
| 132 | for (key in keySet) { | ||
| 133 | val section = sections[key] | ||
| 134 | writeSection(writer, section!!) | ||
| 135 | } | ||
| 136 | writer.store() | ||
| 137 | } catch (e: IOException) { | ||
| 138 | Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.message) | ||
| 139 | view.showToastMessage( | ||
| 140 | YuzuApplication.appContext | ||
| 141 | .getString(R.string.error_saving, fileName, e.message), | ||
| 142 | false | ||
| 143 | ) | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | fun saveCustomGameSettings(gameId: String?, sections: HashMap<String, SettingSection?>) { | ||
| 148 | val sortedSections: Set<String> = TreeSet(sections.keys) | ||
| 149 | for (sectionKey in sortedSections) { | ||
| 150 | val section = sections[sectionKey] | ||
| 151 | val settings = section!!.settings | ||
| 152 | val sortedKeySet: Set<String> = TreeSet(settings.keys) | ||
| 153 | for (settingKey in sortedKeySet) { | ||
| 154 | val setting = settings[settingKey] | ||
| 155 | NativeLibrary.SetUserSetting( | ||
| 156 | gameId, mapSectionNameFromIni( | ||
| 157 | section.name | ||
| 158 | ), setting!!.key, setting.valueAsString | ||
| 159 | ) | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | private fun mapSectionNameFromIni(generalSectionName: String): String? { | ||
| 165 | return if (sectionsMap.getForward(generalSectionName) != null) { | ||
| 166 | sectionsMap.getForward(generalSectionName) | ||
| 167 | } else generalSectionName | ||
| 168 | } | ||
| 169 | |||
| 170 | private fun mapSectionNameToIni(generalSectionName: String): String { | ||
| 171 | return if (sectionsMap.getBackward(generalSectionName) != null) { | ||
| 172 | sectionsMap.getBackward(generalSectionName).toString() | ||
| 173 | } else generalSectionName | ||
| 174 | } | ||
| 175 | |||
| 176 | private fun getSettingsFile(fileName: String): File { | ||
| 177 | return File( | ||
| 178 | DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini" | ||
| 179 | ) | ||
| 180 | } | ||
| 181 | |||
| 182 | private fun getCustomGameSettingsFile(gameId: String): File { | ||
| 183 | return File(DirectoryInitialization.userDirectory + "/GameSettings/" + gameId + ".ini") | ||
| 184 | } | ||
| 185 | |||
| 186 | private fun sectionFromLine(line: String, isCustomGame: Boolean): SettingSection { | ||
| 187 | var sectionName: String = line.substring(1, line.length - 1) | ||
| 188 | if (isCustomGame) { | ||
| 189 | sectionName = mapSectionNameToIni(sectionName) | ||
| 190 | } | ||
| 191 | return SettingSection(sectionName) | ||
| 192 | } | ||
| 193 | |||
| 194 | /** | ||
| 195 | * For a line of text, determines what type of data is being represented, and returns | ||
| 196 | * a Setting object containing this data. | ||
| 197 | * | ||
| 198 | * @param current The section currently being parsed by the consuming method. | ||
| 199 | * @param line The line of text being parsed. | ||
| 200 | * @return A typed Setting containing the key/value contained in the line. | ||
| 201 | */ | ||
| 202 | private fun settingFromLine(current: SettingSection, line: String): Setting? { | ||
| 203 | val splitLine = line.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() | ||
| 204 | if (splitLine.size != 2) { | ||
| 205 | Log.warning("Skipping invalid config line \"$line\"") | ||
| 206 | return null | ||
| 207 | } | ||
| 208 | val key = splitLine[0].trim { it <= ' ' } | ||
| 209 | val value = splitLine[1].trim { it <= ' ' } | ||
| 210 | if (value.isEmpty()) { | ||
| 211 | Log.warning("Skipping null value in config line \"$line\"") | ||
| 212 | return null | ||
| 213 | } | ||
| 214 | try { | ||
| 215 | val valueAsInt = value.toInt() | ||
| 216 | return IntSetting(key, current.name, valueAsInt) | ||
| 217 | } catch (_: NumberFormatException) { | ||
| 218 | } | ||
| 219 | try { | ||
| 220 | val valueAsFloat = value.toFloat() | ||
| 221 | return FloatSetting(key, current.name, valueAsFloat) | ||
| 222 | } catch (_: NumberFormatException) { | ||
| 223 | } | ||
| 224 | return StringSetting(key, current.name, value) | ||
| 225 | } | ||
| 226 | |||
| 227 | /** | ||
| 228 | * Writes the contents of a Section HashMap to disk. | ||
| 229 | * | ||
| 230 | * @param parser A Wini pointed at a file on disk. | ||
| 231 | * @param section A section containing settings to be written to the file. | ||
| 232 | */ | ||
| 233 | private fun writeSection(parser: Wini, section: SettingSection) { | ||
| 234 | // Write the section header. | ||
| 235 | val header = section.name | ||
| 236 | |||
| 237 | // Write this section's values. | ||
| 238 | val settings = section.settings | ||
| 239 | val keySet: Set<String> = settings.keys | ||
| 240 | for (key in keySet) { | ||
| 241 | val setting = settings[key] | ||
| 242 | parser.put(header, setting!!.key, setting.valueAsString) | ||
| 243 | } | ||
| 244 | } | ||
| 245 | } | ||