Core: linearish, create playthrough alternative - #6326
Open
Severencir wants to merge 16 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is this fixing or adding?
This is a new pr to replace one that was lost with the deletion of a branch.
the algorithm is linear with number of unique advancements x spheres. with progression balancing on, number of spheres tends to stay relatively consistent. without progression balancing, spheres grow sublinearly with number of players and seems to plateu around 300 from my testing. either way it has consistently beaten stock create playthrough in every test i have made.
the algorithm first builds spheres and takes a state snapshot at each sphere to use as a base for later sphere processing.
it then separates locations that require cross world logic by rebuilding the spheres per player using only that players items. any locations that are not reachable at the same sphere they were with the global sphere build are considered global (relies on another players' items)
we loop through every sphere in reverse sphere order looking for an irreducible set of items that allow us to beat the game and collect locations that are required to beat the game or required for other required locations.
the main loop relies on a couple patterns:
the search method takes a bulk group of locations and looks for the minimal set from the sphere that satisfies the group using a binary search with a state cache stack. we collect all items in a sphere in order to a probe point. when we find the item that satisfies the whole set, we know that it is required by the set and nothing before it can satisfy the set, and it's the earliest point in the sphere where that is true, therefore it is minimal to the set we are searching, and necessary. we keep searching in this manner until we find all such items.
for global items we binary search the whole sphere, but for others, we only use player scoped states and their partition of the sphere.
for efficiency and minimal-ness, we force all higher sphere required items into the state before we search for dependencies so that we can let the set use them as prerequisites. this allows items to become their own prerequisite though, so we have to individually resolve any locations that are still not able to be reached after the search. because we are now adding items that were not found in the bulk search, we lose the minimal guarantee, so we can run it again with the circular resolving items forced to re-minimize. loop through that until there are no circular dependencies.
because the items required to resolve circular dependencies, as well as the prerequisites found in the global search, were found outside the last bulk search, we cannot guarantee that these are necessary. but they are few, and we only need to know if we can reach higher spheres with them, so we do a typical remove and test but cheaper than the stock method and on only a handful of locations.
because we know that all lower sphere copies of a type of fungible item are required whenever we find any required, we can simply promote them to the required set, add them to the base, and move on to the rest of the sphere.
at the end we use a can_beat_game check to ensure that the set is sufficient. falling back to stock if it fails, or any other step cannot fulfill something.
How was this tested?
this was tested by generating many seeds (i have lost track) across 5-320 player sets with default and randomized settings all coming back sufficient and minimal. (unable to be reduced by the remove and test method)
additional testing was done with hk's grubhunt and item-links with all successful
i even found other bugs with generation while testing and submitted a fix for one i was able to identify the cause of.