shedaniel / cloth-config

Client-Sided API for Minecraft 1.14
Other
194 stars 71 forks source link

Add GUI Registry pre/post hooks #215

Open MattSturgeon opened 1 year ago

MattSturgeon commented 1 year ago

Overview

This PR adds the ability to register pre & post hooks with the GuiRegistry. Registered hooks are run before and after each Field is transformed into GUIs, allowing users to (for example) get a reference to the final GUIs.

Motivation

A user could achieve a similar effect using a GuiTransformer, however there is a risk that another transformer may "pull the rug out" and remove/replace the GUI in question. Hooks solve this issue with an immutable GUI list and not using a return value. Therefore a post hook is guaranteed to run after all destructive changes have happened.

Without this PR, a user could register their own requirements using the transformer API, which will work for most cases.

With this PR, a user can register requirements without having to make any assumptions.

This PR also starts the ball rolling for a dedicated AutoConfig Requirements API using declarative annotations.

Question

The above motivation hopefully justifies having a "post hook" API, however I've only included a "pre hook" for completeness.
Is there any reasom to include or not include a "pre hook" in this PR? If not, should "post hook" be renamed?

Related changes

This PR includes a number of small related changes to cleanup and modernize GuiRegistry's internal implementation. Namely:

These changes could be dropped or moved to a different PR, however I felt it was simpler to include them here as they lay the foundation for this PR's core changes.

You may find it easier to review this PR one commit at a time.

A temporary "example" commit is also included, to aid in testing & reviewing. This commit should be dropped before merging (d789d6ca5f5c3fdff4f9526448ca1d18cc16150f).

Original description

Autoconfig requirement support will require operating with _finished_ Config Entry GUIs in order to _a)_ keep track of what GUIs have been created in a lookup table and _b)_ register GUIs that have dependencies declared with a `RequirementManager`. This could be done internally by injecting additional code into `GuiRegistry` or by adding default `GuiTransformers`, however the former seems short-sighted and the latter isn't very robust, seeing as **there's no guarantee the `gui` list won't change** (or be entirely replaced) by another transformer running after us. IMO the best solution is a "post" event hook. The handler can be passed an `Unmodifiable List`, ensuring that the GUI objects the handler sees are the same ones that will actually be used. It seems silly to do this entirely internally, and strange to have a public "post" hook without a "pre" hook, so this PR follows the above to its logical conclusion and adds an experimental public API to register pre & post event hooks on `GuiRegistry`. I wasn't sure whether or not it made sense for event hooks to be subject to predicates (in the same way that registered `GuiProvider` and `GuiTransformer`s are). This can be added easily if desired, but will increase the number of new experimental API methods on `GuiRegistry` a lot... This PR is blocking Requirement support for autoconfig (as per #195 & #204).

MattSturgeon commented 1 year ago

d789d6ca5f5c3fdff4f9526448ca1d18cc16150f (debug prints) is included in this PR for demonstrative purposes only. It shouldn't actually be merged.

For additional example usage, you could refer to my in-progress autoconfig-dependencies branch:

public class DefaultGuiHooks {
    public static GuiRegistry apply(GuiRegistry registry) {

        registry.registerPostHook((guis, i18n, field, config, defaults, guiProvider) ->
                guiProvider.getLookupTable().register(field, guis));

        registry.registerPostHook((guis, i18n, field, config, defaults, guiProvider) ->
                guiProvider.getRequirementManager().registerRequirements(guis, field));

        return registry;
    }
}
MattSturgeon commented 11 months ago

I've pushed some changes and clarified the PR description.