mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-04-06 16:18:13 -07:00
Merge remote-tracking branch 'remotes/upstream/main'
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
# Archipelago World Code Owners / Maintainers Document
|
||||
#
|
||||
# This file is used to notate the current "owners" or "maintainers" of any currently merged world folder. For any pull
|
||||
# requests that modify these worlds, a code owner must approve the PR in addition to a core maintainer. This is not to
|
||||
# be used for files/folders outside the /worlds folder, those will always need sign off from a core maintainer.
|
||||
# This file is used to notate the current "owners" or "maintainers" of any currently merged world folder as well as
|
||||
# certain documentation. For any pull requests that modify these worlds/docs, a code owner must approve the PR in
|
||||
# addition to a core maintainer. All other files and folders are owned and maintained by core maintainers directly.
|
||||
#
|
||||
# All usernames must be GitHub usernames (and are case sensitive).
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
/worlds/clique/ @ThePhar
|
||||
|
||||
# Dark Souls III
|
||||
/worlds/dark_souls_3/ @Marechal-L
|
||||
/worlds/dark_souls_3/ @Marechal-L @nex3
|
||||
|
||||
# Donkey Kong Country 3
|
||||
/worlds/dkc3/ @PoryGone
|
||||
@@ -81,6 +81,9 @@
|
||||
# Kirby's Dream Land 3
|
||||
/worlds/kdl3/ @Silvris
|
||||
|
||||
# Kingdom Hearts
|
||||
/worlds/kh1/ @gaithern
|
||||
|
||||
# Kingdom Hearts 2
|
||||
/worlds/kh2/ @JaredWeakStrike
|
||||
|
||||
@@ -106,6 +109,9 @@
|
||||
# Minecraft
|
||||
/worlds/minecraft/ @KonoTyran @espeon65536
|
||||
|
||||
# Mega Man 2
|
||||
/worlds/mm2/ @Silvris
|
||||
|
||||
# MegaMan Battle Network 3
|
||||
/worlds/mmbn3/ @digiholic
|
||||
|
||||
@@ -115,8 +121,8 @@
|
||||
# Noita
|
||||
/worlds/noita/ @ScipioWright @heinermann
|
||||
|
||||
# Ocarina of Time
|
||||
/worlds/oot/ @espeon65536
|
||||
# Old School Runescape
|
||||
/worlds/osrs @digiholic
|
||||
|
||||
# Overcooked! 2
|
||||
/worlds/overcooked2/ @toasterparty
|
||||
@@ -196,6 +202,9 @@
|
||||
# The Witness
|
||||
/worlds/witness/ @NewSoupVi @blastron
|
||||
|
||||
# Yacht Dice
|
||||
/worlds/yachtdice/ @spinerak
|
||||
|
||||
# Yoshi's Island
|
||||
/worlds/yoshisisland/ @PinkSwitch
|
||||
|
||||
@@ -221,6 +230,9 @@
|
||||
# Links Awakening DX
|
||||
# /worlds/ladx/
|
||||
|
||||
# Ocarina of Time
|
||||
# /worlds/oot/
|
||||
|
||||
## Disabled Unmaintained Worlds
|
||||
|
||||
# The following worlds in this repo are currently unmaintained and disabled as they do not work in core. If you are
|
||||
@@ -229,3 +241,11 @@
|
||||
|
||||
# Ori and the Blind Forest
|
||||
# /worlds_disabled/oribf/
|
||||
|
||||
###################
|
||||
## Documentation ##
|
||||
###################
|
||||
|
||||
# Apworld Dev Faq
|
||||
/docs/apworld_dev_faq.md @qwint @ScipioWright
|
||||
|
||||
|
||||
45
docs/apworld_dev_faq.md
Normal file
45
docs/apworld_dev_faq.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# APWorld Dev FAQ
|
||||
|
||||
This document is meant as a reference tool to show solutions to common problems when developing an apworld.
|
||||
It is not intended to answer every question about Archipelago and it assumes you have read the other docs,
|
||||
including [Contributing](contributing.md), [Adding Games](<adding games.md>), and [World API](<world api.md>).
|
||||
|
||||
---
|
||||
|
||||
### My game has a restrictive start that leads to fill errors
|
||||
|
||||
Hint to the Generator that an item needs to be in sphere one with local_early_items. Here, `1` represents the number of "Sword" items to attempt to place in sphere one.
|
||||
```py
|
||||
early_item_name = "Sword"
|
||||
self.multiworld.local_early_items[self.player][early_item_name] = 1
|
||||
```
|
||||
|
||||
Some alternative ways to try to fix this problem are:
|
||||
* Add more locations to sphere one of your world, potentially only when there would be a restrictive start
|
||||
* Pre-place items yourself, such as during `create_items`
|
||||
* Put items into the player's starting inventory using `push_precollected`
|
||||
* Raise an exception, such as an `OptionError` during `generate_early`, to disallow options that would lead to a restrictive start
|
||||
|
||||
---
|
||||
|
||||
### I have multiple settings that change the item/location pool counts and need to balance them out
|
||||
|
||||
In an ideal situation your system for producing locations and items wouldn't leave any opportunity for them to be unbalanced. But in real, complex situations, that might be unfeasible.
|
||||
|
||||
If that's the case, you can create extra filler based on the difference between your unfilled locations and your itempool by comparing [get_unfilled_locations](https://github.com/ArchipelagoMW/Archipelago/blob/main/BaseClasses.py#:~:text=get_unfilled_locations) to your list of items to submit
|
||||
|
||||
Note: to use self.create_filler(), self.get_filler_item_name() should be defined to only return valid filler item names
|
||||
```py
|
||||
total_locations = len(self.multiworld.get_unfilled_locations(self.player))
|
||||
item_pool = self.create_non_filler_items()
|
||||
|
||||
for _ in range(total_locations - len(item_pool)):
|
||||
item_pool.append(self.create_filler())
|
||||
|
||||
self.multiworld.itempool += item_pool
|
||||
```
|
||||
|
||||
A faster alternative to the `for` loop would be to use a [list comprehension](https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions):
|
||||
```py
|
||||
item_pool += [self.create_filler() for _ in range(total_locations - len(item_pool))]
|
||||
```
|
||||
@@ -702,14 +702,18 @@ GameData is a **dict** but contains these keys and values. It's broken out into
|
||||
| checksum | str | A checksum hash of this game's data. |
|
||||
|
||||
### Tags
|
||||
Tags are represented as a list of strings, the common Client tags follow:
|
||||
Tags are represented as a list of strings, the common client tags follow:
|
||||
|
||||
| Name | Notes |
|
||||
|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| AP | Signifies that this client is a reference client, its usefulness is mostly in debugging to compare client behaviours more easily. |
|
||||
| DeathLink | Client participates in the DeathLink mechanic, therefore will send and receive DeathLink bounce packets |
|
||||
| Tracker | Tells the server that this client will not send locations and is actually a Tracker. When specified and used with empty or null `game` in [Connect](#connect), game and game's version validation will be skipped. |
|
||||
| TextOnly | Tells the server that this client will not send locations and is intended for chat. When specified and used with empty or null `game` in [Connect](#connect), game and game's version validation will be skipped. |
|
||||
| Name | Notes |
|
||||
|-----------|--------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| AP | Signifies that this client is a reference client, its usefulness is mostly in debugging to compare client behaviours more easily. |
|
||||
| DeathLink | Client participates in the DeathLink mechanic, therefore will send and receive DeathLink bounce packets. |
|
||||
| HintGame | Indicates the client is a hint game, made to send hints instead of locations. Special join/leave message,¹ `game` is optional.² |
|
||||
| Tracker | Indicates the client is a tracker, made to track instead of sending locations. Special join/leave message,¹ `game` is optional.² |
|
||||
| TextOnly | Indicates the client is a basic client, made to chat instead of sending locations. Special join/leave message,¹ `game` is optional.² |
|
||||
|
||||
¹: When connecting or disconnecting, the chat message shows e.g. "tracking".\
|
||||
²: Allows `game` to be empty or null in [Connect](#connect). Game and version validation will then be skipped.
|
||||
|
||||
### DeathLink
|
||||
A special kind of Bounce packet that can be supported by any AP game. It targets the tag "DeathLink" and carries the following data:
|
||||
|
||||
@@ -24,7 +24,7 @@ display as `Value1` on the webhost.
|
||||
files, and both will resolve as `value1`. This should be used when changing options around, i.e. changing a Toggle to a
|
||||
Choice, and defining `alias_true = option_full`.
|
||||
- All options with a fixed set of possible values (i.e. those which inherit from `Toggle`, `(Text)Choice` or
|
||||
`(Named/Special)Range`) support `random` as a generic option. `random` chooses from any of the available values for that
|
||||
`(Named)Range`) support `random` as a generic option. `random` chooses from any of the available values for that
|
||||
option, and is reserved by AP. You can set this as your default value, but you cannot define your own `option_random`.
|
||||
However, you can override `from_text` and handle `text == "random"` to customize its behavior or
|
||||
implement it for additional option types.
|
||||
@@ -129,6 +129,23 @@ class Difficulty(Choice):
|
||||
default = 1
|
||||
```
|
||||
|
||||
### Option Visibility
|
||||
Every option has a Visibility IntFlag, defaulting to `all` (`0b1111`). This lets you choose where the option will be
|
||||
displayed. This only impacts where options are displayed, not how they can be used. Hidden options are still valid
|
||||
options in a yaml. The flags are as follows:
|
||||
* `none` (`0b0000`): This option is not shown anywhere
|
||||
* `template` (`0b0001`): This option shows up in template yamls
|
||||
* `simple_ui` (`0b0010`): This option shows up on the options page
|
||||
* `complex_ui` (`0b0100`): This option shows up on the advanced/weighted options page
|
||||
* `spoiler` (`0b1000`): This option shows up in spoiler logs
|
||||
|
||||
```python
|
||||
from Options import Choice, Visibility
|
||||
|
||||
class HiddenChoiceOption(Choice):
|
||||
visibility = Visibility.none
|
||||
```
|
||||
|
||||
### Option Groups
|
||||
Options may be categorized into groups for display on the WebHost. Option groups are displayed in the order specified
|
||||
by your world on the player-options and weighted-options pages. In the generated template files, there will be a comment
|
||||
|
||||
@@ -8,7 +8,7 @@ use that version. These steps are for developers or platforms without compiled r
|
||||
|
||||
What you'll need:
|
||||
* [Python 3.8.7 or newer](https://www.python.org/downloads/), not the Windows Store version
|
||||
* **Python 3.12 is currently unsupported**
|
||||
* Python 3.12.x is currently the newest supported version
|
||||
* pip: included in downloads from python.org, separate in many Linux distributions
|
||||
* Matching C compiler
|
||||
* possibly optional, read operating system specific sections
|
||||
@@ -31,14 +31,14 @@ After this, you should be able to run the programs.
|
||||
|
||||
Recommended steps
|
||||
* Download and install a "Windows installer (64-bit)" from the [Python download page](https://www.python.org/downloads)
|
||||
* **Python 3.12 is currently unsupported**
|
||||
* [read above](#General) which versions are supported
|
||||
|
||||
* **Optional**: Download and install Visual Studio Build Tools from
|
||||
[Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/).
|
||||
* Refer to [Windows Compilers on the python wiki](https://wiki.python.org/moin/WindowsCompilers) for details.
|
||||
Generally, selecting the box for "Desktop Development with C++" will provide what you need.
|
||||
* Build tools are not required if all modules are installed pre-compiled. Pre-compiled modules are pinned on
|
||||
[Discord in #archipelago-dev](https://discord.com/channels/731205301247803413/731214280439103580/905154456377757808)
|
||||
[Discord in #ap-core-dev](https://discord.com/channels/731205301247803413/731214280439103580/905154456377757808)
|
||||
|
||||
* It is recommended to use [PyCharm IDE](https://www.jetbrains.com/pycharm/)
|
||||
* Run Generate.py which will prompt installation of missing modules, press enter to confirm
|
||||
|
||||
@@ -303,6 +303,31 @@ generation (entrance randomization).
|
||||
An access rule is a function that returns `True` or `False` for a `Location` or `Entrance` based on the current `state`
|
||||
(items that have been collected).
|
||||
|
||||
The two possible ways to make a [CollectionRule](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/generic/Rules.py#L10) are:
|
||||
- `def rule(state: CollectionState) -> bool:`
|
||||
- `lambda state: ... boolean expression ...`
|
||||
|
||||
An access rule can be assigned through `set_rule(location, rule)`.
|
||||
|
||||
Access rules usually check for one of two things.
|
||||
- Items that have been collected (e.g. `state.has("Sword", player)`)
|
||||
- Locations, Regions or Entrances that have been reached (e.g. `state.can_reach_region("Boss Room")`)
|
||||
|
||||
Keep in mind that entrances and locations implicitly check for the accessibility of their parent region, so you do not need to check explicitly for it.
|
||||
|
||||
#### An important note on Entrance access rules:
|
||||
When using `state.can_reach` within an entrance access condition, you must also use `multiworld.register_indirect_condition`.
|
||||
|
||||
For efficiency reasons, every time reachable regions are searched, every entrance is only checked once in a somewhat non-deterministic order.
|
||||
This is fine when checking for items using `state.has`, because items do not change during a region sweep.
|
||||
However, `state.can_reach` checks for the very same thing we are updating: Regions.
|
||||
This can lead to non-deterministic behavior and, in the worst case, even generation failures.
|
||||
Even doing `state.can_reach_location` or `state.can_reach_entrance` is problematic, as these functions call `state.can_reach_region` on the respective parent region.
|
||||
|
||||
**Therefore, it is considered unsafe to perform `state.can_reach` from within an access condition for an entrance**, unless you are checking for something that sits in the source region of the entrance.
|
||||
You can use `multiworld.register_indirect_condition(region, entrance)` to explicitly tell the generator that, when a given region becomes accessible, it is necessary to re-check a specific entrance.
|
||||
You **must** use `multiworld.register_indirect_condition` if you perform this kind of `can_reach` from an entrance access rule, unless you have a **very** good technical understanding of the relevant code and can reason why it will never lead to problems in your case.
|
||||
|
||||
### Item Rules
|
||||
|
||||
An item rule is a function that returns `True` or `False` for a `Location` based on a single item. It can be used to
|
||||
@@ -630,7 +655,7 @@ def set_rules(self) -> None:
|
||||
|
||||
Custom methods can be defined for your logic rules. The access rule that ultimately gets assigned to the Location or
|
||||
Entrance should be
|
||||
a [`CollectionRule`](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/generic/Rules.py#L9).
|
||||
a [`CollectionRule`](https://github.com/ArchipelagoMW/Archipelago/blob/main/worlds/generic/Rules.py#L10).
|
||||
Typically, this is done by defining a lambda expression on demand at the relevant bit, typically calling other
|
||||
functions, but this can also be achieved by defining a method with the appropriate format and assigning it directly.
|
||||
For an example, see [The Messenger](/worlds/messenger/rules.py).
|
||||
|
||||
@@ -26,8 +26,17 @@ Unless these are shared between multiple people, we expect the following from ea
|
||||
### Adding a World
|
||||
|
||||
When we merge your world into the core Archipelago repository, you automatically become world maintainer unless you
|
||||
nominate someone else (i.e. there are multiple devs). You can define who is allowed to approve changes to your world
|
||||
in the [CODEOWNERS](/docs/CODEOWNERS) document.
|
||||
nominate someone else (i.e. there are multiple devs).
|
||||
|
||||
### Being added as a maintainer to an existing implementation
|
||||
|
||||
At any point, a world maintainer can approve the addition of another maintainer to their world.
|
||||
In order to do this, either an existing maintainer or the new maintainer must open a PR updating the
|
||||
[CODEOWNERS](/docs/CODEOWNERS) file.
|
||||
This change must be approved by all existing maintainers of the affected world, the new maintainer candidate, and
|
||||
one core maintainer.
|
||||
To help the core team review the change, information about the new maintainer and their contributions should be
|
||||
included in the PR description.
|
||||
|
||||
### Getting Voted
|
||||
|
||||
@@ -35,7 +44,7 @@ When a world is unmaintained, the [core maintainers](https://github.com/orgs/Arc
|
||||
can vote for a new maintainer if there is a candidate.
|
||||
For a vote to pass, the majority of participating core maintainers must vote in the affirmative.
|
||||
The time limit is 1 week, but can end early if the majority is reached earlier.
|
||||
Voting shall be conducted on Discord in #archipelago-dev.
|
||||
Voting shall be conducted on Discord in #ap-core-dev.
|
||||
|
||||
## Dropping out
|
||||
|
||||
@@ -51,7 +60,7 @@ for example when they become unreachable.
|
||||
For a vote to pass, the majority of participating core maintainers must vote in the affirmative.
|
||||
The time limit is 2 weeks, but can end early if the majority is reached earlier AND the world maintainer was pinged and
|
||||
made their case or was pinged and has been unreachable for more than 2 weeks already.
|
||||
Voting shall be conducted on Discord in #archipelago-dev. Commits that are a direct result of the voting shall include
|
||||
Voting shall be conducted on Discord in #ap-core-dev. Commits that are a direct result of the voting shall include
|
||||
date, voting members and final result in the commit message.
|
||||
|
||||
## Handling of Unmaintained Worlds
|
||||
|
||||
Reference in New Issue
Block a user