| 
									
										
										
										
											2023-07-05 22:39:35 +02:00
										 |  |  | # Archipelago Settings API
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The settings API describes how to use installation-wide config and let the user configure them, like paths, etc. using | 
					
						
							| 
									
										
										
										
											2024-04-06 19:25:26 -04:00
										 |  |  | host.yaml. For the player options / player yamls see [options api.md](options api.md). | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:35 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | The settings API replaces `Utils.get_options()` and `Utils.get_default_options()` | 
					
						
							|  |  |  | as well as the predefined `host.yaml` in the repository. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For backwards compatibility with APWorlds, some interfaces are kept for now and will produce a warning when being used. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Config File
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Settings use options.yaml (manual override), if that exists, or host.yaml (the default) otherwise. | 
					
						
							|  |  |  | The files are searched for in the current working directory, if different from install directory, and in `user_path`, | 
					
						
							|  |  |  | which either points to the installation directory, if writable, or to %home%/Archipelago otherwise. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **Examples:** | 
					
						
							|  |  |  | * C:\Program Data\Archipelago\options.yaml | 
					
						
							|  |  |  | * C:\Program Data\Archipelago\host.yaml | 
					
						
							|  |  |  | * path\to\code\repository\host.yaml | 
					
						
							|  |  |  | * ~/Archipelago/host.yaml | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Using the settings API, AP can update the config file or create a new one with default values and comments,  | 
					
						
							|  |  |  | if it does not exist. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Global Settings
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | All non-world-specific settings are defined directly in settings.py. | 
					
						
							|  |  |  | Each value needs to have a default. If the default should be `None`, define it as `typing.Optional` and assign `None`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To access a "global" config value, with correct typing, use one of | 
					
						
							|  |  |  | ```python | 
					
						
							|  |  |  | from settings import get_settings, GeneralOptions, FolderPath | 
					
						
							|  |  |  | from typing import cast | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | x = get_settings().general_options.output_path | 
					
						
							|  |  |  | y = cast(GeneralOptions, get_settings()["general_options"]).output_path | 
					
						
							|  |  |  | z = cast(FolderPath, get_settings()["general_options"]["output_path"]) | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## World Settings
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Worlds can define the top level key to use by defining `settings_key: ClassVar[str]` in their World class. | 
					
						
							|  |  |  | It defaults to `{folder_name}_options` if undefined, i.e. `worlds/factorio/...` defaults to `factorio_options`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Worlds define the layout of their config section using type annotation of the variable `settings` in the class. | 
					
						
							|  |  |  | The type has to inherit from `settings.Group`. Each value in the config can have a comment by subclassing a built-in | 
					
						
							|  |  |  | type. Some helper types are defined in `settings.py`, see [Types](#Types) for a list.``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Inside the class code, you can then simply use `self.settings.rom_file` to get the value. | 
					
						
							|  |  |  | In case of paths they will automatically be read as absolute file paths. No need to use user_path or local_path. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```python | 
					
						
							|  |  |  | import settings | 
					
						
							|  |  |  | from worlds.AutoWorld import World | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MyGameSettings(settings.Group): | 
					
						
							|  |  |  |     class RomFile(settings.SNESRomPath): | 
					
						
							|  |  |  |         """Description that is put into host.yaml""" | 
					
						
							|  |  |  |         description = "My Game US v1.0 ROM File"  # displayed in the file browser | 
					
						
							|  |  |  |         copy_to = "MyGame.sfc"  # instead of storing the path, copy to AP dir | 
					
						
							|  |  |  |         md5s = ["..."] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     rom_file: RomFile = RomFile("MyGame.sfc")  # definition and default value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MyGameWorld(World): | 
					
						
							|  |  |  |     ... | 
					
						
							|  |  |  |     settings: MyGameSettings | 
					
						
							|  |  |  |     ... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def something(self): | 
					
						
							|  |  |  |         pass  # use self.settings.rom_file here | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Types
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When writing the host.yaml, the code will down cast the values to builtins. | 
					
						
							|  |  |  | When reading the host.yaml, the code will upcast the values to what is defined in the type annotations. | 
					
						
							|  |  |  | E.g. an IntEnum becomes int when saving and will construct the IntEnum when loading. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Types that can not be down cast to / up cast from a builtin can not be used except for Group, which will be converted | 
					
						
							|  |  |  | to/from a dict. | 
					
						
							|  |  |  | `bool` is a special case, see settings.py: ServerOptions.disable_item_cheat for an example. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Below are some predefined types that can be used if they match your requirements: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Group
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A section / dict in the config file. Behaves similar to a dataclass. | 
					
						
							|  |  |  | Type annotation and default assignment define how loading, saving and default values behave. | 
					
						
							|  |  |  | It can be accessed using attributes or as a dict: `group["a"]` is equivalent to `group.a`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In worlds, this should only be used for the top level to avoid issues when upgrading/migrating. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Bool
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Since `bool` can not be subclassed, use the `settings.Bool` helper in a `typing.Union` to get a comment in host.yaml. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```python | 
					
						
							|  |  |  | import settings | 
					
						
							|  |  |  | import typing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class MySettings(settings.Group): | 
					
						
							|  |  |  |     class MyBool(settings.Bool): | 
					
						
							|  |  |  |         """Doc string""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     my_value: typing.Union[MyBool, bool] = True | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### UserFilePath
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Path to a single file. Automatically resolves as user_path: | 
					
						
							|  |  |  | Source folder or AP install path on Windows. ~/Archipelago for the AppImage. | 
					
						
							|  |  |  | Will open a file browser if the file is missing when in GUI mode. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-03 17:00:32 +01:00
										 |  |  | If the file is used in the world's `generate_output`, make sure to add a `stage_assert_generate` that checks if the | 
					
						
							|  |  |  | file is available, otherwise generation may fail at the very end. | 
					
						
							|  |  |  | See also [world api.md](https://github.com/ArchipelagoMW/Archipelago/blob/main/docs/world%20api.md#generation). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-05 22:39:35 +02:00
										 |  |  | #### class method validate(cls, path: str)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Override this and raise ValueError if validation fails. | 
					
						
							|  |  |  | Checks the file against [md5s](#md5s) by default. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### is_exe: bool
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Resolves to an executable (varying file extension based on platform) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### description: Optional\[str\]
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Human-readable name to use in file browser | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### copy_to: Optional\[str\]
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Instead of storing the path, copy the file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### md5s: List[Union[str, bytes]]
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Provide md5 hashes as hex digests or raw bytes for automatic validation. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### UserFolderPath
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Same as [UserFilePath](#UserFilePath), but for a folder instead of a file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### LocalFilePath
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Same as [UserFilePath](#UserFilePath), but resolves as local_path: | 
					
						
							|  |  |  | path inside the AP dir or Appimage even if read-only. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### LocalFolderPath
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Same as [LocalFilePath](#LocalFilePath), but for a folder instead of a file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### OptionalUserFilePath, OptionalUserFolderPath, OptionalLocalFilePath, OptionalLocalFolderPath
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Same as UserFilePath, UserFolderPath, LocalFilePath, LocalFolderPath but does not open a file browser if missing. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### SNESRomPath
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Specialized [UserFilePath](#UserFilePath) that ignores an optional 512 byte header when validating. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Caveats
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Circular Imports
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Because the settings are defined on import, code that runs on import can not use settings since that would result in | 
					
						
							|  |  |  | circular / partial imports. Instead, the code should fetch from settings on demand during generation. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "Global" settings are populated immediately, while worlds settings are lazy loaded, so if really necessary, | 
					
						
							|  |  |  | "global" settings could be used in global scope of worlds. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### APWorld Backwards Compatibility
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | APWorlds that want to be compatible with both stable and dev versions, have two options: | 
					
						
							|  |  |  | 1. use the old Utils.get_options() API until Archipelago 0.4.2 is out | 
					
						
							|  |  |  | 2. add some sort of compatibility code to your world that mimics the new API |