CTM support
This commit is contained in:
parent
8937ca020d
commit
e5cd9f57b5
|
|
@ -96,6 +96,7 @@ dependencies {
|
|||
modCompileOnly("curse.maven:babel-436964:3196072")
|
||||
modCompileOnly("curse.maven:twforest-227639:3575220")
|
||||
modRuntimeOnly("curse.maven:ferritecore-429235:4074330")
|
||||
modCompileOnly("team.chisel.ctm:CTM:${ctm_version}")
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
package org.embeddedt.modernfix.dynamicresources;
|
||||
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.event.lifecycle.IModBusEvent;
|
||||
|
||||
/**
|
||||
* Fired when a model is baked dynamically. Intended to be used as a replacement for ModelBakeEvent
|
||||
|
|
@ -11,12 +15,16 @@ import net.minecraftforge.eventbus.api.Event;
|
|||
* Note that this event can fire many times for the same resource location, as models are unloaded
|
||||
* if unused/under memory pressure.
|
||||
*/
|
||||
public class DynamicModelBakeEvent extends Event {
|
||||
public class DynamicModelBakeEvent extends Event implements IModBusEvent {
|
||||
private final ResourceLocation location;
|
||||
private BakedModel model;
|
||||
public DynamicModelBakeEvent(ResourceLocation location, BakedModel model) {
|
||||
private final UnbakedModel unbakedModel;
|
||||
private final ModelLoader modelLoader;
|
||||
public DynamicModelBakeEvent(ResourceLocation location, UnbakedModel unbakedModel, BakedModel model, ModelLoader loader) {
|
||||
this.location = location;
|
||||
this.model = model;
|
||||
this.unbakedModel = unbakedModel;
|
||||
this.modelLoader = loader;
|
||||
}
|
||||
|
||||
public ResourceLocation getLocation() {
|
||||
|
|
@ -27,6 +35,14 @@ public class DynamicModelBakeEvent extends Event {
|
|||
return this.model;
|
||||
}
|
||||
|
||||
public UnbakedModel getUnbakedModel() {
|
||||
return this.unbakedModel;
|
||||
}
|
||||
|
||||
public ModelLoader getModelLoader() {
|
||||
return this.modelLoader;
|
||||
}
|
||||
|
||||
public void setModel(BakedModel model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,10 @@ import net.minecraft.world.level.block.Block;
|
|||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.fml.ModLoader;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
|
|
@ -291,8 +293,8 @@ public abstract class ModelBakeryMixin {
|
|||
if(ibakedmodel == null) {
|
||||
ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg);
|
||||
}
|
||||
DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, ibakedmodel);
|
||||
MinecraftForge.EVENT_BUS.post(event);
|
||||
DynamicModelBakeEvent event = new DynamicModelBakeEvent(arg, iunbakedmodel, ibakedmodel, (ModelLoader)(Object)this);
|
||||
ModLoader.get().postEvent(event);
|
||||
this.bakedCache.put(triple, event.getModel());
|
||||
return event.getModel();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.dynamic_resources.ctm;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.minecraft.client.renderer.ItemBlockRenderTypes;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.block.BlockModelShaper;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.MultiPartBakedModel;
|
||||
import net.minecraft.client.resources.model.WeightedBakedModel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.EventPriority;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.IRegistryDelegate;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicModelBakeEvent;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
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 team.chisel.ctm.client.model.AbstractCTMBakedModel;
|
||||
import team.chisel.ctm.client.util.CTMPackReloadListener;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(CTMPackReloadListener.class)
|
||||
public abstract class CTMPackReloadListenerMixin {
|
||||
@Shadow @Final private static Map<IRegistryDelegate<Block>, Predicate<RenderType>> blockRenderChecks;
|
||||
|
||||
@Shadow protected abstract Predicate<RenderType> getLayerCheck(BlockState state, BakedModel model);
|
||||
|
||||
@Shadow protected abstract Predicate<RenderType> getExistingRenderCheck(Block block);
|
||||
|
||||
private Map<ModelResourceLocation, BlockState> locationToState = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void onInit(CallbackInfo ci) {
|
||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(EventPriority.LOW, this::onModelBake);
|
||||
}
|
||||
|
||||
@Overwrite(remap = false)
|
||||
private void refreshLayerHacks() {
|
||||
blockRenderChecks.forEach((b, p) -> ItemBlockRenderTypes.setRenderLayer((Block) b.get(), p));
|
||||
blockRenderChecks.clear();
|
||||
if(locationToState.isEmpty()) {
|
||||
for(Block block : ForgeRegistries.BLOCKS.getValues()) {
|
||||
for(BlockState state : block.getStateDefinition().getPossibleStates()) {
|
||||
locationToState.put(BlockModelShaper.stateToModelLocation(state), state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onModelBake(DynamicModelBakeEvent event) {
|
||||
if(!(event.getModel() instanceof AbstractCTMBakedModel || event.getModel() instanceof WeightedBakedModel || event.getModel() instanceof MultiPartBakedModel))
|
||||
return;
|
||||
BlockState state = locationToState.get(event.getLocation());
|
||||
if(state == null)
|
||||
return;
|
||||
Block block = state.getBlock();
|
||||
if(blockRenderChecks.containsKey(block.delegate))
|
||||
return;
|
||||
Predicate<RenderType> newPredicate = this.getLayerCheck(state, event.getModel());
|
||||
if(newPredicate != null) {
|
||||
blockRenderChecks.put(block.delegate, this.getExistingRenderCheck(block));
|
||||
ItemBlockRenderTypes.setRenderLayer(block, newPredicate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
package org.embeddedt.modernfix.mixin.perf.dynamic_resources.ctm;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.Material;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.client.model.ModelLoader;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicModelBakeEvent;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import team.chisel.ctm.CTM;
|
||||
import team.chisel.ctm.client.model.AbstractCTMBakedModel;
|
||||
import team.chisel.ctm.client.texture.IMetadataSectionCTM;
|
||||
import team.chisel.ctm.client.util.ResourceUtil;
|
||||
import team.chisel.ctm.client.util.TextureMetadataHandler;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
@Mixin(TextureMetadataHandler.class)
|
||||
public abstract class TextureMetadataHandlerMixin {
|
||||
|
||||
@Shadow @Nonnull protected abstract BakedModel wrap(ResourceLocation loc, UnbakedModel model, BakedModel object, ModelLoader loader) throws IOException;
|
||||
|
||||
@SubscribeEvent
|
||||
public void onDynamicModelBake(DynamicModelBakeEvent event) {
|
||||
UnbakedModel rootModel = event.getUnbakedModel();
|
||||
BakedModel baked = event.getModel();
|
||||
ResourceLocation rl = event.getLocation();
|
||||
if (!(baked instanceof AbstractCTMBakedModel) && !baked.isCustomRenderer()) {
|
||||
Deque<ResourceLocation> dependencies = new ArrayDeque<>();
|
||||
Set<ResourceLocation> seenModels = new HashSet<>();
|
||||
dependencies.push(rl);
|
||||
seenModels.add(rl);
|
||||
boolean shouldWrap = false;
|
||||
Set<Pair<String, String>> errors = new HashSet<>();
|
||||
// Breadth-first loop through dependencies, exiting as soon as a CTM texture is found, and skipping duplicates/cycles
|
||||
while (!shouldWrap && !dependencies.isEmpty()) {
|
||||
ResourceLocation dep = dependencies.pop();
|
||||
UnbakedModel model;
|
||||
try {
|
||||
model = dep == rl ? rootModel : event.getModelLoader().getModel(dep);
|
||||
} catch (Exception e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Collection<Material> textures = model.getMaterials(event.getModelLoader()::getModel, errors);
|
||||
Collection<ResourceLocation> newDependencies = model.getDependencies();
|
||||
for (Material tex : textures) {
|
||||
IMetadataSectionCTM meta = null;
|
||||
// Cache all dependent texture metadata
|
||||
try {
|
||||
meta = ResourceUtil.getMetadata(ResourceUtil.spriteToAbsolute(tex.texture()));
|
||||
} catch (IOException e) {} // Fallthrough
|
||||
if (meta != null) {
|
||||
// At least one texture has CTM metadata, so we should wrap this model
|
||||
shouldWrap = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (ResourceLocation newDep : newDependencies) {
|
||||
if (seenModels.add(newDep)) {
|
||||
dependencies.push(newDep);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldWrap) {
|
||||
try {
|
||||
event.setModel(wrap(rl, rootModel, baked, event.getModelLoader()));
|
||||
dependencies.clear();
|
||||
} catch (IOException e) {
|
||||
CTM.logger.error("Could not wrap model " + rl + ". Aborting...", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -78,6 +78,8 @@
|
|||
"perf.dynamic_resources.BlockModelShaperMixin",
|
||||
"perf.dynamic_resources.ItemModelShaperMixin",
|
||||
"perf.dynamic_resources.ModelBakeryMixin",
|
||||
"perf.dynamic_resources.ctm.TextureMetadataHandlerMixin",
|
||||
"perf.dynamic_resources.ctm.CTMPackReloadListenerMixin",
|
||||
"perf.model_optimizations.OBJLoaderMixin",
|
||||
"perf.model_optimizations.SelectorMixin",
|
||||
"perf.model_optimizations.TransformationMatrixMixin",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user