25w07a - rewrite dynamic resources, drop faster_item_rendering and wall block deduplication (for now)
This commit is contained in:
parent
37cb92a64f
commit
52d4aba120
|
|
@ -21,7 +21,11 @@ dependencies {
|
|||
|
||||
modCompileOnly "curse.maven:spark-361579:${rootProject.spark_version}"
|
||||
|
||||
modCompileOnly fabricApi.module("fabric-model-loading-api-v1", rootProject.fabric_api_version)
|
||||
try {
|
||||
modCompileOnly fabricApi.module("fabric-model-loading-api-v1", rootProject.fabric_api_version)
|
||||
} catch(ignored) {
|
||||
println "Model Loading API not found for this Minecraft version!"
|
||||
}
|
||||
// Remove the next line if you don't want to depend on the API
|
||||
// modApi "me.shedaniel:architectury:${rootProject.architectury_version}"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
package org.embeddedt.modernfix.api.entrypoint;
|
||||
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
|
||||
/**
|
||||
* Implement this interface in a mod class and add it to "modernfix:integration_v1" in your mod metadata file
|
||||
* to integrate with ModernFix's features.
|
||||
|
|
@ -19,19 +13,4 @@ public interface ModernFixClientIntegration {
|
|||
*/
|
||||
default void onDynamicResourcesStatusChange(boolean enabled) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to allow mods to observe the loading of a baked model and either make changes to it or wrap it with their
|
||||
* own instance.
|
||||
*
|
||||
* @param location the ResourceLocation of the model (this may be a ModelResourceLocation)
|
||||
* @param originalModel the original model
|
||||
* @param bakery the model bakery - do not touch internal fields as they probably don't behave the way you expect
|
||||
* with dynamic resources on
|
||||
* @param textureGetter function to retrieve textures for this model
|
||||
* @return the model which should actually be loaded for this resource location
|
||||
*/
|
||||
default BakedModel onBakedModelLoad(ModelResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery, ModelBakery.TextureGetter textureGetter) {
|
||||
return originalModel;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,76 +0,0 @@
|
|||
package org.embeddedt.modernfix.api.helpers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import org.embeddedt.modernfix.dynamicresources.ModelBakeryHelpers;
|
||||
import org.embeddedt.modernfix.util.DynamicMap;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class ModelHelpers {
|
||||
/**
|
||||
* Allows converting a ModelResourceLocation back into the corresponding BlockState(s). Try to avoid calling this
|
||||
* multiple times if possible.
|
||||
* @param location the location of the model
|
||||
* @return a list of all blockstates related to the model
|
||||
*/
|
||||
public static ImmutableList<BlockState> getBlockStateForLocation(ModelResourceLocation location) {
|
||||
Optional<Block> blockOpt = BuiltInRegistries.BLOCK.getOptional(location.id());
|
||||
if(blockOpt.isPresent())
|
||||
return ModelBakeryHelpers.getBlockStatesForMRL(blockOpt.get().getStateDefinition(), location);
|
||||
else
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows converting a ModelResourceLocation back into the corresponding BlockState(s). Faster version of its
|
||||
* companion function if and only if you know the corresponding Block already for some reason.
|
||||
* @param definition the state definition for the Block
|
||||
* @param location the location of the model
|
||||
* @return a list of all blockstates related to the model
|
||||
*/
|
||||
public static ImmutableList<BlockState> getBlockStateForLocation(StateDefinition<Block, BlockState> definition, ModelResourceLocation location) {
|
||||
return ModelBakeryHelpers.getBlockStatesForMRL(definition, location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatibility helper for mods to use to get a map-like view of the model bakery.
|
||||
* @param modelGetter the model getter function supplied by the integration class
|
||||
* @return a fake map of the top-level models
|
||||
*/
|
||||
public static Map<ResourceLocation, BakedModel> createFakeTopLevelMap(BiFunction<ResourceLocation, ModelState, BakedModel> modelGetter) {
|
||||
return new DynamicMap<>(ResourceLocation.class, location -> modelGetter.apply(location, BlockModelRotation.X0_Y0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a ModelBaker for mods to use.
|
||||
* @param bakery the ModelBakery supplied to your integration
|
||||
* @return an appropriate ModelBaker
|
||||
*/
|
||||
public static ModelBaker adaptBakery(ModelBakery bakery) {
|
||||
throw new UnsupportedOperationException("TODO");
|
||||
/*
|
||||
return new ModelBaker() {
|
||||
@Override
|
||||
public UnbakedModel getModel(ResourceLocation resourceLocation) {
|
||||
return bakery.getModel(resourceLocation);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BakedModel bake(ResourceLocation resourceLocation, ModelState modelState) {
|
||||
return ((IExtendedModelBakery)bakery).bakeDefault(resourceLocation, modelState);
|
||||
}
|
||||
};
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
@ -47,8 +47,7 @@ public abstract class ServerLevelMixin extends Level implements IServerLevel {
|
|||
@Inject(method = "<init>", at = @At("TAIL"))
|
||||
private void ensureGeneration(CallbackInfo ci) {
|
||||
mfix$strongholdCache = this.getDataStorage().computeIfAbsent(
|
||||
StrongholdLocationCache.factory((ServerLevel)(Object)this),
|
||||
StrongholdLocationCache.getFileId(this.dimensionTypeRegistration()));
|
||||
StrongholdLocationCache.TYPE);
|
||||
this.chunkSource.getGeneratorState().ensureStructuresGenerated();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Most wall blocks use the default set of vanilla properties, and the default sizes for their shapes. This means
|
||||
|
|
@ -31,36 +32,5 @@ public abstract class WallBlockMixin extends Block {
|
|||
super(properties);
|
||||
}
|
||||
|
||||
@Inject(method = "makeShapes", at = @At("HEAD"), cancellable = true)
|
||||
private synchronized void useCachedShapeMap(float f1, float f2, float f3, float f4, float f5, float f6, CallbackInfoReturnable<Map<BlockState, VoxelShape>> cir) {
|
||||
ImmutableList<Float> key = ImmutableList.of(f1, f2, f3, f4, f5, f6);
|
||||
Pair<Map<Map<Property<?>, Comparable<?>>, VoxelShape>, StateDefinition<Block, BlockState>> cache = CACHE_BY_SHAPE_VALS.get(key);
|
||||
// require the properties to be identical
|
||||
if(cache == null || !cache.getSecond().getProperties().equals(this.stateDefinition.getProperties()))
|
||||
return;
|
||||
ImmutableMap.Builder<BlockState, VoxelShape> builder = ImmutableMap.builder();
|
||||
for(BlockState state : this.stateDefinition.getPossibleStates()) {
|
||||
VoxelShape shape = cache.getFirst().get(state.getValues());
|
||||
if(shape == null)
|
||||
return; // fallback to vanilla logic
|
||||
builder.put(state, shape);
|
||||
}
|
||||
cir.setReturnValue(builder.build());
|
||||
}
|
||||
|
||||
@Inject(method = "makeShapes", at = @At("RETURN"))
|
||||
private synchronized void storeCachedShapesByProperty(float f1, float f2, float f3, float f4, float f5, float f6, CallbackInfoReturnable<Map<BlockState, VoxelShape>> cir) {
|
||||
// never populate cache as a non-vanilla block
|
||||
if((Class<?>)this.getClass() != WallBlock.class)
|
||||
return;
|
||||
ImmutableList<Float> key = ImmutableList.of(f1, f2, f3, f4, f5, f6);
|
||||
if(!CACHE_BY_SHAPE_VALS.containsKey(key)) {
|
||||
Map<Map<Property<?>, Comparable<?>>, VoxelShape> cacheByProperties = new HashMap<>();
|
||||
Map<BlockState, VoxelShape> shapeMap = cir.getReturnValue();
|
||||
for(Map.Entry<BlockState, VoxelShape> entry : shapeMap.entrySet()) {
|
||||
cacheByProperties.put(entry.getKey().getValues(), entry.getValue());
|
||||
}
|
||||
CACHE_BY_SHAPE_VALS.put(key, Pair.of(cacheByProperties, this.stateDefinition));
|
||||
}
|
||||
}
|
||||
// TODO reimplement for 1.21.5
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
||||
|
||||
import net.minecraft.client.renderer.block.BlockModelShaper;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.duck.IModelHoldingBlockState;
|
||||
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
|
||||
import org.embeddedt.modernfix.util.DynamicOverridableMap;
|
||||
import org.spongepowered.asm.mixin.*;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Mixin(BlockModelShaper.class)
|
||||
@ClientOnlyMixin
|
||||
public class BlockModelShaperMixin {
|
||||
@Shadow @Final private ModelManager modelManager;
|
||||
|
||||
@Shadow
|
||||
private Map<BlockState, BakedModel> modelByStateCache;
|
||||
|
||||
@Inject(method = { "<init>", "replaceCache" }, at = @At("RETURN"))
|
||||
private void replaceModelMap(CallbackInfo ci) {
|
||||
// replace the backing map for mods which will access it
|
||||
this.modelByStateCache = new DynamicOverridableMap<>(BlockState.class, state -> modelManager.getModel(ModelLocationCache.get(state)));
|
||||
// Clear the cached models on blockstate objects
|
||||
for(Block block : BuiltInRegistries.BLOCK) {
|
||||
for(BlockState state : block.getStateDefinition().getPossibleStates()) {
|
||||
if(state instanceof IModelHoldingBlockState modelHolder) {
|
||||
modelHolder.mfix$setModel(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BakedModel cacheBlockModel(BlockState state) {
|
||||
// Do all model system accesses in the unlocked path
|
||||
ModelResourceLocation mrl = ModelLocationCache.get(state);
|
||||
BakedModel model = mrl == null ? null : modelManager.getModel(mrl);
|
||||
if (model == null) {
|
||||
model = modelManager.getMissingModel();
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason get the model from the dynamic model provider
|
||||
*/
|
||||
@Overwrite
|
||||
public BakedModel getBlockModel(BlockState state) {
|
||||
if(state instanceof IModelHoldingBlockState modelHolder) {
|
||||
BakedModel model = modelHolder.mfix$getModel();
|
||||
|
||||
if(model != null) {
|
||||
return model;
|
||||
}
|
||||
|
||||
model = this.cacheBlockModel(state);
|
||||
modelHolder.mfix$setModel(model);
|
||||
return model;
|
||||
} else {
|
||||
return this.cacheBlockModel(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
||||
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.renderer.block.model.BlockStateModel;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.duck.IModelHoldingBlockState;
|
||||
|
|
@ -11,16 +11,16 @@ import java.lang.ref.SoftReference;
|
|||
@Mixin(BlockBehaviour.BlockStateBase.class)
|
||||
@ClientOnlyMixin
|
||||
public class BlockStateBaseMixin implements IModelHoldingBlockState {
|
||||
private volatile SoftReference<BakedModel> mfix$model;
|
||||
private volatile SoftReference<BlockStateModel> mfix$model;
|
||||
|
||||
@Override
|
||||
public BakedModel mfix$getModel() {
|
||||
public BlockStateModel mfix$getModel() {
|
||||
var ref = mfix$model;
|
||||
return ref != null ? ref.get() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mfix$setModel(BakedModel model) {
|
||||
public void mfix$setModel(BlockStateModel model) {
|
||||
mfix$model = model != null ? new SoftReference<>(model) : null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public class ModelDiscoveryMixin {
|
|||
* @reason We will show the warning ourselves later when loading the model dynamically, this is just spam since
|
||||
* the models don't exist during early loading
|
||||
*/
|
||||
@Redirect(method = "loadBlockModel", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V"))
|
||||
@Redirect(method = "method_68027", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;)V"))
|
||||
private void disableMissingModelWarning(Logger instance, String s, Object o) {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,26 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
||||
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.model.geom.EntityModelSet;
|
||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||
import net.minecraft.client.renderer.block.model.BlockStateModel;
|
||||
import net.minecraft.client.renderer.item.ClientItem;
|
||||
import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.client.resources.model.AtlasSet;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.BlockStateModelLoader;
|
||||
import net.minecraft.client.resources.model.ClientItemInfoLoader;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.duck.IModelHoldingBlockState;
|
||||
import org.embeddedt.modernfix.dynamicresources.DynamicModelProvider;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
|
|
@ -32,13 +34,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Mixin(ModelManager.class)
|
||||
@ClientOnlyMixin
|
||||
public class ModelManagerMixin implements DynamicModelProvider.ModelManagerExtension {
|
||||
@Shadow private Map<ModelResourceLocation, BakedModel> bakedBlockStateModels;
|
||||
@Shadow private Map<ResourceLocation, ItemModel> bakedItemStackModels;
|
||||
@Shadow private Map<ResourceLocation, ClientItem.Properties> itemProperties;
|
||||
|
||||
|
|
@ -50,18 +52,43 @@ public class ModelManagerMixin implements DynamicModelProvider.ModelManagerExten
|
|||
return CompletableFuture.completedFuture(Map.of());
|
||||
}
|
||||
|
||||
@Redirect(method = "reload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/BlockStateModelLoader;loadBlockStates(Lnet/minecraft/client/resources/model/UnbakedModel;Lnet/minecraft/server/packs/resources/ResourceManager;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
|
||||
private CompletableFuture<BlockStateModelLoader.LoadedModels> deferBlockStateLoad(UnbakedModel unbakedModel, ResourceManager resourceManager, Executor executor) {
|
||||
@Redirect(method = "reload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/BlockStateModelLoader;loadBlockStates(Lnet/minecraft/server/packs/resources/ResourceManager;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
|
||||
private CompletableFuture<BlockStateModelLoader.LoadedModels> deferBlockStateLoad(ResourceManager resourceManager, Executor executor) {
|
||||
return CompletableFuture.completedFuture(new BlockStateModelLoader.LoadedModels(Map.of()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason disable map creation
|
||||
* @reason disable map creation, use dynamic dispatch
|
||||
*/
|
||||
@Overwrite
|
||||
private static Map<BlockState, BakedModel> createBlockStateToModelDispatch(Map<ModelResourceLocation, BakedModel> map, BakedModel bakedModel) {
|
||||
return Map.of();
|
||||
private static Map<BlockState, BlockStateModel> createBlockStateToModelDispatch(Map<BlockState, BlockStateModel> map, BlockStateModel missingModel) {
|
||||
var dynamicProvider = Objects.requireNonNull(DynamicModelProvider.currentReloadingModelProvider.get());
|
||||
|
||||
var dynamicRegistry = dynamicProvider.getTopLevelEmulatedRegistry();
|
||||
|
||||
return new ForwardingMap<>() {
|
||||
@Override
|
||||
protected Map<BlockState, BlockStateModel> delegate() {
|
||||
return dynamicRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockStateModel get(Object key) {
|
||||
BlockStateModel result;
|
||||
if (key instanceof IModelHoldingBlockState state) {
|
||||
result = state.mfix$getModel();
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result = dynamicRegistry.getOrDefault(key, dynamicProvider.getMissingBakedModel());
|
||||
if (key instanceof IModelHoldingBlockState state) {
|
||||
state.mfix$setModel(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Redirect(method = "reload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/resources/model/ClientItemInfoLoader;scheduleLoad(Lnet/minecraft/server/packs/resources/ResourceManager;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
|
||||
|
|
@ -86,9 +113,15 @@ public class ModelManagerMixin implements DynamicModelProvider.ModelManagerExten
|
|||
|
||||
@Inject(method = "apply", at = @At("RETURN"))
|
||||
private void setModelRegistries(CallbackInfo ci) {
|
||||
this.bakedBlockStateModels = this.mfix$modelProvider.getTopLevelEmulatedRegistry();
|
||||
this.bakedItemStackModels = this.mfix$modelProvider.getItemModelEmulatedRegistry();
|
||||
this.itemProperties = this.mfix$modelProvider.getItemPropertiesEmulatedRegistry();
|
||||
for(Block block : BuiltInRegistries.BLOCK) {
|
||||
for(BlockState state : block.getStateDefinition().getPossibleStates()) {
|
||||
if(state instanceof IModelHoldingBlockState modelHolder) {
|
||||
modelHolder.mfix$setModel(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.faster_item_rendering;
|
||||
|
||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.SimpleBakedModel;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.embeddedt.modernfix.render.FastItemRenderType;
|
||||
import org.embeddedt.modernfix.render.RenderState;
|
||||
import org.embeddedt.modernfix.render.SimpleItemModelView;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
|
||||
@Mixin(value = ItemStackRenderState.LayerRenderState.class, priority = 600)
|
||||
@ClientOnlyMixin
|
||||
public abstract class LayerRenderStateMixin {
|
||||
@Shadow(aliases = {"this$0"}) @Final private ItemStackRenderState field_55345;
|
||||
|
||||
@Shadow abstract ItemTransform transform();
|
||||
|
||||
@Unique
|
||||
private final SimpleItemModelView modelView = new SimpleItemModelView();
|
||||
|
||||
/**
|
||||
* If a model
|
||||
* - is a vanilla item model (SimpleBakedModel),
|
||||
* - has no custom GUI transforms, and
|
||||
* - is being rendered in 2D on a GUI
|
||||
* we do not need to go through the process of rendering every quad. Just render the south ones (the ones facing the
|
||||
* camera).
|
||||
*/
|
||||
@ModifyArg(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/ItemRenderer;renderItem(Lnet/minecraft/world/item/ItemDisplayContext;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;II[ILnet/minecraft/client/resources/model/BakedModel;Lnet/minecraft/client/renderer/RenderType;Lnet/minecraft/client/renderer/item/ItemStackRenderState$FoilType;)V"), index = 6)
|
||||
private BakedModel useSimpleWrappedItemModel(BakedModel model) {
|
||||
var transformType = ((ItemStackRenderStateAccessor)this.field_55345).getDisplayContext();
|
||||
// Forge composite models split themselves into a smaller simple model, we need to detect that the parent
|
||||
// was not simple
|
||||
// TODO 1.21.4 - I don't think that is needed anymore with the changes to item rendering
|
||||
/*
|
||||
if(originalModel != null && originalModel.getClass() != SimpleBakedModel.class) {
|
||||
return model;
|
||||
}
|
||||
*/
|
||||
|
||||
if(!RenderState.IS_RENDERING_LEVEL && model.getClass() == SimpleBakedModel.class && transformType == ItemDisplayContext.GUI) {
|
||||
FastItemRenderType type;
|
||||
ItemTransform transform = this.transform();
|
||||
if(transform == ItemTransform.NO_TRANSFORM)
|
||||
type = FastItemRenderType.SIMPLE_ITEM;
|
||||
else if(model.isGui3d() && isBlockTransforms(transform))
|
||||
type = FastItemRenderType.SIMPLE_BLOCK;
|
||||
else
|
||||
return model;
|
||||
modelView.setItem(model);
|
||||
modelView.setType(type);
|
||||
return modelView;
|
||||
} else
|
||||
return model;
|
||||
}
|
||||
|
||||
private boolean isBlockTransforms(ItemTransform transform) {
|
||||
return transform.rotation.x() == 30f
|
||||
&& transform.rotation.y() == 225f
|
||||
&& transform.rotation.z() == 0f;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.model_optimizations;
|
||||
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.client.renderer.block.model.multipart.Selector;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(Selector.class)
|
||||
@ClientOnlyMixin
|
||||
public class SelectorMixin {
|
||||
private ConcurrentHashMap<StateDefinition<Block, BlockState>, Predicate<BlockState>> predicateCache = new ConcurrentHashMap<>();
|
||||
@Inject(method = "getPredicate", at = @At("HEAD"), cancellable = true)
|
||||
private void useCachedPredicate(StateDefinition<Block, BlockState> pState, CallbackInfoReturnable<Predicate<BlockState>> cir) {
|
||||
Predicate<BlockState> cached = this.predicateCache.get(pState);
|
||||
if(cached != null)
|
||||
cir.setReturnValue(cached);
|
||||
}
|
||||
|
||||
@Inject(method = "getPredicate", at = @At("RETURN"))
|
||||
private void storeCachedPredicate(StateDefinition<Block, BlockState> pState, CallbackInfoReturnable<Predicate<BlockState>> cir) {
|
||||
this.predicateCache.put(pState, cir.getReturnValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package org.embeddedt.modernfix.common.mixin.perf.model_optimizations;
|
||||
|
||||
import com.mojang.math.Transformation;
|
||||
import org.joml.Matrix4f;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.joml.Matrix4fc;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
|
|
@ -13,7 +13,7 @@ import java.util.Objects;
|
|||
@Mixin(Transformation.class)
|
||||
@ClientOnlyMixin
|
||||
public class TransformationMatrixMixin {
|
||||
@Shadow @Final private Matrix4f matrix;
|
||||
@Shadow @Final private Matrix4fc matrix;
|
||||
private Integer cachedHashCode = null;
|
||||
/**
|
||||
* @author embeddedt
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
|
||||
public interface IBlockStateModelLoader {
|
||||
void loadSpecificBlock(ModelResourceLocation location);
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public interface IExtendedModelBakery {
|
||||
void mfix$tick();
|
||||
void mfix$finishLoading();
|
||||
UnbakedModel mfix$loadUnbakedModelDynamic(ModelResourceLocation location);
|
||||
UnbakedModel mfix$getMissingModel();
|
||||
ReentrantLock mfix$getLock();
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package org.embeddedt.modernfix.duck;
|
||||
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.renderer.block.model.BlockStateModel;
|
||||
|
||||
public interface IModelHoldingBlockState {
|
||||
BakedModel mfix$getModel();
|
||||
void mfix$setModel(BakedModel model);
|
||||
BlockStateModel mfix$getModel();
|
||||
void mfix$setModel(BlockStateModel model);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
package org.embeddedt.modernfix.dynamicresources;
|
||||
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
public class BlockStateSet implements Set<BlockState> {
|
||||
private static final BlockStateSet INSTANCE = new BlockStateSet();
|
||||
|
||||
private BlockStateSet() {
|
||||
|
||||
}
|
||||
|
||||
public static BlockStateSet instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Block.BLOCK_STATE_REGISTRY.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return o instanceof BlockState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterator<BlockState> iterator() {
|
||||
return Block.BLOCK_STATE_REGISTRY.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Object[] toArray() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <T> T[] toArray(@NotNull T[] a) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(BlockState blockState) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(@NotNull Collection<?> c) {
|
||||
return c.stream().allMatch(o -> o instanceof BlockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(@NotNull Collection<? extends BlockState> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(@NotNull Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(@NotNull Collection<?> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -10,28 +10,34 @@ import com.google.gson.JsonObject;
|
|||
import com.google.gson.JsonParser;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceSets;
|
||||
import net.minecraft.client.model.geom.EntityModelSet;
|
||||
import net.minecraft.client.renderer.block.BlockModelShaper;
|
||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||
import net.minecraft.client.renderer.block.model.BlockModelDefinition;
|
||||
import net.minecraft.client.renderer.block.model.BlockStateModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemModelGenerator;
|
||||
import net.minecraft.client.renderer.block.model.UnbakedBlockStateModel;
|
||||
import net.minecraft.client.renderer.block.model.SimpleModelWrapper;
|
||||
import net.minecraft.client.renderer.item.ClientItem;
|
||||
import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.client.renderer.item.MissingItemModel;
|
||||
import net.minecraft.client.renderer.item.ModelRenderProperties;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.AtlasSet;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||
import net.minecraft.client.resources.model.BlockStateDefinitions;
|
||||
import net.minecraft.client.resources.model.BlockStateModelLoader;
|
||||
import net.minecraft.client.resources.model.Material;
|
||||
import net.minecraft.client.resources.model.MissingBlockModel;
|
||||
import net.minecraft.client.resources.model.ModelBaker;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ModelDebugName;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.ModelDiscovery;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.client.resources.model.ResolvableModel;
|
||||
import net.minecraft.client.resources.model.ResolvedModel;
|
||||
import net.minecraft.client.resources.model.SpriteGetter;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
|
|
@ -75,7 +81,10 @@ public class DynamicModelProvider {
|
|||
private final LoadingCache<ResourceLocation, Optional<UnbakedModel>> loadedBlockModels =
|
||||
this.makeLoadingCache(this::loadBlockModel);
|
||||
|
||||
private final LoadingCache<ModelResourceLocation, Optional<BakedModel>> loadedBakedModels =
|
||||
private final LoadingCache<ResourceLocation, Optional<ModelDiscovery.ModelWrapper>> resolvedBlockModels =
|
||||
this.makeLoadingCache(this::resolveBlockModel);
|
||||
|
||||
private final LoadingCache<BlockState, Optional<BlockStateModel>> loadedBakedModels =
|
||||
this.makeLoadingCache(this::loadBakedModel);
|
||||
|
||||
private final LoadingCache<ResourceLocation, Optional<ClientItem>> loadedClientItemProperties =
|
||||
|
|
@ -84,23 +93,26 @@ public class DynamicModelProvider {
|
|||
private final LoadingCache<ResourceLocation, Optional<ItemModel>> loadedItemModels =
|
||||
this.makeLoadingCache(this::loadItemModel);
|
||||
|
||||
/*
|
||||
private final LoadingCache<ResourceLocation, Optional<BakedModel>> loadedStandaloneModels =
|
||||
this.makeLoadingCache(this::loadStandaloneModel);
|
||||
|
||||
private final BakedModel missingModel;
|
||||
*/
|
||||
|
||||
private final BlockStateModel missingModel;
|
||||
private final ModelDiscovery.ModelWrapper resolvedMissingModel;
|
||||
private final ItemModel missingItemModel;
|
||||
private final UnbakedModel unbakedMissingModel;
|
||||
private final Function<ResourceLocation, StateDefinition<Block, BlockState>> stateMapper;
|
||||
private final ResourceManager resourceManager;
|
||||
private final ModelBakery.TextureGetter textureGetter;
|
||||
private final DynamicResolver resolver;
|
||||
private final SpriteGetter textureGetter;
|
||||
private final EntityModelSet entityModelSet;
|
||||
private final ItemModelGenerator itemModelGenerator;
|
||||
|
||||
private final Map<ModelResourceLocation, BakedModel> mrlModelOverrides = new ConcurrentHashMap<>();
|
||||
private final Map<BlockState, BlockStateModel> mrlModelOverrides = new ConcurrentHashMap<>();
|
||||
private final Map<ResourceLocation, ItemModel> itemStackModelOverrides = new ConcurrentHashMap<>();
|
||||
private final Map<ResourceLocation, BakedModel> standaloneModelOverrides = new ConcurrentHashMap<>();
|
||||
private final Map<ModelResourceLocation, UnbakedBlockStateModel> unbakedBlockStateModelOverrides = new ConcurrentHashMap<>();
|
||||
//private final Map<ResourceLocation, BakedModel> standaloneModelOverrides = new ConcurrentHashMap<>();
|
||||
private final Map<BlockState, BlockStateModel.Unbaked> unbakedBlockStateModelOverrides = new ConcurrentHashMap<>();
|
||||
|
||||
private final List<DynamicModelProvider.DynamicModelPlugin> pluginList = new ArrayList<>();
|
||||
|
||||
|
|
@ -111,39 +123,54 @@ public class DynamicModelProvider {
|
|||
this.unbakedMissingModel = MissingBlockModel.missingModel();
|
||||
this.entityModelSet = entityModelSet;
|
||||
var missing = atlasMap.get(TextureAtlas.LOCATION_BLOCKS).missing();
|
||||
this.textureGetter = new ModelBakery.TextureGetter() {
|
||||
this.textureGetter = new SpriteGetter() {
|
||||
@Override
|
||||
public TextureAtlasSprite get(ModelDebugName modelDebugName, Material material) {
|
||||
public TextureAtlasSprite get(Material material, ModelDebugName modelDebugName) {
|
||||
var atlas = atlasMap.get(material.atlasLocation());
|
||||
var sprite = atlas.getSprite(material.texture());
|
||||
if (sprite != null) {
|
||||
return sprite;
|
||||
} else {
|
||||
ModernFix.LOGGER.warn("Unable to find sprite '{}' referenced by model '{}'", material.texture(), modelDebugName.get());
|
||||
ModernFix.LOGGER.warn("Unable to find sprite '{}' referenced by model '{}'", material.texture(), modelDebugName.debugName());
|
||||
return missing;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite reportMissingReference(ModelDebugName modelDebugName, String string) {
|
||||
public TextureAtlasSprite reportMissingReference(String string, ModelDebugName modelDebugName) {
|
||||
return missing;
|
||||
}
|
||||
};
|
||||
this.stateMapper = BlockStateModelLoader.definitionLocationToBlockMapper();
|
||||
this.stateMapper = BlockStateDefinitions.definitionLocationToBlockStateMapper();
|
||||
this.resourceManager = resourceManager;
|
||||
this.resolver = new DynamicResolver();
|
||||
this.itemModelGenerator = new ItemModelGenerator();
|
||||
this.missingModel = this.bakeMissingModel();
|
||||
this.missingItemModel = new MissingItemModel(this.missingModel);
|
||||
this.resolvedMissingModel = new ModelDiscovery.ModelWrapper(MissingBlockModel.LOCATION, this.unbakedMissingModel, true);
|
||||
var missingModelBaker = new ModelBaker() {
|
||||
@Override
|
||||
public ResolvedModel getModel(ResourceLocation resourceLocation) {
|
||||
throw new IllegalStateException("Missing model should not have dependencies");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpriteGetter sprites() {
|
||||
return DynamicModelProvider.this.textureGetter;
|
||||
}
|
||||
};
|
||||
var textureSlots = this.resolvedMissingModel.getTopTextureSlots();
|
||||
var quadCollection = this.resolvedMissingModel.bakeTopGeometry(textureSlots, missingModelBaker, BlockModelRotation.X0_Y0);
|
||||
var particleSprite = this.resolvedMissingModel.resolveParticleSprite(textureSlots, missingModelBaker);
|
||||
this.missingModel = new SimpleModelWrapper(quadCollection, resolvedMissingModel.getTopAmbientOcclusion(), particleSprite);
|
||||
this.missingItemModel = new MissingItemModel(quadCollection.getAll(), new ModelRenderProperties(resolvedMissingModel.getTopGuiLight().lightLikeBlock(), particleSprite, resolvedMissingModel.getTopTransforms()));
|
||||
try {
|
||||
Class.forName("net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin");
|
||||
pluginList.add(new FabricDynamicModelHandler(this, this.resourceManager));
|
||||
// TODO
|
||||
//pluginList.add(new FabricDynamicModelHandler(this, this.resourceManager));
|
||||
} catch(Exception ignored) {
|
||||
// Fabric API likely not present
|
||||
}
|
||||
}
|
||||
|
||||
public BakedModel getMissingBakedModel() {
|
||||
public BlockStateModel getMissingBakedModel() {
|
||||
return this.missingModel;
|
||||
}
|
||||
|
||||
|
|
@ -151,25 +178,15 @@ public class DynamicModelProvider {
|
|||
return this.missingItemModel;
|
||||
}
|
||||
|
||||
private static final Supplier<Set<ModelResourceLocation>> TOP_LEVEL_LOCATIONS_SUPPLIER = Suppliers.memoizeWithExpiration(() -> {
|
||||
Set<ModelResourceLocation> set = new HashSet<>();
|
||||
// Skip going through ModelLocationCache because most of the accesses will be misses
|
||||
BuiltInRegistries.BLOCK.entrySet().forEach(entry -> {
|
||||
var location = entry.getKey().location();
|
||||
for(BlockState state : entry.getValue().getStateDefinition().getPossibleStates()) {
|
||||
set.add(BlockModelShaper.stateToModelLocation(location, state));
|
||||
}
|
||||
});
|
||||
return Collections.unmodifiableSet(set);
|
||||
}, 2, TimeUnit.MINUTES);
|
||||
|
||||
public Map<ModelResourceLocation, BakedModel> getTopLevelEmulatedRegistry() {
|
||||
return new EmulatedRegistry<>(ModelResourceLocation.class, this.loadedBakedModels, TOP_LEVEL_LOCATIONS_SUPPLIER, this.mrlModelOverrides);
|
||||
public Map<BlockState, BlockStateModel> getTopLevelEmulatedRegistry() {
|
||||
return new EmulatedRegistry<>(BlockState.class, this.loadedBakedModels, BlockStateSet::instance, this.mrlModelOverrides);
|
||||
}
|
||||
|
||||
/*
|
||||
public Map<ResourceLocation, BakedModel> getStandaloneEmulatedRegistry() {
|
||||
return new EmulatedRegistry<>(ResourceLocation.class, this.loadedStandaloneModels, Set::of, this.standaloneModelOverrides);
|
||||
}
|
||||
*/
|
||||
|
||||
public Map<ResourceLocation, ItemModel> getItemModelEmulatedRegistry() {
|
||||
return new EmulatedRegistry<>(ResourceLocation.class, this.loadedItemModels, BuiltInRegistries.ITEM::keySet, this.itemStackModelOverrides);
|
||||
|
|
@ -348,62 +365,31 @@ public class DynamicModelProvider {
|
|||
for(Resource resource : resources) {
|
||||
try(Reader reader = resource.openAsReader()) {
|
||||
JsonObject jsonObject = GsonHelper.parse(reader);
|
||||
BlockModelDefinition blockModelDefinition = BlockModelDefinition.fromJsonElement(jsonObject);
|
||||
BlockModelDefinition blockModelDefinition = BlockModelDefinition.CODEC.decode(JsonOps.INSTANCE, jsonObject).getOrThrow().getFirst();
|
||||
loadedDefinitions.add(new BlockStateModelLoader.LoadedBlockModelDefinition(resource.sourcePackId(), blockModelDefinition));
|
||||
} catch(Exception e) {
|
||||
ModernFix.LOGGER.error("Failed to load blockstate definition {} from pack '{}'", location, resource.sourcePackId(), e);
|
||||
}
|
||||
}
|
||||
var loadedModels = new HashMap<>(BlockStateModelLoader.loadBlockStateDefinitionStack(location, stateDefinition, loadedDefinitions, this.unbakedMissingModel).models());
|
||||
var loadedModels = new HashMap<>(BlockStateModelLoader.loadBlockStateDefinitionStack(location, stateDefinition, loadedDefinitions).models());
|
||||
if (!pluginList.isEmpty()) {
|
||||
loadedModels.replaceAll((mrl, oldModel) -> {
|
||||
UnbakedBlockStateModel ubm = oldModel.model();
|
||||
BlockStateModel.Unbaked ubm = oldModel;
|
||||
for (var plugin : pluginList) {
|
||||
ubm = plugin.modifyBlockModelOnLoad(ubm, mrl, oldModel.state());
|
||||
}
|
||||
if (ubm == oldModel.model()) {
|
||||
return oldModel;
|
||||
} else {
|
||||
return new BlockStateModelLoader.LoadedModel(oldModel.state(), ubm);
|
||||
ubm = plugin.modifyBlockModelOnLoad(oldModel, mrl);
|
||||
}
|
||||
return ubm;
|
||||
});
|
||||
}
|
||||
return Optional.of(new BlockStateModelLoader.LoadedModels(loadedModels));
|
||||
}
|
||||
|
||||
private BakedModel bakeMissingModel() {
|
||||
this.resolver.clearResolver();
|
||||
this.unbakedMissingModel.resolveDependencies(this.resolver);
|
||||
var modelBaker = new DynamicBaker(() -> "missing");
|
||||
return UnbakedModel.bakeWithTopModelValues(this.unbakedMissingModel, modelBaker, BlockModelRotation.X0_Y0);
|
||||
}
|
||||
|
||||
private BakedModel bakeModel(UnbakedModel model, ResourceLocation location) {
|
||||
if (DEBUG_DYNAMIC_MODEL_LOADING) {
|
||||
ModernFix.LOGGER.info("Baking model '{}'", location);
|
||||
}
|
||||
synchronized (this) {
|
||||
this.resolver.clearResolver();
|
||||
model.resolveDependencies(this.resolver);
|
||||
var modelBaker = new DynamicBaker(location::toString);
|
||||
for (var plugin : pluginList) {
|
||||
model = plugin.modifyModelBeforeBake(model, location, BlockModelRotation.X0_Y0, modelBaker);
|
||||
}
|
||||
var bakedModel = UnbakedModel.bakeWithTopModelValues(model, modelBaker, BlockModelRotation.X0_Y0);
|
||||
for (var plugin : pluginList) {
|
||||
bakedModel = plugin.modifyModelAfterBake(bakedModel, model, location, BlockModelRotation.X0_Y0, modelBaker);
|
||||
}
|
||||
return bakedModel;
|
||||
}
|
||||
}
|
||||
|
||||
private BakedModel bakeModel(UnbakedBlockStateModel model, ModelResourceLocation mrl) {
|
||||
private BlockStateModel bakeModel(BlockStateModel.Unbaked model, BlockState mrl) {
|
||||
if (DEBUG_DYNAMIC_MODEL_LOADING) {
|
||||
ModernFix.LOGGER.info("Baking model '{}'", mrl);
|
||||
}
|
||||
synchronized (this) {
|
||||
this.resolver.clearResolver();
|
||||
model.resolveDependencies(this.resolver);
|
||||
model.resolveDependencies(dep -> {});
|
||||
var modelBaker = new DynamicBaker(mrl::toString);
|
||||
for (var plugin : pluginList) {
|
||||
model = plugin.modifyBlockModelBeforeBake(model, mrl, modelBaker);
|
||||
|
|
@ -416,32 +402,26 @@ public class DynamicModelProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private Optional<BakedModel> loadBakedModel(ModelResourceLocation location) {
|
||||
var override = this.mrlModelOverrides.get(location);
|
||||
private Optional<BlockStateModel> loadBakedModel(BlockState state) {
|
||||
var override = this.mrlModelOverrides.get(state);
|
||||
if (override != null) {
|
||||
return Optional.of(override);
|
||||
}
|
||||
if (location.variant().equals("standalone") || location.variant().equals("fabric_resource")) {
|
||||
return this.loadStandaloneModel(location.id());
|
||||
if (false) { //location.variant().equals("standalone") || location.variant().equals("fabric_resource")) {
|
||||
throw new UnsupportedOperationException(); //return this.loadStandaloneModel(location.id());
|
||||
} else {
|
||||
Optional<UnbakedBlockStateModel> unbakedModelOpt = Optional.ofNullable(this.unbakedBlockStateModelOverrides.get(location));
|
||||
Optional<BlockStateModel.Unbaked> unbakedModelOpt = Optional.ofNullable(this.unbakedBlockStateModelOverrides.get(state));
|
||||
if (unbakedModelOpt.isEmpty()) {
|
||||
var optLoadedModels = this.loadedStateDefinitions.getUnchecked(location.id());
|
||||
unbakedModelOpt = optLoadedModels.map(loadedModels -> {
|
||||
var loadedModel = loadedModels.models().get(location);
|
||||
if(loadedModel != null) {
|
||||
return loadedModel.model();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
var optLoadedModels = this.loadedStateDefinitions.getUnchecked(state.getBlock().builtInRegistryHolder().key().location());
|
||||
unbakedModelOpt = optLoadedModels.map(loadedModels -> loadedModels.models().get(state));
|
||||
}
|
||||
return unbakedModelOpt.map(unbakedModel -> {
|
||||
return this.bakeModel(unbakedModel, location);
|
||||
return this.bakeModel(unbakedModel, state);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
private Optional<BakedModel> loadStandaloneModel(ResourceLocation location) {
|
||||
var override = this.standaloneModelOverrides.get(location);
|
||||
if (override != null) {
|
||||
|
|
@ -451,6 +431,7 @@ public class DynamicModelProvider {
|
|||
return this.bakeModel(unbakedModel, location);
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
private Optional<UnbakedModel> loadBlockModelDefault(ResourceLocation location) {
|
||||
if (DEBUG_DYNAMIC_MODEL_LOADING) {
|
||||
|
|
@ -484,6 +465,29 @@ public class DynamicModelProvider {
|
|||
return value;
|
||||
}
|
||||
|
||||
private Optional<ModelDiscovery.ModelWrapper> resolveBlockModel(ResourceLocation location) {
|
||||
var unbakedOpt = this.loadedBlockModels.getUnchecked(location);
|
||||
if (unbakedOpt.isEmpty()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
ModelDiscovery.ModelWrapper wrapper = new ModelDiscovery.ModelWrapper(location, unbakedOpt.get(), true);
|
||||
var parent = wrapper.wrapped().parent();
|
||||
if (parent != null) {
|
||||
Optional<ModelDiscovery.ModelWrapper> resolvedParentOpt;
|
||||
try {
|
||||
resolvedParentOpt = this.resolvedBlockModels.getUnchecked(parent);
|
||||
} catch (Exception e) {
|
||||
// Possible recursive load, etc.
|
||||
ModernFix.LOGGER.error("Error while resolving model '{}'", location, e);
|
||||
return Optional.empty();
|
||||
}
|
||||
if (resolvedParentOpt.isPresent()) {
|
||||
wrapper.parent = resolvedParentOpt.get();
|
||||
}
|
||||
}
|
||||
return Optional.of(wrapper);
|
||||
}
|
||||
|
||||
|
||||
private Optional<ClientItem> loadClientItemProperties(ResourceLocation location) {
|
||||
if (DEBUG_DYNAMIC_MODEL_LOADING) {
|
||||
|
|
@ -513,12 +517,12 @@ public class DynamicModelProvider {
|
|||
return Optional.of(override);
|
||||
}
|
||||
return this.loadedClientItemProperties.getUnchecked(location).map(clientItem -> {
|
||||
var bakingContext = new ItemModel.BakingContext(new DynamicBaker(location::toString), this.entityModelSet, this.missingItemModel);
|
||||
var bakingContext = new ItemModel.BakingContext(new DynamicBaker(location::toString), this.entityModelSet, this.missingItemModel, clientItem.registrySwapper());
|
||||
return clientItem.model().bake(bakingContext);
|
||||
});
|
||||
}
|
||||
|
||||
public BakedModel getModel(ModelResourceLocation location) {
|
||||
public BlockStateModel getModel(BlockState location) {
|
||||
return this.loadedBakedModels.getUnchecked(location).orElse(this.missingModel);
|
||||
}
|
||||
|
||||
|
|
@ -530,11 +534,14 @@ public class DynamicModelProvider {
|
|||
return this.loadedItemModels.getUnchecked(location).orElse(this.missingItemModel);
|
||||
}
|
||||
|
||||
/*
|
||||
public BakedModel getStandaloneModel(ResourceLocation location) {
|
||||
return this.loadedStandaloneModels.getUnchecked(location).orElse(this.missingModel);
|
||||
}
|
||||
|
||||
public void addUnbakedBlockStateOverride(ModelResourceLocation location, UnbakedBlockStateModel model) {
|
||||
*/
|
||||
|
||||
public void addUnbakedBlockStateOverride(BlockState location, BlockStateModel.Unbaked model) {
|
||||
this.unbakedBlockStateModelOverrides.put(location, model);
|
||||
}
|
||||
|
||||
|
|
@ -546,56 +553,13 @@ public class DynamicModelProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BakedModel bake(ResourceLocation location, ModelState transform) {
|
||||
return DynamicModelProvider.this.loadedBlockModels.getUnchecked(location).map(unbakedModel -> {
|
||||
DynamicModelProvider.this.resolver.clearResolver();
|
||||
unbakedModel.resolveDependencies(DynamicModelProvider.this.resolver);
|
||||
return UnbakedModel.bakeWithTopModelValues(unbakedModel, this, transform);
|
||||
}).orElse(DynamicModelProvider.this.missingModel);
|
||||
public ResolvedModel getModel(ResourceLocation location) {
|
||||
return DynamicModelProvider.this.resolvedBlockModels.getUnchecked(location).orElse(DynamicModelProvider.this.resolvedMissingModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpriteGetter sprites() {
|
||||
return DynamicModelProvider.this.textureGetter.bind(this.modelDebugName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelDebugName rootName() {
|
||||
return this.modelDebugName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the Mojang impl but with some changes to make it slightly more efficient.
|
||||
*/
|
||||
private class DynamicResolver implements UnbakedModel.Resolver {
|
||||
private final Set<ResourceLocation> stack = new ObjectOpenHashSet<>(4);
|
||||
private final Set<ResourceLocation> resolvedModels = new ObjectOpenHashSet<>();
|
||||
|
||||
@Override
|
||||
public UnbakedModel resolve(ResourceLocation resourceLocation) {
|
||||
if (this.stack.contains(resourceLocation)) {
|
||||
ModernFix.LOGGER.warn("Detected model loading loop: {}->{}", this.stacktraceToString(), resourceLocation);
|
||||
return DynamicModelProvider.this.unbakedMissingModel;
|
||||
} else {
|
||||
UnbakedModel unbakedModel = DynamicModelProvider.this.loadedBlockModels.getUnchecked(resourceLocation).orElse(DynamicModelProvider.this.unbakedMissingModel);
|
||||
if (this.resolvedModels.add(resourceLocation)) {
|
||||
this.stack.add(resourceLocation);
|
||||
unbakedModel.resolveDependencies(this);
|
||||
this.stack.remove(resourceLocation);
|
||||
}
|
||||
|
||||
return unbakedModel;
|
||||
}
|
||||
}
|
||||
|
||||
private String stacktraceToString() {
|
||||
return this.stack.stream().map(ResourceLocation::toString).collect(Collectors.joining("->"));
|
||||
}
|
||||
|
||||
public void clearResolver() {
|
||||
this.stack.clear();
|
||||
this.resolvedModels.clear();
|
||||
return DynamicModelProvider.this.textureGetter;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -607,12 +571,12 @@ public class DynamicModelProvider {
|
|||
|
||||
public interface DynamicModelPlugin {
|
||||
Optional<UnbakedModel> modifyModelOnLoad(Optional<UnbakedModel> model, ResourceLocation id);
|
||||
UnbakedBlockStateModel modifyBlockModelOnLoad(UnbakedBlockStateModel model, ModelResourceLocation id, BlockState state);
|
||||
BlockStateModel.Unbaked modifyBlockModelOnLoad(BlockStateModel.Unbaked model, BlockState state);
|
||||
|
||||
UnbakedModel modifyModelBeforeBake(UnbakedModel model, ResourceLocation id, ModelState state, ModelBaker baker);
|
||||
BakedModel modifyModelAfterBake(BakedModel bakedModel, UnbakedModel model, ResourceLocation id, ModelState state, ModelBaker baker);
|
||||
//BakedModel modifyModelAfterBake(BakedModel bakedModel, UnbakedModel model, ResourceLocation id, ModelState state, ModelBaker baker);
|
||||
|
||||
UnbakedBlockStateModel modifyBlockModelBeforeBake(UnbakedBlockStateModel model, ModelResourceLocation id, ModelBaker baker);
|
||||
BakedModel modifyBlockModelAfterBake(BakedModel bakedModel, UnbakedBlockStateModel model, ModelResourceLocation id, ModelBaker baker);
|
||||
BlockStateModel.Unbaked modifyBlockModelBeforeBake(BlockStateModel.Unbaked model, BlockState state, ModelBaker baker);
|
||||
BlockStateModel modifyBlockModelAfterBake(BlockStateModel bakedModel, BlockStateModel.Unbaked unbaked, BlockState state, ModelBaker baker);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,301 +1,301 @@
|
|||
package org.embeddedt.modernfix.dynamicresources;
|
||||
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.BlockStateResolver;
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.ModelModifier;
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlugin;
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.minecraft.client.renderer.block.BlockModelShaper;
|
||||
import net.minecraft.client.renderer.block.model.UnbakedBlockStateModel;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelBaker;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.ModelState;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class FabricDynamicModelHandler implements DynamicModelProvider.DynamicModelPlugin {
|
||||
// Borrowed from Fabric API, this dispatching logic is extremely trivial
|
||||
|
||||
private static final ResourceLocation[] MODEL_MODIFIER_PHASES = new ResourceLocation[] { ModelModifier.OVERRIDE_PHASE, ModelModifier.DEFAULT_PHASE, ModelModifier.WRAP_PHASE, ModelModifier.WRAP_LAST_PHASE };
|
||||
|
||||
private final Event<ModelModifier.OnLoad> onLoadModifiers = EventFactory.createWithPhases(ModelModifier.OnLoad.class, modifiers -> (model, context) -> {
|
||||
for (ModelModifier.OnLoad modifier : modifiers) {
|
||||
try {
|
||||
model = modifier.modifyModelOnLoad(model, context);
|
||||
} catch (Exception exception) {
|
||||
ModernFix.LOGGER.error("Failed to modify unbaked model on load", exception);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}, MODEL_MODIFIER_PHASES);
|
||||
|
||||
private final Event<ModelModifier.OnLoadBlock> onLoadBlockModifiers = EventFactory.createWithPhases(ModelModifier.OnLoadBlock.class, modifiers -> (model, context) -> {
|
||||
for (ModelModifier.OnLoadBlock modifier : modifiers) {
|
||||
try {
|
||||
model = modifier.modifyModelOnLoad(model, context);
|
||||
} catch (Exception exception) {
|
||||
ModernFix.LOGGER.error("Failed to modify unbaked block model on load", exception);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}, MODEL_MODIFIER_PHASES);
|
||||
|
||||
private final Event<ModelModifier.BeforeBakeBlock> beforeBakeBlockModifiers = EventFactory.createWithPhases(ModelModifier.BeforeBakeBlock.class, modifiers -> (model, context) -> {
|
||||
for (ModelModifier.BeforeBakeBlock modifier : modifiers) {
|
||||
try {
|
||||
model = modifier.modifyModelBeforeBake(model, context);
|
||||
} catch (Exception exception) {
|
||||
ModernFix.LOGGER.error("Failed to modify unbaked block model before bake", exception);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}, MODEL_MODIFIER_PHASES);
|
||||
private final Event<ModelModifier.AfterBakeBlock> afterBakeBlockModifiers = EventFactory.createWithPhases(ModelModifier.AfterBakeBlock.class, modifiers -> (model, context) -> {
|
||||
for (ModelModifier.AfterBakeBlock modifier : modifiers) {
|
||||
try {
|
||||
model = modifier.modifyModelAfterBake(model, context);
|
||||
} catch (Exception exception) {
|
||||
ModernFix.LOGGER.error("Failed to modify baked block model after bake", exception);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}, MODEL_MODIFIER_PHASES);
|
||||
private final Event<ModelModifier.BeforeBake> beforeBakeModifiers = EventFactory.createWithPhases(ModelModifier.BeforeBake.class, modifiers -> (model, context) -> {
|
||||
for (ModelModifier.BeforeBake modifier : modifiers) {
|
||||
try {
|
||||
model = modifier.modifyModelBeforeBake(model, context);
|
||||
} catch (Exception exception) {
|
||||
ModernFix.LOGGER.error("Failed to modify unbaked model before bake", exception);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}, MODEL_MODIFIER_PHASES);
|
||||
private final Event<ModelModifier.AfterBake> afterBakeModifiers = EventFactory.createWithPhases(ModelModifier.AfterBake.class, modifiers -> (model, context) -> {
|
||||
for (ModelModifier.AfterBake modifier : modifiers) {
|
||||
try {
|
||||
model = modifier.modifyModelAfterBake(model, context);
|
||||
} catch (Exception exception) {
|
||||
ModernFix.LOGGER.error("Failed to modify baked model after bake", exception);
|
||||
}
|
||||
}
|
||||
|
||||
return model;
|
||||
}, MODEL_MODIFIER_PHASES);
|
||||
|
||||
record PreparablePluginData<T>(CompletableFuture<T> data, PreparableModelLoadingPlugin.Holder<T> plugin) {
|
||||
void initialize(ModelLoadingPlugin.Context context) {
|
||||
plugin.plugin().initialize(data.join(), context);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> PreparablePluginData<T> makeDataRecord(ResourceManager manager, PreparableModelLoadingPlugin.Holder<T> holder) {
|
||||
return new PreparablePluginData<>(holder.loader().load(manager, ModernFix.resourceReloadExecutor()), holder);
|
||||
}
|
||||
|
||||
public FabricDynamicModelHandler(DynamicModelProvider provider, ResourceManager manager) {
|
||||
List<ModelLoadingPlugin> pluginList = new ArrayList<>(ModelLoadingPlugin.getAll());
|
||||
var preparablePluginData = new ArrayList<PreparablePluginData<?>>();
|
||||
for (var holder : PreparableModelLoadingPlugin.getAll()) {
|
||||
preparablePluginData.add(makeDataRecord(manager, holder));
|
||||
}
|
||||
// Wait for all the preparable plugins to finish loading
|
||||
CompletableFuture.allOf(preparablePluginData.stream().map(PreparablePluginData::data).toArray(CompletableFuture[]::new)).join();
|
||||
var context = new PluginContext(provider);
|
||||
for (var plugin : pluginList) {
|
||||
plugin.initialize(context);
|
||||
}
|
||||
for (var data : preparablePluginData) {
|
||||
data.initialize(context);
|
||||
}
|
||||
context.fireResolvers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<UnbakedModel> modifyModelOnLoad(Optional<UnbakedModel> model, ResourceLocation id) {
|
||||
return Optional.ofNullable(this.onLoadModifiers.invoker().modifyModelOnLoad(model.orElse(null), () -> id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedBlockStateModel modifyBlockModelOnLoad(UnbakedBlockStateModel model, ModelResourceLocation id, BlockState state) {
|
||||
return this.onLoadBlockModifiers.invoker().modifyModelOnLoad(model, new ModelModifier.OnLoadBlock.Context() {
|
||||
@Override
|
||||
public ModelResourceLocation id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState state() {
|
||||
return state;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedModel modifyModelBeforeBake(UnbakedModel model, ResourceLocation id, ModelState state, ModelBaker baker) {
|
||||
return beforeBakeModifiers.invoker().modifyModelBeforeBake(model, new ModelModifier.BeforeBake.Context() {
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelState settings() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelBaker baker() {
|
||||
return baker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public BakedModel modifyModelAfterBake(BakedModel bakedModel, UnbakedModel model, ResourceLocation id, ModelState state, ModelBaker baker) {
|
||||
return afterBakeModifiers.invoker().modifyModelAfterBake(bakedModel, new ModelModifier.AfterBake.Context() {
|
||||
@Override
|
||||
public ResourceLocation id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedModel sourceModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelState settings() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelBaker baker() {
|
||||
return baker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedBlockStateModel modifyBlockModelBeforeBake(UnbakedBlockStateModel model, ModelResourceLocation id, ModelBaker baker) {
|
||||
return beforeBakeBlockModifiers.invoker().modifyModelBeforeBake(model, new ModelModifier.BeforeBakeBlock.Context() {
|
||||
@Override
|
||||
public ModelResourceLocation id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelBaker baker() {
|
||||
return baker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public BakedModel modifyBlockModelAfterBake(BakedModel bakedModel, UnbakedBlockStateModel model, ModelResourceLocation id, ModelBaker baker) {
|
||||
return afterBakeBlockModifiers.invoker().modifyModelAfterBake(bakedModel, new ModelModifier.AfterBakeBlock.Context() {
|
||||
@Override
|
||||
public ModelResourceLocation id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedBlockStateModel sourceModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelBaker baker() {
|
||||
return baker;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class PluginContext implements ModelLoadingPlugin.Context {
|
||||
private final DynamicModelProvider provider;
|
||||
private final Map<Block, BlockStateResolver> resolvers = new HashMap<>();
|
||||
|
||||
private PluginContext(DynamicModelProvider provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addModels(ResourceLocation... ids) {
|
||||
/* no-op on dynamic model loader */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addModels(Collection<? extends ResourceLocation> ids) {
|
||||
/* no-op on dynamic model loader */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBlockStateResolver(Block block, BlockStateResolver resolver) {
|
||||
resolvers.put(block, resolver);
|
||||
}
|
||||
|
||||
public void fireResolvers() {
|
||||
resolvers.forEach((block, resolver) -> {
|
||||
resolver.resolveBlockStates(new BlockStateResolver.Context() {
|
||||
@Override
|
||||
public Block block() {
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModel(BlockState state, UnbakedBlockStateModel model) {
|
||||
provider.addUnbakedBlockStateOverride(BlockModelShaper.stateToModelLocation(state), model);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ModelModifier.OnLoad> modifyModelOnLoad() {
|
||||
return onLoadModifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ModelModifier.OnLoadBlock> modifyBlockModelOnLoad() {
|
||||
return onLoadBlockModifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ModelModifier.BeforeBake> modifyModelBeforeBake() {
|
||||
return beforeBakeModifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ModelModifier.AfterBake> modifyModelAfterBake() {
|
||||
return afterBakeModifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ModelModifier.BeforeBakeBlock> modifyBlockModelBeforeBake() {
|
||||
return beforeBakeBlockModifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Event<ModelModifier.AfterBakeBlock> modifyBlockModelAfterBake() {
|
||||
return afterBakeBlockModifiers;
|
||||
}
|
||||
}
|
||||
}
|
||||
//package org.embeddedt.modernfix.dynamicresources;
|
||||
//
|
||||
//import net.fabricmc.fabric.api.client.model.loading.v1.BlockStateResolver;
|
||||
//import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
|
||||
//import net.fabricmc.fabric.api.client.model.loading.v1.ModelModifier;
|
||||
//import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlugin;
|
||||
//import net.fabricmc.fabric.api.event.Event;
|
||||
//import net.fabricmc.fabric.api.event.EventFactory;
|
||||
//import net.minecraft.client.renderer.block.BlockModelShaper;
|
||||
//import net.minecraft.client.renderer.block.model.UnbakedBlockStateModel;
|
||||
//import net.minecraft.client.resources.model.BakedModel;
|
||||
//import net.minecraft.client.resources.model.ModelBaker;
|
||||
//import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
//import net.minecraft.client.resources.model.ModelState;
|
||||
//import net.minecraft.client.resources.model.UnbakedModel;
|
||||
//import net.minecraft.resources.ResourceLocation;
|
||||
//import net.minecraft.server.packs.resources.ResourceManager;
|
||||
//import net.minecraft.world.level.block.Block;
|
||||
//import net.minecraft.world.level.block.state.BlockState;
|
||||
//import org.embeddedt.modernfix.ModernFix;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.Collection;
|
||||
//import java.util.HashMap;
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//import java.util.Optional;
|
||||
//import java.util.concurrent.CompletableFuture;
|
||||
//
|
||||
//public class FabricDynamicModelHandler implements DynamicModelProvider.DynamicModelPlugin {
|
||||
// // Borrowed from Fabric API, this dispatching logic is extremely trivial
|
||||
//
|
||||
// private static final ResourceLocation[] MODEL_MODIFIER_PHASES = new ResourceLocation[] { ModelModifier.OVERRIDE_PHASE, ModelModifier.DEFAULT_PHASE, ModelModifier.WRAP_PHASE, ModelModifier.WRAP_LAST_PHASE };
|
||||
//
|
||||
// private final Event<ModelModifier.OnLoad> onLoadModifiers = EventFactory.createWithPhases(ModelModifier.OnLoad.class, modifiers -> (model, context) -> {
|
||||
// for (ModelModifier.OnLoad modifier : modifiers) {
|
||||
// try {
|
||||
// model = modifier.modifyModelOnLoad(model, context);
|
||||
// } catch (Exception exception) {
|
||||
// ModernFix.LOGGER.error("Failed to modify unbaked model on load", exception);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return model;
|
||||
// }, MODEL_MODIFIER_PHASES);
|
||||
//
|
||||
// private final Event<ModelModifier.OnLoadBlock> onLoadBlockModifiers = EventFactory.createWithPhases(ModelModifier.OnLoadBlock.class, modifiers -> (model, context) -> {
|
||||
// for (ModelModifier.OnLoadBlock modifier : modifiers) {
|
||||
// try {
|
||||
// model = modifier.modifyModelOnLoad(model, context);
|
||||
// } catch (Exception exception) {
|
||||
// ModernFix.LOGGER.error("Failed to modify unbaked block model on load", exception);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return model;
|
||||
// }, MODEL_MODIFIER_PHASES);
|
||||
//
|
||||
// private final Event<ModelModifier.BeforeBakeBlock> beforeBakeBlockModifiers = EventFactory.createWithPhases(ModelModifier.BeforeBakeBlock.class, modifiers -> (model, context) -> {
|
||||
// for (ModelModifier.BeforeBakeBlock modifier : modifiers) {
|
||||
// try {
|
||||
// model = modifier.modifyModelBeforeBake(model, context);
|
||||
// } catch (Exception exception) {
|
||||
// ModernFix.LOGGER.error("Failed to modify unbaked block model before bake", exception);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return model;
|
||||
// }, MODEL_MODIFIER_PHASES);
|
||||
// private final Event<ModelModifier.AfterBakeBlock> afterBakeBlockModifiers = EventFactory.createWithPhases(ModelModifier.AfterBakeBlock.class, modifiers -> (model, context) -> {
|
||||
// for (ModelModifier.AfterBakeBlock modifier : modifiers) {
|
||||
// try {
|
||||
// model = modifier.modifyModelAfterBake(model, context);
|
||||
// } catch (Exception exception) {
|
||||
// ModernFix.LOGGER.error("Failed to modify baked block model after bake", exception);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return model;
|
||||
// }, MODEL_MODIFIER_PHASES);
|
||||
// private final Event<ModelModifier.BeforeBake> beforeBakeModifiers = EventFactory.createWithPhases(ModelModifier.BeforeBake.class, modifiers -> (model, context) -> {
|
||||
// for (ModelModifier.BeforeBake modifier : modifiers) {
|
||||
// try {
|
||||
// model = modifier.modifyModelBeforeBake(model, context);
|
||||
// } catch (Exception exception) {
|
||||
// ModernFix.LOGGER.error("Failed to modify unbaked model before bake", exception);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return model;
|
||||
// }, MODEL_MODIFIER_PHASES);
|
||||
// private final Event<ModelModifier.AfterBake> afterBakeModifiers = EventFactory.createWithPhases(ModelModifier.AfterBake.class, modifiers -> (model, context) -> {
|
||||
// for (ModelModifier.AfterBake modifier : modifiers) {
|
||||
// try {
|
||||
// model = modifier.modifyModelAfterBake(model, context);
|
||||
// } catch (Exception exception) {
|
||||
// ModernFix.LOGGER.error("Failed to modify baked model after bake", exception);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return model;
|
||||
// }, MODEL_MODIFIER_PHASES);
|
||||
//
|
||||
// record PreparablePluginData<T>(CompletableFuture<T> data, PreparableModelLoadingPlugin.Holder<T> plugin) {
|
||||
// void initialize(ModelLoadingPlugin.Context context) {
|
||||
// plugin.plugin().initialize(data.join(), context);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private <T> PreparablePluginData<T> makeDataRecord(ResourceManager manager, PreparableModelLoadingPlugin.Holder<T> holder) {
|
||||
// return new PreparablePluginData<>(holder.loader().load(manager, ModernFix.resourceReloadExecutor()), holder);
|
||||
// }
|
||||
//
|
||||
// public FabricDynamicModelHandler(DynamicModelProvider provider, ResourceManager manager) {
|
||||
// List<ModelLoadingPlugin> pluginList = new ArrayList<>(ModelLoadingPlugin.getAll());
|
||||
// var preparablePluginData = new ArrayList<PreparablePluginData<?>>();
|
||||
// for (var holder : PreparableModelLoadingPlugin.getAll()) {
|
||||
// preparablePluginData.add(makeDataRecord(manager, holder));
|
||||
// }
|
||||
// // Wait for all the preparable plugins to finish loading
|
||||
// CompletableFuture.allOf(preparablePluginData.stream().map(PreparablePluginData::data).toArray(CompletableFuture[]::new)).join();
|
||||
// var context = new PluginContext(provider);
|
||||
// for (var plugin : pluginList) {
|
||||
// plugin.initialize(context);
|
||||
// }
|
||||
// for (var data : preparablePluginData) {
|
||||
// data.initialize(context);
|
||||
// }
|
||||
// context.fireResolvers();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Optional<UnbakedModel> modifyModelOnLoad(Optional<UnbakedModel> model, ResourceLocation id) {
|
||||
// return Optional.ofNullable(this.onLoadModifiers.invoker().modifyModelOnLoad(model.orElse(null), () -> id));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UnbakedBlockStateModel modifyBlockModelOnLoad(UnbakedBlockStateModel model, ModelResourceLocation id, BlockState state) {
|
||||
// return this.onLoadBlockModifiers.invoker().modifyModelOnLoad(model, new ModelModifier.OnLoadBlock.Context() {
|
||||
// @Override
|
||||
// public ModelResourceLocation id() {
|
||||
// return id;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public BlockState state() {
|
||||
// return state;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UnbakedModel modifyModelBeforeBake(UnbakedModel model, ResourceLocation id, ModelState state, ModelBaker baker) {
|
||||
// return beforeBakeModifiers.invoker().modifyModelBeforeBake(model, new ModelModifier.BeforeBake.Context() {
|
||||
// @Override
|
||||
// public ResourceLocation id() {
|
||||
// return id;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ModelState settings() {
|
||||
// return state;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ModelBaker baker() {
|
||||
// return baker;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public BakedModel modifyModelAfterBake(BakedModel bakedModel, UnbakedModel model, ResourceLocation id, ModelState state, ModelBaker baker) {
|
||||
// return afterBakeModifiers.invoker().modifyModelAfterBake(bakedModel, new ModelModifier.AfterBake.Context() {
|
||||
// @Override
|
||||
// public ResourceLocation id() {
|
||||
// return id;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UnbakedModel sourceModel() {
|
||||
// return model;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ModelState settings() {
|
||||
// return state;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ModelBaker baker() {
|
||||
// return baker;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UnbakedBlockStateModel modifyBlockModelBeforeBake(UnbakedBlockStateModel model, ModelResourceLocation id, ModelBaker baker) {
|
||||
// return beforeBakeBlockModifiers.invoker().modifyModelBeforeBake(model, new ModelModifier.BeforeBakeBlock.Context() {
|
||||
// @Override
|
||||
// public ModelResourceLocation id() {
|
||||
// return id;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ModelBaker baker() {
|
||||
// return baker;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public BakedModel modifyBlockModelAfterBake(BakedModel bakedModel, UnbakedBlockStateModel model, ModelResourceLocation id, ModelBaker baker) {
|
||||
// return afterBakeBlockModifiers.invoker().modifyModelAfterBake(bakedModel, new ModelModifier.AfterBakeBlock.Context() {
|
||||
// @Override
|
||||
// public ModelResourceLocation id() {
|
||||
// return id;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UnbakedBlockStateModel sourceModel() {
|
||||
// return model;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ModelBaker baker() {
|
||||
// return baker;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// private class PluginContext implements ModelLoadingPlugin.Context {
|
||||
// private final DynamicModelProvider provider;
|
||||
// private final Map<Block, BlockStateResolver> resolvers = new HashMap<>();
|
||||
//
|
||||
// private PluginContext(DynamicModelProvider provider) {
|
||||
// this.provider = provider;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void addModels(ResourceLocation... ids) {
|
||||
// /* no-op on dynamic model loader */
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void addModels(Collection<? extends ResourceLocation> ids) {
|
||||
// /* no-op on dynamic model loader */
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void registerBlockStateResolver(Block block, BlockStateResolver resolver) {
|
||||
// resolvers.put(block, resolver);
|
||||
// }
|
||||
//
|
||||
// public void fireResolvers() {
|
||||
// resolvers.forEach((block, resolver) -> {
|
||||
// resolver.resolveBlockStates(new BlockStateResolver.Context() {
|
||||
// @Override
|
||||
// public Block block() {
|
||||
// return block;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void setModel(BlockState state, UnbakedBlockStateModel model) {
|
||||
// provider.addUnbakedBlockStateOverride(BlockModelShaper.stateToModelLocation(state), model);
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Event<ModelModifier.OnLoad> modifyModelOnLoad() {
|
||||
// return onLoadModifiers;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Event<ModelModifier.OnLoadBlock> modifyBlockModelOnLoad() {
|
||||
// return onLoadBlockModifiers;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Event<ModelModifier.BeforeBake> modifyModelBeforeBake() {
|
||||
// return beforeBakeModifiers;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Event<ModelModifier.AfterBake> modifyModelAfterBake() {
|
||||
// return afterBakeModifiers;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Event<ModelModifier.BeforeBakeBlock> modifyBlockModelBeforeBake() {
|
||||
// return beforeBakeBlockModifiers;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Event<ModelModifier.AfterBakeBlock> modifyBlockModelAfterBake() {
|
||||
// return afterBakeBlockModifiers;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package org.embeddedt.modernfix.dynamicresources;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
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.minecraft.world.level.block.state.properties.Property;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ModelBakeryHelpers {
|
||||
private static <T extends Comparable<T>, V extends T> BlockState setPropertyGeneric(BlockState state, Property<T> prop, Object o) {
|
||||
return state.setValue(prop, (V)o);
|
||||
}
|
||||
|
||||
private static <T extends Comparable<T>> T getValueHelper(Property<T> property, String value) {
|
||||
return property.getValue(value).orElse(null);
|
||||
}
|
||||
|
||||
private static final Splitter COMMA_SPLITTER = Splitter.on(',');
|
||||
private static final Splitter EQUAL_SPLITTER = Splitter.on('=').limit(2);
|
||||
|
||||
public static ImmutableList<BlockState> getBlockStatesForMRL(StateDefinition<Block, BlockState> stateDefinition, ModelResourceLocation location) {
|
||||
if(Objects.equals(location.getVariant(), "inventory"))
|
||||
return ImmutableList.of();
|
||||
Set<Property<?>> fixedProperties = new HashSet<>();
|
||||
BlockState fixedState = stateDefinition.any();
|
||||
for(String s : COMMA_SPLITTER.split(location.getVariant())) {
|
||||
Iterator<String> iterator = EQUAL_SPLITTER.split(s).iterator();
|
||||
if (iterator.hasNext()) {
|
||||
String s1 = iterator.next();
|
||||
Property<?> property = stateDefinition.getProperty(s1);
|
||||
if (property != null && iterator.hasNext()) {
|
||||
String s2 = iterator.next();
|
||||
Object value = getValueHelper(property, s2);
|
||||
if (value == null) {
|
||||
throw new RuntimeException("Unknown value: '" + s2 + "' for blockstate property: '" + s1 + "' " + property.getPossibleValues());
|
||||
}
|
||||
fixedState = setPropertyGeneric(fixedState, property, value);
|
||||
fixedProperties.add(property);
|
||||
} else if (!s1.isEmpty()) {
|
||||
throw new RuntimeException("Unknown blockstate property: '" + s1 + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
// check if there is only one possible state
|
||||
if(fixedProperties.size() == stateDefinition.getProperties().size()) {
|
||||
return ImmutableList.of(fixedState);
|
||||
}
|
||||
// generate all possible blockstates from the remaining properties
|
||||
ArrayList<Property<?>> anyProperties = new ArrayList<>(stateDefinition.getProperties());
|
||||
anyProperties.removeAll(fixedProperties);
|
||||
ArrayList<BlockState> finalList = new ArrayList<>();
|
||||
finalList.add(fixedState);
|
||||
for(Property<?> property : anyProperties) {
|
||||
ArrayList<BlockState> newPermutations = new ArrayList<>();
|
||||
for(BlockState state : finalList) {
|
||||
for(Comparable<?> value : property.getPossibleValues()) {
|
||||
newPermutations.add(setPropertyGeneric(state, property, value));
|
||||
}
|
||||
}
|
||||
finalList = newPermutations;
|
||||
}
|
||||
return ImmutableList.copyOf(finalList);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
package org.embeddedt.modernfix.dynamicresources;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import net.minecraft.client.renderer.block.BlockModelShaper;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class ModelLocationCache {
|
||||
private static final LoadingCache<BlockState, ModelResourceLocation> blockLocationCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(10000)
|
||||
.build(new CacheLoader<BlockState, ModelResourceLocation>() {
|
||||
@Override
|
||||
public ModelResourceLocation load(BlockState key) throws Exception {
|
||||
return BlockModelShaper.stateToModelLocation(key);
|
||||
}
|
||||
});
|
||||
|
||||
private static final LoadingCache<Item, ModelResourceLocation> itemLocationCache = CacheBuilder.newBuilder()
|
||||
.maximumSize(10000)
|
||||
.build(new CacheLoader<Item, ModelResourceLocation>() {
|
||||
@Override
|
||||
public ModelResourceLocation load(Item key) throws Exception {
|
||||
return new ModelResourceLocation(BuiltInRegistries.ITEM.getKey(key), "inventory");
|
||||
}
|
||||
});
|
||||
|
||||
public static ModelResourceLocation get(BlockState state) {
|
||||
if(state == null)
|
||||
return null;
|
||||
try {
|
||||
return blockLocationCache.get(state);
|
||||
} catch(ExecutionException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
public static ModelResourceLocation get(Item item) {
|
||||
if(item == null)
|
||||
return null;
|
||||
try {
|
||||
return itemLocationCache.get(item);
|
||||
} catch(ExecutionException e) {
|
||||
throw new RuntimeException(e.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
package org.embeddedt.modernfix.render;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransforms;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper class that presents a fake view of item models (only showing the simple front-facing quads), rather
|
||||
* than every quad.
|
||||
*/
|
||||
public class SimpleItemModelView implements BakedModel {
|
||||
private BakedModel wrappedItem;
|
||||
private FastItemRenderType type;
|
||||
|
||||
public void setItem(BakedModel model) {
|
||||
this.wrappedItem = model;
|
||||
}
|
||||
|
||||
public void setType(FastItemRenderType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private boolean isCorrectDirectionForType(Direction direction) {
|
||||
if(type == FastItemRenderType.SIMPLE_ITEM)
|
||||
return direction == Direction.SOUTH;
|
||||
else {
|
||||
return direction == Direction.UP || direction == Direction.EAST || direction == Direction.NORTH;
|
||||
}
|
||||
}
|
||||
|
||||
private final List<BakedQuad> nullQuadList = new ObjectArrayList<>();
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, RandomSource rand) {
|
||||
boolean isWholeListValid = isCorrectDirectionForType(side);
|
||||
List<BakedQuad> realList = wrappedItem.getQuads(state, side, rand);
|
||||
if (isWholeListValid) {
|
||||
return realList;
|
||||
}
|
||||
nullQuadList.clear();
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for(int i = 0; i < realList.size(); i++) {
|
||||
BakedQuad quad = realList.get(i);
|
||||
if(isCorrectDirectionForType(quad.getDirection())) {
|
||||
nullQuadList.add(quad);
|
||||
}
|
||||
}
|
||||
return nullQuadList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return wrappedItem.useAmbientOcclusion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGui3d() {
|
||||
return wrappedItem.isGui3d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesBlockLight() {
|
||||
return wrappedItem.usesBlockLight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureAtlasSprite getParticleIcon() {
|
||||
return wrappedItem.getParticleIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemTransforms getTransforms() {
|
||||
return wrappedItem.getTransforms();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ public class OptionList extends ContainerObjectSelectionList<OptionList.Entry> {
|
|||
String friendlyKey = "modernfix.option.name." + option.getName();
|
||||
MutableComponent baseComponent = Component.literal(option.getSelfName());
|
||||
if(I18n.exists(friendlyKey))
|
||||
return Component.translatable(friendlyKey).withStyle(style -> style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, baseComponent)));
|
||||
return Component.translatable(friendlyKey).withStyle(style -> style.withHoverEvent(new HoverEvent.ShowText(baseComponent)));
|
||||
else
|
||||
return baseComponent;
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ public class OptionList extends ContainerObjectSelectionList<OptionList.Entry> {
|
|||
for(String category : theCategories) {
|
||||
String categoryTranslationKey = "modernfix.option.category." + category;
|
||||
this.addEntry(new CategoryEntry(Component.translatable(categoryTranslationKey)
|
||||
.withStyle(Style.EMPTY.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable(categoryTranslationKey + ".description"))))
|
||||
.withStyle(Style.EMPTY.withHoverEvent(new HoverEvent.ShowText(Component.translatable(categoryTranslationKey + ".description"))))
|
||||
));
|
||||
optionsByCategory.get(category).stream().filter(key -> {
|
||||
int dotCount = 0;
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
package org.embeddedt.modernfix.util;
|
||||
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ItemMesherMap<K> implements Map<K, ModelResourceLocation> {
|
||||
private final Function<K, ModelResourceLocation> getLocation;
|
||||
|
||||
public ItemMesherMap(Function<K, ModelResourceLocation> getLocation) {
|
||||
this.getLocation = getLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return BuiltInRegistries.ITEM.keySet().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelResourceLocation get(Object key) {
|
||||
return getLocation.apply((K)key);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ModelResourceLocation put(K key, ModelResourceLocation value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelResourceLocation remove(Object key) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NotNull Map<? extends K, ? extends ModelResourceLocation> m) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<ModelResourceLocation> values() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Map.Entry<K, ModelResourceLocation>> entrySet() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package org.embeddedt.modernfix.world;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
|
@ -9,6 +11,7 @@ import net.minecraft.util.datafix.DataFixTypes;
|
|||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.saveddata.SavedData;
|
||||
import net.minecraft.world.level.saveddata.SavedDataType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -20,11 +23,22 @@ public class StrongholdLocationCache extends SavedData {
|
|||
chunkPosList = new ArrayList<>();
|
||||
}
|
||||
|
||||
public static SavedData.Factory<StrongholdLocationCache> factory(ServerLevel serverLevel) {
|
||||
// FIXME datafixer will probably throw on update
|
||||
return new SavedData.Factory<>(StrongholdLocationCache::new, StrongholdLocationCache::load, DataFixTypes.SAVED_DATA_FORCED_CHUNKS);
|
||||
private StrongholdLocationCache(List<ChunkPos> list) {
|
||||
this.chunkPosList = new ArrayList<>(list);
|
||||
}
|
||||
|
||||
public static final Codec<StrongholdLocationCache> CODEC = RecordCodecBuilder.create(instance ->
|
||||
instance.group(ChunkPos.CODEC.listOf().optionalFieldOf("stronghold_positions", List.of()).forGetter(StrongholdLocationCache::getChunkPosList))
|
||||
.apply(instance, StrongholdLocationCache::new)
|
||||
);
|
||||
|
||||
public static final SavedDataType<StrongholdLocationCache> TYPE = new SavedDataType<>(
|
||||
"modernfix_stronghold_cache",
|
||||
StrongholdLocationCache::new,
|
||||
CODEC,
|
||||
DataFixTypes.SAVED_DATA_FORCED_CHUNKS
|
||||
);
|
||||
|
||||
public List<ChunkPos> getChunkPosList() {
|
||||
return new ArrayList<>(chunkPosList);
|
||||
}
|
||||
|
|
@ -33,30 +47,4 @@ public class StrongholdLocationCache extends SavedData {
|
|||
this.chunkPosList = new ArrayList<>(positions);
|
||||
this.setDirty();
|
||||
}
|
||||
|
||||
public static StrongholdLocationCache load(CompoundTag arg, HolderLookup.Provider provider) {
|
||||
StrongholdLocationCache cache = new StrongholdLocationCache();
|
||||
if(arg.contains("Positions", Tag.TAG_LONG_ARRAY)) {
|
||||
long[] positions = arg.getLongArray("Positions");
|
||||
for(long position : positions) {
|
||||
cache.chunkPosList.add(new ChunkPos(position));
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag save(CompoundTag compoundTag, HolderLookup.Provider provider) {
|
||||
long[] serialized = new long[chunkPosList.size()];
|
||||
for(int i = 0; i < chunkPosList.size(); i++) {
|
||||
ChunkPos thePos = chunkPosList.get(i);
|
||||
serialized[i] = thePos.toLong();
|
||||
}
|
||||
compoundTag.putLongArray("Positions", serialized);
|
||||
return compoundTag;
|
||||
}
|
||||
|
||||
public static String getFileId(Holder<DimensionType> dimensionType) {
|
||||
return "mfix_strongholds";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ accessible method net/minecraft/client/resources/model/ModelBakery$BakedCacheKey
|
|||
accessible class net/minecraft/client/resources/model/ModelBakery$ModelBakerImpl
|
||||
accessible class net/minecraft/client/resources/model/ModelManager$ReloadState
|
||||
accessible method net/minecraft/client/resources/model/BlockStateModelLoader definitionLocationToBlockMapper ()Ljava/util/function/Function;
|
||||
accessible method net/minecraft/client/resources/model/BlockStateModelLoader loadBlockStateDefinitionStack (Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/world/level/block/state/StateDefinition;Ljava/util/List;Lnet/minecraft/client/resources/model/UnbakedModel;)Lnet/minecraft/client/resources/model/BlockStateModelLoader$LoadedModels;
|
||||
accessible method net/minecraft/client/resources/model/BlockStateModelLoader loadBlockStateDefinitionStack (Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/world/level/block/state/StateDefinition;Ljava/util/List;)Lnet/minecraft/client/resources/model/BlockStateModelLoader$LoadedModels;
|
||||
accessible class net/minecraft/client/resources/model/BlockStateModelLoader$LoadedBlockModelDefinition
|
||||
accessible method net/minecraft/client/resources/model/BlockStateModelLoader$LoadedBlockModelDefinition <init> (Ljava/lang/String;Lnet/minecraft/client/renderer/block/model/BlockModelDefinition;)V
|
||||
accessible class net/minecraft/world/level/chunk/PalettedContainer$Data
|
||||
|
|
@ -53,3 +53,8 @@ accessible method net/minecraft/client/gui/screens/Screen addRenderableWidget (L
|
|||
accessible field net/minecraft/client/KeyMapping ALL Ljava/util/Map;
|
||||
accessible method net/minecraft/world/level/block/state/StateDefinition appendPropertyCodec (Lcom/mojang/serialization/MapCodec;Ljava/util/function/Supplier;Ljava/lang/String;Lnet/minecraft/world/level/block/state/properties/Property;)Lcom/mojang/serialization/MapCodec;
|
||||
accessible class net/minecraft/client/multiplayer/SessionSearchTrees$Key
|
||||
|
||||
accessible class net/minecraft/client/resources/model/ModelDiscovery$ModelWrapper
|
||||
accessible method net/minecraft/client/resources/model/ModelDiscovery$ModelWrapper <init> (Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/client/resources/model/UnbakedModel;Z)V
|
||||
accessible field net/minecraft/client/resources/model/ModelDiscovery$ModelWrapper parent Lnet/minecraft/client/resources/model/ModelDiscovery$ModelWrapper;
|
||||
accessible method net/minecraft/client/resources/model/BlockStateDefinitions definitionLocationToBlockStateMapper ()Ljava/util/function/Function;
|
||||
|
|
@ -33,7 +33,11 @@ dependencies {
|
|||
modCompileOnly(fabricApi.module("fabric-api-base", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly(fabricApi.module("fabric-command-api-v2", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly(fabricApi.module("fabric-model-loading-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
try {
|
||||
modCompileOnly(fabricApi.module("fabric-model-loading-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
} catch(ignored) {
|
||||
// already reported in common
|
||||
}
|
||||
modCompileOnly(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly(fabricApi.module("fabric-data-generation-api-v1", rootProject.fabric_api_version)) { exclude group: 'net.fabricmc', module: 'fabric-loader' }
|
||||
modCompileOnly("com.terraformersmc:modmenu:${rootProject.modmenu_version}") { transitive false }
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.safety;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import org.embeddedt.modernfix.ModernFix;
|
||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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;
|
||||
|
||||
@Mixin(DynamicTexture.class)
|
||||
@ClientOnlyMixin
|
||||
public class DynamicTextureMixin {
|
||||
@Shadow @Nullable private NativeImage pixels;
|
||||
|
||||
private Exception closeTrace;
|
||||
|
||||
@Inject(method = "method_22793", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/texture/DynamicTexture;pixels:Lcom/mojang/blaze3d/platform/NativeImage;", ordinal = 0))
|
||||
private void checkNullPixels(CallbackInfo ci) {
|
||||
if(pixels == null) {
|
||||
ModernFix.LOGGER.error("Attempted to upload null texture! This is not allowed, closed here", closeTrace);
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "close", at = @At("HEAD"))
|
||||
private void storeCloseTrace(CallbackInfo ci) {
|
||||
closeTrace = new Exception();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,8 @@ junit_version=5.10.0-M1
|
|||
mixinextras_version=0.4.1
|
||||
|
||||
mod_id=modernfix
|
||||
minecraft_version=1.21.4
|
||||
enabled_platforms=fabric,neoforge
|
||||
minecraft_version=25w07a
|
||||
enabled_platforms=fabric
|
||||
forge_version=21.4.47-beta
|
||||
parchment_version=2024.12.22
|
||||
parchment_mc_version=1.21.4
|
||||
|
|
@ -17,10 +17,10 @@ ctm_version=1.21-1.2.0+2
|
|||
ldlib_version=5782845
|
||||
kubejs_version=1902.6.0-build.142
|
||||
rhino_version=1902.2.2-build.268
|
||||
supported_minecraft_versions=1.21.4
|
||||
supported_minecraft_versions=25w07a
|
||||
|
||||
fabric_loader_version=0.16.10
|
||||
fabric_api_version=0.113.0+1.21.4
|
||||
fabric_api_version=0.116.1+1.21.5
|
||||
|
||||
continuity_version=3.0.0-beta.4+1.20.2
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user