-
-
Notifications
You must be signed in to change notification settings - Fork 177
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
Simplified usage of GatherDataEvent #1427
base: 1.21.x
Are you sure you want to change the base?
Conversation
rewrote gatherData using the helpers
|
src/main/java/net/neoforged/neoforge/data/event/GatherDataEvent.java
Outdated
Show resolved
Hide resolved
As one comment, the "complicated" datagen that is simplified by the helpers only really applies to vanilla or Forge datagen, I've got quite a few custom data generators that need more arguments, such as requiring instances of one being passed to the other. It make me wonder if this is the best approach for adding such helpers, or if it wouldn't be better to do in some way that can be extended to custom data generators from mods. As another comment, it looks probably 10x cleaner if you make a local variable for |
just left that as it was, I'll change it |
this should cover like 95% of all cases but you are correct. In case someone has an idea for a better approach let me know. |
I could make addProvider return the added provider. var example = event.addProvider(include, ExampleProvider::new);
event.addProvider(include, (...) -> new OtherProvider(..., example, ...); |
this would introduce generics (because the return type has to match the input type) which indeed leads to ambiguous calls. to fix this I would have to rename builder methods to |
The idea is good; I would like to see some streamlining in the data provider registration process (especially with the requirement that registry set builders be registered first and then that object propagated downwards); But, I would also like to explore some alternatives and assess some design considerations on what type of utility is the best from a user-facing perspective. Externally, I've developed an alternative solution to this: the DataGenBuilder class, which has the following example usage1: @SubscribeEvent
public void data(GatherDataEvent event) {
DataGenBuilder.create(MODID, "minecraft")
.registry(Registries.ENCHANTMENT, ApothEnchantmentProvider::bootstrap)
.provider(LootProvider::create)
.provider(EnchTagsProvider::new)
.provider(EnchRecipeProvider::new)
.build(event);
} This current structure has some limitations (it makes no differentiation between Between the two solutions, I think I find myself leaning towards Footnotes |
event.createProvider(includeServer, NeoForgeAdvancementProvider::new); | ||
event.createBlockAndItemTags(NeoForgeBlockTagsProvider::new, NeoForgeItemTagsProvider::new); | ||
event.createProvider(includeServer, NeoForgeEntityTypeTagsProvider::new); | ||
event.createProvider(includeServer, NeoForgeFluidTagsProvider::new); | ||
event.createProvider(includeServer, NeoForgeEnchantmentTagsProvider::new); | ||
event.createProvider(includeServer, NeoForgeRecipeProvider::new); | ||
event.createProvider(includeServer, NeoForgeLootTableProvider::new); | ||
event.createProvider(includeServer, NeoForgeBiomeTagsProvider::new); | ||
event.createProvider(includeServer, NeoForgeStructureTagsProvider::new); | ||
event.createProvider(includeServer, NeoForgeDamageTypeTagsProvider::new); | ||
event.createProvider(includeServer, NeoForgeRegistryOrderReportProvider::new); | ||
event.createProvider(includeServer, NeoForgeDataMapsProvider::new); | ||
|
||
event.createProvider(includeClient, NeoForgeSpriteSourceProvider::new); | ||
event.createProvider(includeClient, VanillaSoundDefinitionsProvider::new); | ||
event.createProvider(includeClient, NeoForgeLanguageProvider::new); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given these general usages, it might make more sense to have additional createServerProvider
and createClientProvider
methods instead of requiring the caller to pass boolean run
.
The current interface-based definition structure means this would lead to mass method overload though, so I'm not sure how clean that would be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given these general usages, it might make more sense to have additional
createServerProvider
andcreateClientProvider
methods instead of requiring the caller to passboolean run
.
great idea, but it would tripple the method count (we still need one with parameter for dynamic scenarios or when using includeDev/includeReports). do we want this? I also talked about automatically detecting when to run what via some sort of marker in the provider class or pattern matching in addProvider.
The current interface-based definition structure means this would lead to mass method overload though, so I'm not sure how clean that would be.
yes, i don't like that too but i couldn't come up with a better option.
I did not want to use generic interfaces (like BiFunction) because I find them hard to read (BiFunction<PackOutput, CompletableFuture<HolderLookup.Provider>, T>
). DataProviderFromOutputLookupFileHelper<T>
is only slightly better though. I decided not to use DataProvider.Factory<T>
for consistency but i could swap it to remove one interface.
As I mentioned before somewhere an alternative would be a depency injection system but I feel like that would be overkill. This would also fix cases where users reorder their parameters. I might consider it if there are other usecases for such a system. Alternativly we could use a library. (or does neo already has one?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As @KnightMiner pointed out there are scenarios where data providers depend on other providers to run (e.g. item tag provider). I'm not sure how this would be possible with your |
I'm curious to hear Knight's opinion on the builder approach. While true it does not supply an OOTB solution for chaining additional generators (nor custom generators), the fact that it is an extensible object means modders can add those utilities themselves if necessary or desired. |
I think this can be built on top of this pr once it is merged. I have to admit that I don't feel confident enough to built something like this on my own. |
@BarionLP, this pull request has conflicts, please resolve them for this PR to move forward. |
This reverts commit b62c6c9.
A while ago i showed a helper class to reduce the boilerplate of adding DataProviders to a DataGenerator during GatherDataEvent on discord.
This PR aims to implement those helper methods directly into the GatherDataEvent as Minecraft moves more and more to an data driven approach leading to more and more DataProviders.
NeoForge datagen without helper:
NeoForge DataGen with helper:
I also showed a simplification for the LootTableProvider which I would contribute in the future
I thought about removing the need to define when to run which provider as every provider type is either server or client.
This could be done through a maker on the base providers or through pattern matching in the addProvider method.
Both approaches are not perfect and @Technici4n pointed out the code saved is not worth the effort but i do think it could greatly help beginners.
my original implementation: https://github.com/Ametrin-Studios/Ametrin/blob/master/Ametrin/src/main/java/com/ametrinstudios/ametrin/data/DataProviderHelper.java