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());
|
ModernFix.LOGGER.error("Suppressed additional {} model errors for domain {}", entry.getIntValue(), entry.getKey());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
blockstateErrors.clear();
|
||||||
modelFiles = null;
|
modelFiles = null;
|
||||||
Function<ResourceLocation, UnbakedModel> modelGetter = loc -> {
|
Function<ResourceLocation, UnbakedModel> modelGetter = loc -> {
|
||||||
UnbakedModel m = basicModels.get(loc);
|
UnbakedModel m = basicModels.get(loc);
|
||||||
|
|
@ -275,7 +276,11 @@ public class ModelBakeryHelpers {
|
||||||
return m != null ? m : bakeryModelGetter.apply(loc);
|
return m != null ? m : bakeryModelGetter.apply(loc);
|
||||||
};
|
};
|
||||||
for(BlockModel model : basicModels.values()) {
|
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()));
|
//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();
|
stopwatch.stop();
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,33 @@
|
||||||
package org.embeddedt.modernfix.fabric.mixin.perf.dynamic_resources;
|
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.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.cache.RemovalNotification;
|
import com.google.common.cache.RemovalNotification;
|
||||||
import com.google.common.collect.ForwardingMap;
|
import com.google.common.collect.ForwardingMap;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.mojang.math.Transformation;
|
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.BlockModel;
|
||||||
|
import net.minecraft.client.renderer.block.model.BlockModelDefinition;
|
||||||
import net.minecraft.client.renderer.block.model.ItemModelGenerator;
|
import net.minecraft.client.renderer.block.model.ItemModelGenerator;
|
||||||
import net.minecraft.client.renderer.block.model.MultiVariant;
|
import net.minecraft.client.renderer.block.model.MultiVariant;
|
||||||
import net.minecraft.client.renderer.block.model.multipart.MultiPart;
|
import net.minecraft.client.renderer.block.model.multipart.MultiPart;
|
||||||
import net.minecraft.client.renderer.texture.AtlasSet;
|
import net.minecraft.client.renderer.texture.*;
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
import net.minecraft.client.resources.ClientPackSource;
|
||||||
import net.minecraft.client.renderer.texture.TextureManager;
|
|
||||||
import net.minecraft.client.resources.model.*;
|
import net.minecraft.client.resources.model.*;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
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.server.packs.resources.ResourceManager;
|
||||||
import net.minecraft.util.profiling.ProfilerFiller;
|
import net.minecraft.util.profiling.ProfilerFiller;
|
||||||
import net.minecraft.world.level.block.Block;
|
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.BlockState;
|
||||||
import net.minecraft.world.level.block.state.StateDefinition;
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
import org.apache.commons.lang3.tuple.Triple;
|
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.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
@ -44,6 +55,9 @@ import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
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' */
|
/* high priority so that our injectors are added before other mods' */
|
||||||
@Mixin(value = ModelBakery.class, priority = 600)
|
@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 @Nullable public abstract BakedModel bake(ResourceLocation location, ModelState transform);
|
||||||
|
|
||||||
@Shadow @Final private Map<ResourceLocation, UnbakedModel> topLevelModels;
|
@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<Triple<ResourceLocation, Transformation, Boolean>, BakedModel> loadedBakedModels;
|
||||||
private Cache<ResourceLocation, UnbakedModel> loadedModels;
|
private Cache<ResourceLocation, UnbakedModel> loadedModels;
|
||||||
|
|
||||||
|
|
@ -144,6 +164,103 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
||||||
return this.missingModel;
|
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)
|
@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) {
|
private void skipBake(TextureManager resourceManager, ProfilerFiller profiler, CallbackInfoReturnable<AtlasSet> cir) {
|
||||||
profiler.pop();
|
profiler.pop();
|
||||||
|
|
@ -165,15 +282,21 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// discard unwrapped models
|
// 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;
|
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);
|
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.unbakedCache = new LayeredForwardingMap<>(new Map[] { this.unbakedCache, mutableBackingMap });
|
||||||
this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache);
|
this.bakedTopLevelModels = new DynamicBakedModelProvider((ModelBakery)(Object)this, bakedCache);
|
||||||
|
|
||||||
|
|
@ -197,7 +320,6 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
||||||
return unbakedCache.get(rl);
|
return unbakedCache.get(rl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author embeddedt
|
* @author embeddedt
|
||||||
* @reason synchronize
|
* @reason synchronize
|
||||||
|
|
@ -284,7 +406,19 @@ public abstract class ModelBakeryMixin implements IExtendedModelBakery {
|
||||||
if(debugDynamicModelLoading)
|
if(debugDynamicModelLoading)
|
||||||
LOGGER.info("Baking {}", arg);
|
LOGGER.info("Baking {}", arg);
|
||||||
UnbakedModel iunbakedmodel = this.getModel(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)
|
if(iunbakedmodel == missingModel && debugDynamicModelLoading)
|
||||||
LOGGER.warn("Model {} not present", arg);
|
LOGGER.warn("Model {} not present", arg);
|
||||||
BakedModel ibakedmodel = null;
|
BakedModel ibakedmodel = null;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user