Skip to content

Commit

Permalink
[Patch]: Baked model selection rewrite (#873)
Browse files Browse the repository at this point in the history
## Baked model selection rewrite
Closes #870 
Closes #865 

**Goal**: Rebuild the model selection process to be more flexible and
easier to maintain

## Changes
* Removes the old monolith class that handled everything before
* Removed itemstack cache keys
* Removed the old 
* Removed dependency on the deprecated Fabric Model selection api

* Adds a new 1-1 binding between items and the Unbaked model class
* Implemented using Fabric's new ModelLoadingPlugin
* Adds a system of decorator strategies to be able to quickly set up and
build a BakedModel selection process
* Added the following selectors: AsyncStrategy, SingleCachedStrategy,
LayeredCachedStrategy, DefaultedBakedModelStrategy, ModelBakerStrategy


## Compatibility
* Adds compat for Modernfix
* Adds compat for Emissive Textures plugin

## Further work
- [ ]  #890
  • Loading branch information
SigmundGranaas authored Apr 14, 2024
1 parent 5735cfc commit 0b26f09
Show file tree
Hide file tree
Showing 80 changed files with 2,210 additions and 678 deletions.
9 changes: 9 additions & 0 deletions fabric/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ subprojects {
implementation 'org.jetbrains:annotations:23.0.0'
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.0'
}

test {
useJUnitPlatform()
}

java {
withSourcesJar()
}

}

curseforge {
Expand Down
5 changes: 4 additions & 1 deletion fabric/forgero-fabric-compat/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ dependencies {
//modImplementation "maven.modrinth:cloth-config:9.0.94+fabric"
//modImplementation("dev.kosmx.player-anim:player-animation-lib-fabric:${project.player_anim_version}")

modCompileOnly("maven.modrinth:moremcmeta-emissive:v1.20.2-2.0.4-fabric")

// Betterend & Betternether
// modImplementation "maven.modrinth:BgNRHReB:mKksn4EY"
// modImplementation "maven.modrinth:gc8OEnCC:5CIFclEA"
Expand All @@ -32,7 +34,8 @@ dependencies {
//emi
//modCompileOnly "dev.emi:emi:${emi_version}:api"
//modLocalRuntime "dev.emi:emi:${emi_version}"
//modImplementation "maven.modrinth:emi-loot:0.5.0+1.19"
// modImplementation "maven.modrinth:emi-loot:0.6.5+1.20.1"
// modImplementation "maven.modrinth:emi:1.1.4+1.20.1+fabric"

//JEI
// modRuntimeOnly "maven.modrinth:jei:${project.jei_version}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import java.util.function.Supplier;

import com.sigmundgranaas.forgero.core.configuration.ForgeroConfigurationLoader;
import com.sigmundgranaas.forgero.fabric.api.entrypoint.ForgeroInitializedEntryPoint;
import com.sigmundgranaas.forgero.fabric.mythicmetals.MythicMetalsCommons;
import com.sigmundgranaas.forgero.fabric.patchouli.BookDropOnAdvancement;
Expand All @@ -16,6 +15,7 @@ public class ForgeroCompatInitializer implements ForgeroInitializedEntryPoint {
public static final Supplier<Boolean> toolstats;
public static final Supplier<Boolean> patchouli;
public static final Supplier<Boolean> bettercombat;
public static final Supplier<Boolean> emissiveModel;
public static final Supplier<Boolean> mythicmetals;
public static final Supplier<Boolean> yacl;
public static final Supplier<Boolean> emi;
Expand All @@ -27,6 +27,7 @@ public class ForgeroCompatInitializer implements ForgeroInitializedEntryPoint {
mythicmetals = () -> isModLoaded("mythicmetals");
patchouli = () -> isModLoaded("patchouli");
bettercombat = () -> isModLoaded("bettercombat");
emissiveModel = () -> isModLoaded("moremcmeta_emissive_plugin");
yacl = () -> isModLoaded("yet-another-config-lib") || isModLoaded("yet_another_config_lib_v3");
}

Expand All @@ -40,10 +41,6 @@ public void onInitialized(StateService service) {
ToolStatTagGenerator.generateTags();
}

if(emi.get()){
ForgeroConfigurationLoader.configuration.buildModelsAsync = false;
}

if (patchouli.get()) {
BookDropOnAdvancement.registerBookDrop();
GuideBookGenerator.registerGuideBookRecipes();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ public class CompatMixinPlugin implements IMixinConfigPlugin {
private static final Supplier<Boolean> TRUE = () -> true;

private static final Map<String, Supplier<Boolean>> CONDITIONS = ImmutableMap.of(
"com.sigmundgranaas.forgero.fabric.mixins.BetterCombatWeaponRegistryMixin", ForgeroCompatInitializer.bettercombat
"com.sigmundgranaas.forgero.fabric.mixins.BetterCombatWeaponRegistryMixin", ForgeroCompatInitializer.bettercombat,
"com.sigmundgranaas.forgero.fabric.mixins.EmissiveOverlayModelMixin", ForgeroCompatInitializer.bettercombat

);

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.sigmundgranaas.forgero.fabric.mixins;

import static net.minecraft.client.render.model.json.ModelTransformationMode.GROUND;

import com.sigmundgranaas.forgero.minecraft.common.client.model.QuadProviderPreparer;
import io.github.moremcmeta.emissiveplugin.fabric.model.OverlayBakedModel;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.ItemModels;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;

@Mixin(ItemRenderer.class)
public class EmissiveOverlayModelMixin {
@Shadow
@Final
private ItemModels models;

@Inject(at = @At("HEAD"), method = "getModel")
public void forgero$preparOverlayModel(ItemStack stack, @Nullable World world, @Nullable LivingEntity entity, int seed, CallbackInfoReturnable<BakedModel> ci) {
BakedModel bakedModel = this.models.getModel(stack);
if (bakedModel instanceof OverlayBakedModel overlay) {
if (overlay.getWrappedModel() instanceof QuadProviderPreparer preparer && world instanceof ClientWorld clientWorld) {
preparer.provideContext(stack, clientWorld, entity, seed);
}
}
}

@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;translate(FFF)V"), method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V")
private void forgero$applyGroundTransformationToOverlayModel(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) {
if (renderMode.equals(GROUND) && model instanceof OverlayBakedModel overlayBakedModel && overlayBakedModel.getWrappedModel() instanceof QuadProviderPreparer) {
// The ground model is scaled down by half to make sure it's the same size as other models
// Investigate why it's doing this. This mixin should not be needed.
matrices.scale(0.5f, 0.5f, 0.5f);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package com.sigmundgranaas.forgero.fabric.yacl;

import com.sigmundgranaas.forgero.core.configuration.ForgeroConfigurationLoader;
import static com.sigmundgranaas.forgero.core.model.Strategy.PRE_BAKED;

import java.util.Collections;

import com.sigmundgranaas.forgero.core.configuration.ForgeroConfigurationLoader;
import com.sigmundgranaas.forgero.core.model.Strategy;
import dev.isxander.yacl3.api.ConfigCategory;
import dev.isxander.yacl3.api.ListOption;
import dev.isxander.yacl3.api.Option;
import dev.isxander.yacl3.api.OptionDescription;
import dev.isxander.yacl3.api.OptionGroup;
import dev.isxander.yacl3.api.YetAnotherConfigLib;

import dev.isxander.yacl3.api.controller.BooleanControllerBuilder;
import dev.isxander.yacl3.api.controller.EnumControllerBuilder;
import dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder;
import dev.isxander.yacl3.api.controller.IntegerFieldControllerBuilder;
import dev.isxander.yacl3.api.controller.IntegerSliderControllerBuilder;
Expand All @@ -18,8 +22,6 @@
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;

import java.util.Collections;

/**
* Forgero config screen builder, uses YACL to generate the config screen.
* <p>
Expand Down Expand Up @@ -217,16 +219,30 @@ private static ConfigCategory buildDebugCategory() {

private static class PerformanceCategory {
private static ConfigCategory buildPerformanceCategory() {
return ConfigCategory.createBuilder().name(Text.translatable("forgero.config.category.performance.title")).tooltip(
Text.translatable("forgero.config.category.performance.title.tooltip")).group(
OptionGroup.createBuilder().name(Text.translatable("forgero.config.group.performance.title")).description(
OptionDescription.of(Text.translatable("forgero.config.group.performance.title.tooltip"))).option(
Option.<Boolean>createBuilder().name(Text.translatable("forgero.config.buildModelsAsync")).description(
OptionDescription.of(Text.translatable("forgero.config.buildModelsAsync.tooltip"))).binding(
true,
() -> ForgeroConfigurationLoader.configuration.buildModelsAsync,
newValue -> ForgeroConfigurationLoader.configuration.buildModelsAsync = newValue
).controller(BooleanControllerBuilder::create).build()).build()).build();
return ConfigCategory.createBuilder()
.name(Text.translatable("forgero.config.category.performance.title"))
.tooltip(
Text.translatable("forgero.config.category.performance.title.tooltip"))
.group(
OptionGroup.createBuilder()
.name(Text.translatable("forgero.config.group.performance.title"))
.description(
OptionDescription.of(Text.translatable("forgero.config.group.performance.title.tooltip")))
.option(
Option.<Strategy>createBuilder()
.name(Text.translatable("forgero.config.modelStrategy"))
.description(
OptionDescription.of(Text.translatable("forgero.config.modelStrategy.tooltip")))
.binding(
PRE_BAKED,
() -> ForgeroConfigurationLoader.configuration.modelStrategy,
newValue -> ForgeroConfigurationLoader.configuration.modelStrategy = newValue
)
.controller((option) -> EnumControllerBuilder.create(option).enumClass(Strategy.class))
.build()
)
.build())
.build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,6 @@
"forgero.config.category.performance.title.tooltip": "Performance and threading related settings.",
"forgero.config.group.performance.title": "Performance",
"forgero.config.group.performance.title.tooltip": "Performance and threading related settings.",
"forgero.config.buildModelsAsync": "Build models async",
"forgero.config.buildModelsAsync.tooltip": "Builds models asynchronously (off-thread) so the game's main server thread and render thread aren't blocked during model building."
"forgero.config.modelStrategy": "Model selection strategy",
"forgero.config.modelStrategy.tooltip": "(FULLY_ASYNC) Build and cache models fully async so the thread is not blocked. \n \n (PRE_BAKED) Pre-bake default models, combined with async models and cache. \n \n (NO_ASYNC) Cache models, but build them using a blocking strategy. \n (NO_CACHE) Don't cache anything. This is very slow, only use for debugging."
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@
],
"injectors": {
"defaultRequire": 1
}
},
"client": [
"EmissiveOverlayModelMixin"
]
}
1 change: 0 additions & 1 deletion fabric/forgero-fabric-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ loom {
name "Game Test"
// Enable the gametest runner
vmArg "-Dfabric-api.gametest"
vmArg "-Dfabric-api.gametest.report-file=${project.buildDir}/junit.xml"
runDir "build/gametest"
}
testClient {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,62 +1,52 @@
package com.sigmundgranaas.forgero.fabric.client;

import static com.sigmundgranaas.forgero.minecraft.common.block.assemblystation.AssemblyStationScreenHandler.ASSEMBLY_STATION_SCREEN_HANDLER;
import static com.sigmundgranaas.forgero.minecraft.common.block.upgradestation.UpgradeStationScreenHandler.UPGRADE_STATION_SCREEN_HANDLER;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import com.google.common.collect.ImmutableList;
import com.sigmundgranaas.forgero.core.Forgero;
import com.sigmundgranaas.forgero.core.ForgeroStateRegistry;
import com.sigmundgranaas.forgero.core.model.ModelRegistry;
import com.sigmundgranaas.forgero.core.model.ModelTemplate;
import com.sigmundgranaas.forgero.core.model.PaletteTemplateModel;
import com.sigmundgranaas.forgero.core.model.TextureModel;
import com.sigmundgranaas.forgero.core.resource.PipelineBuilder;
import com.sigmundgranaas.forgero.core.state.State;
import com.sigmundgranaas.forgero.core.texture.V2.TextureGenerator;
import com.sigmundgranaas.forgero.core.type.Type;
import com.sigmundgranaas.forgero.fabric.client.model.ForgeroModelVariantProvider;
import com.sigmundgranaas.forgero.fabric.client.model.ForgeroStateModelResolver;
import com.sigmundgranaas.forgero.fabric.client.texture.Generator;
import com.sigmundgranaas.forgero.fabric.resources.FabricPackFinder;
import com.sigmundgranaas.forgero.fabric.resources.FileService;
import com.sigmundgranaas.forgero.minecraft.common.block.assemblystation.AssemblyStationScreen;
import com.sigmundgranaas.forgero.minecraft.common.block.upgradestation.UpgradeStationScreen;
import com.sigmundgranaas.forgero.minecraft.common.entity.Entities;
import com.sigmundgranaas.forgero.minecraft.common.handler.use.ThrowableItemRenderer;
import com.sigmundgranaas.forgero.minecraft.common.service.StateService;
import net.devtech.arrp.api.RRPCallback;

import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;

import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourceType;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.Identifier;

import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry;
import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
import net.fabricmc.fabric.api.client.model.loading.v1.ModelResolver;
import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.metadata.ModMetadata;
import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourceType;
import net.minecraft.screen.PlayerScreenHandler;
import net.minecraft.util.Identifier;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import static com.sigmundgranaas.forgero.fabric.client.SoulEntityModel.SOUL_ENTITY_MODEL_LAYER;
import static com.sigmundgranaas.forgero.minecraft.common.block.assemblystation.AssemblyStationScreenHandler.ASSEMBLY_STATION_SCREEN_HANDLER;
import static com.sigmundgranaas.forgero.minecraft.common.block.upgradestation.UpgradeStationScreenHandler.UPGRADE_STATION_SCREEN_HANDLER;

@Environment(EnvType.CLIENT)
public class ForgeroClient implements ClientModInitializer {
Expand Down Expand Up @@ -87,11 +77,18 @@ private void initializeItemModels() {
// TODO: Set configuration's available dependencies
assetReloader();
registerToolPartTextures(modelRegistry);
var modelProvider = new ForgeroModelVariantProvider(modelRegistry);
ModelLoadingRegistry.INSTANCE.registerVariantProvider(variant -> modelProvider);
// EntityRendererRegistry.register(Entities.SOUL_ENTITY, SoulEntityRenderer::new);

StateService stateService = StateService.INSTANCE;
Set<Identifier> models = ForgeroStateRegistry.COMPOSITES.parallelStream()
.map(stateService::find)
.flatMap(Optional::stream)
.map(id -> new Identifier(id.nameSpace(), "item/" + id.name()))
.collect(Collectors.toSet());

ModelResolver stateModels = new ForgeroStateModelResolver(modelRegistry, StateService.INSTANCE, models);
ModelLoadingPlugin.register(pluginContext -> pluginContext.resolveModel().register(stateModels));

EntityRendererRegistry.register(Entities.THROWN_ITEM_ENTITY, ThrowableItemRenderer::new);
// EntityModelLayerRegistry.registerModelLayer(SOUL_ENTITY_MODEL_LAYER, SoulEntityModel::getTexturedModelData);
}

private void registerToolPartTextures(ModelRegistry modelRegistry) {
Expand Down
Loading

0 comments on commit 0b26f09

Please sign in to comment.