Merge remote-tracking branch 'origin/1.18' into 1.19.2

This commit is contained in:
embeddedt 2023-05-08 14:24:27 -04:00
commit 985b5a68fe
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
2 changed files with 160 additions and 14 deletions

View File

@ -260,6 +260,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);
@ -267,7 +268,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();
@ -308,6 +313,10 @@ public class ModelBakeryHelpers {
}
}
}
// 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);

View File

@ -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,17 +282,25 @@ 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);
if(this.bakedMissingModel != null)
((DynamicBakedModelProvider)this.bakedTopLevelModels).setMissingModel(this.bakedMissingModel);
// ensure missing model is a permanent override
this.bakedTopLevelModels.put(MISSING_MODEL_LOCATION, this.bake(MISSING_MODEL_LOCATION, BlockModelRotation.X0_Y0));
@ -197,7 +322,6 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
return unbakedCache.get(rl);
}
/**
* @author embeddedt
* @reason synchronize
@ -284,7 +408,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;
@ -299,8 +435,9 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
// use a shared baked missing model
if(bakedMissingModel == null) {
bakedMissingModel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg);
((DynamicBakedModelProvider)this.bakedTopLevelModels).setMissingModel(bakedMissingModel);
}
if(this.bakedTopLevelModels instanceof DynamicBakedModelProvider)
((DynamicBakedModelProvider)this.bakedTopLevelModels).setMissingModel(bakedMissingModel);
ibakedmodel = bakedMissingModel;
} else
ibakedmodel = iunbakedmodel.bake((ModelBakery) (Object) this, textureGetter, arg2, arg);