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

Model Loading API v1 #3145

Merged
merged 28 commits into from
Jul 18, 2023
Merged

Conversation

Technici4n
Copy link
Member

@Technici4n Technici4n commented Jun 25, 2023

This PR deprecates and supersedes the old fabric-models-v0 module.

Refactors compared to v0

Model loading hooks

Mods now register a single ModelLoadingPlugin for any change they want to make to the model loading process. (Or multiple plugins if they want to). This replaces the old ModelLoadingRegistry.

Here is an example:

ModelLoadingPlugin.register(pluginContext -> {
    // ResourceManager access is provided like in the v0 API, but in a central place, and can be used for shared processing in the plugin.
    ResourceManager manager = pluginContext.resourceManager();

    // Model resource providers still exist, but they are called model resolvers now
    pluginContext.resolveModel().register(context -> {
        // ...
    });
});

ModelVariantProvider -> BlockStateResolver

ModelVariantProvider was heavily reworked, and is now replaced by the BlockStateResolver, with a much better defined contract.

ModelResourceProvider -> ModelResolver

The resource provider is mostly unchanged. The biggest difference is that it is now registered as an event listener. This allows mods to use event phases for ordering between conflicting providers resolvers.

Removed custom exception

Additionally, ModelProviderException could be thrown by a variant or resource provider in the v0 API. This was not explained in the documentation, and would according to the code stop further processing of the providers and log an error.

In the new API, any Exception is caught and logged. If that happens, the other resolvers are still processed. There is no custom Exception subclass anymore.

Helper method to get a BakedModel by Identifier from the manager

The v0 had such a method in a helper class: BakedModelManagerHelper#getBakedModel. It is now interface-injected instead. See FabricBakedModelManager.

New model wrapping hooks

New hooks are added for the various needs of mods that want to override or wrap specific models. Thanks to @embeddedt for contributing an initial version of them!

Here is an example of wrapping the gold model to remove the bottom quads, for example:

ModelLoadingPlugin.register(pluginContext -> {
	// remove bottom face of gold blocks
	pluginContext.modifyModelAfterBake().register(ModelModifier.WRAP_PHASE, (model, context) -> {
		if (context.identifier().getPath().equals("block/gold_block")) {
			return new DownQuadRemovingModel(model);
		} else {
			return model;
		}
	});
});

There are 3 events, for the following use cases:

  • Wrapping UnbakedModels right when they are loaded. This allows replacing them entirely in dependent models too.
  • Wrapping UnbakedModels right before they are baked. This allows replacing them without affecting dependent models (which might not be expecting a model class change).
  • Wrapping BakedModels right when they are baked.

Multiple mods have implemented their own version of them. Providing them in Fabric API will make it easier on these mods, and will additionally allow optimization mods that perform on-demand model loading to simply fire the hooks themselves instead of working around injections performed by other mods.

@Technici4n Technici4n requested a review from a team July 2, 2023 23:17
@Technici4n Technici4n added the last call If you care, make yourself heard right away! label Jul 13, 2023
/**
* Function that can be used to retrieve sprites.
*/
Function<SpriteIdentifier, Sprite> textureGetter();
Copy link
Member

Choose a reason for hiding this comment

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

Should this be Sprite getTexture(SpriteIdentifier) instead? Exposing functional interfaces as method return values is a bit strange.

Copy link
Member Author

Choose a reason for hiding this comment

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

This mimics what UnbakedModel receives - as discussed on Discord it's fine either way.

Technici4n and others added 16 commits July 15, 2023 11:14
* Remove ModelLoaderInstance.finish()

It harms optimization mods that implement dynamic model loading

* Add model loading observation events

Useful for wrapping models, modifying models, etc

* Move mutable parameter out of context record to avoid withModel

* Spotless

* Renames

* Add event phases, restructure modifier interfaces to be under shared parent class

* Clean up test mod, use ForwardingBakedModel instead of hacks

* Phase javadoc

* Remove null check for loader in ModelLoaderInstance, can't occur
anymore after removing finish()

* More javadoc

* More tests
Technici4n and others added 2 commits July 15, 2023 13:30
…c/impl/client/model/loading/ModelLoadingEventDispatcher.java

Co-authored-by: Juuz <[email protected]>
@modmuss50 modmuss50 self-requested a review July 18, 2023 09:42
@modmuss50 modmuss50 added the merge me please Pull requests that are ready to merge label Jul 18, 2023
@modmuss50 modmuss50 merged commit 9386d8a into FabricMC:1.20.1 Jul 18, 2023
5 checks passed
modmuss50 pushed a commit that referenced this pull request Jul 18, 2023
This PR deprecates and supersedes the old `fabric-models-v0` module.

## Refactors compared to v0
### Model loading hooks
Mods now register a single `ModelLoadingPlugin` for any change they want to make to the model loading process. (Or multiple plugins if they want to). This replaces the old `ModelLoadingRegistry`.

Here is an example:

```java
ModelLoadingPlugin.register(pluginContext -> {
    // ResourceManager access is provided like in the v0 API, but in a central place, and can be used for shared processing in the plugin.
    ResourceManager manager = pluginContext.resourceManager();

    // Model resource providers still exist, but they are called model resolvers now
    pluginContext.resolveModel().register(context -> {
        // ...
    });
});
```

#### `ModelVariantProvider` -> `BlockStateResolver`
`ModelVariantProvider` was heavily reworked, and is now replaced by the `BlockStateResolver`, with a much better defined contract.

#### `ModelResourceProvider` -> `ModelResolver`
The resource provider is mostly unchanged. The biggest difference is that it is now registered as an event listener. This allows mods to use event phases for ordering between conflicting ~~providers~~ resolvers.

#### Removed custom exception
Additionally, `ModelProviderException` could be thrown by a variant or resource provider in the v0 API. This was not explained in the documentation, and would according to the code stop further processing of the providers and log an error.

In the new API, any `Exception` is caught and logged. If that happens, the other resolvers are still processed. There is no custom `Exception` subclass anymore.

### Helper method to get a `BakedModel` by `Identifier` from the manager
The v0 had such a method in a helper class: `BakedModelManagerHelper#getBakedModel`. It is now interface-injected instead. See `FabricBakedModelManager`.

## New model wrapping hooks
New hooks are added for the various needs of mods that want to override or wrap specific models. Thanks to @embeddedt for contributing an initial version of them!

Here is an example of wrapping the gold model to remove the bottom quads, for example:
```java
ModelLoadingPlugin.register(pluginContext -> {
	// remove bottom face of gold blocks
	pluginContext.modifyModelAfterBake().register(ModelModifier.WRAP_PHASE, (model, context) -> {
		if (context.identifier().getPath().equals("block/gold_block")) {
			return new DownQuadRemovingModel(model);
		} else {
			return model;
		}
	});
});
```

There are 3 events, for the following use cases:
- Wrapping `UnbakedModel`s right when they are loaded. This allows replacing them entirely in dependent models too.
- Wrapping `UnbakedModel`s right before they are baked. This allows replacing them without affecting dependent models (which might not be expecting a model class change).
- Wrapping `BakedModel`s right when they are baked.

Multiple mods have implemented their own version of them. Providing them in Fabric API will make it easier on these mods, and will additionally allow optimization mods that perform on-demand model loading to simply fire the hooks themselves instead of working around injections performed by other mods.

Co-authored-by: embeddedt <[email protected]>
Co-authored-by: PepperCode1 <[email protected]>
Co-authored-by: Juuz <[email protected]>
Signed-off-by: modmuss50 <[email protected]>
EnnuiL added a commit to QuiltMC/quilted-fabric-api that referenced this pull request Aug 1, 2023
* Model Loading API v1 (FabricMC#3145)

This PR deprecates and supersedes the old `fabric-models-v0` module.

## Refactors compared to v0
### Model loading hooks
Mods now register a single `ModelLoadingPlugin` for any change they want to make to the model loading process. (Or multiple plugins if they want to). This replaces the old `ModelLoadingRegistry`.

Here is an example:

```java
ModelLoadingPlugin.register(pluginContext -> {
    // ResourceManager access is provided like in the v0 API, but in a central place, and can be used for shared processing in the plugin.
    ResourceManager manager = pluginContext.resourceManager();

    // Model resource providers still exist, but they are called model resolvers now
    pluginContext.resolveModel().register(context -> {
        // ...
    });
});
```

#### `ModelVariantProvider` -> `BlockStateResolver`
`ModelVariantProvider` was heavily reworked, and is now replaced by the `BlockStateResolver`, with a much better defined contract.

#### `ModelResourceProvider` -> `ModelResolver`
The resource provider is mostly unchanged. The biggest difference is that it is now registered as an event listener. This allows mods to use event phases for ordering between conflicting ~~providers~~ resolvers.

#### Removed custom exception
Additionally, `ModelProviderException` could be thrown by a variant or resource provider in the v0 API. This was not explained in the documentation, and would according to the code stop further processing of the providers and log an error.

In the new API, any `Exception` is caught and logged. If that happens, the other resolvers are still processed. There is no custom `Exception` subclass anymore.

### Helper method to get a `BakedModel` by `Identifier` from the manager
The v0 had such a method in a helper class: `BakedModelManagerHelper#getBakedModel`. It is now interface-injected instead. See `FabricBakedModelManager`.

## New model wrapping hooks
New hooks are added for the various needs of mods that want to override or wrap specific models. Thanks to @embeddedt for contributing an initial version of them!

Here is an example of wrapping the gold model to remove the bottom quads, for example:
```java
ModelLoadingPlugin.register(pluginContext -> {
	// remove bottom face of gold blocks
	pluginContext.modifyModelAfterBake().register(ModelModifier.WRAP_PHASE, (model, context) -> {
		if (context.identifier().getPath().equals("block/gold_block")) {
			return new DownQuadRemovingModel(model);
		} else {
			return model;
		}
	});
});
```

There are 3 events, for the following use cases:
- Wrapping `UnbakedModel`s right when they are loaded. This allows replacing them entirely in dependent models too.
- Wrapping `UnbakedModel`s right before they are baked. This allows replacing them without affecting dependent models (which might not be expecting a model class change).
- Wrapping `BakedModel`s right when they are baked.

Multiple mods have implemented their own version of them. Providing them in Fabric API will make it easier on these mods, and will additionally allow optimization mods that perform on-demand model loading to simply fire the hooks themselves instead of working around injections performed by other mods.

Co-authored-by: embeddedt <[email protected]>
Co-authored-by: PepperCode1 <[email protected]>
Co-authored-by: Juuz <[email protected]>

* Add dynamic registry API (FabricMC#3163)

* Add API for adding custom dynamic registries

Closes FabricMC#1012, supersedes FabricMC#1031 and FabricMC#2719.

* Add missing license headers

* Clarify RegistryLoaderMixin namespace injection

* Replace event with static registration, add skeleton for sorting registries

* Fix typo

* Refactor event phase sorting system for use with dynamic registries (#1)

* Make minor changes to Technici4n's PR

* Add test for nested dynamic objects

* Revert "Add test for nested dynamic objects"

This reverts commit 486e3e1.

* Revert "Make minor changes to Technici4n's PR"

This reverts commit 741bd52.

* Revert "Refactor event phase sorting system for use with dynamic registries (#1)"

This reverts commit bb7c8b8.

* Remove sorting API

* Add support for defaulted dynamic registries

* Re-add test for nested dynamic objects

* Add missing license headers

* Fix typo

* Remove defaulted dynamic registries; flatten registration methods

* Remove last reference to registry sorting

* Add option to skip syncing for empty dynregs

* Update DynamicRegistrySyncOption docs

Co-authored-by: Technici4n <[email protected]>

* Address review feedback

* Add registry namespace to tag paths for modded registries

* Move dynamic registry tests into their own class for readibility

* Finish DynamicRegistries doc

* Only apply tag change to dynamic registries

* Fix checkstyle

* Update fabric-registry-sync-v0/src/main/java/net/fabricmc/fabric/api/event/registry/DynamicRegistries.java

Co-authored-by: Technici4n <[email protected]>

---------

Co-authored-by: Technici4n <[email protected]>

* Fix incorrect behavior with ClientMessageEvents and CommandApi (FabricMC#3182)

* Make event phase ordering logic usable in other contexts (internally only) (FabricMC#3183)

* Make event phase ordering logic usable in other contexts (internally only)

* Rename and move to toposort package

* Fix crash when beehive is broken by fake player (FabricMC#3190)

* Fix crash when beehive is broken by fake player

When a beehive is broken, every nearby bee targets a random player.
However, if there are no nearby players, the game crashes.

This should not occur under normal (vanilla) conditions. However, if a
beehive is broken by a fake player there are no players in range, and so
we see a crash.

* Checkstyle, my beloved

* Remove public modifier

* See see see

* Fix Indigo handling of sculk sensor AO (FabricMC#3200)

* Fix Indigo handling of sculk sensor AO. Fixes FabricMC#3153

* Split offset and mean formula lighting config options

* Some more TAWs for block creation and block loot tables (FabricMC#3201)

* Some more TAWs

Added some TAWs for various methods in `Blocks` used to create certain types of blocks that mods may want to also create. Using these methods will allow them to ensure they have all the right block settings they need to stay consistent with vanilla blocks that use the same methods.

* Add some fields from BlockLootTableGenerator

useful fields from BlockLootTableGenerator. also cleaned up the datagen api's accesswidener file

* Add the cherry grove to the floral biome tag (FabricMC#3202)

* Ukrainian translations (FabricMC#3169)

* Add files via upload

* Add files via upload

* A few transfer API improvements and deprecations (FabricMC#3204)

* A few transfer API improvements and deprecations

* Forward implementation of deprecated methods

* Bump version

* Start porting process for real this time
Redid process of setting up QMJ and mixins.json for model_loading_v1, fixed registry sync access wideners
First area of focus is going to be the new fapi dyn. registries, as they will likely require the most substantial work.

* Implement compat with Fabric's Dynamic Registry API.

* Implement compat with Fabric's Fabric Model Loading API (v1), replacing the old Model API (v0). Basically a drag-and-drop addition.

* Remove mixin into QSL's DynamicMetaRegistryImpl that is not actively required, and in fact would potentially cause a breakage with QSL behavior.
- Also began work on smaller compat changes, such as the FakePlayerTests gametest entry for fake player hive breakage.

* Fix some QMJ related things

* Run checkstyle and header application, apply fix to model-loading-api qmj

* Revert weird change to RegistrySyncTest (blame codestyle auto-application?? I have no clue tbh)

* Apply suggestions from code review

Co-authored-by: Ennui Langeweile <[email protected]>

* Upgrade to upstream FAPI 0.86.1 & QSL 6.1.0
- Involved manually copy-pasting in the changes from the following FAPI upstream commits:
-- FabricMC#3222 (one-to-one)
-- FabricMC#3216 (required some modification in FabricDynamicRegistryProvider to quiltify)
-- FabricMC#3212 (one-to-one other than converting FMJ additions to QMJ)
-- FabricMC#3219 does not have to be added as it is not an issue with QSL's 0.86.1 impl of the same concept
- Removed/rewrote parts of the QFAPI impl of FAPI's Dynamic Registry API that are better supported by using QSL's equivalents
- Applied checkstyle and licensing checks. No licensing changes were made, though checkstyle changes were.

* Remove mixins removed in last commit from quilted_fabric_registry_sync_v0.mixins.json

* Remove SaveLoadingMixin

---------

Co-authored-by: Technici4n <[email protected]>
Co-authored-by: embeddedt <[email protected]>
Co-authored-by: PepperCode1 <[email protected]>
Co-authored-by: Juuz <[email protected]>
Co-authored-by: Kevin <[email protected]>
Co-authored-by: Jonathan Coates <[email protected]>
Co-authored-by: Shnupbups <[email protected]>
Co-authored-by: maityyy <[email protected]>
Co-authored-by: Un roman <[email protected]>
Co-authored-by: modmuss50 <[email protected]>
Co-authored-by: Ennui Langeweile <[email protected]>
cocona20xx pushed a commit to cocona20xx/quilted-fabric-api that referenced this pull request Oct 1, 2023
This PR deprecates and supersedes the old `fabric-models-v0` module.

## Refactors compared to v0
### Model loading hooks
Mods now register a single `ModelLoadingPlugin` for any change they want to make to the model loading process. (Or multiple plugins if they want to). This replaces the old `ModelLoadingRegistry`.

Here is an example:

```java
ModelLoadingPlugin.register(pluginContext -> {
    // ResourceManager access is provided like in the v0 API, but in a central place, and can be used for shared processing in the plugin.
    ResourceManager manager = pluginContext.resourceManager();

    // Model resource providers still exist, but they are called model resolvers now
    pluginContext.resolveModel().register(context -> {
        // ...
    });
});
```

#### `ModelVariantProvider` -> `BlockStateResolver`
`ModelVariantProvider` was heavily reworked, and is now replaced by the `BlockStateResolver`, with a much better defined contract.

#### `ModelResourceProvider` -> `ModelResolver`
The resource provider is mostly unchanged. The biggest difference is that it is now registered as an event listener. This allows mods to use event phases for ordering between conflicting ~~providers~~ resolvers.

#### Removed custom exception
Additionally, `ModelProviderException` could be thrown by a variant or resource provider in the v0 API. This was not explained in the documentation, and would according to the code stop further processing of the providers and log an error.

In the new API, any `Exception` is caught and logged. If that happens, the other resolvers are still processed. There is no custom `Exception` subclass anymore.

### Helper method to get a `BakedModel` by `Identifier` from the manager
The v0 had such a method in a helper class: `BakedModelManagerHelper#getBakedModel`. It is now interface-injected instead. See `FabricBakedModelManager`.

## New model wrapping hooks
New hooks are added for the various needs of mods that want to override or wrap specific models. Thanks to @embeddedt for contributing an initial version of them!

Here is an example of wrapping the gold model to remove the bottom quads, for example:
```java
ModelLoadingPlugin.register(pluginContext -> {
	// remove bottom face of gold blocks
	pluginContext.modifyModelAfterBake().register(ModelModifier.WRAP_PHASE, (model, context) -> {
		if (context.identifier().getPath().equals("block/gold_block")) {
			return new DownQuadRemovingModel(model);
		} else {
			return model;
		}
	});
});
```

There are 3 events, for the following use cases:
- Wrapping `UnbakedModel`s right when they are loaded. This allows replacing them entirely in dependent models too.
- Wrapping `UnbakedModel`s right before they are baked. This allows replacing them without affecting dependent models (which might not be expecting a model class change).
- Wrapping `BakedModel`s right when they are baked.

Multiple mods have implemented their own version of them. Providing them in Fabric API will make it easier on these mods, and will additionally allow optimization mods that perform on-demand model loading to simply fire the hooks themselves instead of working around injections performed by other mods.

Co-authored-by: embeddedt <[email protected]>
Co-authored-by: PepperCode1 <[email protected]>
Co-authored-by: Juuz <[email protected]>
Signed-off-by: modmuss50 <[email protected]>
PrimalCat-Real added a commit to PrimalCat-Real/SpecialModelLoader-1.21 that referenced this pull request Jun 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
last call If you care, make yourself heard right away! merge me please Pull requests that are ready to merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants