Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Plando Items "rewrite" #3046

Open
wants to merge 46 commits into
base: main
Choose a base branch
from

Conversation

Silvris
Copy link
Collaborator

@Silvris Silvris commented Mar 28, 2024

What is this fixing or adding?

This PR is the combination of three major changes to plando items.

  • Moves plando items to the options api as a member of PerGameCommonOptions
  • Changes the placement of items to use fill_restrictive, which means plando should be capable of avoiding placements that can never result in a playable world
  • Plando now evaluates item and location groups.

How was this tested?

Manually via generating games with yamls using plando items. Opening as draft since any game using pre_fill will need thorough testing with this approach (KDL3 was already found to be bugged).

Ran unittests, but more unittests should likely be added.

Silvris added 3 commits March 27, 2024 22:30
the test is still busted, but now it actually plandos the items
@github-actions github-actions bot added the affects: core Issues/PRs that touch core and may need additional validation. label Mar 28, 2024
Options.py Outdated Show resolved Hide resolved
@alwaysintreble alwaysintreble added is: enhancement Issues requesting new features or pull requests implementing new features. is: refactor/cleanup Improvements to code/output readability or organizization. labels Mar 28, 2024
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
@Exempt-Medic
Copy link
Member

It seems like this removes the ability to have plando blocks without any locations listed. For example, so that specific items end up in specific worlds. Is the intended workaround to use Everywhere?

count = new_block["count"]
failed(f"Plando count {count} greater than locations specified", block.force)
new_block["count"] = len(new_block["locations"])
new_block["count"]["target"] = multiworld.random.randint(new_block["count"]["min"],
Copy link
Member

@Exempt-Medic Exempt-Medic Mar 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is actually already an error on main, but it might be worth mentioning here anyway: If either of the two above if blocks trigger, new_block["count"] becomes an int, so min and max don't exist and generation fails with TypeError: 'int' object is not subscriptable on this line (880)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump, I guess?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely thought I had changed that already.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you totally might have, you just never replied. I can check again XD

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it is definitely unchanged.

@Silvris
Copy link
Collaborator Author

Silvris commented Mar 29, 2024

It seems like this removes the ability to have plando blocks without any locations listed. For example, so that specific items end up in specific worlds. Is the intended workaround to use Everywhere?

I believe I missed this usecase (plando items guide doesn't mention it, and it's built into get_unfilled_locations_for_players so I couldn't tell it from the plando code).

@BadMagic100
Copy link
Collaborator

Disclaimer: I have not looked at the code yet

It might be worth considering and documenting/fixing possible negative interactions with #3032 if you haven't already

I'm also curious about how pre_fill is impacted as it may affect generic ER

@beauxq
Copy link
Collaborator

beauxq commented Mar 29, 2024

Some people use plando when they WANT to make something that will be seen as unbeatable according to the logic.
Will this still be possible with this change?

@Silvris
Copy link
Collaborator Author

Silvris commented Mar 29, 2024

Some people use plando when they WANT to make something that will be seen as unbeatable according to the logic. Will this still be possible with this change?

It might still be possible, but current methods (such as locking the item behind a location that logically requires it) will no longer work. It should be noted that this doesn't prevent impossible combinations (that usually end in fill error) such as filling your entire sphere 1 with junk.

@Silvris
Copy link
Collaborator Author

Silvris commented Mar 29, 2024

Disclaimer: I have not looked at the code yet

It might be worth considering and documenting/fixing possible negative interactions with #3032 if you haven't already

I'm also curious about how pre_fill is impacted as it may affect generic ER

This should be fine, as we use the actual instance of the item instead of creating a new item and then removing using that. It's definitely worth testing though.

It appears that any world that uses pre_fill to place items that are not in the itempool must also define get_pre_fill_items so that the state used for plando can account for those items.

@Silvris
Copy link
Collaborator Author

Silvris commented May 21, 2024

List of worlds that implement pre_fill and not get_pre_fill_items:

  • Adventure (does not place progression in prefill)
  • Blasphemous
  • Castlevania 64 (does not place progression in prefill)
  • Hylics 2
  • KH2
  • KDL3 (KDL3: Version 2.0.0 #3323)
  • Pokemon Emerald
  • Pokemon RB
  • Shivers
  • Super Metroid (does not place progression)

Worlds that implement get_pre_fill_items but do not actually include all pre_fill items

  • A Link to the Past
  • Raft (very funny)

I will need to check all of these later to confirm if this is the proper reason for some worlds having issues.

Options.py Outdated Show resolved Hide resolved
@Exempt-Medic
Copy link
Member

I opened a PR including/addressing my comments and also some discussion in ap-core-dev on the item group unrolling methods

@NewSoupVi
Copy link
Member

NewSoupVi commented Nov 21, 2024

I'm going to put my concerns on this PR so that they're documented somewhere.

I don't like that this is trying to make "Event Plando" work.

At first, it looks like one upside and one downside.
The upside is: World devs now have an easy way to make "Dungeon Reward Plando" work.
The downside is: We can't do validation ahead of time using location_name_to_id and item_name_to_id, and the plando code has to be bigger.

But I don't even actually think the "upside" is a genuine upside.
Any given instance of something that "wants" Event Plando can be realized through a custom option. We could even make a cute new option class like "PlandoMatchingOption" that takes two sets of valid keys to match to each other.
Having it in ItemPlando looks nice because it makes ItemPlando look "powerful" and provides an out-of-the-box way to do this kind of thing immediately, it's a cute extra feature and I'm sure it was very fun to add this little cherry ontop, but I don't like it at all.

  1. Breaking different behavior into multiple options is a good thing. The fact that we're talking about one set of items being able to be plandoed on one set of locations, and then a different set of items only being plandoed on a different set of locations, but we are realizing this through one option with one combined syntax and one combined docstring that now has to make sure the user isn't trying to put one type of item on the other type of location, rings an alarm bell for me. Heck, what if a game has two sets of events that can't go onto each other? Like in OoT, Local Songs and local Dungeon Rewards. Should they override the plando code somehow or realize this through item rules? My opinion is: Stop. These should be separate options
  2. This is the much bigger point. In terms of how we design core features, hooking into the generic player-facing options for custom world features should be discouraged. These options should be as simple as possible and behave consistently across games, and we should be encouraging people to make their own custom options if they want custom behavior. If there is a common use case that is hard to realize, we make a new generic option class to subclass. We should not be effectively saying: One world's plando_items should work different from another's, and that's fine.

I am extremely uncomfortable with the world where a world dev says "I want to shuffle my major event items, but I also want the user to be able to plando them" and the suggested solution is "Use ItemPlando, and subclass it with a docstring to explain it", and suddenly we have 5 games that rely on this behavior and can never go back on it. And then we realize we didn't account for "world: null" or something. No no no no no :( It should be "Here's how you can make your own custom plando option for your local randomization"

This is essentially me saying: I do not approve. However, Berserker has already approved the PR, so maybe this is too late or I'm outvoted here.

@Silvris
Copy link
Collaborator Author

Silvris commented Nov 21, 2024

I don't like that this is trying to make "Event Plando" work.

The problem is that event plando is already a usecase supported by core and is being used by worlds. Removing it requires adjusting even more worlds, or removing functionality.

@Silvris
Copy link
Collaborator Author

Silvris commented Nov 21, 2024

The downside is: We can't do validation ahead of time using location_name_to_id and item_name_to_id, and the plando code has to be bigger.

This is already the case with plando, not every item/location that we can plando to are in datapackage.

@Exempt-Medic
Copy link
Member

The downside is: We can't do validation ahead of time using location_name_to_id and item_name_to_id, and the plando code has to be bigger.

This is already the case with plando, not every item/location that we can plando to are in datapackage.

Aren't the only exceptions to this events?

@NewSoupVi
Copy link
Member

NewSoupVi commented Nov 21, 2024

The problem is that event plando is already a usecase supported by core and is being used by worlds. Removing it requires adjusting even more worlds, or removing functionality.

I would actually like to do this. But dropping a feature is obviously a taller ask, I get that.

For the sake of completeness, could you provide an example of a world that currently supports & uses this? Or ideally if you have the full list of supported worlds, but I don't expect you're just gonna have that on hand lol

@Silvris
Copy link
Collaborator Author

Silvris commented Nov 21, 2024

For the sake of completeness, could you provide an example of a world that currently supports & uses this? Or ideally if you have the full list of supported worlds, but I don't expect you're just gonna have that on hand lol

Admittedly, I'm pretty sure it's just A Link to the Past at the moment. But it being supported there is much stronger on the intent, given it is a world maintained by a core maintainer.

@NewSoupVi
Copy link
Member

NewSoupVi commented Nov 21, 2024

If there is an example of a supported world losing a currently working feature if event plando is dropped, then I'm going to revoke my disapproval, but I will still strongly discourage future use of this feature & if I have time, push for a removal of the feature in a followup PR changing those worlds. (Essentially, I will considered it "grandfathered" - The first thing I'd probably do is open a PR that makes it output a warning)

Edit: Sniped

@beauxq
Copy link
Collaborator

beauxq commented Nov 21, 2024

However, Berserker has already approved the PR, so maybe this is too late or I'm outvoted here.

I was seeing Berserker's review as just the a review of the LTTP changes, since that's how his review was requested - not of the PR overall.

Silvris requested a review from Berserker66 as a code owner

And that links to the LTTP line in codeowners

I could be misunderstanding though.

Copy link
Member

@Exempt-Medic Exempt-Medic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More just putting this here to remove my approval, but this has conflicts and, for me, is waiting on at least Silvris#12 and potentially Silvris#11

Copy link
Member

@Exempt-Medic Exempt-Medic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My comments were addressed. I do think there should be some discussion (maybe even a poll?) on how to unfold groups (especially item groups). I did some testing with various yamls and plando configurations, certainly not enough overall but 🤷 not exactly the easiest thing to test all the states for. The timing/location of all the value/type checking is a bit of a mess, but it was like that beforehand and was missing quite a lot of it anyway.
Basically just https://discord.com/channels/731205301247803413/731214280439103580/1306329230392692757

Options.py Outdated Show resolved Hide resolved
Options.py Outdated Show resolved Hide resolved
Silvris and others added 3 commits November 29, 2024 22:39
Co-authored-by: Doug Hoskisson <beauxq@users.noreply.github.com>
maybe do this for the others? out of scope here though
@Exempt-Medic Exempt-Medic removed the waiting-on: author Issue/PR is waiting for feedback or changes from its author. label Dec 3, 2024
@Mysteryem
Copy link
Contributor

It doesn't look like this rewrite fixes early_locations/non_early_locations, is that something the rewrite could/should also fix?

Targetting early_locations across more than one world of the same game gathers the names of the early locations across these worlds into a single list, but just because a location is early in one world, does not mean that location is also early in another world (e.g. entrance rando). This means that item plando targetting early_locations can place an item into a world where the location is not early, just because in one of the worlds that location is early.

@Exempt-Medic
Copy link
Member

It doesn't look like this rewrite fixes early_locations/non_early_locations, is that something the rewrite could/should also fix?

FWIW, this is known. To me, with the number of changes already in this PR, I'm not sure how well adding more in will go. I think Silvris was waiting until after this since it would require some pretty significant changes to the way candidate locations work or adding player-specific locations for early/non-early which would also be a good bit of extra work/code

@Silvris
Copy link
Collaborator Author

Silvris commented Dec 11, 2024

It doesn't look like this rewrite fixes early_locations/non_early_locations, is that something the rewrite could/should also fix?

Targetting early_locations across more than one world of the same game gathers the names of the early locations across these worlds into a single list, but just because a location is early in one world, does not mean that location is also early in another world (e.g. entrance rando). This means that item plando targetting early_locations can place an item into a world where the location is not early, just because in one of the worlds that location is early.

While I'm not necessarily against doing this change in this PR, I think scope here has already gotten way out of hand, and the changes would be much easier to review isolated (especially with the amount of review having already gone into this PR). The idea I have to fix it effectively is a rewrite of the locations handling to be str-int pairs of location/player, which needs to be adjusted in a number of places.

@@ -114,6 +114,14 @@ def set_rules(self):
def create_regions(self):
create_regions(self.multiworld, self.player)

def get_pre_fill_items(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raft's pre_fill has been removed as of a948697

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
affects: core Issues/PRs that touch core and may need additional validation. is: enhancement Issues requesting new features or pull requests implementing new features. is: refactor/cleanup Improvements to code/output readability or organizization. waiting-on: core-review Issue/PR has been peer-reviewed and is ready to be merged or needs input from a core maintainer.
Projects
None yet
Development

Successfully merging this pull request may close these issues.