Docs: minor updates to recommend modern PEP8 (#2384)
* docs: update world api for modern PEP8 conventions * docs: update options api for modern PEP8 styling * missed a spot
This commit is contained in:
		
							parent
							
								
									2af5410301
								
							
						
					
					
						commit
						bf8432faa7
					
				|  | @ -29,6 +29,7 @@ The zip can contain arbitrary files in addition what was specified above. | |||
| 
 | ||||
| ## Caveats | ||||
| 
 | ||||
| Imports from other files inside the apworld have to use relative imports. | ||||
| Imports from other files inside the apworld have to use relative imports. e.g. `from .options import MyGameOptions` | ||||
| 
 | ||||
| Imports from AP base have to use absolute imports, e.g. Options.py and worlds/AutoWorld.py. | ||||
| Imports from AP base have to use absolute imports, e.g. `from Options import Toggle` or | ||||
| `from worlds.AutoWorld import World` | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ As an example, suppose we want an option that lets the user start their game wit | |||
| create our option class (with a docstring), give it a `display_name`, and add it to our game's options dataclass: | ||||
| 
 | ||||
| ```python | ||||
| # Options.py | ||||
| # options.py | ||||
| from dataclasses import dataclass | ||||
| 
 | ||||
| from Options import Toggle, PerGameCommonOptions | ||||
|  |  | |||
|  | @ -286,11 +286,11 @@ See [pip documentation](https://pip.pypa.io/en/stable/cli/pip_install/#requireme | |||
| AP will only import the `__init__.py`. Depending on code size it makes sense to | ||||
| use multiple files and use relative imports to access them. | ||||
| 
 | ||||
| e.g. `from .Options import MyGameOptions` from your `__init__.py` will load | ||||
| `world/[world_name]/Options.py` and make its `MyGameOptions` accessible. | ||||
| e.g. `from .options import MyGameOptions` from your `__init__.py` will load | ||||
| `world/[world_name]/options.py` and make its `MyGameOptions` accessible. | ||||
| 
 | ||||
| When imported names pile up it may be easier to use `from . import Options` | ||||
| and access the variable as `Options.MyGameOptions`. | ||||
| When imported names pile up it may be easier to use `from . import options` | ||||
| and access the variable as `options.MyGameOptions`. | ||||
| 
 | ||||
| Imports from directories outside your world should use absolute imports. | ||||
| Correct use of relative / absolute imports is required for zipped worlds to | ||||
|  | @ -311,7 +311,7 @@ class MyGameItem(Item): | |||
|     game: str = "My Game" | ||||
| ``` | ||||
| By convention this class definition will either be placed in your `__init__.py` | ||||
| or your `Items.py`. For a more elaborate example see `worlds/oot/Items.py`. | ||||
| or your `items.py`. For a more elaborate example see `worlds/oot/Items.py`. | ||||
| 
 | ||||
| ### Your location type | ||||
| 
 | ||||
|  | @ -323,15 +323,15 @@ class MyGameLocation(Location): | |||
|     game: str = "My Game" | ||||
| 
 | ||||
|     # override constructor to automatically mark event locations as such | ||||
|     def __init__(self, player: int, name = "", code = None, parent = None): | ||||
|     def __init__(self, player: int, name = "", code = None, parent = None) -> None: | ||||
|         super(MyGameLocation, self).__init__(player, name, code, parent) | ||||
|         self.event = code is None | ||||
| ``` | ||||
| in your `__init__.py` or your `Locations.py`. | ||||
| in your `__init__.py` or your `locations.py`. | ||||
| 
 | ||||
| ### Options | ||||
| 
 | ||||
| By convention options are defined in `Options.py` and will be used when parsing | ||||
| By convention options are defined in `options.py` and will be used when parsing | ||||
| the players' yaml files. | ||||
| 
 | ||||
| Each option has its own class, inherits from a base option type, has a docstring  | ||||
|  | @ -347,7 +347,7 @@ For more see `Options.py` in AP's base directory. | |||
| 
 | ||||
| #### Toggle, DefaultOnToggle | ||||
| 
 | ||||
| Those don't need any additional properties defined. After parsing the option, | ||||
| These don't need any additional properties defined. After parsing the option, | ||||
| its `value` will either be True or False. | ||||
| 
 | ||||
| #### Range | ||||
|  | @ -373,7 +373,7 @@ default = 0 | |||
| 
 | ||||
| #### Sample | ||||
| ```python | ||||
| # Options.py | ||||
| # options.py | ||||
| 
 | ||||
| from dataclasses import dataclass | ||||
| from Options import Toggle, Range, Choice, PerGameCommonOptions | ||||
|  | @ -412,7 +412,7 @@ class MyGameOptions(PerGameCommonOptions): | |||
| # __init__.py | ||||
| 
 | ||||
| from worlds.AutoWorld import World | ||||
| from .Options import MyGameOptions  # import the options dataclass | ||||
| from .options import MyGameOptions  # import the options dataclass | ||||
| 
 | ||||
| 
 | ||||
| class MyGameWorld(World): | ||||
|  | @ -429,9 +429,9 @@ class MyGameWorld(World): | |||
| 
 | ||||
| import settings | ||||
| import typing | ||||
| from .Options import MyGameOptions  # the options we defined earlier | ||||
| from .Items import mygame_items  # data used below to add items to the World | ||||
| from .Locations import mygame_locations  # same as above | ||||
| from .options import MyGameOptions  # the options we defined earlier | ||||
| from .items import mygame_items  # data used below to add items to the World | ||||
| from .locations import mygame_locations  # same as above | ||||
| from worlds.AutoWorld import World | ||||
| from BaseClasses import Region, Location, Entrance, Item, RegionType, ItemClassification | ||||
| 
 | ||||
|  | @ -490,7 +490,7 @@ The world has to provide the following things for generation | |||
| * additions to the regions list: at least one called "Menu" | ||||
| * locations placed inside those regions | ||||
| * a `def create_item(self, item: str) -> MyGameItem` to create any item on demand | ||||
| * applying `self.multiworld.push_precollected` for start inventory | ||||
| * applying `self.multiworld.push_precollected` for world defined start inventory | ||||
| * `required_client_version: Tuple[int, int, int]` | ||||
|   Optional client version as tuple of 3 ints to make sure the client is compatible to | ||||
|   this world (e.g. implements all required features) when connecting. | ||||
|  | @ -500,31 +500,32 @@ In addition, the following methods can be implemented and are called in this ord | |||
| * `stage_assert_generate(cls, multiworld)` is a class method called at the start of | ||||
|   generation to check the existence of prerequisite files, usually a ROM for | ||||
|   games which require one. | ||||
| * `def generate_early(self)` | ||||
|   called per player before any items or locations are created. You can set | ||||
|   properties on your world here. Already has access to player options and RNG. | ||||
| * `def create_regions(self)` | ||||
| * `generate_early(self)` | ||||
|   called per player before any items or locations are created. You can set properties on your world here. Already has | ||||
|   access to player options and RNG. This is the earliest step where the world should start setting up for the current | ||||
|   multiworld as any steps before this, the multiworld itself is still getting set up | ||||
| * `create_regions(self)` | ||||
|   called to place player's regions and their locations into the MultiWorld's regions list. If it's | ||||
|   hard to separate, this can be done during `generate_early` or `create_items` as well. | ||||
| * `def create_items(self)` | ||||
| * `create_items(self)` | ||||
|   called to place player's items into the MultiWorld's itempool. After this step all regions and items have to be in | ||||
|   the MultiWorld's regions and itempool, and these lists should not be modified afterwards. | ||||
| * `def set_rules(self)` | ||||
| * `set_rules(self)` | ||||
|   called to set access and item rules on locations and entrances.  | ||||
|   Locations have to be defined before this, or rule application can miss them. | ||||
| * `def generate_basic(self)` | ||||
| * `generate_basic(self)` | ||||
|   called after the previous steps. Some placement and player specific | ||||
|   randomizations can be done here. | ||||
| * `pre_fill`, `fill_hook` and `post_fill` are called to modify item placement | ||||
| * `pre_fill(self)`, `fill_hook(self)` and `post_fill(self)` are called to modify item placement | ||||
|   before, during and after the regular fill process, before `generate_output`. | ||||
|   If items need to be placed during pre_fill, these items can be determined | ||||
|   and created using `get_prefill_items` | ||||
| * `def generate_output(self, output_directory: str)` that creates the output | ||||
| * `generate_output(self, output_directory: str)` that creates the output | ||||
|   files if there is output to be generated. When this is | ||||
|   called, `self.multiworld.get_locations(self.player)` has all locations for the player, with | ||||
|   attribute `item` pointing to the item. | ||||
|   `location.item.player` can be used to see if it's a local item. | ||||
| * `fill_slot_data` and `modify_multidata` can be used to modify the data that | ||||
| * `fill_slot_data(self)` and `modify_multidata(self, multidata: Dict[str, Any])` can be used to modify the data that | ||||
|   will be used by the server to host the MultiWorld. | ||||
| 
 | ||||
| 
 | ||||
|  | @ -541,9 +542,9 @@ def generate_early(self) -> None: | |||
| ```python | ||||
| # we need a way to know if an item provides progress in the game ("key item") | ||||
| # this can be part of the items definition, or depend on recipe randomization | ||||
| from .Items import is_progression  # this is just a dummy | ||||
| from .items import is_progression  # this is just a dummy | ||||
| 
 | ||||
| def create_item(self, item: str): | ||||
| def create_item(self, item: str) -> MyGameItem: | ||||
|     # This is called when AP wants to create an item by name (for plando) or | ||||
|     # when you call it from your own code. | ||||
|     classification = ItemClassification.progression if is_progression(item) else \ | ||||
|  | @ -551,7 +552,7 @@ def create_item(self, item: str): | |||
|     return MyGameItem(item, classification, self.item_name_to_id[item], | ||||
|                       self.player) | ||||
| 
 | ||||
| def create_event(self, event: str): | ||||
| def create_event(self, event: str) -> MyGameItem: | ||||
|     # while we are at it, we can also add a helper to create events | ||||
|     return MyGameItem(event, True, None, self.player) | ||||
| ``` | ||||
|  | @ -644,7 +645,7 @@ def generate_basic(self) -> None: | |||
| 
 | ||||
| ```python | ||||
| from worlds.generic.Rules import add_rule, set_rule, forbid_item | ||||
| from Items import get_item_type | ||||
| from .items import get_item_type | ||||
| 
 | ||||
| 
 | ||||
| def set_rules(self) -> None: | ||||
|  | @ -713,12 +714,12 @@ Please do this with caution and only when necessary. | |||
| #### Sample | ||||
| 
 | ||||
| ```python | ||||
| # Logic.py | ||||
| # logic.py | ||||
| 
 | ||||
| from worlds.AutoWorld import LogicMixin | ||||
| 
 | ||||
| class MyGameLogic(LogicMixin): | ||||
|     def mygame_has_key(self, player: int): | ||||
|     def mygame_has_key(self, player: int) -> bool: | ||||
|         # Arguments above are free to choose | ||||
|         # MultiWorld can be accessed through self.multiworld, explicitly passing in | ||||
|         # MyGameWorld instance for easy options access is also a valid approach | ||||
|  | @ -728,11 +729,11 @@ class MyGameLogic(LogicMixin): | |||
| # __init__.py | ||||
| 
 | ||||
| from worlds.generic.Rules import set_rule | ||||
| import .Logic  # apply the mixin by importing its file | ||||
| import .logic  # apply the mixin by importing its file | ||||
| 
 | ||||
| class MyGameWorld(World): | ||||
|     # ... | ||||
|     def set_rules(self): | ||||
|     def set_rules(self) -> None: | ||||
|         set_rule(self.multiworld.get_location("A Door", self.player), | ||||
|                  lambda state: state.mygame_has_key(self.player)) | ||||
| ``` | ||||
|  | @ -740,10 +741,10 @@ class MyGameWorld(World): | |||
| ### Generate Output | ||||
| 
 | ||||
| ```python | ||||
| from .Mod import generate_mod | ||||
| from .mod import generate_mod | ||||
| 
 | ||||
| 
 | ||||
| def generate_output(self, output_directory: str): | ||||
| def generate_output(self, output_directory: str) -> None: | ||||
|     # How to generate the mod or ROM highly depends on the game | ||||
|     # if the mod is written in Lua, Jinja can be used to fill a template | ||||
|     # if the mod reads a json file, `json.dump()` can be used to generate that | ||||
|  | @ -758,12 +759,10 @@ def generate_output(self, output_directory: str): | |||
|         # make sure to mark as not remote_start_inventory when connecting if stored in rom/mod | ||||
|         "starter_items": [item.name for item | ||||
|                           in self.multiworld.precollected_items[self.player]], | ||||
|         "final_boss_hp": self.final_boss_hp, | ||||
|         # store option name "easy", "normal" or "hard" for difficuly | ||||
|         "difficulty": self.options.difficulty.current_key, | ||||
|         # store option value True or False for fixing a glitch | ||||
|         "fix_xyz_glitch": self.options.fix_xyz_glitch.value, | ||||
|     } | ||||
| 
 | ||||
|     # add needed option results to the dictionary | ||||
|     data.update(self.options.as_dict("final_boss_hp", "difficulty", "fix_xyz_glitch")) | ||||
|     # point to a ROM specified by the installation | ||||
|     src = self.settings.rom_file | ||||
|     # or point to worlds/mygame/data/mod_template | ||||
|  | @ -787,7 +786,7 @@ data already exists on the server. The most common usage of slot data is to send | |||
| to be aware of. | ||||
| 
 | ||||
| ```python | ||||
| def fill_slot_data(self): | ||||
| def fill_slot_data(self) -> Dict[str, Any]: | ||||
|     # in order for our game client to handle the generated seed correctly we need to know what the user selected | ||||
|     # for their difficulty and final boss HP | ||||
|     # a dictionary returned from this method gets set as the slot_data and will be sent to the client after connecting | ||||
|  | @ -839,14 +838,14 @@ from . import MyGameTestBase | |||
| 
 | ||||
| 
 | ||||
| class TestChestAccess(MyGameTestBase): | ||||
|     def test_sword_chests(self): | ||||
|     def test_sword_chests(self) -> None: | ||||
|         """Test locations that require a sword""" | ||||
|         locations = ["Chest1", "Chest2"] | ||||
|         items = [["Sword"]] | ||||
|         # this will test that each location can't be accessed without the "Sword", but can be accessed once obtained. | ||||
|         self.assertAccessDependency(locations, items) | ||||
| 
 | ||||
|     def test_any_weapon_chests(self): | ||||
|     def test_any_weapon_chests(self) -> None: | ||||
|         """Test locations that require any weapon""" | ||||
|         locations = [f"Chest{i}" for i in range(3, 6)] | ||||
|         items = [["Sword"], ["Axe"], ["Spear"]] | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue