Merge remote-tracking branch 'origin/main' into 1.18
This commit is contained in:
commit
4a47ed7f43
|
|
@ -268,6 +268,7 @@ public class ModelBakeryHelpers {
|
|||
ModernFix.LOGGER.error("Suppressed additional {} model errors for domain {}", entry.getIntValue(), entry.getKey());
|
||||
}
|
||||
});
|
||||
blockstateErrors.clear();
|
||||
modelFiles = null;
|
||||
Function<ResourceLocation, UnbakedModel> modelGetter = loc -> {
|
||||
UnbakedModel m = basicModels.get(loc);
|
||||
|
|
@ -275,7 +276,11 @@ public class ModelBakeryHelpers {
|
|||
return m != null ? m : bakeryModelGetter.apply(loc);
|
||||
};
|
||||
for(BlockModel model : basicModels.values()) {
|
||||
materialSet.addAll(model.getMaterials(modelGetter, errorSet));
|
||||
try {
|
||||
materialSet.addAll(model.getMaterials(modelGetter, errorSet));
|
||||
} catch(Throwable e) {
|
||||
ModernFix.LOGGER.error("Model {} threw error while getting materials", model.name, e);
|
||||
}
|
||||
}
|
||||
//errorSet.stream().filter(pair -> !pair.getSecond().equals(MISSING_MODEL_LOCATION_STRING)).forEach(pair -> LOGGER.warn("Unable to resolve texture reference: {} in {}", pair.getFirst(), pair.getSecond()));
|
||||
stopwatch.stop();
|
||||
|
|
|
|||
|
|
@ -1,23 +1,33 @@
|
|||
package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.RemovalNotification;
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.math.Transformation;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
||||
import net.minecraft.client.renderer.block.model.BlockModelDefinition;
|
||||
import net.minecraft.client.renderer.block.model.ItemModelGenerator;
|
||||
import net.minecraft.client.renderer.block.model.MultiVariant;
|
||||
import net.minecraft.client.renderer.block.model.multipart.MultiPart;
|
||||
import net.minecraft.client.renderer.texture.AtlasSet;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.texture.*;
|
||||
import net.minecraft.client.resources.ClientPackSource;
|
||||
import net.minecraft.client.resources.model.*;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.FilePackResources;
|
||||
import net.minecraft.server.packs.FolderPackResources;
|
||||
import net.minecraft.server.packs.PackResources;
|
||||
import net.minecraft.server.packs.VanillaPackResources;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
|
|
@ -37,6 +47,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.*;
|
||||
|
|
@ -44,6 +55,9 @@ import java.util.concurrent.ConcurrentMap;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collector;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/* high priority so that our injectors are added before other mods' */
|
||||
@Mixin(value = ModelBakery.class, priority = 600)
|
||||
|
|
@ -78,6 +92,12 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
@Shadow @Nullable public abstract BakedModel bake(ResourceLocation location, ModelState transform);
|
||||
|
||||
@Shadow @Final private Map<ResourceLocation, UnbakedModel> topLevelModels;
|
||||
@Shadow @Final private static String MISSING_MODEL_LOCATION_STRING;
|
||||
|
||||
@Shadow protected abstract void cacheAndQueueDependencies(ResourceLocation location, UnbakedModel model);
|
||||
|
||||
@Shadow @Final private BlockModelDefinition.Context context;
|
||||
@Shadow @Final private static Map<ResourceLocation, StateDefinition<Block, BlockState>> STATIC_DEFINITIONS;
|
||||
private Cache<Triple<ResourceLocation, Transformation, Boolean>, BakedModel> loadedBakedModels;
|
||||
private Cache<ResourceLocation, UnbakedModel> loadedModels;
|
||||
|
||||
|
|
@ -144,6 +164,103 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
return this.missingModel;
|
||||
}
|
||||
|
||||
private Set<ResourceLocation> blockStateFiles = new ObjectOpenHashSet<>();
|
||||
private Set<ResourceLocation> modelFiles = new ObjectOpenHashSet<>();
|
||||
|
||||
private boolean forceLoadModel = false;
|
||||
|
||||
@Inject(method = "loadModel", at = @At(value = "HEAD", shift = At.Shift.AFTER), cancellable = true)
|
||||
private void ignoreNonFabricModel(ResourceLocation modelLocation, CallbackInfo ci) throws Exception {
|
||||
if(this.inTextureGatheringPass && !this.forceLoadModel) {
|
||||
// Custom model processor, try to avoid loading unwrapped models
|
||||
// First add this to the list of models to scan for textures
|
||||
ResourceLocation blockStateLocation = null;
|
||||
if(modelLocation instanceof ModelResourceLocation) {
|
||||
ModelResourceLocation location = (ModelResourceLocation)modelLocation;
|
||||
if(Objects.equals(location.getVariant(), "inventory")) {
|
||||
modelFiles.add(new ResourceLocation(location.getNamespace(), "item/" + location.getPath()));
|
||||
} else {
|
||||
blockStateLocation = new ResourceLocation(location.getNamespace(), location.getPath());
|
||||
blockStateFiles.add(blockStateLocation);
|
||||
}
|
||||
} else
|
||||
modelFiles.add(modelLocation);
|
||||
// Now check if it's a wrapped model
|
||||
boolean isWrappedModel = false;
|
||||
Set<ResourceLocation> oldLoadingStack = this.loadingStack.size() > 0 ? new ObjectOpenHashSet<>(this.loadingStack) : ImmutableSet.of();
|
||||
// Set the correct blockstate context
|
||||
StateDefinition<Block, BlockState> statecontainer;
|
||||
if(blockStateLocation != null) {
|
||||
statecontainer = STATIC_DEFINITIONS.get(blockStateLocation);
|
||||
if(statecontainer == null)
|
||||
statecontainer = Registry.BLOCK.get(blockStateLocation).getStateDefinition();
|
||||
} else
|
||||
statecontainer = Blocks.AIR.getStateDefinition();
|
||||
this.context.setDefinition(statecontainer);
|
||||
// Pretend to be caching the model by caching the missing model, if the actually cached model isn't
|
||||
// the exact same instance we know a mixin tampered with it
|
||||
this.forceLoadModel = true;
|
||||
this.cacheAndQueueDependencies(modelLocation, this.missingModel);
|
||||
this.forceLoadModel = false;
|
||||
this.loadingStack.clear();
|
||||
this.loadingStack.addAll(oldLoadingStack);
|
||||
if(this.smallLoadingCache.get(modelLocation) != this.missingModel) {
|
||||
/* probably a wrapped model, allow it to load normally */
|
||||
isWrappedModel = true;
|
||||
}
|
||||
this.smallLoadingCache.clear();
|
||||
this.unbakedCache.remove(modelLocation);
|
||||
// Load the model through the normal code path
|
||||
if(isWrappedModel) {
|
||||
ModernFix.LOGGER.warn("Model {} appears to be replaced by another mod and will load at startup", modelLocation);
|
||||
this.forceLoadModel = true;
|
||||
this.loadModel(modelLocation);
|
||||
this.forceLoadModel = false;
|
||||
}
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean trustedResourcePack(PackResources pack) {
|
||||
return pack instanceof VanillaPackResources ||
|
||||
pack instanceof ClientPackSource ||
|
||||
pack instanceof FolderPackResources ||
|
||||
pack instanceof FilePackResources;
|
||||
}
|
||||
|
||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Ljava/util/stream/Stream;collect(Ljava/util/stream/Collector;)Ljava/lang/Object;", ordinal = 0))
|
||||
private Object collectExtraTextures(Stream<Material> instance, Collector<?, ?, ?> arCollector) {
|
||||
Set<Material> materialsSet = new ObjectOpenHashSet<>(instance.collect(Collectors.toSet()));
|
||||
ModelBakeryHelpers.gatherModelMaterials(this.resourceManager, this::trustedResourcePack, materialsSet,
|
||||
blockStateFiles, modelFiles, this.missingModel, json -> BlockModel.GSON.fromJson(json, BlockModel.class),
|
||||
this::getModel);
|
||||
/* take every texture from these folders (1.19.3+ emulation) */
|
||||
String[] extraFolders = new String[] {
|
||||
"block",
|
||||
"blocks",
|
||||
"item",
|
||||
"items",
|
||||
"bettergrass"
|
||||
};
|
||||
for(String folder : extraFolders) {
|
||||
Collection<ResourceLocation> textureLocations = this.resourceManager.listResources("textures/" + folder, p -> p.endsWith(".png"));
|
||||
for(ResourceLocation rl : textureLocations) {
|
||||
if(rl.getNamespace().equals("assets")) {
|
||||
/* buggy pack, correct path */
|
||||
int slashIndex = rl.getPath().indexOf('/');
|
||||
String actualNamespace = rl.getPath().substring(0, slashIndex);
|
||||
String actualPath = rl.getPath().substring(slashIndex + 1);
|
||||
rl = new ResourceLocation(actualNamespace, actualPath);
|
||||
}
|
||||
ResourceLocation texLoc = new ResourceLocation(rl.getNamespace(), rl.getPath().substring(9, rl.getPath().length() - 4));
|
||||
materialsSet.add(new Material(TextureAtlas.LOCATION_BLOCKS, texLoc));
|
||||
}
|
||||
}
|
||||
blockStateFiles = null;
|
||||
modelFiles = null;
|
||||
return materialsSet;
|
||||
}
|
||||
|
||||
@Inject(method = "uploadTextures", at = @At(value = "FIELD", target = "Lnet/minecraft/client/resources/model/ModelBakery;topLevelModels:Ljava/util/Map;", ordinal = 0), cancellable = true)
|
||||
private void skipBake(TextureManager resourceManager, ProfilerFiller profiler, CallbackInfoReturnable<AtlasSet> cir) {
|
||||
profiler.pop();
|
||||
|
|
@ -165,15 +282,21 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
}
|
||||
};
|
||||
// discard unwrapped models
|
||||
int oldSize = this.unbakedCache.size();
|
||||
Predicate<Map.Entry<ResourceLocation, UnbakedModel>> isVanillaModel = entry -> entry.getValue() instanceof BlockModel || entry.getValue() instanceof MultiVariant || entry.getValue() instanceof MultiPart;
|
||||
// bake indigo models
|
||||
this.topLevelModels.entrySet().forEach((entry) -> {
|
||||
if(!isVanillaModel.test(entry))
|
||||
this.bake(entry.getKey(), BlockModelRotation.X0_Y0);
|
||||
});
|
||||
this.unbakedCache.entrySet().removeIf(isVanillaModel);
|
||||
ModernFix.LOGGER.info("{} models evicted, {} custom models loaded permanently", oldSize - this.unbakedCache.size(), this.unbakedCache.size());
|
||||
this.topLevelModels.entrySet().removeIf(isVanillaModel);
|
||||
// bake indigo models
|
||||
Stopwatch watch = Stopwatch.createStarted();
|
||||
this.topLevelModels.forEach((key, value) -> {
|
||||
try {
|
||||
this.bake(key, BlockModelRotation.X0_Y0);
|
||||
} catch(RuntimeException e) {
|
||||
ModernFix.LOGGER.error("Model {} failed to bake", key, e);
|
||||
}
|
||||
});
|
||||
watch.stop();
|
||||
ModernFix.LOGGER.info("Early model bake took {}", watch);
|
||||
ModernFix.LOGGER.info("{} unbaked models, {} baked models loaded permanently", this.unbakedCache.size(), this.bakedCache.size());
|
||||
this.unbakedCache = new LayeredForwardingMap<>(new Map[] { this.unbakedCache, mutableBackingMap });
|
||||
this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache);
|
||||
|
||||
|
|
@ -197,7 +320,6 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
return unbakedCache.get(rl);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @author embeddedt
|
||||
* @reason synchronize
|
||||
|
|
@ -284,7 +406,19 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
|||
if(debugDynamicModelLoading)
|
||||
LOGGER.info("Baking {}", arg);
|
||||
UnbakedModel iunbakedmodel = this.getModel(arg);
|
||||
iunbakedmodel.getMaterials(this::getModel, new HashSet<>());
|
||||
Set<Pair<String, String>> errorSet = new HashSet<>();
|
||||
Collection<Material> theMaterials = iunbakedmodel.getMaterials(this::getModel, errorSet);
|
||||
/* check if sprites are actually present */
|
||||
TextureAtlasSprite missingSprite = this.atlasSet.getAtlas(TextureAtlas.LOCATION_BLOCKS).getSprite(MissingTextureAtlasSprite.getLocation());
|
||||
for(Material m : theMaterials) {
|
||||
if(m.atlasLocation().equals(TextureAtlas.LOCATION_BLOCKS)) {
|
||||
TextureAtlasSprite sprite = this.atlasSet.getAtlas(TextureAtlas.LOCATION_BLOCKS).getSprite(m.texture());
|
||||
if(sprite == missingSprite && !m.texture().equals(MissingTextureAtlasSprite.getLocation()))
|
||||
ModernFix.LOGGER.warn("Texture {} is not present in blocks atlas", m.texture());
|
||||
}
|
||||
}
|
||||
errorSet.stream().filter(pair -> !pair.getSecond().equals(MISSING_MODEL_LOCATION_STRING)).forEach(pair -> LOGGER.warn("Unable to resolve texture reference: {} in {}", pair.getFirst(), pair.getSecond()));
|
||||
|
||||
if(iunbakedmodel == missingModel && debugDynamicModelLoading)
|
||||
LOGGER.warn("Model {} not present", arg);
|
||||
BakedModel ibakedmodel = null;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user